botframework-webchat-fluent-theme 4.18.1-main.20240830.4534802 → 4.18.1-main.20240911.3e47786

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 (46) 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 +35 -17
  16. package/src/components/activity/ActivityDecorator.tsx +1 -1
  17. package/src/components/activity/CopilotMessageHeader.module.css +5 -3
  18. package/src/components/activity/CopilotMessageHeader.tsx +20 -12
  19. package/src/components/activity/index.ts +1 -0
  20. package/src/components/activity/private/isAIGeneratedActivity.ts +5 -0
  21. package/src/components/activity/private/useActivityAuthor.ts +16 -0
  22. package/src/components/activity/private/useActivityStyleOptions.ts +19 -0
  23. package/src/components/decorator/private/BorderFlair.module.css +4 -0
  24. package/src/components/decorator/private/BorderFlair.tsx +15 -2
  25. package/src/components/linerActivity/index.ts +2 -0
  26. package/src/components/linerActivity/private/LinerActivity.tsx +20 -0
  27. package/src/components/linerActivity/private/LinerMessageActivity.module.css +28 -0
  28. package/src/components/linerActivity/private/isLinerMessageActivity.ts +7 -0
  29. package/src/components/preChatActivity/PreChatMessageActivity.module.css +21 -7
  30. package/src/components/preChatActivity/PreChatMessageActivity.tsx +32 -26
  31. package/src/components/preChatActivity/StarterPromptsCardAction.module.css +55 -16
  32. package/src/components/preChatActivity/StarterPromptsCardAction.tsx +30 -24
  33. package/src/components/preChatActivity/StarterPromptsToolbar.tsx +23 -10
  34. package/src/components/sendBox/Attachments.tsx +5 -4
  35. package/src/components/sendBox/SendBox.module.css +7 -0
  36. package/src/components/sendBox/SendBox.tsx +31 -17
  37. package/src/components/sendBox/TextArea.tsx +50 -30
  38. package/src/components/sendBox/Toolbar.module.css +7 -1
  39. package/src/components/sendBox/Toolbar.tsx +17 -7
  40. package/src/components/suggestedActions/AccessibleButton.tsx +15 -13
  41. package/src/components/suggestedActions/SuggestedAction.module.css +8 -7
  42. package/src/components/suggestedActions/SuggestedAction.tsx +7 -4
  43. package/src/components/suggestedActions/SuggestedActions.tsx +3 -2
  44. package/src/components/theme/Theme.module.css +25 -8
  45. package/src/private/FluentThemeProvider.tsx +7 -1
  46. 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.20240830.4534802",
3
+ "version": "4.18.1-main.20240911.3e47786",
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.20240830.4534802",
73
- "botframework-webchat-component": "4.18.1-main.20240830.4534802",
74
- "botframework-webchat-core": "4.18.1-main.20240830.4534802",
72
+ "botframework-webchat-api": "4.18.1-main.20240911.3e47786",
73
+ "botframework-webchat-component": "4.18.1-main.20240911.3e47786",
74
+ "botframework-webchat-core": "4.18.1-main.20240911.3e47786",
75
75
  "classnames": "2.5.1",
76
76
  "inject-meta-tag": "0.0.1",
77
77
  "math-random": "2.0.1",
@@ -30,11 +30,15 @@
30
30
  /* Decorator copilot variant */
31
31
  :global(.webchat-fluent) .activity-decorator.variant-copilot {
32
32
  --webchat__bubble--border-radius: var(--webchat-borderRadiusXLarge);
33
-
33
+
34
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);
35
+ --webchat__bubble--block-padding: var(--webchat-spacingVerticalS) var(--webchat-spacingVerticalS);
36
+ --webchat__bubble--border-radius: var(--webchat-borderRadiusMedium);
37
+ --webchat__bubble--inline-padding: 34px var(--webchat-spacingHorizontalS);
38
+ --webchat__bubble--max-width: 100%;
39
+
40
+ display: block;
41
+ padding-inline-start: var(--webchat-spacingHorizontalM);
38
42
  }
39
43
 
