import type { Meta, StoryObj } from 'storybook-solidjs-vite'; import { onMount } from 'solid-js'; import './register'; // side effect: registers the custom elements import { argTypesFor, specDescription } from '../stories/docs/element-controls'; // The web components are custom DOM elements, so declare the tags for JSX. declare module 'solid-js' { // eslint-disable-next-line @typescript-eslint/no-namespace namespace JSX { interface IntrinsicElements { 'kc-voice-input': JSX.HTMLAttributes & { disabled?: boolean | string; }; } } } /** Render `` with a stub `transcribe` function-property. */ function VoiceElement(props: { disabled?: boolean }) { let el: (HTMLElement & { transcribe?: (audio: Blob) => Promise }) | undefined; onMount(() => { if (!el) return; // transcribe MUST be set as a JS property — a value-returning callback // can't be modelled as an attribute. el.transcribe = async () => { await new Promise((r) => setTimeout(r, 400)); return 'transcribed text'; }; el.addEventListener('kc-transcription', (e) => { const ev = e as CustomEvent<{ text: string }>; console.log('kc-transcription', ev.detail.text); }); }); return ( (el = e as HTMLElement)} disabled={props.disabled ? true : undefined} style={{ display: 'inline-block', padding: '40px' }} /> ); } const HTML_SNIPPET = ` `; const meta = { title: 'Components/VoiceInput', tags: ['autodocs'], argTypes: argTypesFor('kc-voice-input'), parameters: { layout: 'fullscreen', docs: { description: specDescription('kc-voice-input', [ '`` is the framework-agnostic **web component** for a mic button that records and transcribes audio — isolated in **Shadow DOM**. It is the canonical **function-property** element.', '**When to use:** adding voice dictation to an input in a non-Solid app. In SolidJS, use the `VoiceInput` primitive.', '**Placement:** inline beside the prompt input field or as an icon button in the composer toolbar; renders as an inline-block sized to the mic button.', "**How to use:** register once with `import '@kitn.ai/chat/elements'`, then set the `transcribe` **function property** (`el.transcribe = async blob => '...'`) — a value-returning callback can't be modelled as an event. It also emits `kc-audio-captured` (raw blob) and `kc-transcription` (text) **CustomEvents**.", 'See the **Code** tab for HTML usage.', ]), }, }, } satisfies Meta; export default meta; type Story = StoryObj; /** A working mic button wired to a stub transcriber. */ export const Default: Story = { render: () => , parameters: { docs: { source: { code: HTML_SNIPPET, language: 'html' } } }, }; /** A disabled mic button (non-interactive). */ export const Disabled: Story = { render: () => , };