Skip to content

Commit 0889fa0

Browse files
compulimtdurnford
andauthored
Add React hooks for customization (part 2) (#2541)
* Add useActivities, useReferenceGrammarID and useSendBoxDictationStarted * Typo * Update entry * Add useActivities, useReferenceGrammarID and useSendBoxDictationStarted * Add useStyleOptions and useStyleSet * Fix errors * Update PR number * Fix ESLint * Fix ESLint * Remove unused prop types * Fix style options * Save inputs * Use useStyleOptions and useStyleSet * Apply suggestions from code review Co-Authored-By: TJ Durnford <[email protected]>
1 parent ef38aa4 commit 0889fa0

54 files changed

Lines changed: 770 additions & 742 deletions

Some content is hidden

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

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
2828

2929
### Added
3030

31-
- Resolves [#2539](https://github.com/Microsoft/BotFramework-WebChat/issues/2539), added React hooks for customization, by [@compulim](https://github.com/compulim), in the following PRs:
31+
- Resolves [#2539](https://github.com/Microsoft/BotFramework-WebChat/issues/2539), added React hooks for customziation, by [@compulim](https://github.com/compulim) and [@corinagum](https://github.com/corinagum), in the following PRs:
3232
- PR [#2540](https://github.com/microsoft/BotFramework-WebChat/pull/2540): `useActivities`, `useReferenceGrammarID`, `useSendBoxDictationStarted`
33+
- PR [#2541](https://github.com/microsoft/BotFramework-WebChat/pull/2541): `useStyleOptions`, `useStyleSet`
3334

3435
### Fixed
3536

HOOKS.md

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,16 @@ To enable Web Chat API, all UI components must be located under the [`<Composer>
88

99
React Hooks will make your code cleaner and shorter, and also greatly improve readability.
1010

11-
Web Chat expose our APIs through React Hooks. This API surface enables us to freely move stuff behind the scene, introduce new APIs, and a safe way to deprecate APIs. It will also make us easier to shuffle work between our internal Redux store and React Context.
11+
Web Chat expose our APIs through React Hooks. This API surface enables us to freely move stuff behind the scene, introduce new APIs, and a safe way to deprecate APIs. It will also make it easier to shuffle work between our internal Redux store and React Context.
1212

1313
## Two types of hooks
1414

1515
We design our hooks largely with two basic shapes:
1616

1717
- Actions, these are functions that you can call at any time to perform a side-effect
1818
- Properties, these are getter function with an optional setter
19-
- This is same as [React State Hook pattern](https://reactjs.org/docs/hooks-state.html), but setter could be optional
20-
- If the value changed, React will call your render function again
19+
- This is same as [React State Hook pattern](https://reactjs.org/docs/hooks-state.html), but setters are optional
20+
- If the value is changed, React will call your render function again
2121

2222
### Actions
2323

@@ -130,7 +130,7 @@ useAvatarForBot(): [{
130130

131131
This function will return the image and initials of the bot. Both image and initials are optional and can be falsy.
132132

133-
To set the avatar for bot, use style options.
133+
To set the avatar for the bot, use style options.
134134

135135
## `useAvatarForUser`
136136

@@ -143,7 +143,7 @@ useAvatarForUser(): [{
143143

144144
This function will return the image and initials of the user. Both image and initials are optional and can be falsy.
145145

146-
To set the avatar for user, use style options.
146+
To set the avatar for the user, use style options.
147147

148148
## `useConnectivityStatus`
149149

@@ -263,7 +263,7 @@ This property is computed on every incoming activity.
263263
useLocalize(identifier: string) => string
264264
```
265265

266-
This function will return a localized string represented by the identifier. It honor the language settings from `useLanguage` hook.
266+
This function will return a localized string represented by the identifier. It honors the language settings from `useLanguage` hook.
267267

268268
To modify this value, change the props passed to Web Chat.
269269

@@ -296,7 +296,7 @@ usePostActivity(): (activity: Activity) => void
296296

297297
When called, this function will post the activity on behalf of the user, to the bot.
298298

299-
You can use this function to send any type of activities to the bot. We highly recommend you send the following type of activities only:
299+
You can use this function to send any type of activities to the bot, but we highly recommend you send the following type of activities only:
300300

301301
- `event`
302302
- `message`
@@ -336,7 +336,7 @@ useRenderAttachment(): ({
336336
}) => React.Element
337337
```
338338

339-
This function is for rendering attachment into React element. The caller will need to pass `activity` and `attachment`. This function is a composition of `attachmentRendererMiddleware`, which is passed as a prop.
339+
This function is for rendering attachments into React element. The caller will need to pass `activity` and `attachment` as parameters. This function is a composition of `attachmentRendererMiddleware`, which is passed as a prop.
340340

341341
```js
342342
() => next => { activity, attachment } => next({ activity, attachment })
@@ -391,9 +391,9 @@ useSendFiles(): (files: (Blob | File)[]) => void
391391
When called, this function will send a message activity with one or more [File](https://developer.mozilla.org/en-US/docs/Web/API/File) attachments to the bot, including these operations:
392392

393393
- Convert [File](https://developer.mozilla.org/en-US/docs/Web/API/File) into object URL
394-
- Generate thumbnail and will use Web Worker and offscreen canvas if supported
394+
- Generate thumbnail and will use a Web Worker and a offscreen canvas if supported
395395

396-
If you are using `ArrayBuffer`, you can use `FileReader` to convert it into a blob before calling [`URL.createObjectURL`](https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL).
396+
If you are using an `ArrayBuffer`, you can use `FileReader` to convert it into a blob before calling [`URL.createObjectURL`](https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL).
397397

398398
## `useSendMessage`
399399

@@ -403,7 +403,7 @@ useSendMessage(): (text: string, method: string) => void
403403

404404
When called, this function will send a text message activity to the bot.
405405

406-
You can optionally include the input method the text message is collected. Currently, if specified, only `speech` is supported.
406+
You can optionally include the input method how the text message was collected. Currently, if specified, only `speech` is supported.
407407

408408
## `useSendMessageBack`
409409

@@ -503,7 +503,7 @@ The suggested actions is computed from the last message activity sent from the b
503503
useTimeoutForSend(): [number]
504504
```
505505

506-
This function will return the interval before a sending activity is considered fail. The interval is represented in milliseconds. Due to network partitioning problem, activity that failed to send could eventually successfully deliver to the bot.
506+
This function will return the interval before a sending activity is considered unsuccessful. The interval is represented in milliseconds. Due to network partitioning problem, an activity that has failed to send could eventually be successfully delivered to the bot.
507507

508508
To modify this value, change the props passed to Web Chat.
509509

@@ -577,7 +577,7 @@ When called, this function will toggle microphone open or close.
577577
useMicrophoneButtonDisabled(): () => void
578578
```
579579

580-
This function will return whether the microphone button is disabled. This is more than `useDisabled()`. The microphone button could be disabled because it is currently starting or stopping.
580+
This function will return whether the microphone button is disabled. This is different from `useDisabled()`. The microphone button could be disabled because it is currently starting or stopping.
581581

582582
This value can be partly controllable through Web Chat props.
583583

@@ -636,7 +636,7 @@ useTypingIndicatorVisible(): [boolean]
636636

637637
This function will return whether the typing indicator should be visible or not. This function is time-sensitive, means, the value could varies based on the clock.
638638

639-
This function derive the visibility of the typing indicator by:
639+
This function derives the visibility of the typing indicator by:
640640

641641
- `typingAnimationDuration` value specified in style options, in milliseconds
642642
- Values from the `useLastTypingAt` hook
1.28 KB
Loading
1.26 KB
Loading
6.97 KB
Loading

__tests__/adaptiveCards.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,16 +58,29 @@ test('disable card inputs', async () => {
5858
await driver.wait(scrollToBottomCompleted(), timeouts.scrollToBottom);
5959

6060
await driver.executeScript(() => {
61-
document.querySelector('.ac-input input[type="checkbox"]').checked = true;
61+
document.querySelector('.ac-adaptiveCard input[type="checkbox"]').checked = true;
62+
document.querySelector('.ac-adaptiveCard input[type="date"]').value = '2019-11-01';
63+
document.querySelector('.ac-adaptiveCard input[type="radio"]').checked = true;
64+
document.querySelector('.ac-adaptiveCard input[type="text"]').value = 'William';
65+
document.querySelector('.ac-adaptiveCard input[type="time"]').value = '12:34';
66+
document.querySelector('.ac-adaptiveCard select').value = '1';
67+
document.querySelector('.ac-adaptiveCard textarea').value = 'One Redmond Way, Redmond, WA';
6268
});
6369

6470
expect(await driver.takeScreenshot()).toMatchImageSnapshot(imageSnapshotOptions);
6571

6672
await pageObjects.updateProps({ disabled: true });
6773

74+
// Click "Submit" button should have no effect
75+
await driver.executeScript(() => {
76+
document.querySelector('.ac-actionSet button:nth-of-type(2)').click();
77+
});
78+
6879
expect(await driver.takeScreenshot()).toMatchImageSnapshot(imageSnapshotOptions);
6980

7081
await pageObjects.updateProps({ disabled: false });
82+
83+
// Click "Submit" button should send values to the bot
7184
await driver.executeScript(() => {
7285
document.querySelector('.ac-actionSet button:nth-of-type(2)').click();
7386
});

__tests__/hooks/useStyleOptions.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { timeouts } from '../constants.json';
2+
3+
// selenium-webdriver API doc:
4+
// https://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/index_exports_WebDriver.html
5+
6+
jest.setTimeout(timeouts.test);
7+
8+
test('getter should get styleOptions from props', async () => {
9+
const { pageObjects } = await setupWebDriver({ props: { styleOptions: { backgroundColor: 'Red' } } });
10+
11+
await expect(pageObjects.runHook('useStyleOptions', [], result => result[0])).resolves.toHaveProperty(
12+
'backgroundColor',
13+
'Red'
14+
);
15+
});
16+
17+
test('setter should throw exception', async () => {
18+
const { pageObjects } = await setupWebDriver();
19+
20+
await expect(pageObjects.runHook('useStyleOptions', [], result => result[1]())).rejects.toThrow();
21+
});

__tests__/hooks/useStyleSet.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { timeouts } from '../constants.json';
2+
3+
// selenium-webdriver API doc:
4+
// https://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/index_exports_WebDriver.html
5+
6+
jest.setTimeout(timeouts.test);
7+
8+
test('getter should get styleSet from props', async () => {
9+
const { pageObjects } = await setupWebDriver({
10+
props: { styleSet: { options: {}, root: { backgroundColor: 'Red' } } }
11+
});
12+
13+
await expect(pageObjects.runHook('useStyleSet', [], result => result[0])).resolves.toMatchInlineSnapshot(`
14+
Object {
15+
"options": Object {},
16+
"root": Object {
17+
"data-css-1mjk9yt": "",
18+
},
19+
}
20+
`);
21+
});
22+
23+
test('setter should throw exception', async () => {
24+
const { pageObjects } = await setupWebDriver();
25+
26+
await expect(pageObjects.runHook('useStyleSet', [], result => result[1]())).rejects.toThrow();
27+
});

0 commit comments

Comments
 (0)