Skip to content

Commit 60fdd80

Browse files
authored
[Fluent theme] Hide buttons, suggested actions FnF and flow layout, DTMF FnF (#5132)
* Hide attach file and telephone keypad button * Touch up * Smaller suggested actions button * Fix telephone keypad color contrast * Sort * Suggested actions fit-and-finish * Add entry * Disable Terrapin * Fix tests
1 parent ff34969 commit 60fdd80

File tree

38 files changed

+218
-49
lines changed

38 files changed

+218
-49
lines changed

.github/workflows/pull-request-validation.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ env:
2323
CI_PULL_REQUEST: 1 # Skip nightly tests
2424
NODE_ENV: test # Add instrumentation code
2525
node-version: 18.18 # Need to bump jest@29 to resolve something in https://github.com/facebook/react-native/issues/35701
26-
skip-secure-feed: false
26+
skip-secure-feed: true # Terrapin service is degrading and their team told us to disable Terrapin to unblock ourselves
2727

2828
jobs:
2929
build:

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
4141
- `styleOptions.maxMessageLength` to specify maximum length of the outgoing message
4242
- Drag-and-drop file support, in PR [#5122](https://github.com/microsoft/BotFramework-WebChat/pull/5122)
4343
- Added telephone keypad (DTMF keypad), in PR [#5122](https://github.com/microsoft/BotFramework-WebChat/pull/5122)
44+
- Added support of `styleOptions.hideUploadButton`, in PR [#5132](https://github.com/microsoft/BotFramework-WebChat/pull/5132)
45+
- Added `styleOptions.hideTelephoneKeypadButton` and default to `true`, in PR [#5132](https://github.com/microsoft/BotFramework-WebChat/pull/5132)
46+
- Fit-and-finish on suggested actions and telephone keypad, in PR [#5132](https://github.com/microsoft/BotFramework-WebChat/pull/5132)
47+
- Fixed to keep telephone keypad on-screen on click, in PR [#5132](https://github.com/microsoft/BotFramework-WebChat/pull/5132)
4448
- Added `<ThemeProvider>` component to apply theme pack to Web Chat, by [@compulim](https://github.com/compulim), in PR [#5120](https://github.com/microsoft/BotFramework-WebChat/pull/5120)
4549
- Added `useMakeThumbnail` hook option to create a thumbnail from the file given, by [@compulim](https://github.com/compulim), in PR [#5123](https://github.com/microsoft/BotFramework-WebChat/pull/5123) and [#5122](https://github.com/microsoft/BotFramework-WebChat/pull/5122)
4650

Loading
Loading
Loading
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<!doctype html>
2+
<html lang="en-US">
3+
<head>
4+
<link href="/assets/index.css" rel="stylesheet" type="text/css" />
5+
<script crossorigin="anonymous" src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
6+
<script crossorigin="anonymous" src="https://unpkg.com/[email protected]/umd/react.production.min.js"></script>
7+
<script crossorigin="anonymous" src="https://unpkg.com/[email protected]/umd/react-dom.production.min.js"></script>
8+
<script crossorigin="anonymous" src="/test-harness.js"></script>
9+
<script crossorigin="anonymous" src="/test-page-object.js"></script>
10+
<script crossorigin="anonymous" src="/__dist__/webchat-es5.js"></script>
11+
<script crossorigin="anonymous" src="/__dist__/botframework-webchat-fluent-theme.production.min.js"></script>
12+
</head>
13+
<body>
14+
<main id="webchat"></main>
15+
<script type="text/babel">
16+
run(async function () {
17+
const {
18+
React,
19+
ReactDOM: { render },
20+
WebChat: { FluentThemeProvider, ReactWebChat }
21+
} = window; // Imports in UMD fashion.
22+
23+
const { directLine, store } = testHelpers.createDirectLineEmulator();
24+
25+
const App = () => (
26+
<ReactWebChat directLine={directLine} store={store} styleOptions={{ hideUploadButton: true }} />
27+
);
28+
29+
render(
30+
<FluentThemeProvider>
31+
<App />
32+
</FluentThemeProvider>,
33+
document.getElementById('webchat')
34+
);
35+
36+
await pageConditions.uiConnected();
37+
38+
// THEN: No attach button should be render.
39+
expect(pageElements.byTestId(WebChat.testIds.sendBoxUploadButton)).toBeFalsy();
40+
await host.snapshot();
41+
});
42+
</script>
43+
</body>
44+
</html>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/** @jest-environment ./packages/test/harness/src/host/jest/WebDriverEnvironment.js */
2+
3+
describe('Fluent theme applied', () => {
4+
test('when styleOptions.hideUploadButton is truthy should not render attach file button', () => runHTML('fluentTheme/hideAttachFileButton'));
5+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
<!doctype html>
2+
<html lang="en-US">
3+
<head>
4+
<link href="/assets/index.css" rel="stylesheet" type="text/css" />
5+
<script crossorigin="anonymous" src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
6+
<script crossorigin="anonymous" src="https://unpkg.com/[email protected]/umd/react.production.min.js"></script>
7+
<script crossorigin="anonymous" src="https://unpkg.com/[email protected]/umd/react-dom.production.min.js"></script>
8+
<script crossorigin="anonymous" src="/test-harness.js"></script>
9+
<script crossorigin="anonymous" src="/test-page-object.js"></script>
10+
<script crossorigin="anonymous" src="/__dist__/webchat-es5.js"></script>
11+
<script crossorigin="anonymous" src="/__dist__/botframework-webchat-fluent-theme.production.min.js"></script>
12+
</head>
13+
<body>
14+
<main id="webchat"></main>
15+
<script type="text/babel">
16+
run(async function () {
17+
const {
18+
React,
19+
ReactDOM: { render },
20+
WebChat: { FluentThemeProvider, ReactWebChat }
21+
} = window; // Imports in UMD fashion.
22+
23+
const { directLine, store } = testHelpers.createDirectLineEmulator();
24+
25+
const App = () => (
26+
<ReactWebChat directLine={directLine} store={store} styleOptions={{ suggestedActionLayout: 'flow' }} />
27+
);
28+
29+
render(
30+
<FluentThemeProvider>
31+
<App />
32+
</FluentThemeProvider>,
33+
document.getElementById('webchat')
34+
);
35+
36+
await pageConditions.uiConnected();
37+
38+
await directLine.emulateIncomingActivity({
39+
type: 'message',
40+
textFormat: 'plain',
41+
text: 'Please select one of the actions below',
42+
suggestedActions: {
43+
actions: [
44+
{ title: 'A', type: 'imBack' },
45+
{ title: 'B', type: 'imBack' },
46+
{ title: 'C', type: 'imBack' },
47+
{ title: 'D', type: 'imBack' },
48+
{ title: 'E', type: 'imBack' },
49+
{ title: 'F', type: 'imBack' },
50+
{ title: 'G', type: 'imBack' },
51+
{ title: 'H', type: 'imBack' },
52+
{ title: 'I', type: 'imBack' },
53+
{ title: 'J', type: 'imBack' },
54+
{ title: 'K', type: 'imBack' },
55+
{ title: 'L', type: 'imBack' },
56+
{ title: 'M', type: 'imBack' },
57+
{ title: 'N', type: 'imBack' },
58+
{ title: 'O', type: 'imBack' },
59+
{ title: 'P', type: 'imBack' },
60+
{ title: 'Q', type: 'imBack' },
61+
{ title: 'R', type: 'imBack' },
62+
{ title: 'S', type: 'imBack' },
63+
{ title: 'T', type: 'imBack' },
64+
{ title: 'U', type: 'imBack' },
65+
{ title: 'V', type: 'imBack' },
66+
{ title: 'W', type: 'imBack' },
67+
{ title: 'X', type: 'imBack' },
68+
{ title: 'Y', type: 'imBack' },
69+
{ title: 'Z', type: 'imBack' }
70+
],
71+
to: []
72+
}
73+
});
74+
75+
// THEN: Should render the activity.
76+
await host.snapshot();
77+
});
78+
</script>
79+
</body>
80+
</html>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/** @jest-environment ./packages/test/harness/src/host/jest/WebDriverEnvironment.js */
2+
3+
describe('Fluent theme applied', () => {
4+
test('renders suggested actions with a flow layout', () => runHTML('fluentTheme/suggestedActions.layout.flow'));
5+
});

__tests__/html/fluentTheme/tabOrder.html

+3-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@
2222

2323
const { directLine, store } = testHelpers.createDirectLineEmulator();
2424

25-
const App = () => <ReactWebChat directLine={directLine} store={store} />;
25+
const App = () => (
26+
<ReactWebChat directLine={directLine} store={store} styleOptions={{ hideTelephoneKeypadButton: false }} />
27+
);
2628

2729
render(
2830
<FluentThemeProvider>

__tests__/html/fluentTheme/telephoneKeypad.showHide.html

+3-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@
2222

2323
const { directLine, store } = testHelpers.createDirectLineEmulator();
2424

25-
const App = () => <ReactWebChat directLine={directLine} store={store} />;
25+
const App = () => (
26+
<ReactWebChat directLine={directLine} store={store} styleOptions={{ hideTelephoneKeypadButton: false }} />
27+
);
2628

2729
render(
2830
<FluentThemeProvider>

__tests__/html/fluentTheme/telephoneKeypad.tap.html

+9-10
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@
2222

2323
const { directLine, store } = testHelpers.createDirectLineEmulator();
2424

25-
const App = () => <ReactWebChat directLine={directLine} store={store} />;
25+
const App = () => (
26+
<ReactWebChat directLine={directLine} store={store} styleOptions={{ hideTelephoneKeypadButton: false }} />
27+
);
2628

2729
render(
2830
<FluentThemeProvider>
@@ -40,24 +42,21 @@
4042
await pageConditions.numActivitiesShown(1);
4143

4244
// WHEN: Telephone keypad button is clicked.
43-
await host.click(
44-
document.querySelector(`[data-testid="${WebChat.testIds.sendBoxTelephoneKeypadToolbarButton}"]`)
45-
);
45+
await host.click(pageElements.byTestId(WebChat.testIds.sendBoxTelephoneKeypadToolbarButton));
4646

4747
await (
4848
await directLine.actPostActivity(() =>
49-
host.click(document.querySelector(`[data-testid="${WebChat.testIds.sendBoxTelephoneKeypadButton5}"]`))
49+
host.click(pageElements.byTestId(WebChat.testIds.sendBoxTelephoneKeypadButton5))
5050
)
5151
).resolveAll();
5252

53-
// THEN: Should send "/DTMF 5" and focus on the send box.
53+
// THEN: Should send "/DTMF 5".
5454
await pageConditions.numActivitiesShown(2);
5555
expect(pageElements.activityContents()[1]).toHaveProperty('textContent', '/DTMF 5');
5656

57-
// Commented out because it is not working today.
58-
// expect(document.activeElement).toBe(
59-
// document.querySelector(`[data-testid="${WebChat.testIds.sendBoxTextBox}"]`)
60-
// );
57+
// THEN: Should not close the keypad and keep focusing on the button "5".
58+
expect(pageElements.byTestId(WebChat.testIds.sendBoxTelephoneKeypadButton5)).toBeTruthy();
59+
expect(document.activeElement).toBe(pageElements.byTestId(WebChat.testIds.sendBoxTelephoneKeypadButton5));
6160

6261
await host.snapshot();
6362
});

packages/api/src/StyleOptions.ts

+8
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,14 @@ type StyleOptions = {
256256

257257
hideSendBox?: boolean;
258258
hideUploadButton?: boolean;
259+
260+
/**
261+
* (EXPERIMENTAL) `true`, if the telephone keypad button should be shown, otherwise, `false`. Defaults to `true`.
262+
*
263+
* @deprecated This is an experimental style options and should not be used without understanding its risk.
264+
*/
265+
hideTelephoneKeypadButton?: boolean | undefined;
266+
259267
microphoneButtonColorOnDictate?: string;
260268
sendBoxBackground?: string;
261269

packages/api/src/defaultStyleOptions.ts

+1
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ const DEFAULT_OPTIONS: Required<StyleOptions> = {
9393
// Send box
9494
hideSendBox: false,
9595
hideUploadButton: false,
96+
hideTelephoneKeypadButton: true,
9697
microphoneButtonColorOnDictate: '#F33',
9798
sendBoxBackground: 'White',
9899
uploadAccept: undefined,

packages/fluent-theme/src/components/Theme.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,10 @@ const styles = {
3737

3838
'--webchat-colorStatusDangerForeground1': 'var(--colorStatusDangerForeground1, #b10e1c)',
3939

40-
// https://github.com/microsoft/fluentui/blob/master/packages/tokens/src/global/colors.ts
40+
// https://github.com/microsoft/fluentui/blob/master/packages/theme/src/colors/FluentColors.ts
4141
'--webchat-colorGray30': 'var(--colorGray30, #edebe9)',
4242
'--webchat-colorGray160': 'var(--colorGray160, #323130)',
43+
'--webchat-colorGray190': 'var(--colorGray190, #201f1e)',
4344
'--webchat-colorGray200': 'var(--colorGray200, #1b1a19)',
4445

4546
// https://github.com/microsoft/fluentui/blob/master/packages/tokens/src/global/borderRadius.ts

packages/fluent-theme/src/components/sendbox/TextArea.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ const styles = {
4949
},
5050

5151
'&::-webkit-scrollbar-track': {
52-
backgroundColor: ' var(--webchat-colorNeutralBackground5)',
52+
backgroundColor: 'var(--webchat-colorNeutralBackground5)',
5353
borderRadius: '16px'
5454
},
5555

packages/fluent-theme/src/components/sendbox/Toolbar.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ const styles = {
3838
color: 'var(--webchat-colorCompoundBrandForeground1Pressed)'
3939
},
4040
'&[aria-disabled="true"]': {
41-
color: ' var(--webchat-colorNeutralForegroundDisabled)',
41+
color: 'var(--webchat-colorNeutralForegroundDisabled)',
4242
cursor: 'not-allowed'
4343
}
4444
},

packages/fluent-theme/src/components/sendbox/index.tsx

+7-12
Original file line numberDiff line numberDiff line change
@@ -89,15 +89,15 @@ function SendBox(
8989
const inputRef = useRef<HTMLTextAreaElement>(null);
9090
const [message, setMessage] = useState('');
9191
const [attachments, setAttachments] = useSendBoxAttachments();
92-
const [{ maxMessageLength }] = useStyleOptions();
92+
const [{ hideTelephoneKeypadButton, hideUploadButton, maxMessageLength }] = useStyleOptions();
9393
const isMessageLengthExceeded = !!maxMessageLength && message.length > maxMessageLength;
9494
const classNames = useStyles(styles);
9595
const localize = useLocalizer();
9696
const sendMessage = useSendMessage();
9797
const makeThumbnail = useMakeThumbnail();
9898
const errorMessageId = useUniqueId('webchat-fluent__sendbox__error-message-id');
9999
const [errorRef, errorMessage] = useSubmitError({ message, attachments });
100-
const [telephoneKeypadShown, setTelephoneKeypadShown] = useTelephoneKeypadShown();
100+
const [telephoneKeypadShown] = useTelephoneKeypadShown();
101101

102102
const attachmentsRef = useRefFrom(attachments);
103103
const messageRef = useRefFrom(message);
@@ -162,14 +162,9 @@ function SendBox(
162162
);
163163

164164
const handleTelephoneKeypadButtonClick = useCallback(
165-
(dtmf: DTMF) => {
166-
// TODO: We need more official way of sending DTMF.
167-
sendMessage(`/DTMF ${dtmf}`);
168-
169-
// TODO: In the future when we work on input modality, it should manage the focus in a better way.
170-
setTelephoneKeypadShown(false);
171-
},
172-
[sendMessage, setTelephoneKeypadShown]
165+
// TODO: We need more official way of sending DTMF.
166+
(dtmf: DTMF) => sendMessage(`/DTMF ${dtmf}`),
167+
[sendMessage]
173168
);
174169

175170
const aria = {
@@ -211,8 +206,8 @@ function SendBox(
211206
</div>
212207
)}
213208
<Toolbar>
214-
<TelephoneKeypadToolbarButton />
215-
<AddAttachmentButton onFilesAdded={handleAddFiles} />
209+
{!hideTelephoneKeypadButton && <TelephoneKeypadToolbarButton />}
210+
{!hideUploadButton && <AddAttachmentButton onFilesAdded={handleAddFiles} />}
216211
<ToolbarSeparator />
217212
<ToolbarButton
218213
aria-label={localize('TEXT_INPUT_SEND_BUTTON_ALT')}

packages/fluent-theme/src/components/suggestedActions/SuggestedAction.tsx

+10-12
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ import { hooks } from 'botframework-webchat-component';
22
import { type DirectLineCardAction } from 'botframework-webchat-core';
33
import cx from 'classnames';
44
import React, { MouseEventHandler, memo, useCallback, useRef } from 'react';
5-
import AccessibleButton from './AccessibleButton';
65
import { useStyles } from '../../styles';
6+
import AccessibleButton from './AccessibleButton';
77

8-
const { useScrollToEnd, useStyleSet, usePerformCardAction, useFocus, useSuggestedActions, useDisabled } = hooks;
8+
const { useDisabled, useFocus, usePerformCardAction, useScrollToEnd, useStyleSet, useSuggestedActions } = hooks;
99

1010
type SuggestedActionProps = Readonly<{
1111
buttonText: string | undefined;
@@ -31,17 +31,16 @@ type SuggestedActionProps = Readonly<{
3131

3232
const styles = {
3333
'webchat-fluent__suggested-action': {
34+
alignItems: 'center',
3435
background: 'transparent',
3536
border: '1px solid var(--webchat-colorBrandStroke2)',
3637
borderRadius: '8px',
3738
cursor: 'pointer',
38-
fontSize: '12px',
39-
lineHeight: '14px',
40-
padding: '6px 8px 4px',
41-
textAlign: 'start',
4239
display: 'flex',
40+
fontSize: '12px',
4341
gap: '4px',
44-
alignItems: 'center',
42+
padding: '4px 8px 4px',
43+
textAlign: 'start',
4544
transition: 'all .15s ease-out',
4645

4746
'@media (hover: hover)': {
@@ -50,21 +49,20 @@ const styles = {
5049
color: 'var(--webchat-colorBrandForeground2Hover)'
5150
}
5251
},
52+
5353
'&:not([aria-disabled="true"]):active': {
5454
backgroundColor: 'var(--webchat-colorBrandBackground2Pressed)',
5555
color: 'var(--webchat-colorBrandForeground2Pressed)'
5656
},
57+
5758
'&[aria-disabled="true"]': {
58-
color: ' var(--webchat-colorNeutralForegroundDisabled)',
59+
color: 'var(--webchat-colorNeutralForegroundDisabled)',
5960
cursor: 'not-allowed'
6061
}
6162
},
6263

6364
'webchat-fluent__suggested-action__image': {
64-
width: '1em',
65-
height: '1em',
66-
fontSize: '20px',
67-
translate: '0 -1px'
65+
height: '12px'
6866
}
6967
};
7068

0 commit comments

Comments
 (0)