diff --git a/.changeset/adr-0057-p3b-fab-launcher.md b/.changeset/adr-0057-p3b-fab-launcher.md new file mode 100644 index 0000000000..810df07495 --- /dev/null +++ b/.changeset/adr-0057-p3b-fab-launcher.md @@ -0,0 +1,13 @@ +--- +"@object-ui/app-shell": patch +--- + +feat(console-ai): the FAB becomes the ChatDock launcher when the dock is on (ADR-0057 P3b) + +When `features.chatDock` is enabled, the console FAB opens the docked rail instead +of the floating overlay — one entry point, the ADR's "FAB → launcher" step. In +dock mode the FAB stays the lightweight button (it never mounts the heavy floating +chatbot; the rail loads the chat on demand), and a designer "Ask AI" open signal +(assistantBus) opens the dock too. With the flag OFF the FAB is unchanged (floating +overlay). Supersedes P3a's edge launcher (the dock is gated on the same +`showChatbot`, so the FAB is always present to launch it). diff --git a/packages/app-shell/src/layout/ConsoleChatbotFab.tsx b/packages/app-shell/src/layout/ConsoleChatbotFab.tsx index 9be3ae63c1..7d05b62b5f 100644 --- a/packages/app-shell/src/layout/ConsoleChatbotFab.tsx +++ b/packages/app-shell/src/layout/ConsoleChatbotFab.tsx @@ -26,25 +26,38 @@ const prefetchChatbot = () => { import type { ConsoleFloatingChatbotProps } from './ConsoleFloatingChatbot'; -export type ConsoleChatbotFabProps = ConsoleFloatingChatbotProps; +export type ConsoleChatbotFabProps = ConsoleFloatingChatbotProps & { + /** + * ADR-0057 P3b — when the ChatDock is enabled, the FAB becomes the dock's + * LAUNCHER: a click (and a designer "Ask AI" open signal) opens the docked + * rail instead of arming the floating overlay, and the heavy floating chatbot + * is never mounted (the dock owns the chat). Absent → unchanged floating-FAB + * behavior. + */ + onOpenDock?: () => void; +}; -export function ConsoleChatbotFab(props: ConsoleChatbotFabProps) { +export function ConsoleChatbotFab({ onOpenDock, ...props }: ConsoleChatbotFabProps) { const [armed, setArmed] = useState(false); const { t } = useObjectTranslation(); // A designer surface can ask the assistant to open (e.g. an "Ask AI" // button) via the assistant bus — arming the lazy chatbot just like a // click does. Once armed, the chatbot's own trigger owns open/close. + // When the dock is the target (P3b), the open signal opens the dock instead. const { openSeq } = useAssistant(); const seenOpenSeq = useRef(openSeq); useEffect(() => { if (openSeq !== seenOpenSeq.current) { seenOpenSeq.current = openSeq; - setArmed(true); + if (onOpenDock) onOpenDock(); + else setArmed(true); } - }, [openSeq]); + }, [openSeq, onOpenDock]); - if (armed) { + // Dock mode (P3b): stay the lightweight launcher — never mount the floating + // overlay; the click opens the rail, which loads the chat on demand. + if (armed && !onOpenDock) { return ( @@ -56,9 +69,9 @@ export function ConsoleChatbotFab(props: ConsoleChatbotFabProps) {