botframework-webchat-fluent-theme 4.18.1-main.20240831.f4058ce → 4.18.1-main.20240912.54a6a40

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.
Files changed (43) hide show
  1. package/dist/botframework-webchat-fluent-theme.css.map +1 -1
  2. package/dist/botframework-webchat-fluent-theme.d.mts +2 -0
  3. package/dist/botframework-webchat-fluent-theme.d.ts +2 -0
  4. package/dist/botframework-webchat-fluent-theme.development.css.map +1 -1
  5. package/dist/botframework-webchat-fluent-theme.development.js +8 -8
  6. package/dist/botframework-webchat-fluent-theme.development.js.map +1 -1
  7. package/dist/botframework-webchat-fluent-theme.js +1 -1
  8. package/dist/botframework-webchat-fluent-theme.js.map +1 -1
  9. package/dist/botframework-webchat-fluent-theme.mjs +1 -1
  10. package/dist/botframework-webchat-fluent-theme.mjs.map +1 -1
  11. package/dist/botframework-webchat-fluent-theme.production.min.css.map +1 -1
  12. package/dist/botframework-webchat-fluent-theme.production.min.js +8 -8
  13. package/dist/botframework-webchat-fluent-theme.production.min.js.map +1 -1
  14. package/package.json +4 -4
  15. package/src/components/activity/ActivityDecorator.module.css +91 -26
  16. package/src/components/activity/CopilotMessageHeader.module.css +4 -7
  17. package/src/components/activity/CopilotMessageHeader.tsx +20 -12
  18. package/src/components/activity/index.ts +1 -0
  19. package/src/components/activity/private/isAIGeneratedActivity.ts +5 -0
  20. package/src/components/activity/private/useActivityAuthor.ts +16 -0
  21. package/src/components/activity/private/useActivityStyleOptions.ts +19 -0
  22. package/src/components/decorator/private/BorderFlair.module.css +4 -0
  23. package/src/components/decorator/private/BorderFlair.tsx +15 -2
  24. package/src/components/linerActivity/private/LinerActivity.tsx +1 -1
  25. package/src/components/linerActivity/private/LinerMessageActivity.module.css +4 -0
  26. package/src/components/preChatActivity/PreChatMessageActivity.module.css +21 -7
  27. package/src/components/preChatActivity/PreChatMessageActivity.tsx +32 -26
  28. package/src/components/preChatActivity/StarterPromptsCardAction.module.css +55 -16
  29. package/src/components/preChatActivity/StarterPromptsCardAction.tsx +30 -24
  30. package/src/components/preChatActivity/StarterPromptsToolbar.tsx +23 -10
  31. package/src/components/sendBox/Attachments.tsx +5 -4
  32. package/src/components/sendBox/SendBox.module.css +7 -0
  33. package/src/components/sendBox/SendBox.tsx +31 -17
  34. package/src/components/sendBox/TextArea.tsx +50 -30
  35. package/src/components/sendBox/Toolbar.module.css +7 -1
  36. package/src/components/sendBox/Toolbar.tsx +17 -7
  37. package/src/components/suggestedActions/AccessibleButton.tsx +15 -13
  38. package/src/components/suggestedActions/SuggestedAction.module.css +8 -7
  39. package/src/components/suggestedActions/SuggestedAction.tsx +7 -4
  40. package/src/components/suggestedActions/SuggestedActions.tsx +3 -2
  41. package/src/components/theme/Theme.module.css +19 -8
  42. package/src/private/FluentThemeProvider.tsx +2 -0
  43. package/src/testIds.ts +2 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "botframework-webchat-fluent-theme",
3
- "version": "4.18.1-main.20240831.f4058ce",
3
+ "version": "4.18.1-main.20240912.54a6a40",
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",
@@ -69,9 +69,9 @@
69
69
  "typescript": "^5.4.5"
70
70
  },
