@kitnai/chat 0.7.0 → 0.8.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/README.md +9 -9
- package/dist/custom-elements.json +1626 -883
- package/dist/kitn-chat.es.js +36 -36
- package/dist/llms/llms-full.txt +303 -142
- package/dist/llms/llms.txt +18 -18
- package/dist/schemas/card-envelope.schema.json +14 -0
- package/dist/schemas/card-event.schema.json +12 -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/task-list.result.schema.json +16 -0
- package/dist/schemas/task-list.schema.json +78 -0
- package/dist/theme.tokens.css +65 -65
- package/dist/tsx-B8rCNbgL.js +1 -0
- package/dist/typescript-RycA9KXf.js +1 -0
- package/frameworks/react/index.tsx +356 -189
- package/frameworks/react/runtime.tsx +2 -2
- package/llms-full.txt +303 -142
- package/llms.txt +18 -18
- package/package.json +5 -2
- package/src/components/artifact.stories.tsx +138 -0
- package/src/components/artifact.tsx +581 -0
- package/src/components/attachments.stories.tsx +7 -8
- package/src/components/attachments.tsx +2 -2
- package/src/components/card.tsx +110 -0
- package/src/components/chain-of-thought.stories.tsx +7 -8
- package/src/components/chat-container.stories.tsx +7 -8
- package/src/components/chat-container.tsx +4 -0
- package/src/components/checkpoint.stories.tsx +7 -8
- package/src/components/checkpoint.tsx +3 -0
- package/src/components/code-block.stories.tsx +8 -9
- package/src/components/code-block.tsx +5 -2
- package/src/components/component-meta.json +3419 -0
- package/src/components/confirm-card.stories.tsx +74 -0
- package/src/components/confirm-card.tsx +299 -0
- package/src/components/context.stories.tsx +7 -8
- package/src/components/conversation-item.stories.tsx +7 -8
- package/src/components/conversation-item.tsx +2 -2
- package/src/components/conversation-list.stories.tsx +7 -8
- package/src/components/conversation-list.tsx +1 -1
- package/src/components/embed.tsx +196 -0
- package/src/components/empty.stories.tsx +8 -9
- package/src/components/feedback-bar.stories.tsx +7 -8
- package/src/components/file-tree.stories.tsx +73 -0
- package/src/components/file-tree.tsx +383 -0
- package/src/components/file-upload.stories.tsx +7 -8
- package/src/components/form-widgets.tsx +461 -0
- package/src/components/form.tsx +796 -0
- package/src/components/image.stories.tsx +7 -8
- package/src/components/link-card.tsx +194 -0
- package/src/components/loader.stories.tsx +7 -8
- package/src/components/markdown.stories.tsx +7 -8
- package/src/components/message-narrow.stories.tsx +12 -13
- package/src/components/message-skills.stories.tsx +16 -17
- package/src/components/message.stories.tsx +17 -18
- package/src/components/model-switcher.stories.tsx +7 -8
- package/src/components/prompt-input.stories.tsx +8 -9
- package/src/components/prompt-suggestion.stories.tsx +7 -8
- package/src/components/prompt-suggestion.tsx +3 -3
- package/src/components/reasoning.stories.tsx +7 -8
- package/src/components/scroll-button.stories.tsx +7 -8
- package/src/components/slash-command.stories.tsx +8 -9
- package/src/components/slash-command.tsx +2 -2
- package/src/components/source.stories.tsx +7 -8
- package/src/components/source.tsx +1 -1
- package/src/components/task-list-card.stories.tsx +78 -0
- package/src/components/task-list-card.tsx +388 -0
- package/src/components/text-shimmer.stories.tsx +7 -8
- package/src/components/thinking-bar.stories.tsx +7 -8
- package/src/components/tool.stories.tsx +7 -8
- package/src/components/tool.tsx +2 -2
- package/src/components/voice-input.stories.tsx +7 -8
- package/src/elements/artifact.stories.tsx +291 -0
- package/src/elements/artifact.tsx +72 -0
- package/src/elements/{kitn-attachments.stories.tsx → attachments.stories.tsx} +11 -20
- package/src/elements/attachments.tsx +4 -4
- package/src/elements/card.stories.tsx +118 -0
- package/src/elements/card.tsx +40 -0
- package/src/elements/catalog.stories.tsx +491 -0
- package/src/elements/{kitn-chain-of-thought.stories.tsx → chain-of-thought.stories.tsx} +13 -22
- package/src/elements/chain-of-thought.tsx +3 -3
- package/src/elements/{kitn-chat-scope-picker.stories.tsx → chat-scope-picker.stories.tsx} +10 -19
- package/src/elements/chat-scope-picker.tsx +4 -4
- package/src/elements/{kitn-chat-workspace.stories.tsx → chat-workspace.stories.tsx} +15 -23
- package/src/elements/chat-workspace.tsx +2 -2
- package/src/elements/{kitn-chat.stories.tsx → chat.stories.tsx} +12 -20
- package/src/elements/chat.tsx +2 -2
- package/src/elements/{kitn-checkpoint.stories.tsx → checkpoint.stories.tsx} +11 -20
- package/src/elements/checkpoint.tsx +8 -4
- package/src/elements/{kitn-code-block.stories.tsx → code-block.stories.tsx} +10 -19
- package/src/elements/code-block.tsx +3 -3
- package/src/elements/compiled.css +1 -1
- package/src/elements/composed-shell.stories.tsx +316 -0
- package/src/elements/confirm-card.stories.tsx +186 -0
- package/src/elements/confirm-card.tsx +45 -0
- package/src/elements/{kitn-context-meter.stories.tsx → context-meter.stories.tsx} +10 -19
- package/src/elements/context-meter.tsx +3 -3
- package/src/elements/{kitn-conversation-list.stories.tsx → conversation-list.stories.tsx} +12 -20
- package/src/elements/conversation-list.tsx +2 -2
- package/src/elements/css.ts +1 -1
- package/src/elements/define.tsx +10 -10
- package/src/elements/element-meta.json +1379 -733
- package/src/elements/element-types.d.ts +251 -125
- package/src/elements/embed.stories.tsx +197 -0
- package/src/elements/embed.tsx +35 -0
- package/src/elements/{kitn-empty.stories.tsx → empty.stories.tsx} +12 -21
- package/src/elements/empty.tsx +3 -3
- package/src/elements/{kitn-feedback-bar.stories.tsx → feedback-bar.stories.tsx} +11 -20
- package/src/elements/feedback-bar.tsx +4 -4
- package/src/elements/file-tree.stories.tsx +133 -0
- package/src/elements/file-tree.tsx +52 -0
- package/src/elements/{kitn-file-upload.stories.tsx → file-upload.stories.tsx} +12 -21
- package/src/elements/file-upload.tsx +4 -4
- package/src/elements/form.stories.tsx +204 -0
- package/src/elements/form.tsx +37 -0
- package/src/elements/{kitn-image.stories.tsx → image.stories.tsx} +10 -19
- package/src/elements/image.tsx +3 -3
- package/src/elements/link-card.stories.tsx +193 -0
- package/src/elements/link-card.tsx +34 -0
- package/src/elements/{kitn-loader.stories.tsx → loader.stories.tsx} +11 -20
- package/src/elements/loader.tsx +3 -3
- package/src/elements/{kitn-markdown.stories.tsx → markdown.stories.tsx} +10 -19
- package/src/elements/markdown.tsx +3 -3
- package/src/elements/{kitn-message-skills.stories.tsx → message-skills.stories.tsx} +10 -19
- package/src/elements/message-skills.tsx +3 -3
- package/src/elements/{kitn-message.stories.tsx → message.stories.tsx} +12 -21
- package/src/elements/message.tsx +5 -5
- package/src/elements/{kitn-model-switcher.stories.tsx → model-switcher.stories.tsx} +10 -19
- package/src/elements/model-switcher.tsx +5 -5
- package/src/elements/{kitn-prompt-input.stories.tsx → prompt-input.stories.tsx} +14 -22
- package/src/elements/prompt-input.tsx +3 -3
- package/src/elements/{kitn-prompt-suggestions.stories.tsx → prompt-suggestions.stories.tsx} +13 -22
- package/src/elements/prompt-suggestions.tsx +4 -4
- package/src/elements/{kitn-reasoning.stories.tsx → reasoning.stories.tsx} +10 -19
- package/src/elements/reasoning.tsx +4 -4
- package/src/elements/register.ts +11 -1
- package/src/elements/resizable.stories.tsx +200 -0
- package/src/elements/resizable.tsx +264 -0
- package/src/elements/{kitn-response-stream.stories.tsx → response-stream.stories.tsx} +10 -19
- package/src/elements/response-stream.tsx +4 -4
- package/src/elements/{kitn-source-list.stories.tsx → source-list.stories.tsx} +11 -20
- package/src/elements/{kitn-source.stories.tsx → source.stories.tsx} +12 -21
- package/src/elements/source.tsx +5 -5
- package/src/elements/styles.css +140 -1
- package/src/elements/task-list-card.stories.tsx +194 -0
- package/src/elements/task-list-card.tsx +40 -0
- package/src/elements/{kitn-text-shimmer.stories.tsx → text-shimmer.stories.tsx} +10 -19
- package/src/elements/text-shimmer.tsx +3 -3
- package/src/elements/{kitn-thinking-bar.stories.tsx → thinking-bar.stories.tsx} +11 -20
- package/src/elements/thinking-bar.tsx +5 -5
- package/src/elements/{kitn-tool.stories.tsx → tool.stories.tsx} +10 -19
- package/src/elements/tool.tsx +3 -3
- package/src/elements/{kitn-voice-input.stories.tsx → voice-input.stories.tsx} +10 -19
- package/src/elements/voice-input.tsx +4 -4
- package/src/index.ts +94 -2
- package/src/primitives/card-contract.ts +60 -0
- package/src/primitives/card-host.tsx +35 -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/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/task-list.result.schema.json +16 -0
- package/src/primitives/card-schemas/task-list.schema.json +78 -0
- package/src/primitives/card-validate.ts +95 -0
- package/src/primitives/embed-providers.ts +254 -0
- package/src/primitives/highlighter.ts +4 -0
- package/src/primitives/link-preview.ts +87 -0
- package/src/primitives/pdf-preview.ts +121 -0
- package/src/stories/chat-panel-layout.stories.tsx +2 -1
- package/src/stories/chat-scene.tsx +22 -21
- package/src/stories/checkpoint-restore.stories.tsx +10 -10
- package/src/stories/conversation-with-reasoning.stories.tsx +4 -4
- package/src/stories/conversation-with-sources.stories.tsx +7 -7
- package/src/stories/docs/Accessibility.mdx +2 -2
- package/src/stories/docs/ForAIAgents.mdx +3 -3
- package/src/stories/docs/GettingStarted.mdx +2 -2
- package/src/stories/docs/Installation.mdx +2 -2
- package/src/stories/docs/Integrations.mdx +29 -29
- package/src/stories/docs/Introduction.mdx +3 -3
- package/src/stories/docs/Theming.mdx +2 -2
- package/src/stories/docs/element-controls.ts +32 -0
- package/src/stories/docs/theme-editor/theme-editor.tsx +1 -0
- package/src/stories/examples/ChoosingComponents.mdx +94 -0
- package/src/stories/examples/sample-data.ts +79 -0
- package/src/stories/message-actions.stories.tsx +13 -13
- package/src/stories/pattern-centered-conversation.stories.tsx +3 -3
- package/src/stories/pattern-docked-widget.stories.tsx +1 -1
- package/src/stories/pattern-empty-state.stories.tsx +3 -3
- package/src/stories/prompt-input-variants.stories.tsx +13 -13
- package/src/stories/streaming-response.stories.tsx +3 -3
- package/src/stories/typography.stories.tsx +4 -4
- package/src/ui/avatar.stories.tsx +7 -8
- package/src/ui/badge.stories.tsx +7 -8
- package/src/ui/button.stories.tsx +8 -9
- package/src/ui/button.tsx +1 -0
- package/src/ui/collapsible.stories.tsx +6 -7
- package/src/ui/dropdown.stories.tsx +6 -7
- package/src/ui/hover-card.stories.tsx +6 -7
- package/src/ui/resizable.stories.tsx +74 -9
- package/src/ui/resizable.tsx +351 -71
- package/src/ui/scroll-area.stories.tsx +6 -7
- package/src/ui/scroll-area.tsx +3 -1
- package/src/ui/separator.stories.tsx +7 -8
- package/src/ui/skeleton.stories.tsx +7 -8
- package/src/ui/textarea.stories.tsx +6 -7
- package/src/ui/tooltip.stories.tsx +8 -9
- package/theme.css +65 -65
- package/src/stories/docs/element-spec.tsx +0 -86
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { type JSX, Show, splitProps, mergeProps, createUniqueId } from 'solid-js';
|
|
2
|
+
import { cn } from '../utils/cn';
|
|
3
|
+
import { AlertTriangle } from 'lucide-solid';
|
|
4
|
+
|
|
5
|
+
export interface CardProps extends JSX.HTMLAttributes<HTMLDivElement> {
|
|
6
|
+
/** Heading rendered in the card chrome (the contract's CardEnvelope.title).
|
|
7
|
+
* NB: NOT `title` — `title` is a reserved IDL attr (see define.tsx RESERVED). */
|
|
8
|
+
heading?: string;
|
|
9
|
+
/** Optional supporting text under the heading. */
|
|
10
|
+
description?: string;
|
|
11
|
+
/** Media region (image/icon) rendered above the heading. */
|
|
12
|
+
media?: JSX.Element;
|
|
13
|
+
/** Footer action region (buttons). */
|
|
14
|
+
actions?: JSX.Element;
|
|
15
|
+
/** When set, the card renders its standard inline error state INSTEAD of body. */
|
|
16
|
+
errorMessage?: string;
|
|
17
|
+
/** Compact spacing for dense lists of cards. */
|
|
18
|
+
dense?: boolean;
|
|
19
|
+
/** Stable id for the heading (so composing cards can `aria-labelledby` it).
|
|
20
|
+
* Auto-generated when omitted. */
|
|
21
|
+
headingId?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* `Card` — the shared presentational chrome every native card composes from:
|
|
26
|
+
* an optional media region, a heading + description, a body (default slot), an
|
|
27
|
+
* actions footer, and one consistent inline **error** state (the contract's
|
|
28
|
+
* "never a broken/partial card" rule). It is intentionally chrome-only: it reads
|
|
29
|
+
* no `CardContext` and emits no `CardEvent` — the cards that compose it (e.g.
|
|
30
|
+
* `kc-form`) own the contract interaction.
|
|
31
|
+
*/
|
|
32
|
+
export function Card(props: CardProps): JSX.Element {
|
|
33
|
+
const merged = mergeProps({ dense: false }, props);
|
|
34
|
+
const [local, rest] = splitProps(merged, [
|
|
35
|
+
'heading',
|
|
36
|
+
'description',
|
|
37
|
+
'media',
|
|
38
|
+
'actions',
|
|
39
|
+
'errorMessage',
|
|
40
|
+
'dense',
|
|
41
|
+
'headingId',
|
|
42
|
+
'class',
|
|
43
|
+
'children',
|
|
44
|
+
]);
|
|
45
|
+
|
|
46
|
+
const autoId = createUniqueId();
|
|
47
|
+
const headingId = () => local.headingId ?? `kc-card-heading-${autoId}`;
|
|
48
|
+
const hasError = () => local.errorMessage !== undefined && local.errorMessage !== '';
|
|
49
|
+
const hasHeader = () => Boolean(local.heading) || Boolean(local.description);
|
|
50
|
+
|
|
51
|
+
return (
|
|
52
|
+
<div
|
|
53
|
+
class={cn(
|
|
54
|
+
'flex flex-col rounded-xl border border-border bg-card text-card-foreground shadow-sm',
|
|
55
|
+
local.dense ? 'gap-2.5 p-3.5' : 'gap-4 p-5',
|
|
56
|
+
local.class,
|
|
57
|
+
)}
|
|
58
|
+
{...rest}
|
|
59
|
+
>
|
|
60
|
+
<Show when={local.media}>
|
|
61
|
+
<div class="overflow-hidden rounded-lg">{local.media}</div>
|
|
62
|
+
</Show>
|
|
63
|
+
|
|
64
|
+
<Show when={hasHeader()}>
|
|
65
|
+
<div
|
|
66
|
+
class={cn(
|
|
67
|
+
'flex flex-col border-b border-border',
|
|
68
|
+
local.dense ? 'gap-0.5 pb-2.5' : 'gap-1 pb-4',
|
|
69
|
+
)}
|
|
70
|
+
>
|
|
71
|
+
<Show when={local.heading}>
|
|
72
|
+
<h3
|
|
73
|
+
id={headingId()}
|
|
74
|
+
class="text-[1.0625rem] font-semibold leading-snug tracking-tight text-foreground"
|
|
75
|
+
>
|
|
76
|
+
{local.heading}
|
|
77
|
+
</h3>
|
|
78
|
+
</Show>
|
|
79
|
+
<Show when={local.description}>
|
|
80
|
+
<p class="text-[0.8125rem] leading-relaxed text-muted-foreground">{local.description}</p>
|
|
81
|
+
</Show>
|
|
82
|
+
</div>
|
|
83
|
+
</Show>
|
|
84
|
+
|
|
85
|
+
<Show
|
|
86
|
+
when={hasError()}
|
|
87
|
+
fallback={
|
|
88
|
+
<>
|
|
89
|
+
<Show when={local.children}>
|
|
90
|
+
<div class="text-sm text-foreground">{local.children}</div>
|
|
91
|
+
</Show>
|
|
92
|
+
<Show when={local.actions}>
|
|
93
|
+
<div class="flex flex-wrap items-center justify-end gap-2 pt-1">
|
|
94
|
+
{local.actions}
|
|
95
|
+
</div>
|
|
96
|
+
</Show>
|
|
97
|
+
</>
|
|
98
|
+
}
|
|
99
|
+
>
|
|
100
|
+
<div
|
|
101
|
+
role="alert"
|
|
102
|
+
class="flex items-start gap-2 rounded-lg border border-destructive/40 bg-destructive/10 p-3 text-sm text-destructive dark:bg-destructive/15 dark:text-red-400"
|
|
103
|
+
>
|
|
104
|
+
<AlertTriangle size={16} class="mt-0.5 shrink-0" aria-hidden="true" />
|
|
105
|
+
<span>{local.errorMessage}</span>
|
|
106
|
+
</div>
|
|
107
|
+
</Show>
|
|
108
|
+
</div>
|
|
109
|
+
);
|
|
110
|
+
}
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
ChainOfThoughtContent,
|
|
7
7
|
ChainOfThoughtItem,
|
|
8
8
|
} from './chain-of-thought';
|
|
9
|
+
import { componentDescription } from '../stories/docs/element-controls';
|
|
9
10
|
|
|
10
11
|
const meta = {
|
|
11
12
|
title: 'Components/ChainOfThought',
|
|
@@ -14,14 +15,12 @@ const meta = {
|
|
|
14
15
|
parameters: {
|
|
15
16
|
layout: 'padded',
|
|
16
17
|
docs: {
|
|
17
|
-
description:
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
].join('\n\n'),
|
|
24
|
-
},
|
|
18
|
+
description: componentDescription([
|
|
19
|
+
'A vertical, collapsible timeline that reveals an agent\'s reasoning as a series of connected steps. Composed of `ChainOfThought` (root) wrapping `ChainOfThoughtStep` items, each with a `ChainOfThoughtTrigger`, `ChainOfThoughtContent`, and one or more `ChainOfThoughtItem`s.',
|
|
20
|
+
'**When to use:** to surface multi-step reasoning, tool calls, or research progress behind an assistant response, letting users expand each step on demand.',
|
|
21
|
+
'**How to use:** map each reasoning step to a `ChainOfThoughtStep` (mark the final one with `isLast`); put the summary in `ChainOfThoughtTrigger` and the detail inside `ChainOfThoughtContent` / `ChainOfThoughtItem`.',
|
|
22
|
+
'**Placement:** above or within an assistant message, typically before the final answer.',
|
|
23
|
+
]),
|
|
25
24
|
controls: { exclude: ['use:eventListener'] },
|
|
26
25
|
},
|
|
27
26
|
},
|
|
@@ -2,6 +2,7 @@ import type { Meta, StoryObj } from 'storybook-solidjs-vite';
|
|
|
2
2
|
import { For } from 'solid-js';
|
|
3
3
|
import { ChatContainerRoot, ChatContainerContent, ChatContainerScrollAnchor } from './chat-container';
|
|
4
4
|
import { Message, MessageAvatar, MessageContent } from './message';
|
|
5
|
+
import { componentDescription } from '../stories/docs/element-controls';
|
|
5
6
|
|
|
6
7
|
const sampleMessages = [
|
|
7
8
|
{ role: 'user', content: 'What is SolidJS?' },
|
|
@@ -40,14 +41,12 @@ const meta = {
|
|
|
40
41
|
parameters: {
|
|
41
42
|
layout: 'padded',
|
|
42
43
|
docs: {
|
|
43
|
-
description:
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
].join('\n\n'),
|
|
50
|
-
},
|
|
44
|
+
description: componentDescription([
|
|
45
|
+
'A scrollable message viewport that automatically sticks to the bottom as new content streams in. Composed of `ChatContainerRoot` (the scroll region), `ChatContainerContent` (the message stack), and `ChatContainerScrollAnchor` (the stick-to-bottom target).',
|
|
46
|
+
'**When to use:** as the conversation transcript region of a chat UI, where messages append over time and the view should follow the latest output unless the user scrolls up.',
|
|
47
|
+
'**How to use:** wrap your message list in `ChatContainerRoot`, place messages inside `ChatContainerContent`, and end with `ChatContainerScrollAnchor`. Give the root a fixed height so it can scroll.',
|
|
48
|
+
'**Placement:** the central pane of a chat layout, between the header and the prompt input.',
|
|
49
|
+
]),
|
|
51
50
|
controls: { exclude: ['use:eventListener'] },
|
|
52
51
|
},
|
|
53
52
|
},
|
|
@@ -30,6 +30,10 @@ function ChatContainerRoot(props: ChatContainerRootProps) {
|
|
|
30
30
|
ref={ref}
|
|
31
31
|
class={cn('flex flex-col overflow-y-auto', local.class)}
|
|
32
32
|
role="log"
|
|
33
|
+
// Keyboard users must be able to scroll the conversation even when no
|
|
34
|
+
// message contains a focusable control (WCAG 2.1.1 — axe
|
|
35
|
+
// `scrollable-region-focusable`).
|
|
36
|
+
tabindex={0}
|
|
33
37
|
{...rest}
|
|
34
38
|
>
|
|
35
39
|
{local.children}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from 'storybook-solidjs-vite';
|
|
2
2
|
import { fn } from 'storybook/test';
|
|
3
3
|
import { Checkpoint, CheckpointIcon, CheckpointTrigger } from './checkpoint';
|
|
4
|
+
import { componentDescription } from '../stories/docs/element-controls';
|
|
4
5
|
|
|
5
6
|
const meta = {
|
|
6
7
|
title: 'Components/Checkpoint',
|
|
@@ -9,14 +10,12 @@ const meta = {
|
|
|
9
10
|
parameters: {
|
|
10
11
|
layout: 'padded',
|
|
11
12
|
docs: {
|
|
12
|
-
description:
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
].join('\n\n'),
|
|
19
|
-
},
|
|
13
|
+
description: componentDescription([
|
|
14
|
+
'An inline marker that lets a user restore the conversation to a saved point. Composed of `Checkpoint` (row + separator) wrapping a `CheckpointIcon` and a `CheckpointTrigger` button.',
|
|
15
|
+
'**When to use:** to mark a restorable state in a transcript — e.g. before an edit or a branching action — so the user can revert to it.',
|
|
16
|
+
'**How to use:** place a `CheckpointIcon` and a `CheckpointTrigger` inside `Checkpoint`. Give the trigger an `onClick` handler and an optional `tooltip`; pass custom SVG children to `CheckpointIcon` to override the default flag.',
|
|
17
|
+
'**Placement:** between messages in a chat transcript, as a thin separator-style row.',
|
|
18
|
+
]),
|
|
20
19
|
controls: { exclude: ['use:eventListener'] },
|
|
21
20
|
},
|
|
22
21
|
},
|
|
@@ -50,6 +50,8 @@ export function CheckpointIcon(props: CheckpointIconProps) {
|
|
|
50
50
|
|
|
51
51
|
export interface CheckpointTriggerProps {
|
|
52
52
|
tooltip?: string;
|
|
53
|
+
/** Accessible name for the button — required when it has no visible text (icon-only). */
|
|
54
|
+
'aria-label'?: string;
|
|
53
55
|
onClick?: () => void;
|
|
54
56
|
children?: JSX.Element;
|
|
55
57
|
class?: string;
|
|
@@ -70,6 +72,7 @@ export function CheckpointTrigger(props: CheckpointTriggerProps) {
|
|
|
70
72
|
variant={variant()}
|
|
71
73
|
size={size()}
|
|
72
74
|
type="button"
|
|
75
|
+
aria-label={props['aria-label']}
|
|
73
76
|
onClick={props.onClick}
|
|
74
77
|
class={props.class}
|
|
75
78
|
>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from 'storybook-solidjs-vite';
|
|
2
2
|
import { CodeBlock, CodeBlockCode, CodeBlockGroup } from './code-block';
|
|
3
3
|
import { Button } from '../ui/button';
|
|
4
|
+
import { componentDescription } from '../stories/docs/element-controls';
|
|
4
5
|
|
|
5
6
|
const tsCode = `interface User {
|
|
6
7
|
id: string;
|
|
@@ -48,14 +49,12 @@ const meta = {
|
|
|
48
49
|
parameters: {
|
|
49
50
|
layout: 'padded',
|
|
50
51
|
docs: {
|
|
51
|
-
description:
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
].join('\n\n'),
|
|
58
|
-
},
|
|
52
|
+
description: componentDescription([
|
|
53
|
+
'A bordered code card with optional syntax highlighting. `CodeBlock` is the container, `CodeBlockCode` renders the (Shiki-)highlighted source, and `CodeBlockGroup` is a flex row for a header/footer (filename + copy button).',
|
|
54
|
+
'**When to use:** to display code snippets in chat messages, documentation, or anywhere fenced code appears — typically emitted by the Markdown renderer for ``` blocks.',
|
|
55
|
+
'**How to use:** wrap one or more children in `<CodeBlock>`. Pass the source string and a `language` to `<CodeBlockCode>`; optionally override the `theme`. Add a `<CodeBlockGroup>` for a filename row and copy action.',
|
|
56
|
+
'**Placement:** inside assistant message content, README/docs panes, and tool-output views.',
|
|
57
|
+
]),
|
|
59
58
|
controls: { exclude: ['use:eventListener'] },
|
|
60
59
|
},
|
|
61
60
|
},
|
|
@@ -130,7 +129,7 @@ export const WithHeader: Story = {
|
|
|
130
129
|
<CodeBlock>
|
|
131
130
|
<CodeBlockGroup class="border-b border-border px-4 py-2">
|
|
132
131
|
<span class="text-xs text-muted-foreground font-mono">user.ts</span>
|
|
133
|
-
<Button variant="ghost" size="icon-sm">
|
|
132
|
+
<Button variant="ghost" size="icon-sm" aria-label="Copy code">
|
|
134
133
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
135
134
|
<rect x="9" y="9" width="13" height="13" rx="2" ry="2" />
|
|
136
135
|
<path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1" />
|
|
@@ -65,15 +65,18 @@ function CodeBlockCode(props: CodeBlockCodeProps) {
|
|
|
65
65
|
);
|
|
66
66
|
|
|
67
67
|
return (
|
|
68
|
+
// `tabindex={0}` makes the horizontally-scrollable region reachable by
|
|
69
|
+
// keyboard (axe `scrollable-region-focusable`); `{...rest}` lets a consumer
|
|
70
|
+
// override it. No `role="region"` — that would demand an accessible name.
|
|
68
71
|
<Show
|
|
69
72
|
when={highlighted()}
|
|
70
73
|
fallback={
|
|
71
|
-
<div class={classNames()} {...rest}>
|
|
74
|
+
<div class={classNames()} tabindex={0} {...rest}>
|
|
72
75
|
<pre><code>{local.code}</code></pre>
|
|
73
76
|
</div>
|
|
74
77
|
}
|
|
75
78
|
>
|
|
76
|
-
<div class={classNames()} innerHTML={highlighted()} {...rest} />
|
|
79
|
+
<div class={classNames()} tabindex={0} innerHTML={highlighted()} {...rest} />
|
|
77
80
|
</Show>
|
|
78
81
|
);
|
|
79
82
|
}
|