import "./composer.css"; import type * as React from "react"; import { useRender } from "@base-ui/react/use-render"; import { type HighlightRange } from "./highlight_segments"; import { type StyleProps } from "./style_props"; /** * The pure composer *chrome* — a bordered, auto-growing multiline text field * with Enter-to-send, a send/stop button, and a footer. Everything domain- or * Lotics-specific is injected: labels (no i18n), and `pills` / `files` / * `children` slots the consumer fills (the product's chat wraps this and fills * them with skill/knowledge pills + an upload grid; a custom-code app fills * `files` with its own attachment region, or leaves it empty). * * Adapts to its content. A *minimal* composer — no `footerRight` / `pills` / * `files` / `children` — starts as a COMPACT PILL (a single row: an optional * `actionsButton`, the input, the send button) so an empty command surface * reads as a small pill, the same geometry `AgentRun variant="pill"` morphs into. The * moment the text wraps past one line (or files/pills/footer chrome appear) it * EXPANDS: the input lifts onto its own row, slots stack above it, and the * buttons drop to a footer row. The expansion latches until the text is cleared * (the input is wider when expanded, so re-collapsing mid-edit would oscillate). * * Pure by the package contract: no i18n, no domain types, no upload machinery. * Compose those above it. */ export interface ComposerProps extends StyleProps { onSend: (text: string) => void; onStop?: () => void; disabled?: boolean; /** Override the default "block on empty text" send-disable (e.g. allow send with attachments only). */ sendDisabled?: boolean; placeholder?: string; /** Accessible name for the text field. Defaults to `placeholder`, which is * drawn as an overlay rather than set on the field (see below) and so names * nothing on its own — without one the field is announced unlabelled. */ accessibilityLabel?: string; autoFocus?: boolean; testID?: string; /** Control text externally; omit to let the composer manage its own state. */ value?: string; onChangeText?: (text: string) => void; /** Ranges of `value` to tint. What they MEAN is the caller's business — this * package never learns what a skill or a document is. Omit it and nothing is * rendered, so a consumer that never tints pays nothing. */ highlightRanges?: readonly HighlightRange[]; /** Extra props for the `