71
71
  "dependencies": {
72
- "botframework-webchat-api": "4.18.1-main.20240831.f4058ce",
73
- "botframework-webchat-component": "4.18.1-main.20240831.f4058ce",
74
- "botframework-webchat-core": "4.18.1-main.20240831.f4058ce",
72
+ "botframework-webchat-api": "4.18.1-main.20240912.54a6a40",
73
+ "botframework-webchat-component": "4.18.1-main.20240912.54a6a40",
74
+ "botframework-webchat-core": "4.18.1-main.20240912.54a6a40",
75
75
  "classnames": "2.5.1",
76
76
  "inject-meta-tag": "0.0.1",
77
77
  "math-random": "2.0.1",
@@ -31,16 +31,6 @@
31
31
  :global(.webchat-fluent) .activity-decorator.variant-copilot {
32
32
  --webchat__bubble--border-radius: var(--webchat-borderRadiusXLarge);
33
33
 
34
- &:not(:has(:global(.webchat__bubble--from-user))) {
35
- --webchat__bubble--block-padding: var(--webchat-spacingVerticalS) var(--webchat-spacingVerticalXXS);
36
- --webchat__bubble--border-radius: var(--webchat-borderRadiusSmall);
37
- --webchat__bubble--inline-padding: 32px var(--webchat-spacingHorizontalNone);
38
- }
39
-
40
- &:not(:has(:global(.webchat__bubble--from-user))) :global(.webchat__stacked-layout__status) {
41
- display: none;
42
- }
43
-
44
34
  :global(.webchat__activity-status) {
45
35
  margin: 0 0 var(--webchat-spacingHorizontalXXS);
46
36
  }
@@ -49,14 +39,63 @@
49
39
  order: -1;
50
40
  }
51
41
 
52
- /* TODO: remove when we get decorators in and can place header directly to the bubble */
53
- &:not(:has(:global(.webchat__bubble--from-user))) :global(.webchat__stacked-layout .webchat__bubble .webchat__text-content) {
54
- padding-block: calc(var(--webchat-spacingVerticalS) + 20px) var(--webchat-spacingVerticalXXS);
42
+ &:has(:global(.webchat__bubble--from-user)) :global(.webchat__bubble) {
43
+ margin-block-end: var(--webchat-spacingVerticalM);
44
+ }
45
+ }
46
+
47
+ /* Decorator copilot variant which has bot message */
48
+ :global(.webchat-fluent) .activity-decorator.variant-copilot:not(:has(:global(.webchat__bubble--from-user))) {
49
+ --webchat__bubble--block-padding: 0;
50
+ --webchat__bubble--border-radius: var(--webchat-borderRadiusMedium);
51
+ --webchat__bubble--inline-padding: 0;
52
+ --webchat__bubble--max-width: 100%;
53
+ --webchat__bubble--min-height: 20px;
54
+
55
+ display: flex;
56
+ flex-flow: column nowrap;
57
+ gap: var(--webchat-spacingVerticalS);
58
+ margin-inline: var(--webchat-spacingHorizontalM);
59
+ padding: var(--webchat-spacingVerticalMNudge) var(--webchat-spacingHorizontalM) var(--webchat-spacingVerticalM);
60
+ position: relative;
61
+
62
+ :global(.webchat__stacked-layout) {
63
+ margin: 0;
64
+ position: static;
65
+ }
66
+
67
+ :global(.webchat__bubble) {
68
+ position: static;
69
+ width: var(--webchat__bubble--max-width);
70
+ }
71
+
72
+ :global(.webchat__bubble .webchat__bubble__content) {
73
+ overflow: visible;
74
+ }
75
+
76
+ :global(.webchat__text-content) {
77
+ margin-inline-start: 28px;
78
+ }
79
+
80
+ :global(.border-loader) {
81
+ display: flex;
82
+ flex-flow: column nowrap;
83
+ gap: var(--webchat-spacingVerticalS);
84
+ padding-inline-end: var(--webchat-spacingHorizontalM);
85
+ width: 500px;
86
+ }
87
+
88
+ :global(.border-loader__track) {
89
+ border-radius: inherit;
90
+ box-sizing: border-box;
91
+ clip-path: border-box;
92
+ margin-inline-start: 28px;
93
+ order: -1;
94
+ width: auto;
55
95
  }
56
96
 
57
- &:not(:has(:global(.webchat__bubble--from-user))) :global(.webchat__stacked-layout .webchat__bubble) {
58
- margin-block-start: -24px;
59
- margin-inline-start: -4px;
97
+ :global(.webchat__stacked-layout__status) {
98
+ display: none;
60
99
  }
61
100
  }
62
101
 
@@ -73,6 +112,7 @@
73
112
 
74
113
  /* Stacked layout which has message bubble */
75
114
  :global(.webchat-fluent) .activity-decorator :global(.webchat__stacked-layout .webchat__stacked-layout__content:has(.webchat__bubble)) {
115
+ max-width: 100%;
76
116
  overflow: visible;
77
117
  }
78
118
 
@@ -84,7 +124,7 @@
84
124
 
85
125
  /* Message bubble */
86
126
  :global(.webchat-fluent) .activity-decorator :global(.webchat__stacked-layout .webchat__bubble) {
87
- max-width: var(--webchat__bubble--max-width);
127
+ max-width: 100%;
88
128
  overflow: visible;
89
129
  }
90
130
 
@@ -93,8 +133,10 @@
93
133
  background-color: var(--webchat__bubble--background-color);
94
134
  border-radius: var(--webchat__bubble--border-radius);
95
135
  border-width: 0;
136
+ box-shadow: var(--webchat__bubble--box-shadow);
96
137
  box-sizing: border-box;
97
138
  color: var(--webchat-colorNeutralForeground1);
139
+ max-width: var(--webchat__bubble--max-width);
98
140
  min-height: var(--webchat__bubble--min-height);
99
141
  }
100
142
 
@@ -107,15 +149,26 @@
107
149
  padding-inline: var(--webchat__bubble--inline-padding);
108
150
  }
