Skip to content

Commit 95ab4e6

Browse files
authored
Adds AdaptiveCardsComposer and AdaptiveCardsContext for composability (#2648)
* Adds AdaptiveCardsComposer and AdaptiveCardsContext * Refactor * Update entry * Fix Markdown * Fix ESLint * Update packages/bundle/src/FullReactWebChat.js Co-Authored-By: TJ Durnford <[email protected]> * Remove deprecated code (avatarInitials)
1 parent 5b2e0c2 commit 95ab4e6

18 files changed

Lines changed: 202 additions & 141 deletions

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
4545
- 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)
4646
- 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)
4747
- Adds Arabic Language Support, by [@midineo](https://github.com/midineo), in PR [#2593](https://github.com/microsoft/BotFramework-WebChat/pull/2593)
48+
- Adds `AdaptiveCardsComposer` and `AdaptiveCardsContext` for composability for Adaptive Cards, by [@compulim](https://github.com/compulim), in PR [#2648](https://github.com/microsoft/BotFramework-WebChat/pull/2648)
4849

4950
### Fixed
5051

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import PropTypes from 'prop-types';
2+
import React from 'react';
3+
4+
import AdaptiveCardsComposer from './adaptiveCards/AdaptiveCardsComposer';
5+
import { Components } from 'botframework-webchat-component';
6+
7+
import useComposerProps from './useComposerProps';
8+
9+
const { Composer } = Components;
10+
11+
const FullComposer = props => {
12+
const { adaptiveCardsHostConfig, adaptiveCardsPackage, children, ...otherProps } = props;
13+
const composerProps = useComposerProps(props);
14+
15+
return (
16+
<AdaptiveCardsComposer
17+
adaptiveCardsHostConfig={adaptiveCardsHostConfig}
18+
adaptiveCardsPackage={adaptiveCardsPackage}
19+
>
20+
<Composer {...otherProps} {...composerProps}>
21+
{children}
22+
</Composer>
23+
</AdaptiveCardsComposer>
24+
);
25+
};
26+
27+
FullComposer.defaultProps = {
28+
...Composer.defaultProps,
29+
adaptiveCardsHostConfig: undefined,
30+
adaptiveCardsPackage: undefined,
31+
children: undefined
32+
};
33+
34+
FullComposer.propTypes = {
35+
...Composer.propTypes,
36+
adaptiveCardsHostConfig: PropTypes.any,
37+
adaptiveCardsPackage: PropTypes.any,
38+
children: PropTypes.any
39+
};
40+
41+
export default FullComposer;
Lines changed: 18 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,93 +1,47 @@
1-
import * as defaultAdaptiveCardsPackage from 'adaptivecards';
2-
import BasicWebChat, { concatMiddleware } from 'botframework-webchat-component';
1+
import BasicWebChat from 'botframework-webchat-component';
32
import PropTypes from 'prop-types';
4-
import React, { useEffect, useMemo } from 'react';
3+
import React, { useEffect } from 'react';
54

6-
import AdaptiveCardsContext from './adaptiveCards/AdaptiveCardsContext';
7-
import createAdaptiveCardsAttachmentMiddleware from './adaptiveCards/createAdaptiveCardMiddleware';
8-
import createDefaultAdaptiveCardHostConfig from './adaptiveCards/Styles/adaptiveCardHostConfig';
9-
import createStyleSet from './adaptiveCards/Styles/createStyleSetWithAdaptiveCards';
10-
import defaultRenderMarkdown from './renderMarkdown';
5+
import AdaptiveCardsComposer from './adaptiveCards/AdaptiveCardsComposer';
6+
import useComposerProps from './useComposerProps';
117

128
// Add additional props to <WebChat>, so it support additional features
13-
const FullReactWebChat = ({
14-
adaptiveCardHostConfig,
15-
adaptiveCardsHostConfig,
16-
adaptiveCardsPackage,
17-
attachmentMiddleware,
18-
renderMarkdown,
19-
styleOptions,
20-
styleSet,
21-
...otherProps
22-
}) => {
9+
const FullReactWebChat = props => {
10+
const { adaptiveCardHostConfig, adaptiveCardsHostConfig, adaptiveCardsPackage, ...otherProps } = props;
11+
2312
useEffect(() => {
2413
adaptiveCardHostConfig &&
2514
console.warn(
2615
'Web Chat: "adaptiveCardHostConfig" is deprecated. Please use "adaptiveCardsHostConfig" instead. "adaptiveCardHostConfig" will be removed on or after 2022-01-01.'
2716
);
2817
}, [adaptiveCardHostConfig]);
2918

30-
const patchedStyleSet = useMemo(() => styleSet || createStyleSet(styleOptions), [styleOptions, styleSet]);
31-
const { options: patchedStyleOptions } = patchedStyleSet;
32-
33-
const patchedAdaptiveCardsHostConfig = useMemo(
34-
() => adaptiveCardsHostConfig || adaptiveCardHostConfig || createDefaultAdaptiveCardHostConfig(patchedStyleOptions),
35-
[adaptiveCardHostConfig, adaptiveCardsHostConfig, patchedStyleOptions]
36-
);
37-
38-
const patchedAdaptiveCardsPackage = useMemo(() => adaptiveCardsPackage || defaultAdaptiveCardsPackage, [
39-
adaptiveCardsPackage
40-
]);
41-
42-
const patchedRenderMarkdown = useMemo(
43-
() => renderMarkdown || (markdown => defaultRenderMarkdown(markdown, patchedStyleOptions)),
44-
[renderMarkdown, patchedStyleOptions]
45-
);
46-
47-
const patchedAttachmentMiddleware = useMemo(
48-
() => concatMiddleware(attachmentMiddleware, createAdaptiveCardsAttachmentMiddleware()),
49-
[attachmentMiddleware]
50-
);
51-
52-
const adaptiveCardsContext = useMemo(
53-
() => ({
54-
adaptiveCardsPackage: patchedAdaptiveCardsPackage,
55-
hostConfig: patchedAdaptiveCardsHostConfig
56-
}),
57-
[patchedAdaptiveCardsHostConfig, patchedAdaptiveCardsPackage]
58-
);
19+
const composerProps = useComposerProps(props);
5920

6021
return (
61-
<AdaptiveCardsContext.Provider value={adaptiveCardsContext}>
62-
<BasicWebChat
63-
attachmentMiddleware={patchedAttachmentMiddleware}
64-
renderMarkdown={patchedRenderMarkdown}
65-
styleOptions={styleOptions}
66-
styleSet={patchedStyleSet}
67-
{...otherProps}
68-
/>
69-
</AdaptiveCardsContext.Provider>
22+
<AdaptiveCardsComposer
23+
adaptiveCardsHostConfig={adaptiveCardHostConfig || adaptiveCardsHostConfig}
24+
adaptiveCardsPackage={adaptiveCardsPackage}
25+
>
26+
<BasicWebChat {...otherProps} {...composerProps} />
27+
</AdaptiveCardsComposer>
7028
);
7129
};
7230

7331
FullReactWebChat.defaultProps = {
32+
...BasicWebChat.defaultProps,
7433
adaptiveCardHostConfig: undefined,
7534
adaptiveCardsHostConfig: undefined,
7635
adaptiveCardsPackage: undefined,
77-
attachmentMiddleware: undefined,
78-
renderMarkdown: undefined,
79-
styleOptions: undefined,
80-
styleSet: undefined
36+
renderMarkdown: undefined
8137
};
8238

8339
FullReactWebChat.propTypes = {
40+
...BasicWebChat.propTypes,
8441
adaptiveCardHostConfig: PropTypes.any,
8542
adaptiveCardsHostConfig: PropTypes.any,
8643
adaptiveCardsPackage: PropTypes.any,
87-
attachmentMiddleware: PropTypes.func,
88-
renderMarkdown: PropTypes.func,
89-
styleOptions: PropTypes.any,
90-
styleSet: PropTypes.any
44+
renderMarkdown: PropTypes.func
9145
};
9246

9347
export default FullReactWebChat;
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import * as defaultAdaptiveCardsPackage from 'adaptivecards';
2+
import PropTypes from 'prop-types';
3+
import React, { useMemo } from 'react';
4+
5+
import AdaptiveCardsContext from './AdaptiveCardsContext';
6+
7+
const AdaptiveCardsComposer = ({ adaptiveCardsHostConfig, adaptiveCardsPackage, children }) => {
8+
const patchedAdaptiveCardsPackage = useMemo(() => adaptiveCardsPackage || defaultAdaptiveCardsPackage, [
9+
adaptiveCardsPackage
10+
]);
11+
12+
const adaptiveCardsContext = useMemo(
13+
() => ({
14+
adaptiveCardsPackage: patchedAdaptiveCardsPackage,
15+
hostConfigFromProps: adaptiveCardsHostConfig
16+
}),
17+
[adaptiveCardsHostConfig, patchedAdaptiveCardsPackage]
18+
);
19+
20+
return <AdaptiveCardsContext.Provider value={adaptiveCardsContext}>{children}</AdaptiveCardsContext.Provider>;
21+
};
22+
23+
AdaptiveCardsComposer.defaultProps = {
24+
adaptiveCardsHostConfig: undefined,
25+
adaptiveCardsPackage: undefined,
26+
children: undefined
27+
};
28+
29+
AdaptiveCardsComposer.propTypes = {
30+
adaptiveCardsHostConfig: PropTypes.any,
31+
adaptiveCardsPackage: PropTypes.any,
32+
children: PropTypes.any
33+
};
34+
35+
export default AdaptiveCardsComposer;
Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
import { createContext } from 'react';
22

3-
const AdaptiveCardHostConfigContext = createContext({
4-
adaptiveCardsPackage: undefined,
5-
hostConfig: undefined
6-
});
3+
const AdaptiveCardHostConfigContext = createContext();
74

85
export default AdaptiveCardHostConfigContext;

packages/bundle/src/adaptiveCards/Attachment/HeroCardAttachment.js

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,6 @@ HeroCardAttachment.propTypes = {
3232
content: PropTypes.shape({
3333
tap: PropTypes.any
3434
}).isRequired
35-
}).isRequired,
36-
styleSet: PropTypes.shape({
37-
options: PropTypes.any.isRequired
3835
}).isRequired
3936
};
4037

packages/bundle/src/adaptiveCards/Styles/createStyleSetWithAdaptiveCards.js renamed to packages/bundle/src/adaptiveCards/Styles/createAdaptiveCardsStyleSet.js

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { createStyleSet as createBasicStyleSet, defaultStyleOptions } from 'botframework-webchat-component';
1+
import { defaultStyleOptions } from 'botframework-webchat-component';
2+
23
import createAdaptiveCardRendererStyle from './StyleSet/AdaptiveCardRenderer';
34
import createAnimationCardAttachmentStyle from './StyleSet/AnimationCardAttachment';
45
import createAudioCardAttachmentStyle from './StyleSet/AudioCardAttachment';
@@ -7,15 +8,10 @@ import createAudioCardAttachmentStyle from './StyleSet/AudioCardAttachment';
78
// "styleSet" is actually CSS stylesheet and it is based on the DOM tree.
89
// DOM tree may change from time to time, thus, maintaining "styleSet" becomes a constant effort.
910

10-
export default function createStyleSet(options) {
11+
export default function createAdaptiveCardsStyleSet(options) {
1112
options = { ...defaultStyleOptions, ...options };
1213

13-
const basicStyleSet = createBasicStyleSet(options);
14-
15-
// Keep this list flat (no nested style) and serializable (no functions)
16-
1714
return {
18-
...basicStyleSet,
1915
adaptiveCardRenderer: createAdaptiveCardRendererStyle(options),
2016
animationCardAttachment: createAnimationCardAttachmentStyle(options),
2117
audioCardAttachment: createAudioCardAttachmentStyle(options)

packages/bundle/src/adaptiveCards/Styles/createStyleSetWithAdaptiveCards.spec.js renamed to packages/bundle/src/adaptiveCards/Styles/createAdaptiveCardsStyleSet.spec.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import createStyleSet from './createStyleSetWithAdaptiveCards';
1+
import createStyleSet from './createAdaptiveCardsStyleSet';
22

3-
describe('createStyleSetWithAdaptiveCards', () => {
3+
describe('createAdaptiveCardsStyleSet', () => {
44
it('should contain Adaptive Card styles in createStyleSet', () => {
55
const { adaptiveCardRenderer, animationCardAttachment, audioCardAttachment } = createStyleSet();
66

packages/bundle/src/adaptiveCards/createAdaptiveCardMiddleware.js renamed to packages/bundle/src/adaptiveCards/createAdaptiveCardsAttachmentMiddleware.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@ import SignInCardAttachment from './Attachment/SignInCardAttachment';
1111
import ThumbnailCardAttachment from './Attachment/ThumbnailCardAttachment';
1212
import VideoCardAttachment from './Attachment/VideoCardAttachment';
1313

14-
// TODO: [P4] Rename this file or the whole middleware, it looks either too simple or too comprehensive now
15-
export default function createAdaptiveCardMiddleware() {
14+
export default function createAdaptiveCardsAttachmentMiddleware() {
1615
return () => next => {
1716
function AdaptiveCardMiddleware({ activity, attachment }) {
1817
return attachment.contentType === 'application/vnd.microsoft.card.hero' ? (
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { useContext } from 'react';
2+
3+
import AdaptiveCardsContext from '../../AdaptiveCardsContext';
4+
5+
export default function useAdaptiveCardsContext() {
6+
const context = useContext(AdaptiveCardsContext);
7+
8+
if (!context) {
9+
throw new Error('This hook can only be used on component that is decendants of <ComposerWithAdaptiveCards>');
10+
}
11+
12+
return context;
13+
}

0 commit comments

Comments
 (0)