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.
- package/dist/botframework-webchat-fluent-theme.css.map +1 -1
- package/dist/botframework-webchat-fluent-theme.d.mts +1 -0
- package/dist/botframework-webchat-fluent-theme.d.ts +1 -0
- package/dist/botframework-webchat-fluent-theme.development.css.map +1 -1
- package/dist/botframework-webchat-fluent-theme.development.js +1 -1
- package/dist/botframework-webchat-fluent-theme.development.js.map +1 -1
- package/dist/botframework-webchat-fluent-theme.js +1 -1
- package/dist/botframework-webchat-fluent-theme.js.map +1 -1
- package/dist/botframework-webchat-fluent-theme.mjs +1 -1
- package/dist/botframework-webchat-fluent-theme.mjs.map +1 -1
- package/dist/botframework-webchat-fluent-theme.production.min.css.map +1 -1
- package/dist/botframework-webchat-fluent-theme.production.min.js +1 -1
- package/dist/botframework-webchat-fluent-theme.production.min.js.map +1 -1
- package/package.json +6 -5
- package/src/components/preChatActivity/PreChatMessageActivity.module.css +34 -0
- package/src/components/preChatActivity/PreChatMessageActivity.tsx +35 -0
- package/src/components/preChatActivity/StarterPromptsCardAction.module.css +58 -0
- package/src/components/preChatActivity/StarterPromptsCardAction.tsx +64 -0
- package/src/components/preChatActivity/StarterPromptsToolbar.module.css +18 -0
- package/src/components/preChatActivity/StarterPromptsToolbar.tsx +35 -0
- package/src/components/preChatActivity/index.tsx +2 -0
- package/src/components/preChatActivity/isPreChatMessageActivity.ts +26 -0
- package/src/components/preChatActivity/private/MonochromeImageMasker.module.css +5 -0
- package/src/components/preChatActivity/private/MonochromeImageMasker.tsx +19 -0
- package/src/components/sendBox/SendBox.tsx +24 -13
- package/src/components/sendBox/index.tsx +1 -1
- package/src/components/suggestedActions/SuggestedActions.tsx +46 -43
- package/src/components/theme/Theme.module.css +23 -5
- package/src/components/theme/Theme.tsx +1 -1
- package/src/private/FluentThemeProvider.tsx +20 -3
- 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.
|
|
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.
|
|
73
|
-
"botframework-webchat-component": "4.18.
|
|
74
|
-
"botframework-webchat-core": "4.18.
|
|
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,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,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
|
|
20
|
-
import
|
|
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
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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 [
|
|
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 =
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
+
if (!suggestedActions?.length) {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
77
80
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
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
|
|
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
|
|
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}>
|
|
32
|
+
<ThemeProvider activityMiddleware={activityMiddleware} sendBoxMiddleware={sendBoxMiddleware}>
|
|
33
|
+
{children}
|
|
34
|
+
</ThemeProvider>
|
|
18
35
|
</TelephoneKeypadProvider>
|
|
19
36
|
</WebChatTheme>
|
|
20
37
|
);
|
package/src/testIds.ts
CHANGED