109
151
 
110
- /* Message bubble content pseudo */
111
- :global(.webchat-fluent) .activity-decorator :global(.webchat__stacked-layout .webchat__bubble .webchat__bubble__content)::before {
112
- border-radius: inherit;
113
- box-shadow: var(--webchat__bubble--box-shadow);
114
- content: '';
115
- inset: 0;
116
- isolation: isolate;
117
- pointer-events: none;
118
- position: absolute;
152
+ /* Message bubble attachment content */
153
+ :global(.webchat-fluent) .activity-decorator :global(.webchat__stacked-layout .webchat__bubble .webchat__fileContent__badge) {
154
+ cursor: default;
155
+ font-size: var(--webchat-fontSizeBase300);
156
+ line-height: var(--webchat-lineHeightBase300);
157
+
158
+ :global(.webchat__fileContent__fileName) {
159
+ color: var(--webchat-colorBrandForegroundLink);
160
+ font-family: inherit;
161
+ }
162
+ :global(.webchat__fileContent__size) {
163
+ color: var(--webchat-colorNeutralForeground2);
164
+ font-family: inherit;
165
+ }
166
+ }
167
+
168
+ /* Message bubble latency loader */
169
+ :global(.webchat-fluent) .activity-decorator :global(.border-loader) {
170
+ max-width: 100%;
171
+ width: var(--webchat__bubble--max-width);
119
172
  }
120
173
 
121
174
  /* Markdown links and citation links */
@@ -201,6 +254,8 @@
201
254
 
202
255
  /* Citation summary chevron */
203
256
  :global(.webchat-fluent) .activity-decorator :global(.webchat__link-definitions__header) {
257
+ border-radius: var(--webchat-borderRadiusMedium);
258
+
204
259
  :global(.webchat__link-definitions__header-text) {
205
260
  color: var(--webchat-colorNeutralForeground3);
206
261
  }
@@ -210,6 +265,11 @@
210
265
  font-size: var(--webchat__font-size--small);
211
266
  width: 1em;
212
267
  }
268
+
269
+ &:focus-visible {
270
+ outline-offset: 1px;
271
+ outline: var(--webchat-strokeWidthThin) solid var(--webchat-colorStrokeFocus2);
272
+ }
213
273
  }