40
44
  &:not(:has(:global(.webchat__bubble--from-user))) :global(.webchat__stacked-layout__status) {
@@ -51,12 +55,13 @@
51
55
 
52
56
  /* TODO: remove when we get decorators in and can place header directly to the bubble */
53
57
  &: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);
58
+ padding-block: calc(var(--webchat-spacingVerticalMNudge) + 20px) var(--webchat-spacingVerticalS);
55
59
  }
56
60
 
57
61
  &:not(:has(:global(.webchat__bubble--from-user))) :global(.webchat__stacked-layout .webchat__bubble) {
58
- margin-block-start: -24px;
59
- margin-inline-start: -4px;
62
+ margin-block-start: -28px;
63
+ margin-inline-start: -10px;
64
+ width: var(--webchat__bubble--max-width);
60
65
  }
61
66
  }
62
67
 
@@ -73,6 +78,7 @@
73
78
 
74
79
  /* Stacked layout which has message bubble */
75
80
  :global(.webchat-fluent) .activity-decorator :global(.webchat__stacked-layout .webchat__stacked-layout__content:has(.webchat__bubble)) {
81
+ max-width: 100%;
76
82
  overflow: visible;
77
83
  }
78
84
 
@@ -84,7 +90,7 @@
84
90
 
85
91
  /* Message bubble */
86
92
  :global(.webchat-fluent) .activity-decorator :global(.webchat__stacked-layout .webchat__bubble) {
87
- max-width: var(--webchat__bubble--max-width);
93
+ max-width: 100%;
88
94
  overflow: visible;
89
95
  }
90
96
 
@@ -93,9 +99,11 @@
93
99
  background-color: var(--webchat__bubble--background-color);
94
100
  border-radius: var(--webchat__bubble--border-radius);
95
101
  border-width: 0;
102
+ box-shadow: var(--webchat__bubble--box-shadow);
96
103
  box-sizing: border-box;
97
104
  color: var(--webchat-colorNeutralForeground1);
98
105
  min-height: var(--webchat__bubble--min-height);
106
+ max-width: var(--webchat__bubble--max-width);
99
107
  }
100
108
 
101
109
  /* Message bubble text content */
@@ -107,15 +115,20 @@
107
115
  padding-inline: var(--webchat__bubble--inline-padding);
108
116
  }
109
117
 
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;
118
+ /* Message bubble attachment content */
119
+ :global(.webchat-fluent) .activity-decorator :global(.webchat__stacked-layout .webchat__bubble .webchat__fileContent__badge) {
120
+ cursor: default;
121
+ font-size: var(--webchat-fontSizeBase300);
122
+ line-height: var(--webchat-lineHeightBase300);
123
+
124
+ :global(.webchat__fileContent__fileName) {
125
+ color: var(--webchat-colorBrandForegroundLink);
126
+ font-family: inherit;
127
+ }
128
+ :global(.webchat__fileContent__size) {
129
+ color: var(--webchat-colorNeutralForeground2);
130
+ font-family: inherit;
131
+ }
119
132
  }
120
133
 
121
134
  /* Markdown links and citation links */
@@ -300,6 +313,11 @@
300
313
  width: 1em;
301
314
  }
302
315
 
316
+ /* It seems Copilot does not show per-item sensitivity label, i.e. "General", etc. */
317
+ :global(.webchat__link-definitions__list-item-badge) {
318
+ display: none;
319
+ }
320
+
303
321
  :global(.webchat__link-definitions__open-in-new-window-icon) {
304
322
  display: none;
305
323
  }
