From c629fe068bd9cf656efe19251a597ee5b98e80b9 Mon Sep 17 00:00:00 2001 From: loosand Date: Tue, 26 May 2026 21:58:16 +0800 Subject: [PATCH 1/3] refactor(ui): migrate from Radix UI to Base UI (@base-ui/react) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Replace @radix-ui/react-select, dropdown-menu, scroll-area, slot with @base-ui/react equivalents - Rewrite button.tsx: replace asChild/Slot pattern with render prop - Rewrite confirm-action-popover.tsx using Base UI Popover (adds focus trap, Esc key, ARIA) - Fix Select alignItemWithTrigger=false to prevent popup overlapping trigger - Fix --radix-dropdown-menu-content-available-height → --available-height in ChatHeader - Fix data-[state=open/checked] → data-[open]/data-[selected] in ChatComposerBar - Add data-scroll-viewport attribute to ScrollArea.Viewport; update ChatTranscript queries - Add components.json for shadcn/ui configuration - Add docs/ui-code-review.md with a11y and implementation review Co-Authored-By: Claude Sonnet 4.6 --- crates/agent-gui/components.json | 17 + crates/agent-gui/package.json | 5 +- crates/agent-gui/pnpm-lock.yaml | 823 ++---------------- .../components/chat/ChatHistorySidebar.tsx | 46 +- crates/agent-gui/src/components/ui/button.tsx | 28 +- .../components/ui/confirm-action-popover.tsx | 111 +-- .../src/components/ui/dropdown-menu.tsx | 93 +- .../src/components/ui/scroll-area.tsx | 21 +- crates/agent-gui/src/components/ui/select.tsx | 129 ++- .../src/pages/chat/ChatComposerBar.tsx | 8 +- .../agent-gui/src/pages/chat/ChatHeader.tsx | 48 +- .../src/pages/chat/ChatTranscript.tsx | 4 +- .../src/pages/mcp-hub/McpRegistryBrowser.tsx | 8 +- .../src/pages/settings/MemoryPanel.tsx | 104 +-- .../src/pages/skills-hub/SkillsHubPage.tsx | 8 +- docs/ui-code-review.md | 201 +++++ 16 files changed, 611 insertions(+), 1043 deletions(-) create mode 100644 crates/agent-gui/components.json create mode 100644 docs/ui-code-review.md diff --git a/crates/agent-gui/components.json b/crates/agent-gui/components.json new file mode 100644 index 000000000..10cef78c5 --- /dev/null +++ b/crates/agent-gui/components.json @@ -0,0 +1,17 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "default", + "rsc": false, + "tsx": true, + "tailwind": { + "config": "tailwind.config.js", + "css": "src/index.css", + "baseColor": "slate", + "cssVariables": true + }, + "aliases": { + "components": "@/components", + "utils": "@/lib/shared/utils", + "ui": "@/components/ui" + } +} diff --git a/crates/agent-gui/package.json b/crates/agent-gui/package.json index 64e7554be..d22ff97bc 100644 --- a/crates/agent-gui/package.json +++ b/crates/agent-gui/package.json @@ -16,15 +16,12 @@ }, "dependencies": { "@anthropic-ai/claude-agent-sdk": "^0.2.96", + "@base-ui/react": "^1.5.0", "@git-diff-view/file": "^0.1.3", "@git-diff-view/react": "^0.1.3", "@mariozechner/pi-agent-core": "^0.65.2", "@mariozechner/pi-ai": "^0.65.2", "@openai/codex-sdk": "^0.118.0", - "@radix-ui/react-dropdown-menu": "^2.1.16", - "@radix-ui/react-scroll-area": "^1.2.10", - "@radix-ui/react-select": "^2.2.6", - "@radix-ui/react-slot": "^1.2.4", "@sinclair/typebox": "^0.34.49", "@streamdown/cjk": "^1.0.3", "@streamdown/code": "^1.1.1", diff --git a/crates/agent-gui/pnpm-lock.yaml b/crates/agent-gui/pnpm-lock.yaml index 1dd6f1f49..66b7d2c51 100644 --- a/crates/agent-gui/pnpm-lock.yaml +++ b/crates/agent-gui/pnpm-lock.yaml @@ -11,6 +11,9 @@ importers: '@anthropic-ai/claude-agent-sdk': specifier: ^0.2.96 version: 0.2.96(zod@4.3.6) + '@base-ui/react': + specifier: ^1.5.0 + version: 1.5.0(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@git-diff-view/file': specifier: ^0.1.3 version: 0.1.3 @@ -26,18 +29,6 @@ importers: '@openai/codex-sdk': specifier: ^0.118.0 version: 0.118.0 - '@radix-ui/react-dropdown-menu': - specifier: ^2.1.16 - version: 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-scroll-area': - specifier: ^1.2.10 - version: 1.2.10(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-select': - specifier: ^2.2.6 - version: 2.2.6(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-slot': - specifier: ^1.2.4 - version: 1.2.4(@types/react@19.2.14)(react@19.2.4) '@sinclair/typebox': specifier: ^0.34.49 version: 0.34.49 @@ -364,6 +355,10 @@ packages: resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==} engines: {node: '>=6.9.0'} + '@babel/runtime@7.29.7': + resolution: {integrity: sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==} + engines: {node: '>=6.9.0'} + '@babel/template@7.28.6': resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} engines: {node: '>=6.9.0'} @@ -376,6 +371,33 @@ packages: resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} engines: {node: '>=6.9.0'} + '@base-ui/react@1.5.0': + resolution: {integrity: sha512-z1gSAlced1yY+iM+mHDEtIkD8UI3Ebs52MuBPxvV6f5hRutk+xvCH/wuB7hDqDzK9JG5FoMz5nhrqtSs1wjt1A==} + engines: {node: '>=14.0.0'} + peerDependencies: + '@date-fns/tz': ^1.2.0 + '@types/react': ^17 || ^18 || ^19 + date-fns: ^4.0.0 + react: ^17 || ^18 || ^19 + react-dom: ^17 || ^18 || ^19 + peerDependenciesMeta: + '@date-fns/tz': + optional: true + '@types/react': + optional: true + date-fns: + optional: true + + '@base-ui/utils@0.2.9': + resolution: {integrity: sha512-x/PDDCYzoqPpjrdyb3VcyylTI2IjUXEtYDGi5foh7KsnmNJIIaVwA2GLgDH1dps1GgXiJbA60hM+AyuTfQzIvw==} + peerDependencies: + '@types/react': ^17 || ^18 || ^19 + react: ^17 || ^18 || ^19 + react-dom: ^17 || ^18 || ^19 + peerDependenciesMeta: + '@types/react': + optional: true + '@braintree/sanitize-url@7.1.2': resolution: {integrity: sha512-jigsZK+sMF/cuiB7sERuo9V7N9jx+dhmHHnQyDSVdpZwVutaBu7WvNYqMDLSgFgfB30n452TP3vjDAvFC973mA==} @@ -684,332 +706,6 @@ packages: '@protobufjs/utf8@1.1.0': resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==} - '@radix-ui/number@1.1.1': - resolution: {integrity: sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==} - - '@radix-ui/primitive@1.1.3': - resolution: {integrity: sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==} - - '@radix-ui/react-arrow@1.1.7': - resolution: {integrity: sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==} - 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 - - '@radix-ui/react-collection@1.1.7': - resolution: {integrity: sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==} - 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 - - '@radix-ui/react-compose-refs@1.1.2': - resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-context@1.1.2': - resolution: {integrity: sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-direction@1.1.1': - resolution: {integrity: sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-dismissable-layer@1.1.11': - resolution: {integrity: sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==} - 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 - - '@radix-ui/react-dropdown-menu@2.1.16': - resolution: {integrity: sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw==} - 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 - - '@radix-ui/react-focus-guards@1.1.3': - resolution: {integrity: sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-focus-scope@1.1.7': - resolution: {integrity: sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==} - 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 - - '@radix-ui/react-id@1.1.1': - resolution: {integrity: sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-menu@2.1.16': - resolution: {integrity: sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg==} - 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 - - '@radix-ui/react-popper@1.2.8': - resolution: {integrity: sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==} - 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 - - '@radix-ui/react-portal@1.1.9': - resolution: {integrity: sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==} - 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 - - '@radix-ui/react-presence@1.1.5': - resolution: {integrity: sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==} - 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 - - '@radix-ui/react-primitive@2.1.3': - resolution: {integrity: sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==} - 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 - - '@radix-ui/react-roving-focus@1.1.11': - resolution: {integrity: sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==} - 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 - - '@radix-ui/react-scroll-area@1.2.10': - resolution: {integrity: sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A==} - 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 - - '@radix-ui/react-select@2.2.6': - resolution: {integrity: sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ==} - 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 - - '@radix-ui/react-slot@1.2.3': - resolution: {integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-slot@1.2.4': - resolution: {integrity: sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-callback-ref@1.1.1': - resolution: {integrity: sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-controllable-state@1.2.2': - resolution: {integrity: sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-effect-event@0.0.2': - resolution: {integrity: sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-escape-keydown@1.1.1': - resolution: {integrity: sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-layout-effect@1.1.1': - resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-previous@1.1.1': - resolution: {integrity: sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-rect@1.1.1': - resolution: {integrity: sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-size@1.1.1': - resolution: {integrity: sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-visually-hidden@1.2.3': - resolution: {integrity: sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==} - 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 - - '@radix-ui/rect@1.1.1': - resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==} - '@rolldown/binding-android-arm64@1.0.0-rc.12': resolution: {integrity: sha512-pv1y2Fv0JybcykuiiD3qBOBdz6RteYojRFY1d+b95WVuzx211CRh+ytI/+9iVyWQ6koTh5dawe4S/yRfOFjgaA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1801,10 +1497,6 @@ packages: argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - aria-hidden@1.2.6: - resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} - engines: {node: '>=10'} - ast-types@0.13.4: resolution: {integrity: sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==} engines: {node: '>=4'} @@ -2164,9 +1856,6 @@ packages: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} - detect-node-es@1.1.0: - resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} - devlop@1.1.0: resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} @@ -2357,10 +2046,6 @@ packages: resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} engines: {node: '>= 0.4'} - get-nonce@1.0.1: - resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} - engines: {node: '>=6'} - get-proto@1.0.1: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} @@ -3089,36 +2774,6 @@ packages: peerDependencies: react: ^19.2.4 - react-remove-scroll-bar@2.3.8: - resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - - react-remove-scroll@2.7.2: - resolution: {integrity: sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==} - 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 - - react-style-singleton@2.2.3: - resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} - 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 - react@19.2.4: resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==} engines: {node: '>=0.10.0'} @@ -3194,6 +2849,9 @@ packages: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} + reselect@5.2.0: + resolution: {integrity: sha512-AgZ3UOZm3YndfrJ4OYjgrT7bmCm/1iqkjvEfH/oYjzh6PD2qw4QuT3jjnXIrpdt4MTpMXclMT3lXbmRY+XRakw==} + resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -3437,26 +3095,6 @@ packages: peerDependencies: browserslist: '>= 4.21.0' - use-callback-ref@1.3.3: - resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} - 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 - - use-sidecar@1.1.3: - resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==} - 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 - use-sync-external-store@1.6.0: resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==} peerDependencies: @@ -4098,6 +3736,8 @@ snapshots: '@babel/runtime@7.28.6': {} + '@babel/runtime@7.29.7': {} + '@babel/template@7.28.6': dependencies: '@babel/code-frame': 7.29.0 @@ -4121,6 +3761,29 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 + '@base-ui/react@1.5.0(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@babel/runtime': 7.29.7 + '@base-ui/utils': 0.2.9(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@floating-ui/react-dom': 2.1.8(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@floating-ui/utils': 0.2.11 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + use-sync-external-store: 1.6.0(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.14 + + '@base-ui/utils@0.2.9(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@babel/runtime': 7.29.7 + '@floating-ui/utils': 0.2.11 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + reselect: 5.2.0 + use-sync-external-store: 1.6.0(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.14 + '@braintree/sanitize-url@7.1.2': {} '@chevrotain/cst-dts-gen@11.1.2': @@ -4458,316 +4121,6 @@ snapshots: '@protobufjs/utf8@1.1.0': {} - '@radix-ui/number@1.1.1': {} - - '@radix-ui/primitive@1.1.3': {} - - '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - optionalDependencies: - '@types/react': 19.2.14 - '@types/react-dom': 19.2.3(@types/react@19.2.14) - - '@radix-ui/react-collection@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - optionalDependencies: - '@types/react': 19.2.14 - '@types/react-dom': 19.2.3(@types/react@19.2.14) - - '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.14)(react@19.2.4)': - dependencies: - react: 19.2.4 - optionalDependencies: - '@types/react': 19.2.14 - - '@radix-ui/react-context@1.1.2(@types/react@19.2.14)(react@19.2.4)': - dependencies: - react: 19.2.4 - optionalDependencies: - '@types/react': 19.2.14 - - '@radix-ui/react-direction@1.1.1(@types/react@19.2.14)(react@19.2.4)': - dependencies: - react: 19.2.4 - optionalDependencies: - '@types/react': 19.2.14 - - '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - optionalDependencies: - '@types/react': 19.2.14 - '@types/react-dom': 19.2.3(@types/react@19.2.14) - - '@radix-ui/react-dropdown-menu@2.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - optionalDependencies: - '@types/react': 19.2.14 - '@types/react-dom': 19.2.3(@types/react@19.2.14) - - '@radix-ui/react-focus-guards@1.1.3(@types/react@19.2.14)(react@19.2.4)': - dependencies: - react: 19.2.4 - optionalDependencies: - '@types/react': 19.2.14 - - '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - optionalDependencies: - '@types/react': 19.2.14 - '@types/react-dom': 19.2.3(@types/react@19.2.14) - - '@radix-ui/react-id@1.1.1(@types/react@19.2.14)(react@19.2.4)': - dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - optionalDependencies: - '@types/react': 19.2.14 - - '@radix-ui/react-menu@2.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.4) - aria-hidden: 1.2.6 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - react-remove-scroll: 2.7.2(@types/react@19.2.14)(react@19.2.4) - optionalDependencies: - '@types/react': 19.2.14 - '@types/react-dom': 19.2.3(@types/react@19.2.14) - - '@radix-ui/react-popper@1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@floating-ui/react-dom': 2.1.8(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-rect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/rect': 1.1.1 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - optionalDependencies: - '@types/react': 19.2.14 - '@types/react-dom': 19.2.3(@types/react@19.2.14) - - '@radix-ui/react-portal@1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - optionalDependencies: - '@types/react': 19.2.14 - '@types/react-dom': 19.2.3(@types/react@19.2.14) - - '@radix-ui/react-presence@1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - optionalDependencies: - '@types/react': 19.2.14 - '@types/react-dom': 19.2.3(@types/react@19.2.14) - - '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - optionalDependencies: - '@types/react': 19.2.14 - '@types/react-dom': 19.2.3(@types/react@19.2.14) - - '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - optionalDependencies: - '@types/react': 19.2.14 - '@types/react-dom': 19.2.3(@types/react@19.2.14) - - '@radix-ui/react-scroll-area@1.2.10(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@radix-ui/number': 1.1.1 - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - optionalDependencies: - '@types/react': 19.2.14 - '@types/react-dom': 19.2.3(@types/react@19.2.14) - - '@radix-ui/react-select@2.2.6(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@radix-ui/number': 1.1.1 - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - aria-hidden: 1.2.6 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - react-remove-scroll: 2.7.2(@types/react@19.2.14)(react@19.2.4) - optionalDependencies: - '@types/react': 19.2.14 - '@types/react-dom': 19.2.3(@types/react@19.2.14) - - '@radix-ui/react-slot@1.2.3(@types/react@19.2.14)(react@19.2.4)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - optionalDependencies: - '@types/react': 19.2.14 - - '@radix-ui/react-slot@1.2.4(@types/react@19.2.14)(react@19.2.4)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - optionalDependencies: - '@types/react': 19.2.14 - - '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.2.14)(react@19.2.4)': - dependencies: - react: 19.2.4 - optionalDependencies: - '@types/react': 19.2.14 - - '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.14)(react@19.2.4)': - dependencies: - '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - optionalDependencies: - '@types/react': 19.2.14 - - '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.14)(react@19.2.4)': - dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - optionalDependencies: - '@types/react': 19.2.14 - - '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.2.14)(react@19.2.4)': - dependencies: - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - optionalDependencies: - '@types/react': 19.2.14 - - '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.14)(react@19.2.4)': - dependencies: - react: 19.2.4 - optionalDependencies: - '@types/react': 19.2.14 - - '@radix-ui/react-use-previous@1.1.1(@types/react@19.2.14)(react@19.2.4)': - dependencies: - react: 19.2.4 - optionalDependencies: - '@types/react': 19.2.14 - - '@radix-ui/react-use-rect@1.1.1(@types/react@19.2.14)(react@19.2.4)': - dependencies: - '@radix-ui/rect': 1.1.1 - react: 19.2.4 - optionalDependencies: - '@types/react': 19.2.14 - - '@radix-ui/react-use-size@1.1.1(@types/react@19.2.14)(react@19.2.4)': - dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - optionalDependencies: - '@types/react': 19.2.14 - - '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - optionalDependencies: - '@types/react': 19.2.14 - '@types/react-dom': 19.2.3(@types/react@19.2.14) - - '@radix-ui/rect@1.1.1': {} - '@rolldown/binding-android-arm64@1.0.0-rc.12': optional: true @@ -5604,10 +4957,6 @@ snapshots: argparse@2.0.1: {} - aria-hidden@1.2.6: - dependencies: - tslib: 2.8.1 - ast-types@0.13.4: dependencies: tslib: 2.8.1 @@ -5964,8 +5313,6 @@ snapshots: detect-libc@2.1.2: {} - detect-node-es@1.1.0: {} - devlop@1.1.0: dependencies: dequal: 2.0.3 @@ -6172,8 +5519,6 @@ snapshots: hasown: 2.0.2 math-intrinsics: 1.1.0 - get-nonce@1.0.1: {} - get-proto@1.0.1: dependencies: dunder-proto: 1.0.1 @@ -7214,33 +6559,6 @@ snapshots: react: 19.2.4 scheduler: 0.27.0 - react-remove-scroll-bar@2.3.8(@types/react@19.2.14)(react@19.2.4): - dependencies: - react: 19.2.4 - react-style-singleton: 2.2.3(@types/react@19.2.14)(react@19.2.4) - tslib: 2.8.1 - optionalDependencies: - '@types/react': 19.2.14 - - react-remove-scroll@2.7.2(@types/react@19.2.14)(react@19.2.4): - dependencies: - react: 19.2.4 - react-remove-scroll-bar: 2.3.8(@types/react@19.2.14)(react@19.2.4) - react-style-singleton: 2.2.3(@types/react@19.2.14)(react@19.2.4) - tslib: 2.8.1 - use-callback-ref: 1.3.3(@types/react@19.2.14)(react@19.2.4) - use-sidecar: 1.1.3(@types/react@19.2.14)(react@19.2.4) - optionalDependencies: - '@types/react': 19.2.14 - - react-style-singleton@2.2.3(@types/react@19.2.14)(react@19.2.4): - dependencies: - get-nonce: 1.0.1 - react: 19.2.4 - tslib: 2.8.1 - optionalDependencies: - '@types/react': 19.2.14 - react@19.2.4: {} reactivity-store@0.4.0(react@19.2.4): @@ -7358,6 +6676,8 @@ snapshots: require-from-string@2.0.2: {} + reselect@5.2.0: {} + resolve-from@4.0.0: {} retry@0.13.1: {} @@ -7662,21 +6982,6 @@ snapshots: escalade: 3.2.0 picocolors: 1.1.1 - use-callback-ref@1.3.3(@types/react@19.2.14)(react@19.2.4): - dependencies: - react: 19.2.4 - tslib: 2.8.1 - optionalDependencies: - '@types/react': 19.2.14 - - use-sidecar@1.1.3(@types/react@19.2.14)(react@19.2.4): - dependencies: - detect-node-es: 1.1.0 - react: 19.2.4 - tslib: 2.8.1 - optionalDependencies: - '@types/react': 19.2.14 - use-sync-external-store@1.6.0(react@19.2.4): dependencies: react: 19.2.4 diff --git a/crates/agent-gui/src/components/chat/ChatHistorySidebar.tsx b/crates/agent-gui/src/components/chat/ChatHistorySidebar.tsx index 524a6ec82..a636d1a75 100644 --- a/crates/agent-gui/src/components/chat/ChatHistorySidebar.tsx +++ b/crates/agent-gui/src/components/chat/ChatHistorySidebar.tsx @@ -277,26 +277,32 @@ const HistoryRow = memo(function HistoryRow(props: { ) : null} - - + ) => + e.stopPropagation() + } + onClick={(e: React.MouseEvent) => + e.stopPropagation() + } + className={cn( + "h-8 w-8 shrink-0 rounded-xl text-muted-foreground opacity-0 pointer-events-none transition-[opacity,colors]", + "hover:bg-muted/70 hover:text-foreground", + "group-hover/item:opacity-100 group-hover/item:pointer-events-auto", + "group-focus-within/item:opacity-100 group-focus-within/item:pointer-events-auto", + menuOpen && "bg-muted/70 text-foreground", + menuOpen && "opacity-100 pointer-events-auto", + )} + /> + } + > + & VariantProps & { - asChild?: boolean; + render?: React.ReactElement; }; export const Button = React.forwardRef( - ({ className, variant, size, asChild = false, ...props }, ref) => { - const Comp = asChild ? Slot : "button"; + ({ className, variant, size, render: renderProp, children, ...props }, ref) => { + const mergedClass = cn(buttonVariants({ variant, size }), className); + + if (renderProp) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const rp = renderProp as React.ReactElement; + return React.cloneElement(rp, { + className: cn(mergedClass, rp.props.className), + ...props, + children: children ?? rp.props.children, + }); + } + return ( - + ); }, ); Button.displayName = "Button"; + +export { buttonVariants }; diff --git a/crates/agent-gui/src/components/ui/confirm-action-popover.tsx b/crates/agent-gui/src/components/ui/confirm-action-popover.tsx index 1ceb280a9..c30fb795d 100644 --- a/crates/agent-gui/src/components/ui/confirm-action-popover.tsx +++ b/crates/agent-gui/src/components/ui/confirm-action-popover.tsx @@ -1,4 +1,5 @@ -import { useEffect, useRef, useState, type ReactNode } from "react"; +import { type ReactNode } from "react"; +import { Popover } from "@base-ui/react"; import { AlertTriangle } from "../icons"; import { useLocale } from "../../i18n"; @@ -13,78 +14,52 @@ export function ConfirmActionPopover(props: { }) { const { title, description, confirmLabel, onConfirm, children } = props; const { t } = useLocale(); - const [show, setShow] = useState(false); - const [flipUp, setFlipUp] = useState(false); - const ref = useRef(null); - - useEffect(() => { - if (!show) return; - - function handleClick(e: MouseEvent) { - if (ref.current && !ref.current.contains(e.target as Node)) setShow(false); - } - - document.addEventListener("mousedown", handleClick); - return () => document.removeEventListener("mousedown", handleClick); - }, [show]); - - function handleOpen() { - if (ref.current) { - const rect = ref.current.getBoundingClientRect(); - // Popover is ~160px tall; flip upward if not enough space below - setFlipUp(window.innerHeight - rect.bottom < 170); - } - setShow(true); - } return ( -
- {children(handleOpen)} - {show ? ( -
-
-
-
- -
-
-

{title}

-
- {description} + + {/* Pass no-op — Popover.Trigger merges its own click handler via render prop */} + {}) as React.ReactElement} /> + + + +
+
+
+ +
+
+

{title}

+
+ {description} +
+
+ + } + > + {t("settings.cancel")} + + + } + > + {confirmLabel} + +
-
- - -
-
-
- ) : null} -
+ + + + ); } diff --git a/crates/agent-gui/src/components/ui/dropdown-menu.tsx b/crates/agent-gui/src/components/ui/dropdown-menu.tsx index 779e5b64d..16aa9f027 100644 --- a/crates/agent-gui/src/components/ui/dropdown-menu.tsx +++ b/crates/agent-gui/src/components/ui/dropdown-menu.tsx @@ -1,87 +1,98 @@ import * as React from "react"; -import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"; +import { Menu } from "@base-ui/react"; import { Check } from "../icons"; import { cn } from "../../lib/shared/utils"; -export const DropdownMenu = DropdownMenuPrimitive.Root; -export const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger; +export const DropdownMenu = Menu.Root; +export const DropdownMenuTrigger = Menu.Trigger; -export const DropdownMenuContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, sideOffset = 4, ...props }, ref) => ( - - - -)); -DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName; +type DropdownMenuContentProps = React.ComponentPropsWithoutRef & + Pick< + React.ComponentPropsWithoutRef, + "side" | "align" | "sideOffset" | "collisionPadding" + >; + +export const DropdownMenuContent = React.forwardRef( + ({ className, side, align, sideOffset = 4, collisionPadding, ...props }, ref) => ( + + + + + + ), +); +DropdownMenuContent.displayName = "DropdownMenuContent"; export const DropdownMenuLabel = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + HTMLDivElement, + React.HTMLAttributes >(({ className, ...props }, ref) => ( - )); -DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName; +DropdownMenuLabel.displayName = "DropdownMenuLabel"; export const DropdownMenuSeparator = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + HTMLDivElement, + React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( - )); -DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName; +DropdownMenuSeparator.displayName = "DropdownMenuSeparator"; export const DropdownMenuCheckboxItem = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + HTMLDivElement, + React.ComponentPropsWithoutRef >(({ className, children, ...props }, ref) => ( - - + - + {children} - + )); -DropdownMenuCheckboxItem.displayName = DropdownMenuPrimitive.CheckboxItem.displayName; +DropdownMenuCheckboxItem.displayName = "DropdownMenuCheckboxItem"; export const DropdownMenuItem = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + HTMLDivElement, + React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( - )); -DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName; +DropdownMenuItem.displayName = "DropdownMenuItem"; diff --git a/crates/agent-gui/src/components/ui/scroll-area.tsx b/crates/agent-gui/src/components/ui/scroll-area.tsx index 0f8686809..9f9388dd0 100644 --- a/crates/agent-gui/src/components/ui/scroll-area.tsx +++ b/crates/agent-gui/src/components/ui/scroll-area.tsx @@ -1,10 +1,10 @@ import * as React from "react"; -import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area"; +import { ScrollArea as ScrollAreaPrimitive } from "@base-ui/react"; import { cn } from "../../lib/shared/utils"; export const ScrollArea = React.forwardRef< - React.ElementRef, + HTMLDivElement, React.ComponentPropsWithoutRef >(({ className, children, ...props }, ref) => ( - - {children} + + {children} )); - -ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName; +ScrollArea.displayName = "ScrollArea"; const ScrollBar = React.forwardRef< - React.ElementRef, + HTMLDivElement, React.ComponentPropsWithoutRef >(({ className, orientation = "vertical", ...props }, ref) => ( )); - -ScrollBar.displayName = ScrollAreaPrimitive.Scrollbar.displayName; +ScrollBar.displayName = "ScrollBar"; diff --git a/crates/agent-gui/src/components/ui/select.tsx b/crates/agent-gui/src/components/ui/select.tsx index a28267a2a..b23017ad4 100644 --- a/crates/agent-gui/src/components/ui/select.tsx +++ b/crates/agent-gui/src/components/ui/select.tsx @@ -1,14 +1,58 @@ import * as React from "react"; -import * as SelectPrimitive from "@radix-ui/react-select"; +import { Select as SelectPrimitive } from "@base-ui/react"; import { Check, ChevronDown, ChevronUp } from "../icons"; import { cn } from "../../lib/shared/utils"; -export const Select = SelectPrimitive.Root; -export const SelectValue = SelectPrimitive.Value; +type SelectProps = Omit< + React.ComponentPropsWithoutRef, + "onValueChange" +> & { + onValueChange?: (value: string) => void; +}; + +export function Select({ onValueChange, ...props }: SelectProps) { + return ( + { + if (value != null) onValueChange(value as string); + } + : undefined + } + {...props} + /> + ); +} + +type SelectValueProps = Omit< + React.ComponentPropsWithoutRef, + "children" +> & { + placeholder?: React.ReactNode; + children?: React.ReactNode | ((value: unknown) => React.ReactNode); +}; + +export const SelectValue = React.forwardRef( + ({ placeholder, children, ...props }, ref) => { + const rendered = + children !== undefined + ? children + : placeholder !== undefined + ? (value: unknown) => (value == null ? placeholder : undefined) + : undefined; + return ( + + {rendered as React.ComponentPropsWithoutRef["children"]} + + ); + }, +); +SelectValue.displayName = "SelectValue"; export const SelectTrigger = React.forwardRef< - React.ElementRef, + HTMLButtonElement, React.ComponentPropsWithoutRef >(({ className, children, ...props }, ref) => ( {children} - + )); -SelectTrigger.displayName = SelectPrimitive.Trigger.displayName; +SelectTrigger.displayName = "SelectTrigger"; const SelectScrollUpButton = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + HTMLDivElement, + React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( - - + )); -SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName; +SelectScrollUpButton.displayName = "SelectScrollUpButton"; const SelectScrollDownButton = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + HTMLDivElement, + React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( - - + )); -SelectScrollDownButton.displayName = - SelectPrimitive.ScrollDownButton.displayName; +SelectScrollDownButton.displayName = "SelectScrollDownButton"; export const SelectContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + HTMLDivElement, + React.ComponentPropsWithoutRef & { + position?: "popper" | "item-aligned"; + } >(({ className, children, position = "popper", ...props }, ref) => ( - - - + - {children} - - - + + + {children} + + + + )); -SelectContent.displayName = SelectPrimitive.Content.displayName; +SelectContent.displayName = "SelectContent"; export const SelectItem = React.forwardRef< - React.ElementRef, + HTMLDivElement, React.ComponentPropsWithoutRef >(({ className, children, ...props }, ref) => ( {children} )); -SelectItem.displayName = SelectPrimitive.Item.displayName; +SelectItem.displayName = "SelectItem"; diff --git a/crates/agent-gui/src/pages/chat/ChatComposerBar.tsx b/crates/agent-gui/src/pages/chat/ChatComposerBar.tsx index af89653c0..d77073159 100644 --- a/crates/agent-gui/src/pages/chat/ChatComposerBar.tsx +++ b/crates/agent-gui/src/pages/chat/ChatComposerBar.tsx @@ -298,10 +298,10 @@ export const ChatComposerBar = memo(function ChatComposerBar(props: { > svg:last-child]:h-3 [&>svg:last-child]:w-3 [&>svg:last-child]:opacity-50 [&>svg:last-child]:transition-transform [&>svg:last-child]:duration-200 [&[data-state=open]>svg:last-child]:rotate-180", + "composer-reasoning-trigger group/reasoning h-8 w-auto shrink-0 gap-0.5 rounded-full border pl-2 pr-1.5 text-xs font-medium shadow-none outline-hidden transition-all duration-200 ease-out disabled:opacity-45 [&>svg:last-child]:h-3 [&>svg:last-child]:w-3 [&>svg:last-child]:opacity-50 [&>svg:last-child]:transition-transform [&>svg:last-child]:duration-200 [&[data-open]>svg:last-child]:rotate-180", chatRuntimeControls.thinkingEnabled ? "border-violet-300/30 bg-violet-50/55 text-foreground hover:border-violet-300/45 hover:bg-violet-50/80 dark:border-violet-300/15 dark:bg-violet-400/[0.07] dark:text-foreground dark:hover:bg-violet-400/[0.13]" - : "border-transparent bg-foreground/[0.04] text-muted-foreground hover:bg-foreground/[0.07] dark:bg-white/[0.04] dark:hover:bg-white/[0.08]", + : "border-transparent bg-foreground/4 text-muted-foreground hover:bg-foreground/[0.07] dark:bg-white/[0.04] dark:hover:bg-white/[0.08]", )} aria-label={t("chat.runtime.reasoning")} > @@ -317,12 +317,12 @@ export const ChatComposerBar = memo(function ChatComposerBar(props: { - + {reasoningOptions.map((value, index) => ( {t(REASONING_I18N_KEYS[value])} diff --git a/crates/agent-gui/src/pages/chat/ChatHeader.tsx b/crates/agent-gui/src/pages/chat/ChatHeader.tsx index 6e7bff9fd..4d39b9de1 100644 --- a/crates/agent-gui/src/pages/chat/ChatHeader.tsx +++ b/crates/agent-gui/src/pages/chat/ChatHeader.tsx @@ -112,31 +112,33 @@ export const ChatHeader = memo(function ChatHeader(props: { ) : null} - - + } + > + + {selectedOption ? ( + + ) : null} + {currentModelLabel} + + -
+
{(() => { let animationIndex = 0; return groups.map((group, groupIndex) => ( diff --git a/crates/agent-gui/src/pages/chat/ChatTranscript.tsx b/crates/agent-gui/src/pages/chat/ChatTranscript.tsx index 34608b34a..026e78c01 100644 --- a/crates/agent-gui/src/pages/chat/ChatTranscript.tsx +++ b/crates/agent-gui/src/pages/chat/ChatTranscript.tsx @@ -85,11 +85,11 @@ function writeUploadedImagePreviewCache(cacheKey: string, value: string) { } function resolveNearestScrollViewport(element: HTMLElement | null) { - return element?.closest("[data-radix-scroll-area-viewport]") as HTMLDivElement | null; + return element?.closest("[data-scroll-viewport]") as HTMLDivElement | null; } function resolveScrollAreaViewport(root: HTMLDivElement | null) { - return root?.querySelector("[data-radix-scroll-area-viewport]") as HTMLDivElement | null; + return root?.querySelector("[data-scroll-viewport]") as HTMLDivElement | null; } async function loadUploadedImagePreview(params: { diff --git a/crates/agent-gui/src/pages/mcp-hub/McpRegistryBrowser.tsx b/crates/agent-gui/src/pages/mcp-hub/McpRegistryBrowser.tsx index 238bc6d0a..6e07561cb 100644 --- a/crates/agent-gui/src/pages/mcp-hub/McpRegistryBrowser.tsx +++ b/crates/agent-gui/src/pages/mcp-hub/McpRegistryBrowser.tsx @@ -1185,12 +1185,10 @@ function McpRegistryPreviewDrawer(props: { variant="outline" size="sm" className="h-9 flex-1 gap-1.5 rounded-xl border-border/50 bg-background/70" - asChild + render={} > - - - {t("mcpHub.storeOpenExternal")} - + + {t("mcpHub.storeOpenExternal")} ) : null} ) : null}
-

- {t("chat.welcome")} -

-

- {t("chat.noModelSelected")} -

-

- {t("chat.configureModel")} -

-
-
- ) : showStartChatState ? ( -
-
-
-
- -
-
- + ) : showStartChatState ? ( +
+
+
-

- {t("chat.startChat")} -

+
+
+ +
+ +

+ {t("chat.startChat")} +

-

- {t("chat.startChatDesc")} -

+

+ {t("chat.startChatDesc")} +

+
-
- ) : null} + ) : null} -
- +
+ - -
+ +
-
+
{isHistorySwitching ? : null} diff --git a/crates/agent-gui/src/pages/settings/MemoryPanel.tsx b/crates/agent-gui/src/pages/settings/MemoryPanel.tsx index c111c41cf..98ce106f2 100644 --- a/crates/agent-gui/src/pages/settings/MemoryPanel.tsx +++ b/crates/agent-gui/src/pages/settings/MemoryPanel.tsx @@ -1,12 +1,12 @@ +import { Select as SelectPrimitive } from "@base-ui/react"; import { useEffect, useMemo, useRef, useState } from "react"; import { createPortal } from "react-dom"; -import { Select as SelectPrimitive } from "@base-ui/react"; import { AlertTriangle, + BookOpen, Brain, BrushCleaning, Check, - BookOpen, ChevronDown, Folder, Globe2, @@ -18,28 +18,26 @@ import { Trash2, X, } from "../../components/icons"; - +import { pokeMemoryOrganizerRunner } from "../../components/memory/MemoryOrganizerRunner"; import { Button } from "../../components/ui/button"; import { Input } from "../../components/ui/input"; import { useLocale } from "../../i18n"; import { buildModelOptions } from "../../lib/chat/page/chatPageHelpers"; -import { - computeNextMemoryOrganizerRunAt, - updateMemorySettings, - type AppSettings, - type MemoryOrganizerFrequency, - type MemoryOrganizerMode, - type MemoryOrganizerScope, -} from "../../lib/settings"; -import { parseModelValue, toModelValue } from "../../lib/providers/llm"; import { formatMemoryError, + type MemoryListResponse, + type MemoryMeta, + type MemoryOrganizeRun, + type MemoryOrganizeRunStatus, + type MemoryPathsInfo, + type MemoryReadResponse, + type MemoryType, memoryAccept, memoryApplyBatch, memoryDelete, memoryList, - memoryOrganizeRunCreate, memoryOrganizeRunClearHistory, + memoryOrganizeRunCreate, memoryOrganizeRunList, memoryOrganizeRunRead, memoryOrganizeRunUpdate, @@ -48,16 +46,8 @@ import { memoryUpdate, memoryWipeAll, memoryWrite, - type MemoryListResponse, - type MemoryMeta, - type MemoryOrganizeRun, - type MemoryOrganizeRunStatus, - type MemoryPathsInfo, - type MemoryReadResponse, - type MemoryType, } from "../../lib/memory/api"; import { - ORGANIZER_PROTOCOL_VERSION, appliedBatchCount, buildManualApplyState, buildReviewItemsForBatch, @@ -66,6 +56,9 @@ import { failedDecisionKeysFromReviewItems, inferOrganizerDecisionGroupIds, isDefaultSelectedOrganizerDecision, + ORGANIZER_PROTOCOL_VERSION, + type OrganizerReviewItem, + type OrganizerSafeDecision, organizerDecisionKey, protocolManualApplyState, protocolObject, @@ -74,10 +67,16 @@ import { protocolStringArray, reviewItemsFromProtocol, successfulDecisionKeys, - type OrganizerReviewItem, - type OrganizerSafeDecision, } from "../../lib/memory/organizerProtocol"; -import { pokeMemoryOrganizerRunner } from "../../components/memory/MemoryOrganizerRunner"; +import { parseModelValue, toModelValue } from "../../lib/providers/llm"; +import { + type AppSettings, + computeNextMemoryOrganizerRunAt, + type MemoryOrganizerFrequency, + type MemoryOrganizerMode, + type MemoryOrganizerScope, + updateMemorySettings, +} from "../../lib/settings"; import { AgentActivationSwitch } from "./shared"; type MemoryTab = "global" | "project" | "journal"; @@ -155,14 +154,14 @@ function DrawerSelect(props: { return ( { if (v != null) onValueChange(v as string); }} + onValueChange={(v) => { + if (v != null) onValueChange(v as string); + }} disabled={disabled} > - - {selected ? selected.label : placeholder} - + {selected ? selected.label : placeholder} @@ -247,15 +246,11 @@ function dailyTitle(entry: { slug: string; dateLocal?: string | null }) { } function entryTitle(entry: MemoryMeta) { - return entry.memoryType === "daily" - ? dailyTitle(entry) - : entry.description || entry.slug; + return entry.memoryType === "daily" ? dailyTitle(entry) : entry.description || entry.slug; } function selectedTitle(entry: MemoryReadResponse) { - return entry.memoryType === "daily" - ? dailyTitle(entry) - : entry.description || entry.slug; + return entry.memoryType === "daily" ? dailyTitle(entry) : entry.description || entry.slug; } function entryKey(entry: MemoryMeta) { @@ -288,9 +283,7 @@ function memoryTypeLabel( } function memoryScopeLabel(scope: MemoryMeta["scope"], t: (key: string) => string) { - return scope === "project" - ? t("settings.memoryScopeProject") - : t("settings.memoryScopeGlobal"); + return scope === "project" ? t("settings.memoryScopeProject") : t("settings.memoryScopeGlobal"); } function organizerStatusLabel(status: MemoryOrganizeRunStatus, t: (key: string) => string) { @@ -343,10 +336,7 @@ function isOrganizerRunActive(run: Pick | null | un return run?.status === "pending" || run?.status === "running"; } -function organizerRiskLabel( - risk: OrganizerSafeDecision["riskLevel"], - t: (key: string) => string, -) { +function organizerRiskLabel(risk: OrganizerSafeDecision["riskLevel"], t: (key: string) => string) { if (risk === "high") return t("settings.memoryOrganizerRiskHigh"); if (risk === "medium") return t("settings.memoryOrganizerRiskMedium"); return t("settings.memoryOrganizerRiskLow"); @@ -691,7 +681,8 @@ function MemoryOrganizerHistoryModal(props: { const failedKeySet = new Set(failedDecisionKeys); const safeDecisionsForProtocol = parsedSafeDecisions.map((decision, index) => { const key = organizerDecisionKey(decision, index); - const grouped = selectedWithGroupedKeys.find((item) => item.key === key)?.decision ?? decision; + const grouped = + selectedWithGroupedKeys.find((item) => item.key === key)?.decision ?? decision; if (failedKeySet.has(key)) return { ...grouped, applyStatus: "failed" as const }; if (appliedKeySet.has(key)) return { ...grouped, applyStatus: "applied" as const }; return grouped; @@ -757,381 +748,396 @@ function MemoryOrganizerHistoryModal(props: { >
-
-
-
- {t("settings.memoryOrganizerHistory")} -
-
- {t("settings.memoryOrganizerHistoryDescription")} +
+
+
+ {t("settings.memoryOrganizerHistory")} +
+
+ {t("settings.memoryOrganizerHistoryDescription")} +
+
- -
-
- + +
+ {error ? ( +
+ {error}
- ) : ( -
- {runs.map((run) => { - const active = selectedRun?.runId === run.runId; - return ( - - ); - })} + ) : null} + {historyFeedback ? ( +
+ {historyFeedback}
- )} -
- - -
- {error ? ( -
- {error} -
- ) : null} - {historyFeedback ? ( -
- {historyFeedback} -
- ) : null} - {selectedRun ? ( -
-
-
-
- - {organizerStatusLabel(selectedRun.status, t)} + ) : null} + {selectedRun ? ( +
+
+
+
+ + {organizerStatusLabel(selectedRun.status, t)} + + + {organizerTriggerLabel(selectedRun.trigger, t)} + + + {selectedRun.scope} / {selectedRun.mode} + +
+
+ {selectedRun.runId} +
+
+
+ + {t("settings.memoryOrganizerStarted")} - - {organizerTriggerLabel(selectedRun.trigger, t)} + + {formatTime(selectedRun.startedAt || selectedRun.createdAt)} - - {selectedRun.scope} / {selectedRun.mode} + + {t("settings.memoryOrganizerFinished")} + + + {selectedRun.finishedAt ? formatTime(selectedRun.finishedAt) : "-"}
-
- {selectedRun.runId} -
-
-
- {t("settings.memoryOrganizerStarted")} - - {formatTime(selectedRun.startedAt || selectedRun.createdAt)} - - {t("settings.memoryOrganizerFinished")} - - {selectedRun.finishedAt ? formatTime(selectedRun.finishedAt) : "-"} -
-
-
-
- {t("settings.memoryOrganizerFinalSummary")} -
-
- {displayedFinalSummary(selectedRun, manualApplyDisplay) || - t("settings.memoryOrganizerHistoryPending")} +
+
+ {t("settings.memoryOrganizerFinalSummary")} +
+
+ {displayedFinalSummary(selectedRun, manualApplyDisplay) || + t("settings.memoryOrganizerHistoryPending")} +
-
-
- {[ - ["settings.memoryOrganizerInputCount", selectedRun.inputCount], - ["settings.memoryOrganizerClusterCount", selectedRun.clusterCount], - ["settings.memoryOrganizerSafeApplied", selectedRun.safeApplied], - ["settings.memoryOrganizerReviewSkipped", selectedRun.reviewSkipped], - ["settings.memoryOrganizerCreatedCount", selectedRun.createdCount], - ["settings.memoryOrganizerUpdatedCount", selectedRun.updatedCount], - ["settings.memoryOrganizerDeletedCount", selectedRun.deletedCount], - ["settings.memoryOrganizerParseFailures", selectedRun.parseFailures], - ].map(([key, value]) => ( -
-
{t(String(key))}
-
{value}
-
- ))} -
+
+ {[ + ["settings.memoryOrganizerInputCount", selectedRun.inputCount], + ["settings.memoryOrganizerClusterCount", selectedRun.clusterCount], + ["settings.memoryOrganizerSafeApplied", selectedRun.safeApplied], + ["settings.memoryOrganizerReviewSkipped", selectedRun.reviewSkipped], + ["settings.memoryOrganizerCreatedCount", selectedRun.createdCount], + ["settings.memoryOrganizerUpdatedCount", selectedRun.updatedCount], + ["settings.memoryOrganizerDeletedCount", selectedRun.deletedCount], + ["settings.memoryOrganizerParseFailures", selectedRun.parseFailures], + ].map(([key, value]) => ( +
+
{t(String(key))}
+
{value}
+
+ ))} +
- {safeDecisions.length > 0 ? ( -
-
-
-
- {t("settings.memoryOrganizerManualPreview")} -
-
- {manualApplyDisplay.status === "applied" - ? t("settings.memoryOrganizerApplied") - : manualApplyDisplay.status === "partial" - ? t("settings.memoryOrganizerPartiallyApplied") - : manualApplyDisplay.status === "failed" - ? t("settings.memoryOrganizerApplyFailed") - : t("settings.memoryOrganizerManualPreviewDescription")} + {safeDecisions.length > 0 ? ( +
+
+
+
+ {t("settings.memoryOrganizerManualPreview")} +
+
+ {manualApplyDisplay.status === "applied" + ? t("settings.memoryOrganizerApplied") + : manualApplyDisplay.status === "partial" + ? t("settings.memoryOrganizerPartiallyApplied") + : manualApplyDisplay.status === "failed" + ? t("settings.memoryOrganizerApplyFailed") + : t("settings.memoryOrganizerManualPreviewDescription")} +
-
- {canApplyManualPreview ? ( - - ) : null} -
-
- {safeDecisions.map((decision, index) => { - const key = organizerDecisionKey(decision, index); - const checked = - manualApplyDisplay.status && manualApplyDisplay.status !== "pending" - ? manualApplyDisplay.appliedDecisionKeys.size === 0 - ? decision.applyStatus !== "failed" - : manualApplyDisplay.appliedDecisionKeys.has(key) - : selectedDecisionKeys.has(key); - return ( -
+
+ {safeDecisions.map((decision, index) => { + const key = organizerDecisionKey(decision, index); + const checked = + manualApplyDisplay.status && manualApplyDisplay.status !== "pending" + ? manualApplyDisplay.appliedDecisionKeys.size === 0 + ? decision.applyStatus !== "failed" + : manualApplyDisplay.appliedDecisionKeys.has(key) + : selectedDecisionKeys.has(key); + return ( + + ); + })} +
+
+ ) : null} + + {rejectionBuckets.length > 0 ? ( +
+
+ {t("settings.memoryOrganizerRejectionBuckets")} +
+
+ {rejectionBuckets.map(([key, count]) => ( +
+
{t(key)}
+
{count}
+
+ ))} +
+
+ ) : null} + + {reviewItems.length > 0 ? ( +
+
+ {t("settings.memoryOrganizerReviewNotes")} +
+
    + {reviewItems.map((item, index) => ( +
  • +
    + + {organizerReviewItemLabel(item, t)} - {decision.applyError?.message ? ( - - {decision.applyError.message} + {item.code ? ( + + {item.code} ) : null} - {decision.sourceSlugs?.length ? ( - - {t("settings.memoryOrganizerSources")}{" "} - {decision.sourceSlugs.join(", ")} + {item.slug ? ( + + {item.slug} ) : null} - - - ); - })} -
    -
- ) : null} - - {rejectionBuckets.length > 0 ? ( -
-
- {t("settings.memoryOrganizerRejectionBuckets")} +
+
{item.message}
+ + ))} +
-
- {rejectionBuckets.map(([key, count]) => ( -
-
{t(key)}
-
{count}
-
- ))} -
-
- ) : null} + ) : null} - {reviewItems.length > 0 ? ( -
-
- {t("settings.memoryOrganizerReviewNotes")} -
-
    - {reviewItems.map((item, index) => ( -
  • -
    - - {organizerReviewItemLabel(item, t)} - - {item.code ? ( - - {item.code} - - ) : null} - {item.slug ? ( - - {item.slug} - - ) : null} + {clusterSummaries.length > 0 ? ( +
    +
    + {t("settings.memoryOrganizerClusterSummaries")} +
    +
    + {clusterSummaries.map((summary, index) => ( +
    + {summary}
    -
    {item.message}
    -
  • - ))} -
-
- ) : null} - - {clusterSummaries.length > 0 ? ( -
-
- {t("settings.memoryOrganizerClusterSummaries")} -
-
- {clusterSummaries.map((summary, index) => ( -
- {summary} -
- ))} + ))} +
-
- ) : null} + ) : null} - {rawBlocks.length > 0 ? ( -
- - {t("settings.memoryOrganizerTrimmedProtocol")} - -
-                      {JSON.stringify(rawBlocks, null, 2)}
-                    
-
- ) : null} -
- ) : ( -
- {t("settings.memoryOrganizerHistoryEmpty")} -
- )} -
-
+ {rawBlocks.length > 0 ? ( +
+ + {t("settings.memoryOrganizerTrimmedProtocol")} + +
+                        {JSON.stringify(rawBlocks, null, 2)}
+                      
+
+ ) : null} +
+ ) : ( +
+ {t("settings.memoryOrganizerHistoryEmpty")} +
+ )} + +
{clearConfirmOpen ? ( @@ -1283,17 +1289,11 @@ function MemorySettingsDrawer(props: { [modelOptions, t], ); - function renderModelSelect( - value: string, - onChange: (value: string) => void, - ariaLabel: string, - ) { + function renderModelSelect(value: string, onChange: (value: string) => void, ariaLabel: string) { return ( 0 ? value : DRAWER_SELECT_NONE_VALUE} - onValueChange={(next) => - onChange(next === DRAWER_SELECT_NONE_VALUE ? "" : next) - } + onValueChange={(next) => onChange(next === DRAWER_SELECT_NONE_VALUE ? "" : next)} options={memoryModelDrawerOptions} ariaLabel={ariaLabel} placeholder={t("settings.memoryModelNone")} @@ -1341,9 +1341,7 @@ function MemorySettingsDrawer(props: { }); } - function updateOrganizerSchedule( - patch: Partial, - ) { + function updateOrganizerSchedule(patch: Partial) { setSettings((prev) => { const organizerSchedule = { ...prev.memory.organizerSchedule, @@ -1395,11 +1393,7 @@ function MemorySettingsDrawer(props: { } const runnerPoked = pokeMemoryOrganizerRunner(); setOrganizerFeedback( - t( - runnerPoked - ? "settings.memoryOrganizerQueued" - : "settings.memoryOrganizerQueuedRemote", - ), + t(runnerPoked ? "settings.memoryOrganizerQueued" : "settings.memoryOrganizerQueuedRemote"), ); setHistoryOpen(true); } catch (err) { @@ -1548,9 +1542,7 @@ function MemorySettingsDrawer(props: { - updateOrganizerSchedule({ weekday: Number(next) }) - } + onValueChange={(next) => updateOrganizerSchedule({ weekday: Number(next) })} ariaLabel={t("settings.memoryOrganizerWeekday")} options={MEMORY_ORGANIZER_WEEKDAYS.map((key, index) => ({ value: String(index), @@ -1568,9 +1560,7 @@ function MemorySettingsDrawer(props: { value={settings.memory.organizerScope} onValueChange={(next) => { const organizerScope = next as MemoryOrganizerScope; - setSettings((prev) => - updateMemorySettings(prev, { organizerScope }), - ); + setSettings((prev) => updateMemorySettings(prev, { organizerScope })); }} ariaLabel={t("settings.memoryOrganizerScope")} options={MEMORY_ORGANIZER_SCOPES.map((item) => ({ @@ -1587,9 +1577,7 @@ function MemorySettingsDrawer(props: { value={settings.memory.organizerMode} onValueChange={(next) => { const organizerMode = next as MemoryOrganizerMode; - setSettings((prev) => - updateMemorySettings(prev, { organizerMode }), - ); + setSettings((prev) => updateMemorySettings(prev, { organizerMode })); }} ariaLabel={t("settings.memoryOrganizerMode")} options={MEMORY_ORGANIZER_MODES.map((item) => ({ @@ -1638,7 +1626,9 @@ function MemorySettingsDrawer(props: { disabled={!settings.memory.organizerModel || organizerSubmitting} onClick={handleRunNow} > - + {t("settings.memoryOrganizerRunNow")}
@@ -1764,10 +1754,7 @@ export function MemoryPanel(props: { appendBody: "", }); - const modelOptions = useMemo( - () => buildMemoryModelOptions(props.settings), - [props.settings], - ); + const modelOptions = useMemo(() => buildMemoryModelOptions(props.settings), [props.settings]); const globalEntries = useMemo(() => { return entries @@ -1840,7 +1827,8 @@ export function MemoryPanel(props: { setEntries(list.entries); setQuota(list.quota); setPathsInfo(info); - const keepKey = keepEntry === undefined ? (selectedEntry ? entryKey(selectedEntry) : null) : keepEntry; + const keepKey = + keepEntry === undefined ? (selectedEntry ? entryKey(selectedEntry) : null) : keepEntry; if (keepKey) { const found = list.entries.find((entry) => entryKey(entry) === keepKey) ?? @@ -2086,343 +2074,369 @@ export function MemoryPanel(props: { <>
-
-
-
- - {t("settings.memoryTitle")} -
-
- {pathsInfo?.root ?? "~/.liveagent/memory"} -
-
-
- {quotaItems.map((item) => { - const level = quotaLevel(item); - const label = - item.scope === "global" - ? t("settings.memoryQuotaGlobal") - : t("settings.memoryQuotaProject"); - return ( -
- {label} {item.used} / {item.limit} -
- ); - })} -
- {t(quotaStatusLabelKey(quotaStatus))} +
+
+
+ + {t("settings.memoryTitle")} +
+
+ {pathsInfo?.root ?? "~/.liveagent/memory"} +
- - -
-
- - {unreviewedCount > 0 ? ( -
- {unreviewedCount} {t("settings.memoryAwaitingReview")} -
- ) : null} - {pathsInfo?.isInCloud ? ( -
- - {t("settings.memoryCloudWarningPrefix")}{" "} - {pathsInfo.cloudProvider ?? t("settings.memoryCloudSyncFolder")} -
- ) : null} - {quotaStatus === "full" || quotaStatus === "danger" ? ( -
- - {t( - quotaStatus === "full" - ? "settings.memoryQuotaFullMessage" - : "settings.memoryQuotaNearLimitMessage", - )} -
- ) : quotaStatus === "warning" ? ( -
- - {t("settings.memoryQuotaWarningMessage")} -
- ) : null} - {error ? ( -
- {error} -
- ) : null} -
- -
-
-
-
- - - -
-
-
- - setFilter(event.target.value)} - className="pl-8 text-xs" - placeholder={t("settings.memorySearchPlaceholder")} - /> + {t(quotaStatusLabelKey(quotaStatus))}
+
-
- {tab === "global" ? ( - renderFlatEntries(globalEntries, "settings.memoryNoGlobalEntries") - ) : tab === "journal" ? ( - renderFlatEntries(dailyEntries, "settings.memoryNoJournalEntries") - ) : projectGroups.length === 0 ? ( -
- {t("settings.memoryNoProjectEntries")} -
- ) : ( -
- {projectGroups.map((group) => ( -
- - - - - {group.label} - - - {group.entries.length} - - -
- {group.entries.map((entry) => renderEntryButton(entry, true))} -
-
- ))} -
- )} -
-
- -
- {showCreate ? ( -
-
{t("settings.memoryNew")}
-
- setDraft((prev) => ({ ...prev, slug: event.target.value }))} - placeholder={t("settings.memorySlugPlaceholder")} - /> - - - - setDraft((prev) => ({ ...prev, description: event.target.value })) - } - placeholder={t("settings.memoryDescriptionPlaceholder")} - /> + + {t("settings.memoryCategoryProject")} + + {projectEntryCount} + + +
-