Skip to content
Merged
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ Notes: web developers are advised to use [`~` (tilde range)](https://github.com/
- Resolved [#5463](https://github.com/microsoft/BotFramework-WebChat/issues/5463). Added attachment preview for `sendAttachmentOn: "send"`, in PR [#5464](https://github.com/microsoft/BotFramework-WebChat/pull/5464), by [@compulim](https://github.com/compulim), in PR [#5492](https://github.com/microsoft/BotFramework-WebChat/pull/5492), by [@OEvgeny](https://github.com/OEvgeny)
- Attaching files will no longer remove previously attached files
- Updated Fluent theme to use the new attachment preview feature
- Added collapsible activity and activity with abstract handling, in PR [#5506](https://github.com/microsoft/BotFramework-WebChat/pull/5506), by [@OEvgeny](https://github.com/OEvgeny)

### Changed

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.
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
await pageConditions.minNumActivitiesShown(2);
await pageConditions.scrollToBottomCompleted();

const messageRole = document.querySelector('.webchat__stacked-layout__message-row').getAttribute('role');
const messageRole = document.querySelector('.stacked-layout__message-row').getAttribute('role');

expect(messageRole).toEqual('group');
});
Expand Down
Binary file modified __tests__/html2/activity/citation.longRef.copilot.html.snap-1.png
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.
Binary file modified __tests__/html2/activity/citation.longRef.html.snap-1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions __tests__/html2/activity/collapsible.copilot.dark.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<!doctype html>
<html>
<head>
<title>Collapsible activity (copilot, dark)</title>
<script>
location = './collapsible?variant=copilot&fluent-theme=dark';
</script>
</head>
<body></body>
</html>
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.
10 changes: 10 additions & 0 deletions __tests__/html2/activity/collapsible.copilot.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<!doctype html>
<html>
<head>
<title>Collapsible activity (copilot)</title>
<script>
location = './collapsible?variant=copilot';
</script>
</head>
<body></body>
</html>
10 changes: 10 additions & 0 deletions __tests__/html2/activity/collapsible.fluent.dark.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<!doctype html>
<html>
<head>
<title>Collapsible activity (fluent, dark)</title>
<script>
location = './collapsible?variant=fluent&fluent-theme=dark';
</script>
</head>
<body></body>
</html>
10 changes: 10 additions & 0 deletions __tests__/html2/activity/collapsible.fluent.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<!doctype html>
<html>
<head>
<title>Collapsible activity (fluent)</title>
<script>
location = './collapsible?variant=fluent';
</script>
</head>
<body></body>
</html>
377 changes: 377 additions & 0 deletions __tests__/html2/activity/collapsible.html

Large diffs are not rendered by default.

Binary file modified __tests__/html2/copyButton/layout.copilot.dark.html.snap-1.png
Binary file modified __tests__/html2/copyButton/layout.copilot.light.html.snap-1.png
Binary file modified __tests__/html2/copyButton/layout.fluent.dark.html.snap-1.png
Binary file modified __tests__/html2/copyButton/layout.fluent.light.html.snap-1.png
Binary file modified __tests__/html2/copyButton/layout.html.snap-1.png
Binary file modified __tests__/html2/grouping/fluentTheme.html.snap-1.png
Binary file modified __tests__/html2/linkDefinition/badge.copilot.html.snap-1.png
Binary file modified __tests__/html2/linkDefinition/badge.dark.copilot.html.snap-1.png
Binary file modified __tests__/html2/linkDefinition/badge.fluent.html.snap-1.png
Binary file modified __tests__/html2/linkDefinition/badge.html.snap-1.png
Binary file modified __tests__/html2/side-by-side/codeblock.navigation.html.snap-1.png
Binary file modified __tests__/html2/side-by-side/codeblock.navigation.html.snap-2.png
Binary file modified __tests__/html2/side-by-side/codeblock.navigation.html.snap-3.png
Binary file modified __tests__/html2/side-by-side/codeblock.navigation.html.snap-5.png
Binary file modified __tests__/html2/side-by-side/feedback.navigation.html.snap-1.png
Binary file modified __tests__/html2/side-by-side/feedback.navigation.html.snap-2.png
Binary file modified __tests__/html2/side-by-side/feedback.navigation.html.snap-3.png
Binary file modified __tests__/html2/side-by-side/feedback.navigation.html.snap-4.png
Binary file modified __tests__/html2/side-by-side/feedback.navigation.html.snap-5.png
Binary file modified __tests__/html2/side-by-side/feedback.navigation.html.snap-6.png
Binary file modified __tests__/html2/side-by-side/feedback.navigation.html.snap-7.png
Binary file modified __tests__/html2/side-by-side/fluent.dark.html.snap-1.png
Binary file modified __tests__/html2/side-by-side/fluent.html.snap-1.png
2 changes: 1 addition & 1 deletion __tests__/html2/side-by-side/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -846,7 +846,7 @@
await host.snapshot('local');
await host.sendKeys('ENTER');
// hide timestamp to not fail snapshot if is not relative
sendbox.parentElement.parentElement.parentElement.parentElement.querySelector('.webchat__basic-transcript__activity:last-child .webchat__stacked-layout__status').style.opacity = 0
sendbox.parentElement.parentElement.parentElement.parentElement.querySelector('.webchat__basic-transcript__activity:last-child .stacked-layout__status').style.opacity = 0;
await host.snapshot('local');
await host.sendShiftTab();
await host.snapshot('local');
Expand Down
Binary file modified __tests__/html2/side-by-side/index.html.snap-1.png
Binary file modified __tests__/html2/side-by-side/pre-chat.navigation.html.snap-1.png
Binary file modified __tests__/html2/side-by-side/pre-chat.navigation.html.snap-2.png
Binary file modified __tests__/html2/side-by-side/pre-chat.navigation.html.snap-4.png
Binary file modified __tests__/html2/side-by-side/pre-chat.navigation.html.snap-6.png
Binary file modified __tests__/html2/side-by-side/pre-chat.navigation.html.snap-8.png
Binary file modified __tests__/html2/side-by-side/pre-chat.navigation.html.snap-9.png
Binary file modified __tests__/html2/side-by-side/pre-liner.dark.html.snap-1.png
Binary file modified __tests__/html2/side-by-side/pre-liner.html.snap-1.png
Binary file modified __tests__/html2/side-by-side/streaming.dark.html.snap-1.png
4 changes: 2 additions & 2 deletions __tests__/html2/side-by-side/streaming.html
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<!doctype html>
<html>
<head>
<title>Two Chat panes side-by-side (dark): streaming (right)</title>
<title>Two Chat panes side-by-side: streaming (right)</title>
<script>
location = './?transcript=0&transcript=4&theme=fluent-dark';
location = './?transcript=0&transcript=4';
</script>
</head>
<body></body>
Expand Down
Binary file modified __tests__/html2/side-by-side/streaming.html.snap-1.png
2 changes: 2 additions & 0 deletions packages/api/src/decorator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@

export { default as DecoratorComposer } from './decorator/DecoratorComposer';
export { type DecoratorMiddleware } from './decorator/types';
export { default as useDecoratorRequest, type InferDecoratorRequest } from './decorator/useDecoratorRequest';

// ActivityBorderDecorator

export {
default as ActivityBorderDecorator,
createActivityBorderMiddleware,
ActivityBorderDecoratorRequest,
type ActivityBorderDecoratorProps
} from './decorator/ActivityBorder/ActivityBorderDecorator';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
createActivityBorderMiddleware,
type ActivityBorderDecoratorMiddlewareRequest
} from './private/ActivityBorderDecoratorMiddleware';
import ActivityBorderDecoratorRequestContext from './private/ActivityBorderDecoratorRequestContext';

