Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions docs/content/docs/2.components/chat-message.md
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,37 @@ collapse: true
---
::

### Color :badge{label="Soon" class="align-text-top"}

Use the `color` prop to tint the inner [Avatar](/docs/components/avatar/). An explicit `avatar.color` overrides this default.

::component-code
---
prettier: true
ignore:
- parts
- side
- variant
- role
- id
- avatar.src
- avatar.loading
props:
color: 'air-primary-copilot'
avatar:
src: 'https://github.com/bitrix24.png'
loading: lazy
variant: 'message'
side: 'left'
parts:
- type: 'text'
id: '1'
text: 'Hello! Tell me more about building AI chatbots with Bitrix24 UI.'
role: 'assistant'
id: '1'
---
::

### Actions

Use the `actions` prop to display actions below the message that will be displayed when hovering over the message.
Expand Down
15 changes: 13 additions & 2 deletions src/runtime/components/ChatMessage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ export interface ChatMessageProps<TMetadata = unknown, TDataParts extends UIData
*/
icon?: IconComponent
avatar?: AvatarProps & { [key: string]: any }
/**
* Default `color` for the inner `B24Avatar`. Overridden by `avatar.color` when set.
*/
color?: AvatarProps['color']
/**
* @defaultValue 'message'
*/
Expand Down Expand Up @@ -77,7 +81,7 @@ const appConfig = useAppConfig() as ChatMessage['AppConfig']
const fileParts = computed(() => props.parts?.filter((part): part is FileUIPart => part.type === 'file') ?? [])
const textParts = computed(() => props.parts?.filter((part): part is TextUIPart => part.type === 'text') ?? [])

const messageProps = computed(() => omit(props, ['as', 'icon', 'avatar', 'variant', 'side', 'actions', 'compact', 'class', 'b24ui']))
const messageProps = computed(() => omit(props, ['as', 'icon', 'avatar', 'color', 'variant', 'side', 'actions', 'compact', 'class', 'b24ui']))

