botframework-webchat-fluent-theme 4.18.1-main.20250701.b63791f → 4.18.1-main.20250708.40736b1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "botframework-webchat-fluent-theme",
3
- "version": "4.18.1-main.20250701.b63791f",
3
+ "version": "4.18.1-main.20250708.40736b1",
4
4
  "description": "Fluent theme for Bot Framework Web Chat",
5
5
  "main": "./dist/botframework-webchat-fluent-theme.js",
6
6
  "types": "./dist/botframework-webchat-fluent-theme.d.ts",
@@ -68,15 +68,15 @@
68
68
  "@types/math-random": "^1.0.2",
69
69
  "@types/node": "^22.13.4",
70
70
  "@types/react": "^16.14.62",
71
- "botframework-webchat-base": "4.18.1-main.20250701.b63791f",
72
- "botframework-webchat-styles": "4.18.1-main.20250701.b63791f",
71
+ "botframework-webchat-base": "4.18.1-main.20250708.40736b1",
72
+ "botframework-webchat-styles": "4.18.1-main.20250708.40736b1",
73
73
  "tsup": "^8.3.6",
74
74
  "typescript": "^5.7.3"
75
75
  },
76
76
  "dependencies": {
77
- "botframework-webchat-api": "4.18.1-main.20250701.b63791f",
78
- "botframework-webchat-component": "4.18.1-main.20250701.b63791f",
79
- "botframework-webchat-core": "4.18.1-main.20250701.b63791f",
77
+ "botframework-webchat-api": "4.18.1-main.20250708.40736b1",
78
+ "botframework-webchat-component": "4.18.1-main.20250708.40736b1",
79
+ "botframework-webchat-core": "4.18.1-main.20250708.40736b1",
80
80
  "classnames": "2.5.1",
81
81
  "inject-meta-tag": "0.0.1",
82
82
  "math-random": "2.0.1",
@@ -19,7 +19,7 @@
19
19
  --webchat-externalLink-maxWidth: var(--externalLink-maxWidth, 204px);
20
20
 
21
21
  /* Override for stacked layout message which has user message bubble props */
22
- &:has(:global(.webchat__stacked-layout .webchat__bubble--from-user)) {
22
+ &:has(:global(.stacked-layout .webchat__bubble--from-user)) {
23
23
  --webchat__bubble--background-color: var(--webchat-colorBrandBackground2);
24
24
  --webchat__bubble--block-padding: var(--webchat-spacingVerticalS);
25
25
  --webchat__bubble--min-width: auto;
@@ -41,7 +41,7 @@
41
41
  margin: 0 0 var(--webchat-spacingHorizontalXXS);
42
42
  }
43
43
 
44
- :global(.webchat__stacked-layout__status) {
44
+ :global(.stacked-layout__status) {
45
45
  order: -1;
46
46
  }
47
47
 
@@ -70,7 +70,7 @@
70
70
  padding: var(--webchat-spacingVerticalMNudge) var(--webchat-spacingHorizontalM) var(--webchat-spacingVerticalM);
71
71
  position: relative;
72
72
 
73
- :global(.webchat__stacked-layout) {
73
+ :global(.stacked-layout) {
74
74
  margin: 0;
75
75
  position: static;
76
76
  }
@@ -81,31 +81,24 @@
81
81
  }
82
82
 
83
83
  :global(.webchat__bubble .webchat__bubble__content) {
84
- overflow: visible;
85
- }
86
-
87
- :global(.webchat__text-content) {
88
- margin-inline-start: 28px;
89
- }
90
-
91
- :global(.border-loader) {
92
84
  display: flex;
93
- flex-flow: column nowrap;
85
+ flex-direction: column;
94
86
  gap: var(--webchat-spacingVerticalS);
95
- padding-inline-end: var(--webchat-spacingHorizontalM);
96
- width: 500px;
87
+ margin-block: calc(var(--webchat-spacingVerticalS) * -1);
88
+ margin-inline: 20px calc(var(--webchat-spacingHorizontalS) * -1);
89
+ padding-block: var(--webchat-spacingVerticalS);
90
+ padding-inline: var(--webchat-spacingHorizontalS);
97
91
  }
98
92
 
99
- :global(.border-loader__track) {
100
- border-radius: inherit;
101
- box-sizing: border-box;
102
- clip-path: border-box;
103
- margin-inline-start: 28px;
104
- order: -1;
105
- width: auto;
93
+ :global(.webchat__bubble .collapsible-content .collapsible-content__content .stacked-layout__attachment-list) {
94
+ margin-block-start: var(--webchat-spacingVerticalS);
95
+ }
96
+
97
+ :global(.webchat__bubble .collapsible-content .collapsible-content__content .stacked-layout__attachment) {
98
+ max-width: var(--webchat__bubble--max-width);
106
99
  }
107
100
 
108
- :global(.webchat__stacked-layout__status) {
101
+ :global(.stacked-layout__status) {
109
102
  display: none;
110
103
  }
111
104
  }
@@ -116,36 +109,45 @@
116
109
  }
117
110
 
118
111
  /* Stacked layout */
119
- :global(.webchat-fluent) .activity-decorator :global(.webchat__stacked-layout) {
112
+ :global(.webchat-fluent) .activity-decorator :global(.stacked-layout) {
120
113
  display: flex;
121
114
  flex-flow: column nowrap;
115
+ margin-inline: var(--webchat-spacingHorizontalMNudge);
116
+
117
+ :global(.stacked-layout__title) {
118
+ font-size: var(--webchat-fontSizeBase400);
119
+ line-height: var(--webchat-lineHeightBase400);
120
+ color: var(--webchat-colorNeutralForeground4);
121
+ margin: var(--webchat__bubble--block-padding) var(--webchat__bubble--inline-padding) 0;
122
+ }
123
+
124
+ :global(.stacked-layout__attachment-row) {
125
+ margin-block-start: var(--webchat-spacingVerticalMNudge);
126
+ }
127
+
128
+ &:global(.stacked-layout--no-message .stacked-layout__attachment-row) {
129
+ margin-block-start: 0;
130
+ }
122
131
  }
123
132
 
124
133
  /* Stacked layout which has message bubble */
125
- :global(.webchat-fluent)
126
- .activity-decorator
127
- :global(.webchat__stacked-layout .webchat__stacked-layout__content:has(.webchat__bubble)) {
134
+ :global(.webchat-fluent) .activity-decorator :global(.stacked-layout .stacked-layout__content:has(.webchat__bubble)) {
128
135
  max-width: 100%;
129
136
  overflow: visible;
130
137
  }
131
138
 
132
139
  /* Message status */
133
- :global(.webchat-fluent) .activity-decorator :global(.webchat__stacked-layout .webchat__stacked-layout__status) {
140
+ :global(.webchat-fluent) .activity-decorator :global(.stacked-layout .stacked-layout__status) {
134
141
  font-size: var(--webchat__font-size--small);
135
142
  line-height: var(--webchat__line-height--small);
136
143
  }
137
144
 
138
145
  /* Message bubble */
139
- :global(.webchat-fluent) .activity-decorator :global(.webchat__stacked-layout .webchat__bubble) {
146
+ :global(.webchat-fluent) .activity-decorator :global(.stacked-layout .webchat__bubble) {
140
147
  max-width: min(var(--webchat__bubble--max-width), 100%);
141
148
  min-width: var(--webchat__bubble--min-width);
142
149
  overflow: visible;
143
150
 
144
- /* Take all width available when has message bubble latency loader */
145
- &:has(:global(.border-loader)) {
146
- width: 100%;
147
- }
148
-
149
151
  /* Ensure activity loader doesn't have bubble and shadow */
150
152
  &:has(:global(.activity-loader)) :global(.webchat__bubble__content) {
151
153
  background: transparent;
@@ -154,9 +156,7 @@
154
156
  }
155
157
 
156
158
  /* Message bubble content */
157
- :global(.webchat-fluent)
158
- .activity-decorator
159
- :global(.webchat__stacked-layout .webchat__bubble .webchat__bubble__content) {
159
+ :global(.webchat-fluent) .activity-decorator :global(.stacked-layout .webchat__bubble .webchat__bubble__content) {
160
160
  background-color: var(--webchat__bubble--background-color);
161
161
  border-radius: var(--webchat__bubble--border-radius);
162
162
  border-width: 0;
@@ -168,7 +168,7 @@
168
168
  }
169
169
 
170
170
  /* Message bubble text content */
171
- :global(.webchat-fluent) .activity-decorator :global(.webchat__stacked-layout .webchat__bubble .webchat__text-content) {
171
+ :global(.webchat-fluent) .activity-decorator :global(.stacked-layout .webchat__bubble .webchat__text-content) {
172
172
  font-size: var(--webchat__font-size--medium);
173
173
  line-height: var(--webchat__line-height--medium);
174
174
  min-height: auto;
@@ -187,7 +187,7 @@
187
187
  /* Message bubble text content generated badge */
188
188
  :global(.webchat-fluent)
189
189
  .activity-decorator
190
- :global(.webchat__stacked-layout .webchat__bubble .webchat__text-content__generated-badge) {
190
+ :global(.stacked-layout .webchat__bubble .webchat__text-content__generated-badge) {
191
191
  align-items: center;
192
192
  align-self: flex-start;
193
193
  background-color: var(--webchat-colorNeutralBackground5);
@@ -203,9 +203,7 @@
203
203
  }
204
204
 
205
205
  /* Message bubble attachment content */
206
- :global(.webchat-fluent)
207
- .activity-decorator
208
- :global(.webchat__stacked-layout .webchat__bubble .webchat__fileContent__badge) {
206
+ :global(.webchat-fluent) .activity-decorator :global(.stacked-layout .webchat__bubble .webchat__fileContent__badge) {
209
207
  cursor: default;
210
208
  font-size: var(--webchat-fontSizeBase300);
211
209
  line-height: var(--webchat-lineHeightBase300);
@@ -222,10 +220,70 @@
222
220
 
223
221
  :global(.webchat-fluent)
224
222
  .activity-decorator
225
- :global(.webchat__stacked-layout .webchat__bubble .webchat__fileContent__downloadIcon) {
223
+ :global(.stacked-layout .webchat__bubble .webchat__fileContent__downloadIcon) {
226
224
  color: var(--webchat-colorBrandForegroundLink);
227
225
  }
228
226
 
227
+ /* Message bubble collapsible content */
228
+ :global(.webchat-fluent) .activity-decorator :global(.stacked-layout .webchat__bubble .collapsible-content) {
229
+ :global(.collapsible-content__summary) {
230
+ margin-block: var(--webchat__bubble--block-padding);
231
+ margin-inline: var(--webchat__bubble--inline-padding);
232
+
233
+ &:focus-visible {
234
+ border-radius: var(--webchat-borderRadiusSmall);
235
+ outline-offset: 4px;
236
+ outline: var(--webchat-strokeWidthThick) solid var(--webchat-colorStrokeFocus2);
237
+ }
238
+ }
239
+
240
+ :global(.collapsible-content__content) {
241
+ margin-block: 0 var(--webchat__bubble--block-padding);
242
+ }
243
+
244
+ :global(.collapsible-content__content .stacked-layout__attachment-list) {
245
+ gap: var(--webchat-spacingVerticalS);
246
+ }
247
+
248
+ :global(.collapsible-content__content .stacked-layout__attachment-row) {
249
+ margin: 0;
250
+ }
251
+
252
+ :global(.collapsible-content__content .stacked-layout__attachment-row .webchat__text-content) {
253
+ padding-block: 0;
254
+ }
255
+ }
256
+
257
+ /* Message bubble code block content */
258
+ :global(.webchat-fluent) .activity-decorator :global(.stacked-layout .webchat__bubble .code-block-content) {
259
+ border-radius: var(--webchat-borderRadiusXLarge);
260
+ border: var(--webchat-strokeWidthThin) solid var(--webchat-colorNeutralStroke1);
261
+ font-size: var(--webchat-fontSizeBase300);
262
+ font-weight: var(--webchat-fontWeightRegular);
263
+ margin-block: 0;
264
+ margin-inline: var(--webchat__bubble--inline-padding);
265
+
266
+ :global(.code-block-content__header) {
267
+ padding: var(--webchat-spacingVerticalM) var(--webchat-spacingHorizontalL);
268
+ }
269
+
270
+ :global(.code-block-content__code-block) {
271
+ padding-block: var(--webchat-spacingVerticalM);
272
+ padding-inline: var(--webchat-spacingHorizontalL) var(--webchat-spacingHorizontalS);
273
+ }
274
+
275
+ :global(.webchat__code-block-copy-button) {
276
+ --webchat__code-block__copy-button--color: var(--webchat-colorNeutralForeground1);
277
+ --webchat__code-block__copy-button--background: var(--webchat-colorNeutralBackground3);
278
+
279
+ margin-block-start: var(--webchat-spacingVerticalM);
280
+ margin-inline-end: var(--webchat-spacingHorizontalL);
281
+ position: absolute;
282
+ right: 0;
283
+ top: 0;
284
+ }
285
+ }
286
+
229
287
  /* Markdown links and citation links */
230
288
  :global(.webchat-fluent)
231
289
  .activity-decorator
@@ -330,9 +388,8 @@
330
388
  }
331
389
 
332
390
  :global(.webchat__link-definitions__header-chevron) {
333
- fill: var(--webchat-colorNeutralForeground3);
391
+ color: var(--webchat-colorNeutralForeground3);
334
392
  font-size: var(--webchat__font-size--small);
335
- width: 1em;
336
393
  }
337
394
 
338
395
  &:focus-visible {
@@ -1,10 +1,15 @@
1
1
  :global(.webchat-fluent) .activity-loader {
2
+ align-self: flex-start;
2
3
  flex: none;
3
4
  height: 8px;
4
- margin: var(--webchat-spacingHorizontalM) 0 0 18px;
5
+ margin: var(--webchat-spacingVerticalM) 0 0 18px;
5
6
  width: auto;
6
7
 
7
8
  &.variant-fluent {
8
- margin: 0 0 var(--webchat-spacingHorizontalM) var(--webchat-spacingVerticalSNudge);
9
+ margin: 0 0 var(--webchat-spacingVerticalM) var(--webchat-spacingHorizontalSNudge);
10
+ }
11
+
12
+ &.variant-copilot {
13
+ margin: var(--webchat-spacingVerticalXS) 0 0 -10px;
9
14
  }
10
15
  }
@@ -6,14 +6,17 @@ import { useVariantClassName } from '../../styles';
6
6
  import SlidingDots from '../assets/SlidingDots';
7
7
  import styles from './ActivityLoader.module.css';
8
8
 
9
- function FluentActivityLoader({ children }: Readonly<{ children?: ReactNode | undefined }>) {
9
+ function FluentActivityLoader({
10
+ children,
11
+ showLoader = true
12
+ }: Readonly<{ children?: ReactNode | undefined; showLoader?: boolean }>) {
10
13
  const classNames = useStyles(styles);
11
14
  const variantClassName = useVariantClassName(classNames);
12
15
 
13
16
  return (
14
17
  <Fragment>
15
18
  {children}
16
- <SlidingDots className={cx(classNames['activity-loader'], variantClassName)} />
19
+ {showLoader && <SlidingDots className={cx(classNames['activity-loader'], variantClassName)} />}
17
20
  </Fragment>
18
21
  );
19
22
  }
@@ -199,6 +199,7 @@
199
199
  --webchat__line-height--small: var(--webchat-lineHeightBase200);
200
200
  --webchat__line-height--medium: var(--webchat-lineHeightBase300);
201
201
  --webchat__max-width--bubble: var(--webchat-bubble-maxWidth);
202
+ --webchat__max-width--attachment-bubble: var(--webchat-bubble-maxWidth);
202
203
  --webchat__min-height--bubble: var(--webchat-bubble-minHeight);
203
204
  --webchat__padding--regular: var(--webchat-spacingVerticalS);
204
205
  --webchat__padding--sendbox: var(--webchat-spacingVerticalNone) var(--webchat-spacingHorizontalMNudge)
@@ -224,6 +225,7 @@
224
225
  }
225
226
 
226
227
  /* Scrollbars */
228
+ :global(.webchat-fluent).theme :global(.code-block-content .code-block-content__code-block),
227
229
  :global(.webchat-fluent).theme :global(.send-box-attachment-bar.send-box-attachment-bar--as-list-item),
228
230
  :global(.webchat-fluent).theme :global(.text-area.text-area--scroll),
229
231
  :global(.webchat-fluent).theme :global(.webchat__basic-transcript .webchat__basic-transcript__scrollable),
@@ -1,11 +1,15 @@
1
+ /* eslint-disable prefer-arrow-callback */
1
2
  import { type ActivityMiddleware, type StyleOptions, type TypingIndicatorMiddleware } from 'botframework-webchat-api';
2
3
  import {
4
+ ActivityBorderDecoratorRequest,
3
5
  createActivityBorderMiddleware,
4
6
  DecoratorComposer,
7
+ type InferDecoratorRequest,
8
+ useDecoratorRequest,
5
9
  type DecoratorMiddleware
6
10
  } from 'botframework-webchat-api/decorator';
11
+ import { BorderFlair, WebChatDecorator } from 'botframework-webchat-component/decorator';
7
12
  import { Components } from 'botframework-webchat-component';
8
- import { WebChatDecorator } from 'botframework-webchat-component/decorator';
9
13
  import React, { memo, type ReactNode } from 'react';
10
14
 
11
15
  import { ActivityDecorator } from '../components/activity';
@@ -18,6 +22,7 @@ import { TelephoneKeypadProvider } from '../components/telephoneKeypad';
18
22
  import { WebChatTheme } from '../components/theme';
19
23
  import SlidingDotsTypingIndicator from '../components/typingIndicator/SlidingDotsTypingIndicator';
20
24
  import { createStyles } from '../styles';
25
+ import { composePipeline } from './composePipeline';
21
26
  import VariantComposer, { VariantList } from './VariantComposer';
22
27
 
23
28
  const { ThemeProvider } = Components;
@@ -52,10 +57,34 @@ const activityMiddleware: readonly ActivityMiddleware[] = Object.freeze([
52
57
 
53
58
  const sendBoxMiddleware = [() => () => () => PrimarySendBox];
54
59
 
60
+ const FluentDecorator = composePipeline<InferDecoratorRequest<typeof ActivityBorderDecoratorRequest>>([
61
+ function FluentBorderLoader({ request, Next, ...props }) {
62
+ return (
63
+ <ActivityLoader showLoader={request.livestreamingState === 'preparing'}>
64
+ <Next {...props} />
65
+ </ActivityLoader>
66
+ );
67
+ },
68
+ function FluentBorderFlair({ request, Next, ...props }) {
69
+ return (
70
+ <BorderFlair showFlair={request.livestreamingState === 'completing'}>
71
+ <Next {...props} />
72
+ </BorderFlair>
73
+ );
74
+ }
75
+ ]);
76
+
77
+ FluentDecorator.displayName = 'FluentDecoratorPipeline';
78
+
79
+ const FluentDecoratorWithRequest = memo(function DecoratorWithRequest(props) {
80
+ const request = useDecoratorRequest(ActivityBorderDecoratorRequest);
81
+ return <FluentDecorator {...props} request={request} />;
82
+ });
83
+
84
+ FluentDecoratorWithRequest.displayName = 'FluentDecoratorWithRequest';
85
+
55
86
  const decoratorMiddleware: readonly DecoratorMiddleware[] = Object.freeze([
56
- createActivityBorderMiddleware(
57
- next => request => (request.livestreamingState === 'preparing' ? ActivityLoader : next(request))
58
- )
87
+ createActivityBorderMiddleware(() => () => FluentDecoratorWithRequest)
59
88
  ]);
60
89
 
61
90
  const styles = createStyles('fluent-theme');
@@ -0,0 +1,49 @@
1
+ /* eslint-disable prefer-arrow-callback */
2
+ import React, { Fragment, memo, type ComponentType, type ReactNode } from 'react';
3
+
4
+ type PipelineProps<R, P> = Readonly<{ request: R }> & P;
5
+ type InnerPipelineProps<R, P> = PipelineProps<R, P> & Readonly<{ originalRequest: R }>;
6
+
7
+ type NextComponent<P, R> = ComponentType<P & Readonly<{ request?: R | undefined }>>;
8
+ type ComposedComponent<P, R> = ComponentType<InnerPipelineProps<R, P>>;
9
+ type StageComponent<R, P> = ComponentType<
10
+ PipelineProps<R, P> & {
11
+ Next: NextComponent<P, R>;
12
+ }
13
+ >;
14
+ type PipelineComponent<P, R> = ComponentType<PipelineProps<R, P>>;
15
+
16
+ const Passthrough = memo(function PipelinePassthrough({ children }: Readonly<{ children?: ReactNode | undefined }>) {
17
+ return <Fragment>{children}</Fragment>;
18
+ });
19
+
20
+ export function composePipeline<
21
+ Request,
22
+ Props extends { children?: ReactNode | undefined } = { children?: ReactNode | undefined }
23
+ >(stages: StageComponent<Request, Props>[], PassthroughComponent = Passthrough): PipelineComponent<Props, Request> {
24
+ const ComposedPipeline = stages.reduceRight<ComposedComponent<Props, Request>>((Next, Stage) => {
25
+ const StageMemo = memo(Stage);
26
+
27
+ const StageWrapper = memo<InnerPipelineProps<Request, Props>>(({ originalRequest, request, ...innerRest }) => {
28
+ const resolvedRequest = request ?? originalRequest;
29
+ return (
30
+ <StageMemo
31
+ Next={Next as NextComponent<Props, Request>}
32
+ request={resolvedRequest}
33
+ {...(innerRest as Props)}
34
+ originalRequest={originalRequest}
35
+ />
36
+ );
37
+ });
38
+ StageWrapper.displayName = `PipelineStage(Memo(${Stage.displayName || Stage.name}))`;
39
+ return StageWrapper;
40
+ }, PassthroughComponent);
41
+
42
+ return memo(function Pipeline(props: PipelineProps<Request, Props>) {
43
+ const { request, ...restProps } = props;
44
+
45
+ return <ComposedPipeline request={request} {...(restProps as unknown as Props)} originalRequest={request} />;
46
+ });
47
+ }
48
+
49
+ export type { NextComponent, PipelineProps, PipelineComponent, StageComponent };