UNPKG

@kitn.ai/ui

Version:

Framework-agnostic, Shadow-DOM web components for building AI chat interfaces — works in React, Vue, Angular, Svelte, or plain HTML. Authored in SolidJS.

981 lines 113 kB
import { registerAll, WebComponentProps } from './runtime'; export { registerAll }; export { useKaiChat } from './use-kai-chat'; export type { UseKaiChatOptions, KaiChatController, ChatMessage } from './use-kai-chat'; export interface AgentCardProps extends WebComponentProps { /** The agent's name — the primary label. Attribute: `name`. */ name?: string; /** Selected / focused state: highlighted border + surface. Attribute: `active`. */ active?: boolean; /** Raise a prominent "Needs you" pill plus a glowing amber edge — the attention-routing signal that pulls focus to this agent. Attribute: `needs-attention`. */ needsAttention?: boolean; /** Run status — a JS PROPERTY (object), not an attribute. Shape: `{ tone, label?, pulse? }`, where `tone` is one of `working` | `idle` | `done` | `error` | `blocked` (maps to the kit's tool hues), `label` is an optional short string beside the dot, and `pulse` animates the dot. Set it with `el.status = { tone: 'working', label: 'Working', pulse: true }`. */ status?: { tone: "working" | "idle" | "done" | "error" | "blocked"; label?: string; pulse?: boolean; }; /** The card was activated — clicked, or Enter / Space while focused. Promote this agent back to focus. */ onActivate?: (event: CustomEvent) => void; /** The trailing "..." kebab was clicked. The consumer opens its own menu; the card only surfaces the affordance (the click does not also activate the card). */ onMenu?: (event: CustomEvent) => void; } export declare const AgentCard: import('react').ForwardRefExoticComponent<AgentCardProps & import('react').RefAttributes<HTMLElement>>; export interface ArtifactProps extends WebComponentProps { /** URL the preview iframe frames. Consumer-controlled. */ src?: string; /** Files for the Code tab tree + each file's preview `url`. Set as a JS property (array). */ files: { path: string; url?: undefined | string; code?: undefined | string; language?: undefined | string; type?: undefined | "html" | "pdf" | "image" | "other"; additions?: undefined | number; deletions?: undefined | number; status?: undefined | "added" | "modified" | "deleted" | "renamed" | "untracked"; }[]; /** Controlled active tab: `preview` or `code`. When set, the artifact follows it (re-asserted on change). Leave unset for an uncontrolled tab (see `defaultTab`). */ tab?: "preview" | "code"; /** Uncontrolled INITIAL tab (used only when `tab` is unset). Default `preview`. Seeds the starting tab; the user can then switch freely without the consumer re-asserting a controlled `tab`. */ defaultTab?: "preview" | "code"; /** Selected file path — syncs the tree highlight, Code source, and preview. */ activeFile?: string; /** iframe `sandbox` override. Secure default `allow-scripts allow-forms` (NOT `allow-same-origin`). */ sandbox?: string; /** Accessible title for the preview iframe. */ iframeTitle?: string; /** Reflects the artifact's own maximized view-state (usually driven by the protocol). */ maximized?: boolean; /** Show the expand-to-fill button (OPT-IN). */ expandable?: boolean; /** Show the open-in-new-tab button (OPT-IN). */ openInTab?: boolean; /** Hide back/forward. */ noNav?: boolean; /** Hide reload. */ noReload?: boolean; /** Hide home. */ noHome?: boolean; /** Hide the address field. */ noPathField?: boolean; /** Hide the Preview|Code toggle. */ noTabs?: boolean; /** Standalone chrome: rounded corners + border (else square, borderless in-panel). */ standalone?: boolean; /** Show the address but make it read-only (visible, nav-tracking, non-editable). */ readonlyPath?: boolean; /** Friendly address shown in the path field instead of the real current url (read-only, non-navigable). Use when the framed url is not consumer-facing (e.g. a `data:` blob) so a clean address shows instead of leaking it. Scalar string: set as the `display-url` attribute or the `displayUrl` property. */ displayUrl?: string; /** Fired when a file is selected. `detail.path`. */ onFileSelect?: (event: CustomEvent<{ path: string; }>) => void; /** Artifact's own maximize button toggled (consumer-observable; non-bubbling). */ onMaximizeChange?: (event: CustomEvent<{ maximized: boolean; }>) => void; /** Fired when the preview navigates. `detail.url` = the new location. */ onNavigate?: (event: CustomEvent<{ url: string; }>) => void; /** Fired when the Preview|Code tab changes. `detail.tab`. */ onTabChange?: (event: CustomEvent<{ tab: "preview" | "code"; }>) => void; } export declare const Artifact: import('react').ForwardRefExoticComponent<ArtifactProps & import('react').RefAttributes<HTMLElement>>; export interface AttachmentsProps extends WebComponentProps { /** The attachments to render. Set as a JS property (array). */ items: { id: string; type: "file" | "source-document"; filename?: undefined | string; mediaType?: undefined | string; url?: undefined | string; title?: undefined | string; }[]; /** Layout: `grid` = visual tiles, `inline` = icon + label chips, `list` = rows. */ variant?: "grid" | "inline" | "list"; /** Wrap each item in a hover card that previews its details. */ hoverCard?: boolean; /** Show a remove button per item; clicking it fires a `kai-remove` event. */ removable?: boolean; /** Also show the media type beneath the filename (non-grid variants). */ showMediaType?: boolean; /** Text shown when `items` is empty. */ emptyText?: string; /** A remove button was clicked. */ onRemove?: (event: CustomEvent<{ id: string; }>) => void; } export declare const Attachments: import('react').ForwardRefExoticComponent<AttachmentsProps & import('react').RefAttributes<HTMLElement>>; export interface AvatarProps extends WebComponentProps { /** Image URL/data-URI. When absent, the `fallback` initials show instead. */ src?: string; /** Alt text for the image. Defaults to `fallback`. */ alt?: string; /** Short text shown when there's no image — usually initials (e.g. "JD", "AI"). */ fallback?: string; /** Size token: `sm` | `md` (default) | `lg`. */ size?: "sm" | "md" | "lg"; } export declare const Avatar: import('react').ForwardRefExoticComponent<AvatarProps & import('react').RefAttributes<HTMLElement>>; export interface BadgeProps extends WebComponentProps { /** `default` (muted pill) · `count` (compact number badge) · `citation` (filled primary, for inline citation markers). Defaults to `default`. */ variant?: "default" | "count" | "citation"; } export declare const Badge: import('react').ForwardRefExoticComponent<BadgeProps & import('react').RefAttributes<HTMLElement>>; export interface ButtonProps extends WebComponentProps { /** Visual style. `default` (filled), `subtle` (muted text, hover tint — the toolbar icon look), `ghost` (transparent, hover fill), `outline`, or `destructive`. Defaults to `default`. */ variant?: "default" | "subtle" | "ghost" | "outline" | "destructive"; /** Size token. `icon` / `icon-sm` are square (for icon-only buttons); `sm` / `md` / `lg` size text buttons. Defaults to `md`. */ size?: "sm" | "md" | "lg" | "icon" | "icon-sm"; /** Leading icon: a named icon (e.g. `"mic"`, `"plus"`), an image URL/data-URI, or plain text. Renders before any slotted label. */ icon?: string; /** Trailing icon, after the label (e.g. `"chevron-down"` for a menu affordance). */ iconTrailing?: string; /** Accessible name. REQUIRED for icon-only buttons (no visible text); ignored when you slot visible text, which already names the button. */ label?: string; /** Disable the button (non-interactive, dimmed). */ disabled?: boolean; /** Stretch the button to the full width of its container (a block button) — e.g. a card CTA or a stacked action. Attribute: `full`. */ full?: boolean; /** Justify the button's content: `start`, `center` (default), or `end`. Combine with `full` for a full-width, left-aligned button. */ align?: "start" | "center" | "end"; /** Native button `type`. Defaults to `button` (so it never submits a form). */ type?: "button" | "submit" | "reset"; /** The button was activated (pointer or keyboard). Carries no detail. The native `click` also bubbles (composed) for consumers who prefer it. */ onClick?: (event: CustomEvent) => void; } export declare const Button: import('react').ForwardRefExoticComponent<ButtonProps & import('react').RefAttributes<HTMLElement>>; export interface CardProps extends WebComponentProps { /** Surface treatment: `outlined` (default) | `filled` | `plain` | `accent`. Attribute: `appearance`. */ appearance?: "outlined" | "filled" | "plain" | "accent"; /** `vertical` (default, media on top) | `horizontal` (media at the start) | `responsive` (horizontal when the card's container is wide enough, else vertical — a container query on the card's own width). Attribute: `orientation`. */ orientation?: "vertical" | "horizontal" | "responsive"; /** The card width below which a `responsive` card collapses to vertical and the footer actions stack. A CSS length; default `28rem`. Attribute: `collapse`. */ collapse?: string; /** Tighter spacing for dense lists. Attribute: `dense`. */ dense?: boolean; /** Show a close (×) that hides the card and emits `kai-dismiss`. Attribute: `dismissible`. Off by default. */ dismissible?: boolean; /** Render the whole card as a link. Attribute: `href`. Wins over `clickable`. */ href?: string; /** `target` for the `href` anchor. Attribute: `target`. */ target?: string; /** `rel` for the `href` anchor. Attribute: `rel`. */ rel?: string; /** Make the whole card a button (`role="button"`, Enter/Space, hover affordance) that emits `kai-card-click`. Attribute: `clickable`. Ignored when `href` is set. */ clickable?: boolean; /** A `clickable`/`href` card was activated (click, or Enter/Space). */ onCardClick?: (event: CustomEvent) => void; /** The card was dismissed via its × (it also hides itself). */ onDismiss?: (event: CustomEvent) => void; } export declare const Card: import('react').ForwardRefExoticComponent<CardProps & import('react').RefAttributes<HTMLElement>>; export interface CardsProps extends WebComponentProps { /** The stream of card envelopes to render. Set as a JS PROPERTY: `el.cards = [...]`. */ cards?: { type: string; id: string; data: unknown; title?: string; resolution?: { kind: "action"; action: string; payload?: unknown; at?: string; } | { kind: "submit"; data: unknown; at?: string; } | { kind: "dismissed"; at?: string; } | { kind: "expired"; reason?: string; at?: string; }; }[]; /** Optional type→tag overrides/additions (merged over the built-ins). Property: `el.types`. Typed as a plain string map (not the `CardTagMap` alias) so the generated React wrapper inlines it instead of emitting an unresolved named type. */ types?: Record<string, string>; /** Optional CardPolicy handling child events. Property: `el.policy`. */ policy?: { onSubmit?: (cardId: string, data: unknown) => void; onAction?: (cardId: string, action: string, payload?: unknown) => void; onSendPrompt?: (text: string, opts: { mode: "compose" | "send"; context?: unknown; }) => void; onOpen?: (url: string, target: "tab" | "artifact") => void; onState?: (cardId: string, patch: unknown) => void; onDismiss?: (cardId: string) => void; onReopen?: (cardId: string) => void; onError?: (cardId: string, message: string) => void; maxSendPromptMode?: "compose" | "send"; }; /** A child card transitioned to a resolved/deferred state (an action was chosen, a form/tasks submission landed, or it was dismissed) — re-emitted off the host as a non-bubbling convenience event so a consumer can observe resolution centrally without diffing the cards array. `detail` = `{ cardId, resolution }`. (A `reopen` un-resolves a card and has no `CardResolution`, so it does NOT fire this — observe reopen via the underlying bubbling `kai-card` event.) */ onCardResolved?: (event: CustomEvent<{ cardId: string; resolution: { kind: "action"; action: string; payload?: unknown; at?: undefined | string; } | { kind: "submit"; data: unknown; at?: undefined | string; } | { kind: "dismissed"; at?: undefined | string; } | { kind: "expired"; reason?: undefined | string; at?: undefined | string; }; }>) => void; } export declare const Cards: import('react').ForwardRefExoticComponent<CardsProps & import('react').RefAttributes<HTMLElement>>; export interface ChainOfThoughtProps extends WebComponentProps { /** The reasoning steps. Set as a JS property. Compound sub-parts collapse to this one data model (Route 1). Each `{ label, content?, id? }`. */ steps: { label: string; content?: undefined | string; id?: undefined | string; }[]; /** Open mode: `'multiple'` (default — any number of steps open at once) or `'single'` (at most one open; opening a step closes the others). */ type?: "single" | "multiple"; /** Controlled open step key(s). When set, it WINS over user interaction (the consumer owns the open set). String in `single` mode, string[] in `multiple` mode. Set as a JS property. */ value?: string | string[]; /** Uncontrolled INITIAL open step key(s) — seeds which steps render expanded. Ignored once `value` is provided. Set as a JS property. */ defaultValue?: string | string[]; /** The open set changed — by user click OR an expand()/collapse()/toggle() call. `value` is a string in `single` mode, a string[] in `multiple` mode. (Maps Radix Accordion's onValueChange.) */ onValueChange?: (event: CustomEvent<{ value: string | string[]; }>) => void; } export declare const ChainOfThought: import('react').ForwardRefExoticComponent<ChainOfThoughtProps & import('react').RefAttributes<HTMLElement>>; export interface ChatProps extends WebComponentProps { /** The full message thread to render, newest last. Each entry carries its role, content, and optional reasoning/tools/attachments/actions. Set as a JS property (`el.messages = [...]`). */ messages: { id: string; role: "user" | "assistant"; content: string; reasoning?: undefined | { text: string; label?: undefined | string; }; tools?: undefined | { type: string; state: "input-streaming" | "input-available" | "output-available" | "output-error"; input?: undefined | Record<string, unknown>; output?: undefined | Record<string, unknown>; toolCallId?: undefined | string; errorText?: undefined | string; }[]; attachments?: undefined | { id: string; type: "file" | "source-document"; filename?: undefined | string; mediaType?: undefined | string; url?: undefined | string; title?: undefined | string; }[]; actions?: undefined | ("copy" | "like" | "dislike" | "regenerate" | "edit" | { id: string; label: string; icon?: undefined | string; tooltip?: undefined | string; })[]; avatar?: undefined | { src?: undefined | string; fallback?: undefined | string; alt?: undefined | string; }; feedback?: undefined | "like" | "dislike"; }[]; /** Value of the input. A **string** is controlled (the host owns the text and updates it on `kai-value-change`). A **ComposerDoc** is a one-time seed that pre-populates pills; the user then edits freely. Leave unset for uncontrolled. */ value?: string | ({ type: "text"; text: string; } | { type: "entity"; entity: { kind: string; id: string; label: string; icon?: string; promptText?: string; data?: Record<string, unknown>; }; })[]; /** Placeholder text shown in the empty input. */ placeholder?: string; /** When true, shows the loading/streaming state and disables submit (use while awaiting the assistant's reply). */ loading?: boolean; /** Starter prompts shown above the input when the thread is empty. Clicking one follows `suggestionMode`. Set as a JS property. */ suggestions?: string[]; /** What clicking a suggestion does: `'submit'` (default) sends it immediately as if typed and submitted; `'fill'` just places it in the input. */ suggestionMode?: "submit" | "fill"; /** Keep suggestions visible after the conversation starts. By default suggestions are conversation starters and hide once `messages` is non-empty; set this to keep them always shown. Default false. */ persistSuggestions?: boolean; /** Body/prose font scale for rendered markdown (`'xs' | 'sm' | 'base' | 'lg'`). Defaults to `'sm'`. */ proseSize?: "sm" | "lg" | "xs" | "base"; /** Shiki theme name for syntax-highlighted code blocks (e.g. `'github-dark-dimmed'`). */ codeTheme?: string; /** Enable Shiki syntax highlighting in code blocks. Turn off to render plain `<pre>` blocks (lighter, no highlighter load). Default true. */ codeHighlight?: boolean; /** Optional header title shown on the left of the header. */ chatTitle?: string; /** Optional model list. When set (>1 model) a ModelSwitcher is shown in the header and a `kai-model-change` event fires on selection. */ models?: { id: string; name: string; provider?: string; description?: string; group?: string; }[]; /** The currently selected model id (pairs with `models`). */ currentModel?: string; /** Optional context-window token usage. When set, a Context token meter is shown in the header. */ context?: { usedTokens: number; maxTokens: number; inputTokens?: number; outputTokens?: number; estimatedCost?: number; }; /** Show the scroll-to-bottom button inside the scroll area. Default true. */ scrollButton?: boolean; /** Whether the host has `slot="header-start"` content (left of the title) — set by the `<kai-chat>` facade so a custom control forces the header open. */ headerStart?: boolean; /** Whether the host has `slot="header-end"` content (right of the controls). */ headerEnd?: boolean; /** REPLACE — full custom header in place of the built-in title/model/context bar. */ headerFull?: boolean; /** INJECT — left sidebar column (e.g. a conversation list / your own nav). */ sidebar?: boolean; /** REPLACE — custom zero-state rendered in the message area while the thread is empty (replaces the empty message list only; the composer and its suggestions still render). */ empty?: boolean; /** REPLACE — full custom composer in place of the built-in prompt input. The projected content wires its own submit (the data-flow boundary). */ composer?: boolean; /** INJECT — accessory row just above the composer (e.g. extra actions). */ composerActions?: boolean; /** INJECT — footer row below the composer (disclaimers, token meter, …). */ footer?: boolean; /** Show a Search (Globe) button in the input toolbar; fires a `search` event. */ search?: boolean; /** Show a Voice (Mic) button in the input toolbar; fires a `voice` event. */ voice?: boolean; /** Rich entity triggers — each `{ char, kind, items }` opens a caret-anchored menu that inserts an atomic pill (`/` skills, `@` agents/plugins). Set as a JS property; forwarded to the input. */ triggers?: { char: string; kind: string; items?: { id: string; label: string; icon?: string; description?: string; group?: string; kind?: string; promptText?: string; data?: Record<string, unknown>; }[]; }[]; /** Default icon per entity kind (kind → image src) for pills/menu items. */ kindIcons?: Record<string, string>; /** Whether each message's action bar is always visible (`'always'`, default) or only revealed on hover of that message row (`'hover'`). */ actionsReveal?: "always" | "hover"; /** The staged attachments changed (file added or removed). Carries the full current list so a consumer can react in real time. */ onAttachmentsChange?: (event: CustomEvent<{ attachments: { id: string; type: "file" | "source-document"; filename?: undefined | string; mediaType?: undefined | string; url?: undefined | string; title?: undefined | string; }[]; }>) => void; /** An action button on a message was clicked. `action` is the built-in name or custom id. `state` is present only for the toggleable feedback votes: `'on'` when a like/dislike is set, `'off'` when re-tapped to clear. */ onMessageAction?: (event: CustomEvent<{ messageId: string; action: string; state?: undefined | "on" | "off"; }>) => void; /** The header model switcher changed. */ onModelChange?: (event: CustomEvent<{ modelId: string; }>) => void; /** The Search button was clicked. */ onSearch?: (event: CustomEvent<Record<string, never>>) => void; /** User submitted a message. */ onSubmit?: (event: CustomEvent<{ value: string; attachments: { id: string; type: "file" | "source-document"; filename?: undefined | string; mediaType?: undefined | string; url?: undefined | string; title?: undefined | string; }[]; }>) => void; /** A suggestion chip was clicked (only in `suggestion-mode="fill"`). */ onSuggestionClick?: (event: CustomEvent<{ value: string; }>) => void; /** Fired on every input change. */ onValueChange?: (event: CustomEvent<{ value: string; }>) => void; /** The Mic / voice button was clicked. */ onVoice?: (event: CustomEvent<Record<string, never>>) => void; } export declare const Chat: import('react').ForwardRefExoticComponent<ChatProps & import('react').RefAttributes<HTMLElement>>; export interface CheckpointProps extends WebComponentProps { /** Optional text beside the icon. */ label?: string; /** Tooltip on hover. */ tooltip?: string; /** Visual button style. */ variant?: "default" | "ghost" | "outline"; /** Button size (use an `icon*` size for an icon-only checkpoint). */ size?: "sm" | "md" | "lg" | "icon" | "icon-sm"; /** The checkpoint was clicked. */ onSelect?: (event: CustomEvent) => void; } export declare const Checkpoint: import('react').ForwardRefExoticComponent<CheckpointProps & import('react').RefAttributes<HTMLElement>>; export interface ChoiceProps extends WebComponentProps { /** The choice definition (the CardEnvelope.data). Set as a JS PROPERTY: `el.data = { prompt, options:[…], allowOther?, submitLabel? }`. Import `ChoiceCardData` from `@kitn.ai/ui` for the full shape. */ data?: Record<string, unknown>; /** Stable card id correlating every emitted CardEvent. Attribute: `card-id`. */ cardId?: string; /** Heading rendered in the card chrome (= CardEnvelope.title). Attribute: `heading`. */ heading?: string; /** Set when the user resolved this card; renders the read-only view. Property: `el.resolution = { kind:'action', action:'…' }`. */ resolution?: Record<string, unknown>; /** Controlled selection — the selected option id. When set, the consumer owns the current pick (RadioGroup `value`). Attribute: `value`. */ value?: string; /** Option id to pre-select on mount (uncontrolled seed). Attribute: `default-value`. */ defaultValue?: string; /** Disable the whole radiogroup + Submit (e.g. while the agent is busy). Attribute: `disabled`. */ disabled?: boolean; /** The selection changed BEFORE submit (a row click or the `select()` method). Distinct from the terminal `action` verb on the `kai-card` contract event. */ onValueChange?: (event: CustomEvent<{ value: string; }>) => void; } export declare const Choice: import('react').ForwardRefExoticComponent<ChoiceProps & import('react').RefAttributes<HTMLElement>>; export interface CoachmarkProps extends WebComponentProps { /** Drive/observe open state (Shoelace-style: settable + reflected to the `open` attribute; the element still self-manages). Set `el.open = true`, or `<kai-coachmark open>`; listen for `kai-open-change`. */ open?: boolean; /** Initial open state on mount (uncontrolled seed). */ defaultOpen?: boolean; /** The bold title. Named `headline` because `title` collides with the global `HTMLElement.title` attribute (it throws at registration). */ headline?: string; /** A small badge pill beside the headline (e.g. "New"). */ badge?: string; /** Floating placement relative to the anchor (default `bottom`). */ placement?: string; /** Color tone: `primary` (default, theme accent), `info` (blue), `success` (green), `warning` (amber), or `error` (red) — reusing the kit's tool hues. */ tone?: "error" | "primary" | "info" | "success" | "warning"; /** Render the arrow that points at the anchor (default `true`). Set `arrow="false"` for a plain bubble with no pointer. */ arrow?: boolean; /** The × dismiss button was pressed. The consumer records that this hint was seen so it won't show again. */ onDismiss?: (event: CustomEvent<Record<string, never>>) => void; /** The coachmark opened or closed (a method, the ×, or a driven `open`). */ onOpenChange?: (event: CustomEvent<{ open: boolean; }>) => void; } export declare const Coachmark: import('react').ForwardRefExoticComponent<CoachmarkProps & import('react').RefAttributes<HTMLElement>>; export interface CodeBlockProps extends WebComponentProps { /** The source code to render. */ code: string; /** Language grammar (e.g. `js`, `python`). Defaults to `tsx`. */ language?: string; /** Shiki theme name. */ codeTheme?: string; /** Disable syntax highlighting (renders plain text, no Shiki). */ codeHighlight?: boolean; /** Code text sizing. */ proseSize?: "sm" | "lg" | "xs" | "base"; } export declare const CodeBlock: import('react').ForwardRefExoticComponent<CodeBlockProps & import('react').RefAttributes<HTMLElement>>; export interface CommandProps extends WebComponentProps { /** Flat list of items. Set as a JS property — not an HTML attribute. */ items?: { id: string; label: string; icon?: string; description?: string; shortcut?: string; group?: string; }[]; /** Placeholder text for the search input. */ placeholder?: string; /** Label shown when no items match the current query. */ emptyLabel?: string; /** Fired when the highlighted/active item changes — via Arrow keys or when filtering re-clamps the active row. `id` is the newly active item's id, or `undefined` when no item is active (e.g. the filtered list is empty). Lets a host preview the active item without committing a selection. */ onActiveChange?: (event: CustomEvent<{ id: undefined | string; }>) => void; /** Fired on every keystroke in the search input. */ onQueryChange?: (event: CustomEvent<{ value: string; }>) => void; /** Fired when the user selects an item (click or Enter). */ onSelect?: (event: CustomEvent<{ id: string; }>) => void; } export declare const Command: import('react').ForwardRefExoticComponent<CommandProps & import('react').RefAttributes<HTMLElement>>; export interface CompareProps extends WebComponentProps { /** The compare definition (prompt + the two candidates). Set as a JS PROPERTY: `el.data = { prompt, candidates: [A, B], collapse? }`. Import `ResponseCompareData` from `@kitn.ai/ui` for the full shape. */ data?: Record<string, unknown>; /** Stable id correlating every emitted event. Attribute: `compare-id`. */ compareId?: string; /** Re-hydrate / control the user's pick. Set as a JS PROPERTY: `el.selection = { chosenId, rejectedIds }`. Renders the collapsed winner. */ selection?: Record<string, unknown>; /** Layout: `'auto'` (default — columns when wide, tabs when narrow, by CONTAINER width) | `'columns'` (side-by-side) | `'tabs'` (pills to switch). Attribute: `layout`. */ layout?: "auto" | "columns" | "tabs"; /** Prose/text size for the rendered candidates. Attribute: `prose-size`. */ proseSize?: "sm" | "lg" | "xs" | "base"; /** Shiki theme for code blocks in the candidates. Attribute: `code-theme`. */ codeTheme?: string; /** Whether code blocks are syntax-highlighted. Attribute: `code-highlight`. */ codeHighlight?: boolean; /** The user committed a pick. `detail` = `{ chosenId, rejectedIds, at }`. */ onCompareSelect?: (event: CustomEvent<{ chosenId: string; rejectedIds: string[]; at?: undefined | number; }>) => void; /** The definition was unusable. */ onError?: (event: CustomEvent<{ compareId: string; message: string; }>) => void; /** Both candidates have settled and the pick is live. */ onReady?: (event: CustomEvent<{ compareId: string; }>) => void; } export declare const Compare: import('react').ForwardRefExoticComponent<CompareProps & import('react').RefAttributes<HTMLElement>>; export interface ComposerProps extends WebComponentProps { /** Controlled value — string or a full ComposerDoc (set as JS property). */ value?: string | ({ type: "text"; text: string; } | { type: "entity"; entity: { kind: string; id: string; label: string; icon?: string; promptText?: string; data?: Record<string, unknown>; }; })[]; /** Placeholder text shown when the composer is empty. */ placeholder?: string; /** Disable the composer entirely (non-interactive). */ disabled?: boolean; /** Show a loading/streaming state and block submit. */ loading?: boolean; /** Maximum height in px before the content scrolls. Default 240. */ maxHeight?: string | number; /** Whether pressing Enter (without Shift) submits. Default true. */ submitOnEnter?: boolean; /** Trigger definitions — set as a JS property. */ triggers?: { char: string; kind: string; items?: { id: string; label: string; icon?: string; description?: string; group?: string; kind?: string; promptText?: string; data?: Record<string, unknown>; }[]; }[]; /** Keyword highlight rules — set as a JS property. */ highlights?: (string | { pattern: string; flags?: string; class?: string; })[]; /** Default icon per entity kind (kind → image URL/data-URI) for items without their own `icon`. Overrides the built-in agent/plugin glyphs. JS property. */ kindIcons?: Record<string, string>; /** The composer lost focus. */ onBlur?: (event: CustomEvent<{ originalEvent: FocusEvent; }>) => void; /** An entity pill was inserted into the composer. */ onEntityAdd?: (event: CustomEvent<{ entity: { kind: string; id: string; label: string; icon?: undefined | string; promptText?: undefined | string; data?: undefined | Record<string, unknown>; }; }>) => void; /** An entity pill was deleted from the composer. */ onEntityRemove?: (event: CustomEvent<{ entity: { kind: string; id: string; label: string; icon?: undefined | string; promptText?: undefined | string; data?: undefined | Record<string, unknown>; }; }>) => void; /** The composer gained focus. `focus`/`blur` are NOT composed natively, so they don't escape the shadow root — these re-expose them on the host. (For `keydown`/`paste`/`focusin`/`focusout`, listen NATIVELY on `<kai-composer>`: they're composed and already cross the shadow boundary.) */ onFocus?: (event: CustomEvent<{ originalEvent: FocusEvent; }>) => void; /** The user submitted the composer (Enter or programmatic submit). */ onSubmit?: (event: CustomEvent<{ doc: ({ type: "text"; text: string; } | { type: "entity"; entity: { kind: string; id: string; label: string; icon?: undefined | string; promptText?: undefined | string; data?: undefined | Record<string, unknown>; }; })[]; text: string; entities: { kind: string; id: string; label: string; icon?: undefined | string; promptText?: undefined | string; data?: undefined | Record<string, unknown>; }[]; }>) => void; /** A trigger character was detected at the caret (e.g. `/` or `@`). */ onTrigger?: (event: CustomEvent<{ char: string; query: string; rect: DOMRect; }>) => void; /** The active trigger was dismissed (Escape, space, or outside click). */ onTriggerClose?: (event: CustomEvent<Record<string, never>>) => void; /** The content changed (fires on every input event). */ onValueChange?: (event: CustomEvent<{ doc: ({ type: "text"; text: string; } | { type: "entity"; entity: { kind: string; id: string; label: string; icon?: undefined | string; promptText?: undefined | string; data?: undefined | Record<string, unknown>; }; })[]; text: string; entities: { kind: string; id: string; label: string; icon?: undefined | string; promptText?: undefined | string; data?: undefined | Record<string, unknown>; }[]; }>) => void; } export declare const Composer: import('react').ForwardRefExoticComponent<ComposerProps & import('react').RefAttributes<HTMLElement>>; export interface ConfirmProps extends WebComponentProps { /** The confirm definition (the CardEnvelope.data). Set as a JS PROPERTY: `el.data = { body, tone, actions:[…] }`. Import `ConfirmCardData` from `@kitn.ai/ui` for the full shape. */ data?: Record<string, unknown>; /** Stable card id correlating every emitted CardEvent. Attribute: `card-id`. */ cardId?: string; /** Heading rendered in the card chrome (= CardEnvelope.title). Attribute: `heading`. */ heading?: string; /** Focus the default action on mount (off by default — no focus-stealing). Attribute: `autofocus`. */ autofocus?: boolean; /** Set when the user resolved this card; renders the read-only view. Property: `el.resolution = { kind:'action', action:'…' }`. */ resolution?: Record<string, unknown>; } export declare const Confirm: import('react').ForwardRefExoticComponent<ConfirmProps & import('react').RefAttributes<HTMLElement>>; export interface ContextProps extends WebComponentProps { /** Token-usage data. Set as a JS property. */ context?: { usedTokens: number; maxTokens: number; inputTokens?: number; outputTokens?: number; reasoningTokens?: number; cacheTokens?: number; estimatedCost?: number; }; /** Fraction (0–1) above which the meter turns yellow. Defaults to `0.7` (70%). */ warnThreshold?: number; /** Fraction (0–1) above which the meter turns red. Defaults to `0.9` (90%). */ dangerThreshold?: number; /** Fires when the computed severity level changes (ok → warn → danger or back). `detail.level` is `'ok'`, `'warn'`, or `'danger'`. */ onThresholdChange?: (event: CustomEvent<{ level: "ok" | "warn" | "danger"; }>) => void; } export declare const Context: import('react').ForwardRefExoticComponent<ContextProps & import('react').RefAttributes<HTMLElement>>; export interface ConversationsProps extends WebComponentProps { /** Pre-bucketed conversation groups (e.g. "Today", "Yesterday"), each with its own conversations. Use this when you want to control the grouping/headers yourself; otherwise pass a flat `conversations` array. Set as a JS property. */ groups: { id: string; userId?: undefined | string; teamId?: undefined | string; name: string; sortOrder: number; createdAt: string; }[]; /** A flat list of conversation summaries; the component buckets them by recency for you. Ignored when `groups` is provided. Set as a JS property. */ conversations: { id: string; title: string; groupId?: undefined | string; scope: { type: "document" | "collection"; documentId?: undefined | string; filters?: undefined | { tags?: undefined | string[]; authors?: undefined | string[]; contentType?: undefined | "transcript" | "markdown"; dateRange?: undefined | { from: string; to: string; }; }; }; messageCount: number; lastMessageAt: string; updatedAt: string; trailing?: undefined | string; }[]; /** The id of the currently-open conversation, highlighted in the list. */ activeId?: string; /** Controlled collapsed state. Set as a JS property (`el.collapsed = true`) to drive the rail from your app, updating it in response to `kai-collapse-toggle`. Omit for uncontrolled (the element manages it). Collapsed shrinks the rail to a floating reopen button. */ collapsed?: boolean; /** Initial collapsed state when uncontrolled (default false). Use the `default-collapsed` attribute to start collapsed in plain HTML. */ defaultCollapsed?: boolean; /** The rail was collapsed or expanded (via the toggle, the reopen button, or a `collapse()`/`expand()`/`toggle()` call). */ onCollapseToggle?: (event: CustomEvent<{ collapsed: boolean; }>) => void; /** A conversation was selected. */ onConversationSelect?: (event: CustomEvent<{ id: string; }>) => void; /** The "New chat" button was clicked. */ onNewChat?: (event: CustomEvent<Record<string, never>>) => void; /** The built-in search box query changed (typing, or a programmatic `clear()` which fires it with `''`). Lets a consumer mirror or server-side the filter. */ onSearch?: (event: CustomEvent<{ query: string; }>) => void; /** The sidebar toggle was clicked. */ onToggleSidebar?: (event: CustomEvent<Record<string, never>>) => void; } export declare const Conversations: import('react').ForwardRefExoticComponent<ConversationsProps & import('react').RefAttributes<HTMLElement>>; export interface DialogProps extends WebComponentProps { /** Drive/observe open state (Shoelace-style: settable + reflected to the `open` attribute; the element still self-manages on Escape/backdrop). Set `el.open = true`, or `<kai-dialog open>`; listen for `kai-open-change`. */ open?: boolean; /** Initial open state on mount (uncontrolled seed). */ defaultOpen?: boolean; /** The dialog opened or closed (Escape, backdrop click, a driven `open`, or a method). */ onOpenChange?: (event: CustomEvent<{ open: boolean; }>) => void; } export declare const Dialog: import('react').ForwardRefExoticComponent<DialogProps & import('react').RefAttributes<HTMLElement>>; export interface EditableLabelProps extends WebComponentProps { /** The label text — settable and reflected to the `value` attribute. Read `el.value` for live state. */ value?: string; /** Controlled edit state. `el.editing = true` opens the field; reflected to the `editing` attribute. */ editing?: boolean; /** Placeholder shown while editing / when the value is empty. */ placeholder?: string; /** Disable entering edit mode. */ disabled?: boolean; /** Edit was cancelled (Esc); the text is restored. */ onCancel?: (event: CustomEvent<Record<string, never>>) => void; /** Committed a changed value (Enter / blur). */ onRename?: (event: CustomEvent<{ value: string; }>) => void; } export declare const EditableLabel: import('react').ForwardRefExoticComponent<EditableLabelProps & import('react').RefAttributes<HTMLElement>>; export interface EmbedProps extends WebComponentProps { /** Stable card id correlating every emitted event. Set as an attribute or property. */ cardId?: string; /** The embed payload (provider + id/url + options). Set as a JS **property** (object). */ data?: { provider: "youtube" | "vimeo" | "generic"; id?: string; url?: string; title?: string; poster?: string; start?: number; aspectRatio?: "16:9" | "4:3" | "1:1" | "9:16"; }; } export declare const Embed: import('react').ForwardRefExoticComponent<EmbedProps & import('react').RefAttributes<HTMLElement>>; export interface EmptyProps extends WebComponentProps { /** Title text. Attribute: `empty-title` (`title` is a global HTML attribute). */ emptyTitle?: string; /** Description text. */ description?: string; } export declare const Empty: import('react').ForwardRefExoticComponent<EmptyProps & import('react').RefAttributes<HTMLElement>>; export interface FeedbackBarProps extends WebComponentProps { /** The banner label (e.g. "Was this helpful?"). Attribute: `bar-title` (`title` is avoided — it's a global HTML attribute). */ barTitle?: string; /** When set, a not-helpful vote opens an optional detail form before the thank-you confirmation. Attribute: `collect-detail`. */ collectDetail?: boolean; /** Optional category chips for the detail form. Set as a JS property (array). */ categories?: string[]; /** Heading for the detail form. Attribute: `detail-title`. */ detailTitle?: string; /** Placeholder for the detail comment box. Attribute: `detail-placeholder`. */ detailPlaceholder?: string; /** Submit button label in the detail form. Attribute: `submit-label`. */ submitLabel?: string; /** Confirmation copy shown after a vote/submit. Attribute: `thanks-message`. */ thanksMessage?: string; /** The user dismissed the banner. */ onClose?: (event: CustomEvent) => void; /** The user rated the response. `value` is `'helpful'` or `'not-helpful'`. */ onFeedback?: (event: CustomEvent<{ value: "helpful" | "not-helpful"; }>) => void; /** The user submitted the optional detail form (`collect-detail`). */ onFeedbackDetail?: (event: CustomEvent<{ value: "helpful" | "not-helpful"; category?: undefined | string; comment?: undefined | string; }>) => void; } export declare const FeedbackBar: import('react').ForwardRefExoticComponent<FeedbackBarProps & import('react').RefAttributes<HTMLElement>>; export interface FileTreeProps extends WebComponentProps { /** The files to render. Set as a JS property (array of `{ path, url?, code?, language?, type?, additions?, deletions?, status? }`). */ files: { path: string; url?: undefined | string; code?: undefined | string; language?: undefined | string; type?: undefined | "html" | "pdf" | "image" | "other"; additions?: undefined | number; deletions?: undefined | number; status?: undefined | "added" | "modified" | "deleted" | "renamed" | "untracked"; }[]; /** Selected file path — highlighted in the tree. */ activeFile?: string; /** Folder paths expanded initially. Omit to start with all folders open. */ defaultExpanded?: string[]; /** Show a changed-files summary header (file count + summed `+/-` + Collapse-all). Attribute: `summary`. Off by default. */ summary?: boolean; /** Fired when a file is selected. `detail.path` = the file's path. */ onSelect?: (event: CustomEvent<{ path: string; }>) => void; } export declare const FileTree: import('react').ForwardRefExoticComponent<FileTreeProps & import('react').RefAttributes<HTMLElement>>; export interface FileUploadProps extends WebComponentProps { /** Allow selecting multiple files (default true). */ multiple?: boolean; /** `accept` attribute for the file picker (e.g. `image/*`). */ accept?: string; /** Disable the dropzone — no clicking, no drag-and-drop. */ disabled?: boolean; /** Default dropzone label (overridable via the default slot). */ label?: string; /** Files were picked or dropped. */ onFilesAdded?: (event: CustomEvent<{ files: File[]; }>) => void; } export declare const FileUpload: import('react').ForwardRefExoticComponent<FileUploadProps & import('react').RefAttributes<HTMLElement>>; export interface FormProps extends WebComponentProps { /** The form definition — a JSON Schema (`type:'object'`) + `x-kai-*` UI hints (the CardEnvelope.data). Set as a JS PROPERTY: `el.data = { type:'object', properties:{…} }`. Import the `FormDefinition` type from `@kitn.ai/ui` for the full shape (it is self-referential, so the element types it loosely). */ data?: Record<string, unknown>; /** Stable card id correlating every emitted CardEvent. Attribute: `card-id`. */ cardId?: string; /** Heading rendered in the card chrome (= CardEnvelope.title). Attribute: `heading`. */ heading?: string; /** Set when the user resolved this card; renders the read-only view. Property: `el.resolution = { kind:'submit', data:{…} }`. */ resolution?: Record<string, unknown>; /** Controlled field values (JS property). When set, it wins over local edits. */ values?: Record<string, unknown>; /** Initial values overlaying the schema defaults (uncontrolled seed; JS property). */ defaultValues?: Record<string, unknown>; /** Disable all fields + submit. Attribute: `disabled`. */ disabled?: boolean; /** The form's values changed on input — current coerced values + validity. */ onValuesChange?: (event: CustomEvent<{ values: Record<string, unknown>; valid: boolean; }>) => void; } export declare const Form: import('react').ForwardRefExoticComponent<FormProps & import('react').RefAttributes<HTMLElement>>; export interface HoverCardProps extends WebComponentProps { /** Delay (ms) before the card opens on hover. Defaults to 0 (focus opens it immediately too). */ openDelay?: number; /** Delay (ms) before it closes after the pointer leaves. Defaults to 300. */ closeDelay?: number; /** Preferred placement: `'top' | 'bottom' | 'left' | 'right'` (+ optional `-start`/`-end`). Defaults to `'bottom'`; flips to stay in view. */ placement?: string; /** Drive/observe open state (Shoelace-style: settable + reflected to the `open` attribute, the element still self-manages on hover). Set `el.open = true`, or `<kai-hover-card open>`; listen for `kai-open-change`. */ open?: boolean; /** Initial open state on mount (uncontrolled seed). */ defaultOpen?: boolean; /** Suppress the hover behavior entirely without unmounting. */ disabled?: boolean; /** The card opened or closed (by hover/focus, outside-click, or a method). */ onOpenChange?: (event: CustomEvent<{ open: boolean; }>) => void; } export declare const HoverCard: import('react').ForwardRefExoticComponent<HoverCardProps & import('react').RefAttributes<HTMLElement>>; export interface IconProps extends WebComponentProps { /** A curated icon name (e.g. `"mic"`, `"globe"`), an image URL/data-URI, or plain text. */ name?: string; /** Size token: `sm` | `md` (default) | `lg`. */ size?: "sm" | "md" | "lg"; } export declare const Icon: import('react').ForwardRefExoticComponent<IconProps & import('react').RefAttributes<HTMLElement>>; export interface ImageProps extends WebComponentProps { /** Base64-encoded image data (pair with `media-type`). */ base64?: string; /** Raw image bytes (set as a JS property). */ bytes?: Uint8Array; /** Alt text. */ alt?: string; /** MIME type (default `image/png`). */ mediaType?: string; } export declare const Image: import('react').ForwardRefExoticComponent<ImageProps & import('react').RefAttributes<HTMLElement>>; export interface InputProps extends WebComponentProps { /** Native input type: `text` (default) · `email` · `url` · `search` · `tel` · `password` · `number`. Single-line only. */ type?: str