@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.
Files changed (119) hide show
  1. package/README.md +35 -5
  2. package/dist/custom-elements.json +2969 -0
  3. package/dist/kitn-chat.es.js +52 -39
  4. package/dist/llms/llms-full.txt +718 -0
  5. package/dist/llms/llms.txt +104 -0
  6. package/dist/theme.tokens.css +137 -0
  7. package/frameworks/react/index.tsx +584 -0
  8. package/frameworks/react/runtime.tsx +94 -0
  9. package/llms-full.txt +718 -0
  10. package/llms.txt +104 -0
  11. package/package.json +53 -6
  12. package/src/components/attachments.tsx +4 -2
  13. package/src/components/chain-of-thought.tsx +1 -1
  14. package/src/components/chat-scope-picker.tsx +2 -2
  15. package/src/components/chat-thread.tsx +217 -0
  16. package/src/components/checkpoint.tsx +7 -3
  17. package/src/components/context.tsx +14 -18
  18. package/src/components/conversation-item.tsx +1 -1
  19. package/src/components/conversation-list.tsx +5 -4
  20. package/src/components/message-skills.tsx +1 -1
  21. package/src/components/message.tsx +1 -0
  22. package/src/components/model-switcher.tsx +3 -3
  23. package/src/components/prompt-input.tsx +20 -2
  24. package/src/components/reasoning.tsx +2 -2
  25. package/src/components/scroll-button.tsx +1 -0
  26. package/src/components/slash-command.tsx +17 -8
  27. package/src/components/source.tsx +2 -2
  28. package/src/components/thinking-bar.tsx +2 -2
  29. package/src/components/tool.tsx +17 -6
  30. package/src/components/voice-input.tsx +5 -1
  31. package/src/elements/attachments.tsx +132 -0
  32. package/src/elements/chain-of-thought.tsx +45 -0
  33. package/src/elements/chat-scope-picker.tsx +36 -0
  34. package/src/elements/chat-workspace.tsx +122 -0
  35. package/src/elements/chat.tsx +31 -228
  36. package/src/elements/checkpoint.tsx +43 -0
  37. package/src/elements/code-block.tsx +42 -0
  38. package/src/elements/compiled.css +1 -1
  39. package/src/elements/context-meter.tsx +71 -0
  40. package/src/elements/conversation-list.tsx +6 -0
  41. package/src/elements/default-input.tsx +22 -1
  42. package/src/elements/define.tsx +98 -12
  43. package/src/elements/element-types.d.ts +444 -0
  44. package/src/elements/empty.tsx +29 -0
  45. package/src/elements/feedback-bar.tsx +33 -0
  46. package/src/elements/file-upload.tsx +44 -0
  47. package/src/elements/image.tsx +32 -0
  48. package/src/elements/kitn-attachments.stories.tsx +181 -0
  49. package/src/elements/kitn-chain-of-thought.stories.tsx +75 -0
  50. package/src/elements/kitn-chat-scope-picker.stories.tsx +72 -0
  51. package/src/elements/kitn-chat-workspace.stories.tsx +195 -0
  52. package/src/elements/kitn-checkpoint.stories.tsx +71 -0
  53. package/src/elements/kitn-code-block.stories.tsx +82 -0
  54. package/src/elements/kitn-context-meter.stories.tsx +85 -0
  55. package/src/elements/kitn-empty.stories.tsx +110 -0
  56. package/src/elements/kitn-feedback-bar.stories.tsx +73 -0
  57. package/src/elements/kitn-file-upload.stories.tsx +81 -0
  58. package/src/elements/kitn-image.stories.tsx +70 -0
  59. package/src/elements/kitn-loader.stories.tsx +87 -0
  60. package/src/elements/kitn-markdown.stories.tsx +75 -0
  61. package/src/elements/kitn-message-skills.stories.tsx +74 -0
  62. package/src/elements/kitn-message.stories.tsx +105 -0
  63. package/src/elements/kitn-model-switcher.stories.tsx +80 -0
  64. package/src/elements/kitn-prompt-input.stories.tsx +74 -16
  65. package/src/elements/kitn-prompt-suggestions.stories.tsx +157 -0
  66. package/src/elements/kitn-reasoning.stories.tsx +76 -0
  67. package/src/elements/kitn-response-stream.stories.tsx +79 -0
  68. package/src/elements/kitn-source-list.stories.tsx +77 -0
  69. package/src/elements/kitn-source.stories.tsx +87 -0
  70. package/src/elements/kitn-text-shimmer.stories.tsx +63 -0
  71. package/src/elements/kitn-thinking-bar.stories.tsx +72 -0
  72. package/src/elements/kitn-tool.stories.tsx +88 -0
  73. package/src/elements/kitn-voice-input.stories.tsx +87 -0
  74. package/src/elements/loader.tsx +25 -0
  75. package/src/elements/markdown.tsx +38 -0
  76. package/src/elements/message-skills.tsx +22 -0
  77. package/src/elements/message.tsx +125 -0
  78. package/src/elements/model-switcher.tsx +35 -0
  79. package/src/elements/prompt-input.tsx +83 -7
  80. package/src/elements/prompt-suggestions.tsx +58 -0
  81. package/src/elements/reasoning.tsx +50 -0
  82. package/src/elements/register.ts +32 -0
  83. package/src/elements/response-stream.tsx +40 -0
  84. package/src/elements/source.tsx +67 -0
  85. package/src/elements/styles.css +14 -0
  86. package/src/elements/text-shimmer.tsx +28 -0
  87. package/src/elements/thinking-bar.tsx +34 -0
  88. package/src/elements/tool.tsx +23 -0
  89. package/src/elements/voice-input.tsx +41 -0
  90. package/src/index.ts +0 -1
  91. package/src/primitives/chat-config.tsx +3 -3
  92. package/src/stories/docs/Accessibility.mdx +119 -0
  93. package/src/stories/docs/ForAIAgents.mdx +93 -0
  94. package/src/stories/docs/GettingStarted.mdx +2 -2
  95. package/src/stories/docs/Installation.mdx +29 -2
  96. package/src/stories/docs/Integrations.mdx +417 -15
  97. package/src/stories/docs/Introduction.mdx +17 -8
  98. package/src/stories/docs/Theming.mdx +1 -1
  99. package/src/stories/pattern-centered-conversation.stories.tsx +93 -0
  100. package/src/stories/pattern-docked-widget.stories.tsx +93 -0
  101. package/src/stories/pattern-empty-state.stories.tsx +76 -0
  102. package/src/stories/typography.stories.tsx +78 -0
  103. package/src/ui/button.tsx +1 -1
  104. package/src/ui/collapsible.stories.tsx +70 -0
  105. package/src/ui/collapsible.tsx +119 -8
  106. package/src/ui/dropdown.stories.tsx +60 -0
  107. package/src/ui/dropdown.tsx +177 -12
  108. package/src/ui/hover-card.stories.tsx +78 -0
  109. package/src/ui/hover-card.tsx +147 -26
  110. package/src/ui/overlay.stories.tsx +115 -0
  111. package/src/ui/overlay.tsx +151 -0
  112. package/src/ui/scroll-area.stories.tsx +51 -0
  113. package/src/ui/textarea.stories.tsx +77 -0
  114. package/src/ui/textarea.tsx +1 -1
  115. package/src/ui/tooltip.stories.tsx +1 -1
  116. package/src/ui/tooltip.tsx +59 -13
  117. package/src/utils/cn.ts +19 -1
  118. package/theme.css +76 -43
  119. package/src/ui/dialog.tsx +0 -21
