Skip to content

Commit 60bded3

Browse files
authored
Stablize Caption Banner component (#5460)
* caption banner component stablize * Change files * linter
1 parent 815fff8 commit 60bded3

19 files changed

Lines changed: 178 additions & 61 deletions

File tree

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"type": "prerelease",
3+
"area": "feature",
4+
"workstream": "Captions",
5+
"comment": "Stablize Captions Banner Component",
6+
"packageName": "@azure/communication-react",
7+
"email": "96077406+carocao-msft@users.noreply.github.com",
8+
"dependentChangeType": "patch"
9+
}

packages/calling-component-bindings/src/captionsSelector.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import {
1919
} from './baseSelectors';
2020
import * as reselect from 'reselect';
2121
import { toFlatCommunicationIdentifier } from '@internal/acs-ui-common';
22-
import { _CaptionsInfo, _SupportedCaptionLanguage, _SupportedSpokenLanguage } from '@internal/react-components';
22+
import { CaptionsInformation, _SupportedCaptionLanguage, _SupportedSpokenLanguage } from '@internal/react-components';
2323

2424
/**
2525
* Selector type for the {@link StartCaptionsButton} component.
@@ -96,22 +96,22 @@ export const _captionSettingsSelector: _CaptionSettingsSelector = reselect.creat
9696
);
9797
/**
9898
* Selector type for the {@link CaptionsBanner} component.
99-
* @internal
99+
* @public
100100
*/
101-
export type _CaptionsBannerSelector = (
101+
export type CaptionsBannerSelector = (
102102
state: CallClientState,
103103
props: CallingBaseSelectorProps
104104
) => {
105-
captions: _CaptionsInfo[];
105+
captions: CaptionsInformation[];
106106
isCaptionsOn: boolean;
107107
};
108108

109109
/**
110110
* Selector for {@link CaptionsBanner} component.
111111
*
112-
* @internal
112+
* @public
113113
*/
114-
export const _captionsBannerSelector: _CaptionsBannerSelector = reselect.createSelector(
114+
export const captionsBannerSelector: CaptionsBannerSelector = reselect.createSelector(
115115
[getCaptions, getCaptionsStatus, getStartCaptionsInProgress, getRemoteParticipants, getDisplayName, getIdentifier],
116116
(captions, isCaptionsFeatureActive, startCaptionsInProgress, remoteParticipants, displayName, identifier) => {
117117
const captionsInfo = captions?.map((c, index) => {

packages/calling-component-bindings/src/hooks/usePropsFor.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ import {
99
DevicesButton,
1010
ParticipantList,
1111
ScreenShareButton,
12-
VideoGallery
12+
VideoGallery,
13+
CaptionsBanner
1314
} from '@internal/react-components';
1415
import { IncomingCallStack } from '@internal/react-components';
1516

@@ -45,6 +46,7 @@ import { ReactionButton } from '@internal/react-components';
4546
import { _ComponentCallingHandlers } from '../handlers/createHandlers';
4647
import { notificationStackSelector, NotificationStackSelector } from '../notificationStackSelector';
4748
import { incomingCallStackSelector, IncomingCallStackSelector } from '../incomingCallStackSelector';
49+
import { captionsBannerSelector } from '../captionsSelector';
4850

4951
/**
5052
* Primary hook to get all hooks necessary for a calling Component.
@@ -126,7 +128,9 @@ export type GetSelector<Component extends (props: any) => JSX.Element | undefine
126128
? RaiseHandButtonSelector
127129
: AreEqual<Component, typeof RaiseHandButton> extends true
128130
? EmptySelector
129-
: undefined;
131+
: AreEqual<Component, typeof CaptionsBanner> extends true
132+
? EmptySelector
133+
: undefined;
130134

131135
/**
132136
* Get the selector for a specified component.
@@ -178,6 +182,8 @@ const findSelector = (component: (props: any) => JSX.Element | undefined): any =
178182
return holdButtonSelector;
179183
case IncomingCallStack:
180184
return incomingCallStackSelector;
185+
case CaptionsBanner:
186+
return captionsBannerSelector;
181187
}
182188
return undefined;
183189
};

packages/calling-component-bindings/src/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@ export { incomingCallStackSelector } from './incomingCallStackSelector';
2121
export type {
2222
_StartCaptionsButtonSelector,
2323
_CaptionSettingsSelector,
24-
_CaptionsBannerSelector
24+
CaptionsBannerSelector
2525
} from './captionsSelector';
2626

27-
export { _captionsBannerSelector, _startCaptionsButtonSelector, _captionSettingsSelector } from './captionsSelector';
27+
export { captionsBannerSelector, _startCaptionsButtonSelector, _captionSettingsSelector } from './captionsSelector';
2828

2929
export type { CallingHandlers, CreateDefaultCallingHandlers } from './handlers/createHandlers';
3030

packages/communication-react/review/beta/communication-react.api.md

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1814,6 +1814,27 @@ export interface CaptionLanguageStrings {
18141814
vi: string;
18151815
}
18161816

1817+
// @public
1818+
export const CaptionsBanner: (props: CaptionsBannerProps) => JSX.Element;
1819+
1820+
// @public
1821+
export interface CaptionsBannerProps {
1822+
captions: CaptionsInformation[];
1823+
captionsOptions?: {
1824+
height: 'full' | 'default';
1825+
};
1826+
formFactor?: 'default' | 'compact';
1827+
isCaptionsOn?: boolean;
1828+
onRenderAvatar?: OnRenderAvatarCallback;
1829+
startCaptionsInProgress?: boolean;
1830+
strings?: CaptionsBannerStrings;
1831+
}
1832+
1833+
// @public
1834+
export interface CaptionsBannerStrings {
1835+
captionsBannerSpinnerText?: string;
1836+
}
1837+
18171838
// @public (undocumented)
18181839
export interface CaptionsCallFeatureState {
18191840
captions: CaptionsInfo[];
@@ -1837,6 +1858,14 @@ export interface CaptionsInfo {
18371858
timestamp: Date;
18381859
}
18391860

1861+
// @public
1862+
export type CaptionsInformation = {
1863+
id: string;
1864+
displayName: string;
1865+
captionText: string;
1866+
userId?: string;
1867+
};
1868+
18401869
// @public
18411870
export type CaptionsOptions = {
18421871
spokenLanguage: string;
@@ -2430,6 +2459,7 @@ export interface ComponentStrings {
24302459
CameraSitePermissionsDenied: SitePermissionsStrings;
24312460
CameraSitePermissionsDeniedSafari: SitePermissionsStrings;
24322461
CameraSitePermissionsRequest: SitePermissionsStrings;
2462+
captionsBanner: CaptionsBannerStrings;
24332463
devicesButton: DevicesButtonStrings;
24342464
dialpad: DialpadStrings;
24352465
endCallButton: EndCallButtonStrings;
@@ -3287,7 +3317,7 @@ export interface FluentThemeProviderProps {
32873317
export const fromFlatCommunicationIdentifier: (id: string) => CommunicationIdentifier;
32883318

32893319
// @public
3290-
export type GetCallingSelector<Component extends (props: any) => JSX.Element | undefined> = AreEqual<Component, typeof VideoGallery> extends true ? VideoGallerySelector : AreEqual<Component, typeof DevicesButton> extends true ? DevicesButtonSelector : AreEqual<Component, typeof MicrophoneButton> extends true ? MicrophoneButtonSelector : AreEqual<Component, typeof CameraButton> extends true ? CameraButtonSelector : AreEqual<Component, typeof ScreenShareButton> extends true ? ScreenShareButtonSelector : AreEqual<Component, typeof ParticipantList> extends true ? ParticipantListSelector : AreEqual<Component, typeof ParticipantsButton> extends true ? ParticipantsButtonSelector : AreEqual<Component, typeof EndCallButton> extends true ? EmptySelector : AreEqual<Component, typeof ErrorBar> extends true ? CallErrorBarSelector : AreEqual<Component, typeof Dialpad> extends true ? EmptySelector : AreEqual<Component, typeof HoldButton> extends true ? HoldButtonSelector : AreEqual<Component, typeof NotificationStack> extends true ? NotificationStackSelector : AreEqual<Component, typeof IncomingCallStack> extends true ? IncomingCallStackSelector : AreEqual<Component, typeof ReactionButton> extends true ? RaiseHandButtonSelector : AreEqual<Component, typeof RaiseHandButton> extends true ? EmptySelector : undefined;
3320+
export type GetCallingSelector<Component extends (props: any) => JSX.Element | undefined> = AreEqual<Component, typeof VideoGallery> extends true ? VideoGallerySelector : AreEqual<Component, typeof DevicesButton> extends true ? DevicesButtonSelector : AreEqual<Component, typeof MicrophoneButton> extends true ? MicrophoneButtonSelector : AreEqual<Component, typeof CameraButton> extends true ? CameraButtonSelector : AreEqual<Component, typeof ScreenShareButton> extends true ? ScreenShareButtonSelector : AreEqual<Component, typeof ParticipantList> extends true ? ParticipantListSelector : AreEqual<Component, typeof ParticipantsButton> extends true ? ParticipantsButtonSelector : AreEqual<Component, typeof EndCallButton> extends true ? EmptySelector : AreEqual<Component, typeof ErrorBar> extends true ? CallErrorBarSelector : AreEqual<Component, typeof Dialpad> extends true ? EmptySelector : AreEqual<Component, typeof HoldButton> extends true ? HoldButtonSelector : AreEqual<Component, typeof NotificationStack> extends true ? NotificationStackSelector : AreEqual<Component, typeof IncomingCallStack> extends true ? IncomingCallStackSelector : AreEqual<Component, typeof ReactionButton> extends true ? RaiseHandButtonSelector : AreEqual<Component, typeof RaiseHandButton> extends true ? EmptySelector : AreEqual<Component, typeof CaptionsBanner> extends true ? EmptySelector : undefined;
32913321

32923322
// @public
32933323
export const getCallingSelector: <Component extends (props: any) => JSX.Element | undefined>(component: Component) => GetCallingSelector<Component>;

packages/communication-react/review/stable/communication-react.api.md

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1524,6 +1524,27 @@ export interface CaptionLanguageStrings {
15241524
vi: string;
15251525
}
15261526

1527+
// @public
1528+
export const CaptionsBanner: (props: CaptionsBannerProps) => JSX.Element;
1529+
1530+
// @public
1531+
export interface CaptionsBannerProps {
1532+
captions: CaptionsInformation[];
1533+
captionsOptions?: {
1534+
height: 'full' | 'default';
1535+
};
1536+
formFactor?: 'default' | 'compact';
1537+
isCaptionsOn?: boolean;
1538+
onRenderAvatar?: OnRenderAvatarCallback;
1539+
startCaptionsInProgress?: boolean;
1540+
strings?: CaptionsBannerStrings;
1541+
}
1542+
1543+
// @public
1544+
export interface CaptionsBannerStrings {
1545+
captionsBannerSpinnerText?: string;
1546+
}
1547+
15271548
// @public (undocumented)
15281549
export interface CaptionsCallFeatureState {
15291550
captions: CaptionsInfo[];
@@ -1547,6 +1568,14 @@ export interface CaptionsInfo {
15471568
timestamp: Date;
15481569
}
15491570

1571+
// @public
1572+
export type CaptionsInformation = {
1573+
id: string;
1574+
displayName: string;
1575+
captionText: string;
1576+
userId?: string;
1577+
};
1578+
15501579
// @public
15511580
export type CaptionsOptions = {
15521581
spokenLanguage: string;
@@ -2073,6 +2102,7 @@ export type ComponentSlotStyle = Omit<IRawStyle, 'animation'>;
20732102
// @public
20742103
export interface ComponentStrings {
20752104
cameraButton: CameraButtonStrings;
2105+
captionsBanner: CaptionsBannerStrings;
20762106
devicesButton: DevicesButtonStrings;
20772107
dialpad: DialpadStrings;
20782108
endCallButton: EndCallButtonStrings;
@@ -2846,7 +2876,7 @@ export interface FluentThemeProviderProps {
28462876
export const fromFlatCommunicationIdentifier: (id: string) => CommunicationIdentifier;
28472877

28482878
// @public
2849-
export type GetCallingSelector<Component extends (props: any) => JSX.Element | undefined> = AreEqual<Component, typeof VideoGallery> extends true ? VideoGallerySelector : AreEqual<Component, typeof DevicesButton> extends true ? DevicesButtonSelector : AreEqual<Component, typeof MicrophoneButton> extends true ? MicrophoneButtonSelector : AreEqual<Component, typeof CameraButton> extends true ? CameraButtonSelector : AreEqual<Component, typeof ScreenShareButton> extends true ? ScreenShareButtonSelector : AreEqual<Component, typeof ParticipantList> extends true ? ParticipantListSelector : AreEqual<Component, typeof ParticipantsButton> extends true ? ParticipantsButtonSelector : AreEqual<Component, typeof EndCallButton> extends true ? EmptySelector : AreEqual<Component, typeof ErrorBar> extends true ? CallErrorBarSelector : AreEqual<Component, typeof Dialpad> extends true ? EmptySelector : AreEqual<Component, typeof HoldButton> extends true ? HoldButtonSelector : AreEqual<Component, typeof NotificationStack> extends true ? NotificationStackSelector : AreEqual<Component, typeof IncomingCallStack> extends true ? IncomingCallStackSelector : AreEqual<Component, typeof ReactionButton> extends true ? RaiseHandButtonSelector : AreEqual<Component, typeof RaiseHandButton> extends true ? EmptySelector : undefined;
2879+
export type GetCallingSelector<Component extends (props: any) => JSX.Element | undefined> = AreEqual<Component, typeof VideoGallery> extends true ? VideoGallerySelector : AreEqual<Component, typeof DevicesButton> extends true ? DevicesButtonSelector : AreEqual<Component, typeof MicrophoneButton> extends true ? MicrophoneButtonSelector : AreEqual<Component, typeof CameraButton> extends true ? CameraButtonSelector : AreEqual<Component, typeof ScreenShareButton> extends true ? ScreenShareButtonSelector : AreEqual<Component, typeof ParticipantList> extends true ? ParticipantListSelector : AreEqual<Component, typeof ParticipantsButton> extends true ? ParticipantsButtonSelector : AreEqual<Component, typeof EndCallButton> extends true ? EmptySelector : AreEqual<Component, typeof ErrorBar> extends true ? CallErrorBarSelector : AreEqual<Component, typeof Dialpad> extends true ? EmptySelector : AreEqual<Component, typeof HoldButton> extends true ? HoldButtonSelector : AreEqual<Component, typeof NotificationStack> extends true ? NotificationStackSelector : AreEqual<Component, typeof IncomingCallStack> extends true ? IncomingCallStackSelector : AreEqual<Component, typeof ReactionButton> extends true ? RaiseHandButtonSelector : AreEqual<Component, typeof RaiseHandButton> extends true ? EmptySelector : AreEqual<Component, typeof CaptionsBanner> extends true ? EmptySelector : undefined;
28502880

28512881
// @public
28522882
export const getCallingSelector: <Component extends (props: any) => JSX.Element | undefined>(component: Component) => GetCallingSelector<Component>;

packages/communication-react/src/index.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,3 +460,9 @@ export type { RealTimeTextProps, RealTimeTextStrings } from '../../react-compone
460460
export { RealTimeText } from '../../react-components/src/components/RealTimeText';
461461
/* @conditional-compile-remove(media-access) */
462462
export type { MediaAccess } from '../../react-components/src';
463+
export type {
464+
CaptionsBannerProps,
465+
CaptionsInformation,
466+
CaptionsBannerStrings
467+
} from '../../react-components/src/components/CaptionsBanner';
468+
export { CaptionsBanner } from '../../react-components/src/components/CaptionsBanner';

packages/react-components/src/components/Caption.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@ import {
1111
displayNameContainerClassName,
1212
iconClassName
1313
} from './styles/Captions.style';
14-
import { _CaptionsInfo } from './CaptionsBanner';
14+
import { CaptionsInformation } from './CaptionsBanner';
1515

1616
/**
1717
* @internal
1818
* Props for a single line of caption.
1919
*/
20-
export interface _CaptionProps extends _CaptionsInfo {
20+
export interface _CaptionProps extends CaptionsInformation {
2121
/**
2222
* Optional callback to override render of the avatar.
2323
*

packages/react-components/src/components/CaptionsBanner.tsx

Lines changed: 45 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,46 +12,78 @@ import {
1212
loadingBannerStyles
1313
} from './styles/Captions.style';
1414
import { OnRenderAvatarCallback } from '../types';
15+
import { useLocale } from '../localization';
1516

1617
/**
17-
* @internal
18+
* @public
1819
* information required for each line of caption
1920
*/
20-
export type _CaptionsInfo = {
21+
export type CaptionsInformation = {
22+
/**
23+
* unique id for each caption
24+
*/
2125
id: string;
26+
/**
27+
* speaker's display name
28+
*/
2229
displayName: string;
30+
/**
31+
* content of the caption
32+
*/
2333
captionText: string;
34+
/**
35+
* id of the speaker
36+
*/
2437
userId?: string;
2538
};
2639

2740
/**
28-
* @internal
41+
* @public
2942
* strings for captions banner
3043
*/
31-
export interface _CaptionsBannerStrings {
44+
export interface CaptionsBannerStrings {
45+
/**
46+
* Spinner text for captions banner
47+
*/
3248
captionsBannerSpinnerText?: string;
3349
}
3450

3551
/**
36-
* @internal
37-
* _CaptionsBanner Component Props.
52+
* @public
53+
* CaptionsBanner Component Props.
3854
*/
39-
export interface _CaptionsBannerProps {
40-
captions: _CaptionsInfo[];
55+
export interface CaptionsBannerProps {
56+
/**
57+
* Array of captions to be displayed
58+
*/
59+
captions: CaptionsInformation[];
60+
/**
61+
* Flag to indicate if captions are on
62+
*/
4163
isCaptionsOn?: boolean;
64+
/**
65+
* Flag to indicate if captions are being started
66+
* This is used to show spinner while captions are being started
67+
*/
4268
startCaptionsInProgress?: boolean;
4369
/**
4470
* Optional callback to override render of the avatar.
4571
*
4672
* @param userId - user Id
4773
*/
4874
onRenderAvatar?: OnRenderAvatarCallback;
49-
strings?: _CaptionsBannerStrings;
75+
/**
76+
* Optional strings for the component
77+
*/
78+
strings?: CaptionsBannerStrings;
5079
/**
5180
* Optional form factor for the component.
5281
* @defaultValue 'default'
5382
*/
5483
formFactor?: 'default' | 'compact';
84+
/**
85+
* Optional options for the component.
86+
*/
5587
captionsOptions?: {
5688
height: 'full' | 'default';
5789
};
@@ -60,19 +92,20 @@ export interface _CaptionsBannerProps {
6092
const SCROLL_OFFSET_ALLOWANCE = 20;
6193

6294
/**
63-
* @internal
95+
* @public
6496
* A component for displaying a CaptionsBanner with user icon, displayName and captions text.
6597
*/
66-
export const _CaptionsBanner = (props: _CaptionsBannerProps): JSX.Element => {
98+
export const CaptionsBanner = (props: CaptionsBannerProps): JSX.Element => {
6799
const {
68100
captions,
69101
isCaptionsOn,
70102
startCaptionsInProgress,
71103
onRenderAvatar,
72-
strings,
73104
formFactor = 'default',
74105
captionsOptions
75106
} = props;
107+
const localeStrings = useLocale().strings.captionsBanner;
108+
const strings = { ...localeStrings, ...props.strings };
76109
const captionsScrollDivRef = useRef<HTMLUListElement>(null);
77110
const [isAtBottomOfScroll, setIsAtBottomOfScroll] = useState<boolean>(true);
78111
const theme = useTheme();

packages/react-components/src/components/RealTimeText.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@ import {
1717
rttContainerClassName
1818
} from './styles/Captions.style';
1919
/* @conditional-compile-remove(rtt) */
20-
import { _CaptionsInfo } from './CaptionsBanner';
21-
/* @conditional-compile-remove(rtt) */
2220
import { useLocale } from '../localization';
2321

2422
/* @conditional-compile-remove(rtt) */

0 commit comments

Comments
 (0)