Skip to content

Commit ff34969

Browse files
OEvgenycompulim
andauthored
Add Fluent SendBox (#5122)
* [WIP] Add Fluent package * TEXT_INPUT_DROPZONE -> TEXT_INPUT_DROP_ZONE * classnames -> classNames * Add more Readonly to the god of reaonly * Sort * Sort style properties asc * Specify deps * DropZone to own file * Remove <span> tag * dropzone -> drop-zone * AttachmentDropZone -> DropZone * webchat__sendbox__root -> webchat__sendbox * Naming and freezing * Forbid arbitrary props * webchat__ -> webchat-fluent__ * disabled -> aria-disabled * Use native form * DialpadIcon -> TelephoneKeypadIcon * Readonly<T> -> readonly * useStlyeToEmotionObject -> useStyleToEmotionObject * Add message length exceeded aria * TEXT_INPUT_DIALPAD_BUTTON_ALT -> TEXT_INPUT_TELEPHON_KEYPAD_BUTTON_ALT * integration: sendMessage * integration: SuggestedActions * Remove unnecessary readonly * milestone: passing build * Remove unused types * Redo import UMD * Remove obsolate tsconfig * Fix attachments types * Rework attachments display * Add attachment counter test * Always use latest attachments * Respect style options for file upload * Remove empty space * Add tests * Fix aria-label * Typo and aria-label * Fix aria-label * Add padding around send box * Add connectivity status test * Rename aria-label * Add suggested actions test * Add padding * Rename umd * Add data-testid * Add send on ENTER key test * Add send button click test * Add useRefFrom for useCallback * Use useSendBoxAttachments * Sort * Simplify ToolbarButton props.type * Use button.type * Refactor DropZone components * Remove red color * Rename to <WebChatTheme> * TextArea improvements: - New line on Shift+Enter - Submit on Enter - Fix form submission - Added missing props * Fix drop zone and add droppable class * SuggestedActions and more: - SuggestedActions work - SuggestedActions are styled - SuggestedActions are splitted from SendBox - Use memo for all components * TextArea: padding and rows - Added configurable startRows to set initial row count - Set startRows default to 1 - Remove unwanted textarea padding * SendBox: Add ErrorMessage for connect and empty - Added useSubmitError hook to check for empty sendbox and connection issues - Copied useUniqueId hook to provide id for error message alert - Added ErrorMessage component to render hidden message - Integrated everything into SendBox component * Add drag and drop test * Fix drag over icon * SendBox: focus back on the input - Only empty message error now prevents from sending - Focus message textbox after empty message error - Focus message textbox after sucessfully sent * Theme: better align with Design Brand colors * SuggestedActions: move icon one pixel to the top We have asymmetrical vertical padding for suggested action balloon, this change centers icon in the balloon by moving it 1px above its calculated position * CodeStyle: prefer not to use erly return * Self bugbash - Hide input on Safari/Webkit - Remove gap created by ErrorMessage - Fix typos * Fix: SuggestedActions types Fixed useSuggestedActions: it returns an array of DirectLineCardAction and a setter which accepts only empty array * SendBox: wire maxMessageLength - Added maxMessageLength into styleOptions with default value 2000 - Implemented in SendBox * Toolbar: fix disabled button is clickable * SendBox: update simple snapshot * Adding new vars * Tests: enable tests and add more - focus back tests - auto-resize tests - max-length tests * SendBox: fix able to send form with Enter when maxLength exceeded Added a check to respect message length setting when sending the form via Enter key * TextBox: fix doppelganger width While doppelganger isn't scrollable it should use the same scroll styles as the textarea to avoid any discrepancies * Tests: fix host.sendKeys usage * Add telephone keypad * Theme: prefix webchat variables and fallback to fluent if present * Tests: rollback unwanted * Test: disable problematic activeElement check for now * AddAttachmentButton: remove unused icon prop * SendBox: reorganize modules Reorganize modules to follow estabilished conventions * AddAttachmentsButton: remove unused import * Localize: remove TODO and fix localization docs * ESCAPE key to close DTMF keypad * Add more test * Styles: avoid lint warnings The nonce is not a dependency as it is defined in the module scope * Reduce height when hiding * Add test entrypoints * Add entry * Add entry --------- Co-authored-by: William Wong <[email protected]>
1 parent 647b269 commit ff34969

File tree

120 files changed

+4062
-87
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

120 files changed

+4062
-87
lines changed

CHANGELOG.md

+9-2
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,23 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
2626

2727
- `useSendMessage` hook is updated to support sending attachments with a message. To reduce complexity, the `useSendFiles` hook is being deprecated. The hook will be removed on or after 2026-04-03
2828
- `styleOptions.uploadThumbnailHeight` and `styleOptions.uploadThumbnailWidth` must be a `number` of pixels
29+
- `useSuggestedActions` type is updated to align with its actual implementation, by [@OEvgeny](https://github.com/OEvgeny), in PR [#5122](https://github.com/microsoft/BotFramework-WebChat/pull/5122)
2930

3031
### Added
3132

32-
- Resolves [#5083](https://github.com/microsoft/BotFramework-WebChat/issues/5083). Added `sendAttachmentOn` style option to send attachments and text in a single activity, by [@ms-jb](https://github.com/ms-jb) and [@compulim](https://github.com/compulim)
33+
- Resolves [#5083](https://github.com/microsoft/BotFramework-WebChat/issues/5083). Added `sendAttachmentOn` style option to send attachments and text in a single activity, by [@ms-jb](https://github.com/ms-jb) and [@compulim](https://github.com/compulim), in PR [#5123](https://github.com/microsoft/BotFramework-WebChat/pull/5123)
3334
- `useSendMessage` hook is updated to support sending attachments with a message
3435
- `useSendBoxAttachments` hook is added to get/set attachments in the send box
3536
- Resolves [#5081](https://github.com/microsoft/BotFramework-WebChat/issues/5081). Added `uploadAccept` and `uploadMultiple` style options, by [@ms-jb](https://github.com/ms-jb), in PR [#5048](https://github.com/microsoft/BotFramework-WebChat/pull/5048)
3637
- Added `sendBoxMiddleware` and `sendBoxToolbarMiddleware`, by [@compulim](https://github.com/compulim), in PR [#5120](https://github.com/microsoft/BotFramework-WebChat/pull/5120)
37-
- Added `botframework-webchat-fluent-theme` package for applying Fluent UI theme to Web Chat, by [@compulim](https://github.com/compulim), in PR [#5120](https://github.com/microsoft/BotFramework-WebChat/pull/5120)
38+
- (Experimental) Added `botframework-webchat-fluent-theme` package for applying Fluent UI theme to Web Chat, by [@compulim](https://github.com/compulim) and [@OEvgeny](https://github.com/OEvgeny), in PR [#5120](https://github.com/microsoft/BotFramework-WebChat/pull/5120)
39+
- Inherits Fluent CSS palette if available, in PR [#5122](https://github.com/microsoft/BotFramework-WebChat/pull/5122)
40+
- New send box with Fluent look-and-feel, in PR [#5122](https://github.com/microsoft/BotFramework-WebChat/pull/5122)
41+
- `styleOptions.maxMessageLength` to specify maximum length of the outgoing message
42+
- Drag-and-drop file support, in PR [#5122](https://github.com/microsoft/BotFramework-WebChat/pull/5122)
43+
- Added telephone keypad (DTMF keypad), in PR [#5122](https://github.com/microsoft/BotFramework-WebChat/pull/5122)
3844
- 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)
45+
- 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)
3946

4047
### Fixed
4148

Loading
Loading
Loading
Loading
Loading
Loading
+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
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 = () => <ReactWebChat directLine={directLine} locale="yue" store={store} />;
26+
27+
render(
28+
<FluentThemeProvider>
29+
<App />
30+
</FluentThemeProvider>,
31+
document.getElementById('webchat')
32+
);
33+
34+
await pageConditions.uiConnected();
35+
36+
await pageObjects.uploadFile('seaofthieves.jpg');
37+
38+
await pageConditions.became(
39+
'attachment count change to 1',
40+
() => {
41+
try {
42+
// It seems "yue" doesn't use plural form of "one".
43+
expect(document.querySelector('.webchat-fluent__sendbox__attachment').textContent.trim()).toBe(
44+
'1 件附件'
45+
);
46+
47+
return true;
48+
} catch {
49+
return false;
50+
}
51+
},
52+
1000
53+
);
54+
55+
await host.snapshot();
56+
});
57+
</script>
58+
</body>
59+
</html>
+5
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('attach a single file', () => runHTML('fluentTheme/attachFile'));
5+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
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
27+
activityMiddleware={testHelpers.createRunHookActivityMiddleware()}
28+
directLine={directLine}
29+
store={store}
30+
/>
31+
);
32+
33+
render(
34+
<FluentThemeProvider>
35+
<App />
36+
</FluentThemeProvider>,
37+
document.getElementById('webchat')
38+
);
39+
40+
await pageConditions.uiConnected();
41+
42+
const blob1 = new File(
43+
[
44+
await (
45+
await fetch(
46+
'https://raw.githubusercontent.com/compulim/BotFramework-MockBot/master/public/assets/surface1.jpg'
47+
)
48+
).blob()
49+
],
50+
'surface1.jpg',
51+
{ type: 'image/jpeg' }
52+
);
53+
54+
const blob2 = new File(
55+
[
56+
await (
57+
await fetch(
58+
'https://raw.githubusercontent.com/compulim/BotFramework-MockBot/master/public/assets/surface2.jpg'
59+
)
60+
).blob()
61+
],
62+
'surface2.jpg',
63+
{ type: 'image/jpeg' }
64+
);
65+
66+
await pageObjects.runHook(({ useSendBoxAttachments }) =>
67+
useSendBoxAttachments()[1]([{ blob: blob1 }, { blob: blob2 }])
68+
);
69+
70+
await pageConditions.became(
71+
'attachment count change to 2',
72+
() => {
73+
try {
74+
expect(document.querySelector('.webchat-fluent__sendbox__attachment').textContent.trim()).toBe(
75+
'2 attachments'
76+
);
77+
78+
return true;
79+
} catch {
80+
return false;
81+
}
82+
},
83+
1000
84+
);
85+
86+
await host.snapshot();
87+
});
88+
</script>
89+
</body>
90+
</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('attach multiple files', () => runHTML('fluentTheme/attachMultipleFiles'));
5+
});
+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
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 = () => <ReactWebChat directLine={directLine} store={store} />;
26+
27+
render(
28+
<FluentThemeProvider>
29+
<App />
30+
</FluentThemeProvider>,
31+
document.getElementById('webchat')
32+
);
33+
34+
await pageConditions.uiConnected();
35+
36+
await directLine.emulateIncomingActivity(
37+
'Eiusmod anim adipisicing cupidatat adipisicing officia sint qui consequat veniam id aute.'
38+
);
39+
40+
await pageConditions.numActivitiesShown(1);
41+
document.querySelector(`[data-testid="${WebChat.testIds.sendBoxTextBox}"]`).focus();
42+
43+
// With new lines
44+
document.querySelector(`[data-testid="${WebChat.testIds.sendBoxTextBox}"]`).value = ['One', 'Two', 'Three'].join('\n');
45+
await host.sendKeys(' ');
46+
await host.snapshot();
47+
48+
// With a single long line
49+
document.querySelector(`[data-testid="${WebChat.testIds.sendBoxTextBox}"]`).value = '';
50+
await host.sendKeys('Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris '.repeat(2));
51+
await host.snapshot();
52+
53+
// With a scroll-bar when passed 10 lines
54+
document.querySelector(`[data-testid="${WebChat.testIds.sendBoxTextBox}"]`).value += ['', 'One', 'Two', 'Three'].join('\n');
55+
await host.sendKeys(' ');
56+
await host.snapshot();
57+
});
58+
</script>
59+
</body>
60+
</html>
+5
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('textbox auto resize', () => runHTML('fluentTheme/autoResize'));
5+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
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({ autoConnect: false });
24+
25+
const App = () => <ReactWebChat directLine={directLine} store={store} />;
26+
27+
render(
28+
<FluentThemeProvider>
29+
<App />
30+
</FluentThemeProvider>,
31+
document.getElementById('webchat')
32+
);
33+
34+
// THEN: Should render the activity.
35+
await host.snapshot();
36+
});
37+
</script>
38+
</body>
39+
</html>

0 commit comments

Comments
 (0)