import type { ReactNode } from 'react'; /** Valid built-in icon names (69 icons, Lucide-based). */ export type CxIconName = 'chevron-down' | 'chevron-right' | 'chevron-left' | 'chevron-up' | 'arrow-right' | 'arrow-left' | 'menu' | 'x' | 'plus' | 'minus' | 'check' | 'search' | 'edit' | 'trash' | 'copy' | 'download' | 'upload' | 'share' | 'external-link' | 'save' | 'refresh-cw' | 'link-2' | 'more-horizontal' | 'book-open' | 'wrench' | 'pen-line' | 'info' | 'warning' | 'error' | 'success' | 'loading' | 'bold' | 'italic' | 'underline' | 'align-left' | 'align-center' | 'align-right' | 'credit-card' | 'shopping-cart' | 'bar-chart-2' | 'bar-chart' | 'users' | 'layout-dashboard' | 'globe' | 'github' | 'eye' | 'eye-off' | 'settings' | 'user' | 'mail' | 'bell' | 'star' | 'heart' | 'home' | 'filter' | 'sun' | 'moon' | 'panel-left' | 'log-in' | 'log-out' | 'lock' | 'unlock' | 'more-vertical' | 'calendar' | 'file-text' | 'file' | 'image' | 'file-spreadsheet' | 'user-plus' | 'shield'; /** * Icon prop type — accepts built-in icon name OR custom SVG HTML. * * @example Built-in * ```tsx * * ``` * * @example Custom SVG (inherits Collet size, color, a11y) * ```tsx * * ``` */ export type CxIconProp = CxIconName | (string & {}); export interface SelectOption { value: string; label: string; icon?: string; description?: string; disabled?: boolean; } export interface OptionGroup { label: string; options: SelectOption[]; } export interface TabItem { value: string; label: string; content?: string | ReactNode; /** * Name of a slot to project into this panel instead of `content`. * Put your own element in light DOM with a matching `slot` attribute — it * keeps its event listeners and framework state. Takes precedence over * `content`. */ content_slot?: string; icon?: string; disabled?: boolean; } export interface TableColumn { id: string; header: string; sortable?: boolean; width?: string; align?: 'left' | 'center' | 'right'; visible?: boolean; pinned?: 'left' | 'right'; resizable?: boolean; sr_only?: boolean; min_width?: string; max_width?: string; } export interface TableCell { text?: string; html?: string | ReactNode; number?: number; /** * Name of a slot to project into this cell. Put your own element in light DOM * with a matching `slot` attribute — a real button with a real click handler, * not a serialized copy of one. Takes precedence over the other fields. */ slot?: string; } export interface TableRow { id: string; cells: TableCell[] | Record; disabled?: boolean; detail?: string | ReactNode; /** Name of a slot to project into the expansion row. Takes precedence over `detail`. */ detail_slot?: string; expanded?: boolean; } export interface SortState { column_id: string; direction: 'asc' | 'desc' | 'ascending' | 'descending'; } export interface PaginationConfig { current_page: number; page_size: number; total_items: number; page_size_options?: number[]; } export interface FooterRow { cells: Record; } export interface EmptyStateConfig { title?: string; icon?: string; description?: string; } export interface AccordionItem { id: string; trigger_label: string; panel_content: string | ReactNode; /** * Name of a slot to project into this panel instead of `panel_content`. * Put your own element in light DOM with a matching `slot` attribute — it * keeps its event listeners and framework state. Takes precedence over * `panel_content`. */ panel_slot?: string; icon?: string; description?: string; disabled?: boolean; } export interface MenuRadioItem { value: string; label: string; icon?: string; disabled?: boolean; } export interface MenuEntry { type: 'item' | 'checkbox' | 'radio-group' | 'separator' | 'label'; id?: string; label?: string; icon?: string; shortcut?: string; disabled?: boolean; danger?: boolean; intent?: string; checked?: boolean; value?: string; items?: MenuRadioItem[]; } export interface SidebarNavItem { id: string; label: string; href?: string; icon?: string; badge?: string; active?: boolean; disabled?: boolean; } export interface SidebarGroup { label?: string; icon?: string; items: SidebarNavItem[]; collapsible?: boolean; expanded?: boolean; } export interface BreadcrumbItem { label: string; href?: string; icon?: string; current?: boolean; ellipsis?: boolean; } export interface RadioOption { value: string; label: string; description?: string; disabled?: boolean; icon?: string; } export interface ToggleItem { id: string; label: string; icon?: string; icon_only?: boolean; pressed?: boolean; disabled?: boolean; } export interface SplitMenuEntry { type: 'item' | 'separator'; id?: string; label?: string; icon?: string; shortcut?: string; intent?: string; disabled?: boolean; } export interface CarouselSlide { image_url?: string; title: string; badge?: string; badge_color?: string; subtitle?: string; href?: string; } export interface CarouselDetail { index: number; total: number; } export interface SpeedDialAction { id: string; icon: string; label: string; intent?: string; disabled?: boolean; handler?: string; } /** * A part inside a . Connections are auto-computed from array * position. Mirrors `MessagePartConfig` in crates/wasm-api/src/message_part.rs * field for field — the two are rendered from one table (MESSAGE_PART_FIELDS). */ export interface MessageGroupPart { /** Unique part ID. Auto-generated as `{groupId}-part-{index}` if omitted. */ id?: string; /** Part kind. Selects which renderer the part uses. */ kind: 'text' | 'tool-call' | 'tool-result' | 'thinking' | 'code-block' | 'error' | 'preview' | 'attachment'; /** Override the auto-computed connection to neighbouring parts. Usually omit this. */ connection?: 'standalone' | 'first' | 'middle' | 'last'; /** Text/code/error content. */ content?: string; /** Pre-rendered HTML content. */ html_content?: string; /** Tool/function name (for `tool-call` and `tool-result` kinds). */ tool_name?: string; /** Tool arguments as a JSON string (for `tool-call` kind). */ tool_arguments?: string; /** Tool execution status. */ tool_status?: 'pending' | 'success' | 'error'; /** Tool action type — selects the status icon. Omit for a generic tool. */ tool_action?: 'read' | 'write' | 'edit' | 'delete' | 'search'; /** Secondary description line, shown under the tool name. */ description?: string; /** Whether a tool result renders inside a collapsible disclosure. */ collapsible?: boolean; /** Whether the tool call has finished — drives the completed styling. */ completed?: boolean; /** Border treatment. Accepts `auto` (default), `none`, or `subtle`. */ border?: string; /** Label for the thinking indicator. */ thinking_label?: string; /** Code language hint (for `code-block` kind). */ language?: string; /** Filename shown in the `code-block` header. */ filename?: string; /** Render `content` as GFM markdown. Requires the markdown WASM chunk. */ markdown?: boolean; /** Size override for this part (inherits the group size if omitted). */ size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl'; /** File name for `attachment` kind. */ attachment_name?: string; /** File size in bytes for `attachment` kind. */ attachment_size?: number; /** MIME type for `attachment` kind. */ attachment_type?: string; /** Thumbnail URL (data URL or remote) for `attachment` kind. */ attachment_thumbnail?: string; } /** Step configuration for Stepper component. */ export interface StepperStep { /** Unique step ID. */ id: string; /** Step label text. */ label: string; /** Optional description text below the label. */ description?: string; /** Override auto-computed status (pending/active/completed/error/loading). */ status?: 'pending' | 'active' | 'completed' | 'error' | 'loading'; /** Whether this step is disabled (non-interactive). */ disabled?: boolean; /** Whether this step is optional. */ optional?: boolean; } /** A single color stop in a gradient. */ export interface GradientStop { /** CSS color value (e.g., "oklch(0.7 0.15 250)"). */ color: string; /** Position as a fraction 0.0–1.0. */ position: number; } /** Gradient layer configuration. */ export interface GradientConfig { /** Gradient shape: "linear" | "radial" | "conic" | "mesh". */ kind?: 'linear' | 'radial' | 'conic' | 'mesh'; /** Angle in degrees (used by linear and conic). */ angle?: number; /** Color stops. At least 2 required for a visible gradient. */ stops: GradientStop[]; } /** Noise/grain layer configuration. */ export interface NoiseConfig { /** SVG feTurbulence baseFrequency (default 0.65). */ frequency?: number; /** SVG feTurbulence numOctaves (default 4). */ octaves?: number; /** SVG feTurbulence seed (default 0). */ seed?: number; /** Layer opacity 0.0–1.0 (default 0.12). */ opacity?: number; /** CSS mix-blend-mode for compositing. */ blend?: 'normal' | 'multiply' | 'screen' | 'overlay' | 'soft-light' | 'color-dodge' | 'color-burn'; } /** Texture pattern layer configuration. */ export interface TextureConfig { /** Which texture pattern to render. */ kind?: 'paper' | 'linen' | 'halftone' | 'hatch' | 'grid' | 'scanlines' | 'checker'; /** Layer opacity 0.0–1.0 (default 0.1). */ opacity?: number; /** Pattern repeat scale multiplier (default 1.0). */ scale?: number; /** CSS mix-blend-mode for compositing. */ blend?: 'normal' | 'multiply' | 'screen' | 'overlay' | 'soft-light' | 'color-dodge' | 'color-burn'; } /** Solid color overlay with blend mode. */ export interface OverlayConfig { /** CSS color value for the tint. */ color: string; /** Layer opacity 0.0–1.0. */ opacity: number; /** CSS mix-blend-mode for compositing. */ blend?: 'normal' | 'multiply' | 'screen' | 'overlay' | 'soft-light' | 'color-dodge' | 'color-burn'; } /** Edge-darkening vignette via radial gradient. */ export interface VignetteConfig { /** Darkness strength 0.0–1.0 (default 0.3). */ strength?: number; /** Inner clear-zone radius as a fraction 0.0–1.0 (default 0.5). */ radius?: number; } /** Detail for `cx-input` on TextInput, ChatInput, Autocomplete. */ export interface InputDetail { value: string; } /** Detail for `cx-change` on Select, Autocomplete, Listbox, RadioGroup, Tabs. */ export interface SelectDetail { value: string; } /** Detail for `cx-input`/`cx-change` on Checkbox, Switch. */ export interface CheckedDetail { checked: boolean; } /** Detail for `cx-input` on Slider. */ export interface SliderDetail { value: number; } /** Detail for `cx-change` on ToggleGroup. */ export interface ToggleDetail { pressed: string[]; } /** Detail for `cx-change` on Accordion. */ export interface AccordionDetail { expanded: string[]; } /** Detail for `cx-change` on Collapsible. */ export interface CollapsibleDetail { open: boolean; } /** Detail for `cx-action` on Menu. */ export interface MenuActionDetail { id: string; label?: string; } /** Detail for `cx-change` on Menu (checkbox/radio state changes). */ export interface MenuChangeDetail { id: string; checked?: boolean; value?: string; } /** Filter comparison operator. */ export type FilterOperator = 'contains' | 'equals' | 'starts_with' | 'ends_with' | 'gt' | 'lt' | 'gte' | 'lte' | 'is_empty' | 'is_not_empty'; /** Active filter state for a column. */ export interface FilterState { column_id: string; operator: FilterOperator; value: string; } /** Virtual scroll configuration. */ export interface VirtualScrollConfig { total_count: number; render_count: number; start_index: number; } /** Detail for `cx-sort` on Table. */ export interface SortDetail { column_id: string; direction: 'asc' | 'desc' | 'none'; /** Full multi-column sort stack (present when multi-sort is active). */ sorts?: Array<{ column_id: string; direction: 'asc' | 'desc'; }>; } /** Detail for `cx-select` on Table. */ export interface TableSelectDetail { selected: string[]; /** The row that triggered the selection change (undefined for select-all). */ row_id?: string; } /** Detail for `cx-expand` on Table. */ export interface TableExpandDetail { row_id: string; expanded: boolean; } /** Detail for `cx-page` on Table, Pagination. */ export interface PageDetail { page: number; page_size?: number; } /** Detail for `cx-resize` on Table. */ export interface ResizeDetail { column_id: string; width: number; } /** Detail for `cx-scroll` on Table. */ export interface ScrollDetail { scrollTop: number; firstVisibleRow: number; visibleCount: number; } /** Detail for `cx-crush` on TopBar. Emitted when the bar enters/leaves crushed (compact) layout. */ export interface CrushDetail { crushed: boolean; } /** Detail for `cx-move` on TopBar. Emitted while dragging a movable bar. */ export interface MoveDetail { left: number; top: number; } /** Detail for `cx-navigate` on Breadcrumb, Sidebar. */ export interface NavigateDetail { href: string; label: string; } /** Detail for `cx-submit` on ChatInput. Carries message value and role for MessageBubble alignment. */ export interface ChatSubmitDetail { value: string; role: 'user'; attachments?: FileInfo[]; } /** Detail for `cx-file-add` on ChatInput/Chat. Emitted when files are added to the attachment tray. */ export interface FileAddDetail { files: FileInfo[]; } /** Detail for `cx-file-remove` on ChatInput/Chat. Emitted when files are removed. Contains remaining files. */ export interface FileRemoveDetail { files: FileInfo[]; } /** Detail for `cx-file-reject` on ChatInput/Chat. Emitted when a file fails validation. */ export interface FileRejectDetail { name: string; reason: 'size' | 'type'; } /** Detail for `cx-scroll-end` on ScrollArea, Chat. Emitted when user scrolls to the top (load-more trigger). */ export interface ScrollEndDetail { } /** * Detail for `cx-stream-end` on MessagePart. Fires when a streamed part * finalizes. static/_behaviors/message-stream.js dispatches it with no payload, * so this is an empty marker — typed explicitly rather than left as a bare * CustomEvent (invariant #22). */ export interface StreamEndDetail { } /** A pre-rendered conversation turn for the Chat component. */ export interface ChatTurn { /** Pre-rendered HTML string for the message turn. */ html: string; } /** Options for addUserMessage / addAssistantMessage on Chat ref. */ export interface BubbleOptions { /** Unique ID (auto-generated if omitted). */ id?: string; /** Render content as GFM markdown. */ markdown?: boolean; /** Sender display name. */ senderName?: string; /** Timestamp string (e.g. "2:34 PM"). */ timestamp?: string; /** Visual variant. */ variant?: 'filled' | 'ghost'; /** Corner shape. */ shape?: 'rounded' | 'sharp'; /** Horizontal alignment (defaults to auto: user=end, assistant=start). */ alignment?: 'auto' | 'start' | 'end'; /** Border style. */ border?: 'auto' | 'none'; /** Size override. */ size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl'; /** Enable entrance animation. */ animated?: boolean; } /** * A part config for addGroupMessage() and ActivityOptions.items. * * Structurally identical to `MessageGroupPart`: chat-builders.js forwards both * to the same Rust config, so both are rendered from MESSAGE_PART_FIELDS. */ export interface GroupPart { /** Unique part ID. Auto-generated as `{groupId}-part-{index}` if omitted. */ id?: string; /** Part kind. Selects which renderer the part uses. */ kind: 'text' | 'tool-call' | 'tool-result' | 'thinking' | 'code-block' | 'error' | 'preview' | 'attachment'; /** Override the auto-computed connection to neighbouring parts. Usually omit this. */ connection?: 'standalone' | 'first' | 'middle' | 'last'; /** Text/code/error content. */ content?: string; /** Pre-rendered HTML content. */ html_content?: string; /** Tool/function name (for `tool-call` and `tool-result` kinds). */ tool_name?: string; /** Tool arguments as a JSON string (for `tool-call` kind). */ tool_arguments?: string; /** Tool execution status. */ tool_status?: 'pending' | 'success' | 'error'; /** Tool action type — selects the status icon. Omit for a generic tool. */ tool_action?: 'read' | 'write' | 'edit' | 'delete' | 'search'; /** Secondary description line, shown under the tool name. */ description?: string; /** Whether a tool result renders inside a collapsible disclosure. */ collapsible?: boolean; /** Whether the tool call has finished — drives the completed styling. */ completed?: boolean; /** Border treatment. Accepts `auto` (default), `none`, or `subtle`. */ border?: string; /** Label for the thinking indicator. */ thinking_label?: string; /** Code language hint (for `code-block` kind). */ language?: string; /** Filename shown in the `code-block` header. */ filename?: string; /** Render `content` as GFM markdown. Requires the markdown WASM chunk. */ markdown?: boolean; /** Size override for this part (inherits the group size if omitted). */ size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl'; /** File name for `attachment` kind. */ attachment_name?: string; /** File size in bytes for `attachment` kind. */ attachment_size?: number; /** MIME type for `attachment` kind. */ attachment_type?: string; /** Thumbnail URL (data URL or remote) for `attachment` kind. */ attachment_thumbnail?: string; } /** Options for addGroupMessage on Chat ref. */ export interface GroupOptions { /** Unique group ID (auto-generated if omitted). */ id?: string; /** Sender display name. */ senderName?: string; /** Horizontal alignment (defaults to auto: user=end, assistant=start). */ alignment?: 'auto' | 'start' | 'end'; /** Size override. */ size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl'; /** Enable entrance animation. */ animated?: boolean; } /** Options for addActivity on Chat ref. */ export interface ActivityOptions { /** Unique ID (auto-generated if omitted). */ id?: string; /** Activity summary text. */ summary?: string; /** Activity status. */ status?: 'running' | 'done' | 'error'; /** Tool action type. */ action?: 'read' | 'write' | 'edit' | 'delete' | 'search'; /** Size override. */ size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl'; /** Border style. */ border?: string; /** Start expanded. */ expanded?: boolean; /** Pre-rendered activity part HTML strings (low-level). */ parts?: string[]; /** Structured activity sub-items — rendered through WASM automatically. * Mutually exclusive with `parts`. When both are provided, `items` takes precedence. */ items?: GroupPart[]; } /** Handle returned by startStreamingTurn() for incremental token streaming. */ export interface StreamHandle { /** The turn ID. */ id: string; /** Append streaming tokens to the turn. */ appendTokens(text: string): void; /** End the stream. Triggers WASM re-sanitization and removes cursor. */ end(): void; } /** A timeline event for the MessageTimeline reducer. Each event type uses a subset of fields. */ export interface TimelineEvent { type: 'text-delta' | 'text-done' | 'thinking-start' | 'thinking-delta' | 'thinking-done' | 'tool-call-start' | 'tool-call-done' | 'tool-result' | 'code-block' | 'error'; id?: string; delta?: string; content?: string; html?: string; label?: string; markdown?: boolean; group_id?: string; call_id?: string; result_id?: string; tool_name?: string; description?: string; arguments?: string; action?: 'generic' | 'read' | 'write' | 'edit' | 'delete' | 'search'; summary?: string; collapsible?: boolean; status?: 'pending' | 'success' | 'error'; code?: string; language?: string; filename?: string; show_line_numbers?: boolean; message?: string; } /** Detail for `cx-clear` on SearchBar. Carries the value before clear. */ export interface ClearDetail { previousValue: string; } /** Detail for `cx-click` on Button, Card. */ export interface ClickDetail { /** Original mouse event coordinates, if applicable. */ x?: number; y?: number; } /** Detail for `cx-change` on FileUpload. */ export interface FileChangeDetail { /** * The selected files as real `File` objects — readable via * `.text()`, `.arrayBuffer()`, or `.stream()`. * * `File` structurally satisfies the older `FileInfo` shape * (`name`/`size`/`type`), so code written against that keeps compiling. */ files: File[]; } /** Metadata for a selected file. */ export interface FileInfo { name: string; size: number; type: string; } /** Detail for `cx-close` on Dialog, Drawer. */ export interface CloseDetail { reason?: 'escape' | 'backdrop' | 'close-button'; } /** Detail for `cx-toggle` on Sidebar. */ export interface SidebarToggleDetail { state: 'expanded' | 'narrow'; } /** Detail for `cx-dismiss` on Alert, Toast. */ export interface DismissDetail { reason?: 'user' | 'timeout'; } /** Detail for `cx-focus` / `cx-blur` on form/interactive components. */ export interface FocusDetail { relatedTarget: EventTarget | null; } /** Detail for `cx-keydown` / `cx-keyup` on form/interactive components. */ export interface KeyboardDetail { key: string; code: string; shiftKey: boolean; ctrlKey: boolean; altKey: boolean; metaKey: boolean; } /** * A single tag for TagInput. * * Exactly the two fields `parse_tags_from_array` reads in * crates/wasm-api/src/tag_input.rs. There is no `id`, `icon` or `disabled` on * the wire; a tag whose `value` is empty renders nothing at all. */ export interface CxTagData { /** Unique tag value. Required — a tag with an empty value is dropped by WASM. */ value: string; /** Display label. Falls back to `value` when empty. */ label: string; } /** Detail for `cx-change` on TagInput. Emitted when the tag list changes. */ export interface TagInputChangeDetail { tags: CxTagData[]; } /** * Detail for `cx-dismiss` on TagInput. * * `removeTag()` in packages/core/src/elements/tag_input.js dispatches exactly * `{ value }`. There is no tag object and no index on the wire — look the tag * up in your own list by `value`. */ export interface TagDismissDetail { /** The `value` of the tag that was removed. */ value: string; } /** A single command item inside a CommandPalette group. */ export interface CxCommandItem { /** Unique command identifier — returned in `cx-select` detail. */ id: string; /** Display label. */ label: string; /** Optional icon name. */ icon?: string; /** Optional keyboard shortcut hint. */ shortcut?: string; /** Optional description text shown below the label. */ description?: string; /** Whether this command is disabled. */ disabled?: boolean; /** Navigation target — renders the item as a link. */ href?: string; } /** A group of commands for CommandPalette. */ export interface CxCommandGroup { /** Group heading label. Required: it is the group's accessible name. */ label: string; /** Command items in this group. */ items: CxCommandItem[]; } /** Detail for `cx-select` on CommandPalette. Emitted when a command is activated. */ export interface CommandSelectDetail { id: string; label: string; } /** A node in the TreeView hierarchy. */ export interface CxTreeNode { /** Unique node identifier — returned in selection/expand events. */ id: string; /** Display label. */ label: string; /** Optional icon name. */ icon?: string; /** Whether the node is initially expanded. */ expanded?: boolean; /** Whether the node is selected. */ selected?: boolean; /** Whether the node is disabled (non-interactive). */ disabled?: boolean; /** Child nodes (renders as a subtree). */ children?: CxTreeNode[]; } /** Detail for `cx-select` on TreeView. Emitted when a node is selected or deselected. */ export interface TreeSelectDetail { id: string; label: string; selected: boolean; } /** Detail for `cx-change` on TreeView. Emitted when a node is expanded or collapsed. */ export interface TreeChangeDetail { id: string; expanded: boolean; } /** Recursive node data for the Treemap component. */ export interface TreemapNode { id: string; label: string; value: number; intent?: 'neutral' | 'primary' | 'info' | 'success' | 'warning' | 'danger'; children?: TreemapNode[]; disabled?: boolean; } /** Detail for `cx-change` on Treemap. Emitted when the zoom level changes. */ export interface TreemapChangeDetail { nodeId: string; path: string[]; depth: number; } /** Detail for `cx-select` on Treemap. Emitted when a leaf cell is clicked. */ export interface TreemapSelectDetail { id: string; label: string; value: number; } /** Detail for `cx-hover` on Treemap. Emitted on cell hover enter/leave. */ export interface TreemapHoverDetail { id: string; label: string; value: number; hasChildren: boolean; rect?: { x: number; y: number; width: number; height: number; }; enter: boolean; }