const supportedActivityRoles: ActivityBorderDecoratorMiddlewareRequest['from'][] = [
'bot',
Expand Down Expand Up @@ -39,12 +40,17 @@ function ActivityBorderDecorator({ activity, children }: ActivityBorderDecorator
};
}, [activity]);

const requestValue = useMemo(() => Object.freeze({ request }), [request]);

return (
<ActivityBorderDecoratorMiddlewareProxy fallbackComponent={PassthroughFallback} request={request}>
{children}
</ActivityBorderDecoratorMiddlewareProxy>
<ActivityBorderDecoratorRequestContext.Provider value={requestValue}>
<ActivityBorderDecoratorMiddlewareProxy fallbackComponent={PassthroughFallback} request={request}>
{children}
</ActivityBorderDecoratorMiddlewareProxy>
</ActivityBorderDecoratorRequestContext.Provider>
);
}

export default memo(ActivityBorderDecorator);
export { createActivityBorderMiddleware, type ActivityBorderDecoratorProps };
export { ActivityBorderDecoratorRequestContext as ActivityBorderDecoratorRequest };
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { createContext } from 'react';
import { ActivityBorderDecoratorMiddlewareRequest } from './ActivityBorderDecoratorMiddleware';

type ActivityBorderDecoratorRequestContextType = Readonly<{
request: ActivityBorderDecoratorMiddlewareRequest;
}>;

