@kitnai/chat 0.3.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -5
- package/dist/custom-elements.json +2969 -0
- package/dist/kitn-chat.es.js +52 -39
- package/dist/llms/llms-full.txt +718 -0
- package/dist/llms/llms.txt +104 -0
- package/dist/theme.tokens.css +137 -0
- package/frameworks/react/index.tsx +584 -0
- package/frameworks/react/runtime.tsx +94 -0
- package/llms-full.txt +718 -0
- package/llms.txt +104 -0
- package/package.json +53 -6
- package/src/components/attachments.tsx +4 -2
- package/src/components/chain-of-thought.tsx +1 -1
- package/src/components/chat-scope-picker.tsx +2 -2
- package/src/components/chat-thread.tsx +217 -0
- package/src/components/checkpoint.tsx +7 -3
- package/src/components/context.tsx +14 -18
- package/src/components/conversation-item.tsx +1 -1
- package/src/components/conversation-list.tsx +5 -4
- package/src/components/message-skills.tsx +1 -1
- package/src/components/message.tsx +1 -0
- package/src/components/model-switcher.tsx +3 -3
- package/src/components/prompt-input.tsx +20 -2
- package/src/components/reasoning.tsx +2 -2
- package/src/components/scroll-button.tsx +1 -0
- package/src/components/slash-command.tsx +17 -8
- package/src/components/source.tsx +2 -2
- package/src/components/thinking-bar.tsx +2 -2
- package/src/components/tool.tsx +17 -6
- package/src/components/voice-input.tsx +5 -1
- package/src/elements/attachments.tsx +132 -0
- package/src/elements/chain-of-thought.tsx +45 -0
- package/src/elements/chat-scope-picker.tsx +36 -0
- package/src/elements/chat-workspace.tsx +122 -0
- package/src/elements/chat.tsx +31 -228
- package/src/elements/checkpoint.tsx +43 -0
- package/src/elements/code-block.tsx +42 -0
- package/src/elements/compiled.css +1 -1
- package/src/elements/context-meter.tsx +71 -0
- package/src/elements/conversation-list.tsx +6 -0
- package/src/elements/default-input.tsx +22 -1
- package/src/elements/define.tsx +98 -12
- package/src/elements/element-types.d.ts +444 -0
- package/src/elements/empty.tsx +29 -0
- package/src/elements/feedback-bar.tsx +33 -0
- package/src/elements/file-upload.tsx +44 -0
- package/src/elements/image.tsx +32 -0
- package/src/elements/kitn-attachments.stories.tsx +181 -0
- package/src/elements/kitn-chain-of-thought.stories.tsx +75 -0
- package/src/elements/kitn-chat-scope-picker.stories.tsx +72 -0
- package/src/elements/kitn-chat-workspace.stories.tsx +195 -0
- package/src/elements/kitn-checkpoint.stories.tsx +71 -0
- package/src/elements/kitn-code-block.stories.tsx +82 -0
- package/src/elements/kitn-context-meter.stories.tsx +85 -0
- package/src/elements/kitn-empty.stories.tsx +110 -0
- package/src/elements/kitn-feedback-bar.stories.tsx +73 -0
- package/src/elements/kitn-file-upload.stories.tsx +81 -0
- package/src/elements/kitn-image.stories.tsx +70 -0
- package/src/elements/kitn-loader.stories.tsx +87 -0
- package/src/elements/kitn-markdown.stories.tsx +75 -0
- package/src/elements/kitn-message-skills.stories.tsx +74 -0
- package/src/elements/kitn-message.stories.tsx +105 -0
- package/src/elements/kitn-model-switcher.stories.tsx +80 -0
- package/src/elements/kitn-prompt-input.stories.tsx +74 -16
- package/src/elements/kitn-prompt-suggestions.stories.tsx +157 -0
- package/src/elements/kitn-reasoning.stories.tsx +76 -0
- package/src/elements/kitn-response-stream.stories.tsx +79 -0
- package/src/elements/kitn-source-list.stories.tsx +77 -0
- package/src/elements/kitn-source.stories.tsx +87 -0
- package/src/elements/kitn-text-shimmer.stories.tsx +63 -0
- package/src/elements/kitn-thinking-bar.stories.tsx +72 -0
- package/src/elements/kitn-tool.stories.tsx +88 -0
- package/src/elements/kitn-voice-input.stories.tsx +87 -0
- package/src/elements/loader.tsx +25 -0
- package/src/elements/markdown.tsx +38 -0
- package/src/elements/message-skills.tsx +22 -0
- package/src/elements/message.tsx +125 -0
- package/src/elements/model-switcher.tsx +35 -0
- package/src/elements/prompt-input.tsx +83 -7
- package/src/elements/prompt-suggestions.tsx +58 -0
- package/src/elements/reasoning.tsx +50 -0
- package/src/elements/register.ts +32 -0
- package/src/elements/response-stream.tsx +40 -0
- package/src/elements/source.tsx +67 -0
- package/src/elements/styles.css +14 -0
- package/src/elements/text-shimmer.tsx +28 -0
- package/src/elements/thinking-bar.tsx +34 -0
- package/src/elements/tool.tsx +23 -0
- package/src/elements/voice-input.tsx +41 -0
- package/src/index.ts +0 -1
- package/src/primitives/chat-config.tsx +3 -3
- package/src/stories/docs/Accessibility.mdx +119 -0
- package/src/stories/docs/ForAIAgents.mdx +93 -0
- package/src/stories/docs/GettingStarted.mdx +2 -2
- package/src/stories/docs/Installation.mdx +29 -2
- package/src/stories/docs/Integrations.mdx +417 -15
- package/src/stories/docs/Introduction.mdx +17 -8
- package/src/stories/docs/Theming.mdx +1 -1
- 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/typography.stories.tsx +78 -0
- package/src/ui/button.tsx +1 -1
- package/src/ui/collapsible.stories.tsx +70 -0
- package/src/ui/collapsible.tsx +119 -8
- package/src/ui/dropdown.stories.tsx +60 -0
- package/src/ui/dropdown.tsx +177 -12
- package/src/ui/hover-card.stories.tsx +78 -0
- package/src/ui/hover-card.tsx +147 -26
- package/src/ui/overlay.stories.tsx +115 -0
- package/src/ui/overlay.tsx +151 -0
- package/src/ui/scroll-area.stories.tsx +51 -0
- package/src/ui/textarea.stories.tsx +77 -0
- package/src/ui/textarea.tsx +1 -1
- package/src/ui/tooltip.stories.tsx +1 -1
- package/src/ui/tooltip.tsx +59 -13
- package/src/utils/cn.ts +19 -1
- package/theme.css +76 -43
- package/src/ui/dialog.tsx +0 -21
package/src/elements/chat.tsx
CHANGED
|
@@ -1,234 +1,37 @@
|
|
|
1
|
-
import { createSignal, For, Show } from 'solid-js';
|
|
2
1
|
import { defineKitnElement } from './define';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { Message, MessageContent, MessageActions } from '../components/message';
|
|
6
|
-
import { Reasoning, ReasoningTrigger, ReasoningContent } from '../components/reasoning';
|
|
7
|
-
import { Tool } from '../components/tool';
|
|
8
|
-
import { Attachments, Attachment, AttachmentPreview, AttachmentInfo, type AttachmentData } from '../components/attachments';
|
|
9
|
-
import { ModelSwitcher } from '../components/model-switcher';
|
|
10
|
-
import { ScrollButton } from '../components/scroll-button';
|
|
11
|
-
import {
|
|
12
|
-
Context,
|
|
13
|
-
ContextTrigger,
|
|
14
|
-
ContextContent,
|
|
15
|
-
ContextContentHeader,
|
|
16
|
-
ContextContentBody,
|
|
17
|
-
ContextContentFooter,
|
|
18
|
-
ContextInputUsage,
|
|
19
|
-
ContextOutputUsage,
|
|
20
|
-
} from '../components/context';
|
|
21
|
-
import { Button } from '../ui/button';
|
|
22
|
-
import { Copy, ThumbsUp, ThumbsDown, RefreshCw, Pencil } from 'lucide-solid';
|
|
23
|
-
import type { Component } from 'solid-js';
|
|
24
|
-
import { DefaultPromptInput } from './default-input';
|
|
25
|
-
import type { ChatMessage, ChatMessageAction } from './chat-types';
|
|
2
|
+
import { ChatThread, type ChatThreadProps, type ChatThreadContextUsage } from '../components/chat-thread';
|
|
3
|
+
import type { SlashCommandItem } from '../components/slash-command';
|
|
26
4
|
import type { ProseSize } from '../primitives/chat-config';
|
|
27
5
|
import type { ModelOption } from '../types';
|
|
28
6
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
inputTokens?: number;
|
|
33
|
-
outputTokens?: number;
|
|
34
|
-
estimatedCost?: number;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
interface Props extends Record<string, unknown> {
|
|
38
|
-
messages: ChatMessage[];
|
|
39
|
-
value?: string;
|
|
40
|
-
placeholder?: string;
|
|
41
|
-
loading?: boolean;
|
|
42
|
-
suggestions?: string[];
|
|
43
|
-
proseSize?: ProseSize;
|
|
44
|
-
codeTheme?: string;
|
|
45
|
-
codeHighlight?: boolean;
|
|
46
|
-
/** Optional header title shown on the left of the header. */
|
|
47
|
-
chatTitle?: string;
|
|
48
|
-
/** Optional model list. When set (>1 model) a ModelSwitcher is shown in the
|
|
49
|
-
* header and a `modelchange` event fires on selection. */
|
|
50
|
-
models?: ModelOption[];
|
|
51
|
-
/** The currently selected model id (pairs with `models`). */
|
|
52
|
-
currentModel?: string;
|
|
53
|
-
/** Optional context-window token usage. When set, a Context token meter is
|
|
54
|
-
* shown in the header. */
|
|
55
|
-
context?: ContextUsage;
|
|
56
|
-
/** Show the scroll-to-bottom button inside the scroll area. Default true. */
|
|
57
|
-
scrollButton?: boolean;
|
|
58
|
-
/** Show a Search (Globe) button in the input toolbar; fires a `search` event. */
|
|
59
|
-
search?: boolean;
|
|
60
|
-
/** Show a Voice (Mic) button in the input toolbar; fires a `voice` event. */
|
|
61
|
-
voice?: boolean;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const ACTION_LABEL: Record<ChatMessageAction, string> = {
|
|
65
|
-
copy: 'Copy', like: 'Like', dislike: 'Dislike', regenerate: 'Regenerate', edit: 'Edit',
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
const ACTION_ICON: Record<ChatMessageAction, Component<{ class?: string }>> = {
|
|
69
|
-
copy: Copy, like: ThumbsUp, dislike: ThumbsDown, regenerate: RefreshCw, edit: Pencil,
|
|
70
|
-
};
|
|
7
|
+
type Props = Omit<ChatThreadProps,
|
|
8
|
+
'class' | 'onValueChange' | 'onSubmit' | 'onSuggestionClick' | 'onModelChange'
|
|
9
|
+
| 'onMessageAction' | 'onSearch' | 'onVoice' | 'onSlashSelect'> & Record<string, unknown>;
|
|
71
10
|
|
|
72
11
|
defineKitnElement<Props>('kitn-chat', {
|
|
73
|
-
messages: [],
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
setAttachments([]);
|
|
100
|
-
};
|
|
101
|
-
const handleSuggestionClick = (v: string) => { handleChange(v); dispatch('suggestionclick', { value: v }); };
|
|
102
|
-
|
|
103
|
-
const showHeader = () => !!(props.chatTitle || props.models || props.context);
|
|
104
|
-
const showScrollButton = () => props.scrollButton !== false;
|
|
105
|
-
|
|
106
|
-
return (
|
|
107
|
-
<ChatConfig proseSize={props.proseSize} codeTheme={props.codeTheme} codeHighlight={props.codeHighlight} portalMount={outer.portalMount()}>
|
|
108
|
-
<div class="flex h-full flex-col bg-background">
|
|
109
|
-
<Show when={showHeader()}>
|
|
110
|
-
<header class="flex h-14 shrink-0 items-center justify-between border-b border-border px-5">
|
|
111
|
-
<div class="text-sm font-semibold text-foreground">
|
|
112
|
-
{props.chatTitle}
|
|
113
|
-
</div>
|
|
114
|
-
<div class="flex items-center gap-2">
|
|
115
|
-
<Show when={props.models}>
|
|
116
|
-
<ModelSwitcher
|
|
117
|
-
models={props.models!}
|
|
118
|
-
currentModelId={props.currentModel ?? props.models![0]?.id ?? ''}
|
|
119
|
-
onModelChange={(modelId) => dispatch('modelchange', { modelId })}
|
|
120
|
-
/>
|
|
121
|
-
</Show>
|
|
122
|
-
<Show when={props.context}>
|
|
123
|
-
<Context
|
|
124
|
-
usedTokens={props.context!.usedTokens}
|
|
125
|
-
maxTokens={props.context!.maxTokens}
|
|
126
|
-
inputTokens={props.context!.inputTokens}
|
|
127
|
-
outputTokens={props.context!.outputTokens}
|
|
128
|
-
estimatedCost={props.context!.estimatedCost}
|
|
129
|
-
>
|
|
130
|
-
<ContextTrigger />
|
|
131
|
-
<ContextContent>
|
|
132
|
-
<ContextContentHeader />
|
|
133
|
-
<ContextContentBody>
|
|
134
|
-
<div class="space-y-1.5">
|
|
135
|
-
<ContextInputUsage />
|
|
136
|
-
<ContextOutputUsage />
|
|
137
|
-
</div>
|
|
138
|
-
</ContextContentBody>
|
|
139
|
-
<ContextContentFooter />
|
|
140
|
-
</ContextContent>
|
|
141
|
-
</Context>
|
|
142
|
-
</Show>
|
|
143
|
-
</div>
|
|
144
|
-
</header>
|
|
145
|
-
</Show>
|
|
146
|
-
<div class="relative flex-1 overflow-hidden">
|
|
147
|
-
<ChatContainer class="h-full px-4 py-3">
|
|
148
|
-
<ChatContainerContent class="mx-auto w-full max-w-3xl space-y-4">
|
|
149
|
-
<For each={props.messages}>
|
|
150
|
-
{(m) => (
|
|
151
|
-
<Message class={m.role === 'user' ? 'flex-col items-end' : 'flex-col items-start'}>
|
|
152
|
-
<Show when={m.reasoning}>
|
|
153
|
-
<Reasoning class="mb-2 w-full">
|
|
154
|
-
<ReasoningTrigger>{m.reasoning!.label ?? 'Reasoning'}</ReasoningTrigger>
|
|
155
|
-
<ReasoningContent markdown>{m.reasoning!.text}</ReasoningContent>
|
|
156
|
-
</Reasoning>
|
|
157
|
-
</Show>
|
|
158
|
-
<For each={m.tools ?? []}>
|
|
159
|
-
{(tp) => <Tool toolPart={tp} class="mb-2 w-full" />}
|
|
160
|
-
</For>
|
|
161
|
-
<Show when={m.attachments?.length}>
|
|
162
|
-
<Attachments variant="inline" class={m.role === 'user' ? 'mb-2 justify-end' : 'mb-2'}>
|
|
163
|
-
<For each={m.attachments!}>
|
|
164
|
-
{(att) => (
|
|
165
|
-
<Attachment data={att}>
|
|
166
|
-
<AttachmentPreview />
|
|
167
|
-
<AttachmentInfo />
|
|
168
|
-
</Attachment>
|
|
169
|
-
)}
|
|
170
|
-
</For>
|
|
171
|
-
</Attachments>
|
|
172
|
-
</Show>
|
|
173
|
-
<MessageContent
|
|
174
|
-
markdown={m.role === 'assistant'}
|
|
175
|
-
class={m.role === 'user'
|
|
176
|
-
? 'bg-muted text-primary max-w-[85%] rounded-2xl px-4 py-2'
|
|
177
|
-
: 'bg-transparent p-0'}
|
|
178
|
-
>
|
|
179
|
-
{m.content}
|
|
180
|
-
</MessageContent>
|
|
181
|
-
<Show when={m.actions?.length}>
|
|
182
|
-
<MessageActions class="mt-1 flex gap-0">
|
|
183
|
-
<For each={m.actions!}>
|
|
184
|
-
{(a) => (
|
|
185
|
-
<Button
|
|
186
|
-
variant="ghost" size="icon-sm" class="rounded-full"
|
|
187
|
-
data-action={a}
|
|
188
|
-
aria-label={ACTION_LABEL[a]}
|
|
189
|
-
onClick={() => dispatch('messageaction', { messageId: m.id, action: a })}
|
|
190
|
-
>
|
|
191
|
-
{(() => {
|
|
192
|
-
const Icon = ACTION_ICON[a];
|
|
193
|
-
return <Icon class="size-3.5" />;
|
|
194
|
-
})()}
|
|
195
|
-
</Button>
|
|
196
|
-
)}
|
|
197
|
-
</For>
|
|
198
|
-
</MessageActions>
|
|
199
|
-
</Show>
|
|
200
|
-
</Message>
|
|
201
|
-
)}
|
|
202
|
-
</For>
|
|
203
|
-
<ChatContainerScrollAnchor />
|
|
204
|
-
</ChatContainerContent>
|
|
205
|
-
<Show when={showScrollButton()}>
|
|
206
|
-
<div class="absolute bottom-4 left-1/2 flex w-full max-w-3xl -translate-x-1/2 justify-center px-5">
|
|
207
|
-
<ScrollButton class="shadow-sm" />
|
|
208
|
-
</div>
|
|
209
|
-
</Show>
|
|
210
|
-
</ChatContainer>
|
|
211
|
-
</div>
|
|
212
|
-
<div class="shrink-0 px-4 pb-4">
|
|
213
|
-
<div class="mx-auto max-w-3xl">
|
|
214
|
-
<DefaultPromptInput
|
|
215
|
-
value={current()}
|
|
216
|
-
placeholder={props.placeholder}
|
|
217
|
-
loading={props.loading}
|
|
218
|
-
suggestions={props.suggestions}
|
|
219
|
-
attachments={attachments()}
|
|
220
|
-
search={props.search}
|
|
221
|
-
voice={props.voice}
|
|
222
|
-
onValueChange={handleChange}
|
|
223
|
-
onSubmit={handleSubmit}
|
|
224
|
-
onSuggestionClick={handleSuggestionClick}
|
|
225
|
-
onAttachmentsChange={setAttachments}
|
|
226
|
-
onSearch={() => dispatch('search', {})}
|
|
227
|
-
onVoice={() => dispatch('voice', {})}
|
|
228
|
-
/>
|
|
229
|
-
</div>
|
|
230
|
-
</div>
|
|
231
|
-
</div>
|
|
232
|
-
</ChatConfig>
|
|
233
|
-
);
|
|
234
|
-
});
|
|
12
|
+
messages: [], value: undefined, placeholder: 'Send a message...', loading: false,
|
|
13
|
+
suggestions: undefined, suggestionMode: 'submit', proseSize: 'sm',
|
|
14
|
+
codeTheme: 'github-dark-dimmed', codeHighlight: true, chatTitle: undefined,
|
|
15
|
+
models: undefined, currentModel: undefined, context: undefined, scrollButton: true,
|
|
16
|
+
search: false, voice: false, slashCommands: undefined, slashActiveIds: undefined, slashCompact: false,
|
|
17
|
+
}, (props, { dispatch, flag }) => (
|
|
18
|
+
<ChatThread
|
|
19
|
+
messages={props.messages} value={props.value as string | undefined} placeholder={props.placeholder as string}
|
|
20
|
+
loading={flag('loading')} suggestions={props.suggestions as string[] | undefined}
|
|
21
|
+
suggestionMode={props.suggestionMode as 'submit' | 'fill'} proseSize={props.proseSize as ProseSize}
|
|
22
|
+
codeTheme={props.codeTheme as string} codeHighlight={flag('codeHighlight')}
|
|
23
|
+
chatTitle={props.chatTitle as string | undefined} models={props.models as ModelOption[] | undefined}
|
|
24
|
+
currentModel={props.currentModel as string | undefined} context={props.context as ChatThreadContextUsage | undefined}
|
|
25
|
+
scrollButton={props.scrollButton !== false} search={flag('search')} voice={flag('voice')}
|
|
26
|
+
slashCommands={props.slashCommands as SlashCommandItem[] | undefined}
|
|
27
|
+
slashActiveIds={props.slashActiveIds as string[] | undefined} slashCompact={flag('slashCompact')}
|
|
28
|
+
onValueChange={(value) => dispatch('valuechange', { value })}
|
|
29
|
+
onSubmit={(detail) => dispatch('submit', detail)}
|
|
30
|
+
onSuggestionClick={(value) => dispatch('suggestionclick', { value })}
|
|
31
|
+
onModelChange={(modelId) => dispatch('modelchange', { modelId })}
|
|
32
|
+
onMessageAction={(detail) => dispatch('messageaction', detail)}
|
|
33
|
+
onSearch={() => dispatch('search', {})}
|
|
34
|
+
onVoice={() => dispatch('voice', {})}
|
|
35
|
+
onSlashSelect={(command) => dispatch('slashselect', { command })}
|
|
36
|
+
/>
|
|
37
|
+
));
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Show } from 'solid-js';
|
|
2
|
+
import { defineKitnElement } from './define';
|
|
3
|
+
import { Checkpoint, CheckpointIcon, CheckpointTrigger } from '../components/checkpoint';
|
|
4
|
+
|
|
5
|
+
interface Props extends Record<string, unknown> {
|
|
6
|
+
/** Optional text beside the icon. */
|
|
7
|
+
label?: string;
|
|
8
|
+
/** Tooltip on hover. */
|
|
9
|
+
tooltip?: string;
|
|
10
|
+
/** Visual button style. */
|
|
11
|
+
variant?: 'ghost' | 'default' | 'outline';
|
|
12
|
+
/** Button size (use an `icon*` size for an icon-only checkpoint). */
|
|
13
|
+
size?: 'sm' | 'md' | 'lg' | 'icon' | 'icon-sm';
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** Events fired by `<kitn-checkpoint>`. */
|
|
17
|
+
interface Events {
|
|
18
|
+
/** The checkpoint was clicked. */
|
|
19
|
+
select: void;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* `<kitn-checkpoint>` — a bookmark/checkpoint button (optional tooltip + label).
|
|
24
|
+
* Emits `select`.
|
|
25
|
+
*/
|
|
26
|
+
defineKitnElement<Props, Events>('kitn-checkpoint', {
|
|
27
|
+
label: undefined,
|
|
28
|
+
tooltip: undefined,
|
|
29
|
+
variant: 'ghost',
|
|
30
|
+
size: 'sm',
|
|
31
|
+
}, (props, { dispatch }) => (
|
|
32
|
+
<Checkpoint>
|
|
33
|
+
<CheckpointTrigger
|
|
34
|
+
tooltip={props.tooltip}
|
|
35
|
+
variant={props.variant}
|
|
36
|
+
size={props.size}
|
|
37
|
+
onClick={() => dispatch('select')}
|
|
38
|
+
>
|
|
39
|
+
<CheckpointIcon />
|
|
40
|
+
<Show when={props.label}><span class="ml-1.5">{props.label}</span></Show>
|
|
41
|
+
</CheckpointTrigger>
|
|
42
|
+
</Checkpoint>
|
|
43
|
+
));
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { defineKitnElement } from './define';
|
|
2
|
+
import { CodeBlock, CodeBlockCode } from '../components/code-block';
|
|
3
|
+
import { ChatConfig, useChatConfig, type ProseSize } from '../primitives/chat-config';
|
|
4
|
+
|
|
5
|
+
interface Props extends Record<string, unknown> {
|
|
6
|
+
/** The source code to render. */
|
|
7
|
+
code: string;
|
|
8
|
+
/** Language grammar (e.g. `js`, `python`). Defaults to `tsx`. */
|
|
9
|
+
language?: string;
|
|
10
|
+
/** Shiki theme name. */
|
|
11
|
+
codeTheme?: string;
|
|
12
|
+
/** Disable syntax highlighting (renders plain text, no Shiki). */
|
|
13
|
+
codeHighlight?: boolean;
|
|
14
|
+
/** Code text sizing. */
|
|
15
|
+
proseSize?: ProseSize;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* `<kitn-code-block>` — one syntax-highlighted code block (with a copy button).
|
|
20
|
+
* Code via the `code` property; `language`/`code-theme` via attributes.
|
|
21
|
+
*/
|
|
22
|
+
defineKitnElement<Props>('kitn-code-block', {
|
|
23
|
+
code: '',
|
|
24
|
+
language: undefined,
|
|
25
|
+
codeTheme: 'github-dark-dimmed',
|
|
26
|
+
codeHighlight: true,
|
|
27
|
+
proseSize: 'sm',
|
|
28
|
+
}, (props, { flag }) => {
|
|
29
|
+
const outer = useChatConfig();
|
|
30
|
+
return (
|
|
31
|
+
<ChatConfig
|
|
32
|
+
proseSize={props.proseSize}
|
|
33
|
+
codeTheme={props.codeTheme}
|
|
34
|
+
codeHighlight={flag('codeHighlight')}
|
|
35
|
+
portalMount={outer.portalMount()}
|
|
36
|
+
>
|
|
37
|
+
<CodeBlock>
|
|
38
|
+
<CodeBlockCode code={props.code} language={props.language} />
|
|
39
|
+
</CodeBlock>
|
|
40
|
+
</ChatConfig>
|
|
41
|
+
);
|
|
42
|
+
});
|