@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
TypeScript
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 {};