@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,74 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from 'storybook-solidjs-vite';
|
|
2
|
+
import { createSignal } from 'solid-js';
|
|
3
|
+
import { ConfirmCard, type ConfirmCardData } from './confirm-card';
|
|
4
|
+
import { componentDescription } from '../stories/docs/element-controls';
|
|
5
|
+
import type { CardEvent, CardHost, CardContext } from '../primitives/card-contract';
|
|
6
|
+
|
|
7
|
+
const ctx: CardContext = { theme: { mode: 'light' }, locale: 'en' };
|
|
8
|
+
|
|
9
|
+
/** Renders the Solid <ConfirmCard> with a capturing `host`, logging emitted events. */
|
|
10
|
+
function Demo(props: { def: ConfirmCardData; heading?: string; cardId: string }) {
|
|
11
|
+
const [log, setLog] = createSignal<CardEvent[]>([]);
|
|
12
|
+
const host: CardHost = { context: () => ctx, emit: (e) => setLog((p) => [...p, e]) };
|
|
13
|
+
return (
|
|
14
|
+
<div style={{ 'max-width': '460px', display: 'flex', 'flex-direction': 'column', gap: '12px' }}>
|
|
15
|
+
<ConfirmCard host={host} data={props.def} heading={props.heading} cardId={props.cardId} />
|
|
16
|
+
<pre
|
|
17
|
+
style={{
|
|
18
|
+
margin: 0,
|
|
19
|
+
'max-height': '180px',
|
|
20
|
+
overflow: 'auto',
|
|
21
|
+
background: 'var(--color-muted, #f4f4f5)',
|
|
22
|
+
'border-radius': '8px',
|
|
23
|
+
padding: '8px',
|
|
24
|
+
'font-size': '12px',
|
|
25
|
+
}}
|
|
26
|
+
>
|
|
27
|
+
{log().length === 0 ? '// emitted CardEvents appear here' : JSON.stringify(log(), null, 2)}
|
|
28
|
+
</pre>
|
|
29
|
+
</div>
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const APPROVE: ConfirmCardData = {
|
|
34
|
+
body: 'This will apply 3 pending migrations to production. This cannot be undone.',
|
|
35
|
+
tone: 'warning',
|
|
36
|
+
actions: [
|
|
37
|
+
{ id: 'approve', label: 'Run migration', style: 'primary', default: true },
|
|
38
|
+
{ id: 'reject', label: 'Cancel' },
|
|
39
|
+
],
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const DESTRUCTIVE: ConfirmCardData = {
|
|
43
|
+
body: 'Permanently delete 12 files? This cannot be undone.',
|
|
44
|
+
tone: 'danger',
|
|
45
|
+
actions: [
|
|
46
|
+
{ id: 'delete', label: 'Delete files', style: 'destructive', default: true },
|
|
47
|
+
{ id: 'cancel', label: 'Keep them' },
|
|
48
|
+
],
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const meta = {
|
|
52
|
+
title: 'Solid (Advanced)/Elements/ConfirmCard',
|
|
53
|
+
component: ConfirmCard,
|
|
54
|
+
tags: ['autodocs'],
|
|
55
|
+
parameters: {
|
|
56
|
+
layout: 'padded',
|
|
57
|
+
docs: {
|
|
58
|
+
description: componentDescription([
|
|
59
|
+
'The SolidJS layer behind `<kai-confirm>`. Pass a `host` (a `CardHost`) to receive the emitted `CardEvent`s directly (the native-host path), or wrap in a `CardProvider`. Activating an action emits the `action` verb and resolves the card.',
|
|
60
|
+
]),
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
} satisfies Meta<typeof ConfirmCard>;
|
|
64
|
+
|
|
65
|
+
export default meta;
|
|
66
|
+
type Story = StoryObj<typeof ConfirmCard>;
|
|
67
|
+
|
|
68
|
+
export const ApproveReject: Story = {
|
|
69
|
+
render: () => <Demo def={APPROVE} heading="Run database migration?" cardId="card-approve" />,
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export const Destructive: Story = {
|
|
73
|
+
render: () => <Demo def={DESTRUCTIVE} heading="Delete files?" cardId="card-delete" />,
|
|
74
|
+
};
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type JSX,
|
|
3
|
+
For,
|
|
4
|
+
Show,
|
|
5
|
+
splitProps,
|
|
6
|
+
mergeProps,
|
|
7
|
+
createMemo,
|
|
8
|
+
createEffect,
|
|
9
|
+
on,
|
|
10
|
+
ErrorBoundary,
|
|
11
|
+
} from 'solid-js';
|
|
12
|
+
import { cn } from '../utils/cn';
|
|
13
|
+
import { Button } from '../ui/button';
|
|
14
|
+
import { Card } from './card';
|
|
15
|
+
import type { CardEnvelope, CardEvent, CardHost, CardResolution } from '../primitives/card-contract';
|
|
16
|
+
import { useCardResolution } from './use-card-resolution';
|
|
17
|
+
import { emitCardEvent } from '../primitives/card-routing';
|
|
18
|
+
import { useCardHost } from '../primitives/card-host';
|
|
19
|
+
import { AlertTriangle, Check, X } from 'lucide-solid';
|
|
20
|
+
|
|
21
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
22
|
+
// Types (confirm.schema.json) — see src/primitives/card-schemas/confirm.schema.json
|
|
23
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
24
|
+
|
|
25
|
+
export type ConfirmActionStyle = 'primary' | 'default' | 'destructive';
|
|
26
|
+
export type ConfirmTone = 'default' | 'warning' | 'danger';
|
|
27
|
+
|
|
28
|
+
export interface ConfirmAction {
|
|
29
|
+
id: string;
|
|
30
|
+
label: string;
|
|
31
|
+
style?: ConfirmActionStyle;
|
|
32
|
+
payload?: unknown;
|
|
33
|
+
default?: boolean;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface ConfirmCardData {
|
|
37
|
+
heading?: string;
|
|
38
|
+
body?: string;
|
|
39
|
+
tone?: ConfirmTone;
|
|
40
|
+
actions: ConfirmAction[]; // 1..4
|
|
41
|
+
dismissible?: boolean;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export type ConfirmCardEnvelope = CardEnvelope<'confirm', ConfirmCardData>;
|
|
45
|
+
|
|
46
|
+
export const CONFIRM_CARD_TYPE = 'confirm' as const;
|
|
47
|
+
|
|
48
|
+
const VALID_STYLES = new Set<ConfirmActionStyle>(['primary', 'default', 'destructive']);
|
|
49
|
+
|
|
50
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
51
|
+
// Pure helpers (unit-tested in isolation).
|
|
52
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
53
|
+
|
|
54
|
+
/** Map an action's `style` to a Button variant (falls back + warns on unknown). */
|
|
55
|
+
export function buttonVariantForStyle(
|
|
56
|
+
style: ConfirmActionStyle | undefined,
|
|
57
|
+
): 'default' | 'outline' | 'destructive' {
|
|
58
|
+
switch (style) {
|
|
59
|
+
case 'primary':
|
|
60
|
+
return 'default';
|
|
61
|
+
case 'destructive':
|
|
62
|
+
return 'destructive';
|
|
63
|
+
case 'default':
|
|
64
|
+
case undefined:
|
|
65
|
+
return 'outline';
|
|
66
|
+
default:
|
|
67
|
+
// eslint-disable-next-line no-console
|
|
68
|
+
console.warn(`[kai-confirm] unknown action style "${style as string}"; using default`);
|
|
69
|
+
return 'outline';
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** De-dupe actions by id (first wins) and validate their shape. Returns the usable
|
|
74
|
+
* list + an optional error message when there's nothing renderable. */
|
|
75
|
+
export function normalizeActions(actions: unknown): {
|
|
76
|
+
actions: ConfirmAction[];
|
|
77
|
+
error?: string;
|
|
78
|
+
} {
|
|
79
|
+
if (!Array.isArray(actions) || actions.length === 0) {
|
|
80
|
+
return { actions: [], error: "This card couldn't be displayed." };
|
|
81
|
+
}
|
|
82
|
+
const seen = new Set<string>();
|
|
83
|
+
const out: ConfirmAction[] = [];
|
|
84
|
+
for (const a of actions) {
|
|
85
|
+
if (!a || typeof a !== 'object') continue;
|
|
86
|
+
const action = a as Partial<ConfirmAction>;
|
|
87
|
+
if (typeof action.id !== 'string' || action.id.length === 0) continue;
|
|
88
|
+
if (typeof action.label !== 'string' || action.label.length === 0) continue;
|
|
89
|
+
if (seen.has(action.id)) {
|
|
90
|
+
// eslint-disable-next-line no-console
|
|
91
|
+
console.warn(`[kai-confirm] duplicate action id "${action.id}" ignored`);
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
seen.add(action.id);
|
|
95
|
+
const style = VALID_STYLES.has(action.style as ConfirmActionStyle)
|
|
96
|
+
? (action.style as ConfirmActionStyle)
|
|
97
|
+
: undefined;
|
|
98
|
+
if (action.style !== undefined && style === undefined) {
|
|
99
|
+
// eslint-disable-next-line no-console
|
|
100
|
+
console.warn(`[kai-confirm] unknown action style "${String(action.style)}"; using default`);
|
|
101
|
+
}
|
|
102
|
+
out.push({
|
|
103
|
+
id: action.id,
|
|
104
|
+
label: action.label,
|
|
105
|
+
style,
|
|
106
|
+
payload: action.payload,
|
|
107
|
+
default: action.default === true,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
if (out.length === 0) return { actions: [], error: "This card couldn't be displayed." };
|
|
111
|
+
return { actions: out };
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** The id of the default action (first with `default:true`), if any. */
|
|
115
|
+
export function defaultActionId(actions: ConfirmAction[]): string | undefined {
|
|
116
|
+
return actions.find((a) => a.default)?.id;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
120
|
+
// The <ConfirmCard> component.
|
|
121
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
122
|
+
|
|
123
|
+
export interface ConfirmCardProps {
|
|
124
|
+
/** The confirm definition (CardEnvelope.data). */
|
|
125
|
+
data?: ConfirmCardData;
|
|
126
|
+
/** The card id used to correlate every emitted CardEvent. */
|
|
127
|
+
cardId?: string;
|
|
128
|
+
/** The envelope title rendered in the card chrome. */
|
|
129
|
+
heading?: string;
|
|
130
|
+
/** Optional explicit CardHost (otherwise read from a CardProvider, otherwise the
|
|
131
|
+
* bubbling `kai-card` CustomEvent off `hostElement`). */
|
|
132
|
+
host?: CardHost;
|
|
133
|
+
/** The custom-element host node, for the bubbling `kai-card` fallback emit. */
|
|
134
|
+
hostElement?: HTMLElement;
|
|
135
|
+
/** Focus the default action on mount. Default OFF (no focus-stealing mid-stream). */
|
|
136
|
+
autofocus?: boolean;
|
|
137
|
+
class?: string;
|
|
138
|
+
/** When set, render the chromed read-only view instead of the buttons. */
|
|
139
|
+
resolution?: CardResolution;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* `ConfirmCard` — a named-intent approval card. Renders a title + body + a small
|
|
144
|
+
* set of action buttons inside `Card` chrome. Activating an action emits the Card
|
|
145
|
+
* contract's `action` verb (`{ kind:'action', cardId, action, payload }`) and
|
|
146
|
+
* resolves the card (other actions disabled, the chosen one marked) so the same
|
|
147
|
+
* approval can't double-fire. Emits `ready` on mount, `dismiss` for the optional
|
|
148
|
+
* close affordance, and `error` for an unusable definition (inline error state).
|
|
149
|
+
*/
|
|
150
|
+
export function ConfirmCard(props: ConfirmCardProps): JSX.Element {
|
|
151
|
+
const merged = mergeProps({ cardId: 'kai-confirm', autofocus: false }, props);
|
|
152
|
+
const [local] = splitProps(merged, [
|
|
153
|
+
'data',
|
|
154
|
+
'cardId',
|
|
155
|
+
'heading',
|
|
156
|
+
'host',
|
|
157
|
+
'hostElement',
|
|
158
|
+
'autofocus',
|
|
159
|
+
'class',
|
|
160
|
+
'resolution',
|
|
161
|
+
]);
|
|
162
|
+
|
|
163
|
+
const ctxHost = useCardHost();
|
|
164
|
+
|
|
165
|
+
const emit = (event: CardEvent): void => {
|
|
166
|
+
const h = local.host ?? ctxHost;
|
|
167
|
+
if (h) h.emit(event);
|
|
168
|
+
else if (local.hostElement) emitCardEvent(local.hostElement, event);
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
const normalized = createMemo(() => normalizeActions(local.data?.actions));
|
|
172
|
+
const valid = createMemo(() => normalized().error === undefined);
|
|
173
|
+
const errorMessage = createMemo(() => normalized().error ?? '');
|
|
174
|
+
const actions = createMemo(() => normalized().actions);
|
|
175
|
+
const tone = (): ConfirmTone => local.data?.tone ?? 'default';
|
|
176
|
+
const isDanger = () => tone() === 'danger';
|
|
177
|
+
const defaultId = createMemo(() => defaultActionId(actions()));
|
|
178
|
+
|
|
179
|
+
const res = useCardResolution({ prop: () => local.resolution, data: () => local.data });
|
|
180
|
+
|
|
181
|
+
const resolvedAction = createMemo(() => {
|
|
182
|
+
const r = res.resolution();
|
|
183
|
+
if (!r || r.kind !== 'action') return undefined;
|
|
184
|
+
const found = actions().find((a) => a.id === r.action);
|
|
185
|
+
return { label: found?.label ?? r.action };
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
// ready / error lifecycle emits.
|
|
189
|
+
createEffect(
|
|
190
|
+
on(valid, (ok) => {
|
|
191
|
+
if (ok) emit({ kind: 'ready', cardId: local.cardId });
|
|
192
|
+
else emit({ kind: 'error', cardId: local.cardId, message: errorMessage() });
|
|
193
|
+
}),
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
const onAction = (action: ConfirmAction): void => {
|
|
197
|
+
if (res.isResolved()) return; // single-shot
|
|
198
|
+
emit({
|
|
199
|
+
kind: 'action',
|
|
200
|
+
cardId: local.cardId,
|
|
201
|
+
action: action.id,
|
|
202
|
+
...(action.payload !== undefined ? { payload: action.payload } : {}),
|
|
203
|
+
});
|
|
204
|
+
res.setLocal({
|
|
205
|
+
kind: 'action',
|
|
206
|
+
action: action.id,
|
|
207
|
+
...(action.payload !== undefined ? { payload: action.payload } : {}),
|
|
208
|
+
});
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
const onDismiss = (): void => emit({ kind: 'dismiss', cardId: local.cardId });
|
|
212
|
+
|
|
213
|
+
let bodyRef: HTMLDivElement | undefined;
|
|
214
|
+
|
|
215
|
+
// Surface the resolved action id for host styling.
|
|
216
|
+
createEffect(() => {
|
|
217
|
+
const el = local.hostElement;
|
|
218
|
+
if (!el) return;
|
|
219
|
+
const r = res.resolution();
|
|
220
|
+
if (r && r.kind === 'action') el.setAttribute('data-kai-resolved', r.action);
|
|
221
|
+
else el.removeAttribute('data-kai-resolved');
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
return (
|
|
225
|
+
<Show when={valid()} fallback={<Card heading={local.heading} errorMessage={errorMessage()} />}>
|
|
226
|
+
<ErrorBoundary
|
|
227
|
+
fallback={() => {
|
|
228
|
+
emit({ kind: 'error', cardId: local.cardId, message: 'The card failed to render.' });
|
|
229
|
+
return <Card heading={local.heading} errorMessage="The card failed to render." />;
|
|
230
|
+
}}
|
|
231
|
+
>
|
|
232
|
+
<Card
|
|
233
|
+
heading={local.heading}
|
|
234
|
+
actions={
|
|
235
|
+
<Show
|
|
236
|
+
when={!res.isResolved()}
|
|
237
|
+
fallback={
|
|
238
|
+
<div
|
|
239
|
+
class="ml-auto flex items-center gap-2 text-sm font-medium text-foreground"
|
|
240
|
+
role={res.isOptimistic() ? 'status' : undefined}
|
|
241
|
+
>
|
|
242
|
+
<Check size={16} aria-hidden="true" />
|
|
243
|
+
<span>{resolvedAction()?.label}</span>
|
|
244
|
+
</div>
|
|
245
|
+
}
|
|
246
|
+
>
|
|
247
|
+
<div class="flex w-full flex-wrap items-center justify-between gap-2">
|
|
248
|
+
<Show when={local.data?.dismissible === true}>
|
|
249
|
+
<Button
|
|
250
|
+
type="button"
|
|
251
|
+
variant="ghost"
|
|
252
|
+
size="icon-sm"
|
|
253
|
+
aria-label="Dismiss"
|
|
254
|
+
onClick={onDismiss}
|
|
255
|
+
>
|
|
256
|
+
<X size={16} aria-hidden="true" />
|
|
257
|
+
</Button>
|
|
258
|
+
</Show>
|
|
259
|
+
<div class="ml-auto flex flex-wrap items-center gap-2">
|
|
260
|
+
<For each={actions()}>
|
|
261
|
+
{(action) => (
|
|
262
|
+
<Button
|
|
263
|
+
type="button"
|
|
264
|
+
variant={buttonVariantForStyle(action.style)}
|
|
265
|
+
data-action-id={action.id}
|
|
266
|
+
data-kai-default={action.default ? 'true' : undefined}
|
|
267
|
+
ref={(el) => {
|
|
268
|
+
if (local.autofocus && action.id === defaultId()) {
|
|
269
|
+
queueMicrotask(() => el.focus());
|
|
270
|
+
}
|
|
271
|
+
}}
|
|
272
|
+
onClick={() => onAction(action)}
|
|
273
|
+
>
|
|
274
|
+
{action.label}
|
|
275
|
+
</Button>
|
|
276
|
+
)}
|
|
277
|
+
</For>
|
|
278
|
+
</div>
|
|
279
|
+
</div>
|
|
280
|
+
</Show>
|
|
281
|
+
}
|
|
282
|
+
>
|
|
283
|
+
<div
|
|
284
|
+
ref={bodyRef}
|
|
285
|
+
class={cn('flex flex-col gap-2', local.class)}
|
|
286
|
+
onKeyDown={(e) => {
|
|
287
|
+
// Enter on the card body (not on a focused button) invokes the default action.
|
|
288
|
+
if (e.key !== 'Enter') return;
|
|
289
|
+
const target = e.target as HTMLElement;
|
|
290
|
+
if (target.tagName === 'BUTTON') return;
|
|
291
|
+
const id = defaultId();
|
|
292
|
+
if (id === undefined) return;
|
|
293
|
+
const action = actions().find((a) => a.id === id);
|
|
294
|
+
if (action) onAction(action);
|
|
295
|
+
}}
|
|
296
|
+
tabindex={defaultId() !== undefined ? 0 : undefined}
|
|
297
|
+
>
|
|
298
|
+
<Show when={isDanger()}>
|
|
299
|
+
<div class="flex items-center gap-2 text-sm font-medium text-destructive dark:text-red-400">
|
|
300
|
+
<AlertTriangle size={16} class="shrink-0" aria-hidden="true" />
|
|
301
|
+
<span>Heads up</span>
|
|
302
|
+
</div>
|
|
303
|
+
</Show>
|
|
304
|
+
<Show when={local.data?.heading}>
|
|
305
|
+
<p class="text-sm font-semibold text-foreground">{local.data?.heading}</p>
|
|
306
|
+
</Show>
|
|
307
|
+
<Show when={local.data?.body}>
|
|
308
|
+
<p class="text-sm text-foreground">{local.data?.body}</p>
|
|
309
|
+
</Show>
|
|
310
|
+
</div>
|
|
311
|
+
</Card>
|
|
312
|
+
</ErrorBoundary>
|
|
313
|
+
</Show>
|
|
314
|
+
);
|
|
315
|
+
}
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from 'storybook-solidjs-vite';
|
|
2
|
+
import {
|
|
3
|
+
Context,
|
|
4
|
+
ContextTrigger,
|
|
5
|
+
ContextContent,
|
|
6
|
+
ContextContentHeader,
|
|
7
|
+
ContextContentBody,
|
|
8
|
+
ContextContentFooter,
|
|
9
|
+
ContextInputUsage,
|
|
10
|
+
ContextOutputUsage,
|
|
11
|
+
ContextReasoningUsage,
|
|
12
|
+
ContextCacheUsage,
|
|
13
|
+
} from './context';
|
|
14
|
+
import { componentDescription } from '../stories/docs/element-controls';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Story for the compound `Context` family. `Context` is the root provider that
|
|
18
|
+
* holds the token-usage values; the trigger/content/usage-row subcomponents read
|
|
19
|
+
* from it. The controllable props all live on the `Context` root, so `Playground`
|
|
20
|
+
* drives the root and composes a full hover-card breakdown.
|
|
21
|
+
*/
|
|
22
|
+
const meta = {
|
|
23
|
+
title: 'Solid (Advanced)/Elements/Context',
|
|
24
|
+
component: Context,
|
|
25
|
+
tags: ['autodocs'],
|
|
26
|
+
parameters: {
|
|
27
|
+
layout: 'padded',
|
|
28
|
+
docs: {
|
|
29
|
+
description: componentDescription([
|
|
30
|
+
'A model context-window usage indicator: a hover-card trigger showing the used-percent ring, with a popover breaking down token usage (input / output / reasoning / cache) and estimated cost.',
|
|
31
|
+
'**When to use:** to surface how much of a model\'s context window a conversation has consumed and roughly what it costs — near the prompt input or in a chat header.',
|
|
32
|
+
'**How to use:** wrap the composition in `<Context>` and pass `usedTokens` / `maxTokens` (plus optional `inputTokens`, `outputTokens`, `reasoningTokens`, `cacheTokens`, `estimatedCost`). Compose `ContextTrigger`, `ContextContent` (with `Header`/`Body`/`Footer`), and the usage rows.',
|
|
33
|
+
'**Placement:** chat toolbars, prompt-input action bars, and conversation headers.',
|
|
34
|
+
]),
|
|
35
|
+
controls: { exclude: ['use:eventListener'] },
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
argTypes: {
|
|
39
|
+
usedTokens: {
|
|
40
|
+
control: 'number',
|
|
41
|
+
description: 'Tokens consumed so far. Drives the ring fill and progress bar.',
|
|
42
|
+
},
|
|
43
|
+
maxTokens: {
|
|
44
|
+
control: 'number',
|
|
45
|
+
description: 'Total context window size.',
|
|
46
|
+
},
|
|
47
|
+
inputTokens: {
|
|
48
|
+
control: 'number',
|
|
49
|
+
description: 'Prompt/input tokens (shown by `ContextInputUsage`).',
|
|
50
|
+
},
|
|
51
|
+
outputTokens: {
|
|
52
|
+
control: 'number',
|
|
53
|
+
description: 'Generated/output tokens (shown by `ContextOutputUsage`).',
|
|
54
|
+
},
|
|
55
|
+
reasoningTokens: {
|
|
56
|
+
control: 'number',
|
|
57
|
+
description: 'Reasoning tokens (shown by `ContextReasoningUsage`).',
|
|
58
|
+
},
|
|
59
|
+
cacheTokens: {
|
|
60
|
+
control: 'number',
|
|
61
|
+
description: 'Cached tokens (shown by `ContextCacheUsage`).',
|
|
62
|
+
},
|
|
63
|
+
estimatedCost: {
|
|
64
|
+
control: 'number',
|
|
65
|
+
description: 'Estimated cost in USD (shown by `ContextContentFooter`).',
|
|
66
|
+
},
|
|
67
|
+
warnThreshold: {
|
|
68
|
+
control: 'number',
|
|
69
|
+
description: 'Fraction (0–1) above which the bar turns yellow. Default `0.7`.',
|
|
70
|
+
},
|
|
71
|
+
dangerThreshold: {
|
|
72
|
+
control: 'number',
|
|
73
|
+
description: 'Fraction (0–1) above which the bar turns red. Default `0.9`.',
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
args: {
|
|
77
|
+
usedTokens: 85000,
|
|
78
|
+
maxTokens: 128000,
|
|
79
|
+
inputTokens: 60000,
|
|
80
|
+
outputTokens: 15000,
|
|
81
|
+
reasoningTokens: 8000,
|
|
82
|
+
cacheTokens: 2000,
|
|
83
|
+
estimatedCost: 0.45,
|
|
84
|
+
},
|
|
85
|
+
render: (args) => (
|
|
86
|
+
<Context {...args}>
|
|
87
|
+
<ContextTrigger />
|
|
88
|
+
<ContextContent>
|
|
89
|
+
<ContextContentHeader />
|
|
90
|
+
<ContextContentBody>
|
|
91
|
+
<div class="space-y-1">
|
|
92
|
+
<ContextInputUsage />
|
|
93
|
+
<ContextOutputUsage />
|
|
94
|
+
<ContextReasoningUsage />
|
|
95
|
+
<ContextCacheUsage />
|
|
96
|
+
</div>
|
|
97
|
+
</ContextContentBody>
|
|
98
|
+
<ContextContentFooter />
|
|
99
|
+
</ContextContent>
|
|
100
|
+
</Context>
|
|
101
|
+
),
|
|
102
|
+
} satisfies Meta<typeof Context>;
|
|
103
|
+
|
|
104
|
+
export default meta;
|
|
105
|
+
type Story = StoryObj<typeof meta>;
|
|
106
|
+
|
|
107
|
+
const IMPORT = `import {
|
|
108
|
+
Context, ContextTrigger, ContextContent, ContextContentHeader,
|
|
109
|
+
ContextContentBody, ContextContentFooter,
|
|
110
|
+
ContextInputUsage, ContextOutputUsage, ContextReasoningUsage, ContextCacheUsage,
|
|
111
|
+
} from '@kitn.ai/ui';`;
|
|
112
|
+
const src = (code: string) => ({
|
|
113
|
+
parameters: { docs: { source: { code: `${IMPORT}\n\n${code}`, language: 'tsx' } } },
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
const usage = `<Context usedTokens={85000} maxTokens={128000} inputTokens={60000} outputTokens={15000} reasoningTokens={8000} cacheTokens={2000} estimatedCost={0.45}>
|
|
117
|
+
<ContextTrigger />
|
|
118
|
+
<ContextContent>
|
|
119
|
+
<ContextContentHeader />
|
|
120
|
+
<ContextContentBody>
|
|
121
|
+
<div class="space-y-1">
|
|
122
|
+
<ContextInputUsage />
|
|
123
|
+
<ContextOutputUsage />
|
|
124
|
+
<ContextReasoningUsage />
|
|
125
|
+
<ContextCacheUsage />
|
|
126
|
+
</div>
|
|
127
|
+
</ContextContentBody>
|
|
128
|
+
<ContextContentFooter />
|
|
129
|
+
</ContextContent>
|
|
130
|
+
</Context>`;
|
|
131
|
+
|
|
132
|
+
/** Interactive playground — tweak token counts to watch the ring, bar color, and breakdown update. */
|
|
133
|
+
export const Playground: Story = {
|
|
134
|
+
...src(usage),
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
export const LowUsage: Story = {
|
|
138
|
+
args: {
|
|
139
|
+
usedTokens: 12000,
|
|
140
|
+
maxTokens: 128000,
|
|
141
|
+
inputTokens: 8000,
|
|
142
|
+
outputTokens: 4000,
|
|
143
|
+
reasoningTokens: undefined,
|
|
144
|
+
cacheTokens: undefined,
|
|
145
|
+
estimatedCost: 0.02,
|
|
146
|
+
},
|
|
147
|
+
...src(usage),
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
export const MediumUsage: Story = {
|
|
151
|
+
args: {
|
|
152
|
+
usedTokens: 85000,
|
|
153
|
+
maxTokens: 128000,
|
|
154
|
+
inputTokens: 60000,
|
|
155
|
+
outputTokens: 15000,
|
|
156
|
+
reasoningTokens: 8000,
|
|
157
|
+
cacheTokens: 2000,
|
|
158
|
+
estimatedCost: 0.45,
|
|
159
|
+
},
|
|
160
|
+
...src(usage),
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
export const HighUsage: Story = {
|
|
164
|
+
args: {
|
|
165
|
+
usedTokens: 122000,
|
|
166
|
+
maxTokens: 128000,
|
|
167
|
+
inputTokens: 90000,
|
|
168
|
+
outputTokens: 22000,
|
|
169
|
+
reasoningTokens: 10000,
|
|
170
|
+
cacheTokens: undefined,
|
|
171
|
+
estimatedCost: 1.85,
|
|
172
|
+
},
|
|
173
|
+
...src(usage),
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
export const WithCost: Story = {
|
|
177
|
+
args: {
|
|
178
|
+
usedTokens: 50000,
|
|
179
|
+
maxTokens: 200000,
|
|
180
|
+
inputTokens: 35000,
|
|
181
|
+
outputTokens: 10000,
|
|
182
|
+
reasoningTokens: 5000,
|
|
183
|
+
cacheTokens: undefined,
|
|
184
|
+
estimatedCost: 0.32,
|
|
185
|
+
},
|
|
186
|
+
...src(usage),
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
const customThresholdUsage = `<Context
|
|
190
|
+
usedTokens={110000}
|
|
191
|
+
maxTokens={200000}
|
|
192
|
+
inputTokens={70000}
|
|
193
|
+
outputTokens={40000}
|
|
194
|
+
estimatedCost={0.65}
|
|
195
|
+
warnThreshold={0.5}
|
|
196
|
+
dangerThreshold={0.75}
|
|
197
|
+
>
|
|
198
|
+
<ContextTrigger />
|
|
199
|
+
<ContextContent>
|
|
200
|
+
<ContextContentHeader />
|
|
201
|
+
<ContextContentBody>
|
|
202
|
+
<div class="space-y-1">
|
|
203
|
+
<ContextInputUsage />
|
|
204
|
+
<ContextOutputUsage />
|
|
205
|
+
</div>
|
|
206
|
+
</ContextContentBody>
|
|
207
|
+
<ContextContentFooter />
|
|
208
|
+
</ContextContent>
|
|
209
|
+
</Context>`;
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Custom thresholds — `warnThreshold=0.5` / `dangerThreshold=0.75` so the bar
|
|
213
|
+
* turns yellow at 50% and red at 75%. At 55% (110 000 / 200 000) the bar renders
|
|
214
|
+
* yellow even though the defaults would show green at this level.
|
|
215
|
+
*/
|
|
216
|
+
export const CustomThresholds: Story = {
|
|
217
|
+
args: {
|
|
218
|
+
usedTokens: 110000,
|
|
219
|
+
maxTokens: 200000,
|
|
220
|
+
inputTokens: 70000,
|
|
221
|
+
outputTokens: 40000,
|
|
222
|
+
reasoningTokens: undefined,
|
|
223
|
+
cacheTokens: undefined,
|
|
224
|
+
estimatedCost: 0.65,
|
|
225
|
+
warnThreshold: 0.5,
|
|
226
|
+
dangerThreshold: 0.75,
|
|
227
|
+
},
|
|
228
|
+
...src(customThresholdUsage),
|
|
229
|
+
};
|