@aleph-alpha/chat-kit 3.3.0 → 5.0.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 (189) hide show
  1. package/dist/{CkInput.vue_vue_type_script_setup_true_lang-BAcBFs6I.js → CkHistory.vue_vue_type_script_setup_true_lang-Bp9hXdH6.js} +452 -348
  2. package/dist/adapters/responses-api.d.ts +11 -5
  3. package/dist/adapters/responses-api.d.ts.map +1 -1
  4. package/dist/adapters/responses-api.js +9 -3
  5. package/dist/chat-kit.css +36 -14
  6. package/dist/components/base/CkAgentMessage/CkAgentMessage.stories.d.ts +14 -13
  7. package/dist/components/base/CkAgentMessage/CkAgentMessage.stories.d.ts.map +1 -1
  8. package/dist/components/base/CkAgentMessage/CkAgentMessage.vue.d.ts +8 -7
  9. package/dist/components/base/CkAgentMessage/CkAgentMessage.vue.d.ts.map +1 -1
  10. package/dist/components/base/CkAgentMessage/types.d.ts +16 -5
  11. package/dist/components/base/CkAgentMessage/types.d.ts.map +1 -1
  12. package/dist/components/base/CkAgentMessageHeader/CkAgentMessageHeader.stories.d.ts +16 -0
  13. package/dist/components/base/CkAgentMessageHeader/CkAgentMessageHeader.stories.d.ts.map +1 -0
  14. package/dist/components/base/CkAgentMessageHeader/CkAgentMessageHeader.vue.d.ts +21 -0
  15. package/dist/components/base/CkAgentMessageHeader/CkAgentMessageHeader.vue.d.ts.map +1 -0
  16. package/dist/components/base/CkAgentMessageHeader/index.d.ts +3 -0
  17. package/dist/components/base/CkAgentMessageHeader/index.d.ts.map +1 -0
  18. package/dist/components/base/CkAgentMessageHeader/types.d.ts +22 -0
  19. package/dist/components/base/CkAgentMessageHeader/types.d.ts.map +1 -0
  20. package/dist/components/base/CkCitation/CkCitation.stories.d.ts +6 -0
  21. package/dist/components/base/CkCitation/CkCitation.stories.d.ts.map +1 -1
  22. package/dist/components/base/CkCitation/CkCitation.vue.d.ts.map +1 -1
  23. package/dist/components/base/CkCitationCard/CkCitationCard.stories.d.ts +5 -4
  24. package/dist/components/base/CkCitationCard/CkCitationCard.stories.d.ts.map +1 -1
  25. package/dist/components/base/CkCitationCard/CkCitationCard.vue.d.ts.map +1 -1
  26. package/dist/components/base/{CkCopyMessageActionButton/CkCopyMessageActionButton.stories.d.ts → CkCopyMessageButton/CkCopyMessageButton.stories.d.ts} +3 -3
  27. package/dist/components/base/CkCopyMessageButton/CkCopyMessageButton.stories.d.ts.map +1 -0
  28. package/dist/components/base/{CkCopyMessageActionButton/CkCopyMessageActionButton.vue.d.ts → CkCopyMessageButton/CkCopyMessageButton.vue.d.ts} +4 -4
  29. package/dist/components/base/CkCopyMessageButton/CkCopyMessageButton.vue.d.ts.map +1 -0
  30. package/dist/components/base/CkCopyMessageButton/index.d.ts +3 -0
  31. package/dist/components/base/CkCopyMessageButton/index.d.ts.map +1 -0
  32. package/dist/components/base/{CkCopyMessageActionButton → CkCopyMessageButton}/types.d.ts +3 -3
  33. package/dist/components/base/CkCopyMessageButton/types.d.ts.map +1 -0
  34. package/dist/components/base/CkFeedbackButton/types.d.ts +1 -1
  35. package/dist/components/base/CkFeedbackDialog/types.d.ts +1 -1
  36. package/dist/components/base/CkFileItemsList/CkFileItemsList.stories.d.ts +15 -4
  37. package/dist/components/base/CkFileItemsList/CkFileItemsList.stories.d.ts.map +1 -1
  38. package/dist/components/base/CkFileItemsList/CkFileItemsList.vue.d.ts +2 -1
  39. package/dist/components/base/CkFileItemsList/CkFileItemsList.vue.d.ts.map +1 -1
  40. package/dist/components/base/CkFileItemsList/types.d.ts +17 -4
  41. package/dist/components/base/CkFileItemsList/types.d.ts.map +1 -1
  42. package/dist/components/base/CkHeaderActivityButton/CkHeaderActivityButton.stories.d.ts +19 -0
  43. package/dist/components/base/CkHeaderActivityButton/CkHeaderActivityButton.stories.d.ts.map +1 -0
  44. package/dist/components/base/CkHeaderActivityButton/CkHeaderActivityButton.vue.d.ts +22 -0
  45. package/dist/components/base/CkHeaderActivityButton/CkHeaderActivityButton.vue.d.ts.map +1 -0
  46. package/dist/components/base/CkHeaderActivityButton/index.d.ts +3 -0
  47. package/dist/components/base/CkHeaderActivityButton/index.d.ts.map +1 -0
  48. package/dist/components/base/CkHeaderActivityButton/types.d.ts +36 -0
  49. package/dist/components/base/CkHeaderActivityButton/types.d.ts.map +1 -0
  50. package/dist/components/base/{CkMessageActionButton/CkMessageActionButton.stories.d.ts → CkMessageButton/CkMessageButton.stories.d.ts} +3 -3
  51. package/dist/components/base/CkMessageButton/CkMessageButton.stories.d.ts.map +1 -0
  52. package/dist/components/base/{CkMessageActionButton/CkMessageActionButton.vue.d.ts → CkMessageButton/CkMessageButton.vue.d.ts} +3 -3
  53. package/dist/components/base/CkMessageButton/CkMessageButton.vue.d.ts.map +1 -0
  54. package/dist/components/base/CkMessageButton/index.d.ts +3 -0
  55. package/dist/components/base/CkMessageButton/index.d.ts.map +1 -0
  56. package/dist/components/base/{CkMessageActionButton → CkMessageButton}/types.d.ts +2 -2
  57. package/dist/components/base/CkMessageButton/types.d.ts.map +1 -0
  58. package/dist/components/base/CkPromptInput/CkPromptInput.stories.d.ts +6 -6
  59. package/dist/components/base/CkPromptInput/CkPromptInput.vue.d.ts.map +1 -1
  60. package/dist/components/base/CkPromptInput/types.d.ts +4 -4
  61. package/dist/components/base/CkPromptInputDisclaimer/CkPromptInputDisclaimer.vue.d.ts.map +1 -1
  62. package/dist/components/base/CkPromptInputDisclaimer/types.d.ts +1 -1
  63. package/dist/components/base/CkPromptSendButton/CkPromptSendButton.vue.d.ts +1 -1
  64. package/dist/components/base/CkPromptSendButton/types.d.ts +1 -1
  65. package/dist/components/base/CkPromptStopButton/types.d.ts +1 -1
  66. package/dist/components/base/CkRegenerateMessageButton/CkRegenerateMessageButton.stories.d.ts +16 -0
  67. package/dist/components/base/CkRegenerateMessageButton/CkRegenerateMessageButton.stories.d.ts.map +1 -0
  68. package/dist/components/base/CkRegenerateMessageButton/CkRegenerateMessageButton.vue.d.ts +12 -0
  69. package/dist/components/base/CkRegenerateMessageButton/CkRegenerateMessageButton.vue.d.ts.map +1 -0
  70. package/dist/components/base/CkRegenerateMessageButton/index.d.ts +3 -0
  71. package/dist/components/base/{CkCopyMessageActionButton → CkRegenerateMessageButton}/index.d.ts.map +1 -1
  72. package/dist/components/base/CkRegenerateMessageButton/types.d.ts +27 -0
  73. package/dist/components/base/CkRegenerateMessageButton/types.d.ts.map +1 -0
  74. package/dist/components/base/index.d.ts +7 -2
  75. package/dist/components/base/index.d.ts.map +1 -1
  76. package/dist/components/composed/CkConversation/CkConversation.stories.d.ts +1 -1
  77. package/dist/components/composed/CkConversation/CkConversation.vue.d.ts +13 -1
  78. package/dist/components/composed/CkConversation/CkConversation.vue.d.ts.map +1 -1
  79. package/dist/components/composed/CkConversation/types.d.ts +1 -1
  80. package/dist/components/composed/index.d.ts +0 -1
  81. package/dist/components/composed/index.d.ts.map +1 -1
  82. package/dist/components/index.d.ts +3 -3
  83. package/dist/components/index.d.ts.map +1 -1
  84. package/dist/components/index.js +26 -24
  85. package/dist/composables/index.js +1 -1
  86. package/dist/handlers/index.js +2 -2
  87. package/dist/handlers/useChatKitLabels.d.ts +2 -0
  88. package/dist/handlers/useChatKitLabels.d.ts.map +1 -1
  89. package/dist/handlers/useMessageHandler.d.ts +37 -0
  90. package/dist/handlers/useMessageHandler.d.ts.map +1 -1
  91. package/dist/helpers/conversationTree.d.ts +15 -0
  92. package/dist/helpers/conversationTree.d.ts.map +1 -1
  93. package/dist/{index-C6njJ8EB.js → index-CyrVnbS9.js} +1 -1
  94. package/dist/index.d.ts +2 -2
  95. package/dist/index.d.ts.map +1 -1
  96. package/dist/index.js +30 -28
  97. package/dist/{useChatKitLabels-BM2I7-9o.js → useChatKitLabels-zMFV7aEz.js} +1 -0
  98. package/dist/{useMessageHandler-CMdy-lm0.js → useMessageHandler-N50Yj-NU.js} +45 -7
  99. package/package.json +3 -3
  100. package/src/adapters/responses-api.spec.ts +52 -5
  101. package/src/adapters/responses-api.ts +26 -7
  102. package/src/components/base/CkAgentMessage/CkAgentMessage.spec.ts +12 -17
  103. package/src/components/base/CkAgentMessage/CkAgentMessage.stories.ts +124 -113
  104. package/src/components/base/CkAgentMessage/CkAgentMessage.vue +18 -16
  105. package/src/components/base/CkAgentMessage/types.ts +16 -5
  106. package/src/components/base/CkAgentMessageHeader/CkAgentMessageHeader.spec.ts +64 -0
  107. package/src/components/base/CkAgentMessageHeader/CkAgentMessageHeader.stories.ts +90 -0
  108. package/src/components/base/CkAgentMessageHeader/CkAgentMessageHeader.vue +47 -0
  109. package/src/components/base/CkAgentMessageHeader/index.ts +2 -0
  110. package/src/components/base/CkAgentMessageHeader/types.ts +21 -0
  111. package/src/components/base/CkCitation/CkCitation.stories.ts +12 -0
  112. package/src/components/base/CkCitation/CkCitation.vue +34 -9
  113. package/src/components/base/CkCitationCard/CkCitationCard.stories.ts +5 -4
  114. package/src/components/base/CkCitationCard/CkCitationCard.vue +2 -2
  115. package/src/components/base/CkConversationLayout/CkConversationLayout.vue +1 -1
  116. package/src/components/base/{CkCopyMessageActionButton/CkCopyMessageActionButton.spec.ts → CkCopyMessageButton/CkCopyMessageButton.spec.ts} +6 -6
  117. package/src/components/base/{CkCopyMessageActionButton/CkCopyMessageActionButton.stories.ts → CkCopyMessageButton/CkCopyMessageButton.stories.ts} +8 -8
  118. package/src/components/base/{CkCopyMessageActionButton/CkCopyMessageActionButton.vue → CkCopyMessageButton/CkCopyMessageButton.vue} +6 -6
  119. package/src/components/base/CkCopyMessageButton/index.ts +2 -0
  120. package/src/components/base/{CkCopyMessageActionButton → CkCopyMessageButton}/types.ts +3 -3
  121. package/src/components/base/CkFeedbackButton/CkFeedbackButton.vue +5 -5
  122. package/src/components/base/CkFeedbackButton/types.ts +1 -1
  123. package/src/components/base/CkFeedbackDialog/types.ts +1 -1
  124. package/src/components/base/CkFileItemsList/CkFileItemsList.spec.ts +88 -13
  125. package/src/components/base/CkFileItemsList/CkFileItemsList.stories.ts +61 -13
  126. package/src/components/base/CkFileItemsList/CkFileItemsList.vue +153 -110
  127. package/src/components/base/CkFileItemsList/types.ts +17 -4
  128. package/src/components/base/CkHeaderActivityButton/CkHeaderActivityButton.spec.ts +50 -0
  129. package/src/components/base/CkHeaderActivityButton/CkHeaderActivityButton.stories.ts +102 -0
  130. package/src/components/base/CkHeaderActivityButton/CkHeaderActivityButton.vue +39 -0
  131. package/src/components/base/CkHeaderActivityButton/index.ts +2 -0
  132. package/src/components/base/CkHeaderActivityButton/types.ts +36 -0
  133. package/src/components/base/{CkMessageActionButton/CkMessageActionButton.spec.ts → CkMessageButton/CkMessageButton.spec.ts} +6 -6
  134. package/src/components/base/{CkMessageActionButton/CkMessageActionButton.stories.ts → CkMessageButton/CkMessageButton.stories.ts} +10 -10
  135. package/src/components/base/{CkMessageActionButton/CkMessageActionButton.vue → CkMessageButton/CkMessageButton.vue} +3 -3
  136. package/src/components/base/CkMessageButton/index.ts +2 -0
  137. package/src/components/base/{CkMessageActionButton → CkMessageButton}/types.ts +2 -2
  138. package/src/components/base/CkPromptInput/CkPromptInput.spec.ts +88 -0
  139. package/src/components/base/CkPromptInput/CkPromptInput.stories.ts +6 -6
  140. package/src/components/base/CkPromptInput/CkPromptInput.vue +63 -12
  141. package/src/components/base/CkPromptInput/types.ts +4 -4
  142. package/src/components/base/CkPromptInputDisclaimer/CkPromptInputDisclaimer.spec.ts +1 -1
  143. package/src/components/base/CkPromptInputDisclaimer/CkPromptInputDisclaimer.vue +1 -1
  144. package/src/components/base/CkPromptInputDisclaimer/types.ts +1 -1
  145. package/src/components/base/CkPromptSendButton/types.ts +1 -1
  146. package/src/components/base/CkPromptStopButton/types.ts +1 -1
  147. package/src/components/base/CkRegenerateMessageButton/CkRegenerateMessageButton.spec.ts +49 -0
  148. package/src/components/base/CkRegenerateMessageButton/CkRegenerateMessageButton.stories.ts +63 -0
  149. package/src/components/base/CkRegenerateMessageButton/CkRegenerateMessageButton.vue +43 -0
  150. package/src/components/base/CkRegenerateMessageButton/index.ts +2 -0
  151. package/src/components/base/CkRegenerateMessageButton/types.ts +27 -0
  152. package/src/components/base/index.ts +10 -2
  153. package/src/components/composed/CkConversation/CkConversation.spec.ts +81 -6
  154. package/src/components/composed/CkConversation/CkConversation.stories.ts +6 -6
  155. package/src/components/composed/CkConversation/CkConversation.vue +80 -37
  156. package/src/components/composed/CkConversation/types.ts +1 -1
  157. package/src/components/composed/index.ts +0 -1
  158. package/src/components/index.ts +9 -3
  159. package/src/handlers/useChatKitLabels.spec.ts +1 -0
  160. package/src/handlers/useChatKitLabels.ts +3 -0
  161. package/src/handlers/useMessageHandler.spec.ts +79 -0
  162. package/src/handlers/useMessageHandler.ts +50 -2
  163. package/src/helpers/conversationTree.spec.ts +120 -0
  164. package/src/helpers/conversationTree.ts +57 -8
  165. package/src/index.ts +8 -3
  166. package/dist/components/base/CkCopyMessageActionButton/CkCopyMessageActionButton.stories.d.ts.map +0 -1
  167. package/dist/components/base/CkCopyMessageActionButton/CkCopyMessageActionButton.vue.d.ts.map +0 -1
  168. package/dist/components/base/CkCopyMessageActionButton/index.d.ts +0 -3
  169. package/dist/components/base/CkCopyMessageActionButton/types.d.ts.map +0 -1
  170. package/dist/components/base/CkMessageActionButton/CkMessageActionButton.stories.d.ts.map +0 -1
  171. package/dist/components/base/CkMessageActionButton/CkMessageActionButton.vue.d.ts.map +0 -1
  172. package/dist/components/base/CkMessageActionButton/index.d.ts +0 -3
  173. package/dist/components/base/CkMessageActionButton/index.d.ts.map +0 -1
  174. package/dist/components/base/CkMessageActionButton/types.d.ts.map +0 -1
  175. package/dist/components/composed/CkInput/CkInput.stories.d.ts +0 -43
  176. package/dist/components/composed/CkInput/CkInput.stories.d.ts.map +0 -1
  177. package/dist/components/composed/CkInput/CkInput.vue.d.ts +0 -50
  178. package/dist/components/composed/CkInput/CkInput.vue.d.ts.map +0 -1
  179. package/dist/components/composed/CkInput/index.d.ts +0 -3
  180. package/dist/components/composed/CkInput/index.d.ts.map +0 -1
  181. package/dist/components/composed/CkInput/types.d.ts +0 -55
  182. package/dist/components/composed/CkInput/types.d.ts.map +0 -1
  183. package/src/components/base/CkCopyMessageActionButton/index.ts +0 -2
  184. package/src/components/base/CkMessageActionButton/index.ts +0 -2
  185. package/src/components/composed/CkInput/CkInput.spec.ts +0 -191
  186. package/src/components/composed/CkInput/CkInput.stories.ts +0 -434
  187. package/src/components/composed/CkInput/CkInput.vue +0 -106
  188. package/src/components/composed/CkInput/index.ts +0 -2
  189. package/src/components/composed/CkInput/types.ts +0 -55
