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.

117 lines (116 loc) 6.1 kB
import { ComposerDoc } from '../primitives/composer-model'; import { AttachmentData } from './attachments'; import { MessageActionDetail } from '../primitives/message-feedback'; import { TriggerDef } from './composer'; import { ChatMessage } from '../elements/chat-types'; import { ProseSize } from '../primitives/chat-config'; import { ModelOption } from '../types'; export interface ChatThreadContextUsage { usedTokens: number; maxTokens: number; inputTokens?: number; outputTokens?: number; estimatedCost?: number; } export interface ChatThreadProps { /** Extra classes for the thread root (e.g. `h-full`). */ class?: string; /** 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: ChatMessage[]; /** 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 | ComposerDoc; /** 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?: ProseSize; /** 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?: ModelOption[]; /** 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?: ChatThreadContextUsage; /** 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?: TriggerDef[]; /** 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'; onValueChange?: (value: string) => void; onSubmit?: (detail: { value: string; attachments: AttachmentData[]; }) => void; onAttachmentsChange?: (attachments: AttachmentData[]) => void; onSuggestionClick?: (value: string) => void; onModelChange?: (modelId: string) => void; onMessageAction?: (detail: MessageActionDetail) => void; onSearch?: () => void; onVoice?: () => void; /** Receive the imperative controller once mounted. The kai-chat facade forwards * these as element methods (focus/clear/send/scrollToBottom). */ controllerRef?: (controller: ChatThreadController) => void; } /** Imperative handle exposed via `controllerRef` — the input half of the chat's * interaction surface, forwarded onto `<kai-chat>` as instance methods. */ export interface ChatThreadController { focus(options?: FocusOptions): void; clear(): void; send(): void; scrollToBottom(behavior?: ScrollBehavior): void; } export declare function ChatThread(props: ChatThreadProps): import("solid-js").JSX.Element;