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.

124 lines (123 loc) 5.97 kB
import { JSX } from 'solid-js'; import { ChatMessageAction, CustomAction, FeedbackVote } from '../elements/chat-types'; import { ToolPart } from './tool'; import { AttachmentData } from './attachments'; export interface MessageProps extends JSX.HTMLAttributes<HTMLDivElement> { children: JSX.Element; } declare function Message(props: MessageProps): JSX.Element; export interface MessageAvatarProps { src: string; alt: string; fallback?: string; class?: string; } declare function MessageAvatar(props: MessageAvatarProps): JSX.Element; export interface MessageContentProps extends JSX.HTMLAttributes<HTMLDivElement> { children: JSX.Element | string; markdown?: boolean; /** `::part` name(s) exposed on the content node. The body passes * `"bubble content"` so consumers can target either the rounded bubble or the * text region from outside the shadow boundary. */ part?: string; } declare function MessageContent(props: MessageContentProps): JSX.Element; export interface MessageActionsProps extends JSX.HTMLAttributes<HTMLDivElement> { children: JSX.Element; } declare function MessageActions(props: MessageActionsProps): JSX.Element; export interface MessageActionBarProps { /** Built-in action names and/or custom action descriptors, in order. */ actions: (ChatMessageAction | CustomAction)[]; /** `'always'` (default) keeps the bar visible; `'hover'` reveals it on * parent `.group` hover. */ reveal?: 'always' | 'hover'; /** Fired with the built-in name or the custom action id when a button is clicked. */ onAction: (id: string) => void; /** The active feedback vote. When `'like'`/`'dislike'` is set, that button is * marked pressed (filled) and the OTHER vote button animates out. `undefined` * shows both. Pure/prop-driven so the bar survives re-renders. */ activeFeedback?: FeedbackVote; /** When true, the `copy` button shows its emerald check icon instead of the * copy glyph (cleared by the owner after ~2s). */ copied?: boolean; class?: string; } /** * The shared message action toolbar. Renders one ghost icon button per entry — * built-in names pull their label+icon from the curated registry; custom * descriptors use their `label` plus `actionIcon(icon)` (label-only when the * icon is unknown or absent). `reveal="hover"` makes the bar fade in on the * parent `.group`'s hover. * * Pure/prop-driven: feedback (`activeFeedback`) and copy (`copied`) state are * owned by the parent facade and passed in — the bar holds no internal signals, * so it survives the new-array-per-chunk re-renders of a streaming thread. With * a vote active, the chosen `like`/`dislike` button is marked `aria-pressed` + * filled and the other vote button collapses its width (sliding the active thumb * into its place) via a 0fr↔1fr grid transition. The * `copy` button swaps to an emerald check while `copied`. */ declare function MessageActionBar(props: MessageActionBarProps): JSX.Element; export interface MessageBodyProps { /** The message text/markdown. */ content: string; /** Optional collapsible reasoning block, rendered above the content. */ reasoning?: { text: string; label?: string; }; /** Tool-call parts, rendered above the content. */ tools?: ToolPart[]; /** Inline attachment previews, rendered above the content. */ attachments?: AttachmentData[]; /** Whether this is a user message (right-aligned bubble) vs an assistant * message (full-width transparent). */ isUser: boolean; /** Whether the content renders as markdown. */ markdown: boolean; /** Action-bar entries — built-in names and/or custom descriptors. When empty * the bar is not rendered. */ actions?: (ChatMessageAction | CustomAction)[]; /** `'always'` (default) keeps the bar visible; `'hover'` reveals it on parent * `.group` hover. */ actionsReveal?: 'always' | 'hover'; /** Fired with the built-in name or custom id when an action is clicked. */ onAction?: (id: string) => void; /** The currently-active feedback vote, so the bar can mark like/dislike and * hide the other. */ activeFeedback?: FeedbackVote; /** When true, the copy button shows its "copied" check icon. */ copied?: boolean; /** INJECT slot projected at the TOP of the body — above the reasoning / tools / * content. A per-message header: a model-name label, a role + timestamp line. * In the `<kai-message>` shadow this is `<slot name="before-body" />`. */ beforeBody?: JSX.Element; /** INJECT slot projected at the BOTTOM of the body — below the action bar. A * citation / sources row, a token-cost / latency line. In the `<kai-message>` * shadow this is `<slot name="after-body" />`. */ afterBody?: JSX.Element; } /** * The shared message body: an optional reasoning block, tool calls, inline * attachments, the content bubble, and the action bar — in that order. This is * the single source of truth for how a message renders, consumed by `ChatThread` * (the `<For>` over `messages`), the standalone `<kai-message>` facade, and (in * future) `kai-compare` for each candidate. Pure/prop-driven: all interaction * state (copied, feedback vote) is owned above and passed in. */ declare function MessageBody(props: MessageBodyProps): JSX.Element; export interface MessageActionProps { tooltip: string; children: JSX.Element; side?: "top" | "bottom" | "left" | "right"; class?: string; } declare function MessageAction(props: MessageActionProps): JSX.Element; export interface MessageCopyButtonProps { content: string; size?: number; class?: string; } declare function MessageCopyButton(props: MessageCopyButtonProps): JSX.Element; export { Message, MessageAvatar, MessageContent, MessageActions, MessageActionBar, MessageBody, MessageAction, MessageCopyButton };