214
274
 
215
275
  /* Citation link definitions */
@@ -300,6 +360,11 @@
300
360
  width: 1em;
301
361
  }
302
362
 
363
+ /* It seems Copilot does not show per-item sensitivity label, i.e. "General", etc. */
364
+ :global(.webchat__link-definitions__list-item-badge) {
365
+ display: none;
366
+ }
367
+
303
368
  :global(.webchat__link-definitions__open-in-new-window-icon) {
304
369
  display: none;
305
370
  }
@@ -1,15 +1,12 @@
1
1
 
2
2
  :global(.webchat-fluent) .copilot-message-header {
3
3
  align-items: center;
4
+ box-sizing: border-box;
4
5
  cursor: default;
5
6
  display: flex;
6
7
  flex-wrap: nowrap;
7
8
  gap: var(--webchat-spacingHorizontalS);
8
- margin-inline-start: var(--webchat-spacingVerticalMNudge);
9
- padding-block-start: var(--webchat-spacingVerticalXS);
10
- /* TODO: remove when moved to the bubble */
11
- position: relative;
12
- z-index: 1;
9
+ max-width: var(--webchat__bubble--max-width);
13
10
  }
14
11
 
15
12
  :global(.webchat-fluent) .copilot-message-header__avatar {
@@ -23,7 +20,6 @@
23
20
  font-size: var(--webchat-fontSizeBase300);
24
21
  font-weight: var(--webchat-fontWeightSemibold);
25
22
  line-height: var(--webchat-lineHeightBase300);
26
- max-width: 240px;
27
23
  overflow: hidden;
28
24
  text-overflow: ellipsis;
29
25
  text-wrap: nowrap;
@@ -35,8 +31,9 @@
35
31
  border-radius: var(--webchat-borderRadiusMedium);
36
32
  color: var(--webchat-colorNeutralForeground3);
37
33
  display: flex;
34
+ flex: none;
38
35
  font-size: var(--webchat-fontSizeBase100);
39
36
  height: 20px;
40
37
  line-height: var(--webchat-lineHeightBase100);
41
- padding-inline: 4px;
38
+ padding-inline: var(--webchat-spacingHorizontalXS);
42
39
  }
@@ -1,31 +1,39 @@
1
- import { WebChatActivity, hooks } from 'botframework-webchat-component';
2
1
  import React, { memo, useMemo, type CSSProperties } from 'react';
2
+ import { WebChatActivity, hooks } from 'botframework-webchat-component';
3
+
4
+ import useActivityStyleOptions from './private/useActivityStyleOptions';
5
+ import isAIGeneratedActivity from './private/isAIGeneratedActivity';
6
+ import useActivityAuthor from './private/useActivityAuthor';
3
7
  import { useStyles } from '../../styles';
4
8
  import styles from './CopilotMessageHeader.module.css';
5
9
 
6
- const { useStyleOptions, useLocalizer } = hooks;
10
+ const { useLocalizer } = hooks;
7
11
 
