@kitnai/chat 0.6.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -9
- package/dist/custom-elements.json +1676 -881
- package/dist/kitn-chat.es.js +36 -36
- package/dist/llms/llms-full.txt +316 -155
- package/dist/llms/llms.txt +18 -18
- package/dist/schemas/card-envelope.schema.json +14 -0
- package/dist/schemas/card-event.schema.json +12 -0
- package/dist/schemas/confirm.schema.json +65 -0
- package/dist/schemas/embed.schema.json +65 -0
- package/dist/schemas/form.result.schema.json +7 -0
- package/dist/schemas/form.schema.json +33 -0
- package/dist/schemas/link.schema.json +56 -0
- package/dist/schemas/task-list.result.schema.json +16 -0
- package/dist/schemas/task-list.schema.json +78 -0
- package/dist/theme.tokens.css +65 -65
- package/dist/tsx-B8rCNbgL.js +1 -0
- package/dist/typescript-RycA9KXf.js +1 -0
- package/frameworks/react/index.tsx +382 -193
- package/frameworks/react/runtime.tsx +2 -2
- package/llms-full.txt +316 -155
- package/llms.txt +18 -18
- package/package.json +5 -2
- package/src/components/artifact.stories.tsx +138 -0
- package/src/components/artifact.tsx +581 -0
- package/src/components/attachments.stories.tsx +7 -8
- package/src/components/attachments.tsx +2 -2
- package/src/components/card.tsx +110 -0
- package/src/components/chain-of-thought.stories.tsx +7 -8
- package/src/components/chat-container.stories.tsx +7 -8
- package/src/components/chat-container.tsx +4 -0
- package/src/components/checkpoint.stories.tsx +7 -8
- package/src/components/code-block.stories.tsx +8 -9
- package/src/components/component-meta.json +3411 -0
- package/src/components/confirm-card.stories.tsx +74 -0
- package/src/components/confirm-card.tsx +299 -0
- package/src/components/context.stories.tsx +7 -8
- package/src/components/conversation-item.stories.tsx +7 -8
- package/src/components/conversation-item.tsx +2 -2
- package/src/components/conversation-list.stories.tsx +7 -8
- package/src/components/conversation-list.tsx +1 -1
- package/src/components/embed.tsx +196 -0
- package/src/components/empty.stories.tsx +8 -9
- package/src/components/feedback-bar.stories.tsx +7 -8
- package/src/components/file-tree.stories.tsx +73 -0
- package/src/components/file-tree.tsx +383 -0
- package/src/components/file-upload.stories.tsx +7 -8
- package/src/components/form-widgets.tsx +461 -0
- package/src/components/form.tsx +796 -0
- package/src/components/image.stories.tsx +7 -8
- package/src/components/link-card.tsx +194 -0
- package/src/components/loader.stories.tsx +7 -8
- package/src/components/markdown.stories.tsx +7 -8
- package/src/components/message-narrow.stories.tsx +12 -13
- package/src/components/message-skills.stories.tsx +16 -17
- package/src/components/message.stories.tsx +17 -18
- package/src/components/model-switcher.stories.tsx +7 -8
- package/src/components/prompt-input.stories.tsx +8 -9
- package/src/components/prompt-suggestion.stories.tsx +7 -8
- package/src/components/prompt-suggestion.tsx +3 -3
- package/src/components/reasoning.stories.tsx +7 -8
- package/src/components/scroll-button.stories.tsx +7 -8
- package/src/components/slash-command.stories.tsx +8 -9
- package/src/components/slash-command.tsx +2 -2
- package/src/components/source.stories.tsx +7 -8
- package/src/components/source.tsx +1 -1
- package/src/components/task-list-card.stories.tsx +78 -0
- package/src/components/task-list-card.tsx +388 -0
- package/src/components/text-shimmer.stories.tsx +7 -8
- package/src/components/thinking-bar.stories.tsx +7 -8
- package/src/components/tool.stories.tsx +7 -8
- package/src/components/tool.tsx +2 -2
- package/src/components/voice-input.stories.tsx +7 -8
- package/src/elements/artifact.stories.tsx +291 -0
- package/src/elements/artifact.tsx +72 -0
- package/src/elements/{kitn-attachments.stories.tsx → attachments.stories.tsx} +11 -11
- package/src/elements/attachments.tsx +4 -4
- package/src/elements/card.stories.tsx +118 -0
- package/src/elements/card.tsx +40 -0
- package/src/elements/catalog.stories.tsx +491 -0
- package/src/elements/{kitn-chain-of-thought.stories.tsx → chain-of-thought.stories.tsx} +13 -13
- package/src/elements/chain-of-thought.tsx +3 -3
- package/src/elements/{kitn-chat-scope-picker.stories.tsx → chat-scope-picker.stories.tsx} +10 -10
- package/src/elements/chat-scope-picker.tsx +4 -4
- package/src/elements/{kitn-chat-workspace.stories.tsx → chat-workspace.stories.tsx} +71 -29
- package/src/elements/chat-workspace.tsx +29 -3
- package/src/elements/{kitn-chat.stories.tsx → chat.stories.tsx} +61 -16
- package/src/elements/chat.tsx +23 -2
- package/src/elements/{kitn-checkpoint.stories.tsx → checkpoint.stories.tsx} +11 -11
- package/src/elements/checkpoint.tsx +4 -4
- package/src/elements/{kitn-code-block.stories.tsx → code-block.stories.tsx} +10 -10
- package/src/elements/code-block.tsx +3 -3
- package/src/elements/compiled.css +1 -1
- package/src/elements/composed-shell.stories.tsx +316 -0
- package/src/elements/confirm-card.stories.tsx +186 -0
- package/src/elements/confirm-card.tsx +45 -0
- package/src/elements/{kitn-context-meter.stories.tsx → context-meter.stories.tsx} +10 -10
- package/src/elements/context-meter.tsx +3 -3
- package/src/elements/{kitn-conversation-list.stories.tsx → conversation-list.stories.tsx} +35 -22
- package/src/elements/conversation-list.tsx +11 -2
- package/src/elements/css.ts +1 -1
- package/src/elements/define.tsx +10 -10
- package/src/elements/element-meta.json +2649 -0
- package/src/elements/element-types.d.ts +251 -125
- package/src/elements/embed.stories.tsx +197 -0
- package/src/elements/embed.tsx +35 -0
- package/src/elements/{kitn-empty.stories.tsx → empty.stories.tsx} +12 -12
- package/src/elements/empty.tsx +3 -3
- package/src/elements/{kitn-feedback-bar.stories.tsx → feedback-bar.stories.tsx} +11 -11
- package/src/elements/feedback-bar.tsx +4 -4
- package/src/elements/file-tree.stories.tsx +133 -0
- package/src/elements/file-tree.tsx +52 -0
- package/src/elements/{kitn-file-upload.stories.tsx → file-upload.stories.tsx} +12 -12
- package/src/elements/file-upload.tsx +4 -4
- package/src/elements/form.stories.tsx +204 -0
- package/src/elements/form.tsx +37 -0
- package/src/elements/{kitn-image.stories.tsx → image.stories.tsx} +10 -10
- package/src/elements/image.tsx +3 -3
- package/src/elements/link-card.stories.tsx +193 -0
- package/src/elements/link-card.tsx +34 -0
- package/src/elements/{kitn-loader.stories.tsx → loader.stories.tsx} +11 -11
- package/src/elements/loader.tsx +3 -3
- package/src/elements/{kitn-markdown.stories.tsx → markdown.stories.tsx} +10 -10
- package/src/elements/markdown.tsx +3 -3
- package/src/elements/{kitn-message-skills.stories.tsx → message-skills.stories.tsx} +10 -10
- package/src/elements/message-skills.tsx +3 -3
- package/src/elements/{kitn-message.stories.tsx → message.stories.tsx} +12 -12
- package/src/elements/message.tsx +5 -5
- package/src/elements/{kitn-model-switcher.stories.tsx → model-switcher.stories.tsx} +10 -10
- package/src/elements/model-switcher.tsx +5 -5
- package/src/elements/{kitn-prompt-input.stories.tsx → prompt-input.stories.tsx} +41 -19
- package/src/elements/prompt-input.tsx +5 -5
- package/src/elements/{kitn-prompt-suggestions.stories.tsx → prompt-suggestions.stories.tsx} +13 -13
- package/src/elements/prompt-suggestions.tsx +4 -4
- package/src/elements/{kitn-reasoning.stories.tsx → reasoning.stories.tsx} +10 -10
- package/src/elements/reasoning.tsx +4 -4
- package/src/elements/register.ts +11 -1
- package/src/elements/resizable.stories.tsx +200 -0
- package/src/elements/resizable.tsx +264 -0
- package/src/elements/{kitn-response-stream.stories.tsx → response-stream.stories.tsx} +10 -10
- package/src/elements/response-stream.tsx +4 -4
- package/src/elements/{kitn-source-list.stories.tsx → source-list.stories.tsx} +11 -11
- package/src/elements/{kitn-source.stories.tsx → source.stories.tsx} +12 -12
- package/src/elements/source.tsx +5 -5
- package/src/elements/styles.css +140 -1
- package/src/elements/task-list-card.stories.tsx +194 -0
- package/src/elements/task-list-card.tsx +40 -0
- package/src/elements/{kitn-text-shimmer.stories.tsx → text-shimmer.stories.tsx} +10 -10
- package/src/elements/text-shimmer.tsx +3 -3
- package/src/elements/{kitn-thinking-bar.stories.tsx → thinking-bar.stories.tsx} +11 -11
- package/src/elements/thinking-bar.tsx +5 -5
- package/src/elements/{kitn-tool.stories.tsx → tool.stories.tsx} +10 -10
- package/src/elements/tool.tsx +3 -3
- package/src/elements/{kitn-voice-input.stories.tsx → voice-input.stories.tsx} +10 -10
- package/src/elements/voice-input.tsx +4 -4
- package/src/index.ts +94 -2
- package/src/primitives/card-contract.ts +60 -0
- package/src/primitives/card-host.tsx +35 -0
- package/src/primitives/card-routing.ts +79 -0
- package/src/primitives/card-schemas/card-envelope.schema.json +14 -0
- package/src/primitives/card-schemas/card-event.schema.json +12 -0
- package/src/primitives/card-schemas/confirm.schema.json +65 -0
- package/src/primitives/card-schemas/embed.schema.json +65 -0
- package/src/primitives/card-schemas/form.result.schema.json +7 -0
- package/src/primitives/card-schemas/form.schema.json +33 -0
- package/src/primitives/card-schemas/link.schema.json +56 -0
- package/src/primitives/card-schemas/task-list.result.schema.json +16 -0
- package/src/primitives/card-schemas/task-list.schema.json +78 -0
- package/src/primitives/card-validate.ts +95 -0
- package/src/primitives/embed-providers.ts +254 -0
- package/src/primitives/highlighter.ts +4 -0
- package/src/primitives/link-preview.ts +87 -0
- package/src/primitives/pdf-preview.ts +121 -0
- package/src/stories/chat-panel-layout.stories.tsx +2 -1
- package/src/stories/chat-scene.tsx +22 -21
- package/src/stories/checkpoint-restore.stories.tsx +10 -10
- package/src/stories/conversation-with-reasoning.stories.tsx +4 -4
- package/src/stories/conversation-with-sources.stories.tsx +7 -7
- package/src/stories/docs/Accessibility.mdx +2 -2
- package/src/stories/docs/ForAIAgents.mdx +3 -3
- package/src/stories/docs/GettingStarted.mdx +2 -2
- package/src/stories/docs/Installation.mdx +2 -2
- package/src/stories/docs/Integrations.mdx +29 -29
- package/src/stories/docs/Introduction.mdx +3 -3
- package/src/stories/docs/Theming.mdx +2 -2
- package/src/stories/docs/element-controls.ts +60 -0
- package/src/stories/docs/theme-editor/theme-editor.tsx +1 -0
- package/src/stories/examples/ChoosingComponents.mdx +94 -0
- package/src/stories/examples/sample-data.ts +79 -0
- package/src/stories/message-actions.stories.tsx +13 -13
- package/src/stories/pattern-centered-conversation.stories.tsx +3 -3
- package/src/stories/pattern-docked-widget.stories.tsx +1 -1
- package/src/stories/pattern-empty-state.stories.tsx +3 -3
- package/src/stories/prompt-input-variants.stories.tsx +13 -13
- package/src/stories/streaming-response.stories.tsx +3 -3
- package/src/stories/typography.stories.tsx +4 -4
- package/src/ui/avatar.stories.tsx +7 -8
- package/src/ui/badge.stories.tsx +7 -8
- package/src/ui/button.stories.tsx +8 -9
- package/src/ui/button.tsx +1 -0
- package/src/ui/collapsible.stories.tsx +6 -7
- package/src/ui/dropdown.stories.tsx +6 -7
- package/src/ui/hover-card.stories.tsx +6 -7
- package/src/ui/resizable.stories.tsx +74 -9
- package/src/ui/resizable.tsx +351 -71
- package/src/ui/scroll-area.stories.tsx +6 -7
- package/src/ui/scroll-area.tsx +3 -1
- package/src/ui/separator.stories.tsx +7 -8
- package/src/ui/skeleton.stories.tsx +7 -8
- package/src/ui/textarea.stories.tsx +6 -7
- package/src/ui/tooltip.stories.tsx +8 -9
- package/theme.css +65 -65
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from 'storybook-solidjs-vite';
|
|
2
2
|
import './register'; // side effect: registers the custom elements
|
|
3
|
+
import { argTypesFor, specDescription } from '../stories/docs/element-controls';
|
|
3
4
|
|
|
4
5
|
// The web components are custom DOM elements, so declare the tags for JSX.
|
|
5
6
|
declare module 'solid-js' {
|
|
6
7
|
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
7
8
|
namespace JSX {
|
|
8
9
|
interface IntrinsicElements {
|
|
9
|
-
'
|
|
10
|
+
'kc-loader': JSX.HTMLAttributes<HTMLElement> & {
|
|
10
11
|
variant?: string;
|
|
11
12
|
size?: string;
|
|
12
13
|
text?: string;
|
|
@@ -16,26 +17,25 @@ declare module 'solid-js' {
|
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
const HTML_SNIPPET = `<!-- Works in any framework or plain HTML -->
|
|
19
|
-
<
|
|
20
|
+
<kc-loader variant="dots" size="md"></kc-loader>
|
|
20
21
|
|
|
21
22
|
<script type="module">
|
|
22
23
|
import '@kitnai/chat/elements'; // registers the custom elements
|
|
23
24
|
</script>`;
|
|
24
25
|
|
|
25
26
|
const meta = {
|
|
26
|
-
title: 'Web Components/
|
|
27
|
+
title: 'Web Components/kc-loader',
|
|
27
28
|
tags: ['autodocs'],
|
|
29
|
+
argTypes: argTypesFor('kc-loader'),
|
|
28
30
|
parameters: {
|
|
29
31
|
layout: 'fullscreen',
|
|
30
32
|
docs: {
|
|
31
|
-
description:
|
|
32
|
-
|
|
33
|
-
'`<kitn-loader>` is the framework-agnostic **web component** for an animated busy indicator — a dozen styles (circular, dots, wave, bars, text-shimmer, …) selected via the `variant` attribute, isolated in **Shadow DOM**.',
|
|
33
|
+
description: specDescription('kc-loader', [
|
|
34
|
+
'`<kc-loader>` is the framework-agnostic **web component** for an animated busy indicator — a dozen styles (circular, dots, wave, bars, text-shimmer, …) selected via the `variant` attribute, isolated in **Shadow DOM**.',
|
|
34
35
|
'**When to use:** showing a small "working" indicator anywhere outside the chat thread (toolbars, buttons, panels). In SolidJS, use the `Loader` primitive directly.',
|
|
35
36
|
"**How to use:** register once with `import '@kitnai/chat/elements'`, then set `variant`, `size`, and (for text variants) `text` as plain HTML attributes.",
|
|
36
37
|
'See the **Code** tab for HTML usage.',
|
|
37
|
-
]
|
|
38
|
-
},
|
|
38
|
+
]),
|
|
39
39
|
},
|
|
40
40
|
},
|
|
41
41
|
} satisfies Meta;
|
|
@@ -52,7 +52,7 @@ const VARIANTS = [
|
|
|
52
52
|
export const Default: Story = {
|
|
53
53
|
render: () => (
|
|
54
54
|
<div style={{ padding: '24px' }}>
|
|
55
|
-
<
|
|
55
|
+
<kc-loader variant="circular" size="md" />
|
|
56
56
|
</div>
|
|
57
57
|
),
|
|
58
58
|
parameters: { docs: { source: { code: HTML_SNIPPET, language: 'html' } } },
|
|
@@ -64,7 +64,7 @@ export const AllVariants: Story = {
|
|
|
64
64
|
<div style={{ display: 'flex', 'flex-wrap': 'wrap', gap: '32px', 'align-items': 'center', padding: '24px' }}>
|
|
65
65
|
{VARIANTS.map((v) => (
|
|
66
66
|
<div style={{ display: 'flex', 'flex-direction': 'column', 'align-items': 'center', gap: '8px', 'min-width': '90px' }}>
|
|
67
|
-
<
|
|
67
|
+
<kc-loader variant={v} size="md" text="Loading" />
|
|
68
68
|
<code style={{ 'font-size': '11px', opacity: 0.6 }}>{v}</code>
|
|
69
69
|
</div>
|
|
70
70
|
))}
|
|
@@ -78,7 +78,7 @@ export const Sizes: Story = {
|
|
|
78
78
|
<div style={{ display: 'flex', gap: '32px', 'align-items': 'center', padding: '24px' }}>
|
|
79
79
|
{['sm', 'md', 'lg'].map((s) => (
|
|
80
80
|
<div style={{ display: 'flex', 'flex-direction': 'column', 'align-items': 'center', gap: '8px' }}>
|
|
81
|
-
<
|
|
81
|
+
<kc-loader variant="dots" size={s} />
|
|
82
82
|
<code style={{ 'font-size': '11px', opacity: 0.6 }}>{s}</code>
|
|
83
83
|
</div>
|
|
84
84
|
))}
|
package/src/elements/loader.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { defineWebComponent } from './define';
|
|
2
2
|
import { Loader, type LoaderVariant, type LoaderSize } from '../components/loader';
|
|
3
3
|
|
|
4
4
|
interface Props extends Record<string, unknown> {
|
|
@@ -13,10 +13,10 @@ interface Props extends Record<string, unknown> {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
|
-
* `<
|
|
16
|
+
* `<kc-loader>` — an animated loader. `variant` selects the style (circular,
|
|
17
17
|
* dots, wave, text-shimmer, …); `size` and `text` are attributes.
|
|
18
18
|
*/
|
|
19
|
-
|
|
19
|
+
defineWebComponent<Props>('kc-loader', {
|
|
20
20
|
variant: 'circular',
|
|
21
21
|
size: 'md',
|
|
22
22
|
text: undefined,
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from 'storybook-solidjs-vite';
|
|
2
2
|
import { onMount } from 'solid-js';
|
|
3
3
|
import './register'; // side effect: registers the custom elements
|
|
4
|
+
import { argTypesFor, specDescription } from '../stories/docs/element-controls';
|
|
4
5
|
|
|
5
6
|
// The web components are custom DOM elements, so declare the tags for JSX.
|
|
6
7
|
declare module 'solid-js' {
|
|
7
8
|
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
8
9
|
namespace JSX {
|
|
9
10
|
interface IntrinsicElements {
|
|
10
|
-
'
|
|
11
|
+
'kc-markdown': JSX.HTMLAttributes<HTMLElement>;
|
|
11
12
|
}
|
|
12
13
|
}
|
|
13
14
|
}
|
|
@@ -25,19 +26,19 @@ export function add(a: number, b: number): number {
|
|
|
25
26
|
}
|
|
26
27
|
\`\`\``;
|
|
27
28
|
|
|
28
|
-
/** Render the actual `<
|
|
29
|
+
/** Render the actual `<kc-markdown>` custom element with a `content` property. */
|
|
29
30
|
function MarkdownElement(props: { content: string }) {
|
|
30
31
|
let el: (HTMLElement & { content?: string }) | undefined;
|
|
31
32
|
onMount(() => {
|
|
32
33
|
if (el) el.content = props.content;
|
|
33
34
|
});
|
|
34
35
|
return (
|
|
35
|
-
<
|
|
36
|
+
<kc-markdown ref={(e) => (el = e as HTMLElement)} style={{ display: 'block', padding: '16px', 'max-width': '720px' }} />
|
|
36
37
|
);
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
const HTML_SNIPPET = `<!-- Works in any framework or plain HTML -->
|
|
40
|
-
<
|
|
41
|
+
<kc-markdown id="md" code-theme="github-dark-dimmed"></kc-markdown>
|
|
41
42
|
|
|
42
43
|
<script type="module">
|
|
43
44
|
import '@kitnai/chat/elements'; // registers the custom elements
|
|
@@ -48,19 +49,18 @@ const HTML_SNIPPET = `<!-- Works in any framework or plain HTML -->
|
|
|
48
49
|
</script>`;
|
|
49
50
|
|
|
50
51
|
const meta = {
|
|
51
|
-
title: 'Web Components/
|
|
52
|
+
title: 'Web Components/kc-markdown',
|
|
52
53
|
tags: ['autodocs'],
|
|
54
|
+
argTypes: argTypesFor('kc-markdown'),
|
|
53
55
|
parameters: {
|
|
54
56
|
layout: 'fullscreen',
|
|
55
57
|
docs: {
|
|
56
|
-
description:
|
|
57
|
-
|
|
58
|
-
'`<kitn-markdown>` is the framework-agnostic **web component** that renders a markdown string (with fenced-code syntax highlighting via Shiki) as a standalone element, isolated in **Shadow DOM**.',
|
|
58
|
+
description: specDescription('kc-markdown', [
|
|
59
|
+
'`<kc-markdown>` is the framework-agnostic **web component** that renders a markdown string (with fenced-code syntax highlighting via Shiki) as a standalone element, isolated in **Shadow DOM**.',
|
|
59
60
|
'**When to use:** showing model output or any markdown in a non-Solid app without pulling in a markdown stack. In SolidJS, use the `Markdown` primitive directly.',
|
|
60
61
|
"**How to use:** register once with `import '@kitnai/chat/elements'`, set the source via the `content` **property** (`el.content = '...'`), and tune rendering with the `prose-size`, `code-theme`, and `code-highlight` attributes.",
|
|
61
62
|
'See the **Code** tab for HTML usage.',
|
|
62
|
-
]
|
|
63
|
-
},
|
|
63
|
+
]),
|
|
64
64
|
},
|
|
65
65
|
},
|
|
66
66
|
} satisfies Meta;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { defineWebComponent } from './define';
|
|
2
2
|
import { Markdown } from '../components/markdown';
|
|
3
3
|
import { ChatConfig, useChatConfig, type ProseSize } from '../primitives/chat-config';
|
|
4
4
|
|
|
@@ -14,11 +14,11 @@ interface Props extends Record<string, unknown> {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
|
-
* `<
|
|
17
|
+
* `<kc-markdown>` — renders markdown (with fenced-code syntax highlighting) as
|
|
18
18
|
* a standalone element. Content via the `content` property; sizing/highlighting
|
|
19
19
|
* via attributes.
|
|
20
20
|
*/
|
|
21
|
-
|
|
21
|
+
defineWebComponent<Props>('kc-markdown', {
|
|
22
22
|
content: '',
|
|
23
23
|
proseSize: 'sm',
|
|
24
24
|
codeTheme: 'github-dark-dimmed',
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from 'storybook-solidjs-vite';
|
|
2
2
|
import { onMount } from 'solid-js';
|
|
3
3
|
import './register'; // side effect: registers the custom elements
|
|
4
|
+
import { argTypesFor, specDescription } from '../stories/docs/element-controls';
|
|
4
5
|
|
|
5
6
|
// The web components are custom DOM elements, so declare the tags for JSX.
|
|
6
7
|
declare module 'solid-js' {
|
|
7
8
|
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
8
9
|
namespace JSX {
|
|
9
10
|
interface IntrinsicElements {
|
|
10
|
-
'
|
|
11
|
+
'kc-skills': JSX.HTMLAttributes<HTMLElement>;
|
|
11
12
|
}
|
|
12
13
|
}
|
|
13
14
|
}
|
|
@@ -22,19 +23,19 @@ const sampleSkills: Skill[] = [
|
|
|
22
23
|
{ id: 's2', name: 'code' },
|
|
23
24
|
];
|
|
24
25
|
|
|
25
|
-
/** Render the actual `<
|
|
26
|
+
/** Render the actual `<kc-skills>` custom element with a `skills` property. */
|
|
26
27
|
function MessageSkillsElement(props: { skills: Skill[] }) {
|
|
27
28
|
let el: (HTMLElement & { skills?: Skill[] }) | undefined;
|
|
28
29
|
onMount(() => {
|
|
29
30
|
if (el) el.skills = props.skills;
|
|
30
31
|
});
|
|
31
32
|
return (
|
|
32
|
-
<
|
|
33
|
+
<kc-skills ref={(e) => (el = e as HTMLElement)} style={{ display: 'block', padding: '16px' }} />
|
|
33
34
|
);
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
const HTML_SNIPPET = `<!-- Works in any framework or plain HTML -->
|
|
37
|
-
<
|
|
38
|
+
<kc-skills id="skills"></kc-skills>
|
|
38
39
|
|
|
39
40
|
<script type="module">
|
|
40
41
|
import '@kitnai/chat/elements'; // registers the custom elements
|
|
@@ -47,19 +48,18 @@ const HTML_SNIPPET = `<!-- Works in any framework or plain HTML -->
|
|
|
47
48
|
</script>`;
|
|
48
49
|
|
|
49
50
|
const meta = {
|
|
50
|
-
title: 'Web Components/
|
|
51
|
+
title: 'Web Components/kc-skills',
|
|
51
52
|
tags: ['autodocs'],
|
|
53
|
+
argTypes: argTypesFor('kc-skills'),
|
|
52
54
|
parameters: {
|
|
53
55
|
layout: 'fullscreen',
|
|
54
56
|
docs: {
|
|
55
|
-
description:
|
|
56
|
-
|
|
57
|
-
'`<kitn-message-skills>` is the framework-agnostic **web component** that badges which skills were active for a message, isolated in **Shadow DOM**.',
|
|
57
|
+
description: specDescription('kc-skills', [
|
|
58
|
+
'`<kc-skills>` is the framework-agnostic **web component** that badges which skills were active for a message, isolated in **Shadow DOM**.',
|
|
58
59
|
'**When to use:** annotating a message row with the skills/tools it used, in a non-Solid app. In SolidJS, use the `MessageSkills` primitive directly.',
|
|
59
60
|
"**How to use:** register once with `import '@kitnai/chat/elements'`, then set the `skills` **property** to an array of `{ id, name }`.",
|
|
60
61
|
'See the **Code** tab for HTML usage.',
|
|
61
|
-
]
|
|
62
|
-
},
|
|
62
|
+
]),
|
|
63
63
|
},
|
|
64
64
|
},
|
|
65
65
|
} satisfies Meta;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { defineWebComponent } from './define';
|
|
2
2
|
import { MessageSkills } from '../components/message-skills';
|
|
3
3
|
|
|
4
4
|
interface Skill {
|
|
@@ -14,9 +14,9 @@ interface Props extends Record<string, unknown> {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
|
-
* `<
|
|
17
|
+
* `<kc-skills>` — badges showing which skills were active for a
|
|
18
18
|
* message. Data via the `skills` property.
|
|
19
19
|
*/
|
|
20
|
-
|
|
20
|
+
defineWebComponent<Props>('kc-skills', {
|
|
21
21
|
skills: [],
|
|
22
22
|
}, (props) => <MessageSkills skills={props.skills} />);
|
|
@@ -2,13 +2,14 @@ import type { Meta, StoryObj } from 'storybook-solidjs-vite';
|
|
|
2
2
|
import { onMount } from 'solid-js';
|
|
3
3
|
import './register'; // side effect: registers the custom elements
|
|
4
4
|
import type { ChatMessage } from './chat-types';
|
|
5
|
+
import { argTypesFor, specDescription } from '../stories/docs/element-controls';
|
|
5
6
|
|
|
6
7
|
// The web components are custom DOM elements, so declare the tags for JSX.
|
|
7
8
|
declare module 'solid-js' {
|
|
8
9
|
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
9
10
|
namespace JSX {
|
|
10
11
|
interface IntrinsicElements {
|
|
11
|
-
'
|
|
12
|
+
'kc-message': JSX.HTMLAttributes<HTMLElement>;
|
|
12
13
|
}
|
|
13
14
|
}
|
|
14
15
|
}
|
|
@@ -17,7 +18,7 @@ const assistantMessage: ChatMessage = {
|
|
|
17
18
|
id: 'm-a',
|
|
18
19
|
role: 'assistant',
|
|
19
20
|
content:
|
|
20
|
-
"Here's the plan, with a quick code sample:\n\n```js\nconst kit =
|
|
21
|
+
"Here's the plan, with a quick code sample:\n\n```js\nconst kit = useChat();\n```\n\nThat wires the kit into your component.",
|
|
21
22
|
reasoning: { text: 'The user wants X, so I should do Y then Z.', label: 'Reasoning' },
|
|
22
23
|
tools: [{ type: 'search', state: 'output-available', input: { query: 'kitn docs' }, output: { hits: 3 } }],
|
|
23
24
|
attachments: [
|
|
@@ -42,19 +43,19 @@ const userMessage: ChatMessage = {
|
|
|
42
43
|
content: 'How do I compose these myself?',
|
|
43
44
|
};
|
|
44
45
|
|
|
45
|
-
/** Render the actual `<
|
|
46
|
+
/** Render the actual `<kc-message>` custom element with a `message` property. */
|
|
46
47
|
function MessageElement(props: { message: ChatMessage }) {
|
|
47
48
|
let el: (HTMLElement & { message?: ChatMessage }) | undefined;
|
|
48
49
|
onMount(() => {
|
|
49
50
|
if (el) el.message = props.message;
|
|
50
51
|
});
|
|
51
52
|
return (
|
|
52
|
-
<
|
|
53
|
+
<kc-message ref={(e) => (el = e as HTMLElement)} style={{ display: 'block', padding: '16px', 'max-width': '720px' }} />
|
|
53
54
|
);
|
|
54
55
|
}
|
|
55
56
|
|
|
56
57
|
const HTML_SNIPPET = `<!-- Works in any framework or plain HTML -->
|
|
57
|
-
<
|
|
58
|
+
<kc-message id="msg" style="display:block;"></kc-message>
|
|
58
59
|
|
|
59
60
|
<script type="module">
|
|
60
61
|
import '@kitnai/chat/elements'; // registers the custom elements
|
|
@@ -62,7 +63,7 @@ const HTML_SNIPPET = `<!-- Works in any framework or plain HTML -->
|
|
|
62
63
|
const msg = document.getElementById('msg');
|
|
63
64
|
msg.message = {
|
|
64
65
|
id: 'm-a', role: 'assistant',
|
|
65
|
-
content: "Here's the plan:\\n\\n\\\`\\\`\\\`js\\nconst kit =
|
|
66
|
+
content: "Here's the plan:\\n\\n\\\`\\\`\\\`js\\nconst kit = useChat();\\n\\\`\\\`\\\`",
|
|
66
67
|
reasoning: { text: 'The user wants X, so I should do Y.' },
|
|
67
68
|
tools: [{ type: 'search', state: 'output-available', output: { hits: 3 } }],
|
|
68
69
|
actions: ['copy', 'like', 'dislike', 'regenerate'],
|
|
@@ -73,19 +74,18 @@ const HTML_SNIPPET = `<!-- Works in any framework or plain HTML -->
|
|
|
73
74
|
</script>`;
|
|
74
75
|
|
|
75
76
|
const meta = {
|
|
76
|
-
title: 'Web Components/
|
|
77
|
+
title: 'Web Components/kc-message',
|
|
77
78
|
tags: ['autodocs'],
|
|
79
|
+
argTypes: argTypesFor('kc-message'),
|
|
78
80
|
parameters: {
|
|
79
81
|
layout: 'fullscreen',
|
|
80
82
|
docs: {
|
|
81
|
-
description:
|
|
82
|
-
|
|
83
|
-
'`<kitn-message>` is the framework-agnostic **web component** for a single message row — markdown/plain content, an optional reasoning block, tool calls, attachments, and action buttons — all rendered from one `message` object (the same shape `<kitn-chat>` uses per message). It is the keystone of the "compose your own message list" pattern, isolated in **Shadow DOM**.',
|
|
83
|
+
description: specDescription('kc-message', [
|
|
84
|
+
'`<kc-message>` is the framework-agnostic **web component** for a single message row — markdown/plain content, an optional reasoning block, tool calls, attachments, and action buttons — all rendered from one `message` object (the same shape `<kc-chat>` uses per message). It is the keystone of the "compose your own message list" pattern, isolated in **Shadow DOM**.',
|
|
84
85
|
"**When to use:** building a custom message thread in a non-Solid app, or anywhere you want to lay out the list yourself but keep the kit's rich message rendering. In SolidJS, compose the `Message` primitives for finer control.",
|
|
85
86
|
"**How to use:** register once with `import '@kitnai/chat/elements'`, set the whole row via the `message` **property** (`el.message = {...}`), and listen for the `messageaction` **CustomEvent** for action-button clicks. For simple cases, set `role` + `content` attributes instead of a full object.",
|
|
86
87
|
'See the **Code** tab for HTML usage.',
|
|
87
|
-
]
|
|
88
|
-
},
|
|
88
|
+
]),
|
|
89
89
|
},
|
|
90
90
|
},
|
|
91
91
|
} satisfies Meta;
|
package/src/elements/message.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { For, Show, type Component } from 'solid-js';
|
|
2
|
-
import {
|
|
2
|
+
import { defineWebComponent } from './define';
|
|
3
3
|
import { ChatConfig, useChatConfig, type ProseSize } from '../primitives/chat-config';
|
|
4
4
|
import { Message, MessageContent, MessageActions } from '../components/message';
|
|
5
5
|
import { Reasoning, ReasoningTrigger, ReasoningContent } from '../components/reasoning';
|
|
@@ -26,7 +26,7 @@ interface Props extends Record<string, unknown> {
|
|
|
26
26
|
codeHighlight?: boolean;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
/** Events fired by `<
|
|
29
|
+
/** Events fired by `<kc-message>`. */
|
|
30
30
|
interface Events {
|
|
31
31
|
/** An action button was clicked. */
|
|
32
32
|
messageaction: { messageId: string; action: ChatMessageAction };
|
|
@@ -40,12 +40,12 @@ const ACTION_ICON: Record<ChatMessageAction, Component<{ class?: string }>> = {
|
|
|
40
40
|
};
|
|
41
41
|
|
|
42
42
|
/**
|
|
43
|
-
* `<
|
|
43
|
+
* `<kc-message>` — a single message row: markdown/plain content, reasoning,
|
|
44
44
|
* tool calls, attachments, and action buttons, rendered from one `message`
|
|
45
|
-
* object (the same shape `<
|
|
45
|
+
* object (the same shape `<kc-chat>` uses per message). The keystone of the
|
|
46
46
|
* "compose your own message list" pattern. Emits `messageaction`.
|
|
47
47
|
*/
|
|
48
|
-
|
|
48
|
+
defineWebComponent<Props, Events>('kc-message', {
|
|
49
49
|
message: undefined,
|
|
50
50
|
role: 'assistant',
|
|
51
51
|
content: undefined,
|
|
@@ -2,13 +2,14 @@ import type { Meta, StoryObj } from 'storybook-solidjs-vite';
|
|
|
2
2
|
import { onMount } from 'solid-js';
|
|
3
3
|
import './register'; // side effect: registers the custom elements
|
|
4
4
|
import type { ModelOption } from '../types';
|
|
5
|
+
import { argTypesFor, specDescription } from '../stories/docs/element-controls';
|
|
5
6
|
|
|
6
7
|
// The web components are custom DOM elements, so declare the tags for JSX.
|
|
7
8
|
declare module 'solid-js' {
|
|
8
9
|
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
9
10
|
namespace JSX {
|
|
10
11
|
interface IntrinsicElements {
|
|
11
|
-
'
|
|
12
|
+
'kc-model-switcher': JSX.HTMLAttributes<HTMLElement>;
|
|
12
13
|
}
|
|
13
14
|
}
|
|
14
15
|
}
|
|
@@ -19,7 +20,7 @@ const models: ModelOption[] = [
|
|
|
19
20
|
{ id: 'haiku', name: 'Claude Haiku', provider: 'Anthropic' },
|
|
20
21
|
];
|
|
21
22
|
|
|
22
|
-
/** Render `<
|
|
23
|
+
/** Render `<kc-model-switcher>` with `models` set as a property; tracks selection. */
|
|
23
24
|
function SwitcherElement(props: { models: ModelOption[]; current?: string }) {
|
|
24
25
|
let el: (HTMLElement & { models?: ModelOption[]; currentModel?: string }) | undefined;
|
|
25
26
|
onMount(() => {
|
|
@@ -33,12 +34,12 @@ function SwitcherElement(props: { models: ModelOption[]; current?: string }) {
|
|
|
33
34
|
});
|
|
34
35
|
});
|
|
35
36
|
return (
|
|
36
|
-
<
|
|
37
|
+
<kc-model-switcher ref={(e) => (el = e as HTMLElement)} style={{ display: 'inline-block', padding: '40px' }} />
|
|
37
38
|
);
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
const HTML_SNIPPET = `<!-- Works in any framework or plain HTML -->
|
|
41
|
-
<
|
|
42
|
+
<kc-model-switcher id="ms"></kc-model-switcher>
|
|
42
43
|
|
|
43
44
|
<script type="module">
|
|
44
45
|
import '@kitnai/chat/elements'; // registers the custom elements
|
|
@@ -53,19 +54,18 @@ const HTML_SNIPPET = `<!-- Works in any framework or plain HTML -->
|
|
|
53
54
|
</script>`;
|
|
54
55
|
|
|
55
56
|
const meta = {
|
|
56
|
-
title: 'Web Components/
|
|
57
|
+
title: 'Web Components/kc-model-switcher',
|
|
57
58
|
tags: ['autodocs'],
|
|
59
|
+
argTypes: argTypesFor('kc-model-switcher'),
|
|
58
60
|
parameters: {
|
|
59
61
|
layout: 'fullscreen',
|
|
60
62
|
docs: {
|
|
61
|
-
description:
|
|
62
|
-
|
|
63
|
-
'`<kitn-model-switcher>` is the framework-agnostic **web component** for picking the active model — a dropdown showing each model\'s name and provider — isolated in **Shadow DOM**. It mirrors the switcher inside `<kitn-chat>` as a standalone, composable piece.',
|
|
63
|
+
description: specDescription('kc-model-switcher', [
|
|
64
|
+
'`<kc-model-switcher>` is the framework-agnostic **web component** for picking the active model — a dropdown showing each model\'s name and provider — isolated in **Shadow DOM**. It mirrors the switcher inside `<kc-chat>` as a standalone, composable piece.',
|
|
64
65
|
'**When to use:** building your own chat header and want the model picker on its own. In SolidJS, use the `ModelSwitcher` primitive.',
|
|
65
66
|
"**How to use:** register once with `import '@kitnai/chat/elements'`, set the `models` **property** (and optionally `currentModel`), and listen for the `modelchange` **CustomEvent**. Note: like the underlying primitive, it only renders when more than one model is provided.",
|
|
66
67
|
'See the **Code** tab for HTML usage.',
|
|
67
|
-
]
|
|
68
|
-
},
|
|
68
|
+
]),
|
|
69
69
|
},
|
|
70
70
|
},
|
|
71
71
|
} satisfies Meta;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { defineWebComponent } from './define';
|
|
2
2
|
import { ModelSwitcher } from '../components/model-switcher';
|
|
3
3
|
import type { ModelOption } from '../types';
|
|
4
4
|
|
|
@@ -9,21 +9,21 @@ interface Props extends Record<string, unknown> {
|
|
|
9
9
|
currentModel?: string;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
/** Events fired by `<
|
|
12
|
+
/** Events fired by `<kc-model-switcher>`. */
|
|
13
13
|
interface Events {
|
|
14
14
|
/** A model was selected. */
|
|
15
15
|
modelchange: { modelId: string };
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
|
-
* `<
|
|
19
|
+
* `<kc-model-switcher>` — an event-emitting leaf element. Data in via the
|
|
20
20
|
* `models` property, selection out via a `modelchange` event. Mirrors the
|
|
21
|
-
* header switcher inside `<
|
|
21
|
+
* header switcher inside `<kc-chat>` as a standalone, composable piece.
|
|
22
22
|
*
|
|
23
23
|
* Note: like the underlying primitive, this only renders when more than one
|
|
24
24
|
* model is provided.
|
|
25
25
|
*/
|
|
26
|
-
|
|
26
|
+
defineWebComponent<Props, Events>('kc-model-switcher', {
|
|
27
27
|
models: [],
|
|
28
28
|
currentModel: undefined,
|
|
29
29
|
}, (props, { dispatch }) => (
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from 'storybook-solidjs-vite';
|
|
2
2
|
import { onMount } from 'solid-js';
|
|
3
|
-
import './register'; // side effect: registers <
|
|
3
|
+
import './register'; // side effect: registers <kc-chat>, <kc-conversations>, <kc-prompt-input>
|
|
4
4
|
import type { AttachmentData } from '../components/attachments';
|
|
5
|
+
import { argTypesFor, specDescription } from '../stories/docs/element-controls';
|
|
5
6
|
|
|
6
7
|
// The web components are custom DOM elements, so declare the tags for JSX.
|
|
7
8
|
declare module 'solid-js' {
|
|
8
9
|
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
9
10
|
namespace JSX {
|
|
10
11
|
interface IntrinsicElements {
|
|
11
|
-
'
|
|
12
|
+
'kc-prompt-input': JSX.HTMLAttributes<HTMLElement>;
|
|
12
13
|
}
|
|
13
14
|
}
|
|
14
15
|
}
|
|
@@ -40,21 +41,33 @@ interface PromptInputEl extends HTMLElement {
|
|
|
40
41
|
attachments?: AttachmentData[];
|
|
41
42
|
}
|
|
42
43
|
|
|
43
|
-
/** Live demo of the actual `<
|
|
44
|
-
function PromptInputElement(props
|
|
44
|
+
/** Live demo of the actual `<kc-prompt-input>` custom element (Shadow DOM and all). */
|
|
45
|
+
function PromptInputElement(props: { search?: boolean; voice?: boolean; attachments?: AttachmentData[]; args?: Record<string, unknown> }) {
|
|
45
46
|
let el: PromptInputEl | undefined;
|
|
46
47
|
onMount(() => {
|
|
47
48
|
if (!el) return;
|
|
49
|
+
// Default fixed data
|
|
48
50
|
el.placeholder = 'Ask anything...';
|
|
49
51
|
el.suggestions = sampleSuggestions;
|
|
50
|
-
if (props
|
|
51
|
-
if (props
|
|
52
|
-
if (props
|
|
52
|
+
if (props.search) el.setAttribute('search', '');
|
|
53
|
+
if (props.voice) el.setAttribute('voice', '');
|
|
54
|
+
if (props.attachments) el.attachments = props.attachments;
|
|
55
|
+
// Scalar args from Controls
|
|
56
|
+
const args = props.args;
|
|
57
|
+
if (args) {
|
|
58
|
+
const scalarNames = [
|
|
59
|
+
'value', 'placeholder', 'disabled', 'loading', 'suggestionMode',
|
|
60
|
+
'slashCompact', 'search', 'voice',
|
|
61
|
+
];
|
|
62
|
+
for (const name of scalarNames) {
|
|
63
|
+
if (name in args) (el as unknown as Record<string, unknown>)[name] = args[name];
|
|
64
|
+
}
|
|
65
|
+
}
|
|
53
66
|
el.addEventListener('search', () => console.log('search clicked'));
|
|
54
67
|
el.addEventListener('voice', () => console.log('voice clicked'));
|
|
55
68
|
});
|
|
56
69
|
return (
|
|
57
|
-
<
|
|
70
|
+
<kc-prompt-input
|
|
58
71
|
ref={(e) => (el = e as PromptInputEl)}
|
|
59
72
|
style={{ display: 'block', width: '100%', padding: '16px' }}
|
|
60
73
|
/>
|
|
@@ -62,7 +75,7 @@ function PromptInputElement(props?: { search?: boolean; voice?: boolean; attachm
|
|
|
62
75
|
}
|
|
63
76
|
|
|
64
77
|
const HTML_SNIPPET = `<!-- Works in any framework or plain HTML -->
|
|
65
|
-
<
|
|
78
|
+
<kc-prompt-input id="input" style="display:block; width:100%;"></kc-prompt-input>
|
|
66
79
|
|
|
67
80
|
<script type="module">
|
|
68
81
|
import '@kitnai/chat/elements'; // registers the custom elements
|
|
@@ -95,7 +108,7 @@ function Composer() {
|
|
|
95
108
|
el.suggestions = ['Summarize this thread', 'Draft a reply'];
|
|
96
109
|
});
|
|
97
110
|
return (
|
|
98
|
-
<
|
|
111
|
+
<kc-prompt-input
|
|
99
112
|
ref={el}
|
|
100
113
|
style={{ display: 'block', width: '100%' }}
|
|
101
114
|
on:submit={(e) => console.log('send:', e.detail.value)}
|
|
@@ -106,20 +119,19 @@ function Composer() {
|
|
|
106
119
|
}`;
|
|
107
120
|
|
|
108
121
|
const meta = {
|
|
109
|
-
title: 'Web Components/
|
|
122
|
+
title: 'Web Components/kc-prompt-input',
|
|
110
123
|
tags: ['autodocs'],
|
|
124
|
+
argTypes: argTypesFor('kc-prompt-input'),
|
|
111
125
|
parameters: {
|
|
112
126
|
layout: 'fullscreen',
|
|
113
127
|
docs: {
|
|
114
|
-
description:
|
|
115
|
-
|
|
116
|
-
'`<kitn-prompt-input>` is the framework-agnostic **web component** version of the chat composer — an auto-resizing textarea with a send button and optional suggestion chips, isolated in **Shadow DOM** so the host page\'s CSS can\'t leak in and the kit\'s styles can\'t leak out. SolidJS is bundled in, so the host needs nothing.',
|
|
128
|
+
description: specDescription('kc-prompt-input', [
|
|
129
|
+
'`<kc-prompt-input>` is the framework-agnostic **web component** version of the chat composer — an auto-resizing textarea with a send button and optional suggestion chips, isolated in **Shadow DOM** so the host page\'s CSS can\'t leak in and the kit\'s styles can\'t leak out. SolidJS is bundled in, so the host needs nothing.',
|
|
117
130
|
'**When to use:** adding a message composer to a non-Solid app (React, Vue, Svelte, plain HTML), or anywhere you want zero style conflicts. If you *are* in SolidJS and want fine-grained control, compose the `PromptInput` primitives instead.',
|
|
118
131
|
'**How to use:** register once with `import \'@kitnai/chat/elements\'`, configure it with JS **properties** (`placeholder`, `value`, `disabled`, `loading`, `suggestions`, `attachments`) and flag attributes (`search`, `voice` to show the Globe/Mic toolbar buttons), and listen for **CustomEvents** (`submit`, `valuechange`, `suggestionclick`, `search`, `voice`) directly on the element. Leave `value` unset to let the element manage its own input state; seed `attachments` to pre-populate staged files.',
|
|
119
132
|
'**Placement:** pinned to the bottom of a chat surface, full width. Set `loading` while a response streams to show the busy state, and `disabled` to block input entirely.',
|
|
120
133
|
'See the **Code** tab below for the HTML usage; the *SolidJS* story shows the same element inside a Solid component.',
|
|
121
|
-
]
|
|
122
|
-
},
|
|
134
|
+
]),
|
|
123
135
|
},
|
|
124
136
|
},
|
|
125
137
|
} satisfies Meta;
|
|
@@ -129,7 +141,16 @@ type Story = StoryObj;
|
|
|
129
141
|
|
|
130
142
|
/** The element used the plain-HTML / any-framework way. */
|
|
131
143
|
export const Default: Story = {
|
|
132
|
-
|
|
144
|
+
args: {
|
|
145
|
+
placeholder: 'Send a message...',
|
|
146
|
+
disabled: false,
|
|
147
|
+
loading: false,
|
|
148
|
+
suggestionMode: 'submit',
|
|
149
|
+
slashCompact: false,
|
|
150
|
+
search: false,
|
|
151
|
+
voice: false,
|
|
152
|
+
},
|
|
153
|
+
render: (args: Record<string, unknown>) => <PromptInputElement args={args} />,
|
|
133
154
|
parameters: { docs: { source: { code: HTML_SNIPPET, language: 'html' } } },
|
|
134
155
|
};
|
|
135
156
|
|
|
@@ -141,7 +162,7 @@ export const InSolidJS: Story = {
|
|
|
141
162
|
};
|
|
142
163
|
|
|
143
164
|
const TOOLBAR_SNIPPET = `<!-- show the Search (Globe) + Voice (Mic) toolbar buttons -->
|
|
144
|
-
<
|
|
165
|
+
<kc-prompt-input id="input" search voice></kc-prompt-input>
|
|
145
166
|
|
|
146
167
|
<script type="module">
|
|
147
168
|
import '@kitnai/chat/elements';
|
|
@@ -159,7 +180,7 @@ export const WithVoiceAndSearch: Story = {
|
|
|
159
180
|
};
|
|
160
181
|
|
|
161
182
|
const ATTACHMENTS_SNIPPET = `<!-- seed staged attachments without an upload -->
|
|
162
|
-
<
|
|
183
|
+
<kc-prompt-input id="input" voice></kc-prompt-input>
|
|
163
184
|
|
|
164
185
|
<script type="module">
|
|
165
186
|
import '@kitnai/chat/elements';
|
|
@@ -179,3 +200,4 @@ export const WithAttachments: Story = {
|
|
|
179
200
|
render: () => <PromptInputElement voice attachments={sampleAttachments} />,
|
|
180
201
|
parameters: { docs: { source: { code: ATTACHMENTS_SNIPPET, language: 'html' } } },
|
|
181
202
|
};
|
|
203
|
+
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createEffect, createSignal } from 'solid-js';
|
|
2
|
-
import {
|
|
2
|
+
import { defineWebComponent } from './define';
|
|
3
3
|
import { DefaultPromptInput } from './default-input';
|
|
4
4
|
import type { AttachmentData } from '../components/attachments';
|
|
5
5
|
import type { SlashCommandItem } from '../components/slash-command';
|
|
@@ -40,7 +40,7 @@ interface Props extends Record<string, unknown> {
|
|
|
40
40
|
attachments?: AttachmentData[];
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
/** Events fired by `<
|
|
43
|
+
/** Events fired by `<kc-prompt-input>`. */
|
|
44
44
|
interface Events {
|
|
45
45
|
/** The user submitted the prompt (Enter or send button) with its attachments. */
|
|
46
46
|
submit: { value: string; attachments: AttachmentData[] };
|
|
@@ -51,12 +51,12 @@ interface Events {
|
|
|
51
51
|
/** A slash command was chosen from the palette. */
|
|
52
52
|
slashselect: { command: SlashCommandItem };
|
|
53
53
|
/** The Search (Globe) toolbar button was clicked. */
|
|
54
|
-
search:
|
|
54
|
+
search: Record<string, never>;
|
|
55
55
|
/** The Voice (Mic) toolbar button was clicked. */
|
|
56
|
-
voice:
|
|
56
|
+
voice: Record<string, never>;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
|
|
59
|
+
defineWebComponent<Props, Events>('kc-prompt-input', {
|
|
60
60
|
value: undefined,
|
|
61
61
|
placeholder: 'Send a message...',
|
|
62
62
|
disabled: false,
|