From 79197454f8296ebbb7423b961f9db6fcff688b6e Mon Sep 17 00:00:00 2001 From: Danny Avila Date: Sun, 27 Jul 2025 12:19:01 -0400 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=A6=20feat:=20Move=20Shared=20Componen?= =?UTF-8?q?ts=20to=20`@librechat/client`=20(#8685)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: init @librechat/client * feat: Add common types and interfaces for accessibility, agents, artifacts, assistants, and tools * feat: Add jotai as a peer dependency * fix build client package * feat: cleanup unused types from common/index.ts - Remove 104 unused type exports from packages/client/src/common/index.ts - Keep only 7 actually used exports (93% reduction) - Add cleanup script with enhanced import pattern detection - Support both named imports and namespace imports (* as t) - Create automatic backups and comprehensive documentation - Maintain type safety with build verification - No breaking changes to existing code Kept exports: - TShowToast, Option, OptionWithIcon, DropdownValueSetter - MentionOption, NotificationSeverity, MenuItemProps Scripts: cleanup-common-types-safe.js, README-CLEANUP.md * fix: cleanup * fix: package; refactor: tsconfig * feat: add back `recoil` * fix: move dependencies to peerDependencies in client package * feat: add @librechat/client as a dependency in package.json and package-lock.json * feat: update client package configuration and dependencies - Added new dependencies for Rollup plugins and updated existing ones in package.json and package-lock.json. - Introduced a new Rollup configuration file for building the client package. - Refactored build scripts to include a dedicated build command for the client. - Updated TypeScript configuration for improved module resolution and type declaration output. - Integrated a Toast component from the client package into the main App component. * feat: enhance Rollup configuration for client package - Updated terser plugin settings to preserve directives like 'use client'. - Added custom warning handler to ignore "use client" directive warnings during the build process. * chore: rename package/client build script command * feat: update client package dependencies and Rollup configuration - Added rollup-plugin-postcss to package.json and updated package-lock.json. - Enhanced Rollup configuration to include postcss plugin for CSS handling. - Updated index.ts to export all components from the components directory for better modularity. * feat: add client package directory to update configuration - Included the 'client' package directory in the update.js configuration to ensure it is recognized during updates. * feat: export Toast component in client package - Added export for the Toast component in index.ts to enhance modularity and accessibility of components. * feat: /client transition to @librechat/client * chore: fixed formatting issues * fix: update peer dependencies in @librechat/client to prevent bundling them * fix: correct useSprings implementation in SplitText component * fix: circular dependencies in DataTable * fix: add remaining peer dependencies and match actual versions previously used in `client/package.json` * fix: correct frontend:ci script to include client package build * chore: enhance unused package detection for @librechat/client and improve dependency extraction * fix: add missing peer dependency for @radix-ui/react-collapsible * chore: include "packages/client" in unused i18next keys detection * test: update AgentFooter tests to use document.querySelector for spinner checks test: mock window.matchMedia in setupTests.js for consistent test environment * feat: add react-hook-form dependency and update FormInput component to use its types * chore: linting * refactor: remove unused defaultSelectedValues prop from MCPSelect and MultiSelect components * chore: linting * feat: update GitHub Actions workflow to publish @librechat/client * chore: update GitHub Actions workflow to install and build data-provider and client dependencies * chore: add missing @testing-library/react dependency to client package * chore: update tsconfig.json to exclude additional test files * chore: fix build issues, resolve latest LC changes * chore: move MCP components outside of `~/components/ui` * feat: implement dynamic theme system with environment variable support and Tailwind CSS integration * chore: remove unnecessary logging of sttExternal and ttsExternal in Speech component * chore: squashed cleanup commits chore: move @tanstack/react-virtual to dependencies and remove recoil from package.json chore: move dependencies to peerDependencies in package.json feat: update package.json and rollup.config.js to include jotai and enhance bundling configuration feat: update package.json and rollup.config.js to include jotai and enhance bundling configuration refactor: reorganize exports in index.ts for improved clarity refactor: remove unused types and interfaces from common files refactor: update peer dependencies and improve component typings - Removed duplicate peer dependencies from package.json and organized them. - Updated rollup.config.js to disable TypeScript checking during the build process. - Modified AnimatedTabs component to use React.ReactNode for label and content types, and added TypeScript workarounds for compatibility. - Enhanced Label and Separator components to accept an optional className prop and improved prop spreading. - Updated Slider component to include an optional className prop and refined prop handling for better type safety. refactor: clean up client workflow and update package dependencies refactor: update package dependencies and improve PostCSS and Rollup configurations chore: bump version to 0.1.2 in package.json chore: bump client version to 0.1.2 in package-lock.json chore: bump client version to 0.1.3 and update dependencies chore: bump client version to 0.1.4 and update @react-spring dependencies chore: update package version to 0.1.5 and adjust peer dependencies - Bump version in package.json from 0.1.4 to 0.1.5. - Update peer dependency for @tanstack/react-query to allow version 5.0.0. - Add @tanstack/react-table and @tanstack/react-virtual as dependencies. - Update various dependencies to their latest compatible versions. - Simplify postcss.config.js by removing unnecessary options. - Clean up rollup.config.js by removing ignored PostCSS warnings. - Update CheckboxButton component to cast icon as React JSX element. - Adjust Combobox component's class names for better styling. - Change DropdownPopup component to use React's namespace import. - Modify InputOTP component to use 'any' type for OTPInputContext. - Ensure displayLabel and value in ModelParameters are converted to strings. - Update MultiSearch component's placeholder to ensure it's a string. - Cast selectIcon in MultiSelect as React JSX element for consistency. - Update OGDialogTemplate to cast selectText as React JSX element. - Initialize animationRef in PixelCard with undefined for clarity. - Add TypeScript ignore comments in Select and SelectDropDown components for Radix UI type conflicts. - Ensure title in SelectDropDown is a string and adjust rendering of options. - Update useLocalize hook to cast options as any for compatibility. refactor: code structure; chore: translations cleanup chore: remove unused imports and clean up code in NewChat component refactor: enhance Menu component to support custom render functions for menu items style: update itemClassName in ToolsDropdown for improved UI consistency fix: merge conflicts chore: update @radix-ui/react-accordion to version 1.2.11 * refactor: remove unnecessary TypeScript type assertions in AnimatedTabs, Label, Separator, and Slider components * feat: enhance theme system with localStorage persistence and new theme atoms * chore: bump version of @librechat/client to 0.1.7 * chore: fix ci/cd warnings/errors related to linting and unused localization keys * chore: update dependencies for class-variance-authority, clsx, and match-sorter * chore: bump @librechat/client to v0.1.8 * feat: add utility colors for theme customization and remove unused tailwindConfig * v0.1.9 --------- Co-authored-by: Marco Beretta <81851188+berry-13@users.noreply.github.com> --- .github/workflows/client.yml | 46 +- .github/workflows/i18n-unused-keys.yml | 3 +- .github/workflows/unused-packages.yml | 53 +- bun.lockb | Bin 1131200 -> 1113680 bytes client/package.json | 8 +- client/src/App.jsx | 20 +- client/src/Providers/index.ts | 2 - client/src/a11y/LiveAnnouncer.tsx | 3 +- client/src/common/menus.ts | 1 - client/src/common/types.ts | 15 +- client/src/components/Artifacts/Artifacts.tsx | 2 +- client/src/components/Artifacts/Code.tsx | 7 +- .../components/Artifacts/DownloadArtifact.tsx | 2 +- client/src/components/Artifacts/Mermaid.tsx | 3 +- client/src/components/Audio/TTS.tsx | 2 +- client/src/components/Audio/Voices.tsx | 2 +- client/src/components/Auth/AuthLayout.tsx | 4 +- client/src/components/Auth/Login.tsx | 4 +- client/src/components/Auth/LoginForm.tsx | 6 +- client/src/components/Auth/Registration.tsx | 4 +- .../components/Auth/RequestPasswordReset.tsx | 4 +- client/src/components/Auth/ResetPassword.tsx | 2 +- .../src/components/Auth/SocialLoginRender.tsx | 2 +- .../src/components/Auth/TwoFactorScreen.tsx | 4 +- client/src/components/Auth/VerifyEmail.tsx | 5 +- .../Bookmarks/BookmarkEditDialog.tsx | 4 +- .../src/components/Bookmarks/BookmarkForm.tsx | 3 +- .../src/components/Bookmarks/BookmarkItem.tsx | 2 +- .../Bookmarks/DeleteBookmarkButton.tsx | 13 +- .../Bookmarks/EditBookmarkButton.tsx | 4 +- client/src/components/Chat/AddMultiConvo.tsx | 2 +- client/src/components/Chat/ChatView.tsx | 2 +- .../components/Chat/ExportAndShareMenu.tsx | 4 +- client/src/components/Chat/Header.tsx | 3 +- .../src/components/Chat/Input/Artifacts.tsx | 2 +- .../Chat/Input/ArtifactsSubMenu.tsx | 2 +- .../components/Chat/Input/AudioRecorder.tsx | 5 +- client/src/components/Chat/Input/BadgeRow.tsx | 2 +- client/src/components/Chat/Input/ChatForm.tsx | 2 +- .../components/Chat/Input/CircleRender.tsx | 2 +- .../components/Chat/Input/CodeInterpreter.tsx | 2 +- .../components/Chat/Input/CollapseChat.tsx | 2 +- .../src/components/Chat/Input/EditBadges.tsx | 2 +- .../src/components/Chat/Input/FileSearch.tsx | 3 +- .../Chat/Input/Files/AttachFile.tsx | 2 +- .../Chat/Input/Files/AttachFileMenu.tsx | 6 +- .../Chat/Input/Files/DragDropModal.tsx | 2 +- .../Chat/Input/Files/FilePreview.tsx | 4 +- .../components/Chat/Input/Files/FileRow.tsx | 4 +- .../components/Chat/Input/Files/FilesView.tsx | 2 +- .../Chat/Input/Files/ImagePreview.tsx | 8 +- .../Chat/Input/Files/Table/Columns.tsx | 11 +- .../Chat/Input/Files/Table/DataTable.tsx | 13 +- .../Input/Files/Table/SortFilterHeader.tsx | 4 +- .../Chat/Input/Files/Table/TemplateTable.tsx | 2 +- .../components/Chat/Input/HeaderOptions.tsx | 6 +- .../components/Chat/Input/MCPConfigDialog.tsx | 121 + .../src/components/Chat/Input/MCPSelect.tsx | 8 +- .../src/components/Chat/Input/MCPSubMenu.tsx | 6 +- client/src/components/Chat/Input/Mention.tsx | 5 +- .../components/Chat/Input/OptionsPopover.tsx | 5 +- .../components/Chat/Input/PopoverButtons.tsx | 3 +- .../components/Chat/Input/PromptsCommand.tsx | 4 +- .../src/components/Chat/Input/SendButton.tsx | 3 +- .../src/components/Chat/Input/StopButton.tsx | 2 +- .../components/Chat/Input/ToolsDropdown.tsx | 5 +- .../src/components/Chat/Input/WebSearch.tsx | 2 +- client/src/components/Chat/Landing.tsx | 2 +- .../components/Chat/Menus/BookmarkMenu.tsx | 4 +- .../Menus/Bookmarks/BookmarkMenuItems.tsx | 2 +- .../Endpoints/components/EndpointItem.tsx | 2 +- .../components/Chat/Menus/HeaderNewChat.tsx | 3 +- .../src/components/Chat/Menus/OpenSidebar.tsx | 3 +- .../Chat/Menus/Presets/EditPresetDialog.tsx | 16 +- .../Chat/Menus/Presets/PresetItems.tsx | 14 +- .../src/components/Chat/Menus/PresetsMenu.tsx | 2 +- .../components/Chat/Menus/UI/TitleButton.tsx | 2 +- .../Chat/Messages/Content/ContentParts.tsx | 2 +- .../Chat/Messages/Content/DialogImage.tsx | 2 +- .../Chat/Messages/Content/EditMessage.tsx | 4 +- .../Chat/Messages/Content/Image.tsx | 2 +- .../Messages/Content/MarkdownComponents.tsx | 5 +- .../Chat/Messages/Content/MessageContent.tsx | 2 +- .../Messages/Content/Parts/EditTextPart.tsx | 2 +- .../Chat/Messages/Content/Parts/LogLink.tsx | 2 +- .../Parts/OpenAIImageGen/OpenAIImageGen.tsx | 2 +- .../Chat/Messages/Content/ProgressText.tsx | 2 +- .../Chat/Messages/Content/SearchContent.tsx | 2 +- .../Chat/Messages/Content/ToolCall.tsx | 2 +- .../src/components/Chat/Messages/Feedback.tsx | 16 +- client/src/components/Chat/Messages/Fork.tsx | 2 +- .../components/Chat/Messages/HoverButtons.tsx | 2 +- .../components/Chat/Messages/MessageParts.tsx | 1 - .../Chat/Messages/MinimalHoverButtons.tsx | 2 +- .../components/Chat/Messages/MultiMessage.tsx | 3 - client/src/components/Chat/TemporaryChat.tsx | 2 +- .../Conversations/Conversations.tsx | 4 +- client/src/components/Conversations/Convo.tsx | 4 +- .../ConvoOptions/ConvoOptions.tsx | 4 +- .../ConvoOptions/DeleteButton.tsx | 6 +- .../ConvoOptions/ShareButton.tsx | 3 +- .../ConvoOptions/SharedLinkButton.tsx | 12 +- client/src/components/Endpoints/Icon.tsx | 22 +- .../Endpoints/MessageEndpointIcon.tsx | 2 +- .../src/components/Endpoints/MinimalIcon.tsx | 2 +- .../Endpoints/SaveAsPresetDialog.tsx | 10 +- .../Endpoints/Settings/Advanced.tsx | 10 +- .../Endpoints/Settings/AgentSettings.tsx | 4 +- .../Endpoints/Settings/Assistants.tsx | 7 +- .../Endpoints/Settings/Examples.tsx | 6 +- .../components/Endpoints/Settings/Google.tsx | 15 +- .../Endpoints/Settings/OptionHover.tsx | 4 +- .../components/Endpoints/Settings/Plugins.tsx | 10 +- client/src/components/Files/ActionButton.tsx | 2 +- .../src/components/Files/DeleteIconButton.tsx | 3 +- .../Files/FileList/DataTableFile.tsx | 11 +- .../Files/FileList/FileListItem.tsx | 5 +- .../Files/FileList/FileListItem2.tsx | 7 +- .../components/Files/FileList/FilePreview.tsx | 9 +- .../Files/FileList/FileSidePanel.tsx | 5 +- .../Files/FileList/FileTableColumns.tsx | 9 +- .../Files/FileList/UploadFileButton.tsx | 4 +- .../Files/FileList/UploadFileModal.tsx | 3 +- .../Files/VectorStore/VectorStoreButton.tsx | 4 +- .../Files/VectorStore/VectorStoreListItem.tsx | 3 +- .../Files/VectorStore/VectorStorePreview.tsx | 5 +- .../VectorStore/VectorStoreSidePanel.tsx | 9 +- .../Input/Generations/Regenerate.tsx | 4 +- .../src/components/Input/Generations/Stop.tsx | 6 +- .../Input/ModelSelect/Anthropic.tsx | 2 +- .../components/Input/ModelSelect/ChatGPT.tsx | 2 +- .../components/Input/ModelSelect/Google.tsx | 2 +- .../ModelSelect}/MultiSelectDropDown.tsx | 10 +- .../ModelSelect}/MultiSelectPop.tsx | 12 +- .../components/Input/ModelSelect/OpenAI.tsx | 2 +- .../Input/ModelSelect/PluginsByIndex.tsx | 11 +- .../ModelSelect}/SelectDropDownPop.tsx | 2 +- .../Input/SetKeyDialog/GoogleConfig.tsx | 2 +- .../Input/SetKeyDialog/InputWithLabel.tsx | 2 +- .../Input/SetKeyDialog/SetKeyDialog.tsx | 8 +- .../{ui => }/MCP/CustomUserVarsSection.tsx | 4 +- .../{ui => }/MCP/MCPConfigDialog.tsx | 10 +- .../{ui => }/MCP/MCPServerStatusIcon.tsx | 0 .../MCP/ServerInitializationSection.tsx | 7 +- .../components/Messages/Content/CodeBlock.tsx | 7 +- .../src/components/Messages/Content/Error.tsx | 2 +- .../components/Messages/Content/Plugin.tsx | 10 +- .../components/Messages/Content/RunCode.tsx | 9 +- client/src/components/Nav/AccountSettings.tsx | 3 +- .../components/Nav/Bookmarks/BookmarkNav.tsx | 2 +- .../Nav/ExportConversation/ExportModal.tsx | 11 +- client/src/components/Nav/Nav.tsx | 2 +- client/src/components/Nav/NavToggle.tsx | 4 +- client/src/components/Nav/NewChat.tsx | 7 +- client/src/components/Nav/Settings.tsx | 29 +- .../Nav/SettingsTabs/Account/Avatar.tsx | 6 +- .../SettingsTabs/Account/BackupCodesItem.tsx | 4 +- .../SettingsTabs/Account/DeleteAccount.tsx | 4 +- .../Account/DisableTwoFactorToggle.tsx | 2 +- .../Account/DisplayUsernameMessages.tsx | 2 +- .../Account/TwoFactorAuthentication.tsx | 18 +- .../Account/TwoFactorPhases/BackupPhase.tsx | 2 +- .../Account/TwoFactorPhases/DisablePhase.tsx | 2 +- .../Account/TwoFactorPhases/QRPhase.tsx | 2 +- .../Account/TwoFactorPhases/SetupPhase.tsx | 2 +- .../Account/TwoFactorPhases/VerifyPhase.tsx | 8 +- .../Balance/AutoRefillSettings.tsx | 4 +- .../SettingsTabs/Balance/TokenCreditsItem.tsx | 4 +- .../Nav/SettingsTabs/Chat/ChatDirection.tsx | 2 +- .../SettingsTabs/Chat/FontSizeSelector.tsx | 3 +- .../Nav/SettingsTabs/Chat/ForkSettings.tsx | 4 +- .../Nav/SettingsTabs/Chat/SaveBadgesState.tsx | 4 +- .../Nav/SettingsTabs/Chat/ShowThinking.tsx | 4 +- .../SettingsTabs/Commands/AtCommandSwitch.tsx | 2 +- .../Commands/PlusCommandSwitch.tsx | 2 +- .../Commands/SlashCommandSwitch.tsx | 2 +- .../Nav/SettingsTabs/DangerButton.tsx | 5 +- .../Nav/SettingsTabs/Data/ClearChats.tsx | 12 +- .../components/Nav/SettingsTabs/Data/Data.tsx | 2 +- .../Nav/SettingsTabs/Data/DeleteCache.tsx | 13 +- .../SettingsTabs/Data/ImportConversations.tsx | 3 +- .../Nav/SettingsTabs/Data/RevokeAllKeys.tsx | 2 +- .../SettingsTabs/Data/RevokeKeysButton.tsx | 12 +- .../Nav/SettingsTabs/Data/SharedLinks.tsx | 19 +- .../SettingsTabs/General/ArchivedChats.tsx | 3 +- .../General/ArchivedChatsTable.tsx | 16 +- .../Nav/SettingsTabs/General/General.tsx | 4 +- .../Nav/SettingsTabs/HoverCardSettings.tsx | 9 +- .../Nav/SettingsTabs/Personalization.tsx | 3 +- .../Speech/ConversationModeSwitch.tsx | 2 +- .../Speech/STT/AutoSendTextSelector.tsx | 2 +- .../Speech/STT/AutoTranscribeAudioSwitch.tsx | 2 +- .../Speech/STT/DecibelSelector.tsx | 8 +- .../Speech/STT/EngineSTTDropdown.tsx | 2 +- .../Speech/STT/LanguageSTTDropdown.tsx | 2 +- .../Speech/STT/SpeechToTextSwitch.tsx | 2 +- .../Nav/SettingsTabs/Speech/Speech.tsx | 7 +- .../Speech/TTS/AutomaticPlaybackSwitch.tsx | 2 +- .../Speech/TTS/CacheTTSSwitch.tsx | 2 +- .../Speech/TTS/CloudBrowserVoicesSwitch.tsx | 2 +- .../Speech/TTS/EngineTTSDropdown.tsx | 2 +- .../SettingsTabs/Speech/TTS/PlaybackRate.tsx | 8 +- .../Speech/TTS/TextToSpeechSwitch.tsx | 2 +- .../SettingsTabs/Speech/TTS/VoiceDropdown.tsx | 2 +- .../Nav/SettingsTabs/ToggleSwitch.tsx | 7 +- .../Plugins/Store/PluginAuthForm.tsx | 2 +- .../Plugins/Store/PluginTooltip.tsx | 2 +- .../src/components/Prompts/AdminSettings.tsx | 10 +- client/src/components/Prompts/BackToChat.tsx | 4 +- client/src/components/Prompts/Command.tsx | 2 +- .../src/components/Prompts/DeleteVersion.tsx | 3 +- client/src/components/Prompts/Description.tsx | 2 +- .../Prompts/Groups/AlwaysMakeProd.tsx | 2 +- .../Prompts/Groups/AutoSendPrompt.tsx | 2 +- .../Prompts/Groups/CategorySelector.tsx | 4 +- .../Prompts/Groups/ChatGroupItem.tsx | 4 +- .../Prompts/Groups/CreatePromptForm.tsx | 4 +- .../Prompts/Groups/DashGroupItem.tsx | 14 +- .../Prompts/Groups/FilterPrompts.tsx | 8 +- .../Prompts/Groups/GroupSidePanel.tsx | 3 +- client/src/components/Prompts/Groups/List.tsx | 2 +- .../components/Prompts/Groups/ListCard.tsx | 5 +- .../Prompts/Groups/NoPromptGroup.tsx | 2 +- .../Prompts/Groups/PanelNavigation.tsx | 2 +- .../Prompts/Groups/VariableDialog.tsx | 2 +- .../Prompts/Groups/VariableForm.tsx | 2 +- .../src/components/Prompts/ManagePrompts.tsx | 2 +- .../src/components/Prompts/PreviewLabels.tsx | 2 +- .../src/components/Prompts/PreviewPrompt.tsx | 2 +- .../src/components/Prompts/PromptDetails.tsx | 2 +- .../src/components/Prompts/PromptEditor.tsx | 17 +- client/src/components/Prompts/PromptForm.tsx | 29 +- client/src/components/Prompts/PromptName.tsx | 2 +- .../components/Prompts/PromptVariables.tsx | 2 +- .../src/components/Prompts/PromptVersions.tsx | 2 +- client/src/components/Prompts/SharePrompt.tsx | 14 +- .../src/components/Prompts/SkeletonForm.tsx | 2 +- .../components/Prompts/VariablesDropdown.tsx | 2 +- client/src/components/Share/MessageIcon.tsx | 2 +- client/src/components/Share/ShareView.tsx | 2 +- .../SidePanel/Agents/ActionsInput.tsx | 7 +- .../SidePanel/Agents/ActionsPanel.tsx | 15 +- .../SidePanel/Agents/AdminSettings.tsx | 13 +- .../Agents/Advanced/AdvancedButton.tsx | 2 +- .../SidePanel/Agents/Advanced/AgentChain.tsx | 11 +- .../Agents/Advanced/MaxAgentSteps.tsx | 6 +- .../SidePanel/Agents/AgentAvatar.tsx | 4 +- .../SidePanel/Agents/AgentConfig.tsx | 3 +- .../SidePanel/Agents/AgentFooter.tsx | 4 +- .../SidePanel/Agents/AgentPanel.tsx | 3 +- .../SidePanel/Agents/AgentPanelSkeleton.tsx | 2 +- .../SidePanel/Agents/AgentSelect.tsx | 2 +- .../components/SidePanel/Agents/AgentTool.tsx | 18 +- .../components/SidePanel/Agents/Artifacts.tsx | 6 +- .../SidePanel/Agents/Code/Action.tsx | 6 +- .../SidePanel/Agents/Code/ApiKeyDialog.tsx | 5 +- .../SidePanel/Agents/Code/Files.tsx | 2 +- .../SidePanel/Agents/DeleteButton.tsx | 13 +- .../SidePanel/Agents/DuplicateAgent.tsx | 2 +- .../SidePanel/Agents/FileContext.tsx | 10 +- .../SidePanel/Agents/FileSearch.tsx | 2 +- .../SidePanel/Agents/FileSearchCheckbox.tsx | 6 +- .../SidePanel/Agents/ImageVision.tsx | 6 +- .../SidePanel/Agents/Instructions.tsx | 6 +- .../components/SidePanel/Agents/MCPIcon.tsx | 2 +- .../components/SidePanel/Agents/MCPInput.tsx | 6 +- .../components/SidePanel/Agents/MCPPanel.tsx | 24 +- .../SidePanel/Agents/MCPSection.tsx | 2 +- .../SidePanel/Agents/ModelPanel.tsx | 4 +- .../components/SidePanel/Agents/Retrieval.tsx | 4 +- .../SidePanel/Agents/Search/Action.tsx | 6 +- .../SidePanel/Agents/Search/ApiKeyDialog.tsx | 3 +- .../SidePanel/Agents/Search/InputSection.tsx | 7 +- .../SidePanel/Agents/ShareAgent.tsx | 6 +- .../Agents/Version/VersionButton.tsx | 4 +- .../Agents/Version/VersionContent.tsx | 6 +- .../SidePanel/Agents/Version/VersionPanel.tsx | 5 +- .../Version/__tests__/VersionContent.spec.tsx | 2 +- .../Agents/__tests__/AgentFooter.spec.tsx | 6 +- .../SidePanel/Bookmarks/BookmarkTable.tsx | 4 +- .../SidePanel/Bookmarks/BookmarkTableRow.tsx | 3 +- .../components/SidePanel/Builder/Action.tsx | 2 +- .../SidePanel/Builder/ActionCallback.tsx | 3 +- .../SidePanel/Builder/ActionsAuth.tsx | 2 +- .../SidePanel/Builder/ActionsInput.tsx | 6 +- .../SidePanel/Builder/ActionsPanel.tsx | 17 +- .../SidePanel/Builder/AppendDateCheckbox.tsx | 8 +- .../SidePanel/Builder/AssistantAvatar.tsx | 9 +- .../Builder/AssistantConversationStarters.tsx | 2 +- .../SidePanel/Builder/AssistantPanel.tsx | 7 +- .../SidePanel/Builder/AssistantSelect.tsx | 8 +- .../SidePanel/Builder/AssistantTool.tsx | 14 +- .../src/components/SidePanel/Builder/Code.tsx | 8 +- .../SidePanel/Builder/CodeFiles.tsx | 2 +- .../SidePanel/Builder/ContextButton.tsx | 15 +- .../SidePanel/Builder/ImageVision.tsx | 6 +- .../SidePanel/Builder/Knowledge.tsx | 2 +- .../src/components/SidePanel/Builder/MCP.tsx | 3 +- .../components/SidePanel/Builder/MCPAuth.tsx | 2 +- .../SidePanel/Builder/Retrieval.tsx | 6 +- .../SidePanel/Files/PanelColumns.tsx | 5 +- .../components/SidePanel/Files/PanelTable.tsx | 24 +- .../src/components/SidePanel/MCP/MCPPanel.tsx | 11 +- .../SidePanel/MCP/MCPPanelSkeleton.tsx | 2 +- .../SidePanel/Memories/AdminSettings.tsx | 13 +- .../SidePanel/Memories/MemoryCreateDialog.tsx | 12 +- .../SidePanel/Memories/MemoryEditDialog.tsx | 12 +- .../SidePanel/Memories/MemoryViewer.tsx | 8 +- client/src/components/SidePanel/Nav.tsx | 8 +- .../SidePanel/Parameters/DynamicCheckbox.tsx | 10 +- .../SidePanel/Parameters/DynamicCombobox.tsx | 19 +- .../SidePanel/Parameters/DynamicDropdown.tsx | 16 +- .../SidePanel/Parameters/DynamicInput.tsx | 2 +- .../SidePanel/Parameters/DynamicSlider.tsx | 2 +- .../SidePanel/Parameters/DynamicSwitch.tsx | 2 +- .../SidePanel/Parameters/DynamicTags.tsx | 6 +- .../SidePanel/Parameters/DynamicTextarea.tsx | 18 +- .../SidePanel/Parameters/OptionHover.tsx | 2 +- .../components/SidePanel/Parameters/Panel.tsx | 4 +- client/src/components/SidePanel/SidePanel.tsx | 4 +- .../components/SidePanel/SidePanelGroup.tsx | 8 +- client/src/components/Web/Sources.tsx | 14 +- .../components/svg/{Files => }/CodePaths.tsx | 0 .../components/svg/{Files => }/FileIcon.tsx | 0 .../components/svg/{Files => }/FilePaths.tsx | 0 .../components/svg/{Files => }/SheetPaths.tsx | 0 .../components/svg/{Files => }/TextPaths.tsx | 0 client/src/components/svg/index.ts | 71 +- .../src/components/ui/AnimatedSearchInput.tsx | 111 - client/src/components/ui/DelayedRender.tsx | 5 - client/src/components/ui/ModelParameters.tsx | 186 - client/src/components/ui/Prompt.tsx | 22 - client/src/components/ui/Slider.tsx | 26 - .../components/ui/TermsAndConditionsModal.tsx | 6 +- client/src/components/ui/index.ts | 49 +- client/src/data-provider/Files/mutations.ts | 2 +- client/src/hooks/Conversations/usePresets.ts | 5 +- client/src/hooks/Endpoint/Icons.tsx | 6 +- client/src/hooks/Endpoint/UnknownIcon.tsx | 2 +- .../src/hooks/Files/useDelayedUploadToast.ts | 4 +- client/src/hooks/Files/useFileHandling.ts | 2 +- client/src/hooks/Input/index.ts | 1 - .../src/hooks/Input/useSpeechToTextBrowser.ts | 2 +- .../hooks/Input/useSpeechToTextExternal.ts | 5 +- .../hooks/Input/useTextToSpeechExternal.ts | 6 +- client/src/hooks/Input/useTextarea.ts | 2 +- .../hooks/MCP/useMCPServerInitialization.ts | 4 +- client/src/hooks/MCP/useMCPServerManager.ts | 10 +- client/src/hooks/Nav/useSideNavLinks.ts | 2 +- client/src/hooks/Plugins/useAuthCodeTool.ts | 2 - client/src/hooks/Prompts/useCategories.tsx | 2 +- client/src/hooks/ScreenshotContext.tsx | 2 +- client/src/hooks/index.ts | 6 +- client/src/locales/Translation.spec.ts | 7 +- client/src/locales/en/translation.json | 3 +- client/src/routes/ChatRoute.tsx | 2 +- client/src/routes/Layouts/DashBreadcrumb.tsx | 2 +- client/src/routes/Root.tsx | 2 +- client/src/routes/RouteErrorBoundary.tsx | 3 +- client/src/routes/Search.tsx | 6 +- client/src/style.css | 3 + client/src/utils/files.ts | 5 +- client/src/utils/getThemeFromEnv.js | 58 + client/src/utils/index.ts | 2 +- client/tailwind.config.cjs | 12 +- client/test/setupTests.js | 15 + client/tsconfig.json | 2 +- config/update.js | 1 + package-lock.json | 3738 +++++++++++++++-- package.json | 5 +- packages/client/package.json | 92 + packages/client/rollup.config.js | 84 + .../client}/src/Providers/ToastContext.tsx | 4 +- packages/client/src/Providers/index.ts | 2 + packages/client/src/common/index.ts | 11 + packages/client/src/common/menus.ts | 24 + packages/client/src/common/types.ts | 33 + .../client/src/components}/Accordion.tsx | 3 +- .../client/src/components}/AlertDialog.tsx | 3 +- .../src/components/AnimatedSearchInput.tsx | 79 + .../client/src/components}/AnimatedTabs.css | 2 +- .../client/src/components}/AnimatedTabs.tsx | 10 +- .../client/src/components}/Badge.tsx | 9 +- .../client/src/components}/Breadcrumb.tsx | 7 +- .../client/src/components}/Button.tsx | 0 .../client/src/components}/Checkbox.tsx | 4 +- .../client/src/components}/CheckboxButton.tsx | 4 +- .../client/src/components}/Collapsible.tsx | 0 .../client/src/components}/Combobox.tsx | 14 +- .../src/components}/ControlCombobox.tsx | 0 .../client/src/components}/DataTable.tsx | 39 +- .../src/components}/DataTableColumnHeader.tsx | 15 +- .../client/src/components/DelayedRender.tsx | 12 + .../client/src/components}/Dialog.tsx | 4 +- .../src/components}/DialogTemplate.spec.tsx | 17 +- .../client/src/components}/DialogTemplate.tsx | 6 +- .../client/src/components}/Dropdown.tsx | 0 .../client/src/components}/DropdownMenu.tsx | 0 .../src/components}/DropdownNoState.tsx | 6 +- .../client/src/components}/DropdownPopup.tsx | 1 - .../client/src/components}/FileUpload.tsx | 0 .../client/src/components}/FormInput.tsx | 11 +- .../client/src/components}/HoverCard.tsx | 3 +- .../client/src/components}/Input.tsx | 1 - .../client/src/components}/InputCombobox.tsx | 0 .../client/src/components}/InputNumber.tsx | 0 .../client/src/components}/InputOTP.tsx | 5 + .../src/components}/InputWithDropDown.tsx | 6 +- .../client/src/components}/Label.tsx | 17 +- .../client/src/components}/MultiSearch.tsx | 8 +- .../client/src/components}/MultiSelect.tsx | 12 +- .../src/components}/OGDialogTemplate.tsx | 8 +- .../client/src/components}/OriginalDialog.tsx | 0 .../client/src/components}/Pagination.tsx | 0 .../client/src/components}/PixelCard.tsx | 14 +- .../client/src/components}/Progress.tsx | 0 .../client/src/components}/QuestionMark.tsx | 1 + .../client/src/components}/Resizable.tsx | 8 +- .../client/src/components}/Select.tsx | 3 + .../client/src/components}/SelectDropDown.tsx | 15 +- .../client/src/components}/Separator.tsx | 20 +- .../client/src/components}/Skeleton.tsx | 0 packages/client/src/components/Slider.tsx | 38 + .../client/src/components}/SplitText.spec.tsx | 0 .../client/src/components}/SplitText.tsx | 51 +- .../client/src/components}/Switch.tsx | 0 .../client/src/components}/Table.tsx | 0 .../client/src/components}/Tabs.tsx | 0 .../client/src/components}/Tag.tsx | 22 +- .../client/src/components}/Textarea.tsx | 3 +- .../src/components}/TextareaAutosize.tsx | 6 +- .../client/src/components}/ThemeSelector.tsx | 10 +- .../client/src/components}/Toast.tsx | 2 +- .../client/src/components}/Tooltip.tsx | 0 packages/client/src/components/index.ts | 51 + .../client/src/hooks/ThemeContext.old.tsx | 14 +- packages/client/src/hooks/index.ts | 10 + .../client/src/hooks}/useCombobox.ts | 0 .../client}/src/hooks/useDelayedRender.tsx | 0 packages/client/src/hooks/useLocalize.ts | 21 + .../client}/src/hooks/useMediaQuery.tsx | 0 .../client}/src/hooks/useOnClickOutside.ts | 0 .../client}/src/hooks/useToast.ts | 8 +- packages/client/src/index.ts | 24 + .../client/src/locales/Translation.spec.ts | 47 + .../client/src/locales/ar/translation.json | 3 + .../client/src/locales/ca/translation.json | 3 + .../client/src/locales/cs/translation.json | 3 + .../client/src/locales/da/translation.json | 3 + .../client/src/locales/de/translation.json | 3 + .../client/src/locales/en/translation.json | 3 + .../client/src/locales/es/translation.json | 3 + .../client/src/locales/et/translation.json | 3 + .../client/src/locales/fa/translation.json | 3 + .../client/src/locales/fi/translation.json | 3 + .../client/src/locales/fr/translation.json | 3 + .../client/src/locales/he/translation.json | 3 + .../client/src/locales/hu/translation.json | 3 + packages/client/src/locales/i18n.ts | 87 + .../client/src/locales/id/translation.json | 3 + .../client/src/locales/it/translation.json | 3 + .../client/src/locales/ja/translation.json | 3 + .../client/src/locales/ka/translation.json | 3 + .../client/src/locales/ko/translation.json | 3 + .../client/src/locales/nl/translation.json | 3 + .../client/src/locales/pl/translation.json | 3 + .../client/src/locales/pt-BR/translation.json | 3 + .../client/src/locales/pt-PT/translation.json | 3 + .../client/src/locales/ru/translation.json | 3 + .../client/src/locales/sv/translation.json | 3 + .../client/src/locales/th/translation.json | 3 + .../client/src/locales/tr/translation.json | 3 + .../client/src/locales/vi/translation.json | 3 + .../src/locales/zh-Hans/translation.json | 3 + .../src/locales/zh-Hant/translation.json | 3 + packages/client/src/store.ts | 20 + .../client/src/svgs}/AnthropicIcon.tsx | 0 .../client/src/svgs}/AnthropicMinimalIcon.tsx | 0 .../client/src/svgs}/AppleIcon.tsx | 2 +- .../client/src/svgs}/ArchiveIcon.tsx | 0 .../client/src/svgs}/AssistantIcon.tsx | 0 .../client/src/svgs}/AttachmentIcon.tsx | 0 .../client/src/svgs}/AzureMinimalIcon.tsx | 1 - .../client/src/svgs}/BedrockIcon.tsx | 0 .../client/src/svgs}/BirthdayIcon.tsx | 0 .../client/src/svgs}/Blocks.tsx | 0 .../client/src/svgs}/CautionIcon.tsx | 0 .../client/src/svgs}/ChatGPTMinimalIcon.tsx | 0 .../client/src/svgs}/ChatIcon.tsx | 0 .../client/src/svgs}/CheckMark.tsx | 0 .../client/src/svgs}/CircleHelpIcon.tsx | 0 .../client/src/svgs}/Clipboard.tsx | 0 .../client/src/svgs}/CodeyIcon.tsx | 0 .../client/src/svgs}/ContinueIcon.tsx | 0 .../client/src/svgs}/ConvoIcon.tsx | 0 .../client/src/svgs}/CrossIcon.tsx | 0 .../client/src/svgs}/CustomMinimalIcon.tsx | 0 .../client/src/svgs}/DarkModeIcon.tsx | 0 .../client/src/svgs}/DataIcon.tsx | 0 .../client/src/svgs}/DiscordIcon.tsx | 0 .../client/src/svgs}/DislikeIcon.tsx | 0 .../client/src/svgs}/DotsIcon.tsx | 0 .../client/src/svgs}/EditIcon.tsx | 0 .../client/src/svgs}/ExperimentIcon.tsx | 0 .../client/src/svgs}/FacebookIcon.tsx | 0 .../client/src/svgs}/GPTIcon.tsx | 0 .../client/src/svgs}/GearIcon.tsx | 0 .../client/src/svgs}/GeminiIcon.tsx | 0 .../client/src/svgs}/GithubIcon.tsx | 0 .../client/src/svgs}/GoogleIcon.tsx | 0 .../client/src/svgs}/GoogleIconChat.tsx | 0 .../client/src/svgs}/GoogleMinimalIcon.tsx | 0 .../client/src/svgs}/LightModeIcon.tsx | 0 .../client/src/svgs}/LightningIcon.tsx | 0 .../client/src/svgs}/LikeIcon.tsx | 0 .../client/src/svgs}/LinkIcon.tsx | 0 .../client/src/svgs}/ListeningIcon.tsx | 6 +- .../client/src/svgs}/LockIcon.tsx | 0 .../client/src/svgs}/LogOutIcon.tsx | 0 .../client/src/svgs}/MCPIcon.tsx | 0 .../client/src/svgs}/MessagesSquared.tsx | 0 .../client/src/svgs}/MinimalPlugin.tsx | 0 .../client/src/svgs}/MobileSidebar.tsx | 0 .../client/src/svgs}/NewChatIcon.tsx | 0 .../client/src/svgs}/OpenAIMinimalIcon.tsx | 0 .../client/src/svgs}/OpenIDIcon.tsx | 0 .../client/src/svgs}/PaLMIcon.tsx | 0 .../client/src/svgs}/PaLMinimalIcon.tsx | 0 .../client/src/svgs}/PersonalizationIcon.tsx | 0 .../client/src/svgs}/PinIcon.tsx | 0 .../client/src/svgs}/Plugin.tsx | 0 .../client/src/svgs}/RegenerateIcon.tsx | 0 .../client/src/svgs}/RenameIcon.tsx | 0 .../client/src/svgs}/SamlIcon.tsx | 0 .../client/src/svgs}/SaveIcon.tsx | 7 +- .../client/src/svgs}/SendIcon.tsx | 0 .../client/src/svgs}/SendMessageIcon.tsx | 0 .../client/src/svgs}/Sidebar.tsx | 0 .../client/src/svgs}/Sparkles.tsx | 0 .../client/src/svgs}/SpeechIcon.tsx | 6 +- .../client/src/svgs}/Spinner.tsx | 0 .../client/src/svgs}/SquirclePlusIcon.tsx | 0 .../client/src/svgs}/StopGeneratingIcon.tsx | 0 .../client/src/svgs}/SunIcon.tsx | 0 .../client/src/svgs}/SwitchIcon.tsx | 7 +- .../client/src/svgs}/ThumbDownIcon.tsx | 2 - .../client/src/svgs}/ThumbUpIcon.tsx | 2 - .../client/src/svgs}/TrashIcon.tsx | 0 .../client/src/svgs}/UserIcon.tsx | 0 .../client/src/svgs}/VectorIcon.tsx | 0 .../client/src/svgs}/VolumeIcon.tsx | 0 .../client/src/svgs}/VolumeMuteIcon.tsx | 0 .../client/src/svgs}/XAIcon.tsx | 0 packages/client/src/svgs/index.ts | 67 + packages/client/src/theme/README.md | 473 +++ packages/client/src/theme/atoms/themeAtoms.ts | 36 + .../src/theme/context/ThemeProvider.tsx | 165 + packages/client/src/theme/index.ts | 14 + packages/client/src/theme/themes/dark.ts | 72 + packages/client/src/theme/themes/default.ts | 72 + packages/client/src/theme/themes/index.ts | 2 + packages/client/src/theme/types/index.ts | 189 + packages/client/src/theme/utils/applyTheme.ts | 115 + .../src/theme/utils/createTailwindColors.js | 86 + packages/client/src/utils/index.ts | 2 + .../client}/src/utils/theme.ts | 2 +- packages/client/src/utils/utils.ts | 7 + packages/client/tailwind.config.js | 13 + packages/client/tsconfig.json | 34 + 569 files changed, 7010 insertions(+), 1848 deletions(-) create mode 100644 client/src/components/Chat/Input/MCPConfigDialog.tsx rename client/src/components/{ui => Input/ModelSelect}/MultiSelectDropDown.tsx (97%) rename client/src/components/{ui => Input/ModelSelect}/MultiSelectPop.tsx (95%) rename client/src/components/{ui => Input/ModelSelect}/SelectDropDownPop.tsx (98%) rename client/src/components/{ui => }/MCP/CustomUserVarsSection.tsx (98%) rename client/src/components/{ui => }/MCP/MCPConfigDialog.tsx (97%) rename client/src/components/{ui => }/MCP/MCPServerStatusIcon.tsx (100%) rename client/src/components/{ui => }/MCP/ServerInitializationSection.tsx (96%) rename client/src/components/svg/{Files => }/CodePaths.tsx (100%) rename client/src/components/svg/{Files => }/FileIcon.tsx (100%) rename client/src/components/svg/{Files => }/FilePaths.tsx (100%) rename client/src/components/svg/{Files => }/SheetPaths.tsx (100%) rename client/src/components/svg/{Files => }/TextPaths.tsx (100%) delete mode 100644 client/src/components/ui/AnimatedSearchInput.tsx delete mode 100644 client/src/components/ui/DelayedRender.tsx delete mode 100644 client/src/components/ui/ModelParameters.tsx delete mode 100644 client/src/components/ui/Prompt.tsx delete mode 100644 client/src/components/ui/Slider.tsx create mode 100644 client/src/utils/getThemeFromEnv.js create mode 100644 packages/client/package.json create mode 100644 packages/client/rollup.config.js rename {client => packages/client}/src/Providers/ToastContext.tsx (77%) create mode 100644 packages/client/src/Providers/index.ts create mode 100644 packages/client/src/common/index.ts create mode 100644 packages/client/src/common/menus.ts create mode 100644 packages/client/src/common/types.ts rename {client/src/components/ui => packages/client/src/components}/Accordion.tsx (94%) rename {client/src/components/ui => packages/client/src/components}/AlertDialog.tsx (99%) create mode 100644 packages/client/src/components/AnimatedSearchInput.tsx rename {client/src/components/ui => packages/client/src/components}/AnimatedTabs.css (96%) rename {client/src/components/ui => packages/client/src/components}/AnimatedTabs.tsx (93%) rename {client/src/components/ui => packages/client/src/components}/Badge.tsx (92%) rename {client/src/components/ui => packages/client/src/components}/Breadcrumb.tsx (91%) rename {client/src/components/ui => packages/client/src/components}/Button.tsx (100%) rename {client/src/components/ui => packages/client/src/components}/Checkbox.tsx (96%) rename {client/src/components/ui => packages/client/src/components}/CheckboxButton.tsx (98%) rename {client/src/components/ui => packages/client/src/components}/Collapsible.tsx (100%) rename {client/src/components/ui => packages/client/src/components}/Combobox.tsx (92%) rename {client/src/components/ui => packages/client/src/components}/ControlCombobox.tsx (100%) rename {client/src/components/ui => packages/client/src/components}/DataTable.tsx (94%) rename {client/src/components/ui => packages/client/src/components}/DataTableColumnHeader.tsx (83%) create mode 100644 packages/client/src/components/DelayedRender.tsx rename {client/src/components/ui => packages/client/src/components}/Dialog.tsx (99%) rename {client/src/components/ui => packages/client/src/components}/DialogTemplate.spec.tsx (92%) rename {client/src/components/ui => packages/client/src/components}/DialogTemplate.tsx (95%) rename {client/src/components/ui => packages/client/src/components}/Dropdown.tsx (100%) rename {client/src/components/ui => packages/client/src/components}/DropdownMenu.tsx (100%) rename {client/src/components/ui => packages/client/src/components}/DropdownNoState.tsx (95%) rename {client/src/components/ui => packages/client/src/components}/DropdownPopup.tsx (98%) rename {client/src/components/ui => packages/client/src/components}/FileUpload.tsx (100%) rename {client/src/components/ui => packages/client/src/components}/FormInput.tsx (79%) rename {client/src/components/ui => packages/client/src/components}/HoverCard.tsx (97%) rename {client/src/components/ui => packages/client/src/components}/Input.tsx (99%) rename {client/src/components/ui => packages/client/src/components}/InputCombobox.tsx (100%) rename {client/src/components/ui => packages/client/src/components}/InputNumber.tsx (100%) rename {client/src/components/ui => packages/client/src/components}/InputOTP.tsx (95%) rename {client/src/components/ui => packages/client/src/components}/InputWithDropDown.tsx (95%) rename {client/src/components/ui => packages/client/src/components}/Label.tsx (51%) rename {client/src/components/ui => packages/client/src/components}/MultiSearch.tsx (94%) rename {client/src/components/ui => packages/client/src/components}/MultiSelect.tsx (92%) rename {client/src/components/ui => packages/client/src/components}/OGDialogTemplate.tsx (93%) rename {client/src/components/ui => packages/client/src/components}/OriginalDialog.tsx (100%) rename {client/src/components/ui => packages/client/src/components}/Pagination.tsx (100%) rename {client/src/components/ui => packages/client/src/components}/PixelCard.tsx (96%) rename {client/src/components/ui => packages/client/src/components}/Progress.tsx (100%) rename {client/src/components/ui => packages/client/src/components}/QuestionMark.tsx (99%) rename {client/src/components/ui => packages/client/src/components}/Resizable.tsx (75%) rename {client/src/components/ui => packages/client/src/components}/Select.tsx (97%) rename {client/src/components/ui => packages/client/src/components}/SelectDropDown.tsx (96%) rename {client/src/components/ui => packages/client/src/components}/Separator.tsx (67%) rename {client/src/components/ui => packages/client/src/components}/Skeleton.tsx (100%) create mode 100644 packages/client/src/components/Slider.tsx rename {client/src/components/ui => packages/client/src/components}/SplitText.spec.tsx (100%) rename {client/src/components/ui => packages/client/src/components}/SplitText.tsx (77%) rename {client/src/components/ui => packages/client/src/components}/Switch.tsx (100%) rename {client/src/components/ui => packages/client/src/components}/Table.tsx (100%) rename {client/src/components/ui => packages/client/src/components}/Tabs.tsx (100%) rename {client/src/components/ui => packages/client/src/components}/Tag.tsx (76%) rename {client/src/components/ui => packages/client/src/components}/Textarea.tsx (96%) rename {client/src/components/ui => packages/client/src/components}/TextareaAutosize.tsx (75%) rename {client/src/components/ui => packages/client/src/components}/ThemeSelector.tsx (91%) rename {client/src/components/ui => packages/client/src/components}/Toast.tsx (98%) rename {client/src/components/ui => packages/client/src/components}/Tooltip.tsx (100%) create mode 100644 packages/client/src/components/index.ts rename client/src/hooks/ThemeContext.tsx => packages/client/src/hooks/ThemeContext.old.tsx (89%) create mode 100644 packages/client/src/hooks/index.ts rename {client/src/hooks/Input => packages/client/src/hooks}/useCombobox.ts (100%) rename {client => packages/client}/src/hooks/useDelayedRender.tsx (100%) create mode 100644 packages/client/src/hooks/useLocalize.ts rename {client => packages/client}/src/hooks/useMediaQuery.tsx (100%) rename {client => packages/client}/src/hooks/useOnClickOutside.ts (100%) rename {client => packages/client}/src/hooks/useToast.ts (87%) create mode 100644 packages/client/src/index.ts create mode 100644 packages/client/src/locales/Translation.spec.ts create mode 100644 packages/client/src/locales/ar/translation.json create mode 100644 packages/client/src/locales/ca/translation.json create mode 100644 packages/client/src/locales/cs/translation.json create mode 100644 packages/client/src/locales/da/translation.json create mode 100644 packages/client/src/locales/de/translation.json create mode 100644 packages/client/src/locales/en/translation.json create mode 100644 packages/client/src/locales/es/translation.json create mode 100644 packages/client/src/locales/et/translation.json create mode 100644 packages/client/src/locales/fa/translation.json create mode 100644 packages/client/src/locales/fi/translation.json create mode 100644 packages/client/src/locales/fr/translation.json create mode 100644 packages/client/src/locales/he/translation.json create mode 100644 packages/client/src/locales/hu/translation.json create mode 100644 packages/client/src/locales/i18n.ts create mode 100644 packages/client/src/locales/id/translation.json create mode 100644 packages/client/src/locales/it/translation.json create mode 100644 packages/client/src/locales/ja/translation.json create mode 100644 packages/client/src/locales/ka/translation.json create mode 100644 packages/client/src/locales/ko/translation.json create mode 100644 packages/client/src/locales/nl/translation.json create mode 100644 packages/client/src/locales/pl/translation.json create mode 100644 packages/client/src/locales/pt-BR/translation.json create mode 100644 packages/client/src/locales/pt-PT/translation.json create mode 100644 packages/client/src/locales/ru/translation.json create mode 100644 packages/client/src/locales/sv/translation.json create mode 100644 packages/client/src/locales/th/translation.json create mode 100644 packages/client/src/locales/tr/translation.json create mode 100644 packages/client/src/locales/vi/translation.json create mode 100644 packages/client/src/locales/zh-Hans/translation.json create mode 100644 packages/client/src/locales/zh-Hant/translation.json create mode 100644 packages/client/src/store.ts rename {client/src/components/svg => packages/client/src/svgs}/AnthropicIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/AnthropicMinimalIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/AppleIcon.tsx (99%) rename {client/src/components/svg => packages/client/src/svgs}/ArchiveIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/AssistantIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/AttachmentIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/AzureMinimalIcon.tsx (99%) rename {client/src/components/svg => packages/client/src/svgs}/BedrockIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/BirthdayIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/Blocks.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/CautionIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/ChatGPTMinimalIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/ChatIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/CheckMark.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/CircleHelpIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/Clipboard.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/CodeyIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/ContinueIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/ConvoIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/CrossIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/CustomMinimalIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/DarkModeIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/DataIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/DiscordIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/DislikeIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/DotsIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/EditIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/ExperimentIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/FacebookIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/GPTIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/GearIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/GeminiIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/GithubIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/GoogleIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/GoogleIconChat.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/GoogleMinimalIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/LightModeIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/LightningIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/LikeIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/LinkIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/ListeningIcon.tsx (78%) rename {client/src/components/svg => packages/client/src/svgs}/LockIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/LogOutIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/MCPIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/MessagesSquared.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/MinimalPlugin.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/MobileSidebar.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/NewChatIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/OpenAIMinimalIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/OpenIDIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/PaLMIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/PaLMinimalIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/PersonalizationIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/PinIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/Plugin.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/RegenerateIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/RenameIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/SamlIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/SaveIcon.tsx (82%) rename {client/src/components/svg => packages/client/src/svgs}/SendIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/SendMessageIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/Sidebar.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/Sparkles.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/SpeechIcon.tsx (80%) rename {client/src/components/svg => packages/client/src/svgs}/Spinner.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/SquirclePlusIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/StopGeneratingIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/SunIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/SwitchIcon.tsx (79%) rename {client/src/components/svg => packages/client/src/svgs}/ThumbDownIcon.tsx (98%) rename {client/src/components/svg => packages/client/src/svgs}/ThumbUpIcon.tsx (98%) rename {client/src/components/svg => packages/client/src/svgs}/TrashIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/UserIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/VectorIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/VolumeIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/VolumeMuteIcon.tsx (100%) rename {client/src/components/svg => packages/client/src/svgs}/XAIcon.tsx (100%) create mode 100644 packages/client/src/svgs/index.ts create mode 100644 packages/client/src/theme/README.md create mode 100644 packages/client/src/theme/atoms/themeAtoms.ts create mode 100644 packages/client/src/theme/context/ThemeProvider.tsx create mode 100644 packages/client/src/theme/index.ts create mode 100644 packages/client/src/theme/themes/dark.ts create mode 100644 packages/client/src/theme/themes/default.ts create mode 100644 packages/client/src/theme/themes/index.ts create mode 100644 packages/client/src/theme/types/index.ts create mode 100644 packages/client/src/theme/utils/applyTheme.ts create mode 100644 packages/client/src/theme/utils/createTailwindColors.js create mode 100644 packages/client/src/utils/index.ts rename {client => packages/client}/src/utils/theme.ts (95%) create mode 100644 packages/client/src/utils/utils.ts create mode 100644 packages/client/tailwind.config.js create mode 100644 packages/client/tsconfig.json diff --git a/.github/workflows/client.yml b/.github/workflows/client.yml index 1f0e2fd86..6b97a1e61 100644 --- a/.github/workflows/client.yml +++ b/.github/workflows/client.yml @@ -1,6 +1,11 @@ name: Publish `@librechat/client` to NPM on: + push: + branches: + - main + paths: + - 'packages/client/package.json' workflow_dispatch: inputs: reason: @@ -17,16 +22,37 @@ jobs: - name: Use Node.js uses: actions/setup-node@v4 with: - node-version: '18.x' - - - name: Check if client package exists + node-version: '20.x' + + - name: Install client dependencies + run: cd packages/client && npm ci + + - name: Build client + run: cd packages/client && npm run build + + - name: Set up npm authentication + run: echo "//registry.npmjs.org/:_authToken=${{ secrets.PUBLISH_NPM_TOKEN }}" > ~/.npmrc + + - name: Check version change + id: check + working-directory: packages/client run: | - if [ -d "packages/client" ]; then - echo "Client package directory found" + PACKAGE_VERSION=$(node -p "require('./package.json').version") + PUBLISHED_VERSION=$(npm view @librechat/client version 2>/dev/null || echo "0.0.0") + if [ "$PACKAGE_VERSION" = "$PUBLISHED_VERSION" ]; then + echo "No version change, skipping publish" + echo "skip=true" >> $GITHUB_OUTPUT else - echo "Client package directory not found - workflow ready for future use" - exit 0 + echo "Version changed, proceeding with publish" + echo "skip=false" >> $GITHUB_OUTPUT fi - - - name: Placeholder for future publishing - run: echo "Client package publishing workflow is ready" \ No newline at end of file + + - name: Pack package + if: steps.check.outputs.skip != 'true' + working-directory: packages/client + run: npm pack + + - name: Publish + if: steps.check.outputs.skip != 'true' + working-directory: packages/client + run: npm publish *.tgz --access public \ No newline at end of file diff --git a/.github/workflows/i18n-unused-keys.yml b/.github/workflows/i18n-unused-keys.yml index 07cc77a1a..9fb2fd683 100644 --- a/.github/workflows/i18n-unused-keys.yml +++ b/.github/workflows/i18n-unused-keys.yml @@ -6,6 +6,7 @@ on: - "client/src/**" - "api/**" - "packages/data-provider/src/**" + - "packages/client/**" jobs: detect-unused-i18n-keys: @@ -23,7 +24,7 @@ jobs: # Define paths I18N_FILE="client/src/locales/en/translation.json" - SOURCE_DIRS=("client/src" "api" "packages/data-provider/src") + SOURCE_DIRS=("client/src" "api" "packages/data-provider/src" "packages/client") # Check if translation file exists if [[ ! -f "$I18N_FILE" ]]; then diff --git a/.github/workflows/unused-packages.yml b/.github/workflows/unused-packages.yml index 5429a1abd..442925b69 100644 --- a/.github/workflows/unused-packages.yml +++ b/.github/workflows/unused-packages.yml @@ -7,6 +7,7 @@ on: - 'package-lock.json' - 'client/**' - 'api/**' + - 'packages/client/**' jobs: detect-unused-packages: @@ -28,7 +29,7 @@ jobs: - name: Validate JSON files run: | - for FILE in package.json client/package.json api/package.json; do + for FILE in package.json client/package.json api/package.json packages/client/package.json; do if [[ -f "$FILE" ]]; then jq empty "$FILE" || (echo "::error title=Invalid JSON::$FILE is invalid" && exit 1) fi @@ -63,12 +64,31 @@ jobs: local folder=$1 local output_file=$2 if [[ -d "$folder" ]]; then - grep -rEho "require\\(['\"]([a-zA-Z0-9@/._-]+)['\"]\\)" "$folder" --include=\*.{js,ts,mjs,cjs} | \ + # Extract require() statements + grep -rEho "require\\(['\"]([a-zA-Z0-9@/._-]+)['\"]\\)" "$folder" --include=\*.{js,ts,tsx,jsx,mjs,cjs} | \ sed -E "s/require\\(['\"]([a-zA-Z0-9@/._-]+)['\"]\\)/\1/" > "$output_file" - grep -rEho "import .* from ['\"]([a-zA-Z0-9@/._-]+)['\"]" "$folder" --include=\*.{js,ts,mjs,cjs} | \ + # Extract ES6 imports - various patterns + # import x from 'module' + grep -rEho "import .* from ['\"]([a-zA-Z0-9@/._-]+)['\"]" "$folder" --include=\*.{js,ts,tsx,jsx,mjs,cjs} | \ sed -E "s/import .* from ['\"]([a-zA-Z0-9@/._-]+)['\"]/\1/" >> "$output_file" + + # import 'module' (side-effect imports) + grep -rEho "import ['\"]([a-zA-Z0-9@/._-]+)['\"]" "$folder" --include=\*.{js,ts,tsx,jsx,mjs,cjs} | \ + sed -E "s/import ['\"]([a-zA-Z0-9@/._-]+)['\"]/\1/" >> "$output_file" + + # export { x } from 'module' or export * from 'module' + grep -rEho "export .* from ['\"]([a-zA-Z0-9@/._-]+)['\"]" "$folder" --include=\*.{js,ts,tsx,jsx,mjs,cjs} | \ + sed -E "s/export .* from ['\"]([a-zA-Z0-9@/._-]+)['\"]/\1/" >> "$output_file" + + # import type { x } from 'module' (TypeScript) + grep -rEho "import type .* from ['\"]([a-zA-Z0-9@/._-]+)['\"]" "$folder" --include=\*.{ts,tsx} | \ + sed -E "s/import type .* from ['\"]([a-zA-Z0-9@/._-]+)['\"]/\1/" >> "$output_file" + # Remove subpath imports but keep the base package + # e.g., '@tanstack/react-query/devtools' becomes '@tanstack/react-query' + sed -i -E 's|^(@?[a-zA-Z0-9-]+(/[a-zA-Z0-9-]+)?)/.*|\1|' "$output_file" + sort -u "$output_file" -o "$output_file" else touch "$output_file" @@ -78,6 +98,33 @@ jobs: extract_deps_from_code "." root_used_code.txt extract_deps_from_code "client" client_used_code.txt extract_deps_from_code "api" api_used_code.txt + + # Extract dependencies used by @librechat/client package + extract_deps_from_code "packages/client" packages_client_used_code.txt + + - name: Get @librechat/client dependencies + id: get-librechat-client-deps + run: | + if [[ -f "packages/client/package.json" ]]; then + # Get all dependencies from @librechat/client (dependencies, devDependencies, and peerDependencies) + DEPS=$(jq -r '.dependencies // {} | keys[]' packages/client/package.json 2>/dev/null || echo "") + DEV_DEPS=$(jq -r '.devDependencies // {} | keys[]' packages/client/package.json 2>/dev/null || echo "") + PEER_DEPS=$(jq -r '.peerDependencies // {} | keys[]' packages/client/package.json 2>/dev/null || echo "") + + # Combine all dependencies + echo "$DEPS" > librechat_client_deps.txt + echo "$DEV_DEPS" >> librechat_client_deps.txt + echo "$PEER_DEPS" >> librechat_client_deps.txt + + # Also include dependencies that are imported in packages/client + cat packages_client_used_code.txt >> librechat_client_deps.txt + + # Remove empty lines and sort + grep -v '^$' librechat_client_deps.txt | sort -u > temp_deps.txt + mv temp_deps.txt librechat_client_deps.txt + else + touch librechat_client_deps.txt + fi - name: Extract Workspace Dependencies id: extract-workspace-deps diff --git a/bun.lockb b/bun.lockb index 61118178fd40c4cda7f4ba0f1055623a2ae2722e..77b01df558deaabf076fb3025af57bd314ef37ef 100755 GIT binary patch delta 272436 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 z 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

WaGVoOq+~GW>&`F^}5dhLyen_W5qyU-APV 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%0AZ?-=^ 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 Ox&8iaXyiZH&;JiGgf311 diff --git a/client/package.json b/client/package.json index d0c7c54e1..f1d68d27e 100644 --- a/client/package.json +++ b/client/package.json @@ -34,6 +34,7 @@ "@dicebear/collection": "^9.2.2", "@dicebear/core": "^9.2.2", "@headlessui/react": "^2.1.2", + "@librechat/client": "*", "@marsidev/react-turnstile": "^1.1.0", "@radix-ui/react-accordion": "^1.1.2", "@radix-ui/react-alert-dialog": "^1.0.2", @@ -56,8 +57,8 @@ "@react-spring/web": "^9.7.5", "@tanstack/react-query": "^4.28.0", "@tanstack/react-table": "^8.11.7", - "class-variance-authority": "^0.6.0", - "clsx": "^1.2.1", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", "copy-to-clipboard": "^3.3.3", "cross-env": "^7.0.3", "date-fns": "^3.3.1", @@ -70,11 +71,12 @@ "i18next": "^24.2.2", "i18next-browser-languagedetector": "^8.0.3", "input-otp": "^1.4.2", + "jotai": "^2.12.5", "js-cookie": "^3.0.5", "librechat-data-provider": "*", "lodash": "^4.17.21", "lucide-react": "^0.394.0", - "match-sorter": "^6.3.4", + "match-sorter": "^8.1.0", "micromark-extension-llm-math": "^3.1.0", "qrcode.react": "^4.2.0", "rc-input-number": "^7.4.2", diff --git a/client/src/App.jsx b/client/src/App.jsx index 38e568e42..d329bdd9b 100644 --- a/client/src/App.jsx +++ b/client/src/App.jsx @@ -4,10 +4,10 @@ import { RouterProvider } from 'react-router-dom'; import * as RadixToast from '@radix-ui/react-toast'; import { HTML5Backend } from 'react-dnd-html5-backend'; import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; +import { Toast, ThemeProvider, ToastProvider } from '@librechat/client'; import { QueryClient, QueryClientProvider, QueryCache } from '@tanstack/react-query'; -import { ScreenshotProvider, ThemeProvider, useApiErrorBoundary } from './hooks'; -import { ToastProvider } from './Providers'; -import Toast from './components/ui/Toast'; +import { ScreenshotProvider, useApiErrorBoundary } from './hooks'; +import { getThemeFromEnv } from './utils/getThemeFromEnv'; import { LiveAnnouncer } from '~/a11y'; import { router } from './routes'; @@ -24,11 +24,23 @@ const App = () => { }), }); + // Load theme from environment variables if available + const envTheme = getThemeFromEnv(); + return ( - + + {/* The ThemeProvider will automatically: + 1. Apply dark/light mode classes + 2. Apply custom theme colors if envTheme is provided + 3. Otherwise use stored theme preferences from localStorage + 4. Fall back to default theme colors if nothing is stored */} diff --git a/client/src/Providers/index.ts b/client/src/Providers/index.ts index caf5b82b7..7300813ae 100644 --- a/client/src/Providers/index.ts +++ b/client/src/Providers/index.ts @@ -1,11 +1,9 @@ export { default as AssistantsProvider } from './AssistantsContext'; export { default as AgentsProvider } from './AgentsContext'; -export { default as ToastProvider } from './ToastContext'; export * from './ActivePanelContext'; export * from './AgentPanelContext'; export * from './ChatContext'; export * from './ShareContext'; -export * from './ToastContext'; export * from './FileMapContext'; export * from './AddedChatContext'; export * from './EditorContext'; diff --git a/client/src/a11y/LiveAnnouncer.tsx b/client/src/a11y/LiveAnnouncer.tsx index 29912b49a..9a0271155 100644 --- a/client/src/a11y/LiveAnnouncer.tsx +++ b/client/src/a11y/LiveAnnouncer.tsx @@ -1,8 +1,7 @@ -// client/src/a11y/LiveAnnouncer.tsx import React, { useState, useCallback, useRef, useEffect, useMemo } from 'react'; import type { AnnounceOptions } from '~/common'; import AnnouncerContext from '~/Providers/AnnouncerContext'; -import useLocalize from '~/hooks/useLocalize'; +import { useLocalize } from '~/hooks'; import Announcer from './Announcer'; interface LiveAnnouncerProps { diff --git a/client/src/common/menus.ts b/client/src/common/menus.ts index c46ad3f8b..4d70f282c 100644 --- a/client/src/common/menus.ts +++ b/client/src/common/menus.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ export type RenderProp< P = React.HTMLAttributes & { ref?: React.Ref; diff --git a/client/src/common/types.ts b/client/src/common/types.ts index a222cb29b..214dc349b 100644 --- a/client/src/common/types.ts +++ b/client/src/common/types.ts @@ -206,7 +206,9 @@ export type AgentPanelProps = { setActivePanel: React.Dispatch>; setMcp: React.Dispatch>; setAction: React.Dispatch>; + endpointsConfig?: t.TEndpointsConfig; setCurrentAgentId: React.Dispatch>; + agentsConfig?: t.TAgentsEndpoint | null; }; export type AgentPanelContextType = { @@ -217,14 +219,12 @@ export type AgentPanelContextType = { mcps?: t.MCP[]; setMcp: React.Dispatch>; setMcps: React.Dispatch>; + groupedTools: Record; tools: t.AgentToolType[]; activePanel?: string; setActivePanel: React.Dispatch>; setCurrentAgentId: React.Dispatch>; - groupedTools?: Record; agent_id?: string; - agentsConfig?: t.TAgentsEndpoint | null; - endpointsConfig?: t.TEndpointsConfig | null; }; export type AgentModelPanelProps = { @@ -336,16 +336,13 @@ export type TAskProps = { export type TOptions = { editedMessageId?: string | null; editedText?: string | null; - editedContent?: { - index: number; - text: string; - type: 'text' | 'think'; - }; isRegenerate?: boolean; isContinued?: boolean; isEdited?: boolean; overrideMessages?: t.TMessage[]; - /** Currently only utilized when resubmitting user-created message, uses that message's currently attached files */ + /** This value is only true when the user submits a message with "Save & Submit" for a user-created message */ + isResubmission?: boolean; + /** Currently only utilized when `isResubmission === true`, uses that message's currently attached files */ overrideFiles?: t.TMessage['files']; }; diff --git a/client/src/components/Artifacts/Artifacts.tsx b/client/src/components/Artifacts/Artifacts.tsx index 4268ef5fe..41c620102 100644 --- a/client/src/components/Artifacts/Artifacts.tsx +++ b/client/src/components/Artifacts/Artifacts.tsx @@ -6,9 +6,9 @@ import type { SandpackPreviewRef, CodeEditorRef } from '@codesandbox/sandpack-re import useArtifacts from '~/hooks/Artifacts/useArtifacts'; import DownloadArtifact from './DownloadArtifact'; import { useEditorContext } from '~/Providers'; -import useLocalize from '~/hooks/useLocalize'; import ArtifactTabs from './ArtifactTabs'; import { CopyCodeButton } from './Code'; +import { useLocalize } from '~/hooks'; import store from '~/store'; export default function Artifacts() { diff --git a/client/src/components/Artifacts/Code.tsx b/client/src/components/Artifacts/Code.tsx index 21db2055d..4b6d1a006 100644 --- a/client/src/components/Artifacts/Code.tsx +++ b/client/src/components/Artifacts/Code.tsx @@ -1,12 +1,11 @@ import React, { memo, useEffect, useRef, useState } from 'react'; +import copy from 'copy-to-clipboard'; import rehypeKatex from 'rehype-katex'; import ReactMarkdown from 'react-markdown'; import rehypeHighlight from 'rehype-highlight'; -import copy from 'copy-to-clipboard'; +import { Clipboard, CheckMark } from '@librechat/client'; import { handleDoubleClick, langSubset } from '~/utils'; -import Clipboard from '~/components/svg/Clipboard'; -import CheckMark from '~/components/svg/CheckMark'; -import useLocalize from '~/hooks/useLocalize'; +import { useLocalize } from '~/hooks'; type TCodeProps = { inline: boolean; diff --git a/client/src/components/Artifacts/DownloadArtifact.tsx b/client/src/components/Artifacts/DownloadArtifact.tsx index a4b6f5031..afced5a37 100644 --- a/client/src/components/Artifacts/DownloadArtifact.tsx +++ b/client/src/components/Artifacts/DownloadArtifact.tsx @@ -1,9 +1,9 @@ import React, { useState } from 'react'; import { Download } from 'lucide-react'; import type { Artifact } from '~/common'; +import { CheckMark } from '@librechat/client'; import useArtifactProps from '~/hooks/Artifacts/useArtifactProps'; import { useEditorContext } from '~/Providers'; -import { CheckMark } from '~/components/svg'; import { useLocalize } from '~/hooks'; const DownloadArtifact = ({ diff --git a/client/src/components/Artifacts/Mermaid.tsx b/client/src/components/Artifacts/Mermaid.tsx index 551a5a5a7..f7291998a 100644 --- a/client/src/components/Artifacts/Mermaid.tsx +++ b/client/src/components/Artifacts/Mermaid.tsx @@ -1,8 +1,7 @@ import React, { useEffect, useRef, useState } from 'react'; import mermaid from 'mermaid'; +import { Button } from '@librechat/client'; import { TransformWrapper, TransformComponent, ReactZoomPanPinchRef } from 'react-zoom-pan-pinch'; -// import { Button } from '/components/ui/Button'; // Live component -import { Button } from '~/components/ui/Button'; import { ZoomIn, ZoomOut, RefreshCw } from 'lucide-react'; interface MermaidDiagramProps { diff --git a/client/src/components/Audio/TTS.tsx b/client/src/components/Audio/TTS.tsx index 9343b483d..0d9351703 100644 --- a/client/src/components/Audio/TTS.tsx +++ b/client/src/components/Audio/TTS.tsx @@ -2,8 +2,8 @@ import { useEffect } from 'react'; import { useRecoilValue } from 'recoil'; import type { TMessageAudio } from '~/common'; +import { VolumeIcon, VolumeMuteIcon, Spinner } from '@librechat/client'; import { useLocalize, useTTSBrowser, useTTSExternal } from '~/hooks'; -import { VolumeIcon, VolumeMuteIcon, Spinner } from '~/components'; import { logger } from '~/utils'; import store from '~/store'; diff --git a/client/src/components/Audio/Voices.tsx b/client/src/components/Audio/Voices.tsx index 985e5e32d..6064a1662 100644 --- a/client/src/components/Audio/Voices.tsx +++ b/client/src/components/Audio/Voices.tsx @@ -1,8 +1,8 @@ import React from 'react'; import { useRecoilState } from 'recoil'; +import { Dropdown } from '@librechat/client'; import type { Option } from '~/common'; import { useLocalize, useTTSBrowser, useTTSExternal } from '~/hooks'; -import { Dropdown } from '~/components/ui'; import { logger } from '~/utils'; import store from '~/store'; diff --git a/client/src/components/Auth/AuthLayout.tsx b/client/src/components/Auth/AuthLayout.tsx index 02b380291..c49ba2a7d 100644 --- a/client/src/components/Auth/AuthLayout.tsx +++ b/client/src/components/Auth/AuthLayout.tsx @@ -1,9 +1,9 @@ -import { TranslationKeys, useLocalize } from '~/hooks'; +import { ThemeSelector } from '@librechat/client'; import { TStartupConfig } from 'librechat-data-provider'; import { ErrorMessage } from '~/components/Auth/ErrorMessage'; +import { TranslationKeys, useLocalize } from '~/hooks'; import SocialLoginRender from './SocialLoginRender'; import { BlinkAnimation } from './BlinkAnimation'; -import { ThemeSelector } from '~/components'; import { Banner } from '../Banners'; import Footer from './Footer'; diff --git a/client/src/components/Auth/Login.tsx b/client/src/components/Auth/Login.tsx index ee0b87246..39406e300 100644 --- a/client/src/components/Auth/Login.tsx +++ b/client/src/components/Auth/Login.tsx @@ -1,10 +1,10 @@ import { useOutletContext, useSearchParams } from 'react-router-dom'; import { useEffect, useState } from 'react'; -import { useAuthContext } from '~/hooks/AuthContext'; +import { OpenIDIcon } from '@librechat/client'; import type { TLoginLayoutContext } from '~/common'; import { ErrorMessage } from '~/components/Auth/ErrorMessage'; import SocialButton from '~/components/Auth/SocialButton'; -import { OpenIDIcon } from '~/components'; +import { useAuthContext } from '~/hooks/AuthContext'; import { getLoginError } from '~/utils'; import { useLocalize } from '~/hooks'; import LoginForm from './LoginForm'; diff --git a/client/src/components/Auth/LoginForm.tsx b/client/src/components/Auth/LoginForm.tsx index c13535db2..c7a469fc2 100644 --- a/client/src/components/Auth/LoginForm.tsx +++ b/client/src/components/Auth/LoginForm.tsx @@ -1,11 +1,11 @@ -import { useForm } from 'react-hook-form'; import React, { useState, useEffect, useContext } from 'react'; +import { useForm } from 'react-hook-form'; import { Turnstile } from '@marsidev/react-turnstile'; +import { ThemeContext, Spinner, Button } from '@librechat/client'; import type { TLoginUser, TStartupConfig } from 'librechat-data-provider'; import type { TAuthContext } from '~/common'; import { useResendVerificationEmail, useGetStartupConfig } from '~/data-provider'; -import { ThemeContext, useLocalize } from '~/hooks'; -import { Spinner, Button } from '~/components'; +import { useLocalize } from '~/hooks'; type TLoginFormProps = { onSubmit: (data: TLoginUser) => void; diff --git a/client/src/components/Auth/Registration.tsx b/client/src/components/Auth/Registration.tsx index b193cff11..2e915e013 100644 --- a/client/src/components/Auth/Registration.tsx +++ b/client/src/components/Auth/Registration.tsx @@ -1,12 +1,12 @@ import { useForm } from 'react-hook-form'; import React, { useContext, useState } from 'react'; import { Turnstile } from '@marsidev/react-turnstile'; +import { ThemeContext, Spinner, Button } from '@librechat/client'; import { useNavigate, useOutletContext, useLocation } from 'react-router-dom'; import { useRegisterUserMutation } from 'librechat-data-provider/react-query'; import type { TRegisterUser, TError } from 'librechat-data-provider'; -import { useLocalize, TranslationKeys, ThemeContext } from '~/hooks'; import type { TLoginLayoutContext } from '~/common'; -import { Spinner, Button } from '~/components'; +import { useLocalize, TranslationKeys } from '~/hooks'; import { ErrorMessage } from './ErrorMessage'; const Registration: React.FC = () => { diff --git a/client/src/components/Auth/RequestPasswordReset.tsx b/client/src/components/Auth/RequestPasswordReset.tsx index c0ef5751c..9f50a7e42 100644 --- a/client/src/components/Auth/RequestPasswordReset.tsx +++ b/client/src/components/Auth/RequestPasswordReset.tsx @@ -1,11 +1,11 @@ import { useForm } from 'react-hook-form'; import { useState, ReactNode } from 'react'; +import { Spinner, Button } from '@librechat/client'; import { useOutletContext } from 'react-router-dom'; import { useRequestPasswordResetMutation } from 'librechat-data-provider/react-query'; import type { TRequestPasswordReset, TRequestPasswordResetResponse } from 'librechat-data-provider'; -import type { FC } from 'react'; import type { TLoginLayoutContext } from '~/common'; -import { Spinner, Button } from '~/components'; +import type { FC } from 'react'; import { useLocalize } from '~/hooks'; const BodyTextWrapper: FC<{ children: ReactNode }> = ({ children }) => { diff --git a/client/src/components/Auth/ResetPassword.tsx b/client/src/components/Auth/ResetPassword.tsx index 231c501cb..2882e1dc5 100644 --- a/client/src/components/Auth/ResetPassword.tsx +++ b/client/src/components/Auth/ResetPassword.tsx @@ -1,10 +1,10 @@ import { useForm } from 'react-hook-form'; +import { Spinner, Button } from '@librechat/client'; import { useOutletContext } from 'react-router-dom'; import { useNavigate, useSearchParams } from 'react-router-dom'; import { useResetPasswordMutation } from 'librechat-data-provider/react-query'; import type { TResetPassword } from 'librechat-data-provider'; import type { TLoginLayoutContext } from '~/common'; -import { Spinner, Button } from '~/components'; import { useLocalize } from '~/hooks'; function ResetPassword() { diff --git a/client/src/components/Auth/SocialLoginRender.tsx b/client/src/components/Auth/SocialLoginRender.tsx index 55a8ade6b..ad76354a5 100644 --- a/client/src/components/Auth/SocialLoginRender.tsx +++ b/client/src/components/Auth/SocialLoginRender.tsx @@ -6,7 +6,7 @@ import { DiscordIcon, AppleIcon, SamlIcon, -} from '~/components'; +} from '@librechat/client'; import SocialButton from './SocialButton'; diff --git a/client/src/components/Auth/TwoFactorScreen.tsx b/client/src/components/Auth/TwoFactorScreen.tsx index 04f89d7ce..11eab660c 100644 --- a/client/src/components/Auth/TwoFactorScreen.tsx +++ b/client/src/components/Auth/TwoFactorScreen.tsx @@ -1,10 +1,10 @@ import React, { useState, useCallback } from 'react'; import { useSearchParams } from 'react-router-dom'; +import { useToastContext } from '@librechat/client'; import { useForm, Controller } from 'react-hook-form'; import { REGEXP_ONLY_DIGITS, REGEXP_ONLY_DIGITS_AND_CHARS } from 'input-otp'; -import { InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, Label } from '~/components'; +import { InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, Label } from '@librechat/client'; import { useVerifyTwoFactorTempMutation } from '~/data-provider'; -import { useToastContext } from '~/Providers'; import { useLocalize } from '~/hooks'; interface VerifyPayload { diff --git a/client/src/components/Auth/VerifyEmail.tsx b/client/src/components/Auth/VerifyEmail.tsx index 9c143224b..fb5c78719 100644 --- a/client/src/components/Auth/VerifyEmail.tsx +++ b/client/src/components/Auth/VerifyEmail.tsx @@ -1,8 +1,7 @@ -import { useSearchParams, useNavigate } from 'react-router-dom'; import { useState, useEffect, useMemo, useCallback } from 'react'; +import { Spinner, ThemeSelector } from '@librechat/client'; +import { useSearchParams, useNavigate } from 'react-router-dom'; import { useVerifyEmailMutation, useResendVerificationEmail } from '~/data-provider'; -import { ThemeSelector } from '~/components/ui'; -import { Spinner } from '~/components/svg'; import { useLocalize } from '~/hooks'; function RequestPasswordReset() { diff --git a/client/src/components/Bookmarks/BookmarkEditDialog.tsx b/client/src/components/Bookmarks/BookmarkEditDialog.tsx index ae81c3b81..7c0b494d7 100644 --- a/client/src/components/Bookmarks/BookmarkEditDialog.tsx +++ b/client/src/components/Bookmarks/BookmarkEditDialog.tsx @@ -1,10 +1,8 @@ import React, { useRef, Dispatch, SetStateAction } from 'react'; import { TConversationTag } from 'librechat-data-provider'; -import OGDialogTemplate from '~/components/ui/OGDialogTemplate'; +import { OGDialogTemplate, OGDialog, Button, Spinner, useToastContext } from '@librechat/client'; import { useConversationTagMutation } from '~/data-provider'; -import { OGDialog, Button, Spinner } from '~/components'; import { NotificationSeverity } from '~/common'; -import { useToastContext } from '~/Providers'; import BookmarkForm from './BookmarkForm'; import { useLocalize } from '~/hooks'; import { logger } from '~/utils'; diff --git a/client/src/components/Bookmarks/BookmarkForm.tsx b/client/src/components/Bookmarks/BookmarkForm.tsx index c866216be..857eacb10 100644 --- a/client/src/components/Bookmarks/BookmarkForm.tsx +++ b/client/src/components/Bookmarks/BookmarkForm.tsx @@ -2,11 +2,10 @@ import React, { useEffect } from 'react'; import { QueryKeys } from 'librechat-data-provider'; import { Controller, useForm } from 'react-hook-form'; import { useQueryClient } from '@tanstack/react-query'; +import { Checkbox, Label, TextareaAutosize, Input, useToastContext } from '@librechat/client'; import type { TConversationTag, TConversationTagRequest } from 'librechat-data-provider'; -import { Checkbox, Label, TextareaAutosize, Input } from '~/components'; import { useBookmarkContext } from '~/Providers/BookmarkContext'; import { useConversationTagMutation } from '~/data-provider'; -import { useToastContext } from '~/Providers'; import { useLocalize } from '~/hooks'; import { cn, logger } from '~/utils'; diff --git a/client/src/components/Bookmarks/BookmarkItem.tsx b/client/src/components/Bookmarks/BookmarkItem.tsx index 60698a316..b12a5b5ac 100644 --- a/client/src/components/Bookmarks/BookmarkItem.tsx +++ b/client/src/components/Bookmarks/BookmarkItem.tsx @@ -1,8 +1,8 @@ import { useState } from 'react'; +import { Spinner } from '@librechat/client'; import { MenuItem } from '@headlessui/react'; import { BookmarkFilledIcon, BookmarkIcon } from '@radix-ui/react-icons'; import type { FC } from 'react'; -import { Spinner } from '~/components/svg'; type MenuItemProps = { tag: string | React.ReactNode; diff --git a/client/src/components/Bookmarks/DeleteBookmarkButton.tsx b/client/src/components/Bookmarks/DeleteBookmarkButton.tsx index 911659de7..e63feb762 100644 --- a/client/src/components/Bookmarks/DeleteBookmarkButton.tsx +++ b/client/src/components/Bookmarks/DeleteBookmarkButton.tsx @@ -1,10 +1,17 @@ import { useCallback, useState } from 'react'; +import { + Button, + TrashIcon, + Label, + OGDialog, + OGDialogTrigger, + TooltipAnchor, + OGDialogTemplate, + useToastContext, +} from '@librechat/client'; import type { FC } from 'react'; -import { Button, TrashIcon, Label, OGDialog, OGDialogTrigger, TooltipAnchor } from '~/components'; import { useDeleteConversationTagMutation } from '~/data-provider'; -import OGDialogTemplate from '~/components/ui/OGDialogTemplate'; import { NotificationSeverity } from '~/common'; -import { useToastContext } from '~/Providers'; import { useLocalize } from '~/hooks'; const DeleteBookmarkButton: FC<{ diff --git a/client/src/components/Bookmarks/EditBookmarkButton.tsx b/client/src/components/Bookmarks/EditBookmarkButton.tsx index 6e976a53c..7c4355be8 100644 --- a/client/src/components/Bookmarks/EditBookmarkButton.tsx +++ b/client/src/components/Bookmarks/EditBookmarkButton.tsx @@ -1,7 +1,7 @@ import { useState } from 'react'; -import type { FC } from 'react'; +import { TooltipAnchor, OGDialogTrigger, EditIcon, Button } from '@librechat/client'; import type { TConversationTag } from 'librechat-data-provider'; -import { TooltipAnchor, OGDialogTrigger, EditIcon, Button } from '~/components'; +import type { FC } from 'react'; import BookmarkEditDialog from './BookmarkEditDialog'; import { useLocalize } from '~/hooks'; diff --git a/client/src/components/Chat/AddMultiConvo.tsx b/client/src/components/Chat/AddMultiConvo.tsx index 79131dfdb..26395c7a6 100644 --- a/client/src/components/Chat/AddMultiConvo.tsx +++ b/client/src/components/Chat/AddMultiConvo.tsx @@ -1,8 +1,8 @@ import { PlusCircle } from 'lucide-react'; +import { TooltipAnchor } from '@librechat/client'; import { isAssistantsEndpoint } from 'librechat-data-provider'; import type { TConversation } from 'librechat-data-provider'; import { useChatContext, useAddedChatContext } from '~/Providers'; -import { TooltipAnchor } from '~/components'; import { mainTextareaId } from '~/common'; import { useLocalize } from '~/hooks'; diff --git a/client/src/components/Chat/ChatView.tsx b/client/src/components/Chat/ChatView.tsx index a554c5f7d..f488d76b2 100644 --- a/client/src/components/Chat/ChatView.tsx +++ b/client/src/components/Chat/ChatView.tsx @@ -1,6 +1,7 @@ import { memo, useCallback } from 'react'; import { useRecoilValue } from 'recoil'; import { useForm } from 'react-hook-form'; +import { Spinner } from '@librechat/client'; import { useParams } from 'react-router-dom'; import { Constants } from 'librechat-data-provider'; import type { TMessage } from 'librechat-data-provider'; @@ -10,7 +11,6 @@ import { useChatHelpers, useAddedResponse, useSSE } from '~/hooks'; import ConversationStarters from './Input/ConversationStarters'; import { useGetMessagesByConvoId } from '~/data-provider'; import MessagesView from './Messages/MessagesView'; -import { Spinner } from '~/components/svg'; import Presentation from './Presentation'; import { buildTree, cn } from '~/utils'; import ChatForm from './Input/ChatForm'; diff --git a/client/src/components/Chat/ExportAndShareMenu.tsx b/client/src/components/Chat/ExportAndShareMenu.tsx index aa9ee8be9..207efcbc8 100644 --- a/client/src/components/Chat/ExportAndShareMenu.tsx +++ b/client/src/components/Chat/ExportAndShareMenu.tsx @@ -2,11 +2,11 @@ import { useState, useId, useRef } from 'react'; import { useRecoilValue } from 'recoil'; import * as Ariakit from '@ariakit/react'; import { Upload, Share2 } from 'lucide-react'; +import { DropdownPopup, TooltipAnchor, useMediaQuery } from '@librechat/client'; import type * as t from '~/common'; import ExportModal from '~/components/Nav/ExportConversation/ExportModal'; import { ShareButton } from '~/components/Conversations/ConvoOptions'; -import { DropdownPopup, TooltipAnchor } from '~/components/ui'; -import { useMediaQuery, useLocalize } from '~/hooks'; +import { useLocalize } from '~/hooks'; import store from '~/store'; export default function ExportAndShareMenu({ diff --git a/client/src/components/Chat/Header.tsx b/client/src/components/Chat/Header.tsx index 93a265f4a..d252e58df 100644 --- a/client/src/components/Chat/Header.tsx +++ b/client/src/components/Chat/Header.tsx @@ -1,4 +1,5 @@ import { useMemo } from 'react'; +import { useMediaQuery } from '@librechat/client'; import { useOutletContext } from 'react-router-dom'; import { getConfigDefaults, PermissionTypes, Permissions } from 'librechat-data-provider'; import type { ContextType } from '~/common'; @@ -6,10 +7,10 @@ import ModelSelector from './Menus/Endpoints/ModelSelector'; import { PresetsMenu, HeaderNewChat, OpenSidebar } from './Menus'; import { useGetStartupConfig } from '~/data-provider'; import ExportAndShareMenu from './ExportAndShareMenu'; -import { useMediaQuery, useHasAccess } from '~/hooks'; import BookmarkMenu from './Menus/BookmarkMenu'; import { TemporaryChat } from './TemporaryChat'; import AddMultiConvo from './AddMultiConvo'; +import { useHasAccess } from '~/hooks'; const defaultInterface = getConfigDefaults().interface; diff --git a/client/src/components/Chat/Input/Artifacts.tsx b/client/src/components/Chat/Input/Artifacts.tsx index eb2c49572..493f126e3 100644 --- a/client/src/components/Chat/Input/Artifacts.tsx +++ b/client/src/components/Chat/Input/Artifacts.tsx @@ -1,8 +1,8 @@ import React, { memo, useState, useCallback, useMemo } from 'react'; import * as Ariakit from '@ariakit/react'; +import { CheckboxButton } from '@librechat/client'; import { ArtifactModes } from 'librechat-data-provider'; import { WandSparkles, ChevronDown } from 'lucide-react'; -import CheckboxButton from '~/components/ui/CheckboxButton'; import { useBadgeRowContext } from '~/Providers'; import { useLocalize } from '~/hooks'; import { cn } from '~/utils'; diff --git a/client/src/components/Chat/Input/ArtifactsSubMenu.tsx b/client/src/components/Chat/Input/ArtifactsSubMenu.tsx index 944ecb66c..654c129fb 100644 --- a/client/src/components/Chat/Input/ArtifactsSubMenu.tsx +++ b/client/src/components/Chat/Input/ArtifactsSubMenu.tsx @@ -1,8 +1,8 @@ import React from 'react'; import * as Ariakit from '@ariakit/react'; +import { PinIcon } from '@librechat/client'; import { ChevronRight, WandSparkles } from 'lucide-react'; import { ArtifactModes } from 'librechat-data-provider'; -import { PinIcon } from '~/components/svg'; import { useLocalize } from '~/hooks'; import { cn } from '~/utils'; diff --git a/client/src/components/Chat/Input/AudioRecorder.tsx b/client/src/components/Chat/Input/AudioRecorder.tsx index eae7c266c..ae4252f4f 100644 --- a/client/src/components/Chat/Input/AudioRecorder.tsx +++ b/client/src/components/Chat/Input/AudioRecorder.tsx @@ -1,8 +1,7 @@ import { useCallback } from 'react'; -import { useChatFormContext, useToastContext } from '~/Providers'; -import { ListeningIcon, Spinner } from '~/components/svg'; +import { useToastContext, TooltipAnchor, ListeningIcon, Spinner } from '@librechat/client'; import { useLocalize, useSpeechToText } from '~/hooks'; -import { TooltipAnchor } from '~/components/ui'; +import { useChatFormContext } from '~/Providers'; import { globalAudioId } from '~/common'; import { cn } from '~/utils'; diff --git a/client/src/components/Chat/Input/BadgeRow.tsx b/client/src/components/Chat/Input/BadgeRow.tsx index d77fc5426..5036dcd5e 100644 --- a/client/src/components/Chat/Input/BadgeRow.tsx +++ b/client/src/components/Chat/Input/BadgeRow.tsx @@ -8,6 +8,7 @@ import React, { useReducer, useCallback, } from 'react'; +import { Badge } from '@librechat/client'; import { useRecoilValue, useRecoilCallback } from 'recoil'; import type { LucideIcon } from 'lucide-react'; import CodeInterpreter from './CodeInterpreter'; @@ -15,7 +16,6 @@ import { BadgeRowProvider } from '~/Providers'; import ToolsDropdown from './ToolsDropdown'; import type { BadgeItem } from '~/common'; import { useChatBadges } from '~/hooks'; -import { Badge } from '~/components/ui'; import ToolDialogs from './ToolDialogs'; import FileSearch from './FileSearch'; import Artifacts from './Artifacts'; diff --git a/client/src/components/Chat/Input/ChatForm.tsx b/client/src/components/Chat/Input/ChatForm.tsx index 0ca644809..50fa318b3 100644 --- a/client/src/components/Chat/Input/ChatForm.tsx +++ b/client/src/components/Chat/Input/ChatForm.tsx @@ -1,5 +1,6 @@ import { memo, useRef, useMemo, useEffect, useState, useCallback } from 'react'; import { useWatch } from 'react-hook-form'; +import { TextareaAutosize } from '@librechat/client'; import { useRecoilState, useRecoilValue } from 'recoil'; import { Constants, isAssistantsEndpoint, isAgentsEndpoint } from 'librechat-data-provider'; import { @@ -20,7 +21,6 @@ import { import { mainTextareaId, BadgeItem } from '~/common'; import AttachFileChat from './Files/AttachFileChat'; import FileFormChat from './Files/FileFormChat'; -import { TextareaAutosize } from '~/components'; import { cn, removeFocusRings } from '~/utils'; import TextareaHeader from './TextareaHeader'; import PromptsCommand from './PromptsCommand'; diff --git a/client/src/components/Chat/Input/CircleRender.tsx b/client/src/components/Chat/Input/CircleRender.tsx index 88b794763..5b46f6574 100644 --- a/client/src/components/Chat/Input/CircleRender.tsx +++ b/client/src/components/Chat/Input/CircleRender.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import { CircleIcon, CircleDotsIcon } from '~/components/svg'; import { ECallState } from 'librechat-data-provider'; +import { CircleIcon, CircleDotsIcon } from '@librechat/client'; const CircleRender = ({ rmsLevel, isCameraOn, state }) => { const getIconComponent = (state) => { diff --git a/client/src/components/Chat/Input/CodeInterpreter.tsx b/client/src/components/Chat/Input/CodeInterpreter.tsx index f2d9760cc..6805c3300 100644 --- a/client/src/components/Chat/Input/CodeInterpreter.tsx +++ b/client/src/components/Chat/Input/CodeInterpreter.tsx @@ -1,7 +1,7 @@ import React, { memo } from 'react'; import { TerminalSquareIcon } from 'lucide-react'; +import { CheckboxButton } from '@librechat/client'; import { PermissionTypes, Permissions } from 'librechat-data-provider'; -import CheckboxButton from '~/components/ui/CheckboxButton'; import { useLocalize, useHasAccess } from '~/hooks'; import { useBadgeRowContext } from '~/Providers'; diff --git a/client/src/components/Chat/Input/CollapseChat.tsx b/client/src/components/Chat/Input/CollapseChat.tsx index 1bec59217..1ae0caf79 100644 --- a/client/src/components/Chat/Input/CollapseChat.tsx +++ b/client/src/components/Chat/Input/CollapseChat.tsx @@ -1,6 +1,6 @@ import React from 'react'; +import { TooltipAnchor } from '@librechat/client'; import { ChevronDown, ChevronUp } from 'lucide-react'; -import { TooltipAnchor } from '~/components/ui'; import { useLocalize } from '~/hooks'; import { cn } from '~/utils'; diff --git a/client/src/components/Chat/Input/EditBadges.tsx b/client/src/components/Chat/Input/EditBadges.tsx index 0c9c0b5b2..821fdd4b3 100644 --- a/client/src/components/Chat/Input/EditBadges.tsx +++ b/client/src/components/Chat/Input/EditBadges.tsx @@ -1,9 +1,9 @@ import React, { useCallback } from 'react'; import { Edit3, Check, X } from 'lucide-react'; +import { Button, Badge } from '@librechat/client'; import type { LucideIcon } from 'lucide-react'; import type { BadgeItem } from '~/common'; import { useChatBadges, useLocalize } from '~/hooks'; -import { Button, Badge } from '~/components/ui'; interface EditBadgesProps { isEditingChatBadges: boolean; diff --git a/client/src/components/Chat/Input/FileSearch.tsx b/client/src/components/Chat/Input/FileSearch.tsx index 4de6c35b6..b5106dd05 100644 --- a/client/src/components/Chat/Input/FileSearch.tsx +++ b/client/src/components/Chat/Input/FileSearch.tsx @@ -1,9 +1,8 @@ import React, { memo } from 'react'; +import { CheckboxButton, VectorIcon } from '@librechat/client'; import { PermissionTypes, Permissions } from 'librechat-data-provider'; -import CheckboxButton from '~/components/ui/CheckboxButton'; import { useLocalize, useHasAccess } from '~/hooks'; import { useBadgeRowContext } from '~/Providers'; -import { VectorIcon } from '~/components/svg'; function FileSearch() { const localize = useLocalize(); diff --git a/client/src/components/Chat/Input/Files/AttachFile.tsx b/client/src/components/Chat/Input/Files/AttachFile.tsx index fe8c03c80..c896109ab 100644 --- a/client/src/components/Chat/Input/Files/AttachFile.tsx +++ b/client/src/components/Chat/Input/Files/AttachFile.tsx @@ -1,5 +1,5 @@ import React, { useRef } from 'react'; -import { FileUpload, TooltipAnchor, AttachmentIcon } from '~/components'; +import { FileUpload, TooltipAnchor, AttachmentIcon } from '@librechat/client'; import { useLocalize, useFileHandling } from '~/hooks'; import { cn } from '~/utils'; diff --git a/client/src/components/Chat/Input/Files/AttachFileMenu.tsx b/client/src/components/Chat/Input/Files/AttachFileMenu.tsx index 9fe298860..5e42dd063 100644 --- a/client/src/components/Chat/Input/Files/AttachFileMenu.tsx +++ b/client/src/components/Chat/Input/Files/AttachFileMenu.tsx @@ -1,11 +1,11 @@ -import { useSetRecoilState } from 'recoil'; -import * as Ariakit from '@ariakit/react'; import React, { useRef, useState, useMemo } from 'react'; +import * as Ariakit from '@ariakit/react'; +import { useSetRecoilState } from 'recoil'; import { FileSearch, ImageUpIcon, TerminalSquareIcon, FileType2Icon } from 'lucide-react'; +import { FileUpload, TooltipAnchor, DropdownPopup, AttachmentIcon } from '@librechat/client'; import { EToolResources, EModelEndpoint, defaultAgentCapabilities } from 'librechat-data-provider'; import type { EndpointFileConfig } from 'librechat-data-provider'; import { useLocalize, useGetAgentsConfig, useFileHandling, useAgentCapabilities } from '~/hooks'; -import { FileUpload, TooltipAnchor, DropdownPopup, AttachmentIcon } from '~/components'; import { ephemeralAgentByConvoId } from '~/store'; import { cn } from '~/utils'; diff --git a/client/src/components/Chat/Input/Files/DragDropModal.tsx b/client/src/components/Chat/Input/Files/DragDropModal.tsx index f80af70de..c3b337b42 100644 --- a/client/src/components/Chat/Input/Files/DragDropModal.tsx +++ b/client/src/components/Chat/Input/Files/DragDropModal.tsx @@ -1,8 +1,8 @@ import React, { useMemo } from 'react'; +import { OGDialog, OGDialogTemplate } from '@librechat/client'; import { ImageUpIcon, FileSearch, TerminalSquareIcon, FileType2Icon } from 'lucide-react'; import { EToolResources, defaultAgentCapabilities } from 'librechat-data-provider'; import { useLocalize, useGetAgentsConfig, useAgentCapabilities } from '~/hooks'; -import { OGDialog, OGDialogTemplate } from '~/components/ui'; interface DragDropModalProps { onOptionSelect: (option: EToolResources | undefined) => void; diff --git a/client/src/components/Chat/Input/Files/FilePreview.tsx b/client/src/components/Chat/Input/Files/FilePreview.tsx index 400834a5b..600092278 100644 --- a/client/src/components/Chat/Input/Files/FilePreview.tsx +++ b/client/src/components/Chat/Input/Files/FilePreview.tsx @@ -1,7 +1,7 @@ +import { Spinner } from '@librechat/client'; import type { TFile } from 'librechat-data-provider'; import type { ExtendedFile } from '~/common'; -import FileIcon from '~/components/svg/Files/FileIcon'; -import { Spinner } from '~/components'; +import { FileIcon } from '~/components/svg'; import SourceIcon from './SourceIcon'; import { cn } from '~/utils'; diff --git a/client/src/components/Chat/Input/Files/FileRow.tsx b/client/src/components/Chat/Input/Files/FileRow.tsx index 67d687eef..47da77bbf 100644 --- a/client/src/components/Chat/Input/Files/FileRow.tsx +++ b/client/src/components/Chat/Input/Files/FileRow.tsx @@ -1,11 +1,11 @@ import { useEffect } from 'react'; +import { useToastContext } from '@librechat/client'; import { EToolResources } from 'librechat-data-provider'; import type { ExtendedFile } from '~/common'; import { useDeleteFilesMutation } from '~/data-provider'; -import { useToastContext } from '~/Providers'; -import { useLocalize } from '~/hooks'; import { useFileDeletion } from '~/hooks/Files'; import FileContainer from './FileContainer'; +import { useLocalize } from '~/hooks'; import { logger } from '~/utils'; import Image from './Image'; diff --git a/client/src/components/Chat/Input/Files/FilesView.tsx b/client/src/components/Chat/Input/Files/FilesView.tsx index afffa34c1..13a378b93 100644 --- a/client/src/components/Chat/Input/Files/FilesView.tsx +++ b/client/src/components/Chat/Input/Files/FilesView.tsx @@ -1,6 +1,6 @@ import { FileSources, FileContext } from 'librechat-data-provider'; import type { TFile } from 'librechat-data-provider'; -import { OGDialog, OGDialogContent, OGDialogHeader, OGDialogTitle } from '~/components'; +import { OGDialog, OGDialogContent, OGDialogHeader, OGDialogTitle } from '@librechat/client'; import { useGetFiles } from '~/data-provider'; import { DataTable, columns } from './Table'; import { useLocalize } from '~/hooks'; diff --git a/client/src/components/Chat/Input/Files/ImagePreview.tsx b/client/src/components/Chat/Input/Files/ImagePreview.tsx index fe761da86..37d4e7900 100644 --- a/client/src/components/Chat/Input/Files/ImagePreview.tsx +++ b/client/src/components/Chat/Input/Files/ImagePreview.tsx @@ -1,7 +1,7 @@ import { useState, useEffect, useCallback } from 'react'; import { Maximize2 } from 'lucide-react'; -import { OGDialog, OGDialogContent } from '~/components/ui'; import { FileSources } from 'librechat-data-provider'; +import { OGDialog, OGDialogContent } from '@librechat/client'; import ProgressCircle from './ProgressCircle'; import SourceIcon from './SourceIcon'; import { cn } from '~/utils'; @@ -93,9 +93,9 @@ const ImagePreview = ({ const style: styleProps = imageUrl ? { - ...baseStyle, - backgroundImage: `url(${imageUrl})`, - } + ...baseStyle, + backgroundImage: `url(${imageUrl})`, + } : baseStyle; if (typeof style.backgroundImage !== 'string' || style.backgroundImage.length === 0) { diff --git a/client/src/components/Chat/Input/Files/Table/Columns.tsx b/client/src/components/Chat/Input/Files/Table/Columns.tsx index bc60de361..fb0eccee6 100644 --- a/client/src/components/Chat/Input/Files/Table/Columns.tsx +++ b/client/src/components/Chat/Input/Files/Table/Columns.tsx @@ -1,14 +1,19 @@ /* eslint-disable react-hooks/rules-of-hooks */ - import { ArrowUpDown, Database } from 'lucide-react'; import { FileSources, FileContext } from 'librechat-data-provider'; +import { + Button, + Checkbox, + OpenAIMinimalIcon, + AzureMinimalIcon, + useMediaQuery, +} from '@librechat/client'; import type { ColumnDef } from '@tanstack/react-table'; import type { TFile } from 'librechat-data-provider'; -import { Button, Checkbox, OpenAIMinimalIcon, AzureMinimalIcon } from '~/components'; import ImagePreview from '~/components/Chat/Input/Files/ImagePreview'; import FilePreview from '~/components/Chat/Input/Files/FilePreview'; +import { TranslationKeys, useLocalize } from '~/hooks'; import { SortFilterHeader } from './SortFilterHeader'; -import { TranslationKeys, useLocalize, useMediaQuery } from '~/hooks'; import { formatDate, getFileType } from '~/utils'; const contextMap: Record = { diff --git a/client/src/components/Chat/Input/Files/Table/DataTable.tsx b/client/src/components/Chat/Input/Files/Table/DataTable.tsx index c8c3190bc..ffb3e2825 100644 --- a/client/src/components/Chat/Input/Files/Table/DataTable.tsx +++ b/client/src/components/Chat/Input/Files/Table/DataTable.tsx @@ -16,8 +16,6 @@ import type { ColumnFiltersState, } from '@tanstack/react-table'; import { FileContext } from 'librechat-data-provider'; -import type { AugmentedColumnDef } from '~/common'; -import type { TFile } from 'librechat-data-provider'; import { Button, Input, @@ -31,11 +29,14 @@ import { DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuTrigger, -} from '~/components/ui'; + TrashIcon, + Spinner, + useMediaQuery, +} from '@librechat/client'; +import type { TFile } from 'librechat-data-provider'; +import type { AugmentedColumnDef } from '~/common'; import { useDeleteFilesFromTable } from '~/hooks/Files'; -import { TrashIcon, Spinner } from '~/components/svg'; -import useLocalize from '~/hooks/useLocalize'; -import { useMediaQuery } from '~/hooks'; +import { useLocalize } from '~/hooks'; import { cn } from '~/utils'; import store from '~/store'; diff --git a/client/src/components/Chat/Input/Files/Table/SortFilterHeader.tsx b/client/src/components/Chat/Input/Files/Table/SortFilterHeader.tsx index bb9247c15..d275044ee 100644 --- a/client/src/components/Chat/Input/Files/Table/SortFilterHeader.tsx +++ b/client/src/components/Chat/Input/Files/Table/SortFilterHeader.tsx @@ -2,13 +2,13 @@ import { Column } from '@tanstack/react-table'; import { ListFilter, FilterX } from 'lucide-react'; import { ArrowDownIcon, ArrowUpIcon, CaretSortIcon } from '@radix-ui/react-icons'; import { + Button, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, -} from '~/components/ui/DropdownMenu'; -import { Button } from '~/components/ui/Button'; +} from '@librechat/client'; import { useLocalize, TranslationKeys } from '~/hooks'; import { cn } from '~/utils'; diff --git a/client/src/components/Chat/Input/Files/Table/TemplateTable.tsx b/client/src/components/Chat/Input/Files/Table/TemplateTable.tsx index dc288c73a..9f6b78f91 100644 --- a/client/src/components/Chat/Input/Files/Table/TemplateTable.tsx +++ b/client/src/components/Chat/Input/Files/Table/TemplateTable.tsx @@ -1,4 +1,4 @@ -import { DotsIcon, TrashIcon } from '~/components/svg'; +import { DotsIcon, TrashIcon } from '@librechat/client'; export default function Template() { return ( diff --git a/client/src/components/Chat/Input/HeaderOptions.tsx b/client/src/components/Chat/Input/HeaderOptions.tsx index ac4b03976..5ba263941 100644 --- a/client/src/components/Chat/Input/HeaderOptions.tsx +++ b/client/src/components/Chat/Input/HeaderOptions.tsx @@ -2,12 +2,12 @@ import { useRecoilState } from 'recoil'; import { Settings2 } from 'lucide-react'; import { useState, useEffect, useMemo } from 'react'; import { Root, Anchor } from '@radix-ui/react-popover'; -import { EModelEndpoint, isParamEndpoint, tConvoUpdateSchema } from 'librechat-data-provider'; +import { PluginStoreDialog, TooltipAnchor } from '@librechat/client'; import { useUserKeyQuery } from 'librechat-data-provider/react-query'; +import { EModelEndpoint, isParamEndpoint, tConvoUpdateSchema } from 'librechat-data-provider'; import type { TPreset, TInterfaceConfig } from 'librechat-data-provider'; import { EndpointSettings, SaveAsPresetDialog, AlternativeSettings } from '~/components/Endpoints'; -import { useSetIndexOptions, useMediaQuery, useLocalize } from '~/hooks'; -import { PluginStoreDialog, TooltipAnchor } from '~/components'; +import { useSetIndexOptions, useLocalize } from '~/hooks'; import { useGetEndpointsQuery } from '~/data-provider'; import OptionsPopover from './OptionsPopover'; import PopoverButtons from './PopoverButtons'; diff --git a/client/src/components/Chat/Input/MCPConfigDialog.tsx b/client/src/components/Chat/Input/MCPConfigDialog.tsx new file mode 100644 index 000000000..5cb217086 --- /dev/null +++ b/client/src/components/Chat/Input/MCPConfigDialog.tsx @@ -0,0 +1,121 @@ +import React, { useEffect } from 'react'; +import { useForm, Controller } from 'react-hook-form'; +import { Button, Input, Label, OGDialog, OGDialogTemplate } from '@librechat/client'; +import { useLocalize } from '~/hooks'; + +export interface ConfigFieldDetail { + title: string; + description: string; +} + +interface MCPConfigDialogProps { + isOpen: boolean; + onOpenChange: (isOpen: boolean) => void; + fieldsSchema: Record; + initialValues: Record; + onSave: (updatedValues: Record) => void; + isSubmitting?: boolean; + onRevoke?: () => void; + serverName: string; +} + +export default function MCPConfigDialog({ + isOpen, + onOpenChange, + fieldsSchema, + initialValues, + onSave, + isSubmitting = false, + onRevoke, + serverName, +}: MCPConfigDialogProps) { + const localize = useLocalize(); + const { + control, + handleSubmit, + reset, + formState: { errors, _ }, + } = useForm>({ + defaultValues: initialValues, + }); + + useEffect(() => { + if (isOpen) { + reset(initialValues); + } + }, [isOpen, initialValues, reset]); + + const onFormSubmit = (data: Record) => { + onSave(data); + }; + + const handleRevoke = () => { + if (onRevoke) { + onRevoke(); + } + }; + + const dialogTitle = localize('com_ui_configure_mcp_variables_for', { 0: serverName }); + const dialogDescription = localize('com_ui_mcp_dialog_desc'); + + return ( + + + {Object.entries(fieldsSchema).map(([key, details]) => ( +

+ + ( + + )} + /> + {details.description && ( +

+ )} + {errors[key] &&

{errors[key]?.message}

} +
+ ))} + + } + selection={{ + selectHandler: handleSubmit(onFormSubmit), + selectClasses: 'bg-green-500 hover:bg-green-600 text-white', + selectText: isSubmitting ? localize('com_ui_saving') : localize('com_ui_save'), + }} + buttons={ + onRevoke && ( + + ) + } + footerClassName="flex justify-end gap-2 px-6 pb-6 pt-2" + showCancelButton={true} + /> + + ); +} diff --git a/client/src/components/Chat/Input/MCPSelect.tsx b/client/src/components/Chat/Input/MCPSelect.tsx index 2f9b4071c..8160cdd2f 100644 --- a/client/src/components/Chat/Input/MCPSelect.tsx +++ b/client/src/components/Chat/Input/MCPSelect.tsx @@ -1,9 +1,8 @@ import React, { memo, useCallback } from 'react'; -import MCPConfigDialog from '~/components/ui/MCP/MCPConfigDialog'; -import MCPServerStatusIcon from '~/components/ui/MCP/MCPServerStatusIcon'; -import MultiSelect from '~/components/ui/MultiSelect'; -import { MCPIcon } from '~/components/svg'; +import { MultiSelect, MCPIcon } from '@librechat/client'; +import MCPServerStatusIcon from '~/components/MCP/MCPServerStatusIcon'; import { useMCPServerManager } from '~/hooks/MCP/useMCPServerManager'; +import MCPConfigDialog from '~/components/MCP/MCPConfigDialog'; function MCPSelect() { const { @@ -80,7 +79,6 @@ function MCPSelect() { items={configuredServers} selectedValues={mcpValues ?? []} setSelectedValues={batchToggleServers} - defaultSelectedValues={mcpValues ?? []} renderSelectedValues={renderSelectedValues} renderItemContent={renderItemContent} placeholder={placeholderText} diff --git a/client/src/components/Chat/Input/MCPSubMenu.tsx b/client/src/components/Chat/Input/MCPSubMenu.tsx index 8f271c0b6..1d704f2a6 100644 --- a/client/src/components/Chat/Input/MCPSubMenu.tsx +++ b/client/src/components/Chat/Input/MCPSubMenu.tsx @@ -1,10 +1,10 @@ import React from 'react'; import * as Ariakit from '@ariakit/react'; import { ChevronRight } from 'lucide-react'; -import { PinIcon, MCPIcon } from '~/components/svg'; -import MCPConfigDialog from '~/components/ui/MCP/MCPConfigDialog'; -import MCPServerStatusIcon from '~/components/ui/MCP/MCPServerStatusIcon'; +import { PinIcon, MCPIcon } from '@librechat/client'; +import MCPServerStatusIcon from '~/components/MCP/MCPServerStatusIcon'; import { useMCPServerManager } from '~/hooks/MCP/useMCPServerManager'; +import MCPConfigDialog from '~/components/MCP/MCPConfigDialog'; import { cn } from '~/utils'; interface MCPSubMenuProps { diff --git a/client/src/components/Chat/Input/Mention.tsx b/client/src/components/Chat/Input/Mention.tsx index 067383711..e3472a2aa 100644 --- a/client/src/components/Chat/Input/Mention.tsx +++ b/client/src/components/Chat/Input/Mention.tsx @@ -1,12 +1,13 @@ import { useState, useRef, useEffect } from 'react'; +import { useCombobox } from '@librechat/client'; import { AutoSizer, List } from 'react-virtualized'; import { EModelEndpoint } from 'librechat-data-provider'; -import type { SetterOrUpdater } from 'recoil'; import type { MentionOption, ConvoGenerator } from '~/common'; +import type { SetterOrUpdater } from 'recoil'; import useSelectMention from '~/hooks/Input/useSelectMention'; +import { useLocalize, TranslationKeys } from '~/hooks'; import { useAssistantsMapContext } from '~/Providers'; import useMentions from '~/hooks/Input/useMentions'; -import { useLocalize, useCombobox, TranslationKeys } from '~/hooks'; import { removeCharIfLast } from '~/utils'; import MentionItem from './MentionItem'; diff --git a/client/src/components/Chat/Input/OptionsPopover.tsx b/client/src/components/Chat/Input/OptionsPopover.tsx index a49d31f33..f3102bd27 100644 --- a/client/src/components/Chat/Input/OptionsPopover.tsx +++ b/client/src/components/Chat/Input/OptionsPopover.tsx @@ -1,11 +1,10 @@ import { useRef } from 'react'; import { Save } from 'lucide-react'; import { Portal, Content } from '@radix-ui/react-popover'; +import { Button, CrossIcon, useOnClickOutside } from '@librechat/client'; import type { ReactNode } from 'react'; -import { useLocalize, useOnClickOutside } from '~/hooks'; import { cn, removeFocusOutlines } from '~/utils'; -import { CrossIcon } from '~/components/svg'; -import { Button } from '~/components/ui'; +import { useLocalize } from '~/hooks'; type TOptionsPopoverProps = { children: ReactNode; diff --git a/client/src/components/Chat/Input/PopoverButtons.tsx b/client/src/components/Chat/Input/PopoverButtons.tsx index fa2211ecc..31bb6ee2f 100644 --- a/client/src/components/Chat/Input/PopoverButtons.tsx +++ b/client/src/components/Chat/Input/PopoverButtons.tsx @@ -1,9 +1,8 @@ import { useRecoilState } from 'recoil'; import { EModelEndpoint, SettingsViews } from 'librechat-data-provider'; +import { Button, MessagesSquared, GPTIcon, AssistantIcon, DataIcon } from '@librechat/client'; import type { ReactNode } from 'react'; -import { MessagesSquared, GPTIcon, AssistantIcon, DataIcon } from '~/components/svg'; import { useChatContext } from '~/Providers'; -import { Button } from '~/components/ui'; import { useLocalize } from '~/hooks'; import { cn } from '~/utils/'; import store from '~/store'; diff --git a/client/src/components/Chat/Input/PromptsCommand.tsx b/client/src/components/Chat/Input/PromptsCommand.tsx index 835c7cd31..0756be17e 100644 --- a/client/src/components/Chat/Input/PromptsCommand.tsx +++ b/client/src/components/Chat/Input/PromptsCommand.tsx @@ -1,5 +1,6 @@ import { useState, useRef, useEffect, useMemo, memo, useCallback } from 'react'; import { AutoSizer, List } from 'react-virtualized'; +import { Spinner, useCombobox } from '@librechat/client'; import { useSetRecoilState, useRecoilValue } from 'recoil'; import { PermissionTypes, Permissions } from 'librechat-data-provider'; import type { TPromptGroup } from 'librechat-data-provider'; @@ -7,9 +8,8 @@ import type { PromptOption } from '~/common'; import { removeCharIfLast, mapPromptGroups, detectVariables } from '~/utils'; import VariableDialog from '~/components/Prompts/Groups/VariableDialog'; import CategoryIcon from '~/components/Prompts/Groups/CategoryIcon'; -import { useLocalize, useCombobox, useHasAccess } from '~/hooks'; +import { useLocalize, useHasAccess } from '~/hooks'; import { useGetAllPromptGroups } from '~/data-provider'; -import { Spinner } from '~/components/svg'; import MentionItem from './MentionItem'; import store from '~/store'; diff --git a/client/src/components/Chat/Input/SendButton.tsx b/client/src/components/Chat/Input/SendButton.tsx index 52a2b4bed..14c21f058 100644 --- a/client/src/components/Chat/Input/SendButton.tsx +++ b/client/src/components/Chat/Input/SendButton.tsx @@ -1,8 +1,7 @@ import React, { forwardRef } from 'react'; import { useWatch } from 'react-hook-form'; import type { Control } from 'react-hook-form'; -import { TooltipAnchor } from '~/components/ui'; -import { SendIcon } from '~/components/svg'; +import { SendIcon, TooltipAnchor } from '@librechat/client'; import { useLocalize } from '~/hooks'; import { cn } from '~/utils'; diff --git a/client/src/components/Chat/Input/StopButton.tsx b/client/src/components/Chat/Input/StopButton.tsx index 6c785811c..4a058777f 100644 --- a/client/src/components/Chat/Input/StopButton.tsx +++ b/client/src/components/Chat/Input/StopButton.tsx @@ -1,4 +1,4 @@ -import { TooltipAnchor } from '~/components/ui'; +import { TooltipAnchor } from '@librechat/client'; import { useLocalize } from '~/hooks'; import { cn } from '~/utils'; diff --git a/client/src/components/Chat/Input/ToolsDropdown.tsx b/client/src/components/Chat/Input/ToolsDropdown.tsx index 159fe455d..60ad0156f 100644 --- a/client/src/components/Chat/Input/ToolsDropdown.tsx +++ b/client/src/components/Chat/Input/ToolsDropdown.tsx @@ -1,6 +1,7 @@ import React, { useState, useMemo, useCallback } from 'react'; import * as Ariakit from '@ariakit/react'; import { Globe, Settings, Settings2, TerminalSquareIcon } from 'lucide-react'; +import { TooltipAnchor, DropdownPopup, PinIcon, VectorIcon } from '@librechat/client'; import type { MenuItemProps } from '~/common'; import { AuthType, @@ -9,11 +10,9 @@ import { PermissionTypes, defaultAgentCapabilities, } from 'librechat-data-provider'; -import { TooltipAnchor, DropdownPopup } from '~/components'; import { useLocalize, useHasAccess, useAgentCapabilities } from '~/hooks'; import ArtifactsSubMenu from '~/components/Chat/Input/ArtifactsSubMenu'; import MCPSubMenu from '~/components/Chat/Input/MCPSubMenu'; -import { PinIcon, VectorIcon } from '~/components/svg'; import { useBadgeRowContext } from '~/Providers'; import { cn } from '~/utils'; @@ -317,7 +316,7 @@ const ToolsDropdown = ({ disabled }: ToolsDropdownProps) => { return ( { const localize = useLocalize(); diff --git a/client/src/components/Chat/Menus/UI/TitleButton.tsx b/client/src/components/Chat/Menus/UI/TitleButton.tsx index c23fdeb3a..d6f7dec09 100644 --- a/client/src/components/Chat/Menus/UI/TitleButton.tsx +++ b/client/src/components/Chat/Menus/UI/TitleButton.tsx @@ -1,7 +1,7 @@ import { useState } from 'react'; import { ChevronDown } from 'lucide-react'; import { Trigger } from '@radix-ui/react-popover'; -import useLocalize from '~/hooks/useLocalize'; +import { useLocalize } from '~/hooks'; export default function TitleButton({ primaryText = '', secondaryText = '' }) { const localize = useLocalize(); diff --git a/client/src/components/Chat/Messages/Content/ContentParts.tsx b/client/src/components/Chat/Messages/Content/ContentParts.tsx index 49f6be255..9c38dd92d 100644 --- a/client/src/components/Chat/Messages/Content/ContentParts.tsx +++ b/client/src/components/Chat/Messages/Content/ContentParts.tsx @@ -11,9 +11,9 @@ import { ThinkingButton } from '~/components/Artifacts/Thinking'; import { MessageContext, SearchContext } from '~/Providers'; import MemoryArtifacts from './MemoryArtifacts'; import Sources from '~/components/Web/Sources'; -import useLocalize from '~/hooks/useLocalize'; import { mapAttachments } from '~/utils/map'; import { EditTextPart } from './Parts'; +import { useLocalize } from '~/hooks'; import store from '~/store'; import Part from './Part'; diff --git a/client/src/components/Chat/Messages/Content/DialogImage.tsx b/client/src/components/Chat/Messages/Content/DialogImage.tsx index 0711757df..9eb5f9e71 100644 --- a/client/src/components/Chat/Messages/Content/DialogImage.tsx +++ b/client/src/components/Chat/Messages/Content/DialogImage.tsx @@ -1,6 +1,6 @@ import { useState, useEffect, useCallback, useRef } from 'react'; +import { Button, OGDialog, OGDialogContent, TooltipAnchor } from '@librechat/client'; import { X, ArrowDownToLine, PanelLeftOpen, PanelLeftClose, RotateCcw } from 'lucide-react'; -import { Button, OGDialog, OGDialogContent, TooltipAnchor } from '~/components'; import { useLocalize } from '~/hooks'; const getQualityStyles = (quality: string): string => { diff --git a/client/src/components/Chat/Messages/Content/EditMessage.tsx b/client/src/components/Chat/Messages/Content/EditMessage.tsx index e2781aaa5..e87321090 100644 --- a/client/src/components/Chat/Messages/Content/EditMessage.tsx +++ b/client/src/components/Chat/Messages/Content/EditMessage.tsx @@ -1,10 +1,10 @@ import { useRef, useEffect, useCallback } from 'react'; -import { useRecoilState, useRecoilValue } from 'recoil'; import { useForm } from 'react-hook-form'; +import { useRecoilState, useRecoilValue } from 'recoil'; +import { TextareaAutosize, TooltipAnchor } from '@librechat/client'; import { useUpdateMessageMutation } from 'librechat-data-provider/react-query'; import type { TEditProps } from '~/common'; import { useChatContext, useAddedChatContext } from '~/Providers'; -import { TextareaAutosize, TooltipAnchor } from '~/components/ui'; import { cn, removeFocusRings } from '~/utils'; import { useLocalize } from '~/hooks'; import Container from './Container'; diff --git a/client/src/components/Chat/Messages/Content/Image.tsx b/client/src/components/Chat/Messages/Content/Image.tsx index ba4f65671..450ed0fc2 100644 --- a/client/src/components/Chat/Messages/Content/Image.tsx +++ b/client/src/components/Chat/Messages/Content/Image.tsx @@ -1,8 +1,8 @@ import React, { useState, useRef, useMemo } from 'react'; +import { Skeleton } from '@librechat/client'; import { LazyLoadImage } from 'react-lazy-load-image-component'; import { cn, scaleImage } from '~/utils'; import DialogImage from './DialogImage'; -import { Skeleton } from '~/components'; const Image = ({ imagePath, diff --git a/client/src/components/Chat/Messages/Content/MarkdownComponents.tsx b/client/src/components/Chat/Messages/Content/MarkdownComponents.tsx index e0a381ff5..de1e82443 100644 --- a/client/src/components/Chat/Messages/Content/MarkdownComponents.tsx +++ b/client/src/components/Chat/Messages/Content/MarkdownComponents.tsx @@ -1,12 +1,13 @@ import React, { memo, useMemo, useRef, useEffect } from 'react'; import { useRecoilValue } from 'recoil'; +import { useToastContext } from '@librechat/client'; import { PermissionTypes, Permissions } from 'librechat-data-provider'; -import { useToastContext, useCodeBlockContext } from '~/Providers'; import CodeBlock from '~/components/Messages/Content/CodeBlock'; import useHasAccess from '~/hooks/Roles/useHasAccess'; import { useFileDownload } from '~/data-provider'; -import useLocalize from '~/hooks/useLocalize'; +import { useCodeBlockContext } from '~/Providers'; import { handleDoubleClick } from '~/utils'; +import { useLocalize } from '~/hooks'; import store from '~/store'; type TCodeProps = { diff --git a/client/src/components/Chat/Messages/Content/MessageContent.tsx b/client/src/components/Chat/Messages/Content/MessageContent.tsx index f70a15b77..dd3433d56 100644 --- a/client/src/components/Chat/Messages/Content/MessageContent.tsx +++ b/client/src/components/Chat/Messages/Content/MessageContent.tsx @@ -1,10 +1,10 @@ import { memo, Suspense, useMemo } from 'react'; import { useRecoilValue } from 'recoil'; +import { DelayedRender } from '@librechat/client'; import type { TMessage } from 'librechat-data-provider'; import type { TMessageContentProps, TDisplayProps } from '~/common'; import Error from '~/components/Messages/Content/Error'; import Thinking from '~/components/Artifacts/Thinking'; -import { DelayedRender } from '~/components/ui'; import { useChatContext } from '~/Providers'; import MarkdownLite from './MarkdownLite'; import EditMessage from './EditMessage'; diff --git a/client/src/components/Chat/Messages/Content/Parts/EditTextPart.tsx b/client/src/components/Chat/Messages/Content/Parts/EditTextPart.tsx index ab15355d1..1898920ea 100644 --- a/client/src/components/Chat/Messages/Content/Parts/EditTextPart.tsx +++ b/client/src/components/Chat/Messages/Content/Parts/EditTextPart.tsx @@ -1,5 +1,6 @@ import { useRef, useEffect, useCallback, useMemo } from 'react'; import { useForm } from 'react-hook-form'; +import { TextareaAutosize } from '@librechat/client'; import { ContentTypes } from 'librechat-data-provider'; import { useRecoilState, useRecoilValue } from 'recoil'; import { useUpdateMessageContentMutation } from 'librechat-data-provider/react-query'; @@ -7,7 +8,6 @@ import type { Agents } from 'librechat-data-provider'; import type { TEditProps } from '~/common'; import Container from '~/components/Chat/Messages/Content/Container'; import { useChatContext, useAddedChatContext } from '~/Providers'; -import { TextareaAutosize } from '~/components/ui'; import { cn, removeFocusRings } from '~/utils'; import { useLocalize } from '~/hooks'; import store from '~/store'; diff --git a/client/src/components/Chat/Messages/Content/Parts/LogLink.tsx b/client/src/components/Chat/Messages/Content/Parts/LogLink.tsx index 590b6d7b8..d328f202e 100644 --- a/client/src/components/Chat/Messages/Content/Parts/LogLink.tsx +++ b/client/src/components/Chat/Messages/Content/Parts/LogLink.tsx @@ -1,6 +1,6 @@ import React from 'react'; +import { useToastContext } from '@librechat/client'; import { useCodeOutputDownload } from '~/data-provider'; -import { useToastContext } from '~/Providers'; interface LogLinkProps { href: string; diff --git a/client/src/components/Chat/Messages/Content/Parts/OpenAIImageGen/OpenAIImageGen.tsx b/client/src/components/Chat/Messages/Content/Parts/OpenAIImageGen/OpenAIImageGen.tsx index ef24c3553..c0f77b14f 100644 --- a/client/src/components/Chat/Messages/Content/Parts/OpenAIImageGen/OpenAIImageGen.tsx +++ b/client/src/components/Chat/Messages/Content/Parts/OpenAIImageGen/OpenAIImageGen.tsx @@ -1,8 +1,8 @@ import { useState, useEffect, useRef, useCallback } from 'react'; +import { PixelCard } from '@librechat/client'; import type { TAttachment, TFile, TAttachmentMetadata } from 'librechat-data-provider'; import Image from '~/components/Chat/Messages/Content/Image'; import ProgressText from './ProgressText'; -import { PixelCard } from '~/components'; import { scaleImage } from '~/utils'; export default function OpenAIImageGen({ diff --git a/client/src/components/Chat/Messages/Content/ProgressText.tsx b/client/src/components/Chat/Messages/Content/ProgressText.tsx index 1d8030907..e131579f6 100644 --- a/client/src/components/Chat/Messages/Content/ProgressText.tsx +++ b/client/src/components/Chat/Messages/Content/ProgressText.tsx @@ -1,8 +1,8 @@ import * as Popover from '@radix-ui/react-popover'; +import { Spinner } from '@librechat/client'; import { ChevronDown, ChevronUp } from 'lucide-react'; import CancelledIcon from './CancelledIcon'; import FinishedIcon from './FinishedIcon'; -import { Spinner } from '~/components'; import { cn } from '~/utils'; const wrapperClass = diff --git a/client/src/components/Chat/Messages/Content/SearchContent.tsx b/client/src/components/Chat/Messages/Content/SearchContent.tsx index 8b409804b..81752ddf9 100644 --- a/client/src/components/Chat/Messages/Content/SearchContent.tsx +++ b/client/src/components/Chat/Messages/Content/SearchContent.tsx @@ -1,5 +1,6 @@ import { Suspense, useMemo } from 'react'; import { useRecoilValue } from 'recoil'; +import { DelayedRender } from '@librechat/client'; import { ContentTypes } from 'librechat-data-provider'; import type { Agents, @@ -9,7 +10,6 @@ import type { TMessageContentParts, } from 'librechat-data-provider'; import { UnfinishedMessage } from './MessageContent'; -import { DelayedRender } from '~/components/ui'; import Sources from '~/components/Web/Sources'; import { cn, mapAttachments } from '~/utils'; import { SearchContext } from '~/Providers'; diff --git a/client/src/components/Chat/Messages/Content/ToolCall.tsx b/client/src/components/Chat/Messages/Content/ToolCall.tsx index 3408ba5a5..84fc8cdf7 100644 --- a/client/src/components/Chat/Messages/Content/ToolCall.tsx +++ b/client/src/components/Chat/Messages/Content/ToolCall.tsx @@ -1,4 +1,5 @@ import { useMemo, useState, useEffect, useRef, useLayoutEffect } from 'react'; +import { Button } from '@librechat/client'; import { TriangleAlert } from 'lucide-react'; import { actionDelimiter, actionDomainSeparator, Constants } from 'librechat-data-provider'; import type { TAttachment } from 'librechat-data-provider'; @@ -6,7 +7,6 @@ import { useLocalize, useProgress } from '~/hooks'; import { AttachmentGroup } from './Parts'; import ToolCallInfo from './ToolCallInfo'; import ProgressText from './ProgressText'; -import { Button } from '~/components'; import { logger, cn } from '~/utils'; export default function ToolCall({ diff --git a/client/src/components/Chat/Messages/Feedback.tsx b/client/src/components/Chat/Messages/Feedback.tsx index 4879808d9..a43b9700e 100644 --- a/client/src/components/Chat/Messages/Feedback.tsx +++ b/client/src/components/Chat/Messages/Feedback.tsx @@ -1,6 +1,14 @@ import React, { useState, useCallback, useMemo, useEffect } from 'react'; import * as Ariakit from '@ariakit/react'; import { TFeedback, TFeedbackTag, getTagsForRating } from 'librechat-data-provider'; +import { + Button, + OGDialog, + OGDialogContent, + OGDialogTitle, + ThumbUpIcon, + ThumbDownIcon, +} from '@librechat/client'; import { AlertCircle, PenTool, @@ -11,14 +19,6 @@ import { Lightbulb, Search, } from 'lucide-react'; -import { - Button, - OGDialog, - OGDialogContent, - OGDialogTitle, - ThumbUpIcon, - ThumbDownIcon, -} from '~/components'; import { useLocalize } from '~/hooks'; import { cn } from '~/utils'; diff --git a/client/src/components/Chat/Messages/Fork.tsx b/client/src/components/Chat/Messages/Fork.tsx index 0a0c0a114..810692c32 100644 --- a/client/src/components/Chat/Messages/Fork.tsx +++ b/client/src/components/Chat/Messages/Fork.tsx @@ -3,11 +3,11 @@ import { useRecoilState } from 'recoil'; import * as Ariakit from '@ariakit/react'; import { VisuallyHidden } from '@ariakit/react'; import { GitFork, InfoIcon } from 'lucide-react'; +import { useToastContext } from '@librechat/client'; import { ForkOptions } from 'librechat-data-provider'; import { GitCommit, GitBranchPlus, ListTree } from 'lucide-react'; import { TranslationKeys, useLocalize, useNavigateToConvo } from '~/hooks'; import { useForkConvoMutation } from '~/data-provider'; -import { useToastContext } from '~/Providers'; import { cn } from '~/utils'; import store from '~/store'; diff --git a/client/src/components/Chat/Messages/HoverButtons.tsx b/client/src/components/Chat/Messages/HoverButtons.tsx index a13266f04..8c9067374 100644 --- a/client/src/components/Chat/Messages/HoverButtons.tsx +++ b/client/src/components/Chat/Messages/HoverButtons.tsx @@ -1,7 +1,7 @@ import React, { useState, useMemo, memo } from 'react'; import { useRecoilState } from 'recoil'; import type { TConversation, TMessage, TFeedback } from 'librechat-data-provider'; -import { EditIcon, Clipboard, CheckMark, ContinueIcon, RegenerateIcon } from '~/components'; +import { EditIcon, Clipboard, CheckMark, ContinueIcon, RegenerateIcon } from '@librechat/client'; import { useGenerationsByLatest, useLocalize } from '~/hooks'; import { Fork } from '~/components/Conversations'; import MessageAudio from './MessageAudio'; diff --git a/client/src/components/Chat/Messages/MessageParts.tsx b/client/src/components/Chat/Messages/MessageParts.tsx index 889e75d4e..d53522e64 100644 --- a/client/src/components/Chat/Messages/MessageParts.tsx +++ b/client/src/components/Chat/Messages/MessageParts.tsx @@ -6,7 +6,6 @@ import { useMessageHelpers, useLocalize, useAttachments } from '~/hooks'; import MessageIcon from '~/components/Chat/Messages/MessageIcon'; import ContentParts from './Content/ContentParts'; import SiblingSwitch from './SiblingSwitch'; - import MultiMessage from './MultiMessage'; import HoverButtons from './HoverButtons'; import SubRow from './SubRow'; diff --git a/client/src/components/Chat/Messages/MinimalHoverButtons.tsx b/client/src/components/Chat/Messages/MinimalHoverButtons.tsx index 150cc59f7..3f4e1711a 100644 --- a/client/src/components/Chat/Messages/MinimalHoverButtons.tsx +++ b/client/src/components/Chat/Messages/MinimalHoverButtons.tsx @@ -1,7 +1,7 @@ import { useState } from 'react'; +import { Clipboard, CheckMark } from '@librechat/client'; import type { TMessage, TAttachment, SearchResultData } from 'librechat-data-provider'; import { useLocalize, useCopyToClipboard } from '~/hooks'; -import { Clipboard, CheckMark } from '~/components/svg'; type THoverButtons = { message: TMessage; diff --git a/client/src/components/Chat/Messages/MultiMessage.tsx b/client/src/components/Chat/Messages/MultiMessage.tsx index 9050a6149..99733143f 100644 --- a/client/src/components/Chat/Messages/MultiMessage.tsx +++ b/client/src/components/Chat/Messages/MultiMessage.tsx @@ -3,11 +3,8 @@ import { useEffect, useCallback } from 'react'; import { isAssistantsEndpoint } from 'librechat-data-provider'; import type { TMessage } from 'librechat-data-provider'; import type { TMessageProps } from '~/common'; - import MessageContent from '~/components/Messages/MessageContent'; - import MessageParts from './MessageParts'; - import Message from './Message'; import store from '~/store'; diff --git a/client/src/components/Chat/TemporaryChat.tsx b/client/src/components/Chat/TemporaryChat.tsx index 69e39a1a6..a13437949 100644 --- a/client/src/components/Chat/TemporaryChat.tsx +++ b/client/src/components/Chat/TemporaryChat.tsx @@ -1,8 +1,8 @@ import React from 'react'; import { motion } from 'framer-motion'; +import { TooltipAnchor } from '@librechat/client'; import { MessageCircleDashed } from 'lucide-react'; import { useRecoilState, useRecoilCallback } from 'recoil'; -import { TooltipAnchor } from '~/components/ui'; import { useChatContext } from '~/Providers'; import { useLocalize } from '~/hooks'; import { cn } from '~/utils'; diff --git a/client/src/components/Conversations/Conversations.tsx b/client/src/components/Conversations/Conversations.tsx index 46f217a83..10203c89e 100644 --- a/client/src/components/Conversations/Conversations.tsx +++ b/client/src/components/Conversations/Conversations.tsx @@ -1,11 +1,11 @@ import { useMemo, memo, type FC, useCallback } from 'react'; import throttle from 'lodash/throttle'; import { parseISO, isToday } from 'date-fns'; +import { Spinner, useMediaQuery } from '@librechat/client'; import { List, AutoSizer, CellMeasurer, CellMeasurerCache } from 'react-virtualized'; -import { useLocalize, TranslationKeys, useMediaQuery } from '~/hooks'; import { TConversation } from 'librechat-data-provider'; +import { useLocalize, TranslationKeys } from '~/hooks'; import { groupConversationsByDate } from '~/utils'; -import { Spinner } from '~/components/svg'; import Convo from './Convo'; interface ConversationsProps { diff --git a/client/src/components/Conversations/Convo.tsx b/client/src/components/Conversations/Convo.tsx index afd14a4cb..3804cbf2b 100644 --- a/client/src/components/Conversations/Convo.tsx +++ b/client/src/components/Conversations/Convo.tsx @@ -2,14 +2,14 @@ import React, { useState, useEffect, useRef, useMemo } from 'react'; import { useRecoilValue } from 'recoil'; import { useParams } from 'react-router-dom'; import { Constants } from 'librechat-data-provider'; +import { useToastContext, useMediaQuery } from '@librechat/client'; import type { TConversation } from 'librechat-data-provider'; -import { useNavigateToConvo, useMediaQuery, useLocalize } from '~/hooks'; import { useUpdateConversationMutation } from '~/data-provider'; import EndpointIcon from '~/components/Endpoints/EndpointIcon'; +import { useNavigateToConvo, useLocalize } from '~/hooks'; import { useGetEndpointsQuery } from '~/data-provider'; import { NotificationSeverity } from '~/common'; import { ConvoOptions } from './ConvoOptions'; -import { useToastContext } from '~/Providers'; import RenameForm from './RenameForm'; import ConvoLink from './ConvoLink'; import { cn } from '~/utils'; diff --git a/client/src/components/Conversations/ConvoOptions/ConvoOptions.tsx b/client/src/components/Conversations/ConvoOptions/ConvoOptions.tsx index 87211c1a6..7affbd8e9 100644 --- a/client/src/components/Conversations/ConvoOptions/ConvoOptions.tsx +++ b/client/src/components/Conversations/ConvoOptions/ConvoOptions.tsx @@ -1,6 +1,7 @@ import { useState, useId, useRef, memo, useCallback, useMemo } from 'react'; import * as Menu from '@ariakit/react/menu'; import { useParams, useNavigate } from 'react-router-dom'; +import { DropdownPopup, Spinner, useToastContext } from '@librechat/client'; import { Ellipsis, Share2, Copy, Archive, Pen, Trash } from 'lucide-react'; import type { MouseEvent } from 'react'; import { @@ -9,9 +10,8 @@ import { useArchiveConvoMutation, } from '~/data-provider'; import { useLocalize, useNavigateToConvo, useNewConvo } from '~/hooks'; -import { useToastContext, useChatContext } from '~/Providers'; -import { DropdownPopup, Spinner } from '~/components'; import { NotificationSeverity } from '~/common'; +import { useChatContext } from '~/Providers'; import DeleteButton from './DeleteButton'; import ShareButton from './ShareButton'; import { cn } from '~/utils'; diff --git a/client/src/components/Conversations/ConvoOptions/DeleteButton.tsx b/client/src/components/Conversations/ConvoOptions/DeleteButton.tsx index c40ca5295..3c34cb8c3 100644 --- a/client/src/components/Conversations/ConvoOptions/DeleteButton.tsx +++ b/client/src/components/Conversations/ConvoOptions/DeleteButton.tsx @@ -2,7 +2,6 @@ import React, { useCallback, useState } from 'react'; import { QueryKeys } from 'librechat-data-provider'; import { useQueryClient } from '@tanstack/react-query'; import { useParams, useNavigate } from 'react-router-dom'; -import type { TMessage } from 'librechat-data-provider'; import { Button, Spinner, @@ -10,11 +9,12 @@ import { OGDialogTitle, OGDialogHeader, OGDialogContent, -} from '~/components'; + useToastContext, +} from '@librechat/client'; +import type { TMessage } from 'librechat-data-provider'; import { useDeleteConversationMutation } from '~/data-provider'; import { useLocalize, useNewConvo } from '~/hooks'; import { NotificationSeverity } from '~/common'; -import { useToastContext } from '~/Providers'; type DeleteButtonProps = { conversationId: string; diff --git a/client/src/components/Conversations/ConvoOptions/ShareButton.tsx b/client/src/components/Conversations/ConvoOptions/ShareButton.tsx index c979019f0..177dd5ae5 100644 --- a/client/src/components/Conversations/ConvoOptions/ShareButton.tsx +++ b/client/src/components/Conversations/ConvoOptions/ShareButton.tsx @@ -2,9 +2,8 @@ import React, { useState, useEffect } from 'react'; import { QRCodeSVG } from 'qrcode.react'; import { Copy, CopyCheck } from 'lucide-react'; import { useGetSharedLinkQuery } from 'librechat-data-provider/react-query'; -import OGDialogTemplate from '~/components/ui/OGDialogTemplate'; +import { OGDialogTemplate, Button, Spinner, OGDialog } from '@librechat/client'; import { useLocalize, useCopyToClipboard } from '~/hooks'; -import { Button, Spinner, OGDialog } from '~/components'; import SharedLinkButton from './SharedLinkButton'; import { cn } from '~/utils'; diff --git a/client/src/components/Conversations/ConvoOptions/SharedLinkButton.tsx b/client/src/components/Conversations/ConvoOptions/SharedLinkButton.tsx index 425551574..35609ba5e 100644 --- a/client/src/components/Conversations/ConvoOptions/SharedLinkButton.tsx +++ b/client/src/components/Conversations/ConvoOptions/SharedLinkButton.tsx @@ -1,15 +1,21 @@ import { useState, useCallback } from 'react'; import { QrCode, RotateCw, Trash2 } from 'lucide-react'; +import { + Button, + OGDialog, + Spinner, + TooltipAnchor, + Label, + OGDialogTemplate, + useToastContext, +} from '@librechat/client'; import type { TSharedLinkGetResponse } from 'librechat-data-provider'; import { useCreateSharedLinkMutation, useUpdateSharedLinkMutation, useDeleteSharedLinkMutation, } from '~/data-provider'; -import { Button, OGDialog, Spinner, TooltipAnchor, Label } from '~/components'; -import OGDialogTemplate from '~/components/ui/OGDialogTemplate'; import { NotificationSeverity } from '~/common'; -import { useToastContext } from '~/Providers'; import { useLocalize } from '~/hooks'; export default function SharedLinkButton({ diff --git a/client/src/components/Endpoints/Icon.tsx b/client/src/components/Endpoints/Icon.tsx index aa9f4d16c..acc602769 100644 --- a/client/src/components/Endpoints/Icon.tsx +++ b/client/src/components/Endpoints/Icon.tsx @@ -1,11 +1,11 @@ import React, { memo, useState } from 'react'; +import { UserIcon } from '@librechat/client'; import type { TUser } from 'librechat-data-provider'; import type { IconProps } from '~/common'; import MessageEndpointIcon from './MessageEndpointIcon'; import { useAuthContext } from '~/hooks/AuthContext'; import useAvatar from '~/hooks/Messages/useAvatar'; -import useLocalize from '~/hooks/useLocalize'; -import { UserIcon } from '~/components/svg'; +import { useLocalize } from '~/hooks'; import { cn } from '~/utils'; type UserAvatarProps = { @@ -48,15 +48,15 @@ const UserAvatar = memo(({ size, user, avatarSrc, username, className }: UserAva > {(!(user?.avatar ?? '') && (!(user?.username ?? '') || user?.username.trim() === '')) || imageError ? ( - renderDefaultAvatar() - ) : ( - avatar - )} + renderDefaultAvatar() + ) : ( + avatar + )} ); }); diff --git a/client/src/components/Endpoints/MessageEndpointIcon.tsx b/client/src/components/Endpoints/MessageEndpointIcon.tsx index e405c01d3..1eb859c06 100644 --- a/client/src/components/Endpoints/MessageEndpointIcon.tsx +++ b/client/src/components/Endpoints/MessageEndpointIcon.tsx @@ -12,7 +12,7 @@ import { AnthropicIcon, AzureMinimalIcon, CustomMinimalIcon, -} from '~/components/svg'; +} from '@librechat/client'; import UnknownIcon from '~/hooks/Endpoint/UnknownIcon'; import { IconProps } from '~/common'; import { cn } from '~/utils'; diff --git a/client/src/components/Endpoints/MinimalIcon.tsx b/client/src/components/Endpoints/MinimalIcon.tsx index 953859c43..f21cad1e0 100644 --- a/client/src/components/Endpoints/MinimalIcon.tsx +++ b/client/src/components/Endpoints/MinimalIcon.tsx @@ -10,7 +10,7 @@ import { AnthropicIcon, BedrockIcon, Sparkles, -} from '~/components/svg'; +} from '@librechat/client'; import UnknownIcon from '~/hooks/Endpoint/UnknownIcon'; import { IconProps } from '~/common'; import { cn } from '~/utils'; diff --git a/client/src/components/Endpoints/SaveAsPresetDialog.tsx b/client/src/components/Endpoints/SaveAsPresetDialog.tsx index b827a2d8c..6467a4a40 100644 --- a/client/src/components/Endpoints/SaveAsPresetDialog.tsx +++ b/client/src/components/Endpoints/SaveAsPresetDialog.tsx @@ -1,11 +1,9 @@ import React, { useEffect, useState } from 'react'; import { useCreatePresetMutation } from 'librechat-data-provider/react-query'; +import { OGDialogTemplate, OGDialog, Input, Label, useToastContext } from '@librechat/client'; import type { TEditPresetProps } from '~/common'; -import { cn, removeFocusOutlines, cleanupPreset, defaultTextProps } from '~/utils/'; -import OGDialogTemplate from '~/components/ui/OGDialogTemplate'; -import { OGDialog, Input, Label } from '~/components/ui/'; +import { cn, removeFocusOutlines, cleanupPreset, defaultTextProps } from '~/utils'; import { NotificationSeverity } from '~/common'; -import { useToastContext } from '~/Providers'; import { useLocalize } from '~/hooks'; const SaveAsPresetDialog = ({ open, onOpenChange, preset }: TEditPresetProps) => { @@ -23,7 +21,7 @@ const SaveAsPresetDialog = ({ open, onOpenChange, preset }: TEditPresetProps) => }); const toastTitle = - _preset.title ?? '' ? `\`${_preset.title}\`` : localize('com_endpoint_preset_title'); + (_preset.title ?? '') ? `\`${_preset.title}\`` : localize('com_endpoint_preset_title'); createPresetMutation.mutate(_preset, { onSuccess: () => { @@ -76,7 +74,7 @@ const SaveAsPresetDialog = ({ open, onOpenChange, preset }: TEditPresetProps) => aria-label={localize('com_endpoint_preset_name')} className={cn( defaultTextProps, - 'flex h-10 max-h-10 w-full resize-none border-border-medium px-3 py-2 ', + 'flex h-10 max-h-10 w-full resize-none border-border-medium px-3 py-2', removeFocusOutlines, )} /> diff --git a/client/src/components/Endpoints/Settings/Advanced.tsx b/client/src/components/Endpoints/Settings/Advanced.tsx index 601e9a675..d0beaa902 100644 --- a/client/src/components/Endpoints/Settings/Advanced.tsx +++ b/client/src/components/Endpoints/Settings/Advanced.tsx @@ -1,7 +1,5 @@ import TextareaAutosize from 'react-textarea-autosize'; import { ImageDetail, imageDetailNumeric, imageDetailValue } from 'librechat-data-provider'; -import type { ValueType } from '@rc-component/mini-decimal'; -import type { TModelSelectProps } from '~/common'; import { Input, Label, @@ -10,8 +8,10 @@ import { HoverCard, InputNumber, HoverCardTrigger, -} from '~/components/ui'; -import { cn, defaultTextProps, optionText, removeFocusOutlines } from '~/utils/'; +} from '@librechat/client'; +import type { ValueType } from '@rc-component/mini-decimal'; +import type { TModelSelectProps } from '~/common'; +import { cn, defaultTextProps, optionText, removeFocusOutlines } from '~/utils'; import { useLocalize, useDebouncedInput } from '~/hooks'; import OptionHover from './OptionHover'; import { ESide } from '~/common'; @@ -109,7 +109,7 @@ export default function Settings({ placeholder={localize('com_endpoint_openai_prompt_prefix_placeholder')} className={cn( defaultTextProps, - 'flex max-h-[138px] min-h-[100px] w-full resize-none px-3 py-2 ', + 'flex max-h-[138px] min-h-[100px] w-full resize-none px-3 py-2', )} /> diff --git a/client/src/components/Endpoints/Settings/AgentSettings.tsx b/client/src/components/Endpoints/Settings/AgentSettings.tsx index 8ba20f250..f41a8bc19 100644 --- a/client/src/components/Endpoints/Settings/AgentSettings.tsx +++ b/client/src/components/Endpoints/Settings/AgentSettings.tsx @@ -1,4 +1,3 @@ -import type { TModelSelectProps } from '~/common'; import { Switch, Label, @@ -7,7 +6,8 @@ import { InputNumber, SelectDropDown, HoverCardTrigger, -} from '~/components'; +} from '@librechat/client'; +import type { TModelSelectProps } from '~/common'; import { cn, optionText, defaultTextProps, removeFocusRings } from '~/utils'; import OptionHover from './OptionHover'; import { useLocalize } from '~/hooks'; diff --git a/client/src/components/Endpoints/Settings/Assistants.tsx b/client/src/components/Endpoints/Settings/Assistants.tsx index a35f9f7eb..1ae0f8cb4 100644 --- a/client/src/components/Endpoints/Settings/Assistants.tsx +++ b/client/src/components/Endpoints/Settings/Assistants.tsx @@ -1,5 +1,6 @@ import { useState, useMemo, useEffect } from 'react'; import TextareaAutosize from 'react-textarea-autosize'; +import { Label, HoverCard, SelectDropDown, HoverCardTrigger } from '@librechat/client'; import type { Assistant, TPreset } from 'librechat-data-provider'; import type { TModelSelectProps, Option } from '~/common'; import { @@ -9,7 +10,6 @@ import { mapAssistants, createDropdownSetter, } from '~/utils'; -import { Label, HoverCard, SelectDropDown, HoverCardTrigger } from '~/components/ui'; import { useLocalize, useDebouncedInput, useAssistantListMap } from '~/hooks'; import OptionHover from './OptionHover'; import { ESide } from '~/common'; @@ -121,6 +121,7 @@ export default function Settings({ conversation, setOption, models, readonly }:
@@ -178,7 +179,7 @@ export default function Settings({ conversation, setOption, models, readonly }: placeholder={localize('com_endpoint_instructions_assistants_placeholder')} className={cn( defaultTextProps, - 'flex max-h-[240px] min-h-[80px] w-full resize-none px-3 py-2 ', + 'flex max-h-[240px] min-h-[80px] w-full resize-none px-3 py-2', )} /> diff --git a/client/src/components/Endpoints/Settings/Examples.tsx b/client/src/components/Endpoints/Settings/Examples.tsx index 98dac9ea9..10f623685 100644 --- a/client/src/components/Endpoints/Settings/Examples.tsx +++ b/client/src/components/Endpoints/Settings/Examples.tsx @@ -1,9 +1,9 @@ import React from 'react'; import { Plus, Minus } from 'lucide-react'; +import { Button, Label } from '@librechat/client'; import TextareaAutosize from 'react-textarea-autosize'; import type { TExample } from 'librechat-data-provider'; import type { TSetExample } from '~/common'; -import { Button, Label } from '~/components/ui'; import { cn, defaultTextProps } from '~/utils/'; import { useLocalize } from '~/hooks'; @@ -42,7 +42,7 @@ function Examples({ readonly, examples, setExample, addExample, removeExample }: placeholder="Set example input. Example is ignored if empty." className={cn( defaultTextProps, - 'flex max-h-[138px] min-h-[75px] w-full resize-none px-3 py-2 ', + 'flex max-h-[138px] min-h-[75px] w-full resize-none px-3 py-2', )} /> @@ -67,7 +67,7 @@ function Examples({ readonly, examples, setExample, addExample, removeExample }: placeholder={'Set example output. Example is ignored if empty.'} className={cn( defaultTextProps, - 'flex max-h-[300px] min-h-[75px] w-full resize-none px-3 py-2 ', + 'flex max-h-[300px] min-h-[75px] w-full resize-none px-3 py-2', )} /> diff --git a/client/src/components/Endpoints/Settings/Google.tsx b/client/src/components/Endpoints/Settings/Google.tsx index 063d5f098..6e513c179 100644 --- a/client/src/components/Endpoints/Settings/Google.tsx +++ b/client/src/components/Endpoints/Settings/Google.tsx @@ -1,6 +1,5 @@ import TextareaAutosize from 'react-textarea-autosize'; import { EModelEndpoint, endpointSettings } from 'librechat-data-provider'; -import type { TModelSelectProps, OnInputNumberChange } from '~/common'; import { Input, Label, @@ -9,7 +8,8 @@ import { InputNumber, SelectDropDown, HoverCardTrigger, -} from '~/components/ui'; +} from '@librechat/client'; +import type { TModelSelectProps, OnInputNumberChange } from '~/common'; import { cn, defaultTextProps, optionText, removeFocusOutlines, removeFocusRings } from '~/utils'; import OptionHoverAlt from '~/components/SidePanel/Parameters/OptionHover'; import { useLocalize, useDebouncedInput } from '~/hooks'; @@ -55,6 +55,7 @@ export default function Settings({ conversation, setOption, models, readonly }:
@@ -221,7 +222,7 @@ export default function Settings({ conversation, setOption, models, readonly }: {localize('com_endpoint_max_output_tokens')}{' '} - ({localize('com_endpoint_default_with_num', { 0: google.maxOutputTokens.default + '' })}) + ( + {localize('com_endpoint_default_with_num', { + 0: google.maxOutputTokens.default + '', + })} + )
diff --git a/client/src/components/Files/ActionButton.tsx b/client/src/components/Files/ActionButton.tsx index 03f58da6c..0d4c59f8d 100644 --- a/client/src/components/Files/ActionButton.tsx +++ b/client/src/components/Files/ActionButton.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Button } from '~/components/ui'; +import { Button } from '@librechat/client'; import { useLocalize } from '~/hooks'; type ActionButtonProps = { diff --git a/client/src/components/Files/DeleteIconButton.tsx b/client/src/components/Files/DeleteIconButton.tsx index 50ac461ba..0173a3d57 100644 --- a/client/src/components/Files/DeleteIconButton.tsx +++ b/client/src/components/Files/DeleteIconButton.tsx @@ -1,6 +1,5 @@ import React from 'react'; -import { CrossIcon, TrashIcon } from '~/components/svg'; -import { Button } from '~/components/ui'; +import { Button, TrashIcon } from '@librechat/client'; type DeleteIconButtonProps = { onClick: () => void; diff --git a/client/src/components/Files/FileList/DataTableFile.tsx b/client/src/components/Files/FileList/DataTableFile.tsx index d64699e2e..269001d0a 100644 --- a/client/src/components/Files/FileList/DataTableFile.tsx +++ b/client/src/components/Files/FileList/DataTableFile.tsx @@ -16,27 +16,28 @@ import type { ColumnFiltersState, } from '@tanstack/react-table'; import { FileContext } from 'librechat-data-provider'; -import type { AugmentedColumnDef } from '~/common'; -import type { TFile } from 'librechat-data-provider'; import { Input, Table, Button, + Spinner, TableRow, TableBody, TableCell, TableHead, + TrashIcon, TableHeader, DropdownMenu, DropdownMenuContent, DropdownMenuTrigger, DropdownMenuCheckboxItem, -} from '~/components/ui'; +} from '@librechat/client'; +import type { TFile } from 'librechat-data-provider'; +import type { AugmentedColumnDef } from '~/common'; import ActionButton from '~/components/Files/ActionButton'; import { useDeleteFilesFromTable } from '~/hooks/Files'; -import { TrashIcon, Spinner } from '~/components/svg'; import UploadFileButton from './UploadFileButton'; -import useLocalize from '~/hooks/useLocalize'; +import { useLocalize } from '~/hooks'; import store from '~/store'; interface DataTableProps { diff --git a/client/src/components/Files/FileList/FileListItem.tsx b/client/src/components/Files/FileList/FileListItem.tsx index 5760b2917..e7ee5d1d2 100644 --- a/client/src/components/Files/FileList/FileListItem.tsx +++ b/client/src/components/Files/FileList/FileListItem.tsx @@ -1,7 +1,6 @@ -import type { TFile } from 'librechat-data-provider'; import React from 'react'; -import { TrashIcon } from '~/components/svg'; -import { Button } from '~/components/ui'; +import { Button, TrashIcon } from '@librechat/client'; +import type { TFile } from 'librechat-data-provider'; type FileListItemProps = { file: TFile; diff --git a/client/src/components/Files/FileList/FileListItem2.tsx b/client/src/components/Files/FileList/FileListItem2.tsx index 2b8ff1d6a..b692a6962 100644 --- a/client/src/components/Files/FileList/FileListItem2.tsx +++ b/client/src/components/Files/FileList/FileListItem2.tsx @@ -1,9 +1,8 @@ -import type { TFile } from 'librechat-data-provider'; -import { FileIcon, PlusIcon } from 'lucide-react'; import React from 'react'; +import { FileIcon, PlusIcon } from 'lucide-react'; +import { Button, DotsIcon, TrashIcon } from '@librechat/client'; +import type { TFile } from 'librechat-data-provider'; import { useNavigate } from 'react-router-dom'; -import { DotsIcon, TrashIcon } from '~/components/svg'; -import { Button } from '~/components/ui'; type FileListItemProps = { file: TFile; diff --git a/client/src/components/Files/FileList/FilePreview.tsx b/client/src/components/Files/FileList/FilePreview.tsx index e0c2624b3..0b416fa70 100644 --- a/client/src/components/Files/FileList/FilePreview.tsx +++ b/client/src/components/Files/FileList/FilePreview.tsx @@ -1,11 +1,10 @@ -import { TFile } from 'librechat-data-provider/dist/types'; import React, { useState } from 'react'; -import { TThread, TVectorStore } from '~/common'; -import { CheckMark, TrashIcon } from '~/components/svg'; -import { Button } from '~/components/ui'; -import DeleteIconButton from '../DeleteIconButton'; +import { TFile } from 'librechat-data-provider/dist/types'; +import { CheckMark, TrashIcon, Button } from '@librechat/client'; import VectorStoreButton from '../VectorStore/VectorStoreButton'; import { CircleIcon, Clock3Icon, InfoIcon } from 'lucide-react'; +import DeleteIconButton from '../DeleteIconButton'; +import { TThread, TVectorStore } from '~/common'; import { useParams } from 'react-router-dom'; const tempFile: TFile = { diff --git a/client/src/components/Files/FileList/FileSidePanel.tsx b/client/src/components/Files/FileList/FileSidePanel.tsx index e1552d2a8..5b5967842 100644 --- a/client/src/components/Files/FileList/FileSidePanel.tsx +++ b/client/src/components/Files/FileList/FileSidePanel.tsx @@ -1,10 +1,9 @@ import React from 'react'; import FileList from './FileList'; +import { Button, Input } from '@librechat/client'; import { TFile } from 'librechat-data-provider/dist/types'; -import FilesSectionSelector from '../FilesSectionSelector'; -import { Button, Input } from '~/components/ui'; -import { ListFilter } from 'lucide-react'; import UploadFileButton from './UploadFileButton'; +import { ListFilter } from 'lucide-react'; import { useLocalize } from '~/hooks'; const fakeFiles = [ diff --git a/client/src/components/Files/FileList/FileTableColumns.tsx b/client/src/components/Files/FileList/FileTableColumns.tsx index 8e670aa80..754cb061d 100644 --- a/client/src/components/Files/FileList/FileTableColumns.tsx +++ b/client/src/components/Files/FileList/FileTableColumns.tsx @@ -1,13 +1,10 @@ /* eslint-disable react-hooks/rules-of-hooks */ -import { FileSources, FileContext } from 'librechat-data-provider'; +import { PlusIcon } from 'lucide-react'; +import { Button, Checkbox, DotsIcon, FileIcon } from '@librechat/client'; import type { ColumnDef } from '@tanstack/react-table'; import type { TFile } from 'librechat-data-provider'; -import { CrossIcon, DotsIcon } from '~/components/svg'; -import { Button, Checkbox } from '~/components/ui'; import { formatDate, getFileType } from '~/utils'; -import useLocalize from '~/hooks/useLocalize'; -import FileIcon from '~/components/svg/Files/FileIcon'; -import { PlusIcon } from 'lucide-react'; +import { useLocalize } from '~/hooks'; export const fileTableColumns: ColumnDef[] = [ { diff --git a/client/src/components/Files/FileList/UploadFileButton.tsx b/client/src/components/Files/FileList/UploadFileButton.tsx index e2b8acdd0..0823f706e 100644 --- a/client/src/components/Files/FileList/UploadFileButton.tsx +++ b/client/src/components/Files/FileList/UploadFileButton.tsx @@ -1,6 +1,6 @@ -import { PlusIcon } from 'lucide-react'; import React from 'react'; -import { Button } from '~/components/ui'; +import { PlusIcon } from 'lucide-react'; +import { Button } from '@librechat/client'; type UploadFileProps = { onClick: () => void; diff --git a/client/src/components/Files/FileList/UploadFileModal.tsx b/client/src/components/Files/FileList/UploadFileModal.tsx index 4e2e31e27..7be59184a 100644 --- a/client/src/components/Files/FileList/UploadFileModal.tsx +++ b/client/src/components/Files/FileList/UploadFileModal.tsx @@ -1,6 +1,5 @@ import React, { useState, ChangeEvent } from 'react'; -import AttachFile from '~/components/Chat/Input/Files/AttachFile'; -import { Button, Dialog, DialogContent, DialogHeader, DialogTitle, Input } from '~/components/ui'; +import { Button, Dialog, DialogContent, DialogHeader, DialogTitle, Input } from '@librechat/client'; import { useLocalize } from '~/hooks'; import { cn } from '~/utils'; diff --git a/client/src/components/Files/VectorStore/VectorStoreButton.tsx b/client/src/components/Files/VectorStore/VectorStoreButton.tsx index dc3e34c4f..6eb0f35a2 100644 --- a/client/src/components/Files/VectorStore/VectorStoreButton.tsx +++ b/client/src/components/Files/VectorStore/VectorStoreButton.tsx @@ -1,6 +1,6 @@ -import { PlusIcon } from 'lucide-react'; import React from 'react'; -import { Button } from '~/components/ui'; +import { PlusIcon } from 'lucide-react'; +import { Button } from '@librechat/client'; type VectorStoreButtonProps = { onClick: () => void; diff --git a/client/src/components/Files/VectorStore/VectorStoreListItem.tsx b/client/src/components/Files/VectorStore/VectorStoreListItem.tsx index 720ebd0af..66a54b159 100644 --- a/client/src/components/Files/VectorStore/VectorStoreListItem.tsx +++ b/client/src/components/Files/VectorStore/VectorStoreListItem.tsx @@ -1,8 +1,7 @@ import React from 'react'; import { useNavigate } from 'react-router-dom'; +import { Button, DotsIcon, TrashIcon } from '@librechat/client'; import { TVectorStore } from '~/common'; -import { DotsIcon, TrashIcon } from '~/components/svg'; -import { Button } from '~/components/ui'; type VectorStoreListItemProps = { vectorStore: TVectorStore; diff --git a/client/src/components/Files/VectorStore/VectorStorePreview.tsx b/client/src/components/Files/VectorStore/VectorStorePreview.tsx index c1d70107f..d75a82742 100644 --- a/client/src/components/Files/VectorStore/VectorStorePreview.tsx +++ b/client/src/components/Files/VectorStore/VectorStorePreview.tsx @@ -1,7 +1,6 @@ import React, { useState } from 'react'; import DeleteIconButton from '../DeleteIconButton'; -import { Button } from '~/components/ui'; -import { TrashIcon } from '~/components/svg'; +import { TrashIcon, Button } from '@librechat/client'; import { TFile } from 'librechat-data-provider/dist/types'; import UploadFileButton from '../FileList/UploadFileButton'; import UploadFileModal from '../FileList/UploadFileModal'; @@ -99,7 +98,7 @@ export default function VectorStorePreview() { const params = useParams(); return ( -
+
VECTOR STORE diff --git a/client/src/components/Files/VectorStore/VectorStoreSidePanel.tsx b/client/src/components/Files/VectorStore/VectorStoreSidePanel.tsx index b1d0fe166..0616bcc7b 100644 --- a/client/src/components/Files/VectorStore/VectorStoreSidePanel.tsx +++ b/client/src/components/Files/VectorStore/VectorStoreSidePanel.tsx @@ -1,12 +1,9 @@ import React from 'react'; +import { ListFilter } from 'lucide-react'; +import { Button, Input } from '@librechat/client'; +import VectorStoreButton from './VectorStoreButton'; import VectorStoreList from './VectorStoreList'; import { TVectorStore } from '~/common'; -import VectorStoreButton from './VectorStoreButton'; -import { Button, Input } from '~/components/ui'; -import FilesSectionSelector from '../FilesSectionSelector'; -import ActionButton from '../ActionButton'; -import DeleteIconButton from '../DeleteIconButton'; -import { ListFilter } from 'lucide-react'; import { useLocalize } from '~/hooks'; const fakeVectorStores: TVectorStore[] = [ diff --git a/client/src/components/Input/Generations/Regenerate.tsx b/client/src/components/Input/Generations/Regenerate.tsx index 83eabf493..715168cb9 100644 --- a/client/src/components/Input/Generations/Regenerate.tsx +++ b/client/src/components/Input/Generations/Regenerate.tsx @@ -1,7 +1,7 @@ +import { RegenerateIcon } from '@librechat/client'; import type { TGenButtonProps } from '~/common'; -import { RegenerateIcon } from '~/components/svg'; -import Button from './Button'; import { useLocalize } from '~/hooks'; +import Button from './Button'; export default function Regenerate({ onClick }: TGenButtonProps) { const localize = useLocalize(); diff --git a/client/src/components/Input/Generations/Stop.tsx b/client/src/components/Input/Generations/Stop.tsx index 8214152c4..d66baa945 100644 --- a/client/src/components/Input/Generations/Stop.tsx +++ b/client/src/components/Input/Generations/Stop.tsx @@ -1,14 +1,14 @@ +import { StopGeneratingIcon } from '@librechat/client'; import type { TGenButtonProps } from '~/common'; -import { StopGeneratingIcon } from '~/components/svg'; -import Button from './Button'; import { useLocalize } from '~/hooks'; +import Button from './Button'; export default function Stop({ onClick }: TGenButtonProps) { const localize = useLocalize(); return ( ); diff --git a/client/src/components/Input/ModelSelect/Anthropic.tsx b/client/src/components/Input/ModelSelect/Anthropic.tsx index bbe634478..38669871e 100644 --- a/client/src/components/Input/ModelSelect/Anthropic.tsx +++ b/client/src/components/Input/ModelSelect/Anthropic.tsx @@ -1,4 +1,4 @@ -import { SelectDropDown, SelectDropDownPop } from '~/components/ui'; +import { SelectDropDown, SelectDropDownPop } from '@librechat/client'; import type { TModelSelectProps } from '~/common'; import { cn, cardStyle } from '~/utils/'; diff --git a/client/src/components/Input/ModelSelect/ChatGPT.tsx b/client/src/components/Input/ModelSelect/ChatGPT.tsx index 89c884429..1405bcdbd 100644 --- a/client/src/components/Input/ModelSelect/ChatGPT.tsx +++ b/client/src/components/Input/ModelSelect/ChatGPT.tsx @@ -1,4 +1,4 @@ -import { SelectDropDown, SelectDropDownPop } from '~/components/ui'; +import { SelectDropDown, SelectDropDownPop } from '@librechat/client'; import type { TModelSelectProps } from '~/common'; import { cn, cardStyle } from '~/utils/'; diff --git a/client/src/components/Input/ModelSelect/Google.tsx b/client/src/components/Input/ModelSelect/Google.tsx index eab7f9539..eb04adc9e 100644 --- a/client/src/components/Input/ModelSelect/Google.tsx +++ b/client/src/components/Input/ModelSelect/Google.tsx @@ -1,4 +1,4 @@ -import { SelectDropDown, SelectDropDownPop } from '~/components/ui'; +import { SelectDropDown, SelectDropDownPop } from '@librechat/client'; import type { TModelSelectProps } from '~/common'; import { cn, cardStyle } from '~/utils/'; diff --git a/client/src/components/ui/MultiSelectDropDown.tsx b/client/src/components/Input/ModelSelect/MultiSelectDropDown.tsx similarity index 97% rename from client/src/components/ui/MultiSelectDropDown.tsx rename to client/src/components/Input/ModelSelect/MultiSelectDropDown.tsx index 0e2724dcf..6a1deee15 100644 --- a/client/src/components/ui/MultiSelectDropDown.tsx +++ b/client/src/components/Input/ModelSelect/MultiSelectDropDown.tsx @@ -1,4 +1,6 @@ import React, { useState, useRef } from 'react'; +import { Wrench, ArrowRight } from 'lucide-react'; +import { CheckMark, useOnClickOutside, useMultiSearch } from '@librechat/client'; import { Listbox, ListboxButton, @@ -7,12 +9,8 @@ import { ListboxOption, Transition, } from '@headlessui/react'; -import { Wrench, ArrowRight } from 'lucide-react'; -import { CheckMark } from '~/components/svg'; -import useOnClickOutside from '~/hooks/useOnClickOutside'; -import { useMultiSearch } from './MultiSearch'; -import { cn } from '~/utils/'; import type { TPlugin } from 'librechat-data-provider'; +import { cn } from '~/utils/'; export type TMultiSelectDropDownProps = { title?: string; @@ -142,7 +140,7 @@ function MultiSelectDropDown({ viewBox="0 0 24 24" strokeLinecap="round" strokeLinejoin="round" - className="h-4 w-4 text-gray-400" + className="h-4 w-4 text-gray-400" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg" diff --git a/client/src/components/ui/MultiSelectPop.tsx b/client/src/components/Input/ModelSelect/MultiSelectPop.tsx similarity index 95% rename from client/src/components/ui/MultiSelectPop.tsx rename to client/src/components/Input/ModelSelect/MultiSelectPop.tsx index 3f4377291..8421c673a 100644 --- a/client/src/components/ui/MultiSelectPop.tsx +++ b/client/src/components/Input/ModelSelect/MultiSelectPop.tsx @@ -1,8 +1,8 @@ import { Wrench } from 'lucide-react'; +import { useMultiSearch } from '@librechat/client'; import { Root, Trigger, Content, Portal } from '@radix-ui/react-popover'; import type { TPlugin } from 'librechat-data-provider'; import MenuItem from '~/components/Chat/Menus/UI/MenuItem'; -import { useMultiSearch } from './MultiSearch'; import { cn } from '~/utils/'; type SelectDropDownProps = { @@ -32,8 +32,6 @@ function MultiSelectPop({ optionValueKey = 'value', searchPlaceholder, }: SelectDropDownProps) { - // const localize = useLocalize(); - const title = _title; const excludeIds = ['select-plugin', 'plugins-label', 'selected-plugins']; @@ -54,14 +52,14 @@ function MultiSelectPop({ - -
- )} -
-
-
- setIsHovering(true)} - onMouseLeave={() => setIsHovering(false)} - className={`slider-thumb h-2 w-full appearance-none rounded-lg bg-gradient-to-r from-gray-500 to-gray-500 bg-no-repeat focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 ${ - disabled ? 'cursor-not-allowed opacity-50' : 'cursor-pointer' - }`} - tabIndex={0} - style={{ - backgroundSize: '50% 100%', - backgroundPosition: 'left', - }} - aria-valuemin={min} - aria-valuemax={max} - aria-valuenow={value} - aria-valuetext={`${value.toFixed(decimalPlaces).replace('-0.00', '0.00')}`} - disabled={disabled} - /> - {isHovering ? ( -
- {min} - {max} -
- ) : ( -
- )} -
-
- ); -}; - -export default React.memo(ModelParameters); diff --git a/client/src/components/ui/Prompt.tsx b/client/src/components/ui/Prompt.tsx deleted file mode 100644 index 3453ce436..000000000 --- a/client/src/components/ui/Prompt.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { useLocalize } from '~/hooks'; - -export default function Prompt({ title, prompt }: { title: string; prompt: string }) { - const localize = useLocalize(); - - return ( -
-

- {title} -

- - {localize('com_ui_use_prompt')} → -
- ); -} diff --git a/client/src/components/ui/Slider.tsx b/client/src/components/ui/Slider.tsx deleted file mode 100644 index 74908b4e6..000000000 --- a/client/src/components/ui/Slider.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import * as React from 'react'; -import * as SliderPrimitive from '@radix-ui/react-slider'; -import { cn } from '~/utils'; - -const Slider = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef & { onDoubleClick?: () => void } - >(({ className, onDoubleClick, ...props }, ref) => ( - - - - - - - )); -Slider.displayName = SliderPrimitive.Root.displayName; - -export { Slider }; diff --git a/client/src/components/ui/TermsAndConditionsModal.tsx b/client/src/components/ui/TermsAndConditionsModal.tsx index bdf6e8fb3..0736e422f 100644 --- a/client/src/components/ui/TermsAndConditionsModal.tsx +++ b/client/src/components/ui/TermsAndConditionsModal.tsx @@ -1,10 +1,8 @@ import { useMemo } from 'react'; +import { OGDialog, DialogTemplate, useToastContext } from '@librechat/client'; import type { TTermsOfService } from 'librechat-data-provider'; import MarkdownLite from '~/components/Chat/Messages/Content/MarkdownLite'; -import DialogTemplate from '~/components/ui/DialogTemplate'; import { useAcceptTermsMutation } from '~/data-provider'; -import { useToastContext } from '~/Providers'; -import { OGDialog } from '~/components/ui'; import { useLocalize } from '~/hooks'; const TermsAndConditionsModal = ({ @@ -73,7 +71,7 @@ const TermsAndConditionsModal = ({ main={
{ const localize = useLocalize(); diff --git a/client/src/hooks/Files/useFileHandling.ts b/client/src/hooks/Files/useFileHandling.ts index 343841776..8c8f33e57 100644 --- a/client/src/hooks/Files/useFileHandling.ts +++ b/client/src/hooks/Files/useFileHandling.ts @@ -1,5 +1,6 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { v4 } from 'uuid'; +import { useToastContext } from '@librechat/client'; import { useQueryClient } from '@tanstack/react-query'; import { QueryKeys, @@ -17,7 +18,6 @@ import { useGetFileConfig, useUploadFileMutation } from '~/data-provider'; import useLocalize, { TranslationKeys } from '~/hooks/useLocalize'; import { useDelayedUploadToast } from './useDelayedUploadToast'; import { processFileForUpload } from '~/utils/heicConverter'; -import { useToastContext } from '~/Providers/ToastContext'; import { useChatContext } from '~/Providers/ChatContext'; import { logger, validateFiles } from '~/utils'; import useClientResize from './useClientResize'; diff --git a/client/src/hooks/Input/index.ts b/client/src/hooks/Input/index.ts index bfc40ebb3..dc959e357 100644 --- a/client/src/hooks/Input/index.ts +++ b/client/src/hooks/Input/index.ts @@ -2,7 +2,6 @@ export * from './useAutoSave'; export { default as useUserKey } from './useUserKey'; export { default as useDebounce } from './useDebounce'; export { default as useTextarea } from './useTextarea'; -export { default as useCombobox } from './useCombobox'; export { default as useQueryParams } from './useQueryParams'; export { default as useHandleKeyUp } from './useHandleKeyUp'; export { default as useRequiresKey } from './useRequiresKey'; diff --git a/client/src/hooks/Input/useSpeechToTextBrowser.ts b/client/src/hooks/Input/useSpeechToTextBrowser.ts index 1d31c3348..d4c301367 100644 --- a/client/src/hooks/Input/useSpeechToTextBrowser.ts +++ b/client/src/hooks/Input/useSpeechToTextBrowser.ts @@ -1,8 +1,8 @@ import { useEffect, useRef, useMemo } from 'react'; import { useRecoilState } from 'recoil'; +import { useToastContext } from '@librechat/client'; import SpeechRecognition, { useSpeechRecognition } from 'react-speech-recognition'; import useGetAudioSettings from './useGetAudioSettings'; -import { useToastContext } from '~/Providers'; import store from '~/store'; const useSpeechToTextBrowser = ( diff --git a/client/src/hooks/Input/useSpeechToTextExternal.ts b/client/src/hooks/Input/useSpeechToTextExternal.ts index 3160696e9..6571a0911 100644 --- a/client/src/hooks/Input/useSpeechToTextExternal.ts +++ b/client/src/hooks/Input/useSpeechToTextExternal.ts @@ -1,8 +1,8 @@ import { useState, useEffect, useRef } from 'react'; import { useRecoilState } from 'recoil'; +import { useToastContext } from '@librechat/client'; import { useSpeechToTextMutation } from '~/data-provider'; import useGetAudioSettings from './useGetAudioSettings'; -import { useToastContext } from '~/Providers'; import store from '~/store'; const useSpeechToTextExternal = ( @@ -107,7 +107,7 @@ const useSpeechToTextExternal = ( }); setPermission(true); audioStream.current = streamData ?? null; - } catch (err) { + } catch { setPermission(false); } }; @@ -268,6 +268,7 @@ const useSpeechToTextExternal = ( return () => { window.removeEventListener('keydown', handleKeyDown); }; + // eslint-disable-next-line react-hooks/exhaustive-deps }, [isListening]); return { diff --git a/client/src/hooks/Input/useTextToSpeechExternal.ts b/client/src/hooks/Input/useTextToSpeechExternal.ts index cf8edb038..99c1a2344 100644 --- a/client/src/hooks/Input/useTextToSpeechExternal.ts +++ b/client/src/hooks/Input/useTextToSpeechExternal.ts @@ -1,8 +1,8 @@ -import { useRecoilValue } from 'recoil'; import { useState, useMemo, useRef, useCallback, useEffect } from 'react'; +import { useRecoilValue } from 'recoil'; +import { useToastContext } from '@librechat/client'; import { useTextToSpeechMutation, useVoicesQuery } from '~/data-provider'; -import { useToastContext } from '~/Providers/ToastContext'; -import useLocalize from '~/hooks/useLocalize'; +import { useLocalize } from '~/hooks'; import store from '~/store'; const createFormData = (text: string, voice: string) => { diff --git a/client/src/hooks/Input/useTextarea.ts b/client/src/hooks/Input/useTextarea.ts index 7a0711e7a..7d32cbbe0 100644 --- a/client/src/hooks/Input/useTextarea.ts +++ b/client/src/hooks/Input/useTextarea.ts @@ -16,8 +16,8 @@ import useGetSender from '~/hooks/Conversations/useGetSender'; import useFileHandling from '~/hooks/Files/useFileHandling'; import { useInteractionHealthCheck } from '~/data-provider'; import { useChatContext } from '~/Providers/ChatContext'; -import useLocalize from '~/hooks/useLocalize'; import { globalAudioId } from '~/common'; +import { useLocalize } from '~/hooks'; import store from '~/store'; type KeyEvent = KeyboardEvent; diff --git a/client/src/hooks/MCP/useMCPServerInitialization.ts b/client/src/hooks/MCP/useMCPServerInitialization.ts index ec5ab2cc0..8a73c7d49 100644 --- a/client/src/hooks/MCP/useMCPServerInitialization.ts +++ b/client/src/hooks/MCP/useMCPServerInitialization.ts @@ -1,12 +1,12 @@ import { useCallback, useState, useEffect, useMemo } from 'react'; -import { useQueryClient } from '@tanstack/react-query'; +import { useToastContext } from '@librechat/client'; import { QueryKeys } from 'librechat-data-provider'; +import { useQueryClient } from '@tanstack/react-query'; import { useReinitializeMCPServerMutation, useCancelMCPOAuthMutation, } from 'librechat-data-provider/react-query'; import { useMCPConnectionStatusQuery } from '~/data-provider/Tools/queries'; -import { useToastContext } from '~/Providers'; import { useLocalize } from '~/hooks'; import { logger } from '~/utils'; diff --git a/client/src/hooks/MCP/useMCPServerManager.ts b/client/src/hooks/MCP/useMCPServerManager.ts index 95891b47e..a7d2c7c98 100644 --- a/client/src/hooks/MCP/useMCPServerManager.ts +++ b/client/src/hooks/MCP/useMCPServerManager.ts @@ -1,12 +1,12 @@ +import { useCallback, useState, useMemo, useRef } from 'react'; +import { useToastContext } from '@librechat/client'; import { useQueryClient } from '@tanstack/react-query'; import { Constants, QueryKeys } from 'librechat-data-provider'; -import { useCallback, useState, useMemo, useRef } from 'react'; import { useUpdateUserPluginsMutation } from 'librechat-data-provider/react-query'; -import { useMCPServerInitialization } from '~/hooks/MCP/useMCPServerInitialization'; -import type { ConfigFieldDetail } from '~/components/ui/MCP/MCPConfigDialog'; import type { TUpdateUserPlugins, TPlugin } from 'librechat-data-provider'; -import { useToastContext, useBadgeRowContext } from '~/Providers'; -import { useLocalize } from '~/hooks'; +import type { ConfigFieldDetail } from '~/components/MCP/MCPConfigDialog'; +import { useLocalize, useMCPServerInitialization } from '~/hooks'; +import { useBadgeRowContext } from '~/Providers'; export function useMCPServerManager() { const localize = useLocalize(); diff --git a/client/src/hooks/Nav/useSideNavLinks.ts b/client/src/hooks/Nav/useSideNavLinks.ts index 728b85673..734541521 100644 --- a/client/src/hooks/Nav/useSideNavLinks.ts +++ b/client/src/hooks/Nav/useSideNavLinks.ts @@ -1,4 +1,5 @@ import { useMemo } from 'react'; +import { Blocks, MCPIcon, AttachmentIcon } from '@librechat/client'; import { MessageSquareQuote, ArrowRightToLine, Settings2, Database, Bookmark } from 'lucide-react'; import { isAssistantsEndpoint, @@ -15,7 +16,6 @@ import BookmarkPanel from '~/components/SidePanel/Bookmarks/BookmarkPanel'; import MemoryViewer from '~/components/SidePanel/Memories/MemoryViewer'; import PanelSwitch from '~/components/SidePanel/Builder/PanelSwitch'; import PromptsAccordion from '~/components/Prompts/PromptsAccordion'; -import { Blocks, MCPIcon, AttachmentIcon } from '~/components/svg'; import Parameters from '~/components/SidePanel/Parameters/Panel'; import FilesPanel from '~/components/SidePanel/Files/Panel'; import MCPPanel from '~/components/SidePanel/MCP/MCPPanel'; diff --git a/client/src/hooks/Plugins/useAuthCodeTool.ts b/client/src/hooks/Plugins/useAuthCodeTool.ts index b33e05c16..f523fd01e 100644 --- a/client/src/hooks/Plugins/useAuthCodeTool.ts +++ b/client/src/hooks/Plugins/useAuthCodeTool.ts @@ -2,10 +2,8 @@ import { useCallback } from 'react'; import { useQueryClient } from '@tanstack/react-query'; import { AuthType, Tools, QueryKeys } from 'librechat-data-provider'; import { useUpdateUserPluginsMutation } from 'librechat-data-provider/react-query'; -// import { useToastContext } from '~/Providers'; const useAuthCodeTool = (options?: { isEntityTool: boolean }) => { - // const { showToast } = useToastContext(); const queryClient = useQueryClient(); const isEntityTool = options?.isEntityTool ?? true; const updateUserPlugins = useUpdateUserPluginsMutation({ diff --git a/client/src/hooks/Prompts/useCategories.tsx b/client/src/hooks/Prompts/useCategories.tsx index a5083f8ed..b4611e8dc 100644 --- a/client/src/hooks/Prompts/useCategories.tsx +++ b/client/src/hooks/Prompts/useCategories.tsx @@ -1,6 +1,6 @@ import { useGetCategories } from '~/data-provider'; import CategoryIcon from '~/components/Prompts/Groups/CategoryIcon'; -import useLocalize, { TranslationKeys } from '~/hooks/useLocalize'; +import { useLocalize, TranslationKeys } from '~/hooks'; const loadingCategories: { label: TranslationKeys; value: string }[] = [ { diff --git a/client/src/hooks/ScreenshotContext.tsx b/client/src/hooks/ScreenshotContext.tsx index 2f9069c5f..435327e57 100644 --- a/client/src/hooks/ScreenshotContext.tsx +++ b/client/src/hooks/ScreenshotContext.tsx @@ -1,6 +1,6 @@ import { createContext, useRef, useContext, RefObject } from 'react'; import { toCanvas } from 'html-to-image'; -import { ThemeContext } from '~/hooks/ThemeContext'; +import { ThemeContext } from '@librechat/client'; type ScreenshotContextType = { ref?: RefObject; diff --git a/client/src/hooks/index.ts b/client/src/hooks/index.ts index 83cdb7fbc..92fd39e37 100644 --- a/client/src/hooks/index.ts +++ b/client/src/hooks/index.ts @@ -8,30 +8,26 @@ export * from './Nav'; export * from './Files'; export * from './Generic'; export * from './Input'; +export * from './MCP'; export * from './Messages'; export * from './Plugins'; export * from './Prompts'; export * from './Roles'; export * from './SSE'; export * from './AuthContext'; -export * from './ThemeContext'; export * from './ScreenshotContext'; export * from './ApiErrorBoundaryContext'; export * from './Endpoint'; export type { TranslationKeys } from './useLocalize'; -export { default as useToast } from './useToast'; export { default as useTimeout } from './useTimeout'; export { default as useNewConvo } from './useNewConvo'; export { default as useLocalize } from './useLocalize'; -export { default as useMediaQuery } from './useMediaQuery'; export { default as useChatBadges } from './useChatBadges'; export { default as useScrollToRef } from './useScrollToRef'; export { default as useLocalStorage } from './useLocalStorage'; export { default as useDocumentTitle } from './useDocumentTitle'; -export { default as useDelayedRender } from './useDelayedRender'; -export { default as useOnClickOutside } from './useOnClickOutside'; export { default as useSpeechToText } from './Input/useSpeechToText'; export { default as useTextToSpeech } from './Input/useTextToSpeech'; export { default as useGenerationsByLatest } from './useGenerationsByLatest'; diff --git a/client/src/locales/Translation.spec.ts b/client/src/locales/Translation.spec.ts index 89c7b1d7b..6c6e1b7ac 100644 --- a/client/src/locales/Translation.spec.ts +++ b/client/src/locales/Translation.spec.ts @@ -1,9 +1,8 @@ -// Translation.spec.ts - import i18n from './i18n'; import English from './en/translation.json'; import French from './fr/translation.json'; import Spanish from './es/translation.json'; +import { TranslationKeys } from '~/hooks'; describe('i18next translation tests', () => { // Ensure i18next is initialized before any tests run @@ -36,7 +35,7 @@ describe('i18next translation tests', () => { it('should return the key itself for an invalid key', () => { i18n.changeLanguage('en'); - expect(i18n.t('invalid-key')).toBe('invalid-key'); // Returns the key itself + expect(i18n.t('invalid-key' as TranslationKeys)).toBe('invalid-key'); // Returns the key itself }); it('should correctly format placeholders in the translation', () => { @@ -46,4 +45,4 @@ describe('i18next translation tests', () => { i18n.changeLanguage('fr'); expect(i18n.t('com_endpoint_default_with_num', { 0: 'Marie' })).toBe('par défaut : Marie'); }); -}); \ No newline at end of file +}); diff --git a/client/src/locales/en/translation.json b/client/src/locales/en/translation.json index 95aa05fee..444f869dd 100644 --- a/client/src/locales/en/translation.json +++ b/client/src/locales/en/translation.json @@ -1072,7 +1072,6 @@ "com_ui_use_backup_code": "Use Backup Code Instead", "com_ui_use_memory": "Use memory", "com_ui_use_micrphone": "Use microphone", - "com_ui_use_prompt": "Use prompt", "com_ui_used": "Used", "com_ui_value": "Value", "com_ui_variables": "Variables", @@ -1110,4 +1109,4 @@ "com_ui_yes": "Yes", "com_ui_zoom": "Zoom", "com_user_message": "You" -} \ No newline at end of file +} diff --git a/client/src/routes/ChatRoute.tsx b/client/src/routes/ChatRoute.tsx index 77c6d7397..d81cbc075 100644 --- a/client/src/routes/ChatRoute.tsx +++ b/client/src/routes/ChatRoute.tsx @@ -1,4 +1,5 @@ import { useEffect } from 'react'; +import { Spinner } from '@librechat/client'; import { useParams } from 'react-router-dom'; import { Constants, EModelEndpoint } from 'librechat-data-provider'; import { useGetModelsQuery } from 'librechat-data-provider/react-query'; @@ -10,7 +11,6 @@ import { ToolCallsMapProvider } from '~/Providers'; import ChatView from '~/components/Chat/ChatView'; import useAuthRedirect from './useAuthRedirect'; import temporaryStore from '~/store/temporary'; -import { Spinner } from '~/components/svg'; import { useRecoilCallback } from 'recoil'; import store from '~/store'; diff --git a/client/src/routes/Layouts/DashBreadcrumb.tsx b/client/src/routes/Layouts/DashBreadcrumb.tsx index 0138e63ab..c6db3a18b 100644 --- a/client/src/routes/Layouts/DashBreadcrumb.tsx +++ b/client/src/routes/Layouts/DashBreadcrumb.tsx @@ -14,7 +14,7 @@ import { // DropdownMenuItem, // DropdownMenuContent, // DropdownMenuTrigger, -} from '~/components/ui'; +} from '@librechat/client'; import { useLocalize, useCustomLink, useAuthContext } from '~/hooks'; import AdvancedSwitch from '~/components/Prompts/AdvancedSwitch'; // import { RightPanel } from '../../components/Prompts/RightPanel'; diff --git a/client/src/routes/Root.tsx b/client/src/routes/Root.tsx index 42ef88c34..bede0ba54 100644 --- a/client/src/routes/Root.tsx +++ b/client/src/routes/Root.tsx @@ -14,8 +14,8 @@ import { FileMapContext, SetConvoProvider, } from '~/Providers'; -import TermsAndConditionsModal from '~/components/ui/TermsAndConditionsModal'; import { useUserTermsQuery, useGetStartupConfig } from '~/data-provider'; +import { TermsAndConditionsModal } from '~/components/ui'; import { Nav, MobileNav } from '~/components/Nav'; import { useHealthCheck } from '~/data-provider'; import { Banner } from '~/components/Banners'; diff --git a/client/src/routes/RouteErrorBoundary.tsx b/client/src/routes/RouteErrorBoundary.tsx index 6221ab25b..f112e29d7 100644 --- a/client/src/routes/RouteErrorBoundary.tsx +++ b/client/src/routes/RouteErrorBoundary.tsx @@ -1,5 +1,6 @@ +/* eslint-disable i18next/no-literal-string */ +import { Button } from '@librechat/client'; import { useRouteError } from 'react-router-dom'; -import { Button } from '~/components/ui'; import logger from '~/utils/logger'; interface UserAgentData { diff --git a/client/src/routes/Search.tsx b/client/src/routes/Search.tsx index 9508806df..f7992745c 100644 --- a/client/src/routes/Search.tsx +++ b/client/src/routes/Search.tsx @@ -1,11 +1,11 @@ import { useEffect, useMemo } from 'react'; import { useRecoilValue } from 'recoil'; +import { Spinner, useToastContext } from '@librechat/client'; import MinimalMessagesWrapper from '~/components/Chat/Messages/MinimalMessages'; import { useNavScrolling, useLocalize, useAuthContext } from '~/hooks'; import SearchMessage from '~/components/Chat/Messages/SearchMessage'; -import { useToastContext, useFileMapContext } from '~/Providers'; import { useMessagesInfiniteQuery } from '~/data-provider'; -import { Spinner } from '~/components'; +import { useFileMapContext } from '~/Providers'; import { buildTree } from '~/utils'; import store from '~/store'; @@ -23,7 +23,7 @@ export default function Search() { isError, fetchNextPage, isFetchingNextPage, - hasNextPage, + hasNextPage: _hasNextPage, } = useMessagesInfiniteQuery( { search: searchQuery || undefined, diff --git a/client/src/style.css b/client/src/style.css index 4139dfd04..d401bf5a1 100644 --- a/client/src/style.css +++ b/client/src/style.css @@ -51,6 +51,7 @@ --amber-800: #92400e; --amber-900: #78350f; --amber-950: #451a03; + --brand-purple: #ab68ff; --gizmo-gray-500: #999; --gizmo-gray-600: #666; --gizmo-gray-950: #0f0f0f; @@ -61,6 +62,7 @@ --font-size-xl: 1.25rem; } html { + --brand-purple: #ab68ff; --presentation: var(--white); --text-primary: var(--gray-800); --text-secondary: var(--gray-600); @@ -121,6 +123,7 @@ html { --switch-unchecked: 0 0% 58%; } .dark { + --brand-purple: #ab68ff; --presentation: var(--gray-800); --text-primary: var(--gray-100); --text-secondary: var(--gray-300); diff --git a/client/src/utils/files.ts b/client/src/utils/files.ts index 3ca07e51d..e98909012 100644 --- a/client/src/utils/files.ts +++ b/client/src/utils/files.ts @@ -1,3 +1,4 @@ +import { SheetPaths, TextPaths, FilePaths, CodePaths } from '~/components/svg'; import { megabyte, QueryKeys, @@ -8,10 +9,6 @@ import { import type { TFile, EndpointFileConfig } from 'librechat-data-provider'; import type { QueryClient } from '@tanstack/react-query'; import type { ExtendedFile } from '~/common'; -import SheetPaths from '~/components/svg/Files/SheetPaths'; -import TextPaths from '~/components/svg/Files/TextPaths'; -import FilePaths from '~/components/svg/Files/FilePaths'; -import CodePaths from '~/components/svg/Files/CodePaths'; export const partialTypes = ['text/x-']; diff --git a/client/src/utils/getThemeFromEnv.js b/client/src/utils/getThemeFromEnv.js new file mode 100644 index 000000000..b294d799a --- /dev/null +++ b/client/src/utils/getThemeFromEnv.js @@ -0,0 +1,58 @@ +/** + * Loads theme configuration from environment variables + * @returns {import('@librechat/client').IThemeRGB | undefined} + */ +export function getThemeFromEnv() { + // Check if any theme environment variables are set + const hasThemeEnvVars = Object.keys(process.env).some((key) => + key.startsWith('REACT_APP_THEME_'), + ); + + if (!hasThemeEnvVars) { + return undefined; // Use default themes + } + + // Build theme object from environment variables + const theme = {}; + + // Helper to get env value with prefix + const getEnv = (key) => process.env[`REACT_APP_THEME_${key}`]; + + // Text colors + if (getEnv('TEXT_PRIMARY')) theme['rgb-text-primary'] = getEnv('TEXT_PRIMARY'); + if (getEnv('TEXT_SECONDARY')) theme['rgb-text-secondary'] = getEnv('TEXT_SECONDARY'); + if (getEnv('TEXT_TERTIARY')) theme['rgb-text-tertiary'] = getEnv('TEXT_TERTIARY'); + if (getEnv('TEXT_WARNING')) theme['rgb-text-warning'] = getEnv('TEXT_WARNING'); + + // Surface colors + if (getEnv('SURFACE_PRIMARY')) theme['rgb-surface-primary'] = getEnv('SURFACE_PRIMARY'); + if (getEnv('SURFACE_SECONDARY')) theme['rgb-surface-secondary'] = getEnv('SURFACE_SECONDARY'); + if (getEnv('SURFACE_TERTIARY')) theme['rgb-surface-tertiary'] = getEnv('SURFACE_TERTIARY'); + if (getEnv('SURFACE_SUBMIT')) theme['rgb-surface-submit'] = getEnv('SURFACE_SUBMIT'); + if (getEnv('SURFACE_SUBMIT_HOVER')) + theme['rgb-surface-submit-hover'] = getEnv('SURFACE_SUBMIT_HOVER'); + if (getEnv('SURFACE_DESTRUCTIVE')) + theme['rgb-surface-destructive'] = getEnv('SURFACE_DESTRUCTIVE'); + if (getEnv('SURFACE_DESTRUCTIVE_HOVER')) + theme['rgb-surface-destructive-hover'] = getEnv('SURFACE_DESTRUCTIVE_HOVER'); + if (getEnv('SURFACE_DIALOG')) theme['rgb-surface-dialog'] = getEnv('SURFACE_DIALOG'); + if (getEnv('SURFACE_CHAT')) theme['rgb-surface-chat'] = getEnv('SURFACE_CHAT'); + + // Border colors + if (getEnv('BORDER_LIGHT')) theme['rgb-border-light'] = getEnv('BORDER_LIGHT'); + if (getEnv('BORDER_MEDIUM')) theme['rgb-border-medium'] = getEnv('BORDER_MEDIUM'); + if (getEnv('BORDER_HEAVY')) theme['rgb-border-heavy'] = getEnv('BORDER_HEAVY'); + if (getEnv('BORDER_XHEAVY')) theme['rgb-border-xheavy'] = getEnv('BORDER_XHEAVY'); + + // Brand colors + if (getEnv('BRAND_PURPLE')) theme['rgb-brand-purple'] = getEnv('BRAND_PURPLE'); + + // Header colors + if (getEnv('HEADER_PRIMARY')) theme['rgb-header-primary'] = getEnv('HEADER_PRIMARY'); + if (getEnv('HEADER_HOVER')) theme['rgb-header-hover'] = getEnv('HEADER_HOVER'); + + // Presentation + if (getEnv('PRESENTATION')) theme['rgb-presentation'] = getEnv('PRESENTATION'); + + return Object.keys(theme).length > 0 ? theme : undefined; +} diff --git a/client/src/utils/index.ts b/client/src/utils/index.ts index 82bf1f8a4..b86676a48 100644 --- a/client/src/utils/index.ts +++ b/client/src/utils/index.ts @@ -4,7 +4,6 @@ export * from './map'; export * from './json'; export * from './files'; export * from './latex'; -export * from './theme'; export * from './forms'; export * from './drafts'; export * from './convos'; @@ -25,6 +24,7 @@ export { default as cleanupPreset } from './cleanupPreset'; export { default as buildDefaultConvo } from './buildDefaultConvo'; export { default as getDefaultEndpoint } from './getDefaultEndpoint'; export { default as createChatSearchParams } from './createChatSearchParams'; +export { getThemeFromEnv } from './getThemeFromEnv'; export const languages = [ 'java', diff --git a/client/tailwind.config.cjs b/client/tailwind.config.cjs index f114a8733..e2f493ad6 100644 --- a/client/tailwind.config.cjs +++ b/client/tailwind.config.cjs @@ -2,7 +2,11 @@ /** @type {import('tailwindcss').Config} */ module.exports = { - content: ['./src/**/*.{js,jsx,ts,tsx}'], + content: [ + './src/**/*.{js,jsx,ts,tsx}', + // Include component library files + '../packages/client/src/**/*.{js,jsx,ts,tsx}', + ], // darkMode: 'class', darkMode: ['class'], theme: { @@ -61,8 +65,8 @@ module.exports = { 800: '#06373e', 900: '#031f29', }, - 'brand-purple': '#ab68ff', - 'presentation': 'var(--presentation)', + 'brand-purple': 'var(--brand-purple)', + presentation: 'var(--presentation)', 'text-primary': 'var(--text-primary)', 'text-secondary': 'var(--text-secondary)', 'text-secondary-alt': 'var(--text-secondary-alt)', @@ -135,7 +139,7 @@ module.exports = { }, plugins: [ require('tailwindcss-animate'), - require('tailwindcss-radix')(), + require('tailwindcss-radix'), // require('@tailwindcss/typography'), ], }; diff --git a/client/test/setupTests.js b/client/test/setupTests.js index 043c7cdf6..c489fc8b5 100644 --- a/client/test/setupTests.js +++ b/client/test/setupTests.js @@ -20,6 +20,21 @@ import 'jest-canvas-mock'; // Mock ResizeObserver import './resizeObserver.mock'; +// Mock window.matchMedia +Object.defineProperty(window, 'matchMedia', { + writable: true, + value: jest.fn().mockImplementation((query) => ({ + matches: false, + media: query, + onchange: null, + addListener: jest.fn(), // deprecated + removeListener: jest.fn(), // deprecated + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + dispatchEvent: jest.fn(), + })), +}); + beforeEach(() => { jest.clearAllMocks(); }); diff --git a/client/tsconfig.json b/client/tsconfig.json index ba00b0d24..59ea7f46c 100644 --- a/client/tsconfig.json +++ b/client/tsconfig.json @@ -35,5 +35,5 @@ "test/setupTests.js", "env.d.ts", "../config/translations/**/*.ts" - ] +, "../packages/client/src/hooks/useDelayedRender.tsx" ] } diff --git a/config/update.js b/config/update.js index e0dba111e..d6ffd5590 100644 --- a/config/update.js +++ b/config/update.js @@ -19,6 +19,7 @@ const directories = [ rootDir, path.resolve(rootDir, 'packages', 'data-provider'), path.resolve(rootDir, 'packages', 'data-schemas'), + path.resolve(rootDir, 'packages', 'client'), path.resolve(rootDir, 'packages', 'api'), path.resolve(rootDir, 'client'), path.resolve(rootDir, 'api'), diff --git a/package-lock.json b/package-lock.json index 97df522f4..9cef1c664 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2744,6 +2744,7 @@ "@dicebear/collection": "^9.2.2", "@dicebear/core": "^9.2.2", "@headlessui/react": "^2.1.2", + "@librechat/client": "*", "@marsidev/react-turnstile": "^1.1.0", "@radix-ui/react-accordion": "^1.1.2", "@radix-ui/react-alert-dialog": "^1.0.2", @@ -2766,8 +2767,8 @@ "@react-spring/web": "^9.7.5", "@tanstack/react-query": "^4.28.0", "@tanstack/react-table": "^8.11.7", - "class-variance-authority": "^0.6.0", - "clsx": "^1.2.1", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", "copy-to-clipboard": "^3.3.3", "cross-env": "^7.0.3", "date-fns": "^3.3.1", @@ -2780,11 +2781,12 @@ "i18next": "^24.2.2", "i18next-browser-languagedetector": "^8.0.3", "input-otp": "^1.4.2", + "jotai": "^2.12.5", "js-cookie": "^3.0.5", "librechat-data-provider": "*", "lodash": "^4.17.21", "lucide-react": "^0.394.0", - "match-sorter": "^6.3.4", + "match-sorter": "^8.1.0", "micromark-extension-llm-math": "^3.1.0", "qrcode.react": "^4.2.0", "rc-input-number": "^7.4.2", @@ -2860,58 +2862,6 @@ "vite-plugin-pwa": "^0.21.2" } }, - "client/node_modules/@ariakit/react": { - "version": "0.4.15", - "resolved": "https://registry.npmjs.org/@ariakit/react/-/react-0.4.15.tgz", - "integrity": "sha512-0V2LkNPFrGRT+SEIiObx/LQjR6v3rR+mKEDUu/3tq7jfCZ+7+6Q6EMR1rFaK+XMkaRY1RWUcj/rRDWAUWnsDww==", - "dependencies": { - "@ariakit/react-core": "0.4.15" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/ariakit" - }, - "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": { - "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", @@ -4612,6 +4562,22 @@ "@dicebear/core": "^9.0.0" } }, + "client/node_modules/@react-spring/web": { + "version": "9.7.5", + "resolved": "https://registry.npmjs.org/@react-spring/web/-/web-9.7.5.tgz", + "integrity": "sha512-lmvqGwpe+CSttsWNZVr+Dg62adtKhauGwLyGE/RRyZ8AAMLgb9x3NDMA5RMElXo+IMyTkPp7nxTB8ZQlmhb6JQ==", + "license": "MIT", + "dependencies": { + "@react-spring/animated": "~9.7.5", + "@react-spring/core": "~9.7.5", + "@react-spring/shared": "~9.7.5", + "@react-spring/types": "~9.7.5" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "client/node_modules/@types/jest": { "version": "29.5.14", "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.14.tgz", @@ -4811,6 +4777,33 @@ "node": ">=6" } }, + "client/node_modules/framer-motion": { + "version": "11.18.2", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-11.18.2.tgz", + "integrity": "sha512-5F5Och7wrvtLVElIpclDT0CBzMVg3dL22B64aZwHtsIY8RB4mXICLrkajK4G9R+ieSAGcgrLeae2SeUTg2pr6w==", + "license": "MIT", + "dependencies": { + "motion-dom": "^11.18.1", + "motion-utils": "^11.18.1", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@emotion/is-prop-valid": "*", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/is-prop-valid": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, "client/node_modules/globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -4821,6 +4814,15 @@ "node": ">=4" } }, + "client/node_modules/lucide-react": { + "version": "0.394.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.394.0.tgz", + "integrity": "sha512-PzTbJ0bsyXRhH59k5qe7MpTd5MxlpYZUcM9kGSwvPGAfnn0J6FElDwu2EX6Vuh//F7y60rcVJiFQ7EK9DCMgfw==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0" + } + }, "client/node_modules/node-releases": { "version": "2.0.19", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", @@ -4843,16 +4845,6 @@ "node": ">=0.10.0" } }, - "client/node_modules/react-resizable-panels": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/react-resizable-panels/-/react-resizable-panels-3.0.2.tgz", - "integrity": "sha512-j4RNII75fnHkLnbsTb5G5YsDvJsSEZrJK2XSF2z0Tc2jIonYlIVir/Yh/5LvcUFCfs1HqrMAoiBFmIrRjC4XnA==", - "license": "MIT", - "peerDependencies": { - "react": "^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc", - "react-dom": "^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" - } - }, "client/node_modules/ts-jest": { "version": "29.2.5", "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.2.5.tgz", @@ -5027,9 +5019,42 @@ } }, "node_modules/@ariakit/core": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/@ariakit/core/-/core-0.4.14.tgz", - "integrity": "sha512-hpzZvyYzGhP09S9jW1XGsU/FD5K3BKsH1eG/QJ8rfgEeUdPS7BvHPt5lHbOeJ2cMrRzBEvsEzLi1ivfDifHsVA==" + "version": "0.4.15", + "resolved": "https://registry.npmjs.org/@ariakit/core/-/core-0.4.15.tgz", + "integrity": "sha512-vvxmZvkNhiisKM+Y1TbGMUfVVchV/sWu9F0xw0RYADXcimWPK31dd9JnIZs/OQ5pwAryAHmERHwuGQVESkSjwQ==", + "license": "MIT" + }, + "node_modules/@ariakit/react": { + "version": "0.4.17", + "resolved": "https://registry.npmjs.org/@ariakit/react/-/react-0.4.17.tgz", + "integrity": "sha512-HQaIboE2axtlncJz1hRTaiQfJ1GGjhdtNcAnPwdjvl2RybfmlHowIB+HTVBp36LzroKPs/M4hPCxk7XTaqRZGg==", + "license": "MIT", + "dependencies": { + "@ariakit/react-core": "0.4.17" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/ariakit" + }, + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "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" + } }, "node_modules/@aws-crypto/crc32": { "version": "3.0.0", @@ -17750,6 +17775,25 @@ "tslib": "^2.4.0" } }, + "node_modules/@emotion/is-prop-valid": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz", + "integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@emotion/memoize": "0.7.4" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz", + "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==", + "license": "MIT", + "optional": true, + "peer": true + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.1.tgz", @@ -19028,21 +19072,23 @@ } }, "node_modules/@headlessui/react": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-2.1.2.tgz", - "integrity": "sha512-Kb3hgk9gRNRcTZktBrKdHhF3xFhYkca1Rk6e1/im2ENf83dgN54orMW0uSKTXFnUpZOUFZ+wcY05LlipwgZIFQ==", + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-2.2.4.tgz", + "integrity": "sha512-lz+OGcAH1dK93rgSMzXmm1qKOJkBUqZf1L4M8TWLNplftQD3IkoEDdUFNfAn4ylsN6WOTVtWaLmvmaHOUk1dTA==", + "license": "MIT", "dependencies": { "@floating-ui/react": "^0.26.16", - "@react-aria/focus": "^3.17.1", - "@react-aria/interactions": "^3.21.3", - "@tanstack/react-virtual": "^3.8.1" + "@react-aria/focus": "^3.20.2", + "@react-aria/interactions": "^3.25.0", + "@tanstack/react-virtual": "^3.13.9", + "use-sync-external-store": "^1.5.0" }, "engines": { "node": ">=10" }, "peerDependencies": { - "react": "^18", - "react-dom": "^18" + "react": "^18 || ^19 || ^19.0.0-rc", + "react-dom": "^18 || ^19 || ^19.0.0-rc" } }, "node_modules/@humanfs/core": { @@ -22143,6 +22189,10 @@ "resolved": "api", "link": true }, + "node_modules/@librechat/client": { + "resolved": "packages/client", + "link": true + }, "node_modules/@librechat/data-schemas": { "resolved": "packages/data-schemas", "link": true @@ -22872,12 +22922,10 @@ "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" }, "node_modules/@radix-ui/number": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.0.1.tgz", - "integrity": "sha512-T5gIdVO2mmPW3NNhjNgEP3cqMXjXL9UbO0BzWcXfvdBs+BohbQxvd/K5hSVKmn9/lbTdsQVKbUcP5WLCwvUbBg==", - "dependencies": { - "@babel/runtime": "^7.13.10" - } + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz", + "integrity": "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==", + "license": "MIT" }, "node_modules/@radix-ui/primitive": { "version": "1.0.1", @@ -22888,26 +22936,26 @@ } }, "node_modules/@radix-ui/react-accordion": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-accordion/-/react-accordion-1.1.2.tgz", - "integrity": "sha512-fDG7jcoNKVjSK6yfmuAs0EnPDro0WMXIhMtXdTBWqEioVW206ku+4Lw07e+13lUkFkpoEQ2PdeMIAGpdqEAmDg==", + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-accordion/-/react-accordion-1.2.11.tgz", + "integrity": "sha512-l3W5D54emV2ues7jjeG1xcyN7S3jnK3zE2zHqgn0CmMsy9lNJwmgcrmaxS+7ipw15FAivzKNzH3d5EcGoFKw0A==", + "license": "MIT", "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/primitive": "1.0.1", - "@radix-ui/react-collapsible": "1.0.3", - "@radix-ui/react-collection": "1.0.3", - "@radix-ui/react-compose-refs": "1.0.1", - "@radix-ui/react-context": "1.0.1", - "@radix-ui/react-direction": "1.0.1", - "@radix-ui/react-id": "1.0.1", - "@radix-ui/react-primitive": "1.0.3", - "@radix-ui/react-use-controllable-state": "1.0.1" + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-collapsible": "1.1.11", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { @@ -22918,6 +22966,176 @@ } } }, + "node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/primitive": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.2.tgz", + "integrity": "sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/react-collection": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz", + "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", + "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/react-direction": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz", + "integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/react-id": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz", + "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", + "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", + "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-alert-dialog": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/@radix-ui/react-alert-dialog/-/react-alert-dialog-1.0.5.tgz", @@ -23000,25 +23218,25 @@ } }, "node_modules/@radix-ui/react-collapsible": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.0.3.tgz", - "integrity": "sha512-UBmVDkmR6IvDsloHVN+3rtx4Mi5TFvylYXpluuv0f37dtaz3H99bp8No0LGXRigVpl3UAT4l9j6bIchh42S/Gg==", + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.11.tgz", + "integrity": "sha512-2qrRsVGSCYasSz1RFOorXwl0H7g7J1frQtgpQgYrt+MOidtPAINHn9CPovQXb83r8ahapdx3Tu0fa/pdFFSdPg==", + "license": "MIT", "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/primitive": "1.0.1", - "@radix-ui/react-compose-refs": "1.0.1", - "@radix-ui/react-context": "1.0.1", - "@radix-ui/react-id": "1.0.1", - "@radix-ui/react-presence": "1.0.1", - "@radix-ui/react-primitive": "1.0.3", - "@radix-ui/react-use-controllable-state": "1.0.1", - "@radix-ui/react-use-layout-effect": "1.0.1" + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-presence": "1.1.4", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { @@ -23029,6 +23247,159 @@ } } }, + "node_modules/@radix-ui/react-collapsible/node_modules/@radix-ui/primitive": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.2.tgz", + "integrity": "sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-collapsible/node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", + "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collapsible/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collapsible/node_modules/@radix-ui/react-id": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz", + "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collapsible/node_modules/@radix-ui/react-presence": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.4.tgz", + "integrity": "sha512-ueDqRbdc4/bkaQT3GIpLQssRlFgWaL/U2z/S31qRwwLWoxHLgry3SIfCwhxeQNbirEUXFa+lq3RL3oBYXtcmIA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collapsible/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collapsible/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collapsible/node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", + "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collapsible/node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", + "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-collection": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.0.3.tgz", @@ -23441,18 +23812,18 @@ } }, "node_modules/@radix-ui/react-label": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.0.2.tgz", - "integrity": "sha512-N5ehvlM7qoTLx7nWPodsPYPgMzA5WM8zZChQg8nyFJKnDO5WHdba1vv5/H6IO5LtJMfD2Q3wh1qHFGNtK0w3bQ==", + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.7.tgz", + "integrity": "sha512-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ==", + "license": "MIT", "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-primitive": "1.0.3" + "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { @@ -23463,6 +23834,62 @@ } } }, + "node_modules/@radix-ui/react-label/node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", + "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-label/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-label/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-menu": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.1.tgz", @@ -24183,27 +24610,27 @@ } }, "node_modules/@radix-ui/react-radio-group": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-radio-group/-/react-radio-group-1.1.3.tgz", - "integrity": "sha512-x+yELayyefNeKeTx4fjK6j99Fs6c4qKm3aY38G3swQVTN6xMpsrbigC0uHs2L//g8q4qR7qOcww8430jJmi2ag==", + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-radio-group/-/react-radio-group-1.3.7.tgz", + "integrity": "sha512-9w5XhD0KPOrm92OTTE0SysH3sYzHsSTHNvZgUBo/VZ80VdYyB5RneDbc0dKpURS24IxkoFRu/hI0i4XyfFwY6g==", + "license": "MIT", "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/primitive": "1.0.1", - "@radix-ui/react-compose-refs": "1.0.1", - "@radix-ui/react-context": "1.0.1", - "@radix-ui/react-direction": "1.0.1", - "@radix-ui/react-presence": "1.0.1", - "@radix-ui/react-primitive": "1.0.3", - "@radix-ui/react-roving-focus": "1.0.4", - "@radix-ui/react-use-controllable-state": "1.0.1", - "@radix-ui/react-use-previous": "1.0.1", - "@radix-ui/react-use-size": "1.0.1" + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-presence": "1.1.4", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.10", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { @@ -24214,6 +24641,279 @@ } } }, + "node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/primitive": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.2.tgz", + "integrity": "sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-collection": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz", + "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", + "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-direction": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz", + "integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-id": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz", + "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-presence": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.4.tgz", + "integrity": "sha512-ueDqRbdc4/bkaQT3GIpLQssRlFgWaL/U2z/S31qRwwLWoxHLgry3SIfCwhxeQNbirEUXFa+lq3RL3oBYXtcmIA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-roving-focus": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.10.tgz", + "integrity": "sha512-dT9aOXUen9JSsxnMPv/0VqySQf5eDQ6LCk5Sw28kamz8wSOW2bJdlX2Bg5VUIIcV+6XlHpWTIuTPCf/UNIyq8Q==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz", + "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", + "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", + "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-use-previous": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.1.tgz", + "integrity": "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-use-size": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz", + "integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-roving-focus": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.0.4.tgz", @@ -24246,38 +24946,38 @@ } }, "node_modules/@radix-ui/react-select": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.0.0.tgz", - "integrity": "sha512-RH5b7af4oHtkcHS7pG6Sgv5rk5Wxa7XI8W5gvB1N/yiuDGZxko1ynvOiVhFM7Cis2A8zxF9bTOUVbRDzPepe6w==", + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.2.5.tgz", + "integrity": "sha512-HnMTdXEVuuyzx63ME0ut4+sEMYW6oouHWNGUZc7ddvUWIcfCva/AMoqEW/3wnEllriMWBa0RHspCYnfCWJQYmA==", + "license": "MIT", "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/number": "1.0.1", - "@radix-ui/primitive": "1.0.1", - "@radix-ui/react-collection": "1.0.3", - "@radix-ui/react-compose-refs": "1.0.1", - "@radix-ui/react-context": "1.0.1", - "@radix-ui/react-direction": "1.0.1", - "@radix-ui/react-dismissable-layer": "1.0.5", - "@radix-ui/react-focus-guards": "1.0.1", - "@radix-ui/react-focus-scope": "1.0.4", - "@radix-ui/react-id": "1.0.1", - "@radix-ui/react-popper": "1.1.3", - "@radix-ui/react-portal": "1.0.4", - "@radix-ui/react-primitive": "1.0.3", - "@radix-ui/react-slot": "1.0.2", - "@radix-ui/react-use-callback-ref": "1.0.1", - "@radix-ui/react-use-controllable-state": "1.0.1", - "@radix-ui/react-use-layout-effect": "1.0.1", - "@radix-ui/react-use-previous": "1.0.1", - "@radix-ui/react-visually-hidden": "1.0.3", - "aria-hidden": "^1.1.1", - "react-remove-scroll": "2.5.5" + "@radix-ui/number": "1.1.1", + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.10", + "@radix-ui/react-focus-guards": "1.1.2", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.7", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-visually-hidden": "1.2.3", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { @@ -24288,19 +24988,473 @@ } } }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/primitive": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.2.tgz", + "integrity": "sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-arrow": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz", + "integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-collection": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz", + "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", + "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-direction": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz", + "integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.10.tgz", + "integrity": "sha512-IM1zzRV4W3HtVgftdQiiOmA0AdJlCtMLe00FXaHwgt3rAnNsIyDqshvkIW3hj/iu5hu8ERP7KIYki6NkqDxAwQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-escape-keydown": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-focus-guards": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.2.tgz", + "integrity": "sha512-fyjAACV62oPV925xFCrH8DR5xWhg9KYtJT4s3u54jxp+L/hbpTY2kIeEFFbFe+a/HCE94zGQMZLIpVTPVZDhaA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-focus-scope": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz", + "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-id": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz", + "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-popper": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.7.tgz", + "integrity": "sha512-IUFAccz1JyKcf/RjB552PlWwxjeCJB8/4KxT7EhBHOJM+mN7LdW+B3kacJXILm32xawcMMjb2i0cIZpo+f9kiQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.0.0", + "@radix-ui/react-arrow": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-rect": "1.1.1", + "@radix-ui/react-use-size": "1.1.1", + "@radix-ui/rect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-portal": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz", + "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz", + "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", + "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-use-escape-keydown": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz", + "integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", + "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-use-previous": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.1.tgz", + "integrity": "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-use-rect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.1.tgz", + "integrity": "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==", + "license": "MIT", + "dependencies": { + "@radix-ui/rect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-use-size": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz", + "integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-visually-hidden": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz", + "integrity": "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/rect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.1.tgz", + "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-select/node_modules/react-remove-scroll": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.1.tgz", + "integrity": "sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA==", + "license": "MIT", + "dependencies": { + "react-remove-scroll-bar": "^2.3.7", + "react-style-singleton": "^2.2.3", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.3", + "use-sidecar": "^1.1.3" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-separator": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.0.3.tgz", - "integrity": "sha512-itYmTy/kokS21aiV5+Z56MZB54KrhPgn6eHDKkFeOLR34HMN2s8PaN47qZZAGnvupcjxHaFZnW4pQEh0BvvVuw==", + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.7.tgz", + "integrity": "sha512-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA==", + "license": "MIT", "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-primitive": "1.0.3" + "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { @@ -24311,29 +25465,34 @@ } } }, - "node_modules/@radix-ui/react-slider": { + "node_modules/@radix-ui/react-separator/node_modules/@radix-ui/react-compose-refs": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slider/-/react-slider-1.1.2.tgz", - "integrity": "sha512-NKs15MJylfzVsCagVSWKhGGLNR1W9qWs+HtgbmjjVUB3B9+lb3PYoXxVju3kOrpf0VKyVCtZp+iTwVoqpa1Chw==", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", + "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-separator/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/number": "1.0.1", - "@radix-ui/primitive": "1.0.1", - "@radix-ui/react-collection": "1.0.3", - "@radix-ui/react-compose-refs": "1.0.1", - "@radix-ui/react-context": "1.0.1", - "@radix-ui/react-direction": "1.0.1", - "@radix-ui/react-primitive": "1.0.3", - "@radix-ui/react-use-controllable-state": "1.0.1", - "@radix-ui/react-use-layout-effect": "1.0.1", - "@radix-ui/react-use-previous": "1.0.1", - "@radix-ui/react-use-size": "1.0.1" + "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { @@ -24344,6 +25503,242 @@ } } }, + "node_modules/@radix-ui/react-separator/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slider": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slider/-/react-slider-1.3.5.tgz", + "integrity": "sha512-rkfe2pU2NBAYfGaxa3Mqosi7VZEWX5CxKaanRv0vZd4Zhl9fvQrg0VM93dv3xGLGfrHuoTRF3JXH8nb9g+B3fw==", + "license": "MIT", + "dependencies": { + "@radix-ui/number": "1.1.1", + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-use-size": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slider/node_modules/@radix-ui/primitive": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.2.tgz", + "integrity": "sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-slider/node_modules/@radix-ui/react-collection": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz", + "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slider/node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", + "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slider/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slider/node_modules/@radix-ui/react-direction": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz", + "integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slider/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slider/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slider/node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", + "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slider/node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", + "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slider/node_modules/@radix-ui/react-use-previous": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.1.tgz", + "integrity": "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slider/node_modules/@radix-ui/react-use-size": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz", + "integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-slot": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.0.2.tgz", @@ -24363,24 +25758,24 @@ } }, "node_modules/@radix-ui/react-switch": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-switch/-/react-switch-1.0.3.tgz", - "integrity": "sha512-mxm87F88HyHztsI7N+ZUmEoARGkC22YVW5CaC+Byc+HRpuvCrOBPTAnXgf+tZ/7i0Sg/eOePGdMhUKhPaQEqow==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-switch/-/react-switch-1.2.5.tgz", + "integrity": "sha512-5ijLkak6ZMylXsaImpZ8u4Rlf5grRmoc0p0QeX9VJtlrM4f5m3nCTX8tWga/zOA8PZYIR/t0p2Mnvd7InrJ6yQ==", + "license": "MIT", "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/primitive": "1.0.1", - "@radix-ui/react-compose-refs": "1.0.1", - "@radix-ui/react-context": "1.0.1", - "@radix-ui/react-primitive": "1.0.3", - "@radix-ui/react-use-controllable-state": "1.0.1", - "@radix-ui/react-use-previous": "1.0.1", - "@radix-ui/react-use-size": "1.0.1" + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { @@ -24391,6 +25786,150 @@ } } }, + "node_modules/@radix-ui/react-switch/node_modules/@radix-ui/primitive": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.2.tgz", + "integrity": "sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-switch/node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", + "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-switch/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-switch/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-switch/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-switch/node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", + "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-switch/node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", + "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-switch/node_modules/@radix-ui/react-use-previous": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.1.tgz", + "integrity": "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-switch/node_modules/@radix-ui/react-use-size": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz", + "integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-tabs": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.0.4.tgz", @@ -24490,6 +26029,39 @@ } } }, + "node_modules/@radix-ui/react-use-effect-event": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz", + "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-effect-event/node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", + "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-use-escape-keydown": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.0.3.tgz", @@ -24621,49 +26193,43 @@ } }, "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==", + "version": "3.20.5", + "resolved": "https://registry.npmjs.org/@react-aria/focus/-/focus-3.20.5.tgz", + "integrity": "sha512-JpFtXmWQ0Oca7FcvkqgjSyo6xEP7v3oQOLUId6o0xTvm4AD5W0mU2r3lYrbhsJ+XxdUUX4AVR5473sZZ85kU4A==", "license": "Apache-2.0", "dependencies": { - "@react-aria/interactions": "^3.21.3", - "@react-aria/utils": "^3.24.1", - "@react-types/shared": "^3.23.1", + "@react-aria/interactions": "^3.25.3", + "@react-aria/utils": "^3.29.1", + "@react-types/shared": "^3.30.0", "@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" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, "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==", + "version": "3.25.3", + "resolved": "https://registry.npmjs.org/@react-aria/interactions/-/interactions-3.25.3.tgz", + "integrity": "sha512-J1bhlrNtjPS/fe5uJQ+0c7/jiXniwa4RQlP+Emjfc/iuqpW2RhbF9ou5vROcLzWIyaW8tVMZ468J68rAs/aZ5A==", "license": "Apache-2.0", "dependencies": { - "@react-aria/ssr": "^3.9.4", - "@react-aria/utils": "^3.24.1", - "@react-types/shared": "^3.23.1", + "@react-aria/ssr": "^3.9.9", + "@react-aria/utils": "^3.29.1", + "@react-stately/flags": "^3.1.2", + "@react-types/shared": "^3.30.0", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, "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==", + "version": "3.9.9", + "resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.9.9.tgz", + "integrity": "sha512-2P5thfjfPy/np18e5wD4WPt8ydNXhij1jwA8oehxZTFqlgVMGXzcWKxTb4RtJrLFsqPO7RUQTiY8QJk0M4Vy2g==", "license": "Apache-2.0", "dependencies": { "@swc/helpers": "^0.5.0" @@ -24672,32 +26238,25 @@ "node": ">= 12" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, "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==", + "version": "3.29.1", + "resolved": "https://registry.npmjs.org/@react-aria/utils/-/utils-3.29.1.tgz", + "integrity": "sha512-yXMFVJ73rbQ/yYE/49n5Uidjw7kh192WNN9PNQGV0Xoc7EJUlSOxqhnpHmYTyO0EotJ8fdM1fMH8durHjUSI8g==", "license": "Apache-2.0", "dependencies": { - "@react-aria/ssr": "^3.9.4", - "@react-stately/utils": "^3.10.1", - "@react-types/shared": "^3.23.1", + "@react-aria/ssr": "^3.9.9", + "@react-stately/flags": "^3.1.2", + "@react-stately/utils": "^3.10.7", + "@react-types/shared": "^3.30.0", "@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" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, "node_modules/@react-dnd/asap": { @@ -24792,40 +26351,111 @@ "license": "MIT" }, "node_modules/@react-spring/web": { - "version": "9.7.5", - "resolved": "https://registry.npmjs.org/@react-spring/web/-/web-9.7.5.tgz", - "integrity": "sha512-lmvqGwpe+CSttsWNZVr+Dg62adtKhauGwLyGE/RRyZ8AAMLgb9x3NDMA5RMElXo+IMyTkPp7nxTB8ZQlmhb6JQ==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@react-spring/web/-/web-10.0.1.tgz", + "integrity": "sha512-FgQk02OqFrYyJBTTnBTWAU0WPzkHkKXauc6aeexcvATvLapUxwnfGuLlsLYF8BYjEVfkivPT04ziAue6zyRBtQ==", "license": "MIT", + "peer": true, "dependencies": { - "@react-spring/animated": "~9.7.5", - "@react-spring/core": "~9.7.5", - "@react-spring/shared": "~9.7.5", - "@react-spring/types": "~9.7.5" + "@react-spring/animated": "~10.0.1", + "@react-spring/core": "~10.0.1", + "@react-spring/shared": "~10.0.1", + "@react-spring/types": "~10.0.1" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@react-spring/web/node_modules/@react-spring/animated": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@react-spring/animated/-/animated-10.0.1.tgz", + "integrity": "sha512-BGL3hA66Y8Qm3KmRZUlfG/mFbDPYajgil2/jOP0VXf2+o2WPVmcDps/eEgdDqgf5Pv9eBbyj7LschLMuSjlW3Q==", + "license": "MIT", + "peer": true, + "dependencies": { + "@react-spring/shared": "~10.0.1", + "@react-spring/types": "~10.0.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@react-spring/web/node_modules/@react-spring/core": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@react-spring/core/-/core-10.0.1.tgz", + "integrity": "sha512-KaMMsN1qHuVTsFpg/5ajAVye7OEqhYbCq0g4aKM9bnSZlDBBYpO7Uf+9eixyXN8YEbF+YXaYj9eoWDs+npZ+sA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@react-spring/animated": "~10.0.1", + "@react-spring/shared": "~10.0.1", + "@react-spring/types": "~10.0.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/react-spring/donate" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@react-spring/web/node_modules/@react-spring/rafz": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@react-spring/rafz/-/rafz-10.0.1.tgz", + "integrity": "sha512-UrzG/d6Is+9i0aCAjsjWRqIlFFiC4lFqFHrH63zK935z2YDU95TOFio4VKGISJ5SG0xq4ULy7c1V3KU+XvL+Yg==", + "license": "MIT", + "peer": true + }, + "node_modules/@react-spring/web/node_modules/@react-spring/shared": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@react-spring/shared/-/shared-10.0.1.tgz", + "integrity": "sha512-KR2tmjDShPruI/GGPfAZOOLvDgkhFseabjvxzZFFggJMPkyICLjO0J6mCIoGtdJSuHywZyc4Mmlgi+C88lS00g==", + "license": "MIT", + "peer": true, + "dependencies": { + "@react-spring/rafz": "~10.0.1", + "@react-spring/types": "~10.0.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@react-spring/web/node_modules/@react-spring/types": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@react-spring/types/-/types-10.0.1.tgz", + "integrity": "sha512-Fk1wYVAKL+ZTYK+4YFDpHf3Slsy59pfFFvnnTfRjQQFGlyIo4VejPtDs3CbDiuBjM135YztRyZjIH2VbycB+ZQ==", + "license": "MIT", + "peer": true + }, + "node_modules/@react-stately/flags": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@react-stately/flags/-/flags-3.1.2.tgz", + "integrity": "sha512-2HjFcZx1MyQXoPqcBGALwWWmgFVUk2TuKVIQxCbRq7fPyWXIl6VHcakCLurdtYC2Iks7zizvz0Idv48MQ38DWg==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0" } }, "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==", + "version": "3.10.7", + "resolved": "https://registry.npmjs.org/@react-stately/utils/-/utils-3.10.7.tgz", + "integrity": "sha512-cWvjGAocvy4abO9zbr6PW6taHgF24Mwy/LbQ4TC4Aq3tKdKDntxyD+sh7AkSRfJRT2ccMVaHVv2+FfHThd3PKQ==", "license": "Apache-2.0", "dependencies": { "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, "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==", + "version": "3.30.0", + "resolved": "https://registry.npmjs.org/@react-types/shared/-/shared-3.30.0.tgz", + "integrity": "sha512-COIazDAx1ncDg046cTJ8SFYsX8aS3lB/08LDnbkH/SkdYrFPWDlXMrO/sUam8j1WWM+PJ+4d1mj7tODIKNiFog==", "license": "Apache-2.0", "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, "node_modules/@redis/bloom": { @@ -27082,12 +28712,12 @@ } }, "node_modules/@swc/helpers": { - "version": "0.5.11", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.11.tgz", - "integrity": "sha512-YNlnKRWF2sVojTpIyzwou9XoTNbzbzONwRhOoniEioF1AtaitTvVZblaQRrAzChWQ1bLYyYSWzM18y4WwgzJ+A==", + "version": "0.5.17", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.17.tgz", + "integrity": "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==", "license": "Apache-2.0", "dependencies": { - "tslib": "^2.4.0" + "tslib": "^2.8.0" } }, "node_modules/@tanstack/match-sorter-utils": { @@ -27181,20 +28811,20 @@ } }, "node_modules/@tanstack/react-virtual": { - "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==", + "version": "3.13.12", + "resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.13.12.tgz", + "integrity": "sha512-Gd13QdxPSukP8ZrkbgS2RwoZseTTbQPLnQEn7HY/rqtM+8Zt95f7xKC7N0EsKs7aoz0WzZ+fditZux+F8EzYxA==", "license": "MIT", "dependencies": { - "@tanstack/virtual-core": "3.8.2" + "@tanstack/virtual-core": "3.13.12" }, "funding": { "type": "github", "url": "https://github.com/sponsors/tannerlinsley" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "node_modules/@tanstack/table-core": { @@ -27210,9 +28840,9 @@ } }, "node_modules/@tanstack/virtual-core": { - "version": "3.8.2", - "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.8.2.tgz", - "integrity": "sha512-ffpN6kTaPGwQPoWMcBAHbdv2ZCpj1SugldoYAcY0C4xH+Pej1KCOEUisNeEgbUnXOp8Y/4q6wGPu2tFHthOIQw==", + "version": "3.13.12", + "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.13.12.tgz", + "integrity": "sha512-1YBOJfRHV4sXUmWsFSf5rQor4Ss82G8dQWLRbnk3GA4jeP8hQt1hxXh0tmflpC0dz3VgEv/1+qwPyLeWkQuPFA==", "license": "MIT", "funding": { "type": "github", @@ -27350,6 +28980,16 @@ "node": ">= 10" } }, + "node_modules/@trysound/sax": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", + "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/@tsconfig/node10": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", @@ -28540,9 +30180,10 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, "node_modules/aria-hidden": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.3.tgz", - "integrity": "sha512-xcLxITLe2HYa1cnYnwCjkOO1PqUHQpozB8x9AR0OgWN2woOBi5kSDVxKfd0b7sb1hw5qFeJhXm9H1nu3xSfLeQ==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz", + "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==", + "license": "MIT", "dependencies": { "tslib": "^2.0.0" }, @@ -29629,6 +31270,19 @@ "node": ">= 6" } }, + "node_modules/caniuse-api": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } + }, "node_modules/caniuse-lite": { "version": "1.0.30001706", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001706.tgz", @@ -29857,14 +31511,15 @@ "dev": true }, "node_modules/class-variance-authority": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.6.1.tgz", - "integrity": "sha512-eurOEGc7YVx3majOrOb099PNKgO3KnKSApOprXI4BTq6bcfbqbQXPN2u+rPPmIJ2di23bMwhk0SxCCthBmszEQ==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz", + "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==", + "license": "Apache-2.0", "dependencies": { - "clsx": "1.2.1" + "clsx": "^2.1.1" }, "funding": { - "url": "https://joebell.co.uk" + "url": "https://polar.sh/cva" } }, "node_modules/classnames": { @@ -30020,9 +31675,10 @@ } }, "node_modules/clsx": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", - "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", "engines": { "node": ">=6" } @@ -30177,6 +31833,13 @@ "simple-swizzle": "^0.2.2" } }, + "node_modules/colord": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", + "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", + "dev": true, + "license": "MIT" + }, "node_modules/colorette": { "version": "2.0.20", "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", @@ -30235,6 +31898,16 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, "node_modules/common-tags": { "version": "1.8.2", "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", @@ -30306,6 +31979,16 @@ "node": ">= 6" } }, + "node_modules/concat-with-sourcemaps": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/concat-with-sourcemaps/-/concat-with-sourcemaps-1.1.0.tgz", + "integrity": "sha512-4gEjHJFT9e+2W/77h/DS5SGUgwDaOwprX8L/gl5+3ixnzkVJJsZWDSelmN3Oilw3LNDZjZV0yqH1hLG3k6nghg==", + "dev": true, + "license": "ISC", + "dependencies": { + "source-map": "^0.6.1" + } + }, "node_modules/console-browserify": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", @@ -30656,6 +32339,19 @@ "postcss": "^8.4" } }, + "node_modules/css-declaration-sorter": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.4.1.tgz", + "integrity": "sha512-rtdthzxKuyq6IzqX6jEcIzQF/YqccluefyCYheovBOLhFT/drQA9zj/UbRAa9J7C0o6EG6u3E6g+vKkay7/k3g==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.0.9" + } + }, "node_modules/css-has-pseudo": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/css-has-pseudo/-/css-has-pseudo-5.0.2.tgz", @@ -30709,6 +32405,20 @@ "url": "https://github.com/sponsors/fb55" } }, + "node_modules/css-tree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/css-what": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", @@ -30760,6 +32470,108 @@ "integrity": "sha512-6tun4LoZnj7VN6YeegOVb67KBX/7JJsqvj+pv3ZA7F878/eN33AbGa5b/S/wXxS/tcp8nc40xRUrsPlxIyNUPg==", "dev": true }, + "node_modules/cssnano": { + "version": "5.1.15", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-5.1.15.tgz", + "integrity": "sha512-j+BKgDcLDQA+eDifLx0EO4XSA56b7uut3BQFH+wbSaSTuGLuiyTa/wbRYthUXX8LC9mLg+WWKe8h+qJuwTAbHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssnano-preset-default": "^5.2.14", + "lilconfig": "^2.0.3", + "yaml": "^1.10.2" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/cssnano" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/cssnano-preset-default": { + "version": "5.2.14", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.2.14.tgz", + "integrity": "sha512-t0SFesj/ZV2OTylqQVOrFgEh5uanxbO6ZAdeCrNsUQ6fVuXwYTxJPNAGvGTxHbD68ldIJNec7PyYZDBrfDQ+6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "css-declaration-sorter": "^6.3.1", + "cssnano-utils": "^3.1.0", + "postcss-calc": "^8.2.3", + "postcss-colormin": "^5.3.1", + "postcss-convert-values": "^5.1.3", + "postcss-discard-comments": "^5.1.2", + "postcss-discard-duplicates": "^5.1.0", + "postcss-discard-empty": "^5.1.1", + "postcss-discard-overridden": "^5.1.0", + "postcss-merge-longhand": "^5.1.7", + "postcss-merge-rules": "^5.1.4", + "postcss-minify-font-values": "^5.1.0", + "postcss-minify-gradients": "^5.1.1", + "postcss-minify-params": "^5.1.4", + "postcss-minify-selectors": "^5.2.1", + "postcss-normalize-charset": "^5.1.0", + "postcss-normalize-display-values": "^5.1.0", + "postcss-normalize-positions": "^5.1.1", + "postcss-normalize-repeat-style": "^5.1.1", + "postcss-normalize-string": "^5.1.0", + "postcss-normalize-timing-functions": "^5.1.0", + "postcss-normalize-unicode": "^5.1.1", + "postcss-normalize-url": "^5.1.0", + "postcss-normalize-whitespace": "^5.1.1", + "postcss-ordered-values": "^5.1.3", + "postcss-reduce-initial": "^5.1.2", + "postcss-reduce-transforms": "^5.1.0", + "postcss-svgo": "^5.1.0", + "postcss-unique-selectors": "^5.1.1" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/cssnano-utils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-3.1.0.tgz", + "integrity": "sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/cssnano/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, + "node_modules/csso": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", + "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", + "dev": true, + "license": "MIT", + "dependencies": { + "css-tree": "^1.1.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/cssom": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", @@ -33425,17 +35237,20 @@ } }, "node_modules/framer-motion": { - "version": "11.5.4", - "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-11.5.4.tgz", - "integrity": "sha512-E+tb3/G6SO69POkdJT+3EpdMuhmtCh9EWuK4I1DnIC23L7tFPrl8vxP+LSovwaw6uUr73rUbpb4FgK011wbRJQ==", + "version": "12.23.9", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.23.9.tgz", + "integrity": "sha512-TqEHXj8LWfQSKqfdr5Y4mYltYLw96deu6/K9kGDd+ysqRJPNwF9nb5mZcrLmybHbU7gcJ+HQar41U3UTGanbbQ==", "license": "MIT", + "peer": true, "dependencies": { + "motion-dom": "^12.23.9", + "motion-utils": "^12.23.6", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", - "react": "^18.0.0", - "react-dom": "^18.0.0" + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" }, "peerDependenciesMeta": { "@emotion/is-prop-valid": { @@ -33449,6 +35264,23 @@ } } }, + "node_modules/framer-motion/node_modules/motion-dom": { + "version": "12.23.9", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.23.9.tgz", + "integrity": "sha512-6Sv++iWS8XMFCgU1qwKj9l4xuC47Hp4+2jvPfyTXkqDg2tTzSgX6nWKD4kNFXk0k7llO59LZTPuJigza4A2K1A==", + "license": "MIT", + "peer": true, + "dependencies": { + "motion-utils": "^12.23.6" + } + }, + "node_modules/framer-motion/node_modules/motion-utils": { + "version": "12.23.6", + "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.23.6.tgz", + "integrity": "sha512-eAWoPgr4eFEOFfg2WjIsMoqJTW6Z8MTUCgn/GZ3VRpClWBdnbjryiA3ZSNLyxCTmCQx4RmYX6jX1iWHbenUPNQ==", + "license": "MIT", + "peer": true + }, "node_modules/fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", @@ -33591,6 +35423,16 @@ "node": ">=12" } }, + "node_modules/generic-names": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/generic-names/-/generic-names-4.0.0.tgz", + "integrity": "sha512-ySFolZQfw9FoDb3ed9d80Cm9f0+r7qj+HJkWjeD9RBfpxEVTlVhol+gvaQB/78WbwYfbnNh8nWHHBSlg072y6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "loader-utils": "^3.2.0" + } + }, "node_modules/generic-pool": { "version": "3.9.0", "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz", @@ -33977,7 +35819,8 @@ "node_modules/hamt_plus": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/hamt_plus/-/hamt_plus-1.0.2.tgz", - "integrity": "sha512-t2JXKaehnMb9paaYA7J0BX8QQAY8lwfQ9Gjf4pg/mk4krt+cmwmU652HOoWonf+7+EQV97ARPMhhVgU1ra2GhA==" + "integrity": "sha512-t2JXKaehnMb9paaYA7J0BX8QQAY8lwfQ9Gjf4pg/mk4krt+cmwmU652HOoWonf+7+EQV97ARPMhhVgU1ra2GhA==", + "license": "MIT" }, "node_modules/handlebars": { "version": "4.7.8", @@ -34586,9 +36429,9 @@ } }, "node_modules/i18next-browser-languagedetector": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-8.0.3.tgz", - "integrity": "sha512-beOOLArattPBc2YZG5IXGJytdYFgUR7cS8Wd6HT4IczIoWKgmTspOQ2yasaGklelVo5seLPmnEKvLHR+E/MdWQ==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-8.2.0.tgz", + "integrity": "sha512-P+3zEKLnOF0qmiesW383vsLdtQVyKtCNA9cjSoKCppTKPQVfKd2W8hbVo5ZhNJKDqeM7BOcvNoKJOjpHh4Js9g==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.23.2" @@ -34706,6 +36549,26 @@ "node": ">=0.10.0" } }, + "node_modules/icss-replace-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz", + "integrity": "sha512-chIaY3Vh2mh2Q3RGXttaDIzeiPvaVXJ+C4DAh/w3c37SKZ/U6PGMmuicR2EQQp9bKG8zLMCl7I+PtIoOOPp8Gg==", + "dev": true, + "license": "ISC" + }, + "node_modules/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, "node_modules/idb": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz", @@ -34757,6 +36620,19 @@ "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", "dev": true }, + "node_modules/import-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-3.0.0.tgz", + "integrity": "sha512-4pnzH16plW+hgvRECbDWpQl3cqtvSofHWh44met7ESfZ8UZOWWddm8hEyDTqREJ9RbYHY8gi8DqmaelApoOGMg==", + "dev": true, + "license": "MIT", + "dependencies": { + "import-from": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -34773,6 +36649,29 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/import-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/import-from/-/import-from-3.0.0.tgz", + "integrity": "sha512-CiuXOFFSzkU5x/CR0+z7T91Iht4CXgfCxVOFRhh2Zyhg5wOpWvvDLQUsWl+gcN+QscYBjez8hDCt85O7RLDttQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/import-from/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/import-local": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", @@ -34860,14 +36759,6 @@ "resolved": "https://registry.npmjs.org/intersection-observer/-/intersection-observer-0.10.0.tgz", "integrity": "sha512-fn4bQ0Xq8FTej09YC/jqKZwtijpvARlRp6wxL5WTA6yPe2YWSJ5RJh7Nm79rK2qB0wr6iDQzH60XGq5V/7u8YQ==" }, - "node_modules/invariant": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "dependencies": { - "loose-envify": "^1.0.0" - } - }, "node_modules/ioredis": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.3.2.tgz", @@ -36425,6 +38316,27 @@ "url": "https://github.com/sponsors/panva" } }, + "node_modules/jotai": { + "version": "2.12.5", + "resolved": "https://registry.npmjs.org/jotai/-/jotai-2.12.5.tgz", + "integrity": "sha512-G8m32HW3lSmcz/4mbqx0hgJIQ0ekndKWiYP7kWVKi0p6saLXdSoye+FZiOFyonnd7Q482LCzm8sMDl7Ar1NWDw==", + "license": "MIT", + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "@types/react": ">=17.0.0", + "react": ">=17.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react": { + "optional": true + } + } + }, "node_modules/js-base64": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.2.tgz", @@ -37347,6 +39259,16 @@ "node": ">=6.11.5" } }, + "node_modules/loader-utils": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.3.1.tgz", + "integrity": "sha512-FMJTLMXfCLMLfJxcX9PFqX5qD88Z5MRGaZCVzfuqeZSPsyiBzs+pahDQjbIWz2QIzPZz0NX9Zy4FX3lmK6YHIg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12.13.0" + } + }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -37451,6 +39373,13 @@ "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==" }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", + "dev": true, + "license": "MIT" + }, "node_modules/log-update": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", @@ -37785,11 +39714,13 @@ "license": "ISC" }, "node_modules/lucide-react": { - "version": "0.394.0", - "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.394.0.tgz", - "integrity": "sha512-PzTbJ0bsyXRhH59k5qe7MpTd5MxlpYZUcM9kGSwvPGAfnn0J6FElDwu2EX6Vuh//F7y60rcVJiFQ7EK9DCMgfw==", + "version": "0.525.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.525.0.tgz", + "integrity": "sha512-Tm1txJ2OkymCGkvwoHt33Y2JpN5xucVq1slHcgE6Lk0WjDfjgKWor5CdVER8U6DvcfMwh4M8XxmpTiyzfmfDYQ==", + "license": "ISC", + "peer": true, "peerDependencies": { - "react": "^16.5.1 || ^17.0.0 || ^18.0.0" + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "node_modules/lz-string": { @@ -37805,6 +39736,7 @@ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } @@ -37849,9 +39781,10 @@ } }, "node_modules/match-sorter": { - "version": "6.3.4", - "resolved": "https://registry.npmjs.org/match-sorter/-/match-sorter-6.3.4.tgz", - "integrity": "sha512-jfZW7cWS5y/1xswZo8VBOdudUiSd9nifYRWphc9M5D/ee4w4AoXLgBEdRbgVaxbMuagBPeUC5y2Hi8DO6o9aDg==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/match-sorter/-/match-sorter-8.1.0.tgz", + "integrity": "sha512-0HX3BHPixkbECX+Vt7nS1vJ6P2twPgGTU3PMXjWrl1eyVCL24tFHeyYN1FN5RKLzve0TyzNI9qntqQGbebnfPQ==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.23.8", "remove-accents": "0.5.0" @@ -37860,7 +39793,8 @@ "node_modules/match-sorter/node_modules/remove-accents": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/remove-accents/-/remove-accents-0.5.0.tgz", - "integrity": "sha512-8g3/Otx1eJaVD12e31UbJj1YzdtVvzH85HV7t+9MJYk/u3XmkOUJ5Ys9wQrf9PCPK8+xn4ymzqYCiZl6QWKn+A==" + "integrity": "sha512-8g3/Otx1eJaVD12e31UbJj1YzdtVvzH85HV7t+9MJYk/u3XmkOUJ5Ys9wQrf9PCPK8+xn4ymzqYCiZl6QWKn+A==", + "license": "MIT" }, "node_modules/math-intrinsics": { "version": "1.1.0", @@ -38486,6 +40420,13 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", + "dev": true, + "license": "CC0-1.0" + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -39466,6 +41407,21 @@ "color-name": "^1.1.4" } }, + "node_modules/motion-dom": { + "version": "11.18.1", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-11.18.1.tgz", + "integrity": "sha512-g76KvA001z+atjfxczdRtw/RXOM3OMSdd1f4DL77qCTF/+avrRJiawSG4yDibEQ215sr9kpinSlX2pCTJ9zbhw==", + "license": "MIT", + "dependencies": { + "motion-utils": "^11.18.1" + } + }, + "node_modules/motion-utils": { + "version": "11.18.1", + "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-11.18.1.tgz", + "integrity": "sha512-49Kt+HKjtbJKLtgO/LKj9Ld+6vw9BjH5d9sc40R/kVyH8GLAXgT42M2NnuPcJNuA3s9ZfZBUcwIgpmZWGEE+hA==", + "license": "MIT" + }, "node_modules/mpath": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz", @@ -39890,6 +41846,19 @@ "node": ">=0.10.0" } }, + "node_modules/normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/npm-run-path": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", @@ -40769,6 +42738,19 @@ "node": ">=0.10" } }, + "node_modules/pify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-5.0.0.tgz", + "integrity": "sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/pirates": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", @@ -40949,6 +42931,20 @@ "postcss": "^8.4" } }, + "node_modules/postcss-calc": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-8.2.4.tgz", + "integrity": "sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.0.9", + "postcss-value-parser": "^4.2.0" + }, + "peerDependencies": { + "postcss": "^8.2.2" + } + }, "node_modules/postcss-clamp": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/postcss-clamp/-/postcss-clamp-4.1.0.tgz", @@ -41034,6 +43030,42 @@ "postcss": "^8.4" } }, + "node_modules/postcss-colormin": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-5.3.1.tgz", + "integrity": "sha512-UsWQG0AqTFQmpBegeLLc1+c3jIqBNB0zlDGRWR+dQ3pRKJL1oeMzyqmH3o2PIfn9MBdNrVPWhDbT769LxCTLJQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0", + "colord": "^2.9.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-convert-values": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-5.1.3.tgz", + "integrity": "sha512-82pC1xkJZtcJEfiLw6UXnXVXScgtBrjlO5CBmuDQc+dlb88ZYheFsjTn40+zBVi3DkfF7iezO0nJUPLcJK3pvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.21.4", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, "node_modules/postcss-custom-media": { "version": "9.1.5", "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-9.1.5.tgz", @@ -41137,6 +43169,58 @@ "postcss": "^8.4" } }, + "node_modules/postcss-discard-comments": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.1.2.tgz", + "integrity": "sha512-+L8208OVbHVF2UQf1iDmRcbdjJkuBF6IS29yBDSiWUIzpYaAhtNl6JYnYm12FnkeCwQqF5LeklOu6rAqgfBZqQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-duplicates": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-5.1.0.tgz", + "integrity": "sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-empty": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-5.1.1.tgz", + "integrity": "sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-overridden": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-5.1.0.tgz", + "integrity": "sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, "node_modules/postcss-double-position-gradients": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/postcss-double-position-gradients/-/postcss-double-position-gradients-4.0.4.tgz", @@ -41405,6 +43489,221 @@ "postcss": "^8.4" } }, + "node_modules/postcss-merge-longhand": { + "version": "5.1.7", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-5.1.7.tgz", + "integrity": "sha512-YCI9gZB+PLNskrK0BB3/2OzPnGhPkBEwmwhfYk1ilBHYVAZB7/tkTHFBAnCrvBBOmeYyMYw3DMjT55SyxMBzjQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0", + "stylehacks": "^5.1.1" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-merge-rules": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-5.1.4.tgz", + "integrity": "sha512-0R2IuYpgU93y9lhVbO/OylTtKMVcHb67zjWIfCiKR9rWL3GUk1677LAqD/BcHizukdZEjT8Ru3oHRoAYoJy44g==", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0", + "cssnano-utils": "^3.1.0", + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-font-values": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-5.1.0.tgz", + "integrity": "sha512-el3mYTgx13ZAPPirSVsHqFzl+BBBDrXvbySvPGFnQcTI4iNslrPaFq4muTkLZmKlGk4gyFAYUBMH30+HurREyA==", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-gradients": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-5.1.1.tgz", + "integrity": "sha512-VGvXMTpCEo4qHTNSa9A0a3D+dxGFZCYwR6Jokk+/3oB6flu2/PnPXAh2x7x52EkY5xlIHLm+Le8tJxe/7TNhzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "colord": "^2.9.1", + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-params": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-5.1.4.tgz", + "integrity": "sha512-+mePA3MgdmVmv6g+30rn57USjOGSAyuxUmkfiWpzalZ8aiBkdPYjXWtHuwJGm1v5Ojy0Z0LaSYhHaLJQB0P8Jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.21.4", + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-selectors": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-5.2.1.tgz", + "integrity": "sha512-nPJu7OjZJTsVUmPdm2TcaiohIwxP+v8ha9NehQ2ye9szv4orirRU3SDdtUmKH+10nzn0bAyOXZ0UEr7OpvLehg==", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-modules": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/postcss-modules/-/postcss-modules-4.3.1.tgz", + "integrity": "sha512-ItUhSUxBBdNamkT3KzIZwYNNRFKmkJrofvC2nWab3CPKhYBQ1f27XXh1PAPE27Psx58jeelPsxWB/+og+KEH0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "generic-names": "^4.0.0", + "icss-replace-symbols": "^1.1.0", + "lodash.camelcase": "^4.3.0", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.0", + "postcss-modules-scope": "^3.0.0", + "postcss-modules-values": "^4.0.0", + "string-hash": "^1.1.1" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-modules-extract-imports": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", + "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.2.0.tgz", + "integrity": "sha512-5kcJm/zk+GJDSfw+V/42fJ5fhjL5YbFDl8nVdXkJPLLW+Vf9mTD5Xe0wqIaDnLuL2U6cDNpTr+UQ+v2HWIBhzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^7.0.0", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default/node_modules/postcss-selector-parser": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-modules-scope": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.1.tgz", + "integrity": "sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA==", + "dev": true, + "license": "ISC", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-scope/node_modules/postcss-selector-parser": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, "node_modules/postcss-nested": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz", @@ -41449,6 +43748,149 @@ "postcss": "^8.4" } }, + "node_modules/postcss-normalize-charset": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.1.0.tgz", + "integrity": "sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-display-values": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-5.1.0.tgz", + "integrity": "sha512-WP4KIM4o2dazQXWmFaqMmcvsKmhdINFblgSeRgn8BJ6vxaMyaJkwAzpPpuvSIoG/rmX3M+IrRZEz2H0glrQNEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-positions": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-5.1.1.tgz", + "integrity": "sha512-6UpCb0G4eofTCQLFVuI3EVNZzBNPiIKcA1AKVka+31fTVySphr3VUgAIULBhxZkKgwLImhzMR2Bw1ORK+37INg==", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-repeat-style": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.1.1.tgz", + "integrity": "sha512-mFpLspGWkQtBcWIRFLmewo8aC3ImN2i/J3v8YCFUwDnPu3Xz4rLohDO26lGjwNsQxB3YF0KKRwspGzE2JEuS0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-string": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-5.1.0.tgz", + "integrity": "sha512-oYiIJOf4T9T1N4i+abeIc7Vgm/xPCGih4bZz5Nm0/ARVJ7K6xrDlLwvwqOydvyL3RHNf8qZk6vo3aatiw/go3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-timing-functions": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.1.0.tgz", + "integrity": "sha512-DOEkzJ4SAXv5xkHl0Wa9cZLF3WCBhF3o1SKVxKQAa+0pYKlueTpCgvkFAHfk+Y64ezX9+nITGrDZeVGgITJXjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-unicode": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-5.1.1.tgz", + "integrity": "sha512-qnCL5jzkNUmKVhZoENp1mJiGNPcsJCs1aaRmURmeJGES23Z/ajaln+EPTD+rBeNkSryI+2WTdW+lwcVdOikrpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.21.4", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-5.1.0.tgz", + "integrity": "sha512-5upGeDO+PVthOxSmds43ZeMeZfKH+/DKgGRD7TElkkyS46JXAUhMzIKiCa7BabPeIy3AQcTkXwVVN7DbqsiCew==", + "dev": true, + "license": "MIT", + "dependencies": { + "normalize-url": "^6.0.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-whitespace": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.1.1.tgz", + "integrity": "sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, "node_modules/postcss-opacity-percentage": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/postcss-opacity-percentage/-/postcss-opacity-percentage-2.0.0.tgz", @@ -41471,6 +43913,23 @@ "postcss": "^8.2" } }, + "node_modules/postcss-ordered-values": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-5.1.3.tgz", + "integrity": "sha512-9UO79VUhPwEkzbb3RNpqqghc6lcYej1aveQteWY+4POIwlqkYE21HKWaLDF6lWNuqCobEAyTovVhtI32Rbv2RQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, "node_modules/postcss-overflow-shorthand": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-4.0.1.tgz", @@ -41617,6 +44076,39 @@ "postcss": "^8.4" } }, + "node_modules/postcss-reduce-initial": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-5.1.2.tgz", + "integrity": "sha512-dE/y2XRaqAi6OvjzD22pjTUQ8eOfc6m/natGHgKFBK9DxFmIm69YmaRVQrGgFlEfc1HePIurY0TmDeROK05rIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-reduce-transforms": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-5.1.0.tgz", + "integrity": "sha512-2fbdbmgir5AvpW9RLtdONx1QoYG2/EtqpNQbFASDlixBbAYuTcJ0dECwlqNqH7VbaUnEnh8SrxOe2sRIn24XyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, "node_modules/postcss-replace-overflow-wrap": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-4.0.0.tgz", @@ -41657,6 +44149,39 @@ "node": ">=4" } }, + "node_modules/postcss-svgo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-5.1.0.tgz", + "integrity": "sha512-D75KsH1zm5ZrHyxPakAxJWtkyXew5qwS70v56exwvw542d9CRtTo78K0WeFxZB4G7JXKKMbEZtZayTGdIky/eA==", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0", + "svgo": "^2.7.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-unique-selectors": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-5.1.1.tgz", + "integrity": "sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA==", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, "node_modules/postcss-value-parser": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", @@ -42225,6 +44750,16 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, + "node_modules/promise.series": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/promise.series/-/promise.series-0.2.0.tgz", + "integrity": "sha512-VWQJyU2bcDTgZw8kpfBpB/ejZASlCrzwz5f2hjb/zlujOEB4oeiAhHygAWq8ubsX2GVkD4kCU5V2dwOTaCY5EQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12" + } + }, "node_modules/prompts": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", @@ -42841,19 +45376,20 @@ } }, "node_modules/react-remove-scroll-bar": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.4.tgz", - "integrity": "sha512-63C4YQBUt0m6ALadE9XV56hV8BgJWDmmTPY758iIJjfQKt2nYwoUrPk0LXRXcB/yIj82T1/Ixfdpdk68LwIB0A==", + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz", + "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==", + "license": "MIT", "dependencies": { - "react-style-singleton": "^2.2.1", + "react-style-singleton": "^2.2.2", "tslib": "^2.0.0" }, "engines": { "node": ">=10" }, "peerDependencies": { - "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" }, "peerDependenciesMeta": { "@types/react": { @@ -42861,6 +45397,16 @@ } } }, + "node_modules/react-resizable-panels": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/react-resizable-panels/-/react-resizable-panels-3.0.3.tgz", + "integrity": "sha512-7HA8THVBHTzhDK4ON0tvlGXyMAJN1zBeRpuyyremSikgYh2ku6ltD7tsGQOcXx4NKPrZtYCm/5CBr+dkruTGQw==", + "license": "MIT", + "peerDependencies": { + "react": "^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc", + "react-dom": "^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + } + }, "node_modules/react-router": { "version": "6.22.0", "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.22.0.tgz", @@ -42900,20 +45446,20 @@ } }, "node_modules/react-style-singleton": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.1.tgz", - "integrity": "sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz", + "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==", + "license": "MIT", "dependencies": { "get-nonce": "^1.0.0", - "invariant": "^2.2.4", "tslib": "^2.0.0" }, "engines": { "node": ">=10" }, "peerDependencies": { - "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { @@ -42970,6 +45516,15 @@ "react-dom": "^16.3.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, + "node_modules/react-virtualized/node_modules/clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -43074,6 +45629,7 @@ "version": "0.7.7", "resolved": "https://registry.npmjs.org/recoil/-/recoil-0.7.7.tgz", "integrity": "sha512-8Og5KPQW9LwC577Vc7Ug2P0vQshkv1y3zG3tSSkWMqkWSwHmE+by06L8JtnGocjW6gcCvfwB3YtrJG6/tWivNQ==", + "license": "MIT", "dependencies": { "hamt_plus": "1.0.2" }, @@ -44161,6 +46717,74 @@ "rollup": "*" } }, + "node_modules/rollup-plugin-postcss": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/rollup-plugin-postcss/-/rollup-plugin-postcss-4.0.2.tgz", + "integrity": "sha512-05EaY6zvZdmvPUDi3uCcAQoESDcYnv8ogJJQRp6V5kZ6J6P7uAVJlrTZcaaA20wTH527YTnKfkAoPxWI/jPp4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "concat-with-sourcemaps": "^1.1.0", + "cssnano": "^5.0.1", + "import-cwd": "^3.0.0", + "p-queue": "^6.6.2", + "pify": "^5.0.0", + "postcss-load-config": "^3.0.0", + "postcss-modules": "^4.0.0", + "promise.series": "^0.2.0", + "resolve": "^1.19.0", + "rollup-pluginutils": "^2.8.2", + "safe-identifier": "^0.4.2", + "style-inject": "^0.3.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "postcss": "8.x" + } + }, + "node_modules/rollup-plugin-postcss/node_modules/postcss-load-config": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz", + "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "lilconfig": "^2.0.5", + "yaml": "^1.10.2" + }, + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/rollup-plugin-postcss/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, "node_modules/rollup-plugin-typescript2": { "version": "0.35.0", "resolved": "https://registry.npmjs.org/rollup-plugin-typescript2/-/rollup-plugin-typescript2-0.35.0.tgz", @@ -44226,6 +46850,23 @@ "node": ">= 10.0.0" } }, + "node_modules/rollup-pluginutils": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", + "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "estree-walker": "^0.6.1" + } + }, + "node_modules/rollup-pluginutils/node_modules/estree-walker": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", + "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", + "dev": true, + "license": "MIT" + }, "node_modules/router": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", @@ -44322,6 +46963,13 @@ } ] }, + "node_modules/safe-identifier": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/safe-identifier/-/safe-identifier-0.4.2.tgz", + "integrity": "sha512-6pNbSMW6OhAi9j+N8V+U715yBQsaWJ7eyEUaOrawX+isg5ZxhUlV1NipNtgaKHmFGiABwt+ZF04Ii+3Xjkg+8w==", + "dev": true, + "license": "ISC" + }, "node_modules/safe-push-apply": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", @@ -44901,6 +47549,14 @@ "integrity": "sha512-I7zYndqOOkNpz9KIdFZ8c8A7zs1YazNewBr8Nsi/tqThfJkVPuP1q7UE2h4B0RwoWZxbBYpd06uoW3NI3SaZXg==", "license": "Apache-2.0" }, + "node_modules/stable": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", + "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", + "deprecated": "Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility", + "dev": true, + "license": "MIT" + }, "node_modules/stable-hash": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/stable-hash/-/stable-hash-0.0.4.tgz", @@ -45082,6 +47738,13 @@ "node": ">=0.6.19" } }, + "node_modules/string-hash": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/string-hash/-/string-hash-1.1.3.tgz", + "integrity": "sha512-kJUvRUFK49aub+a7T1nNE66EJbZBMnBgoC1UbCZ5n6bsZKBRga4KgBRTMn/pFkeCZSYtNeSyMxPDM0AXWELk2A==", + "dev": true, + "license": "CC0-1.0" + }, "node_modules/string-length": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", @@ -45397,6 +48060,13 @@ "url": "https://github.com/sponsors/Borewit" } }, + "node_modules/style-inject": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/style-inject/-/style-inject-0.3.0.tgz", + "integrity": "sha512-IezA2qp+vcdlhJaVm5SOdPPTUu0FCEqfNSli2vRuSIBbu5Nq5UvygTk/VzeCqfLz2Atj3dVII5QBKGZRZ0edzw==", + "dev": true, + "license": "MIT" + }, "node_modules/style-mod": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.2.tgz", @@ -45410,6 +48080,23 @@ "inline-style-parser": "0.2.3" } }, + "node_modules/stylehacks": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.1.1.tgz", + "integrity": "sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.21.4", + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, "node_modules/sucrase": { "version": "3.35.0", "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", @@ -45565,6 +48252,101 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/svgo": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", + "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^4.1.3", + "css-tree": "^1.1.3", + "csso": "^4.2.0", + "picocolors": "^1.0.0", + "stable": "^0.1.8" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/svgo/node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/svgo/node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dev": true, + "license": "MIT", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/svgo/node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/svgo/node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/svgo/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true, + "license": "BSD-2-Clause", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", @@ -46910,9 +49692,10 @@ } }, "node_modules/use-sidecar": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.2.tgz", - "integrity": "sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz", + "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==", + "license": "MIT", "dependencies": { "detect-node-es": "^1.1.0", "tslib": "^2.0.0" @@ -46921,8 +49704,8 @@ "node": ">=10" }, "peerDependencies": { - "@types/react": "^16.9.0 || ^17.0.0 || ^18.0.0", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { @@ -46931,11 +49714,12 @@ } }, "node_modules/use-sync-external-store": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", - "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.5.0.tgz", + "integrity": "sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==", + "license": "MIT", "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "node_modules/utf8": { @@ -48720,6 +51504,304 @@ "url": "https://github.com/sponsors/isaacs" } }, + "packages/client": { + "name": "@librechat/client", + "version": "0.1.9", + "devDependencies": { + "@rollup/plugin-alias": "^5.1.0", + "@rollup/plugin-commonjs": "^25.0.2", + "@rollup/plugin-node-resolve": "^15.0.0", + "@rollup/plugin-replace": "^5.0.5", + "@rollup/plugin-terser": "^0.4.4", + "@tanstack/react-query": "^4.28.0", + "@testing-library/react": "^14.0.0", + "@types/react": "^18.2.11", + "@types/react-dom": "^18.2.4", + "concat-with-sourcemaps": "^1.1.0", + "i18next": "^24.2.3", + "jotai": "^2.12.5", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-i18next": "^15.4.0", + "rimraf": "^5.0.1", + "rollup": "^4.0.0", + "rollup-plugin-peer-deps-external": "^2.2.4", + "rollup-plugin-postcss": "^4.0.2", + "rollup-plugin-typescript2": "^0.35.0", + "tailwindcss-radix": "^2.8.0", + "typescript": "^5.0.0" + }, + "peerDependencies": { + "@ariakit/react": "^0.4.16", + "@ariakit/react-core": "^0.4.17", + "@headlessui/react": "^2.1.2", + "@radix-ui/react-accordion": "^1.2.11", + "@radix-ui/react-alert-dialog": "^1.0.2", + "@radix-ui/react-checkbox": "^1.0.3", + "@radix-ui/react-collapsible": "^1.1.11", + "@radix-ui/react-dialog": "^1.0.2", + "@radix-ui/react-dropdown-menu": "^2.1.1", + "@radix-ui/react-hover-card": "^1.0.5", + "@radix-ui/react-icons": "^1.3.0", + "@radix-ui/react-label": "^2.1.7", + "@radix-ui/react-progress": "^1.1.2", + "@radix-ui/react-radio-group": "^1.3.7", + "@radix-ui/react-select": "^2.2.5", + "@radix-ui/react-separator": "^1.1.7", + "@radix-ui/react-slider": "^1.3.5", + "@radix-ui/react-slot": "^1.0.0", + "@radix-ui/react-switch": "^1.2.5", + "@radix-ui/react-tabs": "^1.0.3", + "@radix-ui/react-toast": "^1.1.5", + "@react-spring/web": "^10.0.1", + "@tanstack/react-query": "^4.28.0 || ^5.0.0", + "@tanstack/react-table": "^8.11.7", + "@tanstack/react-virtual": "^3.0.0", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "framer-motion": "^12.23.6", + "i18next": "^24.2.2 || ^25.3.2", + "i18next-browser-languagedetector": "^8.2.0", + "input-otp": "^1.4.2", + "jotai": "^2.12.5", + "lucide-react": "^0.525.0", + "match-sorter": "^8.1.0", + "rc-input-number": "^7.4.2", + "react": "^18.2.0 || ^19.1.0", + "react-dom": "^18.2.0 || ^19.1.0", + "react-hook-form": "^7.56.4", + "react-i18next": "^15.4.0 || ^15.6.0", + "react-resizable-panels": "^3.0.2", + "react-textarea-autosize": "^8.4.0", + "tailwind-merge": "^1.9.1" + } + }, + "packages/client/node_modules/@testing-library/dom": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz", + "integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.3.0", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=18" + } + }, + "packages/client/node_modules/@testing-library/react": { + "version": "16.3.0", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.3.0.tgz", + "integrity": "sha512-kFSyxiEDwv1WLl2fgsq6pPBbw5aWKrsY2/noi1Id0TK0UParSF62oFQFGHXIyaG4pp2tEub/Zlel+fjjZILDsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@testing-library/dom": "^10.0.0", + "@types/react": "^18.0.0 || ^19.0.0", + "@types/react-dom": "^18.0.0 || ^19.0.0", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "packages/client/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "packages/client/node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "dequal": "^2.0.3" + } + }, + "packages/client/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "packages/client/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "packages/client/node_modules/i18next": { + "version": "24.2.3", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-24.2.3.tgz", + "integrity": "sha512-lfbf80OzkocvX7nmZtu7nSTNbrTYR52sLWxPtlXX1zAhVw8WEnFk4puUkCR4B1dNQwbSpEHHHemcZu//7EcB7A==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://locize.com" + }, + { + "type": "individual", + "url": "https://locize.com/i18next.html" + }, + { + "type": "individual", + "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project" + } + ], + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.26.10" + }, + "peerDependencies": { + "typescript": "^5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "packages/client/node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "packages/client/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "packages/client/node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "packages/client/node_modules/react-hook-form": { + "version": "7.60.0", + "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.60.0.tgz", + "integrity": "sha512-SBrYOvMbDB7cV8ZfNpaiLcgjH/a1c7aK0lK+aNigpf4xWLO8q+o4tcvVurv3c4EOyzn/3dCsYt4GKD42VvJ/+A==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/react-hook-form" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17 || ^18 || ^19" + } + }, + "packages/client/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true, + "license": "MIT", + "peer": true + }, + "packages/client/node_modules/rimraf": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz", + "integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^10.3.7" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "packages/data-provider": { "name": "librechat-data-provider", "version": "0.7.902", diff --git a/package.json b/package.json index 1aad42eb6..36327241a 100644 --- a/package.json +++ b/package.json @@ -40,8 +40,9 @@ "build:data-provider": "cd packages/data-provider && npm run build", "build:api": "cd packages/api && npm run build", "build:data-schemas": "cd packages/data-schemas && npm run build", - "frontend": "npm run build:data-provider && npm run build:data-schemas && npm run build:api && cd client && npm run build", - "frontend:ci": "npm run build:data-provider && cd client && npm run build:ci", + "build:client-package": "cd packages/client && npm run build", + "frontend": "npm run build:data-provider && npm run build:data-schemas && npm run build:api && npm run build:client-package && cd client && npm run build", + "frontend:ci": "npm run build:data-provider && npm run build:client-package && cd client && npm run build:ci", "frontend:dev": "cd client && npm run dev", "e2e": "playwright test --config=e2e/playwright.config.local.ts", "e2e:headed": "playwright test --config=e2e/playwright.config.local.ts --headed", diff --git a/packages/client/package.json b/packages/client/package.json new file mode 100644 index 000000000..5edd6505c --- /dev/null +++ b/packages/client/package.json @@ -0,0 +1,92 @@ +{ + "name": "@librechat/client", + "version": "0.1.9", + "description": "React components for LibreChat", + "main": "dist/index.js", + "module": "dist/index.es.js", + "types": "dist/types/index.d.ts", + "exports": { + ".": { + "import": "./dist/index.es.js", + "require": "./dist/index.js", + "types": "./dist/types/index.d.ts" + } + }, + "files": [ + "dist" + ], + "scripts": { + "clean": "rimraf dist", + "build": "npm run clean && rollup -c --bundleConfigAsCjs", + "build:watch": "rollup -c -w --bundleConfigAsCjs", + "dev": "rollup -c -w --bundleConfigAsCjs" + }, + "peerDependencies": { + "@tanstack/react-query": "^4.28.0 || ^5.0.0", + "i18next": "^24.2.2 || ^25.3.2", + "jotai": "^2.12.5", + "react": "^18.2.0 || ^19.1.0", + "react-dom": "^18.2.0 || ^19.1.0", + "react-i18next": "^15.4.0 || ^15.6.0", + "@tanstack/react-table": "^8.11.7", + "@tanstack/react-virtual": "^3.0.0", + "@ariakit/react": "^0.4.16", + "@ariakit/react-core": "^0.4.17", + "@headlessui/react": "^2.1.2", + "@radix-ui/react-accordion": "^1.2.11", + "@radix-ui/react-alert-dialog": "^1.0.2", + "@radix-ui/react-checkbox": "^1.0.3", + "@radix-ui/react-collapsible": "^1.1.11", + "@radix-ui/react-dialog": "^1.0.2", + "@radix-ui/react-dropdown-menu": "^2.1.1", + "@radix-ui/react-hover-card": "^1.0.5", + "@radix-ui/react-icons": "^1.3.0", + "@radix-ui/react-label": "^2.1.7", + "@radix-ui/react-progress": "^1.1.2", + "@radix-ui/react-radio-group": "^1.3.7", + "@radix-ui/react-select": "^2.2.5", + "@radix-ui/react-separator": "^1.1.7", + "@radix-ui/react-slider": "^1.3.5", + "@radix-ui/react-slot": "^1.0.0", + "@radix-ui/react-switch": "^1.2.5", + "@radix-ui/react-tabs": "^1.0.3", + "@radix-ui/react-toast": "^1.1.5", + "@react-spring/web": "^10.0.1", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "framer-motion": "^12.23.6", + "i18next-browser-languagedetector": "^8.2.0", + "input-otp": "^1.4.2", + "lucide-react": "^0.525.0", + "match-sorter": "^8.1.0", + "rc-input-number": "^7.4.2", + "react-hook-form": "^7.56.4", + "react-resizable-panels": "^3.0.2", + "react-textarea-autosize": "^8.4.0", + "tailwind-merge": "^1.9.1" + }, + "devDependencies": { + "@rollup/plugin-alias": "^5.1.0", + "@rollup/plugin-commonjs": "^25.0.2", + "@rollup/plugin-node-resolve": "^15.0.0", + "@rollup/plugin-replace": "^5.0.5", + "@rollup/plugin-terser": "^0.4.4", + "@tanstack/react-query": "^4.28.0", + "@testing-library/react": "^14.0.0", + "@types/react": "^18.2.11", + "@types/react-dom": "^18.2.4", + "concat-with-sourcemaps": "^1.1.0", + "i18next": "^24.2.3", + "jotai": "^2.12.5", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-i18next": "^15.4.0", + "rimraf": "^5.0.1", + "rollup": "^4.0.0", + "rollup-plugin-peer-deps-external": "^2.2.4", + "rollup-plugin-postcss": "^4.0.2", + "rollup-plugin-typescript2": "^0.35.0", + "tailwindcss-radix": "^2.8.0", + "typescript": "^5.0.0" + } +} diff --git a/packages/client/rollup.config.js b/packages/client/rollup.config.js new file mode 100644 index 000000000..1523ca9f7 --- /dev/null +++ b/packages/client/rollup.config.js @@ -0,0 +1,84 @@ +// ESM bundler config for React components +import { fileURLToPath } from 'url'; +import alias from '@rollup/plugin-alias'; +import terser from '@rollup/plugin-terser'; +import postcss from 'rollup-plugin-postcss'; +import replace from '@rollup/plugin-replace'; +import commonjs from '@rollup/plugin-commonjs'; +import resolve from '@rollup/plugin-node-resolve'; +import typescript from 'rollup-plugin-typescript2'; +import { dirname, resolve as pathResolve } from 'path'; +import peerDepsExternal from 'rollup-plugin-peer-deps-external'; +import pkg from './package.json'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +const plugins = [ + peerDepsExternal(), + alias({ + entries: [{ find: '~', replacement: pathResolve(__dirname, 'src') }], + }), + resolve({ + extensions: ['.js', '.jsx', '.ts', '.tsx'], + browser: true, + preferBuiltins: false, + }), + replace({ + 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'production'), + preventAssignment: true, + }), + commonjs(), + postcss({ + extract: false, + inject: true, + minimize: process.env.NODE_ENV === 'production', + modules: false, + config: { + path: './postcss.config.js', + }, + }), + typescript({ + tsconfig: './tsconfig.json', + useTsconfigDeclarationDir: true, + clean: true, + check: false, + }), + terser({ + compress: { + directives: false, + }, + }), +]; + +export default { + input: 'src/index.ts', + output: [ + { + file: pkg.main, + format: 'cjs', + sourcemap: true, + exports: 'named', + }, + { + file: pkg.module, + format: 'esm', + sourcemap: true, + exports: 'named', + }, + ], + external: [ + ...Object.keys(pkg.peerDependencies || {}), + 'react/jsx-runtime', + 'react/jsx-dev-runtime', + ], + preserveSymlinks: true, + plugins, + onwarn(warning, warn) { + // Ignore "use client" directive warnings + if (warning.code === 'MODULE_LEVEL_DIRECTIVE') { + return; + } + warn(warning); + }, +}; diff --git a/client/src/Providers/ToastContext.tsx b/packages/client/src/Providers/ToastContext.tsx similarity index 77% rename from client/src/Providers/ToastContext.tsx rename to packages/client/src/Providers/ToastContext.tsx index 2f0e5efcf..afe24995d 100644 --- a/client/src/Providers/ToastContext.tsx +++ b/packages/client/src/Providers/ToastContext.tsx @@ -1,4 +1,4 @@ -import { createContext, useContext } from 'react'; +import { createContext, useContext, ReactNode } from 'react'; import type { TShowToast } from '~/common'; import useToast from '~/hooks/useToast'; @@ -14,7 +14,7 @@ export function useToastContext() { return useContext(ToastContext); } -export default function ToastProvider({ children }) { +export default function ToastProvider({ children }: { children: ReactNode }) { const { showToast } = useToast(); return {children}; diff --git a/packages/client/src/Providers/index.ts b/packages/client/src/Providers/index.ts new file mode 100644 index 000000000..41cb62ae9 --- /dev/null +++ b/packages/client/src/Providers/index.ts @@ -0,0 +1,2 @@ +export { default as ToastProvider } from './ToastContext'; +export * from './ToastContext'; diff --git a/packages/client/src/common/index.ts b/packages/client/src/common/index.ts new file mode 100644 index 000000000..7a855f3c1 --- /dev/null +++ b/packages/client/src/common/index.ts @@ -0,0 +1,11 @@ +export type { + TShowToast, + Option, + OptionWithIcon, + DropdownValueSetter, + MentionOption, +} from './types'; + +export { NotificationSeverity } from './types'; + +export type { MenuItemProps } from './menus'; diff --git a/packages/client/src/common/menus.ts b/packages/client/src/common/menus.ts new file mode 100644 index 000000000..c46ad3f8b --- /dev/null +++ b/packages/client/src/common/menus.ts @@ -0,0 +1,24 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +export type RenderProp< + P = React.HTMLAttributes & { + ref?: React.Ref; + }, +> = (props: P) => React.ReactNode; + +export interface MenuItemProps { + id?: string; + label?: string; + onClick?: (e: React.MouseEvent) => void; + icon?: React.ReactNode; + kbd?: string; + show?: boolean; + disabled?: boolean; + separate?: boolean; + hideOnClick?: boolean; + dialog?: React.ReactElement; + ref?: React.Ref; + render?: + | RenderProp & { ref?: React.Ref | undefined }> + | React.ReactElement> + | undefined; +} diff --git a/packages/client/src/common/types.ts b/packages/client/src/common/types.ts new file mode 100644 index 000000000..aaeb5f524 --- /dev/null +++ b/packages/client/src/common/types.ts @@ -0,0 +1,33 @@ +export enum NotificationSeverity { + INFO = 'info', + SUCCESS = 'success', + WARNING = 'warning', + ERROR = 'error', +} + +export type TShowToast = { + message: string; + severity?: NotificationSeverity; + showIcon?: boolean; + duration?: number; + status?: 'error' | 'success' | 'warning' | 'info'; +}; + +export type Option = Record & { + label?: string; + value: string | number | null; +}; + +export type OptionWithIcon = Option & { icon?: React.ReactNode }; +export type DropdownValueSetter = (value: string | Option | OptionWithIcon) => void; +export type MentionOption = OptionWithIcon & { + type: string; + value: string; + description?: string; +}; + +export interface SelectedValues { + endpoint: string | null; + model: string | null; + modelSpec: string | null; +} diff --git a/client/src/components/ui/Accordion.tsx b/packages/client/src/components/Accordion.tsx similarity index 94% rename from client/src/components/ui/Accordion.tsx rename to packages/client/src/components/Accordion.tsx index 5c8ed39a7..a969531e8 100644 --- a/client/src/components/ui/Accordion.tsx +++ b/packages/client/src/components/Accordion.tsx @@ -1,7 +1,6 @@ import * as React from 'react'; import * as AccordionPrimitive from '@radix-ui/react-accordion'; import { ChevronDownIcon } from '@radix-ui/react-icons'; - import { cn } from '~/utils'; const Accordion = AccordionPrimitive.Root; @@ -28,7 +27,7 @@ const AccordionTrigger = React.forwardRef< {...props} > {children} - + )); diff --git a/client/src/components/ui/AlertDialog.tsx b/packages/client/src/components/AlertDialog.tsx similarity index 99% rename from client/src/components/ui/AlertDialog.tsx rename to packages/client/src/components/AlertDialog.tsx index 6a5a2dbfc..4e78fda21 100644 --- a/client/src/components/ui/AlertDialog.tsx +++ b/packages/client/src/components/AlertDialog.tsx @@ -1,7 +1,6 @@ import * as React from 'react'; import * as AlertDialogPrimitive from '@radix-ui/react-alert-dialog'; - -import { cn } from '../../utils'; +import { cn } from '~/utils'; const AlertDialog = AlertDialogPrimitive.Root; diff --git a/packages/client/src/components/AnimatedSearchInput.tsx b/packages/client/src/components/AnimatedSearchInput.tsx new file mode 100644 index 000000000..66af0c102 --- /dev/null +++ b/packages/client/src/components/AnimatedSearchInput.tsx @@ -0,0 +1,79 @@ +import React from 'react'; +import { Search } from 'lucide-react'; +import { cn } from '~/utils'; + +const AnimatedSearchInput = ({ + value, + onChange, + isSearching: searching, + placeholder, +}: { + value?: string; + onChange: (e: React.ChangeEvent) => void; + isSearching?: boolean; + placeholder: string; +}) => { + const isSearching = searching === true; + const hasValue = value != null && value.length > 0; + + return ( +
+
+
+ {/* Icon on the left */} +
+ +
+ + {/* Input field */} + + + {/* Gradient overlay */} +
+ + {/* Animated loading indicator */} +
+
+
+
+
+
+
+
+ + {/* Outer glow effect */} +
+
+
+
+
+
+
+
+ ); +}; + +export default AnimatedSearchInput; diff --git a/client/src/components/ui/AnimatedTabs.css b/packages/client/src/components/AnimatedTabs.css similarity index 96% rename from client/src/components/ui/AnimatedTabs.css rename to packages/client/src/components/AnimatedTabs.css index 808f5c4ac..4f16a965c 100644 --- a/client/src/components/ui/AnimatedTabs.css +++ b/packages/client/src/components/AnimatedTabs.css @@ -26,7 +26,7 @@ position: relative; } -.animated-tab[data-state="active"] { +.animated-tab[data-state='active'] { border-bottom-color: transparent !important; } diff --git a/client/src/components/ui/AnimatedTabs.tsx b/packages/client/src/components/AnimatedTabs.tsx similarity index 93% rename from client/src/components/ui/AnimatedTabs.tsx rename to packages/client/src/components/AnimatedTabs.tsx index 809699f30..131d871aa 100644 --- a/client/src/components/ui/AnimatedTabs.tsx +++ b/packages/client/src/components/AnimatedTabs.tsx @@ -1,13 +1,13 @@ import * as Ariakit from '@ariakit/react'; -import { ReactNode, forwardRef, useEffect, useRef } from 'react'; +import { forwardRef, useEffect, useRef } from 'react'; import type { ElementRef } from 'react'; import { cn } from '~/utils'; import './AnimatedTabs.css'; export interface TabItem { id?: string; - label: ReactNode; - content: ReactNode; + label: React.ReactNode; + content: React.ReactNode; disabled?: boolean; } @@ -23,7 +23,7 @@ export interface AnimatedTabsProps { } function usePrevious(value: T) { - const ref = useRef(); + const ref = useRef(undefined); useEffect(() => { ref.current = value; }, [value]); @@ -132,6 +132,7 @@ export function AnimatedTabs({ className={tabClassName} data-state={tabIds[index] === firstTabId ? 'active' : 'inactive'} > + {/* TypeScript workaround for React i18next children type compatibility */} {tab.label} ))} @@ -150,6 +151,7 @@ export function AnimatedTabs({ tabId={tabIds[index]} className={tabPanelClassName} > + {/* TypeScript workaround for React i18next children type compatibility */} {tab.content} ))} diff --git a/client/src/components/ui/Badge.tsx b/packages/client/src/components/Badge.tsx similarity index 92% rename from client/src/components/ui/Badge.tsx rename to packages/client/src/components/Badge.tsx index d99017c73..2469eccb2 100644 --- a/client/src/components/ui/Badge.tsx +++ b/packages/client/src/components/Badge.tsx @@ -1,12 +1,15 @@ import type React from 'react'; - import { X, Plus } from 'lucide-react'; import { motion } from 'framer-motion'; import type { ButtonHTMLAttributes } from 'react'; import type { LucideIcon } from 'lucide-react'; import { cn } from '~/utils'; -interface BadgeProps extends ButtonHTMLAttributes { +interface BadgeProps + extends Omit< + ButtonHTMLAttributes, + 'onAnimationStart' | 'onDragStart' | 'onDragEnd' | 'onDrag' + > { icon?: LucideIcon; label: string; id?: string; @@ -71,7 +74,7 @@ export default function Badge({ }} whileTap={{ scale: isDragging ? 1.1 : isDisabled ? 1 : 0.97 }} transition={{ type: 'tween', duration: 0.1, ease: 'easeOut' }} - {...props} + {...(props as React.ComponentProps)} > {Icon && } {label} diff --git a/client/src/components/ui/Breadcrumb.tsx b/packages/client/src/components/Breadcrumb.tsx similarity index 91% rename from client/src/components/ui/Breadcrumb.tsx rename to packages/client/src/components/Breadcrumb.tsx index 08082e51b..f1026a830 100644 --- a/client/src/components/ui/Breadcrumb.tsx +++ b/packages/client/src/components/Breadcrumb.tsx @@ -1,7 +1,6 @@ import * as React from 'react'; import { Slot } from '@radix-ui/react-slot'; import { ChevronRight, MoreHorizontal } from 'lucide-react'; - import { cn } from '~/utils'; const Breadcrumb = React.forwardRef< @@ -17,7 +16,7 @@ const BreadcrumbList = React.forwardRef ); @@ -58,7 +57,7 @@ const BreadcrumbPage = React.forwardRef ), diff --git a/client/src/components/ui/Button.tsx b/packages/client/src/components/Button.tsx similarity index 100% rename from client/src/components/ui/Button.tsx rename to packages/client/src/components/Button.tsx diff --git a/client/src/components/ui/Checkbox.tsx b/packages/client/src/components/Checkbox.tsx similarity index 96% rename from client/src/components/ui/Checkbox.tsx rename to packages/client/src/components/Checkbox.tsx index a28af18c7..36a81ac73 100644 --- a/client/src/components/ui/Checkbox.tsx +++ b/packages/client/src/components/Checkbox.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; -import * as CheckboxPrimitive from '@radix-ui/react-checkbox'; import { Check } from 'lucide-react'; -import { cn } from '../../utils'; +import * as CheckboxPrimitive from '@radix-ui/react-checkbox'; +import { cn } from '~/utils'; const Checkbox = React.forwardRef< React.ElementRef, diff --git a/client/src/components/ui/CheckboxButton.tsx b/packages/client/src/components/CheckboxButton.tsx similarity index 98% rename from client/src/components/ui/CheckboxButton.tsx rename to packages/client/src/components/CheckboxButton.tsx index d71ee71b4..1858b7b68 100644 --- a/client/src/components/ui/CheckboxButton.tsx +++ b/packages/client/src/components/CheckboxButton.tsx @@ -1,7 +1,7 @@ +import * as React from 'react'; import { useEffect } from 'react'; import { Checkbox, useStoreState, useCheckboxStore } from '@ariakit/react'; import { cn } from '~/utils'; -import * as React from 'react'; const CheckboxButton = React.forwardRef< HTMLInputElement, @@ -63,7 +63,7 @@ const CheckboxButton = React.forwardRef< render={ @@ -211,12 +200,11 @@ export default function DataTable({ onFilterChange, filterValue, isLoading, + enableSearch = true, }: DataTableProps) { - const localize = useLocalize(); const isSmallScreen = useMediaQuery('(max-width: 768px)'); const tableContainerRef = useRef(null); - const search = useRecoilValue(store.search); const [isDeleting, setIsDeleting] = useState(false); const [rowSelection, setRowSelection] = useState>({}); const [sorting, setSorting] = useState(defaultSort); @@ -371,16 +359,15 @@ export default function DataTable({ isDeleting={isDeleting} disabled={!table.getFilteredSelectedRowModel().rows.length || isDeleting} isSmallScreen={isSmallScreen} - localize={localize} /> )} - {filterColumn !== undefined && table.getColumn(filterColumn) && search.enabled && ( + {filterColumn !== undefined && table.getColumn(filterColumn) && enableSearch && (
setSearchTerm(e.target.value)} isSearching={isSearching} - placeholder={`${localize('com_ui_search')}...`} + placeholder="Search..." />
)} @@ -448,7 +435,7 @@ export default function DataTable({ {!virtualRows.length && ( - {localize('com_ui_no_data')} + No data available )} diff --git a/client/src/components/ui/DataTableColumnHeader.tsx b/packages/client/src/components/DataTableColumnHeader.tsx similarity index 83% rename from client/src/components/ui/DataTableColumnHeader.tsx rename to packages/client/src/components/DataTableColumnHeader.tsx index 01d335a0e..606f10b12 100644 --- a/client/src/components/ui/DataTableColumnHeader.tsx +++ b/packages/client/src/components/DataTableColumnHeader.tsx @@ -1,8 +1,5 @@ -import { ArrowDownIcon, ArrowUpIcon, CaretSortIcon, EyeNoneIcon } from '@radix-ui/react-icons'; import { Column } from '@tanstack/react-table'; - -import { cn } from '~/utils'; -import { Button } from './Button'; +import { ArrowDownIcon, ArrowUpIcon, CaretSortIcon, EyeNoneIcon } from '@radix-ui/react-icons'; import { DropdownMenu, DropdownMenuContent, @@ -10,6 +7,8 @@ import { DropdownMenuSeparator, DropdownMenuTrigger, } from './DropdownMenu'; +import { Button } from './Button'; +import { cn } from '~/utils'; interface DataTableColumnHeaderProps extends React.HTMLAttributes { column: Column; @@ -29,7 +28,7 @@ export function DataTableColumnHeader({
- diff --git a/client/src/components/ui/MultiSelect.tsx b/packages/client/src/components/MultiSelect.tsx similarity index 92% rename from client/src/components/ui/MultiSelect.tsx rename to packages/client/src/components/MultiSelect.tsx index 20e251279..d7798e810 100644 --- a/client/src/components/ui/MultiSelect.tsx +++ b/packages/client/src/components/MultiSelect.tsx @@ -14,7 +14,6 @@ interface MultiSelectProps { items: T[]; label?: string; placeholder?: string; - defaultSelectedValues?: T[]; onSelectedValuesChange?: (values: T[]) => void; renderSelectedValues?: (values: T[], placeholder?: string) => React.ReactNode; className?: string; @@ -47,7 +46,6 @@ export default function MultiSelect({ items, label, placeholder = 'Select...', - defaultSelectedValues = [], onSelectedValuesChange, renderSelectedValues = defaultRender, className, @@ -89,7 +87,7 @@ export default function MultiSelect({ )} onChange={(e) => e.stopPropagation()} > - {selectIcon && selectIcon} + {selectIcon && {selectIcon as React.JSX.Element}} {renderSelectedValues(selectedValues, placeholder)} @@ -132,8 +130,12 @@ export default function MultiSelect({ )} > {renderItemContent - ? renderItemContent(value, defaultContent, isCurrentItemSelected) - : defaultContent} + ? (renderItemContent( + value, + defaultContent, + isCurrentItemSelected, + ) as React.JSX.Element) + : (defaultContent as React.JSX.Element)} ); })} diff --git a/client/src/components/ui/OGDialogTemplate.tsx b/packages/client/src/components/OGDialogTemplate.tsx similarity index 93% rename from client/src/components/ui/OGDialogTemplate.tsx rename to packages/client/src/components/OGDialogTemplate.tsx index 8595c13ac..fe2e919a4 100644 --- a/client/src/components/ui/OGDialogTemplate.tsx +++ b/packages/client/src/components/OGDialogTemplate.tsx @@ -9,7 +9,7 @@ import { } from './OriginalDialog'; import { useLocalize } from '~/hooks'; import { Button } from './Button'; -import { Spinner } from '../svg'; +import { Spinner } from '~/svgs'; import { cn } from '~/utils/'; type SelectionProps = { @@ -97,7 +97,11 @@ const OGDialogTemplate = forwardRef((props: DialogTemplateProps, ref: Ref - {isLoading === true ? : selectText} + {isLoading === true ? ( + + ) : ( + (selectText as React.JSX.Element) + )} ) : null}
diff --git a/client/src/components/ui/OriginalDialog.tsx b/packages/client/src/components/OriginalDialog.tsx similarity index 100% rename from client/src/components/ui/OriginalDialog.tsx rename to packages/client/src/components/OriginalDialog.tsx diff --git a/client/src/components/ui/Pagination.tsx b/packages/client/src/components/Pagination.tsx similarity index 100% rename from client/src/components/ui/Pagination.tsx rename to packages/client/src/components/Pagination.tsx diff --git a/client/src/components/ui/PixelCard.tsx b/packages/client/src/components/PixelCard.tsx similarity index 96% rename from client/src/components/ui/PixelCard.tsx rename to packages/client/src/components/PixelCard.tsx index 141a3ee55..c1f3d8971 100644 --- a/client/src/components/ui/PixelCard.tsx +++ b/packages/client/src/components/PixelCard.tsx @@ -173,7 +173,7 @@ export default function PixelCard({ const containerRef = useRef(null); const canvasRef = useRef(null); const pixelsRef = useRef([]); - const animationRef = useRef(); + const animationRef = useRef(undefined); const timePrevRef = useRef(performance.now()); const progressRef = useRef(progress); const reducedMotion = useRef( @@ -221,9 +221,11 @@ export default function PixelCard({ let idle = true; for (const p of pixelsRef.current) { if (method === 'appearWithProgress') { - progressRef.current !== undefined - ? p.appearWithProgress(progressRef.current) - : (p.isIdle = true); + if (progressRef.current !== undefined) { + p.appearWithProgress(progressRef.current); + } else { + p.isIdle = true; + } } else { // @ts-ignore dynamic dispatch p[method](); @@ -312,7 +314,9 @@ export default function PixelCard({ useEffect(() => { initPixels(); const obs = new ResizeObserver(initPixels); - containerRef.current && obs.observe(containerRef.current); + if (containerRef.current) { + obs.observe(containerRef.current); + } return () => { obs.disconnect(); cancelAnimationFrame(animationRef.current!); diff --git a/client/src/components/ui/Progress.tsx b/packages/client/src/components/Progress.tsx similarity index 100% rename from client/src/components/ui/Progress.tsx rename to packages/client/src/components/Progress.tsx diff --git a/client/src/components/ui/QuestionMark.tsx b/packages/client/src/components/QuestionMark.tsx similarity index 99% rename from client/src/components/ui/QuestionMark.tsx rename to packages/client/src/components/QuestionMark.tsx index 89785837a..f018226f1 100644 --- a/client/src/components/ui/QuestionMark.tsx +++ b/packages/client/src/components/QuestionMark.tsx @@ -1,4 +1,5 @@ import { cn } from '~/utils'; + export const QuestionMark = ({ className = '' }) => { return ( diff --git a/client/src/components/ui/Resizable.tsx b/packages/client/src/components/Resizable.tsx similarity index 75% rename from client/src/components/ui/Resizable.tsx rename to packages/client/src/components/Resizable.tsx index fc9a32df8..19d3c50e3 100644 --- a/client/src/components/ui/Resizable.tsx +++ b/packages/client/src/components/Resizable.tsx @@ -24,13 +24,13 @@ const ResizableHandle = ({ }) => ( div]:rotate-90', + 'relative flex w-px items-center justify-center bg-border after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1 data-[panel-group-direction=vertical]:h-px data-[panel-group-direction=vertical]:w-full data-[panel-group-direction=vertical]:after:left-0 data-[panel-group-direction=vertical]:after:h-1 data-[panel-group-direction=vertical]:after:w-full data-[panel-group-direction=vertical]:after:-translate-y-1/2 data-[panel-group-direction=vertical]:after:translate-x-0 [&[data-panel-group-direction=vertical]>div]:rotate-90', className, )} {...props} > {withHandle && ( -
+
)} @@ -46,13 +46,13 @@ const ResizableHandleAlt = ({ }) => ( div]:rotate-90', + 'group relative flex w-px items-center justify-center bg-border after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1 data-[panel-group-direction=vertical]:h-px data-[panel-group-direction=vertical]:w-full data-[panel-group-direction=vertical]:after:left-0 data-[panel-group-direction=vertical]:after:h-1 data-[panel-group-direction=vertical]:after:w-full data-[panel-group-direction=vertical]:after:-translate-y-1/2 data-[panel-group-direction=vertical]:after:translate-x-0 [&[data-panel-group-direction=vertical]>div]:rotate-90', className, )} {...props} > {withHandle && ( -
+
)} diff --git a/client/src/components/ui/Select.tsx b/packages/client/src/components/Select.tsx similarity index 97% rename from client/src/components/ui/Select.tsx rename to packages/client/src/components/Select.tsx index 671bae443..3301e3577 100644 --- a/client/src/components/ui/Select.tsx +++ b/packages/client/src/components/Select.tsx @@ -4,12 +4,15 @@ import { CaretSortIcon, CheckIcon, ChevronDownIcon, ChevronUpIcon } from '@radix import { cn } from '~/utils'; +// @ts-ignore - Radix UI type conflicts with React types const Select = SelectPrimitive.Root; +// @ts-ignore - Radix UI type conflicts with React types const SelectGroup = SelectPrimitive.Group; const SelectValue = SelectPrimitive.Value; +// @ts-ignore - Radix UI type conflicts with React types const SelectTrigger = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef diff --git a/client/src/components/ui/SelectDropDown.tsx b/packages/client/src/components/SelectDropDown.tsx similarity index 96% rename from client/src/components/ui/SelectDropDown.tsx rename to packages/client/src/components/SelectDropDown.tsx index 454799192..e9a6027bc 100644 --- a/client/src/components/ui/SelectDropDown.tsx +++ b/packages/client/src/components/SelectDropDown.tsx @@ -8,10 +8,9 @@ import { ListboxOptions, } from '@headlessui/react'; import type { Option, OptionWithIcon, DropdownValueSetter } from '~/common'; -import CheckMark from '~/components/svg/CheckMark'; import { useMultiSearch } from './MultiSearch'; -import { useLocalize } from '~/hooks'; -import { cn } from '~/utils/'; +import { CheckMark } from '~/svgs'; +import { cn } from '~/utils'; type SelectDropDownProps = { id?: string; @@ -75,7 +74,6 @@ function SelectDropDown({ searchPlaceholder, showOptionIcon = false, }: SelectDropDownProps) { - const localize = useLocalize(); const transitionProps = { className: 'top-full mt-3' }; if (showAbove) { transitionProps.className = 'bottom-full mb-3'; @@ -84,9 +82,8 @@ function SelectDropDown({ let title = _title; if (emptyTitle) { title = ''; - } else if (!(title ?? '')) { - title = localize('com_ui_model'); } + const values = availableValues ?? []; // Enable searchable select if enough items are provided. @@ -186,7 +183,7 @@ function SelectDropDown({ - {renderOption()} + {renderOption() as React.JSX.Element} )} - {searchRender} + {searchRender as React.JSX.Element} {options.map((option: string | Option, i: number) => { if (!option) { return null; diff --git a/client/src/components/ui/Separator.tsx b/packages/client/src/components/Separator.tsx similarity index 67% rename from client/src/components/ui/Separator.tsx rename to packages/client/src/components/Separator.tsx index f95d48a79..7ba6d3809 100644 --- a/client/src/components/ui/Separator.tsx +++ b/packages/client/src/components/Separator.tsx @@ -5,18 +5,22 @@ import { cn } from '~/utils'; const Separator = React.forwardRef< React.ElementRef, - React.ComponentPropsWithoutRef + React.ComponentPropsWithoutRef & { + className?: string; + } >(({ className = '', orientation = 'horizontal', decorative = true, ...props }, ref) => ( )); Separator.displayName = SeparatorPrimitive.Root.displayName; diff --git a/client/src/components/ui/Skeleton.tsx b/packages/client/src/components/Skeleton.tsx similarity index 100% rename from client/src/components/ui/Skeleton.tsx rename to packages/client/src/components/Skeleton.tsx diff --git a/packages/client/src/components/Slider.tsx b/packages/client/src/components/Slider.tsx new file mode 100644 index 000000000..4be0f2003 --- /dev/null +++ b/packages/client/src/components/Slider.tsx @@ -0,0 +1,38 @@ +import * as React from 'react'; +import * as SliderPrimitive from '@radix-ui/react-slider'; +import { cn } from '~/utils'; + +const Slider = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + className?: string; + onDoubleClick?: () => void; + } +>(({ className, onDoubleClick, ...props }, ref) => ( + + + + + + +)); +Slider.displayName = SliderPrimitive.Root.displayName; + +export { Slider }; diff --git a/client/src/components/ui/SplitText.spec.tsx b/packages/client/src/components/SplitText.spec.tsx similarity index 100% rename from client/src/components/ui/SplitText.spec.tsx rename to packages/client/src/components/SplitText.spec.tsx diff --git a/client/src/components/ui/SplitText.tsx b/packages/client/src/components/SplitText.tsx similarity index 77% rename from client/src/components/ui/SplitText.tsx rename to packages/client/src/components/SplitText.tsx index cde04eb8a..46dd75736 100644 --- a/client/src/components/ui/SplitText.tsx +++ b/packages/client/src/components/SplitText.tsx @@ -1,6 +1,36 @@ import { useSprings, animated, SpringConfig } from '@react-spring/web'; import { useEffect, useRef, useState } from 'react'; +interface SegmenterOptions { + granularity?: 'grapheme' | 'word' | 'sentence'; + localeMatcher?: 'lookup' | 'best fit'; +} + +interface SegmentData { + segment: string; + index: number; + input: string; + isWordLike?: boolean; +} + +interface Segments { + [Symbol.iterator](): IterableIterator; +} + +interface IntlSegmenter { + segment(input: string): Segments; +} + +interface IntlSegmenterConstructor { + new (locales?: string | string[], options?: SegmenterOptions): IntlSegmenter; +} + +declare global { + interface Intl { + Segmenter: IntlSegmenterConstructor; + } +} + interface SplitTextProps { text?: string; className?: string; @@ -16,12 +46,14 @@ interface SplitTextProps { } const splitGraphemes = (text: string): string[] => { - if (typeof Intl !== 'undefined' && Intl.Segmenter) { - const segmenter = new Intl.Segmenter('en', { granularity: 'grapheme' }); + if (typeof Intl !== 'undefined' && 'Segmenter' in Intl) { + const segmenter = new (Intl as typeof Intl & { Segmenter: IntlSegmenterConstructor }).Segmenter( + 'en', + { granularity: 'grapheme' }, + ); const segments = segmenter.segment(text); - return Array.from(segments).map((s) => s.segment); + return Array.from(segments).map((s: SegmentData) => s.segment); } else { - // Fallback for browsers without Intl.Segmenter return [...text]; } }; @@ -45,12 +77,12 @@ const SplitText: React.FC = ({ const ref = useRef(null); const animatedCount = useRef(0); - const springs = useSprings( + const [springs] = useSprings( letters.length, - letters.map((_, i) => ({ + (i) => ({ from: animationFrom, to: inView - ? async (next: (props: any) => Promise) => { + ? async (next) => { await next(animationTo); animatedCount.current += 1; if (animatedCount.current === letters.length && onLetterAnimationComplete) { @@ -60,7 +92,8 @@ const SplitText: React.FC = ({ : animationFrom, delay: i * delay, config: { easing }, - })), + }), + [inView, text, delay, animationFrom, animationTo, easing, onLetterAnimationComplete], ); useEffect(() => { @@ -118,7 +151,7 @@ const SplitText: React.FC = ({ return ( {letter} diff --git a/client/src/components/ui/Switch.tsx b/packages/client/src/components/Switch.tsx similarity index 100% rename from client/src/components/ui/Switch.tsx rename to packages/client/src/components/Switch.tsx diff --git a/client/src/components/ui/Table.tsx b/packages/client/src/components/Table.tsx similarity index 100% rename from client/src/components/ui/Table.tsx rename to packages/client/src/components/Table.tsx diff --git a/client/src/components/ui/Tabs.tsx b/packages/client/src/components/Tabs.tsx similarity index 100% rename from client/src/components/ui/Tabs.tsx rename to packages/client/src/components/Tabs.tsx diff --git a/client/src/components/ui/Tag.tsx b/packages/client/src/components/Tag.tsx similarity index 76% rename from client/src/components/ui/Tag.tsx rename to packages/client/src/components/Tag.tsx index 38660d11c..4d17617d6 100644 --- a/client/src/components/ui/Tag.tsx +++ b/packages/client/src/components/Tag.tsx @@ -30,17 +30,17 @@ const TagPrimitiveRoot = React.forwardRef( {CancelButton ? CancelButton : onRemove && ( - - )} + + )}
), ); diff --git a/client/src/components/ui/Textarea.tsx b/packages/client/src/components/Textarea.tsx similarity index 96% rename from client/src/components/ui/Textarea.tsx rename to packages/client/src/components/Textarea.tsx index a738bc8b7..f9167e91c 100644 --- a/client/src/components/ui/Textarea.tsx +++ b/packages/client/src/components/Textarea.tsx @@ -1,8 +1,7 @@ /* eslint-disable */ import * as React from 'react'; import TextareaAutosize from 'react-textarea-autosize'; - -import { cn } from '../../utils'; +import { cn } from '~/utils'; export interface TextareaProps extends React.TextareaHTMLAttributes {} diff --git a/client/src/components/ui/TextareaAutosize.tsx b/packages/client/src/components/TextareaAutosize.tsx similarity index 75% rename from client/src/components/ui/TextareaAutosize.tsx rename to packages/client/src/components/TextareaAutosize.tsx index eeaa94d4a..78083ab7a 100644 --- a/client/src/components/ui/TextareaAutosize.tsx +++ b/packages/client/src/components/TextareaAutosize.tsx @@ -1,13 +1,13 @@ -import { useRecoilValue } from 'recoil'; +import { useAtomValue } from 'jotai'; import { forwardRef, useLayoutEffect, useState } from 'react'; import ReactTextareaAutosize from 'react-textarea-autosize'; import type { TextareaAutosizeProps } from 'react-textarea-autosize'; -import store from '~/store'; +import { chatDirectionAtom } from '~/store'; export const TextareaAutosize = forwardRef( (props, ref) => { const [, setIsRerendered] = useState(false); - const chatDirection = useRecoilValue(store.chatDirection).toLowerCase(); + const chatDirection = useAtomValue(chatDirectionAtom).toLowerCase(); useLayoutEffect(() => setIsRerendered(true), []); return ; }, diff --git a/client/src/components/ui/ThemeSelector.tsx b/packages/client/src/components/ThemeSelector.tsx similarity index 91% rename from client/src/components/ui/ThemeSelector.tsx rename to packages/client/src/components/ThemeSelector.tsx index e643f05d8..5954b96e7 100644 --- a/client/src/components/ui/ThemeSelector.tsx +++ b/packages/client/src/components/ThemeSelector.tsx @@ -1,6 +1,6 @@ -import React, { useContext, useCallback, useEffect, useState } from 'react'; +import { useContext, useCallback, useEffect, useState } from 'react'; import { Sun, Moon, Monitor } from 'lucide-react'; -import { ThemeContext } from '~/hooks'; +import { ThemeContext } from '../theme'; declare global { interface Window { @@ -8,8 +8,10 @@ declare global { } } +type ThemeType = 'system' | 'dark' | 'light'; + const Theme = ({ theme, onChange }: { theme: string; onChange: (value: string) => void }) => { - const themeIcons = { + const themeIcons: Record = { system: , dark: , light: , @@ -45,7 +47,7 @@ const Theme = ({ theme, onChange }: { theme: string; onChange: (value: string) = } }} > - {themeIcons[theme]} + {themeIcons[theme as ThemeType]} ); }; diff --git a/client/src/components/ui/Toast.tsx b/packages/client/src/components/Toast.tsx similarity index 98% rename from client/src/components/ui/Toast.tsx rename to packages/client/src/components/Toast.tsx index 54dcc4ed0..34ca1a053 100644 --- a/client/src/components/ui/Toast.tsx +++ b/packages/client/src/components/Toast.tsx @@ -2,7 +2,7 @@ import * as RadixToast from '@radix-ui/react-toast'; import { NotificationSeverity } from '~/common/types'; import { useToast } from '~/hooks'; -export default function Toast() { +export function Toast() { const { toast, onOpenChange } = useToast(); const severityClassName = { [NotificationSeverity.INFO]: 'border-gray-500 bg-gray-500', diff --git a/client/src/components/ui/Tooltip.tsx b/packages/client/src/components/Tooltip.tsx similarity index 100% rename from client/src/components/ui/Tooltip.tsx rename to packages/client/src/components/Tooltip.tsx diff --git a/packages/client/src/components/index.ts b/packages/client/src/components/index.ts new file mode 100644 index 000000000..edaf240dc --- /dev/null +++ b/packages/client/src/components/index.ts @@ -0,0 +1,51 @@ +export * from './Accordion'; +export * from './AnimatedTabs'; +export * from './AlertDialog'; +export * from './Breadcrumb'; +export * from './Button'; +export * from './Checkbox'; +export * from './DataTableColumnHeader'; +export * from './Dialog'; +export * from './DropdownMenu'; +export * from './HoverCard'; +export * from './Input'; +export * from './InputNumber'; +export * from './Label'; +export * from './OriginalDialog'; +export * from './QuestionMark'; +export * from './Slider'; +export * from './Separator'; +export * from './InputCombobox'; +export * from './Skeleton'; +export * from './Switch'; +export * from './Table'; +export * from './Tabs'; +export * from './Tag'; +export * from './Textarea'; +export * from './TextareaAutosize'; +export * from './Toast'; +export * from './Tooltip'; +export * from './Pagination'; +export * from './Progress'; +export * from './InputOTP'; +export * from './MultiSearch'; +export * from './Resizable'; +export { default as Badge } from './Badge'; +export { default as Combobox } from './Combobox'; +export { default as Dropdown } from './Dropdown'; +export { default as SplitText } from './SplitText'; +export { default as DataTable } from './DataTable'; +export { default as FormInput } from './FormInput'; +export { default as PixelCard } from './PixelCard'; +export { default as FileUpload } from './FileUpload'; +export { default as MultiSelect } from './MultiSelect'; +export { default as DropdownPopup } from './DropdownPopup'; +export { default as DelayedRender } from './DelayedRender'; +export { default as ThemeSelector } from './ThemeSelector'; +export { default as CheckboxButton } from './CheckboxButton'; +export { default as DialogTemplate } from './DialogTemplate'; +export { default as SelectDropDown } from './SelectDropDown'; +export { default as ControlCombobox } from './ControlCombobox'; +export { default as OGDialogTemplate } from './OGDialogTemplate'; +export { default as InputWithDropdown } from './InputWithDropDown'; +export { default as AnimatedSearchInput } from './AnimatedSearchInput'; diff --git a/client/src/hooks/ThemeContext.tsx b/packages/client/src/hooks/ThemeContext.old.tsx similarity index 89% rename from client/src/hooks/ThemeContext.tsx rename to packages/client/src/hooks/ThemeContext.old.tsx index 76b272598..74516fcab 100644 --- a/client/src/hooks/ThemeContext.tsx +++ b/packages/client/src/hooks/ThemeContext.old.tsx @@ -1,9 +1,9 @@ //ThemeContext.js // source: https://plainenglish.io/blog/light-and-dark-mode-in-react-web-application-with-tailwind-css-89674496b942 -import { useSetRecoilState } from 'recoil'; +import { useSetAtom } from 'jotai'; import React, { createContext, useState, useEffect } from 'react'; import { getInitialTheme, applyFontSize } from '~/utils'; -import store from '~/store'; +import { fontSizeAtom } from '~/store'; type ProviderValue = { theme: string; @@ -26,9 +26,15 @@ export const isDark = (theme: string): boolean => { export const ThemeContext = createContext(defaultContextValue); -export const ThemeProvider = ({ initialTheme, children }) => { +export const ThemeProvider = ({ + initialTheme, + children, +}: { + initialTheme?: string; + children: React.ReactNode; +}) => { const [theme, setTheme] = useState(getInitialTheme); - const setFontSize = useSetRecoilState(store.fontSize); + const setFontSize = useSetAtom(fontSizeAtom); const rawSetTheme = (rawTheme: string) => { const root = window.document.documentElement; diff --git a/packages/client/src/hooks/index.ts b/packages/client/src/hooks/index.ts new file mode 100644 index 000000000..019dae0ee --- /dev/null +++ b/packages/client/src/hooks/index.ts @@ -0,0 +1,10 @@ +// Theme exports are now handled by the theme module in the main index.ts + +export type { TranslationKeys } from './useLocalize'; + +export { default as useToast } from './useToast'; +export { default as useCombobox } from './useCombobox'; +export { default as useLocalize } from './useLocalize'; +export { default as useMediaQuery } from './useMediaQuery'; +export { default as useDelayedRender } from './useDelayedRender'; +export { default as useOnClickOutside } from './useOnClickOutside'; diff --git a/client/src/hooks/Input/useCombobox.ts b/packages/client/src/hooks/useCombobox.ts similarity index 100% rename from client/src/hooks/Input/useCombobox.ts rename to packages/client/src/hooks/useCombobox.ts diff --git a/client/src/hooks/useDelayedRender.tsx b/packages/client/src/hooks/useDelayedRender.tsx similarity index 100% rename from client/src/hooks/useDelayedRender.tsx rename to packages/client/src/hooks/useDelayedRender.tsx diff --git a/packages/client/src/hooks/useLocalize.ts b/packages/client/src/hooks/useLocalize.ts new file mode 100644 index 000000000..83366cff1 --- /dev/null +++ b/packages/client/src/hooks/useLocalize.ts @@ -0,0 +1,21 @@ +import { useEffect } from 'react'; +import { TOptions } from 'i18next'; +import { useAtomValue } from 'jotai'; +import { useTranslation } from 'react-i18next'; +import { resources } from '~/locales/i18n'; +import { langAtom } from '~/store'; + +export type TranslationKeys = keyof typeof resources.en.translation; + +export default function useLocalize() { + const lang = useAtomValue(langAtom); + const { t, i18n } = useTranslation(); + + useEffect(() => { + if (i18n.language !== lang) { + i18n.changeLanguage(lang); + } + }, [lang, i18n]); + + return (phraseKey: TranslationKeys, options?: TOptions) => t(phraseKey, options); +} diff --git a/client/src/hooks/useMediaQuery.tsx b/packages/client/src/hooks/useMediaQuery.tsx similarity index 100% rename from client/src/hooks/useMediaQuery.tsx rename to packages/client/src/hooks/useMediaQuery.tsx diff --git a/client/src/hooks/useOnClickOutside.ts b/packages/client/src/hooks/useOnClickOutside.ts similarity index 100% rename from client/src/hooks/useOnClickOutside.ts rename to packages/client/src/hooks/useOnClickOutside.ts diff --git a/client/src/hooks/useToast.ts b/packages/client/src/hooks/useToast.ts similarity index 87% rename from client/src/hooks/useToast.ts rename to packages/client/src/hooks/useToast.ts index 92f7bbfe1..9937c640d 100644 --- a/client/src/hooks/useToast.ts +++ b/packages/client/src/hooks/useToast.ts @@ -1,11 +1,11 @@ -import { useRecoilState } from 'recoil'; +import { useAtom } from 'jotai'; import { useRef, useEffect } from 'react'; import type { TShowToast } from '~/common'; import { NotificationSeverity } from '~/common'; -import store from '~/store'; +import { toastState, type ToastState } from '~/store'; export default function useToast(showDelay = 100) { - const [toast, setToast] = useRecoilState(store.toastState); + const [toast, setToast] = useAtom(toastState); const showTimerRef = useRef(null); const hideTimerRef = useRef(null); @@ -45,7 +45,7 @@ export default function useToast(showDelay = 100) { }); // Hides the toast after the specified duration hideTimerRef.current = window.setTimeout(() => { - setToast((prevToast) => ({ ...prevToast, open: false })); + setToast((prevToast: ToastState) => ({ ...prevToast, open: false })); }, duration); }, showDelay); }; diff --git a/packages/client/src/index.ts b/packages/client/src/index.ts new file mode 100644 index 000000000..709697c99 --- /dev/null +++ b/packages/client/src/index.ts @@ -0,0 +1,24 @@ +// Components +export * from './components'; + +// Hooks +export * from './hooks'; + +// Common +export * from './common'; +export * from './common/types'; + +// Store +export * from './store'; + +// SVGs +export * from './svgs'; + +// Utils +export * from './utils'; + +// Providers +export * from './Providers'; + +// Theme +export * from './theme'; diff --git a/packages/client/src/locales/Translation.spec.ts b/packages/client/src/locales/Translation.spec.ts new file mode 100644 index 000000000..fc3de6e0e --- /dev/null +++ b/packages/client/src/locales/Translation.spec.ts @@ -0,0 +1,47 @@ +import i18n from './i18n'; +import English from './en/translation.json'; +import French from './fr/translation.json'; +import Spanish from './es/translation.json'; + +describe('i18next translation tests', () => { + // Ensure i18next is initialized before any tests run + beforeAll(async () => { + if (!i18n.isInitialized) { + await i18n.init(); + } + }); + + it('should return the correct translation for a valid key in English', () => { + i18n.changeLanguage('en'); + expect(i18n.t('com_ui_examples')).toBe(English.com_ui_examples); + }); + + it('should return the correct translation for a valid key in French', () => { + i18n.changeLanguage('fr'); + expect(i18n.t('com_ui_examples')).toBe(French.com_ui_examples); + }); + + it('should return the correct translation for a valid key in Spanish', () => { + i18n.changeLanguage('es'); + expect(i18n.t('com_ui_examples')).toBe(Spanish.com_ui_examples); + }); + + it('should fallback to English for an invalid language code', () => { + // When an invalid language is provided, i18next should fallback to English + i18n.changeLanguage('invalid-code'); + expect(i18n.t('com_ui_examples')).toBe(English.com_ui_examples); + }); + + it('should return the key itself for an invalid key', () => { + i18n.changeLanguage('en'); + expect(i18n.t('invalid-key')).toBe('invalid-key'); // Returns the key itself + }); + + it('should correctly format placeholders in the translation', () => { + i18n.changeLanguage('en'); + expect(i18n.t('com_endpoint_default_with_num', { 0: 'John' })).toBe('default: John'); + + i18n.changeLanguage('fr'); + expect(i18n.t('com_endpoint_default_with_num', { 0: 'Marie' })).toBe('par défaut : Marie'); + }); +}); diff --git a/packages/client/src/locales/ar/translation.json b/packages/client/src/locales/ar/translation.json new file mode 100644 index 000000000..aa0372363 --- /dev/null +++ b/packages/client/src/locales/ar/translation.json @@ -0,0 +1,3 @@ +{ + "com_ui_cancel": "إلغاء" +} diff --git a/packages/client/src/locales/ca/translation.json b/packages/client/src/locales/ca/translation.json new file mode 100644 index 000000000..8c42ae78f --- /dev/null +++ b/packages/client/src/locales/ca/translation.json @@ -0,0 +1,3 @@ +{ + "com_ui_cancel": "Cancel·la" +} diff --git a/packages/client/src/locales/cs/translation.json b/packages/client/src/locales/cs/translation.json new file mode 100644 index 000000000..4d34a884c --- /dev/null +++ b/packages/client/src/locales/cs/translation.json @@ -0,0 +1,3 @@ +{ + "com_ui_cancel": "Zrušit" +} diff --git a/packages/client/src/locales/da/translation.json b/packages/client/src/locales/da/translation.json new file mode 100644 index 000000000..796263989 --- /dev/null +++ b/packages/client/src/locales/da/translation.json @@ -0,0 +1,3 @@ +{ + "com_ui_cancel": "Annuller" +} diff --git a/packages/client/src/locales/de/translation.json b/packages/client/src/locales/de/translation.json new file mode 100644 index 000000000..b1d864561 --- /dev/null +++ b/packages/client/src/locales/de/translation.json @@ -0,0 +1,3 @@ +{ + "com_ui_cancel": "Abbrechen" +} diff --git a/packages/client/src/locales/en/translation.json b/packages/client/src/locales/en/translation.json new file mode 100644 index 000000000..de39a3005 --- /dev/null +++ b/packages/client/src/locales/en/translation.json @@ -0,0 +1,3 @@ +{ + "com_ui_cancel": "Cancel" +} diff --git a/packages/client/src/locales/es/translation.json b/packages/client/src/locales/es/translation.json new file mode 100644 index 000000000..c831d5737 --- /dev/null +++ b/packages/client/src/locales/es/translation.json @@ -0,0 +1,3 @@ +{ + "com_ui_cancel": "Cancelar" +} diff --git a/packages/client/src/locales/et/translation.json b/packages/client/src/locales/et/translation.json new file mode 100644 index 000000000..fffcde416 --- /dev/null +++ b/packages/client/src/locales/et/translation.json @@ -0,0 +1,3 @@ +{ + "com_ui_cancel": "Tühista" +} diff --git a/packages/client/src/locales/fa/translation.json b/packages/client/src/locales/fa/translation.json new file mode 100644 index 000000000..73e57d028 --- /dev/null +++ b/packages/client/src/locales/fa/translation.json @@ -0,0 +1,3 @@ +{ + "com_ui_cancel": "لغو کنید" +} diff --git a/packages/client/src/locales/fi/translation.json b/packages/client/src/locales/fi/translation.json new file mode 100644 index 000000000..00797137b --- /dev/null +++ b/packages/client/src/locales/fi/translation.json @@ -0,0 +1,3 @@ +{ + "com_ui_cancel": "Peruuta" +} diff --git a/packages/client/src/locales/fr/translation.json b/packages/client/src/locales/fr/translation.json new file mode 100644 index 000000000..1d6265d6c --- /dev/null +++ b/packages/client/src/locales/fr/translation.json @@ -0,0 +1,3 @@ +{ + "com_ui_cancel": "Annuler" +} diff --git a/packages/client/src/locales/he/translation.json b/packages/client/src/locales/he/translation.json new file mode 100644 index 000000000..5bf5a86d9 --- /dev/null +++ b/packages/client/src/locales/he/translation.json @@ -0,0 +1,3 @@ +{ + "com_ui_cancel": "בטל" +} diff --git a/packages/client/src/locales/hu/translation.json b/packages/client/src/locales/hu/translation.json new file mode 100644 index 000000000..8616ee927 --- /dev/null +++ b/packages/client/src/locales/hu/translation.json @@ -0,0 +1,3 @@ +{ + "com_ui_cancel": "Mégse" +} diff --git a/packages/client/src/locales/i18n.ts b/packages/client/src/locales/i18n.ts new file mode 100644 index 000000000..f463723a4 --- /dev/null +++ b/packages/client/src/locales/i18n.ts @@ -0,0 +1,87 @@ +import i18n from 'i18next'; +import { initReactI18next } from 'react-i18next'; +import LanguageDetector from 'i18next-browser-languagedetector'; + +import translationEn from './en/translation.json'; +import translationAr from './ar/translation.json'; +import translationCa from './ca/translation.json'; +import translationCs from './cs/translation.json'; +import translationDa from './da/translation.json'; +import translationDe from './de/translation.json'; +import translationEs from './es/translation.json'; +import translationEt from './et/translation.json'; +import translationFa from './fa/translation.json'; +import translationFr from './fr/translation.json'; +import translationIt from './it/translation.json'; +import translationPl from './pl/translation.json'; +import translationPt_BR from './pt-BR/translation.json'; +import translationPt_PT from './pt-PT/translation.json'; +import translationRu from './ru/translation.json'; +import translationJa from './ja/translation.json'; +import translationKa from './ka/translation.json'; +import translationSv from './sv/translation.json'; +import translationKo from './ko/translation.json'; +import translationTh from './th/translation.json'; +import translationTr from './tr/translation.json'; +import translationVi from './vi/translation.json'; +import translationNl from './nl/translation.json'; +import translationId from './id/translation.json'; +import translationHe from './he/translation.json'; +import translationHu from './hu/translation.json'; +import translationFi from './fi/translation.json'; +import translationZh_Hans from './zh-Hans/translation.json'; +import translationZh_Hant from './zh-Hant/translation.json'; + +export const defaultNS = 'translation'; + +export const resources = { + en: { translation: translationEn }, + ar: { translation: translationAr }, + ca: { translation: translationCa }, + cs: { translation: translationCs }, + 'zh-Hans': { translation: translationZh_Hans }, + 'zh-Hant': { translation: translationZh_Hant }, + da: { translation: translationDa }, + de: { translation: translationDe }, + es: { translation: translationEs }, + et: { translation: translationEt }, + fa: { translation: translationFa }, + fr: { translation: translationFr }, + it: { translation: translationIt }, + pl: { translation: translationPl }, + 'pt-BR': { translation: translationPt_BR }, + 'pt-PT': { translation: translationPt_PT }, + ru: { translation: translationRu }, + ja: { translation: translationJa }, + ka: { translation: translationKa }, + sv: { translation: translationSv }, + ko: { translation: translationKo }, + th: { translation: translationTh }, + tr: { translation: translationTr }, + vi: { translation: translationVi }, + nl: { translation: translationNl }, + id: { translation: translationId }, + he: { translation: translationHe }, + hu: { translation: translationHu }, + fi: { translation: translationFi }, +} as const; + +i18n + .use(LanguageDetector) + .use(initReactI18next) + .init({ + fallbackLng: { + 'zh-TW': ['zh-Hant', 'en'], + 'zh-HK': ['zh-Hant', 'en'], + zh: ['zh-Hans', 'en'], + default: ['en'], + }, + fallbackNS: 'translation', + ns: ['translation'], + debug: false, + defaultNS, + resources, + interpolation: { escapeValue: false }, + }); + +export default i18n; diff --git a/packages/client/src/locales/id/translation.json b/packages/client/src/locales/id/translation.json new file mode 100644 index 000000000..24d3467bd --- /dev/null +++ b/packages/client/src/locales/id/translation.json @@ -0,0 +1,3 @@ +{ + "com_ui_cancel": "Batal" +} diff --git a/packages/client/src/locales/it/translation.json b/packages/client/src/locales/it/translation.json new file mode 100644 index 000000000..cc082b4a2 --- /dev/null +++ b/packages/client/src/locales/it/translation.json @@ -0,0 +1,3 @@ +{ + "com_ui_cancel": "Annulla" +} diff --git a/packages/client/src/locales/ja/translation.json b/packages/client/src/locales/ja/translation.json new file mode 100644 index 000000000..4400b0282 --- /dev/null +++ b/packages/client/src/locales/ja/translation.json @@ -0,0 +1,3 @@ +{ + "com_ui_cancel": "キャンセル" +} diff --git a/packages/client/src/locales/ka/translation.json b/packages/client/src/locales/ka/translation.json new file mode 100644 index 000000000..0c90d6bf7 --- /dev/null +++ b/packages/client/src/locales/ka/translation.json @@ -0,0 +1,3 @@ +{ + "com_ui_cancel": "გაუქმება" +} diff --git a/packages/client/src/locales/ko/translation.json b/packages/client/src/locales/ko/translation.json new file mode 100644 index 000000000..96650ed6a --- /dev/null +++ b/packages/client/src/locales/ko/translation.json @@ -0,0 +1,3 @@ +{ + "com_ui_cancel": "취소" +} diff --git a/packages/client/src/locales/nl/translation.json b/packages/client/src/locales/nl/translation.json new file mode 100644 index 000000000..2ec1fb8c6 --- /dev/null +++ b/packages/client/src/locales/nl/translation.json @@ -0,0 +1,3 @@ +{ + "com_ui_cancel": "Annuleren" +} diff --git a/packages/client/src/locales/pl/translation.json b/packages/client/src/locales/pl/translation.json new file mode 100644 index 000000000..9c05e4cd7 --- /dev/null +++ b/packages/client/src/locales/pl/translation.json @@ -0,0 +1,3 @@ +{ + "com_ui_cancel": "Anuluj" +} diff --git a/packages/client/src/locales/pt-BR/translation.json b/packages/client/src/locales/pt-BR/translation.json new file mode 100644 index 000000000..c831d5737 --- /dev/null +++ b/packages/client/src/locales/pt-BR/translation.json @@ -0,0 +1,3 @@ +{ + "com_ui_cancel": "Cancelar" +} diff --git a/packages/client/src/locales/pt-PT/translation.json b/packages/client/src/locales/pt-PT/translation.json new file mode 100644 index 000000000..c831d5737 --- /dev/null +++ b/packages/client/src/locales/pt-PT/translation.json @@ -0,0 +1,3 @@ +{ + "com_ui_cancel": "Cancelar" +} diff --git a/packages/client/src/locales/ru/translation.json b/packages/client/src/locales/ru/translation.json new file mode 100644 index 000000000..e3f16ae66 --- /dev/null +++ b/packages/client/src/locales/ru/translation.json @@ -0,0 +1,3 @@ +{ + "com_ui_cancel": "Отмена" +} diff --git a/packages/client/src/locales/sv/translation.json b/packages/client/src/locales/sv/translation.json new file mode 100644 index 000000000..c606ec621 --- /dev/null +++ b/packages/client/src/locales/sv/translation.json @@ -0,0 +1,3 @@ +{ + "com_ui_cancel": "Avbryt" +} diff --git a/packages/client/src/locales/th/translation.json b/packages/client/src/locales/th/translation.json new file mode 100644 index 000000000..b78cd2cc2 --- /dev/null +++ b/packages/client/src/locales/th/translation.json @@ -0,0 +1,3 @@ +{ + "com_ui_cancel": "ยกเลิก" +} diff --git a/packages/client/src/locales/tr/translation.json b/packages/client/src/locales/tr/translation.json new file mode 100644 index 000000000..10468437f --- /dev/null +++ b/packages/client/src/locales/tr/translation.json @@ -0,0 +1,3 @@ +{ + "com_ui_cancel": "İptal" +} diff --git a/packages/client/src/locales/vi/translation.json b/packages/client/src/locales/vi/translation.json new file mode 100644 index 000000000..64634b0df --- /dev/null +++ b/packages/client/src/locales/vi/translation.json @@ -0,0 +1,3 @@ +{ + "com_ui_cancel": "Hủy" +} diff --git a/packages/client/src/locales/zh-Hans/translation.json b/packages/client/src/locales/zh-Hans/translation.json new file mode 100644 index 000000000..d763c638c --- /dev/null +++ b/packages/client/src/locales/zh-Hans/translation.json @@ -0,0 +1,3 @@ +{ + "com_ui_cancel": "取消" +} diff --git a/packages/client/src/locales/zh-Hant/translation.json b/packages/client/src/locales/zh-Hant/translation.json new file mode 100644 index 000000000..d763c638c --- /dev/null +++ b/packages/client/src/locales/zh-Hant/translation.json @@ -0,0 +1,3 @@ +{ + "com_ui_cancel": "取消" +} diff --git a/packages/client/src/store.ts b/packages/client/src/store.ts new file mode 100644 index 000000000..6e23be6e0 --- /dev/null +++ b/packages/client/src/store.ts @@ -0,0 +1,20 @@ +import { atom } from 'jotai'; +import { NotificationSeverity } from '~/common'; + +export const langAtom = atom('en'); +export const chatDirectionAtom = atom('ltr'); +export const fontSizeAtom = atom('text-base'); + +export type ToastState = { + open: boolean; + message: string; + severity: NotificationSeverity; + showIcon: boolean; +}; + +export const toastState = atom({ + open: false, + message: '', + severity: NotificationSeverity.SUCCESS, + showIcon: true, +}); diff --git a/client/src/components/svg/AnthropicIcon.tsx b/packages/client/src/svgs/AnthropicIcon.tsx similarity index 100% rename from client/src/components/svg/AnthropicIcon.tsx rename to packages/client/src/svgs/AnthropicIcon.tsx diff --git a/client/src/components/svg/AnthropicMinimalIcon.tsx b/packages/client/src/svgs/AnthropicMinimalIcon.tsx similarity index 100% rename from client/src/components/svg/AnthropicMinimalIcon.tsx rename to packages/client/src/svgs/AnthropicMinimalIcon.tsx diff --git a/client/src/components/svg/AppleIcon.tsx b/packages/client/src/svgs/AppleIcon.tsx similarity index 99% rename from client/src/components/svg/AppleIcon.tsx rename to packages/client/src/svgs/AppleIcon.tsx index 4f1ff404d..e84b70386 100644 --- a/client/src/components/svg/AppleIcon.tsx +++ b/packages/client/src/svgs/AppleIcon.tsx @@ -15,4 +15,4 @@ export default function AppleIcon() { /> ); -} \ No newline at end of file +} diff --git a/client/src/components/svg/ArchiveIcon.tsx b/packages/client/src/svgs/ArchiveIcon.tsx similarity index 100% rename from client/src/components/svg/ArchiveIcon.tsx rename to packages/client/src/svgs/ArchiveIcon.tsx diff --git a/client/src/components/svg/AssistantIcon.tsx b/packages/client/src/svgs/AssistantIcon.tsx similarity index 100% rename from client/src/components/svg/AssistantIcon.tsx rename to packages/client/src/svgs/AssistantIcon.tsx diff --git a/client/src/components/svg/AttachmentIcon.tsx b/packages/client/src/svgs/AttachmentIcon.tsx similarity index 100% rename from client/src/components/svg/AttachmentIcon.tsx rename to packages/client/src/svgs/AttachmentIcon.tsx diff --git a/client/src/components/svg/AzureMinimalIcon.tsx b/packages/client/src/svgs/AzureMinimalIcon.tsx similarity index 99% rename from client/src/components/svg/AzureMinimalIcon.tsx rename to packages/client/src/svgs/AzureMinimalIcon.tsx index 171a0c1eb..bd73c5d13 100644 --- a/client/src/components/svg/AzureMinimalIcon.tsx +++ b/packages/client/src/svgs/AzureMinimalIcon.tsx @@ -1,4 +1,3 @@ - import { cn } from '~/utils/'; export default function AzureMinimalIcon({ diff --git a/client/src/components/svg/BedrockIcon.tsx b/packages/client/src/svgs/BedrockIcon.tsx similarity index 100% rename from client/src/components/svg/BedrockIcon.tsx rename to packages/client/src/svgs/BedrockIcon.tsx diff --git a/client/src/components/svg/BirthdayIcon.tsx b/packages/client/src/svgs/BirthdayIcon.tsx similarity index 100% rename from client/src/components/svg/BirthdayIcon.tsx rename to packages/client/src/svgs/BirthdayIcon.tsx diff --git a/client/src/components/svg/Blocks.tsx b/packages/client/src/svgs/Blocks.tsx similarity index 100% rename from client/src/components/svg/Blocks.tsx rename to packages/client/src/svgs/Blocks.tsx diff --git a/client/src/components/svg/CautionIcon.tsx b/packages/client/src/svgs/CautionIcon.tsx similarity index 100% rename from client/src/components/svg/CautionIcon.tsx rename to packages/client/src/svgs/CautionIcon.tsx diff --git a/client/src/components/svg/ChatGPTMinimalIcon.tsx b/packages/client/src/svgs/ChatGPTMinimalIcon.tsx similarity index 100% rename from client/src/components/svg/ChatGPTMinimalIcon.tsx rename to packages/client/src/svgs/ChatGPTMinimalIcon.tsx diff --git a/client/src/components/svg/ChatIcon.tsx b/packages/client/src/svgs/ChatIcon.tsx similarity index 100% rename from client/src/components/svg/ChatIcon.tsx rename to packages/client/src/svgs/ChatIcon.tsx diff --git a/client/src/components/svg/CheckMark.tsx b/packages/client/src/svgs/CheckMark.tsx similarity index 100% rename from client/src/components/svg/CheckMark.tsx rename to packages/client/src/svgs/CheckMark.tsx diff --git a/client/src/components/svg/CircleHelpIcon.tsx b/packages/client/src/svgs/CircleHelpIcon.tsx similarity index 100% rename from client/src/components/svg/CircleHelpIcon.tsx rename to packages/client/src/svgs/CircleHelpIcon.tsx diff --git a/client/src/components/svg/Clipboard.tsx b/packages/client/src/svgs/Clipboard.tsx similarity index 100% rename from client/src/components/svg/Clipboard.tsx rename to packages/client/src/svgs/Clipboard.tsx diff --git a/client/src/components/svg/CodeyIcon.tsx b/packages/client/src/svgs/CodeyIcon.tsx similarity index 100% rename from client/src/components/svg/CodeyIcon.tsx rename to packages/client/src/svgs/CodeyIcon.tsx diff --git a/client/src/components/svg/ContinueIcon.tsx b/packages/client/src/svgs/ContinueIcon.tsx similarity index 100% rename from client/src/components/svg/ContinueIcon.tsx rename to packages/client/src/svgs/ContinueIcon.tsx diff --git a/client/src/components/svg/ConvoIcon.tsx b/packages/client/src/svgs/ConvoIcon.tsx similarity index 100% rename from client/src/components/svg/ConvoIcon.tsx rename to packages/client/src/svgs/ConvoIcon.tsx diff --git a/client/src/components/svg/CrossIcon.tsx b/packages/client/src/svgs/CrossIcon.tsx similarity index 100% rename from client/src/components/svg/CrossIcon.tsx rename to packages/client/src/svgs/CrossIcon.tsx diff --git a/client/src/components/svg/CustomMinimalIcon.tsx b/packages/client/src/svgs/CustomMinimalIcon.tsx similarity index 100% rename from client/src/components/svg/CustomMinimalIcon.tsx rename to packages/client/src/svgs/CustomMinimalIcon.tsx diff --git a/client/src/components/svg/DarkModeIcon.tsx b/packages/client/src/svgs/DarkModeIcon.tsx similarity index 100% rename from client/src/components/svg/DarkModeIcon.tsx rename to packages/client/src/svgs/DarkModeIcon.tsx diff --git a/client/src/components/svg/DataIcon.tsx b/packages/client/src/svgs/DataIcon.tsx similarity index 100% rename from client/src/components/svg/DataIcon.tsx rename to packages/client/src/svgs/DataIcon.tsx diff --git a/client/src/components/svg/DiscordIcon.tsx b/packages/client/src/svgs/DiscordIcon.tsx similarity index 100% rename from client/src/components/svg/DiscordIcon.tsx rename to packages/client/src/svgs/DiscordIcon.tsx diff --git a/client/src/components/svg/DislikeIcon.tsx b/packages/client/src/svgs/DislikeIcon.tsx similarity index 100% rename from client/src/components/svg/DislikeIcon.tsx rename to packages/client/src/svgs/DislikeIcon.tsx diff --git a/client/src/components/svg/DotsIcon.tsx b/packages/client/src/svgs/DotsIcon.tsx similarity index 100% rename from client/src/components/svg/DotsIcon.tsx rename to packages/client/src/svgs/DotsIcon.tsx diff --git a/client/src/components/svg/EditIcon.tsx b/packages/client/src/svgs/EditIcon.tsx similarity index 100% rename from client/src/components/svg/EditIcon.tsx rename to packages/client/src/svgs/EditIcon.tsx diff --git a/client/src/components/svg/ExperimentIcon.tsx b/packages/client/src/svgs/ExperimentIcon.tsx similarity index 100% rename from client/src/components/svg/ExperimentIcon.tsx rename to packages/client/src/svgs/ExperimentIcon.tsx diff --git a/client/src/components/svg/FacebookIcon.tsx b/packages/client/src/svgs/FacebookIcon.tsx similarity index 100% rename from client/src/components/svg/FacebookIcon.tsx rename to packages/client/src/svgs/FacebookIcon.tsx diff --git a/client/src/components/svg/GPTIcon.tsx b/packages/client/src/svgs/GPTIcon.tsx similarity index 100% rename from client/src/components/svg/GPTIcon.tsx rename to packages/client/src/svgs/GPTIcon.tsx diff --git a/client/src/components/svg/GearIcon.tsx b/packages/client/src/svgs/GearIcon.tsx similarity index 100% rename from client/src/components/svg/GearIcon.tsx rename to packages/client/src/svgs/GearIcon.tsx diff --git a/client/src/components/svg/GeminiIcon.tsx b/packages/client/src/svgs/GeminiIcon.tsx similarity index 100% rename from client/src/components/svg/GeminiIcon.tsx rename to packages/client/src/svgs/GeminiIcon.tsx diff --git a/client/src/components/svg/GithubIcon.tsx b/packages/client/src/svgs/GithubIcon.tsx similarity index 100% rename from client/src/components/svg/GithubIcon.tsx rename to packages/client/src/svgs/GithubIcon.tsx diff --git a/client/src/components/svg/GoogleIcon.tsx b/packages/client/src/svgs/GoogleIcon.tsx similarity index 100% rename from client/src/components/svg/GoogleIcon.tsx rename to packages/client/src/svgs/GoogleIcon.tsx diff --git a/client/src/components/svg/GoogleIconChat.tsx b/packages/client/src/svgs/GoogleIconChat.tsx similarity index 100% rename from client/src/components/svg/GoogleIconChat.tsx rename to packages/client/src/svgs/GoogleIconChat.tsx diff --git a/client/src/components/svg/GoogleMinimalIcon.tsx b/packages/client/src/svgs/GoogleMinimalIcon.tsx similarity index 100% rename from client/src/components/svg/GoogleMinimalIcon.tsx rename to packages/client/src/svgs/GoogleMinimalIcon.tsx diff --git a/client/src/components/svg/LightModeIcon.tsx b/packages/client/src/svgs/LightModeIcon.tsx similarity index 100% rename from client/src/components/svg/LightModeIcon.tsx rename to packages/client/src/svgs/LightModeIcon.tsx diff --git a/client/src/components/svg/LightningIcon.tsx b/packages/client/src/svgs/LightningIcon.tsx similarity index 100% rename from client/src/components/svg/LightningIcon.tsx rename to packages/client/src/svgs/LightningIcon.tsx diff --git a/client/src/components/svg/LikeIcon.tsx b/packages/client/src/svgs/LikeIcon.tsx similarity index 100% rename from client/src/components/svg/LikeIcon.tsx rename to packages/client/src/svgs/LikeIcon.tsx diff --git a/client/src/components/svg/LinkIcon.tsx b/packages/client/src/svgs/LinkIcon.tsx similarity index 100% rename from client/src/components/svg/LinkIcon.tsx rename to packages/client/src/svgs/LinkIcon.tsx diff --git a/client/src/components/svg/ListeningIcon.tsx b/packages/client/src/svgs/ListeningIcon.tsx similarity index 78% rename from client/src/components/svg/ListeningIcon.tsx rename to packages/client/src/svgs/ListeningIcon.tsx index e81c7e37e..ef8de6a4e 100644 --- a/client/src/components/svg/ListeningIcon.tsx +++ b/packages/client/src/svgs/ListeningIcon.tsx @@ -1,6 +1,10 @@ import { cn } from '~/utils/'; -export default function ListeningIcon({ className }) { +type ListeningIconProps = { + className?: string; +}; + +export default function ListeningIcon({ className }: ListeningIconProps) { return ( + + + ); +} +``` + +### 3. Set Up Your Base CSS + +Ensure your app has CSS variables defined as fallbacks: + +```css +/* style.css */ +:root { + --white: #fff; + --gray-800: #212121; + --gray-100: #ececec; + /* ... other color definitions */ +} + +html { + --text-primary: var(--gray-800); + --surface-primary: var(--white); + /* ... other theme variables */ +} + +.dark { + --text-primary: var(--gray-100); + --surface-primary: var(--gray-900); + /* ... other dark theme variables */ +} +``` + +### 4. Configure Tailwind + +Update your `tailwind.config.js`: + +```js +module.exports = { + content: [ + './src/**/*.{js,jsx,ts,tsx}', + // Include component library files + './node_modules/@librechat/client/dist/**/*.js', + ], + darkMode: ['class'], + theme: { + extend: { + colors: { + // Map CSS variables to Tailwind colors + 'text-primary': 'var(--text-primary)', + 'surface-primary': 'var(--surface-primary)', + 'brand-purple': 'var(--brand-purple)', + // ... other colors + }, + }, + }, +}; +``` + +### 5. Use Theme Colors in Components + +```tsx +function MyComponent() { + return ( +
+

Hello World

+ +
+ ); +} +``` + +## Available Theme Colors + +### Text Colors +- `text-text-primary` - Primary text color +- `text-text-secondary` - Secondary text color +- `text-text-secondary-alt` - Alternative secondary text +- `text-text-tertiary` - Tertiary text color +- `text-text-warning` - Warning text color + +### Surface Colors +- `bg-surface-primary` - Primary background +- `bg-surface-secondary` - Secondary background +- `bg-surface-tertiary` - Tertiary background +- `bg-surface-submit` - Submit button background +- `bg-surface-destructive` - Destructive action background +- `bg-surface-dialog` - Dialog/modal background +- `bg-surface-chat` - Chat interface background + +### Border Colors +- `border-border-light` - Light border +- `border-border-medium` - Medium border +- `border-border-heavy` - Heavy border +- `border-border-xheavy` - Extra heavy border + +### Other Colors +- `bg-brand-purple` - Brand purple color +- `bg-presentation` - Presentation background +- `ring-ring-primary` - Focus ring color + +## Creating Custom Themes + +### 1. Define Your Theme + +```tsx +import { IThemeRGB } from '@librechat/client'; + +export const customTheme: IThemeRGB = { + 'rgb-text-primary': '0 0 0', // Black + 'rgb-text-secondary': '100 100 100', // Gray + 'rgb-surface-primary': '255 255 255', // White + 'rgb-surface-submit': '0 128 0', // Green + 'rgb-brand-purple': '138 43 226', // Blue Violet + // ... define other colors +}; +``` + +### 2. Use Your Custom Theme + +```tsx +import { ThemeProvider } from '@librechat/client'; +import { customTheme } from './themes/custom'; + +function App() { + return ( + + + + ); +} +``` + +## Environment Variable Themes + +Load theme colors from environment variables: + +### 1. Create Environment Variables + +```env +# .env.local +REACT_APP_THEME_BRAND_PURPLE=171 104 255 +REACT_APP_THEME_TEXT_PRIMARY=33 33 33 +REACT_APP_THEME_TEXT_SECONDARY=66 66 66 +REACT_APP_THEME_SURFACE_PRIMARY=255 255 255 +REACT_APP_THEME_SURFACE_SUBMIT=4 120 87 +``` + +### 2. Create a Theme Loader + +```tsx +function getThemeFromEnv(): IThemeRGB | undefined { + // Check if any theme environment variables are set + const hasThemeEnvVars = Object.keys(process.env).some(key => + key.startsWith('REACT_APP_THEME_') + ); + + if (!hasThemeEnvVars) { + return undefined; // Use default themes + } + + return { + 'rgb-text-primary': process.env.REACT_APP_THEME_TEXT_PRIMARY || '33 33 33', + 'rgb-brand-purple': process.env.REACT_APP_THEME_BRAND_PURPLE || '171 104 255', + // ... other colors + }; +} +``` + +### 3. Apply Environment Theme + +```tsx + + + +``` + +## Dark/Light Mode + +The ThemeProvider handles dark/light mode automatically: + +### Using the Theme Hook + +```tsx +import { useTheme } from '@librechat/client'; + +function ThemeToggle() { + const { theme, setTheme } = useTheme(); + + return ( + + ); +} +``` + +### Theme Options +- `'light'` - Force light mode +- `'dark'` - Force dark mode +- `'system'` - Follow system preference + +## Migration Guide + +If you're migrating from an older theme system: + +### 1. Update Imports + +**Before:** +```tsx +import { ThemeContext, ThemeProvider } from '~/hooks/ThemeContext'; +``` + +**After:** +```tsx +import { ThemeContext, ThemeProvider } from '@librechat/client'; +``` + +### 2. Update ThemeProvider Usage + +The new ThemeProvider is backward compatible but adds new capabilities: + +```tsx + + + +``` + +### 3. Existing Components + +Components using ThemeContext continue to work without changes: + +```tsx +// This still works! +const { theme, setTheme } = useContext(ThemeContext); +``` + +## Implementation Details + +### File Structure +``` +packages/client/src/theme/ +├── context/ +│ └── ThemeProvider.tsx # Main theme provider +├── types/ +│ └── index.ts # TypeScript interfaces +├── themes/ +│ ├── default.ts # Light theme colors +│ ├── dark.ts # Dark theme colors +│ └── index.ts # Theme exports +├── utils/ +│ ├── applyTheme.ts # Apply CSS variables +│ ├── tailwindConfig.ts # Tailwind helpers +│ └── createTailwindColors.js +├── README.md # This documentation +└── index.ts # Main exports +``` + +### CSS Variable Format + +The theme system uses RGB values in CSS variables: +- CSS Variable: `--text-primary: rgb(33 33 33)` +- Theme Definition: `'rgb-text-primary': '33 33 33'` +- Tailwind Usage: `text-text-primary` + +### RGB Format Requirements + +All color values must be in space-separated RGB format: +- ✅ Correct: `'255 255 255'` +- ❌ Incorrect: `'#ffffff'` or `'rgb(255, 255, 255)'` + +This format allows Tailwind to apply opacity modifiers like `bg-surface-primary/50`. + +## Troubleshooting + +### Common Issues + +#### 1. Colors Not Applying +- **Issue**: Custom theme colors aren't showing +- **Solution**: Ensure you're passing the `themeRGB` prop to ThemeProvider +- **Check**: CSS variables in DevTools should show `rgb(R G B)` format + +#### 2. Circular Reference Errors +- **Issue**: `--brand-purple: var(--brand-purple)` creates infinite loop +- **Solution**: Use direct color values: `--brand-purple: #ab68ff` + +#### 3. Dark Mode Not Working +- **Issue**: Dark mode doesn't switch +- **Solution**: Ensure `darkMode: ['class']` is in your Tailwind config +- **Check**: The `` element should have `class="dark"` in dark mode + +#### 4. TypeScript Errors +- **Issue**: Type errors when defining themes +- **Solution**: Import and use the `IThemeRGB` interface: +```tsx +import { IThemeRGB } from '@librechat/client'; +``` + +### Debugging Tips + +1. **Check CSS Variables**: Use browser DevTools to inspect computed CSS variables +2. **Verify Theme Application**: Look for inline styles on the root element +3. **Console Errors**: Check for validation errors in the console +4. **Test Isolation**: Try a minimal theme to isolate issues + +## Examples + +### Dynamic Theme Switching + +```tsx +import { ThemeProvider, defaultTheme, darkTheme } from '@librechat/client'; +import { useState } from 'react'; + +function App() { + const [isDark, setIsDark] = useState(false); + + return ( + + + + + ); +} +``` + +### Multi-Theme Selector + +```tsx +const themes = { + default: undefined, // Use CSS defaults + ocean: { + 'rgb-brand-purple': '0 119 190', + 'rgb-surface-primary': '240 248 255', + // ... ocean theme colors + }, + forest: { + 'rgb-brand-purple': '34 139 34', + 'rgb-surface-primary': '245 255 250', + // ... forest theme colors + }, +}; + +function App() { + const [selectedTheme, setSelectedTheme] = useState('default'); + + return ( + + + + + ); +} +``` + +### Using with the Main Application + +When using the ThemeProvider in your main application with localStorage persistence: + +```tsx +import { ThemeProvider } from '@librechat/client'; +import { getThemeFromEnv } from './utils'; + +function App() { + const envTheme = getThemeFromEnv(); + + return ( + + {/* Your app content */} + + ); +} +``` + +**Important**: Props passed to ThemeProvider will override stored values on initial mount. Only pass props when you explicitly want to override the user's saved preferences. + +## Contributing + +When adding new theme colors: + +1. Add the type definition in `types/index.ts` +2. Add the color to default and dark themes +3. Update the applyTheme mapping +4. Add to Tailwind configuration +5. Document in this README + +## License + +This theme system is part of the @librechat/client package. \ No newline at end of file diff --git a/packages/client/src/theme/atoms/themeAtoms.ts b/packages/client/src/theme/atoms/themeAtoms.ts new file mode 100644 index 000000000..316d092fb --- /dev/null +++ b/packages/client/src/theme/atoms/themeAtoms.ts @@ -0,0 +1,36 @@ +import { atomWithStorage } from 'jotai/utils'; +import { IThemeRGB } from '../types'; + +/** + * Atom for storing the theme mode (light/dark/system) in localStorage + * Key: 'color-theme' + */ +export const themeModeAtom = atomWithStorage('color-theme', 'system', undefined, { + getOnInit: true, +}); + +/** + * Atom for storing custom theme colors in localStorage + * Key: 'theme-colors' + */ +export const themeColorsAtom = atomWithStorage( + 'theme-colors', + undefined, + undefined, + { + getOnInit: true, + }, +); + +/** + * Atom for storing the theme name in localStorage + * Key: 'theme-name' + */ +export const themeNameAtom = atomWithStorage( + 'theme-name', + undefined, + undefined, + { + getOnInit: true, + }, +); diff --git a/packages/client/src/theme/context/ThemeProvider.tsx b/packages/client/src/theme/context/ThemeProvider.tsx new file mode 100644 index 000000000..c80379616 --- /dev/null +++ b/packages/client/src/theme/context/ThemeProvider.tsx @@ -0,0 +1,165 @@ +import React, { createContext, useContext, useEffect, useMemo, useCallback, useRef } from 'react'; +import { useAtom } from 'jotai'; +import { IThemeRGB } from '../types'; +import applyTheme from '../utils/applyTheme'; +import { themeModeAtom, themeColorsAtom, themeNameAtom } from '../atoms/themeAtoms'; + +type ThemeContextType = { + theme: string; // 'light' | 'dark' | 'system' + setTheme: (theme: string) => void; + themeRGB?: IThemeRGB; + setThemeRGB: (colors?: IThemeRGB) => void; + themeName?: string; + setThemeName: (name?: string) => void; + resetTheme: () => void; +}; + +// Export ThemeContext so it can be imported from hooks +export const ThemeContext = createContext({ + theme: 'system', + setTheme: () => undefined, + setThemeRGB: () => undefined, + setThemeName: () => undefined, + resetTheme: () => undefined, +}); + +export interface ThemeProviderProps { + children: React.ReactNode; + themeRGB?: IThemeRGB; + themeName?: string; + initialTheme?: string; +} + +/** + * Check if theme is dark + */ +export const isDark = (theme: string): boolean => { + if (theme === 'system') { + return window.matchMedia('(prefers-color-scheme: dark)').matches; + } + return theme === 'dark'; +}; + +/** + * ThemeProvider component that handles both dark/light mode switching + * and dynamic color themes via CSS variables with localStorage persistence + */ +export function ThemeProvider({ + children, + themeRGB: propThemeRGB, + themeName: propThemeName, + initialTheme, +}: ThemeProviderProps) { + // Use jotai atoms for persistent state + const [theme, setTheme] = useAtom(themeModeAtom); + const [storedThemeRGB, setStoredThemeRGB] = useAtom(themeColorsAtom); + const [storedThemeName, setStoredThemeName] = useAtom(themeNameAtom); + + // Track if props have been initialized + const propsInitialized = useRef(false); + + // Initialize from props only once on mount + useEffect(() => { + if (!propsInitialized.current) { + propsInitialized.current = true; + + // Set initial theme if provided + if (initialTheme) { + setTheme(initialTheme); + } + + // Set initial theme colors if provided + if (propThemeRGB) { + setStoredThemeRGB(propThemeRGB); + } + + // Set initial theme name if provided + if (propThemeName) { + setStoredThemeName(propThemeName); + } + } + }, [initialTheme, propThemeRGB, propThemeName, setTheme, setStoredThemeRGB, setStoredThemeName]); + + // Apply class-based dark mode + const applyThemeMode = useCallback((rawTheme: string) => { + const root = window.document.documentElement; + const darkMode = isDark(rawTheme); + + root.classList.remove(darkMode ? 'light' : 'dark'); + root.classList.add(darkMode ? 'dark' : 'light'); + }, []); + + // Handle system theme changes + useEffect(() => { + const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); + const changeThemeOnSystemChange = () => { + if (theme === 'system') { + applyThemeMode('system'); + } + }; + + mediaQuery.addEventListener('change', changeThemeOnSystemChange); + return () => { + mediaQuery.removeEventListener('change', changeThemeOnSystemChange); + }; + }, [theme, applyThemeMode]); + + // Apply dark/light mode class + useEffect(() => { + applyThemeMode(theme); + }, [theme, applyThemeMode]); + + // Apply dynamic color theme + useEffect(() => { + if (storedThemeRGB) { + applyTheme(storedThemeRGB); + } + }, [storedThemeRGB]); + + // Reset theme function + const resetTheme = useCallback(() => { + setTheme('system'); + setStoredThemeRGB(undefined); + setStoredThemeName(undefined); + // Remove any custom CSS variables + const root = document.documentElement; + const customProps = Array.from(root.style).filter((prop) => prop.startsWith('--')); + customProps.forEach((prop) => root.style.removeProperty(prop)); + }, [setTheme, setStoredThemeRGB, setStoredThemeName]); + + const value = useMemo( + () => ({ + theme, + setTheme, + themeRGB: storedThemeRGB, + setThemeRGB: setStoredThemeRGB, + themeName: storedThemeName, + setThemeName: setStoredThemeName, + resetTheme, + }), + [ + theme, + setTheme, + storedThemeRGB, + setStoredThemeRGB, + storedThemeName, + setStoredThemeName, + resetTheme, + ], + ); + + return {children}; +} + +/** + * Hook to access the current theme context + */ +export function useTheme() { + const context = useContext(ThemeContext); + if (!context) { + throw new Error('useTheme must be used within a ThemeProvider'); + } + return context; +} + +export default ThemeProvider; diff --git a/packages/client/src/theme/index.ts b/packages/client/src/theme/index.ts new file mode 100644 index 000000000..18d02ed1e --- /dev/null +++ b/packages/client/src/theme/index.ts @@ -0,0 +1,14 @@ +// Export types +export * from './types'; + +// Export ThemeProvider, ThemeContext, useTheme hook, and isDark +export { ThemeProvider, ThemeContext, useTheme, isDark } from './context/ThemeProvider'; + +// Export utility functions +export { default as applyTheme } from './utils/applyTheme'; + +// Export theme atoms for persistence +export { themeModeAtom, themeColorsAtom, themeNameAtom } from './atoms/themeAtoms'; + +// Export predefined themes +export * from './themes'; diff --git a/packages/client/src/theme/themes/dark.ts b/packages/client/src/theme/themes/dark.ts new file mode 100644 index 000000000..150fee69c --- /dev/null +++ b/packages/client/src/theme/themes/dark.ts @@ -0,0 +1,72 @@ +import { IThemeRGB } from '../types'; + +/** + * Dark theme + * RGB values extracted from the existing dark mode CSS variables + */ +export const darkTheme: IThemeRGB = { + // Text colors + 'rgb-text-primary': '236 236 236', // #ececec (gray-100) + 'rgb-text-secondary': '205 205 205', // #cdcdcd (gray-300) + 'rgb-text-secondary-alt': '153 150 150', // #999696 (gray-400) + 'rgb-text-tertiary': '89 89 89', // #595959 (gray-500) + 'rgb-text-warning': '245 158 11', // #f59e0b (amber-500) + + // Ring colors (not defined in dark mode, using default) + 'rgb-ring-primary': '89 89 89', // #595959 (gray-500) + + // Header colors + 'rgb-header-primary': '47 47 47', // #2f2f2f (gray-700) + 'rgb-header-hover': '66 66 66', // #424242 (gray-600) + 'rgb-header-button-hover': '47 47 47', // #2f2f2f (gray-700) + + // Surface colors + 'rgb-surface-active': '89 89 89', // #595959 (gray-500) + 'rgb-surface-active-alt': '47 47 47', // #2f2f2f (gray-700) + 'rgb-surface-hover': '66 66 66', // #424242 (gray-600) + 'rgb-surface-hover-alt': '66 66 66', // #424242 (gray-600) + 'rgb-surface-primary': '13 13 13', // #0d0d0d (gray-900) + 'rgb-surface-primary-alt': '23 23 23', // #171717 (gray-850) + 'rgb-surface-primary-contrast': '23 23 23', // #171717 (gray-850) + 'rgb-surface-secondary': '33 33 33', // #212121 (gray-800) + 'rgb-surface-secondary-alt': '33 33 33', // #212121 (gray-800) + 'rgb-surface-tertiary': '47 47 47', // #2f2f2f (gray-700) + 'rgb-surface-tertiary-alt': '47 47 47', // #2f2f2f (gray-700) + 'rgb-surface-dialog': '23 23 23', // #171717 (gray-850) + 'rgb-surface-submit': '4 120 87', // #047857 (green-700) + 'rgb-surface-submit-hover': '6 95 70', // #065f46 (green-800) + 'rgb-surface-destructive': '153 27 27', // #991b1b (red-800) + 'rgb-surface-destructive-hover': '127 29 29', // #7f1d1d (red-900) + 'rgb-surface-chat': '47 47 47', // #2f2f2f (gray-700) + + // Border colors + 'rgb-border-light': '47 47 47', // #2f2f2f (gray-700) + 'rgb-border-medium': '66 66 66', // #424242 (gray-600) + 'rgb-border-medium-alt': '66 66 66', // #424242 (gray-600) + 'rgb-border-heavy': '89 89 89', // #595959 (gray-500) + 'rgb-border-xheavy': '153 150 150', // #999696 (gray-400) + + // Brand colors + 'rgb-brand-purple': '171 104 255', // #ab68ff + + // Presentation + 'rgb-presentation': '33 33 33', // #212121 (gray-800) + + // Utility colors (mapped to existing colors for backwards compatibility) + 'rgb-background': '33 33 33', // Same as surface-primary + 'rgb-foreground': '255 255 255', // Same as text-primary + 'rgb-primary': '66 66 66', // Same as surface-active + 'rgb-primary-foreground': '255 255 255', // Same as surface-primary-contrast + 'rgb-secondary': '42 42 42', // Same as surface-secondary + 'rgb-secondary-foreground': '193 193 193', // Same as text-secondary + 'rgb-muted': '56 56 56', // Same as surface-tertiary + 'rgb-muted-foreground': '140 140 140', // Same as text-tertiary + 'rgb-accent': '82 82 82', // Same as surface-active-alt + 'rgb-accent-foreground': '255 255 255', // Same as text-primary + 'rgb-destructive-foreground': '255 255 255', // Same as text-primary + 'rgb-border': '82 82 82', // Same as border-medium + 'rgb-input': '66 66 66', // Same as border-light + 'rgb-ring': '255 255 255', // Same as ring-primary + 'rgb-card': '42 42 42', // Same as surface-secondary + 'rgb-card-foreground': '255 255 255', // Same as text-primary +}; diff --git a/packages/client/src/theme/themes/default.ts b/packages/client/src/theme/themes/default.ts new file mode 100644 index 000000000..d636cc0c2 --- /dev/null +++ b/packages/client/src/theme/themes/default.ts @@ -0,0 +1,72 @@ +import { IThemeRGB } from '../types'; + +/** + * Default light theme + * RGB values extracted from the existing CSS variables + */ +export const defaultTheme: IThemeRGB = { + // Text colors + 'rgb-text-primary': '33 33 33', // #212121 (gray-800) + 'rgb-text-secondary': '66 66 66', // #424242 (gray-600) + 'rgb-text-secondary-alt': '89 89 89', // #595959 (gray-500) + 'rgb-text-tertiary': '89 89 89', // #595959 (gray-500) + 'rgb-text-warning': '245 158 11', // #f59e0b (amber-500) + + // Ring colors + 'rgb-ring-primary': '89 89 89', // #595959 (gray-500) + + // Header colors + 'rgb-header-primary': '255 255 255', // #fff (white) + 'rgb-header-hover': '247 247 248', // #f7f7f8 (gray-50) + 'rgb-header-button-hover': '247 247 248', // #f7f7f8 (gray-50) + + // Surface colors + 'rgb-surface-active': '236 236 236', // #ececec (gray-100) + 'rgb-surface-active-alt': '227 227 227', // #e3e3e3 (gray-200) + 'rgb-surface-hover': '227 227 227', // #e3e3e3 (gray-200) + 'rgb-surface-hover-alt': '205 205 205', // #cdcdcd (gray-300) + 'rgb-surface-primary': '255 255 255', // #fff (white) + 'rgb-surface-primary-alt': '247 247 248', // #f7f7f8 (gray-50) + 'rgb-surface-primary-contrast': '236 236 236', // #ececec (gray-100) + 'rgb-surface-secondary': '247 247 248', // #f7f7f8 (gray-50) + 'rgb-surface-secondary-alt': '227 227 227', // #e3e3e3 (gray-200) + 'rgb-surface-tertiary': '236 236 236', // #ececec (gray-100) + 'rgb-surface-tertiary-alt': '255 255 255', // #fff (white) + 'rgb-surface-dialog': '255 255 255', // #fff (white) + 'rgb-surface-submit': '4 120 87', // #047857 (green-700) + 'rgb-surface-submit-hover': '6 95 70', // #065f46 (green-800) + 'rgb-surface-destructive': '185 28 28', // #b91c1c (red-700) + 'rgb-surface-destructive-hover': '153 27 27', // #991b1b (red-800) + 'rgb-surface-chat': '255 255 255', // #fff (white) + + // Border colors + 'rgb-border-light': '227 227 227', // #e3e3e3 (gray-200) + 'rgb-border-medium': '205 205 205', // #cdcdcd (gray-300) + 'rgb-border-medium-alt': '205 205 205', // #cdcdcd (gray-300) + 'rgb-border-heavy': '153 150 150', // #999696 (gray-400) + 'rgb-border-xheavy': '89 89 89', // #595959 (gray-500) + + // Brand colors + 'rgb-brand-purple': '171 104 255', // #ab68ff + + // Presentation + 'rgb-presentation': '255 255 255', // #fff (white) + + // Utility colors (mapped to existing colors for backwards compatibility) + 'rgb-background': '255 255 255', // Same as surface-primary + 'rgb-foreground': '17 17 17', // Same as text-primary + 'rgb-primary': '235 235 235', // Same as surface-active + 'rgb-primary-foreground': '0 0 0', // Same as surface-primary-contrast + 'rgb-secondary': '247 247 248', // Same as surface-secondary + 'rgb-secondary-foreground': '66 66 66', // Same as text-secondary + 'rgb-muted': '250 250 250', // Same as surface-tertiary + 'rgb-muted-foreground': '120 120 120', // Same as text-tertiary + 'rgb-accent': '245 245 245', // Same as surface-active-alt + 'rgb-accent-foreground': '17 17 17', // Same as text-primary + 'rgb-destructive-foreground': '17 17 17', // Same as text-primary + 'rgb-border': '215 215 215', // Same as border-medium + 'rgb-input': '230 230 230', // Same as border-light + 'rgb-ring': '180 180 180', // Same as ring-primary + 'rgb-card': '247 247 248', // Same as surface-secondary + 'rgb-card-foreground': '17 17 17', // Same as text-primary +}; diff --git a/packages/client/src/theme/themes/index.ts b/packages/client/src/theme/themes/index.ts new file mode 100644 index 000000000..89b1b0e25 --- /dev/null +++ b/packages/client/src/theme/themes/index.ts @@ -0,0 +1,2 @@ +export { defaultTheme } from './default'; +export { darkTheme } from './dark'; diff --git a/packages/client/src/theme/types/index.ts b/packages/client/src/theme/types/index.ts new file mode 100644 index 000000000..47ab88d6b --- /dev/null +++ b/packages/client/src/theme/types/index.ts @@ -0,0 +1,189 @@ +/** + * Defines the color channels. Passed to the context from each app. + * RGB values should be in format "255 255 255" (space-separated) + */ +export interface IThemeRGB { + // Text colors + 'rgb-text-primary'?: string; + 'rgb-text-secondary'?: string; + 'rgb-text-secondary-alt'?: string; + 'rgb-text-tertiary'?: string; + 'rgb-text-warning'?: string; + + // Ring colors + 'rgb-ring-primary'?: string; + + // Header colors + 'rgb-header-primary'?: string; + 'rgb-header-hover'?: string; + 'rgb-header-button-hover'?: string; + + // Surface colors + 'rgb-surface-active'?: string; + 'rgb-surface-active-alt'?: string; + 'rgb-surface-hover'?: string; + 'rgb-surface-hover-alt'?: string; + 'rgb-surface-primary'?: string; + 'rgb-surface-primary-alt'?: string; + 'rgb-surface-primary-contrast'?: string; + 'rgb-surface-secondary'?: string; + 'rgb-surface-secondary-alt'?: string; + 'rgb-surface-tertiary'?: string; + 'rgb-surface-tertiary-alt'?: string; + 'rgb-surface-dialog'?: string; + 'rgb-surface-submit'?: string; + 'rgb-surface-submit-hover'?: string; + 'rgb-surface-destructive'?: string; + 'rgb-surface-destructive-hover'?: string; + 'rgb-surface-chat'?: string; + + // Border colors + 'rgb-border-light'?: string; + 'rgb-border-medium'?: string; + 'rgb-border-medium-alt'?: string; + 'rgb-border-heavy'?: string; + 'rgb-border-xheavy'?: string; + + // Brand colors + 'rgb-brand-purple'?: string; + + // Presentation + 'rgb-presentation'?: string; + + // Utility colors + 'rgb-background'?: string; + 'rgb-foreground'?: string; + 'rgb-primary'?: string; + 'rgb-primary-foreground'?: string; + 'rgb-secondary'?: string; + 'rgb-secondary-foreground'?: string; + 'rgb-muted'?: string; + 'rgb-muted-foreground'?: string; + 'rgb-accent'?: string; + 'rgb-accent-foreground'?: string; + 'rgb-destructive-foreground'?: string; + 'rgb-border'?: string; + 'rgb-input'?: string; + 'rgb-ring'?: string; + 'rgb-card'?: string; + 'rgb-card-foreground'?: string; +} + +/** + * Name of the CSS variables used in tailwind.config + */ +export interface IThemeVariables { + '--text-primary': string; + '--text-secondary': string; + '--text-secondary-alt': string; + '--text-tertiary': string; + '--text-warning': string; + '--ring-primary': string; + '--header-primary': string; + '--header-hover': string; + '--header-button-hover': string; + '--surface-active': string; + '--surface-active-alt': string; + '--surface-hover': string; + '--surface-hover-alt': string; + '--surface-primary': string; + '--surface-primary-alt': string; + '--surface-primary-contrast': string; + '--surface-secondary': string; + '--surface-secondary-alt': string; + '--surface-tertiary': string; + '--surface-tertiary-alt': string; + '--surface-dialog': string; + '--surface-submit': string; + '--surface-submit-hover': string; + '--surface-destructive': string; + '--surface-destructive-hover': string; + '--surface-chat': string; + '--border-light': string; + '--border-medium': string; + '--border-medium-alt': string; + '--border-heavy': string; + '--border-xheavy': string; + '--brand-purple': string; + '--presentation': string; + + // Utility variables + '--background': string; + '--foreground': string; + '--primary': string; + '--primary-foreground': string; + '--secondary': string; + '--secondary-foreground': string; + '--muted': string; + '--muted-foreground': string; + '--accent': string; + '--accent-foreground': string; + '--destructive-foreground': string; + '--border': string; + '--input': string; + '--ring': string; + '--card': string; + '--card-foreground': string; +} + +/** + * Name of the defined colors in the Tailwind theme + */ +export interface IThemeColors { + 'text-primary'?: string; + 'text-secondary'?: string; + 'text-secondary-alt'?: string; + 'text-tertiary'?: string; + 'text-warning'?: string; + 'ring-primary'?: string; + 'header-primary'?: string; + 'header-hover'?: string; + 'header-button-hover'?: string; + 'surface-active'?: string; + 'surface-active-alt'?: string; + 'surface-hover'?: string; + 'surface-hover-alt'?: string; + 'surface-primary'?: string; + 'surface-primary-alt'?: string; + 'surface-primary-contrast'?: string; + 'surface-secondary'?: string; + 'surface-secondary-alt'?: string; + 'surface-tertiary'?: string; + 'surface-tertiary-alt'?: string; + 'surface-dialog'?: string; + 'surface-submit'?: string; + 'surface-submit-hover'?: string; + 'surface-destructive'?: string; + 'surface-destructive-hover'?: string; + 'surface-chat'?: string; + 'border-light'?: string; + 'border-medium'?: string; + 'border-medium-alt'?: string; + 'border-heavy'?: string; + 'border-xheavy'?: string; + 'brand-purple'?: string; + presentation?: string; + + // Utility colors + background?: string; + foreground?: string; + primary?: string; + 'primary-foreground'?: string; + secondary?: string; + 'secondary-foreground'?: string; + muted?: string; + 'muted-foreground'?: string; + accent?: string; + 'accent-foreground'?: string; + 'destructive-foreground'?: string; + border?: string; + input?: string; + ring?: string; + card?: string; + 'card-foreground'?: string; +} + +export interface Theme { + name: string; + colors: IThemeRGB; +} diff --git a/packages/client/src/theme/utils/applyTheme.ts b/packages/client/src/theme/utils/applyTheme.ts new file mode 100644 index 000000000..f98db54dd --- /dev/null +++ b/packages/client/src/theme/utils/applyTheme.ts @@ -0,0 +1,115 @@ +import { IThemeRGB, IThemeVariables } from '../types'; + +/** + * Validates RGB string format (e.g., "255 255 255") + */ +function validateRGB(rgb: string): boolean { + if (!rgb) return true; + const rgbRegex = /^(\d{1,3})\s+(\d{1,3})\s+(\d{1,3})$/; + const match = rgb.match(rgbRegex); + + if (!match) return false; + + // Check that each value is between 0-255 + const [, r, g, b] = match; + return [r, g, b].every((val) => { + const num = parseInt(val, 10); + return num >= 0 && num <= 255; + }); +} + +/** + * Maps theme RGB values to CSS variables + */ +function mapTheme(rgb: IThemeRGB): Partial { + const variables: Partial = {}; + + // Map each RGB value to its corresponding CSS variable + const mappings: Record = { + 'rgb-text-primary': '--text-primary', + 'rgb-text-secondary': '--text-secondary', + 'rgb-text-secondary-alt': '--text-secondary-alt', + 'rgb-text-tertiary': '--text-tertiary', + 'rgb-text-warning': '--text-warning', + 'rgb-ring-primary': '--ring-primary', + 'rgb-header-primary': '--header-primary', + 'rgb-header-hover': '--header-hover', + 'rgb-header-button-hover': '--header-button-hover', + 'rgb-surface-active': '--surface-active', + 'rgb-surface-active-alt': '--surface-active-alt', + 'rgb-surface-hover': '--surface-hover', + 'rgb-surface-hover-alt': '--surface-hover-alt', + 'rgb-surface-primary': '--surface-primary', + 'rgb-surface-primary-alt': '--surface-primary-alt', + 'rgb-surface-primary-contrast': '--surface-primary-contrast', + 'rgb-surface-secondary': '--surface-secondary', + 'rgb-surface-secondary-alt': '--surface-secondary-alt', + 'rgb-surface-tertiary': '--surface-tertiary', + 'rgb-surface-tertiary-alt': '--surface-tertiary-alt', + 'rgb-surface-dialog': '--surface-dialog', + 'rgb-surface-submit': '--surface-submit', + 'rgb-surface-submit-hover': '--surface-submit-hover', + 'rgb-surface-destructive': '--surface-destructive', + 'rgb-surface-destructive-hover': '--surface-destructive-hover', + 'rgb-surface-chat': '--surface-chat', + 'rgb-border-light': '--border-light', + 'rgb-border-medium': '--border-medium', + 'rgb-border-medium-alt': '--border-medium-alt', + 'rgb-border-heavy': '--border-heavy', + 'rgb-border-xheavy': '--border-xheavy', + 'rgb-brand-purple': '--brand-purple', + 'rgb-presentation': '--presentation', + + // Utility colors + 'rgb-background': '--background', + 'rgb-foreground': '--foreground', + 'rgb-primary': '--primary', + 'rgb-primary-foreground': '--primary-foreground', + 'rgb-secondary': '--secondary', + 'rgb-secondary-foreground': '--secondary-foreground', + 'rgb-muted': '--muted', + 'rgb-muted-foreground': '--muted-foreground', + 'rgb-accent': '--accent', + 'rgb-accent-foreground': '--accent-foreground', + 'rgb-destructive-foreground': '--destructive-foreground', + 'rgb-border': '--border', + 'rgb-input': '--input', + 'rgb-ring': '--ring', + 'rgb-card': '--card', + 'rgb-card-foreground': '--card-foreground', + }; + + Object.entries(mappings).forEach(([rgbKey, cssVar]) => { + const value = rgb[rgbKey as keyof IThemeRGB]; + if (value) { + variables[cssVar] = value; + } + }); + + return variables; +} + +/** + * Applies theme to the document root + * Sets CSS variables as rgb() values for compatibility with existing CSS + */ +export default function applyTheme(themeRGB?: IThemeRGB) { + if (!themeRGB) return; + + const themeObject = mapTheme(themeRGB); + const root = document.documentElement; + + Object.entries(themeObject).forEach(([cssVar, value]) => { + if (!value) return; + + const validation = validateRGB(value); + if (!validation) { + console.error(`Invalid RGB value for ${cssVar}: ${value}`); + return; + } + + // Set the CSS variable as rgb() value for compatibility + // This ensures existing CSS that expects color values (not space-separated RGB) continues to work + root.style.setProperty(cssVar, `rgb(${value})`); + }); +} diff --git a/packages/client/src/theme/utils/createTailwindColors.js b/packages/client/src/theme/utils/createTailwindColors.js new file mode 100644 index 000000000..de110ac18 --- /dev/null +++ b/packages/client/src/theme/utils/createTailwindColors.js @@ -0,0 +1,86 @@ +/** + * Helper function to create a color value that uses CSS variables with alpha support + * This is a CommonJS version for use in tailwind.config.js + */ +function withOpacity(variableName) { + return ({ opacityValue }) => { + if (opacityValue !== undefined) { + // The CSS variable already contains rgb() so we need to extract the values + return `rgba(var(${variableName}), ${opacityValue})`.replace('rgb(', '').replace(')', ''); + } + return `var(${variableName})`; + }; +} + +/** + * Creates Tailwind color configuration that uses CSS variables + * This allows dynamic theme switching by changing CSS variable values + */ +function createTailwindColors() { + return { + 'text-primary': withOpacity('--text-primary'), + 'text-secondary': withOpacity('--text-secondary'), + 'text-secondary-alt': withOpacity('--text-secondary-alt'), + 'text-tertiary': withOpacity('--text-tertiary'), + 'text-warning': withOpacity('--text-warning'), + 'ring-primary': withOpacity('--ring-primary'), + 'header-primary': withOpacity('--header-primary'), + 'header-hover': withOpacity('--header-hover'), + 'header-button-hover': withOpacity('--header-button-hover'), + 'surface-active': withOpacity('--surface-active'), + 'surface-active-alt': withOpacity('--surface-active-alt'), + 'surface-hover': withOpacity('--surface-hover'), + 'surface-hover-alt': withOpacity('--surface-hover-alt'), + 'surface-primary': withOpacity('--surface-primary'), + 'surface-primary-alt': withOpacity('--surface-primary-alt'), + 'surface-primary-contrast': withOpacity('--surface-primary-contrast'), + 'surface-secondary': withOpacity('--surface-secondary'), + 'surface-secondary-alt': withOpacity('--surface-secondary-alt'), + 'surface-tertiary': withOpacity('--surface-tertiary'), + 'surface-tertiary-alt': withOpacity('--surface-tertiary-alt'), + 'surface-dialog': withOpacity('--surface-dialog'), + 'surface-submit': withOpacity('--surface-submit'), + 'surface-submit-hover': withOpacity('--surface-submit-hover'), + 'surface-destructive': withOpacity('--surface-destructive'), + 'surface-destructive-hover': withOpacity('--surface-destructive-hover'), + 'surface-chat': withOpacity('--surface-chat'), + 'border-light': withOpacity('--border-light'), + 'border-medium': withOpacity('--border-medium'), + 'border-medium-alt': withOpacity('--border-medium-alt'), + 'border-heavy': withOpacity('--border-heavy'), + 'border-xheavy': withOpacity('--border-xheavy'), + 'brand-purple': withOpacity('--brand-purple'), + presentation: withOpacity('--presentation'), + background: withOpacity('--background'), + foreground: withOpacity('--foreground'), + primary: { + DEFAULT: withOpacity('--primary'), + foreground: withOpacity('--primary-foreground'), + }, + secondary: { + DEFAULT: withOpacity('--secondary'), + foreground: withOpacity('--secondary-foreground'), + }, + muted: { + DEFAULT: withOpacity('--muted'), + foreground: withOpacity('--muted-foreground'), + }, + accent: { + DEFAULT: withOpacity('--accent'), + foreground: withOpacity('--accent-foreground'), + }, + destructive: { + DEFAULT: withOpacity('--surface-destructive'), + foreground: withOpacity('--destructive-foreground'), + }, + border: withOpacity('--border'), + input: withOpacity('--input'), + ring: withOpacity('--ring'), + card: { + DEFAULT: withOpacity('--card'), + foreground: withOpacity('--card-foreground'), + }, + }; +} + +module.exports = { createTailwindColors }; diff --git a/packages/client/src/utils/index.ts b/packages/client/src/utils/index.ts new file mode 100644 index 000000000..94696af63 --- /dev/null +++ b/packages/client/src/utils/index.ts @@ -0,0 +1,2 @@ +export * from './utils'; +export * from './theme'; diff --git a/client/src/utils/theme.ts b/packages/client/src/utils/theme.ts similarity index 95% rename from client/src/utils/theme.ts rename to packages/client/src/utils/theme.ts index d389dea57..a5bc645a0 100644 --- a/client/src/utils/theme.ts +++ b/packages/client/src/utils/theme.ts @@ -34,5 +34,5 @@ export const getInitialTheme = () => { } } - return 'light'; // light theme as the default; + return 'light'; }; diff --git a/packages/client/src/utils/utils.ts b/packages/client/src/utils/utils.ts new file mode 100644 index 000000000..fad4c32a0 --- /dev/null +++ b/packages/client/src/utils/utils.ts @@ -0,0 +1,7 @@ +// ESM utility functions +import { type ClassValue, clsx } from 'clsx'; +import { twMerge } from 'tailwind-merge'; + +export const cn = (...inputs: ClassValue[]): string => { + return twMerge(clsx(inputs)); +}; diff --git a/packages/client/tailwind.config.js b/packages/client/tailwind.config.js new file mode 100644 index 000000000..df7ee31c6 --- /dev/null +++ b/packages/client/tailwind.config.js @@ -0,0 +1,13 @@ +const { createTailwindColors } = require('./src/theme/utils/createTailwindColors.js'); + +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: ['./src/**/*.{js,jsx,ts,tsx}'], + darkMode: ['class'], + theme: { + extend: { + colors: createTailwindColors(), + }, + }, + plugins: [], +}; diff --git a/packages/client/tsconfig.json b/packages/client/tsconfig.json new file mode 100644 index 000000000..447cb1e66 --- /dev/null +++ b/packages/client/tsconfig.json @@ -0,0 +1,34 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "ESNext", + "moduleResolution": "node", + "jsx": "react-jsx", + "jsxImportSource": "react", + "declaration": true, + "declarationMap": true, + "declarationDir": "./dist/types", + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "strict": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "outDir": "./dist", + "rootDir": "./src", + "baseUrl": "./src", + "paths": { + "~/*": ["./*"] + }, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "resolveJsonModule": true + }, + "include": ["src/**/*"], + "exclude": [ + "dist", + "node_modules", + "**/*.test.ts", + "**/*.test.tsx", + "**/*.spec.ts", + "**/*.spec.tsx" + ] +}