botframework-webchat-fluent-theme 4.18.0 → 4.18.1-main.20240808.851825d

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 (31) hide show
  1. package/dist/botframework-webchat-fluent-theme.css.map +1 -1
  2. package/dist/botframework-webchat-fluent-theme.d.mts +1 -0
  3. package/dist/botframework-webchat-fluent-theme.d.ts +1 -0
  4. package/dist/botframework-webchat-fluent-theme.development.css.map +1 -1
  5. package/dist/botframework-webchat-fluent-theme.development.js +1 -1
  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 +1 -1
  13. package/dist/botframework-webchat-fluent-theme.production.min.js.map +1 -1
  14. package/package.json +6 -5
  15. package/src/components/preChatActivity/PreChatMessageActivity.module.css +34 -0
  16. package/src/components/preChatActivity/PreChatMessageActivity.tsx +35 -0
  17. package/src/components/preChatActivity/StarterPromptsCardAction.module.css +58 -0
  18. package/src/components/preChatActivity/StarterPromptsCardAction.tsx +64 -0
  19. package/src/components/preChatActivity/StarterPromptsToolbar.module.css +18 -0
  20. package/src/components/preChatActivity/StarterPromptsToolbar.tsx +35 -0
  21. package/src/components/preChatActivity/index.tsx +2 -0
  22. package/src/components/preChatActivity/isPreChatMessageActivity.ts +26 -0
  23. package/src/components/preChatActivity/private/MonochromeImageMasker.module.css +5 -0
  24. package/src/components/preChatActivity/private/MonochromeImageMasker.tsx +19 -0
  25. package/src/components/sendBox/SendBox.tsx +24 -13
  26. package/src/components/sendBox/index.tsx +1 -1
  27. package/src/components/suggestedActions/SuggestedActions.tsx +46 -43
  28. package/src/components/theme/Theme.module.css +23 -5
  29. package/src/components/theme/Theme.tsx +1 -1
  30. package/src/private/FluentThemeProvider.tsx +20 -3
  31. package/src/testIds.ts +1 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "botframework-webchat-fluent-theme",
3
- "version": "4.18.0",
3
+ "version": "4.18.1-main.20240808.851825d",
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,13 +69,14 @@
69
69
  "typescript": "^5.4.5"
70
70
  },
71
71
  "dependencies": {
72
- "botframework-webchat-api": "4.18.0",
73
- "botframework-webchat-component": "4.18.0",
74
- "botframework-webchat-core": "4.18.0",
72
+ "botframework-webchat-api": "4.18.1-main.20240808.851825d",
73
+ "botframework-webchat-component": "4.18.1-main.20240808.851825d",
74
+ "botframework-webchat-core": "4.18.1-main.20240808.851825d",
75
75
  "classnames": "2.5.1",
76
76
  "inject-meta-tag": "0.0.1",
77
77
  "math-random": "2.0.1",
78
- "use-ref-from": "0.1.0"
78
+ "use-ref-from": "0.1.0",
79
+ "valibot": "^0.37.0"
79
80
  },