const ActivityBorderDecoratorRequestContext = createContext<ActivityBorderDecoratorRequestContextType>(
Object.freeze({
request: Object.freeze({
from: undefined,
livestreamingState: undefined
})
})
);

export default ActivityBorderDecoratorRequestContext;
export { type ActivityBorderDecoratorRequestContextType };
15 changes: 15 additions & 0 deletions packages/api/src/decorator/useDecoratorRequest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { useContext } from 'react';
import { ActivityBorderDecoratorRequest } from './ActivityBorder/ActivityBorderDecorator';

export default function useDecoratorRequest(type: typeof ActivityBorderDecoratorRequest) {
const request = useContext(type)?.request;

if (!request) {
throw new Error(`useDecoratorRequest must be used within a ${type}Provider`);
}

return request;
}

export type InferDecoratorRequest<T extends typeof ActivityBorderDecoratorRequest> =
T extends React.Context<infer U> ? (U extends { request: infer R } ? R : never) : never;
4 changes: 2 additions & 2 deletions packages/bundle/src/module/exports-minimal.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { StrictStyleOptions, StyleOptions } from 'botframework-webchat-api';
import * as apiDecorator from 'botframework-webchat-api/decorator';
import { WebChatDecorator } from 'botframework-webchat-component/decorator';
import * as componentDecorator from 'botframework-webchat-component/decorator';
import * as internal from 'botframework-webchat-component/internal';
import { Constants, createStore, createStoreWithDevTools, createStoreWithOptions } from 'botframework-webchat-core';

Expand Down Expand Up @@ -55,7 +55,7 @@ export default ReactWebChat;

const decorator = Object.freeze({
...apiDecorator,
WebChatDecorator
...componentDecorator
});

