@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,77 @@
|
|
|
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-reasoning': JSX.HTMLAttributes<HTMLElement>;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const sampleText =
|
|
17
|
+
'First I parse the request, then I plan the steps, then I execute and verify each one before responding.';
|
|
18
|
+
|
|
19
|
+
/** Render the actual `<kai-reasoning>` custom element with a `text` property. */
|
|
20
|
+
function ReasoningElement(props: { text: string; streaming?: boolean }) {
|
|
21
|
+
let el: (HTMLElement & { text?: string; streaming?: boolean }) | undefined;
|
|
22
|
+
onMount(() => {
|
|
23
|
+
if (el) {
|
|
24
|
+
el.text = props.text;
|
|
25
|
+
if (props.streaming) el.streaming = true;
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
return (
|
|
29
|
+
<kai-reasoning ref={(e) => (el = e as HTMLElement)} style={{ display: 'block', padding: '16px', 'max-width': '720px' }} />
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const HTML_SNIPPET = `<!-- Works in any framework or plain HTML -->
|
|
34
|
+
<kai-reasoning id="reason" label="Reasoning"></kai-reasoning>
|
|
35
|
+
|
|
36
|
+
<script type="module">
|
|
37
|
+
import '@kitn.ai/ui/elements'; // registers the custom elements
|
|
38
|
+
|
|
39
|
+
const reason = document.getElementById('reason');
|
|
40
|
+
reason.text = 'First I parse the request, then I plan the steps, then I execute.';
|
|
41
|
+
// reason.streaming = true; // auto-expands while a thought streams in
|
|
42
|
+
|
|
43
|
+
// events are CustomEvents on the element (they do not bubble)
|
|
44
|
+
reason.addEventListener('kai-open-change', (e) => console.log('open:', e.detail.open));
|
|
45
|
+
</script>`;
|
|
46
|
+
|
|
47
|
+
const meta = {
|
|
48
|
+
title: 'Components/Reasoning',
|
|
49
|
+
tags: ['autodocs'],
|
|
50
|
+
argTypes: argTypesFor('kai-reasoning'),
|
|
51
|
+
parameters: {
|
|
52
|
+
layout: 'fullscreen',
|
|
53
|
+
docs: {
|
|
54
|
+
description: specDescription('kai-reasoning', [
|
|
55
|
+
'`<kai-reasoning>` is the framework-agnostic **web component** for a collapsible reasoning/thinking block that auto-expands while a thought is `streaming`, isolated in **Shadow DOM**.',
|
|
56
|
+
'**When to use:** surfacing model chain-of-thought in a non-Solid app. In SolidJS, compose the `Reasoning` primitives directly.',
|
|
57
|
+
'**Placement:** inline inside an assistant message row, between the content and any tool calls; renders as a block sized to its content.',
|
|
58
|
+
"**How to use:** register once with `import '@kitn.ai/ui/elements'`, set the body via the `text` **property**, set the `streaming` flag while it streams in, optionally drive the controlled `open` property, and listen for the `kai-open-change` **CustomEvent**.",
|
|
59
|
+
'See the **Code** tab for HTML usage.',
|
|
60
|
+
]),
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
} satisfies Meta;
|
|
64
|
+
|
|
65
|
+
export default meta;
|
|
66
|
+
type Story = StoryObj;
|
|
67
|
+
|
|
68
|
+
/** A collapsed reasoning block (the trigger toggles it). */
|
|
69
|
+
export const Default: Story = {
|
|
70
|
+
render: () => <ReasoningElement text={sampleText} />,
|
|
71
|
+
parameters: { docs: { source: { code: HTML_SNIPPET, language: 'html' } } },
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
/** With `streaming` set, the block auto-expands. */
|
|
75
|
+
export const Streaming: Story = {
|
|
76
|
+
render: () => <ReasoningElement text={sampleText} streaming />,
|
|
77
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { defineWebComponent } from './define';
|
|
2
|
+
import { Reasoning, ReasoningTrigger, ReasoningContent } from '../components/reasoning';
|
|
3
|
+
import { ChatConfig, useChatConfig } from '../primitives/chat-config';
|
|
4
|
+
|
|
5
|
+
interface Props extends Record<string, unknown> {
|
|
6
|
+
/** The reasoning text to display. */
|
|
7
|
+
text: string;
|
|
8
|
+
/** Trigger label. */
|
|
9
|
+
label?: string;
|
|
10
|
+
/** Controlled open state — set as a property (`el.open = true`). Omit for
|
|
11
|
+
* uncontrolled (the trigger toggles it). */
|
|
12
|
+
open?: boolean;
|
|
13
|
+
/** While true, auto-expands (and re-collapses when it flips false). */
|
|
14
|
+
streaming?: boolean;
|
|
15
|
+
/** Render `text` as markdown. */
|
|
16
|
+
markdown?: boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** Events fired by `<kai-reasoning>`. */
|
|
20
|
+
interface Events {
|
|
21
|
+
/** Open state changed (via the trigger or streaming auto-open). */
|
|
22
|
+
'kai-open-change': { open: boolean };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* `<kai-reasoning>` — a collapsible reasoning/thinking block that auto-expands
|
|
27
|
+
* while `streaming`. Text via the `text` property; `markdown`/`streaming` flags;
|
|
28
|
+
* `open` is a controlled property; emits `kai-open-change`.
|
|
29
|
+
*/
|
|
30
|
+
defineWebComponent<Props, Events>('kai-reasoning', {
|
|
31
|
+
text: '',
|
|
32
|
+
label: 'Reasoning',
|
|
33
|
+
open: undefined,
|
|
34
|
+
streaming: false,
|
|
35
|
+
markdown: true,
|
|
36
|
+
}, (props, { dispatch, flag }) => {
|
|
37
|
+
const outer = useChatConfig();
|
|
38
|
+
return (
|
|
39
|
+
<ChatConfig portalMount={outer.portalMount()}>
|
|
40
|
+
<Reasoning
|
|
41
|
+
open={props.open}
|
|
42
|
+
isStreaming={flag('streaming')}
|
|
43
|
+
onOpenChange={(open) => dispatch('kai-open-change', { open })}
|
|
44
|
+
>
|
|
45
|
+
<ReasoningTrigger>{props.label}</ReasoningTrigger>
|
|
46
|
+
<ReasoningContent markdown={flag('markdown')}>{props.text}</ReasoningContent>
|
|
47
|
+
</Reasoning>
|
|
48
|
+
</ChatConfig>
|
|
49
|
+
);
|
|
50
|
+
});
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// Single entry that registers all kitn custom elements. Importing this file
|
|
2
|
+
// (or the built bundle) defines the elements as a side effect.
|
|
3
|
+
import './conversation-list';
|
|
4
|
+
import './prompt-input';
|
|
5
|
+
import './chat';
|
|
6
|
+
import './chat-workspace';
|
|
7
|
+
// Composable leaf elements (spike — see docs/handoff + examples/composable)
|
|
8
|
+
import './thinking-bar';
|
|
9
|
+
import './model-switcher';
|
|
10
|
+
import './attachments';
|
|
11
|
+
// Phase 1 — message-rendering core
|
|
12
|
+
import './message';
|
|
13
|
+
import './markdown';
|
|
14
|
+
import './code-block';
|
|
15
|
+
import './reasoning';
|
|
16
|
+
import './tool';
|
|
17
|
+
// Phase 2 — header / meta
|
|
18
|
+
import './context-meter';
|
|
19
|
+
import './feedback-bar';
|
|
20
|
+
import './chat-scope-picker';
|
|
21
|
+
// Phase 3 — input ecosystem
|
|
22
|
+
// (NB: SlashCommand is context-bound to PromptInput — it observes the input
|
|
23
|
+
// value via usePromptInput() — so it is NOT a standalone element. It will fold
|
|
24
|
+
// into <kai-prompt-input> as a `slash-commands` property in a later pass.)
|
|
25
|
+
import './prompt-suggestions';
|
|
26
|
+
import './file-upload';
|
|
27
|
+
import './voice-input';
|
|
28
|
+
// Phase 4 — indicators & leaves
|
|
29
|
+
import './loader';
|
|
30
|
+
import './text-shimmer';
|
|
31
|
+
import './image';
|
|
32
|
+
import './checkpoint';
|
|
33
|
+
import './message-skills';
|
|
34
|
+
import './source';
|
|
35
|
+
import './response-stream';
|
|
36
|
+
import './empty';
|
|
37
|
+
import './chain-of-thought';
|
|
38
|
+
import './resizable';
|
|
39
|
+
import './file-tree';
|
|
40
|
+
import './artifact';
|
|
41
|
+
import './scroll-button';
|
|
42
|
+
import './popover';
|
|
43
|
+
import './switch';
|
|
44
|
+
// Generative-UI cards (Card Contract)
|
|
45
|
+
import './card';
|
|
46
|
+
import './form';
|
|
47
|
+
import './link-preview';
|
|
48
|
+
import './embed';
|
|
49
|
+
import './confirm-card';
|
|
50
|
+
import './tasks';
|
|
51
|
+
import './choice';
|
|
52
|
+
import './cards';
|
|
53
|
+
|
|
54
|
+
export type { ChatMessage, ChatMessageAction } from './chat-types';
|
|
55
|
+
export { configureCodeHighlighting, isCodeHighlightingEnabled } from '../primitives/highlighter';
|
|
56
|
+
export type { CodeHighlightingOptions } from '../primitives/highlighter';
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from 'storybook-solidjs-vite';
|
|
2
|
+
import { createSignal, createEffect, onMount, onCleanup, type JSX } from 'solid-js';
|
|
3
|
+
import './remote';
|
|
4
|
+
import type { CardEnvelope, CardEvent, CardHost } from '../primitives/card-contract';
|
|
5
|
+
import { formRenderer, infoRenderer } from '../../examples/remote-provider/renderers';
|
|
6
|
+
|
|
7
|
+
declare module 'solid-js' {
|
|
8
|
+
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
9
|
+
namespace JSX {
|
|
10
|
+
interface IntrinsicElements {
|
|
11
|
+
'kai-remote': JSX.HTMLAttributes<HTMLElement> & {
|
|
12
|
+
src?: string;
|
|
13
|
+
'provider-origin'?: string;
|
|
14
|
+
ref?: (el: HTMLElement) => void;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
type RemoteEl = HTMLElement & { envelope?: CardEnvelope; policy?: Record<string, unknown> };
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* The live cross-origin demo only works in **local Storybook dev** (`npm run storybook`):
|
|
24
|
+
* there, `.storybook/main.ts`'s Vite pipeline serves the reference provider at
|
|
25
|
+
* `/remote-provider/`, and we frame it via the `127.0.0.1` alias of the SAME dev server
|
|
26
|
+
* — a genuinely different origin from the `localhost` preview, so `<kai-remote>`'s
|
|
27
|
+
* cross-origin precondition (provider ≠ host) holds.
|
|
28
|
+
*
|
|
29
|
+
* A **static, single-origin deploy** (e.g. the GitHub Pages docs) cannot do this: there
|
|
30
|
+
* is no second origin and the provider isn't served. So `liveProvider()` returns `null`
|
|
31
|
+
* there and the stories render an explanatory panel instead of a doomed mount. The real
|
|
32
|
+
* cross-origin behavior is verified by the standalone Playwright suite (H-L).
|
|
33
|
+
*/
|
|
34
|
+
function liveProvider(): { origin: string; src: string } | null {
|
|
35
|
+
if (typeof window === 'undefined') return null;
|
|
36
|
+
// The deployed/built Storybook (PROD) is single-origin + has no provider middleware.
|
|
37
|
+
if (import.meta.env.PROD) return null;
|
|
38
|
+
const here = new URL(window.location.href);
|
|
39
|
+
if ((here.hostname !== 'localhost' && here.hostname !== '127.0.0.1') || !here.port) return null;
|
|
40
|
+
// Swap localhost ↔ 127.0.0.1 to obtain a cross-origin sibling of the dev server.
|
|
41
|
+
const alias = here.hostname === '127.0.0.1' ? 'localhost' : '127.0.0.1';
|
|
42
|
+
const origin = `${here.protocol}//${alias}:${here.port}`;
|
|
43
|
+
return { origin, src: `${origin}/remote-provider/` };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const FORM_ENVELOPE: CardEnvelope = {
|
|
47
|
+
type: 'form',
|
|
48
|
+
id: 'remote-form-1',
|
|
49
|
+
title: 'Quick question',
|
|
50
|
+
data: {
|
|
51
|
+
type: 'object',
|
|
52
|
+
required: ['email'],
|
|
53
|
+
properties: {
|
|
54
|
+
email: { type: 'string', title: 'Email', format: 'email' },
|
|
55
|
+
role: { type: 'string', title: 'Role', enum: ['Engineer', 'Designer', 'PM'] },
|
|
56
|
+
},
|
|
57
|
+
'x-kai-submitLabel': 'Send',
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const WEATHER_ENVELOPE: CardEnvelope = {
|
|
62
|
+
type: 'info',
|
|
63
|
+
id: 'remote-info-1',
|
|
64
|
+
title: 'San Francisco',
|
|
65
|
+
data: {
|
|
66
|
+
location: 'San Francisco',
|
|
67
|
+
temperature: 18,
|
|
68
|
+
unit: '°C',
|
|
69
|
+
condition: 'Partly cloudy',
|
|
70
|
+
humidity: 64,
|
|
71
|
+
wind: 12,
|
|
72
|
+
feelsLike: 17,
|
|
73
|
+
forecast: [
|
|
74
|
+
{ day: 'Mon', high: 19, low: 12 },
|
|
75
|
+
{ day: 'Tue', high: 21, low: 13 },
|
|
76
|
+
{ day: 'Wed', high: 17, low: 11 },
|
|
77
|
+
],
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
/** The Storybook theme mode, read the way the kit elements do (preview.ts mirrors
|
|
82
|
+
* the resolved Storybook theme by toggling `.dark` on the <html>). Falls back to
|
|
83
|
+
* the OS preference when not in the Storybook shell. */
|
|
84
|
+
function readThemeMode(): 'light' | 'dark' {
|
|
85
|
+
if (typeof document === 'undefined') return 'light';
|
|
86
|
+
if (document.documentElement.classList.contains('dark')) return 'dark';
|
|
87
|
+
if (document.documentElement.classList.contains('light')) return 'light';
|
|
88
|
+
if (typeof window !== 'undefined' && window.matchMedia?.('(prefers-color-scheme: dark)').matches) return 'dark';
|
|
89
|
+
return 'light';
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** Pick the matching provider renderer for a card type (the SAME renderers the live
|
|
93
|
+
* cross-origin provider registers), or null for an unhandled type. */
|
|
94
|
+
function rendererFor(type: string) {
|
|
95
|
+
if (type === 'form') return formRenderer;
|
|
96
|
+
if (type === 'info') return infoRenderer;
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** Mounts a <kai-remote> when a live cross-origin provider is available (local dev),
|
|
101
|
+
* logs every routed CardEvent (via the bubbling kai-card). On a static/deployed
|
|
102
|
+
* Storybook (no second origin) it renders the SAME provider renderer's output
|
|
103
|
+
* DIRECTLY — so the docs show the real, interactive card — with a slim honest
|
|
104
|
+
* banner explaining the production transport. */
|
|
105
|
+
function RemoteDemo(props: { envelope: CardEnvelope; src?: string; providerOrigin?: string; showEnvelope?: boolean }) {
|
|
106
|
+
const live = props.providerOrigin && props.src ? { origin: props.providerOrigin, src: props.src } : liveProvider();
|
|
107
|
+
const [log, setLog] = createSignal<CardEvent[]>([]);
|
|
108
|
+
const [mode, setMode] = createSignal<'light' | 'dark'>(readThemeMode());
|
|
109
|
+
let el: RemoteEl | undefined;
|
|
110
|
+
let container: HTMLDivElement | undefined;
|
|
111
|
+
|
|
112
|
+
const renderer = rendererFor(props.envelope.type);
|
|
113
|
+
|
|
114
|
+
// ── Live (local dev): cross-origin <kai-remote>, exactly as before. ──
|
|
115
|
+
onMount(() => {
|
|
116
|
+
if (!live || !el) return;
|
|
117
|
+
el.envelope = props.envelope;
|
|
118
|
+
const onCard = (e: Event) => {
|
|
119
|
+
const detail = (e as CustomEvent<CardEvent>).detail;
|
|
120
|
+
setLog((prev) => [...prev, detail]);
|
|
121
|
+
};
|
|
122
|
+
el.addEventListener('kai-card', onCard);
|
|
123
|
+
onCleanup(() => el?.removeEventListener('kai-card', onCard));
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
// ── Static (deployed): render the real card content directly, reusing the
|
|
127
|
+
// provider renderer. Re-mount when the theme mode changes so the ThemePush
|
|
128
|
+
// story still means something on static. ──
|
|
129
|
+
if (!live && renderer) {
|
|
130
|
+
// Track Storybook's light/dark toggle (preview.ts flips `.dark` on <html>).
|
|
131
|
+
onMount(() => {
|
|
132
|
+
if (typeof MutationObserver === 'undefined') return;
|
|
133
|
+
const obs = new MutationObserver(() => setMode(readThemeMode()));
|
|
134
|
+
obs.observe(document.documentElement, { attributes: true, attributeFilter: ['class'] });
|
|
135
|
+
onCleanup(() => obs.disconnect());
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
createEffect(() => {
|
|
139
|
+
const m = mode(); // re-run on theme change
|
|
140
|
+
if (!container) return;
|
|
141
|
+
const stubHost: CardHost = {
|
|
142
|
+
context: () => ({ theme: { mode: m }, locale: 'en' }),
|
|
143
|
+
emit: (e) => setLog((prev) => [...prev, e]),
|
|
144
|
+
};
|
|
145
|
+
const dispose = renderer.mount(container, props.envelope, stubHost);
|
|
146
|
+
onCleanup(() => {
|
|
147
|
+
try { dispose(); } catch { /* renderer disposer threw — best-effort */ }
|
|
148
|
+
if (container) container.replaceChildren();
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return (
|
|
154
|
+
<div style={{ display: 'flex', gap: '16px', 'flex-wrap': 'wrap', 'align-items': 'flex-start' }}>
|
|
155
|
+
<div style={{ flex: '1 1 320px', 'min-width': '300px', 'max-width': '460px' }}>
|
|
156
|
+
{live ? (
|
|
157
|
+
<kai-remote ref={(e) => (el = e as RemoteEl)} provider-origin={live.origin} src={live.src} />
|
|
158
|
+
) : renderer ? (
|
|
159
|
+
<div style={{ display: 'flex', 'flex-direction': 'column', gap: '8px' }}>
|
|
160
|
+
<div
|
|
161
|
+
ref={(e) => (container = e)}
|
|
162
|
+
style={{ border: '1px solid var(--color-border, #e4e4e7)', 'border-radius': '12px', overflow: 'hidden' }}
|
|
163
|
+
/>
|
|
164
|
+
<p
|
|
165
|
+
role="note"
|
|
166
|
+
style={{ margin: 0, 'font-size': '12px', 'line-height': '1.5', color: 'var(--color-muted-foreground, #71717a)' }}
|
|
167
|
+
>
|
|
168
|
+
Rendered directly for these static docs. In production <code><kai-remote></code> delivers this over a
|
|
169
|
+
sandboxed cross-origin iframe — run <code>npm run storybook</code> for the live transport; the cross-origin
|
|
170
|
+
model is verified by the Playwright suite.
|
|
171
|
+
</p>
|
|
172
|
+
</div>
|
|
173
|
+
) : (
|
|
174
|
+
<div
|
|
175
|
+
role="note"
|
|
176
|
+
style={{
|
|
177
|
+
border: '1px dashed var(--color-border, #d4d4d8)', 'border-radius': '12px',
|
|
178
|
+
padding: '16px', 'font-size': '13px', 'line-height': '1.55', color: 'var(--color-foreground, #18181b)',
|
|
179
|
+
}}
|
|
180
|
+
>
|
|
181
|
+
<strong>Live cross-origin demo runs in local Storybook</strong>
|
|
182
|
+
<p style={{ margin: '8px 0 0' }}>
|
|
183
|
+
<code><kai-remote></code> delivers this card over a sandboxed{' '}
|
|
184
|
+
<strong>cross-origin</strong> <code><iframe></code>, which needs a second
|
|
185
|
+
origin and the reference provider served by the dev server. Run{' '}
|
|
186
|
+
<code>npm run storybook</code> to see it live; the cross-origin transport is
|
|
187
|
+
verified by the Playwright e2e matrix.
|
|
188
|
+
</p>
|
|
189
|
+
</div>
|
|
190
|
+
)}
|
|
191
|
+
</div>
|
|
192
|
+
<div style={{ flex: '1 1 280px', 'min-width': '260px', display: 'flex', 'flex-direction': 'column', gap: '12px' }}>
|
|
193
|
+
{props.showEnvelope && (
|
|
194
|
+
<pre style={{ margin: 0, 'font-size': '12px', background: 'var(--color-muted, #f4f4f5)', 'border-radius': '8px', padding: '8px', overflow: 'auto' }}>
|
|
195
|
+
{`// CardEnvelope sent down the wire (inside a WireFrame):\n` + JSON.stringify(props.envelope, null, 2)}
|
|
196
|
+
</pre>
|
|
197
|
+
)}
|
|
198
|
+
<pre style={{ margin: 0, 'max-height': '200px', overflow: 'auto', background: 'var(--color-muted, #f4f4f5)', 'border-radius': '8px', padding: '8px', 'font-size': '12px' }}>
|
|
199
|
+
{log().length === 0 ? '// routed CardEvents appear here' : JSON.stringify(log(), null, 2)}
|
|
200
|
+
</pre>
|
|
201
|
+
</div>
|
|
202
|
+
</div>
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const HTML_SNIPPET = (envelope: CardEnvelope) => `<kai-remote
|
|
207
|
+
provider-origin="https://cards.provider.example"
|
|
208
|
+
src="https://cards.provider.example/card"
|
|
209
|
+
></kai-remote>
|
|
210
|
+
<script type="module">
|
|
211
|
+
import '@kitn.ai/ui/elements'; // registers <kai-remote>
|
|
212
|
+
|
|
213
|
+
const el = document.querySelector('kai-remote');
|
|
214
|
+
// The CardEnvelope is set as a JS PROPERTY (it travels down the wire unchanged).
|
|
215
|
+
el.envelope = ${JSON.stringify(envelope, null, 2)};
|
|
216
|
+
|
|
217
|
+
// Every routed CardEvent is re-emitted as a bubbling kai-card CustomEvent.
|
|
218
|
+
el.addEventListener('kai-card', (e) => {
|
|
219
|
+
if (e.detail.kind === 'submit') console.log('submitted', e.detail.data);
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
// Or pass a CardPolicy directly (same shape native cards use):
|
|
223
|
+
// el.policy = { onSubmit: (cardId, data) => save(data) };
|
|
224
|
+
</script>`;
|
|
225
|
+
|
|
226
|
+
const meta = {
|
|
227
|
+
title: 'Generative UI/Remote/kai-remote',
|
|
228
|
+
tags: ['autodocs'],
|
|
229
|
+
parameters: {
|
|
230
|
+
layout: 'padded',
|
|
231
|
+
// axe can't read a CROSS-ORIGIN frame's tree (that's the provider's a11y
|
|
232
|
+
// obligation, proven by the provider's own stories/tests); scope axe to the
|
|
233
|
+
// HOST page only — the iframe boundary + any inline fallback regions (H-L).
|
|
234
|
+
a11y: { context: { exclude: [['iframe']] } },
|
|
235
|
+
docs: {
|
|
236
|
+
description: {
|
|
237
|
+
component:
|
|
238
|
+
"`<kai-remote>` mounts a **sandboxed cross-origin `<iframe>`** card from a card *provider* and bridges it to the host over `postMessage` — the SAME `CardEnvelope`/`CardContext`/`CardEvent` shapes as native cards, routed through the SAME `CardPolicy`. " +
|
|
239
|
+
'It pins the provider **origin + source window + a per-instance nonce + the negotiated protocol version** on every inbound frame, auto-sizes the iframe from the card’s reported height, pushes theme/locale context, and re-emits every routed event as a bubbling **`kai-card`** CustomEvent. ' +
|
|
240
|
+
'These stories frame the reference provider (`examples/remote-provider/`) served by Storybook over its `127.0.0.1` alias so the precondition (provider ≠ host origin) holds; the full cross-origin **security matrix** is the standalone Playwright suite.',
|
|
241
|
+
},
|
|
242
|
+
},
|
|
243
|
+
},
|
|
244
|
+
} satisfies Meta;
|
|
245
|
+
|
|
246
|
+
export default meta;
|
|
247
|
+
type Story = StoryObj;
|
|
248
|
+
|
|
249
|
+
/** Happy path: the framed provider renders a `<kai-form>`; submitting it crosses the
|
|
250
|
+
* origin boundary and the routed `submit` is logged. The CardEnvelope is shown too. */
|
|
251
|
+
export const RemoteForm: Story = {
|
|
252
|
+
name: 'Remote form (happy path)',
|
|
253
|
+
render: () => <RemoteDemo envelope={FORM_ENVELOPE} showEnvelope />,
|
|
254
|
+
parameters: { docs: { source: { code: HTML_SNIPPET(FORM_ENVELOPE), language: 'html' } } },
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
/** Auto-height: the self-contained card’s `<details>` forecast toggle grows the
|
|
258
|
+
* content; the runtime reports a larger `resize` and the host enlarges the iframe. */
|
|
259
|
+
export const AutoHeight: Story = {
|
|
260
|
+
name: 'Auto-height',
|
|
261
|
+
render: () => <RemoteDemo envelope={WEATHER_ENVELOPE} />,
|
|
262
|
+
parameters: { docs: { source: { code: HTML_SNIPPET(WEATHER_ENVELOPE), language: 'html' } } },
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
/** Theme push: toggle the Storybook light/dark toolbar — the host re-pushes
|
|
266
|
+
* `context` and the framed card re-themes live (no reload). */
|
|
267
|
+
export const ThemePush: Story = {
|
|
268
|
+
name: 'Theme push',
|
|
269
|
+
render: () => <RemoteDemo envelope={WEATHER_ENVELOPE} />,
|
|
270
|
+
parameters: { docs: { source: { code: HTML_SNIPPET(WEATHER_ENVELOPE), language: 'html' } } },
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
/** Self-contained display card: a rich, read-only weather view rendered entirely
|
|
274
|
+
* from `envelope.data` inside the provider. It is internally interactive (the
|
|
275
|
+
* forecast toggle) but emits NOTHING back to the host — the zero-round-trip
|
|
276
|
+
* pattern. The bridge still auto-sizes it. */
|
|
277
|
+
export const SelfContained: Story = {
|
|
278
|
+
name: 'Self-contained display',
|
|
279
|
+
render: () => <RemoteDemo envelope={WEATHER_ENVELOPE} showEnvelope />,
|
|
280
|
+
parameters: { docs: { source: { code: HTML_SNIPPET(WEATHER_ENVELOPE), language: 'html' } } },
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
/** Failure: an invalid `provider-origin` (a wildcard) is rejected before any mount
|
|
284
|
+
* — <kai-remote> renders an inline accessible error instead of an iframe. (A bad
|
|
285
|
+
* `src` that loads but never handshakes shows the SDK’s inline fallback + Retry;
|
|
286
|
+
* that path is exercised end-to-end by the Playwright suite.) */
|
|
287
|
+
export const Failure: Story = {
|
|
288
|
+
name: 'Failure: bad provider-origin',
|
|
289
|
+
render: () => {
|
|
290
|
+
let el: RemoteEl | undefined;
|
|
291
|
+
onMount(() => {
|
|
292
|
+
if (el) el.envelope = FORM_ENVELOPE;
|
|
293
|
+
});
|
|
294
|
+
return (
|
|
295
|
+
<div style={{ 'max-width': '460px' }}>
|
|
296
|
+
<kai-remote ref={(e) => (el = e as RemoteEl)} provider-origin="*" src="https://cards.provider.example/card" />
|
|
297
|
+
</div>
|
|
298
|
+
);
|
|
299
|
+
},
|
|
300
|
+
parameters: {
|
|
301
|
+
docs: {
|
|
302
|
+
source: {
|
|
303
|
+
code: `<!-- provider-origin must be a single absolute origin (https, or http://localhost for dev). -->
|
|
304
|
+
<kai-remote provider-origin="*" src="https://cards.provider.example/card"></kai-remote>
|
|
305
|
+
<script type="module">
|
|
306
|
+
import '@kitn.ai/ui/elements';
|
|
307
|
+
document.querySelector('kai-remote').envelope = ${JSON.stringify(FORM_ENVELOPE, null, 2)};
|
|
308
|
+
// "*" is rejected → an inline accessible error renders instead of an iframe.
|
|
309
|
+
</script>`,
|
|
310
|
+
language: 'html',
|
|
311
|
+
},
|
|
312
|
+
},
|
|
313
|
+
},
|
|
314
|
+
};
|