diff --git a/apps/www/src/components/docs/search.tsx b/apps/www/src/components/docs/search.tsx index 3dee20f72..84a33fd87 100644 --- a/apps/www/src/components/docs/search.tsx +++ b/apps/www/src/components/docs/search.tsx @@ -86,7 +86,7 @@ export default function DocsSearch({ pageTree }: { pageTree: Root }) { excluded until the user searches. */ const items = flattened.reduce>((acc, item) => { const folder = getFolderFromUrl(item.url); - if (folder === 'components') return acc; + if (folder === 'components' || folder === 'ai-elements') return acc; if (!acc[folder]) { acc[folder] = []; } diff --git a/apps/www/src/content/docs/ai-elements/chat-panel/demo.ts b/apps/www/src/content/docs/ai-elements/chat-panel/demo.ts new file mode 100644 index 000000000..d236db9e0 --- /dev/null +++ b/apps/www/src/content/docs/ai-elements/chat-panel/demo.ts @@ -0,0 +1,147 @@ +'use client'; + +export const preview = { + type: 'code', + code: `function ChatPanelPreview() { + const [mode, setMode] = React.useState('docked'); + + return ( + + + Main content + + The docked panel is a real flex sibling — it squeezes this content + instead of covering it. Pop it out or minimize it from the header; + floating and minimized modes are fixed to the browser viewport. + + + + + Create task in design system 2 + + + + + + + + + + + + create a task in design system 2 + + + + + + + Done — I created the task and assigned it to you. + + + + + +
+ event.currentTarget.reset()}> + + + + + +
+
+
+ +
+
+ ); +}` +}; + +export const controlledDemo = { + type: 'code', + code: `function ControlledChatPanel() { + const [mode, setMode] = React.useState('docked'); + + return ( + + + + + + + mode: {mode} + + + + Floating and minimized modes leave this frame and pin to the + browser viewport. + + + + + Assistant + + + + + + + + + Drag the header to move the floating window; resize from any + edge or corner. + + + + + + + + ); +}` +}; + +export const unreadBadgeDemo = { + type: 'code', + code: `function MinimizedWithBadge() { + const [mode, setMode] = React.useState('minimized'); + + // The transform makes the frame the containing block for the panel's + // fixed positioning, so this demo's trigger pins to the frame corner + // instead of stacking on the page's other panels. + return ( + + + The minimized trigger is a slot — compose Indicator or Badge for + unread counts. Look at the bottom-right of this frame. + + + + + Click the bubble to restore the panel; minimize it again from the + header. + + + + + Assistant + + + + + + + Minimize me again from the header. + + + + 💬 + + + + + ); +}` +}; diff --git a/apps/www/src/content/docs/ai-elements/chat-panel/index.mdx b/apps/www/src/content/docs/ai-elements/chat-panel/index.mdx new file mode 100644 index 000000000..44f0f4f16 --- /dev/null +++ b/apps/www/src/content/docs/ai-elements/chat-panel/index.mdx @@ -0,0 +1,136 @@ +--- +title: ChatPanel +description: A dockable, floating, minimizable window frame for chat — an inline sidebar that pops out to a draggable, resizable window or collapses to a corner bubble. +source: packages/raystack/components/chat-panel +tag: new +--- + +import { preview, controlledDemo, unreadBadgeDemo } from "./demo.ts"; + + + +## Anatomy + +```tsx +import { ChatPanel } from '@raystack/apsara' + + + + + + Create task in design system 2 + + {/* consumer extras, e.g. ⋯ menu */} + + + + + {/* Chat.Messages + PromptInput */} + {/* minimized bubble */} + + +``` + +The panel mounts **once** in your layout and morphs between modes with pure +CSS — no portal, no remount, so chat state (scroll position, focus, streams) +survives every transition: + +- **`docked`** — an in-flow sidebar (a flex sibling, like `SidePanel`) that + squeezes the main content rather than covering it. +- **`floating`** — the same element switched to `position: fixed`: drag it by + the header, resize it from any edge or corner, both viewport-clamped. +- **`minimized`** — the frame collapses to `ChatPanel.Trigger`, a fixed + corner bubble; clicking it restores the previous mode. If you don't render + a trigger, minimized shows nothing and your app supplies its own affordance. + +There is deliberately no close (×) — header actions are slottable, so apps +add their own controls next to the ready-made mode triggers. + +Because floating and minimized rely on `position: fixed`, mount the panel +near the layout root: an ancestor with `transform`, `filter` or +`backdrop-filter` would break fixed positioning. + +## API Reference + +### Root + + + +### Header + +The title bar. In floating mode it is the drag handle — pointer drags on it +move the window (interactive children like buttons are excluded, as is +anything marked `data-chat-panel-no-drag`). + +### Title + +The heading (`

`), truncated with an ellipsis. + +### Actions + +A slot row at the end of the header for controls. + +### MinimizeTrigger / ExpandTrigger + +Ready-made mode buttons for `ChatPanel.Actions`, built on `IconButton`. +MinimizeTrigger switches to `minimized`; ExpandTrigger toggles between +`docked` and `floating` with a matching icon and accessible name. + +### Content + +The body wrapper — a flex column that gives `Chat.Messages` its bounded +height. + +### Trigger + +The minimized-state corner bubble. + + + +## Examples + +### Controlled mode + +Control `mode` to persist it, or to open the panel from your own UI. The +floating window here is fixed to the browser viewport — pop it out and drag +its header. + + + +### Unread badge on the bubble + + + +### Persisting placement + +Position and size are controllable for apps that restore the floating window +across sessions: + +```tsx + + … + +``` + +## Accessibility + +- The root renders an `