@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.
177 lines (176 loc) • 9.82 kB
TypeScript
/**
* Composition slots for `kai-*` elements. A slot is a named region a consumer
* fills with their own markup. This registry is the SINGLE SOURCE OF TRUTH:
* the facade derives its detection from it (and, later, docs are generated
* from it). See docs/superpowers/specs/2026-06-23-kai-chat-composition-seams-design.md.
*/
/** `inject` = additive (the built-in region still renders, your markup is added
* in). `replace` = your markup stands in for the whole region — you own that
* region's data + events (a slotted light-DOM node can't read the component's
* reactive state). */
export type SlotMode = 'inject' | 'replace';
export interface SlotDef {
/** Slot name (kebab-case). Also the `::part` name when `part` is true. */
name: string;
mode: SlotMode;
/** Expose `::part(name)` on the region wrapper for consumer styling. */
part?: boolean;
/** One-line contract: what the consumer projects / owns. Feeds the docs. */
doc: string;
}
/** Slots of `<kai-chat>`, in render order. */
export declare const CHAT_SLOTS: SlotDef[];
/** Slots of `<kai-prompt-input>` (and the default composer inside `<kai-chat>`). Native
* shadow slots — an empty slot renders nothing, so no facade flag-gating is required.
*
* These are ONLY positions inside the card's shadow boundary — places a consumer
* cannot reach from their own DOM. Content ABOVE/BELOW the whole card is the
* consumer's own light-DOM layout (a sibling element), so there is intentionally
* no outer block slot here. (When the input is nested inside `<kai-chat>`'s shadow,
* that surrounding hole belongs to `kai-chat` — see `composer-actions`/`footer`.) */
export declare const PROMPT_INPUT_SLOTS: SlotDef[];
/** Slots of `<kai-conversations>` (also used inside `<kai-chat>`'s `sidebar`).
* Names mirror `<kai-chat>`'s so the two compose with one vocabulary. */
export declare const CONVERSATIONS_SLOTS: SlotDef[];
/** Styleable `::part`s of `<kai-conversations>`. */
export declare const CONVERSATIONS_PARTS: PartDef[];
/** Slots of `<kai-message>` — per-message composition seams. `before-body` and
* `after-body` are INJECT regions inside the message's body column; `avatar`
* REPLACES the built-in avatar rail (pair it with `avatar="none"` to omit the
* rail entirely). These are the keystone of compose-your-own message lists. */
export declare const MESSAGE_SLOTS: SlotDef[];
/** Slots of `<kai-notice>`. The message is the default slot; these are the named seams. */
export declare const NOTICE_SLOTS: SlotDef[];
/** Slots of `<kai-button>` (the label is the default slot). */
export declare const BUTTON_SLOTS: SlotDef[];
/** Slots of `<kai-hover-card>` (the trigger is the default slot). */
export declare const HOVER_CARD_SLOTS: SlotDef[];
/** Slots of `<kai-menu>` (the menu items come from the `items` prop). */
export declare const MENU_SLOTS: SlotDef[];
/** A styleable `::part` the kit renders (NOT a slot — you don't project into it;
* you restyle it from outside via `::part(name)`). This registry is the source
* of truth so the styling surface is discoverable: docs + the `kai` MCP
* component reference are generated from it, the same way slots are. The
* `recipe` is a copy-pasteable example — including the "just hide it" case that
* is pure CSS and therefore intentionally NOT a prop. */
export interface PartDef {
/** `::part(name)` exposed for consumer styling. */
name: string;
/** One-line contract: what the part is. */
doc: string;
/** A copy-pasteable styling example for docs / the MCP reference. */
recipe?: string;
}
/** Styleable `::part`s of `<kai-chat>` (beyond the slot-backed `header`/`sidebar`/
* `footer` parts). */
export declare const CHAT_PARTS: PartDef[];
/** Styleable `::part`s of `<kai-prompt-input>`. */
export declare const PROMPT_INPUT_PARTS: PartDef[];
/** Styleable `::part`s of `<kai-button>`. */
export declare const BUTTON_PARTS: PartDef[];
/** Styleable `::part`s of `<kai-badge>`. */
export declare const BADGE_PARTS: PartDef[];
/** Styleable `::part`s of `<kai-icon>`. */
export declare const ICON_PARTS: PartDef[];
/** Styleable `::part`s of `<kai-separator>`. */
export declare const SEPARATOR_PARTS: PartDef[];
/** Styleable `::part`s of `<kai-scroll-area>`. */
export declare const SCROLL_AREA_PARTS: PartDef[];
/** Styleable `::part`s of `<kai-skeleton>`. */
export declare const SKELETON_PARTS: PartDef[];
/** Styleable `::part`s of `<kai-message>`. (The `avatar` part is contributed by
* the `avatar` slot's `part: true` flag, so it is not repeated here.) */
export declare const MESSAGE_PARTS: PartDef[];
/** Styleable `::part`s of `<kai-attachments>`. */
export declare const ATTACHMENTS_PARTS: PartDef[];
/** Styleable `::part`s of `<kai-status>`. */
export declare const STATUS_PARTS: PartDef[];
/** Styleable `::part`s of `<kai-tabs>`. */
export declare const TABS_PARTS: PartDef[];
/** Styleable `::part`s of `<kai-voice-output>`. */
export declare const VOICE_OUTPUT_PARTS: PartDef[];
/** Slots of `<kai-screen>` (the default slot is the screen body). */
export declare const SCREEN_SLOTS: SlotDef[];
/** Styleable `::part`s of `<kai-screen>`. */
export declare const SCREEN_PARTS: PartDef[];
/** Slots of `<kai-card>` — structural regions only (the title/description are body
* or `slot="header"` content you mark up). The body is the default slot. */
export declare const CARD_SLOTS: SlotDef[];
/** Styleable `::part`s of `<kai-card>`. */
export declare const CARD_PARTS: PartDef[];
/** Injection slots of `<kai-workspace>` (the carrier regions the consumer drops
* content into: brand/tabs, the upgrade/Design/user-menu cluster, a top banner). */
export declare const WORKSPACE_SLOTS: SlotDef[];
/** Styleable `::part`s of `<kai-workspace>`. */
export declare const WORKSPACE_PARTS: PartDef[];
/** Styleable `::part`s of `<kai-nav>`. */
export declare const NAV_PARTS: PartDef[];
/** Slots of `<kai-coachmark>` (the anchor/trigger is the default slot). */
export declare const COACHMARK_SLOTS: SlotDef[];
/** Styleable `::part`s of `<kai-coachmark>`. */
export declare const COACHMARK_PARTS: PartDef[];
/** Styleable `::part`s of `<kai-progress-bar>`. */
export declare const PROGRESS_BAR_PARTS: PartDef[];
/** Styleable `::part`s of `<kai-file-tree>` — the changed-files / diff bits, shown
* only when a file carries diff metadata (or the `summary` attribute is set). */
export declare const FILE_TREE_PARTS: PartDef[];
/**
* Per-element composition surface — the SINGLE registry the build extracts
* (`scripts/gen-element-api.mjs`) into `element-meta.json`, the Custom Elements
* Manifest (`cssParts`/`slots`), `docs/web-components.md`, and the `kai` MCP
* `component_reference`. Each entry maps a `kai-*` tag to the slots it projects
* and the `::part`s it exposes for styling. Slots flagged `part: true` are ALSO
* styleable parts, so they surface in both places.
*
* Adding a `part="…"` in a facade/component without registering it here fails the
* `slots.test.ts` drift guard — keep this in sync with the source.
*/
export interface ElementComposition {
slots?: SlotDef[];
parts?: PartDef[];
}
/** Slots + styleable `::part`s of `<kai-prompt-dock>`. */
export declare const PROMPT_DOCK_SLOTS: SlotDef[];
export declare const PROMPT_DOCK_PARTS: PartDef[];
/** Styleable `::part`s of `<kai-segmented>`. */
export declare const SEGMENTED_PARTS: PartDef[];
/** Styleable `::part`s of `<kai-settings-group>`. */
export declare const SETTINGS_GROUP_PARTS: PartDef[];
/** Slots + styleable `::part`s of `<kai-setting-item>`. */
export declare const SETTING_ITEM_SLOTS: SlotDef[];
export declare const SETTING_ITEM_PARTS: PartDef[];
/** Slots + styleable `::part`s of `<kai-pane>` (the editor-group pane frame). */
export declare const PANE_SLOTS: SlotDef[];
export declare const PANE_PARTS: PartDef[];
/** Styleable `::part`s of `<kai-agent-card>`. */
export declare const AGENT_CARD_PARTS: PartDef[];
/** Slots + styleable `::part`s of `<kai-dialog>` (the centered modal). */
export declare const DIALOG_SLOTS: SlotDef[];
export declare const DIALOG_PARTS: PartDef[];
/** Styleable `::part`s of `<kai-pane-group>` (the editor group: a tab strip over
* the active tab's pane). The per-tab content slots are NAMED DYNAMICALLY by tab
* id (`slot="<tab id>"`) plus a default slot, so they are not enumerable here —
* only the styleable parts are registered. */
export declare const PANE_GROUP_PARTS: PartDef[];
/** Affix slots + styleable `::part`s of `<kai-input>` (the field shell). */
export declare const INPUT_SLOTS: SlotDef[];
export declare const INPUT_PARTS: PartDef[];
/** Styleable `::part`s of `<kai-search>` (the debounced filter field; composes the
* kai-input field plus a clear button). */
export declare const SEARCH_PARTS: PartDef[];
/** Styleable `::part`s of `<kai-editable-label>` (inline rename; the edit field is the kai-input field). */
export declare const EDITABLE_LABEL_PARTS: PartDef[];
/** Styleable `::part`s of `<kai-kbd>` (the keyboard-shortcut display). */
export declare const KBD_PARTS: PartDef[];
/** Styleable `::part`s of `<kai-command>` (the command palette). */
export declare const COMMAND_PARTS: PartDef[];
/** Styleable `::part`s of `<kai-menu>` (the actions dropdown). */
export declare const MENU_PARTS: PartDef[];
export declare const ELEMENT_COMPOSITION: Record<string, ElementComposition>;
/**
* Which slots have projected light-DOM content — a DIRECT child of `host`
* carrying the matching `slot` attribute. Pure and synchronous; safe in jsdom
* and SSR (returns all-false when `host` has no matching children). The facade
* calls this on mount and on every childList mutation.
*/
export declare function readSlots(host: Element, defs?: SlotDef[]): Record<string, boolean>;