Skip to content

Commit

Permalink
Fluent: polish copilot variant (#5293)
Browse files Browse the repository at this point in the history
* Fluent: polish copilot variant

* Changelog

* Fix entities

* Fix missing activity argument

* Remove duplicate selector

* Use variables

* Relax bot message width

* Sendbox to hide letter count unless more than allowed

* Better spacing

* Fix border flair plays on show-hide

* Complete animation in Firefox as well

* Snapshots

* Remove unneeded maxMessageLength

* Cleanup

* CopyButton snapshots

* Adjust outline for pre-chat activity

* Snapshots

* Sort

* Format
  • Loading branch information
OEvgeny committed Sep 11, 2024
1 parent f62098a commit 3e47786
Show file tree
Hide file tree
Showing 58 changed files with 420 additions and 204 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ Notes: web developers are advised to use [`~` (tilde range)](https://github.com/
- Reworked pre-chat activity layout to use author entity for improved consistency and flexibility, in PR [#5274](https://github.com/microsoft/BotFramework-WebChat/pull/5274), by [@OEvgeny](https://github.com/OEvgeny)
- Updated styles for suggested actions and attachments in Fluent theme to improve readability and consistency, in PR [#5275](https://github.com/microsoft/BotFramework-WebChat/pull/5275), by [@OEvgeny](https://github.com/OEvgeny)
- Moved from `[email protected]` to `@redux/[email protected]`, in PR [#5292](https://github.com/microsoft/BotFramework-WebChat/pull/5292), by [@compulim](https://github.com/compulim)
- Enhanced the visual presentation of the Fluent theme copilot variant, in PR [#5293](https://github.com/microsoft/BotFramework-WebChat/pull/5293), by [@OEvgeny](https://github.com/OEvgeny)

### Fixed

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
227 changes: 148 additions & 79 deletions __tests__/html/fluentTheme/side-by-side.wide.dark.html

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions __tests__/html/fluentTheme/side-by-side.wide.dark.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,7 @@ describe('Fluent theme applied', () => {
runHTML('fluentTheme/side-by-side.wide.dark?transcript=0&transcript=2&focus=0&focus=1'));
test('side by side left - transcript, right - pre liner', () =>
runHTML('fluentTheme/side-by-side.wide.dark?transcript=0&transcript=3'));
test('side by side left - transcript, right - streaming', () =>
runHTML('fluentTheme/side-by-side.wide.dark?transcript=0&transcript=4'));
});
});
226 changes: 148 additions & 78 deletions __tests__/html/fluentTheme/side-by-side.wide.html

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions __tests__/html/fluentTheme/side-by-side.wide.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,6 @@ describe('Fluent theme applied', () => {
runHTML('fluentTheme/side-by-side.wide?transcript=0&transcript=2&focus=0&focus=1'));
test('side by side left - transcript, right - pre liner', () =>
runHTML('fluentTheme/side-by-side.wide?transcript=0&transcript=3'));
test('side by side left - transcript, right - streaming', () =>
runHTML('fluentTheme/side-by-side.wide?transcript=0&transcript=4'));
});
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,15 @@
/* Decorator copilot variant */
:global(.webchat-fluent) .activity-decorator.variant-copilot {
--webchat__bubble--border-radius: var(--webchat-borderRadiusXLarge);

&:not(:has(:global(.webchat__bubble--from-user))) {
--webchat__bubble--block-padding: var(--webchat-spacingVerticalS) var(--webchat-spacingVerticalXXS);
--webchat__bubble--border-radius: var(--webchat-borderRadiusSmall);
--webchat__bubble--inline-padding: 32px var(--webchat-spacingHorizontalNone);
--webchat__bubble--block-padding: var(--webchat-spacingVerticalS) var(--webchat-spacingVerticalS);
--webchat__bubble--border-radius: var(--webchat-borderRadiusMedium);
--webchat__bubble--inline-padding: 34px var(--webchat-spacingHorizontalS);
--webchat__bubble--max-width: 100%;

display: block;
padding-inline-start: var(--webchat-spacingHorizontalM);
}

&:not(:has(:global(.webchat__bubble--from-user))) :global(.webchat__stacked-layout__status) {
Expand All @@ -51,12 +55,13 @@

/* TODO: remove when we get decorators in and can place header directly to the bubble */
&:not(:has(:global(.webchat__bubble--from-user))) :global(.webchat__stacked-layout .webchat__bubble .webchat__text-content) {
padding-block: calc(var(--webchat-spacingVerticalS) + 20px) var(--webchat-spacingVerticalXXS);
padding-block: calc(var(--webchat-spacingVerticalMNudge) + 20px) var(--webchat-spacingVerticalS);
}

&:not(:has(:global(.webchat__bubble--from-user))) :global(.webchat__stacked-layout .webchat__bubble) {
margin-block-start: -24px;
margin-inline-start: -4px;
margin-block-start: -28px;
margin-inline-start: -10px;
width: var(--webchat__bubble--max-width);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@

:global(.webchat-fluent) .copilot-message-header {
align-items: center;
box-sizing: border-box;
cursor: default;
display: flex;
flex-wrap: nowrap;
gap: var(--webchat-spacingHorizontalS);
margin-inline-start: var(--webchat-spacingVerticalMNudge);
max-width: var(--webchat__bubble--max-width);
padding-block-start: var(--webchat-spacingVerticalXS);
padding-inline: var(--webchat-spacingVerticalMNudge);
/* TODO: remove when moved to the bubble */
position: relative;
z-index: 1;
Expand All @@ -23,7 +25,6 @@
font-size: var(--webchat-fontSizeBase300);
font-weight: var(--webchat-fontWeightSemibold);
line-height: var(--webchat-lineHeightBase300);
max-width: 240px;
overflow: hidden;
text-overflow: ellipsis;
text-wrap: nowrap;
Expand All @@ -35,8 +36,9 @@
border-radius: var(--webchat-borderRadiusMedium);
color: var(--webchat-colorNeutralForeground3);
display: flex;
flex: none;
font-size: var(--webchat-fontSizeBase100);
height: 20px;
line-height: var(--webchat-lineHeightBase100);
padding-inline: 4px;
padding-inline: var(--webchat-spacingHorizontalXS);
}
Original file line number Diff line number Diff line change
@@ -1,31 +1,39 @@
import { WebChatActivity, hooks } from 'botframework-webchat-component';
import React, { memo, useMemo, type CSSProperties } from 'react';
import { WebChatActivity, hooks } from 'botframework-webchat-component';

import useActivityStyleOptions from './private/useActivityStyleOptions';
import isAIGeneratedActivity from './private/isAIGeneratedActivity';
import useActivityAuthor from './private/useActivityAuthor';
import { useStyles } from '../../styles';
import styles from './CopilotMessageHeader.module.css';

const { useStyleOptions, useLocalizer } = hooks;
const { useLocalizer } = hooks;

function CopilotMessageHeader({ activity }: Readonly<{ activity?: WebChatActivity | undefined }>) {
const [{ botAvatarImage, botAvatarBackgroundColor }] = useStyleOptions();
const [{ botAvatarImage, botAvatarBackgroundColor }] = useActivityStyleOptions(activity);
const classNames = useStyles(styles);
const localize = useLocalizer();
// TODO: how we determine the activity has ai-generated content
const isAIGenerated = useMemo(() => !!activity, [activity]);
const botTitle = activity?.from?.name;
const isAIGenerated = isAIGeneratedActivity(activity);

const avatarStyle = useMemo(
() => ({ '--background-color': botAvatarBackgroundColor }) as CSSProperties,
[botAvatarBackgroundColor]
);

const author = useActivityAuthor(activity);
const avatarImage = author?.image || botAvatarImage;
const botTitle = author?.name || activity?.from?.name;

return (
<div className={classNames['copilot-message-header']}>
<img
alt={localize('AVATAR_ALT', botTitle)}
className={classNames['copilot-message-header__avatar']}
src={botAvatarImage}
style={avatarStyle}
/>
{avatarImage && (
<img
alt={localize('AVATAR_ALT', botTitle)}
className={classNames['copilot-message-header__avatar']}
src={avatarImage}
style={avatarStyle}
/>
)}
<span className={classNames['copilot-message-header__title']} title={botTitle}>
{botTitle}
</span>
Expand Down
1 change: 1 addition & 0 deletions packages/fluent-theme/src/components/activity/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { default as ActivityDecorator } from './ActivityDecorator';
export { default as useActivityAuthor } from './private/useActivityAuthor';
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { getOrgSchemaMessage, type WebChatActivity } from 'botframework-webchat-core';

export default function isAIGeneratedActivity(activity: undefined | WebChatActivity) {
return !!(activity && getOrgSchemaMessage(activity?.entities || [])?.keywords?.includes('AIGeneratedContent'));
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { useMemo } from 'react';
import { getOrgSchemaMessage, type WebChatActivity } from 'botframework-webchat-core';

export default function useActivityAuthor(activity?: WebChatActivity | undefined) {
return useMemo(() => {
const entity = getOrgSchemaMessage(activity?.entities || []);
return typeof entity?.author === 'string'
? {
'@type': 'Person',
description: undefined,
image: undefined,
name: entity?.author
}
: entity?.author;
}, [activity]);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { useMemo } from 'react';
import { hooks, type WebChatActivity } from 'botframework-webchat-component';
import { type StrictStyleOptions } from 'botframework-webchat-api';

const { useStyleOptions } = hooks;

export default function useActivityStyleOptions(activity?: WebChatActivity | undefined) {
const [styleOptions] = useStyleOptions();
return useMemo<readonly [Readonly<StrictStyleOptions>]>(
() =>
Object.freeze([
{
...styleOptions,
...activity?.channelData?.webChat?.styleOptions
}
]),
[activity?.channelData?.webChat?.styleOptions, styleOptions]
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,10 @@
position: absolute;
}

:global(.webchat-fluent) .border-flair--complete {
animation-play-state: paused;
}

/* Firefox implementation */
@supports (-moz-appearance: none) {
@keyframes borderFlair-animation {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,28 @@
import React, { Fragment, memo, type ReactNode } from 'react';
import React, { Fragment, memo, useCallback, useState, type ReactNode } from 'react';
import cx from 'classnames';

import { useStyles } from '../../../styles';
import styles from './BorderFlair.module.css';

function BorderFlair({ children }: Readonly<{ children?: ReactNode | undefined }>) {
const classNames = useStyles(styles);
const [isComplete, setComplete] = useState(false);

const handleAnimationEnd = useCallback(
event =>
(event.animationName === styles['borderAnimation-angle'] ||
event.animationName === styles['borderFlair-animation']) &&
setComplete(true),
[]
);

return (
<Fragment>
{children}
<div className={classNames['border-flair']} />
<div
className={cx(classNames['border-flair'], isComplete && classNames['border-flair--complete'])}
onAnimationEnd={handleAnimationEnd}
/>
</Fragment>
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { hooks } from 'botframework-webchat-component';
import { getOrgSchemaMessage, type WebChatActivity } from 'botframework-webchat-core';
import { type WebChatActivity } from 'botframework-webchat-core';
import cx from 'classnames';
import React, { memo, useMemo } from 'react';
import { useStyles } from '../../styles/index.js';
import styles from './PreChatMessageActivity.module.css';
import StarterPromptsToolbar from './StarterPromptsToolbar.js';
import { useActivityAuthor } from '../activity/index.js';

type Props = Readonly<{ activity: WebChatActivity & { type: 'message' } }>;

Expand All @@ -16,19 +17,7 @@ const PreChatMessageActivity = ({ activity }: Props) => {
const renderMarkdownAsHTML = useRenderMarkdownAsHTML();
const localize = useLocalizer();

const entity = getOrgSchemaMessage(activity?.entities || []);
const author = useMemo(
() =>
typeof entity?.author === 'string'
? {
'@type': 'Person',
description: undefined,
image: undefined,
name: entity?.author
}
: entity?.author,
[entity?.author]
);
const author = useActivityAuthor(activity);

const html = useMemo(
() => (renderMarkdownAsHTML ? { __html: renderMarkdownAsHTML(author?.description || '') } : { __html: '' }),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@
--webchat-sendbox-border-radius: var(--webchat-borderRadiusLarge);
}

/* Copilot variant */
:global(.webchat-fluent) .sendbox.variant-copilot {
.sendbox__text-counter:not(.sendbox__text-counter--error) {
visibility: hidden;
}
}

:global(.webchat-fluent) .sendbox__sendbox {
background-color: var(--webchat-colorNeutralBackground1);
border-radius: var(--webchat-sendbox-border-radius);
Expand Down
5 changes: 3 additions & 2 deletions packages/fluent-theme/src/components/sendBox/SendBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import cx from 'classnames';
import React, { memo, useCallback, useRef, useState, type FormEventHandler, type MouseEventHandler } from 'react';
import { useRefFrom } from 'use-ref-from';
import { SendIcon } from '../../icons';
import { useStyles } from '../../styles';
import { useStyles, useVariantClassName } from '../../styles';
import testIds from '../../testIds';
import { DropZone } from '../dropZone';
import { SuggestedActions } from '../suggestedActions';
Expand Down Expand Up @@ -45,6 +45,7 @@ function SendBox(props: Props) {
const [telephoneKeypadShown] = useTelephoneKeypadShown();
const [uiState] = useUIState();
const classNames = useStyles(styles);
const variantClassName = useVariantClassName(styles);
const errorMessageId = useUniqueId('sendbox__error-message-id');
const inputRef = useRef<HTMLTextAreaElement>(null);
const localize = useLocalizer();
Expand Down Expand Up @@ -184,7 +185,7 @@ function SendBox(props: Props) {
return (
<form
{...aria}
className={cx(classNames['sendbox'], props.className)}
className={cx(classNames['sendbox'], variantClassName, props.className)}
data-testid={testIds.sendBoxContainer}
onSubmit={handleFormSubmit}
>
Expand Down
16 changes: 9 additions & 7 deletions packages/fluent-theme/src/components/theme/Theme.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -260,18 +260,20 @@
display: none;
}

:global(.webchat__bubble)::after, :global(.pre-chat-message-activity)::after {
content: '';
position: absolute;
inset: -2px;
border: var(--webchat-strokeWidthThick) solid var(--webchat-colorStrokeFocus2);
:global(.webchat__bubble)::after,
:global(.pre-chat-message-activity)::after {
border-radius: var(--webchat__bubble--border-radius);
content: '';
inset: 0;
outline-offset: 0;
outline: var(--webchat-strokeWidthThick) solid var(--webchat-colorStrokeFocus2);
pointer-events: none;
position: absolute;
}

:global(.pre-chat-message-activity)::after {
inset: 0;
border-radius: var(--webchat-borderRadiusSmall);
border-radius: var(--webchat-borderRadiusMedium);
outline-offset: -3px;
}

:global(.liner-message-activity__text) {
Expand Down

0 comments on commit 3e47786

Please sign in to comment.