@@ -11,7 +11,7 @@ function ActivityDecorator({ activity, children }: Readonly<{ activity: WebChatA
11
11
  const variants = useVariants();
12
12
  const variantClassName = useVariantClassName(styles);
13
13
 
14
- const shouldRenderHeader = variants.includes('copilot') && activity?.from?.role !== 'user' && !!children;
14
+ const shouldRenderHeader = variants.includes('copilot') && activity?.from?.role === 'bot' && !!children;
15
15
 
16
16
  return (
17
17
  <div className={cx(classNames['activity-decorator'], variantClassName)}>
@@ -1,12 +1,14 @@
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
+ max-width: var(--webchat__bubble--max-width);
9
10
  padding-block-start: var(--webchat-spacingVerticalXS);
11
+ padding-inline: var(--webchat-spacingVerticalMNudge);
10
12
  /* TODO: remove when moved to the bubble */
11
13
  position: relative;
12
14
  z-index: 1;
@@ -23,7 +25,6 @@
23
25
  font-size: var(--webchat-fontSizeBase300);
24
26
  font-weight: var(--webchat-fontWeightSemibold);
25
27
  line-height: var(--webchat-lineHeightBase300);
26
- max-width: 240px;
27
28
  overflow: hidden;
28
29
  text-overflow: ellipsis;
29
30
  text-wrap: nowrap;
@@ -35,8 +36,9 @@
35
36
  border-radius: var(--webchat-borderRadiusMedium);
36
37
  color: var(--webchat-colorNeutralForeground3);
37
38
  display: flex;
39
+ flex: none;
38
40
  font-size: var(--webchat-fontSizeBase100);
39
41
  height: 20px;
40
42
  line-height: var(--webchat-lineHeightBase100);
41
- padding-inline: 4px;
43
+ padding-inline: var(--webchat-spacingHorizontalXS);
42
44
  }
@@ -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
  }
@@ -0,0 +1,2 @@
1
+ export { default as isLinerMessageActivity } from './private/isLinerMessageActivity';
2
+ export { default as LinerMessageActivity } from './private/LinerActivity';
@@ -0,0 +1,20 @@
1
+ import { type WebChatActivity } from 'botframework-webchat-core';
2
+ import React, { memo } from 'react';
3
+ import { useStyles } from '../../../styles/index.js';
4
+ import styles from './LinerMessageActivity.module.css';
5
+
6
+ type Props = Readonly<{ activity: WebChatActivity & { type: 'message' } }>;
7
+
8
+ const LinerMessageActivity = ({ activity }: Props) => {
9
+ const classNames = useStyles(styles);
10
+
11
+ return (
12
+ <div className={classNames['liner-message-activity']} role="separator">
13
+ <span className={classNames['liner-message-activity__text']}>{activity.text}</span>
14
+ </div>
15
+ );
16
+ };
17
+
18
+ LinerMessageActivity.displayName = 'LinerMessageActivity';
19
+
20
+ export default memo(LinerMessageActivity);
@@ -0,0 +1,28 @@
1
+
2
+ :global(.webchat-fluent) .liner-message-activity {
3
+ align-items: center;
4
+ box-sizing: border-box;
5
+ color: var(--webchat-colorNeutralForeground3);
6
+ display: flex;
7
+ flex-direction: row;
8
+ font-family: var(--webchat__font--primary);
9
+ font-size: var(--webchat-fontSizeBase200);
10
+ font-weight: var(--webchat-fontWeightRegular);
11
+ gap: var(--webchat-spacingHorizontalM);
12
+ line-height: var(--webchat-lineHeightBase200);
13
+ padding: var(--webchat-spacingVerticalSNudge) var(--webchat-spacingHorizontalM);
14
+ text-align: center;
15
+ width: 100%;
16
+
17
+ &::before, &::after {
18
+ border-top: var(--webchat-strokeWidthThin) solid var(--webchat-colorNeutralStroke2);
19
+ content: "";
20
+ display: flex;
21
+ flex: auto;
22
+ min-width: 8px;
23
+ }
24
+ }
25
+
26
+ :global(.webchat-fluent) .liner-message-activity__text {
27
+ text-align: center;
28
+ }
@@ -0,0 +1,7 @@
1
+ import { type WebChatActivity } from 'botframework-webchat-core';
2
+
3
+ export default function isLinerMessageActivity(
4
+ activity: undefined | WebChatActivity
5
+ ): activity is WebChatActivity & { type: 'message'; from: { role: 'channel' } } {
6
+ return !!(activity && activity.from.role === 'channel' && activity.type === 'message' && 'text' in activity);
7
+ }
@@ -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