@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,471 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from 'storybook-solidjs-vite';
|
|
2
|
+
import { onMount } from 'solid-js';
|
|
3
|
+
import {
|
|
4
|
+
ChatContainer, ChatContainerContent, ChatContainerScrollAnchor,
|
|
5
|
+
Message, MessageAvatar, MessageContent, MessageActions,
|
|
6
|
+
PromptInput, PromptInputTextarea, PromptInputActions,
|
|
7
|
+
Source, SourceTrigger, SourceContent, SourceList,
|
|
8
|
+
Button, Separator,
|
|
9
|
+
} from '../index';
|
|
10
|
+
import { Copy, ThumbsUp, ThumbsDown, ArrowUp } from 'lucide-solid';
|
|
11
|
+
import '../elements/register'; // registers kai-sources / kai-source
|
|
12
|
+
|
|
13
|
+
// kai-sources / kai-source IntrinsicElements are already declared in
|
|
14
|
+
// src/elements/source-list.stories.tsx (same TS project, merged interface).
|
|
15
|
+
// Re-declare here so this file is self-contained; types must match exactly.
|
|
16
|
+
declare module 'solid-js' {
|
|
17
|
+
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
18
|
+
namespace JSX {
|
|
19
|
+
interface IntrinsicElements {
|
|
20
|
+
// Plain HTMLAttributes — `numbered` is set via setAttribute in onMount.
|
|
21
|
+
'kai-sources': JSX.HTMLAttributes<HTMLElement>;
|
|
22
|
+
'kai-source': JSX.HTMLAttributes<HTMLElement> & {
|
|
23
|
+
href?: string;
|
|
24
|
+
label?: string;
|
|
25
|
+
headline?: string;
|
|
26
|
+
description?: string;
|
|
27
|
+
'show-favicon'?: boolean | '';
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const meta: Meta = {
|
|
34
|
+
title: 'Examples/Conversation with Sources',
|
|
35
|
+
parameters: {
|
|
36
|
+
layout: 'padded',
|
|
37
|
+
docs: {
|
|
38
|
+
description: {
|
|
39
|
+
component: [
|
|
40
|
+
'Show inline citations below an assistant reply. Two routes:',
|
|
41
|
+
'',
|
|
42
|
+
'**Prop route (`sources` array):** set `<kai-sources>.sources = [{ href, title, description, label?, showFavicon? }]` as a JS property. Prop sources render first.',
|
|
43
|
+
'',
|
|
44
|
+
'**Declarative route (`<kai-source>` children):** place `<kai-source>` elements as children of `<kai-sources>`. They are picked up via `MutationObserver` and appended after any prop sources. Use `headline` (not `title` — `title` is a reserved HTML attribute that conflicts with the custom-element constructor). Confirmed in `src/elements/source.tsx`.',
|
|
45
|
+
'',
|
|
46
|
+
'**Automatic numbered labels (`numbered` prop):** set `<kai-sources numbered>` (HTML) or `el.numbered = true` (JS) to label each citation chip with its 1-based index (`1`, `2`, `3`, …) from the merged prop+children list. Per-item `label` values are ignored when `numbered` is set. For manual control, omit `numbered` and set `label={1}` / `label={2}` etc. on each `SourceTrigger` (Solid) or the `label` attribute on each `<kai-source>` child.',
|
|
47
|
+
'',
|
|
48
|
+
'**When to omit favicons:** the favicon is fetched from the link\'s domain. Skip it for internal/localhost URLs, or when the domain\'s favicon is low-contrast on your background.',
|
|
49
|
+
].join('\n'),
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export default meta;
|
|
56
|
+
type Story = StoryObj;
|
|
57
|
+
|
|
58
|
+
export const Default: Story = {
|
|
59
|
+
name: 'Multi-turn with Citations',
|
|
60
|
+
parameters: {
|
|
61
|
+
docs: {
|
|
62
|
+
description: {
|
|
63
|
+
story: [
|
|
64
|
+
'Two exchanges, two citation styles. First exchange uses `label={1|2|3}` for numbered badges, no favicons. Second exchange adds `showFavicon` per-trigger.',
|
|
65
|
+
'',
|
|
66
|
+
'**Note:** `<kai-source>` uses `headline` not `title` for the hover-card heading — `title` is a reserved HTML attribute that conflicts with the custom-element constructor (`src/elements/source.tsx`).',
|
|
67
|
+
'',
|
|
68
|
+
'See the **Numbered Citations** story for the `numbered` prop that auto-labels all chips with their 1-based index.',
|
|
69
|
+
].join('\n'),
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
render: () => (
|
|
74
|
+
<div class="flex flex-col h-[650px] w-full max-w-2xl bg-background rounded-xl shadow-lg overflow-hidden">
|
|
75
|
+
<div class="flex items-center px-4 py-3">
|
|
76
|
+
<h2 class="text-sm font-semibold text-foreground">Research: WebAssembly in Production</h2>
|
|
77
|
+
</div>
|
|
78
|
+
<Separator />
|
|
79
|
+
|
|
80
|
+
<ChatContainer class="flex-1 p-4">
|
|
81
|
+
<ChatContainerContent class="space-y-6 py-4">
|
|
82
|
+
|
|
83
|
+
{/* First exchange */}
|
|
84
|
+
<Message>
|
|
85
|
+
<MessageAvatar src="" fallback="U" alt="User" />
|
|
86
|
+
<MessageContent>
|
|
87
|
+
What are the real-world performance benefits of using WebAssembly in production web apps? I want concrete examples, not just benchmarks.
|
|
88
|
+
</MessageContent>
|
|
89
|
+
</Message>
|
|
90
|
+
|
|
91
|
+
<Message>
|
|
92
|
+
<MessageAvatar src="" fallback="AI" alt="Assistant" />
|
|
93
|
+
<div class="flex-1 space-y-2">
|
|
94
|
+
<MessageContent markdown>
|
|
95
|
+
{`Several major companies have deployed WebAssembly in production with measurable results:
|
|
96
|
+
|
|
97
|
+
**Figma** replaced their C++ to asm.js pipeline with Wasm and saw a **3x performance improvement** in load times. Their design tool renders complex vector graphics at 60fps using a Wasm-compiled engine.
|
|
98
|
+
|
|
99
|
+
**Google Earth** ported their native rendering engine to Wasm, enabling the full 3D globe experience in browsers without plugins. Frame rendering dropped from **40ms to 12ms** per frame.
|
|
100
|
+
|
|
101
|
+
**Shopify** uses Wasm for their theme editor's Liquid template parsing, achieving **10x faster** template compilation compared to their previous JavaScript parser.
|
|
102
|
+
|
|
103
|
+
The pattern is consistent: CPU-intensive tasks like **image processing, cryptography, physics simulation, and codec operations** see the largest gains. IO-bound operations don't benefit as much.`}
|
|
104
|
+
</MessageContent>
|
|
105
|
+
|
|
106
|
+
<SourceList>
|
|
107
|
+
<Source href="https://www.figma.com/blog/webassembly-cut-figmas-load-time-by-3x/">
|
|
108
|
+
<SourceTrigger label={1} />
|
|
109
|
+
<SourceContent
|
|
110
|
+
title="WebAssembly cut Figma's load time by 3x"
|
|
111
|
+
description="How Figma leveraged WebAssembly to dramatically improve their browser-based design tool performance."
|
|
112
|
+
/>
|
|
113
|
+
</Source>
|
|
114
|
+
<Source href="https://web.dev/case-studies/earth-webassembly">
|
|
115
|
+
<SourceTrigger label={2} />
|
|
116
|
+
<SourceContent
|
|
117
|
+
title="Google Earth and WebAssembly - web.dev"
|
|
118
|
+
description="Case study on porting Google Earth's C++ rendering engine to WebAssembly for browser delivery."
|
|
119
|
+
/>
|
|
120
|
+
</Source>
|
|
121
|
+
<Source href="https://shopify.engineering/shopify-webassembly">
|
|
122
|
+
<SourceTrigger label={3} />
|
|
123
|
+
<SourceContent
|
|
124
|
+
title="How Shopify Uses WebAssembly"
|
|
125
|
+
description="Shopify's journey using WebAssembly for Liquid template parsing in their online store editor."
|
|
126
|
+
/>
|
|
127
|
+
</Source>
|
|
128
|
+
</SourceList>
|
|
129
|
+
|
|
130
|
+
<MessageActions>
|
|
131
|
+
<Button variant="ghost" size="icon-sm" aria-label="Copy message"><Copy class="size-3.5" /></Button>
|
|
132
|
+
<Button variant="ghost" size="icon-sm" aria-label="Good response"><ThumbsUp class="size-3.5" /></Button>
|
|
133
|
+
<Button variant="ghost" size="icon-sm" aria-label="Bad response"><ThumbsDown class="size-3.5" /></Button>
|
|
134
|
+
</MessageActions>
|
|
135
|
+
</div>
|
|
136
|
+
</Message>
|
|
137
|
+
|
|
138
|
+
{/* Second exchange with different citation pattern */}
|
|
139
|
+
<Message>
|
|
140
|
+
<MessageAvatar src="" fallback="U" alt="User" />
|
|
141
|
+
<MessageContent>
|
|
142
|
+
What about the downsides? Are there situations where Wasm actually hurts performance?
|
|
143
|
+
</MessageContent>
|
|
144
|
+
</Message>
|
|
145
|
+
|
|
146
|
+
<Message>
|
|
147
|
+
<MessageAvatar src="" fallback="AI" alt="Assistant" />
|
|
148
|
+
<div class="flex-1 space-y-2">
|
|
149
|
+
<MessageContent markdown>
|
|
150
|
+
{`Yes, there are real tradeoffs to consider:
|
|
151
|
+
|
|
152
|
+
**Bundle size** -- Wasm modules can be significantly larger than equivalent JavaScript. The Squoosh image editor found their Wasm codecs added **2-4MB** of download size, which they mitigated with lazy loading.
|
|
153
|
+
|
|
154
|
+
**DOM access overhead** -- Every call from Wasm to the DOM crosses a boundary with serialization cost. Applications that frequently manipulate the DOM (like React-style UI frameworks) can actually be **slower** in Wasm than optimized JavaScript.
|
|
155
|
+
|
|
156
|
+
**Startup latency** -- Wasm modules must be compiled before execution. While streaming compilation helps, large modules can take **200-500ms** to initialize on mobile devices.
|
|
157
|
+
|
|
158
|
+
**Garbage collection** -- Until the Wasm GC proposal ships broadly, languages like Go and Java bring their own GC runtime, adding **5-20MB** to module size.
|
|
159
|
+
|
|
160
|
+
The consensus from the Chrome team's analysis is: **use Wasm for compute-heavy inner loops, keep UI and orchestration in JavaScript**.`}
|
|
161
|
+
</MessageContent>
|
|
162
|
+
|
|
163
|
+
<SourceList>
|
|
164
|
+
<Source href="https://web.dev/squoosh-v2/">
|
|
165
|
+
<SourceTrigger label={1} showFavicon />
|
|
166
|
+
<SourceContent
|
|
167
|
+
title="Squoosh v2: codec improvements with WebAssembly"
|
|
168
|
+
description="How the Squoosh team manages Wasm codec size and loading strategies for their image compression tool."
|
|
169
|
+
/>
|
|
170
|
+
</Source>
|
|
171
|
+
<Source href="https://surma.dev/things/js-to-asc/">
|
|
172
|
+
<SourceTrigger label={2} showFavicon />
|
|
173
|
+
<SourceContent
|
|
174
|
+
title="JavaScript to AssemblyScript - Surma.dev"
|
|
175
|
+
description="Detailed performance comparison of JS vs AssemblyScript/Wasm for various workloads including DOM-heavy tasks."
|
|
176
|
+
/>
|
|
177
|
+
</Source>
|
|
178
|
+
<Source href="https://v8.dev/blog/wasm-compilation-pipeline">
|
|
179
|
+
<SourceTrigger label={3} showFavicon />
|
|
180
|
+
<SourceContent
|
|
181
|
+
title="Liftoff: V8's Wasm baseline compiler"
|
|
182
|
+
description="V8 team's analysis of Wasm compilation latency and their streaming compilation optimization."
|
|
183
|
+
/>
|
|
184
|
+
</Source>
|
|
185
|
+
<Source href="https://chromestatus.com/feature/6062715726462976">
|
|
186
|
+
<SourceTrigger label={4} showFavicon />
|
|
187
|
+
<SourceContent
|
|
188
|
+
title="WebAssembly Garbage Collection - Chrome Platform Status"
|
|
189
|
+
description="Status of the WasmGC proposal and its impact on languages targeting WebAssembly."
|
|
190
|
+
/>
|
|
191
|
+
</Source>
|
|
192
|
+
</SourceList>
|
|
193
|
+
|
|
194
|
+
<MessageActions>
|
|
195
|
+
<Button variant="ghost" size="icon-sm" aria-label="Copy message"><Copy class="size-3.5" /></Button>
|
|
196
|
+
<Button variant="ghost" size="icon-sm" aria-label="Good response"><ThumbsUp class="size-3.5" /></Button>
|
|
197
|
+
<Button variant="ghost" size="icon-sm" aria-label="Bad response"><ThumbsDown class="size-3.5" /></Button>
|
|
198
|
+
</MessageActions>
|
|
199
|
+
</div>
|
|
200
|
+
</Message>
|
|
201
|
+
|
|
202
|
+
<ChatContainerScrollAnchor />
|
|
203
|
+
</ChatContainerContent>
|
|
204
|
+
</ChatContainer>
|
|
205
|
+
|
|
206
|
+
<div class="px-4 pb-4">
|
|
207
|
+
<PromptInput>
|
|
208
|
+
<PromptInputTextarea placeholder="Ask about WebAssembly..." />
|
|
209
|
+
<PromptInputActions class="justify-end">
|
|
210
|
+
<Button variant="default" size="icon-sm" class="rounded-full" aria-label="Send message">
|
|
211
|
+
<ArrowUp class="size-4" />
|
|
212
|
+
</Button>
|
|
213
|
+
</PromptInputActions>
|
|
214
|
+
</PromptInput>
|
|
215
|
+
</div>
|
|
216
|
+
</div>
|
|
217
|
+
),
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
// ---------------------------------------------------------------------------
|
|
221
|
+
// Numbered Citations story
|
|
222
|
+
// ---------------------------------------------------------------------------
|
|
223
|
+
|
|
224
|
+
export const Numbered: Story = {
|
|
225
|
+
name: 'Numbered Citations',
|
|
226
|
+
parameters: {
|
|
227
|
+
docs: {
|
|
228
|
+
description: {
|
|
229
|
+
story: [
|
|
230
|
+
'Demonstrates the `numbered` boolean prop on `<kai-sources>` / `SourceList`.',
|
|
231
|
+
'',
|
|
232
|
+
'When `numbered` is set, every citation chip is auto-labelled with its **1-based index** in the merged (prop + declarative-children) source list, regardless of any per-item `label` value.',
|
|
233
|
+
'',
|
|
234
|
+
'- Solid: pass `numbered` prop on the wrapping element (future support) or render index manually as shown here.',
|
|
235
|
+
'- Web component: `<kai-sources numbered>` or `el.numbered = true`.',
|
|
236
|
+
'',
|
|
237
|
+
'**Inline prose citations** (e.g. `[1]` inside a markdown paragraph) are still manual — this prop only controls the chip labels in the source strip.',
|
|
238
|
+
'',
|
|
239
|
+
'**Note:** `<kai-source>` uses `headline` (not `title`) as the hover-card attribute.',
|
|
240
|
+
].join('\n'),
|
|
241
|
+
},
|
|
242
|
+
},
|
|
243
|
+
},
|
|
244
|
+
render: () => (
|
|
245
|
+
<div class="flex flex-col gap-6 p-4 w-full max-w-2xl bg-background rounded-xl shadow-lg">
|
|
246
|
+
<div>
|
|
247
|
+
<p class="text-sm text-muted-foreground mb-1">
|
|
248
|
+
Sources strip with <code>numbered</code> — chips show 1, 2, 3 automatically:
|
|
249
|
+
</p>
|
|
250
|
+
<SourceList>
|
|
251
|
+
<Source href="https://www.figma.com/blog/webassembly-cut-figmas-load-time-by-3x/">
|
|
252
|
+
<SourceTrigger label={1} />
|
|
253
|
+
<SourceContent
|
|
254
|
+
title="WebAssembly cut Figma's load time by 3x"
|
|
255
|
+
description="How Figma leveraged WebAssembly to dramatically improve their browser-based design tool performance."
|
|
256
|
+
/>
|
|
257
|
+
</Source>
|
|
258
|
+
<Source href="https://web.dev/case-studies/earth-webassembly">
|
|
259
|
+
<SourceTrigger label={2} />
|
|
260
|
+
<SourceContent
|
|
261
|
+
title="Google Earth and WebAssembly - web.dev"
|
|
262
|
+
description="Case study on porting Google Earth's C++ rendering engine to WebAssembly for browser delivery."
|
|
263
|
+
/>
|
|
264
|
+
</Source>
|
|
265
|
+
<Source href="https://shopify.engineering/shopify-webassembly">
|
|
266
|
+
<SourceTrigger label={3} />
|
|
267
|
+
<SourceContent
|
|
268
|
+
title="How Shopify Uses WebAssembly"
|
|
269
|
+
description="Shopify's journey using WebAssembly for Liquid template parsing in their online store editor."
|
|
270
|
+
/>
|
|
271
|
+
</Source>
|
|
272
|
+
<Source href="https://surma.dev/things/js-to-asc/">
|
|
273
|
+
<SourceTrigger label={4} />
|
|
274
|
+
<SourceContent
|
|
275
|
+
title="JavaScript to AssemblyScript - Surma.dev"
|
|
276
|
+
description="Detailed performance comparison of JS vs AssemblyScript/Wasm for various workloads."
|
|
277
|
+
/>
|
|
278
|
+
</Source>
|
|
279
|
+
</SourceList>
|
|
280
|
+
</div>
|
|
281
|
+
|
|
282
|
+
<div>
|
|
283
|
+
<p class="text-sm text-muted-foreground mb-1">
|
|
284
|
+
Same sources without numbering — chips fall back to domain labels:
|
|
285
|
+
</p>
|
|
286
|
+
<SourceList>
|
|
287
|
+
<Source href="https://www.figma.com/blog/webassembly-cut-figmas-load-time-by-3x/">
|
|
288
|
+
<SourceTrigger />
|
|
289
|
+
<SourceContent
|
|
290
|
+
title="WebAssembly cut Figma's load time by 3x"
|
|
291
|
+
description="How Figma leveraged WebAssembly to dramatically improve their browser-based design tool performance."
|
|
292
|
+
/>
|
|
293
|
+
</Source>
|
|
294
|
+
<Source href="https://web.dev/case-studies/earth-webassembly">
|
|
295
|
+
<SourceTrigger />
|
|
296
|
+
<SourceContent
|
|
297
|
+
title="Google Earth and WebAssembly - web.dev"
|
|
298
|
+
description="Case study on porting Google Earth's C++ rendering engine to WebAssembly for browser delivery."
|
|
299
|
+
/>
|
|
300
|
+
</Source>
|
|
301
|
+
<Source href="https://shopify.engineering/shopify-webassembly">
|
|
302
|
+
<SourceTrigger />
|
|
303
|
+
<SourceContent
|
|
304
|
+
title="How Shopify Uses WebAssembly"
|
|
305
|
+
description="Shopify's journey using WebAssembly for Liquid template parsing in their online store editor."
|
|
306
|
+
/>
|
|
307
|
+
</Source>
|
|
308
|
+
<Source href="https://surma.dev/things/js-to-asc/">
|
|
309
|
+
<SourceTrigger />
|
|
310
|
+
<SourceContent
|
|
311
|
+
title="JavaScript to AssemblyScript - Surma.dev"
|
|
312
|
+
description="Detailed performance comparison of JS vs AssemblyScript/Wasm for various workloads."
|
|
313
|
+
/>
|
|
314
|
+
</Source>
|
|
315
|
+
</SourceList>
|
|
316
|
+
</div>
|
|
317
|
+
|
|
318
|
+
<div>
|
|
319
|
+
<p class="text-sm text-muted-foreground mb-1">
|
|
320
|
+
Numbered with favicons (<code>showFavicon</code> per-trigger):
|
|
321
|
+
</p>
|
|
322
|
+
<SourceList>
|
|
323
|
+
<Source href="https://www.figma.com/blog/webassembly-cut-figmas-load-time-by-3x/">
|
|
324
|
+
<SourceTrigger label={1} showFavicon />
|
|
325
|
+
<SourceContent
|
|
326
|
+
title="WebAssembly cut Figma's load time by 3x"
|
|
327
|
+
description="How Figma leveraged WebAssembly to dramatically improve their browser-based design tool performance."
|
|
328
|
+
/>
|
|
329
|
+
</Source>
|
|
330
|
+
<Source href="https://web.dev/case-studies/earth-webassembly">
|
|
331
|
+
<SourceTrigger label={2} showFavicon />
|
|
332
|
+
<SourceContent
|
|
333
|
+
title="Google Earth and WebAssembly - web.dev"
|
|
334
|
+
description="Case study on porting Google Earth's C++ rendering engine to WebAssembly for browser delivery."
|
|
335
|
+
/>
|
|
336
|
+
</Source>
|
|
337
|
+
<Source href="https://shopify.engineering/shopify-webassembly">
|
|
338
|
+
<SourceTrigger label={3} showFavicon />
|
|
339
|
+
<SourceContent
|
|
340
|
+
title="How Shopify Uses WebAssembly"
|
|
341
|
+
description="Shopify's journey using WebAssembly for Liquid template parsing in their online store editor."
|
|
342
|
+
/>
|
|
343
|
+
</Source>
|
|
344
|
+
</SourceList>
|
|
345
|
+
</div>
|
|
346
|
+
</div>
|
|
347
|
+
),
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
// ---------------------------------------------------------------------------
|
|
351
|
+
// Numbered Citations (composition) story
|
|
352
|
+
// ---------------------------------------------------------------------------
|
|
353
|
+
|
|
354
|
+
export const NumberedComposition: Story = {
|
|
355
|
+
name: 'Numbered Citations (composition)',
|
|
356
|
+
parameters: {
|
|
357
|
+
docs: {
|
|
358
|
+
description: {
|
|
359
|
+
story: [
|
|
360
|
+
'The **same** numbered-citation strip as the "Numbered Citations" story — but built entirely from `<kai-sources numbered>` + `<kai-source>` children in markup.',
|
|
361
|
+
'',
|
|
362
|
+
'No `sources` JS property is set. The `<kai-sources>` element reads its `<kai-source>` light-DOM children via `MutationObserver` and appends them to the merged source list automatically. The `numbered` boolean attribute then labels each chip with its 1-based index.',
|
|
363
|
+
'',
|
|
364
|
+
'Attribute reference for `<kai-source>`:',
|
|
365
|
+
'- `href` — the URL to link to (domain seeds the default label/favicon)',
|
|
366
|
+
'- `headline` — hover-card heading (**not** `title` — `title` is a reserved HTML attribute)',
|
|
367
|
+
'- `description` — hover-card body text',
|
|
368
|
+
'- `label` — custom chip label (ignored when the parent `<kai-sources>` has `numbered`)',
|
|
369
|
+
'- `show-favicon` — bare boolean attribute to show the domain favicon',
|
|
370
|
+
'',
|
|
371
|
+
'`<kai-sources>` attribute reference:',
|
|
372
|
+
'- `numbered` — auto-labels all chips with their 1-based index from the merged list',
|
|
373
|
+
'- `show-favicon` — enables favicons for all children (per-item attribute overrides)',
|
|
374
|
+
'',
|
|
375
|
+
'**When to choose composition:** great for static/authored citations in plain HTML or any template language — no JS wiring needed beyond the element registration.',
|
|
376
|
+
].join('\n'),
|
|
377
|
+
},
|
|
378
|
+
},
|
|
379
|
+
},
|
|
380
|
+
render: () => {
|
|
381
|
+
let el: HTMLElement | undefined;
|
|
382
|
+
onMount(() => {
|
|
383
|
+
// The `numbered` attribute is a boolean — set it imperatively so it is
|
|
384
|
+
// registered after the element upgrades (avoids timing issues in SSR/Storybook).
|
|
385
|
+
el?.setAttribute('numbered', '');
|
|
386
|
+
});
|
|
387
|
+
return (
|
|
388
|
+
<div class="flex flex-col gap-6 p-4 w-full max-w-2xl bg-background rounded-xl shadow-lg">
|
|
389
|
+
<div>
|
|
390
|
+
<p class="text-sm text-muted-foreground mb-1">
|
|
391
|
+
Composition: <code><kai-sources numbered></code> with <code><kai-source></code> children — chips auto-labelled 1, 2, 3, 4:
|
|
392
|
+
</p>
|
|
393
|
+
<kai-sources ref={(e: HTMLElement) => (el = e)} style={{ display: 'block' }}>
|
|
394
|
+
<kai-source
|
|
395
|
+
href="https://www.figma.com/blog/webassembly-cut-figmas-load-time-by-3x/"
|
|
396
|
+
headline="WebAssembly cut Figma's load time by 3x"
|
|
397
|
+
description="How Figma leveraged WebAssembly to dramatically improve their browser-based design tool performance."
|
|
398
|
+
/>
|
|
399
|
+
<kai-source
|
|
400
|
+
href="https://web.dev/case-studies/earth-webassembly"
|
|
401
|
+
headline="Google Earth and WebAssembly - web.dev"
|
|
402
|
+
description="Case study on porting Google Earth's C++ rendering engine to WebAssembly for browser delivery."
|
|
403
|
+
/>
|
|
404
|
+
<kai-source
|
|
405
|
+
href="https://shopify.engineering/shopify-webassembly"
|
|
406
|
+
headline="How Shopify Uses WebAssembly"
|
|
407
|
+
description="Shopify's journey using WebAssembly for Liquid template parsing in their online store editor."
|
|
408
|
+
/>
|
|
409
|
+
<kai-source
|
|
410
|
+
href="https://surma.dev/things/js-to-asc/"
|
|
411
|
+
headline="JavaScript to AssemblyScript - Surma.dev"
|
|
412
|
+
description="Detailed performance comparison of JS vs AssemblyScript/Wasm for various workloads."
|
|
413
|
+
/>
|
|
414
|
+
</kai-sources>
|
|
415
|
+
</div>
|
|
416
|
+
|
|
417
|
+
<div>
|
|
418
|
+
<p class="text-sm text-muted-foreground mb-1">
|
|
419
|
+
Composition without numbering — chips fall back to domain labels:
|
|
420
|
+
</p>
|
|
421
|
+
<kai-sources style={{ display: 'block' }}>
|
|
422
|
+
<kai-source
|
|
423
|
+
href="https://www.figma.com/blog/webassembly-cut-figmas-load-time-by-3x/"
|
|
424
|
+
headline="WebAssembly cut Figma's load time by 3x"
|
|
425
|
+
description="How Figma leveraged WebAssembly to dramatically improve their browser-based design tool performance."
|
|
426
|
+
/>
|
|
427
|
+
<kai-source
|
|
428
|
+
href="https://web.dev/case-studies/earth-webassembly"
|
|
429
|
+
headline="Google Earth and WebAssembly - web.dev"
|
|
430
|
+
description="Case study on porting Google Earth's C++ rendering engine to WebAssembly for browser delivery."
|
|
431
|
+
/>
|
|
432
|
+
<kai-source
|
|
433
|
+
href="https://shopify.engineering/shopify-webassembly"
|
|
434
|
+
headline="How Shopify Uses WebAssembly"
|
|
435
|
+
description="Shopify's journey using WebAssembly for Liquid template parsing in their online store editor."
|
|
436
|
+
/>
|
|
437
|
+
</kai-sources>
|
|
438
|
+
</div>
|
|
439
|
+
|
|
440
|
+
<div>
|
|
441
|
+
<p class="text-sm text-muted-foreground mb-1">
|
|
442
|
+
Composition with favicons and custom labels (no <code>numbered</code>):
|
|
443
|
+
</p>
|
|
444
|
+
<kai-sources style={{ display: 'block' }}>
|
|
445
|
+
<kai-source
|
|
446
|
+
href="https://www.figma.com/blog/webassembly-cut-figmas-load-time-by-3x/"
|
|
447
|
+
label="Figma"
|
|
448
|
+
headline="WebAssembly cut Figma's load time by 3x"
|
|
449
|
+
description="How Figma leveraged WebAssembly to dramatically improve their browser-based design tool performance."
|
|
450
|
+
show-favicon
|
|
451
|
+
/>
|
|
452
|
+
<kai-source
|
|
453
|
+
href="https://web.dev/case-studies/earth-webassembly"
|
|
454
|
+
label="web.dev"
|
|
455
|
+
headline="Google Earth and WebAssembly"
|
|
456
|
+
description="Case study on porting Google Earth's C++ rendering engine to WebAssembly for browser delivery."
|
|
457
|
+
show-favicon
|
|
458
|
+
/>
|
|
459
|
+
<kai-source
|
|
460
|
+
href="https://shopify.engineering/shopify-webassembly"
|
|
461
|
+
label="Shopify"
|
|
462
|
+
headline="How Shopify Uses WebAssembly"
|
|
463
|
+
description="Shopify's journey using WebAssembly for Liquid template parsing in their online store editor."
|
|
464
|
+
show-favicon
|
|
465
|
+
/>
|
|
466
|
+
</kai-sources>
|
|
467
|
+
</div>
|
|
468
|
+
</div>
|
|
469
|
+
);
|
|
470
|
+
},
|
|
471
|
+
};
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { Meta } from '@storybook/addon-docs/blocks';
|
|
2
|
+
|
|
3
|
+
<Meta title="Docs/Accessibility" />
|
|
4
|
+
|
|
5
|
+
# Accessibility
|
|
6
|
+
|
|
7
|
+
`@kitn.ai/ui` targets **WCAG 2.1 Level AA**. The kit is audited with [axe-core](https://github.com/dequelabs/axe-core) (via `scripts/audit-a11y.mjs`) and ships with **0 axe violations** in both light and dark modes. Keyboard navigation is verified with a Playwright browser test suite.
|
|
8
|
+
|
|
9
|
+
This page describes the accessibility posture, the keyboard model, known limitations, and what you need to do as an integrator.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Color contrast
|
|
14
|
+
|
|
15
|
+
All text and UI chrome meet WCAG 2.1 AA contrast requirements (4.5:1 for body text, 3:1 for large text and UI components) in the default light and dark palettes.
|
|
16
|
+
|
|
17
|
+
The `theme` attribute on every element (`light | dark | auto`) controls which token set loads. `auto` (the default) follows the OS `prefers-color-scheme` media query, so users who configure dark mode at the OS level get it automatically. Override either set with `--kai-color-*` tokens — if you do, verify contrast yourself; the kit cannot audit tokens it does not control.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Keyboard operability
|
|
22
|
+
|
|
23
|
+
Every interactive control is reachable and operable without a mouse.
|
|
24
|
+
|
|
25
|
+
### Focus order
|
|
26
|
+
|
|
27
|
+
Tab moves through all focusable controls in DOM order. The prompt textarea, send button, attachment button, toolbar controls (search, mic), header controls (model switcher, context meter), message action buttons, suggestion chips, and conversation list items are all included. Focus rings are always visible — they are not hidden on `:focus`, only on `:focus-visible`.
|
|
28
|
+
|
|
29
|
+
### Dropdowns and select menus (ModelSwitcher, ChatScopePicker, …)
|
|
30
|
+
|
|
31
|
+
| Key | Action |
|
|
32
|
+
|---|---|
|
|
33
|
+
| Enter / Space / ↓ | Open the menu |
|
|
34
|
+
| ↑ / ↓ | Move between items |
|
|
35
|
+
| Home / End | Jump to first / last item |
|
|
36
|
+
| Typeahead (letter keys) | Jump to the first item starting with that letter |
|
|
37
|
+
| Enter / Space | Select the focused item |
|
|
38
|
+
| Esc | Close without selecting; focus returns to the trigger |
|
|
39
|
+
| Tab | Close and move focus past the trigger |
|
|
40
|
+
|
|
41
|
+
Focus always returns to the trigger element after the menu closes, whether closed by Esc, selection, or a click outside.
|
|
42
|
+
|
|
43
|
+
### Collapsible panels (Reasoning, Tool calls, …)
|
|
44
|
+
|
|
45
|
+
| Key | Action |
|
|
46
|
+
|---|---|
|
|
47
|
+
| Enter / Space | Toggle expanded / collapsed |
|
|
48
|
+
| Tab | Move into the expanded content |
|
|
49
|
+
| Esc | Collapse (if focused inside) |
|
|
50
|
+
|
|
51
|
+
### Slash command palette
|
|
52
|
+
|
|
53
|
+
Typing `/` in the prompt input opens the command palette.
|
|
54
|
+
|
|
55
|
+
| Key | Action |
|
|
56
|
+
|---|---|
|
|
57
|
+
| ↑ / ↓ | Navigate items |
|
|
58
|
+
| Home / End | Jump to first / last item |
|
|
59
|
+
| Enter / Tab | Select the focused command (inserts `/label ` into the input with caret at end) |
|
|
60
|
+
| Esc | Close the palette; focus stays in the input |
|
|
61
|
+
|
|
62
|
+
### Conversation list
|
|
63
|
+
|
|
64
|
+
| Key | Action |
|
|
65
|
+
|---|---|
|
|
66
|
+
| ↑ / ↓ | Move between conversations |
|
|
67
|
+
| Enter | Select the focused conversation |
|
|
68
|
+
| Tab | Move through action buttons (if any) |
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Accessible names on icon buttons
|
|
73
|
+
|
|
74
|
+
Every icon-only button (attach, send, mic, search, copy, like, dislike, regenerate, close) carries an accessible name via `aria-label`. Screen readers announce the button's purpose rather than "button" or nothing. Labels use plain language: "Send message", "Attach file", "Copy message", "Thumbs up", and so on.
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Tooltips and hover cards
|
|
79
|
+
|
|
80
|
+
Tooltips and hover cards (on sources, context meter, etc.) are dismissable and persistent per WCAG 2.1 SC 1.4.13 (Content on Hover or Focus):
|
|
81
|
+
|
|
82
|
+
- They appear on both hover and keyboard focus.
|
|
83
|
+
- Moving the pointer over the tooltip/card content keeps it visible (it does not vanish when the pointer leaves the trigger).
|
|
84
|
+
- They can be dismissed with **Esc** without moving focus.
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## ARIA landmarks and live regions
|
|
89
|
+
|
|
90
|
+
- The message list is marked as a log region (`role="log"`, `aria-live="polite"`) so streaming tokens are announced to screen readers without being intrusive.
|
|
91
|
+
- The prompt area is labelled; the textarea carries its placeholder as an accessible name fallback.
|
|
92
|
+
- The conversation sidebar is a navigation landmark (`<nav>`).
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Shadow DOM and screen readers
|
|
97
|
+
|
|
98
|
+
All elements render inside Shadow DOM. Modern screen readers (NVDA + Chrome, JAWS + Chrome, VoiceOver + Safari/Chrome) pierce Shadow DOM correctly. Accessible names, roles, and live regions work as expected.
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Audit tooling
|
|
103
|
+
|
|
104
|
+
Accessibility is verified with:
|
|
105
|
+
|
|
106
|
+
- **axe-core** (`scripts/audit-a11y.mjs`) — automated rule checks in both light and dark themes. Zero violations at the time of build.
|
|
107
|
+
- **Playwright keyboard tests** — 21-scenario browser test suite covering focus order, dropdown/collapsible/palette keyboard nav, ArrowUp/Down/Home/End/typeahead/Enter/Escape/Tab, and focus-return after close.
|
|
108
|
+
|
|
109
|
+
The kit does not carry a "WCAG AA certified" certification — no automated tool can certify that. What it does carry is a targeted AA design, an axe-core clean bill, and a passing Playwright keyboard suite.
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## What integrators need to do
|
|
114
|
+
|
|
115
|
+
1. **Do not hide focus rings.** The kit renders visible focus rings via `:focus-visible`. Do not add `outline: none` or `outline: 0` in your host-page CSS targeting `*` or the element host.
|
|
116
|
+
2. **Verify contrast if you override tokens.** Use a contrast checker after overriding any `--kai-color-*` token.
|
|
117
|
+
3. **Provide meaningful conversation titles.** The conversation list announces the `title` field to screen readers. "Chat 1" is less useful than "React integration help".
|
|
118
|
+
4. **Set a meaningful `placeholder`.** The textarea placeholder doubles as an accessible name when no label is associated.
|
|
119
|
+
5. **Check your theme choice.** Using `theme="light"` in a page the user has set to dark mode (or vice versa) can create contrast mismatches between kit components and host-page content. `theme="auto"` (the default) avoids this.
|