@@ -1,234 +1,37 @@
1
- import { createSignal, For, Show } from 'solid-js';
2
1
  import { defineKitnElement } from './define';
3
- import { ChatConfig, useChatConfig } from '../primitives/chat-config';
4
- import { ChatContainer, ChatContainerContent, ChatContainerScrollAnchor } from '../components/chat-container';
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
- interface ContextUsage {
30
- usedTokens: number;
31
- maxTokens: number;
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
- value: undefined,
75
- placeholder: 'Send a message...',
76
- loading: false,
77
- suggestions: undefined,
78
- proseSize: 'base',
79
- codeTheme: 'github-dark-dimmed',
80
- codeHighlight: true,
81
- chatTitle: undefined,
82
- models: undefined,
83
- currentModel: undefined,
84
- context: undefined,
85
- scrollButton: true,
86
- search: false,
87
- voice: false,
88
- }, (props, { dispatch }) => {
89
- // Preserve the shadow-root portal mount from the wrapper's outer ChatConfig
90
- // when we nest a second ChatConfig to set proseSize/codeTheme.
91
- const outer = useChatConfig();
92
-
93
- const [internal, setInternal] = createSignal(props.value ?? '');
94
- const [attachments, setAttachments] = createSignal<AttachmentData[]>([]);
95
- const current = () => props.value ?? internal();
96
- const handleChange = (v: string) => { setInternal(v); dispatch('valuechange', { value: v }); };
97
- const handleSubmit = () => {
98
- dispatch('submit', { value: current(), attachments: attachments() });
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
+ });