8
12
  function CopilotMessageHeader({ activity }: Readonly<{ activity?: WebChatActivity | undefined }>) {
9
- const [{ botAvatarImage, botAvatarBackgroundColor }] = useStyleOptions();
13
+ const [{ botAvatarImage, botAvatarBackgroundColor }] = useActivityStyleOptions(activity);
10
14
  const classNames = useStyles(styles);
11
15
  const localize = useLocalizer();
12
- // TODO: how we determine the activity has ai-generated content
13
- const isAIGenerated = useMemo(() => !!activity, [activity]);
14
- const botTitle = activity?.from?.name;
16
+ const isAIGenerated = isAIGeneratedActivity(activity);
15
17
 
16
18
  const avatarStyle = useMemo(
17
19
  () => ({ '--background-color': botAvatarBackgroundColor }) as CSSProperties,
18
20
  [botAvatarBackgroundColor]
19
21
  );
20
22
 
23
+ const author = useActivityAuthor(activity);
24
+ const avatarImage = author?.image || botAvatarImage;
25
+ const botTitle = author?.name || activity?.from?.name;
26
+
21
27
  return (
22
28
  <div className={classNames['copilot-message-header']}>
23
- <img
24
- alt={localize('AVATAR_ALT', botTitle)}
25
- className={classNames['copilot-message-header__avatar']}
26
- src={botAvatarImage}
27
- style={avatarStyle}
28
- />
29
+ {avatarImage && (
30
+ <img
31
+ alt={localize('AVATAR_ALT', botTitle)}
32
+ className={classNames['copilot-message-header__avatar']}
33
+ src={avatarImage}
34
+ style={avatarStyle}
35
+ />
36
+ )}
29
37
  <span className={classNames['copilot-message-header__title']} title={botTitle}>
30
38
  {botTitle}
31
39
  </span>
@@ -1 +1,2 @@
1
1
  export { default as ActivityDecorator } from './ActivityDecorator';
2
+ export { default as useActivityAuthor } from './private/useActivityAuthor';
@@ -0,0 +1,5 @@
1
+ import { getOrgSchemaMessage, type WebChatActivity } from 'botframework-webchat-core';
2
+
3
+ export default function isAIGeneratedActivity(activity: undefined | WebChatActivity) {
4
+ return !!(activity && getOrgSchemaMessage(activity?.entities || [])?.keywords?.includes('AIGeneratedContent'));
5
+ }
@@ -0,0 +1,16 @@
1
+ import { useMemo } from 'react';
2
+ import { getOrgSchemaMessage, type WebChatActivity } from 'botframework-webchat-core';
3
+
4
+ export default function useActivityAuthor(activity?: WebChatActivity | undefined) {
5
+ return useMemo(() => {
6
+ const entity = getOrgSchemaMessage(activity?.entities || []);
7
+ return typeof entity?.author === 'string'
8
+ ? {
9
+ '@type': 'Person',
10
+ description: undefined,
11
+ image: undefined,
12
+ name: entity?.author
13
+ }
14
+ : entity?.author;
15
+ }, [activity]);
16
+ }
@@ -0,0 +1,19 @@
1
+ import { useMemo } from 'react';
2
+ import { hooks, type WebChatActivity } from 'botframework-webchat-component';
3
+ import { type StrictStyleOptions } from 'botframework-webchat-api';
4
+
5
+ const { useStyleOptions } = hooks;
6
+
7
+ export default function useActivityStyleOptions(activity?: WebChatActivity | undefined) {
8
+ const [styleOptions] = useStyleOptions();
9
+ return useMemo<readonly [Readonly<StrictStyleOptions>]>(
10
+ () =>
11
+ Object.freeze([
12
+ {
13
+ ...styleOptions,
14
+ ...activity?.channelData?.webChat?.styleOptions
15
+ }
16
+ ]),
17
+ [activity?.channelData?.webChat?.styleOptions, styleOptions]
18
+ );
19
+ }
@@ -123,6 +123,10 @@
123
123
  position: absolute;
124
124
  }
125
125
 
126
+ :global(.webchat-fluent) .border-flair--complete {
127
+ animation-play-state: paused;
128
+ }
129
+
126
130
  /* Firefox implementation */
127
131
  @supports (-moz-appearance: none) {
128
132
  @keyframes borderFlair-animation {
@@ -1,15 +1,28 @@
1
- import React, { Fragment, memo, type ReactNode } from 'react';
1
+ import React, { Fragment, memo, useCallback, useState, type ReactNode } from 'react';
2
+ import cx from 'classnames';
2
3
 
3
4
  import { useStyles } from '../../../styles';
4
5
  import styles from './BorderFlair.module.css';
5
6
 
6
7
  function BorderFlair({ children }: Readonly<{ children?: ReactNode | undefined }>) {
7
8
  const classNames = useStyles(styles);
9
+ const [isComplete, setComplete] = useState(false);
10
+
11
+ const handleAnimationEnd = useCallback(
12
+ event =>
13
+ (event.animationName === styles['borderAnimation-angle'] ||
14
+ event.animationName === styles['borderFlair-animation']) &&
15
+ setComplete(true),
16
+ []
17
+ );
8
18
 
9
19
  return (
10
20
  <Fragment>
11
21
  {children}
12
- <div className={classNames['border-flair']} />
22
+ <div
23
+ className={cx(classNames['border-flair'], isComplete && classNames['border-flair--complete'])}
24
+ onAnimationEnd={handleAnimationEnd}
25
+ />
13
26
  </Fragment>
14
27
  );
15
28
  }
@@ -10,7 +10,7 @@ const LinerMessageActivity = ({ activity }: Props) => {
10
10
 
11
11
  return (
12
12
  <div className={classNames['liner-message-activity']} role="separator">
13
- {activity.text}
13
+ <span className={classNames['liner-message-activity__text']}>{activity.text}</span>
14
14
  </div>
15
15
  );
16
16
  };
@@ -22,3 +22,7 @@
22
22
  min-width: 8px;
23
23
  }
24
24
  }
25
+
26
+ :global(.webchat-fluent) .liner-message-activity__text {
27
+ text-align: center;
28
+ }
@@ -9,30 +9,44 @@
9
9
  }
