Skip to content

Commit 0f28670

Browse files
authored
Fix typings for FullChatComposer (#5580)
* fix typings for fullcomposer * address PR comment and add changelog
1 parent 47373eb commit 0f28670

File tree

5 files changed

+78
-5
lines changed

5 files changed

+78
-5
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,8 @@ Notes: web developers are advised to use [`~` (tilde range)](https://github.com/
303303
- Fixed aria-label only announcing placeholder in feedback form, in PR [#5567](https://github.com/microsoft/BotFramework-WebChat/pull/5567)
304304
- Fixed placing focus on the code block content, so it is possible to scroll code via keyboard, in PR [#5575](https://github.com/microsoft/BotFramework-WebChat/pull/5575), by [@OEvgeny](https://github.com/OEvgeny)
305305
- Fixed [#5581](https://github.com/microsoft/BotFramework-WebChat/issues/5581). Activities should be displayed after upgrading via `npm install`, in PR [#5582](https://github.com/microsoft/BotFramework-WebChat/pull/5582), by [@compulim](https://github.com/compulim)
306+
- Fixed Composer props types not resolving correctly in React 16 in PR [#5580](https://github.com/microsoft/BotFramework-WebChat/pull/5580),
307+
by [@lexi-taylor](https://github.com/lexi-taylor)
306308

307309
### Removed
308310

packages/bundle/src/AddFullBundle.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,14 @@ import { type AdaptiveCardsPackage } from './types/AdaptiveCardsPackage';
1414
import { type StrictFullBundleStyleOptions } from './types/FullBundleStyleOptions';
1515
import useComposerProps from './useComposerProps';
1616

17+
type AddFullBundleChildren = ({ extraStyleSet }: { extraStyleSet: any }) => ReactNode;
18+
1719
type AddFullBundleProps = Readonly<{
1820
adaptiveCardsHostConfig?: any;
1921
adaptiveCardsPackage?: AdaptiveCardsPackage;
2022
attachmentForScreenReaderMiddleware?: OneOrMany<AttachmentForScreenReaderMiddleware>;
2123
attachmentMiddleware?: OneOrMany<AttachmentMiddleware>;
22-
children: ({ extraStyleSet }: { extraStyleSet: any }) => ReactNode;
24+
children: AddFullBundleChildren;
2325
htmlContentTransformMiddleware?: HTMLContentTransformMiddleware[];
2426
renderMarkdown?: (
2527
markdown: string,
@@ -74,4 +76,4 @@ function AddFullBundle({
7476

7577
export default memo(AddFullBundle);
7678

77-
export type { AddFullBundleProps };
79+
export type { AddFullBundleProps, AddFullBundleChildren };

packages/bundle/src/FullComposer.tsx

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,20 @@
11
import { Components, type ComposerProps } from 'botframework-webchat-component';
22
import PropTypes from 'prop-types';
33
import React from 'react';
4-
5-
import AddFullBundle, { type AddFullBundleProps } from './AddFullBundle';
4+
import AddFullBundle, { type AddFullBundleProps, type AddFullBundleChildren } from './AddFullBundle';
65

76
const { Composer } = Components;
87

9-
type FullComposerProps = ComposerProps & AddFullBundleProps;
8+
type BaseFullComposerProps = ComposerProps & AddFullBundleProps;
9+
10+
type ComposerPropsChildren = ComposerProps['children'];
11+
12+
/* The props of FullComposer are the union of Composer and AddFullBundle, except "children".
13+
* The union type of ComposerProps and AddFullBundleProps was not resolving correctly, so manually constructing the type here.
14+
*/
15+
type FullComposerProps = Omit<BaseFullComposerProps, 'children'> & {
16+
children?: ComposerPropsChildren | AddFullBundleChildren;
17+
};
1018

1119
const FullComposer = (props: FullComposerProps) => (
1220
<AddFullBundle {...props}>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import '../setup';
2+
3+
import { expectNotAssignable } from 'tsd';
4+
import { type FullComposerProps } from '../../src/FullComposer';
5+
6+
// Negative test: `directLine` is required in FullComposerProps.
7+
// An empty object should not satisfy FullComposerProps.
8+
9+
expectNotAssignable<FullComposerProps>({});
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import '../setup';
2+
3+
import React from 'react';
4+
import { expectAssignable } from 'tsd';
5+
6+
import { type FullComposerProps } from '../../src/FullComposer';
7+
import { type ComposerProps } from 'botframework-webchat-component';
8+
import { Components } from 'botframework-webchat-component';
9+
10+
type ComposerCoreChildrenRenderProp = ComposerProps['children'];
11+
12+
// We want to assert that `children` on FullComposerProps accepts:
13+
// 1. React.ReactNode
14+
// 2. ComposerCoreChildrenRenderProp
15+
// 3. AddFullBundleChildren (({ extraStyleSet }: { extraStyleSet: any }) => React.ReactNode)
16+
// and is optional.
17+
18+
// Helper asserting assignability.
19+
const expectProps = <T extends FullComposerProps>(props: T) => expectAssignable<FullComposerProps>(props);
20+
21+
// Minimal required props: we must supply a `directLine` from ComposerProps.
22+
// Using a minimal mock for `directLine` which satisfies DirectLineJSBotConnection shape needed for types only.
23+
const mockDirectLine: any = {
24+
activity$: { subscribe: () => ({ unsubscribe: () => undefined }) },
25+
connectionStatus$: { subscribe: () => ({ unsubscribe: () => undefined }) },
26+
postActivity: () => ({ subscribe: () => ({ unsubscribe: () => undefined }) })
27+
};
28+
29+
// 1. Without children (children optional)
30+
expectProps({ directLine: mockDirectLine });
31+
32+
// 2. With ReactNode child
33+
expectProps({ directLine: mockDirectLine, children: <div /> });
34+
35+
// 3. With ComposerCoreChildrenRenderProp child
36+
// The API context type is opaque here; we just confirm it is callable.
37+
const composerCoreChildren: ComposerCoreChildrenRenderProp = () => <div />;
38+
expectProps({ directLine: mockDirectLine, children: composerCoreChildren });
39+
40+
// 4. With AddFullBundleChildren child (takes { extraStyleSet })
41+
const addFullBundleChildren = ({ extraStyleSet }: { extraStyleSet: any }) => <div>{String(!!extraStyleSet)}</div>;
42+
expectProps({ directLine: mockDirectLine, children: addFullBundleChildren });
43+
44+
// Also ensure baseline Composer (from Components) still type checks for overlapping accepted children.
45+
const { Composer } = Components;
46+
const _c1 = <Composer directLine={mockDirectLine} />;
47+
const _c2 = <Composer directLine={mockDirectLine}>{composerCoreChildren}</Composer>;
48+
const _c3 = (
49+
<Composer directLine={mockDirectLine}>
50+
<div />
51+
</Composer>
52+
);

0 commit comments

Comments
 (0)