Skip to content

Commit 4880020

Browse files
authored
Add CSS var(--webchat__min-width--message-bubble) (#5321)
* Add CSS var(--webchat__min-width--bubble) * Add entry * Revert * Switch back to styleOptions.paddingRegular * Fix fixedWidth * Separate attachment and message min/max width * Fix tests * Add entry
1 parent 1d59ded commit 4880020

20 files changed

+259
-91
lines changed

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ Notes: web developers are advised to use [`~` (tilde range)](https://github.com/
2727
### Breaking changes
2828

2929
- `styleOptions.bubbleImageHeight` is being deprecated in favor of `styleOptions.bubbleImageMaxHeight` and `styleOptions.bubbleImageMinHeight`. The option will be removed on or after 2026-07-05
30+
- `styleOptions.bubbleMaxWidth`/`bubbleMinWidth` is being deprecated in favor of `styleOptions.bubbleAttachmentMaxWidth`/`bubbleAttachmentMinWidth` and `styleOptions.bubbleMessageMaxWidth`/`bubbleMessageMinWidth`. The option will be removed on or after 2026-10-08
3031

3132
### Added
3233

@@ -55,6 +56,8 @@ Notes: web developers are advised to use [`~` (tilde range)](https://github.com/
5556
- (Experimental) Added CSS decorator support into Web Chat white-label experience, in PR [#5312](https://github.com/microsoft/BotFramework-WebChat/pull/5312), by [@OEvgeny](https://github.com/OEvgeny)
5657
- Introduced `WebChatDecorator` component for adding animated borders to activities, in PR [#5312](https://github.com/microsoft/BotFramework-WebChat/pull/5312)
5758
- Added new style options `borderAnimationColor1`, `borderAnimationColor2`, and `borderAnimationColor3` for customizing decorator colors, in PR [#5312](https://github.com/microsoft/BotFramework-WebChat/pull/5312)
59+
- Added `styleOptions.bubbleAttachmentMaxWidth`/`bubbleAttachmentMinWidth` and `styleOptions.bubbleMessageMaxWidth`/`bubbleMessageMinWidth`, in PR [#5321](https://github.com/microsoft/BotFramework-WebChat/pull/5321), by [@compulim](https://github.com/compulim)
60+
- (Experimental) Added more CSS variables support, in PR [#5321](https://github.com/microsoft/BotFramework-WebChat/pull/5321), by [@compulim](https://github.com/compulim)
5861

5962
### Changed
6063

+116
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
<!doctype html>
2+
<html lang="en-US">
3+
<head>
4+
<link href="/assets/index.css" rel="stylesheet" type="text/css" />
5+
<script crossorigin="anonymous" src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
6+
<script crossorigin="anonymous" src="https://unpkg.com/[email protected]/umd/react.production.min.js"></script>
7+
<script crossorigin="anonymous" src="https://unpkg.com/[email protected]/umd/react-dom.production.min.js"></script>
8+
<script crossorigin="anonymous" src="/test-harness.js"></script>
9+
<script crossorigin="anonymous" src="/test-page-object.js"></script>
10+
<script crossorigin="anonymous" src="/__dist__/webchat-es5.js"></script>
11+
<style type="text/css">
12+
.my-webchat {
13+
--webchat__max-width--attachment-bubble: 80%;
14+
--webchat__min-width--attachment-bubble: 80%;
15+
16+
--webchat__max-width--message-bubble: 75%;
17+
--webchat__min-width--message-bubble: 75%;
18+
19+
--webchat__max-height--image-bubble: initial;
20+
--webchat__min-height--image-bubble: initial;
21+
}
22+
</style>
23+
</head>
24+
<body>
25+
<main id="webchat"></main>
26+
<script type="text/babel">
27+
run(async function () {
28+
const {
29+
React,
30+
ReactDOM: { render },
31+
WebChat: { ReactWebChat }
32+
} = window; // Imports in UMD fashion.
33+
34+
const { directLine, store } = testHelpers.createDirectLineEmulator();
35+
36+
const styleOptions = {
37+
bubbleMaxWidth: '75%',
38+
bubbleMinWidth: '75%'
39+
};
40+
41+
render(
42+
<ReactWebChat className="my-webchat" directLine={directLine} store={store} />,
43+
document.getElementById('webchat')
44+
);
45+
46+
await pageConditions.uiConnected();
47+
48+
await directLine.emulateIncomingActivity({
49+
from: { role: 'bot' },
50+
text: 'Dolore excepteur laboris.',
51+
type: 'message'
52+
});
53+
54+
await directLine.emulateIncomingActivity({
55+
from: { role: 'bot' },
56+
text: 'Reprehenderit exercitation do aliqua ad reprehenderit pariatur fugiat et deserunt mollit mollit.',
57+
type: 'message'
58+
});
59+
60+
await directLine.emulateIncomingActivity({
61+
attachments: [
62+
{
63+
contentType: 'image/png',
64+
contentUrl:
65+
'https://raw.githubusercontent.com/microsoft/BotFramework-WebChat/main/media/BotFrameworkWebChat_header.png'
66+
},
67+
{
68+
contentType: 'image/png',
69+
contentUrl:
70+
'https://raw.githubusercontent.com/microsoft/BotFramework-WebChat/main/media/BotFrameworkWebChat_header.png'
71+
}
72+
],
73+
from: { role: 'bot' },
74+
text: 'Sunt elit ad voluptate.',
75+
type: 'message'
76+
});
77+
78+
await directLine.emulateIncomingActivity({
79+
attachmentLayout: 'carousel',
80+
attachments: [
81+
{
82+
contentType: 'image/png',
83+
contentUrl:
84+
'https://raw.githubusercontent.com/microsoft/BotFramework-WebChat/main/media/BotFrameworkWebChat_header.png'
85+
},
86+
{
87+
contentType: 'image/png',
88+
contentUrl:
89+
'https://raw.githubusercontent.com/microsoft/BotFramework-WebChat/main/media/BotFrameworkWebChat_header.png'
90+
}
91+
],
92+
from: { role: 'bot' },
93+
text: 'Sint aliqua nisi aute aliqua.',
94+
type: 'message'
95+
});
96+
97+
await directLine.emulateIncomingActivity({
98+
attachments: [
99+
{
100+
contentType: 'image/png',
101+
thumbnailUrl:
102+
'https://raw.githubusercontent.com/microsoft/BotFramework-WebChat/main/media/BotFrameworkWebChat_header.png'
103+
}
104+
],
105+
from: { role: 'user' },
106+
text: 'Ut irure irure exercitation.',
107+
type: 'message'
108+
});
109+
110+
await pageConditions.numActivitiesShown(5);
111+
112+
await host.snapshot('local');
113+
});
114+
</script>
115+
</body>
116+
</html>
Loading

__tests__/html2/markdown/bug.br.html

+2-3
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,8 @@
1717
React,
1818
ReactDOM: { render },
1919
WebChat: {
20-
Components: { BasicWebChat, Composer },
21-
hooks: { useRenderMarkdownAsHTML },
22-
ReactWebChat
20+
Components: { Composer },
21+
hooks: { useRenderMarkdownAsHTML }
2322
}
2423
} = window; // Imports in UMD fashion.
2524

biome.json

+18-18
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
{
2-
"$schema": "https://biomejs.dev/schemas/1.9.3/schema.json",
3-
"vcs": {
4-
"enabled": true,
5-
"clientKind": "git",
6-
"useIgnoreFile": true
7-
},
8-
"files": {
9-
"ignoreUnknown": false,
10-
"ignore": []
11-
},
2+
"$schema": "https://biomejs.dev/schemas/1.9.3/schema.json",
3+
"vcs": {
4+
"enabled": true,
5+
"clientKind": "git",
6+
"useIgnoreFile": true
7+
},
8+
"files": {
9+
"ignoreUnknown": false,
10+
"ignore": ["**/dist"]
11+
},
1212
"formatter": {
1313
"indentStyle": "space",
1414
"indentWidth": 2
@@ -32,17 +32,17 @@
3232
"enabled": false
3333
}
3434
},
35-
"css": {
35+
"css": {
3636
"parser": {
3737
"cssModules": true
3838
},
39-
"formatter": {
40-
"enabled": true,
39+
"formatter": {
40+
"enabled": true,
4141
"quoteStyle": "single",
4242
"lineWidth": 120
43-
},
44-
"linter": {
45-
"enabled": true
46-
}
47-
}
43+
},
44+
"linter": {
45+
"enabled": true
46+
}
47+
}
4848
}

packages/api/src/StyleOptions.ts

+14-3
Original file line numberDiff line numberDiff line change
@@ -176,9 +176,17 @@ type StyleOptions = {
176176
*/
177177
bubbleImageMinHeight?: number | undefined;
178178

179-
bubbleMaxWidth?: number;
179+
/* @deprecated Please use `bubbleAttachmentMaxWidth` and `bubbleMessageMaxWidth` instead. */
180+
bubbleMaxWidth?: number | undefined;
181+
/* @deprecated Please use `bubbleAttachmentMaxWidth` and `bubbleMessageMaxWidth` instead. */
182+
bubbleMinWidth?: number | undefined;
183+
184+
bubbleAttachmentMaxWidth?: number | undefined;
185+
bubbleAttachmentMinWidth?: number | undefined;
186+
bubbleMessageMaxWidth?: number | undefined;
187+
bubbleMessageMinWidth?: number | undefined;
188+
180189
bubbleMinHeight?: number;
181-
bubbleMinWidth?: number;
182190

183191
/**
184192
* Nub offset ''bottom' will render nub at the bottom
@@ -915,7 +923,10 @@ type StyleOptions = {
915923
// 2. Renamed/deprecated options, only the newer option will be kept, the older option will be dropped.
916924
// Internally, no code should use the deprecated value except the migration code.
917925
type StrictStyleOptions = Required<
918-
Omit<StyleOptions, 'bubbleImageHeight' | 'hideScrollToEndButton' | 'newMessagesButtonFontSize'>
926+
Omit<
927+
StyleOptions,
928+
'bubbleImageHeight' | 'bubbleMaxWidth' | 'bubbleMinWidth' | 'hideScrollToEndButton' | 'newMessagesButtonFontSize'
929+
>
919930
> & {
920931
bubbleFromUserNubOffset: number;
921932
bubbleNubOffset: number;

packages/api/src/defaultStyleOptions.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,13 @@ const DEFAULT_OPTIONS: Required<StyleOptions> = {
5656
bubbleImageHeight: undefined,
5757
bubbleImageMaxHeight: 240, // Based on previously default `bubbleImageHeight` of 240px.
5858
bubbleImageMinHeight: 240, // TODO: Should change to 180px. Based on 320px bubble width showing a 16:9 image, or `320 / (16 / 9)`. 320px bubble width is based on 360px wide of the chat canvas.
59-
bubbleMaxWidth: 480, // Based off screen width = 600px
59+
bubbleMaxWidth: undefined, // Deprecated.
60+
bubbleMinWidth: undefined, // Deprecated.
61+
bubbleAttachmentMaxWidth: 480, // Based off screen width = 600px
62+
bubbleAttachmentMinWidth: 250, // min screen width = 300px; Microsoft Edge requires 372px (https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/13621468/)
63+
bubbleMessageMaxWidth: 480, // Based off screen width = 600px
64+
bubbleMessageMinWidth: 0,
6065
bubbleMinHeight: 40,
61-
bubbleMinWidth: 250, // min screen width = 300px; Microsoft Edge requires 372px (https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/13621468/)
6266
bubbleNubOffset: 0,
6367
bubbleNubSize: undefined,
6468
bubbleTextColor: 'Black',

packages/api/src/normalizeStyleOptions.ts

+32
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,14 @@ const bubbleImageHeightDeprecation = warnOnce(
77
'"styleOptions.bubbleImageHeight" has been deprecated. Use "styleOptions.bubbleImageMaxHeight" and "styleOptions.bubbleImageMinHeight" instead. This deprecation migration will be removed on or after 2026-07-05.'
88
);
99

10+
const bubbleMaxWidthDeprecation = warnOnce(
11+
'"styleOptions.bubbleMaxWidth" has been deprecated. Use "styleOptions.bubbleAttachmentMaxWidth" and "styleOptions.bubbleMessageMaxWidth" instead. This deprecation migration will be removed on or after 2026-07-05.'
12+
);
13+
14+
const bubbleMinWidthDeprecation = warnOnce(
15+
'"styleOptions.bubbleMinWidth" has been deprecated. Use "styleOptions.bubbleAttachmentMinWidth" and "styleOptions.bubbleMessageMinWidth" instead. This deprecation migration will be removed on or after 2026-07-05.'
16+
);
17+
1018
const hideScrollToEndButtonDeprecation = warnOnce(
1119
'"styleOptions.hideScrollToEndButton" has been deprecated. To hide scroll to end button, set "scrollToEndBehavior" to false. This deprecation migration will be removed on or after 2023-06-02.'
1220
);
@@ -190,6 +198,30 @@ export default function normalizeStyleOptions({
190198
filledOptions.bubbleImageHeight = undefined;
191199
}
192200

201+
if (typeof options.bubbleAttachmentMaxWidth === 'undefined' && options.bubbleMaxWidth) {
202+
bubbleMaxWidthDeprecation();
203+
filledOptions.bubbleAttachmentMaxWidth = options.bubbleMaxWidth;
204+
filledOptions.bubbleMaxWidth = undefined;
205+
}
206+
207+
if (typeof options.bubbleAttachmentMinWidth === 'undefined' && options.bubbleMinWidth) {
208+
bubbleMinWidthDeprecation();
209+
filledOptions.bubbleAttachmentMinWidth = options.bubbleMinWidth;
210+
filledOptions.bubbleMinWidth = undefined;
211+
}
212+
213+
if (typeof options.bubbleMessageMaxWidth === 'undefined' && options.bubbleMaxWidth) {
214+
bubbleMaxWidthDeprecation();
215+
filledOptions.bubbleMessageMaxWidth = options.bubbleMaxWidth;
216+
filledOptions.bubbleMaxWidth = undefined;
217+
}
218+
219+
if (typeof options.bubbleMessageMinWidth === 'undefined' && options.bubbleMinWidth) {
220+
bubbleMinWidthDeprecation();
221+
filledOptions.bubbleMessageMinWidth = options.bubbleMinWidth;
222+
filledOptions.bubbleMinWidth = undefined;
223+
}
224+
193225
return {
194226
...filledOptions,
195227
bubbleFromUserNubOffset: normalizedBubbleFromUserNubOffset,

packages/component/src/Styles/CustomPropertyNames.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,14 @@ const CustomPropertyNames = Object.freeze({
1010
FontSizeSmall: '--webchat__font-size--small',
1111
IconURLExternalLink: '--webchat__icon-url--external-link',
1212
MaxHeightImageBubble: '--webchat__max-height--image-bubble',
13-
MaxWidthBubble: '--webchat__max-width--bubble',
13+
MaxWidthAttachmentBubble: '--webchat__max-width--attachment-bubble',
14+
MinWidthAttachmentBubble: '--webchat__min-width--attachment-bubble',
15+
MaxWidthMessageBubble: '--webchat__max-width--message-bubble',
16+
MinWidthMessageBubble: '--webchat__min-width--message-bubble',
1417
MinHeightBubble: '--webchat__min-height--bubble',
1518
MinHeightImageBubble: '--webchat__min-height--image-bubble',
16-
PaddingRegular: '--webchat__padding--regular'
19+
PaddingRegular: '--webchat__padding--regular',
20+
SizeAvatar: '--webchat__size--avatar'
1721
});
1822

1923
// This is for type-checking only to make sure the CSS custom property names is `--webchat__${string}`.
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import { StrictStyleOptions } from 'botframework-webchat-api';
1+
import CSSTokens from '../CSSTokens';
22

3-
export default function AudioAttachment({ avatarSize }: StrictStyleOptions) {
3+
export default function AudioAttachment() {
44
return {
55
// TODO: [P2] We should not set "display" in styleSet, this will allow the user to break the layout for no good reasons.
66
display: 'flex',
7-
minHeight: avatarSize
7+
minHeight: CSSTokens.SizeAvatar
88
};
99
}
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import { StrictStyleOptions } from 'botframework-webchat-api';
2+
import CSSTokens from '../CSSTokens';
23

3-
export default function createAvatarStyle({ avatarBorderRadius, avatarSize }: StrictStyleOptions) {
4+
export default function createAvatarStyle({ avatarBorderRadius }: StrictStyleOptions) {
45
return {
56
'&.webchat__defaultAvatar': {
67
borderRadius: avatarBorderRadius,
7-
height: avatarSize,
8-
width: avatarSize
8+
height: CSSTokens.SizeAvatar,
9+
width: CSSTokens.SizeAvatar
910
}
1011
};
1112
}

packages/component/src/Styles/StyleSet/CarouselFilmStrip.ts

+9-7
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
/* eslint no-magic-numbers: ["error", { "ignore": [2] }] */
22
import { StrictStyleOptions } from 'botframework-webchat-api';
33

4+
import CSSTokens from '../CSSTokens';
45
import mirrorStyle from '../mirrorStyle';
56

67
export default function CarouselFilmStrip({
78
avatarSize,
8-
bubbleMaxWidth,
9+
bubbleMessageMaxWidth,
910
paddingRegular,
1011
transitionDuration
1112
}: StrictStyleOptions) {
@@ -17,23 +18,24 @@ export default function CarouselFilmStrip({
1718
marginBottom: -17
1819
},
1920

20-
'& .webchat__carousel-filmstrip__message': {
21-
maxWidth: bubbleMaxWidth,
21+
'& .webchat__carousel-filmstrip__bubble': {
22+
maxWidth: CSSTokens.MaxWidthMessageBubble,
23+
minWidth: CSSTokens.MinWidthMessageBubble,
2224
transitionDuration,
2325
transitionProperty: 'max-width'
2426
},
2527

2628
'&.webchat__carousel-filmstrip--hide-nub, &.webchat__carousel-filmstrip--show-nub, &.webchat__carousel-filmstrip--hide-avatar, &.webchat__carousel-filmstrip--show-avatar':
2729
{
28-
'& .webchat__carousel-filmstrip__message': {
29-
maxWidth: bubbleMaxWidth + paddingRegular
30+
'& .webchat__carousel-filmstrip__bubble': {
31+
maxWidth: bubbleMessageMaxWidth + paddingRegular
3032
}
3133
},
3234

3335
'& .webchat__carousel-filmstrip__alignment-pad': {
3436
transitionDuration,
3537
transitionProperty: 'width',
36-
width: paddingRegular
38+
width: CSSTokens.PaddingRegular
3739
},
3840

3941
'&.webchat__carousel-filmstrip--extra-trailing .webchat__carousel-filmstrip__alignment-pad': {
@@ -58,7 +60,7 @@ export default function CarouselFilmStrip({
5860

5961
'&.webchat__carousel-filmstrip--hide-avatar, &.webchat__carousel-filmstrip--show-avatar': {
6062
'& .webchat__carousel-filmstrip__avatar-gutter': {
61-
width: avatarSize
63+
width: CSSTokens.SizeAvatar
6264
}
6365
},
6466

0 commit comments

Comments
 (0)