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.

54 lines (53 loc) 3.13 kB
import { JSX } from 'solid-js'; /** * Context handed to every element facade. `E` is the element's event map — * `{ eventName: detailType }` — which types `dispatch` so a facade can only fire * its declared events with the right `detail` shape. */ export interface WebComponentContext<E = Record<string, unknown>> { /** The custom-element host node. */ element: HTMLElement; /** Fire a non-bubbling, non-composed CustomEvent off the host. Consumers * listen directly on the element (`el.addEventListener(...)`). Typed by the * element's event map `E`. */ dispatch: <K extends keyof E & string>(type: K, detail?: E[K]) => void; /** * Resolve a boolean flag from a prop the way HTML authors expect. * * `component-register` parses a *bare* boolean attribute (`<el removable>`) to * `undefined`, not `true` — so a facade can't rely on the prop value alone. * `flag('removable')` returns ON when the property is `true`, OR when the * matching attribute is present and not explicitly `="false"`. So all of * `<el removable>`, `<el removable="true">`, and `el.removable = true` turn it * on; `<el removable="false">`, absent, and `el.removable = false` turn it off. * * `name` is the camelCase prop name; the matching kebab attribute is derived. */ flag: (name: string) => boolean; /** * Expose imperative methods on the host element instance — the input half of a * component's interaction surface (`el.focus()`, `el.clear()`, `el.scrollToBottom()`, * …), the counterpart to the events `dispatch` fires. Call once from the facade * with closures over its internal state/refs; each entry is assigned to the host, * so a consumer calls it directly: `document.querySelector('kai-prompt-input').focus()`. * Overriding a native method name (e.g. `focus`) shadows it on the instance so it * can target the right control inside the shadow root (the WebAwesome/Shoelace * convention). Methods are attached when the facade renders (on element upgrade). */ expose: (methods: Record<string, (...args: never[]) => unknown>) => void; } type FacadeComponent<P, E> = (props: P, ctx: WebComponentContext<E>) => JSX.Element; /** * Register a Solid facade as a Shadow-DOM custom element. * * - Renders into the element's shadow root (solid-element's default), with the * compiled kit CSS injected via a `<style>` so Tailwind classes apply inside. * - Creates a portal mount node inside the shadow root and provides it through * `ChatConfig` so the kit's overlays stay inside the shadow root. * - Gives the facade a `dispatch(type, detail)` helper that fires non-bubbling, * non-composed CustomEvents off the host element (consumers listen directly on * the element, so bubbling/composed would only cause consumer collisions). * - Idempotent: redefining an already-registered tag is a no-op. */ export declare function defineWebComponent<P extends Record<string, unknown>, E = Record<string, unknown>>(tag: string, propDefaults: P, Facade: FacadeComponent<P, E>): void; export {};