10
10
 
11
11
  :global(.webchat-fluent) .pre-chat-message-activity__body {
12
+ align-items: center;
13
+ display: flex;
14
+ flex-flow: column nowrap;
12
15
  font-family: var(--webchat-fontFamilyBase);
13
16
  font-size: var(--webchat-fontSizeBase300);
14
17
  font-weight: var(--webchat-fontWeightRegular);
18
+ gap: var(--webchat-spacingVerticalXS);
15
19
  grid-area: body;
16
20
  line-height: var(--webchat-lineHeightBase300);
17
21
  text-align: center;
18
22
  }
19
23
 
20
- :global(.webchat-fluent) .pre-chat-message-activity__body--placeholder {
24
+ :global(.webchat-fluent) .pre-chat-message-activity__body--blueprint {
21
25
  opacity: 60%;
26
+
27
+ .pre-chat-message-activity__body-avatar {
28
+ filter: grayscale(1);
29
+ }
22
30
  }
23
31
 
24
- :global(.webchat-fluent) .pre-chat-message-activity__body h2 {
32
+ :global(.webchat-fluent) .pre-chat-message-activity__body-avatar {
33
+ border-radius: var(--webchat-borderRadiusMedium);
34
+ height: 64px;
35
+ margin-block-end: var(--webchat-spacingVerticalM);
36
+ }
37
+
38
+ :global(.webchat-fluent) .pre-chat-message-activity__body-title {
25
39
  color: var(--webchat-colorNeutralForeground1);
26
40
  font-family: inherit;
27
- font-weight: var(--webchat-fontWeightSemibold);
28
41
  font-size: var(--webchat-fontSizeHero700);
42
+ font-weight: var(--webchat-fontWeightSemibold);
29
43
  line-height: var(--webchat-lineHeightHero700);
30
- margin: var(--webchat-spacingVerticalL) 0 0;
44
+ margin: 0;
31
45
  }
32
46
 
33
- :global(.webchat-fluent) .pre-chat-message-activity__body img {
34
- border-radius: 4px;
35
- height: 64px;
47
+ :global(.webchat-fluent) .pre-chat-message-activity__body-subtitle {
48
+ font-size: var(--webchat-fontSizeBase300);
49
+ line-height: var(--webchat-lineHeightBase300);
36
50
  }
37
51
 
38
52
  :global(.webchat-fluent) .pre-chat-message-activity__toolbar {
@@ -1,50 +1,56 @@
1
- /* eslint-disable react/no-danger */
2
1
  import { hooks } from 'botframework-webchat-component';
2
+ import { type WebChatActivity } from 'botframework-webchat-core';
3
3
  import cx from 'classnames';
4
- import { getOrgSchemaMessage, type WebChatActivity } from 'botframework-webchat-core';
5
- import React, { Fragment, memo, useMemo } from 'react';
4
+ import React, { memo, useMemo } from 'react';
6
5
  import { useStyles } from '../../styles/index.js';
7
6
  import styles from './PreChatMessageActivity.module.css';
8
7
  import StarterPromptsToolbar from './StarterPromptsToolbar.js';
9
- import StarterPromptsCardAction from './StarterPromptsCardAction.js';
8
+ import { useActivityAuthor } from '../activity/index.js';
10
9
 
11
10
  type Props = Readonly<{ activity: WebChatActivity & { type: 'message' } }>;
12
11
 
13
- const { useRenderMarkdownAsHTML } = hooks;
12
+ const { useLocalizer, useRenderMarkdownAsHTML, useUIState } = hooks;
14
13
 
15
14
  const PreChatMessageActivity = ({ activity }: Props) => {
15
+ const [uiState] = useUIState();
16
16
  const classNames = useStyles(styles);
17
17
  const renderMarkdownAsHTML = useRenderMarkdownAsHTML();
18
+ const localize = useLocalizer();
19
+
20
+ const author = useActivityAuthor(activity);
18
21
 
19
22
  const html = useMemo(
20
- () => (renderMarkdownAsHTML ? { __html: renderMarkdownAsHTML(activity.text || '') } : { __html: '' }),
21
- [activity.text, renderMarkdownAsHTML]
23
+ () => (renderMarkdownAsHTML ? { __html: renderMarkdownAsHTML(author?.description || '') } : { __html: '' }),
24
+ [author?.description, renderMarkdownAsHTML]
22
25
  );
23
26
 
24
- const entity = getOrgSchemaMessage(activity?.entities || []);
25
- const isPlaceHolder = entity?.keywords?.includes('PreChatMessage') && entity.creativeWorkStatus === 'Placeholder';
26
-
27
27
  return (
28
28
  <div className={classNames['pre-chat-message-activity']}>
29
- <div
30
- className={cx(
31
- classNames['pre-chat-message-activity__body'],
32
- isPlaceHolder && classNames['pre-chat-message-activity__body--placeholder']
33
- )}
34
- dangerouslySetInnerHTML={html}
35
- />
29
+ {author && (
30
+ <div
31
+ className={cx(
32
+ classNames['pre-chat-message-activity__body'],
33
+ uiState === 'blueprint' && classNames['pre-chat-message-activity__body--blueprint']
34
+ )}
35
+ >
36
+ {author.image && (
37
+ <img
38
+ alt={localize('AVATAR_ALT', author.name)}
39
+ className={classNames['pre-chat-message-activity__body-avatar']}
40
+ src={author.image}
41
+ />
42
+ )}
43
+ {author.name && <h2 className={classNames['pre-chat-message-activity__body-title']}>{author.name}</h2>}
44
+ {author.description && (
45
+ // eslint-disable-next-line react/no-danger
46
+ <div className={classNames['pre-chat-message-activity__body-subtitle']} dangerouslySetInnerHTML={html} />
47
+ )}
48
+ </div>
49
+ )}
36
50
  <StarterPromptsToolbar
37
51
  cardActions={activity.suggestedActions?.actions || []}
38
52
  className={classNames['pre-chat-message-activity__toolbar']}
39
- >
40
- {isPlaceHolder && (
41
- <Fragment>
42
- <StarterPromptsCardAction />
43
- <StarterPromptsCardAction />
44
- <StarterPromptsCardAction />
45
- </Fragment>
46
- )}
47
- </StarterPromptsToolbar>
53
+ />
48
54
  </div>
49
55
  );
50
56
  };
@@ -7,13 +7,14 @@
7
7
  color: var(--webchat-colorNeutralForeground1);
8
8
  cursor: pointer;
9
9
  display: grid;
10
- gap: 8px;
10
+ gap: var(--webchat-spacingVerticalS);
11
11
  grid-template-areas: 'title' 'subtitle';
12
12
  grid-template-columns: 1fr;
13
13
  grid-template-rows: auto 1fr;
14
14
  overflow: hidden;
15
15
  padding: 16px 20px;
16
16
  text-align: left;
17
+ transition: background-color var(--webchat-durationNormal) var(--webchat-curveDecelerateMid);
17
18
  user-select: none;
18
19
 
19
20
  &:has(.pre-chat-message-activity__card-action-image) {
@@ -21,19 +22,24 @@
21
22
  grid-template-columns: 20px 1fr;
22
23
  }
23
24
 
24
- &:disabled {
25
+ &:empty {
26
+ row-gap: 14px;
27
+ }
28
+
29
+ &[aria-disabled='true'],
30
+ &:empty {
25
31
  cursor: default;
26
32
  }
27
33
 
28
- &:disabled:not(:empty) {
34
+ &[aria-disabled='true']:not(:empty) {
29
35
  background-color: var(--webchat-colorNeutralBackgroundDisabled);
30
36
  }
31
37
 
32
- &:hover:not(:disabled) {
38
+ &:hover:not([aria-disabled='true'], :empty) {
33
39
  background-color: var(--webchat-colorNeutralBackground1Hover);
34
40
  }
35
41
 
36
- &:active:not(:disabled) {
42
+ &:active:not([aria-disabled='true'], :empty) {
37
43
  background-color: var(--webchat-colorNeutralBackground1Pressed);
38
44
  }
39
45
 
@@ -42,24 +48,57 @@
42
48
  outline-offset: -2px;
43
49
  }
44
50
 
51
+ &:empty::after,
45
52
  &:empty::before {
53
+ animation: blueprintAnimation 3s linear infinite;
54
+ background-attachment: fixed;
55
+ background-image: linear-gradient(
56
+ -90deg,
57
+ var(--webchat-colorNeutralStencil1) 0%,
58
+ var(--webchat-colorNeutralStencil2) 50%,
59
+ var(--webchat-colorNeutralStencil1) 100%
60
+ );
61
+ background-size: 300% 100%;
46
62
  content: '';
47
63
  display: block;
48
- width: 66%;
49
- height: 18px;
50
- background-color: var(--webchat-colorNeutralBackground6);
51
- border-radius: 18px;
52
- opacity: 1;
64
+ }
65
+
66
+ /* animation-* needs to position after animation shorthand. */
67
+ @media (prefers-reduced-motion: reduce) {
68
+ &:empty::after,
69
+ &:empty::before {
70
+ animation-delay: -1s;
71
+ animation-play-state: paused;
72
+ }
73
+ }
74
+
75
+ &:dir(rtl) {
76
+ &:empty::after,
77
+ &:empty::before {
78
+ animation-direction: reverse;
79
+ }
53
80
  }
54
81
 
55
82
  &:empty::after {
56
- content: '';
57
- display: block;
58
- width: 100%;
59
- height: 16px;
60
- background-color: var(--webchat-colorNeutralBackground6);
61
83
  border-radius: 16px;
62
- opacity: 0.8;
84
+ height: 16px;
85
+ width: 100%;
86
+ }
87
+
88
+ &:empty::before {
89
+ border-radius: 18px;
90
+ height: 18px;
91
+ width: 66%;
92
+ }
93
+ }
94
+
95
+ @keyframes blueprintAnimation {
96
+ from {
97
+ background-position-x: 0%;
98
+ }
99
+
100
+ to {
101
+ background-position-x: -300%;
63
102
  }
64
103
  }
65
104