zidane-ui/ chat/ rich-composer
import { … } from 'zidane-ui/chat/rich-composer'ui/src/chat/rich-composer/index.ts
Components#
PlusButtonComponent#
The + button: attach files.
function PlusButton(props: PlusButtonProps): ElementParameters
| Name | Type | Description |
|---|---|---|
| props | PlusButtonProps | The click handler. |
Returns
ElementProps
| Name | Type | Description |
|---|---|---|
| onClick | () => void | Opens the file picker. |
RichComposerComponent#
zidane-ui/chat/rich-composer: the desktop app's Tiptap composer (mentions, commands, ghost text, shared drafts, prompt history). Its own entry, so an app that does not render it never loads it.
function RichComposer(props: RichComposerProps): ElementParameters
| Name | Type | Description |
|---|---|---|
| props | RichComposerProps | What the composer edits and sends, and its slots. |
Returns
ElementProps
| Name | Type | Description |
|---|---|---|
| activeSessionId? | string | null | The session the composer writes to ( |
| attachmentLabel? | AttachmentLabelFn | The icon and name an attachment tile shows. |
| attachmentsEnabled? | boolean | Pasted and dropped files become attachments (off: images and long pastes stay inline, drops are ignored). Default true. |
| badges? | ReactNode | The badge strip ( |
| className? | string | Classes merged on the root. |
| commandArgs? | ComposerCommandArgs | The commands' fixed argument values (the command badge, the |
| disabled | boolean | No folder picked: read-only, with its own placeholder. |
| fileRoot? | string | Where |
| folderPath | string | null | The folder the session runs in ( |
| footer? | ReactNode | Rendered in the tray under the card (the desktop app's git bar). |
| hostId? | string | null | The server the session (or the draft) runs on: |
| inlineAutocomplete? | boolean | Inline ghost-text autocomplete ( |
| leadingActions? | ReactNode | Rendered next to the |
| messageDelivery? | MessageDelivery | What Enter does with a prompt while |
| onSearchNavigate? | (direction: -1 | 1) => void | Hops to the next ( |
| onSearchQueryChange? | (query: string | null) => void | The search query as typed ( |
| onSend | (text: string, attachments: ComposerAttachment[], skills: string[], opts?: { delivery?: MessageDelivery; keepDraft?: boolean }) => void | Promise<void> | Sends a prompt. |
| onStop? | () => void | Stops the run. |
| promptSuggestions? | boolean | The next-prompt suggestion as a ghost while the composer is empty ( |
| remoteSearchApply? | { active: boolean; query: string; seq: number } | null | Shared-search application (daemon mode) — Center threads the active
session's |
| running? | boolean | When true, the send button is replaced by a stop button that calls |
| scopeKey? | string | null | The composer's scope on the composer bus ( |
| searchOverlayOpen? | boolean | True while the ⌘F overlay is open. The overlay and the composer mode drive the same document-wide highlight registry, so opening the overlay force-exits the composer's search mode. |
| searchStatus? | { activeIndex: number; capped: boolean; count: number; hasNeedle: boolean } | null | The search engine's counter while in search mode: matches, whether capped, the active one, whether a query is typed. |
| siteIcons? | ChatSiteIcons | Site icons for link badges. Absent: links show the globe. |
| style? | CSSProperties | Styles on the root. |
| textPreview? | ComponentType<TextPreviewSlotProps> | What a text attachment opens as in the lightbox. Default: the kit's |
| trailingActions? | ReactNode | Rendered on the right side of the controls row, immediately before the Send / Stop button — the per-session context gauge + cost pill cluster lives here. Slot keeps Chatbox agnostic of the actual pills (App.tsx owns the state, Center.tsx threads the node in). Children are responsible for their own collapse behavior; the Chatbox surface declares a CSS container so container queries on descendants can react to the prompt's inline-size. |
SendStopButtonComponent#
Unified Send / Stop control — one button element that never unmounts, so
the idle→streaming→hover-stop states crossfade in place (no layout jump;
constant 32×32 footprint). Three visual states, all CSS-driven via the
zg-sendstop classes in rich-composer.css:
- idle (
data-state="send") — a lit accent sphere (the daemon orb's drawing) + send glyph; asleep while the prompt is empty. - streaming (
data-state="run") — the same lit sphere, its glyph turned into a thin spinner ring: "the agent is working", not an alarm. - streaming + hover/focus-visible — the stop affordance surfaces: the sphere eases to the danger colour and a square stop glyph fades in.
Clicking while streaming always stops (the hover state is a reveal, not a gate — touch/keyboard users get the same action without hover).
function SendStopButton(props: SendStopButtonProps): ElementParameters
| Name | Type | Description |
|---|---|---|
| props | SendStopButtonProps | The run and draft state, and the handlers. |
Returns
ElementProps
| Name | Type | Description |
|---|---|---|
| canSend | boolean | The draft can be sent. |
| onSend | () => void | Sends the draft. |
| onStop? | () => void | Stops the run. |
| running | boolean | A run streams: the button stops it. |
Interfaces#
PlusButtonPropsInterface#
Props for PlusButton.
interface PlusButtonPropsProperties
| Name | Type | Description |
|---|---|---|
| onClick | () => void | Opens the file picker. |
RichComposerPropsInterface#
Props for RichComposer.
interface RichComposerPropsProperties
| Name | Type | Description |
|---|---|---|
| activeSessionId? | string | null | The session the composer writes to ( |
| attachmentLabel? | AttachmentLabelFn | The icon and name an attachment tile shows. |
| attachmentsEnabled? | boolean | Pasted and dropped files become attachments (off: images and long pastes stay inline, drops are ignored). Default true. |
| badges? | ReactNode | The badge strip ( |
| className? | string | Classes merged on the root. |
| commandArgs? | ComposerCommandArgs | The commands' fixed argument values (the command badge, the |
| disabled | boolean | No folder picked: read-only, with its own placeholder. |
| fileRoot? | string | Where |
| folderPath | string | null | The folder the session runs in ( |
| footer? | ReactNode | Rendered in the tray under the card (the desktop app's git bar). |
| hostId? | string | null | The server the session (or the draft) runs on: |
| inlineAutocomplete? | boolean | Inline ghost-text autocomplete ( |
| leadingActions? | ReactNode | Rendered next to the |
| messageDelivery? | MessageDelivery | What Enter does with a prompt while |
| onSearchNavigate? | (direction: -1 | 1) => void | Hops to the next ( |
| onSearchQueryChange? | (query: string | null) => void | The search query as typed ( |
| onSend | (text: string, attachments: ComposerAttachment[], skills: string[], opts?: { delivery?: MessageDelivery; keepDraft?: boolean }) => void | Promise<void> | Sends a prompt. |
| onStop? | () => void | Stops the run. |
| promptSuggestions? | boolean | The next-prompt suggestion as a ghost while the composer is empty ( |
| remoteSearchApply? | { active: boolean; query: string; seq: number } | null | Shared-search application (daemon mode) — Center threads the active
session's |
| running? | boolean | When true, the send button is replaced by a stop button that calls |
| scopeKey? | string | null | The composer's scope on the composer bus ( |
| searchOverlayOpen? | boolean | True while the ⌘F overlay is open. The overlay and the composer mode drive the same document-wide highlight registry, so opening the overlay force-exits the composer's search mode. |
| searchStatus? | { activeIndex: number; capped: boolean; count: number; hasNeedle: boolean } | null | The search engine's counter while in search mode: matches, whether capped, the active one, whether a query is typed. |
| siteIcons? | ChatSiteIcons | Site icons for link badges. Absent: links show the globe. |
| style? | CSSProperties | Styles on the root. |
| textPreview? | ComponentType<TextPreviewSlotProps> | What a text attachment opens as in the lightbox. Default: the kit's |
| trailingActions? | ReactNode | Rendered on the right side of the controls row, immediately before the Send / Stop button — the per-session context gauge + cost pill cluster lives here. Slot keeps Chatbox agnostic of the actual pills (App.tsx owns the state, Center.tsx threads the node in). Children are responsible for their own collapse behavior; the Chatbox surface declares a CSS container so container queries on descendants can react to the prompt's inline-size. |
SendStopButtonPropsInterface#
Props for SendStopButton.
interface SendStopButtonPropsProperties
| Name | Type | Description |
|---|---|---|
| canSend | boolean | The draft can be sent. |
| onSend | () => void | Sends the draft. |
| onStop? | () => void | Stops the run. |
| running | boolean | A run streams: the button stops it. |