@kitn.ai/ui 0.15.0 → 0.16.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 -0
- package/bin/mcp.js +22 -0
- package/dist/bash-InADTalH.js +6 -1
- package/dist/components/artifact.d.ts +58 -0
- package/dist/components/attachments.d.ts +67 -0
- package/dist/components/card-fallback.d.ts +10 -0
- package/dist/components/card-renderer.d.ts +13 -0
- package/dist/components/card.d.ts +28 -0
- package/dist/components/chain-of-thought.d.ts +29 -0
- package/dist/components/chat-container.d.ts +19 -0
- package/dist/components/chat-scope-picker.d.ts +9 -0
- package/dist/components/chat-thread.d.ts +93 -0
- package/dist/components/checkpoint.d.ts +20 -0
- package/dist/components/choice-card.d.ts +77 -0
- package/dist/components/code-block.d.ts +16 -0
- package/dist/components/confirm-card.d.ts +57 -0
- package/dist/components/context.d.ts +65 -0
- package/dist/components/conversation-item.d.ts +8 -0
- package/dist/components/conversation-list.d.ts +11 -0
- package/dist/components/embed.d.ts +21 -0
- package/dist/components/empty.d.ts +43 -0
- package/dist/components/feedback-bar.d.ts +45 -0
- package/dist/components/file-tree.d.ts +57 -0
- package/dist/components/file-upload.d.ts +16 -0
- package/dist/components/form-widgets.d.ts +31 -0
- package/dist/components/form.d.ts +103 -0
- package/dist/components/image.d.ts +12 -0
- package/dist/components/link-preview.d.ts +23 -0
- package/dist/components/loader.d.ts +60 -0
- package/dist/components/markdown.d.ts +8 -0
- package/dist/components/message-skills.d.ts +15 -0
- package/dist/components/message.d.ts +54 -0
- package/dist/components/model-switcher.d.ts +8 -0
- package/dist/components/prompt-input.d.ts +38 -0
- package/dist/components/prompt-suggestion.d.ts +13 -0
- package/dist/components/reasoning.d.ts +20 -0
- package/dist/components/response-stream.d.ts +14 -0
- package/dist/components/scroll-button.d.ts +7 -0
- package/dist/components/slash-command.d.ts +15 -0
- package/dist/components/source.d.ts +23 -0
- package/dist/components/tasks-card.d.ts +71 -0
- package/dist/components/text-shimmer.d.ts +9 -0
- package/dist/components/thinking-bar.d.ts +10 -0
- package/dist/components/tool.d.ts +16 -0
- package/dist/components/use-card-resolution.d.ts +12 -0
- package/dist/components/voice-input.d.ts +7 -0
- package/dist/core-AYMC6_lb.js +5874 -12
- package/dist/css-M7EaDHN_.js +6 -1
- package/dist/elements/artifact.d.ts +1 -0
- package/dist/elements/attachments.d.ts +1 -0
- package/dist/elements/card.d.ts +1 -0
- package/dist/elements/cards.d.ts +0 -0
- package/dist/elements/chain-of-thought.d.ts +13 -0
- package/dist/elements/chat-scope-picker.d.ts +1 -0
- package/dist/elements/chat-types.d.ts +41 -0
- package/dist/elements/chat-workspace.d.ts +1 -0
- package/dist/elements/chat.d.ts +1 -0
- package/dist/elements/checkpoint.d.ts +1 -0
- package/dist/elements/choice.d.ts +1 -0
- package/dist/elements/code-block.d.ts +1 -0
- package/dist/elements/confirm-card.d.ts +1 -0
- package/dist/elements/context-meter.d.ts +1 -0
- package/dist/elements/conversation-list.d.ts +11 -0
- package/dist/elements/css.d.ts +1 -0
- package/dist/elements/default-input.d.ts +40 -0
- package/dist/elements/define.d.ts +42 -0
- package/dist/elements/embed.d.ts +1 -0
- package/dist/elements/empty.d.ts +1 -0
- package/dist/elements/feedback-bar.d.ts +1 -0
- package/dist/elements/file-tree.d.ts +1 -0
- package/dist/elements/file-upload.d.ts +1 -0
- package/dist/elements/form.d.ts +1 -0
- package/dist/elements/image.d.ts +1 -0
- package/dist/elements/link-preview.d.ts +1 -0
- package/dist/elements/loader.d.ts +1 -0
- package/dist/elements/markdown.d.ts +1 -0
- package/dist/elements/message-skills.d.ts +17 -0
- package/dist/elements/message.d.ts +1 -0
- package/dist/elements/model-switcher.d.ts +11 -0
- package/dist/elements/popover.d.ts +1 -0
- package/dist/elements/prompt-input.d.ts +9 -0
- package/dist/elements/prompt-suggestions.d.ts +7 -0
- package/dist/elements/reasoning.d.ts +1 -0
- package/dist/elements/register-impl.d.ts +0 -0
- package/dist/elements/register.d.ts +3 -0
- package/dist/elements/remote.d.ts +1 -0
- package/dist/elements/resizable.d.ts +17 -0
- package/dist/elements/response-stream.d.ts +1 -0
- package/dist/elements/scroll-button.d.ts +1 -0
- package/dist/elements/source.d.ts +18 -0
- package/dist/elements/switch.d.ts +1 -0
- package/dist/elements/tasks.d.ts +1 -0
- package/dist/elements/text-shimmer.d.ts +1 -0
- package/dist/elements/thinking-bar.d.ts +1 -0
- package/dist/elements/tool.d.ts +1 -0
- package/dist/elements/voice-input.d.ts +1 -0
- package/dist/elements.d.ts +732 -0
- package/dist/engine-javascript-vq0WuIJl.js +2516 -14
- package/dist/github-dark-dimmed-DUshB20C.js +4 -1
- package/dist/github-light-JYsPkUQd.js +4 -1
- package/dist/html-CPZ3oZQ7.js +10 -1
- package/dist/index.d.ts +112 -2
- package/dist/index.js +13551 -0
- package/dist/javascript-C25yR2R2.js +6 -1
- package/dist/json-DxJze_jm.js +6 -1
- package/dist/kitn-chat.es.js +1 -77
- package/dist/llms/llms-full.txt +1 -1
- package/dist/llms/llms.txt +1 -1
- package/dist/mcp.es.js +2140 -0
- package/dist/primitives/card-contract.d.ts +103 -0
- package/dist/primitives/card-host.d.ts +12 -0
- package/dist/primitives/card-registry.d.ts +17 -0
- package/dist/primitives/card-resolution.d.ts +8 -0
- package/dist/primitives/card-routing.d.ts +12 -0
- package/dist/primitives/card-validate.d.ts +25 -0
- package/dist/primitives/chat-config.d.ts +31 -0
- package/dist/primitives/controllable.d.ts +13 -0
- package/dist/primitives/embed-providers.d.ts +65 -0
- package/dist/primitives/highlighter.d.ts +23 -0
- package/dist/primitives/link-preview.d.ts +47 -0
- package/dist/primitives/pdf-preview.d.ts +50 -0
- package/dist/primitives/use-auto-resize.d.ts +8 -0
- package/dist/primitives/use-resize-observer.d.ts +1 -0
- package/dist/primitives/use-stick-to-bottom.d.ts +5 -0
- package/dist/primitives/use-text-stream.d.ts +19 -0
- package/dist/primitives/use-voice-recorder.d.ts +9 -0
- package/dist/react/index.d.ts +1118 -0
- package/dist/react/runtime.d.ts +15 -0
- package/dist/react.js +265 -0
- package/dist/register-impl-wCsFPoh9.js +77 -0
- package/dist/register-ujhr1nBS.js +1 -0
- package/dist/remote/host-embed.d.ts +33 -0
- package/dist/remote/index.d.ts +2 -0
- package/dist/remote/origin.d.ts +5 -0
- package/dist/remote/provider-runtime.d.ts +27 -0
- package/dist/remote/provider.d.ts +2 -0
- package/dist/remote/validate.d.ts +4 -0
- package/dist/remote/version.d.ts +4 -0
- package/dist/remote/wire.d.ts +53 -0
- package/dist/svelte--5p79yCD.js +15 -1
- package/dist/tsx-B8rCNbgL.js +6 -1
- package/dist/types.d.ts +42 -0
- package/dist/typescript-RycA9KXf.js +6 -1
- package/dist/ui/action-icons.d.ts +11 -0
- package/dist/ui/avatar.d.ts +8 -0
- package/dist/ui/badge.d.ts +9 -0
- package/dist/ui/button.d.ts +10 -0
- package/dist/ui/collapsible.d.ts +27 -0
- package/dist/ui/dropdown.d.ts +20 -0
- package/dist/ui/hover-card.d.ts +28 -0
- package/dist/ui/overlay.d.ts +67 -0
- package/dist/ui/popover.d.ts +32 -0
- package/dist/ui/resizable.d.ts +76 -0
- package/dist/ui/scroll-area.d.ts +5 -0
- package/dist/ui/separator.d.ts +5 -0
- package/dist/ui/skeleton.d.ts +5 -0
- package/dist/ui/switch.d.ts +19 -0
- package/dist/ui/textarea.d.ts +6 -0
- package/dist/ui/tooltip.d.ts +8 -0
- package/dist/utils/cn.d.ts +2 -0
- package/dist/vue-BmIZj4XD.js +33 -1
- package/frameworks/react/index.tsx +4 -0
- package/frameworks/react/runtime.tsx +16 -2
- package/llms-full.txt +1 -1
- package/llms.txt +1 -1
- package/package.json +29 -11
- package/src/agent-tooling/archetypes.ts +46 -0
- package/src/agent-tooling/integrations/cloudflare.ts +88 -0
- package/src/agent-tooling/integrations/langgraph.ts +60 -0
- package/src/agent-tooling/integrations/mastra.ts +27 -0
- package/src/agent-tooling/integrations/mock.ts +34 -0
- package/src/agent-tooling/integrations/ollama.ts +47 -0
- package/src/agent-tooling/integrations/openrouter.ts +26 -0
- package/src/agent-tooling/integrations/pi.ts +40 -0
- package/src/agent-tooling/integrations/pydantic-ai.ts +52 -0
- package/src/agent-tooling/integrations/vercel-ai-sdk.ts +44 -0
- package/src/agent-tooling/mcp/manifest.ts +128 -0
- package/src/agent-tooling/mcp/server.ts +59 -0
- package/src/agent-tooling/mcp/stdio.ts +18 -0
- package/src/agent-tooling/mcp/tools/debug.ts +305 -0
- package/src/agent-tooling/mcp/tools/reference.ts +132 -0
- package/src/agent-tooling/mcp/tools/scaffold.ts +1627 -0
- package/src/agent-tooling/mcp/tools/theme.ts +340 -0
- package/src/agent-tooling/mcp/tools/types.ts +14 -0
- package/src/agent-tooling/registry.ts +41 -0
- package/src/agent-tooling/types.ts +30 -0
- package/src/elements/compiled.css +1 -1
- package/src/elements/define.tsx +7 -1
- package/src/elements/element-types.d.ts +2 -1
- package/src/elements/register-impl.ts +55 -0
- package/src/elements/register.ts +17 -51
- package/theme.css +4 -2
- package/src/components/artifact.stories.tsx +0 -138
- package/src/components/attachments.stories.tsx +0 -303
- package/src/components/attachments.test.tsx +0 -64
- package/src/components/chain-of-thought.stories.tsx +0 -211
- package/src/components/chat-container.stories.tsx +0 -187
- package/src/components/chat-thread.test.tsx +0 -58
- package/src/components/checkpoint.stories.tsx +0 -102
- package/src/components/code-block.stories.tsx +0 -150
- package/src/components/confirm-card.stories.tsx +0 -74
- package/src/components/context.stories.tsx +0 -229
- package/src/components/context.test.tsx +0 -133
- package/src/components/conversation-item.stories.tsx +0 -125
- package/src/components/conversation-list.stories.tsx +0 -133
- package/src/components/default-input.test.tsx +0 -111
- package/src/components/empty.stories.tsx +0 -434
- package/src/components/feedback-bar.stories.tsx +0 -138
- package/src/components/feedback-bar.test.tsx +0 -103
- package/src/components/file-tree.stories.tsx +0 -73
- package/src/components/file-upload.stories.tsx +0 -156
- package/src/components/image.stories.tsx +0 -89
- package/src/components/loader.stories.tsx +0 -181
- package/src/components/markdown.stories.tsx +0 -180
- package/src/components/message-action-bar.test.tsx +0 -128
- package/src/components/message-narrow.stories.tsx +0 -329
- package/src/components/message-skills.stories.tsx +0 -211
- package/src/components/message.stories.tsx +0 -281
- package/src/components/model-switcher.stories.tsx +0 -123
- package/src/components/model-switcher.test.tsx +0 -65
- package/src/components/prompt-input.stories.tsx +0 -222
- package/src/components/prompt-suggestion.stories.tsx +0 -142
- package/src/components/reasoning.stories.tsx +0 -140
- package/src/components/resizable.test.tsx +0 -226
- package/src/components/scroll-button.stories.tsx +0 -100
- package/src/components/slash-command.stories.tsx +0 -163
- package/src/components/source-list.test.tsx +0 -152
- package/src/components/source.stories.tsx +0 -124
- package/src/components/tasks-card.stories.tsx +0 -78
- package/src/components/text-shimmer.stories.tsx +0 -87
- package/src/components/thinking-bar.stories.tsx +0 -87
- package/src/components/tool.stories.tsx +0 -153
- package/src/components/voice-input.stories.tsx +0 -83
- package/src/elements/artifact.stories.tsx +0 -506
- package/src/elements/attachments.stories.tsx +0 -190
- package/src/elements/card.stories.tsx +0 -113
- package/src/elements/cards.stories.tsx +0 -59
- package/src/elements/catalog.stories.tsx +0 -491
- package/src/elements/chain-of-thought.declarative.test.tsx +0 -153
- package/src/elements/chain-of-thought.stories.tsx +0 -113
- package/src/elements/chat-scope-picker.stories.tsx +0 -73
- package/src/elements/chat-workspace.stories.tsx +0 -288
- package/src/elements/chat.stories.tsx +0 -151
- package/src/elements/checkpoint.stories.tsx +0 -72
- package/src/elements/choice.stories.tsx +0 -240
- package/src/elements/code-block.stories.tsx +0 -83
- package/src/elements/composed-shell.stories.tsx +0 -316
- package/src/elements/confirm-card.stories.tsx +0 -227
- package/src/elements/context-meter.stories.tsx +0 -151
- package/src/elements/conversation-list.declarative.test.tsx +0 -137
- package/src/elements/conversation-list.stories.tsx +0 -243
- package/src/elements/embed.stories.tsx +0 -213
- package/src/elements/empty.stories.tsx +0 -111
- package/src/elements/feedback-bar.stories.tsx +0 -114
- package/src/elements/file-tree.stories.tsx +0 -134
- package/src/elements/file-upload.stories.tsx +0 -82
- package/src/elements/form.stories.tsx +0 -248
- package/src/elements/image.stories.tsx +0 -71
- package/src/elements/link-preview.stories.tsx +0 -209
- package/src/elements/loader.stories.tsx +0 -88
- package/src/elements/markdown.stories.tsx +0 -76
- package/src/elements/message-skills.declarative.test.tsx +0 -104
- package/src/elements/message-skills.stories.tsx +0 -114
- package/src/elements/message.stories.tsx +0 -218
- package/src/elements/model-switcher.declarative.test.tsx +0 -130
- package/src/elements/model-switcher.stories.tsx +0 -198
- package/src/elements/popover.stories.tsx +0 -80
- package/src/elements/prompt-input-slash-command.test.tsx +0 -128
- package/src/elements/prompt-input-stoppable.test.tsx +0 -88
- package/src/elements/prompt-input-toolbar-actions.test.tsx +0 -120
- package/src/elements/prompt-input.stories.tsx +0 -331
- package/src/elements/prompt-suggestions.declarative.test.tsx +0 -164
- package/src/elements/prompt-suggestions.stories.tsx +0 -213
- package/src/elements/reasoning.stories.tsx +0 -77
- package/src/elements/remote.stories.tsx +0 -314
- package/src/elements/resizable.stories.tsx +0 -426
- package/src/elements/response-stream.stories.tsx +0 -79
- package/src/elements/scroll-button.stories.tsx +0 -202
- package/src/elements/scroll-button.test.tsx +0 -148
- package/src/elements/source-list.stories.tsx +0 -143
- package/src/elements/source.stories.tsx +0 -88
- package/src/elements/switch.stories.tsx +0 -56
- package/src/elements/tasks.stories.tsx +0 -237
- package/src/elements/text-shimmer.stories.tsx +0 -64
- package/src/elements/thinking-bar.stories.tsx +0 -72
- package/src/elements/tool.stories.tsx +0 -89
- package/src/elements/voice-input.stories.tsx +0 -88
- package/src/primitives/controllable.test.ts +0 -47
- package/src/stories/chat-panel-layout.stories.tsx +0 -145
- package/src/stories/chat-scene.tsx +0 -571
- package/src/stories/checkpoint-restore.stories.tsx +0 -256
- package/src/stories/context-usage.stories.tsx +0 -212
- package/src/stories/conversation-with-reasoning.stories.tsx +0 -182
- package/src/stories/conversation-with-sources.stories.tsx +0 -471
- package/src/stories/docs/Accessibility.mdx +0 -119
- package/src/stories/docs/ChildElements.mdx +0 -269
- package/src/stories/docs/ForAIAgents.mdx +0 -162
- package/src/stories/docs/GettingStarted.mdx +0 -65
- package/src/stories/docs/Installation.mdx +0 -83
- package/src/stories/docs/Introduction.mdx +0 -50
- package/src/stories/docs/SolidJsAdvanced.mdx +0 -17
- package/src/stories/docs/Theming.mdx +0 -85
- package/src/stories/docs/element-controls.ts +0 -121
- package/src/stories/docs/frameworks/Angular.mdx +0 -245
- package/src/stories/docs/frameworks/Html.mdx +0 -227
- package/src/stories/docs/frameworks/Overview.mdx +0 -47
- package/src/stories/docs/frameworks/React.mdx +0 -227
- package/src/stories/docs/frameworks/Solid.mdx +0 -173
- package/src/stories/docs/frameworks/Svelte.mdx +0 -194
- package/src/stories/docs/frameworks/Vue.mdx +0 -238
- package/src/stories/docs/generative-ui-overview.mdx +0 -186
- package/src/stories/docs/recipes/SpeechToText.mdx +0 -7
- package/src/stories/docs/recipes/Streaming.mdx +0 -68
- package/src/stories/docs/recipes/TextToSpeech.mdx +0 -35
- package/src/stories/docs/theme-editor/canvas.tsx +0 -32
- package/src/stories/docs/theme-editor/inspector.tsx +0 -66
- package/src/stories/docs/theme-editor/presets.test.ts +0 -32
- package/src/stories/docs/theme-editor/presets.ts +0 -64
- package/src/stories/docs/theme-editor/theme-css.test.ts +0 -19
- package/src/stories/docs/theme-editor/theme-css.ts +0 -15
- package/src/stories/docs/theme-editor/theme-editor.tsx +0 -146
- package/src/stories/docs/theme-tokens.tsx +0 -174
- package/src/stories/examples/ChoosingComponents.mdx +0 -106
- package/src/stories/examples/sample-data.ts +0 -79
- package/src/stories/examples/usage/checkpoint-restore.ts +0 -156
- package/src/stories/examples/usage/context-usage.ts +0 -591
- package/src/stories/examples/usage/conversation-with-reasoning.ts +0 -224
- package/src/stories/examples/usage/conversation-with-sources.ts +0 -589
- package/src/stories/examples/usage/empty-state.ts +0 -144
- package/src/stories/examples/usage/full-chat-app.ts +0 -277
- package/src/stories/examples/usage/index.ts +0 -63
- package/src/stories/examples/usage/message-actions.ts +0 -704
- package/src/stories/examples/usage/pattern-centered-conversation.ts +0 -446
- package/src/stories/examples/usage/pattern-chat-panel-layout.ts +0 -442
- package/src/stories/examples/usage/pattern-docked-widget.ts +0 -479
- package/src/stories/examples/usage/prompt-input-variants.ts +0 -1356
- package/src/stories/examples/usage/streaming-response.ts +0 -687
- package/src/stories/examples/usage/types.ts +0 -33
- package/src/stories/full-chat.stories.tsx +0 -18
- package/src/stories/message-actions.stories.tsx +0 -230
- package/src/stories/pattern-centered-conversation.stories.tsx +0 -93
- package/src/stories/pattern-docked-widget.stories.tsx +0 -93
- package/src/stories/pattern-empty-state.stories.tsx +0 -76
- package/src/stories/prompt-input-variants.stories.tsx +0 -456
- package/src/stories/streaming-response.stories.tsx +0 -438
- package/src/stories/theme-editor.stories.tsx +0 -16
- package/src/stories/token-reference.stories.tsx +0 -18
- package/src/stories/typography.stories.tsx +0 -78
- package/src/ui/avatar.stories.tsx +0 -103
- package/src/ui/badge.stories.tsx +0 -86
- package/src/ui/button.stories.tsx +0 -145
- package/src/ui/collapsible.stories.tsx +0 -69
- package/src/ui/dropdown.stories.tsx +0 -59
- package/src/ui/hover-card.stories.tsx +0 -77
- package/src/ui/hover-card.test.tsx +0 -30
- package/src/ui/overlay.stories.tsx +0 -115
- package/src/ui/popover.stories.tsx +0 -81
- package/src/ui/popover.test.tsx +0 -99
- package/src/ui/resizable.stories.tsx +0 -236
- package/src/ui/scroll-area.stories.tsx +0 -50
- package/src/ui/separator.stories.tsx +0 -81
- package/src/ui/skeleton.stories.tsx +0 -337
- package/src/ui/switch.stories.tsx +0 -51
- package/src/ui/switch.test.tsx +0 -59
- package/src/ui/textarea.stories.tsx +0 -76
- package/src/ui/tooltip.stories.tsx +0 -74
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
import type { Meta, StoryObj } from 'storybook-solidjs-vite';
|
|
2
|
-
import { onMount } from 'solid-js';
|
|
3
|
-
import './register'; // side effect: registers <kai-chat>, <kai-conversations>, <kai-prompt-input>
|
|
4
|
-
import type { ChatMessage } from './chat-types';
|
|
5
|
-
import { argTypesFor, specDescription } from '../stories/docs/element-controls';
|
|
6
|
-
|
|
7
|
-
// The web components are custom DOM elements, so declare the tags for JSX.
|
|
8
|
-
declare module 'solid-js' {
|
|
9
|
-
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
10
|
-
namespace JSX {
|
|
11
|
-
interface IntrinsicElements {
|
|
12
|
-
'kai-chat': JSX.HTMLAttributes<HTMLElement>;
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const sampleMessages: ChatMessage[] = [
|
|
18
|
-
{ id: '1', role: 'user', content: 'How do I center a div?' },
|
|
19
|
-
{
|
|
20
|
-
id: '2',
|
|
21
|
-
role: 'assistant',
|
|
22
|
-
content:
|
|
23
|
-
'The modern way is a grid:\n\n```css\n.box {\n display: grid;\n place-items: center;\n}\n```\n\nThat centers the child on both axes.',
|
|
24
|
-
actions: ['copy', 'like', 'dislike'],
|
|
25
|
-
},
|
|
26
|
-
];
|
|
27
|
-
|
|
28
|
-
type ChatEl = HTMLElement & {
|
|
29
|
-
messages?: ChatMessage[];
|
|
30
|
-
value?: string;
|
|
31
|
-
placeholder?: string;
|
|
32
|
-
loading?: boolean;
|
|
33
|
-
suggestionMode?: string;
|
|
34
|
-
proseSize?: string;
|
|
35
|
-
codeTheme?: string;
|
|
36
|
-
codeHighlight?: boolean;
|
|
37
|
-
chatTitle?: string;
|
|
38
|
-
currentModel?: string;
|
|
39
|
-
scrollButton?: boolean;
|
|
40
|
-
search?: boolean;
|
|
41
|
-
voice?: boolean;
|
|
42
|
-
slashCompact?: boolean;
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
/** Live demo of the actual `<kai-chat>` custom element (Shadow DOM and all). */
|
|
46
|
-
function ChatElement(props: { args?: Record<string, unknown> }) {
|
|
47
|
-
let el: ChatEl | undefined;
|
|
48
|
-
onMount(() => {
|
|
49
|
-
if (el) {
|
|
50
|
-
// Fixed array data
|
|
51
|
-
el.messages = sampleMessages;
|
|
52
|
-
// Scalar args from Controls
|
|
53
|
-
const args = props.args;
|
|
54
|
-
if (args) {
|
|
55
|
-
const scalarNames = [
|
|
56
|
-
'value', 'placeholder', 'loading', 'suggestionMode', 'proseSize',
|
|
57
|
-
'codeTheme', 'codeHighlight', 'chatTitle', 'currentModel',
|
|
58
|
-
'scrollButton', 'search', 'voice', 'slashCompact',
|
|
59
|
-
];
|
|
60
|
-
for (const name of scalarNames) {
|
|
61
|
-
if (name in args) (el as unknown as Record<string, unknown>)[name] = args[name];
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
});
|
|
66
|
-
return <kai-chat ref={(e) => (el = e as ChatEl)} style={{ display: 'block', height: '560px' }} />;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const HTML_SNIPPET = `<!-- Works in any framework or plain HTML -->
|
|
70
|
-
<kai-chat id="chat" style="display:block; height:100vh;"></kai-chat>
|
|
71
|
-
|
|
72
|
-
<script type="module">
|
|
73
|
-
import '@kitn.ai/ui/elements'; // registers the custom elements
|
|
74
|
-
|
|
75
|
-
const chat = document.getElementById('chat');
|
|
76
|
-
chat.messages = [
|
|
77
|
-
{ id: '1', role: 'user', content: 'How do I center a div?' },
|
|
78
|
-
{ id: '2', role: 'assistant', content: 'Use \`display: grid; place-items: center;\`' },
|
|
79
|
-
];
|
|
80
|
-
|
|
81
|
-
// events are CustomEvents on the element (they do not bubble)
|
|
82
|
-
chat.addEventListener('kai-submit', (e) => console.log('user sent:', e.detail.value));
|
|
83
|
-
</script>`;
|
|
84
|
-
|
|
85
|
-
const SOLID_SNIPPET = `import '@kitn.ai/ui/elements'; // registers the custom elements
|
|
86
|
-
import { onMount } from 'solid-js';
|
|
87
|
-
import type { ChatMessage } from '@kitn.ai/ui/elements';
|
|
88
|
-
|
|
89
|
-
function Chat() {
|
|
90
|
-
let el: HTMLElement & { messages?: ChatMessage[] };
|
|
91
|
-
const messages: ChatMessage[] = [
|
|
92
|
-
{ id: '1', role: 'user', content: 'How do I center a div?' },
|
|
93
|
-
{ id: '2', role: 'assistant', content: 'Use \`display: grid; place-items: center;\`' },
|
|
94
|
-
];
|
|
95
|
-
onMount(() => { el.messages = messages; });
|
|
96
|
-
return (
|
|
97
|
-
<kai-chat
|
|
98
|
-
ref={el}
|
|
99
|
-
style={{ display: 'block', height: '100vh' }}
|
|
100
|
-
on:kai-submit={(e) => console.log('user sent:', e.detail.value)}
|
|
101
|
-
/>
|
|
102
|
-
);
|
|
103
|
-
}`;
|
|
104
|
-
|
|
105
|
-
const meta = {
|
|
106
|
-
title: 'Components/Chat',
|
|
107
|
-
tags: ['autodocs'],
|
|
108
|
-
argTypes: argTypesFor('kai-chat'),
|
|
109
|
-
parameters: {
|
|
110
|
-
layout: 'fullscreen',
|
|
111
|
-
docs: {
|
|
112
|
-
description: specDescription('kai-chat', [
|
|
113
|
-
'`<kai-chat>` is the framework-agnostic **web component** version of the chat UI — a complete message thread plus prompt input, 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.',
|
|
114
|
-
'**When to use:** dropping a full chat into 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 primitives (`ChatContainer`, `Message`, `PromptInput`) instead.',
|
|
115
|
-
'**How to use:** register once with `import \'@kitn.ai/ui/elements\'`, set rich data as JS **properties** (`el.messages = [...]`), and listen for **CustomEvents** (`kai-submit`, `kai-message-action`, `kai-value-change`) directly on the element.',
|
|
116
|
-
'**Anatomy:** **header** (model switcher + context-meter, shown when `models`/`context` props are set) → **message list** (scrollable thread of `<Message>` rows, each rendered per `role`; a scroll-to-bottom button appears when scrolled up) → **prompt composer** (`<PromptInput>`: textarea + toolbar with suggestions, slash-command palette, voice/search buttons, and optional attachment area).',
|
|
117
|
-
'**Placement:** as a top-level panel or full-page surface. Give it an explicit height (e.g. `height: 100vh`).',
|
|
118
|
-
'See the **Code** tab below for the HTML usage; the *SolidJS* story shows the same element inside a Solid component.',
|
|
119
|
-
]),
|
|
120
|
-
},
|
|
121
|
-
},
|
|
122
|
-
} satisfies Meta;
|
|
123
|
-
|
|
124
|
-
export default meta;
|
|
125
|
-
type Story = StoryObj;
|
|
126
|
-
|
|
127
|
-
/** The element used the plain-HTML / any-framework way. */
|
|
128
|
-
export const Default: Story = {
|
|
129
|
-
args: {
|
|
130
|
-
placeholder: 'Send a message...',
|
|
131
|
-
loading: false,
|
|
132
|
-
suggestionMode: 'submit',
|
|
133
|
-
proseSize: 'sm',
|
|
134
|
-
codeTheme: 'github-dark-dimmed',
|
|
135
|
-
codeHighlight: true,
|
|
136
|
-
scrollButton: true,
|
|
137
|
-
search: false,
|
|
138
|
-
voice: false,
|
|
139
|
-
slashCompact: false,
|
|
140
|
-
},
|
|
141
|
-
render: (args: Record<string, unknown>) => <ChatElement args={args} />,
|
|
142
|
-
parameters: { docs: { source: { code: HTML_SNIPPET, language: 'html' } } },
|
|
143
|
-
};
|
|
144
|
-
|
|
145
|
-
/** The same element used inside a SolidJS component (properties via `ref`, events via `on:`). */
|
|
146
|
-
export const InSolidJS: Story = {
|
|
147
|
-
name: 'In SolidJS',
|
|
148
|
-
render: () => <ChatElement />,
|
|
149
|
-
parameters: { docs: { source: { code: SOLID_SNIPPET, language: 'tsx' } } },
|
|
150
|
-
};
|
|
151
|
-
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import type { Meta, StoryObj } from 'storybook-solidjs-vite';
|
|
2
|
-
import { onMount } from 'solid-js';
|
|
3
|
-
import './register'; // side effect: registers the custom elements
|
|
4
|
-
import { argTypesFor, specDescription } from '../stories/docs/element-controls';
|
|
5
|
-
|
|
6
|
-
// The web components are custom DOM elements, so declare the tags for JSX.
|
|
7
|
-
declare module 'solid-js' {
|
|
8
|
-
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
9
|
-
namespace JSX {
|
|
10
|
-
interface IntrinsicElements {
|
|
11
|
-
'kai-checkpoint': JSX.HTMLAttributes<HTMLElement>;
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/** Render the actual `<kai-checkpoint>` custom element configured by attributes. */
|
|
17
|
-
function CheckpointElement(props: { label?: string; tooltip?: string; variant?: string; size?: string }) {
|
|
18
|
-
let el: HTMLElement | undefined;
|
|
19
|
-
onMount(() => {
|
|
20
|
-
if (!el) return;
|
|
21
|
-
if (props.label) el.setAttribute('label', props.label);
|
|
22
|
-
if (props.tooltip) el.setAttribute('tooltip', props.tooltip);
|
|
23
|
-
if (props.variant) el.setAttribute('variant', props.variant);
|
|
24
|
-
if (props.size) el.setAttribute('size', props.size);
|
|
25
|
-
el.addEventListener('kai-select', () => console.log('checkpoint selected'));
|
|
26
|
-
});
|
|
27
|
-
return <kai-checkpoint ref={(e) => (el = e as HTMLElement)} style={{ display: 'inline-block', padding: '16px' }} />;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const HTML_SNIPPET = `<!-- Works in any framework or plain HTML -->
|
|
31
|
-
<kai-checkpoint label="Restore" tooltip="Restore this checkpoint" variant="outline" size="sm"></kai-checkpoint>
|
|
32
|
-
|
|
33
|
-
<script type="module">
|
|
34
|
-
import '@kitn.ai/ui/elements'; // registers the custom elements
|
|
35
|
-
|
|
36
|
-
const cp = document.querySelector('kai-checkpoint');
|
|
37
|
-
// events are CustomEvents on the element (they do not bubble)
|
|
38
|
-
cp.addEventListener('kai-select', () => console.log('restore checkpoint'));
|
|
39
|
-
</script>`;
|
|
40
|
-
|
|
41
|
-
const meta = {
|
|
42
|
-
title: 'Components/Checkpoint',
|
|
43
|
-
tags: ['autodocs'],
|
|
44
|
-
argTypes: argTypesFor('kai-checkpoint'),
|
|
45
|
-
parameters: {
|
|
46
|
-
layout: 'fullscreen',
|
|
47
|
-
docs: {
|
|
48
|
-
description: specDescription('kai-checkpoint', [
|
|
49
|
-
'`<kai-checkpoint>` is the framework-agnostic **web component** for a bookmark/checkpoint button (with an optional tooltip and label), isolated in **Shadow DOM**.',
|
|
50
|
-
'**When to use:** marking a restore point in a conversation in a non-Solid app. In SolidJS, compose the `Checkpoint` primitives.',
|
|
51
|
-
'**Placement:** inline inside a message row (e.g. in the action bar) or in a chat toolbar; it is a compact `inline-block` button and does not need a dedicated row.',
|
|
52
|
-
"**How to use:** register once with `import '@kitn.ai/ui/elements'`, set `label`, `tooltip`, `variant` (`ghost` | `default` | `outline`), and `size` via attributes, and listen for the `kai-select` **CustomEvent** on click.",
|
|
53
|
-
'See the **Code** tab for HTML usage.',
|
|
54
|
-
]),
|
|
55
|
-
},
|
|
56
|
-
},
|
|
57
|
-
} satisfies Meta;
|
|
58
|
-
|
|
59
|
-
export default meta;
|
|
60
|
-
type Story = StoryObj;
|
|
61
|
-
|
|
62
|
-
/** A labeled checkpoint button. (Add a `tooltip` attribute for a hover hint — see the Code tab.) */
|
|
63
|
-
export const Labeled: Story = {
|
|
64
|
-
render: () => <CheckpointElement label="Restore" variant="outline" />,
|
|
65
|
-
parameters: { docs: { source: { code: HTML_SNIPPET, language: 'html' } } },
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
/** Icon-only (no label), using an `icon` size. */
|
|
69
|
-
export const IconOnly: Story = {
|
|
70
|
-
name: 'Icon Only',
|
|
71
|
-
render: () => <CheckpointElement size="icon-sm" />,
|
|
72
|
-
};
|
|
@@ -1,240 +0,0 @@
|
|
|
1
|
-
import type { Meta, StoryObj } from 'storybook-solidjs-vite';
|
|
2
|
-
import { createSignal, onMount, type JSX } from 'solid-js';
|
|
3
|
-
import './choice';
|
|
4
|
-
import { argTypesFor, specDescription } from '../stories/docs/element-controls';
|
|
5
|
-
import type { ChoiceCardData } from '../components/choice-card';
|
|
6
|
-
import type { CardEvent } from '../primitives/card-contract';
|
|
7
|
-
|
|
8
|
-
declare module 'solid-js' {
|
|
9
|
-
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
10
|
-
namespace JSX {
|
|
11
|
-
interface IntrinsicElements {
|
|
12
|
-
'kai-choice': JSX.HTMLAttributes<HTMLElement> & {
|
|
13
|
-
heading?: string;
|
|
14
|
-
'card-id'?: string;
|
|
15
|
-
ref?: (el: HTMLElement) => void;
|
|
16
|
-
};
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
type ChoiceEl = HTMLElement & { data?: ChoiceCardData; resolution?: Record<string, unknown> };
|
|
22
|
-
|
|
23
|
-
function Frame(props: { children: JSX.Element }) {
|
|
24
|
-
return <div style={{ 'max-width': '460px' }}>{props.children}</div>;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/** Mounts a <kai-choice>, sets `.data`, logs the emitted CardEvent under the render. */
|
|
28
|
-
function ChoiceDemo(props: { def: ChoiceCardData; cardId: string; heading?: string }) {
|
|
29
|
-
const [log, setLog] = createSignal<CardEvent[]>([]);
|
|
30
|
-
let el: ChoiceEl | undefined;
|
|
31
|
-
onMount(() => {
|
|
32
|
-
if (!el) return;
|
|
33
|
-
el.data = props.def;
|
|
34
|
-
el.addEventListener('kai-card', (e) => {
|
|
35
|
-
const detail = (e as CustomEvent<CardEvent>).detail;
|
|
36
|
-
setLog((prev) => [...prev, detail]);
|
|
37
|
-
});
|
|
38
|
-
});
|
|
39
|
-
return (
|
|
40
|
-
<Frame>
|
|
41
|
-
<div style={{ display: 'flex', 'flex-direction': 'column', gap: '12px' }}>
|
|
42
|
-
<kai-choice ref={(e) => (el = e as ChoiceEl)} card-id={props.cardId} heading={props.heading} />
|
|
43
|
-
<pre
|
|
44
|
-
style={{
|
|
45
|
-
margin: 0,
|
|
46
|
-
'max-height': '180px',
|
|
47
|
-
overflow: 'auto',
|
|
48
|
-
background: 'var(--color-muted, #f4f4f5)',
|
|
49
|
-
'border-radius': '8px',
|
|
50
|
-
padding: '8px',
|
|
51
|
-
'font-size': '12px',
|
|
52
|
-
}}
|
|
53
|
-
>
|
|
54
|
-
{log().length === 0 ? '// emitted CardEvents appear here' : JSON.stringify(log(), null, 2)}
|
|
55
|
-
</pre>
|
|
56
|
-
</div>
|
|
57
|
-
</Frame>
|
|
58
|
-
);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const PLANS: ChoiceCardData = {
|
|
62
|
-
prompt: 'Which plan fits your team?',
|
|
63
|
-
options: [
|
|
64
|
-
{ id: 'free', label: 'Free', description: 'For trying things out', meta: '$0' },
|
|
65
|
-
{
|
|
66
|
-
id: 'pro',
|
|
67
|
-
label: 'Pro',
|
|
68
|
-
description: 'For growing teams',
|
|
69
|
-
meta: '$12/seat',
|
|
70
|
-
recommended: true,
|
|
71
|
-
payload: { plan: 'pro' },
|
|
72
|
-
},
|
|
73
|
-
{ id: 'enterprise', label: 'Enterprise', description: 'SSO, audit log, SLA', meta: 'Contact us' },
|
|
74
|
-
{ id: 'legacy', label: 'Legacy', description: 'No longer available', disabled: true },
|
|
75
|
-
],
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
const TEMPLATES: ChoiceCardData = {
|
|
79
|
-
prompt: 'Pick a workspace template.',
|
|
80
|
-
submitLabel: 'Create workspace',
|
|
81
|
-
options: [
|
|
82
|
-
{
|
|
83
|
-
id: 'blank',
|
|
84
|
-
label: 'Blank',
|
|
85
|
-
description: 'Start from scratch',
|
|
86
|
-
media: { image: 'https://placehold.co/80x80/png?text=Blank', imageAlt: 'A blank canvas' },
|
|
87
|
-
},
|
|
88
|
-
{
|
|
89
|
-
id: 'kanban',
|
|
90
|
-
label: 'Kanban',
|
|
91
|
-
description: 'Board with columns',
|
|
92
|
-
recommended: true,
|
|
93
|
-
media: { image: 'https://placehold.co/80x80/png?text=Kanban', imageAlt: 'A kanban board' },
|
|
94
|
-
payload: { template: 'kanban' },
|
|
95
|
-
},
|
|
96
|
-
{
|
|
97
|
-
id: 'docs',
|
|
98
|
-
label: 'Docs',
|
|
99
|
-
description: 'Wiki-style pages',
|
|
100
|
-
media: { image: 'https://placehold.co/80x80/png?text=Docs', imageAlt: 'A document page' },
|
|
101
|
-
},
|
|
102
|
-
],
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
const QUICK_REPLIES: ChoiceCardData = {
|
|
106
|
-
prompt: 'How did this answer land?',
|
|
107
|
-
options: [
|
|
108
|
-
{ id: 'great', label: 'That solved it', payload: { sentiment: 'positive' } },
|
|
109
|
-
{ id: 'partly', label: 'Partly — needs more', payload: { sentiment: 'neutral' } },
|
|
110
|
-
{ id: 'no', label: 'Not what I meant', payload: { sentiment: 'negative' } },
|
|
111
|
-
],
|
|
112
|
-
allowOther: { label: 'Something else…', placeholder: 'Tell me what you expected' },
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
const HEADING_MAP: Record<string, string | undefined> = {
|
|
116
|
-
'card-plans': 'Choose a plan',
|
|
117
|
-
'card-templates': 'New workspace',
|
|
118
|
-
'card-replies': undefined,
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
const HTML_SNIPPET = (def: ChoiceCardData, cardId: string) => {
|
|
122
|
-
const heading = HEADING_MAP[cardId];
|
|
123
|
-
return `<kai-choice${heading ? ` heading="${heading}"` : ''}></kai-choice>
|
|
124
|
-
<script type="module">
|
|
125
|
-
import '@kitn.ai/ui/elements'; // registers the custom elements
|
|
126
|
-
|
|
127
|
-
const el = document.querySelector('kai-choice');
|
|
128
|
-
// \`data\` is the CardEnvelope.data (set as a property).
|
|
129
|
-
el.data = ${JSON.stringify(def, null, 2)};
|
|
130
|
-
|
|
131
|
-
// Cards bubble ONE \`kai-card\` CustomEvent carrying a typed CardEvent.
|
|
132
|
-
el.addEventListener('kai-card', (e) => {
|
|
133
|
-
const ev = e.detail; // { kind:'action', cardId, action, payload? } | { kind:'ready', ... } | ...
|
|
134
|
-
if (ev.kind === 'action') console.log('chose', ev.action, ev.payload);
|
|
135
|
-
});
|
|
136
|
-
</script>`;
|
|
137
|
-
};
|
|
138
|
-
|
|
139
|
-
const meta = {
|
|
140
|
-
title: 'Generative UI/Cards/kai-choice',
|
|
141
|
-
tags: ['autodocs'],
|
|
142
|
-
argTypes: argTypesFor('kai-choice'),
|
|
143
|
-
parameters: {
|
|
144
|
-
layout: 'padded',
|
|
145
|
-
docs: {
|
|
146
|
-
description: specDescription('kai-choice', [
|
|
147
|
-
"`<kai-choice>` is a **single-select** 'pick one of N rich options' card (set via the `data` **property**): an optional prompt + a radiogroup of list rows + a **Submit** button. Clicking a row (or Space/Enter on the focused row) **selects** it locally — nothing is emitted. Submit then emits the Card contract's **`action`** verb up a bubbling **`kai-card`** CustomEvent of `{ kind:'action', cardId, action: option.id, payload? }`, then **resolves** the card (the chosen option shown read-only) so the same pick can't double-fire. The Submit label is `submitLabel` (default 'Submit').",
|
|
148
|
-
'**Rich-but-bounded options:** every field except `id`/`label` is optional — `description`, `media` (image + `imageAlt`, or a named `icon`), `meta` (trailing price/badge), `recommended` (a pill), `disabled` (inert + skipped in keyboard nav), and an opaque `payload` echoed back. A weaker model can just omit them.',
|
|
149
|
-
"**`allowOther`** (opt-in) appends a final 'Other…' row: selecting it reveals an inline text input. The single shared **Submit** stays disabled until the text is non-empty; submitting emits `{ kind:'action', action:'__other__', payload:{ text } }`.",
|
|
150
|
-
'**Accessibility:** the options are a WAI-ARIA `radiogroup` (`role="radio"` + `aria-checked`) with **roving tabindex** — one tab stop in, Arrow keys move focus (skipping disabled), Enter/Space select the focused row. Disabled options are `aria-disabled` and not focusable; option images carry alt text; the Other input has a label. **0 axe violations** (light + dark).',
|
|
151
|
-
'**Events** (all frozen Card-contract verbs): `ready` on mount, `action` on Submit, `error` for a malformed definition (renders the inline `kai-card` error). It **never invents events**, and — because it carries a registry entry — `<kai-cards>` / `renderCard` dispatch it automatically.',
|
|
152
|
-
]),
|
|
153
|
-
},
|
|
154
|
-
},
|
|
155
|
-
} satisfies Meta;
|
|
156
|
-
|
|
157
|
-
export default meta;
|
|
158
|
-
type Story = StoryObj;
|
|
159
|
-
|
|
160
|
-
/** A list of plans with a `recommended` pill, `meta` prices, and a disabled legacy row.
|
|
161
|
-
* Select a row, then click Submit to emit the `action`. */
|
|
162
|
-
export const Plans: Story = {
|
|
163
|
-
render: () => <ChoiceDemo def={PLANS} cardId="card-plans" heading="Choose a plan" />,
|
|
164
|
-
parameters: { docs: { source: { code: HTML_SNIPPET(PLANS, 'card-plans'), language: 'html' } } },
|
|
165
|
-
};
|
|
166
|
-
|
|
167
|
-
/** Rows with leading images (each `media.image` carries `imageAlt`) and a custom `submitLabel`. */
|
|
168
|
-
export const WithMedia: Story = {
|
|
169
|
-
render: () => <ChoiceDemo def={TEMPLATES} cardId="card-templates" heading="New workspace" />,
|
|
170
|
-
parameters: { docs: { source: { code: HTML_SNIPPET(TEMPLATES, 'card-templates'), language: 'html' } } },
|
|
171
|
-
};
|
|
172
|
-
|
|
173
|
-
/** Quick replies with the `allowOther` free-text escape: select Other, type, then Submit. */
|
|
174
|
-
export const AllowOther: Story = {
|
|
175
|
-
render: () => <ChoiceDemo def={QUICK_REPLIES} cardId="card-replies" />,
|
|
176
|
-
parameters: { docs: { source: { code: HTML_SNIPPET(QUICK_REPLIES, 'card-replies'), language: 'html' } } },
|
|
177
|
-
};
|
|
178
|
-
|
|
179
|
-
const RESOLVED_CHOICE: ChoiceCardData = {
|
|
180
|
-
prompt: 'Which plan?',
|
|
181
|
-
options: [
|
|
182
|
-
{ id: 'free', label: 'Free', meta: '$0' },
|
|
183
|
-
{ id: 'pro', label: 'Pro', meta: '$20/mo' },
|
|
184
|
-
],
|
|
185
|
-
};
|
|
186
|
-
|
|
187
|
-
/** The card after the user chose **Pro** — only the chosen option shown, no radiogroup or Submit. */
|
|
188
|
-
export const Resolved: Story = {
|
|
189
|
-
name: 'Resolved (read-only)',
|
|
190
|
-
render: () => {
|
|
191
|
-
let el: ChoiceEl | undefined;
|
|
192
|
-
onMount(() => {
|
|
193
|
-
if (!el) return;
|
|
194
|
-
el.data = RESOLVED_CHOICE;
|
|
195
|
-
el.resolution = { kind: 'action', action: 'pro' };
|
|
196
|
-
});
|
|
197
|
-
return (
|
|
198
|
-
<Frame>
|
|
199
|
-
<kai-choice ref={(e) => (el = e as ChoiceEl)} card-id="card-resolved-choice" heading="Choose a plan" />
|
|
200
|
-
</Frame>
|
|
201
|
-
);
|
|
202
|
-
},
|
|
203
|
-
parameters: {
|
|
204
|
-
docs: {
|
|
205
|
-
source: {
|
|
206
|
-
code: `<kai-choice heading="Choose a plan"></kai-choice>
|
|
207
|
-
<script type="module">
|
|
208
|
-
import '@kitn.ai/ui/elements';
|
|
209
|
-
const el = document.querySelector('kai-choice');
|
|
210
|
-
el.data = ${JSON.stringify(RESOLVED_CHOICE, null, 2)};
|
|
211
|
-
// Setting .resolution renders the chromed read-only view — no radiogroup or Submit.
|
|
212
|
-
el.resolution = { kind: 'action', action: 'pro' };
|
|
213
|
-
</script>`,
|
|
214
|
-
language: 'html',
|
|
215
|
-
},
|
|
216
|
-
},
|
|
217
|
-
},
|
|
218
|
-
};
|
|
219
|
-
|
|
220
|
-
/** A malformed `data` (empty `options`) → the inline error state + an `error` event. */
|
|
221
|
-
export const ErrorState: Story = {
|
|
222
|
-
render: () => <ChoiceDemo def={{ options: [] } as unknown as ChoiceCardData} cardId="card-bad" />,
|
|
223
|
-
parameters: {
|
|
224
|
-
docs: {
|
|
225
|
-
source: {
|
|
226
|
-
code: `<kai-choice></kai-choice>
|
|
227
|
-
<script type="module">
|
|
228
|
-
import '@kitn.ai/ui/elements';
|
|
229
|
-
const el = document.querySelector('kai-choice');
|
|
230
|
-
// No options → inline error state + an \`error\` event.
|
|
231
|
-
el.data = { options: [] };
|
|
232
|
-
el.addEventListener('kai-card', (e) => {
|
|
233
|
-
if (e.detail.kind === 'error') console.warn('choice error:', e.detail.message);
|
|
234
|
-
});
|
|
235
|
-
</script>`,
|
|
236
|
-
language: 'html',
|
|
237
|
-
},
|
|
238
|
-
},
|
|
239
|
-
},
|
|
240
|
-
};
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
import type { Meta, StoryObj } from 'storybook-solidjs-vite';
|
|
2
|
-
import { onMount } from 'solid-js';
|
|
3
|
-
import './register'; // side effect: registers the custom elements
|
|
4
|
-
import { argTypesFor, specDescription } from '../stories/docs/element-controls';
|
|
5
|
-
|
|
6
|
-
// The web components are custom DOM elements, so declare the tags for JSX.
|
|
7
|
-
declare module 'solid-js' {
|
|
8
|
-
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
9
|
-
namespace JSX {
|
|
10
|
-
interface IntrinsicElements {
|
|
11
|
-
'kai-code-block': JSX.HTMLAttributes<HTMLElement>;
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const sampleCode = `export function add(a: number, b: number): number {
|
|
17
|
-
return a + b;
|
|
18
|
-
}`;
|
|
19
|
-
|
|
20
|
-
const pythonCode = `def fib(n):
|
|
21
|
-
a, b = 0, 1
|
|
22
|
-
for _ in range(n):
|
|
23
|
-
a, b = b, a + b
|
|
24
|
-
return a`;
|
|
25
|
-
|
|
26
|
-
/** Render the actual `<kai-code-block>` custom element with a `code` property. */
|
|
27
|
-
function CodeBlockElement(props: { code: string; language?: string }) {
|
|
28
|
-
let el: (HTMLElement & { code?: string }) | undefined;
|
|
29
|
-
onMount(() => {
|
|
30
|
-
if (el) {
|
|
31
|
-
el.code = props.code;
|
|
32
|
-
if (props.language) el.setAttribute('language', props.language);
|
|
33
|
-
}
|
|
34
|
-
});
|
|
35
|
-
return (
|
|
36
|
-
<kai-code-block
|
|
37
|
-
ref={(e) => (el = e as HTMLElement)}
|
|
38
|
-
style={{ display: 'block', padding: '16px', 'max-width': '720px' }}
|
|
39
|
-
/>
|
|
40
|
-
);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const HTML_SNIPPET = `<!-- Works in any framework or plain HTML -->
|
|
44
|
-
<kai-code-block id="code" language="ts" code-theme="github-dark-dimmed"></kai-code-block>
|
|
45
|
-
|
|
46
|
-
<script type="module">
|
|
47
|
-
import '@kitn.ai/ui/elements'; // registers the custom elements
|
|
48
|
-
|
|
49
|
-
const code = document.getElementById('code');
|
|
50
|
-
code.code = 'export function add(a, b) {\\n return a + b;\\n}';
|
|
51
|
-
</script>`;
|
|
52
|
-
|
|
53
|
-
const meta = {
|
|
54
|
-
title: 'Components/CodeBlock',
|
|
55
|
-
tags: ['autodocs'],
|
|
56
|
-
argTypes: argTypesFor('kai-code-block'),
|
|
57
|
-
parameters: {
|
|
58
|
-
layout: 'fullscreen',
|
|
59
|
-
docs: {
|
|
60
|
-
description: specDescription('kai-code-block', [
|
|
61
|
-
'`<kai-code-block>` is the framework-agnostic **web component** for a single syntax-highlighted code block, complete with a copy button, isolated in **Shadow DOM**.',
|
|
62
|
-
'**When to use:** dropping a highlighted snippet into a non-Solid app. In SolidJS, compose `CodeBlock` + `CodeBlockCode` directly.',
|
|
63
|
-
'**Placement:** as a block inside a message row, tutorial card, or documentation pane; it is `display: block` and fills container width, so set `max-width` on the parent or the element to control line lengths.',
|
|
64
|
-
"**How to use:** register once with `import '@kitn.ai/ui/elements'`, set the source via the `code` **property** (`el.code = '...'`), and pick a grammar with the `language` attribute (defaults to `tsx`). Tune highlighting with `code-theme` / `code-highlight`.",
|
|
65
|
-
'See the **Code** tab for HTML usage.',
|
|
66
|
-
]),
|
|
67
|
-
},
|
|
68
|
-
},
|
|
69
|
-
} satisfies Meta;
|
|
70
|
-
|
|
71
|
-
export default meta;
|
|
72
|
-
type Story = StoryObj;
|
|
73
|
-
|
|
74
|
-
/** A TypeScript snippet (the default `tsx` grammar). */
|
|
75
|
-
export const TypeScript: Story = {
|
|
76
|
-
render: () => <CodeBlockElement code={sampleCode} language="ts" />,
|
|
77
|
-
parameters: { docs: { source: { code: HTML_SNIPPET, language: 'html' } } },
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
/** A different grammar via the `language` attribute. */
|
|
81
|
-
export const Python: Story = {
|
|
82
|
-
render: () => <CodeBlockElement code={pythonCode} language="python" />,
|
|
83
|
-
};
|