@kitnai/chat 0.7.0 → 0.8.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 +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/code-block.stories.tsx +8 -9
- package/src/components/component-meta.json +3411 -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 +4 -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
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from 'storybook-solidjs-vite';
|
|
2
2
|
import { onMount } from 'solid-js';
|
|
3
|
-
import './register'; // side effect: registers <
|
|
3
|
+
import './register'; // side effect: registers <kc-chat>, <kc-conversations>, <kc-prompt-input>
|
|
4
4
|
import type { AttachmentData } from '../components/attachments';
|
|
5
|
-
import {
|
|
6
|
-
import { argTypesFor } from '../stories/docs/element-controls';
|
|
5
|
+
import { argTypesFor, specDescription } from '../stories/docs/element-controls';
|
|
7
6
|
|
|
8
7
|
// The web components are custom DOM elements, so declare the tags for JSX.
|
|
9
8
|
declare module 'solid-js' {
|
|
10
9
|
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
11
10
|
namespace JSX {
|
|
12
11
|
interface IntrinsicElements {
|
|
13
|
-
'
|
|
12
|
+
'kc-prompt-input': JSX.HTMLAttributes<HTMLElement>;
|
|
14
13
|
}
|
|
15
14
|
}
|
|
16
15
|
}
|
|
@@ -42,7 +41,7 @@ interface PromptInputEl extends HTMLElement {
|
|
|
42
41
|
attachments?: AttachmentData[];
|
|
43
42
|
}
|
|
44
43
|
|
|
45
|
-
/** Live demo of the actual `<
|
|
44
|
+
/** Live demo of the actual `<kc-prompt-input>` custom element (Shadow DOM and all). */
|
|
46
45
|
function PromptInputElement(props: { search?: boolean; voice?: boolean; attachments?: AttachmentData[]; args?: Record<string, unknown> }) {
|
|
47
46
|
let el: PromptInputEl | undefined;
|
|
48
47
|
onMount(() => {
|
|
@@ -68,7 +67,7 @@ function PromptInputElement(props: { search?: boolean; voice?: boolean; attachme
|
|
|
68
67
|
el.addEventListener('voice', () => console.log('voice clicked'));
|
|
69
68
|
});
|
|
70
69
|
return (
|
|
71
|
-
<
|
|
70
|
+
<kc-prompt-input
|
|
72
71
|
ref={(e) => (el = e as PromptInputEl)}
|
|
73
72
|
style={{ display: 'block', width: '100%', padding: '16px' }}
|
|
74
73
|
/>
|
|
@@ -76,7 +75,7 @@ function PromptInputElement(props: { search?: boolean; voice?: boolean; attachme
|
|
|
76
75
|
}
|
|
77
76
|
|
|
78
77
|
const HTML_SNIPPET = `<!-- Works in any framework or plain HTML -->
|
|
79
|
-
<
|
|
78
|
+
<kc-prompt-input id="input" style="display:block; width:100%;"></kc-prompt-input>
|
|
80
79
|
|
|
81
80
|
<script type="module">
|
|
82
81
|
import '@kitnai/chat/elements'; // registers the custom elements
|
|
@@ -109,7 +108,7 @@ function Composer() {
|
|
|
109
108
|
el.suggestions = ['Summarize this thread', 'Draft a reply'];
|
|
110
109
|
});
|
|
111
110
|
return (
|
|
112
|
-
<
|
|
111
|
+
<kc-prompt-input
|
|
113
112
|
ref={el}
|
|
114
113
|
style={{ display: 'block', width: '100%' }}
|
|
115
114
|
on:submit={(e) => console.log('send:', e.detail.value)}
|
|
@@ -120,21 +119,19 @@ function Composer() {
|
|
|
120
119
|
}`;
|
|
121
120
|
|
|
122
121
|
const meta = {
|
|
123
|
-
title: 'Web Components/
|
|
122
|
+
title: 'Web Components/kc-prompt-input',
|
|
124
123
|
tags: ['autodocs'],
|
|
125
|
-
argTypes: argTypesFor('
|
|
124
|
+
argTypes: argTypesFor('kc-prompt-input'),
|
|
126
125
|
parameters: {
|
|
127
126
|
layout: 'fullscreen',
|
|
128
127
|
docs: {
|
|
129
|
-
description:
|
|
130
|
-
|
|
131
|
-
'`<kitn-prompt-input>` is the framework-agnostic **web component** version of the chat composer — an auto-resizing textarea with a send button and optional suggestion chips, isolated in **Shadow DOM** so the host page\'s CSS can\'t leak in and the kit\'s styles can\'t leak out. SolidJS is bundled in, so the host needs nothing.',
|
|
128
|
+
description: specDescription('kc-prompt-input', [
|
|
129
|
+
'`<kc-prompt-input>` is the framework-agnostic **web component** version of the chat composer — an auto-resizing textarea with a send button and optional suggestion chips, isolated in **Shadow DOM** so the host page\'s CSS can\'t leak in and the kit\'s styles can\'t leak out. SolidJS is bundled in, so the host needs nothing.',
|
|
132
130
|
'**When to use:** adding a message composer to a non-Solid app (React, Vue, Svelte, plain HTML), or anywhere you want zero style conflicts. If you *are* in SolidJS and want fine-grained control, compose the `PromptInput` primitives instead.',
|
|
133
131
|
'**How to use:** register once with `import \'@kitnai/chat/elements\'`, configure it with JS **properties** (`placeholder`, `value`, `disabled`, `loading`, `suggestions`, `attachments`) and flag attributes (`search`, `voice` to show the Globe/Mic toolbar buttons), and listen for **CustomEvents** (`submit`, `valuechange`, `suggestionclick`, `search`, `voice`) directly on the element. Leave `value` unset to let the element manage its own input state; seed `attachments` to pre-populate staged files.',
|
|
134
132
|
'**Placement:** pinned to the bottom of a chat surface, full width. Set `loading` while a response streams to show the busy state, and `disabled` to block input entirely.',
|
|
135
133
|
'See the **Code** tab below for the HTML usage; the *SolidJS* story shows the same element inside a Solid component.',
|
|
136
|
-
]
|
|
137
|
-
},
|
|
134
|
+
]),
|
|
138
135
|
},
|
|
139
136
|
},
|
|
140
137
|
} satisfies Meta;
|
|
@@ -165,7 +162,7 @@ export const InSolidJS: Story = {
|
|
|
165
162
|
};
|
|
166
163
|
|
|
167
164
|
const TOOLBAR_SNIPPET = `<!-- show the Search (Globe) + Voice (Mic) toolbar buttons -->
|
|
168
|
-
<
|
|
165
|
+
<kc-prompt-input id="input" search voice></kc-prompt-input>
|
|
169
166
|
|
|
170
167
|
<script type="module">
|
|
171
168
|
import '@kitnai/chat/elements';
|
|
@@ -183,7 +180,7 @@ export const WithVoiceAndSearch: Story = {
|
|
|
183
180
|
};
|
|
184
181
|
|
|
185
182
|
const ATTACHMENTS_SNIPPET = `<!-- seed staged attachments without an upload -->
|
|
186
|
-
<
|
|
183
|
+
<kc-prompt-input id="input" voice></kc-prompt-input>
|
|
187
184
|
|
|
188
185
|
<script type="module">
|
|
189
186
|
import '@kitnai/chat/elements';
|
|
@@ -204,8 +201,3 @@ export const WithAttachments: Story = {
|
|
|
204
201
|
parameters: { docs: { source: { code: ATTACHMENTS_SNIPPET, language: 'html' } } },
|
|
205
202
|
};
|
|
206
203
|
|
|
207
|
-
/** Full generated API reference — properties, events, tokens, and the SolidJS components this element is composed from. */
|
|
208
|
-
export const API: Story = {
|
|
209
|
-
render: () => <ElementSpec tag="kitn-prompt-input" />,
|
|
210
|
-
parameters: { layout: 'padded' },
|
|
211
|
-
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createEffect, createSignal } from 'solid-js';
|
|
2
|
-
import {
|
|
2
|
+
import { defineWebComponent } from './define';
|
|
3
3
|
import { DefaultPromptInput } from './default-input';
|
|
4
4
|
import type { AttachmentData } from '../components/attachments';
|
|
5
5
|
import type { SlashCommandItem } from '../components/slash-command';
|
|
@@ -40,7 +40,7 @@ interface Props extends Record<string, unknown> {
|
|
|
40
40
|
attachments?: AttachmentData[];
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
/** Events fired by `<
|
|
43
|
+
/** Events fired by `<kc-prompt-input>`. */
|
|
44
44
|
interface Events {
|
|
45
45
|
/** The user submitted the prompt (Enter or send button) with its attachments. */
|
|
46
46
|
submit: { value: string; attachments: AttachmentData[] };
|
|
@@ -56,7 +56,7 @@ interface Events {
|
|
|
56
56
|
voice: Record<string, never>;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
|
|
59
|
+
defineWebComponent<Props, Events>('kc-prompt-input', {
|
|
60
60
|
value: undefined,
|
|
61
61
|
placeholder: 'Send a message...',
|
|
62
62
|
disabled: false,
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from 'storybook-solidjs-vite';
|
|
2
2
|
import { onMount } from 'solid-js';
|
|
3
3
|
import './register'; // side effect: registers the custom elements
|
|
4
|
-
import {
|
|
5
|
-
import { argTypesFor } from '../stories/docs/element-controls';
|
|
4
|
+
import { argTypesFor, specDescription } from '../stories/docs/element-controls';
|
|
6
5
|
|
|
7
6
|
type Item = string | { label: string; value?: string };
|
|
8
7
|
|
|
@@ -11,7 +10,7 @@ declare module 'solid-js' {
|
|
|
11
10
|
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
12
11
|
namespace JSX {
|
|
13
12
|
interface IntrinsicElements {
|
|
14
|
-
'
|
|
13
|
+
'kc-suggestions': JSX.HTMLAttributes<HTMLElement> & {
|
|
15
14
|
variant?: string;
|
|
16
15
|
size?: string;
|
|
17
16
|
block?: boolean | string;
|
|
@@ -27,7 +26,7 @@ const suggestions: Item[] = [
|
|
|
27
26
|
"What's deferred?",
|
|
28
27
|
];
|
|
29
28
|
|
|
30
|
-
/** Render `<
|
|
29
|
+
/** Render `<kc-suggestions>` with `suggestions` set as a property. */
|
|
31
30
|
function SuggestionsElement(props: { suggestions: Item[]; variant?: string; size?: string; block?: boolean; highlight?: string }) {
|
|
32
31
|
let el: (HTMLElement & { suggestions?: Item[] }) | undefined;
|
|
33
32
|
onMount(() => {
|
|
@@ -39,7 +38,7 @@ function SuggestionsElement(props: { suggestions: Item[]; variant?: string; size
|
|
|
39
38
|
});
|
|
40
39
|
});
|
|
41
40
|
return (
|
|
42
|
-
<
|
|
41
|
+
<kc-suggestions
|
|
43
42
|
ref={(e) => (el = e as HTMLElement)}
|
|
44
43
|
variant={props.variant}
|
|
45
44
|
size={props.size}
|
|
@@ -51,7 +50,7 @@ function SuggestionsElement(props: { suggestions: Item[]; variant?: string; size
|
|
|
51
50
|
}
|
|
52
51
|
|
|
53
52
|
const HTML_SNIPPET = `<!-- Works in any framework or plain HTML -->
|
|
54
|
-
<
|
|
53
|
+
<kc-suggestions id="suggs" variant="outline"></kc-suggestions>
|
|
55
54
|
|
|
56
55
|
<script type="module">
|
|
57
56
|
import '@kitnai/chat/elements'; // registers the custom elements
|
|
@@ -62,20 +61,18 @@ const HTML_SNIPPET = `<!-- Works in any framework or plain HTML -->
|
|
|
62
61
|
</script>`;
|
|
63
62
|
|
|
64
63
|
const meta = {
|
|
65
|
-
title: 'Web Components/
|
|
64
|
+
title: 'Web Components/kc-suggestions',
|
|
66
65
|
tags: ['autodocs'],
|
|
67
|
-
argTypes: argTypesFor('
|
|
66
|
+
argTypes: argTypesFor('kc-suggestions'),
|
|
68
67
|
parameters: {
|
|
69
68
|
layout: 'fullscreen',
|
|
70
69
|
docs: {
|
|
71
|
-
description:
|
|
72
|
-
|
|
73
|
-
'`<kitn-prompt-suggestions>` is the framework-agnostic **web component** for a row (or list) of clickable suggestion chips — starter prompts or follow-ups — isolated in **Shadow DOM**.',
|
|
70
|
+
description: specDescription('kc-suggestions', [
|
|
71
|
+
'`<kc-suggestions>` is the framework-agnostic **web component** for a row (or list) of clickable suggestion chips — starter prompts or follow-ups — isolated in **Shadow DOM**.',
|
|
74
72
|
'**When to use:** offering the user quick prompts to click instead of type, usually above an input. In SolidJS, use the `PromptSuggestion` primitive.',
|
|
75
73
|
"**How to use:** register once with `import '@kitnai/chat/elements'`, set the `suggestions` **property** (strings, or `{ label, value }` when the displayed text differs from the emitted value), choose a `variant` and `size` (`sm` | `md` | `lg`; pills default to `lg`), optionally add the `block` flag for full-width rows or a `highlight` substring to emphasize, and listen for the `select` **CustomEvent**.",
|
|
76
74
|
'See the **Code** tab for HTML usage.',
|
|
77
|
-
]
|
|
78
|
-
},
|
|
75
|
+
]),
|
|
79
76
|
},
|
|
80
77
|
},
|
|
81
78
|
} satisfies Meta;
|
|
@@ -83,12 +80,6 @@ const meta = {
|
|
|
83
80
|
export default meta;
|
|
84
81
|
type Story = StoryObj;
|
|
85
82
|
|
|
86
|
-
/** Full generated API reference — properties, events, tokens, and composed-from. */
|
|
87
|
-
export const API: Story = {
|
|
88
|
-
render: () => <ElementSpec tag="kitn-prompt-suggestions" />,
|
|
89
|
-
parameters: { layout: 'padded' },
|
|
90
|
-
};
|
|
91
|
-
|
|
92
83
|
/** Default outline pills, wrapping in a row. */
|
|
93
84
|
export const Default: Story = {
|
|
94
85
|
render: () => <SuggestionsElement suggestions={suggestions} variant="outline" />,
|
|
@@ -121,7 +112,7 @@ export const WithHighlightedSearch: Story = {
|
|
|
121
112
|
parameters: {
|
|
122
113
|
docs: {
|
|
123
114
|
source: {
|
|
124
|
-
code: `<
|
|
115
|
+
code: `<kc-suggestions id="suggs" highlight="Solid"></kc-suggestions>
|
|
125
116
|
|
|
126
117
|
<script type="module">
|
|
127
118
|
import '@kitnai/chat/elements';
|
|
@@ -156,9 +147,9 @@ export const Sizes: Story = {
|
|
|
156
147
|
docs: {
|
|
157
148
|
source: {
|
|
158
149
|
code: `<!-- default pill -->
|
|
159
|
-
<
|
|
150
|
+
<kc-suggestions variant="outline"></kc-suggestions>
|
|
160
151
|
<!-- smaller pill -->
|
|
161
|
-
<
|
|
152
|
+
<kc-suggestions variant="outline" size="sm"></kc-suggestions>`,
|
|
162
153
|
language: 'html',
|
|
163
154
|
},
|
|
164
155
|
},
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { For } from 'solid-js';
|
|
2
|
-
import {
|
|
2
|
+
import { defineWebComponent } from './define';
|
|
3
3
|
import { PromptSuggestion } from '../components/prompt-suggestion';
|
|
4
4
|
|
|
5
5
|
type Item = string | { label: string; value?: string };
|
|
@@ -19,7 +19,7 @@ interface Props extends Record<string, unknown> {
|
|
|
19
19
|
highlight?: string;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
/** Events fired by `<
|
|
22
|
+
/** Events fired by `<kc-suggestions>`. */
|
|
23
23
|
interface Events {
|
|
24
24
|
/** A suggestion was clicked. */
|
|
25
25
|
select: { value: string };
|
|
@@ -29,11 +29,11 @@ const labelOf = (s: Item) => (typeof s === 'string' ? s : s.label);
|
|
|
29
29
|
const valueOf = (s: Item) => (typeof s === 'string' ? s : s.value ?? s.label);
|
|
30
30
|
|
|
31
31
|
/**
|
|
32
|
-
* `<
|
|
32
|
+
* `<kc-suggestions>` — a row/list of suggestion chips. Data via the
|
|
33
33
|
* `suggestions` property; `variant`/`block`/`highlight` attributes; emits
|
|
34
34
|
* `select`.
|
|
35
35
|
*/
|
|
36
|
-
|
|
36
|
+
defineWebComponent<Props, Events>('kc-suggestions', {
|
|
37
37
|
suggestions: [],
|
|
38
38
|
variant: 'outline',
|
|
39
39
|
size: undefined,
|
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from 'storybook-solidjs-vite';
|
|
2
2
|
import { onMount } from 'solid-js';
|
|
3
3
|
import './register'; // side effect: registers the custom elements
|
|
4
|
-
import {
|
|
5
|
-
import { argTypesFor } from '../stories/docs/element-controls';
|
|
4
|
+
import { argTypesFor, specDescription } from '../stories/docs/element-controls';
|
|
6
5
|
|
|
7
6
|
// The web components are custom DOM elements, so declare the tags for JSX.
|
|
8
7
|
declare module 'solid-js' {
|
|
9
8
|
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
10
9
|
namespace JSX {
|
|
11
10
|
interface IntrinsicElements {
|
|
12
|
-
'
|
|
11
|
+
'kc-reasoning': JSX.HTMLAttributes<HTMLElement>;
|
|
13
12
|
}
|
|
14
13
|
}
|
|
15
14
|
}
|
|
@@ -17,7 +16,7 @@ declare module 'solid-js' {
|
|
|
17
16
|
const sampleText =
|
|
18
17
|
'First I parse the request, then I plan the steps, then I execute and verify each one before responding.';
|
|
19
18
|
|
|
20
|
-
/** Render the actual `<
|
|
19
|
+
/** Render the actual `<kc-reasoning>` custom element with a `text` property. */
|
|
21
20
|
function ReasoningElement(props: { text: string; streaming?: boolean }) {
|
|
22
21
|
let el: (HTMLElement & { text?: string; streaming?: boolean }) | undefined;
|
|
23
22
|
onMount(() => {
|
|
@@ -27,12 +26,12 @@ function ReasoningElement(props: { text: string; streaming?: boolean }) {
|
|
|
27
26
|
}
|
|
28
27
|
});
|
|
29
28
|
return (
|
|
30
|
-
<
|
|
29
|
+
<kc-reasoning ref={(e) => (el = e as HTMLElement)} style={{ display: 'block', padding: '16px', 'max-width': '720px' }} />
|
|
31
30
|
);
|
|
32
31
|
}
|
|
33
32
|
|
|
34
33
|
const HTML_SNIPPET = `<!-- Works in any framework or plain HTML -->
|
|
35
|
-
<
|
|
34
|
+
<kc-reasoning id="reason" label="Reasoning"></kc-reasoning>
|
|
36
35
|
|
|
37
36
|
<script type="module">
|
|
38
37
|
import '@kitnai/chat/elements'; // registers the custom elements
|
|
@@ -46,20 +45,18 @@ const HTML_SNIPPET = `<!-- Works in any framework or plain HTML -->
|
|
|
46
45
|
</script>`;
|
|
47
46
|
|
|
48
47
|
const meta = {
|
|
49
|
-
title: 'Web Components/
|
|
48
|
+
title: 'Web Components/kc-reasoning',
|
|
50
49
|
tags: ['autodocs'],
|
|
51
|
-
argTypes: argTypesFor('
|
|
50
|
+
argTypes: argTypesFor('kc-reasoning'),
|
|
52
51
|
parameters: {
|
|
53
52
|
layout: 'fullscreen',
|
|
54
53
|
docs: {
|
|
55
|
-
description:
|
|
56
|
-
|
|
57
|
-
'`<kitn-reasoning>` is the framework-agnostic **web component** for a collapsible reasoning/thinking block that auto-expands while a thought is `streaming`, isolated in **Shadow DOM**.',
|
|
54
|
+
description: specDescription('kc-reasoning', [
|
|
55
|
+
'`<kc-reasoning>` is the framework-agnostic **web component** for a collapsible reasoning/thinking block that auto-expands while a thought is `streaming`, isolated in **Shadow DOM**.',
|
|
58
56
|
'**When to use:** surfacing model chain-of-thought in a non-Solid app. In SolidJS, compose the `Reasoning` primitives directly.',
|
|
59
57
|
"**How to use:** register once with `import '@kitnai/chat/elements'`, set the body via the `text` **property**, set the `streaming` flag while it streams in, optionally drive the controlled `open` property, and listen for the `openchange` **CustomEvent**.",
|
|
60
58
|
'See the **Code** tab for HTML usage.',
|
|
61
|
-
]
|
|
62
|
-
},
|
|
59
|
+
]),
|
|
63
60
|
},
|
|
64
61
|
},
|
|
65
62
|
} satisfies Meta;
|
|
@@ -67,12 +64,6 @@ const meta = {
|
|
|
67
64
|
export default meta;
|
|
68
65
|
type Story = StoryObj;
|
|
69
66
|
|
|
70
|
-
/** Full generated API reference — properties, events, tokens, and composed-from. */
|
|
71
|
-
export const API: Story = {
|
|
72
|
-
render: () => <ElementSpec tag="kitn-reasoning" />,
|
|
73
|
-
parameters: { layout: 'padded' },
|
|
74
|
-
};
|
|
75
|
-
|
|
76
67
|
/** A collapsed reasoning block (the trigger toggles it). */
|
|
77
68
|
export const Default: Story = {
|
|
78
69
|
render: () => <ReasoningElement text={sampleText} />,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { defineWebComponent } from './define';
|
|
2
2
|
import { Reasoning, ReasoningTrigger, ReasoningContent } from '../components/reasoning';
|
|
3
3
|
import { ChatConfig, useChatConfig } from '../primitives/chat-config';
|
|
4
4
|
|
|
@@ -16,18 +16,18 @@ interface Props extends Record<string, unknown> {
|
|
|
16
16
|
markdown?: boolean;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
/** Events fired by `<
|
|
19
|
+
/** Events fired by `<kc-reasoning>`. */
|
|
20
20
|
interface Events {
|
|
21
21
|
/** Open state changed (via the trigger or streaming auto-open). */
|
|
22
22
|
openchange: { open: boolean };
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
|
-
* `<
|
|
26
|
+
* `<kc-reasoning>` — a collapsible reasoning/thinking block that auto-expands
|
|
27
27
|
* while `streaming`. Text via the `text` property; `markdown`/`streaming` flags;
|
|
28
28
|
* `open` is a controlled property; emits `openchange`.
|
|
29
29
|
*/
|
|
30
|
-
|
|
30
|
+
defineWebComponent<Props, Events>('kc-reasoning', {
|
|
31
31
|
text: '',
|
|
32
32
|
label: 'Reasoning',
|
|
33
33
|
open: undefined,
|
package/src/elements/register.ts
CHANGED
|
@@ -21,7 +21,7 @@ import './chat-scope-picker';
|
|
|
21
21
|
// Phase 3 — input ecosystem
|
|
22
22
|
// (NB: SlashCommand is context-bound to PromptInput — it observes the input
|
|
23
23
|
// value via usePromptInput() — so it is NOT a standalone element. It will fold
|
|
24
|
-
// into <
|
|
24
|
+
// into <kc-prompt-input> as a `slash-commands` property in a later pass.)
|
|
25
25
|
import './prompt-suggestions';
|
|
26
26
|
import './file-upload';
|
|
27
27
|
import './voice-input';
|
|
@@ -35,6 +35,16 @@ import './source';
|
|
|
35
35
|
import './response-stream';
|
|
36
36
|
import './empty';
|
|
37
37
|
import './chain-of-thought';
|
|
38
|
+
import './resizable';
|
|
39
|
+
import './file-tree';
|
|
40
|
+
import './artifact';
|
|
41
|
+
// Generative-UI cards (Card Contract)
|
|
42
|
+
import './card';
|
|
43
|
+
import './form';
|
|
44
|
+
import './link-card';
|
|
45
|
+
import './embed';
|
|
46
|
+
import './confirm-card';
|
|
47
|
+
import './task-list-card';
|
|
38
48
|
|
|
39
49
|
export type { ChatMessage, ChatMessageAction } from './chat-types';
|
|
40
50
|
export { configureCodeHighlighting, isCodeHighlightingEnabled } from '../primitives/highlighter';
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from 'storybook-solidjs-vite';
|
|
2
|
+
import { createSignal, type JSX } from 'solid-js';
|
|
3
|
+
import './register'; // side effect: registers the custom elements
|
|
4
|
+
import { argTypesFor, specDescription } from '../stories/docs/element-controls';
|
|
5
|
+
|
|
6
|
+
// The web components are custom DOM elements, so declare the tags for JSX.
|
|
7
|
+
declare module 'solid-js' {
|
|
8
|
+
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
9
|
+
namespace JSX {
|
|
10
|
+
interface IntrinsicElements {
|
|
11
|
+
'kc-resizable': JSX.HTMLAttributes<HTMLElement> & { orientation?: string };
|
|
12
|
+
'kc-resizable-item': JSX.HTMLAttributes<HTMLElement> & {
|
|
13
|
+
size?: string; min?: string; max?: string; locked?: boolean | string; hidden?: boolean | string;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** A labelled placeholder pane so the layout is visible in stories. */
|
|
20
|
+
function Pane(props: { label: string; tone?: 'muted' | 'plain' }) {
|
|
21
|
+
return (
|
|
22
|
+
<div
|
|
23
|
+
style={{
|
|
24
|
+
height: '100%',
|
|
25
|
+
display: 'flex',
|
|
26
|
+
'align-items': 'center',
|
|
27
|
+
'justify-content': 'center',
|
|
28
|
+
padding: '16px',
|
|
29
|
+
background: props.tone === 'plain' ? 'transparent' : 'var(--color-muted, #f4f4f5)',
|
|
30
|
+
color: 'var(--color-muted-foreground, #71717a)',
|
|
31
|
+
'font-size': '13px',
|
|
32
|
+
}}
|
|
33
|
+
>
|
|
34
|
+
{props.label}
|
|
35
|
+
</div>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** A bordered, sized frame the group fills. */
|
|
40
|
+
function Frame(props: { children: JSX.Element; tall?: boolean }) {
|
|
41
|
+
return (
|
|
42
|
+
<div
|
|
43
|
+
style={{
|
|
44
|
+
height: props.tall ? '384px' : '256px',
|
|
45
|
+
width: '100%',
|
|
46
|
+
'max-width': '768px',
|
|
47
|
+
border: '1px solid var(--color-border, #e4e4e7)',
|
|
48
|
+
'border-radius': '8px',
|
|
49
|
+
overflow: 'hidden',
|
|
50
|
+
}}
|
|
51
|
+
>
|
|
52
|
+
{props.children}
|
|
53
|
+
</div>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const HTML_SNIPPET = `<!-- Works in any framework or plain HTML -->
|
|
58
|
+
<kc-resizable orientation="horizontal" style="display:block;height:400px">
|
|
59
|
+
<kc-resizable-item size="25%" min="160px"> ...list... </kc-resizable-item>
|
|
60
|
+
<kc-resizable-item> ...chat... </kc-resizable-item>
|
|
61
|
+
<kc-resizable-item size="30%"> ...preview... </kc-resizable-item>
|
|
62
|
+
</kc-resizable>
|
|
63
|
+
|
|
64
|
+
<script type="module">
|
|
65
|
+
import '@kitnai/chat/elements'; // registers the custom elements
|
|
66
|
+
document.querySelector('kc-resizable')
|
|
67
|
+
.addEventListener('change', (e) => console.log(e.detail.sizes));
|
|
68
|
+
</script>`;
|
|
69
|
+
|
|
70
|
+
const meta = {
|
|
71
|
+
title: 'Web Components/kc-resizable',
|
|
72
|
+
tags: ['autodocs'],
|
|
73
|
+
argTypes: argTypesFor('kc-resizable'),
|
|
74
|
+
parameters: {
|
|
75
|
+
layout: 'padded',
|
|
76
|
+
docs: {
|
|
77
|
+
description: specDescription('kc-resizable', [
|
|
78
|
+
'`<kc-resizable>` is the framework-agnostic **web component** for a composable, resizable multi-panel layout (up to **3** `<kc-resizable-item>` panels) with **auto-inserted draggable dividers** — isolated in **Shadow DOM**.',
|
|
79
|
+
'**When to use:** to compose an app shell out of slotted regions without hand-wiring panels and handles — e.g. `list | chat | preview`. In SolidJS, use the `Resizable` convenience (UI/Resizable) directly.',
|
|
80
|
+
"**How to use:** register once with `import '@kitnai/chat/elements'`, set `orientation` (`horizontal` row / `vertical` column), and put a `<kc-resizable-item>` per panel. Each item carries `size` (px or %, e.g. `\"280px\"` or `\"25%\"`), `min`/`max`, `locked` (fixed size + non-draggable neighbour), and `hidden` (drops the panel + its divider). Listen for the **`change`** event (`detail.sizes`, percent).",
|
|
81
|
+
'**Placement:** the layout spine for compose-your-own-chat shells — sidebar + conversation, conversation + inspector, or a three-up list/chat/preview.',
|
|
82
|
+
'See the **Code** tab for HTML usage.',
|
|
83
|
+
]),
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
args: { orientation: 'horizontal' },
|
|
87
|
+
} satisfies Meta;
|
|
88
|
+
|
|
89
|
+
export default meta;
|
|
90
|
+
type Story = StoryObj;
|
|
91
|
+
|
|
92
|
+
/** Interactive playground — flip orientation, then drag the dividers. */
|
|
93
|
+
export const Playground: Story = {
|
|
94
|
+
render: (args: { orientation?: string }) => (
|
|
95
|
+
<Frame>
|
|
96
|
+
<kc-resizable orientation={args.orientation ?? 'horizontal'}>
|
|
97
|
+
<kc-resizable-item size="25%" min="120px"><Pane label="List" /></kc-resizable-item>
|
|
98
|
+
<kc-resizable-item><Pane label="Chat" tone="plain" /></kc-resizable-item>
|
|
99
|
+
</kc-resizable>
|
|
100
|
+
</Frame>
|
|
101
|
+
),
|
|
102
|
+
parameters: { docs: { source: { code: HTML_SNIPPET, language: 'html' } } },
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
/** Two panels: a sized list beside a flexible chat. */
|
|
106
|
+
export const ListChat: Story = {
|
|
107
|
+
name: 'Sidebar + chat',
|
|
108
|
+
render: () => (
|
|
109
|
+
<Frame>
|
|
110
|
+
<kc-resizable orientation="horizontal">
|
|
111
|
+
<kc-resizable-item size="28%" min="140px" max="50%"><Pane label="List" /></kc-resizable-item>
|
|
112
|
+
<kc-resizable-item><Pane label="Chat" tone="plain" /></kc-resizable-item>
|
|
113
|
+
</kc-resizable>
|
|
114
|
+
</Frame>
|
|
115
|
+
),
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
/** Three panels, two draggable dividers. */
|
|
119
|
+
export const ListChatPreview: Story = {
|
|
120
|
+
name: 'List + chat + preview',
|
|
121
|
+
render: () => (
|
|
122
|
+
<Frame>
|
|
123
|
+
<kc-resizable orientation="horizontal">
|
|
124
|
+
<kc-resizable-item size="22%" min="120px"><Pane label="List" /></kc-resizable-item>
|
|
125
|
+
<kc-resizable-item><Pane label="Chat" tone="plain" /></kc-resizable-item>
|
|
126
|
+
<kc-resizable-item size="30%" min="160px"><Pane label="Preview" /></kc-resizable-item>
|
|
127
|
+
</kc-resizable>
|
|
128
|
+
</Frame>
|
|
129
|
+
),
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
/** A locked, fixed-px sidebar — its divider is a static (non-draggable) separator. */
|
|
133
|
+
export const LockedSidebar: Story = {
|
|
134
|
+
name: 'Locked sidebar',
|
|
135
|
+
render: () => (
|
|
136
|
+
<Frame>
|
|
137
|
+
<kc-resizable orientation="horizontal">
|
|
138
|
+
<kc-resizable-item size="240px" locked><Pane label="Locked sidebar (240px)" /></kc-resizable-item>
|
|
139
|
+
<kc-resizable-item><Pane label="Chat" tone="plain" /></kc-resizable-item>
|
|
140
|
+
</kc-resizable>
|
|
141
|
+
</Frame>
|
|
142
|
+
),
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
/** Stacked top/bottom split. */
|
|
146
|
+
export const Vertical: Story = {
|
|
147
|
+
name: 'Vertical split',
|
|
148
|
+
render: () => (
|
|
149
|
+
<Frame tall>
|
|
150
|
+
<kc-resizable orientation="vertical">
|
|
151
|
+
<kc-resizable-item size="40%" min="80px"><Pane label="Top" /></kc-resizable-item>
|
|
152
|
+
<kc-resizable-item><Pane label="Bottom" tone="plain" /></kc-resizable-item>
|
|
153
|
+
</kc-resizable>
|
|
154
|
+
</Frame>
|
|
155
|
+
),
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
/** Toggle the preview panel — its divider drops and the rest reflow. */
|
|
159
|
+
export const HiddenToggle: Story = {
|
|
160
|
+
name: 'Show / hide a panel',
|
|
161
|
+
render: () => {
|
|
162
|
+
const [showPreview, setShowPreview] = createSignal(true);
|
|
163
|
+
let previewItem: HTMLElement | undefined;
|
|
164
|
+
const toggle = () => {
|
|
165
|
+
setShowPreview((v) => !v);
|
|
166
|
+
// Drive the boolean attribute directly so the group's MutationObserver
|
|
167
|
+
// re-lays out (Solid sets the `hidden` IDL property, which doesn't reflect
|
|
168
|
+
// to the attribute on a custom element).
|
|
169
|
+
if (previewItem) {
|
|
170
|
+
if (showPreview()) previewItem.removeAttribute('hidden');
|
|
171
|
+
else previewItem.setAttribute('hidden', '');
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
return (
|
|
175
|
+
<div style={{ display: 'flex', 'flex-direction': 'column', gap: '8px' }}>
|
|
176
|
+
<button
|
|
177
|
+
type="button"
|
|
178
|
+
onClick={toggle}
|
|
179
|
+
style={{
|
|
180
|
+
'align-self': 'flex-start',
|
|
181
|
+
padding: '4px 12px',
|
|
182
|
+
'font-size': '13px',
|
|
183
|
+
border: '1px solid var(--color-border, #e4e4e7)',
|
|
184
|
+
'border-radius': '6px',
|
|
185
|
+
cursor: 'pointer',
|
|
186
|
+
}}
|
|
187
|
+
>
|
|
188
|
+
{showPreview() ? 'Hide preview' : 'Show preview'}
|
|
189
|
+
</button>
|
|
190
|
+
<Frame>
|
|
191
|
+
<kc-resizable orientation="horizontal">
|
|
192
|
+
<kc-resizable-item size="24%" min="120px"><Pane label="List" /></kc-resizable-item>
|
|
193
|
+
<kc-resizable-item><Pane label="Chat" tone="plain" /></kc-resizable-item>
|
|
194
|
+
<kc-resizable-item ref={(e) => (previewItem = e as HTMLElement)} size="30%"><Pane label="Preview" /></kc-resizable-item>
|
|
195
|
+
</kc-resizable>
|
|
196
|
+
</Frame>
|
|
197
|
+
</div>
|
|
198
|
+
);
|
|
199
|
+
},
|
|
200
|
+
};
|