export {
Expand Down
56 changes: 56 additions & 0 deletions packages/component/src/Activity/AttachmentRow.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { useStyles } from 'botframework-webchat-styles/react';
import { reactNode, validateProps } from 'botframework-webchat-react-valibot';
import cx from 'classnames';
import React, { memo } from 'react';
import { boolean, object, optional, pipe, readonly, string, type InferInput } from 'valibot';

import ScreenReaderText from '../ScreenReaderText';
import Bubble from './Bubble';

import styles from './StackedLayout.module.css';

const attachmentRowPropsSchema = pipe(
object({
attachedAlt: string(),
children: optional(reactNode()),
fromUser: boolean(),
hasAvatar: boolean(),
hasNub: boolean(),
showBubble: optional(boolean())
}),
readonly()
);

type AttachmentRowProps = InferInput<typeof attachmentRowPropsSchema>;

function AttachmentRow(props: AttachmentRowProps) {
const {
attachedAlt,
children,
fromUser,
hasAvatar,
hasNub,
showBubble = true
} = validateProps(attachmentRowPropsSchema, props);
const classNames = useStyles(styles);

return (
<div aria-roledescription="attachment" className={classNames['stacked-layout__attachment-row']} role="group">
<ScreenReaderText text={attachedAlt} />
{showBubble ? (
<Bubble
className={classNames['stacked-layout__attachment']}
fromUser={fromUser}
nub={hasAvatar || hasNub ? 'hidden' : false}
>
{children}
</Bubble>
) : (
<div className={cx(classNames['stacked-layout__attachment'])}>{children}</div>
)}
</div>
);
}

export default memo(AttachmentRow);
export { attachmentRowPropsSchema, type AttachmentRowProps };
38 changes: 38 additions & 0 deletions packages/component/src/Activity/CodeBlockContent.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
:global(.webchat) .code-block-content {
border-block: var(--webchat__border-width--bubble) var(--webchat__border-style--bubble)
var(--webchat__border-color--bubble);
border-radius: var(--webchat__border-radius--bubble);
display: block;
font-family: var(--webchat__font--primary);
font-size: 14px;
font-style: normal;
font-weight: 400;
margin-block-end: calc(var(--webchat__border-width--bubble) * -1);
overflow: hidden;
overflow: clip;
position: relative;
}

:global(.webchat) .code-block-content__header {
align-items: center;
display: flex;
gap: var(--webchat__padding--regular);
justify-content: space-between;
padding: var(--webchat__padding--regular);
}

:global(.webchat) .code-block-content__title {
font-weight: 600;

&::first-letter {
text-transform: uppercase;
}
}

:global(.webchat) .code-block-content__code-block {
border: none;
margin: 0;
max-height: 360px;
overflow-y: auto;
padding: var(--webchat__padding--regular) 8px var(--webchat__padding--regular) var(--webchat__padding--regular);
}
42 changes: 42 additions & 0 deletions packages/component/src/Activity/CodeBlockContent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { useStyles } from 'botframework-webchat-styles/react';
import { validateProps } from 'botframework-webchat-react-valibot';
import cx from 'classnames';
import React, { memo } from 'react';
import { object, optional, pipe, readonly, string, type InferInput } from 'valibot';

import useCodeBlockTag from '../providers/CustomElements/useCodeBlockTagName';

import styles from './CodeBlockContent.module.css';

const codeBlockContentPropsSchema = pipe(
object({
code: string(),
language: optional(string()),
title: optional(string())
}),
readonly()
);

type CodeBlockContentProps = InferInput<typeof codeBlockContentPropsSchema>;

function CodeBlockContent(props: CodeBlockContentProps) {
const { code, language, title } = validateProps(codeBlockContentPropsSchema, props);
const classNames = useStyles(styles);
const [, CodeBlock] = useCodeBlockTag();

return (
<div className={classNames['code-block-content']}>
{title && (
<div className={cx(classNames['code-block-content__header'])}>
<div className={cx(classNames['code-block-content__title'])}>{title}</div>
</div>
)}
<CodeBlock className={cx(classNames['code-block-content__code-block'])} language={language}>
<code>{code}</code>
</CodeBlock>
</div>
);
}

export default memo(CodeBlockContent);
export { codeBlockContentPropsSchema, type CodeBlockContentProps };
29 changes: 29 additions & 0 deletions packages/component/src/Activity/CollapsibleContent.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
:global(.webchat) .collapsible-content {
&[open] .collapsible-content__chevron {
transform: rotate(180deg);
}
}

:global(.webchat) .collapsible-content__summary {
cursor: pointer;
display: inline-flex;
font-family: var(--webchat__font--primary);
gap: calc(var(--webchat__padding--regular) / 2);
list-style: none;
margin: var(--webchat__padding--regular);
padding: 0;

&::-webkit-details-marker {
display: none;
}

&:focus-visible {
outline-offset: 3px;
}
}

:global(.webchat) .collapsible-content__content {
display: flex;
flex-direction: column;
margin-block-start: calc(var(--webchat__padding--regular) * -1);
}
Loading
Loading