diff --git a/frontend/editor/src/proprietary/components/chat/ChatFAB.tsx b/frontend/editor/src/proprietary/components/chat/ChatFAB.tsx index 34d404d24c..1013c0156d 100644 --- a/frontend/editor/src/proprietary/components/chat/ChatFAB.tsx +++ b/frontend/editor/src/proprietary/components/chat/ChatFAB.tsx @@ -49,6 +49,7 @@ export function ChatFAB() { // Scope the panel's nested MantineProvider to this ref; unscoped it writes // its color scheme onto and overrides the whole app's theme. const panelThemeRootRef = useRef(null); + const triggerButtonRef = useRef(null); const { colorScheme } = useMantineColorScheme(); const panelColorScheme = colorScheme === "dark" ? "dark" : "light"; @@ -94,6 +95,22 @@ export function ChatFAB() { return defaultPanelPos(el.offsetWidth, el.offsetHeight); }; + const closePanel = () => { + const activeElement = document.activeElement; + if ( + activeElement instanceof HTMLElement && + activeElement !== document.body + ) { + activeElement.blur(); + } + + setIsOpen(false); + + requestAnimationFrame(() => { + triggerButtonRef.current?.focus(); + }); + }; + useLayoutEffect(() => { // The overlay only mounts once the AI engine is enabled (config can load // after first render), so re-measure when that flips true rather than only @@ -172,6 +189,7 @@ export function ChatFAB() { > {/* Trigger button — fades out while panel is open */} { // Fallback: ensure a position exists before opening, in case the @@ -232,18 +250,20 @@ export function ChatFAB() { }} > - panelThemeRootRef.current ?? undefined} - forceColorScheme={panelColorScheme} - > -
- setIsOpen(false)} - backLabel={t("chat.fab.close", "Close chat")} - /> -
-
+ {isOpen && ( + panelThemeRootRef.current ?? undefined} + forceColorScheme={panelColorScheme} + > +
+ +
+
+ )}
)} diff --git a/frontend/shared/components/ChatFABButton.tsx b/frontend/shared/components/ChatFABButton.tsx index 8c630a13d4..2dc7e62418 100644 --- a/frontend/shared/components/ChatFABButton.tsx +++ b/frontend/shared/components/ChatFABButton.tsx @@ -1,4 +1,4 @@ -import type { ButtonHTMLAttributes } from "react"; +import { forwardRef, type ButtonHTMLAttributes } from "react"; import "@shared/components/ChatFABButton.css"; export interface ChatFABButtonProps extends ButtonHTMLAttributes { @@ -8,59 +8,59 @@ export interface ChatFABButtonProps extends ButtonHTMLAttributes( + function ChatFABButton( + { isLoading = false, showTick = false, className, ...rest }, + ref, + ) { + const classes = [ + "chat-fab-btn", + isLoading ? "chat-fab-btn--loading" : "", + showTick ? "chat-fab-btn--tick" : "", + className ?? "", + ] + .filter(Boolean) + .join(" "); - return ( - - ); -} + return ( + + ); + }, +);