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-empty': JSX.HTMLAttributes; } } } const HTML_SNIPPET = ` `; const meta = { title: 'Components/Empty', tags: ['autodocs'], argTypes: argTypesFor('kc-empty'), parameters: { layout: 'fullscreen', docs: { description: specDescription('kc-empty', [ '`` is the framework-agnostic **web component** for an empty-state block — an icon, a title, a description, and actions — isolated in **Shadow DOM**.', '**When to use:** placeholder UI for an empty list/thread in a non-Solid app. In SolidJS, compose the `Empty*` primitives.', '**Placement:** filling the main content area where a conversation list or message thread would appear; give it (or its parent) a height so the centered layout renders correctly.', "**How to use:** register once with `import '@kitn.ai/chat/elements'`, set `empty-title` (note `empty-title`, not `title`) and `description` via attributes, and use the **slots** (\"Route 2\") to project your own icon (`slot=\"media\"`) and actions (the default slot).", 'See the **Code** tab for HTML usage.', ]), }, }, } satisfies Meta; export default meta; type Story = StoryObj; /** Render the actual `` custom element with slotted children. */ function EmptyElement() { let el: HTMLElement | undefined; onMount(() => { if (!el) return; el.setAttribute('empty-title', 'No conversations yet'); el.setAttribute('description', 'Start a new chat to see it appear here.'); }); return ( (el = e as HTMLElement)} style={{ display: 'block', padding: '24px' }}> {/* Slotted actions are light DOM — style them with the host page's own CSS. Here a ghost "+ New chat" button, styled inline so it renders correctly in any context (mirrors the composable example's pill-btn). */} ); } /** An empty state with a slotted icon and an action button. */ export const Default: Story = { render: () => , parameters: { docs: { source: { code: HTML_SNIPPET, language: 'html' } } }, };