@aleph-alpha/chat-kit 2.2.0 → 3.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.
- package/dist/{CkInput.vue_vue_type_script_setup_true_lang-CjfKRuZs.js → CkInput.vue_vue_type_script_setup_true_lang-CwH5M5WD.js} +263 -142
- package/dist/chat-kit.css +33 -6
- package/dist/components/base/CkDropZoneOverlay/CkDropZoneOverlay.vue.d.ts.map +1 -1
- package/dist/components/base/CkFileItemsList/CkFileItemsList.stories.d.ts +7 -0
- package/dist/components/base/CkFileItemsList/CkFileItemsList.stories.d.ts.map +1 -1
- package/dist/components/base/CkFileItemsList/CkFileItemsList.vue.d.ts +1 -0
- package/dist/components/base/CkFileItemsList/CkFileItemsList.vue.d.ts.map +1 -1
- package/dist/components/base/CkFileItemsList/types.d.ts +9 -0
- package/dist/components/base/CkFileItemsList/types.d.ts.map +1 -1
- package/dist/components/base/CkModelSelector/types.d.ts +1 -1
- package/dist/components/base/CkPromptInput/CkPromptInput.stories.d.ts +48 -5
- package/dist/components/base/CkPromptInput/CkPromptInput.stories.d.ts.map +1 -1
- package/dist/components/base/CkPromptInput/CkPromptInput.vue.d.ts +7 -6
- package/dist/components/base/CkPromptInput/CkPromptInput.vue.d.ts.map +1 -1
- package/dist/components/base/CkPromptInput/types.d.ts +11 -12
- package/dist/components/base/CkPromptInput/types.d.ts.map +1 -1
- package/dist/components/base/CkPromptMenuButton/CkPromptMenuButton.stories.d.ts +18 -0
- package/dist/components/base/CkPromptMenuButton/CkPromptMenuButton.stories.d.ts.map +1 -0
- package/dist/components/base/CkPromptMenuButton/CkPromptMenuButton.vue.d.ts +18 -0
- package/dist/components/base/CkPromptMenuButton/CkPromptMenuButton.vue.d.ts.map +1 -0
- package/dist/components/base/CkPromptMenuButton/index.d.ts +3 -0
- package/dist/components/base/CkPromptMenuButton/index.d.ts.map +1 -0
- package/dist/components/base/CkPromptMenuButton/types.d.ts +30 -0
- package/dist/components/base/CkPromptMenuButton/types.d.ts.map +1 -0
- package/dist/components/base/{CkPromptActionButton/CkPromptActionButton.stories.d.ts → CkPromptSendButton/CkPromptSendButton.stories.d.ts} +5 -5
- package/dist/components/base/CkPromptSendButton/CkPromptSendButton.stories.d.ts.map +1 -0
- package/dist/components/base/{CkPromptActionButton/CkPromptActionButton.vue.d.ts → CkPromptSendButton/CkPromptSendButton.vue.d.ts} +3 -3
- package/dist/components/base/CkPromptSendButton/CkPromptSendButton.vue.d.ts.map +1 -0
- package/dist/components/base/CkPromptSendButton/index.d.ts +3 -0
- package/dist/components/base/CkPromptSendButton/index.d.ts.map +1 -0
- package/dist/components/base/CkPromptSendButton/types.d.ts +34 -0
- package/dist/components/base/CkPromptSendButton/types.d.ts.map +1 -0
- package/dist/components/base/CkPromptStopButton/CkPromptStopButton.stories.d.ts +1 -1
- package/dist/components/base/CkPromptStopButton/CkPromptStopButton.vue.d.ts.map +1 -1
- package/dist/components/base/CkPromptStopButton/types.d.ts +6 -4
- package/dist/components/base/CkPromptStopButton/types.d.ts.map +1 -1
- package/dist/components/base/icons/CkSendIcon.vue.d.ts.map +1 -1
- package/dist/components/base/index.d.ts +3 -1
- package/dist/components/base/index.d.ts.map +1 -1
- package/dist/components/composed/CkHistory/CkHistory.vue.d.ts +1 -1
- package/dist/components/composed/CkInput/CkInput.stories.d.ts.map +1 -1
- package/dist/components/composed/CkInput/CkInput.vue.d.ts +9 -8
- package/dist/components/composed/CkInput/CkInput.vue.d.ts.map +1 -1
- package/dist/components/composed/CkInput/types.d.ts +2 -7
- package/dist/components/composed/CkInput/types.d.ts.map +1 -1
- package/dist/components/index.d.ts +2 -2
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +9 -8
- package/dist/composables/fileUpload/types.d.ts +1 -1
- package/dist/composables/fileUpload/types.d.ts.map +1 -1
- package/dist/composables/fileUpload/useFileUpload.d.ts.map +1 -1
- package/dist/composables/index.js +1 -1
- package/dist/{index-CfXEGjc7.js → index-THzZwfMU.js} +6 -4
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -10
- package/package.json +1 -1
- package/src/components/base/CkDropZoneOverlay/CkDropZoneOverlay.vue +2 -7
- package/src/components/base/CkFileItemsList/CkFileItemsList.spec.ts +67 -0
- package/src/components/base/CkFileItemsList/CkFileItemsList.stories.ts +48 -0
- package/src/components/base/CkFileItemsList/CkFileItemsList.vue +78 -4
- package/src/components/base/CkFileItemsList/types.ts +9 -0
- package/src/components/base/CkModelSelector/types.ts +1 -1
- package/src/components/base/CkPromptInput/CkPromptInput.spec.ts +206 -11
- package/src/components/base/CkPromptInput/CkPromptInput.stories.ts +1068 -43
- package/src/components/base/CkPromptInput/CkPromptInput.vue +137 -28
- package/src/components/base/CkPromptInput/types.ts +11 -12
- package/src/components/base/CkPromptMenuButton/CkPromptMenuButton.spec.ts +62 -0
- package/src/components/base/CkPromptMenuButton/CkPromptMenuButton.stories.ts +75 -0
- package/src/components/base/CkPromptMenuButton/CkPromptMenuButton.vue +26 -0
- package/src/components/base/CkPromptMenuButton/index.ts +2 -0
- package/src/components/base/CkPromptMenuButton/types.ts +29 -0
- package/src/components/base/{CkPromptActionButton/CkPromptActionButton.spec.ts → CkPromptSendButton/CkPromptSendButton.spec.ts} +11 -11
- package/src/components/base/CkPromptSendButton/CkPromptSendButton.stories.ts +117 -0
- package/src/components/base/{CkPromptActionButton/CkPromptActionButton.vue → CkPromptSendButton/CkPromptSendButton.vue} +4 -4
- package/src/components/base/CkPromptSendButton/index.ts +2 -0
- package/src/components/base/CkPromptSendButton/types.ts +33 -0
- package/src/components/base/CkPromptStopButton/CkPromptStopButton.spec.ts +5 -5
- package/src/components/base/CkPromptStopButton/CkPromptStopButton.stories.ts +1 -1
- package/src/components/base/CkPromptStopButton/CkPromptStopButton.vue +3 -2
- package/src/components/base/CkPromptStopButton/types.ts +6 -4
- package/src/components/base/icons/CkSendIcon.vue +3 -16
- package/src/components/base/icons/CkStopIcon.vue +1 -1
- package/src/components/base/index.ts +3 -1
- package/src/components/composed/CkInput/CkInput.stories.ts +0 -4
- package/src/components/composed/CkInput/CkInput.vue +7 -5
- package/src/components/composed/CkInput/types.ts +2 -7
- package/src/components/index.ts +3 -1
- package/src/composables/fileUpload/types.ts +1 -1
- package/src/composables/fileUpload/useFileUpload.spec.ts +26 -0
- package/src/composables/fileUpload/useFileUpload.ts +12 -3
- package/src/composables/fileUpload/useFileUploadWrapper.ts +1 -1
- package/src/index.ts +3 -1
- package/dist/components/base/CkPromptActionButton/CkPromptActionButton.stories.d.ts.map +0 -1
- package/dist/components/base/CkPromptActionButton/CkPromptActionButton.vue.d.ts.map +0 -1
- package/dist/components/base/CkPromptActionButton/index.d.ts +0 -3
- package/dist/components/base/CkPromptActionButton/index.d.ts.map +0 -1
- package/dist/components/base/CkPromptActionButton/types.d.ts +0 -33
- package/dist/components/base/CkPromptActionButton/types.d.ts.map +0 -1
- package/src/components/base/CkPromptActionButton/CkPromptActionButton.stories.ts +0 -126
- package/src/components/base/CkPromptActionButton/index.ts +0 -2
- package/src/components/base/CkPromptActionButton/types.ts +0 -32
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
import CkPromptInput from './CkPromptInput.vue';
|
|
2
2
|
import { render, screen, fireEvent } from '@testing-library/vue';
|
|
3
|
+
import { defineComponent, nextTick, ref } from 'vue';
|
|
4
|
+
|
|
5
|
+
// Mock the textarea's scrollHeight (jsdom always returns 0). The auto-grow +
|
|
6
|
+
// multi-line latch logic in CkPromptInput depends on scrollHeight; tests that
|
|
7
|
+
// exercise that path call this helper to stage a measured value.
|
|
8
|
+
function mockScrollHeight(value: number): void {
|
|
9
|
+
Object.defineProperty(HTMLTextAreaElement.prototype, 'scrollHeight', {
|
|
10
|
+
configurable: true,
|
|
11
|
+
get() {
|
|
12
|
+
return value;
|
|
13
|
+
},
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function restoreScrollHeight(): void {
|
|
18
|
+
// Re-installing a property descriptor with a getter returning 0 mirrors
|
|
19
|
+
// jsdom's default (`HTMLElement.scrollHeight` returns 0 by spec there).
|
|
20
|
+
Object.defineProperty(HTMLTextAreaElement.prototype, 'scrollHeight', {
|
|
21
|
+
configurable: true,
|
|
22
|
+
get() {
|
|
23
|
+
return 0;
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
}
|
|
3
27
|
|
|
4
28
|
describe('CkPromptInput', () => {
|
|
5
29
|
describe('rendering', () => {
|
|
@@ -122,13 +146,10 @@ describe('CkPromptInput', () => {
|
|
|
122
146
|
expect(screen.getByText('Express')).toBeInTheDocument();
|
|
123
147
|
});
|
|
124
148
|
|
|
125
|
-
it('
|
|
149
|
+
it('renders no toolbar buttons when slots are not provided', () => {
|
|
126
150
|
const { container } = render(CkPromptInput);
|
|
127
151
|
|
|
128
|
-
|
|
129
|
-
'form > div:last-child > div',
|
|
130
|
-
);
|
|
131
|
-
expect(toolbarDivs[0]?.children.length).toBe(0);
|
|
152
|
+
expect(container.querySelectorAll('button')).toHaveLength(0);
|
|
132
153
|
});
|
|
133
154
|
|
|
134
155
|
it('renders toolbar-right slot content', () => {
|
|
@@ -139,13 +160,12 @@ describe('CkPromptInput', () => {
|
|
|
139
160
|
expect(screen.getByText('Custom Send')).toBeInTheDocument();
|
|
140
161
|
});
|
|
141
162
|
|
|
142
|
-
it('renders
|
|
143
|
-
|
|
163
|
+
it('renders toolbar-top slot content', () => {
|
|
164
|
+
render(CkPromptInput, {
|
|
165
|
+
slots: { 'toolbar-top': '<span>Toolbar-top content</span>' },
|
|
166
|
+
});
|
|
144
167
|
|
|
145
|
-
|
|
146
|
-
'form > div:last-child > div.ml-auto',
|
|
147
|
-
);
|
|
148
|
-
expect(toolbarRight?.children.length).toBe(0);
|
|
168
|
+
expect(screen.getByText('Toolbar-top content')).toBeInTheDocument();
|
|
149
169
|
});
|
|
150
170
|
|
|
151
171
|
it('renders footer slot content', () => {
|
|
@@ -178,4 +198,179 @@ describe('CkPromptInput', () => {
|
|
|
178
198
|
expect(screen.getByRole('textbox')).toBeDisabled();
|
|
179
199
|
});
|
|
180
200
|
});
|
|
201
|
+
|
|
202
|
+
// The form switches between compact (single-row, rounded-3xl) and stacked
|
|
203
|
+
// (multi-row, rounded-2xl) layouts based on (a) the presence of the
|
|
204
|
+
// `toolbar-top` slot and (b) whether the textarea content exceeds one line.
|
|
205
|
+
// These tests regression-guard the slot reactivity fix and the multi-line
|
|
206
|
+
// latch threshold.
|
|
207
|
+
describe('layout transitions', () => {
|
|
208
|
+
afterEach(() => {
|
|
209
|
+
restoreScrollHeight();
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
it('reacts to toolbar-top slot becoming available after mount', async () => {
|
|
213
|
+
const Parent = defineComponent({
|
|
214
|
+
components: { CkPromptInput },
|
|
215
|
+
setup() {
|
|
216
|
+
return { show: ref(false) };
|
|
217
|
+
},
|
|
218
|
+
template: `
|
|
219
|
+
<div>
|
|
220
|
+
<button data-testid="toggle" @click="show = !show">toggle</button>
|
|
221
|
+
<CkPromptInput model-value="">
|
|
222
|
+
<template v-if="show" #toolbar-top>
|
|
223
|
+
<span data-testid="top">attached files</span>
|
|
224
|
+
</template>
|
|
225
|
+
</CkPromptInput>
|
|
226
|
+
</div>
|
|
227
|
+
`,
|
|
228
|
+
});
|
|
229
|
+
const { container } = render(Parent);
|
|
230
|
+
|
|
231
|
+
expect(container.querySelector('[data-testid="top"]')).toBeNull();
|
|
232
|
+
expect(container.querySelector('form')?.className).toContain(
|
|
233
|
+
'rounded-3xl',
|
|
234
|
+
);
|
|
235
|
+
|
|
236
|
+
await fireEvent.click(screen.getByTestId('toggle'));
|
|
237
|
+
|
|
238
|
+
// Parent re-render → `useSlots()` flips → computed re-evaluates → top
|
|
239
|
+
// row renders AND the form swaps to the smaller multi-row radius.
|
|
240
|
+
expect(
|
|
241
|
+
container.querySelector('[data-testid="top"]'),
|
|
242
|
+
).toBeInTheDocument();
|
|
243
|
+
expect(container.querySelector('form')?.className).toContain(
|
|
244
|
+
'rounded-2xl',
|
|
245
|
+
);
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
it('also reacts to toolbar-top slot becoming unavailable', async () => {
|
|
249
|
+
const Parent = defineComponent({
|
|
250
|
+
components: { CkPromptInput },
|
|
251
|
+
setup() {
|
|
252
|
+
return { show: ref(true) };
|
|
253
|
+
},
|
|
254
|
+
template: `
|
|
255
|
+
<div>
|
|
256
|
+
<button data-testid="toggle" @click="show = !show">toggle</button>
|
|
257
|
+
<CkPromptInput model-value="">
|
|
258
|
+
<template v-if="show" #toolbar-top>
|
|
259
|
+
<span data-testid="top">attached files</span>
|
|
260
|
+
</template>
|
|
261
|
+
</CkPromptInput>
|
|
262
|
+
</div>
|
|
263
|
+
`,
|
|
264
|
+
});
|
|
265
|
+
const { container } = render(Parent);
|
|
266
|
+
|
|
267
|
+
expect(container.querySelector('form')?.className).toContain(
|
|
268
|
+
'rounded-2xl',
|
|
269
|
+
);
|
|
270
|
+
|
|
271
|
+
await fireEvent.click(screen.getByTestId('toggle'));
|
|
272
|
+
|
|
273
|
+
expect(container.querySelector('[data-testid="top"]')).toBeNull();
|
|
274
|
+
expect(container.querySelector('form')?.className).toContain(
|
|
275
|
+
'rounded-3xl',
|
|
276
|
+
);
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
it('latches to multi-line layout when scrollHeight exceeds 2× line-height', async () => {
|
|
280
|
+
mockScrollHeight(48); // exactly 2 × LINE_HEIGHT
|
|
281
|
+
const Parent = defineComponent({
|
|
282
|
+
components: { CkPromptInput },
|
|
283
|
+
setup() {
|
|
284
|
+
return { text: ref('one') };
|
|
285
|
+
},
|
|
286
|
+
template: `
|
|
287
|
+
<CkPromptInput :model-value="text" @update:model-value="text = $event" />
|
|
288
|
+
`,
|
|
289
|
+
});
|
|
290
|
+
const { container, rerender } = render(Parent);
|
|
291
|
+
// Initial render mounted with scrollHeight=48 but modelValue='one' (no
|
|
292
|
+
// newline) — single line latches to multi when scrollHeight ≥ 48.
|
|
293
|
+
await nextTick();
|
|
294
|
+
// The grid template should now include the input-on-top + toolbar-row
|
|
295
|
+
// shape used for multi-line mode.
|
|
296
|
+
const form = container.querySelector('form');
|
|
297
|
+
expect(form?.style.gridTemplateAreas).toContain('"left . right"');
|
|
298
|
+
|
|
299
|
+
// Rerender to a different value to confirm the latch persists.
|
|
300
|
+
await rerender({});
|
|
301
|
+
await nextTick();
|
|
302
|
+
expect(form?.style.gridTemplateAreas).toContain('"left . right"');
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
it('does NOT latch on borderline scrollHeight (single emoji-line @ 36 px)', async () => {
|
|
306
|
+
mockScrollHeight(36); // 1.5 × LINE_HEIGHT — emoji/CJK sub-pixel rendering
|
|
307
|
+
const Parent = defineComponent({
|
|
308
|
+
components: { CkPromptInput },
|
|
309
|
+
setup() {
|
|
310
|
+
return { text: ref('hi 👋') };
|
|
311
|
+
},
|
|
312
|
+
template: `<CkPromptInput :model-value="text" />`,
|
|
313
|
+
});
|
|
314
|
+
const { container } = render(Parent);
|
|
315
|
+
await nextTick();
|
|
316
|
+
// Single-line layout: textarea + toolbars on the same row.
|
|
317
|
+
const form = container.querySelector('form');
|
|
318
|
+
expect(form?.style.gridTemplateAreas).toContain('"left input right"');
|
|
319
|
+
expect(form?.style.gridTemplateAreas).not.toContain('"left . right"');
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
it('latches when the user inserts an explicit newline (Shift+Enter)', async () => {
|
|
323
|
+
mockScrollHeight(24); // jsdom never reports >24 reliably; rely on \n
|
|
324
|
+
const Parent = defineComponent({
|
|
325
|
+
components: { CkPromptInput },
|
|
326
|
+
setup() {
|
|
327
|
+
return { text: ref('line one') };
|
|
328
|
+
},
|
|
329
|
+
template: `
|
|
330
|
+
<CkPromptInput :model-value="text" @update:model-value="text = $event" />
|
|
331
|
+
`,
|
|
332
|
+
});
|
|
333
|
+
const { container } = render(Parent);
|
|
334
|
+
await nextTick();
|
|
335
|
+
const form = container.querySelector('form');
|
|
336
|
+
expect(form?.style.gridTemplateAreas).toContain('"left input right"');
|
|
337
|
+
|
|
338
|
+
// Now the modelValue contains a newline.
|
|
339
|
+
const ParentTwoLines = defineComponent({
|
|
340
|
+
components: { CkPromptInput },
|
|
341
|
+
setup() {
|
|
342
|
+
return { text: ref('line one\nline two') };
|
|
343
|
+
},
|
|
344
|
+
template: `<CkPromptInput :model-value="text" />`,
|
|
345
|
+
});
|
|
346
|
+
const { container: c2 } = render(ParentTwoLines);
|
|
347
|
+
await nextTick();
|
|
348
|
+
expect(c2.querySelector('form')?.style.gridTemplateAreas).toContain(
|
|
349
|
+
'"left . right"',
|
|
350
|
+
);
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
it('un-latches multi-line state when the field is emptied', async () => {
|
|
354
|
+
mockScrollHeight(48);
|
|
355
|
+
const Parent = defineComponent({
|
|
356
|
+
components: { CkPromptInput },
|
|
357
|
+
setup() {
|
|
358
|
+
return { text: ref('something') };
|
|
359
|
+
},
|
|
360
|
+
template: `
|
|
361
|
+
<CkPromptInput :model-value="text" @update:model-value="text = $event" />
|
|
362
|
+
`,
|
|
363
|
+
});
|
|
364
|
+
const { container, getByRole } = render(Parent);
|
|
365
|
+
await nextTick();
|
|
366
|
+
const form = container.querySelector('form');
|
|
367
|
+
expect(form?.style.gridTemplateAreas).toContain('"left . right"');
|
|
368
|
+
|
|
369
|
+
mockScrollHeight(24);
|
|
370
|
+
await fireEvent.update(getByRole('textbox'), '');
|
|
371
|
+
await nextTick();
|
|
372
|
+
|
|
373
|
+
expect(form?.style.gridTemplateAreas).toContain('"left input right"');
|
|
374
|
+
});
|
|
375
|
+
});
|
|
181
376
|
});
|