Skip to content

Commit 76a858a

Browse files
authored
[Chat] Announce File Attachments in New Messages (#4438)
1 parent ded48cf commit 76a858a

4 files changed

Lines changed: 67 additions & 11 deletions

File tree

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"type": "patch",
3+
"area": "fix",
4+
"workstream": "File Sharing",
5+
"comment": "Add Chat Attachments in Live Messages",
6+
"packageName": "@azure/communication-react",
7+
"email": "109105353+jpeng-ms@users.noreply.github.com",
8+
"dependentChangeType": "patch"
9+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"type": "patch",
3+
"area": "fix",
4+
"workstream": "File Sharing",
5+
"comment": "Add Chat Attachments in Live Messages",
6+
"packageName": "@azure/communication-react",
7+
"email": "109105353+jpeng-ms@users.noreply.github.com",
8+
"dependentChangeType": "patch"
9+
}

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

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import { useMemo } from 'react';
88
import { useLocale } from '../localization';
99
import { _AttachmentCard } from './AttachmentCard';
1010
import { _AttachmentCardGroup } from './AttachmentCardGroup';
11+
/* @conditional-compile-remove(attachment-download) */
12+
import { getAttachmentCountLiveMessage } from './ChatMessage/ChatMessageContent';
1113
import { _formatString } from '@internal/acs-ui-common';
1214
import { AttachmentMenuAction, AttachmentMetadata } from '../types/Attachment';
1315
import { ChatMessage } from '../types';
@@ -102,15 +104,12 @@ export const _AttachmentDownloadCards = (props: _AttachmentDownloadCardsProps):
102104

103105
const attachmentCardGroupDescription = useMemo(
104106
() => () => {
105-
const attachmentGroupLocaleString =
106-
props.strings?.attachmentCardGroupMessage ?? localeStrings.attachmentCardGroupMessage;
107-
/* @conditional-compile-remove(attachment-download) @conditional-compile-remove(attachment-upload) */
108-
return _formatString(attachmentGroupLocaleString, {
109-
attachmentCount: `${attachments?.length ?? 0}`
110-
});
111-
return _formatString(attachmentGroupLocaleString, {
112-
attachmentCount: `${attachments?.length ?? 0}`
113-
});
107+
/* @conditional-compile-remove(attachment-download) */
108+
return getAttachmentCountLiveMessage(
109+
attachments ?? [],
110+
props.strings?.attachmentCardGroupMessage ?? localeStrings.attachmentCardGroupMessage
111+
);
112+
return '';
114113
},
115114
[props.strings?.attachmentCardGroupMessage, localeStrings.attachmentCardGroupMessage, attachments]
116115
);

packages/react-components/src/components/ChatMessage/ChatMessageContent.tsx

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ import LiveMessage from '../Announcer/LiveMessage';
2020
/* @conditional-compile-remove(mention) */
2121
import { defaultOnMentionRender } from './MentionRenderer';
2222
import DOMPurify from 'dompurify';
23+
import { _AttachmentDownloadCardsStrings } from '../AttachmentDownloadCards';
24+
/* @conditional-compile-remove(attachment-download) */
25+
import { AttachmentMetadata } from '../../types';
2326

2427
type ChatMessageContentProps = {
2528
message: ChatMessage;
@@ -164,9 +167,12 @@ export const BlockedMessageContent = (props: BlockedMessageContentProps): JSX.El
164167
};
165168

166169
const extractContentForAllyMessage = (props: ChatMessageContentProps): string => {
167-
if (props.message.content) {
170+
let attachments = undefined;
171+
/* @conditional-compile-remove(attachment-download) */
172+
attachments = props.message.attachments;
173+
if (props.message.content || attachments) {
168174
// Replace all <img> tags with 'image' for aria.
169-
const parsedContent = DOMPurify.sanitize(props.message.content, {
175+
const parsedContent = DOMPurify.sanitize(props.message.content ?? '', {
170176
ALLOWED_TAGS: ['img'],
171177
RETURN_DOM_FRAGMENT: true
172178
});
@@ -180,6 +186,16 @@ const extractContentForAllyMessage = (props: ChatMessageContentProps): string =>
180186
parsedContent.replaceChild(imageTextNode, child);
181187
});
182188

189+
// Inject attachment names for aria.
190+
if (attachments) {
191+
let attachmentList = '';
192+
/* @conditional-compile-remove(attachment-download) */
193+
attachmentList = attachmentCardGroupDescription(props);
194+
const attachmentTextNode = document.createElement('div');
195+
attachmentTextNode.innerHTML = ` ${attachmentList} `;
196+
parsedContent.appendChild(attachmentTextNode);
197+
}
198+
183199
// Strip all html tags from the content for aria.
184200
const message = DOMPurify.sanitize(parsedContent, { ALLOWED_TAGS: [] });
185201
return message;
@@ -207,6 +223,29 @@ const messageContentAriaText = (props: ChatMessageContentProps): string | undefi
207223
});
208224
};
209225

226+
/* @conditional-compile-remove(attachment-download) */
227+
const attachmentCardGroupDescription = (props: ChatMessageContentProps): string => {
228+
const attachments = props.message.attachments;
229+
return getAttachmentCountLiveMessage(attachments ?? [], props.strings.attachmentCardGroupMessage);
230+
};
231+
232+
/* @conditional-compile-remove(attachment-download) */
233+
/**
234+
* @private
235+
*/
236+
export const getAttachmentCountLiveMessage = (
237+
attachments: AttachmentMetadata[],
238+
attachmentCardGroupMessage: string
239+
): string => {
240+
if (attachments.length === 0) {
241+
return '';
242+
}
243+
return _formatString(attachmentCardGroupMessage, {
244+
attachmentCount: `${attachments.length}`
245+
});
246+
return '';
247+
};
248+
210249
const defaultOnRenderInlineImage = (inlineImage: InlineImage): JSX.Element => {
211250
return (
212251
<img

0 commit comments

Comments
 (0)