import type { ExampleUsage, StoryUsage } from './types'; // Shared assistant reply used across the snippets. const REPLY = 'Async functions return Result, and the ? operator propagates errors.'; /** Actions on Hover — the bar reveals on hover via the actions-reveal prop. */ const hover: StoryUsage = { intro: 'Render an assistant message with an action bar that reveals on hover. Declare each button as a `` child of `` and set `actions-reveal="hover"` — the element owns the fade (no consumer CSS). React passes the `actions` array instead; the Solid demo uses the primitives with `group`/`group-hover`.', snippets: { html: ` `, react: `import { Message } from '@kitn.ai/chat/react'; export function AssistantReply() { return ( { const { messageId, action } = e.detail; console.log(messageId, action); }} /> ); }`, vue: ` `, svelte: ` `, angular: `import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; @Component({ selector: 'app-reply', standalone: true, schemas: [CUSTOM_ELEMENTS_SCHEMA], template: \` \`, }) export class ReplyComponent { onAction(e: CustomEvent<{ messageId: string; action: string }>) { console.log(e.detail.messageId, e.detail.action); } }`, solid: `import { Message, MessageAvatar, MessageContent, MessageActions, Button, Tooltip } from '@kitn.ai/chat'; import { Copy, ThumbsUp, ThumbsDown, RefreshCw } from 'lucide-solid'; export function AssistantReply() { return ( {/* group + group-hover reveals the bar on row hover */}
${REPLY}
); }`, }, }; /** Always Visible Actions — bar always shown; custom actions via descriptor objects. */ const alwaysVisible: StoryUsage = { intro: "Keep the bar always visible (the default). Declare each button as a `` child — built-in-style (copy/like/…) and custom (share/bookmark) are all just `` elements, and `` fires `messageaction` with the id. (React passes them as the `actions` array.)", snippets: { html: ` `, react: `import { Message } from '@kitn.ai/chat/react'; export function AssistantReply() { return ( console.log(e.detail)} /> ); }`, vue: ` `, svelte: ` console.log(e.detail)}> `, angular: `import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; @Component({ selector: 'app-reply', standalone: true, schemas: [CUSTOM_ELEMENTS_SCHEMA], template: \` \`, }) export class ReplyComponent { log(e: CustomEvent) { console.log(e.detail); } }`, solid: `import { Message, MessageAvatar, MessageContent, MessageActions, Button, Tooltip } from '@kitn.ai/chat'; import { Copy, ThumbsUp, ThumbsDown, RefreshCw, Share, Bookmark } from 'lucide-solid'; export function AssistantReply() { return (
${REPLY}
); }`, }, }; /** Copy with Confirmation — the copy action swaps to a check for 2s. */ const copyConfirm: StoryUsage = { intro: 'Listen for `messageaction` with `action: "copy"` and write to the clipboard yourself — `` only emits the event; it does not touch the clipboard. In SolidJS you can also swap the icon to a check for 2 seconds as a visual confirmation (see the Solid tab).', snippets: { html: ` `, react: `import { Message } from '@kitn.ai/chat/react'; const content = '${REPLY}'; export function AssistantReply() { return ( { if (e.detail.action === 'copy') navigator.clipboard.writeText(content); }} /> ); }`, vue: ` `, svelte: ` `, angular: `import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; @Component({ selector: 'app-reply', standalone: true, schemas: [CUSTOM_ELEMENTS_SCHEMA], template: \` \`, }) export class ReplyComponent { content = '${REPLY}'; onAction(e: CustomEvent<{ messageId: string; action: string }>) { if (e.detail.action === 'copy') navigator.clipboard.writeText(this.content); } }`, solid: `import { createSignal } from 'solid-js'; import { Message, MessageAvatar, MessageContent, MessageActions, Button, Tooltip } from '@kitn.ai/chat'; import { Copy, Check, ThumbsUp, ThumbsDown } from 'lucide-solid'; export function AssistantReply() { const [copied, setCopied] = createSignal(false); const copy = () => { setCopied(true); setTimeout(() => setCopied(false), 2000); }; return (
${REPLY}
); }`, }, }; /** Feedback Bar — the self-contained ask → optional detail → thanks flow. */ const feedbackBar: StoryUsage = { intro: 'Ask for feedback under a reply. `` owns the whole flow — it asks, optionally collects a category + comment on a not-helpful vote (`collect-detail`), then confirms with a thank-you **in place** (it does not disappear on a vote; only `close` removes it). It fires `feedback` (`{ value }`), `feedbackdetail` (`{ value, category?, comment? }`), and `close`.', snippets: { html: ` `, react: `import { FeedbackBar } from '@kitn.ai/chat/react'; console.log(e.detail.value)} onFeedbackDetail={(e) => console.log(e.detail)} // { value, category?, comment? } onClose={() => {/* dismiss */}} />`, vue: ` `, svelte: ` `, angular: `import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; @Component({ selector: 'app-feedback', standalone: true, schemas: [CUSTOM_ELEMENTS_SCHEMA], template: \` \`, }) export class FeedbackComponent { categories = ['Inaccurate', 'Not helpful', 'Unsafe', 'Other']; onFeedback(e: CustomEvent<{ value: 'helpful' | 'not-helpful' }>) { console.log(e.detail.value); } onDetail(e: CustomEvent<{ value: 'helpful' | 'not-helpful'; category?: string; comment?: string }>) { console.log(e.detail); } }`, solid: `import { createSignal, Show } from 'solid-js'; import { Message, MessageAvatar, MessageContent, FeedbackBar } from '@kitn.ai/chat'; export function AssistantReply() { const [show, setShow] = createSignal(true); return (
${REPLY} console.log(value)} onSubmitDetail={(d) => console.log(d)} onClose={() => setShow(false)} />
); }`, }, }; /** Full Example — all stories combined: avatar + markdown + built-in/custom actions * + copy-to-clipboard with confirmation + a Feedback Bar. */ const fullExample: StoryUsage = { intro: 'Every feature combined: avatar, markdown content, the action bar (copy/regenerate plus custom **Share**/**Bookmark** with tooltips), a copy→clipboard handler with visual confirmation, and a **Feedback Bar** below. Like/dislike are omitted since the Feedback Bar covers that. Icon-only buttons get tooltips automatically; override the text with a `tooltip` field on custom actions. In SolidJS wrap each button with `` (see the Solid tab).', snippets: { html: `
Share Bookmark
`, react: `import { useState } from 'react'; import { Message, FeedbackBar } from '@kitn.ai/chat/react'; export function AssistantReply() { const [showFeedback, setShowFeedback] = useState(true); const content = 'Use anyhow::Result for apps and thiserror for libraries.'; return (
{ if (e.detail.action === 'copy') navigator.clipboard.writeText(content); }} /> {showFeedback && ( setShowFeedback(false)} /> )}
); }`, vue: ` `, svelte: `
Share Bookmark {#if showFeedback} (showFeedback = false)} /> {/if}
`, angular: `import { Component, CUSTOM_ELEMENTS_SCHEMA, signal } from '@angular/core'; @Component({ selector: 'app-reply', standalone: true, schemas: [CUSTOM_ELEMENTS_SCHEMA], template: \`
Share Bookmark @if (showFeedback()) { }
\`, }) export class ReplyComponent { showFeedback = signal(true); content = 'Use anyhow::Result for apps and thiserror for libraries.'; onAction(e: CustomEvent<{ messageId: string; action: string }>) { if (e.detail.action === 'copy') navigator.clipboard.writeText(this.content); } }`, solid: `import { createSignal, Show } from 'solid-js'; import { Message, MessageAvatar, MessageContent, MessageActions, FeedbackBar, Button, Tooltip } from '@kitn.ai/chat'; import { Copy, Check, RefreshCw, Share, Bookmark } from 'lucide-solid'; export function AssistantReply() { const content = 'Use anyhow::Result for apps and thiserror for libraries.'; const [copied, setCopied] = createSignal(false); const [showFeedback, setShowFeedback] = createSignal(true); const handleCopy = () => { navigator.clipboard.writeText(content); setCopied(true); setTimeout(() => setCopied(false), 2000); }; return (
{content} setShowFeedback(false)} />
); }`, }, }; /** * Example: Message Actions — copy / like / dislike / regenerate (and a feedback * bar) on an assistant message. Per-story: the Usage tab shows the snippet for * the story you're on; the example-level fields below are the fallback. */ const messageActions: ExampleUsage = { title: 'Examples/Message Actions', ...hover, // example-level fallback = the headline "Actions on Hover" stories: { 'Actions on Hover': hover, 'Always Visible Actions': alwaysVisible, 'Copy with Confirmation': copyConfirm, 'Feedback Bar': feedbackBar, 'Full Example': fullExample, }, }; export default messageActions;