@kitn.ai/ui 0.14.1
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/LICENSE +21 -0
- package/README.md +394 -0
- package/dist/bash-InADTalH.js +1 -0
- package/dist/core-AYMC6_lb.js +12 -0
- package/dist/css-M7EaDHN_.js +1 -0
- package/dist/custom-elements.json +4739 -0
- package/dist/engine-javascript-vq0WuIJl.js +141 -0
- package/dist/github-dark-dimmed-DUshB20C.js +1 -0
- package/dist/github-light-JYsPkUQd.js +1 -0
- package/dist/host-embed.d.ts +33 -0
- package/dist/html-CPZ3oZQ7.js +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/javascript-C25yR2R2.js +1 -0
- package/dist/json-DxJze_jm.js +1 -0
- package/dist/kitn-chat-provider.d.ts +2 -0
- package/dist/kitn-chat-provider.es.js +240 -0
- package/dist/kitn-chat.es.js +77 -0
- package/dist/llms/llms-full.txt +1018 -0
- package/dist/llms/llms.txt +104 -0
- package/dist/origin.d.ts +5 -0
- package/dist/provider-runtime.d.ts +27 -0
- package/dist/schemas/card-envelope.schema.json +14 -0
- package/dist/schemas/card-event.schema.json +12 -0
- package/dist/schemas/choice.schema.json +70 -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/tasks.result.schema.json +16 -0
- package/dist/schemas/tasks.schema.json +78 -0
- package/dist/svelte--5p79yCD.js +1 -0
- package/dist/theme.tokens.css +176 -0
- package/dist/tsx-B8rCNbgL.js +1 -0
- package/dist/typescript-RycA9KXf.js +1 -0
- package/dist/validate.d.ts +4 -0
- package/dist/version.d.ts +4 -0
- package/dist/vue-BmIZj4XD.js +1 -0
- package/dist/wire.d.ts +53 -0
- package/frameworks/react/index.tsx +948 -0
- package/frameworks/react/runtime.tsx +94 -0
- package/llms-full.txt +1018 -0
- package/llms.txt +104 -0
- package/package.json +141 -0
- package/src/components/artifact.stories.tsx +138 -0
- package/src/components/artifact.tsx +743 -0
- package/src/components/attachments.stories.tsx +303 -0
- package/src/components/attachments.test.tsx +64 -0
- package/src/components/attachments.tsx +399 -0
- package/src/components/card-fallback.tsx +28 -0
- package/src/components/card-renderer.tsx +52 -0
- package/src/components/card.tsx +110 -0
- package/src/components/chain-of-thought.stories.tsx +211 -0
- package/src/components/chain-of-thought.tsx +139 -0
- package/src/components/chat-container.stories.tsx +187 -0
- package/src/components/chat-container.tsx +82 -0
- package/src/components/chat-scope-picker.tsx +47 -0
- package/src/components/chat-thread.test.tsx +58 -0
- package/src/components/chat-thread.tsx +249 -0
- package/src/components/checkpoint.stories.tsx +102 -0
- package/src/components/checkpoint.tsx +88 -0
- package/src/components/choice-card.tsx +569 -0
- package/src/components/code-block.stories.tsx +150 -0
- package/src/components/code-block.tsx +105 -0
- package/src/components/component-meta.json +3735 -0
- package/src/components/confirm-card.stories.tsx +74 -0
- package/src/components/confirm-card.tsx +315 -0
- package/src/components/context.stories.tsx +229 -0
- package/src/components/context.test.tsx +133 -0
- package/src/components/context.tsx +363 -0
- package/src/components/conversation-item.stories.tsx +125 -0
- package/src/components/conversation-item.tsx +16 -0
- package/src/components/conversation-list.stories.tsx +133 -0
- package/src/components/conversation-list.tsx +101 -0
- package/src/components/default-input.test.tsx +111 -0
- package/src/components/embed.tsx +196 -0
- package/src/components/empty.stories.tsx +434 -0
- package/src/components/empty.tsx +166 -0
- package/src/components/feedback-bar.stories.tsx +138 -0
- package/src/components/feedback-bar.test.tsx +103 -0
- package/src/components/feedback-bar.tsx +166 -0
- package/src/components/file-tree.stories.tsx +73 -0
- package/src/components/file-tree.tsx +383 -0
- package/src/components/file-upload.stories.tsx +156 -0
- package/src/components/file-upload.tsx +161 -0
- package/src/components/form-widgets.tsx +461 -0
- package/src/components/form.tsx +873 -0
- package/src/components/image.stories.tsx +89 -0
- package/src/components/image.tsx +67 -0
- package/src/components/link-preview.tsx +194 -0
- package/src/components/loader.stories.tsx +181 -0
- package/src/components/loader.tsx +333 -0
- package/src/components/markdown.stories.tsx +180 -0
- package/src/components/markdown.tsx +81 -0
- package/src/components/message-action-bar.test.tsx +128 -0
- package/src/components/message-narrow.stories.tsx +329 -0
- package/src/components/message-skills.stories.tsx +211 -0
- package/src/components/message-skills.tsx +36 -0
- package/src/components/message.stories.tsx +281 -0
- package/src/components/message.tsx +227 -0
- package/src/components/model-switcher.stories.tsx +123 -0
- package/src/components/model-switcher.test.tsx +65 -0
- package/src/components/model-switcher.tsx +87 -0
- package/src/components/prompt-input.stories.tsx +222 -0
- package/src/components/prompt-input.tsx +211 -0
- package/src/components/prompt-suggestion.stories.tsx +142 -0
- package/src/components/prompt-suggestion.tsx +115 -0
- package/src/components/reasoning.stories.tsx +140 -0
- package/src/components/reasoning.tsx +156 -0
- package/src/components/resizable.test.tsx +226 -0
- package/src/components/response-stream.tsx +103 -0
- package/src/components/scroll-button.stories.tsx +100 -0
- package/src/components/scroll-button.tsx +34 -0
- package/src/components/slash-command.stories.tsx +163 -0
- package/src/components/slash-command.tsx +232 -0
- package/src/components/source-list.test.tsx +152 -0
- package/src/components/source.stories.tsx +124 -0
- package/src/components/source.tsx +129 -0
- package/src/components/tasks-card.stories.tsx +78 -0
- package/src/components/tasks-card.tsx +432 -0
- package/src/components/text-shimmer.stories.tsx +87 -0
- package/src/components/text-shimmer.tsx +37 -0
- package/src/components/thinking-bar.stories.tsx +87 -0
- package/src/components/thinking-bar.tsx +50 -0
- package/src/components/tool.stories.tsx +153 -0
- package/src/components/tool.tsx +184 -0
- package/src/components/use-card-resolution.ts +28 -0
- package/src/components/voice-input.stories.tsx +83 -0
- package/src/components/voice-input.tsx +107 -0
- package/src/elements/artifact.stories.tsx +506 -0
- package/src/elements/artifact.tsx +137 -0
- package/src/elements/attachments.stories.tsx +190 -0
- package/src/elements/attachments.tsx +136 -0
- package/src/elements/card.stories.tsx +113 -0
- package/src/elements/card.tsx +40 -0
- package/src/elements/cards.stories.tsx +59 -0
- package/src/elements/cards.tsx +97 -0
- package/src/elements/catalog.stories.tsx +491 -0
- package/src/elements/chain-of-thought.declarative.test.tsx +153 -0
- package/src/elements/chain-of-thought.stories.tsx +113 -0
- package/src/elements/chain-of-thought.tsx +92 -0
- package/src/elements/chat-scope-picker.stories.tsx +73 -0
- package/src/elements/chat-scope-picker.tsx +36 -0
- package/src/elements/chat-types.ts +42 -0
- package/src/elements/chat-workspace.stories.tsx +288 -0
- package/src/elements/chat-workspace.tsx +161 -0
- package/src/elements/chat.stories.tsx +151 -0
- package/src/elements/chat.tsx +80 -0
- package/src/elements/checkpoint.stories.tsx +72 -0
- package/src/elements/checkpoint.tsx +47 -0
- package/src/elements/choice.stories.tsx +240 -0
- package/src/elements/choice.tsx +48 -0
- package/src/elements/code-block.stories.tsx +83 -0
- package/src/elements/code-block.tsx +42 -0
- package/src/elements/compiled.css +2 -0
- package/src/elements/composed-shell.stories.tsx +316 -0
- package/src/elements/confirm-card.stories.tsx +227 -0
- package/src/elements/confirm-card.tsx +51 -0
- package/src/elements/context-meter.stories.tsx +151 -0
- package/src/elements/context-meter.tsx +121 -0
- package/src/elements/conversation-list.declarative.test.tsx +137 -0
- package/src/elements/conversation-list.stories.tsx +243 -0
- package/src/elements/conversation-list.tsx +80 -0
- package/src/elements/css.ts +5 -0
- package/src/elements/default-input.tsx +247 -0
- package/src/elements/define.tsx +171 -0
- package/src/elements/element-meta.json +3314 -0
- package/src/elements/element-types.d.ts +710 -0
- package/src/elements/embed.stories.tsx +213 -0
- package/src/elements/embed.tsx +35 -0
- package/src/elements/empty.stories.tsx +111 -0
- package/src/elements/empty.tsx +29 -0
- package/src/elements/feedback-bar.stories.tsx +114 -0
- package/src/elements/feedback-bar.tsx +61 -0
- package/src/elements/file-tree.stories.tsx +134 -0
- package/src/elements/file-tree.tsx +52 -0
- package/src/elements/file-upload.stories.tsx +82 -0
- package/src/elements/file-upload.tsx +44 -0
- package/src/elements/form.stories.tsx +248 -0
- package/src/elements/form.tsx +43 -0
- package/src/elements/framework-usage.json +563 -0
- package/src/elements/image.stories.tsx +71 -0
- package/src/elements/image.tsx +32 -0
- package/src/elements/link-preview.stories.tsx +209 -0
- package/src/elements/link-preview.tsx +34 -0
- package/src/elements/loader.stories.tsx +88 -0
- package/src/elements/loader.tsx +25 -0
- package/src/elements/markdown.stories.tsx +76 -0
- package/src/elements/markdown.tsx +38 -0
- package/src/elements/message-skills.declarative.test.tsx +104 -0
- package/src/elements/message-skills.stories.tsx +114 -0
- package/src/elements/message-skills.tsx +85 -0
- package/src/elements/message.stories.tsx +218 -0
- package/src/elements/message.tsx +162 -0
- package/src/elements/model-switcher.declarative.test.tsx +130 -0
- package/src/elements/model-switcher.stories.tsx +198 -0
- package/src/elements/model-switcher.tsx +93 -0
- package/src/elements/popover.stories.tsx +80 -0
- package/src/elements/popover.tsx +59 -0
- package/src/elements/prompt-input-slash-command.test.tsx +128 -0
- package/src/elements/prompt-input-stoppable.test.tsx +88 -0
- package/src/elements/prompt-input-toolbar-actions.test.tsx +120 -0
- package/src/elements/prompt-input.stories.tsx +331 -0
- package/src/elements/prompt-input.tsx +185 -0
- package/src/elements/prompt-suggestions.declarative.test.tsx +164 -0
- package/src/elements/prompt-suggestions.stories.tsx +213 -0
- package/src/elements/prompt-suggestions.tsx +94 -0
- package/src/elements/reasoning.stories.tsx +77 -0
- package/src/elements/reasoning.tsx +50 -0
- package/src/elements/register.ts +56 -0
- package/src/elements/remote.stories.tsx +314 -0
- package/src/elements/remote.tsx +221 -0
- package/src/elements/resizable.d.ts +27 -0
- package/src/elements/resizable.stories.tsx +426 -0
- package/src/elements/resizable.tsx +553 -0
- package/src/elements/response-stream.stories.tsx +79 -0
- package/src/elements/response-stream.tsx +40 -0
- package/src/elements/scroll-button.stories.tsx +202 -0
- package/src/elements/scroll-button.test.tsx +148 -0
- package/src/elements/scroll-button.tsx +126 -0
- package/src/elements/source-list.stories.tsx +143 -0
- package/src/elements/source.stories.tsx +88 -0
- package/src/elements/source.tsx +120 -0
- package/src/elements/styles.css +199 -0
- package/src/elements/switch.stories.tsx +56 -0
- package/src/elements/switch.tsx +43 -0
- package/src/elements/tasks.stories.tsx +237 -0
- package/src/elements/tasks.tsx +46 -0
- package/src/elements/text-shimmer.stories.tsx +64 -0
- package/src/elements/text-shimmer.tsx +28 -0
- package/src/elements/thinking-bar.stories.tsx +72 -0
- package/src/elements/thinking-bar.tsx +34 -0
- package/src/elements/tool.stories.tsx +89 -0
- package/src/elements/tool.tsx +23 -0
- package/src/elements/voice-input.stories.tsx +88 -0
- package/src/elements/voice-input.tsx +41 -0
- package/src/index.ts +253 -0
- package/src/primitives/card-contract.ts +71 -0
- package/src/primitives/card-host.tsx +35 -0
- package/src/primitives/card-registry.tsx +67 -0
- package/src/primitives/card-resolution.ts +36 -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/choice.schema.json +70 -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/tasks.result.schema.json +16 -0
- package/src/primitives/card-schemas/tasks.schema.json +78 -0
- package/src/primitives/card-validate.ts +95 -0
- package/src/primitives/chat-config.tsx +76 -0
- package/src/primitives/controllable.test.ts +47 -0
- package/src/primitives/controllable.ts +21 -0
- package/src/primitives/embed-providers.ts +254 -0
- package/src/primitives/highlighter.ts +157 -0
- package/src/primitives/link-preview.ts +87 -0
- package/src/primitives/pdf-preview.ts +121 -0
- package/src/primitives/use-auto-resize.ts +31 -0
- package/src/primitives/use-resize-observer.ts +12 -0
- package/src/primitives/use-stick-to-bottom.ts +43 -0
- package/src/primitives/use-text-stream.ts +112 -0
- package/src/primitives/use-voice-recorder.ts +50 -0
- package/src/remote/host-embed.ts +345 -0
- package/src/remote/index.ts +2 -0
- package/src/remote/origin.ts +30 -0
- package/src/remote/provider-runtime.ts +259 -0
- package/src/remote/provider.ts +2 -0
- package/src/remote/validate.ts +22 -0
- package/src/remote/version.ts +12 -0
- package/src/remote/wire.ts +48 -0
- package/src/stories/chat-panel-layout.stories.tsx +145 -0
- package/src/stories/chat-scene.tsx +571 -0
- package/src/stories/checkpoint-restore.stories.tsx +256 -0
- package/src/stories/context-usage.stories.tsx +212 -0
- package/src/stories/conversation-with-reasoning.stories.tsx +182 -0
- package/src/stories/conversation-with-sources.stories.tsx +471 -0
- package/src/stories/docs/Accessibility.mdx +119 -0
- package/src/stories/docs/ChildElements.mdx +269 -0
- package/src/stories/docs/ForAIAgents.mdx +162 -0
- package/src/stories/docs/GettingStarted.mdx +65 -0
- package/src/stories/docs/Installation.mdx +83 -0
- package/src/stories/docs/Introduction.mdx +50 -0
- package/src/stories/docs/SolidJsAdvanced.mdx +17 -0
- package/src/stories/docs/Theming.mdx +85 -0
- package/src/stories/docs/element-controls.ts +121 -0
- package/src/stories/docs/frameworks/Angular.mdx +245 -0
- package/src/stories/docs/frameworks/Html.mdx +227 -0
- package/src/stories/docs/frameworks/Overview.mdx +47 -0
- package/src/stories/docs/frameworks/React.mdx +227 -0
- package/src/stories/docs/frameworks/Solid.mdx +173 -0
- package/src/stories/docs/frameworks/Svelte.mdx +194 -0
- package/src/stories/docs/frameworks/Vue.mdx +238 -0
- package/src/stories/docs/generative-ui-overview.mdx +186 -0
- package/src/stories/docs/recipes/SpeechToText.mdx +7 -0
- package/src/stories/docs/recipes/Streaming.mdx +68 -0
- package/src/stories/docs/recipes/TextToSpeech.mdx +35 -0
- package/src/stories/docs/theme-editor/canvas.tsx +32 -0
- package/src/stories/docs/theme-editor/inspector.tsx +66 -0
- package/src/stories/docs/theme-editor/presets.test.ts +32 -0
- package/src/stories/docs/theme-editor/presets.ts +64 -0
- package/src/stories/docs/theme-editor/theme-css.test.ts +19 -0
- package/src/stories/docs/theme-editor/theme-css.ts +15 -0
- package/src/stories/docs/theme-editor/theme-editor.tsx +146 -0
- package/src/stories/docs/theme-tokens.tsx +174 -0
- package/src/stories/examples/ChoosingComponents.mdx +106 -0
- package/src/stories/examples/sample-data.ts +79 -0
- package/src/stories/examples/usage/checkpoint-restore.ts +156 -0
- package/src/stories/examples/usage/context-usage.ts +591 -0
- package/src/stories/examples/usage/conversation-with-reasoning.ts +224 -0
- package/src/stories/examples/usage/conversation-with-sources.ts +589 -0
- package/src/stories/examples/usage/empty-state.ts +144 -0
- package/src/stories/examples/usage/full-chat-app.ts +277 -0
- package/src/stories/examples/usage/index.ts +63 -0
- package/src/stories/examples/usage/message-actions.ts +704 -0
- package/src/stories/examples/usage/pattern-centered-conversation.ts +446 -0
- package/src/stories/examples/usage/pattern-chat-panel-layout.ts +442 -0
- package/src/stories/examples/usage/pattern-docked-widget.ts +479 -0
- package/src/stories/examples/usage/prompt-input-variants.ts +1356 -0
- package/src/stories/examples/usage/streaming-response.ts +687 -0
- package/src/stories/examples/usage/types.ts +33 -0
- package/src/stories/full-chat.stories.tsx +18 -0
- package/src/stories/message-actions.stories.tsx +230 -0
- package/src/stories/pattern-centered-conversation.stories.tsx +93 -0
- package/src/stories/pattern-docked-widget.stories.tsx +93 -0
- package/src/stories/pattern-empty-state.stories.tsx +76 -0
- package/src/stories/prompt-input-variants.stories.tsx +456 -0
- package/src/stories/streaming-response.stories.tsx +438 -0
- package/src/stories/theme-editor.stories.tsx +16 -0
- package/src/stories/token-reference.stories.tsx +18 -0
- package/src/stories/typography.stories.tsx +78 -0
- package/src/types.ts +47 -0
- package/src/ui/action-icons.ts +52 -0
- package/src/ui/avatar.stories.tsx +103 -0
- package/src/ui/avatar.tsx +23 -0
- package/src/ui/badge.stories.tsx +86 -0
- package/src/ui/badge.tsx +21 -0
- package/src/ui/button.stories.tsx +145 -0
- package/src/ui/button.tsx +38 -0
- package/src/ui/collapsible.stories.tsx +69 -0
- package/src/ui/collapsible.tsx +125 -0
- package/src/ui/dropdown.stories.tsx +59 -0
- package/src/ui/dropdown.tsx +196 -0
- package/src/ui/hover-card.stories.tsx +77 -0
- package/src/ui/hover-card.test.tsx +30 -0
- package/src/ui/hover-card.tsx +172 -0
- package/src/ui/overlay.stories.tsx +115 -0
- package/src/ui/overlay.tsx +158 -0
- package/src/ui/popover.stories.tsx +81 -0
- package/src/ui/popover.test.tsx +99 -0
- package/src/ui/popover.tsx +92 -0
- package/src/ui/resizable.stories.tsx +236 -0
- package/src/ui/resizable.tsx +576 -0
- package/src/ui/scroll-area.stories.tsx +50 -0
- package/src/ui/scroll-area.tsx +15 -0
- package/src/ui/separator.stories.tsx +81 -0
- package/src/ui/separator.tsx +10 -0
- package/src/ui/skeleton.stories.tsx +337 -0
- package/src/ui/skeleton.tsx +16 -0
- package/src/ui/switch.stories.tsx +51 -0
- package/src/ui/switch.test.tsx +59 -0
- package/src/ui/switch.tsx +62 -0
- package/src/ui/textarea.stories.tsx +76 -0
- package/src/ui/textarea.tsx +21 -0
- package/src/ui/tooltip.stories.tsx +74 -0
- package/src/ui/tooltip.tsx +68 -0
- package/src/utils/cn.ts +24 -0
- package/theme.css +187 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Meta } from '@storybook/addon-docs/blocks';
|
|
2
|
+
|
|
3
|
+
<Meta title="Docs/Frameworks/Overview" />
|
|
4
|
+
|
|
5
|
+
# Frameworks
|
|
6
|
+
|
|
7
|
+
`@kitn.ai/ui` is **transport-agnostic**: every element renders a `messages` array and emits a
|
|
8
|
+
`submit` event. You bring the model; the kit owns the UI. It works in any framework — pick yours:
|
|
9
|
+
[HTML](?path=/docs/docs-frameworks-html--docs) · [React](?path=/docs/docs-frameworks-react--docs) · [Solid](?path=/docs/docs-frameworks-solid--docs) · [Vue](?path=/docs/docs-frameworks-vue--docs) · [Svelte](?path=/docs/docs-frameworks-svelte--docs) · [Angular](?path=/docs/docs-frameworks-angular--docs).
|
|
10
|
+
Recipes for streaming, text-to-speech, and speech-to-text live under **Docs/Recipes**.
|
|
11
|
+
|
|
12
|
+
## Two ways to build
|
|
13
|
+
|
|
14
|
+
You can adopt the kit at whatever level you need — and mix the two freely:
|
|
15
|
+
|
|
16
|
+
1. **`<kai-chat>` — the all-in-one shell.** One tag gives you a whole chat experience (message
|
|
17
|
+
thread, prompt input, model switcher, …). The fastest way to ship.
|
|
18
|
+
2. **Compose the individual elements.** Assemble `<kai-conversations>`, `<kai-message>`,
|
|
19
|
+
`<kai-prompt-input>`, `<kai-markdown>`, `<kai-artifact>`, … into your own layout for full control —
|
|
20
|
+
or drop a single display element into an app you already have.
|
|
21
|
+
|
|
22
|
+
`<kai-chat>` is the quick start, **not** the only way in. Every framework page shows both paths,
|
|
23
|
+
and each element's **API** tab (under **Components**) lists its full props, events, and copy-paste
|
|
24
|
+
usage for every framework.
|
|
25
|
+
|
|
26
|
+
## The #1 rule: properties vs. attributes
|
|
27
|
+
|
|
28
|
+
Arrays and objects **must** be set as JavaScript **properties** on the element — never as HTML
|
|
29
|
+
attributes. An HTML attribute is always a string, so passing `messages`, `models`, `context`,
|
|
30
|
+
`suggestions`, or `slashCommands` as an attribute silently fails.
|
|
31
|
+
|
|
32
|
+
```js
|
|
33
|
+
const chat = document.querySelector('kai-chat');
|
|
34
|
+
|
|
35
|
+
// ✅ correct — set as a JS property
|
|
36
|
+
chat.messages = [{ id: '1', role: 'assistant', content: 'Hello!' }];
|
|
37
|
+
|
|
38
|
+
// ❌ wrong — an HTML attribute is always a string, never works
|
|
39
|
+
// <kai-chat messages="[...]"></kai-chat>
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Scalar values (strings, numbers, booleans) work fine as attributes: `placeholder`, `loading`,
|
|
43
|
+
`theme`, `prose-size`, and so on. Each framework's binding syntax (React props, Vue's `.prop`
|
|
44
|
+
modifier, Angular's `[prop]`, Svelte's `{prop}`) handles this for you — see your framework's page.
|
|
45
|
+
|
|
46
|
+
The kit ships **40+ elements**. SolidJS apps can also import the **native components** directly for
|
|
47
|
+
full compositional control — see the [Solid](?path=/docs/docs-frameworks-solid--docs) page and the **Solid (Advanced)** section.
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import { Meta } from '@storybook/addon-docs/blocks';
|
|
2
|
+
|
|
3
|
+
<Meta title="Docs/Frameworks/React" />
|
|
4
|
+
|
|
5
|
+
# React
|
|
6
|
+
|
|
7
|
+
The kit ships auto-generated, **typed React wrappers** under `@kitn.ai/ui/react`. They hide the
|
|
8
|
+
custom-element plumbing — rich data goes in as React props (set as DOM **properties**, never
|
|
9
|
+
stringified) and CustomEvents come out as `on<Event>` handlers — so you write idiomatic JSX
|
|
10
|
+
without touching refs.
|
|
11
|
+
|
|
12
|
+
There are **two ways to build with the kit**, and you can mix them:
|
|
13
|
+
|
|
14
|
+
1. **`<Chat>`** — the batteries-included shell: a whole chat experience in one tag. Fastest start.
|
|
15
|
+
2. **Compose the individual elements** (`<Conversations>`, `<Markdown>`, `<Artifact>`, …) into
|
|
16
|
+
your own layout when you want full control.
|
|
17
|
+
|
|
18
|
+
Both are shown below.
|
|
19
|
+
|
|
20
|
+
## Install & setup
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm i @kitn.ai/ui
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Register the custom elements once (a side-effect import), then use the typed wrappers anywhere:
|
|
27
|
+
|
|
28
|
+
```tsx
|
|
29
|
+
// Once, near your app entry — registers the <kai-*> elements globally.
|
|
30
|
+
import '@kitn.ai/ui/elements';
|
|
31
|
+
|
|
32
|
+
// Then import the wrappers you need (tree-shaken).
|
|
33
|
+
import { Chat, Conversations, Markdown } from '@kitn.ai/ui/react';
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
- **`@kitn.ai/ui/react`** — the typed wrappers (recommended). Component names are the PascalCase
|
|
37
|
+
of the tag: `kai-chat → Chat`, `kai-prompt-input → PromptInput`.
|
|
38
|
+
- **`@kitn.ai/ui/elements`** — the raw custom elements, if you'd rather wire refs yourself
|
|
39
|
+
(see [Without the wrappers](#without-the-wrappers-raw-custom-element)).
|
|
40
|
+
- No CSS to import: each element is styled inside its own Shadow DOM. Only pull in
|
|
41
|
+
`@kitn.ai/ui/theme.css` if you want to override design tokens (see **Theming**).
|
|
42
|
+
|
|
43
|
+
> One name collides with a browser global: `kai-image → Image`. Alias it if you import it:
|
|
44
|
+
> `import { Image as KaiImage } from '@kitn.ai/ui/react'`.
|
|
45
|
+
|
|
46
|
+
## Quick start — the all-in-one shell
|
|
47
|
+
|
|
48
|
+
`<Chat>` is **transport-agnostic**: give it a `messages` array, handle the `submit` event, and
|
|
49
|
+
stream your model's reply back into state. You own the request; the component owns the UI.
|
|
50
|
+
|
|
51
|
+
```tsx
|
|
52
|
+
import '@kitn.ai/ui/elements';
|
|
53
|
+
import { Chat } from '@kitn.ai/ui/react';
|
|
54
|
+
import { useState } from 'react';
|
|
55
|
+
|
|
56
|
+
type Message = { id: string; role: 'user' | 'assistant'; content: string };
|
|
57
|
+
|
|
58
|
+
export function App() {
|
|
59
|
+
const [messages, setMessages] = useState<Message[]>([
|
|
60
|
+
{ id: '1', role: 'assistant', content: 'Hello! How can I help?' },
|
|
61
|
+
]);
|
|
62
|
+
|
|
63
|
+
const handleSubmit = async (e: CustomEvent<{ value: string }>) => {
|
|
64
|
+
const history = [...messages, { id: crypto.randomUUID(), role: 'user' as const, content: e.detail.value }];
|
|
65
|
+
setMessages(history);
|
|
66
|
+
|
|
67
|
+
const aid = crypto.randomUUID();
|
|
68
|
+
setMessages([...history, { id: aid, role: 'assistant', content: '' }]);
|
|
69
|
+
|
|
70
|
+
let answer = '';
|
|
71
|
+
for await (const token of streamFromYourAPI(history)) {
|
|
72
|
+
answer += token;
|
|
73
|
+
// Assign a NEW array (and a new object for the message you change) to trigger a re-render.
|
|
74
|
+
setMessages((prev) => prev.map((m) => (m.id === aid ? { ...m, content: answer } : m)));
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
// The elements are `display: block` and fill their container — lay them out with
|
|
79
|
+
// flex and let the element grow with `flex: 1` rather than hard-coding a height.
|
|
80
|
+
return (
|
|
81
|
+
<div style={{ display: 'flex', flexDirection: 'column', height: '100dvh' }}>
|
|
82
|
+
<Chat
|
|
83
|
+
messages={messages}
|
|
84
|
+
suggestions={['Summarize the chat', 'Start fresh']}
|
|
85
|
+
onSubmit={handleSubmit}
|
|
86
|
+
style={{ flex: 1, minHeight: 0 }}
|
|
87
|
+
/>
|
|
88
|
+
</div>
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Go further — compose the pieces
|
|
94
|
+
|
|
95
|
+
`<Chat>` is one option, not the only one. Every element has its own wrapper, so you can assemble
|
|
96
|
+
your own layout. Here's a multi-conversation shell — a `<Conversations>` sidebar next to the
|
|
97
|
+
`<Chat>` thread:
|
|
98
|
+
|
|
99
|
+
```tsx
|
|
100
|
+
import '@kitn.ai/ui/elements';
|
|
101
|
+
import { Chat, Conversations } from '@kitn.ai/ui/react';
|
|
102
|
+
import { useState } from 'react';
|
|
103
|
+
|
|
104
|
+
export function Workspace() {
|
|
105
|
+
const [conversations, setConversations] = useState(myConversations);
|
|
106
|
+
const [activeId, setActiveId] = useState(conversations[0]?.id);
|
|
107
|
+
const [messages, setMessages] = useState(loadMessages(activeId));
|
|
108
|
+
|
|
109
|
+
// Lay panels out with flex: the sidebar is fixed-width, the thread takes the rest
|
|
110
|
+
// with `flex: 1`. The elements fill whatever box you give them.
|
|
111
|
+
return (
|
|
112
|
+
<div style={{ display: 'flex', height: '100dvh' }}>
|
|
113
|
+
<Conversations
|
|
114
|
+
conversations={conversations}
|
|
115
|
+
activeId={activeId}
|
|
116
|
+
onConversationSelect={(e) => {
|
|
117
|
+
setActiveId(e.detail.id);
|
|
118
|
+
setMessages(loadMessages(e.detail.id));
|
|
119
|
+
}}
|
|
120
|
+
onNewChat={() => startNewConversation()}
|
|
121
|
+
style={{ width: 300, flexShrink: 0 }}
|
|
122
|
+
/>
|
|
123
|
+
|
|
124
|
+
<Chat
|
|
125
|
+
messages={messages}
|
|
126
|
+
onSubmit={(e) => sendMessage(e.detail.value)}
|
|
127
|
+
style={{ flex: 1, minWidth: 0 }}
|
|
128
|
+
/>
|
|
129
|
+
</div>
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Make the panels resizable
|
|
135
|
+
|
|
136
|
+
Want a draggable divider between the sidebar and the thread? Wrap the panels in `<Resizable>`
|
|
137
|
+
with one `<ResizableItem>` each — the handles are inserted for you (up to 3 panels). Each item
|
|
138
|
+
takes a `size` (px or `%`) plus optional `min`/`max`; listen for `onChange` (`detail.sizes`) to
|
|
139
|
+
persist the layout.
|
|
140
|
+
|
|
141
|
+
```tsx
|
|
142
|
+
import { Chat, Conversations, Resizable, ResizableItem } from '@kitn.ai/ui/react';
|
|
143
|
+
|
|
144
|
+
<div style={{ display: 'flex', flexDirection: 'column', height: '100dvh' }}>
|
|
145
|
+
<Resizable orientation="horizontal" style={{ flex: 1, minHeight: 0 }}>
|
|
146
|
+
<ResizableItem size="25%" min="200px">
|
|
147
|
+
<Conversations conversations={conversations} activeId={activeId} onConversationSelect={handleSelect} />
|
|
148
|
+
</ResizableItem>
|
|
149
|
+
<ResizableItem>
|
|
150
|
+
<Chat messages={messages} onSubmit={handleSubmit} />
|
|
151
|
+
</ResizableItem>
|
|
152
|
+
</Resizable>
|
|
153
|
+
</div>
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
You can also drop **standalone display elements** anywhere in your own UI — `<Markdown>`,
|
|
157
|
+
`<CodeBlock>`, `<Artifact>`, `<Reasoning>`, `<Tool>` — to render rich AI content without adopting
|
|
158
|
+
the whole chat. Each fills its container and is controlled via props and events.
|
|
159
|
+
|
|
160
|
+
> **See it all assembled:** **[Examples → Full Chat App](?path=/story/examples-full-chat-app--default)**
|
|
161
|
+
> wires a sidebar, threaded markdown, reasoning, a tool call, a model switcher, a context meter, and
|
|
162
|
+
> a rich prompt input into one screen — a working reference to crib from.
|
|
163
|
+
|
|
164
|
+
> **Find every element:** browse the **Components** section in the sidebar. Each element's **API**
|
|
165
|
+
> tab lists its props, events, and copy-paste usage for React (and every other framework).
|
|
166
|
+
|
|
167
|
+
## Props & events
|
|
168
|
+
|
|
169
|
+
The rule for all elements: **rich data goes in as properties, interactions come out as events.**
|
|
170
|
+
The wrappers do this for you — pass arrays/objects as props and they're assigned as live DOM
|
|
171
|
+
properties (not stringified), while CustomEvents surface as `on<Event>` handlers.
|
|
172
|
+
|
|
173
|
+
Event props are `on` + the event name with the `kai-` prefix stripped and each
|
|
174
|
+
hyphen-segment PascalCased:
|
|
175
|
+
|
|
176
|
+
| DOM event | React prop |
|
|
177
|
+
|---|---|
|
|
178
|
+
| `kai-submit` | `onSubmit` |
|
|
179
|
+
| `kai-value-change` | `onValueChange` |
|
|
180
|
+
| `kai-message-action` | `onMessageAction` |
|
|
181
|
+
| `kai-model-change` | `onModelChange` |
|
|
182
|
+
| `kai-conversation-select` | `onConversationSelect` |
|
|
183
|
+
| `kai-suggestion-click` | `onSuggestionClick` |
|
|
184
|
+
|
|
185
|
+
All **40+ elements** have a typed wrapper:
|
|
186
|
+
|
|
187
|
+
```tsx
|
|
188
|
+
import {
|
|
189
|
+
Chat, Conversations, PromptInput, Message, Markdown, CodeBlock,
|
|
190
|
+
Reasoning, Tool, Context, ModelSwitcher, Attachments, Loader,
|
|
191
|
+
// …every kai-* element
|
|
192
|
+
} from '@kitn.ai/ui/react';
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## Without the wrappers (raw custom element)
|
|
196
|
+
|
|
197
|
+
Prefer the raw element (e.g. with React 19's improved custom-element support)? Use a `ref` to set
|
|
198
|
+
object props and wire events:
|
|
199
|
+
|
|
200
|
+
```tsx
|
|
201
|
+
import { useEffect, useRef, useState } from 'react';
|
|
202
|
+
import '@kitn.ai/ui/elements';
|
|
203
|
+
|
|
204
|
+
export function RawChat() {
|
|
205
|
+
const ref = useRef<HTMLElement>(null);
|
|
206
|
+
const [messages, setMessages] = useState([{ id: '1', role: 'assistant', content: 'Hello!' }]);
|
|
207
|
+
|
|
208
|
+
useEffect(() => {
|
|
209
|
+
const el = ref.current;
|
|
210
|
+
if (!el) return;
|
|
211
|
+
(el as any).messages = messages; // object/array props can't go through attributes
|
|
212
|
+
}, [messages]);
|
|
213
|
+
|
|
214
|
+
useEffect(() => {
|
|
215
|
+
const el = ref.current;
|
|
216
|
+
if (!el) return;
|
|
217
|
+
const onSubmit = (e: Event) => {
|
|
218
|
+
const { value } = (e as CustomEvent<{ value: string }>).detail;
|
|
219
|
+
setMessages((prev) => [...prev, { id: crypto.randomUUID(), role: 'user', content: value }]);
|
|
220
|
+
};
|
|
221
|
+
el.addEventListener('kai-submit', onSubmit);
|
|
222
|
+
return () => el.removeEventListener('kai-submit', onSubmit);
|
|
223
|
+
}, []);
|
|
224
|
+
|
|
225
|
+
return <kai-chat ref={ref} style={{ display: 'block', height: '100vh' }} />;
|
|
226
|
+
}
|
|
227
|
+
```
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { Meta } from '@storybook/addon-docs/blocks';
|
|
2
|
+
|
|
3
|
+
<Meta title="Docs/Frameworks/Solid" />
|
|
4
|
+
|
|
5
|
+
# Solid
|
|
6
|
+
|
|
7
|
+
The kit is **authored in SolidJS** — the `<kai-*>` web components are compiled from these very
|
|
8
|
+
components. So Solid devs get the richest path of any framework, with **two ways to build** that
|
|
9
|
+
you can freely mix:
|
|
10
|
+
|
|
11
|
+
1. **Native SolidJS components** (`@kitn.ai/ui`) — `ChatContainer`, `Message`, `PromptInput`, and
|
|
12
|
+
the rest, composed in your own JSX. Full compositional control and the smallest output for a
|
|
13
|
+
Solid app. **This is the recommended Solid path.**
|
|
14
|
+
2. The same framework-agnostic **`<kai-*>` web components** (`@kitn.ai/ui/elements`) — the
|
|
15
|
+
drop-in shells (`<kai-chat>`, …) when you just want batteries included.
|
|
16
|
+
|
|
17
|
+
Both work in the same app; reach for whichever fits the surface you're building.
|
|
18
|
+
|
|
19
|
+
## Install & setup
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm i @kitn.ai/ui
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
`solid-js` is a peer dependency — install it if you haven't already:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npm i solid-js
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Import the design tokens **once**, near your app entry:
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
import '@kitn.ai/ui/theme.css';
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
The `@kitn.ai/ui` entry ships as **source** (TSX), so your bundler compiles and tree-shakes it
|
|
38
|
+
alongside your own Solid code — you only pay for what you import.
|
|
39
|
+
|
|
40
|
+
## Quick start — native components
|
|
41
|
+
|
|
42
|
+
Compose the native components directly in your JSX. Drive the prompt input with a `createSignal`,
|
|
43
|
+
and let the components fill their container — size them with flex / `class="h-full"` rather than a
|
|
44
|
+
hard-coded `height: 100vh`.
|
|
45
|
+
|
|
46
|
+
```tsx
|
|
47
|
+
import {
|
|
48
|
+
ChatConfig, ChatContainer, ChatContainerContent,
|
|
49
|
+
Message, MessageContent,
|
|
50
|
+
PromptInput, PromptInputTextarea, PromptInputActions,
|
|
51
|
+
} from '@kitn.ai/ui';
|
|
52
|
+
import '@kitn.ai/ui/theme.css';
|
|
53
|
+
import { createSignal } from 'solid-js';
|
|
54
|
+
|
|
55
|
+
function Chat() {
|
|
56
|
+
const [input, setInput] = createSignal('');
|
|
57
|
+
|
|
58
|
+
// The components fill their box — give them a flex parent and let
|
|
59
|
+
// ChatContainer grow with `h-full`/flex rather than a fixed viewport height.
|
|
60
|
+
return (
|
|
61
|
+
<div class="flex flex-col h-full">
|
|
62
|
+
<ChatConfig proseSize="sm">
|
|
63
|
+
<ChatContainer class="h-full">
|
|
64
|
+
<ChatContainerContent class="space-y-4 p-4">
|
|
65
|
+
<Message>
|
|
66
|
+
<MessageContent markdown>{`Ask me anything.`}</MessageContent>
|
|
67
|
+
</Message>
|
|
68
|
+
</ChatContainerContent>
|
|
69
|
+
</ChatContainer>
|
|
70
|
+
<PromptInput value={input()} onValueChange={setInput} onSubmit={() => setInput('')}>
|
|
71
|
+
<PromptInputTextarea placeholder="Ask anything..." />
|
|
72
|
+
<PromptInputActions>{/* your buttons */}</PromptInputActions>
|
|
73
|
+
</PromptInput>
|
|
74
|
+
</ChatConfig>
|
|
75
|
+
</div>
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
`<ChatContainer>` is **transport-agnostic**: it owns the conversation UI, you own the request.
|
|
81
|
+
Render your message list inside `<ChatContainerContent>` (a `<For>` over your signal of messages),
|
|
82
|
+
and append the user turn — then stream the assistant reply — in `onSubmit`.
|
|
83
|
+
|
|
84
|
+
## Go further — compose & the web components
|
|
85
|
+
|
|
86
|
+
### The native components *are* the granular composition
|
|
87
|
+
|
|
88
|
+
There's no separate "advanced" component set — the pieces above (`ChatContainer`, `Message`,
|
|
89
|
+
`PromptInput`) plus the feature components (`Markdown`, `CodeBlock`, `Reasoning`, `Tool`,
|
|
90
|
+
`Conversations`, `ModelSwitcher`, …) **are** the building blocks. Assemble them into any layout you
|
|
91
|
+
like: a sidebar next to a thread, a split view, a custom composer — it's all just Solid JSX.
|
|
92
|
+
|
|
93
|
+
For a resizable layout, use the native `Resizable` convenience component with one `ResizablePanel`
|
|
94
|
+
per pane (handles are auto-inserted between visible panels). Each panel takes `defaultSize`
|
|
95
|
+
(px or `%`) plus optional `minSize`/`maxSize`; listen for `onChange` (an array of percent sizes) to
|
|
96
|
+
persist the layout.
|
|
97
|
+
|
|
98
|
+
```tsx
|
|
99
|
+
import { Resizable, ResizablePanel } from '@kitn.ai/ui';
|
|
100
|
+
|
|
101
|
+
function Workspace() {
|
|
102
|
+
return (
|
|
103
|
+
<div class="flex flex-col h-full">
|
|
104
|
+
<Resizable orientation="horizontal" withHandle onChange={(sizes) => persist(sizes)}>
|
|
105
|
+
<ResizablePanel defaultSize="25%" minSize="200px">
|
|
106
|
+
{/* your conversation sidebar */}
|
|
107
|
+
</ResizablePanel>
|
|
108
|
+
<ResizablePanel>
|
|
109
|
+
{/* the message thread + prompt input */}
|
|
110
|
+
</ResizablePanel>
|
|
111
|
+
</Resizable>
|
|
112
|
+
</div>
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
> **Full reference:** the **[Solid (Advanced)](?path=/docs/solid-advanced-overview--docs)** sidebar
|
|
118
|
+
> tier documents every native building block — the composed **Elements** (message, tool, reasoning,
|
|
119
|
+
> …) and the low-level **Primitives** (button, tooltip, dropdown, …) they're built on.
|
|
120
|
+
|
|
121
|
+
### Prefer the drop-in shell? Use the web component
|
|
122
|
+
|
|
123
|
+
When you just want a whole chat in one tag, register the `<kai-*>` elements and use `<kai-chat>`.
|
|
124
|
+
Solid sets rich data as DOM **properties** on custom elements (so arrays/objects pass through
|
|
125
|
+
without stringifying), and you listen for CustomEvents with Solid's `on:` namespace:
|
|
126
|
+
|
|
127
|
+
```tsx
|
|
128
|
+
import '@kitn.ai/ui/elements'; // registers the <kai-*> elements once
|
|
129
|
+
import { createSignal } from 'solid-js';
|
|
130
|
+
|
|
131
|
+
function Shell() {
|
|
132
|
+
const [messages, setMessages] = createSignal([
|
|
133
|
+
{ id: '1', role: 'assistant', content: 'Hello! How can I help?' },
|
|
134
|
+
]);
|
|
135
|
+
|
|
136
|
+
const onSubmit = (e: CustomEvent<{ value: string }>) => {
|
|
137
|
+
setMessages((prev) => [
|
|
138
|
+
...prev,
|
|
139
|
+
{ id: crypto.randomUUID(), role: 'user', content: e.detail.value },
|
|
140
|
+
]);
|
|
141
|
+
// ...call your model, then append an assistant message
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
return (
|
|
145
|
+
<div class="flex flex-col h-full">
|
|
146
|
+
<kai-chat
|
|
147
|
+
// `prop:` forces a property assignment (not an attribute) for rich data.
|
|
148
|
+
prop:messages={messages()}
|
|
149
|
+
on:kai-submit={onSubmit}
|
|
150
|
+
style={{ flex: 1, 'min-height': 0 }}
|
|
151
|
+
/>
|
|
152
|
+
</div>
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
For a resizable web-component layout, use `<kai-resizable>` the same way (set properties, listen
|
|
158
|
+
with `on:`) — though in a Solid app the native `Resizable` above gives you tighter control.
|
|
159
|
+
|
|
160
|
+
> **See it all assembled:** **[Examples → Full Chat App](?path=/story/examples-full-chat-app--default)**
|
|
161
|
+
> wires a sidebar, threaded markdown, reasoning, a tool call, a model switcher, a context meter, and
|
|
162
|
+
> a rich prompt input into one screen — a working reference to crib from.
|
|
163
|
+
|
|
164
|
+
## When to use which
|
|
165
|
+
|
|
166
|
+
- **Native components** (`@kitn.ai/ui`) — full compositional control and the **smallest output**
|
|
167
|
+
for a Solid app, since they compile and tree-shake with your own code. The recommended path when
|
|
168
|
+
you're building in Solid.
|
|
169
|
+
- **Web components** (`@kitn.ai/ui/elements`) — the **fastest drop-in** and fully
|
|
170
|
+
framework-agnostic. Reach for `<kai-chat>` (or any `<kai-*>` shell) when you want batteries included
|
|
171
|
+
or you're sharing UI across frameworks.
|
|
172
|
+
|
|
173
|
+
Mix freely: a native composed thread on one screen, a drop-in `<kai-chat>` on another.
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { Meta } from '@storybook/addon-docs/blocks';
|
|
2
|
+
|
|
3
|
+
<Meta title="Docs/Frameworks/Svelte" />
|
|
4
|
+
|
|
5
|
+
# Svelte
|
|
6
|
+
|
|
7
|
+
Custom elements are **first-class citizens in Svelte**: the compiler sets DOM properties directly
|
|
8
|
+
when you pass non-primitive values, and `on:eventname` wires up CustomEvents with no extra
|
|
9
|
+
boilerplate. No wrappers, no refs, no workarounds needed.
|
|
10
|
+
|
|
11
|
+
There are **two ways to build with the kit**, and you can mix them:
|
|
12
|
+
|
|
13
|
+
1. **`<kai-chat>`** — the batteries-included shell: a whole chat experience in one tag. Fastest start.
|
|
14
|
+
2. **Compose the individual elements** (`<kai-conversations>`, `<kai-markdown>`, `<kai-artifact>`, …)
|
|
15
|
+
into your own layout when you want full control.
|
|
16
|
+
|
|
17
|
+
Both are shown below.
|
|
18
|
+
|
|
19
|
+
## Install & setup
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm i @kitn.ai/ui
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Register the custom elements once (a side-effect import) near your app entry:
|
|
26
|
+
|
|
27
|
+
```js
|
|
28
|
+
// e.g. src/main.js or src/app.svelte <script>
|
|
29
|
+
import '@kitn.ai/ui/elements';
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
- **`@kitn.ai/ui/elements`** — registers every `<kai-*>` element globally. One import is enough
|
|
33
|
+
for the whole app.
|
|
34
|
+
- **No special config needed**: Svelte sets object and array values as DOM **properties** (not
|
|
35
|
+
stringified attributes) when you use the `{prop}` shorthand or `prop={value}` syntax. Custom
|
|
36
|
+
events fire as standard DOM `CustomEvent`s, so `on:eventname` just works.
|
|
37
|
+
- **No CSS to import**: each element is styled inside its own Shadow DOM. Pull in
|
|
38
|
+
`@kitn.ai/ui/theme.css` only if you want to override design tokens (see **Theming**).
|
|
39
|
+
|
|
40
|
+
## Quick start — the all-in-one shell
|
|
41
|
+
|
|
42
|
+
`<kai-chat>` is **transport-agnostic**: give it a `messages` array, handle the `submit` event, and
|
|
43
|
+
stream your model's reply back into state. You own the request; the element owns the UI.
|
|
44
|
+
|
|
45
|
+
```html
|
|
46
|
+
<script>
|
|
47
|
+
import '@kitn.ai/ui/elements';
|
|
48
|
+
|
|
49
|
+
let messages = [
|
|
50
|
+
{ id: '1', role: 'assistant', content: 'Hello! How can I help?' },
|
|
51
|
+
];
|
|
52
|
+
|
|
53
|
+
async function handleSubmit(e) {
|
|
54
|
+
const userContent = e.detail.value;
|
|
55
|
+
const history = [...messages, { id: crypto.randomUUID(), role: 'user', content: userContent }];
|
|
56
|
+
messages = history;
|
|
57
|
+
|
|
58
|
+
const aid = crypto.randomUUID();
|
|
59
|
+
messages = [...history, { id: aid, role: 'assistant', content: '' }];
|
|
60
|
+
|
|
61
|
+
let answer = '';
|
|
62
|
+
for await (const token of streamFromYourAPI(history)) {
|
|
63
|
+
answer += token;
|
|
64
|
+
// Reassign the array (and the changed object) so Svelte detects the update.
|
|
65
|
+
messages = messages.map((m) => (m.id === aid ? { ...m, content: answer } : m));
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
</script>
|
|
69
|
+
|
|
70
|
+
<!--
|
|
71
|
+
The elements are `display: block` and fill their container — lay them out with
|
|
72
|
+
flex and let the element grow with `flex: 1` rather than hard-coding a height.
|
|
73
|
+
-->
|
|
74
|
+
<div style="display: flex; flex-direction: column; height: 100dvh;">
|
|
75
|
+
<kai-chat
|
|
76
|
+
{messages}
|
|
77
|
+
suggestions={['Summarize the chat', 'Start fresh']}
|
|
78
|
+
on:kai-submit={handleSubmit}
|
|
79
|
+
style="flex: 1; min-height: 0;"
|
|
80
|
+
/>
|
|
81
|
+
</div>
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
> **`{messages}`** is Svelte shorthand for `messages={messages}`. Because the value is an array,
|
|
85
|
+
> Svelte assigns it as a DOM **property** (not an attribute), so the element always receives a live
|
|
86
|
+
> JS array — never a stringified version. The same applies to any object prop.
|
|
87
|
+
|
|
88
|
+
## Go further — compose the pieces
|
|
89
|
+
|
|
90
|
+
`<kai-chat>` is one option, not the only one. Every element can be used on its own, so you can
|
|
91
|
+
assemble your own layout. Here's a multi-conversation shell — a `<kai-conversations>` sidebar next
|
|
92
|
+
to the `<kai-chat>` thread:
|
|
93
|
+
|
|
94
|
+
```html
|
|
95
|
+
<script>
|
|
96
|
+
import '@kitn.ai/ui/elements';
|
|
97
|
+
|
|
98
|
+
let conversations = myConversations;
|
|
99
|
+
let activeId = conversations[0]?.id;
|
|
100
|
+
let messages = loadMessages(activeId);
|
|
101
|
+
|
|
102
|
+
function handleConversationSelect(e) {
|
|
103
|
+
activeId = e.detail.id;
|
|
104
|
+
messages = loadMessages(activeId);
|
|
105
|
+
}
|
|
106
|
+
</script>
|
|
107
|
+
|
|
108
|
+
<!--
|
|
109
|
+
Lay panels out with flex: the sidebar is fixed-width, the thread takes the rest
|
|
110
|
+
with `flex: 1`. The elements fill whatever box you give them.
|
|
111
|
+
-->
|
|
112
|
+
<div style="display: flex; height: 100dvh;">
|
|
113
|
+
<kai-conversations
|
|
114
|
+
{conversations}
|
|
115
|
+
{activeId}
|
|
116
|
+
on:kai-conversation-select={handleConversationSelect}
|
|
117
|
+
on:kai-new-chat={() => startNewConversation()}
|
|
118
|
+
on:kai-toggle-sidebar={() => sidebarOpen = !sidebarOpen}
|
|
119
|
+
style="width: 300px; flex-shrink: 0;"
|
|
120
|
+
/>
|
|
121
|
+
|
|
122
|
+
<kai-chat
|
|
123
|
+
{messages}
|
|
124
|
+
on:kai-submit={(e) => sendMessage(e.detail.value)}
|
|
125
|
+
style="flex: 1; min-width: 0;"
|
|
126
|
+
/>
|
|
127
|
+
</div>
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Make the panels resizable
|
|
131
|
+
|
|
132
|
+
Want a draggable divider between the sidebar and the thread? Wrap the panels in `<kai-resizable>`
|
|
133
|
+
with one `<kai-resizable-item>` each — the handles are inserted for you (up to 3 panels). Each item
|
|
134
|
+
takes a `size` (px or `%`) plus optional `min`/`max`; listen for the `change` event
|
|
135
|
+
(`detail.sizes`) to persist the layout.
|
|
136
|
+
|
|
137
|
+
```html
|
|
138
|
+
<script>
|
|
139
|
+
import '@kitn.ai/ui/elements';
|
|
140
|
+
|
|
141
|
+
function handleResize(e) {
|
|
142
|
+
// e.detail.sizes is an array of the current panel sizes
|
|
143
|
+
savePanelSizes(e.detail.sizes);
|
|
144
|
+
}
|
|
145
|
+
</script>
|
|
146
|
+
|
|
147
|
+
<div style="display: flex; flex-direction: column; height: 100dvh;">
|
|
148
|
+
<kai-resizable orientation="horizontal" on:kai-change={handleResize} style="flex: 1; min-height: 0;">
|
|
149
|
+
<kai-resizable-item size="25%" min="200px">
|
|
150
|
+
<kai-conversations {conversations} {activeId} on:kai-conversation-select={handleConversationSelect} />
|
|
151
|
+
</kai-resizable-item>
|
|
152
|
+
<kai-resizable-item>
|
|
153
|
+
<kai-chat {messages} on:kai-submit={handleSubmit} />
|
|
154
|
+
</kai-resizable-item>
|
|
155
|
+
</kai-resizable>
|
|
156
|
+
</div>
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
You can also drop **standalone display elements** anywhere in your own UI — `<kai-markdown>`,
|
|
160
|
+
`<kai-code-block>`, `<kai-artifact>`, `<kai-reasoning>`, `<kai-tool>` — to render rich AI content
|
|
161
|
+
without adopting the whole chat shell. Each fills its container and is controlled via props and
|
|
162
|
+
events.
|
|
163
|
+
|
|
164
|
+
> **See it all assembled:** **[Examples → Full Chat App](?path=/story/examples-full-chat-app--default)**
|
|
165
|
+
> wires a sidebar, threaded markdown, reasoning, a tool call, a model switcher, a context meter, and
|
|
166
|
+
> a rich prompt input into one screen — a working reference to crib from.
|
|
167
|
+
|
|
168
|
+
> **Find every element:** browse the **Components** section in the sidebar. Each element's **API**
|
|
169
|
+
> tab lists its props, events, and copy-paste usage for Svelte (and every other framework).
|
|
170
|
+
|
|
171
|
+
## Props & events
|
|
172
|
+
|
|
173
|
+
The rule for all elements: **rich data goes in as properties, interactions come out as events.**
|
|
174
|
+
|
|
175
|
+
In Svelte, this maps cleanly to the template syntax you already know:
|
|
176
|
+
|
|
177
|
+
| What | Svelte syntax | Notes |
|
|
178
|
+
|---|---|---|
|
|
179
|
+
| Pass a string | `prop="value"` or `{prop}` shorthand | Standard attribute or property |
|
|
180
|
+
| Pass an array / object | `{prop}` or `prop={value}` | Svelte assigns as DOM property — no stringification |
|
|
181
|
+
| Listen to a CustomEvent | `on:eventname={handler}` | `handler(e)` receives the `CustomEvent`; data is on `e.detail` |
|
|
182
|
+
|
|
183
|
+
Key events and their `detail` shapes:
|
|
184
|
+
|
|
185
|
+
| Element | Event | `e.detail` |
|
|
186
|
+
|---|---|---|
|
|
187
|
+
| `kai-chat` | `submit` | `{ value: string }` — the user's input text |
|
|
188
|
+
| `kai-conversations` | `conversationselect` | `{ id: string }` — the selected conversation id |
|
|
189
|
+
| `kai-conversations` | `newchat` | `{}` |
|
|
190
|
+
| `kai-conversations` | `togglesidebar` | `{}` |
|
|
191
|
+
| `kai-resizable` | `change` | `{ sizes: string[] }` — current panel sizes |
|
|
192
|
+
|
|
193
|
+
No adapters, no special directives: Svelte's compiler handles property assignment on custom elements
|
|
194
|
+
automatically, so `{messages}` always delivers a live JS array to the element.
|