ChatLauncher
A floating chat button in a corner of the page that opens a chat panel. The panel is not modal: the page stays interactive, Escape closes it while focus is inside, and focus returns to the button. The chat stays mounted while the panel is closed (keepMounted, true by default), so the conversation and a running stream survive closing. Place it with position (bottom-right or bottom-left) and offset (24px, a number or { x, y }); size the panel with panelWidth (380) and panelHeight (640), both clamped to the viewport. When the panel does not fit, or the available width is below fullScreenBreakpoint (520px), it opens full screen and page scroll is frozen (mobileFullScreen). unreadCount shows a badge on the closed button. Open state can be controlled with opened / onOpenedChange or left to defaultOpened. It renders in a portal by default; set withinPortal={false} to keep it inside a container. To add the chat to a page that is not a React app, or to isolate it from the page CSS, use mountChatLauncher(target, element, options): it renders into a Shadow DOM with its own MantineProvider, injects the stylesheets you pass in styles or styleUrls, and returns unmount. See Embedding the launcher. The previews render the launcher with withinPortal={false} inside a page frame, so it measures the frame instead of the window.
$pnpm add @sinups/ai-kit @mantine/core @mantine/hooks @tabler/icons-react