From 8096114809371eba14dbf1e49200765d44bfaf8d Mon Sep 17 00:00:00 2001 From: William Wong Date: Tue, 19 Nov 2019 08:43:31 +0800 Subject: [PATCH] Add React Hooks for customization (part 7) (#2548) * Add useDisabled * Clean up --- CHANGELOG.md | 1 + __tests__/hooks/useDisabled.js | 29 +++++++++++++++++++ .../Attachment/AdaptiveCardRenderer.js | 10 +++---- packages/component/src/Dictation.js | 7 ++--- .../component/src/SendBox/MicrophoneButton.js | 10 +++---- packages/component/src/SendBox/SendButton.js | 9 ++---- .../component/src/SendBox/SuggestedAction.js | 6 ++-- packages/component/src/SendBox/TextBox.js | 6 ++-- .../component/src/SendBox/UploadButton.js | 15 +++------- packages/component/src/hooks/index.js | 10 ++++--- packages/component/src/hooks/useDisabled.js | 7 +++++ 11 files changed, 67 insertions(+), 43 deletions(-) create mode 100644 __tests__/hooks/useDisabled.js create mode 100644 packages/component/src/hooks/useDisabled.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c0a266efa..c0697b7d45 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Bring your own Adaptive Cards package by specifying `adaptiveCardsPackage` prop, by [@compulim](https://github.com/compulim) in PR [#2543](https://github.com/microsoft/BotFramework-WebChat/pull/2543) - PR [#2544](https://github.com/microsoft/BotFramework-WebChat/pull/2544): `useAvatarForBot`, `useAvatarForUser` - PR [#2547](https://github.com/microsoft/BotFramework-WebChat/pull/2547): `useEmitTypingIndicator`, `usePeformCardAction`, `usePostActivity`, `useSendEvent`, `useSendFiles`, `useSendMessage`, `useSendMessageBack`, `useSendPostBack` + - PR [#2548](https://github.com/microsoft/BotFramework-WebChat/pull/2548): `useDisabled` - Fixes [#2597](https://github.com/microsoft/BotFramework-WebChat/issues/2597). Modify `watch` script to `start` and add `tableflip` script for throwing `node_modules`, by [@corinagum](https://github.com/corinagum) in PR [#2598](https://github.com/microsoft/BotFramework-WebChat/pull/2598) ### Fixed diff --git a/__tests__/hooks/useDisabled.js b/__tests__/hooks/useDisabled.js new file mode 100644 index 0000000000..a2e297707f --- /dev/null +++ b/__tests__/hooks/useDisabled.js @@ -0,0 +1,29 @@ +import { timeouts } from '../constants.json'; + +// selenium-webdriver API doc: +// https://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/index_exports_WebDriver.html + +jest.setTimeout(timeouts.test); + +test('getter should return true if disabled set to true in props', async () => { + const { pageObjects } = await setupWebDriver({ props: { disabled: true } }); + + const [disabled] = await pageObjects.runHook('useDisabled'); + + expect(disabled).toMatchInlineSnapshot(`true`); +}); + +test('getter should return false if disabled is not set in props', async () => { + const { pageObjects } = await setupWebDriver(); + + const [disabled] = await pageObjects.runHook('useDisabled'); + + expect(disabled).toMatchInlineSnapshot(`false`); +}); + +test('setter should be falsy', async () => { + const { pageObjects } = await setupWebDriver(); + const [_, setDisabled] = await pageObjects.runHook('useDisabled'); + + expect(setDisabled).toBeFalsy(); +}); diff --git a/packages/bundle/src/adaptiveCards/Attachment/AdaptiveCardRenderer.js b/packages/bundle/src/adaptiveCards/Attachment/AdaptiveCardRenderer.js index 9fa240a67b..ddbf106a7f 100644 --- a/packages/bundle/src/adaptiveCards/Attachment/AdaptiveCardRenderer.js +++ b/packages/bundle/src/adaptiveCards/Attachment/AdaptiveCardRenderer.js @@ -9,7 +9,7 @@ import useAdaptiveCardsHostConfig from '../hooks/useAdaptiveCardsHostConfig'; import useAdaptiveCardsPackage from '../hooks/useAdaptiveCardsPackage'; const { ErrorBox } = Components; -const { useLocalize, usePerformCardAction, useRenderMarkdownAsHTML, useStyleSet } = hooks; +const { useDisabled, useLocalize, usePerformCardAction, useRenderMarkdownAsHTML, useStyleSet } = hooks; function isPlainObject(obj) { return Object.getPrototypeOf(obj) === Object.prototype; @@ -64,10 +64,11 @@ function saveInputValues(element) { }); } -const AdaptiveCardRenderer = ({ adaptiveCard, disabled, tapAction }) => { +const AdaptiveCardRenderer = ({ adaptiveCard, tapAction }) => { const [{ adaptiveCardRenderer: adaptiveCardRendererStyleSet }] = useStyleSet(); const [{ HostConfig }] = useAdaptiveCardsPackage(); const [adaptiveCardsHostConfig] = useAdaptiveCardsHostConfig(); + const [disabled] = useDisabled(); const errorMessage = useLocalize('Adaptive Card render error'); const performCardAction = usePerformCardAction(); const renderMarkdownAsHTML = useRenderMarkdownAsHTML(); @@ -215,7 +216,6 @@ const AdaptiveCardRenderer = ({ adaptiveCard, disabled, tapAction }) => { AdaptiveCardRenderer.propTypes = { adaptiveCard: PropTypes.any.isRequired, - disabled: PropTypes.bool, tapAction: PropTypes.shape({ type: PropTypes.string.isRequired, value: PropTypes.string @@ -223,11 +223,9 @@ AdaptiveCardRenderer.propTypes = { }; AdaptiveCardRenderer.defaultProps = { - disabled: false, tapAction: undefined }; -export default connectToWebChat(({ disabled, tapAction }) => ({ - disabled, +export default connectToWebChat(({ tapAction }) => ({ tapAction }))(AdaptiveCardRenderer); diff --git a/packages/component/src/Dictation.js b/packages/component/src/Dictation.js index fc51a8f310..17d85ae1ef 100644 --- a/packages/component/src/Dictation.js +++ b/packages/component/src/Dictation.js @@ -6,6 +6,7 @@ import React, { useCallback, useMemo } from 'react'; import connectToWebChat from './connectToWebChat'; import useActivities from './hooks/useActivities'; +import useDisabled from './hooks/useDisabled'; import useLanguage from './hooks/useLanguage'; const { @@ -14,7 +15,6 @@ const { const Dictation = ({ dictateState, - disabled, emitTypingIndicator, onError, sendTypingIndicator, @@ -27,6 +27,7 @@ const Dictation = ({ webSpeechPonyfill: { SpeechGrammarList, SpeechRecognition } = {} }) => { const [activities] = useActivities(); + const [disabled] = useDisabled(); const [language] = useLanguage(); const numSpeakingActivities = useMemo(() => activities.filter(({ channelData: { speak } = {} }) => speak).length, [ @@ -84,14 +85,12 @@ const Dictation = ({ }; Dictation.defaultProps = { - disabled: false, onError: undefined, webSpeechPonyfill: undefined }; Dictation.propTypes = { dictateState: PropTypes.number.isRequired, - disabled: PropTypes.bool, emitTypingIndicator: PropTypes.func.isRequired, onError: PropTypes.func, sendTypingIndicator: PropTypes.bool.isRequired, @@ -110,7 +109,6 @@ Dictation.propTypes = { export default connectToWebChat( ({ dictateState, - disabled, emitTypingIndicator, postActivity, sendTypingIndicator, @@ -123,7 +121,6 @@ export default connectToWebChat( webSpeechPonyfill }) => ({ dictateState, - disabled, emitTypingIndicator, postActivity, sendTypingIndicator, diff --git a/packages/component/src/SendBox/MicrophoneButton.js b/packages/component/src/SendBox/MicrophoneButton.js index 9aa487b849..8a9c2f55fe 100644 --- a/packages/component/src/SendBox/MicrophoneButton.js +++ b/packages/component/src/SendBox/MicrophoneButton.js @@ -11,6 +11,7 @@ import React from 'react'; import connectToWebChat from '../connectToWebChat'; import IconButton from './IconButton'; import MicrophoneIcon from './Assets/MicrophoneIcon'; +import useDisabled from '../hooks/useDisabled'; import useLocalize from '../hooks/useLocalize'; import useStyleSet from '../hooks/useStyleSet'; @@ -77,8 +78,9 @@ const connectMicrophoneButton = (...selectors) => { ); }; -const MicrophoneButton = ({ className, click, dictating, disabled }) => { +const MicrophoneButton = ({ className, click, dictating }) => { const [{ microphoneButton: microphoneButtonStyleSet }] = useStyleSet(); + const [disabled] = useDisabled(); const iconButtonAltText = useLocalize('Speak'); const screenReaderText = useLocalize(dictating ? 'Microphone on' : 'Microphone off'); @@ -99,15 +101,13 @@ const MicrophoneButton = ({ className, click, dictating, disabled }) => { MicrophoneButton.defaultProps = { className: '', - dictating: false, - disabled: false + dictating: false }; MicrophoneButton.propTypes = { className: PropTypes.string, click: PropTypes.func.isRequired, - dictating: PropTypes.bool, - disabled: PropTypes.bool + dictating: PropTypes.bool }; export default connectMicrophoneButton()(MicrophoneButton); diff --git a/packages/component/src/SendBox/SendButton.js b/packages/component/src/SendBox/SendButton.js index ed02956512..b88f381fe1 100644 --- a/packages/component/src/SendBox/SendButton.js +++ b/packages/component/src/SendBox/SendButton.js @@ -4,6 +4,7 @@ import React from 'react'; import connectToWebChat from '../connectToWebChat'; import IconButton from './IconButton'; import SendIcon from './Assets/SendIcon'; +import useDisabled from '../hooks/useDisabled'; import useLocalize from '../hooks/useLocalize'; const connectSendButton = (...selectors) => @@ -16,7 +17,8 @@ const connectSendButton = (...selectors) => ...selectors ); -const SendButton = ({ disabled, submitSendBox }) => { +const SendButton = ({ submitSendBox }) => { + const [disabled] = useDisabled(); const altText = useLocalize('Send'); return ( @@ -26,12 +28,7 @@ const SendButton = ({ disabled, submitSendBox }) => { ); }; -SendButton.defaultProps = { - disabled: false -}; - SendButton.propTypes = { - disabled: PropTypes.bool, submitSendBox: PropTypes.func.isRequired }; diff --git a/packages/component/src/SendBox/SuggestedAction.js b/packages/component/src/SendBox/SuggestedAction.js index 17bf71b9aa..609bf019ca 100644 --- a/packages/component/src/SendBox/SuggestedAction.js +++ b/packages/component/src/SendBox/SuggestedAction.js @@ -4,6 +4,7 @@ import PropTypes from 'prop-types'; import React, { useCallback } from 'react'; import connectToWebChat from '../connectToWebChat'; +import useDisabled from '../hooks/useDisabled'; import usePerformCardAction from '../hooks/usePerformCardAction'; import useStyleSet from '../hooks/useStyleSet'; @@ -29,8 +30,9 @@ const connectSuggestedAction = (...selectors) => ...selectors ); -const SuggestedAction = ({ buttonText, clearSuggestedActions, disabled, displayText, image, text, type, value }) => { +const SuggestedAction = ({ buttonText, clearSuggestedActions, displayText, image, text, type, value }) => { const [{ suggestedAction: suggestedActionStyleSet }] = useStyleSet(); + const [disabled] = useDisabled(); const performCardAction = usePerformCardAction(); const handleClick = useCallback(() => { @@ -52,7 +54,6 @@ const SuggestedAction = ({ buttonText, clearSuggestedActions, disabled, displayT }; SuggestedAction.defaultProps = { - disabled: false, displayText: '', image: '', text: '', @@ -63,7 +64,6 @@ SuggestedAction.defaultProps = { SuggestedAction.propTypes = { buttonText: PropTypes.string.isRequired, clearSuggestedActions: PropTypes.func.isRequired, - disabled: PropTypes.bool, displayText: PropTypes.string, image: PropTypes.string, text: PropTypes.string, diff --git a/packages/component/src/SendBox/TextBox.js b/packages/component/src/SendBox/TextBox.js index 22a5da542f..00d9fcc21a 100644 --- a/packages/component/src/SendBox/TextBox.js +++ b/packages/component/src/SendBox/TextBox.js @@ -5,6 +5,7 @@ import React from 'react'; import { Context as TypeFocusSinkContext } from '../Utils/TypeFocusSink'; import connectToWebChat from '../connectToWebChat'; +import useDisabled from '../hooks/useDisabled'; import useLocalize from '../hooks/useLocalize'; import useStyleOptions from '../hooks/useStyleOptions'; import useStyleSet from '../hooks/useStyleSet'; @@ -55,9 +56,10 @@ const connectSendTextBox = (...selectors) => ...selectors ); -const TextBox = ({ className, disabled, onChange, onKeyPress, onSubmit, value }) => { +const TextBox = ({ className, onChange, onKeyPress, onSubmit, value }) => { const [{ sendBoxTextWrap }] = useStyleOptions(); const [{ sendBoxTextArea: sendBoxTextAreaStyleSet, sendBoxTextBox: sendBoxTextBoxStyleSet }] = useStyleSet(); + const [disabled] = useDisabled(); const sendBoxString = useLocalize('Sendbox'); const typeYourMessageString = useLocalize('Type your message'); @@ -105,13 +107,11 @@ const TextBox = ({ className, disabled, onChange, onKeyPress, onSubmit, value }) TextBox.defaultProps = { className: '', - disabled: false, value: '' }; TextBox.propTypes = { className: PropTypes.string, - disabled: PropTypes.bool, onChange: PropTypes.func.isRequired, onKeyPress: PropTypes.func.isRequired, onSubmit: PropTypes.func.isRequired, diff --git a/packages/component/src/SendBox/UploadButton.js b/packages/component/src/SendBox/UploadButton.js index d2ec7f72d2..9f8e951e1e 100644 --- a/packages/component/src/SendBox/UploadButton.js +++ b/packages/component/src/SendBox/UploadButton.js @@ -1,12 +1,12 @@ import { css } from 'glamor'; import classNames from 'classnames'; -import PropTypes from 'prop-types'; import React, { useCallback, useRef } from 'react'; import AttachmentIcon from './Assets/AttachmentIcon'; import connectToWebChat from '../connectToWebChat'; import downscaleImageToDataURL from '../Utils/downscaleImageToDataURL'; import IconButton from './IconButton'; +import useDisabled from '../hooks/useDisabled'; import useLocalize from '../hooks/useLocalize'; import useSendFiles from '../hooks/useSendFiles'; import useStyleSet from '../hooks/useStyleSet'; @@ -82,8 +82,9 @@ const connectUploadButton = (...selectors) => ...selectors ); -const UploadButton = ({ disabled }) => { +const UploadButton = () => { const [{ uploadButton: uploadButtonStyleSet }] = useStyleSet(); + const [disabled] = useDisabled(); const sendFiles = useSendFiles(); const uploadFileString = useLocalize('Upload file'); @@ -125,14 +126,6 @@ const UploadButton = ({ disabled }) => { ); }; -UploadButton.defaultProps = { - disabled: false -}; - -UploadButton.propTypes = { - disabled: PropTypes.bool -}; - -export default connectUploadButton()(UploadButton); +export default UploadButton; export { connectUploadButton }; diff --git a/packages/component/src/hooks/index.js b/packages/component/src/hooks/index.js index bb7d5d691f..96f9271c2a 100644 --- a/packages/component/src/hooks/index.js +++ b/packages/component/src/hooks/index.js @@ -1,18 +1,19 @@ import useActivities from './useActivities'; import useAvatarForBot from './useAvatarForBot'; import useAvatarForUser from './useAvatarForUser'; +import useDisabled from './useDisabled'; import useEmitTypingIndicator from './useEmitTypingIndicator'; +import useLanguage from './useLanguage'; +import useLocalize from './useLocalize'; +import useLocalizeDate from './useLocalizeDate'; import usePerformCardAction from './usePerformCardAction'; import usePostActivity from './usePostActivity'; +import useReferenceGrammarID from './useReferenceGrammarID'; import useSendEvent from './useSendEvent'; import useSendFiles from './useSendFiles'; import useSendMessage from './useSendMessage'; import useSendMessageBack from './useSendMessageBack'; import useSendPostBack from './useSendPostBack'; -import useLanguage from './useLanguage'; -import useLocalize from './useLocalize'; -import useLocalizeDate from './useLocalizeDate'; -import useReferenceGrammarID from './useReferenceGrammarID'; import useRenderMarkdownAsHTML from './useRenderMarkdownAsHTML'; import useStyleOptions from './useStyleOptions'; import useStyleSet from './useStyleSet'; @@ -23,6 +24,7 @@ export { useActivities, useAvatarForBot, useAvatarForUser, + useDisabled, useEmitTypingIndicator, useLanguage, useLocalize, diff --git a/packages/component/src/hooks/useDisabled.js b/packages/component/src/hooks/useDisabled.js new file mode 100644 index 0000000000..67e684a373 --- /dev/null +++ b/packages/component/src/hooks/useDisabled.js @@ -0,0 +1,7 @@ +import { useContext } from 'react'; + +import WebChatUIContext from '../WebChatUIContext'; + +export default function useDisabled() { + return [useContext(WebChatUIContext).disabled]; +}