@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.
- package/dist/{CkInput.vue_vue_type_script_setup_true_lang-BAcBFs6I.js → CkHistory.vue_vue_type_script_setup_true_lang-Bp9hXdH6.js} +452 -348
- package/dist/adapters/responses-api.d.ts +11 -5
- package/dist/adapters/responses-api.d.ts.map +1 -1
- package/dist/adapters/responses-api.js +9 -3
- package/dist/chat-kit.css +36 -14
- package/dist/components/base/CkAgentMessage/CkAgentMessage.stories.d.ts +14 -13
- package/dist/components/base/CkAgentMessage/CkAgentMessage.stories.d.ts.map +1 -1
- package/dist/components/base/CkAgentMessage/CkAgentMessage.vue.d.ts +8 -7
- package/dist/components/base/CkAgentMessage/CkAgentMessage.vue.d.ts.map +1 -1
- package/dist/components/base/CkAgentMessage/types.d.ts +16 -5
- package/dist/components/base/CkAgentMessage/types.d.ts.map +1 -1
- package/dist/components/base/CkAgentMessageHeader/CkAgentMessageHeader.stories.d.ts +16 -0
- package/dist/components/base/CkAgentMessageHeader/CkAgentMessageHeader.stories.d.ts.map +1 -0
- package/dist/components/base/CkAgentMessageHeader/CkAgentMessageHeader.vue.d.ts +21 -0
- package/dist/components/base/CkAgentMessageHeader/CkAgentMessageHeader.vue.d.ts.map +1 -0
- package/dist/components/base/CkAgentMessageHeader/index.d.ts +3 -0
- package/dist/components/base/CkAgentMessageHeader/index.d.ts.map +1 -0
- package/dist/components/base/CkAgentMessageHeader/types.d.ts +22 -0
- package/dist/components/base/CkAgentMessageHeader/types.d.ts.map +1 -0
- package/dist/components/base/CkCitation/CkCitation.stories.d.ts +6 -0
- package/dist/components/base/CkCitation/CkCitation.stories.d.ts.map +1 -1
- package/dist/components/base/CkCitation/CkCitation.vue.d.ts.map +1 -1
- package/dist/components/base/CkCitationCard/CkCitationCard.stories.d.ts +5 -4
- package/dist/components/base/CkCitationCard/CkCitationCard.stories.d.ts.map +1 -1
- package/dist/components/base/CkCitationCard/CkCitationCard.vue.d.ts.map +1 -1
- package/dist/components/base/{CkCopyMessageActionButton/CkCopyMessageActionButton.stories.d.ts → CkCopyMessageButton/CkCopyMessageButton.stories.d.ts} +3 -3
- package/dist/components/base/CkCopyMessageButton/CkCopyMessageButton.stories.d.ts.map +1 -0
- package/dist/components/base/{CkCopyMessageActionButton/CkCopyMessageActionButton.vue.d.ts → CkCopyMessageButton/CkCopyMessageButton.vue.d.ts} +4 -4
- package/dist/components/base/CkCopyMessageButton/CkCopyMessageButton.vue.d.ts.map +1 -0
- package/dist/components/base/CkCopyMessageButton/index.d.ts +3 -0
- package/dist/components/base/CkCopyMessageButton/index.d.ts.map +1 -0
- package/dist/components/base/{CkCopyMessageActionButton → CkCopyMessageButton}/types.d.ts +3 -3
- package/dist/components/base/CkCopyMessageButton/types.d.ts.map +1 -0
- package/dist/components/base/CkFeedbackButton/types.d.ts +1 -1
- package/dist/components/base/CkFeedbackDialog/types.d.ts +1 -1
- package/dist/components/base/CkFileItemsList/CkFileItemsList.stories.d.ts +15 -4
- package/dist/components/base/CkFileItemsList/CkFileItemsList.stories.d.ts.map +1 -1
- package/dist/components/base/CkFileItemsList/CkFileItemsList.vue.d.ts +2 -1
- package/dist/components/base/CkFileItemsList/CkFileItemsList.vue.d.ts.map +1 -1
- package/dist/components/base/CkFileItemsList/types.d.ts +17 -4
- package/dist/components/base/CkFileItemsList/types.d.ts.map +1 -1
- package/dist/components/base/CkHeaderActivityButton/CkHeaderActivityButton.stories.d.ts +19 -0
- package/dist/components/base/CkHeaderActivityButton/CkHeaderActivityButton.stories.d.ts.map +1 -0
- package/dist/components/base/CkHeaderActivityButton/CkHeaderActivityButton.vue.d.ts +22 -0
- package/dist/components/base/CkHeaderActivityButton/CkHeaderActivityButton.vue.d.ts.map +1 -0
- package/dist/components/base/CkHeaderActivityButton/index.d.ts +3 -0
- package/dist/components/base/CkHeaderActivityButton/index.d.ts.map +1 -0
- package/dist/components/base/CkHeaderActivityButton/types.d.ts +36 -0
- package/dist/components/base/CkHeaderActivityButton/types.d.ts.map +1 -0
- package/dist/components/base/{CkMessageActionButton/CkMessageActionButton.stories.d.ts → CkMessageButton/CkMessageButton.stories.d.ts} +3 -3
- package/dist/components/base/CkMessageButton/CkMessageButton.stories.d.ts.map +1 -0
- package/dist/components/base/{CkMessageActionButton/CkMessageActionButton.vue.d.ts → CkMessageButton/CkMessageButton.vue.d.ts} +3 -3
- package/dist/components/base/CkMessageButton/CkMessageButton.vue.d.ts.map +1 -0
- package/dist/components/base/CkMessageButton/index.d.ts +3 -0
- package/dist/components/base/CkMessageButton/index.d.ts.map +1 -0
- package/dist/components/base/{CkMessageActionButton → CkMessageButton}/types.d.ts +2 -2
- package/dist/components/base/CkMessageButton/types.d.ts.map +1 -0
- package/dist/components/base/CkPromptInput/CkPromptInput.stories.d.ts +6 -6
- package/dist/components/base/CkPromptInput/CkPromptInput.vue.d.ts.map +1 -1
- package/dist/components/base/CkPromptInput/types.d.ts +4 -4
- package/dist/components/base/CkPromptInputDisclaimer/CkPromptInputDisclaimer.vue.d.ts.map +1 -1
- package/dist/components/base/CkPromptInputDisclaimer/types.d.ts +1 -1
- package/dist/components/base/CkPromptSendButton/CkPromptSendButton.vue.d.ts +1 -1
- package/dist/components/base/CkPromptSendButton/types.d.ts +1 -1
- package/dist/components/base/CkPromptStopButton/types.d.ts +1 -1
- package/dist/components/base/CkRegenerateMessageButton/CkRegenerateMessageButton.stories.d.ts +16 -0
- package/dist/components/base/CkRegenerateMessageButton/CkRegenerateMessageButton.stories.d.ts.map +1 -0
- package/dist/components/base/CkRegenerateMessageButton/CkRegenerateMessageButton.vue.d.ts +12 -0
- package/dist/components/base/CkRegenerateMessageButton/CkRegenerateMessageButton.vue.d.ts.map +1 -0
- package/dist/components/base/CkRegenerateMessageButton/index.d.ts +3 -0
- package/dist/components/base/{CkCopyMessageActionButton → CkRegenerateMessageButton}/index.d.ts.map +1 -1
- package/dist/components/base/CkRegenerateMessageButton/types.d.ts +27 -0
- package/dist/components/base/CkRegenerateMessageButton/types.d.ts.map +1 -0
- package/dist/components/base/index.d.ts +7 -2
- package/dist/components/base/index.d.ts.map +1 -1
- package/dist/components/composed/CkConversation/CkConversation.stories.d.ts +1 -1
- package/dist/components/composed/CkConversation/CkConversation.vue.d.ts +13 -1
- package/dist/components/composed/CkConversation/CkConversation.vue.d.ts.map +1 -1
- package/dist/components/composed/CkConversation/types.d.ts +1 -1
- package/dist/components/composed/index.d.ts +0 -1
- package/dist/components/composed/index.d.ts.map +1 -1
- package/dist/components/index.d.ts +3 -3
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +26 -24
- package/dist/composables/index.js +1 -1
- package/dist/handlers/index.js +2 -2
- package/dist/handlers/useChatKitLabels.d.ts +2 -0
- package/dist/handlers/useChatKitLabels.d.ts.map +1 -1
- package/dist/handlers/useMessageHandler.d.ts +37 -0
- package/dist/handlers/useMessageHandler.d.ts.map +1 -1
- package/dist/helpers/conversationTree.d.ts +15 -0
- package/dist/helpers/conversationTree.d.ts.map +1 -1
- package/dist/{index-C6njJ8EB.js → index-CyrVnbS9.js} +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +30 -28
- package/dist/{useChatKitLabels-BM2I7-9o.js → useChatKitLabels-zMFV7aEz.js} +1 -0
- package/dist/{useMessageHandler-CMdy-lm0.js → useMessageHandler-N50Yj-NU.js} +45 -7
- package/package.json +3 -3
- package/src/adapters/responses-api.spec.ts +52 -5
- package/src/adapters/responses-api.ts +26 -7
- package/src/components/base/CkAgentMessage/CkAgentMessage.spec.ts +12 -17
- package/src/components/base/CkAgentMessage/CkAgentMessage.stories.ts +124 -113
- package/src/components/base/CkAgentMessage/CkAgentMessage.vue +18 -16
- package/src/components/base/CkAgentMessage/types.ts +16 -5
- package/src/components/base/CkAgentMessageHeader/CkAgentMessageHeader.spec.ts +64 -0
- package/src/components/base/CkAgentMessageHeader/CkAgentMessageHeader.stories.ts +90 -0
- package/src/components/base/CkAgentMessageHeader/CkAgentMessageHeader.vue +47 -0
- package/src/components/base/CkAgentMessageHeader/index.ts +2 -0
- package/src/components/base/CkAgentMessageHeader/types.ts +21 -0
- package/src/components/base/CkCitation/CkCitation.stories.ts +12 -0
- package/src/components/base/CkCitation/CkCitation.vue +34 -9
- package/src/components/base/CkCitationCard/CkCitationCard.stories.ts +5 -4
- package/src/components/base/CkCitationCard/CkCitationCard.vue +2 -2
- package/src/components/base/CkConversationLayout/CkConversationLayout.vue +1 -1
- package/src/components/base/{CkCopyMessageActionButton/CkCopyMessageActionButton.spec.ts → CkCopyMessageButton/CkCopyMessageButton.spec.ts} +6 -6
- package/src/components/base/{CkCopyMessageActionButton/CkCopyMessageActionButton.stories.ts → CkCopyMessageButton/CkCopyMessageButton.stories.ts} +8 -8
- package/src/components/base/{CkCopyMessageActionButton/CkCopyMessageActionButton.vue → CkCopyMessageButton/CkCopyMessageButton.vue} +6 -6
- package/src/components/base/CkCopyMessageButton/index.ts +2 -0
- package/src/components/base/{CkCopyMessageActionButton → CkCopyMessageButton}/types.ts +3 -3
- package/src/components/base/CkFeedbackButton/CkFeedbackButton.vue +5 -5
- package/src/components/base/CkFeedbackButton/types.ts +1 -1
- package/src/components/base/CkFeedbackDialog/types.ts +1 -1
- package/src/components/base/CkFileItemsList/CkFileItemsList.spec.ts +88 -13
- package/src/components/base/CkFileItemsList/CkFileItemsList.stories.ts +61 -13
- package/src/components/base/CkFileItemsList/CkFileItemsList.vue +153 -110
- package/src/components/base/CkFileItemsList/types.ts +17 -4
- package/src/components/base/CkHeaderActivityButton/CkHeaderActivityButton.spec.ts +50 -0
- package/src/components/base/CkHeaderActivityButton/CkHeaderActivityButton.stories.ts +102 -0
- package/src/components/base/CkHeaderActivityButton/CkHeaderActivityButton.vue +39 -0
- package/src/components/base/CkHeaderActivityButton/index.ts +2 -0
- package/src/components/base/CkHeaderActivityButton/types.ts +36 -0
- package/src/components/base/{CkMessageActionButton/CkMessageActionButton.spec.ts → CkMessageButton/CkMessageButton.spec.ts} +6 -6
- package/src/components/base/{CkMessageActionButton/CkMessageActionButton.stories.ts → CkMessageButton/CkMessageButton.stories.ts} +10 -10
- package/src/components/base/{CkMessageActionButton/CkMessageActionButton.vue → CkMessageButton/CkMessageButton.vue} +3 -3
- package/src/components/base/CkMessageButton/index.ts +2 -0
- package/src/components/base/{CkMessageActionButton → CkMessageButton}/types.ts +2 -2
- package/src/components/base/CkPromptInput/CkPromptInput.spec.ts +88 -0
- package/src/components/base/CkPromptInput/CkPromptInput.stories.ts +6 -6
- package/src/components/base/CkPromptInput/CkPromptInput.vue +63 -12
- package/src/components/base/CkPromptInput/types.ts +4 -4
- package/src/components/base/CkPromptInputDisclaimer/CkPromptInputDisclaimer.spec.ts +1 -1
- package/src/components/base/CkPromptInputDisclaimer/CkPromptInputDisclaimer.vue +1 -1
- package/src/components/base/CkPromptInputDisclaimer/types.ts +1 -1
- package/src/components/base/CkPromptSendButton/types.ts +1 -1
- package/src/components/base/CkPromptStopButton/types.ts +1 -1
- package/src/components/base/CkRegenerateMessageButton/CkRegenerateMessageButton.spec.ts +49 -0
- package/src/components/base/CkRegenerateMessageButton/CkRegenerateMessageButton.stories.ts +63 -0
- package/src/components/base/CkRegenerateMessageButton/CkRegenerateMessageButton.vue +43 -0
- package/src/components/base/CkRegenerateMessageButton/index.ts +2 -0
- package/src/components/base/CkRegenerateMessageButton/types.ts +27 -0
- package/src/components/base/index.ts +10 -2
- package/src/components/composed/CkConversation/CkConversation.spec.ts +81 -6
- package/src/components/composed/CkConversation/CkConversation.stories.ts +6 -6
- package/src/components/composed/CkConversation/CkConversation.vue +80 -37
- package/src/components/composed/CkConversation/types.ts +1 -1
- package/src/components/composed/index.ts +0 -1
- package/src/components/index.ts +9 -3
- package/src/handlers/useChatKitLabels.spec.ts +1 -0
- package/src/handlers/useChatKitLabels.ts +3 -0
- package/src/handlers/useMessageHandler.spec.ts +79 -0
- package/src/handlers/useMessageHandler.ts +50 -2
- package/src/helpers/conversationTree.spec.ts +120 -0
- package/src/helpers/conversationTree.ts +57 -8
- package/src/index.ts +8 -3
- package/dist/components/base/CkCopyMessageActionButton/CkCopyMessageActionButton.stories.d.ts.map +0 -1
- package/dist/components/base/CkCopyMessageActionButton/CkCopyMessageActionButton.vue.d.ts.map +0 -1
- package/dist/components/base/CkCopyMessageActionButton/index.d.ts +0 -3
- package/dist/components/base/CkCopyMessageActionButton/types.d.ts.map +0 -1
- package/dist/components/base/CkMessageActionButton/CkMessageActionButton.stories.d.ts.map +0 -1
- package/dist/components/base/CkMessageActionButton/CkMessageActionButton.vue.d.ts.map +0 -1
- package/dist/components/base/CkMessageActionButton/index.d.ts +0 -3
- package/dist/components/base/CkMessageActionButton/index.d.ts.map +0 -1
- package/dist/components/base/CkMessageActionButton/types.d.ts.map +0 -1
- package/dist/components/composed/CkInput/CkInput.stories.d.ts +0 -43
- package/dist/components/composed/CkInput/CkInput.stories.d.ts.map +0 -1
- package/dist/components/composed/CkInput/CkInput.vue.d.ts +0 -50
- package/dist/components/composed/CkInput/CkInput.vue.d.ts.map +0 -1
- package/dist/components/composed/CkInput/index.d.ts +0 -3
- package/dist/components/composed/CkInput/index.d.ts.map +0 -1
- package/dist/components/composed/CkInput/types.d.ts +0 -55
- package/dist/components/composed/CkInput/types.d.ts.map +0 -1
- package/src/components/base/CkCopyMessageActionButton/index.ts +0 -2
- package/src/components/base/CkMessageActionButton/index.ts +0 -2
- package/src/components/composed/CkInput/CkInput.spec.ts +0 -191
- package/src/components/composed/CkInput/CkInput.stories.ts +0 -434
- package/src/components/composed/CkInput/CkInput.vue +0 -106
- package/src/components/composed/CkInput/index.ts +0 -2
- package/src/components/composed/CkInput/types.ts +0 -55
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from '@storybook/vue3-vite';
|
|
2
|
-
import { ref } from 'vue';
|
|
2
|
+
import { computed, ref } from 'vue';
|
|
3
3
|
import CkFileItemsList from './CkFileItemsList.vue';
|
|
4
4
|
import type { CkFileEntry } from './types';
|
|
5
5
|
|
|
@@ -12,12 +12,13 @@ const meta: Meta<typeof CkFileItemsList> = {
|
|
|
12
12
|
docs: {
|
|
13
13
|
description: {
|
|
14
14
|
component:
|
|
15
|
-
'Compact horizontal row of file attachments. Renders
|
|
15
|
+
'Compact horizontal row of file attachments. Renders as many `UiFileItem`s inline as fit the available width — each kept between `minItemWidth` and `maxItemWidth` wide — and collapses the full list into a single popover trigger once they no longer fit.',
|
|
16
16
|
},
|
|
17
17
|
},
|
|
18
18
|
},
|
|
19
19
|
argTypes: {
|
|
20
|
-
|
|
20
|
+
minItemWidth: { control: { type: 'number', min: 80, max: 320, step: 8 } },
|
|
21
|
+
maxItemWidth: { control: { type: 'number', min: 120, max: 480, step: 8 } },
|
|
21
22
|
size: { control: { type: 'inline-radio' }, options: ['default', 'small'] },
|
|
22
23
|
isRemovable: { control: 'boolean' },
|
|
23
24
|
disabled: { control: 'boolean' },
|
|
@@ -97,15 +98,15 @@ function handleRemove(id: CkFileEntry['id']) {
|
|
|
97
98
|
</template>`;
|
|
98
99
|
|
|
99
100
|
/**
|
|
100
|
-
*
|
|
101
|
-
* row of `UiFileItem`s.
|
|
101
|
+
* As many files as fit the available width are rendered inline as a horizontal
|
|
102
|
+
* row of `UiFileItem`s (each kept between `minItemWidth` and `maxItemWidth`).
|
|
102
103
|
*/
|
|
103
104
|
export const Inline: Story = {
|
|
104
105
|
render: () => ({
|
|
105
106
|
components: { CkFileItemsList },
|
|
106
107
|
setup: () => ({ files: baseFiles }),
|
|
107
108
|
template: `
|
|
108
|
-
<div class="bg-background-surface-primary p-4 w-[
|
|
109
|
+
<div class="bg-background-surface-primary p-4 w-[44rem]">
|
|
109
110
|
<CkFileItemsList :files="files" />
|
|
110
111
|
</div>
|
|
111
112
|
`,
|
|
@@ -114,15 +115,15 @@ export const Inline: Story = {
|
|
|
114
115
|
};
|
|
115
116
|
|
|
116
117
|
/**
|
|
117
|
-
* When the
|
|
118
|
-
* popover trigger. Click it to reveal the full vertical list of files.
|
|
118
|
+
* When the files no longer fit the available width, the component collapses to
|
|
119
|
+
* a single popover trigger. Click it to reveal the full vertical list of files.
|
|
119
120
|
*/
|
|
120
121
|
export const Collapsed: Story = {
|
|
121
122
|
render: () => ({
|
|
122
123
|
components: { CkFileItemsList },
|
|
123
124
|
setup: () => ({ files: overflowFiles }),
|
|
124
125
|
template: `
|
|
125
|
-
<div class="bg-background-surface-primary p-4 w-[
|
|
126
|
+
<div class="bg-background-surface-primary p-4 w-[44rem]">
|
|
126
127
|
<CkFileItemsList :files="files" />
|
|
127
128
|
</div>
|
|
128
129
|
`,
|
|
@@ -193,7 +194,7 @@ export const Removable: Story = {
|
|
|
193
194
|
return { files, handleRemove };
|
|
194
195
|
},
|
|
195
196
|
template: `
|
|
196
|
-
<div class="bg-background-surface-primary p-4 w-[
|
|
197
|
+
<div class="bg-background-surface-primary p-4 w-[44rem]">
|
|
197
198
|
<CkFileItemsList :files="files" is-removable @remove="handleRemove" />
|
|
198
199
|
</div>
|
|
199
200
|
`,
|
|
@@ -232,7 +233,7 @@ export const CustomItem: Story = {
|
|
|
232
233
|
components: { CkFileItemsList },
|
|
233
234
|
setup: () => ({ files: baseFiles }),
|
|
234
235
|
template: `
|
|
235
|
-
<div class="bg-background-surface-primary p-4 w-[
|
|
236
|
+
<div class="bg-background-surface-primary p-4 w-[44rem]">
|
|
236
237
|
<CkFileItemsList :files="files">
|
|
237
238
|
<template #item="{ file }">
|
|
238
239
|
<a
|
|
@@ -283,7 +284,7 @@ export const Clickable: Story = {
|
|
|
283
284
|
return { files: overflowFiles, openFile, lastClicked };
|
|
284
285
|
},
|
|
285
286
|
template: `
|
|
286
|
-
<div class="bg-background-surface-primary p-4 w-[
|
|
287
|
+
<div class="bg-background-surface-primary p-4 w-[44rem]">
|
|
287
288
|
<CkFileItemsList
|
|
288
289
|
:files="files"
|
|
289
290
|
list-label="Attached files"
|
|
@@ -335,7 +336,7 @@ export const Disabled: Story = {
|
|
|
335
336
|
] as CkFileEntry[],
|
|
336
337
|
}),
|
|
337
338
|
template: `
|
|
338
|
-
<div class="flex flex-col gap-6 bg-background-surface-primary p-4 w-[
|
|
339
|
+
<div class="flex flex-col gap-6 bg-background-surface-primary p-4 w-[44rem]">
|
|
339
340
|
<div>
|
|
340
341
|
<p class="label-12-medium text-content-on-surface-muted mb-2">
|
|
341
342
|
Whole list disabled
|
|
@@ -353,3 +354,50 @@ export const Disabled: Story = {
|
|
|
353
354
|
}),
|
|
354
355
|
parameters: { docs: { source: { code: disabledTemplateSource } } },
|
|
355
356
|
};
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* The inline count adapts to the available width. There is no hard cap on the
|
|
360
|
+
* number of inline items — as many fit are kept, each between `minItemWidth`
|
|
361
|
+
* and `maxItemWidth` wide. As the wrapper narrows, fewer items stay inline
|
|
362
|
+
* until the whole list collapses into the popover trigger.
|
|
363
|
+
*
|
|
364
|
+
* Drag the bottom-right corner of the box to resize it and watch the list
|
|
365
|
+
* react. (The other stories use a fixed-width wrapper, so resizing the browser
|
|
366
|
+
* window alone won't change their layout.)
|
|
367
|
+
*/
|
|
368
|
+
export const Responsive: Story = {
|
|
369
|
+
args: {
|
|
370
|
+
minItemWidth: 200,
|
|
371
|
+
maxItemWidth: 256,
|
|
372
|
+
fileCount: 3,
|
|
373
|
+
} as never,
|
|
374
|
+
argTypes: {
|
|
375
|
+
fileCount: { control: { type: 'number', min: 1, max: 5, step: 1 } },
|
|
376
|
+
} as never,
|
|
377
|
+
render: (args) => ({
|
|
378
|
+
components: { CkFileItemsList },
|
|
379
|
+
setup() {
|
|
380
|
+
const argsWithCount = args as typeof args & { fileCount?: number };
|
|
381
|
+
const files = computed(() =>
|
|
382
|
+
overflowFiles.slice(
|
|
383
|
+
0,
|
|
384
|
+
Math.min(5, Math.max(1, argsWithCount.fileCount ?? 5)),
|
|
385
|
+
),
|
|
386
|
+
);
|
|
387
|
+
const listArgs = computed(() => {
|
|
388
|
+
const rest = { ...argsWithCount };
|
|
389
|
+
delete rest.fileCount;
|
|
390
|
+
return rest;
|
|
391
|
+
});
|
|
392
|
+
return { args: listArgs, files };
|
|
393
|
+
},
|
|
394
|
+
template: `
|
|
395
|
+
<div
|
|
396
|
+
class="resize-x overflow-auto bg-background-surface-primary p-4"
|
|
397
|
+
style="resize: horizontal; overflow: auto; width: 44rem; min-width: 12rem; max-width: 100%;"
|
|
398
|
+
>
|
|
399
|
+
<CkFileItemsList v-bind="args" :files="files" />
|
|
400
|
+
</div>
|
|
401
|
+
`,
|
|
402
|
+
}),
|
|
403
|
+
};
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
UiProgress,
|
|
9
9
|
type UiFileItemSize,
|
|
10
10
|
} from '@aleph-alpha/ui-library';
|
|
11
|
-
import { computed, ref } from 'vue';
|
|
11
|
+
import { computed, onBeforeUnmount, onMounted, ref } from 'vue';
|
|
12
12
|
import CkFileItemRow from './CkFileItemRow.vue';
|
|
13
13
|
import type {
|
|
14
14
|
CkFileEntry,
|
|
@@ -21,7 +21,8 @@ defineOptions({
|
|
|
21
21
|
});
|
|
22
22
|
|
|
23
23
|
const props = withDefaults(defineProps<CkFileItemsListProps>(), {
|
|
24
|
-
|
|
24
|
+
minItemWidth: 200,
|
|
25
|
+
maxItemWidth: 256,
|
|
25
26
|
size: 'small',
|
|
26
27
|
isRemovable: false,
|
|
27
28
|
removeLabel: 'Remove file',
|
|
@@ -48,7 +49,42 @@ defineSlots<{
|
|
|
48
49
|
}) => unknown;
|
|
49
50
|
}>();
|
|
50
51
|
|
|
51
|
-
|
|
52
|
+
// Gap between inline items (`gap-2` => 0.5rem => 8px).
|
|
53
|
+
const ITEM_GAP = 8;
|
|
54
|
+
|
|
55
|
+
const rootRef = ref<HTMLElement | null>(null);
|
|
56
|
+
const containerWidth = ref(0);
|
|
57
|
+
let resizeObserver: ResizeObserver | undefined;
|
|
58
|
+
|
|
59
|
+
onMounted(() => {
|
|
60
|
+
const el = rootRef.value;
|
|
61
|
+
if (!el) return;
|
|
62
|
+
containerWidth.value = el.clientWidth;
|
|
63
|
+
if (typeof ResizeObserver !== 'undefined') {
|
|
64
|
+
resizeObserver = new ResizeObserver((entries) => {
|
|
65
|
+
for (const entry of entries) {
|
|
66
|
+
containerWidth.value = entry.contentRect.width;
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
resizeObserver.observe(el);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
onBeforeUnmount(() => resizeObserver?.disconnect());
|
|
74
|
+
|
|
75
|
+
// Number of items that fit at the current width while each stays at least
|
|
76
|
+
// `minItemWidth` wide. There is no upper cap — as many items as fit are kept
|
|
77
|
+
// inline. Falls back to showing every file before the first measurement (SSR /
|
|
78
|
+
// initial render / environments without ResizeObserver) so the list never
|
|
79
|
+
// flashes collapsed; the observer corrects it on mount.
|
|
80
|
+
const inlineCapacity = computed(() => {
|
|
81
|
+
const width = containerWidth.value;
|
|
82
|
+
if (!width) return props.files.length;
|
|
83
|
+
const fit = Math.floor((width + ITEM_GAP) / (props.minItemWidth + ITEM_GAP));
|
|
84
|
+
return Math.max(1, fit);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
const isCollapsed = computed(() => props.files.length > inlineCapacity.value);
|
|
52
88
|
const isOpen = ref(false);
|
|
53
89
|
|
|
54
90
|
function isRowDisabled(file: CkFileEntry): boolean {
|
|
@@ -120,123 +156,130 @@ function handleRowClick(file: CkFileEntry, event: MouseEvent) {
|
|
|
120
156
|
</script>
|
|
121
157
|
|
|
122
158
|
<template>
|
|
123
|
-
<
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
<li
|
|
130
|
-
v-for="file in files"
|
|
131
|
-
:key="file.id"
|
|
132
|
-
class="min-w-0 max-w-64 flex-1 basis-0"
|
|
133
|
-
@click="handleRowClick(file, $event)"
|
|
159
|
+
<div ref="rootRef" class="w-full min-w-0">
|
|
160
|
+
<ul
|
|
161
|
+
v-if="!isCollapsed"
|
|
162
|
+
data-slot="file-items-list"
|
|
163
|
+
class="m-0 flex w-full min-w-0 list-none flex-wrap items-center gap-2 p-0"
|
|
164
|
+
:aria-label="listLabel"
|
|
134
165
|
>
|
|
135
|
-
<
|
|
136
|
-
|
|
137
|
-
:
|
|
138
|
-
|
|
139
|
-
:
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
<slot name="item" v-bind="bindings" />
|
|
145
|
-
</template>
|
|
146
|
-
</CkFileItemRow>
|
|
147
|
-
</li>
|
|
148
|
-
</ul>
|
|
149
|
-
|
|
150
|
-
<UiPopover v-else v-model:open="isOpen">
|
|
151
|
-
<UiPopoverTrigger as-child>
|
|
152
|
-
<button
|
|
153
|
-
type="button"
|
|
154
|
-
data-slot="file-items-list-trigger"
|
|
155
|
-
:disabled="disabled"
|
|
156
|
-
class="relative flex w-full max-w-64 min-w-0 items-center gap-3 rounded-xl bg-background-surface-muted-subtle text-left transition-colors hover:bg-background-surface-muted focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-border-focus disabled:cursor-not-allowed disabled:opacity-50 disabled:hover:bg-background-surface-muted-subtle"
|
|
157
|
-
:class="size === 'small' ? 'p-2' : 'p-3'"
|
|
158
|
-
:aria-label="resolvedTriggerAriaLabel"
|
|
166
|
+
<li
|
|
167
|
+
v-for="file in files"
|
|
168
|
+
:key="file.id"
|
|
169
|
+
class="flex-1 basis-0"
|
|
170
|
+
:style="{
|
|
171
|
+
minWidth: `${minItemWidth}px`,
|
|
172
|
+
maxWidth: `${maxItemWidth}px`,
|
|
173
|
+
}"
|
|
174
|
+
@click="handleRowClick(file, $event)"
|
|
159
175
|
>
|
|
160
|
-
<
|
|
161
|
-
|
|
162
|
-
:
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
v-if="!showStatus"
|
|
168
|
-
class="min-w-0 flex-1 truncate text-content-on-surface-primary"
|
|
169
|
-
:class="size === 'small' ? 'label-12-medium' : 'body-14-medium'"
|
|
176
|
+
<CkFileItemRow
|
|
177
|
+
:file="file"
|
|
178
|
+
:size="size"
|
|
179
|
+
:is-removable="isRemovable"
|
|
180
|
+
:remove-label="removeLabel"
|
|
181
|
+
:disabled="isRowDisabled(file)"
|
|
182
|
+
@remove="handleRemove(file)"
|
|
170
183
|
>
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
184
|
+
<template #default="bindings">
|
|
185
|
+
<slot name="item" v-bind="bindings" />
|
|
186
|
+
</template>
|
|
187
|
+
</CkFileItemRow>
|
|
188
|
+
</li>
|
|
189
|
+
</ul>
|
|
190
|
+
|
|
191
|
+
<UiPopover v-else v-model:open="isOpen">
|
|
192
|
+
<UiPopoverTrigger as-child>
|
|
193
|
+
<button
|
|
194
|
+
type="button"
|
|
195
|
+
data-slot="file-items-list-trigger"
|
|
196
|
+
:disabled="disabled"
|
|
197
|
+
class="relative flex w-full max-w-64 min-w-0 items-center gap-3 rounded-xl bg-background-surface-muted-subtle text-left transition-colors hover:bg-background-surface-muted focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-border-focus disabled:cursor-not-allowed disabled:opacity-50 disabled:hover:bg-background-surface-muted-subtle"
|
|
198
|
+
:class="size === 'small' ? 'p-2' : 'p-3'"
|
|
199
|
+
:aria-label="resolvedTriggerAriaLabel"
|
|
200
|
+
>
|
|
201
|
+
<UiFileType
|
|
202
|
+
v-if="showStatus && hasFailures && !uploadInProgress"
|
|
203
|
+
:error="true"
|
|
204
|
+
/>
|
|
205
|
+
<UiFileType v-else icon="paperclip" tone="default" />
|
|
206
|
+
|
|
174
207
|
<span
|
|
175
|
-
|
|
208
|
+
v-if="!showStatus"
|
|
209
|
+
class="min-w-0 flex-1 truncate text-content-on-surface-primary"
|
|
176
210
|
:class="size === 'small' ? 'label-12-medium' : 'body-14-medium'"
|
|
177
211
|
>
|
|
178
212
|
{{ resolvedTriggerLabel }}
|
|
179
213
|
</span>
|
|
180
|
-
<
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
214
|
+
<div v-else class="flex min-w-0 flex-1 flex-col items-start gap-0.5">
|
|
215
|
+
<span
|
|
216
|
+
class="w-full truncate text-content-on-surface-primary"
|
|
217
|
+
:class="size === 'small' ? 'label-12-medium' : 'body-14-medium'"
|
|
218
|
+
>
|
|
219
|
+
{{ resolvedTriggerLabel }}
|
|
220
|
+
</span>
|
|
221
|
+
<UiProgress
|
|
222
|
+
v-if="uploadInProgress"
|
|
223
|
+
:model-value="aggregateProgress"
|
|
224
|
+
class="h-1 w-full"
|
|
225
|
+
:aria-label="`${resolvedTriggerLabel} upload progress`"
|
|
226
|
+
/>
|
|
227
|
+
<span
|
|
228
|
+
v-else-if="hasFailures"
|
|
229
|
+
class="label-12-medium w-full truncate text-content-on-status-error-inverse"
|
|
230
|
+
>
|
|
231
|
+
{{ failedStatusLabel }}
|
|
232
|
+
</span>
|
|
233
|
+
<span
|
|
234
|
+
v-else-if="triggerLabel"
|
|
235
|
+
class="label-12-medium w-full truncate text-content-on-surface-muted"
|
|
236
|
+
>
|
|
237
|
+
{{ countStatusLabel }}
|
|
238
|
+
</span>
|
|
239
|
+
</div>
|
|
240
|
+
|
|
241
|
+
<UiIcon
|
|
242
|
+
name="chevron-down"
|
|
243
|
+
:size="16"
|
|
244
|
+
aria-hidden="true"
|
|
245
|
+
class="shrink-0 text-content-on-surface-muted transition-transform"
|
|
246
|
+
:class="isOpen && 'rotate-180'"
|
|
185
247
|
/>
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
v-else-if="triggerLabel"
|
|
194
|
-
class="label-12-medium w-full truncate text-content-on-surface-muted"
|
|
195
|
-
>
|
|
196
|
-
{{ countStatusLabel }}
|
|
197
|
-
</span>
|
|
198
|
-
</div>
|
|
199
|
-
|
|
200
|
-
<UiIcon
|
|
201
|
-
name="chevron-down"
|
|
202
|
-
:size="16"
|
|
203
|
-
aria-hidden="true"
|
|
204
|
-
class="shrink-0 text-content-on-surface-muted transition-transform"
|
|
205
|
-
:class="isOpen && 'rotate-180'"
|
|
206
|
-
/>
|
|
207
|
-
</button>
|
|
208
|
-
</UiPopoverTrigger>
|
|
209
|
-
|
|
210
|
-
<UiPopoverContent
|
|
211
|
-
align="start"
|
|
212
|
-
:side-offset="4"
|
|
213
|
-
:class="['w-64 p-2', popoverClass]"
|
|
214
|
-
>
|
|
215
|
-
<ul
|
|
216
|
-
data-slot="file-items-list-collapsed"
|
|
217
|
-
class="m-0 flex list-none flex-col gap-2 p-0"
|
|
218
|
-
:aria-label="listLabel"
|
|
248
|
+
</button>
|
|
249
|
+
</UiPopoverTrigger>
|
|
250
|
+
|
|
251
|
+
<UiPopoverContent
|
|
252
|
+
align="start"
|
|
253
|
+
:side-offset="4"
|
|
254
|
+
:class="['w-64 p-2', popoverClass]"
|
|
219
255
|
>
|
|
220
|
-
<
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
@click="handleRowClick(file, $event)"
|
|
256
|
+
<ul
|
|
257
|
+
data-slot="file-items-list-collapsed"
|
|
258
|
+
class="m-0 flex list-none flex-col gap-2 p-0"
|
|
259
|
+
:aria-label="listLabel"
|
|
225
260
|
>
|
|
226
|
-
<
|
|
227
|
-
|
|
228
|
-
:
|
|
229
|
-
|
|
230
|
-
:
|
|
231
|
-
|
|
232
|
-
@remove="handleRemove(file)"
|
|
261
|
+
<li
|
|
262
|
+
v-for="file in files"
|
|
263
|
+
:key="file.id"
|
|
264
|
+
class="min-w-0"
|
|
265
|
+
:style="{ maxWidth: `${maxItemWidth}px` }"
|
|
266
|
+
@click="handleRowClick(file, $event)"
|
|
233
267
|
>
|
|
234
|
-
<
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
268
|
+
<CkFileItemRow
|
|
269
|
+
:file="file"
|
|
270
|
+
:size="size"
|
|
271
|
+
:is-removable="isRemovable"
|
|
272
|
+
:remove-label="removeLabel"
|
|
273
|
+
:disabled="isRowDisabled(file)"
|
|
274
|
+
@remove="handleRemove(file)"
|
|
275
|
+
>
|
|
276
|
+
<template #default="bindings">
|
|
277
|
+
<slot name="item" v-bind="bindings" />
|
|
278
|
+
</template>
|
|
279
|
+
</CkFileItemRow>
|
|
280
|
+
</li>
|
|
281
|
+
</ul>
|
|
282
|
+
</UiPopoverContent>
|
|
283
|
+
</UiPopover>
|
|
284
|
+
</div>
|
|
242
285
|
</template>
|
|
@@ -25,8 +25,9 @@ export interface CkFileEntry {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
|
-
* Horizontal list of file attachments
|
|
29
|
-
*
|
|
28
|
+
* Horizontal list of file attachments. Renders as many items inline as fit the
|
|
29
|
+
* available width — each kept between `minItemWidth` and `maxItemWidth` wide —
|
|
30
|
+
* and collapses into a popover once they no longer fit.
|
|
30
31
|
*
|
|
31
32
|
* @category Form Inputs
|
|
32
33
|
* @useCases user message attachments, prompt input previews, chat file row
|
|
@@ -36,8 +37,20 @@ export interface CkFileEntry {
|
|
|
36
37
|
export interface CkFileItemsListProps {
|
|
37
38
|
/** Files to render. Order is preserved. */
|
|
38
39
|
files: CkFileEntry[];
|
|
39
|
-
/**
|
|
40
|
-
|
|
40
|
+
/**
|
|
41
|
+
* Minimum width (px) an inline item may occupy. As the wrapper narrows, fewer
|
|
42
|
+
* items stay inline (each kept at least this wide) until the list collapses
|
|
43
|
+
* into the popover. Lower values keep more items inline on narrow widths.
|
|
44
|
+
* @default 200
|
|
45
|
+
*/
|
|
46
|
+
minItemWidth?: number;
|
|
47
|
+
/**
|
|
48
|
+
* Maximum width (px) an inline item may grow to. Items never stretch beyond
|
|
49
|
+
* this width; any extra horizontal space is left unused. There is no cap on
|
|
50
|
+
* the number of inline items as long as they fit the wrapper.
|
|
51
|
+
* @default 256
|
|
52
|
+
*/
|
|
53
|
+
maxItemWidth?: number;
|
|
41
54
|
/** @default 'small' */
|
|
42
55
|
size?: UiFileItemSize;
|
|
43
56
|
/** Show a remove control on every row. @default false */
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import CkHeaderActivityButton from './CkHeaderActivityButton.vue';
|
|
2
|
+
import userEvent from '@testing-library/user-event';
|
|
3
|
+
import { render, screen } from '@testing-library/vue';
|
|
4
|
+
import { describe, expect, it } from 'vitest';
|
|
5
|
+
|
|
6
|
+
describe('CkHeaderActivityButton', () => {
|
|
7
|
+
it('renders the slot content as the label', () => {
|
|
8
|
+
render(CkHeaderActivityButton, {
|
|
9
|
+
slots: { default: '1 tool, 42 sources' },
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
expect(
|
|
13
|
+
screen.getByRole('button', { name: /1 tool, 42 sources/ }),
|
|
14
|
+
).toBeInTheDocument();
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('uses the explicit ariaLabel when provided', () => {
|
|
18
|
+
render(CkHeaderActivityButton, {
|
|
19
|
+
props: { ariaLabel: 'Show activity' },
|
|
20
|
+
slots: { default: '1 tool' },
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
expect(
|
|
24
|
+
screen.getByRole('button', { name: 'Show activity' }),
|
|
25
|
+
).toBeInTheDocument();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('emits click when pressed', async () => {
|
|
29
|
+
const user = userEvent.setup();
|
|
30
|
+
const { emitted } = render(CkHeaderActivityButton, {
|
|
31
|
+
slots: { default: 'Activity' },
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
await user.click(screen.getByRole('button'));
|
|
35
|
+
|
|
36
|
+
expect(emitted('click')).toHaveLength(1);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('does not emit click when disabled', async () => {
|
|
40
|
+
const user = userEvent.setup();
|
|
41
|
+
const { emitted } = render(CkHeaderActivityButton, {
|
|
42
|
+
props: { disabled: true },
|
|
43
|
+
slots: { default: 'Activity' },
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
await user.click(screen.getByRole('button'));
|
|
47
|
+
|
|
48
|
+
expect(emitted('click')).toBeUndefined();
|
|
49
|
+
});
|
|
50
|
+
});
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import CkHeaderActivityButton from './CkHeaderActivityButton.vue';
|
|
2
|
+
import type { Meta, StoryObj } from '@storybook/vue3-vite';
|
|
3
|
+
|
|
4
|
+
const meta: Meta<typeof CkHeaderActivityButton> = {
|
|
5
|
+
title: 'Base/CkHeaderActivityButton',
|
|
6
|
+
component: CkHeaderActivityButton,
|
|
7
|
+
tags: ['autodocs'],
|
|
8
|
+
argTypes: {
|
|
9
|
+
disabled: {
|
|
10
|
+
control: 'boolean',
|
|
11
|
+
description: 'Disables the button and prevents the `click` event.',
|
|
12
|
+
},
|
|
13
|
+
ariaLabel: {
|
|
14
|
+
control: 'text',
|
|
15
|
+
description:
|
|
16
|
+
'Accessible label. Falls back to the label text when omitted.',
|
|
17
|
+
},
|
|
18
|
+
icon: {
|
|
19
|
+
control: 'text',
|
|
20
|
+
description:
|
|
21
|
+
"Trailing Lucide icon name. Set to '' to hide. Defaults to 'arrow-right'.",
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
decorators: [
|
|
25
|
+
() => ({
|
|
26
|
+
template: '<div style="padding: 24px;"><story /></div>',
|
|
27
|
+
}),
|
|
28
|
+
],
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export default meta;
|
|
32
|
+
type Story = StoryObj<typeof meta>;
|
|
33
|
+
|
|
34
|
+
const defaultTemplateSource = `<script setup lang="ts">
|
|
35
|
+
import { CkHeaderActivityButton } from '@aleph-alpha/chat-kit';
|
|
36
|
+
|
|
37
|
+
function openActivity() {
|
|
38
|
+
// open the activity / chain-of-thought panel
|
|
39
|
+
}
|
|
40
|
+
</script>
|
|
41
|
+
|
|
42
|
+
<template>
|
|
43
|
+
<CkHeaderActivityButton @click="openActivity">
|
|
44
|
+
1 tool, 42 sources
|
|
45
|
+
</CkHeaderActivityButton>
|
|
46
|
+
</template>`;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Default activity button: a short label followed by the trailing arrow icon.
|
|
50
|
+
* It emits a generic `click` and performs no action on its own.
|
|
51
|
+
*/
|
|
52
|
+
export const Default: Story = {
|
|
53
|
+
render: (args) => ({
|
|
54
|
+
components: { CkHeaderActivityButton },
|
|
55
|
+
setup() {
|
|
56
|
+
return { args };
|
|
57
|
+
},
|
|
58
|
+
template: `
|
|
59
|
+
<CkHeaderActivityButton v-bind="args">
|
|
60
|
+
1 tool, 42 sources
|
|
61
|
+
</CkHeaderActivityButton>
|
|
62
|
+
`,
|
|
63
|
+
}),
|
|
64
|
+
args: { disabled: false, icon: 'arrow-right' },
|
|
65
|
+
parameters: { docs: { source: { code: defaultTemplateSource } } },
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Without a trailing icon — pass an empty `icon` to render the label only.
|
|
70
|
+
*/
|
|
71
|
+
export const WithoutIcon: Story = {
|
|
72
|
+
render: (args) => ({
|
|
73
|
+
components: { CkHeaderActivityButton },
|
|
74
|
+
setup() {
|
|
75
|
+
return { args };
|
|
76
|
+
},
|
|
77
|
+
template: `
|
|
78
|
+
<CkHeaderActivityButton v-bind="args">
|
|
79
|
+
3 sources
|
|
80
|
+
</CkHeaderActivityButton>
|
|
81
|
+
`,
|
|
82
|
+
}),
|
|
83
|
+
args: { icon: '' },
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Disabled state: the button is non-interactive and does not emit `click`.
|
|
88
|
+
*/
|
|
89
|
+
export const Disabled: Story = {
|
|
90
|
+
render: (args) => ({
|
|
91
|
+
components: { CkHeaderActivityButton },
|
|
92
|
+
setup() {
|
|
93
|
+
return { args };
|
|
94
|
+
},
|
|
95
|
+
template: `
|
|
96
|
+
<CkHeaderActivityButton v-bind="args">
|
|
97
|
+
1 tool, 42 sources
|
|
98
|
+
</CkHeaderActivityButton>
|
|
99
|
+
`,
|
|
100
|
+
}),
|
|
101
|
+
args: { disabled: true },
|
|
102
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { CkHeaderActivityButtonProps } from './types';
|
|
3
|
+
import { UiButton, UiIcon } from '@aleph-alpha/ui-library';
|
|
4
|
+
|
|
5
|
+
defineOptions({
|
|
6
|
+
name: 'CkHeaderActivityButton',
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
const props = withDefaults(defineProps<CkHeaderActivityButtonProps>(), {
|
|
10
|
+
disabled: false,
|
|
11
|
+
icon: 'arrow-right',
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
const emit = defineEmits<{
|
|
15
|
+
click: [];
|
|
16
|
+
}>();
|
|
17
|
+
|
|
18
|
+
function handleClick() {
|
|
19
|
+
if (props.disabled) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
emit('click');
|
|
24
|
+
}
|
|
25
|
+
</script>
|
|
26
|
+
|
|
27
|
+
<template>
|
|
28
|
+
<UiButton
|
|
29
|
+
v-bind="{ ariaLabel }"
|
|
30
|
+
:disabled="disabled"
|
|
31
|
+
variant="ghost"
|
|
32
|
+
size="sm"
|
|
33
|
+
class="label-12-medium text-content-on-surface-muted gap-1 rounded-[3px] px-2 py-1"
|
|
34
|
+
@click="handleClick"
|
|
35
|
+
>
|
|
36
|
+
<slot />
|
|
37
|
+
<UiIcon v-if="icon" :name="icon" :size="12" aria-hidden="true" />
|
|
38
|
+
</UiButton>
|
|
39
|
+
</template>
|