UNPKG

@kitn.ai/chat

Version:

Framework-agnostic, Shadow-DOM web components for building AI chat interfaces — works in React, Vue, Angular, Svelte, or plain HTML. Authored in SolidJS.

443 lines (388 loc) 16.9 kB
import type { ExampleUsage, StoryUsage } from './types'; /** * ChatGPT Style — compact vertical panel with avatar-led assistant rows * and right-aligned user bubbles, scaled to embed inside a larger page. */ const chatGptStyle: StoryUsage = { intro: 'Use **Chat Panel Layout** when the chat lives *inside* a larger page — a sidebar, a drawer, or a companion panel (e.g. ChatGPT-style). The panel is a fixed-size flex column: a header strip, a scrollable `ChatContainer` for the thread, and a `PromptInput` footer. Assistant messages lead with an avatar and use transparent-background markdown prose; user messages are right-aligned pills. Contrast with **Centered Conversation** (the chat *is* the page) and **Docked Widget** (a floating overlay).', snippets: { html: `<!-- Register the elements once (CDN or bundler) --> <script type="module"> import 'https://cdn.jsdelivr.net/npm/@kitn.ai/chat/dist/kitn-chat.es.js'; </script> <!-- Chat Panel Layout — compact vertical panel sized to embed inside a page. Typical sizing: 360-480 px wide, full container height. --> <div class="flex flex-col overflow-hidden rounded-lg bg-card" style="width:420px; height:700px"> <!-- Panel header --> <div class="flex flex-shrink-0 items-center justify-between bg-muted/30 px-3 py-2.5 text-sm font-semibold"> <span>Chat Panel</span> <span class="text-xs text-muted-foreground">GPT-4o Mini</span> </div> <!-- Scrollable thread --> <kc-chat-container class="min-w-0 flex-1 space-y-4 px-4 py-3"> <!-- Assistant message — avatar + transparent prose --> <kc-message> <kc-message-avatar src="" alt="AI" fallback="AI"></kc-message-avatar> <div class="flex min-w-0 w-full flex-col"> <kc-message-content markdown class="bg-transparent p-0 pt-1.5"> Hi there! How can I help? </kc-message-content> <kc-message-actions> <button aria-label="Copy"><!-- icon --></button> </kc-message-actions> </div> </kc-message> <!-- User message — right-aligned pill --> <kc-message class="group flex-col items-end"> <kc-message-content class="bg-muted text-primary mr-1 max-w-[85%] rounded-xl px-4 py-2"> What is this about? </kc-message-content> <kc-message-actions class="opacity-0 transition-opacity group-hover:opacity-100"> <button aria-label="Copy"><!-- icon --></button> </kc-message-actions> </kc-message> </kc-chat-container> <!-- Composer footer --> <div class="flex-shrink-0 px-3 pb-3 pt-1"> <kc-prompt-input id="composer"> <kc-prompt-input-textarea placeholder="Ask about this page…"></kc-prompt-input-textarea> <kc-prompt-input-actions class="mt-2 flex w-full items-center justify-end gap-2 px-3 pb-3"> <button aria-label="Send"><!-- icon --></button> </kc-prompt-input-actions> </kc-prompt-input> </div> </div> <script type="module"> document.getElementById('composer').addEventListener('kc-submit', (e) => { console.log('send', e.detail.value); }); </script>`, react: `import { useState } from 'react'; import { ChatConfig, ChatContainer, Message, MessageAvatar, MessageContent, MessageActions, PromptInput, PromptInputTextarea, PromptInputActions, Button, } from '@kitn.ai/chat/react'; /** * Chat Panel Layout — compact vertical panel for embedding inside a page. * Avatar-led assistant rows, right-aligned user bubbles, composer footer. */ export function ChatPanel() { const [input, setInput] = useState(''); return ( <ChatConfig proseSize="base"> <div className="flex flex-col overflow-hidden rounded-lg bg-card" style={{ width: 420, height: 700 }} > {/* Panel header */} <div className="flex flex-shrink-0 items-center justify-between bg-muted/30 px-3 py-2.5 text-sm font-semibold"> <span>Chat Panel</span> <span className="text-xs text-muted-foreground">GPT-4o Mini</span> </div> {/* Scrollable thread */} <ChatContainer className="min-w-0 flex-1 space-y-4 px-4 py-3"> {/* Assistant message — avatar + transparent prose */} <Message> <MessageAvatar src="" alt="AI" fallback="AI" /> <div className="flex min-w-0 w-full flex-col"> <MessageContent markdown className="bg-transparent p-0 pt-1.5"> Hi there! How can I help? </MessageContent> <MessageActions> <Button variant="ghost" size="icon-sm" aria-label="Copy">{/* icon */}</Button> </MessageActions> </div> </Message> {/* User message — right-aligned pill */} <Message className="group flex-col items-end"> <MessageContent className="bg-muted text-primary mr-1 max-w-[85%] rounded-xl px-4 py-2"> What is this about? </MessageContent> <MessageActions className="opacity-0 transition-opacity group-hover:opacity-100"> <Button variant="ghost" size="icon-sm" aria-label="Copy">{/* icon */}</Button> </MessageActions> </Message> </ChatContainer> {/* Composer footer */} <div className="flex-shrink-0 px-3 pb-3 pt-1"> <PromptInput value={input} onValueChange={setInput} onSubmit={() => setInput('')}> <PromptInputTextarea placeholder="Ask about this page…" className="min-h-[44px] pt-3 pl-4" /> <PromptInputActions className="mt-2 flex w-full items-center justify-end gap-2 px-3 pb-3"> <Button size="icon-sm" className="rounded-full" disabled={!input.trim()} aria-label="Send"> {/* icon */} </Button> </PromptInputActions> </PromptInput> </div> </div> </ChatConfig> ); }`, vue: `<script setup> import '@kitn.ai/chat/elements'; import { ref } from 'vue'; const input = ref(''); function onSubmit(e) { console.log('send', e.detail.value); input.value = ''; } </script> <!-- Chat Panel Layout — compact vertical panel for embedding inside a page. Avatar-led assistant rows, right-aligned user bubbles, composer footer. Typical sizing: 360-480 px wide, full container height. --> <template> <div class="flex flex-col overflow-hidden rounded-lg bg-card" style="width:420px; height:700px"> <!-- Panel header --> <div class="flex flex-shrink-0 items-center justify-between bg-muted/30 px-3 py-2.5 text-sm font-semibold"> <span>Chat Panel</span> <span class="text-xs text-muted-foreground">GPT-4o Mini</span> </div> <!-- Scrollable thread --> <kc-chat-container class="min-w-0 flex-1 space-y-4 px-4 py-3"> <!-- Assistant message — avatar + transparent prose --> <kc-message> <kc-message-avatar src="" alt="AI" fallback="AI"></kc-message-avatar> <div class="flex min-w-0 w-full flex-col"> <kc-message-content markdown class="bg-transparent p-0 pt-1.5"> Hi there! How can I help? </kc-message-content> <kc-message-actions> <button aria-label="Copy"><!-- icon --></button> </kc-message-actions> </div> </kc-message> <!-- User message — right-aligned pill --> <kc-message class="group flex-col items-end"> <kc-message-content class="bg-muted text-primary mr-1 max-w-[85%] rounded-xl px-4 py-2"> What is this about? </kc-message-content> <kc-message-actions class="opacity-0 transition-opacity group-hover:opacity-100"> <button aria-label="Copy"><!-- icon --></button> </kc-message-actions> </kc-message> </kc-chat-container> <!-- Composer footer --> <div class="flex-shrink-0 px-3 pb-3 pt-1"> <kc-prompt-input :value="input" @kc-value-change="input = $event.detail.value" @kc-submit="onSubmit" > <kc-prompt-input-textarea placeholder="Ask about this page…"></kc-prompt-input-textarea> <kc-prompt-input-actions class="mt-2 flex w-full items-center justify-end gap-2 px-3 pb-3"> <button :disabled="!input.trim()" aria-label="Send"><!-- icon --></button> </kc-prompt-input-actions> </kc-prompt-input> </div> </div> </template>`, svelte: `<script> import '@kitn.ai/chat/elements'; let input = ''; </script> <!-- Chat Panel Layout — compact vertical panel for embedding inside a page. Avatar-led assistant rows, right-aligned user bubbles, composer footer. Typical sizing: 360-480 px wide, full container height. --> <div class="flex flex-col overflow-hidden rounded-lg bg-card" style="width:420px; height:700px"> <!-- Panel header --> <div class="flex flex-shrink-0 items-center justify-between bg-muted/30 px-3 py-2.5 text-sm font-semibold"> <span>Chat Panel</span> <span class="text-xs text-muted-foreground">GPT-4o Mini</span> </div> <!-- Scrollable thread --> <kc-chat-container class="min-w-0 flex-1 space-y-4 px-4 py-3"> <!-- Assistant message — avatar + transparent prose --> <kc-message> <kc-message-avatar src="" alt="AI" fallback="AI"></kc-message-avatar> <div class="flex min-w-0 w-full flex-col"> <kc-message-content markdown class="bg-transparent p-0 pt-1.5"> Hi there! How can I help? </kc-message-content> <kc-message-actions> <button aria-label="Copy"><!-- icon --></button> </kc-message-actions> </div> </kc-message> <!-- User message — right-aligned pill --> <kc-message class="group flex-col items-end"> <kc-message-content class="bg-muted text-primary mr-1 max-w-[85%] rounded-xl px-4 py-2"> What is this about? </kc-message-content> <kc-message-actions class="opacity-0 transition-opacity group-hover:opacity-100"> <button aria-label="Copy"><!-- icon --></button> </kc-message-actions> </kc-message> </kc-chat-container> <!-- Composer footer --> <div class="flex-shrink-0 px-3 pb-3 pt-1"> <kc-prompt-input value={input} on:kc-value-change={(e) => (input = e.detail.value)} on:kc-submit={() => (input = '')} > <kc-prompt-input-textarea placeholder="Ask about this page…"></kc-prompt-input-textarea> <kc-prompt-input-actions class="mt-2 flex w-full items-center justify-end gap-2 px-3 pb-3"> <button disabled={!input.trim()} aria-label="Send"><!-- icon --></button> </kc-prompt-input-actions> </kc-prompt-input> </div> </div>`, angular: `// main.ts: import '@kitn.ai/chat/elements' before bootstrapApplication, // and add CUSTOM_ELEMENTS_SCHEMA to the component. import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; /** * Chat Panel Layout — compact vertical panel for embedding inside a page. * Avatar-led assistant rows, right-aligned user bubbles, composer footer. */ @Component({ selector: 'app-chat-panel', standalone: true, schemas: [CUSTOM_ELEMENTS_SCHEMA], styles: [':host { display: contents; }'], template: \` <div class="flex flex-col overflow-hidden rounded-lg bg-card" style="width:420px; height:700px"> <!-- Panel header --> <div class="flex flex-shrink-0 items-center justify-between bg-muted/30 px-3 py-2.5 text-sm font-semibold"> <span>Chat Panel</span> <span class="text-xs text-muted-foreground">GPT-4o Mini</span> </div> <!-- Scrollable thread --> <kc-chat-container class="min-w-0 flex-1 space-y-4 px-4 py-3"> <!-- Assistant message — avatar + transparent prose --> <kc-message> <kc-message-avatar src="" alt="AI" fallback="AI"></kc-message-avatar> <div class="flex min-w-0 w-full flex-col"> <kc-message-content markdown class="bg-transparent p-0 pt-1.5"> Hi there! How can I help? </kc-message-content> <kc-message-actions> <button aria-label="Copy"><!-- icon --></button> </kc-message-actions> </div> </kc-message> <!-- User message — right-aligned pill --> <kc-message class="group flex-col items-end"> <kc-message-content class="bg-muted text-primary mr-1 max-w-[85%] rounded-xl px-4 py-2"> What is this about? </kc-message-content> <kc-message-actions class="opacity-0 transition-opacity group-hover:opacity-100"> <button aria-label="Copy"><!-- icon --></button> </kc-message-actions> </kc-message> </kc-chat-container> <!-- Composer footer --> <div class="flex-shrink-0 px-3 pb-3 pt-1"> <kc-prompt-input [value]="input" (kc-value-change)="input = $event.detail.value" (kc-submit)="input = ''" > <kc-prompt-input-textarea placeholder="Ask about this page…"></kc-prompt-input-textarea> <kc-prompt-input-actions class="mt-2 flex w-full items-center justify-end gap-2 px-3 pb-3"> <button [disabled]="!input.trim()" aria-label="Send"><!-- icon --></button> </kc-prompt-input-actions> </kc-prompt-input> </div> </div> \`, }) export class ChatPanelComponent { input = ''; }`, solid: `import { createSignal } from 'solid-js'; import { ChatConfig, ChatContainer, Message, MessageAvatar, MessageContent, MessageActions, PromptInput, PromptInputTextarea, PromptInputActions, ScrollButton, Button, } from '@kitn.ai/chat'; import { Copy, ArrowUp } from 'lucide-solid'; /** * Chat Panel Layout — compact vertical panel for embedding inside a page. * Avatar-led assistant rows, right-aligned user bubbles, composer footer. * Typical sizing: 360-480 px wide, full container height. */ export function ChatPanel() { const [input, setInput] = createSignal(''); return ( <ChatConfig proseSize="base"> <div style={{ width: '420px', height: '700px' }} class="flex flex-col overflow-hidden rounded-lg bg-card" > {/* Panel header */} <div class="flex flex-shrink-0 items-center justify-between bg-muted/30 px-3 py-2.5 text-sm font-semibold text-foreground"> <span>Chat Panel</span> <span class="text-xs text-muted-foreground">GPT-4o Mini</span> </div> {/* Scrollable thread */} <ChatContainer class="min-w-0 flex-1 space-y-4 px-4 py-3"> {/* Assistant message — avatar + transparent prose */} <Message> <MessageAvatar src="" alt="AI" fallback="AI" /> <div class="flex min-w-0 w-full flex-col"> <MessageContent markdown class="bg-transparent p-0 pt-1.5"> Hi there! How can I help? </MessageContent> <MessageActions> <Button variant="ghost" size="icon-sm" aria-label="Copy"> <Copy size={14} /> </Button> </MessageActions> </div> </Message> {/* User message — right-aligned pill */} <Message class="group flex-col items-end"> <MessageContent class="bg-muted text-primary mr-1 max-w-[85%] rounded-xl px-4 py-2"> What is this about? </MessageContent> <MessageActions class="opacity-0 transition-opacity duration-150 group-hover:opacity-100"> <Button variant="ghost" size="icon-sm" aria-label="Copy"> <Copy size={14} /> </Button> </MessageActions> </Message> <ScrollButton /> </ChatContainer> {/* Composer footer */} <div class="flex-shrink-0 px-3 pb-3 pt-1"> <PromptInput value={input()} onValueChange={setInput} onSubmit={() => setInput('')}> <PromptInputTextarea placeholder="Ask about this page…" class="min-h-[44px] pt-3 pl-4" /> <PromptInputActions class="mt-2 flex w-full items-center justify-end gap-2 px-3 pb-3"> <Button size="icon-sm" class="rounded-full" disabled={!input().trim()} aria-label="Send message"> <ArrowUp class="size-4" /> </Button> </PromptInputActions> </PromptInput> </div> </div> </ChatConfig> ); }`, }, }; /** * Pattern: Chat Panel Layout — compact vertical panel intended to embed inside * a larger page. `ChatContainer` handles scroll; `MessageAvatar` leads each * assistant row; user messages right-align as pill bubbles; `PromptInput` pins * to the bottom. Per-story: the Usage tab shows the snippet for the story you're * on; the example-level fields below are the fallback. */ const chatPanelLayout: ExampleUsage = { title: 'Patterns/Chat Panel Layout', ...chatGptStyle, stories: { 'ChatGPT Style': chatGptStyle, }, }; export default chatPanelLayout;