@kitnai/chat 0.3.0 → 0.4.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 +11 -0
- package/dist/custom-elements.json +2494 -0
- package/dist/kitn-chat.es.js +52 -39
- package/dist/llms/llms-full.txt +667 -0
- package/dist/llms/llms.txt +104 -0
- package/dist/theme.tokens.css +133 -0
- package/frameworks/react/index.tsx +530 -0
- package/frameworks/react/runtime.tsx +94 -0
- package/llms-full.txt +667 -0
- package/llms.txt +104 -0
- package/package.json +34 -5
- 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/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 +15 -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.tsx +51 -7
- 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 +102 -13
- package/src/elements/element-types.d.ts +404 -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-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 +31 -0
- package/src/elements/response-stream.tsx +40 -0
- package/src/elements/source.tsx +67 -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 +2 -2
- 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 +2 -2
- package/src/stories/docs/Integrations.mdx +415 -15
- package/src/stories/docs/Introduction.mdx +5 -5
- package/src/stories/docs/Theming.mdx +1 -1
- package/src/stories/typography.stories.tsx +78 -0
- package/src/ui/button.tsx +1 -1
- package/src/ui/collapsible.tsx +119 -8
- package/src/ui/dropdown.tsx +177 -12
- package/src/ui/hover-card.tsx +147 -26
- package/src/ui/overlay.tsx +151 -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 +72 -43
- package/src/ui/dialog.tsx +0 -21
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { For, Show } from 'solid-js';
|
|
2
|
+
import { defineKitnElement } from './define';
|
|
3
|
+
import {
|
|
4
|
+
Attachments,
|
|
5
|
+
Attachment,
|
|
6
|
+
AttachmentPreview,
|
|
7
|
+
AttachmentInfo,
|
|
8
|
+
AttachmentRemove,
|
|
9
|
+
AttachmentHoverCard,
|
|
10
|
+
AttachmentHoverCardTrigger,
|
|
11
|
+
AttachmentHoverCardContent,
|
|
12
|
+
AttachmentEmpty,
|
|
13
|
+
getAttachmentLabel,
|
|
14
|
+
getMediaCategory,
|
|
15
|
+
type AttachmentData,
|
|
16
|
+
type AttachmentVariant,
|
|
17
|
+
} from '../components/attachments';
|
|
18
|
+
|
|
19
|
+
interface Props extends Record<string, unknown> {
|
|
20
|
+
/** The attachments to render. Set as a JS property (array). */
|
|
21
|
+
items: AttachmentData[];
|
|
22
|
+
/** Layout: `grid` = visual tiles, `inline` = icon + label chips, `list` = rows. */
|
|
23
|
+
variant?: AttachmentVariant;
|
|
24
|
+
/** Wrap each item in a hover card that previews its details. */
|
|
25
|
+
hoverCard?: boolean;
|
|
26
|
+
/** Show a remove button per item; clicking it fires a `remove` event. */
|
|
27
|
+
removable?: boolean;
|
|
28
|
+
/** Also show the media type beneath the filename (non-grid variants). */
|
|
29
|
+
showMediaType?: boolean;
|
|
30
|
+
/** Text shown when `items` is empty. */
|
|
31
|
+
emptyText?: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Events fired by `<kitn-attachments>`. */
|
|
35
|
+
interface Events {
|
|
36
|
+
/** A remove button was clicked. */
|
|
37
|
+
remove: { id: string };
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* `<kitn-attachments>` — the exemplar for the "collapse a compound primitive to
|
|
42
|
+
* ONE configurable element" pattern (Route 1). The presentation knobs that the
|
|
43
|
+
* SolidJS layer expresses by composing sub-parts (`<AttachmentPreview>`,
|
|
44
|
+
* `<AttachmentInfo>`, `<AttachmentHoverCard>`, `<AttachmentRemove>`) become
|
|
45
|
+
* attributes/flags here:
|
|
46
|
+
*
|
|
47
|
+
* - icon + label .......... `variant="inline"`
|
|
48
|
+
* - visual + hover card .... `variant="grid" hover-card`
|
|
49
|
+
* - removable chips ........ add `removable` (emits `remove` → { id })
|
|
50
|
+
*
|
|
51
|
+
* Data in via the `items` property; the only interaction (`remove`) comes back
|
|
52
|
+
* as an event. For fully-custom hover content, the SolidJS primitives remain the
|
|
53
|
+
* escape hatch (a templated slot — "Route 2" — is a deliberate future add).
|
|
54
|
+
*/
|
|
55
|
+
defineKitnElement<Props, Events>('kitn-attachments', {
|
|
56
|
+
items: [],
|
|
57
|
+
variant: 'grid',
|
|
58
|
+
hoverCard: false,
|
|
59
|
+
removable: false,
|
|
60
|
+
showMediaType: false,
|
|
61
|
+
emptyText: undefined,
|
|
62
|
+
}, (props, { dispatch, flag }) => {
|
|
63
|
+
const variant = () => props.variant ?? 'grid';
|
|
64
|
+
const hoverCard = () => flag('hoverCard');
|
|
65
|
+
const removable = () => flag('removable');
|
|
66
|
+
const showMediaType = () => flag('showMediaType');
|
|
67
|
+
|
|
68
|
+
return (
|
|
69
|
+
<Show
|
|
70
|
+
when={props.items.length}
|
|
71
|
+
fallback={<Show when={props.emptyText}><AttachmentEmpty>{props.emptyText}</AttachmentEmpty></Show>}
|
|
72
|
+
>
|
|
73
|
+
<Attachments variant={variant()}>
|
|
74
|
+
<For each={props.items}>
|
|
75
|
+
{(item) => (
|
|
76
|
+
<Attachment
|
|
77
|
+
data={item}
|
|
78
|
+
onRemove={removable() ? () => dispatch('remove', { id: item.id }) : undefined}
|
|
79
|
+
>
|
|
80
|
+
<Show
|
|
81
|
+
when={hoverCard() && variant() !== 'grid'}
|
|
82
|
+
fallback={
|
|
83
|
+
<>
|
|
84
|
+
<AttachmentPreview />
|
|
85
|
+
{/* Info only for non-grid; grid is a self-contained visual tile. */}
|
|
86
|
+
<Show when={variant() !== 'grid'}>
|
|
87
|
+
<AttachmentInfo showMediaType={showMediaType()} />
|
|
88
|
+
</Show>
|
|
89
|
+
</>
|
|
90
|
+
}
|
|
91
|
+
>
|
|
92
|
+
{/* Hover preview is for compact inline/list chips; grid tiles are
|
|
93
|
+
already the visual, so they skip it (wrapping them would also
|
|
94
|
+
collapse non-image tiles to the icon's height). */}
|
|
95
|
+
<AttachmentHoverCard>
|
|
96
|
+
<AttachmentHoverCardTrigger>
|
|
97
|
+
<div class="flex items-center gap-1.5">
|
|
98
|
+
<AttachmentPreview />
|
|
99
|
+
<AttachmentInfo showMediaType={showMediaType()} />
|
|
100
|
+
</div>
|
|
101
|
+
</AttachmentHoverCardTrigger>
|
|
102
|
+
<AttachmentHoverCardContent>
|
|
103
|
+
{/* For image attachments, preview the actual thumbnail;
|
|
104
|
+
otherwise fall back to the label + media-type details. */}
|
|
105
|
+
<Show
|
|
106
|
+
when={getMediaCategory(item) === 'image' && item.type === 'file' && item.url}
|
|
107
|
+
fallback={
|
|
108
|
+
<>
|
|
109
|
+
<div class="text-body font-medium">{getAttachmentLabel(item)}</div>
|
|
110
|
+
<Show when={item.mediaType}>
|
|
111
|
+
<div class="text-muted-foreground text-caption">{item.mediaType}</div>
|
|
112
|
+
</Show>
|
|
113
|
+
</>
|
|
114
|
+
}
|
|
115
|
+
>
|
|
116
|
+
<img
|
|
117
|
+
src={item.url}
|
|
118
|
+
alt={getAttachmentLabel(item)}
|
|
119
|
+
class="block max-h-64 max-w-xs rounded object-contain"
|
|
120
|
+
/>
|
|
121
|
+
</Show>
|
|
122
|
+
</AttachmentHoverCardContent>
|
|
123
|
+
</AttachmentHoverCard>
|
|
124
|
+
</Show>
|
|
125
|
+
<AttachmentRemove />
|
|
126
|
+
</Attachment>
|
|
127
|
+
)}
|
|
128
|
+
</For>
|
|
129
|
+
</Attachments>
|
|
130
|
+
</Show>
|
|
131
|
+
);
|
|
132
|
+
});
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { For, Show } from 'solid-js';
|
|
2
|
+
import { defineKitnElement } from './define';
|
|
3
|
+
import {
|
|
4
|
+
ChainOfThought,
|
|
5
|
+
ChainOfThoughtStep,
|
|
6
|
+
ChainOfThoughtTrigger,
|
|
7
|
+
ChainOfThoughtContent,
|
|
8
|
+
ChainOfThoughtItem,
|
|
9
|
+
} from '../components/chain-of-thought';
|
|
10
|
+
|
|
11
|
+
interface Step {
|
|
12
|
+
/** The step's heading (the always-visible trigger). */
|
|
13
|
+
label: string;
|
|
14
|
+
/** Optional expandable detail. */
|
|
15
|
+
content?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface Props extends Record<string, unknown> {
|
|
19
|
+
/** The reasoning steps. Set as a JS property. Compound sub-parts collapse to
|
|
20
|
+
* this one data model (Route 1). */
|
|
21
|
+
steps: Step[];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* `<kitn-chain-of-thought>` — step-by-step reasoning with connectors and
|
|
26
|
+
* per-step collapsible detail. Data via the `steps` property.
|
|
27
|
+
*/
|
|
28
|
+
defineKitnElement<Props>('kitn-chain-of-thought', {
|
|
29
|
+
steps: [],
|
|
30
|
+
}, (props) => (
|
|
31
|
+
<ChainOfThought>
|
|
32
|
+
<For each={props.steps}>
|
|
33
|
+
{(step, i) => (
|
|
34
|
+
<ChainOfThoughtStep isLast={i() === props.steps.length - 1}>
|
|
35
|
+
<ChainOfThoughtTrigger>{step.label}</ChainOfThoughtTrigger>
|
|
36
|
+
<Show when={step.content}>
|
|
37
|
+
<ChainOfThoughtContent>
|
|
38
|
+
<ChainOfThoughtItem>{step.content}</ChainOfThoughtItem>
|
|
39
|
+
</ChainOfThoughtContent>
|
|
40
|
+
</Show>
|
|
41
|
+
</ChainOfThoughtStep>
|
|
42
|
+
)}
|
|
43
|
+
</For>
|
|
44
|
+
</ChainOfThought>
|
|
45
|
+
));
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { defineKitnElement } from './define';
|
|
2
|
+
import { ChatScopePicker } from '../components/chat-scope-picker';
|
|
3
|
+
import type { SearchFilters } from '../types';
|
|
4
|
+
|
|
5
|
+
interface Props extends Record<string, unknown> {
|
|
6
|
+
/** Authors to offer as scope filters. Set as a JS property. */
|
|
7
|
+
availableAuthors: string[];
|
|
8
|
+
/** Tags to offer as scope filters. Set as a JS property. */
|
|
9
|
+
availableTags: string[];
|
|
10
|
+
/** The label shown on the trigger for the active scope. */
|
|
11
|
+
currentLabel?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** Events fired by `<kitn-chat-scope-picker>`. */
|
|
15
|
+
interface Events {
|
|
16
|
+
/** A scope was chosen (`undefined` filters = "All Content"). */
|
|
17
|
+
scopechange: { filters: SearchFilters | undefined };
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* `<kitn-chat-scope-picker>` — a dropdown to scope a chat by author or tag.
|
|
22
|
+
* Options via `available-authors`/`available-tags` properties; emits
|
|
23
|
+
* `scopechange`.
|
|
24
|
+
*/
|
|
25
|
+
defineKitnElement<Props, Events>('kitn-chat-scope-picker', {
|
|
26
|
+
availableAuthors: [],
|
|
27
|
+
availableTags: [],
|
|
28
|
+
currentLabel: 'All Content',
|
|
29
|
+
}, (props, { dispatch }) => (
|
|
30
|
+
<ChatScopePicker
|
|
31
|
+
currentLabel={props.currentLabel ?? 'All Content'}
|
|
32
|
+
availableAuthors={props.availableAuthors}
|
|
33
|
+
availableTags={props.availableTags}
|
|
34
|
+
onScopeChange={(filters) => dispatch('scopechange', { filters })}
|
|
35
|
+
/>
|
|
36
|
+
));
|
package/src/elements/chat.tsx
CHANGED
|
@@ -22,6 +22,7 @@ import { Button } from '../ui/button';
|
|
|
22
22
|
import { Copy, ThumbsUp, ThumbsDown, RefreshCw, Pencil } from 'lucide-solid';
|
|
23
23
|
import type { Component } from 'solid-js';
|
|
24
24
|
import { DefaultPromptInput } from './default-input';
|
|
25
|
+
import type { SlashCommandItem } from '../components/slash-command';
|
|
25
26
|
import type { ChatMessage, ChatMessageAction } from './chat-types';
|
|
26
27
|
import type { ProseSize } from '../primitives/chat-config';
|
|
27
28
|
import type { ModelOption } from '../types';
|
|
@@ -35,13 +36,32 @@ interface ContextUsage {
|
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
interface Props extends Record<string, unknown> {
|
|
39
|
+
/** The full message thread to render, newest last. Each entry carries its role,
|
|
40
|
+
* content, and optional reasoning/tools/attachments/actions. Set as a JS
|
|
41
|
+
* property (`el.messages = [...]`). */
|
|
38
42
|
messages: ChatMessage[];
|
|
43
|
+
/** Controlled value of the input. When set, the host owns the input text and
|
|
44
|
+
* must update it on `valuechange`; leave unset for uncontrolled behavior. */
|
|
39
45
|
value?: string;
|
|
46
|
+
/** Placeholder text shown in the empty input. */
|
|
40
47
|
placeholder?: string;
|
|
48
|
+
/** When true, shows the loading/streaming state and disables submit (use while
|
|
49
|
+
* awaiting the assistant's reply). */
|
|
41
50
|
loading?: boolean;
|
|
51
|
+
/** Starter prompts shown above the input when the thread is empty. Clicking one
|
|
52
|
+
* follows `suggestionMode`. Set as a JS property. */
|
|
42
53
|
suggestions?: string[];
|
|
54
|
+
/** What clicking a suggestion does: `'submit'` (default) sends it immediately
|
|
55
|
+
* as if typed and submitted; `'fill'` just places it in the input. */
|
|
56
|
+
suggestionMode?: 'submit' | 'fill';
|
|
57
|
+
/** Body/prose font scale for rendered markdown (`'xs' | 'sm' | 'base' | 'lg'`).
|
|
58
|
+
* Defaults to `'sm'`. */
|
|
43
59
|
proseSize?: ProseSize;
|
|
60
|
+
/** Shiki theme name for syntax-highlighted code blocks (e.g.
|
|
61
|
+
* `'github-dark-dimmed'`). */
|
|
44
62
|
codeTheme?: string;
|
|
63
|
+
/** Enable Shiki syntax highlighting in code blocks. Turn off to render plain
|
|
64
|
+
* `<pre>` blocks (lighter, no highlighter load). Default true. */
|
|
45
65
|
codeHighlight?: boolean;
|
|
46
66
|
/** Optional header title shown on the left of the header. */
|
|
47
67
|
chatTitle?: string;
|
|
@@ -59,6 +79,13 @@ interface Props extends Record<string, unknown> {
|
|
|
59
79
|
search?: boolean;
|
|
60
80
|
/** Show a Voice (Mic) button in the input toolbar; fires a `voice` event. */
|
|
61
81
|
voice?: boolean;
|
|
82
|
+
/** Slash commands — when set, typing `/` in the input opens the command
|
|
83
|
+
* palette and fires `slashselect`. Set as a JS property. */
|
|
84
|
+
slashCommands?: SlashCommandItem[];
|
|
85
|
+
/** Command ids to highlight as active in the palette. */
|
|
86
|
+
slashActiveIds?: string[];
|
|
87
|
+
/** Single-line palette rows. */
|
|
88
|
+
slashCompact?: boolean;
|
|
62
89
|
}
|
|
63
90
|
|
|
64
91
|
const ACTION_LABEL: Record<ChatMessageAction, string> = {
|
|
@@ -75,7 +102,8 @@ defineKitnElement<Props>('kitn-chat', {
|
|
|
75
102
|
placeholder: 'Send a message...',
|
|
76
103
|
loading: false,
|
|
77
104
|
suggestions: undefined,
|
|
78
|
-
|
|
105
|
+
suggestionMode: 'submit',
|
|
106
|
+
proseSize: 'sm',
|
|
79
107
|
codeTheme: 'github-dark-dimmed',
|
|
80
108
|
codeHighlight: true,
|
|
81
109
|
chatTitle: undefined,
|
|
@@ -85,7 +113,10 @@ defineKitnElement<Props>('kitn-chat', {
|
|
|
85
113
|
scrollButton: true,
|
|
86
114
|
search: false,
|
|
87
115
|
voice: false,
|
|
88
|
-
|
|
116
|
+
slashCommands: undefined,
|
|
117
|
+
slashActiveIds: undefined,
|
|
118
|
+
slashCompact: false,
|
|
119
|
+
}, (props, { dispatch, flag }) => {
|
|
89
120
|
// Preserve the shadow-root portal mount from the wrapper's outer ChatConfig
|
|
90
121
|
// when we nest a second ChatConfig to set proseSize/codeTheme.
|
|
91
122
|
const outer = useChatConfig();
|
|
@@ -98,13 +129,22 @@ defineKitnElement<Props>('kitn-chat', {
|
|
|
98
129
|
dispatch('submit', { value: current(), attachments: attachments() });
|
|
99
130
|
setAttachments([]);
|
|
100
131
|
};
|
|
101
|
-
const handleSuggestionClick = (v: string) => {
|
|
132
|
+
const handleSuggestionClick = (v: string) => {
|
|
133
|
+
if ((props.suggestionMode ?? 'submit') === 'fill') {
|
|
134
|
+
handleChange(v);
|
|
135
|
+
dispatch('suggestionclick', { value: v });
|
|
136
|
+
} else {
|
|
137
|
+
// Default: behave as if the user typed the suggestion and pressed submit.
|
|
138
|
+
dispatch('submit', { value: v, attachments: attachments() });
|
|
139
|
+
setAttachments([]);
|
|
140
|
+
}
|
|
141
|
+
};
|
|
102
142
|
|
|
103
143
|
const showHeader = () => !!(props.chatTitle || props.models || props.context);
|
|
104
144
|
const showScrollButton = () => props.scrollButton !== false;
|
|
105
145
|
|
|
106
146
|
return (
|
|
107
|
-
<ChatConfig proseSize={props.proseSize} codeTheme={props.codeTheme} codeHighlight={
|
|
147
|
+
<ChatConfig proseSize={props.proseSize} codeTheme={props.codeTheme} codeHighlight={flag('codeHighlight')} portalMount={outer.portalMount()}>
|
|
108
148
|
<div class="flex h-full flex-col bg-background">
|
|
109
149
|
<Show when={showHeader()}>
|
|
110
150
|
<header class="flex h-14 shrink-0 items-center justify-between border-b border-border px-5">
|
|
@@ -214,17 +254,21 @@ defineKitnElement<Props>('kitn-chat', {
|
|
|
214
254
|
<DefaultPromptInput
|
|
215
255
|
value={current()}
|
|
216
256
|
placeholder={props.placeholder}
|
|
217
|
-
loading={
|
|
257
|
+
loading={flag('loading')}
|
|
218
258
|
suggestions={props.suggestions}
|
|
219
259
|
attachments={attachments()}
|
|
220
|
-
search={
|
|
221
|
-
voice={
|
|
260
|
+
search={flag('search')}
|
|
261
|
+
voice={flag('voice')}
|
|
262
|
+
slashCommands={props.slashCommands}
|
|
263
|
+
slashActiveIds={props.slashActiveIds}
|
|
264
|
+
slashCompact={flag('slashCompact')}
|
|
222
265
|
onValueChange={handleChange}
|
|
223
266
|
onSubmit={handleSubmit}
|
|
224
267
|
onSuggestionClick={handleSuggestionClick}
|
|
225
268
|
onAttachmentsChange={setAttachments}
|
|
226
269
|
onSearch={() => dispatch('search', {})}
|
|
227
270
|
onVoice={() => dispatch('voice', {})}
|
|
271
|
+
onSlashSelect={(command) => dispatch('slashselect', { command })}
|
|
228
272
|
/>
|
|
229
273
|
</div>
|
|
230
274
|
</div>
|
|
@@ -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
|
+
});
|