@kitn.ai/ui 0.15.0 → 0.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (177) hide show
  1. package/dist/kitn-chat.es.js +1 -1
  2. package/package.json +6 -1
  3. package/src/elements/compiled.css +1 -1
  4. package/src/components/artifact.stories.tsx +0 -138
  5. package/src/components/attachments.stories.tsx +0 -303
  6. package/src/components/attachments.test.tsx +0 -64
  7. package/src/components/chain-of-thought.stories.tsx +0 -211
  8. package/src/components/chat-container.stories.tsx +0 -187
  9. package/src/components/chat-thread.test.tsx +0 -58
  10. package/src/components/checkpoint.stories.tsx +0 -102
  11. package/src/components/code-block.stories.tsx +0 -150
  12. package/src/components/confirm-card.stories.tsx +0 -74
  13. package/src/components/context.stories.tsx +0 -229
  14. package/src/components/context.test.tsx +0 -133
  15. package/src/components/conversation-item.stories.tsx +0 -125
  16. package/src/components/conversation-list.stories.tsx +0 -133
  17. package/src/components/default-input.test.tsx +0 -111
  18. package/src/components/empty.stories.tsx +0 -434
  19. package/src/components/feedback-bar.stories.tsx +0 -138
  20. package/src/components/feedback-bar.test.tsx +0 -103
  21. package/src/components/file-tree.stories.tsx +0 -73
  22. package/src/components/file-upload.stories.tsx +0 -156
  23. package/src/components/image.stories.tsx +0 -89
  24. package/src/components/loader.stories.tsx +0 -181
  25. package/src/components/markdown.stories.tsx +0 -180
  26. package/src/components/message-action-bar.test.tsx +0 -128
  27. package/src/components/message-narrow.stories.tsx +0 -329
  28. package/src/components/message-skills.stories.tsx +0 -211
  29. package/src/components/message.stories.tsx +0 -281
  30. package/src/components/model-switcher.stories.tsx +0 -123
  31. package/src/components/model-switcher.test.tsx +0 -65
  32. package/src/components/prompt-input.stories.tsx +0 -222
  33. package/src/components/prompt-suggestion.stories.tsx +0 -142
  34. package/src/components/reasoning.stories.tsx +0 -140
  35. package/src/components/resizable.test.tsx +0 -226
  36. package/src/components/scroll-button.stories.tsx +0 -100
  37. package/src/components/slash-command.stories.tsx +0 -163
  38. package/src/components/source-list.test.tsx +0 -152
  39. package/src/components/source.stories.tsx +0 -124
  40. package/src/components/tasks-card.stories.tsx +0 -78
  41. package/src/components/text-shimmer.stories.tsx +0 -87
  42. package/src/components/thinking-bar.stories.tsx +0 -87
  43. package/src/components/tool.stories.tsx +0 -153
  44. package/src/components/voice-input.stories.tsx +0 -83
  45. package/src/elements/artifact.stories.tsx +0 -506
  46. package/src/elements/attachments.stories.tsx +0 -190
  47. package/src/elements/card.stories.tsx +0 -113
  48. package/src/elements/cards.stories.tsx +0 -59
  49. package/src/elements/catalog.stories.tsx +0 -491
  50. package/src/elements/chain-of-thought.declarative.test.tsx +0 -153
  51. package/src/elements/chain-of-thought.stories.tsx +0 -113
  52. package/src/elements/chat-scope-picker.stories.tsx +0 -73
  53. package/src/elements/chat-workspace.stories.tsx +0 -288
  54. package/src/elements/chat.stories.tsx +0 -151
  55. package/src/elements/checkpoint.stories.tsx +0 -72
  56. package/src/elements/choice.stories.tsx +0 -240
  57. package/src/elements/code-block.stories.tsx +0 -83
  58. package/src/elements/composed-shell.stories.tsx +0 -316
  59. package/src/elements/confirm-card.stories.tsx +0 -227
  60. package/src/elements/context-meter.stories.tsx +0 -151
  61. package/src/elements/conversation-list.declarative.test.tsx +0 -137
  62. package/src/elements/conversation-list.stories.tsx +0 -243
  63. package/src/elements/embed.stories.tsx +0 -213
  64. package/src/elements/empty.stories.tsx +0 -111
  65. package/src/elements/feedback-bar.stories.tsx +0 -114
  66. package/src/elements/file-tree.stories.tsx +0 -134
  67. package/src/elements/file-upload.stories.tsx +0 -82
  68. package/src/elements/form.stories.tsx +0 -248
  69. package/src/elements/image.stories.tsx +0 -71
  70. package/src/elements/link-preview.stories.tsx +0 -209
  71. package/src/elements/loader.stories.tsx +0 -88
  72. package/src/elements/markdown.stories.tsx +0 -76
  73. package/src/elements/message-skills.declarative.test.tsx +0 -104
  74. package/src/elements/message-skills.stories.tsx +0 -114
  75. package/src/elements/message.stories.tsx +0 -218
  76. package/src/elements/model-switcher.declarative.test.tsx +0 -130
  77. package/src/elements/model-switcher.stories.tsx +0 -198
  78. package/src/elements/popover.stories.tsx +0 -80
  79. package/src/elements/prompt-input-slash-command.test.tsx +0 -128
  80. package/src/elements/prompt-input-stoppable.test.tsx +0 -88
  81. package/src/elements/prompt-input-toolbar-actions.test.tsx +0 -120
  82. package/src/elements/prompt-input.stories.tsx +0 -331
  83. package/src/elements/prompt-suggestions.declarative.test.tsx +0 -164
  84. package/src/elements/prompt-suggestions.stories.tsx +0 -213
  85. package/src/elements/reasoning.stories.tsx +0 -77
  86. package/src/elements/remote.stories.tsx +0 -314
  87. package/src/elements/resizable.stories.tsx +0 -426
  88. package/src/elements/response-stream.stories.tsx +0 -79
  89. package/src/elements/scroll-button.stories.tsx +0 -202
  90. package/src/elements/scroll-button.test.tsx +0 -148
  91. package/src/elements/source-list.stories.tsx +0 -143
  92. package/src/elements/source.stories.tsx +0 -88
  93. package/src/elements/switch.stories.tsx +0 -56
  94. package/src/elements/tasks.stories.tsx +0 -237
  95. package/src/elements/text-shimmer.stories.tsx +0 -64
  96. package/src/elements/thinking-bar.stories.tsx +0 -72
  97. package/src/elements/tool.stories.tsx +0 -89
  98. package/src/elements/voice-input.stories.tsx +0 -88
  99. package/src/primitives/controllable.test.ts +0 -47
  100. package/src/stories/chat-panel-layout.stories.tsx +0 -145
  101. package/src/stories/chat-scene.tsx +0 -571
  102. package/src/stories/checkpoint-restore.stories.tsx +0 -256
  103. package/src/stories/context-usage.stories.tsx +0 -212
  104. package/src/stories/conversation-with-reasoning.stories.tsx +0 -182
  105. package/src/stories/conversation-with-sources.stories.tsx +0 -471
  106. package/src/stories/docs/Accessibility.mdx +0 -119
  107. package/src/stories/docs/ChildElements.mdx +0 -269
  108. package/src/stories/docs/ForAIAgents.mdx +0 -162
  109. package/src/stories/docs/GettingStarted.mdx +0 -65
  110. package/src/stories/docs/Installation.mdx +0 -83
  111. package/src/stories/docs/Introduction.mdx +0 -50
  112. package/src/stories/docs/SolidJsAdvanced.mdx +0 -17
  113. package/src/stories/docs/Theming.mdx +0 -85
  114. package/src/stories/docs/element-controls.ts +0 -121
  115. package/src/stories/docs/frameworks/Angular.mdx +0 -245
  116. package/src/stories/docs/frameworks/Html.mdx +0 -227
  117. package/src/stories/docs/frameworks/Overview.mdx +0 -47
  118. package/src/stories/docs/frameworks/React.mdx +0 -227
  119. package/src/stories/docs/frameworks/Solid.mdx +0 -173
  120. package/src/stories/docs/frameworks/Svelte.mdx +0 -194
  121. package/src/stories/docs/frameworks/Vue.mdx +0 -238
  122. package/src/stories/docs/generative-ui-overview.mdx +0 -186
  123. package/src/stories/docs/recipes/SpeechToText.mdx +0 -7
  124. package/src/stories/docs/recipes/Streaming.mdx +0 -68
  125. package/src/stories/docs/recipes/TextToSpeech.mdx +0 -35
  126. package/src/stories/docs/theme-editor/canvas.tsx +0 -32
  127. package/src/stories/docs/theme-editor/inspector.tsx +0 -66
  128. package/src/stories/docs/theme-editor/presets.test.ts +0 -32
  129. package/src/stories/docs/theme-editor/presets.ts +0 -64
  130. package/src/stories/docs/theme-editor/theme-css.test.ts +0 -19
  131. package/src/stories/docs/theme-editor/theme-css.ts +0 -15
  132. package/src/stories/docs/theme-editor/theme-editor.tsx +0 -146
  133. package/src/stories/docs/theme-tokens.tsx +0 -174
  134. package/src/stories/examples/ChoosingComponents.mdx +0 -106
  135. package/src/stories/examples/sample-data.ts +0 -79
  136. package/src/stories/examples/usage/checkpoint-restore.ts +0 -156
  137. package/src/stories/examples/usage/context-usage.ts +0 -591
  138. package/src/stories/examples/usage/conversation-with-reasoning.ts +0 -224
  139. package/src/stories/examples/usage/conversation-with-sources.ts +0 -589
  140. package/src/stories/examples/usage/empty-state.ts +0 -144
  141. package/src/stories/examples/usage/full-chat-app.ts +0 -277
  142. package/src/stories/examples/usage/index.ts +0 -63
  143. package/src/stories/examples/usage/message-actions.ts +0 -704
  144. package/src/stories/examples/usage/pattern-centered-conversation.ts +0 -446
  145. package/src/stories/examples/usage/pattern-chat-panel-layout.ts +0 -442
  146. package/src/stories/examples/usage/pattern-docked-widget.ts +0 -479
  147. package/src/stories/examples/usage/prompt-input-variants.ts +0 -1356
  148. package/src/stories/examples/usage/streaming-response.ts +0 -687
  149. package/src/stories/examples/usage/types.ts +0 -33
  150. package/src/stories/full-chat.stories.tsx +0 -18
  151. package/src/stories/message-actions.stories.tsx +0 -230
  152. package/src/stories/pattern-centered-conversation.stories.tsx +0 -93
  153. package/src/stories/pattern-docked-widget.stories.tsx +0 -93
  154. package/src/stories/pattern-empty-state.stories.tsx +0 -76
  155. package/src/stories/prompt-input-variants.stories.tsx +0 -456
  156. package/src/stories/streaming-response.stories.tsx +0 -438
  157. package/src/stories/theme-editor.stories.tsx +0 -16
  158. package/src/stories/token-reference.stories.tsx +0 -18
  159. package/src/stories/typography.stories.tsx +0 -78
  160. package/src/ui/avatar.stories.tsx +0 -103
  161. package/src/ui/badge.stories.tsx +0 -86
  162. package/src/ui/button.stories.tsx +0 -145
  163. package/src/ui/collapsible.stories.tsx +0 -69
  164. package/src/ui/dropdown.stories.tsx +0 -59
  165. package/src/ui/hover-card.stories.tsx +0 -77
  166. package/src/ui/hover-card.test.tsx +0 -30
  167. package/src/ui/overlay.stories.tsx +0 -115
  168. package/src/ui/popover.stories.tsx +0 -81
  169. package/src/ui/popover.test.tsx +0 -99
  170. package/src/ui/resizable.stories.tsx +0 -236
  171. package/src/ui/scroll-area.stories.tsx +0 -50
  172. package/src/ui/separator.stories.tsx +0 -81
  173. package/src/ui/skeleton.stories.tsx +0 -337
  174. package/src/ui/switch.stories.tsx +0 -51
  175. package/src/ui/switch.test.tsx +0 -59
  176. package/src/ui/textarea.stories.tsx +0 -76
  177. package/src/ui/tooltip.stories.tsx +0 -74