@@ -1,191 +0,0 @@
1
- import CkInput from './CkInput.vue';
2
- import { render, screen, fireEvent } from '@testing-library/vue';
3
-
4
- describe('CkInput', () => {
5
- describe('defaults', () => {
6
- it('renders default placeholder', () => {
7
- render(CkInput);
8
-
9
- expect(
10
- screen.getByPlaceholderText('Ask me anything'),
11
- ).toBeInTheDocument();
12
- });
13
-
14
- it('renders default aria label', () => {
15
- render(CkInput);
16
-
17
- expect(screen.getByLabelText('Chat message input')).toBeInTheDocument();
18
- });
19
-
20
- it('renders default send button', () => {
21
- render(CkInput);
22
-
23
- expect(
24
- screen.getByRole('button', { name: 'Send message' }),
25
- ).toBeInTheDocument();
26
- });
27
- });
28
-
29
- describe('disclaimer', () => {
30
- it('renders disclaimer text when provided', () => {
31
- render(CkInput, {
32
- props: { disclaimer: 'AI may make mistakes' },
33
- });
34
-
35
- expect(screen.getByText('AI may make mistakes')).toBeInTheDocument();
36
- });
37
-
38
- it('does not render disclaimer when not provided', () => {
39
- const { container } = render(CkInput);
40
-
41
- expect(container.querySelector('p')).not.toBeInTheDocument();
42
- });
43
- });
44
-
45
- describe('v-model', () => {
46
- it('displays the modelValue in the textarea', () => {
47
- render(CkInput, { props: { modelValue: 'Hello world' } });
48
-
49
- expect(screen.getByRole('textbox')).toHaveValue('Hello world');
50
- });
51
-
52
- it('emits update:modelValue on input', async () => {
53
- const { emitted } = render(CkInput);
54
-
55
- await fireEvent.update(screen.getByRole('textbox'), 'New text');
56
-
57
- expect(emitted()['update:modelValue']).toBeTruthy();
58
- expect(emitted()['update:modelValue'][0]).toEqual(['New text']);
59
- });
60
- });
61
-
62
- describe('submit', () => {
63
- it('emits submit with trimmed text on Enter key', async () => {
64
- const { emitted } = render(CkInput, {
65
- props: { modelValue: ' Hello ' },
66
- });
67
-
68
- await fireEvent.keyDown(screen.getByRole('textbox'), { key: 'Enter' });
69
-
70
- expect(emitted().submit).toBeTruthy();
71
- expect(emitted().submit[0]).toEqual(['Hello']);
72
- });
73
-
74
- it('does not emit submit when textarea is empty', async () => {
75
- const { emitted } = render(CkInput, {
76
- props: { modelValue: '' },
77
- });
78
-
79
- await fireEvent.keyDown(screen.getByRole('textbox'), { key: 'Enter' });
80
-
81
- expect(emitted().submit).toBeFalsy();
82
- });
83
- });
84
-
85
- describe('loading state', () => {
86
- it('disables the textarea when loading', () => {
87
- render(CkInput, { props: { loading: true } });
88
-
89
- expect(screen.getByRole('textbox')).toBeDisabled();
90
- });
91
-
92
- it('does not emit submit when loading', async () => {
93
- const { emitted } = render(CkInput, {
94
- props: { modelValue: 'Hello', loading: true },
95
- });
96
-
97
- await fireEvent.keyDown(screen.getByRole('textbox'), { key: 'Enter' });
98
-
99
- expect(emitted().submit).toBeFalsy();
100
- });
101
-
102
- it('shows stop control instead of send when loading', () => {
103
- render(CkInput, { props: { modelValue: 'Hello', loading: true } });
104
-
105
- expect(
106
- screen.queryByRole('button', { name: 'Send message' }),
107
- ).not.toBeInTheDocument();
108
- expect(
109
- screen.getByRole('button', { name: 'Stop generating' }),
110
- ).toBeInTheDocument();
111
- });
112
-
113
- it('emits stop when stop control is clicked while loading', async () => {
114
- const { emitted } = render(CkInput, {
115
- props: { modelValue: 'Hello', loading: true },
116
- });
117
-
118
- await fireEvent.click(
119
- screen.getByRole('button', { name: 'Stop generating' }),
120
- );
121
-
122
- expect(emitted().stop).toBeTruthy();
123
- });
124
- });
125
-
126
- describe('disabled state', () => {
127
- it('disables the textarea when disabled', () => {
128
- render(CkInput, { props: { disabled: true } });
129
-
130
- expect(screen.getByRole('textbox')).toBeDisabled();
131
- });
132
-
133
- it('disables the send button when textarea is empty', () => {
134
- render(CkInput, { props: { modelValue: '' } });
135
-
136
- expect(
137
- screen.getByRole('button', { name: 'Send message' }),
138
- ).toBeDisabled();
139
- });
140
-
141
- it('enables the send button when there is text and not disabled', () => {
142
- render(CkInput, { props: { modelValue: 'Hello' } });
143
-
144
- expect(
145
- screen.getByRole('button', { name: 'Send message' }),
146
- ).toBeEnabled();
147
- });
148
- });
149
-
150
- describe('slots', () => {
151
- it('renders toolbar-left slot content', () => {
152
- render(CkInput, {
153
- slots: { 'toolbar-left': '<button>Express</button>' },
154
- });
155
-
156
- expect(screen.getByText('Express')).toBeInTheDocument();
157
- });
158
-
159
- it('renders toolbar-right slot content instead of default send button', () => {
160
- render(CkInput, {
161
- slots: { 'toolbar-right': '<button>Custom Send</button>' },
162
- });
163
-
164
- expect(screen.getByText('Custom Send')).toBeInTheDocument();
165
- expect(
166
- screen.queryByRole('button', { name: 'Send message' }),
167
- ).not.toBeInTheDocument();
168
- });
169
-
170
- it('renders footer slot content instead of disclaimer', () => {
171
- render(CkInput, {
172
- props: { disclaimer: 'Default disclaimer' },
173
- slots: { footer: '<span>Custom footer</span>' },
174
- });
175
-
176
- expect(screen.getByText('Custom footer')).toBeInTheDocument();
177
- expect(screen.queryByText('Default disclaimer')).not.toBeInTheDocument();
178
- });
179
-
180
- it('renders send-icon slot content inside default send button', () => {
181
- render(CkInput, {
182
- slots: { 'send-icon': '<span data-testid="custom-icon">Go</span>' },
183
- });
184
-
185
- expect(screen.getByTestId('custom-icon')).toBeInTheDocument();
186
- expect(
187
- screen.getByRole('button', { name: 'Send message' }),
188
- ).toBeInTheDocument();
189
- });
190
- });
191
- });
@@ -1,434 +0,0 @@
1
- import CkInput from './CkInput.vue';
2
- import type { Meta, StoryObj } from '@storybook/vue3-vite';
3
- import { ref } from 'vue';
4
-
5
- const DISCLAIMER =
6
- 'Assistant Chat may occasionally make mistakes. Please, make sure to double-check important information.';
7
-
8
- const meta: Meta<typeof CkInput> = {
9
- title: 'Composed/CkInput',
10
- component: CkInput,
11
- tags: ['autodocs'],
12
- argTypes: {
13
- modelValue: {
14
- control: 'text',
15
- description: 'Current value of the input. Use with `v-model`.',
16
- },
17
- placeholder: {
18
- control: 'text',
19
- description: 'Placeholder shown when empty.',
20
- },
21
- disabled: {
22
- control: 'boolean',
23
- description: 'Disables the input and send button.',
24
- },
25
- loading: {
26
- control: 'boolean',
27
- description:
28
- 'Shows a spinner in the send button and blocks further input.',
29
- },
30
- ariaLabel: {
31
- control: 'text',
32
- description: 'Accessible label for the textarea.',
33
- },
34
- disclaimer: {
35
- control: 'text',
36
- description: 'Optional disclaimer text rendered below the input.',
37
- },
38
- },
39
- decorators: [
40
- () => ({
41
- template:
42
- '<div style="max-width: 640px; margin: 0 auto; padding: 24px;"><story /></div>',
43
- }),
44
- ],
45
- };
46
-
47
- export default meta;
48
- type Story = StoryObj<typeof meta>;
49
-
50
- const defaultTemplateSource = `<script setup lang="ts">
51
- import { CkInput } from '@aleph-alpha/chat-kit';
52
- import { ref } from 'vue';
53
-
54
- const text = ref('');
55
- const disclaimer = 'Assistant Chat may occasionally make mistakes. Please double-check.';
56
- </script>
57
-
58
- <template>
59
- <CkInput v-model="text" :disclaimer="disclaimer" />
60
- </template>`;
61
-
62
- const withModeToggleTemplateSource = `<script setup lang="ts">
63
- import { CkInput } from '@aleph-alpha/chat-kit';
64
- import { ref } from 'vue';
65
-
66
- const text = ref('');
67
- const mode = ref<'express' | 'smart'>('smart');
68
- </script>
69
-
70
- <template>
71
- <CkInput v-model="text">
72
- <template #toolbar-left>
73
- <div class="flex items-center gap-1">
74
- <button @click="mode = 'express'">Express</button>
75
- <button @click="mode = 'smart'">Smart</button>
76
- </div>
77
- </template>
78
- </CkInput>
79
- </template>`;
80
-
81
- const fullExampleTemplateSource = `<script setup lang="ts">
82
- import { CkInput } from '@aleph-alpha/chat-kit';
83
- import { ref } from 'vue';
84
-
85
- const text = ref('');
86
- const attachmentCount = ref(3);
87
- const disclaimer = 'Assistant Chat may occasionally make mistakes. Please double-check.';
88
- function onSubmit() { text.value = ''; }
89
- </script>
90
-
91
- <template>
92
- <CkInput v-model="text" :disclaimer="disclaimer" @submit="onSubmit">
93
- <template #toolbar-left>
94
- <button>Mode</button>
95
- </template>
96
- <template #toolbar-right="{ submit, disabled }">
97
- <button aria-label="Attach file">Attach ({{ attachmentCount }})</button>
98
- <button type="submit" :disabled="disabled" @click="submit" aria-label="Send message">Send</button>
99
- </template>
100
- </CkInput>
101
- </template>`;
102
-
103
- const disabledTemplateSource = `<script setup lang="ts">
104
- import { CkInput } from '@aleph-alpha/chat-kit';
105
- import { ref } from 'vue';
106
-
107
- const text = ref('');
108
- </script>
109
-
110
- <template>
111
- <CkInput v-model="text" disabled placeholder="Input is disabled" />
112
- </template>`;
113
-
114
- const loadingTemplateSource = `<script setup lang="ts">
115
- import { CkInput } from '@aleph-alpha/chat-kit';
116
- import { ref } from 'vue';
117
-
118
- const text = ref('Generating a response...');
119
- </script>
120
-
121
- <template>
122
- <CkInput v-model="text" loading />
123
- </template>`;
124
-
125
- const withLongTextTemplateSource = `<script setup lang="ts">
126
- import { CkInput } from '@aleph-alpha/chat-kit';
127
- import { ref } from 'vue';
128
-
129
- const text = ref('This is a long multi-line message that demonstrates auto-grow behavior.');
130
- </script>
131
-
132
- <template>
133
- <CkInput v-model="text" />
134
- </template>`;
135
-
136
- const mobileWidthTemplateSource = `<script setup lang="ts">
137
- import { CkInput } from '@aleph-alpha/chat-kit';
138
- import { ref } from 'vue';
139
-
140
- const text = ref('');
141
- </script>
142
-
143
- <template>
144
- <div style="max-width: 320px;">
145
- <CkInput v-model="text" />
146
- </div>
147
- </template>`;
148
-
149
- /**
150
- * Default chat input with disclaimer and the built-in send button.
151
- * Use as the primary way to let users submit a prompt to the assistant.
152
- */
153
- export const Default: Story = {
154
- render: () => ({
155
- components: { CkInput },
156
- setup() {
157
- const text = ref('');
158
- return { text, DISCLAIMER };
159
- },
160
- template: `
161
- <CkInput
162
- v-model="text"
163
- :disclaimer="DISCLAIMER"
164
- />
165
- `,
166
- }),
167
- parameters: { docs: { source: { code: defaultTemplateSource } } },
168
- };
169
-
170
- /**
171
- * Adds a mode toggle (Express/Smart) to the left side of the toolbar via
172
- * `#toolbar-left`. Use when the user needs to switch between assistant
173
- * presets or capabilities before submitting.
174
- */
175
- export const WithModeToggle: Story = {
176
- render: () => ({
177
- components: { CkInput },
178
- setup() {
179
- const text = ref('');
180
- const mode = ref<'express' | 'smart'>('smart');
181
- return { text, mode };
182
- },
183
- template: `
184
- <CkInput v-model="text">
185
- <template #toolbar-left>
186
- <div class="flex items-center">
187
- <button
188
- class="flex items-center justify-center rounded-l-md border border-solid h-9 px-2 text-sm font-medium shadow-sm transition-all duration-300 ease-in-out"
189
- :style="mode === 'express'
190
- ? 'background-color: #2888b8; border-color: rgba(183,180,164,0.3); color: #daf2f6;'
191
- : 'background-color: #ebebe5; border-color: rgba(183,180,164,0.3); color: #1d1d1b;'"
192
- @click="mode = 'express'"
193
- >
194
- <svg class="shrink-0" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z"/></svg>
195
- <span
196
- class="overflow-hidden whitespace-nowrap transition-all duration-300 ease-in-out"
197
- :style="mode === 'express'
198
- ? 'max-width: 70px; opacity: 1; padding-left: 8px;'
199
- : 'max-width: 0; opacity: 0; padding-left: 0;'"
200
- >Express</span>
201
- </button>
202
- <button
203
- class="flex items-center justify-center rounded-r-md border-t border-r border-b border-solid h-9 px-2 text-sm font-medium shadow-sm transition-all duration-300 ease-in-out"
204
- :style="mode === 'smart'
205
- ? 'background-color: #2888b8; border-color: rgba(183,180,164,0.3); color: #daf2f6;'
206
- : 'background-color: #ebebe5; border-color: rgba(183,180,164,0.3); color: #1d1d1b;'"
207
- @click="mode = 'smart'"
208
- >
209
- <svg class="shrink-0" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5"/><path d="M9 18h6"/><path d="M10 22h4"/></svg>
210
- <span
211
- class="overflow-hidden whitespace-nowrap transition-all duration-300 ease-in-out"
212
- :style="mode === 'smart'
213
- ? 'max-width: 70px; opacity: 1; padding-left: 8px;'
214
- : 'max-width: 0; opacity: 0; padding-left: 0;'"
215
- >Smart</span>
216
- </button>
217
- </div>
218
- </template>
219
- </CkInput>
220
- `,
221
- }),
222
- parameters: { docs: { source: { code: withModeToggleTemplateSource } } },
223
- };
224
-
225
- /**
226
- * End-to-end example: mode toggle on the left, attachment button + custom
227
- * send button on the right, and a disclaimer underneath. Use as a reference
228
- * for a production-ready chat compose UI.
229
- */
230
- export const FullExample: Story = {
231
- render: () => ({
232
- components: { CkInput },
233
- setup() {
234
- const text = ref('');
235
- const mode = ref<'express' | 'smart'>('smart');
236
- const attachmentCount = ref(3);
237
- const onSubmit = () => {
238
- text.value = '';
239
- };
240
- return { text, mode, attachmentCount, onSubmit, DISCLAIMER };
241
- },
242
- template: `
243
- <CkInput
244
- v-model="text"
245
- :disclaimer="DISCLAIMER"
246
- @submit="onSubmit"
247
- >
248
- <template #toolbar-left>
249
- <div class="flex items-center">
250
- <button
251
- class="flex items-center justify-center rounded-l-md border border-solid h-9 px-2 text-sm font-medium shadow-sm transition-all duration-300 ease-in-out"
252
- :style="mode === 'express'
253
- ? 'background-color: #2888b8; border-color: rgba(183,180,164,0.3); color: #daf2f6;'
254
- : 'background-color: #ebebe5; border-color: rgba(183,180,164,0.3); color: #1d1d1b;'"
255
- @click="mode = 'express'"
256
- >
257
- <svg class="shrink-0" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z"/></svg>
258
- <span
259
- class="overflow-hidden whitespace-nowrap transition-all duration-300 ease-in-out"
260
- :style="mode === 'express'
261
- ? 'max-width: 70px; opacity: 1; padding-left: 8px;'
262
- : 'max-width: 0; opacity: 0; padding-left: 0;'"
263
- >Express</span>
264
- </button>
265
- <button
266
- class="flex items-center justify-center rounded-r-md border-t border-r border-b border-solid h-9 px-2 text-sm font-medium shadow-sm transition-all duration-300 ease-in-out"
267
- :style="mode === 'smart'
268
- ? 'background-color: #2888b8; border-color: rgba(183,180,164,0.3); color: #daf2f6;'
269
- : 'background-color: #ebebe5; border-color: rgba(183,180,164,0.3); color: #1d1d1b;'"
270
- @click="mode = 'smart'"
271
- >
272
- <svg class="shrink-0" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5"/><path d="M9 18h6"/><path d="M10 22h4"/></svg>
273
- <span
274
- class="overflow-hidden whitespace-nowrap transition-all duration-300 ease-in-out"
275
- :style="mode === 'smart'
276
- ? 'max-width: 70px; opacity: 1; padding-left: 8px;'
277
- : 'max-width: 0; opacity: 0; padding-left: 0;'"
278
- >Smart</span>
279
- </button>
280
- </div>
281
- </template>
282
- <template #toolbar-right="{ submit, disabled }">
283
- <div class="flex items-center gap-2">
284
- <button
285
- type="button"
286
- class="flex items-center gap-2 rounded-md border border-solid px-4 py-2 h-9"
287
- style="border-color: rgba(183, 180, 164, 0.3);"
288
- aria-label="Attach file"
289
- >
290
- <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m21.44 11.05-9.19 9.19a6 6 0 0 1-8.49-8.49l8.57-8.57A4 4 0 1 1 18 8.84l-8.59 8.57a2 2 0 0 1-2.83-2.83l8.49-8.48"/></svg>
291
- <span
292
- v-if="attachmentCount > 0"
293
- class="flex items-center justify-center rounded-full min-w-5 h-4 px-1 text-xs"
294
- style="background-color: #c9e400; color: #252422;"
295
- >
296
- {{ attachmentCount }}
297
- </span>
298
- </button>
299
- <button
300
- type="submit"
301
- :disabled="disabled"
302
- class="flex items-center justify-center size-9 rounded-md disabled:opacity-50"
303
- style="background-color: #c9e400; color: #1d1d1b;"
304
- aria-label="Send message"
305
- @click="submit"
306
- >
307
- <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3.714 3.048a.498.498 0 0 0-.683.627l2.843 7.627a2 2 0 0 1 0 1.396l-2.842 7.627a.498.498 0 0 0 .682.627l18-8.5a.5.5 0 0 0 0-.904z"/><path d="M6 12h16"/></svg>
308
- </button>
309
- </div>
310
- </template>
311
- </CkInput>
312
- `,
313
- }),
314
- decorators: [
315
- () => ({
316
- template:
317
- '<div style="max-width: 640px; margin: 0 auto; padding: 24px; background: #ebebe5; min-height: 300px; border-radius: 12px;"><story /></div>',
318
- }),
319
- ],
320
- parameters: { docs: { source: { code: fullExampleTemplateSource } } },
321
- };
322
-
323
- /**
324
- * Disabled state — the textarea is read-only and the send button is inactive.
325
- * Use while waiting for an upstream action to resolve.
326
- */
327
- export const Disabled: Story = {
328
- render: () => ({
329
- components: { CkInput },
330
- setup() {
331
- const text = ref('');
332
- return { text, DISCLAIMER };
333
- },
334
- template: `
335
- <CkInput
336
- v-model="text"
337
- disabled
338
- placeholder="Input is disabled"
339
- :disclaimer="DISCLAIMER"
340
- />
341
- `,
342
- }),
343
- parameters: { docs: { source: { code: disabledTemplateSource } } },
344
- };
345
-
346
- /**
347
- * Loading state — shown while the assistant is generating a reply. The
348
- * send button displays a spinner and the input is blocked.
349
- */
350
- export const Loading: Story = {
351
- render: () => ({
352
- components: { CkInput },
353
- setup() {
354
- const text = ref('Generating a response...');
355
- const loading = ref(true);
356
- function onSubmit() {
357
- text.value = 'Generating a response...';
358
- loading.value = true;
359
- }
360
- function onStop() {
361
- text.value = 'Response stopped';
362
- loading.value = false;
363
- }
364
- return { text, loading, DISCLAIMER, onSubmit, onStop };
365
- },
366
- template: `
367
- <CkInput
368
- v-model="text"
369
- :loading="loading"
370
- :disclaimer="DISCLAIMER"
371
- @submit="onSubmit"
372
- @stop="onStop"
373
- />
374
- `,
375
- }),
376
- parameters: { docs: { source: { code: loadingTemplateSource } } },
377
- };
378
-
379
- /**
380
- * Demonstrates the textarea's auto-grow behavior with multi-paragraph content.
381
- * Use when validating how the input handles long prompts.
382
- */
383
- export const WithLongText: Story = {
384
- render: () => ({
385
- components: { CkInput },
386
- setup() {
387
- const text = ref(
388
- 'This is a long message that demonstrates the auto-grow behavior of the textarea. ' +
389
- 'As the content grows, the textarea expands up to the maximum height. ' +
390
- 'Once the max height is reached, the content becomes scrollable.\n\n' +
391
- 'Here is a second paragraph to show how multi-line content works. ' +
392
- 'The component handles newlines naturally with Shift+Enter.\n\n' +
393
- 'And a third paragraph for good measure. The auto-grow logic recalculates ' +
394
- 'the height on every input event and when the modelValue changes externally.',
395
- );
396
- return { text, DISCLAIMER };
397
- },
398
- template: `
399
- <CkInput
400
- v-model="text"
401
- :disclaimer="DISCLAIMER"
402
- />
403
- `,
404
- }),
405
- parameters: { docs: { source: { code: withLongTextTemplateSource } } },
406
- };
407
-
408
- /**
409
- * Narrow viewport preview (≈320px). Use to verify the input stays usable on
410
- * small screens.
411
- */
412
- export const MobileWidth: Story = {
413
- render: () => ({
414
- components: { CkInput },
415
- setup() {
416
- const text = ref('');
417
- return { text, DISCLAIMER };
418
- },
419
- template: `
420
- <div style="max-width: 320px;">
421
- <CkInput
422
- v-model="text"
423
- :disclaimer="DISCLAIMER"
424
- />
425
- </div>
426
- `,
427
- }),
428
- decorators: [
429
- () => ({
430
- template: '<div style="padding: 16px;"><story /></div>',
431
- }),
432
- ],
433
- parameters: { docs: { source: { code: mobileWidthTemplateSource } } },
434
- };