"use client" /** * Every Leo surface the app shell mounts, and the rules for which one shows. * * Leo has grown three shells — the docked panel, the floating window, and the * corner FAB — and the choice between them depends on the persisted `dock` * preference, whether the window is minimised, the route, and whether the * viewport can carry a draggable window at all. * * Docked panel participates in the workspace `ResizablePanelGroup` (pill * `ResizableHandle`). Window / FAB / overlay flyout mount as siblings outside * that group so they do not break panel layout. * * @see components/ask-leo-context.tsx — `open`, `dock`, `minimized` * @see docs/ask-leo-pattern.md — view modes and their entry points */ import * as React from "react" import { useLocation } from "react-router" import { useAskLeo } from "@/components/ask-leo-context" import { useLeoAmbience } from "@/components/leo-ambience-context" import { LeoLauncherFab } from "@/components/leo-launcher-fab" import { useSecondaryPanel } from "@exxatdesignux/ui/components/shell/secondary-panel" import { useBorrowedPrimarySidebar } from "@/hooks/use-borrowed-primary-sidebar" import { useIsMobile } from "@/hooks/use-mobile" import { useSidebarReflowZoom } from "@/hooks/use-sidebar-reflow-zoom" import { isProductsHomePath } from "@/lib/product-home" // Imported eagerly, unlike the window and the ambience surfaces below. The rail // used to be `React.lazy`, which bought nothing: `utility-bar-slot.tsx` imports // `AskLeoToggle` from this same module, so the code is in the entry chunk // regardless and the lazy boundary only added a suspend-and-retry round trip // before the first open could commit. Measured on the library hub: first open // 511ms with the boundary, 251ms without, and the first open now costs the same // as every later one. import { AskLeoSidebar } from "@/components/ask-leo-sidebar" const AskLeoWindow = React.lazy(() => import("@/components/ask-leo-window").then(m => ({ default: m.AskLeoWindow, })), ) const LeoAmbienceWindow = React.lazy(() => import("@/components/leo-ambience-window").then(m => ({ default: m.LeoAmbienceWindow, })), ) /** Borrow the primary nav's width while the docked panel is up. */ function AskLeoPrimarySidebarCollapse({ panelOpen }: { panelOpen: boolean }) { useBorrowedPrimarySidebar(panelOpen) return null } /** * One floating layer at a time on mobile / reflow: opening Ask Leo closes the * secondary scope sheet. Desktop docked Leo collapses secondary to the icon * strip in {@link SecondaryPanel} (keeps the rail mounted). */ function AskLeoSecondaryPanelCollapse({ panelOpen }: { panelOpen: boolean }) { const { activePanel, closeSecondaryFlyout, secondaryFlyoutVisible } = useSecondaryPanel() const isMobile = useIsMobile() const reflowZoom = useSidebarReflowZoom() const navFlyout = isMobile || reflowZoom const prevOpen = React.useRef(panelOpen) React.useEffect(() => { if ( panelOpen && !prevOpen.current && navFlyout && activePanel && secondaryFlyoutVisible ) { closeSecondaryFlyout() } prevOpen.current = panelOpen }, [ panelOpen, activePanel, navFlyout, secondaryFlyoutVisible, closeSecondaryFlyout, ]) return null } function useAskLeoShellMode() { const { open, dock, minimized } = useAskLeo() const isMobile = useIsMobile() const reflowZoom = useSidebarReflowZoom() const windowMode = dock === "window" && !isMobile && !reflowZoom const dockedPanelOpen = open && !windowMode const overlayFlyout = dockedPanelOpen && (isMobile || reflowZoom) return { open, minimized, windowMode, dockedPanelOpen, overlayFlyout } } /** * Docked Ask Leo rail — `ResizableHandle` + `ResizablePanel` for the workspace * group. Overlay flyout mounts from {@link AskLeoFloatingSlot}. */ export function AskLeoDockedSlot() { const { dockedPanelOpen, overlayFlyout } = useAskLeoShellMode() if (!dockedPanelOpen || overlayFlyout) return null return } /** * Window / FAB / ambience / overlay flyout — mount **outside** `ResizablePanelGroup`. */ export function AskLeoFloatingSlot() { const { pathname } = useLocation() const { settingsOpen } = useLeoAmbience() const { open, minimized, windowMode, dockedPanelOpen, overlayFlyout } = useAskLeoShellMode() const salesFraming = isProductsHomePath(pathname) const showFab = salesFraming || (windowMode && minimized) return ( <> {dockedPanelOpen && overlayFlyout ? : null} {open && windowMode ? ( ) : null} {settingsOpen ? ( ) : null} {showFab ? : null} ) } /** @deprecated Prefer {@link AskLeoDockedSlot} + {@link AskLeoFloatingSlot}. */ export function AskLeoShell() { return ( <> ) }