@@ -1,125 +0,0 @@
1
- import type { Meta, StoryObj } from 'storybook-solidjs-vite';
2
- import { fn } from 'storybook/test';
3
- import { ConversationItem } from './conversation-item';
4
- import { componentDescription } from '../stories/docs/element-controls';
5
-
6
- const baseConversation = {
7
- id: '1',
8
- title: 'How to use SolidJS signals',
9
- messageCount: 8,
10
- lastMessageAt: '2026-04-10T12:00:00Z',
11
- updatedAt: '2026-04-10T12:00:00Z',
12
- scope: { type: 'document' as const },
13
- };
14
-
15
- /**
16
- * A single selectable row in a conversation/chat list: title plus a message
17
- * count, with an active (selected) state.
18
- */
19
- const meta = {
20
- title: 'Solid (Advanced)/Elements/ConversationItem',
21
- component: ConversationItem,
22
- tags: ['autodocs'],
23
- parameters: {
24
- layout: 'padded',
25
- docs: {
26
- description: componentDescription([
27
- 'A single conversation row — shows the title and message count, truncating long titles, with a highlighted active state.',
28
- '**When to use:** as the leaf item inside a chat history sidebar. Usually rendered for you by `ConversationList`; use it directly to build a custom list.',
29
- '**How to use:** pass a `conversation` summary, an `isActive` flag, and an `onSelect(id)` handler fired when the row is clicked.',
30
- '**Placement:** inside a conversation/chat history sidebar list.',
31
- ]),
32
- controls: { exclude: ['use:eventListener'] },
33
- },
34
- },
35
- argTypes: {
36
- conversation: {
37
- control: 'object',
38
- description: 'The conversation summary (id, title, messageCount, scope, timestamps).',
39
- },
40
- isActive: {
41
- control: 'boolean',
42
- description: 'Whether this row is the currently selected conversation.',
43
- },
44
- onSelect: {
45
- action: 'select',
46
- description: 'Fired with the conversation id when the row is clicked.',
47
- table: { category: 'Events' },
48
- },
49
- },
50
- args: {
51
- conversation: baseConversation,
52
- isActive: false,
53
- onSelect: fn(),
54
- },
55
- render: (args) => (
56
- <div class="w-64">
57
- <ConversationItem {...args} />
58
- </div>
59
- ),
60
- } satisfies Meta<typeof ConversationItem>;
61
-
62
- export default meta;
63
- type Story = StoryObj<typeof meta>;
64
-
65
- const IMPORT = `import { ConversationItem } from '@kitn.ai/ui';`;
66
- const src = (code: string) => ({
67
- parameters: { docs: { source: { code: `${IMPORT}\n\n${code}`, language: 'tsx' } } },
68
- });
69
-
70
- /** Interactive playground — toggle `isActive` and edit the conversation object. */
71
- export const Playground: Story = {
72
- ...src(`<ConversationItem conversation={conversation} isActive={false} onSelect={(id) => {}} />`),
73
- };
74
-
75
- export const Active: Story = {
76
- args: { isActive: true },
77
- ...src(`<ConversationItem conversation={conversation} isActive onSelect={(id) => {}} />`),
78
- };
79
-
80
- export const Inactive: Story = {
81
- args: { isActive: false },
82
- ...src(`<ConversationItem conversation={conversation} isActive={false} onSelect={(id) => {}} />`),
83
- };
84
-
85
- export const LongTitle: Story = {
86
- args: {
87
- conversation: {
88
- ...baseConversation,
89
- title: 'This is a very long conversation title that should be truncated with an ellipsis',
90
- },
91
- },
92
- ...src(`<ConversationItem
93
- conversation={{ ...conversation, title: 'A very long title…' }}
94
- isActive={false}
95
- onSelect={(id) => {}}
96
- />`),
97
- };
98
-
99
- /** Several items stacked, one active — showcase. */
100
- export const MultipleItems: Story = {
101
- render: (args: { onSelect: (id: string) => void }) => (
102
- <div class="w-64 space-y-0.5">
103
- <ConversationItem
104
- conversation={{ ...baseConversation, id: '1', title: 'SolidJS reactive primitives' }}
105
- isActive={true}
106
- onSelect={args.onSelect}
107
- />
108
- <ConversationItem
109
- conversation={{ ...baseConversation, id: '2', title: 'TypeScript generics guide', messageCount: 12 }}
110
- isActive={false}
111
- onSelect={args.onSelect}
112
- />
113
- <ConversationItem
114
- conversation={{ ...baseConversation, id: '3', title: 'Tailwind CSS tips and tricks', messageCount: 3 }}
115
- isActive={false}
116
- onSelect={args.onSelect}
117
- />
118
- </div>
119
- ),
120
- ...src(`<div class="space-y-0.5">
121
- <ConversationItem conversation={c1} isActive onSelect={onSelect} />
122
- <ConversationItem conversation={c2} isActive={false} onSelect={onSelect} />
123
- <ConversationItem conversation={c3} isActive={false} onSelect={onSelect} />
124
- </div>`),
125
- };
@@ -1,133 +0,0 @@
1
- import type { Meta, StoryObj } from 'storybook-solidjs-vite';
2
- import { fn } from 'storybook/test';
3
- import { ConversationList, type ConversationListProps } from './conversation-list';
4
- import type { ConversationSummary, ConversationGroup } from '../types';
5
- import { componentDescription } from '../stories/docs/element-controls';
6
-
7
- const scope = { type: 'document' as const };
8
-
9
- const groups: ConversationGroup[] = [
10
- { id: 'today', name: 'Today', sortOrder: 0, createdAt: '2026-04-10' },
11
- { id: 'yesterday', name: 'Yesterday', sortOrder: 1, createdAt: '2026-04-09' },
12
- { id: 'week', name: 'This Week', sortOrder: 2, createdAt: '2026-04-07' },
13
- ];
14
-
15
- const conversations: ConversationSummary[] = [
16
- { id: '1', title: 'SolidJS signals explained', groupId: 'today', scope, messageCount: 5, lastMessageAt: '2026-04-10T14:00:00Z', updatedAt: '2026-04-10T14:00:00Z' },
17
- { id: '2', title: 'TypeScript generics deep dive', groupId: 'today', scope, messageCount: 12, lastMessageAt: '2026-04-10T10:00:00Z', updatedAt: '2026-04-10T10:00:00Z' },
18
- { id: '3', title: 'CSS Grid vs Flexbox', groupId: 'yesterday', scope, messageCount: 8, lastMessageAt: '2026-04-09T16:00:00Z', updatedAt: '2026-04-09T16:00:00Z' },
19
- { id: '4', title: 'Setting up Storybook', groupId: 'yesterday', scope, messageCount: 3, lastMessageAt: '2026-04-09T11:00:00Z', updatedAt: '2026-04-09T11:00:00Z' },
20
- { id: '5', title: 'Vite configuration tips', groupId: 'week', scope, messageCount: 7, lastMessageAt: '2026-04-08T09:00:00Z', updatedAt: '2026-04-08T09:00:00Z' },
21
- { id: '6', title: 'Chrome extension manifest v3', groupId: 'week', scope, messageCount: 15, lastMessageAt: '2026-04-07T14:00:00Z', updatedAt: '2026-04-07T14:00:00Z' },
22
- ];
23
-
24
- /**
25
- * The conversation/chat history sidebar: a header with new-chat action, a search
26
- * box, and grouped, collapsible lists of `ConversationItem`s.
27
- */
28
- const meta = {
29
- title: 'Solid (Advanced)/Elements/ConversationList',
30
- component: ConversationList,
31
- tags: ['autodocs'],
32
- parameters: {
33
- layout: 'padded',
34
- docs: {
35
- description: componentDescription([
36
- 'A full chat-history sidebar: header (sidebar toggle + new chat), a built-in search box that filters by title, and conversations bucketed into collapsible, count-badged groups.',
37
- '**When to use:** as the left-hand navigation for a chat app — browsing, searching, and switching between past conversations.',
38
- '**How to use:** pass `groups` and `conversations` arrays, the `activeId`, and handlers `onSelect(id)` / `onNewChat()` (plus optional `onToggleSidebar()`). Give it a sized, overflow-hidden container.',
39
- '**Placement:** the persistent left sidebar of a chat layout.',
40
- ]),
41
- controls: { exclude: ['use:eventListener'] },
42
- },
43
- },
44
- argTypes: {
45
- groups: {
46
- control: 'object',
47
- description: 'Conversation groups (buckets) to render as collapsible sections.',
48
- },
49
- conversations: {
50
- control: 'object',
51
- description: 'Conversation summaries; placed into groups by their `groupId`.',
52
- },
53
- activeId: {
54
- control: 'text',
55
- description: 'Id of the currently selected conversation.',
56
- },
57
- onSelect: {
58
- action: 'select',
59
- description: 'Fired with the conversation id when a row is clicked.',
60
- table: { category: 'Events' },
61
- },
62
- onNewChat: {
63
- action: 'newChat',
64
- description: 'Fired when the new-chat (+) button is clicked.',
65
- table: { category: 'Events' },
66
- },
67
- onToggleSidebar: {
68
- action: 'toggleSidebar',
69
- description: 'Fired when the sidebar-toggle (menu) button is clicked.',
70
- table: { category: 'Events' },
71
- },
72
- },
73
- args: {
74
- groups,
75
- conversations,
76
- activeId: '1',
77
- onSelect: fn(),
78
- onNewChat: fn(),
79
- onToggleSidebar: fn(),
80
- },
81
- render: (args) => (
82
- <div class="h-[500px] w-72 border border-border rounded-lg overflow-hidden">
83
- <ConversationList {...args} />
84
- </div>
85
- ),
86
- } satisfies Meta<typeof ConversationList>;
87
-
88
- export default meta;
89
- type Story = StoryObj<typeof meta>;
90
-
91
- const IMPORT = `import { ConversationList } from '@kitn.ai/ui';`;
92
- const src = (code: string) => ({
93
- parameters: { docs: { source: { code: `${IMPORT}\n\n${code}`, language: 'tsx' } } },
94
- });
95
-
96
- const usage = `<ConversationList
97
- groups={groups}
98
- conversations={conversations}
99
- activeId={activeId()}
100
- onSelect={setActiveId}
101
- onNewChat={() => {}}
102
- />`;
103
-
104
- /** Interactive playground — edit the groups/conversations arrays and active id via controls. */
105
- export const Playground: Story = {
106
- ...src(usage),
107
- };
108
-
109
- /** Conversations bucketed into Today / Yesterday / This Week. */
110
- export const WithGroups: Story = {
111
- ...src(usage),
112
- };
113
-
114
- /** No conversations — the list renders just its header and search box. */
115
- export const EmptyState: Story = {
116
- args: { groups: [], conversations: [], activeId: undefined },
117
- render: (args: ConversationListProps) => (
118
- <div class="h-[400px] w-72 border border-border rounded-lg overflow-hidden">
119
- <ConversationList {...args} />
120
- </div>
121
- ),
122
- ...src(`<ConversationList
123
- groups={[]}
124
- conversations={[]}
125
- onSelect={() => {}}
126
- onNewChat={() => {}}
127
- />`),
128
- };
129
-
130
- /** Type in the built-in search box to filter conversations by title. */
131
- export const WithSearch: Story = {
132
- ...src(usage),
133
- };
@@ -1,111 +0,0 @@
1
- import { describe, it, expect, afterEach, vi } from 'vitest';
2
- import '@testing-library/jest-dom/vitest';
3
- import { render, cleanup, fireEvent } from '@solidjs/testing-library';
4
- import { createSignal } from 'solid-js';
5
- import { DefaultPromptInput } from '../elements/default-input';
6
-
7
- // jsdom doesn't implement Element.scrollTo; some inner controls may call it.
8
- if (!Element.prototype.scrollTo) (Element.prototype as unknown as { scrollTo: () => void }).scrollTo = () => {};
9
-
10
- afterEach(cleanup);
11
-
12
- const noop = () => {};
13
-
14
- describe('DefaultPromptInput disabled state', () => {
15
- it('renders the textarea and send button as disabled', () => {
16
- const { container } = render(() => (
17
- <DefaultPromptInput
18
- value="hello"
19
- disabled
20
- onValueChange={noop}
21
- onSubmit={noop}
22
- onSuggestionClick={noop}
23
- />
24
- ));
25
- const textarea = container.querySelector('textarea');
26
- const send = container.querySelector('[data-testid="send"]');
27
- expect(textarea).toBeDisabled();
28
- expect(send).toBeDisabled();
29
- });
30
-
31
- it('does not call onSubmit when the send button is clicked while disabled', () => {
32
- const onSubmit = vi.fn();
33
- const { container } = render(() => (
34
- <DefaultPromptInput
35
- value="hello"
36
- disabled
37
- onValueChange={noop}
38
- onSubmit={onSubmit}
39
- onSuggestionClick={noop}
40
- />
41
- ));
42
- const send = container.querySelector('[data-testid="send"]') as HTMLButtonElement;
43
- fireEvent.click(send);
44
- expect(onSubmit).not.toHaveBeenCalled();
45
- });
46
-
47
- it('does not call onSubmit when Enter is pressed while disabled', () => {
48
- const onSubmit = vi.fn();
49
- const { container } = render(() => (
50
- <DefaultPromptInput
51
- value="hello"
52
- disabled
53
- onValueChange={noop}
54
- onSubmit={onSubmit}
55
- onSuggestionClick={noop}
56
- />
57
- ));
58
- const textarea = container.querySelector('textarea') as HTMLTextAreaElement;
59
- fireEvent.keyDown(textarea, { key: 'Enter' });
60
- expect(onSubmit).not.toHaveBeenCalled();
61
- });
62
-
63
- it('reactively disables/enables the textarea when `disabled` changes after mount', () => {
64
- const [disabled, setDisabled] = createSignal(false);
65
- const { container } = render(() => (
66
- <DefaultPromptInput
67
- value="hi"
68
- disabled={disabled()}
69
- onValueChange={noop}
70
- onSubmit={noop}
71
- onSuggestionClick={noop}
72
- />
73
- ));
74
- const textarea = container.querySelector('textarea') as HTMLTextAreaElement;
75
- expect(textarea).not.toBeDisabled();
76
- setDisabled(true);
77
- expect(textarea).toBeDisabled(); // fails if PromptInput context captures `disabled` statically
78
- setDisabled(false);
79
- expect(textarea).not.toBeDisabled();
80
- });
81
-
82
- it('still submits via Enter when not disabled (sanity)', () => {
83
- const onSubmit = vi.fn();
84
- const { container } = render(() => (
85
- <DefaultPromptInput
86
- value="hello"
87
- onValueChange={noop}
88
- onSubmit={onSubmit}
89
- onSuggestionClick={noop}
90
- />
91
- ));
92
- const textarea = container.querySelector('textarea') as HTMLTextAreaElement;
93
- fireEvent.keyDown(textarea, { key: 'Enter' });
94
- expect(onSubmit).toHaveBeenCalledTimes(1);
95
- });
96
- });
97
-
98
- describe('DefaultPromptInput leading/trailing slots', () => {
99
- it('renders a leading and trailing named slot', () => {
100
- const { container } = render(() => (
101
- <DefaultPromptInput
102
- value=""
103
- onValueChange={noop}
104
- onSubmit={noop}
105
- onSuggestionClick={noop}
106
- />
107
- ));
108
- expect(container.querySelector('slot[name="leading"]')).toBeTruthy();
109
- expect(container.querySelector('slot[name="trailing"]')).toBeTruthy();
110
- });
111
- });