80
81
  "peerDependencies": {
81
82
  "react": ">= 16.8.6"
@@ -0,0 +1,34 @@
1
+ :global(.webchat-fluent) .pre-chat-message-activity {
2
+ display: grid;
3
+ grid-template-areas: 'body' 'toolbar';
4
+ grid-template-rows: auto auto;
5
+ gap: var(--webchat-spacingHorizontalXXXL);
6
+ padding: var(--webchat-spacingHorizontalXXXL);
7
+ }
8
+
9
+ :global(.webchat-fluent) .pre-chat-message-activity__body {
10
+ font-family: var(--webchat-fontFamilyBase);
11
+ font-size: var(--webchat-fontSizeBase300);
12
+ font-weight: var(--webchat-fontWeightRegular);
13
+ grid-area: body;
14
+ line-height: var(--webchat-lineHeightBase300);
15
+ text-align: center;
16
+ }
17
+
18
+ :global(.webchat-fluent) .pre-chat-message-activity__body h2 {
19
+ color: var(--webchat-colorNeutralForeground1);
20
+ font-family: inherit;
21
+ font-weight: var(--webchat-fontWeightSemibold);
22
+ font-size: var(--webchat-fontSizeHero700);
23
+ line-height: var(--webchat-lineHeightHero700);
24
+ margin: var(--webchat-spacingVerticalL) 0 0;
25
+ }
26
+
27
+ :global(.webchat-fluent) .pre-chat-message-activity__body img {
28
+ border-radius: 4px;
29
+ height: 64px;
30
+ }
31
+
32
+ :global(.webchat-fluent) .pre-chat-message-activity__toolbar {
33
+ grid-area: toolbar;
34
+ }
@@ -0,0 +1,35 @@
1
+ import { hooks } from 'botframework-webchat-component';
2
+ import { type WebChatActivity } from 'botframework-webchat-core';
3
+ import React, { memo, useMemo } from 'react';
4
+ import { useStyles } from '../../styles/index.js';
5
+ import styles from './PreChatMessageActivity.module.css';
6
+ import StarterPromptsToolbar from './StarterPromptsToolbar.js';
7
+
8
+ type Props = Readonly<{ activity: WebChatActivity & { type: 'message' } }>;
9
+
10
+ const { useRenderMarkdownAsHTML } = hooks;
11
+
12
+ const PreChatMessageActivity = ({ activity }: Props) => {
13
+ const classNames = useStyles(styles);
14
+ const renderMarkdownAsHTML = useRenderMarkdownAsHTML();
15
+
16
+ const html = useMemo(
17
+ () => (renderMarkdownAsHTML ? { __html: renderMarkdownAsHTML(activity.text || '') } : { __html: '' }),
18
+ [activity.text, renderMarkdownAsHTML]
19
+ );
20
+
21
+ return (
22
+ <div className={classNames['pre-chat-message-activity']}>
23
+ {/* eslint-disable-next-line react/no-danger */}
24
+ <div className={classNames['pre-chat-message-activity__body']} dangerouslySetInnerHTML={html} />
25
+ <StarterPromptsToolbar
26
+ cardActions={activity.suggestedActions?.actions || []}
27
+ className={classNames['pre-chat-message-activity__toolbar']}
28
+ />
29
+ </div>
30
+ );
31
+ };
32
+
33
+ PreChatMessageActivity.displayName = 'PreChatMessageActivity';
34
+
35
+ export default memo(PreChatMessageActivity);
@@ -0,0 +1,58 @@
1
+ :global(.webchat-fluent) .pre-chat-message-activity__card-action-box {
2
+ appearance: none;
3
+ background-color: var(--webchat-colorNeutralBackground1);
4
+ border: 0;
5
+ border-radius: 16px;
6
+ box-shadow: var(--webchat-shadow2);
7
+ color: var(--webchat-colorNeutralForeground1);
8
+ cursor: pointer;
9
+ display: grid;
10
+ gap: 8px;
11
+ grid-template-areas: 'image title' 'image subtitle';
12
+ grid-template-columns: 20px 1fr;
13
+ grid-template-rows: auto 1fr;
14
+ overflow: hidden;
15
+ padding: 16px 20px;
16
+ text-align: left;
17
+ user-select: none;
18
+ }
19
+
20
+ :global(.webchat-fluent) .pre-chat-message-activity__card-action-box:disabled {
21
+ background-color: var(--webchat-colorNeutralBackground1Disabled);
22
+ }
23
+
24
+ :global(.webchat-fluent) .pre-chat-message-activity__card-action-box:hover {
25
+ background-color: var(--webchat-colorNeutralGrey94);
26
+ }
27
+
28
+ :global(.webchat-fluent) .pre-chat-message-activity__card-action-box:active {
29
+ background-color: var(--webchat-colorNeutralBackground1Pressed);
30
+ }
31
+
32
+ :global(.webchat-fluent) .pre-chat-message-activity__card-action-box:focus-visible {
33
+ outline: solid 2px var(--webchat-colorStrokeFocus2);
34
+ outline-offset: -2px;
35
+ }
36
+
37
+ :global(.webchat-fluent) .pre-chat-message-activity__card-action-image {
38
+ grid-area: image;
39
+ height: 20px;
40
+ width: 20px;
41
+ }
42
+
43
+ :global(.webchat-fluent) .pre-chat-message-activity__card-action-subtitle {
44
+ font-family: var(--webchat-fontFamilyBase);
45
+ font-size: 14px;
46
+ font-weight: var(--webchat-fontWeightRegular);
47
+ grid-area: subtitle;
48
+ line-height: 20px;
49
+ pointer-events: none; /* Links in subtitle are not clickable. */
50
+ }
51
+
52
+ :global(.webchat-fluent) .pre-chat-message-activity__card-action-title {
53
+ font-family: var(--webchat-fontFamilyBase);
54
+ font-size: 14px;
55
+ font-weight: var(--webchat-fontWeightSemibold);
56
+ grid-area: title;
57
+ line-height: 20px;
58
+ }
@@ -0,0 +1,64 @@
1
+ import { hooks } from 'botframework-webchat-component';
2
+ import { type DirectLineCardAction } from 'botframework-webchat-core';
3
+ import cx from 'classnames';
4
+ import React, { memo, useCallback, useMemo } from 'react';
5
+ import { useRefFrom } from 'use-ref-from';
6
+ import { useStyles } from '../../styles/index.js';
7
+ import testIds from '../../testIds.js';
8
+ import MonochromeImageMasker from './private/MonochromeImageMasker.js';
9
+ import styles from './StarterPromptsCardAction.module.css';
10
+
11
+ const { useFocus, useRenderMarkdownAsHTML, useSendBoxValue } = hooks;
12
+
13
+ type Props = Readonly<{
14
+ className?: string | undefined;
15
+ messageBackAction: DirectLineCardAction & { type: 'messageBack' };
16
+ }>;
17
+
18
+ const StarterPromptAction = ({ className, messageBackAction }: Props) => {
19
+ const [_, setSendBoxValue] = useSendBoxValue();
20
+ const classNames = useStyles(styles);
21
+ const focus = useFocus();
22
+ const inputTextRef = useRefFrom(messageBackAction.displayText || messageBackAction.text || '');
23
+ const renderMarkdownAsHTML = useRenderMarkdownAsHTML('message activity');
24
+ const subtitleHTML = useMemo(
25
+ () => (renderMarkdownAsHTML ? { __html: renderMarkdownAsHTML(messageBackAction.text || '') } : { __html: '' }),
26
+ [messageBackAction.text, renderMarkdownAsHTML]
27
+ );
28
+
29
+ const handleClick = useCallback(() => {
30
+ setSendBoxValue(inputTextRef.current);
31
+
32
+ // Focus on the send box after the value is "pasted."
33
+ focus('sendBox');
34
+ }, [focus, inputTextRef, setSendBoxValue]);
35
+
36
+ return (
37
+ <button
38
+ className={cx(className, classNames['pre-chat-message-activity__card-action-box'])}
39
+ data-testid={testIds.preChatMessageActivityStarterPromptsCardAction}
40
+ onClick={handleClick}
41
+ type="button"
42
+ >
43
+ <div className={classNames['pre-chat-message-activity__card-action-title']}>
44
+ {'title' in messageBackAction && messageBackAction.title}
45
+ </div>
46
+ {'image' in messageBackAction && messageBackAction.image && (
47
+ <MonochromeImageMasker
48
+ className={classNames['pre-chat-message-activity__card-action-image']}
49
+ src={messageBackAction.image}
50
+ />
51
+ // <img className="pre-chat-message-activity__card-action-image" src={messageBackAction.image} />
52
+ )}
53
+ <div
54
+ className={classNames['pre-chat-message-activity__card-action-subtitle']}
55
+ // eslint-disable-next-line react/no-danger
56
+ dangerouslySetInnerHTML={subtitleHTML}
57
+ />
58
+ </button>
59
+ );
60
+ };
61
+
62
+ StarterPromptAction.displayName = 'StarterPromptAction';
63
+
64
+ export default memo(StarterPromptAction);
@@ -0,0 +1,18 @@
1
+ :global(.webchat-fluent) .pre-chat-message-activity__card-action-toolbar {
2
+ container-name: webchat-container;
3
+ container-type: inline-size;
4
+ }
5
+
6
+ :global(.webchat-fluent) .pre-chat-message-activity__card-action-toolbar-grid {
7
+ display: grid;
8
+ gap: var(--webchat-spacingHorizontalM);
9
+ grid-template-columns: 1fr 1fr 1fr;
10
+ padding: 0;
11
+ }
12
+
13
+ /* TODO: What is the good width to show as 3 columns? Web Chat, by default, has a bubble max width of 480px. */
14
+ @container webchat-container (width <= 480px) {
15
+ :global(.webchat-fluent) .pre-chat-message-activity__card-action-toolbar-grid {
16
+ grid-template-columns: 1fr;
17
+ }
18
+ }
@@ -0,0 +1,35 @@
1
+ import { type DirectLineCardAction } from 'botframework-webchat-core';
2
+ import cx from 'classnames';
3
+ import React, { memo } from 'react';
4
+ import { useStyles } from '../../styles/index.js';
5
+ import StarterPromptsCardAction from './StarterPromptsCardAction.js';
6
+ import styles from './StarterPromptsToolbar.module.css';
7
+
8
+ type Props = Readonly<{
9
+ cardActions: readonly DirectLineCardAction[];
10
+ className?: string | undefined;
11
+ }>;
12
+
13
+ const StarterPrompts = ({ cardActions, className }: Props) => {
14
+ const classNames = useStyles(styles);
15
+
16
+ return (
17
+ // TODO: Accessibility-wise, this should be role="toolbar" with keyboard navigation.
18
+ <div className={cx(className, classNames['pre-chat-message-activity__card-action-toolbar'])}>
19
+ <div className={classNames['pre-chat-message-activity__card-action-toolbar-grid']}>
20
+ {cardActions
21
+ .filter<DirectLineCardAction & { type: 'messageBack' }>(
22
+ (card: DirectLineCardAction): card is DirectLineCardAction & { type: 'messageBack' } =>
23
+ card.type === 'messageBack'
24
+ )
25
+ .map(cardAction => (
26
+ <StarterPromptsCardAction key={cardAction.text} messageBackAction={cardAction} />
27
+ ))}
28
+ </div>
29
+ </div>
30
+ );
31
+ };
32
+
33
+ StarterPrompts.displayName = 'StarterPrompts';
34
+
35
+ export default memo(StarterPrompts);
@@ -0,0 +1,2 @@
1
+ export { default as isPreChatMessageActivity } from './isPreChatMessageActivity.js';
2
+ export { default as PreChatMessageActivity } from './PreChatMessageActivity.js';
@@ -0,0 +1,26 @@
1
+ import type { WebChatActivity } from 'botframework-webchat-core';
2
+ import { array, literal, object, safeParse, string, type InferOutput } from 'valibot';
3
+
4
+ const messageEntity = object({
5
+ '@context': literal('https://schema.org'),
6
+ '@id': literal(''), // Must be empty string.
7
+ '@type': literal('Message'),
8
+ keywords: array(string()),
9
+ type: literal('https://schema.org/Message')
10
+ });
11
+
12
+ type MessageEntity = InferOutput<typeof messageEntity>;
13
+
14
+ export default function isPreChatMessageActivity(
15
+ activity: undefined | WebChatActivity
16
+ ): activity is WebChatActivity & { type: 'message' } {
17
+ if (activity?.type !== 'message') {
18
+ return false;
19
+ }
20
+
21
+ const message = activity.entities?.find(
22
+ (entity): entity is MessageEntity => safeParse(messageEntity, entity).success
23
+ );
24
+
25
+ return !!message?.keywords.includes('PreChatMessage');
26
+ }
@@ -0,0 +1,5 @@
1
+ :global(.webchat-fluent) .pre-chat-message-activity__monochrome-image-masker {
2
+ background-color: var(--webchat-colorNeutralForeground4);
3
+ mask-image: var(--mask-image);
4
+ --webkit-mask-image: var(--mask-image);
5
+ }
@@ -0,0 +1,19 @@
1
+ import cx from 'classnames';
2
+ import React, { memo, useMemo, type CSSProperties } from 'react';
3
+ import { useStyles } from '../../../styles/index.js';
4
+ import styles from './MonochromeImageMasker.module.css';
5
+
6
+ type Props = Readonly<{ className?: string | undefined; src: string }>;
7
+
8
+ const MonochromeImageMasker = ({ className, src }: Props) => {
9
+ const classNames = useStyles(styles);
10
+ const style = useMemo(() => ({ '--mask-image': `url(${src})` }) as CSSProperties, [src]);
11
+
12
+ return (
13
+ <div className={cx(className, classNames['pre-chat-message-activity__monochrome-image-masker'])} style={style} />
14
+ );
15
+ };
16
+
17
+ MonochromeImageMasker.displayName = 'MonochromeImageMasker';
18
+
19
+ export default memo(MonochromeImageMasker);
@@ -3,6 +3,7 @@ import cx from 'classnames';
3
3
  import React, { memo, useCallback, useRef, useState, type FormEventHandler, type MouseEventHandler } from 'react';
4
4
  import { useRefFrom } from 'use-ref-from';
5
5
  import { SendIcon } from '../../icons';
6
+ import { useStyles } from '../../styles';
6
7
  import testIds from '../../testIds';
7
8
  import { DropZone } from '../dropZone';
8
9
  import { SuggestedActions } from '../suggestedActions';
@@ -10,14 +11,13 @@ import { TelephoneKeypadSurrogate, useTelephoneKeypadShown, type DTMF } from '..
10
11
  import AddAttachmentButton from './AddAttachmentButton';
11
12
  import Attachments from './Attachments';
12
13
  import ErrorMessage from './ErrorMessage';
13
- import TelephoneKeypadToolbarButton from './TelephoneKeypadToolbarButton';
14
- import TextArea from './TextArea';
15
- import { Toolbar, ToolbarButton, ToolbarSeparator } from './Toolbar';
16
14
  import useSubmitError from './private/useSubmitError';
15
+ import useTranscriptNavigation from './private/useTranscriptNavigation';
17
16
  import useUniqueId from './private/useUniqueId';
18
17
  import styles from './SendBox.module.css';
19
- import { useStyles } from '../../styles';
20
- import useTranscriptNavigation from './private/useTranscriptNavigation';
18
+ import TelephoneKeypadToolbarButton from './TelephoneKeypadToolbarButton';
19
+ import TextArea from './TextArea';
20
+ import { Toolbar, ToolbarButton, ToolbarSeparator } from './Toolbar';
21
21
 
22
22
  const {
23
23
  useFocus,
@@ -25,18 +25,23 @@ const {
25
25
  useMakeThumbnail,
26
26
  useRegisterFocusSendBox,
27
27
  useSendBoxAttachments,
28
+ useSendBoxValue,
28
29
  useSendMessage,
29
30
  useStyleOptions
30
31
  } = hooks;
31
32
 
32
- function SendBox(
33
- props: Readonly<{
34
- className?: string | undefined;
35
- placeholder?: string | undefined;
36
- }>
37
- ) {
33
+ type Props = Readonly<{
34
+ className?: string | undefined;
35
+ isPrimary?: boolean | undefined;
36
+ placeholder?: string | undefined;
37
+ }>;
38
+
39
+ function SendBox(props: Props) {
38
40
  const inputRef = useRef<HTMLTextAreaElement>(null);
39
- const [message, setMessage] = useState('');
41
+ const [localMessage, setLocalMessage] = useState('');
42
+ const [globalMessage, setGlobalMessage] = useSendBoxValue();
43
+ const message = props.isPrimary ? globalMessage : localMessage;
44
+ const setMessage = props.isPrimary ? setGlobalMessage : setLocalMessage;
40
45
  const [attachments, setAttachments] = useSendBoxAttachments();
41
46
  const [{ hideTelephoneKeypadButton, hideUploadButton, maxMessageLength }] = useStyleOptions();
42
47
  const isMessageLengthExceeded = !!maxMessageLength && message.length > maxMessageLength;
@@ -183,7 +188,7 @@ function SendBox(
183
188
  />
184
189
  <Attachments attachments={attachments} className={classNames['sendbox__attachment--in-grid']} />
185
190
  <div className={cx(classNames['sendbox__sendbox-controls'], classNames['sendbox__sendbox-controls--in-grid'])}>
186
- {!telephoneKeypadShown && maxMessageLength && (
191
+ {!telephoneKeypadShown && maxMessageLength && isFinite(maxMessageLength) && (
187
192
  <div
188
193
  className={cx(classNames['sendbox__text-counter'], {
189
194
  [classNames['sendbox__text-counter--error']]: isMessageLengthExceeded
@@ -213,4 +218,10 @@ function SendBox(
213
218
  );
214
219
  }
215
220
 
221
+ const PrimarySendBox = memo((props: Exclude<Props, 'primary'>) => <SendBox {...props} isPrimary={true} />);
222
+
223
+ PrimarySendBox.displayName = 'PrimarySendBox';
224
+
216
225
  export default memo(SendBox);
226
+
227
+ export { PrimarySendBox };
@@ -1 +1 @@
1
- export { default as SendBox } from './SendBox';
1
+ export { PrimarySendBox, default as SendBox } from './SendBox';
@@ -1,11 +1,12 @@
1
1
  import { hooks } from 'botframework-webchat-component';
2
2
  import cx from 'classnames';
3
3
  import React, { memo, useCallback, type ReactNode } from 'react';
4
- import SuggestedAction from './SuggestedAction';
5
- import computeSuggestedActionText from './private/computeSuggestedActionText';
6
- import styles from './SuggestedActions.module.css';
7
4
  import { useStyles } from '../../styles';
5
+ import { isPreChatMessageActivity } from '../preChatActivity';
6
+ import computeSuggestedActionText from './private/computeSuggestedActionText';
8
7
  import RovingFocusProvider from './private/rovingFocus';
8
+ import SuggestedAction from './SuggestedAction';
9
+ import styles from './SuggestedActions.module.css';
9
10
 
10
11
  const { useFocus, useLocalizer, useStyleOptions, useStyleSet, useSuggestedActions } = hooks;
11
12
 
@@ -44,54 +45,56 @@ function SuggestedActionStackedOrFlowContainer(
44
45
  function SuggestedActions() {
45
46
  const classNames = useStyles(styles);
46
47
  const localize = useLocalizer();
47
- const [suggestedActions] = useSuggestedActions();
48
+ const [suggestedActions, _, { activity }] = useSuggestedActions();
48
49
  const focus = useFocus();
49
50
 
50
51
  const handleEscapeKey = useCallback(() => {
51
52
  focus('sendBox');
52
53
  }, [focus]);
53
54
 
54
- const children = suggestedActions.map((cardAction, index) => {
55
- const { displayText, image, imageAltText, text, type, value } = cardAction as {
56
- displayText?: string;
57
- image?: string;
58
- imageAltText?: string;
59
- text?: string;
60
- type:
61
- | 'call'
62
- | 'downloadFile'
63
- | 'imBack'
64
- | 'messageBack'
65
- | 'openUrl'
66
- | 'playAudio'
67
- | 'playVideo'
68
- | 'postBack'
69
- | 'showImage'
70
- | 'signin';
71
- value?: { [key: string]: any } | string;
72
- };
55
+ const children = isPreChatMessageActivity(activity)
56
+ ? [] // Do not show suggested actions for pre-chat message, suggested actions has already shown inlined.
57
+ : suggestedActions.map((cardAction, index) => {
58
+ const { displayText, image, imageAltText, text, type, value } = cardAction as {
59
+ displayText?: string;
60
+ image?: string;
61
+ imageAltText?: string;
62
+ text?: string;
63
+ type:
64
+ | 'call'
65
+ | 'downloadFile'
66
+ | 'imBack'
67
+ | 'messageBack'
68
+ | 'openUrl'
69
+ | 'playAudio'
70
+ | 'playVideo'
71
+ | 'postBack'
72
+ | 'showImage'
73
+ | 'signin';
74
+ value?: { [key: string]: any } | string;
75
+ };
73
76
 
74
- if (!suggestedActions?.length) {
75
- return null;
76
- }
77
+ if (!suggestedActions?.length) {
78
+ return null;
79
+ }
77
80
 
78
- return (
79
- <SuggestedAction
80
- buttonText={computeSuggestedActionText(cardAction)}
81
- displayText={displayText}
82
- image={image}
83
- // Image alt text should use `imageAltText` field and fallback to `text` field.
84
- // https://github.com/microsoft/botframework-sdk/blob/main/specs/botframework-activity/botframework-activity.md#image-alt-text
85
- imageAlt={image && (imageAltText || text)}
86
- itemIndex={index}
87
- // eslint-disable-next-line react/no-array-index-key
88
- key={index}
89
- text={text}
90
- type={type}
91
- value={value}
92
- />
93
- );
94
- });
81
+ return (
82
+ <SuggestedAction
83
+ buttonText={computeSuggestedActionText(cardAction)}
84
+ displayText={displayText}
85
+ image={image}
86
+ // Image alt text should use `imageAltText` field and fallback to `text` field.
87
+ // https://github.com/microsoft/botframework-sdk/blob/main/specs/botframework-activity/botframework-activity.md#image-alt-text
88
+ imageAlt={image && (imageAltText || text)}
89
+ itemIndex={index}
90
+ // eslint-disable-next-line react/no-array-index-key
91
+ key={index}
92
+ text={text}
93
+ type={type}
94
+ value={value}
95
+ />
96
+ );
97
+ });
95
98
 
96
99
  return (
97
100
  <RovingFocusProvider onEscapeKey={handleEscapeKey}>
@@ -1,4 +1,3 @@
1
-
2
1
  :global(.webchat-fluent).theme {
3
2
  display: contents;
4
3
 
@@ -16,10 +15,15 @@
16
15
  --webchat-colorNeutralBackground4: var(--colorNeutralBackground4, #f0f0f0);
17
16
  --webchat-colorNeutralBackground5: var(--colorNeutralBackground5, #ebebeb);
18
17
 
18
+ --webchat-colorNeutralBackground1Disabled: var(--colorNeutralBackground1Disabled, #f0f0f0);
19
+ --webchat-colorNeutralBackground1Pressed: var(--colorNeutralBackground1Pressed, #e0e0e0);
20
+
21
+ --webchat-colorNeutralGrey94: var(--colorNeutralGrey94, #f0f0f0);
22
+
19
23
  --webchat-colorNeutralStroke1: var(--colorNeutralStroke1, #d1d1d1);
20
24
  --webchat-colorNeutralStroke2: var(--colorNeutralStroke2, #e0e0e0);
21
25
  --webchat-colorNeutralStroke1Selected: var(--colorNeutralStroke1Selected, #bdbdbd);
22
-
26
+
23
27
  --webchat-colorStrokeFocus2: var(--colorStrokeFocus2, #000000);
24
28
 
25
29
  --webchat-colorBrandStroke2: var(--colorBrandStroke2, #9edcf7);
@@ -30,7 +34,7 @@
30
34
  --webchat-colorBrandForegroundLink: var(--colorBrandForegroundLink, #01678c);
31
35
  --webchat-colorBrandForegroundLinkHover: var(--colorBrandForegroundLinkHover, #015a7a);
32
36
  --webchat-colorBrandForegroundLinkPressed: var(--colorBrandForegroundLinkPressed, #014259);
33
- --webchat-colorBrandForegroundLinkSelected: var(--colorBrandForegroundLinkSelected, #01678c);
37
+ --webchat-colorBrandForegroundLinkSelected: var(--colorBrandForegroundLinkSelected, #01678c);
34
38
 
35
39
  --webchat-colorBrandBackground2Hover: var(--colorBrandBackground2Hover, #bee7fa);
36
40
  --webchat-colorBrandBackground2Pressed: var(--colorBrandBackground2Pressed, #7fd2f5);
@@ -55,14 +59,25 @@
55
59
 
56
60
  /* https://github.com/microsoft/fluentui/blob/master/packages/tokens/src/global/spacings.ts */
57
61
  --webchat-spacingHorizontalMNudge: var(--spacingHorizontalMNudge, 10px);
62
+ --webchat-spacingHorizontalM: var(--spacingHorizontalM, 12px);
63
+ --webchat-spacingHorizontalXXXL: var(--spacingHorizontalXXXL, 32px);
64
+ --webchat-spacingVerticalL: var(--spacingVerticalL, 16px);
58
65
 
59
66
  /* https://github.com/microsoft/fluentui/blob/master/packages/tokens/src/global/fonts.ts */
60
67
  --webchat-fontFamilyBase: var(--fontFamilyBase, 'Segoe UI', 'Segoe UI Web (West European)', -apple-system, BlinkMacSystemFont, Roboto, 'Helvetica Neue', sans-serif);
61
68
  --webchat-fontFamilyNumeric: var(--fontFamilyNumeric, Bahnschrift, 'Segoe UI', 'Segoe UI Web (West European)', -apple-system, BlinkMacSystemFont, Roboto, 'Helvetica Neue', sans-serif);
62
69
 
63
70
  /* https://github.com/microsoft/fluentui/blob/master/packages/tokens/src/global/fonts.ts */
71
+ --webchat-fontWeightRegular: var(--fontWeightRegular, 400);
64
72
  --webchat-fontWeightSemibold: var(--fontWeightSemibold, 600);
65
-
73
+
74
+ /* https://github.com/microsoft/fluentui/blob/master/packages/tokens/src/global/fonts.ts */
75
+ --webchat-fontSizeBase300: var(--fontSizeBase300, 14px);
76
+ --webchat-fontSizeHero700: var(--fontSizeHero700, 28px);
77
+
78
+ --webchat-lineHeightBase300: var(--lineHeightBase300, 20px);
79
+ --webchat-lineHeightHero700: var(--lineHeightHero700, 36px);
80
+
66
81
  --webchat-strokeWidthThicker: var(--strokeWidthThicker, 3px);
67
82
 
68
83
  --webchat-durationUltraFast: var(--durationUltraFast, 0);
@@ -70,6 +85,9 @@
70
85
 
71
86
  --webchat-curveAccelerateMid: var(--curveAccelerateMid, cubic-bezier(1,0,1,1));
72
87
  --webchat-curveDecelerateMid: var(--curveDecelerateMid, cubic-bezier(0,0,0,1));
88
+
89
+ /* https://github.com/microsoft/fluentui/blob/master/packages/tokens/src/utils/shadows.ts */
90
+ --webchat-shadow2: 0 0 2px rgba(0, 0, 0, 12%), 0 1px 2px rgba(0, 0, 0, 14%);
73
91
  }
74
92
 
75
93
  @media (prefers-reduced-motion) {
@@ -77,4 +95,4 @@
77
95
  --webchat-durationUltraFast: 0.01ms;
78
96
  --webchat-durationNormal: 0.01ms;
79
97
  }
80
- }
98
+ }
@@ -5,7 +5,7 @@ import { useStyles } from '../../styles';
5
5
 
6
6
  export const rootClassName = 'webchat-fluent';
7
7
 
8
- export default function WebchatTheme(props: Readonly<{ readonly children: ReactNode | undefined }>) {
8
+ export default function Theme(props: Readonly<{ readonly children: ReactNode | undefined }>) {
9
9
  const classNames = useStyles(styles);
10
10
  return <div className={cx(rootClassName, classNames['theme'])}>{props.children}</div>;
11
11
  }
@@ -1,20 +1,37 @@
1
1
  import { Components } from 'botframework-webchat-component';
2
2
  import React, { memo, type ReactNode } from 'react';
3
3
 
4
+ import type { ActivityMiddleware } from 'botframework-webchat-api';
5
+ import { isPreChatMessageActivity, PreChatMessageActivity } from '../components/preChatActivity';
6
+ import { PrimarySendBox } from '../components/sendBox';
4
7
  import { TelephoneKeypadProvider } from '../components/telephoneKeypad';
5
8
  import { WebChatTheme } from '../components/theme';
6
- import { SendBox } from '../components/sendBox';
7
9
 
8
10
  const { ThemeProvider } = Components;
9
11
 
10
12
  type Props = Readonly<{ children?: ReactNode | undefined }>;
11
13
 
12
- const sendBoxMiddleware = [() => () => () => SendBox];
14
+ const activityMiddleware: ActivityMiddleware[] = [
15
+ () =>
16
+ next =>
17
+ (...args) => {
18
+ const activity = args[0]?.activity;
19
+
20
+ if (activity && isPreChatMessageActivity(activity)) {
21
+ return () => <PreChatMessageActivity activity={activity} />;
22
+ }
23
+
24
+ return next(...args);
25
+ }
26
+ ];
27
+ const sendBoxMiddleware = [() => () => () => PrimarySendBox];
13
28
 
14
29
  const FluentThemeProvider = ({ children }: Props) => (
15
30
  <WebChatTheme>
16
31
  <TelephoneKeypadProvider>
17
- <ThemeProvider sendBoxMiddleware={sendBoxMiddleware}>{children}</ThemeProvider>
32
+ <ThemeProvider activityMiddleware={activityMiddleware} sendBoxMiddleware={sendBoxMiddleware}>
33
+ {children}
34
+ </ThemeProvider>
18
35
  </TelephoneKeypadProvider>
19
36
  </WebChatTheme>
20
37
  );
package/src/testIds.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  const testIds = {
2
+ preChatMessageActivityStarterPromptsCardAction: 'pre-chat message activity starter prompts card action',
2
3
  sendBoxDropZone: 'send box drop zone',
3
4
  sendBoxSendButton: 'send box send button',
4
5
  sendBoxTextBox: 'send box text area',