// eslint-disable-next-line vue/no-dupe-keys
const b24ui = computed(() => tv({ extend: tv(theme), ...(appConfig.b24ui?.chatMessage || {}) })({
Expand All @@ -99,7 +103,14 @@ const b24ui = computed(() => tv({ extend: tv(theme), ...(appConfig.b24ui?.chatMe
<div v-if="props.icon || props.avatar || !!slots.leading" data-slot="leading" :class="b24ui.leading({ class: props.b24ui?.leading })">
<slot name="leading" v-bind="{ ...messageProps, avatar: props.avatar, b24ui }">
<Component :is="props.icon" v-if="props.icon" data-slot="leadingIcon" :class="b24ui.leadingIcon({ class: props.b24ui?.leadingIcon })" />
<B24Avatar v-else-if="props.avatar" :size="((props.b24ui?.leadingAvatarSize || b24ui.leadingAvatarSize()) as AvatarProps['size'])" v-bind="props.avatar" data-slot="leadingAvatar" :class="b24ui.leadingAvatar({ class: props.b24ui?.leadingAvatar })" />
<B24Avatar
v-else-if="props.avatar"
:size="((props.b24ui?.leadingAvatarSize || b24ui.leadingAvatarSize()) as AvatarProps['size'])"
:color="props.color"
v-bind="props.avatar"
data-slot="leadingAvatar"
:class="b24ui.leadingAvatar({ class: props.b24ui?.leadingAvatar })"
/>
</slot>
</div>

Expand Down
3 changes: 2 additions & 1 deletion test/components/ChatMessage.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ describe('ChatMessage', () => {
['with content', { props: { ...props, content: 'Hello, how are you?' } }],
['with icon', { props: { ...props, icon: Search2Icon } }],
['with avatar', { props: { ...props, avatar: { src: 'https://github.com/bitrix24.png' } } }],
['with color', { props: { ...props, avatar: { src: 'https://github.com/bitrix24.png' }, color: 'air-primary' as const } }],
['with role assistant', { props: { ...props, role: 'assistant' as const } }],
['with side right', { props: { ...props, side: 'right' } }],
['with compact', { props: { ...props, compact: true } }],
Expand Down Expand Up @@ -87,7 +88,7 @@ describe('ChatMessage', () => {
}
})

for (const key of ['as', 'icon', 'avatar', 'variant', 'side', 'actions', 'compact', 'class', 'b24ui']) {
for (const key of ['as', 'icon', 'avatar', 'color', 'variant', 'side', 'actions', 'compact', 'class', 'b24ui']) {
expect(captured[0]).not.toHaveProperty(key)
}
})
Expand Down
11 changes: 11 additions & 0 deletions test/components/__snapshots__/ChatMessage-vue.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,17 @@ exports[`ChatMessage > renders with class correctly 1`] = `
</article>"
`;

exports[`ChatMessage > renders with color correctly 1`] = `
"<article data-role="user" data-slot="root" class="group/message relative w-full scroll-mt-4 sm:scroll-mt-6">
<!--v-if-->
<div data-slot="container" class="relative flex items-start gap-3 pb-8">
<div data-slot="leading" class="inline-flex items-center justify-center min-h-6 mt-2"><span data-slot="root" class="air-secondary-accent inline-flex items-center justify-center select-none rounded-full align-middle bg-(--b24ui-background) ring ring-(--b24ui-border-color) style-filled size-8 text-(length:--ui-font-size-sm)/(--ui-font-line-height-reset) shrink-0"><img src="https://github.com/bitrix24.png" width="32" height="32" data-slot="image" class="h-full w-full rounded-[inherit] object-cover"></span></div>
<div data-slot="content" class="relative text-pretty min-w-0 *:first:mt-0 *:last:mb-0 bg-(--ui-color-design-outline-bg) border-(--ui-color-design-outline-stroke) border-(length:--ui-design-outline-stroke-weight-alt) text-(--ui-color-design-outline-content-secondary) space-y-4 px-3 py-2 rounded-md min-h-[42px]">Hello, how are you?</div>
<!--v-if-->
</div>
</article>"
`;

exports[`ChatMessage > renders with compact correctly 1`] = `
"<article data-role="user" data-slot="root" class="group/message relative w-full scroll-mt-3">
<!--v-if-->
Expand Down
11 changes: 11 additions & 0 deletions test/components/__snapshots__/ChatMessage.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,17 @@ exports[`ChatMessage > renders with class correctly 1`] = `
</article>"
`;

exports[`ChatMessage > renders with color correctly 1`] = `
"<article data-role="user" data-slot="root" class="group/message relative w-full scroll-mt-4 sm:scroll-mt-6">
<!--v-if-->
<div data-slot="container" class="relative flex items-start gap-3 pb-8">
<div data-slot="leading" class="inline-flex items-center justify-center min-h-6 mt-2"><span data-slot="root" class="air-secondary-accent inline-flex items-center justify-center select-none rounded-full align-middle bg-(--b24ui-background) ring ring-(--b24ui-border-color) style-filled size-8 text-(length:--ui-font-size-sm)/(--ui-font-line-height-reset) shrink-0"><img src="https://github.com/bitrix24.png" width="32" height="32" data-slot="image" class="h-full w-full rounded-[inherit] object-cover"></span></div>
<div data-slot="content" class="relative text-pretty min-w-0 *:first:mt-0 *:last:mb-0 bg-(--ui-color-design-outline-bg) border-(--ui-color-design-outline-stroke) border-(length:--ui-design-outline-stroke-weight-alt) text-(--ui-color-design-outline-content-secondary) space-y-4 px-3 py-2 rounded-md min-h-[42px]">Hello, how are you?</div>
<!--v-if-->
</div>
</article>"
`;

exports[`ChatMessage > renders with compact correctly 1`] = `
"<article data-role="user" data-slot="root" class="group/message relative w-full scroll-mt-3">
<!--v-if-->
Expand Down