From 6a4b2504c435cebd5d0101f2db6323c5b5806c58 Mon Sep 17 00:00:00 2001 From: William Wong Date: Sat, 22 Feb 2020 19:58:00 -0800 Subject: [PATCH 01/33] Initial commit --- .../src/Activity/CarouselFilmStrip.js | 7 +- .../component/src/Activity/StackedLayout.js | 16 +- packages/component/src/Avatar/ImageAvatar.js | 43 +++++ .../component/src/Avatar/InitialsAvatar.js | 39 +++++ packages/component/src/BasicWebChat.js | 19 +++ packages/component/src/Composer.js | 5 + .../Middleware/Avatar/createCoreMiddleware.js | 41 +++++ .../component/src/Styles/StyleSet/Avatar.js | 31 +--- .../src/Styles/StyleSet/ImageAvatar.js | 7 + .../src/Styles/StyleSet/InitialsAvatar.js | 26 +++ .../src/Styles/StyleSet/StackedLayout.js | 18 +- .../component/src/Styles/createStyleSet.js | 4 + packages/component/src/hooks/index.js | 2 + .../component/src/hooks/useRenderAvatar.js | 14 ++ .../k.per-message-avatar/index.html | 158 ++++++++++++++++++ 15 files changed, 383 insertions(+), 47 deletions(-) create mode 100644 packages/component/src/Avatar/ImageAvatar.js create mode 100644 packages/component/src/Avatar/InitialsAvatar.js create mode 100644 packages/component/src/Middleware/Avatar/createCoreMiddleware.js create mode 100644 packages/component/src/Styles/StyleSet/ImageAvatar.js create mode 100644 packages/component/src/Styles/StyleSet/InitialsAvatar.js create mode 100644 packages/component/src/hooks/useRenderAvatar.js create mode 100644 samples/05.custom-components/k.per-message-avatar/index.html diff --git a/packages/component/src/Activity/CarouselFilmStrip.js b/packages/component/src/Activity/CarouselFilmStrip.js index e2cc483d67..083d606987 100644 --- a/packages/component/src/Activity/CarouselFilmStrip.js +++ b/packages/component/src/Activity/CarouselFilmStrip.js @@ -17,6 +17,7 @@ import useAvatarForUser from '../hooks/useAvatarForUser'; import useDirection from '../hooks/useDirection'; import useLocalizer from '../hooks/useLocalizer'; import useRenderActivityStatus from '../hooks/useRenderActivityStatus'; +import useRenderAvatar from '../hooks/useRenderAvatar'; import useStyleOptions from '../hooks/useStyleOptions'; import useStyleSet from '../hooks/useStyleSet'; @@ -32,7 +33,7 @@ const ROOT_CSS = css({ display: 'none' }, - '& > .avatar': { + '& > .webchat__carouselFilmStrip__avatar': { flexShrink: 0 }, @@ -98,6 +99,7 @@ const WebChatCarouselFilmStrip = ({ const [direction] = useDirection(); const localize = useLocalizer(); const renderActivityStatus = useRenderActivityStatus({ activity, nextVisibleActivity }); + const renderAvatar = useRenderAvatar({ activity }); const { attachments = [], @@ -128,7 +130,8 @@ const WebChatCarouselFilmStrip = ({ )} ref={scrollableRef} > - + {/* */} + {renderAvatar &&
{renderAvatar()}
}
{!!activityDisplayText && (
diff --git a/packages/component/src/Activity/StackedLayout.js b/packages/component/src/Activity/StackedLayout.js index cbf33cb106..25b4d0600e 100644 --- a/packages/component/src/Activity/StackedLayout.js +++ b/packages/component/src/Activity/StackedLayout.js @@ -18,17 +18,18 @@ import useDateFormatter from '../hooks/useDateFormatter'; import useDirection from '../hooks/useDirection'; import useLocalizer from '../hooks/useLocalizer'; import useRenderActivityStatus from '../hooks/useRenderActivityStatus'; +import useRenderAvatar from '../hooks/useRenderAvatar'; import useStyleOptions from '../hooks/useStyleOptions'; import useStyleSet from '../hooks/useStyleSet'; const ROOT_CSS = css({ display: 'flex', - '& > .avatar': { + '& > .webchat__stackedLayout__avatar': { flexShrink: 0 }, - '& > .content': { + '& > .webchat__stackedLayout__content': { flexGrow: 1, overflow: 'hidden', @@ -54,7 +55,7 @@ const ROOT_CSS = css({ '&.from-user': { flexDirection: 'row-reverse', - '& > .content > .webchat__row': { + '& > .webchat__stackedLayout__content > .webchat__row': { flexDirection: 'row-reverse' } } @@ -90,6 +91,7 @@ const StackedLayout = ({ activity, children, nextVisibleActivity }) => { const formatDate = useDateFormatter(); const localize = useLocalizer(); const renderActivityStatus = useRenderActivityStatus({ activity, nextVisibleActivity }); + const renderAvatar = useRenderAvatar({ activity }); const { attachments = [], @@ -128,13 +130,13 @@ const StackedLayout = ({ activity, children, nextVisibleActivity }) => { webchat__stacked_extra_right_indent: (direction !== 'rtl' && !fromUser && !userAvatarInitials && bubbleFromUserNubSize) || (direction === 'rtl' && fromUser && !botAvatarInitials && bubbleNubSize), - webchat__stacked_indented_content: initials && !indented + webchat__stacked_indented_content: initials && !indented, + 'webchat__stacked--hasAvatar': renderAvatar && !!(fromUser ? bubbleFromUserNubSize : bubbleNubSize) } )} > - {!initials && !!(fromUser ? bubbleFromUserNubSize : bubbleNubSize) &&
} - -
+ {renderAvatar &&
{renderAvatar()}
} +
{!!activityDisplayText && (
diff --git a/packages/component/src/Avatar/ImageAvatar.js b/packages/component/src/Avatar/ImageAvatar.js new file mode 100644 index 0000000000..9a9780534f --- /dev/null +++ b/packages/component/src/Avatar/ImageAvatar.js @@ -0,0 +1,43 @@ +import { css } from 'glamor'; +import classNames from 'classnames'; +import PropTypes from 'prop-types'; +import React from 'react'; + +import CroppedImage from '../Utils/CroppedImage'; +import useAvatarForBot from '../hooks/useAvatarForBot'; +import useAvatarForUser from '../hooks/useAvatarForUser'; +import useStyleSet from '../hooks/useStyleSet'; + +const ROOT_CSS = css({ + '& .webchat__imageAvatar__image': { + width: '100%' + } +}); + +const ImageAvatar = ({ fromUser }) => { + const [{ image: avatarImageForBot }] = useAvatarForBot(); + const [{ image: avatarImageForUser }] = useAvatarForUser(); + const [{ imageAvatar: imageAvatarStyleSet }] = useStyleSet(); + + return ( +
+ +
+ ); +}; + +ImageAvatar.defaultProps = { + fromUser: false +}; + +ImageAvatar.propTypes = { + fromUser: PropTypes.bool +}; + +export default ImageAvatar; diff --git a/packages/component/src/Avatar/InitialsAvatar.js b/packages/component/src/Avatar/InitialsAvatar.js new file mode 100644 index 0000000000..b54213a3ec --- /dev/null +++ b/packages/component/src/Avatar/InitialsAvatar.js @@ -0,0 +1,39 @@ +import { css } from 'glamor'; +import classNames from 'classnames'; +import PropTypes from 'prop-types'; +import React from 'react'; + +import useAvatarForBot from '../hooks/useAvatarForBot'; +import useAvatarForUser from '../hooks/useAvatarForUser'; +import useStyleSet from '../hooks/useStyleSet'; + +const ROOT_CSS = css({ + alignItems: 'center', + display: 'flex', + + '& .webchat__initialsAvatar__initials': { + justifyContent: 'center' + } +}); + +const InitialsAvatar = ({ fromUser }) => { + const [{ initials: avatarInitialsForBot }] = useAvatarForBot(); + const [{ initials: avatarInitialsForUser }] = useAvatarForUser(); + const [{ initialsAvatar: initialsAvatarStyleSet }] = useStyleSet(); + + return ( +
+
{fromUser ? avatarInitialsForUser : avatarInitialsForBot}
+
+ ); +}; + +InitialsAvatar.defaultProps = { + fromUser: false +}; + +InitialsAvatar.propTypes = { + fromUser: PropTypes.bool +}; + +export default InitialsAvatar; diff --git a/packages/component/src/BasicWebChat.js b/packages/component/src/BasicWebChat.js index d1d2ba4f41..1a32a96342 100644 --- a/packages/component/src/BasicWebChat.js +++ b/packages/component/src/BasicWebChat.js @@ -15,6 +15,7 @@ import concatMiddleware from './Middleware/concatMiddleware'; import createCoreActivityMiddleware from './Middleware/Activity/createCoreMiddleware'; import createCoreActivityStatusMiddleware from './Middleware/ActivityStatus/createCoreMiddleware'; import createCoreAttachmentMiddleware from './Middleware/Attachment/createCoreMiddleware'; +import createCoreAvatarMiddleware from './Middleware/Avatar/createCoreMiddleware'; import createCoreToastMiddleware from './Middleware/Toast/createCoreMiddleware'; import createCoreTypingIndicatorMiddleware from './Middleware/TypingIndicator/createCoreMiddleware'; import ErrorBox from './ErrorBox'; @@ -73,6 +74,19 @@ function createActivityRenderer(additionalMiddleware) { }; } +// TODO: [P2] #2859 We should move these into +function createAvatarRenderer(additionalMiddleware) { + const avatarMiddleware = concatMiddleware(additionalMiddleware, createCoreAvatarMiddleware())({}); + + return (...args) => { + try { + return avatarMiddleware(() => false)(...args); + } catch (err) { + console.error('Failed to render avatar', err); + } + }; +} + // TODO: [P2] #2859 We should move these into function createActivityStatusRenderer(additionalMiddleware) { const activityStatusMiddleware = concatMiddleware(additionalMiddleware, createCoreActivityStatusMiddleware())({}); @@ -166,6 +180,7 @@ const BasicWebChat = ({ activityMiddleware, activityStatusMiddleware, attachmentMiddleware, + avatarMiddleware, className, toastMiddleware, typingIndicatorMiddleware, @@ -177,6 +192,7 @@ const BasicWebChat = ({ activityStatusMiddleware ]); const attachmentRenderer = useMemo(() => createAttachmentRenderer(attachmentMiddleware), [attachmentMiddleware]); + const avatarRenderer = useMemo(() => createAvatarRenderer(avatarMiddleware), [avatarMiddleware]); const toastRenderer = useMemo(() => createToastRenderer(toastMiddleware), [toastMiddleware]); const typingIndicatorRenderer = useMemo(() => createTypingIndicatorRenderer(typingIndicatorMiddleware), [ typingIndicatorMiddleware @@ -187,6 +203,7 @@ const BasicWebChat = ({ activityRenderer={activityRenderer} activityStatusRenderer={activityStatusRenderer} attachmentRenderer={attachmentRenderer} + avatarRenderer={avatarRenderer} sendBoxRef={sendBoxRef} toastRenderer={toastRenderer} typingIndicatorRenderer={typingIndicatorRenderer} @@ -214,6 +231,7 @@ BasicWebChat.defaultProps = { ...Composer.defaultProps, activityMiddleware: undefined, attachmentMiddleware: undefined, + avatarMiddleware: undefined, className: '' }; @@ -221,5 +239,6 @@ BasicWebChat.propTypes = { ...Composer.propTypes, activityMiddleware: PropTypes.func, attachmentMiddleware: PropTypes.func, + avatarMiddleware: PropTypes.func, className: PropTypes.string }; diff --git a/packages/component/src/Composer.js b/packages/component/src/Composer.js index 4b68cdd649..a932adee9c 100644 --- a/packages/component/src/Composer.js +++ b/packages/component/src/Composer.js @@ -158,6 +158,7 @@ const Composer = ({ activityRenderer, activityStatusRenderer, attachmentRenderer, + avatarRenderer, cardActionMiddleware, children, dir, @@ -351,6 +352,7 @@ const Composer = ({ activityRenderer, activityStatusRenderer, attachmentRenderer, + avatarRenderer, dictateAbortable, dir: patchedDir, directLine, @@ -382,6 +384,7 @@ const Composer = ({ activityRenderer, activityStatusRenderer, attachmentRenderer, + avatarRenderer, cardActionContext, dictateAbortable, directLine, @@ -473,6 +476,7 @@ Composer.defaultProps = { activityRenderer: undefined, activityStatusRenderer: undefined, attachmentRenderer: undefined, + avatarRenderer: undefined, cardActionMiddleware: undefined, children: undefined, dir: 'auto', @@ -501,6 +505,7 @@ Composer.propTypes = { activityRenderer: PropTypes.func, activityStatusRenderer: PropTypes.func, attachmentRenderer: PropTypes.func, + avatarRenderer: PropTypes.func, cardActionMiddleware: PropTypes.func, children: PropTypes.any, dir: PropTypes.oneOf(['auto', 'ltr', 'rtl']), diff --git a/packages/component/src/Middleware/Avatar/createCoreMiddleware.js b/packages/component/src/Middleware/Avatar/createCoreMiddleware.js new file mode 100644 index 0000000000..5600fd0728 --- /dev/null +++ b/packages/component/src/Middleware/Avatar/createCoreMiddleware.js @@ -0,0 +1,41 @@ +import { css } from 'glamor'; +import classNames from 'classnames'; +import React from 'react'; + +import concatMiddleware from '../concatMiddleware'; +import ImageAvatar from '../../Avatar/ImageAvatar'; +import InitialsAvatar from '../../Avatar/InitialsAvatar'; +import useStyleSet from '../../hooks/useStyleSet'; + +const ROOT_CSS = css({ + position: 'relative', + + '> *': { + left: 0, + position: 'absolute', + top: 0 + } +}); + +const DefaultAvatar = ({ fromUser }) => { + const [{ avatar: avatarStyleSet }] = useStyleSet(); + + return ( +
+ + +
+ ); +}; + +export default function createCoreAvatarMiddleware() { + return concatMiddleware(() => next => ({ fromUser, styleOptions }) => { + const { botAvatarImage, botAvatarInitials, userAvatarImage, userAvatarInitials } = styleOptions; + + if (fromUser ? botAvatarImage || botAvatarInitials : userAvatarImage || userAvatarInitials) { + return () => ; + } + + return false; + }); +} diff --git a/packages/component/src/Styles/StyleSet/Avatar.js b/packages/component/src/Styles/StyleSet/Avatar.js index c52d8a0e9f..1d587f49fb 100644 --- a/packages/component/src/Styles/StyleSet/Avatar.js +++ b/packages/component/src/Styles/StyleSet/Avatar.js @@ -1,35 +1,8 @@ -export default function createAvatarStyle({ - accent, - avatarSize, - botAvatarBackgroundColor, - primaryFont, - userAvatarBackgroundColor -}) { +export default function createAvatarStyle({ avatarSize }) { return { - alignItems: 'center', borderRadius: '50%', - color: 'White', - // TODO: [P2] We should not set "display" in styleSet, this will allow the user to break the layout for no good reasons. - display: 'flex', - fontFamily: primaryFont, height: avatarSize, - justifyContent: 'center', overflow: 'hidden', - position: 'relative', - width: avatarSize, - - '&.from-user': { - backgroundColor: userAvatarBackgroundColor || accent - }, - - '&:not(.from-user)': { - backgroundColor: botAvatarBackgroundColor || accent - }, - - '& > .image': { - left: 0, - position: 'absolute', - top: 0 - } + width: avatarSize }; } diff --git a/packages/component/src/Styles/StyleSet/ImageAvatar.js b/packages/component/src/Styles/StyleSet/ImageAvatar.js new file mode 100644 index 0000000000..abceae3ab9 --- /dev/null +++ b/packages/component/src/Styles/StyleSet/ImageAvatar.js @@ -0,0 +1,7 @@ +export default function createImageAvatarStyle({ avatarSize }) { + return { + height: avatarSize, + overflow: 'hidden', + width: avatarSize + }; +} diff --git a/packages/component/src/Styles/StyleSet/InitialsAvatar.js b/packages/component/src/Styles/StyleSet/InitialsAvatar.js new file mode 100644 index 0000000000..330a096765 --- /dev/null +++ b/packages/component/src/Styles/StyleSet/InitialsAvatar.js @@ -0,0 +1,26 @@ +export default function createInitialsAvatarStyle({ + accent, + avatarSize, + botAvatarBackgroundColor, + primaryFont, + userAvatarBackgroundColor +}) { + return { + alignItems: 'center', + borderRadius: '50%', + color: 'White', + fontFamily: primaryFont, + height: avatarSize, + justifyContent: 'center', + overflow: 'hidden', + width: avatarSize, + + '&.from-user': { + backgroundColor: userAvatarBackgroundColor || accent + }, + + '&:not(.from-user)': { + backgroundColor: botAvatarBackgroundColor || accent + } + }; +} diff --git a/packages/component/src/Styles/StyleSet/StackedLayout.js b/packages/component/src/Styles/StyleSet/StackedLayout.js index e127c5f23d..1db7030728 100644 --- a/packages/component/src/Styles/StyleSet/StackedLayout.js +++ b/packages/component/src/Styles/StyleSet/StackedLayout.js @@ -19,21 +19,21 @@ export default function createStackedLayoutStyle({ bubbleMaxWidth, bubbleMinWidt }, '&:not(.webchat__stacked--rtl)': { '&:not(.from-user)': { - '&.webchat__stacked_indented_content > .avatar': { + '&.webchat__stacked_indented_content > .webchat__stackedLayout__avatar': { marginRight: paddingRegular }, - '& > .content > .webchat__stacked_item_indented': { + '& > .webchat__stackedLayout__content > .webchat__stacked_item_indented': { marginLeft: paddingRegular } }, '&.from-user': { - '&.webchat__stacked_indented_content > .avatar': { + '&.webchat__stacked_indented_content > .webchat__stackedLayout__avatar': { marginLeft: paddingRegular }, - '& > .content > .webchat__stacked_item_indented': { + '& > .webchat__stackedLayout__content > .webchat__stacked_item_indented': { marginRight: paddingRegular } } @@ -41,27 +41,27 @@ export default function createStackedLayoutStyle({ bubbleMaxWidth, bubbleMinWidt '&.webchat__stacked--rtl': { '&:not(.from-user)': { - '&.webchat__stacked_indented_content > .avatar': { + '&.webchat__stacked_indented_content > .webchat__stackedLayout__avatar': { marginLeft: paddingRegular }, - '& > .content > .webchat__stacked_item_indented': { + '& > .webchat__stackedLayout__content > .webchat__stacked_item_indented': { marginRight: paddingRegular } }, '&.from-user': { - '&.webchat__stacked_indented_content > .avatar': { + '&.webchat__stacked_indented_content > .webchat__stackedLayout__avatar': { marginRight: paddingRegular }, - '& > .content > .webchat__stacked_item_indented': { + '& > .webchat__stackedLayout__content > .webchat__stacked_item_indented': { marginLeft: paddingRegular } } }, - '& > .content': { + '& > .webchat__stackedLayout__content': { '& > .webchat__row': { '& > .bubble, & > .timestamp': { maxWidth: bubbleMaxWidth diff --git a/packages/component/src/Styles/createStyleSet.js b/packages/component/src/Styles/createStyleSet.js index dc99f61152..9bee033fe0 100644 --- a/packages/component/src/Styles/createStyleSet.js +++ b/packages/component/src/Styles/createStyleSet.js @@ -12,6 +12,8 @@ import createDictationInterimsStyle from './StyleSet/DictationInterims'; import createErrorBoxStyle from './StyleSet/ErrorBox'; import createErrorNotificationStyle from './StyleSet/ErrorNotification'; import createFileContentStyle from './StyleSet/FileContent'; +import createImageAvatarStyle from './StyleSet/ImageAvatar'; +import createInitialsAvatarStyle from './StyleSet/InitialsAvatar'; import createMicrophoneButtonStyle from './StyleSet/MicrophoneButton'; import createRootStyle from './StyleSet/Root'; import createScrollToEndButtonStyle from './StyleSet/ScrollToEndButton'; @@ -183,6 +185,8 @@ export default function createStyleSet(options) { errorBox: createErrorBoxStyle(options), errorNotification: createErrorNotificationStyle(options), fileContent: createFileContentStyle(options), + imageAvatar: createImageAvatarStyle(options), + initialsAvatar: createInitialsAvatarStyle(options), microphoneButton: createMicrophoneButtonStyle(options), options: { ...options, diff --git a/packages/component/src/hooks/index.js b/packages/component/src/hooks/index.js index 34eded60ef..18050f3e9f 100644 --- a/packages/component/src/hooks/index.js +++ b/packages/component/src/hooks/index.js @@ -28,6 +28,7 @@ import useRelativeTimeFormatter from './useRelativeTimeFormatter'; import useRenderActivity from './useRenderActivity'; import useRenderActivityStatus from './useRenderActivityStatus'; import useRenderAttachment from './useRenderAttachment'; +import useRenderAvatar from './useRenderAvatar'; import useRenderMarkdownAsHTML from './useRenderMarkdownAsHTML'; import useRenderToast from './useRenderToast'; import useRenderTypingIndicator from './useRenderTypingIndicator'; @@ -96,6 +97,7 @@ export { useRenderActivity, useRenderActivityStatus, useRenderAttachment, + useRenderAvatar, useRenderMarkdownAsHTML, useRenderToast, useRenderTypingIndicator, diff --git a/packages/component/src/hooks/useRenderAvatar.js b/packages/component/src/hooks/useRenderAvatar.js new file mode 100644 index 0000000000..b81c1b1e15 --- /dev/null +++ b/packages/component/src/hooks/useRenderAvatar.js @@ -0,0 +1,14 @@ +import { useMemo } from 'react'; + +import useStyleOptions from './useStyleOptions'; +import useWebChatUIContext from './internal/useWebChatUIContext'; + +export default function useRenderAvatar({ activity }) { + const [styleOptions] = useStyleOptions(); + const { avatarRenderer } = useWebChatUIContext(); + const { from: { role } = {} } = activity; + + const fromUser = role === 'user'; + + return useMemo(() => avatarRenderer({ activity, fromUser, styleOptions }), [activity, fromUser, styleOptions]); +} diff --git a/samples/05.custom-components/k.per-message-avatar/index.html b/samples/05.custom-components/k.per-message-avatar/index.html new file mode 100644 index 0000000000..f9d6ae82b4 --- /dev/null +++ b/samples/05.custom-components/k.per-message-avatar/index.html @@ -0,0 +1,158 @@ + + + + Web Chat: Per-message avatar + + + + + + + +
+
Options
+ + + + + + + +
+
+ + + From b3683cb69190085d8493f7dd93e7fd67e32a600f Mon Sep 17 00:00:00 2001 From: William Wong Date: Sat, 22 Feb 2020 20:01:16 -0800 Subject: [PATCH 02/33] Flush --- samples/05.custom-components/k.per-message-avatar/index.html | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/samples/05.custom-components/k.per-message-avatar/index.html b/samples/05.custom-components/k.per-message-avatar/index.html index f9d6ae82b4..35d23ba98f 100644 --- a/samples/05.custom-components/k.per-message-avatar/index.html +++ b/samples/05.custom-components/k.per-message-avatar/index.html @@ -23,7 +23,7 @@ #webchat { flex: 1; - height: 100%; + overflow: hidden; width: 100%; } @@ -32,6 +32,7 @@ border: solid 1px rgba(0, 0, 0, 0.1); border-radius: 4px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); + flex-shrink: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; font-size: 14px; @@ -95,7 +96,7 @@ }; const avatarMiddleware = () => next => ({ activity, styleOptions, ...otherArgs }) => { - if (~activity.text.indexOf('1')) { + if (~(activity.text || '').indexOf('1')) { return false; } From 646521e22cdd1c2a50d4148bfb5ee40bb115043f Mon Sep 17 00:00:00 2001 From: William Wong Date: Sat, 22 Feb 2020 23:53:35 -0800 Subject: [PATCH 03/33] Clean up --- .vscode/launch.json | 14 ++++++++++---- packages/component/src/Activity/StackedLayout.js | 9 ++++----- .../src/Middleware/Avatar/createCoreMiddleware.js | 4 ++-- .../component/src/Styles/StyleSet/StackedLayout.js | 12 ++++++------ .../k.per-message-avatar/index.html | 2 +- 5 files changed, 23 insertions(+), 18 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 28b0da37f1..f48df01603 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,11 +5,17 @@ "version": "0.2.0", "configurations": [ { - "type": "chrome", + "type": "vscode-edge-devtools.debug", "request": "launch", - "name": "Launch Chrome", - "url": "http://localhost:3000", - "webRoot": "${workspaceFolder}" + "name": "Launch Microsoft Edge and open the Elements tool", + "url": "http://localhost:5000/samples/", + "webRoot": "${workspaceFolder}", + "sourceMapPathOverrides": { + "webpack-internal:///../*": "${webRoot}/packages/*", + "webpack://botframework-webchat/bundle:///*": "${webRoot}/packages/bundle/*", + "webpack://botframework-webchat/component:///*": "${webRoot}/packages/component/*", + "webpack://botframework-webchat/core:///*": "${webRoot}/packages/core/*" + } } ] } diff --git a/packages/component/src/Activity/StackedLayout.js b/packages/component/src/Activity/StackedLayout.js index 25b4d0600e..a39201ff30 100644 --- a/packages/component/src/Activity/StackedLayout.js +++ b/packages/component/src/Activity/StackedLayout.js @@ -7,7 +7,6 @@ import PropTypes from 'prop-types'; import React from 'react'; import remarkStripMarkdown from '../Utils/remarkStripMarkdown'; -import Avatar from './Avatar'; import Bubble from './Bubble'; import connectToWebChat from '../connectToWebChat'; import ScreenReaderText from '../ScreenReaderText'; @@ -52,7 +51,7 @@ const ROOT_CSS = css({ flexShrink: 0 }, - '&.from-user': { + '&.webchat__stackedLayout--fromUser': { flexDirection: 'row-reverse', '& > .webchat__stackedLayout__content > .webchat__row': { @@ -121,9 +120,9 @@ const StackedLayout = ({ activity, children, nextVisibleActivity }) => { className={classNames( ROOT_CSS + '', stackedLayoutStyleSet + '', - direction === 'rtl' ? 'webchat__stacked--rtl' : '', + direction === 'rtl' ? 'webchat__stackedLayout--rtl' : '', { - 'from-user': fromUser, + 'webchat__stackedLayout--fromUser': fromUser, webchat__stacked_extra_left_indent: (direction !== 'rtl' && fromUser && !botAvatarInitials && bubbleNubSize) || (direction === 'rtl' && !fromUser && !userAvatarInitials && bubbleFromUserNubSize), @@ -131,7 +130,7 @@ const StackedLayout = ({ activity, children, nextVisibleActivity }) => { (direction !== 'rtl' && !fromUser && !userAvatarInitials && bubbleFromUserNubSize) || (direction === 'rtl' && fromUser && !botAvatarInitials && bubbleNubSize), webchat__stacked_indented_content: initials && !indented, - 'webchat__stacked--hasAvatar': renderAvatar && !!(fromUser ? bubbleFromUserNubSize : bubbleNubSize) + 'webchat__stackedLayout--hasAvatar': renderAvatar && !!(fromUser ? bubbleFromUserNubSize : bubbleNubSize) } )} > diff --git a/packages/component/src/Middleware/Avatar/createCoreMiddleware.js b/packages/component/src/Middleware/Avatar/createCoreMiddleware.js index 5600fd0728..c6770354e7 100644 --- a/packages/component/src/Middleware/Avatar/createCoreMiddleware.js +++ b/packages/component/src/Middleware/Avatar/createCoreMiddleware.js @@ -29,10 +29,10 @@ const DefaultAvatar = ({ fromUser }) => { }; export default function createCoreAvatarMiddleware() { - return concatMiddleware(() => next => ({ fromUser, styleOptions }) => { + return concatMiddleware(() => () => ({ fromUser, styleOptions }) => { const { botAvatarImage, botAvatarInitials, userAvatarImage, userAvatarInitials } = styleOptions; - if (fromUser ? botAvatarImage || botAvatarInitials : userAvatarImage || userAvatarInitials) { + if (fromUser ? userAvatarImage || userAvatarInitials : botAvatarImage || botAvatarInitials) { return () => ; } diff --git a/packages/component/src/Styles/StyleSet/StackedLayout.js b/packages/component/src/Styles/StyleSet/StackedLayout.js index 1db7030728..b5148ec382 100644 --- a/packages/component/src/Styles/StyleSet/StackedLayout.js +++ b/packages/component/src/Styles/StyleSet/StackedLayout.js @@ -17,8 +17,8 @@ export default function createStackedLayoutStyle({ bubbleMaxWidth, bubbleMinWidt '&:not(.webchat__stacked_extra_right_indent)': { marginRight: paddingRegular }, - '&:not(.webchat__stacked--rtl)': { - '&:not(.from-user)': { + '&:not(.webchat__stackedLayout--rtl)': { + '&:not(.webchat__stackedLayout--fromUser)': { '&.webchat__stacked_indented_content > .webchat__stackedLayout__avatar': { marginRight: paddingRegular }, @@ -28,7 +28,7 @@ export default function createStackedLayoutStyle({ bubbleMaxWidth, bubbleMinWidt } }, - '&.from-user': { + '&.webchat__stackedLayout--fromUser': { '&.webchat__stacked_indented_content > .webchat__stackedLayout__avatar': { marginLeft: paddingRegular }, @@ -39,8 +39,8 @@ export default function createStackedLayoutStyle({ bubbleMaxWidth, bubbleMinWidt } }, - '&.webchat__stacked--rtl': { - '&:not(.from-user)': { + '&.webchat__stackedLayout--rtl': { + '&:not(.webchat__stackedLayout--fromUser)': { '&.webchat__stacked_indented_content > .webchat__stackedLayout__avatar': { marginLeft: paddingRegular }, @@ -50,7 +50,7 @@ export default function createStackedLayoutStyle({ bubbleMaxWidth, bubbleMinWidt } }, - '&.from-user': { + '&.webchat__stackedLayout--fromUser': { '&.webchat__stacked_indented_content > .webchat__stackedLayout__avatar': { marginRight: paddingRegular }, diff --git a/samples/05.custom-components/k.per-message-avatar/index.html b/samples/05.custom-components/k.per-message-avatar/index.html index 35d23ba98f..458e167cb4 100644 --- a/samples/05.custom-components/k.per-message-avatar/index.html +++ b/samples/05.custom-components/k.per-message-avatar/index.html @@ -43,7 +43,7 @@ } #commandBar > header { - background-color: DarkGreen; + background-color: #090; border-radius: 0 0 0 4px; color: White; font-size: 11px; From cb0071d82b2cb0d6a1175e9ed8a991b8586b67f9 Mon Sep 17 00:00:00 2001 From: William Wong Date: Sun, 23 Feb 2020 00:58:01 -0800 Subject: [PATCH 04/33] Add Edge debugger --- .vscode/launch.json | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.vscode/launch.json b/.vscode/launch.json index f48df01603..400a8e4524 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -4,6 +4,19 @@ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ + { + "type": "edge", + "request": "launch", + "name": "Launch Edge", + "url": "http://localhost:5000/samples/", + "webRoot": "${workspaceFolder}", + "sourceMapPathOverrides": { + "webpack-internal:///../*": "${webRoot}/packages/*", + "webpack://botframework-webchat/bundle:///*": "${webRoot}/packages/bundle/*", + "webpack://botframework-webchat/component:///*": "${webRoot}/packages/component/*", + "webpack://botframework-webchat/core:///*": "${webRoot}/packages/core/*" + } + }, { "type": "vscode-edge-devtools.debug", "request": "launch", From 9337465a7edf5ec4417e02e8a97b8c12e9cbd533 Mon Sep 17 00:00:00 2001 From: William Wong Date: Sun, 23 Feb 2020 00:58:14 -0800 Subject: [PATCH 05/33] Add online status --- .../k.per-message-avatar/index.html | 340 ++++++++++++++---- 1 file changed, 268 insertions(+), 72 deletions(-) diff --git a/samples/05.custom-components/k.per-message-avatar/index.html b/samples/05.custom-components/k.per-message-avatar/index.html index 458e167cb4..3cb56b3270 100644 --- a/samples/05.custom-components/k.per-message-avatar/index.html +++ b/samples/05.custom-components/k.per-message-avatar/index.html @@ -7,6 +7,9 @@ This CDN points to the latest official release of Web Chat. If you need to test against Web Chat's latest bits, please refer to pointing to Web Chat's MyGet feed: https://github.com/microsoft/BotFramework-WebChat#how-to-test-with-web-chats-latest-bits --> + + + -
-
Options
- - - - - - - -
-
- From d229ffcbfe8e26468571fe6791e912022882f6fa Mon Sep 17 00:00:00 2001 From: William Wong Date: Sun, 23 Feb 2020 02:26:15 -0800 Subject: [PATCH 06/33] Clean up --- packages/component/src/BasicWebChat.js | 26 +++++++++---------- .../component/src/hooks/useRenderAvatar.js | 19 +++++++++++--- 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/packages/component/src/BasicWebChat.js b/packages/component/src/BasicWebChat.js index 1a32a96342..832c2dc5db 100644 --- a/packages/component/src/BasicWebChat.js +++ b/packages/component/src/BasicWebChat.js @@ -74,19 +74,6 @@ function createActivityRenderer(additionalMiddleware) { }; } -// TODO: [P2] #2859 We should move these into -function createAvatarRenderer(additionalMiddleware) { - const avatarMiddleware = concatMiddleware(additionalMiddleware, createCoreAvatarMiddleware())({}); - - return (...args) => { - try { - return avatarMiddleware(() => false)(...args); - } catch (err) { - console.error('Failed to render avatar', err); - } - }; -} - // TODO: [P2] #2859 We should move these into function createActivityStatusRenderer(additionalMiddleware) { const activityStatusMiddleware = concatMiddleware(additionalMiddleware, createCoreActivityStatusMiddleware())({}); @@ -127,6 +114,19 @@ function createAttachmentRenderer(additionalMiddleware) { }; } +// TODO: [P2] #2859 We should move these into +function createAvatarRenderer(additionalMiddleware) { + const avatarMiddleware = concatMiddleware(additionalMiddleware, createCoreAvatarMiddleware())({}); + + return (...args) => { + try { + return avatarMiddleware(() => false)(...args); + } catch (err) { + console.error('Failed to render avatar', err); + } + }; +} + // TODO: [P2] #2859 We should move these into function createToastRenderer(additionalMiddleware) { const toastMiddleware = concatMiddleware(additionalMiddleware, createCoreToastMiddleware())({}); diff --git a/packages/component/src/hooks/useRenderAvatar.js b/packages/component/src/hooks/useRenderAvatar.js index b81c1b1e15..33c2370010 100644 --- a/packages/component/src/hooks/useRenderAvatar.js +++ b/packages/component/src/hooks/useRenderAvatar.js @@ -6,9 +6,22 @@ import useWebChatUIContext from './internal/useWebChatUIContext'; export default function useRenderAvatar({ activity }) { const [styleOptions] = useStyleOptions(); const { avatarRenderer } = useWebChatUIContext(); - const { from: { role } = {} } = activity; - const fromUser = role === 'user'; + return useMemo(() => { + const { from: { role } = {} } = activity; - return useMemo(() => avatarRenderer({ activity, fromUser, styleOptions }), [activity, fromUser, styleOptions]); + const fromUser = role === 'user'; + + const result = avatarRenderer({ activity, fromUser, styleOptions }); + + if (result !== false && typeof result !== 'function') { + console.warn( + 'botframework-webchat: avatarMiddleware should return a function to render the avatar, or return false if avatar should be hidden.' + ); + + return () => result; + } + + return result; + }, [activity, styleOptions]); } From fb5eac83e2f80223a1fd4131ca754c9794e2433a Mon Sep 17 00:00:00 2001 From: William Wong Date: Sun, 23 Feb 2020 05:29:32 -0800 Subject: [PATCH 07/33] Support non-square avatar --- .../component/src/Activity/StackedLayout.js | 10 ++--- .../Middleware/Avatar/createCoreMiddleware.js | 1 + .../component/src/Styles/StyleSet/Avatar.js | 5 +-- .../src/Styles/StyleSet/InitialsAvatar.js | 1 - .../src/Styles/defaultStyleOptions.js | 1 + .../k.per-message-avatar/bot.jpg | Bin 0 -> 3617 bytes .../k.per-message-avatar/index.html | 37 ++++++++++++------ .../k.per-message-avatar/user.jpg | Bin 0 -> 5510 bytes 8 files changed, 34 insertions(+), 21 deletions(-) create mode 100644 samples/05.custom-components/k.per-message-avatar/bot.jpg create mode 100644 samples/05.custom-components/k.per-message-avatar/user.jpg diff --git a/packages/component/src/Activity/StackedLayout.js b/packages/component/src/Activity/StackedLayout.js index a39201ff30..085b5ddf35 100644 --- a/packages/component/src/Activity/StackedLayout.js +++ b/packages/component/src/Activity/StackedLayout.js @@ -124,12 +124,12 @@ const StackedLayout = ({ activity, children, nextVisibleActivity }) => { { 'webchat__stackedLayout--fromUser': fromUser, webchat__stacked_extra_left_indent: - (direction !== 'rtl' && fromUser && !botAvatarInitials && bubbleNubSize) || - (direction === 'rtl' && !fromUser && !userAvatarInitials && bubbleFromUserNubSize), + (direction !== 'rtl' && fromUser && !renderAvatar && bubbleNubSize) || + (direction === 'rtl' && !fromUser && !renderAvatar && bubbleFromUserNubSize), webchat__stacked_extra_right_indent: - (direction !== 'rtl' && !fromUser && !userAvatarInitials && bubbleFromUserNubSize) || - (direction === 'rtl' && fromUser && !botAvatarInitials && bubbleNubSize), - webchat__stacked_indented_content: initials && !indented, + (direction !== 'rtl' && !fromUser && !renderAvatar && bubbleFromUserNubSize) || + (direction === 'rtl' && fromUser && !renderAvatar && bubbleNubSize), + webchat__stacked_indented_content: renderAvatar && !indented, 'webchat__stackedLayout--hasAvatar': renderAvatar && !!(fromUser ? bubbleFromUserNubSize : bubbleNubSize) } )} diff --git a/packages/component/src/Middleware/Avatar/createCoreMiddleware.js b/packages/component/src/Middleware/Avatar/createCoreMiddleware.js index c6770354e7..55493fd100 100644 --- a/packages/component/src/Middleware/Avatar/createCoreMiddleware.js +++ b/packages/component/src/Middleware/Avatar/createCoreMiddleware.js @@ -8,6 +8,7 @@ import InitialsAvatar from '../../Avatar/InitialsAvatar'; import useStyleSet from '../../hooks/useStyleSet'; const ROOT_CSS = css({ + overflow: 'hidden', position: 'relative', '> *': { diff --git a/packages/component/src/Styles/StyleSet/Avatar.js b/packages/component/src/Styles/StyleSet/Avatar.js index 1d587f49fb..1593878933 100644 --- a/packages/component/src/Styles/StyleSet/Avatar.js +++ b/packages/component/src/Styles/StyleSet/Avatar.js @@ -1,8 +1,7 @@ -export default function createAvatarStyle({ avatarSize }) { +export default function createAvatarStyle({ avatarRadius, avatarSize }) { return { - borderRadius: '50%', + borderRadius: avatarRadius, height: avatarSize, - overflow: 'hidden', width: avatarSize }; } diff --git a/packages/component/src/Styles/StyleSet/InitialsAvatar.js b/packages/component/src/Styles/StyleSet/InitialsAvatar.js index 330a096765..00e01292ac 100644 --- a/packages/component/src/Styles/StyleSet/InitialsAvatar.js +++ b/packages/component/src/Styles/StyleSet/InitialsAvatar.js @@ -7,7 +7,6 @@ export default function createInitialsAvatarStyle({ }) { return { alignItems: 'center', - borderRadius: '50%', color: 'White', fontFamily: primaryFont, height: avatarSize, diff --git a/packages/component/src/Styles/defaultStyleOptions.js b/packages/component/src/Styles/defaultStyleOptions.js index de0f6407e8..e19f476941 100644 --- a/packages/component/src/Styles/defaultStyleOptions.js +++ b/packages/component/src/Styles/defaultStyleOptions.js @@ -26,6 +26,7 @@ const DEFAULT_OPTIONS = { primaryFont: fontFamily(['Calibri', 'Helvetica Neue', 'Arial', 'sans-serif']), // Avatar + avatarRadius: '50%', avatarSize: 40, botAvatarBackgroundColor: undefined, // defaults to accent color botAvatarImage: '', diff --git a/samples/05.custom-components/k.per-message-avatar/bot.jpg b/samples/05.custom-components/k.per-message-avatar/bot.jpg new file mode 100644 index 0000000000000000000000000000000000000000..76c164eefbfb9b03055140392bbe247687613338 GIT binary patch literal 3617 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 literal 0 HcmV?d00001 diff --git a/samples/05.custom-components/k.per-message-avatar/index.html b/samples/05.custom-components/k.per-message-avatar/index.html index 3cb56b3270..48092b8c35 100644 --- a/samples/05.custom-components/k.per-message-avatar/index.html +++ b/samples/05.custom-components/k.per-message-avatar/index.html @@ -77,33 +77,34 @@ margin-left: 0.4em; } - .app__customAvatar { + .app__avatarWithOnlineStatus { position: relative; } - .app__customAvatar .app__customAvatar__status { + .app__avatarWithOnlineStatus .app__avatarWithOnlineStatus__status { background-color: White; border-radius: 50%; border: solid 2px White; bottom: -2px; height: 10px; position: absolute; + transition: background-color 200ms; width: 10px; } - .app__customAvatar:not(.app__customAvatar--rtl) .app__customAvatar__status { + .app__avatarWithOnlineStatus:not(.app__avatarWithOnlineStatus--rtl) .app__avatarWithOnlineStatus__status { right: -2px; } - .app__customAvatar.app__customAvatar--rtl .app__customAvatar__status { + .app__avatarWithOnlineStatus.app__avatarWithOnlineStatus--rtl .app__avatarWithOnlineStatus__status { left: -2px; } - .app__customAvatar .app__customAvatar__status.app__customAvatar__status--online { + .app__avatarWithOnlineStatus .app__avatarWithOnlineStatus__status.app__avatarWithOnlineStatus__status--online { background-color: #090; } - .app__customAvatar .app__customAvatar__status.app__customAvatar__status--busy { + .app__avatarWithOnlineStatus .app__avatarWithOnlineStatus__status.app__avatarWithOnlineStatus__status--busy { background-color: Red; } @@ -322,30 +323,42 @@ ); }; - const CustomAvatar = ({ children }) => { + const PortraitAvatar = ({ fromUser }) => { + const style = useMemo(() => ({ borderRadius: 4 }), []); + + return ; + }; + + const AvatarWithOnlineStatus = ({ children }) => { const [direction] = useDirection(); const { onlineStatus, showOnlineStatus } = useContext(AppContext); return ( -
+
{children} {showOnlineStatus && ( -
+
)}
); }; - const avatarMiddleware = () => next => ({ activity, styleOptions, ...otherArgs }) => { + const avatarMiddleware = () => next => ({ activity, fromUser, styleOptions, ...otherArgs }) => { const { text = '' } = activity; if (~text.indexOf('1')) { return false; + } else if (~text.indexOf('2')) { + return ; } - const renderNext = next({ activity, styleOptions, ...otherArgs }); + const renderNext = next({ activity, fromUser, styleOptions, ...otherArgs }); - return renderNext && (() => {renderNext()}); + return renderNext && (() => {renderNext()}); }; ReactDOM.render(, document.getElementById('app')); diff --git a/samples/05.custom-components/k.per-message-avatar/user.jpg b/samples/05.custom-components/k.per-message-avatar/user.jpg new file mode 100644 index 0000000000000000000000000000000000000000..de73dcdaef31f87a9efa345d7166a736fbd6aeca GIT binary patch literal 5510 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 aA=3 Date: Sun, 23 Feb 2020 15:56:23 -0800 Subject: [PATCH 08/33] Fix bubble nub on RTL --- .../component/src/Styles/StyleSet/Bubble.js | 64 ++++++++++++------- .../k.per-message-avatar/index.html | 4 +- 2 files changed, 43 insertions(+), 25 deletions(-) diff --git a/packages/component/src/Styles/StyleSet/Bubble.js b/packages/component/src/Styles/StyleSet/Bubble.js index 69cf12cb0b..f8a2f8098f 100644 --- a/packages/component/src/Styles/StyleSet/Bubble.js +++ b/packages/component/src/Styles/StyleSet/Bubble.js @@ -1,6 +1,6 @@ /* eslint no-magic-numbers: ["error", { "ignore": [0, 1, 2] }] */ -function isPositive(value) { +function isZeroOrPositive(value) { return 1 / value >= 0; } @@ -25,8 +25,8 @@ export default function createBubbleStyle({ messageActivityWordBreak, paddingRegular }) { - const botNubUpSideDown = !isPositive(bubbleNubOffset); - const userNubUpSideDown = !isPositive(bubbleFromUserNubOffset); + const botNubUpSideDown = !isZeroOrPositive(bubbleNubOffset); + const userNubUpSideDown = !isZeroOrPositive(bubbleFromUserNubOffset); const botNubCornerRadius = Math.min(bubbleBorderRadius, Math.abs(bubbleNubOffset)); const userNubCornerRadius = Math.min(bubbleFromUserBorderRadius, Math.abs(bubbleFromUserNubOffset)); @@ -52,15 +52,17 @@ export default function createBubbleStyle({ minHeight: bubbleMinHeight - bubbleBorderWidth * 2 }, - '&.webchat__bubble_has_nub > .webchat__bubble__content': { - // Hide border radius if there is a nub on the top/bottom left corner - ...(bubbleNubSize && botNubUpSideDown ? { borderBottomLeftRadius: botNubCornerRadius } : {}), - ...(bubbleNubSize && !botNubUpSideDown ? { borderTopLeftRadius: botNubCornerRadius } : {}) - }, - '&:not(.webchat__bubble--rtl)': { '&.webchat__bubble_has_nub': { - '& > .webchat__bubble__content': bubbleNubSize ? { marginLeft: paddingRegular } : {} + '& > .webchat__bubble__content': bubbleNubSize + ? { + marginLeft: paddingRegular, + + // Hide border radius if there is a nub on the top/bottom left corner + ...(botNubUpSideDown ? { borderBottomLeftRadius: botNubCornerRadius } : {}), + ...(!botNubUpSideDown ? { borderTopLeftRadius: botNubCornerRadius } : {}) + } + : {} }, '& > .webchat__bubble__nub': { @@ -70,7 +72,15 @@ export default function createBubbleStyle({ '&.webchat__bubble--rtl': { '&.webchat__bubble_has_nub': { - '& > .webchat__bubble__content': bubbleNubSize ? { marginRight: paddingRegular } : {} + '& > .webchat__bubble__content': bubbleNubSize + ? { + marginRight: paddingRegular, + + // Hide border radius if there is a nub on the top/bottom right corner + ...(botNubUpSideDown ? { borderBottomRightRadius: botNubCornerRadius } : {}), + ...(!botNubUpSideDown ? { borderTopRightRadius: botNubCornerRadius } : {}) + } + : {} }, '& > .webchat__bubble__nub': { @@ -80,9 +90,9 @@ export default function createBubbleStyle({ }, '& > .webchat__bubble__nub': { - bottom: isPositive(bubbleNubOffset) ? undefined : -bubbleNubOffset, + bottom: isZeroOrPositive(bubbleNubOffset) ? undefined : -bubbleNubOffset, height: bubbleNubSize, - top: isPositive(bubbleNubOffset) ? bubbleNubOffset : undefined, + top: isZeroOrPositive(bubbleNubOffset) ? bubbleNubOffset : undefined, width: bubbleNubSize, '& > g > path': { @@ -104,15 +114,16 @@ export default function createBubbleStyle({ minHeight: bubbleMinHeight - bubbleFromUserBorderWidth * 2 }, - '&.webchat__bubble_has_nub > .webchat__bubble__content': { - // Hide border radius if there is a nub on the top/bottom right corner - ...(bubbleFromUserNubSize && userNubUpSideDown ? { borderBottomRightRadius: userNubCornerRadius } : {}), - ...(bubbleFromUserNubSize && !userNubUpSideDown ? { borderTopRightRadius: userNubCornerRadius } : {}) - }, - '&:not(.webchat__bubble--rtl)': { '&.webchat__bubble_has_nub': { - '& > .webchat__bubble__content': bubbleFromUserNubSize ? { marginRight: paddingRegular } : {} + '& > .webchat__bubble__content': bubbleFromUserNubSize + ? { + marginRight: paddingRegular, + // Hide border radius if there is a nub on the top/bottom right corner + ...(userNubUpSideDown ? { borderBottomRightRadius: userNubCornerRadius } : {}), + ...(!userNubUpSideDown ? { borderTopRightRadius: userNubCornerRadius } : {}) + } + : {} }, '& > .webchat__bubble__nub': { @@ -122,7 +133,14 @@ export default function createBubbleStyle({ '&.webchat__bubble--rtl': { '&.webchat__bubble_has_nub': { - '& > .webchat__bubble__content': bubbleFromUserNubSize ? { marginLeft: paddingRegular } : {} + '& > .webchat__bubble__content': bubbleFromUserNubSize + ? { + marginLeft: paddingRegular, + // Hide border radius if there is a nub on the top/bottom left corner + ...(userNubUpSideDown ? { borderBottomLeftRadius: userNubCornerRadius } : {}), + ...(!userNubUpSideDown ? { borderTopLeftRadius: userNubCornerRadius } : {}) + } + : {} }, '& > .webchat__bubble__nub': { @@ -133,8 +151,8 @@ export default function createBubbleStyle({ '& > .webchat__bubble__nub': { height: bubbleFromUserNubSize, - bottom: isPositive(bubbleFromUserNubOffset) ? undefined : -bubbleFromUserNubOffset, - top: isPositive(bubbleFromUserNubOffset) ? bubbleFromUserNubOffset : undefined, + bottom: isZeroOrPositive(bubbleFromUserNubOffset) ? undefined : -bubbleFromUserNubOffset, + top: isZeroOrPositive(bubbleFromUserNubOffset) ? bubbleFromUserNubOffset : undefined, width: bubbleFromUserNubSize, '& > g > path': { diff --git a/samples/05.custom-components/k.per-message-avatar/index.html b/samples/05.custom-components/k.per-message-avatar/index.html index 48092b8c35..62c49f0101 100644 --- a/samples/05.custom-components/k.per-message-avatar/index.html +++ b/samples/05.custom-components/k.per-message-avatar/index.html @@ -189,7 +189,7 @@ const styleOptions = useMemo( () => ({ - ...(botRoundBubble ? { bubbleBorderRadius: 20 } : {}), + ...(botRoundBubble ? { bubbleBorderRadius: 20, bubbleNubOffset: 5 } : {}), ...(botShowBubbleNub ? { bubbleNubSize: 10 } : {}), ...(botShowDefaultAvatar ? { @@ -198,7 +198,7 @@ botAvatarInitials: 'BF' } : {}), - ...(userRoundBubble ? { bubbleFromUserBorderRadius: 20 } : {}), + ...(userRoundBubble ? { bubbleFromUserBorderRadius: 20, bubbleFromUserNubOffset: 5 } : {}), ...(userShowBubbleNub ? { bubbleFromUserNubSize: 10 } : {}), ...(userShowDefaultAvatar ? { From aff6935d5f948f08cf461f1143042bfa108c3d4c Mon Sep 17 00:00:00 2001 From: William Wong Date: Sun, 23 Feb 2020 18:32:39 -0800 Subject: [PATCH 09/33] Clean up --- packages/component/src/Activity/Avatar.js | 64 ------------------- .../src/Activity/CarouselFilmStrip.js | 2 - 2 files changed, 66 deletions(-) delete mode 100644 packages/component/src/Activity/Avatar.js diff --git a/packages/component/src/Activity/Avatar.js b/packages/component/src/Activity/Avatar.js deleted file mode 100644 index 0b7f7dc23e..0000000000 --- a/packages/component/src/Activity/Avatar.js +++ /dev/null @@ -1,64 +0,0 @@ -import classNames from 'classnames'; -import PropTypes from 'prop-types'; -import React from 'react'; - -import connectToWebChat from '../connectToWebChat'; -import CroppedImage from '../Utils/CroppedImage'; -import useAvatarForBot from '../hooks/useAvatarForBot'; -import useAvatarForUser from '../hooks/useAvatarForUser'; -import useStyleSet from '../hooks/useStyleSet'; - -const connectAvatar = (...selectors) => - connectToWebChat( - ( - { - styleSet: { - options: { botAvatarImage, botAvatarInitials, userAvatarImage, userAvatarInitials } - } - }, - { fromUser } - ) => ({ - avatarImage: fromUser ? userAvatarImage : botAvatarImage, - avatarInitials: fromUser ? userAvatarInitials : botAvatarInitials - }), - ...selectors - ); - -// TODO: [P2] Consider memoizing "style={ backgroundImage }" in our upstreamers -// We have 2 different upstreamers and - -const Avatar = ({ 'aria-hidden': ariaHidden, className, fromUser }) => { - const [botAvatar] = useAvatarForBot(); - const [userAvatar] = useAvatarForUser(); - const [{ avatar: avatarStyleSet }] = useStyleSet(); - - const { image, initials } = fromUser ? userAvatar : botAvatar; - - return ( - !!(image || initials) && ( -
- {initials} - {!!image && } -
- ) - ); -}; - -Avatar.defaultProps = { - 'aria-hidden': false, - className: '', - fromUser: false -}; - -Avatar.propTypes = { - 'aria-hidden': PropTypes.bool, - className: PropTypes.string, - fromUser: PropTypes.bool -}; - -export default Avatar; - -export { connectAvatar }; diff --git a/packages/component/src/Activity/CarouselFilmStrip.js b/packages/component/src/Activity/CarouselFilmStrip.js index 083d606987..6451424ebc 100644 --- a/packages/component/src/Activity/CarouselFilmStrip.js +++ b/packages/component/src/Activity/CarouselFilmStrip.js @@ -7,7 +7,6 @@ import PropTypes from 'prop-types'; import React from 'react'; import remarkStripMarkdown from '../Utils/remarkStripMarkdown'; -import Avatar from './Avatar'; import Bubble from './Bubble'; import connectToWebChat from '../connectToWebChat'; import ScreenReaderText from '../ScreenReaderText'; @@ -130,7 +129,6 @@ const WebChatCarouselFilmStrip = ({ )} ref={scrollableRef} > - {/* */} {renderAvatar &&
{renderAvatar()}
}
{!!activityDisplayText && ( From 6ea024d3d0f723bb273f5e0e69527c10cf2f2f10 Mon Sep 17 00:00:00 2001 From: William Wong Date: Sun, 23 Feb 2020 18:44:39 -0800 Subject: [PATCH 10/33] Clean up CSS --- .../component/src/Avatar/InitialsAvatar.js | 9 ++++++- .../Middleware/Avatar/createCoreMiddleware.js | 10 ++++++- .../component/src/Styles/StyleSet/Avatar.js | 8 +++--- .../src/Styles/StyleSet/InitialsAvatar.js | 26 ++++++++++--------- 4 files changed, 36 insertions(+), 17 deletions(-) diff --git a/packages/component/src/Avatar/InitialsAvatar.js b/packages/component/src/Avatar/InitialsAvatar.js index b54213a3ec..4bb1a59a75 100644 --- a/packages/component/src/Avatar/InitialsAvatar.js +++ b/packages/component/src/Avatar/InitialsAvatar.js @@ -22,7 +22,14 @@ const InitialsAvatar = ({ fromUser }) => { const [{ initialsAvatar: initialsAvatarStyleSet }] = useStyleSet(); return ( -
+
{fromUser ? avatarInitialsForUser : avatarInitialsForBot}
); diff --git a/packages/component/src/Middleware/Avatar/createCoreMiddleware.js b/packages/component/src/Middleware/Avatar/createCoreMiddleware.js index 55493fd100..a16fc010d7 100644 --- a/packages/component/src/Middleware/Avatar/createCoreMiddleware.js +++ b/packages/component/src/Middleware/Avatar/createCoreMiddleware.js @@ -22,7 +22,15 @@ const DefaultAvatar = ({ fromUser }) => { const [{ avatar: avatarStyleSet }] = useStyleSet(); return ( -
+
diff --git a/packages/component/src/Styles/StyleSet/Avatar.js b/packages/component/src/Styles/StyleSet/Avatar.js index 1593878933..019d685a51 100644 --- a/packages/component/src/Styles/StyleSet/Avatar.js +++ b/packages/component/src/Styles/StyleSet/Avatar.js @@ -1,7 +1,9 @@ export default function createAvatarStyle({ avatarRadius, avatarSize }) { return { - borderRadius: avatarRadius, - height: avatarSize, - width: avatarSize + '&.webchat__defaultAvatar': { + borderRadius: avatarRadius, + height: avatarSize, + width: avatarSize + } }; } diff --git a/packages/component/src/Styles/StyleSet/InitialsAvatar.js b/packages/component/src/Styles/StyleSet/InitialsAvatar.js index 00e01292ac..fd9581004c 100644 --- a/packages/component/src/Styles/StyleSet/InitialsAvatar.js +++ b/packages/component/src/Styles/StyleSet/InitialsAvatar.js @@ -6,20 +6,22 @@ export default function createInitialsAvatarStyle({ userAvatarBackgroundColor }) { return { - alignItems: 'center', - color: 'White', - fontFamily: primaryFont, - height: avatarSize, - justifyContent: 'center', - overflow: 'hidden', - width: avatarSize, + '&.webchat__initialsAvatar': { + alignItems: 'center', + color: 'White', + fontFamily: primaryFont, + height: avatarSize, + justifyContent: 'center', + overflow: 'hidden', + width: avatarSize, - '&.from-user': { - backgroundColor: userAvatarBackgroundColor || accent - }, + '&.webchat__initialsAvatar--fromUser': { + backgroundColor: userAvatarBackgroundColor || accent + }, - '&:not(.from-user)': { - backgroundColor: botAvatarBackgroundColor || accent + '&:not(.webchat__initialsAvatar--fromUser)': { + backgroundColor: botAvatarBackgroundColor || accent + } } }; } From 66bbc0aeec1363019c8c67df01d9cd86f17873bd Mon Sep 17 00:00:00 2001 From: William Wong Date: Sun, 23 Feb 2020 18:45:14 -0800 Subject: [PATCH 11/33] Add .prettierignore --- .prettierignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .prettierignore diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000000..24d6f25469 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,2 @@ +/**/nodes_modules/ +/samples/**/build/static/ From 19974c1be4db727d10be1da4bede1d125d44af47 Mon Sep 17 00:00:00 2001 From: William Wong Date: Sun, 23 Feb 2020 18:46:21 -0800 Subject: [PATCH 12/33] Add background color --- .../k.per-message-avatar/index.html | 59 +++++++++++++++---- 1 file changed, 47 insertions(+), 12 deletions(-) diff --git a/samples/05.custom-components/k.per-message-avatar/index.html b/samples/05.custom-components/k.per-message-avatar/index.html index 62c49f0101..40ef35c699 100644 --- a/samples/05.custom-components/k.per-message-avatar/index.html +++ b/samples/05.custom-components/k.per-message-avatar/index.html @@ -120,13 +120,6 @@ const res = await fetch('https://webchat-mockbot.azurewebsites.net/directline/token', { method: 'POST' }); const { token } = await res.json(); - const styleOptions = { - botAvatarImage: - 'https://docs.microsoft.com/en-us/azure/bot-service/v4sdk/media/logo_bot.svg?view=azure-bot-service-4.0', - botAvatarInitials: 'BF', - userAvatarImage: 'https://github.com/compulim.png?size=64', - userAvatarInitials: 'WC' - }; const { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } = window.React; const { @@ -146,8 +139,15 @@ const [userRoundBubble, setUserRoundBubble] = useState(false); const [userShowBubbleNub, setUserShowBubbleNub] = useState(false); const [userShowDefaultAvatar, setUserShowDefaultAvatar] = useState(true); + const [botDefaultAvatarType, setBotDefaultAvatarType] = useState('image'); + const [userDefaultAvatarType, setUserDefaultAvatarType] = useState('image'); const directLine = useMemo(() => window.WebChat.createDirectLine({ token }), []); + const handleBotDefaultAvatarTypeChange = useCallback( + ({ target: { value } }) => setBotDefaultAvatarType(value), + [setBotDefaultAvatarType] + ); + const handleBotRoundBubbleChange = useCallback(({ target: { checked } }) => setBotRoundBubble(checked), [ setBotRoundBubble ]); @@ -161,6 +161,11 @@ [setBotShowDefaultAvatar] ); + const handleUserDefaultAvatarTypeChange = useCallback( + ({ target: { value } }) => setUserDefaultAvatarType(value), + [setUserDefaultAvatarType] + ); + const handleUserRoundBubbleChange = useCallback(({ target: { checked } }) => setUserRoundBubble(checked), [ setUserRoundBubble ]); @@ -193,24 +198,36 @@ ...(botShowBubbleNub ? { bubbleNubSize: 10 } : {}), ...(botShowDefaultAvatar ? { - botAvatarImage: - 'https://docs.microsoft.com/en-us/azure/bot-service/v4sdk/media/logo_bot.svg?view=azure-bot-service-4.0', - botAvatarInitials: 'BF' + botAvatarBackgroundColor: '#77F', + botAvatarInitials: 'BF', + ...(botDefaultAvatarType === 'image' + ? { + botAvatarImage: + 'https://docs.microsoft.com/en-us/azure/bot-service/v4sdk/media/logo_bot.svg?view=azure-bot-service-4.0' + } + : {}) } : {}), ...(userRoundBubble ? { bubbleFromUserBorderRadius: 20, bubbleFromUserNubOffset: 5 } : {}), ...(userShowBubbleNub ? { bubbleFromUserNubSize: 10 } : {}), ...(userShowDefaultAvatar ? { - userAvatarImage: 'https://github.com/compulim.png?size=64', - userAvatarInitials: 'WC' + userAvatarBackgroundColor: '#F77', + userAvatarInitials: 'WC', + ...(userDefaultAvatarType === 'image' + ? { + userAvatarImage: 'https://github.com/compulim.png?size=64' + } + : {}) } : {}) }), [ + botDefaultAvatarType, botRoundBubble, botShowBubbleNub, botShowDefaultAvatar, + userDefaultAvatarType, userRoundBubble, userShowBubbleNub, userShowDefaultAvatar @@ -256,6 +273,15 @@ type="checkbox" /> Bot: Show default avatar +