@azure/communication-react 1.10.1-alpha-202311230013 → 1.10.1-alpha-202311240012
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/communication-react.d.ts +17 -14
- package/dist/dist-cjs/communication-react/index.js +1871 -1759
- package/dist/dist-cjs/communication-react/index.js.map +1 -1
- package/dist/dist-esm/acs-ui-common/src/telemetryVersion.js +1 -1
- package/dist/dist-esm/acs-ui-common/src/telemetryVersion.js.map +1 -1
- package/dist/dist-esm/react-components/src/components/ChatMessage/ChatMessageComponent.js +2 -2
- package/dist/dist-esm/react-components/src/components/ChatMessage/ChatMessageComponent.js.map +1 -1
- package/dist/dist-esm/react-components/src/components/ChatMessage/ChatMessageComponentAsMessageBubble.js +1 -1
- package/dist/dist-esm/react-components/src/components/ChatMessage/ChatMessageComponentAsMessageBubble.js.map +1 -1
- package/dist/dist-esm/react-components/src/components/ChatMessage/ChatMessageComponentWrapper.d.ts +46 -0
- package/dist/dist-esm/react-components/src/components/ChatMessage/ChatMessageComponentWrapper.js +53 -0
- package/dist/dist-esm/react-components/src/components/ChatMessage/ChatMessageComponentWrapper.js.map +1 -0
- package/dist/dist-esm/react-components/src/components/ChatMessage/ChatMessageContent.d.ts +1 -1
- package/dist/dist-esm/react-components/src/components/ChatMessage/ChatMessageContent.js +16 -10
- package/dist/dist-esm/react-components/src/components/ChatMessage/ChatMessageContent.js.map +1 -1
- package/dist/dist-esm/react-components/src/components/ChatMessage/DefaultSystemMessage.d.ts +6 -0
- package/dist/dist-esm/react-components/src/components/ChatMessage/DefaultSystemMessage.js +38 -0
- package/dist/dist-esm/react-components/src/components/ChatMessage/DefaultSystemMessage.js.map +1 -0
- package/dist/dist-esm/react-components/src/components/ChatMessage/FluentChatMessageComponentWrapper.d.ts +23 -0
- package/dist/dist-esm/react-components/src/components/ChatMessage/FluentChatMessageComponentWrapper.js +183 -0
- package/dist/dist-esm/react-components/src/components/ChatMessage/FluentChatMessageComponentWrapper.js.map +1 -0
- package/dist/dist-esm/react-components/src/components/MessageThread.d.ts +5 -7
- package/dist/dist-esm/react-components/src/components/MessageThread.js +92 -247
- package/dist/dist-esm/react-components/src/components/MessageThread.js.map +1 -1
- package/dist/dist-esm/react-components/src/components/VideoGallery/DefaultLayout.js +1 -3
- package/dist/dist-esm/react-components/src/components/VideoGallery/DefaultLayout.js.map +1 -1
- package/dist/dist-esm/react-components/src/components/VideoGallery/FloatingLocalVideoLayout.js +3 -2
- package/dist/dist-esm/react-components/src/components/VideoGallery/FloatingLocalVideoLayout.js.map +1 -1
- package/dist/dist-esm/react-components/src/components/VideoGallery/OverflowGallery.d.ts +0 -2
- package/dist/dist-esm/react-components/src/components/VideoGallery/OverflowGallery.js +5 -4
- package/dist/dist-esm/react-components/src/components/VideoGallery/OverflowGallery.js.map +1 -1
- package/dist/dist-esm/react-components/src/components/VideoGallery/SpeakerVideoLayout.js +3 -2
- package/dist/dist-esm/react-components/src/components/VideoGallery/SpeakerVideoLayout.js.map +1 -1
- package/dist/dist-esm/react-composites/src/composites/CallComposite/adapter/AzureCommunicationCallAdapter.d.ts +4 -7
- package/dist/dist-esm/react-composites/src/composites/CallComposite/adapter/AzureCommunicationCallAdapter.js +12 -4
- package/dist/dist-esm/react-composites/src/composites/CallComposite/adapter/AzureCommunicationCallAdapter.js.map +1 -1
- package/dist/dist-esm/react-composites/src/composites/CallComposite/adapter/CallAdapter.d.ts +14 -5
- package/dist/dist-esm/react-composites/src/composites/CallComposite/adapter/CallAdapter.js.map +1 -1
- package/dist/dist-esm/react-composites/src/composites/CallComposite/adapter/CallingSoundSubscriber.d.ts +3 -3
- package/dist/dist-esm/react-composites/src/composites/CallComposite/adapter/CallingSoundSubscriber.js +10 -13
- package/dist/dist-esm/react-composites/src/composites/CallComposite/adapter/CallingSoundSubscriber.js.map +1 -1
- package/dist/dist-esm/react-composites/src/composites/CallComposite/components/SidePane/SidePane.js +1 -1
- package/dist/dist-esm/react-composites/src/composites/CallComposite/components/SidePane/SidePane.js.map +1 -1
- package/dist/dist-esm/react-composites/src/composites/CallComposite/selectors/LocalVideoTileSelector.d.ts +1 -0
- package/dist/dist-esm/react-composites/src/composites/CallComposite/selectors/activeVideoBackgroundEffectSelector.d.ts +1 -0
- package/dist/dist-esm/react-composites/src/composites/CallComposite/selectors/callStatusSelector.d.ts +1 -0
- package/dist/dist-esm/react-composites/src/composites/CallComposite/selectors/capabilitiesChangedInfoAndRoleSelector.d.ts +1 -0
- package/dist/dist-esm/react-composites/src/composites/CallComposite/selectors/complianceBannerSelector.d.ts +1 -0
- package/dist/dist-esm/react-composites/src/composites/CallComposite/selectors/deviceCountSelector.d.ts +1 -0
- package/dist/dist-esm/react-composites/src/composites/CallComposite/selectors/devicePermissionSelector.d.ts +1 -0
- package/dist/dist-esm/react-composites/src/composites/CallComposite/selectors/dominantRemoteParticipantSelector.d.ts +1 -0
- package/dist/dist-esm/react-composites/src/composites/CallComposite/selectors/lobbySelector.d.ts +1 -0
- package/dist/dist-esm/react-composites/src/composites/CallComposite/selectors/localAndRemotePIPSelector.d.ts +1 -0
- package/dist/dist-esm/react-composites/src/composites/CallComposite/selectors/localPreviewSelector.d.ts +1 -0
- package/dist/dist-esm/react-composites/src/composites/CallComposite/selectors/localVideoStreamSelector.d.ts +1 -0
- package/dist/dist-esm/react-composites/src/composites/CallComposite/selectors/mediaGallerySelector.d.ts +2 -0
- package/dist/dist-esm/react-composites/src/composites/CallComposite/selectors/mutedNotificationSelector.d.ts +1 -0
- package/dist/dist-esm/react-composites/src/composites/CallComposite/selectors/networkReconnectTileSelector.d.ts +1 -0
- package/dist/dist-esm/react-composites/src/composites/CallWithChatComposite/CallWithChatComposite.js +6 -8
- package/dist/dist-esm/react-composites/src/composites/CallWithChatComposite/CallWithChatComposite.js.map +1 -1
- package/dist/dist-esm/react-composites/src/composites/ChatComposite/ChatComposite.js +3 -13
- package/dist/dist-esm/react-composites/src/composites/ChatComposite/ChatComposite.js.map +1 -1
- package/dist/dist-esm/react-composites/src/composites/ChatComposite/ChatScreen.js +10 -4
- package/dist/dist-esm/react-composites/src/composites/ChatComposite/ChatScreen.js.map +1 -1
- package/package.json +1 -1
@@ -18,10 +18,10 @@ var reactFileTypeIcons = require('@fluentui/react-file-type-icons');
|
|
18
18
|
var uuid = require('uuid');
|
19
19
|
var reactChat = require('@fluentui-contrib/react-chat');
|
20
20
|
var reactComponents = require('@fluentui/react-components');
|
21
|
+
var react$1 = require('@griffel/react');
|
21
22
|
var htmlToReact = require('html-to-react');
|
22
23
|
var Linkify = require('react-linkify');
|
23
24
|
var DOMPurify = require('dompurify');
|
24
|
-
var react$1 = require('@griffel/react');
|
25
25
|
var reactHooks = require('@fluentui/react-hooks');
|
26
26
|
var reactUseDraggableScroll = require('react-use-draggable-scroll');
|
27
27
|
var reactWindowProvider = require('@fluentui/react-window-provider');
|
@@ -177,7 +177,7 @@ const _isValidIdentifier = (identifier) => {
|
|
177
177
|
// Copyright (c) Microsoft Corporation.
|
178
178
|
// Licensed under the MIT License.
|
179
179
|
// GENERATED FILE. DO NOT EDIT MANUALLY.
|
180
|
-
var telemetryVersion = '1.10.1-alpha-
|
180
|
+
var telemetryVersion = '1.10.1-alpha-202311240012';
|
181
181
|
|
182
182
|
// Copyright (c) Microsoft Corporation.
|
183
183
|
/**
|
@@ -9000,1642 +9000,1905 @@ const delay = (delay) => {
|
|
9000
9000
|
|
9001
9001
|
// Copyright (c) Microsoft Corporation.
|
9002
9002
|
/**
|
9003
|
-
*
|
9004
|
-
|
9005
|
-
|
9006
|
-
|
9007
|
-
});
|
9008
|
-
|
9009
|
-
// Copyright (c) Microsoft Corporation.
|
9010
|
-
/**
|
9011
|
-
* @private
|
9003
|
+
* A utility hook for providing the width of a parent element.
|
9004
|
+
* Returns updated width if parent/window resizes.
|
9005
|
+
* @param containerRef - Ref of a parent element whose width will be returned.
|
9006
|
+
* @internal
|
9012
9007
|
*/
|
9013
|
-
const
|
9014
|
-
const
|
9015
|
-
const
|
9016
|
-
|
9017
|
-
|
9018
|
-
|
9008
|
+
const _useContainerWidth = (containerRef) => {
|
9009
|
+
const [width, setWidth] = React.useState(undefined);
|
9010
|
+
const observer = React.useRef(new ResizeObserver((entries) => {
|
9011
|
+
const { width } = entries[0].contentRect;
|
9012
|
+
setWidth(width);
|
9013
|
+
}));
|
9014
|
+
React.useEffect(() => {
|
9015
|
+
if (containerRef.current) {
|
9016
|
+
observer.current.observe(containerRef.current);
|
9017
|
+
}
|
9018
|
+
const currentObserver = observer.current;
|
9019
|
+
return () => {
|
9020
|
+
currentObserver.disconnect();
|
9021
|
+
};
|
9022
|
+
}, [containerRef, observer]);
|
9023
|
+
return width;
|
9019
9024
|
};
|
9020
|
-
|
9021
|
-
// Copyright (c) Microsoft Corporation.
|
9022
9025
|
/**
|
9023
|
-
*
|
9026
|
+
* A utility hook for providing the height of a parent element.
|
9027
|
+
* Returns updated height if parent/window resizes.
|
9028
|
+
* @param containerRef - Ref of a parent element whose height will be returned.
|
9029
|
+
* @internal
|
9024
9030
|
*/
|
9025
|
-
const
|
9026
|
-
|
9027
|
-
|
9028
|
-
}
|
9031
|
+
const _useContainerHeight = (containerRef) => {
|
9032
|
+
const [height, setHeight] = React.useState(undefined);
|
9033
|
+
const observer = React.useRef(new ResizeObserver((entries) => {
|
9034
|
+
const { height } = entries[0].contentRect;
|
9035
|
+
setHeight(height);
|
9036
|
+
}));
|
9037
|
+
React.useEffect(() => {
|
9038
|
+
if (containerRef.current) {
|
9039
|
+
observer.current.observe(containerRef.current);
|
9040
|
+
}
|
9041
|
+
const currentObserver = observer.current;
|
9042
|
+
return () => {
|
9043
|
+
currentObserver.disconnect();
|
9044
|
+
};
|
9045
|
+
}, [containerRef, observer]);
|
9046
|
+
return height;
|
9047
|
+
};
|
9048
|
+
const NARROW_WIDTH_REM = 30;
|
9049
|
+
const SHORT_HEIGHT_REM = 23.75;
|
9029
9050
|
/**
|
9030
|
-
*
|
9051
|
+
* Utility function to determine if container width is narrow
|
9052
|
+
* @param containerWidthRem container width in rem
|
9053
|
+
* @returns boolean
|
9031
9054
|
*/
|
9032
|
-
const
|
9033
|
-
margin: '0',
|
9034
|
-
width: '2.125rem',
|
9035
|
-
height: '2.125rem',
|
9036
|
-
padding: '0.375rem 0 0 0'
|
9037
|
-
});
|
9055
|
+
const isNarrowWidth = (containerWidthRem) => containerWidthRem <= _convertRemToPx(NARROW_WIDTH_REM);
|
9038
9056
|
/**
|
9039
|
-
*
|
9057
|
+
* Utility function to determine if container width is short
|
9058
|
+
* @param containerWidthRem container height in rem
|
9059
|
+
* @returns boolean
|
9040
9060
|
*/
|
9041
|
-
const
|
9042
|
-
|
9043
|
-
|
9044
|
-
|
9045
|
-
}
|
9046
|
-
});
|
9061
|
+
const isShortHeight = (containerHeightRem) => containerHeightRem <= _convertRemToPx(SHORT_HEIGHT_REM);
|
9062
|
+
|
9063
|
+
// Copyright (c) Microsoft Corporation.
|
9064
|
+
// Licensed under the MIT License.
|
9047
9065
|
/**
|
9048
9066
|
* @private
|
9049
|
-
|
9050
|
-
|
9051
|
-
|
9052
|
-
|
9053
|
-
|
9054
|
-
|
9067
|
+
*logic: Looking at message A, how do we know it's read number?
|
9068
|
+
* Assumption: if user read the latest message, user has read all messages before that
|
9069
|
+
* ReadReceipt behaviour: read receipt is only sent to the last message
|
9070
|
+
*
|
9071
|
+
* If participant read a message that is sent later than message A, then the participant has read message A
|
9072
|
+
* How do we check if the message is sent later than message A?
|
9073
|
+
* We compare if the messageID of the last read message is larger than or equal to the message A's id
|
9074
|
+
* Because messageID is the creation timestamp of each message
|
9075
|
+
* Timestamps are in epoch time so lecixographical ordering is the same as time ordering.
|
9076
|
+
*
|
9077
|
+
* if MessageId of B is larger than message Id of A, then B is created after A
|
9078
|
+
* if the last read message is created after the message A is sent, then user should have read message A as well */
|
9079
|
+
var getParticipantsWhoHaveReadMessage = (message, readReceiptsBySenderId) => {
|
9080
|
+
return (Object.entries(readReceiptsBySenderId)
|
9081
|
+
// Filter to only read receipts that match the message OR the participant has read a different message after this message has been created
|
9082
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
9083
|
+
.filter(([_, readReceipt]) => readReceipt.lastReadMessage >= message.messageId)
|
9084
|
+
// make sure the person is not removed from chat
|
9085
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
9086
|
+
.filter(([_, readReceipt]) => readReceipt.displayName && readReceipt.displayName !== '')
|
9087
|
+
// Map properties to useful array
|
9088
|
+
.map(([id, readReceipt]) => ({ id, displayName: readReceipt.displayName })));
|
9055
9089
|
};
|
9056
9090
|
|
9057
9091
|
// Copyright (c) Microsoft Corporation.
|
9058
|
-
|
9059
|
-
|
9060
|
-
|
9061
|
-
* @private
|
9062
|
-
*/
|
9063
|
-
const iconWrapperStyle = (theme, isSubMenuOpen) => ({
|
9064
|
-
root: {
|
9065
|
-
margin: _pxToRem(3),
|
9066
|
-
// Show hover styles when the Edit/Delete menu is showing as this action button is still considered 'active'
|
9067
|
-
color: isSubMenuOpen ? theme.palette.black : theme.palette.neutralPrimary,
|
9068
|
-
strokeWidth: isSubMenuOpen ? _pxToRem(0.5) : _pxToRem(0),
|
9069
|
-
stroke: theme.palette.black,
|
9070
|
-
':hover, :focus': {
|
9071
|
-
color: theme.palette.black,
|
9072
|
-
strokeWidth: _pxToRem(0.5)
|
9073
|
-
}
|
9074
|
-
}
|
9075
|
-
});
|
9076
|
-
/**
|
9077
|
-
* @private
|
9078
|
-
*/
|
9079
|
-
const chatMessageDateStyle = react.mergeStyles({
|
9080
|
-
color: reactComponents.tokens.colorNeutralForeground2,
|
9081
|
-
fontWeight: react.FontWeights.regular,
|
9082
|
-
fontSize: '0.75rem'
|
9083
|
-
});
|
9092
|
+
// Licensed under the MIT License.
|
9093
|
+
// These color records are required for createV9Theme
|
9094
|
+
// For more info, check https://react.fluentui.dev/iframe.html?viewMode=docs&id=concepts-migration-from-v8-components-theme-migration--page#compatible-themes
|
9084
9095
|
/**
|
9085
9096
|
* @private
|
9086
9097
|
*/
|
9087
|
-
const
|
9088
|
-
|
9089
|
-
|
9090
|
-
|
9098
|
+
const grey = {
|
9099
|
+
'0': '#000000',
|
9100
|
+
'2': '#050505',
|
9101
|
+
'4': '#0a0a0a',
|
9102
|
+
'6': '#0f0f0f',
|
9103
|
+
'8': '#141414',
|
9104
|
+
'10': '#1a1a1a',
|
9105
|
+
'12': '#1f1f1f',
|
9106
|
+
'14': '#242424',
|
9107
|
+
'16': '#292929',
|
9108
|
+
'18': '#2e2e2e',
|
9109
|
+
'20': '#333333',
|
9110
|
+
'22': '#383838',
|
9111
|
+
'24': '#3d3d3d',
|
9112
|
+
'26': '#424242',
|
9113
|
+
'28': '#474747',
|
9114
|
+
'30': '#4d4d4d',
|
9115
|
+
'32': '#525252',
|
9116
|
+
'34': '#575757',
|
9117
|
+
'36': '#5c5c5c',
|
9118
|
+
'38': '#616161',
|
9119
|
+
'40': '#666666',
|
9120
|
+
'42': '#6b6b6b',
|
9121
|
+
'44': '#707070',
|
9122
|
+
'46': '#757575',
|
9123
|
+
'48': '#7a7a7a',
|
9124
|
+
'50': '#808080',
|
9125
|
+
'52': '#858585',
|
9126
|
+
'54': '#8a8a8a',
|
9127
|
+
'56': '#8f8f8f',
|
9128
|
+
'58': '#949494',
|
9129
|
+
'60': '#999999',
|
9130
|
+
'62': '#9e9e9e',
|
9131
|
+
'64': '#a3a3a3',
|
9132
|
+
'66': '#a8a8a8',
|
9133
|
+
'68': '#adadad',
|
9134
|
+
'70': '#b3b3b3',
|
9135
|
+
'72': '#b8b8b8',
|
9136
|
+
'74': '#bdbdbd',
|
9137
|
+
'76': '#c2c2c2',
|
9138
|
+
'78': '#c7c7c7',
|
9139
|
+
'80': '#cccccc',
|
9140
|
+
'82': '#d1d1d1',
|
9141
|
+
'84': '#d6d6d6',
|
9142
|
+
'86': '#dbdbdb',
|
9143
|
+
'88': '#e0e0e0',
|
9144
|
+
'90': '#e6e6e6',
|
9145
|
+
'92': '#ebebeb',
|
9146
|
+
'94': '#f0f0f0',
|
9147
|
+
'96': '#f5f5f5',
|
9148
|
+
'98': '#fafafa',
|
9149
|
+
'100': '#ffffff'
|
9150
|
+
};
|
9091
9151
|
/**
|
9092
9152
|
* @private
|
9093
9153
|
*/
|
9094
|
-
const
|
9154
|
+
const whiteAlpha = {
|
9155
|
+
'5': 'rgba(255, 255, 255, 0.05)',
|
9156
|
+
'10': 'rgba(255, 255, 255, 0.1)',
|
9157
|
+
'20': 'rgba(255, 255, 255, 0.2)',
|
9158
|
+
'30': 'rgba(255, 255, 255, 0.3)',
|
9159
|
+
'40': 'rgba(255, 255, 255, 0.4)',
|
9160
|
+
'50': 'rgba(255, 255, 255, 0.5)',
|
9161
|
+
'60': 'rgba(255, 255, 255, 0.6)',
|
9162
|
+
'70': 'rgba(255, 255, 255, 0.7)',
|
9163
|
+
'80': 'rgba(255, 255, 255, 0.8)',
|
9164
|
+
'90': 'rgba(255, 255, 255, 0.9)'
|
9165
|
+
};
|
9095
9166
|
/**
|
9096
9167
|
* @private
|
9097
9168
|
*/
|
9098
|
-
const
|
9099
|
-
|
9100
|
-
|
9101
|
-
|
9102
|
-
|
9103
|
-
|
9169
|
+
const blackAlpha = {
|
9170
|
+
'5': 'rgba(0, 0, 0, 0.05)',
|
9171
|
+
'10': 'rgba(0, 0, 0, 0.1)',
|
9172
|
+
'20': 'rgba(0, 0, 0, 0.2)',
|
9173
|
+
'30': 'rgba(0, 0, 0, 0.3)',
|
9174
|
+
'40': 'rgba(0, 0, 0, 0.4)',
|
9175
|
+
'50': 'rgba(0, 0, 0, 0.5)',
|
9176
|
+
'60': 'rgba(0, 0, 0, 0.6)',
|
9177
|
+
'70': 'rgba(0, 0, 0, 0.7)',
|
9178
|
+
'80': 'rgba(0, 0, 0, 0.8)',
|
9179
|
+
'90': 'rgba(0, 0, 0, 0.9)'
|
9180
|
+
};
|
9104
9181
|
/**
|
9105
9182
|
* @private
|
9106
9183
|
*/
|
9107
|
-
const
|
9108
|
-
|
9109
|
-
|
9184
|
+
const grey10Alpha = {
|
9185
|
+
'5': 'rgba(26, 26, 26, 0.05)',
|
9186
|
+
'10': 'rgba(26, 26, 26, 0.1)',
|
9187
|
+
'20': 'rgba(26, 26, 26, 0.2)',
|
9188
|
+
'30': 'rgba(26, 26, 26, 0.3)',
|
9189
|
+
'40': 'rgba(26, 26, 26, 0.4)',
|
9190
|
+
'50': 'rgba(26, 26, 26, 0.5)',
|
9191
|
+
'60': 'rgba(26, 26, 26, 0.6)',
|
9192
|
+
'70': 'rgba(26, 26, 26, 0.7)',
|
9193
|
+
'80': 'rgba(26, 26, 26, 0.8)',
|
9194
|
+
'90': 'rgba(26, 26, 26, 0.9)'
|
9195
|
+
};
|
9110
9196
|
/**
|
9111
9197
|
* @private
|
9112
9198
|
*/
|
9113
|
-
const
|
9114
|
-
|
9115
|
-
|
9116
|
-
|
9117
|
-
|
9199
|
+
const grey12Alpha = {
|
9200
|
+
'5': 'rgba(31, 31, 31, 0.05)',
|
9201
|
+
'10': 'rgba(31, 31, 31, 0.1)',
|
9202
|
+
'20': 'rgba(31, 31, 31, 0.2)',
|
9203
|
+
'30': 'rgba(31, 31, 31, 0.3)',
|
9204
|
+
'40': 'rgba(31, 31, 31, 0.4)',
|
9205
|
+
'50': 'rgba(31, 31, 31, 0.5)',
|
9206
|
+
'60': 'rgba(31, 31, 31, 0.6)',
|
9207
|
+
'70': 'rgba(31, 31, 31, 0.7)',
|
9208
|
+
'80': 'rgba(31, 31, 31, 0.8)',
|
9209
|
+
'90': 'rgba(31, 31, 31, 0.9)'
|
9210
|
+
};
|
9211
|
+
|
9212
|
+
// Copyright (c) Microsoft Corporation.
|
9213
|
+
// These mappings are required for createV9Theme
|
9214
|
+
// For more info, check https://react.fluentui.dev/iframe.html?viewMode=docs&id=concepts-migration-from-v8-components-theme-migration--page#compatible-themes
|
9215
|
+
/**
|
9216
|
+
* Creates v9 color tokens from a v8 palette.
|
9118
9217
|
*/
|
9119
|
-
const
|
9120
|
-
|
9121
|
-
|
9122
|
-
|
9218
|
+
const mapAliasColors = (palette, inverted) => {
|
9219
|
+
return {
|
9220
|
+
colorNeutralForeground1: palette.neutralPrimary,
|
9221
|
+
colorNeutralForeground1Hover: palette.neutralPrimary,
|
9222
|
+
colorNeutralForeground1Pressed: palette.neutralPrimary,
|
9223
|
+
colorNeutralForeground1Selected: palette.neutralPrimary,
|
9224
|
+
colorNeutralForeground2: palette.neutralSecondary,
|
9225
|
+
colorNeutralForeground2Hover: palette.neutralPrimary,
|
9226
|
+
colorNeutralForeground2Pressed: palette.neutralPrimary,
|
9227
|
+
colorNeutralForeground2Selected: palette.neutralPrimary,
|
9228
|
+
colorNeutralForeground2BrandHover: palette.themePrimary,
|
9229
|
+
colorNeutralForeground2BrandPressed: palette.themeDarkAlt,
|
9230
|
+
colorNeutralForeground2BrandSelected: palette.themePrimary,
|
9231
|
+
colorNeutralForeground3: palette.neutralTertiary,
|
9232
|
+
colorNeutralForeground3Hover: palette.neutralSecondary,
|
9233
|
+
colorNeutralForeground3Pressed: palette.neutralSecondary,
|
9234
|
+
colorNeutralForeground3Selected: palette.neutralSecondary,
|
9235
|
+
colorNeutralForeground3BrandHover: palette.themePrimary,
|
9236
|
+
colorNeutralForeground3BrandPressed: palette.themeDarkAlt,
|
9237
|
+
colorNeutralForeground3BrandSelected: palette.themePrimary,
|
9238
|
+
colorNeutralForeground4: palette.neutralQuaternary,
|
9239
|
+
colorNeutralForegroundDisabled: palette.neutralTertiaryAlt,
|
9240
|
+
colorNeutralForegroundInvertedDisabled: whiteAlpha[40],
|
9241
|
+
colorBrandForegroundLink: palette.themeDarkAlt,
|
9242
|
+
colorBrandForegroundLinkHover: palette.themeDark,
|
9243
|
+
colorBrandForegroundLinkPressed: palette.themeDarker,
|
9244
|
+
colorBrandForegroundLinkSelected: palette.themeDarkAlt,
|
9245
|
+
colorNeutralForeground2Link: palette.neutralSecondary,
|
9246
|
+
colorNeutralForeground2LinkHover: palette.neutralPrimary,
|
9247
|
+
colorNeutralForeground2LinkPressed: palette.neutralPrimary,
|
9248
|
+
colorNeutralForeground2LinkSelected: palette.neutralPrimary,
|
9249
|
+
colorCompoundBrandForeground1: palette.themePrimary,
|
9250
|
+
colorCompoundBrandForeground1Hover: palette.themeDarkAlt,
|
9251
|
+
colorCompoundBrandForeground1Pressed: palette.themeDark,
|
9252
|
+
colorBrandForeground1: palette.themePrimary,
|
9253
|
+
colorBrandForeground2: palette.themeDarkAlt,
|
9254
|
+
colorBrandForeground2Hover: palette.themeDarkAlt,
|
9255
|
+
colorBrandForeground2Pressed: palette.themeDarkAlt,
|
9256
|
+
colorNeutralForeground1Static: palette.neutralPrimary,
|
9257
|
+
colorNeutralForegroundInverted: palette.white,
|
9258
|
+
colorNeutralForegroundInvertedHover: palette.white,
|
9259
|
+
colorNeutralForegroundInvertedPressed: palette.white,
|
9260
|
+
colorNeutralForegroundInvertedSelected: palette.white,
|
9261
|
+
colorNeutralForegroundOnBrand: palette.white,
|
9262
|
+
colorNeutralForegroundStaticInverted: palette.white,
|
9263
|
+
colorNeutralForegroundInvertedLink: palette.white,
|
9264
|
+
colorNeutralForegroundInvertedLinkHover: palette.white,
|
9265
|
+
colorNeutralForegroundInvertedLinkPressed: palette.white,
|
9266
|
+
colorNeutralForegroundInvertedLinkSelected: palette.white,
|
9267
|
+
colorNeutralForegroundInverted2: palette.white,
|
9268
|
+
colorBrandForegroundInverted: palette.themeSecondary,
|
9269
|
+
colorBrandForegroundInvertedHover: palette.themeTertiary,
|
9270
|
+
colorBrandForegroundInvertedPressed: palette.themeSecondary,
|
9271
|
+
colorBrandForegroundOnLight: palette.themePrimary,
|
9272
|
+
colorBrandForegroundOnLightHover: palette.themeDarkAlt,
|
9273
|
+
colorBrandForegroundOnLightPressed: palette.themeDark,
|
9274
|
+
colorBrandForegroundOnLightSelected: palette.themeDark,
|
9275
|
+
colorNeutralBackground1: palette.white,
|
9276
|
+
colorNeutralBackground1Hover: palette.neutralLighter,
|
9277
|
+
colorNeutralBackground1Pressed: palette.neutralQuaternaryAlt,
|
9278
|
+
colorNeutralBackground1Selected: palette.neutralLight,
|
9279
|
+
colorNeutralBackground2: palette.neutralLighterAlt,
|
9280
|
+
colorNeutralBackground2Hover: palette.neutralLighter,
|
9281
|
+
colorNeutralBackground2Pressed: palette.neutralQuaternaryAlt,
|
9282
|
+
colorNeutralBackground2Selected: palette.neutralLight,
|
9283
|
+
colorNeutralBackground3: palette.neutralLighter,
|
9284
|
+
colorNeutralBackground3Hover: palette.neutralLight,
|
9285
|
+
colorNeutralBackground3Pressed: palette.neutralQuaternary,
|
9286
|
+
colorNeutralBackground3Selected: palette.neutralQuaternaryAlt,
|
9287
|
+
colorNeutralBackground4: palette.neutralLighter,
|
9288
|
+
colorNeutralBackground4Hover: palette.neutralLighterAlt,
|
9289
|
+
colorNeutralBackground4Pressed: palette.neutralLighter,
|
9290
|
+
colorNeutralBackground4Selected: palette.white,
|
9291
|
+
colorNeutralBackground5: palette.neutralLight,
|
9292
|
+
colorNeutralBackground5Hover: palette.neutralLighter,
|
9293
|
+
colorNeutralBackground5Pressed: palette.neutralLighter,
|
9294
|
+
colorNeutralBackground5Selected: palette.neutralLighterAlt,
|
9295
|
+
colorNeutralBackground6: palette.neutralLight,
|
9296
|
+
colorNeutralBackgroundStatic: grey[20],
|
9297
|
+
colorNeutralBackgroundInverted: palette.neutralSecondary,
|
9298
|
+
colorNeutralBackgroundAlpha: inverted ? grey10Alpha[50] : whiteAlpha[50],
|
9299
|
+
colorNeutralBackgroundAlpha2: inverted ? grey12Alpha[70] : whiteAlpha[80],
|
9300
|
+
colorSubtleBackground: 'transparent',
|
9301
|
+
colorSubtleBackgroundHover: palette.neutralLighter,
|
9302
|
+
colorSubtleBackgroundPressed: palette.neutralQuaternaryAlt,
|
9303
|
+
colorSubtleBackgroundSelected: palette.neutralLight,
|
9304
|
+
colorSubtleBackgroundLightAlphaHover: inverted ? whiteAlpha[10] : whiteAlpha[80],
|
9305
|
+
colorSubtleBackgroundLightAlphaPressed: inverted ? whiteAlpha[5] : whiteAlpha[50],
|
9306
|
+
colorSubtleBackgroundLightAlphaSelected: 'transparent',
|
9307
|
+
colorSubtleBackgroundInverted: 'transparent',
|
9308
|
+
colorSubtleBackgroundInvertedHover: blackAlpha[10],
|
9309
|
+
colorSubtleBackgroundInvertedPressed: blackAlpha[30],
|
9310
|
+
colorSubtleBackgroundInvertedSelected: blackAlpha[20],
|
9311
|
+
colorTransparentBackground: 'transparent',
|
9312
|
+
colorTransparentBackgroundHover: 'transparent',
|
9313
|
+
colorTransparentBackgroundPressed: 'transparent',
|
9314
|
+
colorTransparentBackgroundSelected: 'transparent',
|
9315
|
+
colorNeutralBackgroundDisabled: palette.neutralLighter,
|
9316
|
+
colorNeutralBackgroundInvertedDisabled: whiteAlpha[10],
|
9317
|
+
colorNeutralStencil1: palette.neutralLight,
|
9318
|
+
colorNeutralStencil2: palette.neutralLighterAlt,
|
9319
|
+
colorNeutralStencil1Alpha: inverted ? whiteAlpha[10] : blackAlpha[10],
|
9320
|
+
colorNeutralStencil2Alpha: inverted ? whiteAlpha[5] : blackAlpha[5],
|
9321
|
+
colorBackgroundOverlay: blackAlpha[40],
|
9322
|
+
colorScrollbarOverlay: blackAlpha[50],
|
9323
|
+
colorBrandBackground: palette.themePrimary,
|
9324
|
+
colorBrandBackgroundHover: palette.themeDarkAlt,
|
9325
|
+
colorBrandBackgroundPressed: palette.themeDarker,
|
9326
|
+
colorBrandBackgroundSelected: palette.themeDark,
|
9327
|
+
colorCompoundBrandBackground: palette.themePrimary,
|
9328
|
+
colorCompoundBrandBackgroundHover: palette.themeDarkAlt,
|
9329
|
+
colorCompoundBrandBackgroundPressed: palette.themeDark,
|
9330
|
+
colorBrandBackgroundStatic: palette.themePrimary,
|
9331
|
+
colorBrandBackground2: palette.themeLighterAlt,
|
9332
|
+
colorBrandBackground2Hover: palette.themeLighterAlt,
|
9333
|
+
colorBrandBackground2Pressed: palette.themeLighterAlt,
|
9334
|
+
colorBrandBackgroundInverted: palette.white,
|
9335
|
+
colorBrandBackgroundInvertedHover: palette.themeLighterAlt,
|
9336
|
+
colorBrandBackgroundInvertedPressed: palette.themeLight,
|
9337
|
+
colorBrandBackgroundInvertedSelected: palette.themeLighter,
|
9338
|
+
colorNeutralStrokeAccessible: palette.neutralSecondary,
|
9339
|
+
colorNeutralStrokeAccessibleHover: palette.neutralSecondary,
|
9340
|
+
colorNeutralStrokeAccessiblePressed: palette.neutralSecondary,
|
9341
|
+
colorNeutralStrokeAccessibleSelected: palette.themePrimary,
|
9342
|
+
colorNeutralStroke1: palette.neutralQuaternary,
|
9343
|
+
colorNeutralStroke1Hover: palette.neutralTertiaryAlt,
|
9344
|
+
colorNeutralStroke1Pressed: palette.neutralTertiaryAlt,
|
9345
|
+
colorNeutralStroke1Selected: palette.neutralTertiaryAlt,
|
9346
|
+
colorNeutralStroke2: palette.neutralQuaternaryAlt,
|
9347
|
+
colorNeutralStroke3: palette.neutralLighter,
|
9348
|
+
colorNeutralStrokeSubtle: palette.neutralQuaternaryAlt,
|
9349
|
+
colorNeutralStrokeOnBrand: palette.white,
|
9350
|
+
colorNeutralStrokeOnBrand2: palette.white,
|
9351
|
+
colorNeutralStrokeOnBrand2Hover: palette.white,
|
9352
|
+
colorNeutralStrokeOnBrand2Pressed: palette.white,
|
9353
|
+
colorNeutralStrokeOnBrand2Selected: palette.white,
|
9354
|
+
colorBrandStroke1: palette.themePrimary,
|
9355
|
+
colorBrandStroke2: palette.themeLight,
|
9356
|
+
colorBrandStroke2Hover: palette.themeLight,
|
9357
|
+
colorBrandStroke2Pressed: palette.themeLight,
|
9358
|
+
colorBrandStroke2Contrast: palette.themeLight,
|
9359
|
+
colorCompoundBrandStroke: palette.themePrimary,
|
9360
|
+
colorCompoundBrandStrokeHover: palette.themeDarkAlt,
|
9361
|
+
colorCompoundBrandStrokePressed: palette.themeDark,
|
9362
|
+
colorNeutralStrokeDisabled: palette.neutralQuaternaryAlt,
|
9363
|
+
colorNeutralStrokeInvertedDisabled: whiteAlpha[40],
|
9364
|
+
colorTransparentStroke: 'transparent',
|
9365
|
+
colorTransparentStrokeInteractive: 'transparent',
|
9366
|
+
colorTransparentStrokeDisabled: 'transparent',
|
9367
|
+
colorNeutralStrokeAlpha: inverted ? whiteAlpha[10] : blackAlpha[5],
|
9368
|
+
colorNeutralStrokeAlpha2: whiteAlpha[20],
|
9369
|
+
colorStrokeFocus1: palette.white,
|
9370
|
+
colorStrokeFocus2: palette.black,
|
9371
|
+
colorNeutralShadowAmbient: 'rgba(0,0,0,0.12)',
|
9372
|
+
colorNeutralShadowKey: 'rgba(0,0,0,0.14)',
|
9373
|
+
colorNeutralShadowAmbientLighter: 'rgba(0,0,0,0.06)',
|
9374
|
+
colorNeutralShadowKeyLighter: 'rgba(0,0,0,0.07)',
|
9375
|
+
colorNeutralShadowAmbientDarker: 'rgba(0,0,0,0.20)',
|
9376
|
+
colorNeutralShadowKeyDarker: 'rgba(0,0,0,0.24)',
|
9377
|
+
colorBrandShadowAmbient: 'rgba(0,0,0,0.30)',
|
9378
|
+
colorBrandShadowKey: 'rgba(0,0,0,0.25)'
|
9379
|
+
};
|
9380
|
+
};
|
9123
9381
|
/**
|
9124
|
-
*
|
9382
|
+
* Creates v9 shadow tokens from v8 effects.
|
9125
9383
|
*/
|
9126
|
-
const
|
9127
|
-
|
9128
|
-
|
9129
|
-
|
9130
|
-
|
9131
|
-
|
9384
|
+
const mapShadowTokens = (effects) => {
|
9385
|
+
return {
|
9386
|
+
shadow4: effects.elevation4,
|
9387
|
+
shadow8: effects.elevation8,
|
9388
|
+
shadow16: effects.elevation16,
|
9389
|
+
shadow64: effects.elevation64
|
9390
|
+
};
|
9391
|
+
};
|
9132
9392
|
/**
|
9133
|
-
*
|
9393
|
+
* Creates v9 border radius tokens from v8 effects
|
9134
9394
|
*/
|
9135
|
-
const
|
9136
|
-
|
9137
|
-
|
9138
|
-
|
9139
|
-
|
9140
|
-
|
9141
|
-
|
9142
|
-
bodyError: Object.assign({}, reactComponents.shorthands.borderColor(errorTextColor)),
|
9143
|
-
bodyDefault: Object.assign(Object.assign({}, reactComponents.shorthands.borderColor(reactComponents.tokens.colorNeutralStrokeAccessible)), { '&:hover, &:active, &:focus, &:focus-within': Object.assign({}, reactComponents.shorthands.borderColor(reactComponents.tokens.colorCompoundBrandStroke)) })
|
9144
|
-
});
|
9395
|
+
const mapBorderRadiusTokens = (effects) => {
|
9396
|
+
return {
|
9397
|
+
borderRadiusSmall: effects.roundedCorner2,
|
9398
|
+
borderRadiusMedium: effects.roundedCorner4,
|
9399
|
+
borderRadiusLarge: effects.roundedCorner6
|
9400
|
+
};
|
9401
|
+
};
|
9145
9402
|
/**
|
9146
|
-
*
|
9403
|
+
* Creates a v9 theme from a v8 theme and base v9 theme.
|
9404
|
+
* FluentUI webLightTheme is used in case if no baseThemeV9 is provided.
|
9147
9405
|
*
|
9148
9406
|
* @private
|
9149
9407
|
*/
|
9150
|
-
const
|
9151
|
-
|
9152
|
-
|
9153
|
-
|
9154
|
-
|
9155
|
-
},
|
9156
|
-
linkContent: {
|
9157
|
-
height: `${MINIMUM_TOUCH_TARGET_HEIGHT_REM$1}rem`,
|
9158
|
-
lineHeight: `${MINIMUM_TOUCH_TARGET_HEIGHT_REM$1}rem`,
|
9159
|
-
maxHeight: 'unset'
|
9160
|
-
},
|
9161
|
-
icon: {
|
9162
|
-
maxHeight: 'unset'
|
9163
|
-
}
|
9408
|
+
const createV9Theme = (themeV8, baseThemeV9) => {
|
9409
|
+
const baseTheme = baseThemeV9 !== null && baseThemeV9 !== void 0 ? baseThemeV9 : reactComponents.webLightTheme;
|
9410
|
+
return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, baseTheme), mapAliasColors(themeV8.palette, themeV8.isInverted)), mapShadowTokens(themeV8.effects)), mapBorderRadiusTokens(themeV8.effects)), { colorBrandBackground2: themeV8.palette.themeLight, colorBrandBackground2Hover: themeV8.palette.themeLight, colorBrandBackground2Pressed: themeV8.palette.themeLight, colorStatusWarningBackground3: '#D83B01', errorText: themeV8.semanticColors.errorText, colorNeutralStroke1Selected: themeV8.palette.neutralQuaternary, colorNeutralForeground2: themeV8.palette.neutralSecondary, colorBrandForegroundLink: themeV8.palette.themePrimary, colorBrandForegroundLinkHover: themeV8.palette.themeDarker,
|
9411
|
+
// Fix for an issue with black borders for iOS that are added with 'after' selector
|
9412
|
+
colorStrokeFocus2: 'transparent' });
|
9164
9413
|
};
|
9414
|
+
|
9415
|
+
// Copyright (c) Microsoft Corporation.
|
9165
9416
|
/**
|
9166
9417
|
* @private
|
9167
9418
|
*/
|
9168
|
-
const
|
9169
|
-
|
9170
|
-
|
9171
|
-
width: '1.25rem'
|
9172
|
-
}
|
9173
|
-
};
|
9419
|
+
const useFluentV9Wrapper = reactComponents.makeStyles({
|
9420
|
+
body: Object.assign(Object.assign(Object.assign(Object.assign({ height: '100%' }, reactComponents.shorthands.margin(0)), reactComponents.shorthands.overflow('hidden')), reactComponents.shorthands.padding(0)), { width: '100%' })
|
9421
|
+
});
|
9174
9422
|
/**
|
9175
9423
|
* @private
|
9176
9424
|
*/
|
9177
|
-
const
|
9178
|
-
|
9179
|
-
|
9180
|
-
|
9181
|
-
|
9182
|
-
|
9425
|
+
const FluentV9ThemeProvider = (props) => {
|
9426
|
+
const { v8Theme, children } = props;
|
9427
|
+
const v9Theme = createV9Theme(v8Theme);
|
9428
|
+
const dir = v8Theme.rtl ? 'rtl' : 'ltr';
|
9429
|
+
return (
|
9430
|
+
// TextDirectionProvider is needed to fix issue with direction value update in FluentProvider
|
9431
|
+
React__default["default"].createElement(react$1.TextDirectionProvider, { dir: dir },
|
9432
|
+
React__default["default"].createElement(FluentProviderWithStylesOverrides, { theme: v9Theme, dir: dir }, children)));
|
9433
|
+
};
|
9434
|
+
const FluentProviderWithStylesOverrides = (props) => {
|
9435
|
+
const classes = useFluentV9Wrapper();
|
9436
|
+
return React__default["default"].createElement(reactComponents.FluentProvider, Object.assign({}, props, { className: classes.body }));
|
9183
9437
|
};
|
9184
9438
|
|
9185
9439
|
// Copyright (c) Microsoft Corporation.
|
9186
|
-
const
|
9187
|
-
|
9188
|
-
|
9189
|
-
|
9190
|
-
|
9191
|
-
|
9192
|
-
|
9193
|
-
|
9440
|
+
const offScreenStyle = {
|
9441
|
+
border: 0,
|
9442
|
+
clip: 'rect(0 0 0 0)',
|
9443
|
+
height: '1px',
|
9444
|
+
margin: '-1px',
|
9445
|
+
overflow: 'hidden',
|
9446
|
+
whiteSpace: 'nowrap',
|
9447
|
+
padding: 0,
|
9448
|
+
width: '1px',
|
9449
|
+
position: 'absolute'
|
9194
9450
|
};
|
9195
|
-
/**
|
9196
|
-
|
9197
|
-
|
9198
|
-
|
9199
|
-
|
9200
|
-
|
9201
|
-
|
9202
|
-
|
9203
|
-
|
9204
|
-
const
|
9205
|
-
const
|
9206
|
-
const
|
9207
|
-
const
|
9208
|
-
const
|
9209
|
-
const chatMyMessageStyles = useChatMyMessageStyles();
|
9451
|
+
/** @private */
|
9452
|
+
const MessageBlock = (props) => (React__default["default"].createElement("div", { style: offScreenStyle, role: "log", "aria-live": props.ariaLive }, props.message ? props.message : ''));
|
9453
|
+
|
9454
|
+
// Copyright (c) Microsoft Corporation.
|
9455
|
+
/** @private */
|
9456
|
+
const EMPTY_MESSAGE = { message: '', id: '' };
|
9457
|
+
/** @private */
|
9458
|
+
const Announcer = (props) => {
|
9459
|
+
var _a, _b;
|
9460
|
+
const newAssertive = (_a = props.assertive) !== null && _a !== void 0 ? _a : EMPTY_MESSAGE;
|
9461
|
+
const oldAssertive = React__default["default"].useRef(EMPTY_MESSAGE);
|
9462
|
+
const [activeAssertive1, setActiveAssertive1] = React__default["default"].useState(EMPTY_MESSAGE);
|
9463
|
+
const [activeAssertive2, setActiveAssertive2] = React__default["default"].useState(EMPTY_MESSAGE);
|
9464
|
+
const alternateAssertive = React__default["default"].useRef(false);
|
9210
9465
|
React.useEffect(() => {
|
9211
|
-
|
9212
|
-
|
9213
|
-
|
9214
|
-
|
9215
|
-
|
9216
|
-
|
9217
|
-
|
9218
|
-
|
9219
|
-
|
9220
|
-
const
|
9221
|
-
const
|
9222
|
-
const
|
9223
|
-
|
9224
|
-
|
9225
|
-
|
9226
|
-
|
9227
|
-
|
9228
|
-
|
9229
|
-
|
9230
|
-
|
9231
|
-
|
9232
|
-
|
9233
|
-
|
9234
|
-
|
9235
|
-
|
9236
|
-
const getContent = () => {
|
9237
|
-
return (React__default["default"].createElement(React__default["default"].Fragment, null,
|
9238
|
-
React__default["default"].createElement(InputBoxComponent, { "data-ui-id": "edit-box", textFieldRef: editTextFieldRef, inputClassName: editBoxStyle, placeholderText: strings.editBoxPlaceholderText, textValue: textValue, onChange: setText, onKeyDown: (ev) => {
|
9239
|
-
if (ev.key === 'ArrowUp' || ev.key === 'ArrowDown') {
|
9240
|
-
ev.stopPropagation();
|
9241
|
-
}
|
9242
|
-
}, onEnterKeyDown: () => {
|
9243
|
-
submitEnabled &&
|
9244
|
-
onSubmit(textValue, message.metadata, {
|
9245
|
-
attachedFilesMetadata
|
9246
|
-
});
|
9247
|
-
}, supportNewline: false, maxLength: MAXIMUM_LENGTH_OF_MESSAGE, errorMessage: textTooLongMessage, styles: editBoxStyles,
|
9248
|
-
/* @conditional-compile-remove(mention) */
|
9249
|
-
mentionLookupOptions: mentionLookupOptions }),
|
9250
|
-
React__default["default"].createElement(react.Stack, { horizontal: true, horizontalAlign: "end", className: editChatMessageButtonsStackStyle, tokens: { childrenGap: '0.25rem' } },
|
9251
|
-
message.failureReason && (React__default["default"].createElement(react.Stack.Item, { grow: true, align: "stretch", className: chatMessageFailedTagStackItemStyle },
|
9252
|
-
React__default["default"].createElement("div", { className: react.mergeStyles(chatMessageFailedTagStyle(theme), editChatMessageFailedTagStyle) }, message.failureReason))),
|
9253
|
-
React__default["default"].createElement(react.Stack.Item, { align: "end" },
|
9254
|
-
React__default["default"].createElement(InputBoxButton, { className: editingButtonStyle, ariaLabel: strings.editBoxCancelButton, tooltipContent: strings.editBoxCancelButton, onRenderIcon: onRenderThemedCancelIcon, onClick: () => {
|
9255
|
-
onCancel && onCancel(message.messageId);
|
9256
|
-
}, id: 'dismissIconWrapper' })),
|
9257
|
-
React__default["default"].createElement(react.Stack.Item, { align: "end" },
|
9258
|
-
React__default["default"].createElement(InputBoxButton, { className: editingButtonStyle, ariaLabel: strings.editBoxSubmitButton, tooltipContent: strings.editBoxSubmitButton, onRenderIcon: onRenderThemedSubmitIcon, onClick: (e) => {
|
9259
|
-
submitEnabled &&
|
9260
|
-
onSubmit(textValue, message.metadata, {
|
9261
|
-
attachedFilesMetadata
|
9262
|
-
});
|
9263
|
-
e.stopPropagation();
|
9264
|
-
}, id: 'submitIconWrapper' }))),
|
9265
|
-
onRenderFileUploads()));
|
9266
|
-
};
|
9267
|
-
const bodyClassName = reactComponents.mergeClasses(editContainerStyles.body, message.failureReason !== undefined ? editContainerStyles.bodyError : editContainerStyles.bodyDefault);
|
9268
|
-
return (React__default["default"].createElement(reactChat.ChatMyMessage, { root: {
|
9269
|
-
className: reactComponents.mergeClasses(chatMyMessageStyles.root, editContainerStyles.root)
|
9270
|
-
}, body: {
|
9271
|
-
className: bodyClassName
|
9272
|
-
} }, getContent()));
|
9466
|
+
if (oldAssertive.current.message !== (newAssertive === null || newAssertive === void 0 ? void 0 : newAssertive.message) || oldAssertive.current.id !== (newAssertive === null || newAssertive === void 0 ? void 0 : newAssertive.id)) {
|
9467
|
+
setActiveAssertive1(alternateAssertive.current ? EMPTY_MESSAGE : newAssertive);
|
9468
|
+
setActiveAssertive2(alternateAssertive.current ? newAssertive : EMPTY_MESSAGE);
|
9469
|
+
oldAssertive.current = newAssertive;
|
9470
|
+
alternateAssertive.current = !alternateAssertive.current;
|
9471
|
+
}
|
9472
|
+
}, [newAssertive]);
|
9473
|
+
const newPolite = (_b = props.polite) !== null && _b !== void 0 ? _b : EMPTY_MESSAGE;
|
9474
|
+
const oldPolite = React__default["default"].useRef(EMPTY_MESSAGE);
|
9475
|
+
const [activePolite1, setActivePolite1] = React__default["default"].useState(EMPTY_MESSAGE);
|
9476
|
+
const [activePolite2, setActivePolite2] = React__default["default"].useState(EMPTY_MESSAGE);
|
9477
|
+
const alternatePolite = React__default["default"].useRef(false);
|
9478
|
+
React.useEffect(() => {
|
9479
|
+
if (oldPolite.current.message !== (newPolite === null || newPolite === void 0 ? void 0 : newPolite.message) || oldPolite.current.id !== (newPolite === null || newPolite === void 0 ? void 0 : newPolite.id)) {
|
9480
|
+
setActivePolite1(alternatePolite.current ? EMPTY_MESSAGE : newPolite);
|
9481
|
+
setActivePolite2(alternatePolite.current ? newPolite : EMPTY_MESSAGE);
|
9482
|
+
oldPolite.current = newPolite;
|
9483
|
+
alternatePolite.current = !alternatePolite.current;
|
9484
|
+
}
|
9485
|
+
}, [newPolite]);
|
9486
|
+
return (React__default["default"].createElement("div", null,
|
9487
|
+
React__default["default"].createElement(MessageBlock, { ariaLive: "assertive", message: activeAssertive1.message }),
|
9488
|
+
React__default["default"].createElement(MessageBlock, { ariaLive: "assertive", message: activeAssertive2.message }),
|
9489
|
+
React__default["default"].createElement(MessageBlock, { ariaLive: "polite", message: activePolite1.message }),
|
9490
|
+
React__default["default"].createElement(MessageBlock, { ariaLive: "polite", message: activePolite2.message })));
|
9273
9491
|
};
|
9274
|
-
|
9275
|
-
|
9276
|
-
|
9277
|
-
|
9278
|
-
const
|
9279
|
-
|
9280
|
-
|
9492
|
+
|
9493
|
+
// Copyright (c) Microsoft Corporation.
|
9494
|
+
/** @private */
|
9495
|
+
const LiveAnnouncer = (props) => {
|
9496
|
+
const [politeMessage, setPoliteMessage] = React__default["default"].useState(EMPTY_MESSAGE);
|
9497
|
+
const [assertiveMessage, setAssertiveMessage] = React__default["default"].useState(EMPTY_MESSAGE);
|
9498
|
+
const announcePolite = React.useCallback((message, id) => {
|
9499
|
+
setPoliteMessage({ message, id });
|
9500
|
+
}, []);
|
9501
|
+
const announceAssertive = React.useCallback((message, id) => {
|
9502
|
+
setAssertiveMessage({ message, id });
|
9503
|
+
}, []);
|
9504
|
+
const updateFunctions = React.useMemo(() => ({
|
9505
|
+
announcePolite,
|
9506
|
+
announceAssertive
|
9507
|
+
}), [announceAssertive, announcePolite]);
|
9508
|
+
return (React__default["default"].createElement(AnnouncerContext.Provider, { value: updateFunctions },
|
9509
|
+
props.children,
|
9510
|
+
React__default["default"].createElement(Announcer, { assertive: assertiveMessage, polite: politeMessage })));
|
9281
9511
|
};
|
9282
9512
|
|
9283
9513
|
// Copyright (c) Microsoft Corporation.
|
9284
9514
|
// Licensed under the MIT License.
|
9285
9515
|
/**
|
9516
|
+
* Function to create a React.CSSProperties object from a v8 style object.
|
9517
|
+
* This function is still not ideal
|
9518
|
+
* as v8Style can use pseudo-class selectors that style objects can't process correctly.
|
9519
|
+
*
|
9286
9520
|
* @private
|
9287
9521
|
*/
|
9288
|
-
|
9289
|
-
|
9290
|
-
|
9522
|
+
function createStyleFromV8Style(v8Style) {
|
9523
|
+
const result = {};
|
9524
|
+
if (v8Style === undefined || v8Style === null || typeof v8Style === 'boolean' || typeof v8Style === 'string') {
|
9525
|
+
return undefined;
|
9526
|
+
}
|
9527
|
+
else if (typeof v8Style === 'object') {
|
9528
|
+
// v8Style is a style object
|
9529
|
+
for (const record in v8Style) {
|
9530
|
+
if (typeof v8Style[record] === 'string') {
|
9531
|
+
// v8Style[record] is just a simple style
|
9532
|
+
const msSuffix = 'MS';
|
9533
|
+
if (record.startsWith(msSuffix)) {
|
9534
|
+
// React.CSSProperties uses camelCase for MS properties but v8Style uses PascalCase
|
9535
|
+
const newRecord = record.substring(0, msSuffix.length).toLowerCase + record.substring(msSuffix.length);
|
9536
|
+
result[newRecord] = v8Style[record];
|
9537
|
+
}
|
9538
|
+
else {
|
9539
|
+
result[record] = v8Style[record];
|
9540
|
+
}
|
9541
|
+
}
|
9542
|
+
else {
|
9543
|
+
result[record] = createStyleFromV8Style(v8Style[record]);
|
9544
|
+
}
|
9545
|
+
}
|
9546
|
+
}
|
9547
|
+
return result;
|
9548
|
+
}
|
9549
|
+
|
9550
|
+
// Copyright (c) Microsoft Corporation.
|
9291
9551
|
/**
|
9292
9552
|
* @private
|
9293
9553
|
*/
|
9294
|
-
const
|
9295
|
-
|
9296
|
-
|
9554
|
+
const editBoxStyle = react.mergeStyles({
|
9555
|
+
marginTop: '0.0875rem',
|
9556
|
+
marginBottom: '0.0875rem'
|
9557
|
+
});
|
9297
9558
|
/**
|
9298
|
-
* Given a message date object in ISO8601 and a current date object, generates a user friendly timestamp text
|
9299
|
-
* using the system locale.
|
9300
|
-
* <time in locale format>.
|
9301
|
-
* Yesterday <time in locale format>.
|
9302
|
-
* <dateStrings day of week> <time in locale format>.
|
9303
|
-
* <date in locale format> <time in locale format>.
|
9304
|
-
*
|
9305
|
-
* If message is after yesterday, then only show the time.
|
9306
|
-
* If message is before yesterday and after day before yesterday, then show 'Yesterday' plus the time.
|
9307
|
-
* If message is before day before yesterday and within the current week, then show 'Monday/Tuesday/etc' plus the time.
|
9308
|
-
* - We consider start of the week as Sunday. If current day is Sunday, then any time before that is in previous week.
|
9309
|
-
* If message is in previous or older weeks, then show date string plus the time.
|
9310
|
-
*
|
9311
|
-
* @param messageDate - date of message
|
9312
|
-
* @param currentDate - date used as offset to create the user friendly timestamp (e.g. to create 'Yesterday' instead of an absolute date)
|
9313
|
-
*
|
9314
9559
|
* @private
|
9315
9560
|
*/
|
9316
|
-
const
|
9317
|
-
|
9318
|
-
|
9319
|
-
|
9320
|
-
|
9561
|
+
const editingButtonStyle = react.mergeStyles({
|
9562
|
+
margin: '0',
|
9563
|
+
width: '2.125rem',
|
9564
|
+
height: '2.125rem',
|
9565
|
+
padding: '0.375rem 0 0 0'
|
9566
|
+
});
|
9567
|
+
/**
|
9568
|
+
* @private
|
9569
|
+
*/
|
9570
|
+
const inputBoxIcon = react.mergeStyles({
|
9571
|
+
margin: 'auto',
|
9572
|
+
'&:hover svg': {
|
9573
|
+
stroke: 'currentColor'
|
9321
9574
|
}
|
9322
|
-
|
9323
|
-
|
9324
|
-
|
9325
|
-
|
9326
|
-
|
9327
|
-
|
9328
|
-
|
9329
|
-
|
9330
|
-
if (weekDay === 0) {
|
9331
|
-
return formatDateForChatMessage(messageDate) + ' ' + formatTimeForChatMessage(messageDate);
|
9332
|
-
}
|
9333
|
-
// If message was before first day of the week then timestamp string is like Monday 1:30 p.m.
|
9334
|
-
const firstDayOfTheWeekDate = new Date(todayDate.getFullYear(), todayDate.getMonth(), todayDate.getDate() - weekDay);
|
9335
|
-
if (messageDate > firstDayOfTheWeekDate) {
|
9336
|
-
return dayToDayName(messageDate.getDay(), dateStrings) + ' ' + formatTimeForChatMessage(messageDate);
|
9337
|
-
}
|
9338
|
-
// If message date is in previous or older weeks then timestamp string is like 2021-01-10 1:30 p.m.
|
9339
|
-
return formatDateForChatMessage(messageDate) + ' ' + formatTimeForChatMessage(messageDate);
|
9340
|
-
};
|
9341
|
-
const dayToDayName = (day, dateStrings) => {
|
9342
|
-
switch (day) {
|
9343
|
-
case 0:
|
9344
|
-
return dateStrings.sunday;
|
9345
|
-
case 1:
|
9346
|
-
return dateStrings.monday;
|
9347
|
-
case 2:
|
9348
|
-
return dateStrings.tuesday;
|
9349
|
-
case 3:
|
9350
|
-
return dateStrings.wednesday;
|
9351
|
-
case 4:
|
9352
|
-
return dateStrings.thursday;
|
9353
|
-
case 5:
|
9354
|
-
return dateStrings.friday;
|
9355
|
-
case 6:
|
9356
|
-
return dateStrings.saturday;
|
9357
|
-
default:
|
9358
|
-
throw new Error(`Invalid day [${day}] passed`);
|
9575
|
+
});
|
9576
|
+
/**
|
9577
|
+
* @private
|
9578
|
+
*/
|
9579
|
+
const editBoxStyleSet = {
|
9580
|
+
root: {
|
9581
|
+
minWidth: '6.25rem',
|
9582
|
+
maxWidth: '100%'
|
9359
9583
|
}
|
9360
9584
|
};
|
9361
9585
|
|
9362
9586
|
// Copyright (c) Microsoft Corporation.
|
9587
|
+
const MINIMUM_TOUCH_TARGET_HEIGHT_REM$1 = 3;
|
9588
|
+
const errorTextColor = 'var(--errorText)';
|
9363
9589
|
/**
|
9364
|
-
* Chat message actions flyout that contains actions such as Edit Message, or Remove Message.
|
9365
|
-
*
|
9366
9590
|
* @private
|
9367
9591
|
*/
|
9368
|
-
const
|
9369
|
-
|
9370
|
-
|
9371
|
-
|
9372
|
-
|
9373
|
-
|
9374
|
-
|
9375
|
-
|
9376
|
-
|
9377
|
-
|
9378
|
-
showOverflowTooltip: false,
|
9379
|
-
styles: {
|
9380
|
-
root: {
|
9381
|
-
margin: '0.25rem'
|
9382
|
-
}
|
9383
|
-
}
|
9384
|
-
};
|
9385
|
-
const { onRenderAvatar } = props;
|
9386
|
-
return {
|
9387
|
-
'data-ui-id': 'chat-composite-message-contextual-menu-read-name-list-item',
|
9388
|
-
key: person.displayName,
|
9389
|
-
text: person.displayName,
|
9390
|
-
itemProps: { styles: props.increaseFlyoutItemSize ? menuItemIncreasedSizeStyles : undefined },
|
9391
|
-
onRenderIcon: () => { var _a; return onRenderAvatar ? onRenderAvatar((_a = person.id) !== null && _a !== void 0 ? _a : '', personaOptions) : React__default["default"].createElement(react.Persona, Object.assign({}, personaOptions)); },
|
9392
|
-
iconProps: {
|
9393
|
-
styles: menuIconStyleSet
|
9394
|
-
}
|
9395
|
-
};
|
9396
|
-
});
|
9397
|
-
const menuItems = React.useMemo(() => {
|
9398
|
-
const items = [
|
9399
|
-
{
|
9400
|
-
key: 'Edit',
|
9401
|
-
'data-ui-id': 'chat-composite-message-contextual-menu-edit-action',
|
9402
|
-
text: props.strings.editMessage,
|
9403
|
-
itemProps: {
|
9404
|
-
styles: props.increaseFlyoutItemSize ? menuItemIncreasedSizeStyles : undefined
|
9405
|
-
},
|
9406
|
-
iconProps: { iconName: 'MessageEdit', styles: menuIconStyleSet },
|
9407
|
-
onClick: props.onEditClick
|
9408
|
-
},
|
9409
|
-
{
|
9410
|
-
key: 'Remove',
|
9411
|
-
text: props.strings.removeMessage,
|
9412
|
-
itemProps: { styles: props.increaseFlyoutItemSize ? menuItemIncreasedSizeStyles : undefined },
|
9413
|
-
iconProps: {
|
9414
|
-
iconName: 'MessageRemove',
|
9415
|
-
styles: menuIconStyleSet
|
9416
|
-
},
|
9417
|
-
onClick: props.onRemoveClick
|
9418
|
-
}
|
9419
|
-
];
|
9420
|
-
// only show read by x of x if more than 3 participants in total including myself
|
9421
|
-
// TODO: change strings.messageReadCount to be required if we can fallback to our own en-us strings for anything that Contoso doesn't provide
|
9422
|
-
if (props.remoteParticipantsCount &&
|
9423
|
-
messageReadByCount !== undefined &&
|
9424
|
-
props.remoteParticipantsCount >= 2 &&
|
9425
|
-
props.showMessageStatus &&
|
9426
|
-
props.strings.messageReadCount &&
|
9427
|
-
props.messageStatus !== 'failed') {
|
9428
|
-
items.push({
|
9429
|
-
key: 'Read Count',
|
9430
|
-
'data-ui-id': 'chat-composite-message-contextual-menu-read-info',
|
9431
|
-
text: _formatString(props.strings.messageReadCount, {
|
9432
|
-
messageReadByCount: `${messageReadByCount}`,
|
9433
|
-
remoteParticipantsCount: `${props.remoteParticipantsCount}`
|
9434
|
-
}),
|
9435
|
-
itemProps: {
|
9436
|
-
styles: react.concatStyleSets({
|
9437
|
-
linkContent: {
|
9438
|
-
color: messageReadByCount > 0 ? theme.palette.neutralPrimary : theme.palette.neutralTertiary
|
9439
|
-
},
|
9440
|
-
root: {
|
9441
|
-
borderTop: `1px solid ${theme.palette.neutralLighter}`
|
9442
|
-
}
|
9443
|
-
}, props.increaseFlyoutItemSize ? menuItemIncreasedSizeStyles : undefined)
|
9444
|
-
},
|
9445
|
-
calloutProps: preventUnwantedDismissProps,
|
9446
|
-
subMenuProps: {
|
9447
|
-
items: messageReadByList !== null && messageReadByList !== void 0 ? messageReadByList : [],
|
9448
|
-
calloutProps: preventUnwantedDismissProps,
|
9449
|
-
styles: react.concatStyleSets({
|
9450
|
-
root: {
|
9451
|
-
maxWidth: _pxToRem(320),
|
9452
|
-
span: {
|
9453
|
-
overflow: 'hidden',
|
9454
|
-
textOverflow: 'ellipsis'
|
9455
|
-
}
|
9456
|
-
}
|
9457
|
-
})
|
9458
|
-
},
|
9459
|
-
iconProps: {
|
9460
|
-
iconName: 'MessageSeen',
|
9461
|
-
styles: {
|
9462
|
-
root: {
|
9463
|
-
color: messageReadByCount > 0 ? theme.palette.themeDarkAlt : theme.palette.neutralTertiary
|
9464
|
-
}
|
9465
|
-
}
|
9466
|
-
},
|
9467
|
-
submenuIconProps: {
|
9468
|
-
iconName: 'HorizontalGalleryRightButton',
|
9469
|
-
styles: menuSubIconStyleSet
|
9470
|
-
},
|
9471
|
-
disabled: messageReadByCount <= 0
|
9472
|
-
});
|
9473
|
-
}
|
9474
|
-
else if (props.messageStatus === 'failed' && props.strings.resendMessage) {
|
9475
|
-
items.push({
|
9476
|
-
key: 'Resend',
|
9477
|
-
text: props.strings.resendMessage,
|
9478
|
-
itemProps: {
|
9479
|
-
styles: react.concatStyleSets({
|
9480
|
-
linkContent: {
|
9481
|
-
color: theme.palette.neutralPrimary
|
9482
|
-
},
|
9483
|
-
root: {
|
9484
|
-
borderTop: `1px solid ${theme.palette.neutralLighter}`
|
9485
|
-
}
|
9486
|
-
}, props.increaseFlyoutItemSize ? menuItemIncreasedSizeStyles : undefined)
|
9487
|
-
},
|
9488
|
-
calloutProps: preventUnwantedDismissProps,
|
9489
|
-
iconProps: {
|
9490
|
-
iconName: 'MessageResend',
|
9491
|
-
styles: {
|
9492
|
-
root: {
|
9493
|
-
color: theme.palette.themeDarkAlt
|
9494
|
-
}
|
9495
|
-
}
|
9496
|
-
},
|
9497
|
-
onClick: props.onResendClick
|
9498
|
-
});
|
9592
|
+
const iconWrapperStyle = (theme, isSubMenuOpen) => ({
|
9593
|
+
root: {
|
9594
|
+
margin: _pxToRem(3),
|
9595
|
+
// Show hover styles when the Edit/Delete menu is showing as this action button is still considered 'active'
|
9596
|
+
color: isSubMenuOpen ? theme.palette.black : theme.palette.neutralPrimary,
|
9597
|
+
strokeWidth: isSubMenuOpen ? _pxToRem(0.5) : _pxToRem(0),
|
9598
|
+
stroke: theme.palette.black,
|
9599
|
+
':hover, :focus': {
|
9600
|
+
color: theme.palette.black,
|
9601
|
+
strokeWidth: _pxToRem(0.5)
|
9499
9602
|
}
|
9500
|
-
|
9501
|
-
|
9502
|
-
props.strings.editMessage,
|
9503
|
-
props.strings.removeMessage,
|
9504
|
-
props.strings.messageReadCount,
|
9505
|
-
props.strings.resendMessage,
|
9506
|
-
props.messageStatus,
|
9507
|
-
props.increaseFlyoutItemSize,
|
9508
|
-
props.onEditClick,
|
9509
|
-
props.onRemoveClick,
|
9510
|
-
props.onResendClick,
|
9511
|
-
props.remoteParticipantsCount,
|
9512
|
-
props.showMessageStatus,
|
9513
|
-
messageReadByCount,
|
9514
|
-
theme.palette.neutralPrimary,
|
9515
|
-
theme.palette.neutralTertiary,
|
9516
|
-
theme.palette.neutralLighter,
|
9517
|
-
theme.palette.themeDarkAlt,
|
9518
|
-
messageReadByList
|
9519
|
-
]);
|
9520
|
-
// gap space uses pixels
|
9521
|
-
return (React__default["default"].createElement(react.ContextualMenu, { alignTargetEdge: true, gapSpace: 2 /*px*/, isBeakVisible: false, items: menuItems, hidden: props.hidden, target: props.target, onDismiss: props.onDismiss, directionalHint: react.DirectionalHint.topRightEdge, className: chatMessageMenuStyle, calloutProps: calloutMenuProps }));
|
9522
|
-
};
|
9603
|
+
}
|
9604
|
+
});
|
9523
9605
|
/**
|
9524
|
-
*
|
9606
|
+
* @private
|
9525
9607
|
*/
|
9526
|
-
const
|
9527
|
-
|
9528
|
-
|
9529
|
-
|
9530
|
-
};
|
9531
|
-
const calloutMenuProps = Object.assign(Object.assign({}, preventUnwantedDismissProps), { styles: { root: { marginRight: '3px' } } });
|
9532
|
-
|
9533
|
-
// Copyright (c) Microsoft Corporation.
|
9608
|
+
const chatMessageDateStyle = react.mergeStyles({
|
9609
|
+
color: reactComponents.tokens.colorNeutralForeground2,
|
9610
|
+
fontWeight: react.FontWeights.regular,
|
9611
|
+
fontSize: '0.75rem'
|
9612
|
+
});
|
9534
9613
|
/**
|
9535
|
-
* Provides the default implementation for rendering an Mention in a message thread
|
9536
|
-
* @param mention - The mention to render
|
9537
|
-
*
|
9538
9614
|
* @private
|
9539
9615
|
*/
|
9540
|
-
const
|
9541
|
-
|
9542
|
-
|
9543
|
-
|
9544
|
-
};
|
9545
|
-
|
9546
|
-
// Copyright (c) Microsoft Corporation.
|
9547
|
-
/** @private */
|
9548
|
-
const ChatMessageContent = (props) => {
|
9549
|
-
switch (props.message.contentType) {
|
9550
|
-
case 'text':
|
9551
|
-
return MessageContentAsText(props);
|
9552
|
-
case 'html':
|
9553
|
-
return MessageContentAsRichTextHTML(props);
|
9554
|
-
case 'richtext/html':
|
9555
|
-
return MessageContentAsRichTextHTML(props);
|
9556
|
-
default:
|
9557
|
-
console.warn('unknown message content type');
|
9558
|
-
return React__default["default"].createElement(React__default["default"].Fragment, null);
|
9559
|
-
}
|
9560
|
-
};
|
9561
|
-
const MessageContentWithLiveAria = (props) => {
|
9562
|
-
return (React__default["default"].createElement("div", { "data-ui-status": props.message.status, role: "text", "aria-label": props.ariaLabel },
|
9563
|
-
React__default["default"].createElement(LiveMessage, { message: props.liveMessage, ariaLive: "polite" }),
|
9564
|
-
props.content));
|
9565
|
-
};
|
9566
|
-
const MessageContentAsRichTextHTML = (props) => {
|
9567
|
-
/* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
|
9568
|
-
React.useEffect(() => {
|
9569
|
-
var _a;
|
9570
|
-
const attachments = (_a = props.message.attachedFilesMetadata) === null || _a === void 0 ? void 0 : _a.filter((fileMetadata) => {
|
9571
|
-
return fileMetadata.attachmentType === 'inlineImage';
|
9572
|
-
});
|
9573
|
-
if (props.attachmentsMap && attachments) {
|
9574
|
-
attachments.forEach((fileMetadata) => {
|
9575
|
-
if (props.onFetchAttachment && props.attachmentsMap && props.attachmentsMap[fileMetadata.id] === undefined) {
|
9576
|
-
props.onFetchAttachment([fileMetadata], props.message.messageId);
|
9577
|
-
return;
|
9578
|
-
}
|
9579
|
-
});
|
9580
|
-
}
|
9581
|
-
}, [props]);
|
9582
|
-
return (React__default["default"].createElement(MessageContentWithLiveAria, { message: props.message, liveMessage: generateLiveMessage(props), ariaLabel: messageContentAriaText(props), content: processHtmlToReact(props) }));
|
9583
|
-
};
|
9584
|
-
const MessageContentAsText = (props) => {
|
9585
|
-
return (React__default["default"].createElement(MessageContentWithLiveAria, { message: props.message, liveMessage: generateLiveMessage(props), ariaLabel: messageContentAriaText(props), content: React__default["default"].createElement(Linkify__default["default"], { componentDecorator: (decoratedHref, decoratedText, key) => {
|
9586
|
-
return (React__default["default"].createElement(react.Link, { target: "_blank", href: decoratedHref, key: key }, decoratedText));
|
9587
|
-
} }, props.message.content) }));
|
9588
|
-
};
|
9589
|
-
/* @conditional-compile-remove(data-loss-prevention) */
|
9616
|
+
const chatMessageAuthorStyle = react.mergeStyles({
|
9617
|
+
fontWeight: react.FontWeights.semibold,
|
9618
|
+
fontSize: '0.75rem'
|
9619
|
+
});
|
9590
9620
|
/**
|
9591
9621
|
* @private
|
9592
9622
|
*/
|
9593
|
-
const
|
9594
|
-
|
9595
|
-
|
9596
|
-
|
9597
|
-
|
9598
|
-
|
9599
|
-
|
9600
|
-
|
9601
|
-
|
9602
|
-
|
9603
|
-
|
9604
|
-
|
9605
|
-
|
9606
|
-
|
9607
|
-
|
9608
|
-
|
9609
|
-
|
9610
|
-
|
9611
|
-
|
9612
|
-
|
9613
|
-
|
9614
|
-
|
9615
|
-
|
9616
|
-
|
9617
|
-
|
9618
|
-
const
|
9619
|
-
|
9620
|
-
|
9621
|
-
|
9622
|
-
|
9623
|
-
|
9624
|
-
|
9625
|
-
|
9626
|
-
|
9627
|
-
|
9628
|
-
|
9629
|
-
|
9630
|
-
};
|
9631
|
-
|
9632
|
-
|
9633
|
-
|
9634
|
-
const
|
9635
|
-
|
9636
|
-
|
9637
|
-
var _a;
|
9638
|
-
function isImageNode(file) {
|
9639
|
-
return file.attachmentType === 'inlineImage' && file.id === node.attribs.id;
|
9640
|
-
}
|
9641
|
-
// Process img node with id in attachments list
|
9642
|
-
return (node.name &&
|
9643
|
-
node.name === 'img' &&
|
9644
|
-
node.attribs &&
|
9645
|
-
node.attribs.id &&
|
9646
|
-
((_a = props.message.attachedFilesMetadata) === null || _a === void 0 ? void 0 : _a.find(isImageNode)));
|
9623
|
+
const chatMessageEditedTagStyle = (theme) => react.mergeStyles({ fontWeight: react.FontWeights.semibold, color: theme.palette.neutralSecondary });
|
9624
|
+
/**
|
9625
|
+
* @private
|
9626
|
+
*/
|
9627
|
+
const chatMessageFailedTagStyle = (theme) => react.mergeStyles({
|
9628
|
+
fontWeight: react.FontWeights.regular,
|
9629
|
+
color: theme.semanticColors.errorText,
|
9630
|
+
fontSize: theme.fonts.smallPlus.fontSize,
|
9631
|
+
lineHeight: '1rem'
|
9632
|
+
});
|
9633
|
+
/**
|
9634
|
+
* @private
|
9635
|
+
*/
|
9636
|
+
const editChatMessageFailedTagStyle = react.mergeStyles({
|
9637
|
+
marginBottom: '0.5rem'
|
9638
|
+
});
|
9639
|
+
/**
|
9640
|
+
* @private
|
9641
|
+
*/
|
9642
|
+
const chatMessageFailedTagStackItemStyle = react.mergeStyles({
|
9643
|
+
alignSelf: 'end'
|
9644
|
+
});
|
9645
|
+
/**
|
9646
|
+
* @private
|
9647
|
+
*/
|
9648
|
+
const editChatMessageButtonsStackStyle = react.mergeStyles({
|
9649
|
+
padding: '0 0.5rem',
|
9650
|
+
marginTop: '-0.25rem'
|
9651
|
+
});
|
9652
|
+
/**
|
9653
|
+
* @private
|
9654
|
+
*/
|
9655
|
+
const chatMessageMenuStyle = react.mergeStyles({
|
9656
|
+
minWidth: '8.5rem',
|
9657
|
+
height: 'max-content',
|
9658
|
+
cursor: 'pointer',
|
9659
|
+
overflow: 'hidden'
|
9660
|
+
});
|
9661
|
+
/**
|
9662
|
+
* @private
|
9663
|
+
*/
|
9664
|
+
const useChatMessageEditContainerStyles = reactComponents.makeStyles({
|
9665
|
+
root: {
|
9666
|
+
paddingTop: '1.25rem' //height of the menu button + marginBottom
|
9647
9667
|
},
|
9648
|
-
|
9649
|
-
|
9650
|
-
|
9651
|
-
|
9652
|
-
|
9653
|
-
}
|
9654
|
-
/* @conditional-compile-remove(image-gallery) */
|
9655
|
-
const handleOnClick = () => {
|
9656
|
-
props.onInlineImageClicked && props.onInlineImageClicked(node.attribs.id);
|
9657
|
-
};
|
9658
|
-
/* @conditional-compile-remove(image-gallery) */
|
9659
|
-
return (React__default["default"].createElement("span", { "data-ui-id": node.attribs.id, onClick: handleOnClick, tabIndex: 0, role: "button", style: {
|
9660
|
-
cursor: 'pointer'
|
9661
|
-
}, onKeyDown: (e) => {
|
9662
|
-
if (e.key === 'Enter') {
|
9663
|
-
handleOnClick();
|
9664
|
-
}
|
9665
|
-
} }, processNodeDefinitions.processDefaultNode(node, children, index)));
|
9666
|
-
}
|
9668
|
+
body: Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, reactComponents.shorthands.padding(0)), { backgroundColor: 'transparent', boxSizing: 'border-box' }), reactComponents.shorthands.border(`${defaultSendBoxInactiveBorderThicknessREM}rem`, 'solid')), reactComponents.shorthands.borderRadius(reactComponents.tokens.borderRadiusMedium)), reactComponents.shorthands.margin(`${defaultSendBoxActiveBorderThicknessREM - defaultSendBoxInactiveBorderThicknessREM}rem`)), {
|
9669
|
+
// Width should be updated on hover to include the border width change
|
9670
|
+
width: `calc(100% - ${defaultSendBoxActiveBorderThicknessREM}rem)`, '&:hover, &:active, &:focus, &:focus-within': Object.assign(Object.assign(Object.assign({}, reactComponents.shorthands.margin('0rem')), reactComponents.shorthands.borderWidth(`${defaultSendBoxActiveBorderThicknessREM}rem`)), { width: '100%' }) }),
|
9671
|
+
bodyError: Object.assign({}, reactComponents.shorthands.borderColor(errorTextColor)),
|
9672
|
+
bodyDefault: Object.assign(Object.assign({}, reactComponents.shorthands.borderColor(reactComponents.tokens.colorNeutralStrokeAccessible)), { '&:hover, &:active, &:focus, &:focus-within': Object.assign({}, reactComponents.shorthands.borderColor(reactComponents.tokens.colorCompoundBrandStroke)) })
|
9667
9673
|
});
|
9668
|
-
|
9669
|
-
|
9670
|
-
|
9671
|
-
|
9672
|
-
|
9673
|
-
|
9674
|
-
|
9675
|
-
}
|
9676
|
-
|
9674
|
+
/**
|
9675
|
+
* Styles that can be applied to ensure flyout items have the minimum touch target size.
|
9676
|
+
*
|
9677
|
+
* @private
|
9678
|
+
*/
|
9679
|
+
const menuItemIncreasedSizeStyles = {
|
9680
|
+
root: {
|
9681
|
+
height: `${MINIMUM_TOUCH_TARGET_HEIGHT_REM$1}rem`,
|
9682
|
+
lineHeight: `${MINIMUM_TOUCH_TARGET_HEIGHT_REM$1}rem`,
|
9683
|
+
maxHeight: 'unset'
|
9677
9684
|
},
|
9678
|
-
|
9679
|
-
|
9680
|
-
|
9681
|
-
|
9682
|
-
|
9683
|
-
|
9684
|
-
|
9685
|
-
};
|
9686
|
-
return props.mentionDisplayOptions.onRenderMention(mention, defaultOnMentionRender);
|
9687
|
-
}
|
9688
|
-
return processNodeDefinitions.processDefaultNode;
|
9685
|
+
linkContent: {
|
9686
|
+
height: `${MINIMUM_TOUCH_TARGET_HEIGHT_REM$1}rem`,
|
9687
|
+
lineHeight: `${MINIMUM_TOUCH_TARGET_HEIGHT_REM$1}rem`,
|
9688
|
+
maxHeight: 'unset'
|
9689
|
+
},
|
9690
|
+
icon: {
|
9691
|
+
maxHeight: 'unset'
|
9689
9692
|
}
|
9690
|
-
});
|
9691
|
-
const processHtmlToReact = (props) => {
|
9692
|
-
var _a;
|
9693
|
-
const steps = [
|
9694
|
-
/* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
|
9695
|
-
processInlineImage(props),
|
9696
|
-
/* @conditional-compile-remove(mention) */
|
9697
|
-
processMention(props),
|
9698
|
-
{
|
9699
|
-
// Process everything else in the default way
|
9700
|
-
shouldProcessNode: htmlToReact.IsValidNodeDefinitions.alwaysValid,
|
9701
|
-
processNode: processNodeDefinitions.processDefaultNode
|
9702
|
-
}
|
9703
|
-
];
|
9704
|
-
return htmlToReactParser.parseWithInstructions((_a = props.message.content) !== null && _a !== void 0 ? _a : '', htmlToReact.IsValidNodeDefinitions.alwaysValid, steps);
|
9705
9693
|
};
|
9706
|
-
|
9707
|
-
// Copyright (c) Microsoft Corporation.
|
9708
9694
|
/**
|
9709
|
-
* Props for the Chat.Message action menu.
|
9710
|
-
* This is the 3 dots that appear when hovering over one of your own chat messages.
|
9711
|
-
*
|
9712
9695
|
* @private
|
9713
9696
|
*/
|
9714
|
-
const
|
9715
|
-
|
9716
|
-
|
9717
|
-
|
9718
|
-
|
9719
|
-
|
9720
|
-
|
9721
|
-
|
9722
|
-
|
9723
|
-
|
9724
|
-
|
9725
|
-
|
9726
|
-
|
9697
|
+
const menuIconStyleSet = {
|
9698
|
+
root: {
|
9699
|
+
height: 'calc(100% - 8px)',
|
9700
|
+
width: '1.25rem'
|
9701
|
+
}
|
9702
|
+
};
|
9703
|
+
/**
|
9704
|
+
* @private
|
9705
|
+
*/
|
9706
|
+
const menuSubIconStyleSet = {
|
9707
|
+
root: {
|
9708
|
+
height: 'unset',
|
9709
|
+
lineHeight: '100%',
|
9710
|
+
width: '1.25rem'
|
9711
|
+
}
|
9727
9712
|
};
|
9728
9713
|
|
9729
9714
|
// Copyright (c) Microsoft Corporation.
|
9730
|
-
|
9731
|
-
|
9732
|
-
|
9733
|
-
return
|
9734
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
9735
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
9736
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
9737
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
9738
|
-
});
|
9715
|
+
const MAXIMUM_LENGTH_OF_MESSAGE = 8000;
|
9716
|
+
const onRenderCancelIcon = (color) => {
|
9717
|
+
const className = react.mergeStyles(inputBoxIcon, { color });
|
9718
|
+
return React__default["default"].createElement(react.Icon, { iconName: 'EditBoxCancel', className: className });
|
9739
9719
|
};
|
9740
|
-
const
|
9741
|
-
|
9720
|
+
const onRenderSubmitIcon = (color) => {
|
9721
|
+
const className = react.mergeStyles(inputBoxIcon, { color });
|
9722
|
+
return React__default["default"].createElement(react.Icon, { iconName: 'EditBoxSubmit', className: className });
|
9742
9723
|
};
|
9743
|
-
const actionIconStyle = { height: '1rem' };
|
9744
9724
|
/**
|
9745
|
-
* @
|
9725
|
+
* @private
|
9746
9726
|
*/
|
9747
|
-
const
|
9748
|
-
|
9749
|
-
|
9750
|
-
const
|
9751
|
-
const
|
9752
|
-
const
|
9753
|
-
|
9754
|
-
|
9755
|
-
|
9756
|
-
const
|
9757
|
-
|
9758
|
-
|
9759
|
-
|
9760
|
-
/* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
|
9761
|
-
const isShowDownloadIcon = React.useCallback((attachment) => {
|
9727
|
+
const ChatMessageComponentAsEditBox = (props) => {
|
9728
|
+
const { onCancel, onSubmit, strings, message } = props;
|
9729
|
+
/* @conditional-compile-remove(mention) */
|
9730
|
+
const { mentionLookupOptions } = props;
|
9731
|
+
const [textValue, setTextValue] = React.useState(message.content || '');
|
9732
|
+
const [attachedFilesMetadata, setAttachedFilesMetadata] = React__default["default"].useState(getMessageAttachedFilesMetadata(message));
|
9733
|
+
const editTextFieldRef = React__default["default"].useRef(null);
|
9734
|
+
const theme = useTheme();
|
9735
|
+
const messageState = getMessageState(textValue, attachedFilesMetadata !== null && attachedFilesMetadata !== void 0 ? attachedFilesMetadata : []);
|
9736
|
+
const submitEnabled = messageState === 'OK';
|
9737
|
+
const editContainerStyles = useChatMessageEditContainerStyles();
|
9738
|
+
const chatMyMessageStyles = useChatMyMessageStyles();
|
9739
|
+
React.useEffect(() => {
|
9762
9740
|
var _a;
|
9763
|
-
|
9764
|
-
return attachment.attachmentType === 'fileSharing' && ((_a = attachment.payload) === null || _a === void 0 ? void 0 : _a.teamsFileAttachment) !== 'true';
|
9741
|
+
(_a = editTextFieldRef.current) === null || _a === void 0 ? void 0 : _a.focus();
|
9765
9742
|
}, []);
|
9766
|
-
const
|
9767
|
-
|
9768
|
-
|
9769
|
-
|
9770
|
-
|
9771
|
-
|
9772
|
-
|
9773
|
-
|
9774
|
-
const
|
9775
|
-
|
9776
|
-
|
9777
|
-
|
9778
|
-
|
9779
|
-
|
9780
|
-
|
9781
|
-
|
9782
|
-
|
9783
|
-
|
9784
|
-
|
9785
|
-
|
9786
|
-
|
9787
|
-
|
9788
|
-
|
9789
|
-
|
9790
|
-
|
9791
|
-
|
9792
|
-
|
9793
|
-
|
9794
|
-
|
9795
|
-
|
9796
|
-
|
9797
|
-
|
9798
|
-
|
9799
|
-
|
9800
|
-
|
9801
|
-
|
9802
|
-
|
9803
|
-
.
|
9804
|
-
|
9805
|
-
|
9806
|
-
|
9807
|
-
|
9808
|
-
|
9809
|
-
|
9810
|
-
|
9743
|
+
const setText = (event, newValue) => {
|
9744
|
+
setTextValue(newValue !== null && newValue !== void 0 ? newValue : '');
|
9745
|
+
};
|
9746
|
+
const textTooLongMessage = messageState === 'too long'
|
9747
|
+
? _formatString(strings.editBoxTextLimit, { limitNumber: `${MAXIMUM_LENGTH_OF_MESSAGE}` })
|
9748
|
+
: undefined;
|
9749
|
+
const onRenderThemedCancelIcon = React.useCallback((isHover) => onRenderCancelIcon(isHover ? theme.palette.accent : theme.palette.neutralSecondary), [theme.palette.neutralSecondary, theme.palette.accent]);
|
9750
|
+
const onRenderThemedSubmitIcon = React.useCallback((isHover) => onRenderSubmitIcon(isHover ? theme.palette.accent : theme.palette.neutralSecondary), [theme.palette.neutralSecondary, theme.palette.accent]);
|
9751
|
+
const editBoxStyles = React.useMemo(() => {
|
9752
|
+
return react.concatStyleSets(editBoxStyleSet, { textField: { borderColor: theme.palette.themePrimary } });
|
9753
|
+
}, [theme.palette.themePrimary]);
|
9754
|
+
const onRenderFileUploads = React.useCallback(() => {
|
9755
|
+
return (!!attachedFilesMetadata &&
|
9756
|
+
attachedFilesMetadata.length > 0 && (React__default["default"].createElement("div", { style: { margin: '0.25rem' } },
|
9757
|
+
React__default["default"].createElement(_FileUploadCards, { activeFileUploads: attachedFilesMetadata === null || attachedFilesMetadata === void 0 ? void 0 : attachedFilesMetadata.map((file) => ({
|
9758
|
+
id: file.name,
|
9759
|
+
filename: file.name,
|
9760
|
+
progress: 1
|
9761
|
+
})), onCancelFileUpload: (fileId) => {
|
9762
|
+
setAttachedFilesMetadata(attachedFilesMetadata === null || attachedFilesMetadata === void 0 ? void 0 : attachedFilesMetadata.filter((file) => file.name !== fileId));
|
9763
|
+
} }))));
|
9764
|
+
}, [attachedFilesMetadata]);
|
9765
|
+
const getContent = () => {
|
9766
|
+
return (React__default["default"].createElement(React__default["default"].Fragment, null,
|
9767
|
+
React__default["default"].createElement(InputBoxComponent, { "data-ui-id": "edit-box", textFieldRef: editTextFieldRef, inputClassName: editBoxStyle, placeholderText: strings.editBoxPlaceholderText, textValue: textValue, onChange: setText, onKeyDown: (ev) => {
|
9768
|
+
if (ev.key === 'ArrowUp' || ev.key === 'ArrowDown') {
|
9769
|
+
ev.stopPropagation();
|
9770
|
+
}
|
9771
|
+
}, onEnterKeyDown: () => {
|
9772
|
+
submitEnabled &&
|
9773
|
+
onSubmit(textValue, message.metadata, {
|
9774
|
+
attachedFilesMetadata
|
9775
|
+
});
|
9776
|
+
}, supportNewline: false, maxLength: MAXIMUM_LENGTH_OF_MESSAGE, errorMessage: textTooLongMessage, styles: editBoxStyles,
|
9777
|
+
/* @conditional-compile-remove(mention) */
|
9778
|
+
mentionLookupOptions: mentionLookupOptions }),
|
9779
|
+
React__default["default"].createElement(react.Stack, { horizontal: true, horizontalAlign: "end", className: editChatMessageButtonsStackStyle, tokens: { childrenGap: '0.25rem' } },
|
9780
|
+
message.failureReason && (React__default["default"].createElement(react.Stack.Item, { grow: true, align: "stretch", className: chatMessageFailedTagStackItemStyle },
|
9781
|
+
React__default["default"].createElement("div", { className: react.mergeStyles(chatMessageFailedTagStyle(theme), editChatMessageFailedTagStyle) }, message.failureReason))),
|
9782
|
+
React__default["default"].createElement(react.Stack.Item, { align: "end" },
|
9783
|
+
React__default["default"].createElement(InputBoxButton, { className: editingButtonStyle, ariaLabel: strings.editBoxCancelButton, tooltipContent: strings.editBoxCancelButton, onRenderIcon: onRenderThemedCancelIcon, onClick: () => {
|
9784
|
+
onCancel && onCancel(message.messageId);
|
9785
|
+
}, id: 'dismissIconWrapper' })),
|
9786
|
+
React__default["default"].createElement(react.Stack.Item, { align: "end" },
|
9787
|
+
React__default["default"].createElement(InputBoxButton, { className: editingButtonStyle, ariaLabel: strings.editBoxSubmitButton, tooltipContent: strings.editBoxSubmitButton, onRenderIcon: onRenderThemedSubmitIcon, onClick: (e) => {
|
9788
|
+
submitEnabled &&
|
9789
|
+
onSubmit(textValue, message.metadata, {
|
9790
|
+
attachedFilesMetadata
|
9791
|
+
});
|
9792
|
+
e.stopPropagation();
|
9793
|
+
}, id: 'submitIconWrapper' }))),
|
9794
|
+
onRenderFileUploads()));
|
9795
|
+
};
|
9796
|
+
const bodyClassName = reactComponents.mergeClasses(editContainerStyles.body, message.failureReason !== undefined ? editContainerStyles.bodyError : editContainerStyles.bodyDefault);
|
9797
|
+
return (React__default["default"].createElement(reactChat.ChatMyMessage, { root: {
|
9798
|
+
className: reactComponents.mergeClasses(chatMyMessageStyles.root, editContainerStyles.root)
|
9799
|
+
}, body: {
|
9800
|
+
className: bodyClassName
|
9801
|
+
} }, getContent()));
|
9802
|
+
};
|
9803
|
+
const isMessageTooLong = (messageText) => messageText.length > MAXIMUM_LENGTH_OF_MESSAGE;
|
9804
|
+
const isMessageEmpty = (messageText, attachedFilesMetadata) => messageText.trim().length === 0 && attachedFilesMetadata.length === 0;
|
9805
|
+
const getMessageState = (messageText, attachedFilesMetadata) => isMessageEmpty(messageText, attachedFilesMetadata) ? 'too short' : isMessageTooLong(messageText) ? 'too long' : 'OK';
|
9806
|
+
// @TODO: Remove when file-sharing feature becomes stable.
|
9807
|
+
const getMessageAttachedFilesMetadata = (message) => {
|
9808
|
+
/* @conditional-compile-remove(file-sharing) */
|
9809
|
+
return message.attachedFilesMetadata;
|
9811
9810
|
};
|
9811
|
+
|
9812
|
+
// Copyright (c) Microsoft Corporation.
|
9813
|
+
// Licensed under the MIT License.
|
9812
9814
|
/**
|
9813
9815
|
* @private
|
9814
9816
|
*/
|
9815
|
-
const
|
9816
|
-
|
9817
|
-
return React__default["default"].createElement(react.Icon, { "data-ui-id": "file-download-card-download-icon", iconName: "DownloadFile", style: actionIconStyle });
|
9817
|
+
const formatTimeForChatMessage = (messageDate) => {
|
9818
|
+
return messageDate.toLocaleTimeString([], { hour: 'numeric', minute: '2-digit' });
|
9818
9819
|
};
|
9819
|
-
|
9820
|
-
|
9821
|
-
|
9820
|
+
/**
|
9821
|
+
* @private
|
9822
|
+
*/
|
9823
|
+
const formatDateForChatMessage = (messageDate) => {
|
9824
|
+
return messageDate.toLocaleDateString();
|
9822
9825
|
};
|
9823
|
-
|
9824
|
-
// Copyright (c) Microsoft Corporation.
|
9825
|
-
// Licensed under the MIT License.
|
9826
9826
|
/**
|
9827
|
-
*
|
9828
|
-
*
|
9829
|
-
*
|
9827
|
+
* Given a message date object in ISO8601 and a current date object, generates a user friendly timestamp text
|
9828
|
+
* using the system locale.
|
9829
|
+
* <time in locale format>.
|
9830
|
+
* Yesterday <time in locale format>.
|
9831
|
+
* <dateStrings day of week> <time in locale format>.
|
9832
|
+
* <date in locale format> <time in locale format>.
|
9833
|
+
*
|
9834
|
+
* If message is after yesterday, then only show the time.
|
9835
|
+
* If message is before yesterday and after day before yesterday, then show 'Yesterday' plus the time.
|
9836
|
+
* If message is before day before yesterday and within the current week, then show 'Monday/Tuesday/etc' plus the time.
|
9837
|
+
* - We consider start of the week as Sunday. If current day is Sunday, then any time before that is in previous week.
|
9838
|
+
* If message is in previous or older weeks, then show date string plus the time.
|
9839
|
+
*
|
9840
|
+
* @param messageDate - date of message
|
9841
|
+
* @param currentDate - date used as offset to create the user friendly timestamp (e.g. to create 'Yesterday' instead of an absolute date)
|
9830
9842
|
*
|
9831
9843
|
* @private
|
9832
9844
|
*/
|
9833
|
-
|
9834
|
-
|
9835
|
-
|
9836
|
-
|
9845
|
+
const formatTimestampForChatMessage = (messageDate, todayDate, dateStrings) => {
|
9846
|
+
// If message was in the same day timestamp string is just the time like '1:30 p.m.'.
|
9847
|
+
const startOfDay = new Date(todayDate.getFullYear(), todayDate.getMonth(), todayDate.getDate());
|
9848
|
+
if (messageDate > startOfDay) {
|
9849
|
+
return formatTimeForChatMessage(messageDate);
|
9837
9850
|
}
|
9838
|
-
|
9839
|
-
|
9840
|
-
|
9841
|
-
|
9842
|
-
// v8Style[record] is just a simple style
|
9843
|
-
const msSuffix = 'MS';
|
9844
|
-
if (record.startsWith(msSuffix)) {
|
9845
|
-
// React.CSSProperties uses camelCase for MS properties but v8Style uses PascalCase
|
9846
|
-
const newRecord = record.substring(0, msSuffix.length).toLowerCase + record.substring(msSuffix.length);
|
9847
|
-
result[newRecord] = v8Style[record];
|
9848
|
-
}
|
9849
|
-
else {
|
9850
|
-
result[record] = v8Style[record];
|
9851
|
-
}
|
9852
|
-
}
|
9853
|
-
else {
|
9854
|
-
result[record] = createStyleFromV8Style(v8Style[record]);
|
9855
|
-
}
|
9856
|
-
}
|
9851
|
+
// If message was yesterday then timestamp string is like this 'Yesterday 1:30 p.m.'.
|
9852
|
+
const yesterdayDate = new Date(todayDate.getFullYear(), todayDate.getMonth(), todayDate.getDate() - 1);
|
9853
|
+
if (messageDate > yesterdayDate) {
|
9854
|
+
return dateStrings.yesterday + ' ' + formatTimeForChatMessage(messageDate);
|
9857
9855
|
}
|
9858
|
-
|
9859
|
-
|
9860
|
-
|
9861
|
-
|
9862
|
-
|
9863
|
-
|
9864
|
-
|
9865
|
-
|
9866
|
-
|
9867
|
-
|
9868
|
-
|
9869
|
-
|
9870
|
-
|
9856
|
+
// If message was before Sunday and today is Sunday (start of week) then timestamp string is like
|
9857
|
+
// '2021-01-10 1:30 p.m.'.
|
9858
|
+
const weekDay = todayDate.getDay();
|
9859
|
+
if (weekDay === 0) {
|
9860
|
+
return formatDateForChatMessage(messageDate) + ' ' + formatTimeForChatMessage(messageDate);
|
9861
|
+
}
|
9862
|
+
// If message was before first day of the week then timestamp string is like Monday 1:30 p.m.
|
9863
|
+
const firstDayOfTheWeekDate = new Date(todayDate.getFullYear(), todayDate.getMonth(), todayDate.getDate() - weekDay);
|
9864
|
+
if (messageDate > firstDayOfTheWeekDate) {
|
9865
|
+
return dayToDayName(messageDate.getDay(), dateStrings) + ' ' + formatTimeForChatMessage(messageDate);
|
9866
|
+
}
|
9867
|
+
// If message date is in previous or older weeks then timestamp string is like 2021-01-10 1:30 p.m.
|
9868
|
+
return formatDateForChatMessage(messageDate) + ' ' + formatTimeForChatMessage(messageDate);
|
9871
9869
|
};
|
9872
|
-
const
|
9873
|
-
|
9874
|
-
|
9875
|
-
|
9876
|
-
|
9870
|
+
const dayToDayName = (day, dateStrings) => {
|
9871
|
+
switch (day) {
|
9872
|
+
case 0:
|
9873
|
+
return dateStrings.sunday;
|
9874
|
+
case 1:
|
9875
|
+
return dateStrings.monday;
|
9876
|
+
case 2:
|
9877
|
+
return dateStrings.tuesday;
|
9878
|
+
case 3:
|
9879
|
+
return dateStrings.wednesday;
|
9880
|
+
case 4:
|
9881
|
+
return dateStrings.thursday;
|
9882
|
+
case 5:
|
9883
|
+
return dateStrings.friday;
|
9884
|
+
case 6:
|
9885
|
+
return dateStrings.saturday;
|
9886
|
+
default:
|
9887
|
+
throw new Error(`Invalid day [${day}] passed`);
|
9888
|
+
}
|
9877
9889
|
};
|
9878
|
-
// onDisplayDateTimeString from props overwrite onDisplayDateTimeString from locale
|
9879
|
-
const generateCustomizedTimestamp = (props, createdOn, locale) => {
|
9880
|
-
/* @conditional-compile-remove(date-time-customization) */
|
9881
|
-
return props.onDisplayDateTimeString
|
9882
|
-
? props.onDisplayDateTimeString(createdOn)
|
9883
|
-
: locale.onDisplayDateTimeString
|
9884
|
-
? locale.onDisplayDateTimeString(createdOn)
|
9885
|
-
: '';
|
9886
|
-
};
|
9887
|
-
/** @private */
|
9888
|
-
const MessageBubble = (props) => {
|
9889
|
-
var _a;
|
9890
|
-
const ids = useIdentifiers();
|
9891
|
-
const theme = useTheme();
|
9892
|
-
const locale = useLocale$1();
|
9893
|
-
const { userId, message, onRemoveClick, onResendClick, disableEditing, showDate, messageContainerStyle, strings, onEditClick, remoteParticipantsCount = 0, onRenderAvatar, showMessageStatus, messageStatus, fileDownloadHandler,
|
9894
|
-
/* @conditional-compile-remove(image-gallery) */
|
9895
|
-
onInlineImageClicked, shouldOverlapAvatarAndMessage } = props;
|
9896
|
-
const defaultTimeStamp = message.createdOn
|
9897
|
-
? generateDefaultTimestamp(message.createdOn, showDate, strings)
|
9898
|
-
: undefined;
|
9899
|
-
const customTimestamp = message.createdOn ? generateCustomizedTimestamp(props, message.createdOn, locale) : '';
|
9900
|
-
const formattedTimestamp = customTimestamp || defaultTimeStamp;
|
9901
|
-
// Track if the action menu was opened by touch - if so we increase the touch targets for the items
|
9902
|
-
const [wasInteractionByTouch, setWasInteractionByTouch] = React.useState(false);
|
9903
|
-
// `focused` state is used for show/hide actionMenu
|
9904
|
-
const [focused, setFocused] = React__default["default"].useState(false);
|
9905
|
-
// The chat message action flyout should target the Chat.Message action menu if clicked,
|
9906
|
-
// or target the chat message if opened via touch press.
|
9907
|
-
// Undefined indicates the flyout menu should not be being shown.
|
9908
|
-
const messageRef = React.useRef(null);
|
9909
|
-
const messageActionButtonRef = React.useRef(null);
|
9910
|
-
const [chatMessageActionFlyoutTarget, setChatMessageActionFlyoutTarget] = React.useState(undefined);
|
9911
|
-
const chatActionsEnabled = !disableEditing &&
|
9912
|
-
message.status !== 'sending' &&
|
9913
|
-
!!message.mine &&
|
9914
|
-
/* @conditional-compile-remove(data-loss-prevention) */ message.messageType !== 'blocked';
|
9915
|
-
const [messageReadBy, setMessageReadBy] = React.useState([]);
|
9916
|
-
const actionMenuProps = chatMessageActionMenuProps({
|
9917
|
-
ariaLabel: (_a = strings.actionMenuMoreOptions) !== null && _a !== void 0 ? _a : '',
|
9918
|
-
enabled: chatActionsEnabled,
|
9919
|
-
menuButtonRef: messageActionButtonRef,
|
9920
|
-
menuExpanded: chatMessageActionFlyoutTarget === messageActionButtonRef,
|
9921
|
-
onActionButtonClick: () => {
|
9922
|
-
if (message.messageType === 'chat') {
|
9923
|
-
props.onActionButtonClick(message, setMessageReadBy);
|
9924
|
-
setChatMessageActionFlyoutTarget(messageActionButtonRef);
|
9925
|
-
}
|
9926
|
-
},
|
9927
|
-
theme
|
9928
|
-
});
|
9929
|
-
const onActionFlyoutDismiss = React.useCallback(() => {
|
9930
|
-
// When the flyout dismiss is called, since we control if the action flyout is visible
|
9931
|
-
// or not we need to set the target to undefined here to actually hide the action flyout
|
9932
|
-
setChatMessageActionFlyoutTarget(undefined);
|
9933
|
-
}, [setChatMessageActionFlyoutTarget]);
|
9934
|
-
const defaultOnRenderFileDownloads = React.useCallback(() => (React__default["default"].createElement(_FileDownloadCards, { userId: userId, fileMetadata: message['attachedFilesMetadata'] || [], downloadHandler: fileDownloadHandler,
|
9935
|
-
/* @conditional-compile-remove(file-sharing) @conditional-compile-remove(teams-inline-images-and-file-sharing)*/
|
9936
|
-
strings: { downloadFile: strings.downloadFile, fileCardGroupMessage: strings.fileCardGroupMessage } })), [
|
9937
|
-
userId,
|
9938
|
-
message,
|
9939
|
-
/* @conditional-compile-remove(file-sharing) @conditional-compile-remove(teams-inline-images-and-file-sharing)*/
|
9940
|
-
strings,
|
9941
|
-
fileDownloadHandler
|
9942
|
-
]);
|
9943
|
-
const editedOn = 'editedOn' in message ? message.editedOn : undefined;
|
9944
|
-
const getMessageDetails = React.useCallback(() => {
|
9945
|
-
if (messageStatus === 'failed') {
|
9946
|
-
return React__default["default"].createElement("div", { className: chatMessageFailedTagStyle(theme) }, strings.failToSendTag);
|
9947
|
-
}
|
9948
|
-
else if (message.messageType === 'chat' && editedOn) {
|
9949
|
-
return React__default["default"].createElement("div", { className: chatMessageEditedTagStyle(theme) }, strings.editedTag);
|
9950
|
-
}
|
9951
|
-
return undefined;
|
9952
|
-
}, [editedOn, message.messageType, messageStatus, strings.editedTag, strings.failToSendTag, theme]);
|
9953
|
-
/* @conditional-compile-remove(image-gallery) */
|
9954
|
-
const handleOnInlineImageClicked = React.useCallback((attachmentId) => __awaiter$x(void 0, void 0, void 0, function* () {
|
9955
|
-
if (onInlineImageClicked === undefined) {
|
9956
|
-
return;
|
9957
|
-
}
|
9958
|
-
yield onInlineImageClicked(attachmentId, message.messageId);
|
9959
|
-
}), [message, onInlineImageClicked]);
|
9960
|
-
const getContent = React.useCallback(() => {
|
9961
|
-
/* @conditional-compile-remove(data-loss-prevention) */
|
9962
|
-
if (message.messageType === 'blocked') {
|
9963
|
-
return (React__default["default"].createElement("div", { tabIndex: 0 },
|
9964
|
-
React__default["default"].createElement(BlockedMessageContent, { message: message, strings: strings })));
|
9965
|
-
}
|
9966
|
-
return (React__default["default"].createElement("div", { tabIndex: 0, className: "ui-chat__message__content" },
|
9967
|
-
React__default["default"].createElement(ChatMessageContent, { message: message, strings: strings,
|
9968
|
-
/* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
|
9969
|
-
onFetchAttachment: props.onFetchAttachments,
|
9970
|
-
/* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
|
9971
|
-
attachmentsMap: props.attachmentsMap,
|
9972
|
-
/* @conditional-compile-remove(mention) */
|
9973
|
-
mentionDisplayOptions: props.mentionDisplayOptions,
|
9974
|
-
/* @conditional-compile-remove(image-gallery) */
|
9975
|
-
onInlineImageClicked: handleOnInlineImageClicked }),
|
9976
|
-
props.onRenderFileDownloads ? props.onRenderFileDownloads(userId, message) : defaultOnRenderFileDownloads()));
|
9977
|
-
}, [
|
9978
|
-
defaultOnRenderFileDownloads,
|
9979
|
-
message,
|
9980
|
-
props,
|
9981
|
-
strings,
|
9982
|
-
userId,
|
9983
|
-
/* @conditional-compile-remove(image-gallery) */
|
9984
|
-
handleOnInlineImageClicked
|
9985
|
-
]);
|
9986
|
-
const isBlockedMessage = /* @conditional-compile-remove(data-loss-prevention) */ message.messageType === 'blocked';
|
9987
|
-
const chatMyMessageStyles = useChatMyMessageStyles();
|
9988
|
-
const chatMessageCommonStyles = useChatMessageCommonStyles();
|
9989
|
-
const chatMessageStyles = useChatMessageStyles();
|
9990
|
-
const chatItemMessageContainerClassName = reactComponents.mergeClasses(
|
9991
|
-
// messageContainerStyle used in className and style prop as style prop can't handle CSS selectors
|
9992
|
-
chatMessageStyles.body, isBlockedMessage
|
9993
|
-
? chatMessageCommonStyles.blocked
|
9994
|
-
: props.message.status === 'failed'
|
9995
|
-
? chatMessageCommonStyles.failed
|
9996
|
-
: undefined, shouldOverlapAvatarAndMessage ? chatMessageStyles.avatarOverlap : chatMessageStyles.avatarNoOverlap, message.attached === 'top' || message.attached === false
|
9997
|
-
? chatMessageStyles.bodyWithAvatar
|
9998
|
-
: chatMessageStyles.bodyWithoutAvatar, react.mergeStyles(messageContainerStyle));
|
9999
|
-
const attached = message.attached === true ? 'center' : message.attached === 'bottom' ? 'bottom' : 'top';
|
10000
|
-
const chatMessage = (React__default["default"].createElement(React__default["default"].Fragment, null,
|
10001
|
-
React__default["default"].createElement("div", { key: props.message.messageId }, message.mine ? (React__default["default"].createElement(reactChat.ChatMyMessage, { attached: attached, key: props.message.messageId, body: {
|
10002
|
-
// messageContainerStyle used in className and style prop as style prop can't handle CSS selectors
|
10003
|
-
className: reactComponents.mergeClasses(chatMyMessageStyles.body, isBlockedMessage
|
10004
|
-
? chatMessageCommonStyles.blocked
|
10005
|
-
: props.message.status === 'failed'
|
10006
|
-
? chatMessageCommonStyles.failed
|
10007
|
-
: undefined, attached !== 'top' ? chatMyMessageStyles.bodyAttached : undefined, react.mergeStyles(messageContainerStyle)),
|
10008
|
-
style: Object.assign({}, createStyleFromV8Style(messageContainerStyle)),
|
10009
|
-
ref: messageRef
|
10010
|
-
}, root: {
|
10011
|
-
className: chatMyMessageStyles.root,
|
10012
|
-
onBlur: (e) => {
|
10013
|
-
// `focused` controls is focused the whole `ChatMessage` or any of its children. When we're navigating
|
10014
|
-
// with keyboard the focused element will be changed and there is no way to use `:focus` selector
|
10015
|
-
if (chatMessageActionFlyoutTarget === null || chatMessageActionFlyoutTarget === void 0 ? void 0 : chatMessageActionFlyoutTarget.current) {
|
10016
|
-
// doesn't dismiss action button if flyout is open, otherwise, narrator's focus will stay on the closed action menu
|
10017
|
-
return;
|
10018
|
-
}
|
10019
|
-
const shouldPreserveFocusState = e.currentTarget.contains(e.relatedTarget);
|
10020
|
-
setFocused(shouldPreserveFocusState);
|
10021
|
-
},
|
10022
|
-
onFocus: () => {
|
10023
|
-
// react onFocus is called even when nested component receives focus (i.e. it bubbles)
|
10024
|
-
// so when focus moves within actionMenu, the `focus` state in chatMessage remains true, and keeps actionMenu visible
|
10025
|
-
setFocused(true);
|
10026
|
-
},
|
10027
|
-
// make body not focusable to remove repetitions from narrators.
|
10028
|
-
// inner components are already focusable
|
10029
|
-
role: 'none',
|
10030
|
-
tabIndex: -1
|
10031
|
-
}, "data-ui-id": "chat-composite-message", author: React__default["default"].createElement(react.Text, { className: chatMessageDateStyle, tabIndex: 0 }, message.senderDisplayName), timestamp: React__default["default"].createElement(react.Text, { className: chatMessageDateStyle, "data-ui-id": ids.messageTimestamp, tabIndex: 0 }, formattedTimestamp), details: getMessageDetails(), actions: {
|
10032
|
-
children: actionMenuProps === null || actionMenuProps === void 0 ? void 0 : actionMenuProps.children,
|
10033
|
-
className: reactComponents.mergeClasses(chatMyMessageStyles.menu,
|
10034
|
-
// Make actions menu visible when the message is focused or the flyout is shown
|
10035
|
-
focused || (chatMessageActionFlyoutTarget === null || chatMessageActionFlyoutTarget === void 0 ? void 0 : chatMessageActionFlyoutTarget.current)
|
10036
|
-
? chatMyMessageStyles.menuVisible
|
10037
|
-
: chatMyMessageStyles.menuHidden, attached !== 'top' ? chatMyMessageStyles.menuAttached : undefined)
|
10038
|
-
}, onTouchStart: () => setWasInteractionByTouch(true), onPointerDown: () => setWasInteractionByTouch(false), onKeyDown: () => setWasInteractionByTouch(false), onClick: () => {
|
10039
|
-
if (!wasInteractionByTouch) {
|
10040
|
-
return;
|
10041
|
-
}
|
10042
|
-
// If the message was touched via touch we immediately open the menu
|
10043
|
-
// flyout (when using mouse the 3-dot menu that appears on hover
|
10044
|
-
// must be clicked to open the flyout).
|
10045
|
-
// In doing so here we set the target of the flyout to be the message and
|
10046
|
-
// not the 3-dot menu button to position the flyout correctly.
|
10047
|
-
setChatMessageActionFlyoutTarget(messageRef);
|
10048
|
-
if (message.messageType === 'chat') {
|
10049
|
-
props.onActionButtonClick(message, setMessageReadBy);
|
10050
|
-
}
|
10051
|
-
} }, getContent())) : (React__default["default"].createElement(reactChat.ChatMessage, { attached: attached, key: props.message.messageId, root: {
|
10052
|
-
className: chatMessageStyles.root,
|
10053
|
-
// make body not focusable to remove repetitions from narrators.
|
10054
|
-
// inner components are already focusable
|
10055
|
-
tabIndex: -1,
|
10056
|
-
role: 'none'
|
10057
|
-
}, author: React__default["default"].createElement(react.Text, { className: chatMessageAuthorStyle }, message.senderDisplayName), body: {
|
10058
|
-
className: chatItemMessageContainerClassName,
|
10059
|
-
style: Object.assign({}, createStyleFromV8Style(messageContainerStyle))
|
10060
|
-
}, "data-ui-id": "chat-composite-message", timestamp: React__default["default"].createElement(react.Text, { className: chatMessageDateStyle, "data-ui-id": ids.messageTimestamp }, formattedTimestamp) }, getContent()))),
|
10061
|
-
chatActionsEnabled && (React__default["default"].createElement(ChatMessageActionFlyout, { hidden: !chatMessageActionFlyoutTarget, target: chatMessageActionFlyoutTarget, increaseFlyoutItemSize: wasInteractionByTouch, onDismiss: onActionFlyoutDismiss, onEditClick: onEditClick, onRemoveClick: onRemoveClick, onResendClick: onResendClick, strings: strings, messageReadBy: messageReadBy, messageStatus: messageStatus !== null && messageStatus !== void 0 ? messageStatus : 'failed', remoteParticipantsCount: remoteParticipantsCount, onRenderAvatar: onRenderAvatar, showMessageStatus: showMessageStatus }))));
|
10062
|
-
return chatMessage;
|
10063
|
-
};
|
10064
|
-
/** @private */
|
10065
|
-
const ChatMessageComponentAsMessageBubble = React__default["default"].memo(MessageBubble);
|
10066
9890
|
|
10067
9891
|
// Copyright (c) Microsoft Corporation.
|
10068
|
-
// Licensed under the MIT License.
|
10069
|
-
var __awaiter$w = (window && window.__awaiter) || function (thisArg, _arguments, P, generator) {
|
10070
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
10071
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
10072
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
10073
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
10074
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
10075
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
10076
|
-
});
|
10077
|
-
};
|
10078
9892
|
/**
|
9893
|
+
* Chat message actions flyout that contains actions such as Edit Message, or Remove Message.
|
9894
|
+
*
|
10079
9895
|
* @private
|
10080
9896
|
*/
|
10081
|
-
const
|
9897
|
+
const ChatMessageActionFlyout = (props) => {
|
10082
9898
|
var _a, _b;
|
10083
|
-
const
|
10084
|
-
const
|
10085
|
-
const
|
10086
|
-
const
|
10087
|
-
|
10088
|
-
|
10089
|
-
|
10090
|
-
|
10091
|
-
|
10092
|
-
|
10093
|
-
|
10094
|
-
|
10095
|
-
|
10096
|
-
|
10097
|
-
const onResendClick = React.useCallback(() => {
|
10098
|
-
onDeleteMessage && clientMessageId && onDeleteMessage(clientMessageId);
|
10099
|
-
onSendMessage && onSendMessage(content !== undefined ? content : '');
|
10100
|
-
}, [clientMessageId, content, onSendMessage, onDeleteMessage]);
|
10101
|
-
if (isEditing && message.messageType === 'chat') {
|
10102
|
-
return (React__default["default"].createElement(ChatMessageComponentAsEditBox, { message: message, strings: props.strings, onSubmit: (text, metadata, options) => __awaiter$w(void 0, void 0, void 0, function* () {
|
10103
|
-
props.onUpdateMessage &&
|
10104
|
-
message.messageId &&
|
10105
|
-
(yield props.onUpdateMessage(message.messageId, text, metadata, options));
|
10106
|
-
setIsEditing(false);
|
10107
|
-
}), onCancel: (messageId) => {
|
10108
|
-
props.onCancelEditMessage && props.onCancelEditMessage(messageId);
|
10109
|
-
setIsEditing(false);
|
10110
|
-
},
|
10111
|
-
/* @conditional-compile-remove(mention) */
|
10112
|
-
mentionLookupOptions: (_a = props.mentionOptions) === null || _a === void 0 ? void 0 : _a.lookupOptions }));
|
10113
|
-
}
|
10114
|
-
else {
|
10115
|
-
return (React__default["default"].createElement(ChatMessageComponentAsMessageBubble, Object.assign({}, props, { onRemoveClick: onRemoveClick, onEditClick: onEditClick, onResendClick: onResendClick, onRenderAvatar: props.onRenderAvatar,
|
10116
|
-
/* @conditional-compile-remove(date-time-customization) */
|
10117
|
-
onDisplayDateTimeString: props.onDisplayDateTimeString, strings: props.strings,
|
10118
|
-
/* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
|
10119
|
-
onFetchAttachments: props.onFetchAttachments,
|
10120
|
-
/* @conditional-compile-remove(image-gallery) */
|
10121
|
-
onInlineImageClicked: props.onInlineImageClicked,
|
10122
|
-
/* @conditional-compile-remove(image-gallery) */
|
10123
|
-
attachmentsMap: props.attachmentsMap,
|
10124
|
-
/* @conditional-compile-remove(mention) */
|
10125
|
-
mentionDisplayOptions: (_b = props.mentionOptions) === null || _b === void 0 ? void 0 : _b.displayOptions })));
|
10126
|
-
}
|
10127
|
-
};
|
10128
|
-
|
10129
|
-
// Copyright (c) Microsoft Corporation.
|
10130
|
-
/**
|
10131
|
-
* A utility hook for providing the width of a parent element.
|
10132
|
-
* Returns updated width if parent/window resizes.
|
10133
|
-
* @param containerRef - Ref of a parent element whose width will be returned.
|
10134
|
-
* @internal
|
10135
|
-
*/
|
10136
|
-
const _useContainerWidth = (containerRef) => {
|
10137
|
-
const [width, setWidth] = React.useState(undefined);
|
10138
|
-
const observer = React.useRef(new ResizeObserver((entries) => {
|
10139
|
-
const { width } = entries[0].contentRect;
|
10140
|
-
setWidth(width);
|
10141
|
-
}));
|
10142
|
-
React.useEffect(() => {
|
10143
|
-
if (containerRef.current) {
|
10144
|
-
observer.current.observe(containerRef.current);
|
10145
|
-
}
|
10146
|
-
const currentObserver = observer.current;
|
10147
|
-
return () => {
|
10148
|
-
currentObserver.disconnect();
|
9899
|
+
const theme = react.useTheme();
|
9900
|
+
const messageReadByCount = (_a = props.messageReadBy) === null || _a === void 0 ? void 0 : _a.length;
|
9901
|
+
const sortedMessageReadyByList = [...((_b = props.messageReadBy) !== null && _b !== void 0 ? _b : [])].sort((a, b) => a.displayName.localeCompare(b.displayName));
|
9902
|
+
const messageReadByList = sortedMessageReadyByList === null || sortedMessageReadyByList === void 0 ? void 0 : sortedMessageReadyByList.map((person) => {
|
9903
|
+
const personaOptions = {
|
9904
|
+
hidePersonaDetails: true,
|
9905
|
+
size: react.PersonaSize.size24,
|
9906
|
+
text: person.displayName,
|
9907
|
+
showOverflowTooltip: false,
|
9908
|
+
styles: {
|
9909
|
+
root: {
|
9910
|
+
margin: '0.25rem'
|
9911
|
+
}
|
9912
|
+
}
|
10149
9913
|
};
|
10150
|
-
|
10151
|
-
|
10152
|
-
|
10153
|
-
|
10154
|
-
|
10155
|
-
|
10156
|
-
|
10157
|
-
|
10158
|
-
|
10159
|
-
|
10160
|
-
const [height, setHeight] = React.useState(undefined);
|
10161
|
-
const observer = React.useRef(new ResizeObserver((entries) => {
|
10162
|
-
const { height } = entries[0].contentRect;
|
10163
|
-
setHeight(height);
|
10164
|
-
}));
|
10165
|
-
React.useEffect(() => {
|
10166
|
-
if (containerRef.current) {
|
10167
|
-
observer.current.observe(containerRef.current);
|
10168
|
-
}
|
10169
|
-
const currentObserver = observer.current;
|
10170
|
-
return () => {
|
10171
|
-
currentObserver.disconnect();
|
9914
|
+
const { onRenderAvatar } = props;
|
9915
|
+
return {
|
9916
|
+
'data-ui-id': 'chat-composite-message-contextual-menu-read-name-list-item',
|
9917
|
+
key: person.displayName,
|
9918
|
+
text: person.displayName,
|
9919
|
+
itemProps: { styles: props.increaseFlyoutItemSize ? menuItemIncreasedSizeStyles : undefined },
|
9920
|
+
onRenderIcon: () => { var _a; return onRenderAvatar ? onRenderAvatar((_a = person.id) !== null && _a !== void 0 ? _a : '', personaOptions) : React__default["default"].createElement(react.Persona, Object.assign({}, personaOptions)); },
|
9921
|
+
iconProps: {
|
9922
|
+
styles: menuIconStyleSet
|
9923
|
+
}
|
10172
9924
|
};
|
10173
|
-
}
|
10174
|
-
|
9925
|
+
});
|
9926
|
+
const menuItems = React.useMemo(() => {
|
9927
|
+
const items = [
|
9928
|
+
{
|
9929
|
+
key: 'Edit',
|
9930
|
+
'data-ui-id': 'chat-composite-message-contextual-menu-edit-action',
|
9931
|
+
text: props.strings.editMessage,
|
9932
|
+
itemProps: {
|
9933
|
+
styles: props.increaseFlyoutItemSize ? menuItemIncreasedSizeStyles : undefined
|
9934
|
+
},
|
9935
|
+
iconProps: { iconName: 'MessageEdit', styles: menuIconStyleSet },
|
9936
|
+
onClick: props.onEditClick
|
9937
|
+
},
|
9938
|
+
{
|
9939
|
+
key: 'Remove',
|
9940
|
+
text: props.strings.removeMessage,
|
9941
|
+
itemProps: { styles: props.increaseFlyoutItemSize ? menuItemIncreasedSizeStyles : undefined },
|
9942
|
+
iconProps: {
|
9943
|
+
iconName: 'MessageRemove',
|
9944
|
+
styles: menuIconStyleSet
|
9945
|
+
},
|
9946
|
+
onClick: props.onRemoveClick
|
9947
|
+
}
|
9948
|
+
];
|
9949
|
+
// only show read by x of x if more than 3 participants in total including myself
|
9950
|
+
// TODO: change strings.messageReadCount to be required if we can fallback to our own en-us strings for anything that Contoso doesn't provide
|
9951
|
+
if (props.remoteParticipantsCount &&
|
9952
|
+
messageReadByCount !== undefined &&
|
9953
|
+
props.remoteParticipantsCount >= 2 &&
|
9954
|
+
props.showMessageStatus &&
|
9955
|
+
props.strings.messageReadCount &&
|
9956
|
+
props.messageStatus !== 'failed') {
|
9957
|
+
items.push({
|
9958
|
+
key: 'Read Count',
|
9959
|
+
'data-ui-id': 'chat-composite-message-contextual-menu-read-info',
|
9960
|
+
text: _formatString(props.strings.messageReadCount, {
|
9961
|
+
messageReadByCount: `${messageReadByCount}`,
|
9962
|
+
remoteParticipantsCount: `${props.remoteParticipantsCount}`
|
9963
|
+
}),
|
9964
|
+
itemProps: {
|
9965
|
+
styles: react.concatStyleSets({
|
9966
|
+
linkContent: {
|
9967
|
+
color: messageReadByCount > 0 ? theme.palette.neutralPrimary : theme.palette.neutralTertiary
|
9968
|
+
},
|
9969
|
+
root: {
|
9970
|
+
borderTop: `1px solid ${theme.palette.neutralLighter}`
|
9971
|
+
}
|
9972
|
+
}, props.increaseFlyoutItemSize ? menuItemIncreasedSizeStyles : undefined)
|
9973
|
+
},
|
9974
|
+
calloutProps: preventUnwantedDismissProps,
|
9975
|
+
subMenuProps: {
|
9976
|
+
items: messageReadByList !== null && messageReadByList !== void 0 ? messageReadByList : [],
|
9977
|
+
calloutProps: preventUnwantedDismissProps,
|
9978
|
+
styles: react.concatStyleSets({
|
9979
|
+
root: {
|
9980
|
+
maxWidth: _pxToRem(320),
|
9981
|
+
span: {
|
9982
|
+
overflow: 'hidden',
|
9983
|
+
textOverflow: 'ellipsis'
|
9984
|
+
}
|
9985
|
+
}
|
9986
|
+
})
|
9987
|
+
},
|
9988
|
+
iconProps: {
|
9989
|
+
iconName: 'MessageSeen',
|
9990
|
+
styles: {
|
9991
|
+
root: {
|
9992
|
+
color: messageReadByCount > 0 ? theme.palette.themeDarkAlt : theme.palette.neutralTertiary
|
9993
|
+
}
|
9994
|
+
}
|
9995
|
+
},
|
9996
|
+
submenuIconProps: {
|
9997
|
+
iconName: 'HorizontalGalleryRightButton',
|
9998
|
+
styles: menuSubIconStyleSet
|
9999
|
+
},
|
10000
|
+
disabled: messageReadByCount <= 0
|
10001
|
+
});
|
10002
|
+
}
|
10003
|
+
else if (props.messageStatus === 'failed' && props.strings.resendMessage) {
|
10004
|
+
items.push({
|
10005
|
+
key: 'Resend',
|
10006
|
+
text: props.strings.resendMessage,
|
10007
|
+
itemProps: {
|
10008
|
+
styles: react.concatStyleSets({
|
10009
|
+
linkContent: {
|
10010
|
+
color: theme.palette.neutralPrimary
|
10011
|
+
},
|
10012
|
+
root: {
|
10013
|
+
borderTop: `1px solid ${theme.palette.neutralLighter}`
|
10014
|
+
}
|
10015
|
+
}, props.increaseFlyoutItemSize ? menuItemIncreasedSizeStyles : undefined)
|
10016
|
+
},
|
10017
|
+
calloutProps: preventUnwantedDismissProps,
|
10018
|
+
iconProps: {
|
10019
|
+
iconName: 'MessageResend',
|
10020
|
+
styles: {
|
10021
|
+
root: {
|
10022
|
+
color: theme.palette.themeDarkAlt
|
10023
|
+
}
|
10024
|
+
}
|
10025
|
+
},
|
10026
|
+
onClick: props.onResendClick
|
10027
|
+
});
|
10028
|
+
}
|
10029
|
+
return items;
|
10030
|
+
}, [
|
10031
|
+
props.strings.editMessage,
|
10032
|
+
props.strings.removeMessage,
|
10033
|
+
props.strings.messageReadCount,
|
10034
|
+
props.strings.resendMessage,
|
10035
|
+
props.messageStatus,
|
10036
|
+
props.increaseFlyoutItemSize,
|
10037
|
+
props.onEditClick,
|
10038
|
+
props.onRemoveClick,
|
10039
|
+
props.onResendClick,
|
10040
|
+
props.remoteParticipantsCount,
|
10041
|
+
props.showMessageStatus,
|
10042
|
+
messageReadByCount,
|
10043
|
+
theme.palette.neutralPrimary,
|
10044
|
+
theme.palette.neutralTertiary,
|
10045
|
+
theme.palette.neutralLighter,
|
10046
|
+
theme.palette.themeDarkAlt,
|
10047
|
+
messageReadByList
|
10048
|
+
]);
|
10049
|
+
// gap space uses pixels
|
10050
|
+
return (React__default["default"].createElement(react.ContextualMenu, { alignTargetEdge: true, gapSpace: 2 /*px*/, isBeakVisible: false, items: menuItems, hidden: props.hidden, target: props.target, onDismiss: props.onDismiss, directionalHint: react.DirectionalHint.topRightEdge, className: chatMessageMenuStyle, calloutProps: calloutMenuProps }));
|
10175
10051
|
};
|
10176
|
-
const NARROW_WIDTH_REM = 30;
|
10177
|
-
const SHORT_HEIGHT_REM = 23.75;
|
10178
|
-
/**
|
10179
|
-
* Utility function to determine if container width is narrow
|
10180
|
-
* @param containerWidthRem container width in rem
|
10181
|
-
* @returns boolean
|
10182
|
-
*/
|
10183
|
-
const isNarrowWidth = (containerWidthRem) => containerWidthRem <= _convertRemToPx(NARROW_WIDTH_REM);
|
10184
10052
|
/**
|
10185
|
-
*
|
10186
|
-
* @param containerWidthRem container height in rem
|
10187
|
-
* @returns boolean
|
10053
|
+
* Similar to {@link preventDismissOnEvent}, but not prevent dismissing from scrolling, since it is causing bugs in chat thread.
|
10188
10054
|
*/
|
10189
|
-
const
|
10055
|
+
const preventUnwantedDismissProps = {
|
10056
|
+
preventDismissOnEvent: (ev) => {
|
10057
|
+
return ev.type === 'resize';
|
10058
|
+
}
|
10059
|
+
};
|
10060
|
+
const calloutMenuProps = Object.assign(Object.assign({}, preventUnwantedDismissProps), { styles: { root: { marginRight: '3px' } } });
|
10190
10061
|
|
10191
10062
|
// Copyright (c) Microsoft Corporation.
|
10192
|
-
// Licensed under the MIT License.
|
10193
10063
|
/**
|
10194
|
-
*
|
10195
|
-
*
|
10196
|
-
* Assumption: if user read the latest message, user has read all messages before that
|
10197
|
-
* ReadReceipt behaviour: read receipt is only sent to the last message
|
10198
|
-
*
|
10199
|
-
* If participant read a message that is sent later than message A, then the participant has read message A
|
10200
|
-
* How do we check if the message is sent later than message A?
|
10201
|
-
* We compare if the messageID of the last read message is larger than or equal to the message A's id
|
10202
|
-
* Because messageID is the creation timestamp of each message
|
10203
|
-
* Timestamps are in epoch time so lecixographical ordering is the same as time ordering.
|
10064
|
+
* Provides the default implementation for rendering an Mention in a message thread
|
10065
|
+
* @param mention - The mention to render
|
10204
10066
|
*
|
10205
|
-
*
|
10206
|
-
|
10207
|
-
|
10208
|
-
|
10209
|
-
|
10210
|
-
|
10211
|
-
.filter(([_, readReceipt]) => readReceipt.lastReadMessage >= message.messageId)
|
10212
|
-
// make sure the person is not removed from chat
|
10213
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
10214
|
-
.filter(([_, readReceipt]) => readReceipt.displayName && readReceipt.displayName !== '')
|
10215
|
-
// Map properties to useful array
|
10216
|
-
.map(([id, readReceipt]) => ({ id, displayName: readReceipt.displayName })));
|
10067
|
+
* @private
|
10068
|
+
*/
|
10069
|
+
const defaultOnMentionRender = (mention) => {
|
10070
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
10071
|
+
const MsftMention = 'msft-mention';
|
10072
|
+
return React__default["default"].createElement(MsftMention, { id: mention.id }, mention.displayText);
|
10217
10073
|
};
|
10218
10074
|
|
10219
10075
|
// Copyright (c) Microsoft Corporation.
|
10220
|
-
|
10221
|
-
|
10222
|
-
|
10223
|
-
|
10224
|
-
|
10225
|
-
|
10226
|
-
|
10227
|
-
|
10228
|
-
|
10229
|
-
|
10230
|
-
|
10231
|
-
|
10232
|
-
|
10233
|
-
'12': '#1f1f1f',
|
10234
|
-
'14': '#242424',
|
10235
|
-
'16': '#292929',
|
10236
|
-
'18': '#2e2e2e',
|
10237
|
-
'20': '#333333',
|
10238
|
-
'22': '#383838',
|
10239
|
-
'24': '#3d3d3d',
|
10240
|
-
'26': '#424242',
|
10241
|
-
'28': '#474747',
|
10242
|
-
'30': '#4d4d4d',
|
10243
|
-
'32': '#525252',
|
10244
|
-
'34': '#575757',
|
10245
|
-
'36': '#5c5c5c',
|
10246
|
-
'38': '#616161',
|
10247
|
-
'40': '#666666',
|
10248
|
-
'42': '#6b6b6b',
|
10249
|
-
'44': '#707070',
|
10250
|
-
'46': '#757575',
|
10251
|
-
'48': '#7a7a7a',
|
10252
|
-
'50': '#808080',
|
10253
|
-
'52': '#858585',
|
10254
|
-
'54': '#8a8a8a',
|
10255
|
-
'56': '#8f8f8f',
|
10256
|
-
'58': '#949494',
|
10257
|
-
'60': '#999999',
|
10258
|
-
'62': '#9e9e9e',
|
10259
|
-
'64': '#a3a3a3',
|
10260
|
-
'66': '#a8a8a8',
|
10261
|
-
'68': '#adadad',
|
10262
|
-
'70': '#b3b3b3',
|
10263
|
-
'72': '#b8b8b8',
|
10264
|
-
'74': '#bdbdbd',
|
10265
|
-
'76': '#c2c2c2',
|
10266
|
-
'78': '#c7c7c7',
|
10267
|
-
'80': '#cccccc',
|
10268
|
-
'82': '#d1d1d1',
|
10269
|
-
'84': '#d6d6d6',
|
10270
|
-
'86': '#dbdbdb',
|
10271
|
-
'88': '#e0e0e0',
|
10272
|
-
'90': '#e6e6e6',
|
10273
|
-
'92': '#ebebeb',
|
10274
|
-
'94': '#f0f0f0',
|
10275
|
-
'96': '#f5f5f5',
|
10276
|
-
'98': '#fafafa',
|
10277
|
-
'100': '#ffffff'
|
10076
|
+
/** @private */
|
10077
|
+
const ChatMessageContent = (props) => {
|
10078
|
+
switch (props.message.contentType) {
|
10079
|
+
case 'text':
|
10080
|
+
return MessageContentAsText(props);
|
10081
|
+
case 'html':
|
10082
|
+
return MessageContentAsRichTextHTML(props);
|
10083
|
+
case 'richtext/html':
|
10084
|
+
return MessageContentAsRichTextHTML(props);
|
10085
|
+
default:
|
10086
|
+
console.warn('unknown message content type');
|
10087
|
+
return React__default["default"].createElement(React__default["default"].Fragment, null);
|
10088
|
+
}
|
10278
10089
|
};
|
10279
|
-
|
10280
|
-
|
10281
|
-
|
10282
|
-
|
10283
|
-
'5': 'rgba(255, 255, 255, 0.05)',
|
10284
|
-
'10': 'rgba(255, 255, 255, 0.1)',
|
10285
|
-
'20': 'rgba(255, 255, 255, 0.2)',
|
10286
|
-
'30': 'rgba(255, 255, 255, 0.3)',
|
10287
|
-
'40': 'rgba(255, 255, 255, 0.4)',
|
10288
|
-
'50': 'rgba(255, 255, 255, 0.5)',
|
10289
|
-
'60': 'rgba(255, 255, 255, 0.6)',
|
10290
|
-
'70': 'rgba(255, 255, 255, 0.7)',
|
10291
|
-
'80': 'rgba(255, 255, 255, 0.8)',
|
10292
|
-
'90': 'rgba(255, 255, 255, 0.9)'
|
10090
|
+
const MessageContentWithLiveAria = (props) => {
|
10091
|
+
return (React__default["default"].createElement("div", { "data-ui-status": props.message.status, role: "text", "aria-label": props.ariaLabel },
|
10092
|
+
React__default["default"].createElement(LiveMessage, { message: props.liveMessage, ariaLive: "polite" }),
|
10093
|
+
props.content));
|
10293
10094
|
};
|
10294
|
-
|
10295
|
-
|
10296
|
-
*/
|
10297
|
-
|
10298
|
-
|
10299
|
-
|
10300
|
-
|
10301
|
-
|
10302
|
-
|
10303
|
-
|
10304
|
-
|
10305
|
-
|
10306
|
-
|
10307
|
-
|
10095
|
+
const MessageContentAsRichTextHTML = (props) => {
|
10096
|
+
const {
|
10097
|
+
/* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
|
10098
|
+
// message is used only in useEffect that is under teams-inline-images-and-file-sharing cc
|
10099
|
+
message,
|
10100
|
+
/* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
|
10101
|
+
attachmentsMap,
|
10102
|
+
/* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
|
10103
|
+
onFetchAttachments } = props;
|
10104
|
+
/* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
|
10105
|
+
React.useEffect(() => {
|
10106
|
+
var _a;
|
10107
|
+
if (!attachmentsMap || !onFetchAttachments) {
|
10108
|
+
return;
|
10109
|
+
}
|
10110
|
+
const attachments = (_a = message.attachedFilesMetadata) === null || _a === void 0 ? void 0 : _a.filter((fileMetadata) => {
|
10111
|
+
return fileMetadata.attachmentType === 'inlineImage' && attachmentsMap[fileMetadata.id] === undefined;
|
10112
|
+
});
|
10113
|
+
if (attachments && attachments.length > 0) {
|
10114
|
+
onFetchAttachments(attachments, message.messageId);
|
10115
|
+
}
|
10116
|
+
}, [message.attachedFilesMetadata, message.messageId, onFetchAttachments, attachmentsMap]);
|
10117
|
+
return (React__default["default"].createElement(MessageContentWithLiveAria, { message: props.message, liveMessage: generateLiveMessage(props), ariaLabel: messageContentAriaText(props), content: processHtmlToReact(props) }));
|
10118
|
+
};
|
10119
|
+
const MessageContentAsText = (props) => {
|
10120
|
+
return (React__default["default"].createElement(MessageContentWithLiveAria, { message: props.message, liveMessage: generateLiveMessage(props), ariaLabel: messageContentAriaText(props), content: React__default["default"].createElement(Linkify__default["default"], { componentDecorator: (decoratedHref, decoratedText, key) => {
|
10121
|
+
return (React__default["default"].createElement(react.Link, { target: "_blank", href: decoratedHref, key: key }, decoratedText));
|
10122
|
+
} }, props.message.content) }));
|
10308
10123
|
};
|
10124
|
+
/* @conditional-compile-remove(data-loss-prevention) */
|
10309
10125
|
/**
|
10310
10126
|
* @private
|
10311
10127
|
*/
|
10312
|
-
const
|
10313
|
-
|
10314
|
-
|
10315
|
-
|
10316
|
-
|
10317
|
-
|
10318
|
-
|
10319
|
-
|
10320
|
-
|
10321
|
-
|
10322
|
-
|
10128
|
+
const BlockedMessageContent = (props) => {
|
10129
|
+
var _a;
|
10130
|
+
const Icon = React__default["default"].createElement(react.FontIcon, { iconName: 'DataLossPreventionProhibited' });
|
10131
|
+
const blockedMessage = props.message.warningText === undefined ? props.strings.blockedWarningText : props.message.warningText;
|
10132
|
+
const blockedMessageLink = props.message.link;
|
10133
|
+
const blockedMessageLinkText = blockedMessageLink
|
10134
|
+
? (_a = props.message.linkText) !== null && _a !== void 0 ? _a : props.strings.blockedWarningLinkText
|
10135
|
+
: '';
|
10136
|
+
const liveAuthor = props.message.mine || props.message.senderDisplayName === undefined ? '' : props.message.senderDisplayName;
|
10137
|
+
const liveBlockedWarningText = `${liveAuthor} ${blockedMessage} ${blockedMessageLinkText}`;
|
10138
|
+
return (React__default["default"].createElement(MessageContentWithLiveAria, { message: props.message, liveMessage: liveBlockedWarningText, ariaLabel: liveBlockedWarningText, content: React__default["default"].createElement(react.Stack, { horizontal: true, wrap: true },
|
10139
|
+
Icon,
|
10140
|
+
blockedMessage && React__default["default"].createElement("p", null, blockedMessage),
|
10141
|
+
blockedMessageLink && (React__default["default"].createElement(react.Link, { target: '_blank', href: blockedMessageLink }, blockedMessageLinkText))) }));
|
10142
|
+
};
|
10143
|
+
// https://stackoverflow.com/questions/28899298/extract-the-text-out-of-html-string-using-javascript
|
10144
|
+
const extractContent = (s) => {
|
10145
|
+
const span = document.createElement('span');
|
10146
|
+
span.innerHTML = s;
|
10147
|
+
return span.textContent || span.innerText;
|
10148
|
+
};
|
10149
|
+
const generateLiveMessage = (props) => {
|
10150
|
+
const liveAuthor = _formatString(props.strings.liveAuthorIntro, { author: `${props.message.senderDisplayName}` });
|
10151
|
+
return `${props.message.editedOn ? props.strings.editedTag : ''} ${props.message.mine ? '' : liveAuthor} ${extractContent(props.message.content || '')} `;
|
10152
|
+
};
|
10153
|
+
const messageContentAriaText = (props) => {
|
10154
|
+
// Strip all html tags from the content for aria.
|
10155
|
+
return props.message.content
|
10156
|
+
? props.message.mine
|
10157
|
+
? _formatString(props.strings.messageContentMineAriaText, {
|
10158
|
+
message: DOMPurify__default["default"].sanitize(props.message.content, { ALLOWED_TAGS: [] })
|
10159
|
+
})
|
10160
|
+
: _formatString(props.strings.messageContentAriaText, {
|
10161
|
+
author: `${props.message.senderDisplayName}`,
|
10162
|
+
message: DOMPurify__default["default"].sanitize(props.message.content, { ALLOWED_TAGS: [] })
|
10163
|
+
})
|
10164
|
+
: undefined;
|
10165
|
+
};
|
10166
|
+
const processNodeDefinitions = htmlToReact.ProcessNodeDefinitions();
|
10167
|
+
const htmlToReactParser = htmlToReact.Parser();
|
10168
|
+
/* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
|
10169
|
+
const processInlineImage = (props) => ({
|
10170
|
+
// Custom <img> processing
|
10171
|
+
shouldProcessNode: (node) => {
|
10172
|
+
var _a;
|
10173
|
+
function isImageNode(file) {
|
10174
|
+
return file.attachmentType === 'inlineImage' && file.id === node.attribs.id;
|
10175
|
+
}
|
10176
|
+
// Process img node with id in attachments list
|
10177
|
+
return (node.name &&
|
10178
|
+
node.name === 'img' &&
|
10179
|
+
node.attribs &&
|
10180
|
+
node.attribs.id &&
|
10181
|
+
((_a = props.message.attachedFilesMetadata) === null || _a === void 0 ? void 0 : _a.find(isImageNode)));
|
10182
|
+
},
|
10183
|
+
processNode: (node, children, index) => {
|
10184
|
+
node.attribs = Object.assign(Object.assign({}, node.attribs), { 'aria-label': node.attribs.name });
|
10185
|
+
// logic to check id in map/list
|
10186
|
+
if (props.attachmentsMap && node.attribs.id in props.attachmentsMap) {
|
10187
|
+
node.attribs = Object.assign(Object.assign({}, node.attribs), { src: props.attachmentsMap[node.attribs.id] });
|
10188
|
+
}
|
10189
|
+
/* @conditional-compile-remove(image-gallery) */
|
10190
|
+
const handleOnClick = () => {
|
10191
|
+
props.onInlineImageClicked && props.onInlineImageClicked(node.attribs.id);
|
10192
|
+
};
|
10193
|
+
/* @conditional-compile-remove(image-gallery) */
|
10194
|
+
return (React__default["default"].createElement("span", { "data-ui-id": node.attribs.id, onClick: handleOnClick, tabIndex: 0, role: "button", style: {
|
10195
|
+
cursor: 'pointer'
|
10196
|
+
}, onKeyDown: (e) => {
|
10197
|
+
if (e.key === 'Enter') {
|
10198
|
+
handleOnClick();
|
10199
|
+
}
|
10200
|
+
} }, processNodeDefinitions.processDefaultNode(node, children, index)));
|
10201
|
+
}
|
10202
|
+
});
|
10203
|
+
/* @conditional-compile-remove(mention) */
|
10204
|
+
const processMention = (props) => ({
|
10205
|
+
shouldProcessNode: (node) => {
|
10206
|
+
var _a;
|
10207
|
+
if ((_a = props.mentionDisplayOptions) === null || _a === void 0 ? void 0 : _a.onRenderMention) {
|
10208
|
+
// Override the handling of the <msft-mention> tag in the HTML if there's a custom renderer
|
10209
|
+
return node.name === 'msft-mention';
|
10210
|
+
}
|
10211
|
+
return false;
|
10212
|
+
},
|
10213
|
+
processNode: (node) => {
|
10214
|
+
var _a, _b, _c;
|
10215
|
+
if ((_a = props.mentionDisplayOptions) === null || _a === void 0 ? void 0 : _a.onRenderMention) {
|
10216
|
+
const { id } = node.attribs;
|
10217
|
+
const mention = {
|
10218
|
+
id: id,
|
10219
|
+
displayText: (_c = (_b = node.children[0]) === null || _b === void 0 ? void 0 : _b.data) !== null && _c !== void 0 ? _c : ''
|
10220
|
+
};
|
10221
|
+
return props.mentionDisplayOptions.onRenderMention(mention, defaultOnMentionRender);
|
10222
|
+
}
|
10223
|
+
return processNodeDefinitions.processDefaultNode;
|
10224
|
+
}
|
10225
|
+
});
|
10226
|
+
const processHtmlToReact = (props) => {
|
10227
|
+
var _a;
|
10228
|
+
const steps = [
|
10229
|
+
/* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
|
10230
|
+
processInlineImage(props),
|
10231
|
+
/* @conditional-compile-remove(mention) */
|
10232
|
+
processMention(props),
|
10233
|
+
{
|
10234
|
+
// Process everything else in the default way
|
10235
|
+
shouldProcessNode: htmlToReact.IsValidNodeDefinitions.alwaysValid,
|
10236
|
+
processNode: processNodeDefinitions.processDefaultNode
|
10237
|
+
}
|
10238
|
+
];
|
10239
|
+
return htmlToReactParser.parseWithInstructions((_a = props.message.content) !== null && _a !== void 0 ? _a : '', htmlToReact.IsValidNodeDefinitions.alwaysValid, steps);
|
10323
10240
|
};
|
10241
|
+
|
10242
|
+
// Copyright (c) Microsoft Corporation.
|
10324
10243
|
/**
|
10244
|
+
* Props for the Chat.Message action menu.
|
10245
|
+
* This is the 3 dots that appear when hovering over one of your own chat messages.
|
10246
|
+
*
|
10325
10247
|
* @private
|
10326
10248
|
*/
|
10327
|
-
const
|
10328
|
-
|
10329
|
-
|
10330
|
-
|
10331
|
-
|
10332
|
-
|
10333
|
-
|
10334
|
-
|
10335
|
-
|
10336
|
-
|
10337
|
-
|
10249
|
+
const chatMessageActionMenuProps = (menuProps) => {
|
10250
|
+
const { ariaLabel, enabled, theme, menuExpanded } = menuProps;
|
10251
|
+
// Show the action button while the flyout is open (otherwise this will dismiss when the pointer is hovered over the flyout)
|
10252
|
+
const showActionMenu = enabled || menuExpanded;
|
10253
|
+
const actionMenuProps = {
|
10254
|
+
children: (React__default["default"].createElement("div", { tabIndex: showActionMenu ? 0 : undefined, key: "menuButton", "data-ui-id": "chat-composite-message-action-icon", ref: menuProps.menuButtonRef, onClick: showActionMenu ? () => menuProps.onActionButtonClick() : undefined, style: { margin: showActionMenu ? '1px' : 0, minHeight: showActionMenu ? undefined : '30px' }, role: "button", "aria-label": showActionMenu ? ariaLabel : undefined, "aria-haspopup": showActionMenu, "aria-expanded": menuExpanded, onKeyDown: (e) => {
|
10255
|
+
// simulate <button> tag behavior
|
10256
|
+
if (showActionMenu && (e.key === 'Enter' || e.key === ' ')) {
|
10257
|
+
menuProps.onActionButtonClick();
|
10258
|
+
}
|
10259
|
+
} }, showActionMenu ? (React__default["default"].createElement(react.Icon, { iconName: "ChatMessageOptions", "aria-label": ariaLabel, styles: iconWrapperStyle(theme, menuExpanded) })) : undefined))
|
10260
|
+
};
|
10261
|
+
return actionMenuProps;
|
10338
10262
|
};
|
10339
10263
|
|
10340
10264
|
// Copyright (c) Microsoft Corporation.
|
10341
|
-
//
|
10342
|
-
|
10343
|
-
|
10344
|
-
|
10265
|
+
// Licensed under the MIT License.
|
10266
|
+
var __awaiter$y = (window && window.__awaiter) || function (thisArg, _arguments, P, generator) {
|
10267
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
10268
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
10269
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
10270
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
10271
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
10272
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
10273
|
+
});
|
10274
|
+
};
|
10275
|
+
const fileDownloadCardsStyle = {
|
10276
|
+
marginTop: '0.25rem'
|
10277
|
+
};
|
10278
|
+
const actionIconStyle = { height: '1rem' };
|
10279
|
+
/**
|
10280
|
+
* @internal
|
10345
10281
|
*/
|
10346
|
-
const
|
10347
|
-
|
10348
|
-
|
10349
|
-
|
10350
|
-
|
10351
|
-
|
10352
|
-
|
10353
|
-
|
10354
|
-
|
10355
|
-
|
10356
|
-
|
10357
|
-
|
10358
|
-
|
10359
|
-
|
10360
|
-
|
10361
|
-
|
10362
|
-
|
10363
|
-
|
10364
|
-
|
10365
|
-
|
10366
|
-
|
10367
|
-
|
10368
|
-
|
10369
|
-
|
10370
|
-
|
10371
|
-
|
10372
|
-
|
10373
|
-
|
10374
|
-
|
10375
|
-
|
10376
|
-
|
10377
|
-
|
10378
|
-
|
10379
|
-
|
10380
|
-
|
10381
|
-
|
10382
|
-
|
10383
|
-
|
10384
|
-
|
10385
|
-
|
10386
|
-
|
10387
|
-
|
10388
|
-
|
10389
|
-
|
10390
|
-
|
10391
|
-
|
10392
|
-
|
10393
|
-
|
10394
|
-
|
10395
|
-
|
10396
|
-
|
10397
|
-
|
10398
|
-
|
10399
|
-
|
10400
|
-
|
10401
|
-
|
10402
|
-
|
10403
|
-
|
10404
|
-
|
10405
|
-
|
10406
|
-
|
10407
|
-
|
10408
|
-
|
10409
|
-
|
10410
|
-
|
10411
|
-
|
10412
|
-
|
10413
|
-
|
10414
|
-
|
10415
|
-
|
10416
|
-
|
10417
|
-
|
10418
|
-
|
10419
|
-
|
10420
|
-
|
10421
|
-
|
10422
|
-
|
10423
|
-
|
10424
|
-
|
10425
|
-
|
10426
|
-
|
10427
|
-
|
10428
|
-
|
10429
|
-
|
10430
|
-
|
10431
|
-
|
10432
|
-
|
10433
|
-
|
10434
|
-
|
10435
|
-
|
10436
|
-
|
10437
|
-
|
10438
|
-
|
10439
|
-
|
10440
|
-
|
10441
|
-
|
10442
|
-
|
10443
|
-
|
10444
|
-
|
10445
|
-
|
10446
|
-
|
10447
|
-
|
10448
|
-
|
10449
|
-
|
10450
|
-
|
10451
|
-
|
10452
|
-
|
10453
|
-
|
10454
|
-
|
10455
|
-
|
10456
|
-
|
10457
|
-
|
10458
|
-
|
10459
|
-
|
10460
|
-
|
10461
|
-
|
10462
|
-
|
10463
|
-
|
10464
|
-
|
10465
|
-
|
10466
|
-
|
10467
|
-
|
10468
|
-
|
10469
|
-
|
10470
|
-
|
10471
|
-
|
10472
|
-
|
10473
|
-
|
10474
|
-
|
10475
|
-
|
10476
|
-
|
10477
|
-
|
10478
|
-
|
10479
|
-
|
10480
|
-
|
10481
|
-
|
10482
|
-
|
10483
|
-
|
10484
|
-
|
10485
|
-
|
10486
|
-
|
10487
|
-
|
10488
|
-
|
10489
|
-
|
10490
|
-
|
10491
|
-
|
10492
|
-
|
10493
|
-
|
10494
|
-
|
10495
|
-
|
10496
|
-
|
10497
|
-
|
10498
|
-
|
10499
|
-
|
10500
|
-
|
10501
|
-
|
10502
|
-
|
10503
|
-
|
10504
|
-
|
10505
|
-
|
10506
|
-
|
10507
|
-
|
10282
|
+
const _FileDownloadCards = (props) => {
|
10283
|
+
var _a, _b;
|
10284
|
+
const { userId, fileMetadata } = props;
|
10285
|
+
const [showSpinner, setShowSpinner] = React.useState(false);
|
10286
|
+
const localeStrings = useLocaleStringsTrampoline();
|
10287
|
+
const downloadFileButtonString = React.useMemo(() => () => {
|
10288
|
+
var _a, _b;
|
10289
|
+
return (_b = (_a = props.strings) === null || _a === void 0 ? void 0 : _a.downloadFile) !== null && _b !== void 0 ? _b : localeStrings.downloadFile;
|
10290
|
+
}, [(_a = props.strings) === null || _a === void 0 ? void 0 : _a.downloadFile, localeStrings.downloadFile]);
|
10291
|
+
const isFileSharingAttachment = React.useCallback((attachment) => {
|
10292
|
+
/* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
|
10293
|
+
return attachment.attachmentType === 'fileSharing';
|
10294
|
+
}, []);
|
10295
|
+
/* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
|
10296
|
+
const isShowDownloadIcon = React.useCallback((attachment) => {
|
10297
|
+
var _a;
|
10298
|
+
/* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
|
10299
|
+
return attachment.attachmentType === 'fileSharing' && ((_a = attachment.payload) === null || _a === void 0 ? void 0 : _a.teamsFileAttachment) !== 'true';
|
10300
|
+
}, []);
|
10301
|
+
const fileCardGroupDescription = React.useMemo(() => () => {
|
10302
|
+
var _a, _b;
|
10303
|
+
const fileGroupLocaleString = (_b = (_a = props.strings) === null || _a === void 0 ? void 0 : _a.fileCardGroupMessage) !== null && _b !== void 0 ? _b : localeStrings.fileCardGroupMessage;
|
10304
|
+
/* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
|
10305
|
+
return _formatString(fileGroupLocaleString, {
|
10306
|
+
fileCount: `${fileMetadata.filter(isFileSharingAttachment).length}`
|
10307
|
+
});
|
10308
|
+
}, [(_b = props.strings) === null || _b === void 0 ? void 0 : _b.fileCardGroupMessage, localeStrings.fileCardGroupMessage, fileMetadata, isFileSharingAttachment]);
|
10309
|
+
const fileDownloadHandler = React.useCallback((userId, file) => __awaiter$y(void 0, void 0, void 0, function* () {
|
10310
|
+
if (!props.downloadHandler) {
|
10311
|
+
window.open(file.url, '_blank', 'noopener,noreferrer');
|
10312
|
+
}
|
10313
|
+
else {
|
10314
|
+
setShowSpinner(true);
|
10315
|
+
try {
|
10316
|
+
const response = yield props.downloadHandler(userId, file);
|
10317
|
+
setShowSpinner(false);
|
10318
|
+
if (response instanceof URL) {
|
10319
|
+
window.open(response.toString(), '_blank', 'noopener,noreferrer');
|
10320
|
+
}
|
10321
|
+
else {
|
10322
|
+
props.onDownloadErrorMessage && props.onDownloadErrorMessage(response.errorMessage);
|
10323
|
+
}
|
10324
|
+
}
|
10325
|
+
finally {
|
10326
|
+
setShowSpinner(false);
|
10327
|
+
}
|
10328
|
+
}
|
10329
|
+
}), [props]);
|
10330
|
+
if (!fileMetadata ||
|
10331
|
+
fileMetadata.length === 0 ||
|
10332
|
+
/* @conditional-compile-remove(teams-inline-images-and-file-sharing) */ !fileMetadata.some(isFileSharingAttachment)) {
|
10333
|
+
return React__default["default"].createElement(React__default["default"].Fragment, null);
|
10334
|
+
}
|
10335
|
+
return (React__default["default"].createElement("div", { style: fileDownloadCardsStyle, "data-ui-id": "file-download-card-group" },
|
10336
|
+
React__default["default"].createElement(_FileCardGroup, { ariaLabel: fileCardGroupDescription() }, fileMetadata &&
|
10337
|
+
fileMetadata
|
10338
|
+
.filter((attachment) => {
|
10339
|
+
/* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
|
10340
|
+
return isFileSharingAttachment(attachment);
|
10341
|
+
})
|
10342
|
+
.map((file) => (React__default["default"].createElement(react.TooltipHost, { content: downloadFileButtonString(), key: file.name },
|
10343
|
+
React__default["default"].createElement(_FileCard, { fileName: file.name, key: file.name, fileExtension: file.extension, actionIcon: showSpinner ? (React__default["default"].createElement(react.Spinner, { size: react.SpinnerSize.medium, "aria-live": 'polite', role: 'status' })) : /* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
|
10344
|
+
isShowDownloadIcon(file) ? (React__default["default"].createElement(react.IconButton, { className: iconButtonClassName, ariaLabel: downloadFileButtonString() },
|
10345
|
+
React__default["default"].createElement(DownloadIconTrampoline, null))) : undefined, actionHandler: () => fileDownloadHandler(userId, file) })))))));
|
10346
|
+
};
|
10347
|
+
/**
|
10348
|
+
* @private
|
10349
|
+
*/
|
10350
|
+
const DownloadIconTrampoline = () => {
|
10351
|
+
// @conditional-compile-remove(file-sharing)
|
10352
|
+
return React__default["default"].createElement(react.Icon, { "data-ui-id": "file-download-card-download-icon", iconName: "DownloadFile", style: actionIconStyle });
|
10353
|
+
};
|
10354
|
+
const useLocaleStringsTrampoline = () => {
|
10355
|
+
/* @conditional-compile-remove(file-sharing) @conditional-compile-remove(teams-inline-images-and-file-sharing)*/
|
10356
|
+
return useLocale$1().strings.messageThread;
|
10357
|
+
};
|
10358
|
+
|
10359
|
+
// Copyright (c) Microsoft Corporation.
|
10360
|
+
// Licensed under the MIT License.
|
10361
|
+
var __awaiter$x = (window && window.__awaiter) || function (thisArg, _arguments, P, generator) {
|
10362
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
10363
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
10364
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
10365
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
10366
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
10367
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
10368
|
+
});
|
10369
|
+
};
|
10370
|
+
const generateDefaultTimestamp = (createdOn, showDate, strings) => {
|
10371
|
+
const formattedTimestamp = showDate
|
10372
|
+
? formatTimestampForChatMessage(createdOn, new Date(), strings)
|
10373
|
+
: formatTimeForChatMessage(createdOn);
|
10374
|
+
return formattedTimestamp;
|
10375
|
+
};
|
10376
|
+
// onDisplayDateTimeString from props overwrite onDisplayDateTimeString from locale
|
10377
|
+
const generateCustomizedTimestamp = (props, createdOn, locale) => {
|
10378
|
+
/* @conditional-compile-remove(date-time-customization) */
|
10379
|
+
return props.onDisplayDateTimeString
|
10380
|
+
? props.onDisplayDateTimeString(createdOn)
|
10381
|
+
: locale.onDisplayDateTimeString
|
10382
|
+
? locale.onDisplayDateTimeString(createdOn)
|
10383
|
+
: '';
|
10384
|
+
};
|
10385
|
+
/** @private */
|
10386
|
+
const MessageBubble = (props) => {
|
10387
|
+
var _a;
|
10388
|
+
const ids = useIdentifiers();
|
10389
|
+
const theme = useTheme();
|
10390
|
+
const locale = useLocale$1();
|
10391
|
+
const { userId, message, onRemoveClick, onResendClick, disableEditing, showDate, messageContainerStyle, strings, onEditClick, remoteParticipantsCount = 0, onRenderAvatar, showMessageStatus, messageStatus, fileDownloadHandler,
|
10392
|
+
/* @conditional-compile-remove(image-gallery) */
|
10393
|
+
onInlineImageClicked, shouldOverlapAvatarAndMessage } = props;
|
10394
|
+
const defaultTimeStamp = message.createdOn
|
10395
|
+
? generateDefaultTimestamp(message.createdOn, showDate, strings)
|
10396
|
+
: undefined;
|
10397
|
+
const customTimestamp = message.createdOn ? generateCustomizedTimestamp(props, message.createdOn, locale) : '';
|
10398
|
+
const formattedTimestamp = customTimestamp || defaultTimeStamp;
|
10399
|
+
// Track if the action menu was opened by touch - if so we increase the touch targets for the items
|
10400
|
+
const [wasInteractionByTouch, setWasInteractionByTouch] = React.useState(false);
|
10401
|
+
// `focused` state is used for show/hide actionMenu
|
10402
|
+
const [focused, setFocused] = React__default["default"].useState(false);
|
10403
|
+
// The chat message action flyout should target the Chat.Message action menu if clicked,
|
10404
|
+
// or target the chat message if opened via touch press.
|
10405
|
+
// Undefined indicates the flyout menu should not be being shown.
|
10406
|
+
const messageRef = React.useRef(null);
|
10407
|
+
const messageActionButtonRef = React.useRef(null);
|
10408
|
+
const [chatMessageActionFlyoutTarget, setChatMessageActionFlyoutTarget] = React.useState(undefined);
|
10409
|
+
const chatActionsEnabled = !disableEditing &&
|
10410
|
+
message.status !== 'sending' &&
|
10411
|
+
!!message.mine &&
|
10412
|
+
/* @conditional-compile-remove(data-loss-prevention) */ message.messageType !== 'blocked';
|
10413
|
+
const [messageReadBy, setMessageReadBy] = React.useState([]);
|
10414
|
+
const actionMenuProps = chatMessageActionMenuProps({
|
10415
|
+
ariaLabel: (_a = strings.actionMenuMoreOptions) !== null && _a !== void 0 ? _a : '',
|
10416
|
+
enabled: chatActionsEnabled,
|
10417
|
+
menuButtonRef: messageActionButtonRef,
|
10418
|
+
menuExpanded: chatMessageActionFlyoutTarget === messageActionButtonRef,
|
10419
|
+
onActionButtonClick: () => {
|
10420
|
+
if (message.messageType === 'chat') {
|
10421
|
+
props.onActionButtonClick(message, setMessageReadBy);
|
10422
|
+
setChatMessageActionFlyoutTarget(messageActionButtonRef);
|
10423
|
+
}
|
10424
|
+
},
|
10425
|
+
theme
|
10426
|
+
});
|
10427
|
+
const onActionFlyoutDismiss = React.useCallback(() => {
|
10428
|
+
// When the flyout dismiss is called, since we control if the action flyout is visible
|
10429
|
+
// or not we need to set the target to undefined here to actually hide the action flyout
|
10430
|
+
setChatMessageActionFlyoutTarget(undefined);
|
10431
|
+
}, [setChatMessageActionFlyoutTarget]);
|
10432
|
+
const defaultOnRenderFileDownloads = React.useCallback(() => (React__default["default"].createElement(_FileDownloadCards, { userId: userId, fileMetadata: message['attachedFilesMetadata'] || [], downloadHandler: fileDownloadHandler,
|
10433
|
+
/* @conditional-compile-remove(file-sharing) @conditional-compile-remove(teams-inline-images-and-file-sharing)*/
|
10434
|
+
strings: { downloadFile: strings.downloadFile, fileCardGroupMessage: strings.fileCardGroupMessage } })), [
|
10435
|
+
userId,
|
10436
|
+
message,
|
10437
|
+
/* @conditional-compile-remove(file-sharing) @conditional-compile-remove(teams-inline-images-and-file-sharing)*/
|
10438
|
+
strings,
|
10439
|
+
fileDownloadHandler
|
10440
|
+
]);
|
10441
|
+
const editedOn = 'editedOn' in message ? message.editedOn : undefined;
|
10442
|
+
const getMessageDetails = React.useCallback(() => {
|
10443
|
+
if (messageStatus === 'failed') {
|
10444
|
+
return React__default["default"].createElement("div", { className: chatMessageFailedTagStyle(theme) }, strings.failToSendTag);
|
10445
|
+
}
|
10446
|
+
else if (message.messageType === 'chat' && editedOn) {
|
10447
|
+
return React__default["default"].createElement("div", { className: chatMessageEditedTagStyle(theme) }, strings.editedTag);
|
10448
|
+
}
|
10449
|
+
return undefined;
|
10450
|
+
}, [editedOn, message.messageType, messageStatus, strings.editedTag, strings.failToSendTag, theme]);
|
10451
|
+
/* @conditional-compile-remove(image-gallery) */
|
10452
|
+
const handleOnInlineImageClicked = React.useCallback((attachmentId) => __awaiter$x(void 0, void 0, void 0, function* () {
|
10453
|
+
if (onInlineImageClicked === undefined) {
|
10454
|
+
return;
|
10455
|
+
}
|
10456
|
+
yield onInlineImageClicked(attachmentId, message.messageId);
|
10457
|
+
}), [message, onInlineImageClicked]);
|
10458
|
+
const getContent = React.useCallback(() => {
|
10459
|
+
/* @conditional-compile-remove(data-loss-prevention) */
|
10460
|
+
if (message.messageType === 'blocked') {
|
10461
|
+
return (React__default["default"].createElement("div", { tabIndex: 0 },
|
10462
|
+
React__default["default"].createElement(BlockedMessageContent, { message: message, strings: strings })));
|
10463
|
+
}
|
10464
|
+
return (React__default["default"].createElement("div", { tabIndex: 0, className: "ui-chat__message__content" },
|
10465
|
+
React__default["default"].createElement(ChatMessageContent, { message: message, strings: strings,
|
10466
|
+
/* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
|
10467
|
+
onFetchAttachments: props.onFetchAttachments,
|
10468
|
+
/* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
|
10469
|
+
attachmentsMap: props.attachmentsMap,
|
10470
|
+
/* @conditional-compile-remove(mention) */
|
10471
|
+
mentionDisplayOptions: props.mentionDisplayOptions,
|
10472
|
+
/* @conditional-compile-remove(image-gallery) */
|
10473
|
+
onInlineImageClicked: handleOnInlineImageClicked }),
|
10474
|
+
props.onRenderFileDownloads ? props.onRenderFileDownloads(userId, message) : defaultOnRenderFileDownloads()));
|
10475
|
+
}, [
|
10476
|
+
defaultOnRenderFileDownloads,
|
10477
|
+
message,
|
10478
|
+
props,
|
10479
|
+
strings,
|
10480
|
+
userId,
|
10481
|
+
/* @conditional-compile-remove(image-gallery) */
|
10482
|
+
handleOnInlineImageClicked
|
10483
|
+
]);
|
10484
|
+
const isBlockedMessage = /* @conditional-compile-remove(data-loss-prevention) */ message.messageType === 'blocked';
|
10485
|
+
const chatMyMessageStyles = useChatMyMessageStyles();
|
10486
|
+
const chatMessageCommonStyles = useChatMessageCommonStyles();
|
10487
|
+
const chatMessageStyles = useChatMessageStyles();
|
10488
|
+
const chatItemMessageContainerClassName = reactComponents.mergeClasses(
|
10489
|
+
// messageContainerStyle used in className and style prop as style prop can't handle CSS selectors
|
10490
|
+
chatMessageStyles.body, isBlockedMessage
|
10491
|
+
? chatMessageCommonStyles.blocked
|
10492
|
+
: props.message.status === 'failed'
|
10493
|
+
? chatMessageCommonStyles.failed
|
10494
|
+
: undefined, shouldOverlapAvatarAndMessage ? chatMessageStyles.avatarOverlap : chatMessageStyles.avatarNoOverlap, message.attached === 'top' || message.attached === false
|
10495
|
+
? chatMessageStyles.bodyWithAvatar
|
10496
|
+
: chatMessageStyles.bodyWithoutAvatar, react.mergeStyles(messageContainerStyle));
|
10497
|
+
const attached = message.attached === true ? 'center' : message.attached === 'bottom' ? 'bottom' : 'top';
|
10498
|
+
const chatMessage = (React__default["default"].createElement(React__default["default"].Fragment, null,
|
10499
|
+
React__default["default"].createElement("div", { key: props.message.messageId }, message.mine ? (React__default["default"].createElement(reactChat.ChatMyMessage, { attached: attached, key: props.message.messageId, body: {
|
10500
|
+
// messageContainerStyle used in className and style prop as style prop can't handle CSS selectors
|
10501
|
+
className: reactComponents.mergeClasses(chatMyMessageStyles.body, isBlockedMessage
|
10502
|
+
? chatMessageCommonStyles.blocked
|
10503
|
+
: props.message.status === 'failed'
|
10504
|
+
? chatMessageCommonStyles.failed
|
10505
|
+
: undefined, attached !== 'top' ? chatMyMessageStyles.bodyAttached : undefined, react.mergeStyles(messageContainerStyle)),
|
10506
|
+
style: Object.assign({}, createStyleFromV8Style(messageContainerStyle)),
|
10507
|
+
ref: messageRef
|
10508
|
+
}, root: {
|
10509
|
+
className: chatMyMessageStyles.root,
|
10510
|
+
onBlur: (e) => {
|
10511
|
+
// `focused` controls is focused the whole `ChatMessage` or any of its children. When we're navigating
|
10512
|
+
// with keyboard the focused element will be changed and there is no way to use `:focus` selector
|
10513
|
+
if (chatMessageActionFlyoutTarget === null || chatMessageActionFlyoutTarget === void 0 ? void 0 : chatMessageActionFlyoutTarget.current) {
|
10514
|
+
// doesn't dismiss action button if flyout is open, otherwise, narrator's focus will stay on the closed action menu
|
10515
|
+
return;
|
10516
|
+
}
|
10517
|
+
const shouldPreserveFocusState = e.currentTarget.contains(e.relatedTarget);
|
10518
|
+
setFocused(shouldPreserveFocusState);
|
10519
|
+
},
|
10520
|
+
onFocus: () => {
|
10521
|
+
// react onFocus is called even when nested component receives focus (i.e. it bubbles)
|
10522
|
+
// so when focus moves within actionMenu, the `focus` state in chatMessage remains true, and keeps actionMenu visible
|
10523
|
+
setFocused(true);
|
10524
|
+
},
|
10525
|
+
// make body not focusable to remove repetitions from narrators.
|
10526
|
+
// inner components are already focusable
|
10527
|
+
role: 'none',
|
10528
|
+
tabIndex: -1
|
10529
|
+
}, "data-ui-id": "chat-composite-message", author: React__default["default"].createElement(react.Text, { className: chatMessageDateStyle, tabIndex: 0 }, message.senderDisplayName), timestamp: React__default["default"].createElement(react.Text, { className: chatMessageDateStyle, "data-ui-id": ids.messageTimestamp, tabIndex: 0 }, formattedTimestamp), details: getMessageDetails(), actions: {
|
10530
|
+
children: actionMenuProps === null || actionMenuProps === void 0 ? void 0 : actionMenuProps.children,
|
10531
|
+
className: reactComponents.mergeClasses(chatMyMessageStyles.menu,
|
10532
|
+
// Make actions menu visible when the message is focused or the flyout is shown
|
10533
|
+
focused || (chatMessageActionFlyoutTarget === null || chatMessageActionFlyoutTarget === void 0 ? void 0 : chatMessageActionFlyoutTarget.current)
|
10534
|
+
? chatMyMessageStyles.menuVisible
|
10535
|
+
: chatMyMessageStyles.menuHidden, attached !== 'top' ? chatMyMessageStyles.menuAttached : undefined)
|
10536
|
+
}, onTouchStart: () => setWasInteractionByTouch(true), onPointerDown: () => setWasInteractionByTouch(false), onKeyDown: () => setWasInteractionByTouch(false), onClick: () => {
|
10537
|
+
if (!wasInteractionByTouch) {
|
10538
|
+
return;
|
10539
|
+
}
|
10540
|
+
// If the message was touched via touch we immediately open the menu
|
10541
|
+
// flyout (when using mouse the 3-dot menu that appears on hover
|
10542
|
+
// must be clicked to open the flyout).
|
10543
|
+
// In doing so here we set the target of the flyout to be the message and
|
10544
|
+
// not the 3-dot menu button to position the flyout correctly.
|
10545
|
+
setChatMessageActionFlyoutTarget(messageRef);
|
10546
|
+
if (message.messageType === 'chat') {
|
10547
|
+
props.onActionButtonClick(message, setMessageReadBy);
|
10548
|
+
}
|
10549
|
+
} }, getContent())) : (React__default["default"].createElement(reactChat.ChatMessage, { attached: attached, key: props.message.messageId, root: {
|
10550
|
+
className: chatMessageStyles.root,
|
10551
|
+
// make body not focusable to remove repetitions from narrators.
|
10552
|
+
// inner components are already focusable
|
10553
|
+
tabIndex: -1,
|
10554
|
+
role: 'none'
|
10555
|
+
}, author: React__default["default"].createElement(react.Text, { className: chatMessageAuthorStyle }, message.senderDisplayName), body: {
|
10556
|
+
className: chatItemMessageContainerClassName,
|
10557
|
+
style: Object.assign({}, createStyleFromV8Style(messageContainerStyle))
|
10558
|
+
}, "data-ui-id": "chat-composite-message", timestamp: React__default["default"].createElement(react.Text, { className: chatMessageDateStyle, "data-ui-id": ids.messageTimestamp }, formattedTimestamp) }, getContent()))),
|
10559
|
+
chatActionsEnabled && (React__default["default"].createElement(ChatMessageActionFlyout, { hidden: !chatMessageActionFlyoutTarget, target: chatMessageActionFlyoutTarget, increaseFlyoutItemSize: wasInteractionByTouch, onDismiss: onActionFlyoutDismiss, onEditClick: onEditClick, onRemoveClick: onRemoveClick, onResendClick: onResendClick, strings: strings, messageReadBy: messageReadBy, messageStatus: messageStatus !== null && messageStatus !== void 0 ? messageStatus : 'failed', remoteParticipantsCount: remoteParticipantsCount, onRenderAvatar: onRenderAvatar, showMessageStatus: showMessageStatus }))));
|
10560
|
+
return chatMessage;
|
10508
10561
|
};
|
10509
|
-
/**
|
10510
|
-
|
10511
|
-
|
10512
|
-
|
10513
|
-
|
10514
|
-
|
10515
|
-
|
10516
|
-
|
10517
|
-
|
10518
|
-
|
10562
|
+
/** @private */
|
10563
|
+
const ChatMessageComponentAsMessageBubble = React__default["default"].memo(MessageBubble);
|
10564
|
+
|
10565
|
+
// Copyright (c) Microsoft Corporation.
|
10566
|
+
// Licensed under the MIT License.
|
10567
|
+
var __awaiter$w = (window && window.__awaiter) || function (thisArg, _arguments, P, generator) {
|
10568
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
10569
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
10570
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
10571
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
10572
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
10573
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
10574
|
+
});
|
10519
10575
|
};
|
10520
10576
|
/**
|
10521
|
-
*
|
10577
|
+
* @private
|
10522
10578
|
*/
|
10523
|
-
const
|
10524
|
-
|
10525
|
-
|
10526
|
-
|
10527
|
-
|
10528
|
-
|
10579
|
+
const ChatMessageComponent = (props) => {
|
10580
|
+
var _a, _b;
|
10581
|
+
const { onDeleteMessage, onSendMessage, message } = props;
|
10582
|
+
const [isEditing, setIsEditing] = React.useState(false);
|
10583
|
+
const onEditClick = React.useCallback(() => setIsEditing(true), [setIsEditing]);
|
10584
|
+
const clientMessageId = 'clientMessageId' in message ? message.clientMessageId : undefined;
|
10585
|
+
const content = 'content' in message ? message.content : undefined;
|
10586
|
+
const onRemoveClick = React.useCallback(() => {
|
10587
|
+
if (onDeleteMessage && message.messageId) {
|
10588
|
+
onDeleteMessage(message.messageId);
|
10589
|
+
}
|
10590
|
+
// when fail to send, message does not have message id, delete message using clientMessageId
|
10591
|
+
else if (onDeleteMessage && message.messageType === 'chat' && clientMessageId) {
|
10592
|
+
onDeleteMessage(clientMessageId);
|
10593
|
+
}
|
10594
|
+
}, [onDeleteMessage, message.messageId, message.messageType, clientMessageId]);
|
10595
|
+
const onResendClick = React.useCallback(() => {
|
10596
|
+
onDeleteMessage && clientMessageId && onDeleteMessage(clientMessageId);
|
10597
|
+
onSendMessage && onSendMessage(content !== undefined ? content : '');
|
10598
|
+
}, [clientMessageId, content, onSendMessage, onDeleteMessage]);
|
10599
|
+
if (isEditing && message.messageType === 'chat') {
|
10600
|
+
return (React__default["default"].createElement(ChatMessageComponentAsEditBox, { message: message, strings: props.strings, onSubmit: (text, metadata, options) => __awaiter$w(void 0, void 0, void 0, function* () {
|
10601
|
+
props.onUpdateMessage &&
|
10602
|
+
message.messageId &&
|
10603
|
+
(yield props.onUpdateMessage(message.messageId, text, metadata, options));
|
10604
|
+
setIsEditing(false);
|
10605
|
+
}), onCancel: (messageId) => {
|
10606
|
+
props.onCancelEditMessage && props.onCancelEditMessage(messageId);
|
10607
|
+
setIsEditing(false);
|
10608
|
+
},
|
10609
|
+
/* @conditional-compile-remove(mention) */
|
10610
|
+
mentionLookupOptions: (_a = props.mentionOptions) === null || _a === void 0 ? void 0 : _a.lookupOptions }));
|
10611
|
+
}
|
10612
|
+
else {
|
10613
|
+
return (React__default["default"].createElement(ChatMessageComponentAsMessageBubble, Object.assign({}, props, { onRemoveClick: onRemoveClick, onEditClick: onEditClick, onResendClick: onResendClick, onRenderAvatar: props.onRenderAvatar,
|
10614
|
+
/* @conditional-compile-remove(date-time-customization) */
|
10615
|
+
onDisplayDateTimeString: props.onDisplayDateTimeString, strings: props.strings,
|
10616
|
+
/* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
|
10617
|
+
onFetchAttachments: props.onFetchAttachments,
|
10618
|
+
/* @conditional-compile-remove(image-gallery) */
|
10619
|
+
onInlineImageClicked: props.onInlineImageClicked,
|
10620
|
+
/* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
|
10621
|
+
attachmentsMap: props.attachmentsMap,
|
10622
|
+
/* @conditional-compile-remove(mention) */
|
10623
|
+
mentionDisplayOptions: (_b = props.mentionOptions) === null || _b === void 0 ? void 0 : _b.displayOptions })));
|
10624
|
+
}
|
10529
10625
|
};
|
10626
|
+
|
10627
|
+
// Copyright (c) Microsoft Corporation.
|
10530
10628
|
/**
|
10531
|
-
*
|
10532
|
-
*
|
10629
|
+
* The component for rendering a chat message using Fluent UI components
|
10630
|
+
* and handling default and custom renderers.
|
10631
|
+
* This component handles rendering for chat message body, avatar and message status.
|
10632
|
+
* The chat message body, avatar and message status should be shown for both default and custom renderers.
|
10533
10633
|
*
|
10534
10634
|
* @private
|
10535
10635
|
*/
|
10536
|
-
const
|
10537
|
-
const
|
10538
|
-
|
10539
|
-
|
10540
|
-
|
10636
|
+
const FluentChatMessageComponentWrapper = (props) => {
|
10637
|
+
const { message, styles, shouldOverlapAvatarAndMessage, onRenderMessage, onRenderAvatar, showMessageStatus, onRenderMessageStatus, participantCount, readCount, onActionButtonClick,
|
10638
|
+
/* @conditional-compile-remove(date-time-customization) */
|
10639
|
+
onDisplayDateTimeString,
|
10640
|
+
/* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
|
10641
|
+
onFetchInlineAttachment,
|
10642
|
+
/* @conditional-compile-remove(image-gallery) */
|
10643
|
+
onInlineImageClicked,
|
10644
|
+
/* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
|
10645
|
+
inlineAttachments,
|
10646
|
+
/* @conditional-compile-remove(mention) */
|
10647
|
+
mentionOptions,
|
10648
|
+
/* @conditional-compile-remove(file-sharing) */
|
10649
|
+
fileDownloadHandler, userId,
|
10650
|
+
/* @conditional-compile-remove(file-sharing) */
|
10651
|
+
onRenderFileDownloads, defaultStatusRenderer, statusToRender } = props;
|
10652
|
+
const chatMessageRenderStyles = useChatMessageRenderStyles();
|
10653
|
+
const onRenderFileDownloadsMemo = React.useMemo(() => {
|
10654
|
+
/* @conditional-compile-remove(file-sharing) */
|
10655
|
+
return onRenderFileDownloads;
|
10656
|
+
}, [/* @conditional-compile-remove(file-sharing) */ onRenderFileDownloads]);
|
10657
|
+
// To rerender the defaultChatMessageRenderer if app running across days(every new day chat time stamp
|
10658
|
+
// needs to be regenerated), the dependency on "new Date().toDateString()"" is added.
|
10659
|
+
const defaultChatMessageRenderer = React.useCallback((messageProps) => {
|
10660
|
+
var _a;
|
10661
|
+
if (messageProps.message.messageType === 'chat' ||
|
10662
|
+
/* @conditional-compile-remove(data-loss-prevention) */ messageProps.message.messageType === 'blocked') {
|
10663
|
+
return (React__default["default"].createElement(ChatMessageComponent, Object.assign({}, messageProps, {
|
10664
|
+
/* @conditional-compile-remove(file-sharing) */
|
10665
|
+
onRenderFileDownloads: onRenderFileDownloadsMemo,
|
10666
|
+
/* @conditional-compile-remove(file-sharing) */
|
10667
|
+
strings: messageProps.strings, message: messageProps.message, userId: userId, remoteParticipantsCount: participantCount ? participantCount - 1 : 0, shouldOverlapAvatarAndMessage: shouldOverlapAvatarAndMessage, onRenderAvatar: onRenderAvatar, showMessageStatus: showMessageStatus, messageStatus: messageProps.message.status, onActionButtonClick: onActionButtonClick,
|
10668
|
+
/* @conditional-compile-remove(date-time-customization) */
|
10669
|
+
onDisplayDateTimeString: onDisplayDateTimeString,
|
10670
|
+
/* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
|
10671
|
+
onFetchAttachments: onFetchInlineAttachment,
|
10672
|
+
/* @conditional-compile-remove(image-gallery) */
|
10673
|
+
onInlineImageClicked: onInlineImageClicked,
|
10674
|
+
/* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
|
10675
|
+
attachmentsMap: (_a = inlineAttachments[messageProps.message.messageId]) !== null && _a !== void 0 ? _a : {},
|
10676
|
+
/* @conditional-compile-remove(mention) */
|
10677
|
+
mentionOptions: mentionOptions,
|
10678
|
+
/* @conditional-compile-remove(file-sharing) */
|
10679
|
+
fileDownloadHandler: fileDownloadHandler })));
|
10680
|
+
}
|
10681
|
+
return React__default["default"].createElement(React__default["default"].Fragment, null);
|
10682
|
+
}, [
|
10683
|
+
onActionButtonClick,
|
10684
|
+
onRenderAvatar,
|
10685
|
+
onRenderFileDownloadsMemo,
|
10686
|
+
participantCount,
|
10687
|
+
shouldOverlapAvatarAndMessage,
|
10688
|
+
showMessageStatus,
|
10689
|
+
userId,
|
10690
|
+
/* @conditional-compile-remove(date-time-customization) */
|
10691
|
+
onDisplayDateTimeString,
|
10692
|
+
/* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
|
10693
|
+
onFetchInlineAttachment,
|
10694
|
+
/* @conditional-compile-remove(image-gallery) */
|
10695
|
+
onInlineImageClicked,
|
10696
|
+
/* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
|
10697
|
+
inlineAttachments,
|
10698
|
+
/* @conditional-compile-remove(mention) */
|
10699
|
+
mentionOptions,
|
10700
|
+
/* @conditional-compile-remove(file-sharing) */
|
10701
|
+
fileDownloadHandler,
|
10702
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
10703
|
+
new Date().toDateString()
|
10704
|
+
]);
|
10705
|
+
const messageRenderer = React.useCallback((messageProps) => {
|
10706
|
+
return onRenderMessage === undefined
|
10707
|
+
? defaultChatMessageRenderer(Object.assign({}, messageProps))
|
10708
|
+
: onRenderMessage(messageProps, defaultChatMessageRenderer);
|
10709
|
+
}, [defaultChatMessageRenderer, onRenderMessage]);
|
10710
|
+
const messageStatusRenderer = React.useCallback((onRenderMessageStatus, defaultStatusRenderer, showMessageStatus, participantCount, readCount) => {
|
10711
|
+
return showMessageStatus && statusToRender ? (onRenderMessageStatus ? (onRenderMessageStatus({ status: message.status })) : (defaultStatusRenderer(message, participantCount !== null && participantCount !== void 0 ? participantCount : 0, readCount !== null && readCount !== void 0 ? readCount : 0, message.status))) : (React__default["default"].createElement("div", { className: react.mergeStyles(noMessageStatusStyle) }));
|
10712
|
+
}, [message, statusToRender]);
|
10713
|
+
const shouldShowAvatar = React.useMemo(() => {
|
10714
|
+
return message.attached === 'top' || message.attached === false;
|
10715
|
+
}, [message.attached]);
|
10716
|
+
const attached = React.useMemo(() => {
|
10717
|
+
return shouldShowAvatar ? 'top' : 'center';
|
10718
|
+
}, [shouldShowAvatar]);
|
10719
|
+
const myMessageRootProps = React.useMemo(() => {
|
10720
|
+
return {
|
10721
|
+
// myChatItemMessageContainer used in className and style prop as style prop can't handle CSS selectors
|
10722
|
+
className: reactComponents.mergeClasses(chatMessageRenderStyles.rootMyMessage, chatMessageRenderStyles.rootCommon, react.mergeStyles(styles === null || styles === void 0 ? void 0 : styles.myChatItemMessageContainer)),
|
10723
|
+
style: (styles === null || styles === void 0 ? void 0 : styles.myChatItemMessageContainer) !== undefined
|
10724
|
+
? createStyleFromV8Style(styles === null || styles === void 0 ? void 0 : styles.myChatItemMessageContainer)
|
10725
|
+
: {},
|
10726
|
+
role: 'none'
|
10727
|
+
};
|
10728
|
+
}, [chatMessageRenderStyles.rootCommon, chatMessageRenderStyles.rootMyMessage, styles === null || styles === void 0 ? void 0 : styles.myChatItemMessageContainer]);
|
10729
|
+
const myMessageBodyProps = React.useMemo(() => {
|
10730
|
+
return {
|
10731
|
+
className: reactComponents.mergeClasses(chatMessageRenderStyles.bodyCommon, chatMessageRenderStyles.bodyMyMessage),
|
10732
|
+
// make body not focusable to remove repetitions from narrators.
|
10733
|
+
// inner components are already focusable
|
10734
|
+
tabIndex: -1,
|
10735
|
+
role: 'none'
|
10736
|
+
};
|
10737
|
+
}, [chatMessageRenderStyles.bodyCommon, chatMessageRenderStyles.bodyMyMessage]);
|
10738
|
+
const myMessageStatusIcon = React.useMemo(() => {
|
10739
|
+
var _a;
|
10740
|
+
return (React__default["default"].createElement("div", { className: react.mergeStyles({ paddingLeft: '0.25rem' }, (styles === null || styles === void 0 ? void 0 : styles.messageStatusContainer) ? styles.messageStatusContainer((_a = message.mine) !== null && _a !== void 0 ? _a : false) : '') }, message.status
|
10741
|
+
? messageStatusRenderer(onRenderMessageStatus, defaultStatusRenderer, showMessageStatus, participantCount, readCount)
|
10742
|
+
: undefined));
|
10743
|
+
}, [
|
10744
|
+
defaultStatusRenderer,
|
10745
|
+
message.mine,
|
10746
|
+
message.status,
|
10747
|
+
messageStatusRenderer,
|
10748
|
+
onRenderMessageStatus,
|
10749
|
+
participantCount,
|
10750
|
+
readCount,
|
10751
|
+
showMessageStatus,
|
10752
|
+
styles
|
10753
|
+
]);
|
10754
|
+
const messageRootProps = React.useMemo(() => {
|
10755
|
+
return { className: reactComponents.mergeClasses(chatMessageRenderStyles.rootMessage, chatMessageRenderStyles.rootCommon) };
|
10756
|
+
}, [chatMessageRenderStyles.rootCommon, chatMessageRenderStyles.rootMessage]);
|
10757
|
+
const messageBodyProps = React.useMemo(() => {
|
10758
|
+
return {
|
10759
|
+
// chatItemMessageContainer used in className and style prop as style prop can't handle CSS selectors
|
10760
|
+
className: reactComponents.mergeClasses(chatMessageRenderStyles.bodyCommon, !shouldShowAvatar ? chatMessageRenderStyles.bodyWithoutAvatar : chatMessageRenderStyles.bodyWithAvatar, shouldOverlapAvatarAndMessage ? chatMessageRenderStyles.avatarOverlap : chatMessageRenderStyles.avatarNoOverlap, react.mergeStyles(styles === null || styles === void 0 ? void 0 : styles.chatItemMessageContainer)),
|
10761
|
+
style: (styles === null || styles === void 0 ? void 0 : styles.chatItemMessageContainer) !== undefined ? createStyleFromV8Style(styles === null || styles === void 0 ? void 0 : styles.chatItemMessageContainer) : {},
|
10762
|
+
// make body not focusable to remove repetitions from narrators.
|
10763
|
+
// inner components are already focusable
|
10764
|
+
tabIndex: -1,
|
10765
|
+
role: 'none'
|
10766
|
+
};
|
10767
|
+
}, [
|
10768
|
+
chatMessageRenderStyles.avatarNoOverlap,
|
10769
|
+
chatMessageRenderStyles.avatarOverlap,
|
10770
|
+
chatMessageRenderStyles.bodyCommon,
|
10771
|
+
chatMessageRenderStyles.bodyWithAvatar,
|
10772
|
+
chatMessageRenderStyles.bodyWithoutAvatar,
|
10773
|
+
shouldOverlapAvatarAndMessage,
|
10774
|
+
shouldShowAvatar,
|
10775
|
+
styles === null || styles === void 0 ? void 0 : styles.chatItemMessageContainer
|
10776
|
+
]);
|
10777
|
+
const avatar = React.useMemo(() => {
|
10778
|
+
const chatAvatarStyle = shouldShowAvatar ? gutterWithAvatar : gutterWithHiddenAvatar;
|
10779
|
+
const personaOptions = {
|
10780
|
+
hidePersonaDetails: true,
|
10781
|
+
size: react.PersonaSize.size32,
|
10782
|
+
text: message.senderDisplayName,
|
10783
|
+
showOverflowTooltip: false
|
10784
|
+
};
|
10785
|
+
return (React__default["default"].createElement("div", { className: react.mergeStyles(chatAvatarStyle) }, onRenderAvatar ? onRenderAvatar === null || onRenderAvatar === void 0 ? void 0 : onRenderAvatar(message.senderId, personaOptions) : React__default["default"].createElement(react.Persona, Object.assign({}, personaOptions))));
|
10786
|
+
}, [message.senderDisplayName, message.senderId, onRenderAvatar, shouldShowAvatar]);
|
10787
|
+
// Fluent UI message components are used here as for default message renderer,
|
10788
|
+
// timestamp and author name should be shown but they aren't shown for custom renderer.
|
10789
|
+
// More investigations are needed to check if this can be simplified with states.
|
10790
|
+
// Status and avatar should be shown for both custom and default renderers.
|
10791
|
+
if (message.mine === true) {
|
10792
|
+
return (React__default["default"].createElement("div", null,
|
10793
|
+
React__default["default"].createElement(reactChat.ChatMyMessage, { attached: attached, root: myMessageRootProps, body: myMessageBodyProps, statusIcon: myMessageStatusIcon }, messageRenderer(Object.assign({}, props)))));
|
10794
|
+
}
|
10795
|
+
else {
|
10796
|
+
return (React__default["default"].createElement("div", null,
|
10797
|
+
React__default["default"].createElement(reactChat.ChatMessage, { attached: attached, root: messageRootProps, body: messageBodyProps, avatar: avatar }, messageRenderer(Object.assign({}, props)))));
|
10798
|
+
}
|
10541
10799
|
};
|
10542
10800
|
|
10543
10801
|
// Copyright (c) Microsoft Corporation.
|
10544
10802
|
/**
|
10545
10803
|
* @private
|
10546
10804
|
*/
|
10547
|
-
const
|
10548
|
-
|
10805
|
+
const systemMessageIconStyle = react.mergeStyles({
|
10806
|
+
marginInlineEnd: '0.688rem'
|
10549
10807
|
});
|
10808
|
+
|
10809
|
+
// Copyright (c) Microsoft Corporation.
|
10550
10810
|
/**
|
10551
10811
|
* @private
|
10552
10812
|
*/
|
10553
|
-
const
|
10554
|
-
const {
|
10555
|
-
const
|
10556
|
-
|
10557
|
-
|
10558
|
-
|
10559
|
-
React__default["default"].createElement(react$1.TextDirectionProvider, { dir: dir },
|
10560
|
-
React__default["default"].createElement(FluentProviderWithStylesOverrides, { theme: v9Theme, dir: dir }, children)));
|
10561
|
-
};
|
10562
|
-
const FluentProviderWithStylesOverrides = (props) => {
|
10563
|
-
const classes = useFluentV9Wrapper();
|
10564
|
-
return React__default["default"].createElement(reactComponents.FluentProvider, Object.assign({}, props, { className: classes.body }));
|
10813
|
+
const SystemMessage = (props) => {
|
10814
|
+
const { iconName, content } = props;
|
10815
|
+
const Icon = React__default["default"].createElement(react.FontIcon, { iconName: iconName, className: react.mergeStyles(systemMessageIconStyle) });
|
10816
|
+
return (React__default["default"].createElement(react.Stack, { horizontal: true, className: react.mergeStyles(props === null || props === void 0 ? void 0 : props.containerStyle), tabIndex: 0 },
|
10817
|
+
Icon,
|
10818
|
+
React__default["default"].createElement(react.Text, { style: { wordBreak: 'break-word' }, role: "status", title: content, variant: 'small' }, content)));
|
10565
10819
|
};
|
10566
10820
|
|
10567
10821
|
// Copyright (c) Microsoft Corporation.
|
10568
|
-
|
10569
|
-
|
10570
|
-
|
10571
|
-
|
10572
|
-
|
10573
|
-
|
10574
|
-
|
10575
|
-
|
10576
|
-
|
10577
|
-
|
10822
|
+
/**
|
10823
|
+
* @private
|
10824
|
+
*/
|
10825
|
+
const DefaultSystemMessage = (props) => {
|
10826
|
+
var _a;
|
10827
|
+
const message = props.message;
|
10828
|
+
switch (message.messageType) {
|
10829
|
+
case 'system':
|
10830
|
+
switch (message.systemMessageType) {
|
10831
|
+
case 'content':
|
10832
|
+
return (React__default["default"].createElement(SystemMessage, { iconName: (message.iconName ? message.iconName : ''), content: (_a = message.content) !== null && _a !== void 0 ? _a : '', containerStyle: props === null || props === void 0 ? void 0 : props.messageContainerStyle }));
|
10833
|
+
case 'participantAdded':
|
10834
|
+
case 'participantRemoved':
|
10835
|
+
return (React__default["default"].createElement(ParticipantSystemMessageComponent, { message: message, style: props.messageContainerStyle, defaultName: props.strings.noDisplayNameSub }));
|
10836
|
+
}
|
10837
|
+
}
|
10838
|
+
return React__default["default"].createElement(React__default["default"].Fragment, null);
|
10839
|
+
};
|
10840
|
+
const ParticipantSystemMessageComponent = ({ message, style, defaultName }) => {
|
10841
|
+
const { strings } = useLocale$1();
|
10842
|
+
const participantsStr = generateParticipantsStr(message.participants, defaultName);
|
10843
|
+
const messageSuffix = message.systemMessageType === 'participantAdded'
|
10844
|
+
? strings.messageThread.participantJoined
|
10845
|
+
: strings.messageThread.participantLeft;
|
10846
|
+
if (participantsStr !== '') {
|
10847
|
+
return (React__default["default"].createElement(SystemMessage, { iconName: (message.iconName ? message.iconName : ''), content: `${participantsStr} ${messageSuffix}`, containerStyle: style }));
|
10848
|
+
}
|
10849
|
+
return React__default["default"].createElement(React__default["default"].Fragment, null);
|
10578
10850
|
};
|
10579
|
-
|
10580
|
-
|
10851
|
+
const generateParticipantsStr = (participants, defaultName) => participants
|
10852
|
+
.map((participant) => `${!participant.displayName || participant.displayName === '' ? defaultName : participant.displayName}`)
|
10853
|
+
.join(', ');
|
10581
10854
|
|
10582
10855
|
// Copyright (c) Microsoft Corporation.
|
10583
|
-
/**
|
10584
|
-
|
10585
|
-
|
10586
|
-
|
10856
|
+
/**
|
10857
|
+
* The wrapper component to display different types of chat message.
|
10858
|
+
*
|
10859
|
+
* @private
|
10860
|
+
*/
|
10861
|
+
const ChatMessageComponentWrapper = (props) => {
|
10587
10862
|
var _a, _b;
|
10588
|
-
const
|
10589
|
-
const
|
10590
|
-
|
10591
|
-
|
10592
|
-
|
10593
|
-
React.useEffect(() => {
|
10594
|
-
if (oldAssertive.current.message !== (newAssertive === null || newAssertive === void 0 ? void 0 : newAssertive.message) || oldAssertive.current.id !== (newAssertive === null || newAssertive === void 0 ? void 0 : newAssertive.id)) {
|
10595
|
-
setActiveAssertive1(alternateAssertive.current ? EMPTY_MESSAGE : newAssertive);
|
10596
|
-
setActiveAssertive2(alternateAssertive.current ? newAssertive : EMPTY_MESSAGE);
|
10597
|
-
oldAssertive.current = newAssertive;
|
10598
|
-
alternateAssertive.current = !alternateAssertive.current;
|
10599
|
-
}
|
10600
|
-
}, [newAssertive]);
|
10601
|
-
const newPolite = (_b = props.polite) !== null && _b !== void 0 ? _b : EMPTY_MESSAGE;
|
10602
|
-
const oldPolite = React__default["default"].useRef(EMPTY_MESSAGE);
|
10603
|
-
const [activePolite1, setActivePolite1] = React__default["default"].useState(EMPTY_MESSAGE);
|
10604
|
-
const [activePolite2, setActivePolite2] = React__default["default"].useState(EMPTY_MESSAGE);
|
10605
|
-
const alternatePolite = React__default["default"].useRef(false);
|
10606
|
-
React.useEffect(() => {
|
10607
|
-
if (oldPolite.current.message !== (newPolite === null || newPolite === void 0 ? void 0 : newPolite.message) || oldPolite.current.id !== (newPolite === null || newPolite === void 0 ? void 0 : newPolite.id)) {
|
10608
|
-
setActivePolite1(alternatePolite.current ? EMPTY_MESSAGE : newPolite);
|
10609
|
-
setActivePolite2(alternatePolite.current ? newPolite : EMPTY_MESSAGE);
|
10610
|
-
oldPolite.current = newPolite;
|
10611
|
-
alternatePolite.current = !alternatePolite.current;
|
10612
|
-
}
|
10613
|
-
}, [newPolite]);
|
10614
|
-
return (React__default["default"].createElement("div", null,
|
10615
|
-
React__default["default"].createElement(MessageBlock, { ariaLive: "assertive", message: activeAssertive1.message }),
|
10616
|
-
React__default["default"].createElement(MessageBlock, { ariaLive: "assertive", message: activeAssertive2.message }),
|
10617
|
-
React__default["default"].createElement(MessageBlock, { ariaLive: "polite", message: activePolite1.message }),
|
10618
|
-
React__default["default"].createElement(MessageBlock, { ariaLive: "polite", message: activePolite2.message })));
|
10619
|
-
};
|
10620
|
-
|
10621
|
-
// Copyright (c) Microsoft Corporation.
|
10622
|
-
/** @private */
|
10623
|
-
const LiveAnnouncer = (props) => {
|
10624
|
-
const [politeMessage, setPoliteMessage] = React__default["default"].useState(EMPTY_MESSAGE);
|
10625
|
-
const [assertiveMessage, setAssertiveMessage] = React__default["default"].useState(EMPTY_MESSAGE);
|
10626
|
-
const announcePolite = React.useCallback((message, id) => {
|
10627
|
-
setPoliteMessage({ message, id });
|
10863
|
+
const { message, styles, onRenderMessage, key: messageKey } = props;
|
10864
|
+
const systemMessageStyle = React.useMemo(() => {
|
10865
|
+
return {
|
10866
|
+
paddingTop: '0.5rem'
|
10867
|
+
};
|
10628
10868
|
}, []);
|
10629
|
-
const
|
10630
|
-
|
10869
|
+
const customMessageStyle = React.useMemo(() => {
|
10870
|
+
return { paddingTop: '1rem', paddingBottom: '0.25rem' };
|
10631
10871
|
}, []);
|
10632
|
-
|
10633
|
-
|
10634
|
-
|
10635
|
-
|
10636
|
-
|
10637
|
-
|
10638
|
-
|
10872
|
+
/* @conditional-compile-remove(data-loss-prevention) */
|
10873
|
+
// Similar logic as switch statement case 'chat', if statement for conditional compile (merge logic to switch case when stabilize)
|
10874
|
+
if (message.messageType === 'blocked') {
|
10875
|
+
const myChatMessageStyle = message.status === 'failed'
|
10876
|
+
? (_a = styles === null || styles === void 0 ? void 0 : styles.failedMyChatMessageContainer) !== null && _a !== void 0 ? _a : styles === null || styles === void 0 ? void 0 : styles.myChatMessageContainer
|
10877
|
+
: styles === null || styles === void 0 ? void 0 : styles.myChatMessageContainer;
|
10878
|
+
const blockedMessageStyle = styles === null || styles === void 0 ? void 0 : styles.blockedMessageContainer;
|
10879
|
+
const messageContainerStyle = message.mine ? myChatMessageStyle : blockedMessageStyle;
|
10880
|
+
return (React__default["default"].createElement(FluentChatMessageComponentWrapper, Object.assign({}, props, { message: message, messageContainerStyle: messageContainerStyle })));
|
10881
|
+
}
|
10882
|
+
switch (message.messageType) {
|
10883
|
+
case 'chat': {
|
10884
|
+
const myChatMessageStyle = message.status === 'failed'
|
10885
|
+
? (_b = styles === null || styles === void 0 ? void 0 : styles.failedMyChatMessageContainer) !== null && _b !== void 0 ? _b : styles === null || styles === void 0 ? void 0 : styles.myChatMessageContainer
|
10886
|
+
: styles === null || styles === void 0 ? void 0 : styles.myChatMessageContainer;
|
10887
|
+
const chatMessageStyle = styles === null || styles === void 0 ? void 0 : styles.chatMessageContainer;
|
10888
|
+
const messageContainerStyle = message.mine ? myChatMessageStyle : chatMessageStyle;
|
10889
|
+
return (React__default["default"].createElement(FluentChatMessageComponentWrapper, Object.assign({}, props, { message: message, messageContainerStyle: messageContainerStyle })));
|
10890
|
+
}
|
10891
|
+
case 'system': {
|
10892
|
+
const messageContainerStyle = styles === null || styles === void 0 ? void 0 : styles.systemMessageContainer;
|
10893
|
+
const systemMessageComponent = onRenderMessage === undefined ? (React__default["default"].createElement(DefaultSystemMessage, Object.assign({}, props))) : (onRenderMessage(Object.assign(Object.assign({}, props), { messageContainerStyle }), (props) => React__default["default"].createElement(DefaultSystemMessage, Object.assign({}, props))));
|
10894
|
+
return (React__default["default"].createElement("div", { key: messageKey, style: systemMessageStyle }, systemMessageComponent));
|
10895
|
+
}
|
10896
|
+
default: {
|
10897
|
+
// We do not handle custom type message by default, users can handle custom type by using onRenderMessage function.
|
10898
|
+
const customMessageComponent = onRenderMessage === undefined ? React__default["default"].createElement(React__default["default"].Fragment, null) : onRenderMessage(Object.assign({}, props));
|
10899
|
+
return (React__default["default"].createElement("div", { key: messageKey, style: customMessageStyle }, customMessageComponent));
|
10900
|
+
}
|
10901
|
+
}
|
10639
10902
|
};
|
10640
10903
|
|
10641
10904
|
// Copyright (c) Microsoft Corporation.
|
@@ -10706,38 +10969,37 @@ const DefaultJumpToNewMessageButton = (props) => {
|
|
10706
10969
|
const { text, onClick } = props;
|
10707
10970
|
return (React__default["default"].createElement(react.PrimaryButton, { className: newMessageButtonStyle, styles: buttonWithIconStyles$1, text: text, onClick: onClick, onRenderIcon: () => React__default["default"].createElement(react.Icon, { iconName: "Down", className: DownIconStyle }) }));
|
10708
10971
|
};
|
10709
|
-
const
|
10710
|
-
|
10711
|
-
|
10712
|
-
|
10713
|
-
|
10714
|
-
|
10715
|
-
|
10716
|
-
|
10717
|
-
|
10718
|
-
|
10719
|
-
|
10720
|
-
|
10721
|
-
|
10722
|
-
}
|
10723
|
-
|
10724
|
-
|
10725
|
-
|
10726
|
-
|
10727
|
-
|
10728
|
-
|
10729
|
-
|
10730
|
-
|
10731
|
-
case 'participantAdded':
|
10732
|
-
case 'participantRemoved':
|
10733
|
-
return (React__default["default"].createElement(ParticipantSystemMessageComponent, { message: message, style: props.messageContainerStyle, defaultName: props.strings.noDisplayNameSub }));
|
10972
|
+
const memoizeAllMessages = memoizeFnAll((message, showMessageDate, showMessageStatus, strings, index, onUpdateMessage, onCancelEditMessage, onDeleteMessage, onSendMessage, disableEditing, lastSeenChatMessage, lastSendingChatMessage, lastDeliveredChatMessage) => {
|
10973
|
+
let key = message.messageId;
|
10974
|
+
let statusToRender = undefined;
|
10975
|
+
if (message.messageType === 'chat' ||
|
10976
|
+
/* @conditional-compile-remove(data-loss-prevention) */ message.messageType === 'blocked') {
|
10977
|
+
if ((!message.messageId || message.messageId === '') && 'clientMessageId' in message) {
|
10978
|
+
key = message.clientMessageId;
|
10979
|
+
}
|
10980
|
+
if (showMessageStatus && message.mine) {
|
10981
|
+
switch (message.messageId) {
|
10982
|
+
case lastSeenChatMessage: {
|
10983
|
+
statusToRender = 'seen';
|
10984
|
+
break;
|
10985
|
+
}
|
10986
|
+
case lastSendingChatMessage: {
|
10987
|
+
statusToRender = 'sending';
|
10988
|
+
break;
|
10989
|
+
}
|
10990
|
+
case lastDeliveredChatMessage: {
|
10991
|
+
statusToRender = 'delivered';
|
10992
|
+
break;
|
10993
|
+
}
|
10734
10994
|
}
|
10995
|
+
}
|
10996
|
+
if (message.mine && message.status === 'failed') {
|
10997
|
+
statusToRender = 'failed';
|
10998
|
+
}
|
10735
10999
|
}
|
10736
|
-
return
|
10737
|
-
|
10738
|
-
|
10739
|
-
var _a, _b;
|
10740
|
-
const messageProps = {
|
11000
|
+
return {
|
11001
|
+
key: key !== null && key !== void 0 ? key : 'id_' + index,
|
11002
|
+
statusToRender,
|
10741
11003
|
message,
|
10742
11004
|
strings,
|
10743
11005
|
showDate: showMessageDate,
|
@@ -10745,92 +11007,9 @@ const memoizeAllMessages = memoizeFnAll((_messageKey, message, showMessageDate,
|
|
10745
11007
|
onCancelEditMessage,
|
10746
11008
|
onDeleteMessage,
|
10747
11009
|
onSendMessage,
|
10748
|
-
disableEditing
|
10749
|
-
|
10750
|
-
const chatMessage = (message, messageProps) => {
|
10751
|
-
var _a;
|
10752
|
-
const messageStatusRenderer = showMessageStatus && statusToRender
|
10753
|
-
? onRenderMessageStatus
|
10754
|
-
? (status) => onRenderMessageStatus({ status })
|
10755
|
-
: (status) => defaultStatusRenderer(message, status, participantCount !== null && participantCount !== void 0 ? participantCount : 0, readCount !== null && readCount !== void 0 ? readCount : 0)
|
10756
|
-
: () => React__default["default"].createElement("div", { className: react.mergeStyles(noMessageStatusStyle) });
|
10757
|
-
let chatMessageComponent;
|
10758
|
-
const shouldShowAvatar = message.attached === 'top' || message.attached === false;
|
10759
|
-
const attached = shouldShowAvatar ? 'top' : 'center';
|
10760
|
-
if (message.mine === true) {
|
10761
|
-
chatMessageComponent = (React__default["default"].createElement(reactChat.ChatMyMessage, { attached: attached, root: {
|
10762
|
-
// myChatItemMessageContainer used in className and style prop as style prop can't handle CSS selectors
|
10763
|
-
className: reactComponents.mergeClasses(chatMessageRenderStyles.rootMyMessage, chatMessageRenderStyles.rootCommon, react.mergeStyles(styles === null || styles === void 0 ? void 0 : styles.myChatItemMessageContainer)),
|
10764
|
-
style: (styles === null || styles === void 0 ? void 0 : styles.myChatItemMessageContainer) !== undefined
|
10765
|
-
? createStyleFromV8Style(styles === null || styles === void 0 ? void 0 : styles.myChatItemMessageContainer)
|
10766
|
-
: {},
|
10767
|
-
role: 'none'
|
10768
|
-
}, body: {
|
10769
|
-
className: reactComponents.mergeClasses(chatMessageRenderStyles.bodyCommon, chatMessageRenderStyles.bodyMyMessage),
|
10770
|
-
// make body not focusable to remove repetitions from narrators.
|
10771
|
-
// inner components are already focusable
|
10772
|
-
tabIndex: -1,
|
10773
|
-
role: 'none'
|
10774
|
-
}, statusIcon: React__default["default"].createElement("div", { className: react.mergeStyles({ paddingLeft: '0.25rem' }, (styles === null || styles === void 0 ? void 0 : styles.messageStatusContainer) ? styles.messageStatusContainer((_a = message.mine) !== null && _a !== void 0 ? _a : false) : '') }, message.status ? messageStatusRenderer(message.status) : undefined) }, onRenderMessage === undefined
|
10775
|
-
? defaultChatMessageRenderer(Object.assign(Object.assign({}, messageProps), { messageStatusRenderer }))
|
10776
|
-
: onRenderMessage(messageProps, defaultChatMessageRenderer)));
|
10777
|
-
}
|
10778
|
-
else {
|
10779
|
-
const chatAvatarStyle = shouldShowAvatar ? gutterWithAvatar : gutterWithHiddenAvatar;
|
10780
|
-
const personaOptions = {
|
10781
|
-
hidePersonaDetails: true,
|
10782
|
-
size: react.PersonaSize.size32,
|
10783
|
-
text: message.senderDisplayName,
|
10784
|
-
showOverflowTooltip: false
|
10785
|
-
};
|
10786
|
-
chatMessageComponent = (React__default["default"].createElement(reactChat.ChatMessage, { attached: attached, root: { className: reactComponents.mergeClasses(chatMessageRenderStyles.rootMessage, chatMessageRenderStyles.rootCommon) }, body: {
|
10787
|
-
// chatItemMessageContainer used in className and style prop as style prop can't handle CSS selectors
|
10788
|
-
className: reactComponents.mergeClasses(chatMessageRenderStyles.bodyCommon, !shouldShowAvatar ? chatMessageRenderStyles.bodyWithoutAvatar : chatMessageRenderStyles.bodyWithAvatar, shouldOverlapAvatarAndMessage
|
10789
|
-
? chatMessageRenderStyles.avatarOverlap
|
10790
|
-
: chatMessageRenderStyles.avatarNoOverlap, react.mergeStyles(styles === null || styles === void 0 ? void 0 : styles.chatItemMessageContainer)),
|
10791
|
-
style: (styles === null || styles === void 0 ? void 0 : styles.chatItemMessageContainer) !== undefined
|
10792
|
-
? createStyleFromV8Style(styles === null || styles === void 0 ? void 0 : styles.chatItemMessageContainer)
|
10793
|
-
: {},
|
10794
|
-
// make body not focusable to remove repetitions from narrators.
|
10795
|
-
// inner components are already focusable
|
10796
|
-
tabIndex: -1,
|
10797
|
-
role: 'none'
|
10798
|
-
}, avatar: React__default["default"].createElement("div", { className: react.mergeStyles(chatAvatarStyle) }, onRenderAvatar ? onRenderAvatar === null || onRenderAvatar === void 0 ? void 0 : onRenderAvatar(message.senderId, personaOptions) : React__default["default"].createElement(react.Persona, Object.assign({}, personaOptions))) }, onRenderMessage === undefined
|
10799
|
-
? defaultChatMessageRenderer(Object.assign(Object.assign({}, messageProps), { messageStatusRenderer }))
|
10800
|
-
: onRenderMessage(messageProps, defaultChatMessageRenderer)));
|
10801
|
-
}
|
10802
|
-
return React__default["default"].createElement("div", { key: _messageKey }, chatMessageComponent);
|
11010
|
+
disableEditing,
|
11011
|
+
showMessageStatus
|
10803
11012
|
};
|
10804
|
-
/* @conditional-compile-remove(data-loss-prevention) */
|
10805
|
-
// Similar logic as switch statement case 'chat', if statement for conditional compile (merge logic to switch case when stabilize)
|
10806
|
-
if (message.messageType === 'blocked') {
|
10807
|
-
const myChatMessageStyle = message.status === 'failed'
|
10808
|
-
? (_a = styles === null || styles === void 0 ? void 0 : styles.failedMyChatMessageContainer) !== null && _a !== void 0 ? _a : styles === null || styles === void 0 ? void 0 : styles.myChatMessageContainer
|
10809
|
-
: styles === null || styles === void 0 ? void 0 : styles.myChatMessageContainer;
|
10810
|
-
const blockedMessageStyle = styles === null || styles === void 0 ? void 0 : styles.blockedMessageContainer;
|
10811
|
-
messageProps.messageContainerStyle = message.mine ? myChatMessageStyle : blockedMessageStyle;
|
10812
|
-
return chatMessage(message, messageProps);
|
10813
|
-
}
|
10814
|
-
switch (message.messageType) {
|
10815
|
-
case 'chat': {
|
10816
|
-
const myChatMessageStyle = message.status === 'failed'
|
10817
|
-
? (_b = styles === null || styles === void 0 ? void 0 : styles.failedMyChatMessageContainer) !== null && _b !== void 0 ? _b : styles === null || styles === void 0 ? void 0 : styles.myChatMessageContainer
|
10818
|
-
: styles === null || styles === void 0 ? void 0 : styles.myChatMessageContainer;
|
10819
|
-
const chatMessageStyle = styles === null || styles === void 0 ? void 0 : styles.chatMessageContainer;
|
10820
|
-
messageProps.messageContainerStyle = message.mine ? myChatMessageStyle : chatMessageStyle;
|
10821
|
-
return chatMessage(message, messageProps);
|
10822
|
-
}
|
10823
|
-
case 'system': {
|
10824
|
-
messageProps.messageContainerStyle = styles === null || styles === void 0 ? void 0 : styles.systemMessageContainer;
|
10825
|
-
const systemMessageComponent = onRenderMessage === undefined ? (React__default["default"].createElement(DefaultSystemMessage, Object.assign({}, messageProps))) : (onRenderMessage(messageProps, (props) => React__default["default"].createElement(DefaultSystemMessage, Object.assign({}, props))));
|
10826
|
-
return (React__default["default"].createElement("div", { key: _messageKey, style: { paddingTop: '0.5rem' } }, systemMessageComponent));
|
10827
|
-
}
|
10828
|
-
default: {
|
10829
|
-
// We do not handle custom type message by default, users can handle custom type by using onRenderMessage function.
|
10830
|
-
const customMessageComponent = onRenderMessage === undefined ? React__default["default"].createElement(React__default["default"].Fragment, null) : onRenderMessage(messageProps);
|
10831
|
-
return (React__default["default"].createElement("div", { key: _messageKey, style: { paddingTop: '1rem', paddingBottom: '0.25rem' } }, customMessageComponent));
|
10832
|
-
}
|
10833
|
-
}
|
10834
11013
|
});
|
10835
11014
|
const getLastChatMessageIdWithStatus = (messages, status) => {
|
10836
11015
|
for (let i = messages.length - 1; i >= 0; i--) {
|
@@ -10874,9 +11053,9 @@ const MessageThreadWrapper = (props) => {
|
|
10874
11053
|
/* @conditional-compile-remove(mention) */
|
10875
11054
|
mentionOptions,
|
10876
11055
|
/* @conditional-compile-remove(image-gallery) */
|
10877
|
-
onInlineImageClicked
|
10878
|
-
|
10879
|
-
|
11056
|
+
onInlineImageClicked,
|
11057
|
+
/* @conditional-compile-remove(file-sharing) */
|
11058
|
+
onRenderFileDownloads } = props;
|
10880
11059
|
// We need this state to wait for one tick and scroll to bottom after messages have been initialized.
|
10881
11060
|
// Otherwise chatScrollDivRef.current.clientHeight is wrong if we scroll to bottom before messages are initialized.
|
10882
11061
|
const [chatMessagesInitialized, setChatMessagesInitialized] = React.useState(false);
|
@@ -10895,19 +11074,24 @@ const MessageThreadWrapper = (props) => {
|
|
10895
11074
|
const [inlineAttachments, setInlineAttachments] = React.useState({});
|
10896
11075
|
/* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
|
10897
11076
|
const onFetchInlineAttachment = React.useCallback((attachments, messageId) => __awaiter$v(void 0, void 0, void 0, function* () {
|
10898
|
-
if (!onFetchAttachments) {
|
11077
|
+
if (!onFetchAttachments || attachments.length === 0) {
|
10899
11078
|
return;
|
10900
11079
|
}
|
10901
11080
|
const attachmentDownloadResult = yield onFetchAttachments(attachments);
|
10902
|
-
|
10903
|
-
|
10904
|
-
|
10905
|
-
|
10906
|
-
|
10907
|
-
|
10908
|
-
|
11081
|
+
if (attachmentDownloadResult.length > 0) {
|
11082
|
+
setInlineAttachments((prev) => {
|
11083
|
+
var _a;
|
11084
|
+
// The new state should always be based on the previous one
|
11085
|
+
// otherwise there can be issues with renders
|
11086
|
+
const listOfAttachments = (_a = prev[messageId]) !== null && _a !== void 0 ? _a : {};
|
11087
|
+
for (const result of attachmentDownloadResult) {
|
11088
|
+
const { attachmentId, blobUrl } = result;
|
11089
|
+
listOfAttachments[attachmentId] = blobUrl;
|
11090
|
+
}
|
11091
|
+
return Object.assign(Object.assign({}, prev), { [messageId]: listOfAttachments });
|
11092
|
+
});
|
10909
11093
|
}
|
10910
|
-
}), [
|
11094
|
+
}), [onFetchAttachments]);
|
10911
11095
|
const isAllChatMessagesLoadedRef = React.useRef(false);
|
10912
11096
|
// isAllChatMessagesLoadedRef needs to be updated every time when a new adapter is set in order to display correct data
|
10913
11097
|
// onLoadPreviousChatMessages is updated when a new adapter is set
|
@@ -10925,10 +11109,12 @@ const MessageThreadWrapper = (props) => {
|
|
10925
11109
|
const messageIdSeenByMeRef = React.useRef('');
|
10926
11110
|
const chatScrollDivRef = React.useRef(null);
|
10927
11111
|
const isLoadingChatMessagesRef = React.useRef(false);
|
11112
|
+
const messages = React.useMemo(() => {
|
11113
|
+
return newMessages;
|
11114
|
+
}, [newMessages]);
|
10928
11115
|
const messagesRef = React.useRef(messages);
|
10929
11116
|
const setMessagesRef = (messagesWithAttachedValue) => {
|
10930
11117
|
messagesRef.current = messagesWithAttachedValue;
|
10931
|
-
setMessages(messagesWithAttachedValue);
|
10932
11118
|
};
|
10933
11119
|
const isAtBottomOfScrollRef = React.useRef(isAtBottomOfScroll);
|
10934
11120
|
const setIsAtBottomOfScrollRef = (isAtBottomOfScrollValue) => {
|
@@ -11114,52 +11300,7 @@ const MessageThreadWrapper = (props) => {
|
|
11114
11300
|
}, []);
|
11115
11301
|
const localeStrings = useLocale$1().strings.messageThread;
|
11116
11302
|
const strings = React.useMemo(() => (Object.assign(Object.assign({}, localeStrings), props.strings)), [localeStrings, props.strings]);
|
11117
|
-
|
11118
|
-
const defaultChatMessageRenderer = React.useCallback((messageProps) => {
|
11119
|
-
var _a;
|
11120
|
-
/* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
|
11121
|
-
if (inlineAttachments[messageProps.message.messageId] === undefined) {
|
11122
|
-
setInlineAttachments((prev) => (Object.assign(Object.assign({}, prev), { [messageProps.message.messageId]: {} })));
|
11123
|
-
}
|
11124
|
-
if (messageProps.message.messageType === 'chat' ||
|
11125
|
-
/* @conditional-compile-remove(data-loss-prevention) */ messageProps.message.messageType === 'blocked') {
|
11126
|
-
return (React__default["default"].createElement(ChatMessageComponent, Object.assign({}, messageProps, { onRenderFileDownloads: onRenderFileDownloads,
|
11127
|
-
/* @conditional-compile-remove(file-sharing) */
|
11128
|
-
strings: strings, message: messageProps.message, userId: props.userId, remoteParticipantsCount: participantCount ? participantCount - 1 : 0, shouldOverlapAvatarAndMessage: isNarrow, onRenderAvatar: onRenderAvatar, showMessageStatus: showMessageStatus, messageStatus: messageProps.message.status, onActionButtonClick: onActionButtonClickMemo,
|
11129
|
-
/* @conditional-compile-remove(date-time-customization) */
|
11130
|
-
onDisplayDateTimeString: onDisplayDateTimeString,
|
11131
|
-
/* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
|
11132
|
-
onFetchAttachments: onFetchInlineAttachment,
|
11133
|
-
/* @conditional-compile-remove(image-gallery) */
|
11134
|
-
onInlineImageClicked: onInlineImageClicked,
|
11135
|
-
/* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
|
11136
|
-
attachmentsMap: (_a = inlineAttachments[messageProps.message.messageId]) !== null && _a !== void 0 ? _a : {},
|
11137
|
-
/* @conditional-compile-remove(mention) */
|
11138
|
-
mentionOptions: mentionOptions })));
|
11139
|
-
}
|
11140
|
-
return React__default["default"].createElement(React__default["default"].Fragment, null);
|
11141
|
-
}, [
|
11142
|
-
onRenderFileDownloads,
|
11143
|
-
/* @conditional-compile-remove(file-sharing) */
|
11144
|
-
strings,
|
11145
|
-
props.userId,
|
11146
|
-
participantCount,
|
11147
|
-
isNarrow,
|
11148
|
-
onRenderAvatar,
|
11149
|
-
showMessageStatus,
|
11150
|
-
onActionButtonClickMemo,
|
11151
|
-
/* @conditional-compile-remove(date-time-customization) */
|
11152
|
-
onDisplayDateTimeString,
|
11153
|
-
/* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
|
11154
|
-
onFetchInlineAttachment,
|
11155
|
-
/* @conditional-compile-remove(image-gallery) */
|
11156
|
-
onInlineImageClicked,
|
11157
|
-
/* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
|
11158
|
-
inlineAttachments,
|
11159
|
-
/* @conditional-compile-remove(mention) */
|
11160
|
-
mentionOptions
|
11161
|
-
]);
|
11162
|
-
const defaultStatusRenderer = React.useCallback((message, status, participantCount, readCount) => {
|
11303
|
+
const defaultStatusRenderer = React.useCallback((message, participantCount, readCount, status) => {
|
11163
11304
|
const onToggleToolTip = (isToggled) => {
|
11164
11305
|
if (isToggled && readReceiptsBySenderIdRef.current) {
|
11165
11306
|
setReadCountForHoveredIndicator(getParticipantsWhoHaveReadMessage(message, readReceiptsBySenderIdRef.current).length);
|
@@ -11173,87 +11314,56 @@ const MessageThreadWrapper = (props) => {
|
|
11173
11314
|
remoteParticipantsCount: participantCount ? participantCount - 1 : 0 }));
|
11174
11315
|
}, []);
|
11175
11316
|
const theme = useTheme();
|
11176
|
-
const
|
11177
|
-
|
11178
|
-
|
11179
|
-
|
11180
|
-
|
11181
|
-
if (message.messageType === 'chat' ||
|
11182
|
-
/* @conditional-compile-remove(data-loss-prevention) */ message.messageType === 'blocked') {
|
11183
|
-
if ((!message.messageId || message.messageId === '') && 'clientMessageId' in message) {
|
11184
|
-
key = message.clientMessageId;
|
11185
|
-
}
|
11186
|
-
if (showMessageStatus && message.mine) {
|
11187
|
-
switch (message.messageId) {
|
11188
|
-
case lastSeenChatMessage: {
|
11189
|
-
statusToRender = 'seen';
|
11190
|
-
break;
|
11191
|
-
}
|
11192
|
-
case lastSendingChatMessage: {
|
11193
|
-
statusToRender = 'sending';
|
11194
|
-
break;
|
11195
|
-
}
|
11196
|
-
case lastDeliveredChatMessage: {
|
11197
|
-
statusToRender = 'delivered';
|
11198
|
-
break;
|
11199
|
-
}
|
11200
|
-
}
|
11201
|
-
}
|
11202
|
-
if (message.mine && message.status === 'failed') {
|
11203
|
-
statusToRender = 'failed';
|
11204
|
-
}
|
11205
|
-
}
|
11206
|
-
return memoizedMessageFn(key !== null && key !== void 0 ? key : 'id_' + index, message, showMessageDate, showMessageStatus, onRenderAvatar, isNarrow, styles, onRenderMessageStatus, defaultStatusRenderer, defaultChatMessageRenderer, strings, theme, chatMessageRenderStyles,
|
11207
|
-
// Temporary solution to make sure we re-render if attach attribute is changed.
|
11208
|
-
// The proper fix should be in selector.
|
11209
|
-
message.messageType === 'chat' ||
|
11210
|
-
/* @conditional-compile-remove(data-loss-prevention) */ message.messageType === 'blocked'
|
11211
|
-
? message.attached
|
11212
|
-
: undefined, statusToRender, participantCount, readCountForHoveredIndicator, onRenderMessage, onUpdateMessage, onCancelEditMessage, onDeleteMessage, onSendMessage, props.disableEditing);
|
11317
|
+
const messagesToDisplay = React.useMemo(() => {
|
11318
|
+
return memoizeAllMessages((memoizedMessageFn) => {
|
11319
|
+
return messages.map((message, index) => {
|
11320
|
+
return memoizedMessageFn(message, showMessageDate, showMessageStatus, strings, index, onUpdateMessage, onCancelEditMessage, onDeleteMessage, onSendMessage, props.disableEditing, lastDeliveredChatMessage, lastSeenChatMessage, lastSendingChatMessage);
|
11321
|
+
});
|
11213
11322
|
});
|
11214
|
-
}
|
11323
|
+
}, [
|
11324
|
+
lastDeliveredChatMessage,
|
11325
|
+
lastSeenChatMessage,
|
11326
|
+
lastSendingChatMessage,
|
11215
11327
|
messages,
|
11216
|
-
showMessageDate,
|
11217
|
-
showMessageStatus,
|
11218
|
-
onRenderAvatar,
|
11219
|
-
isNarrow,
|
11220
|
-
styles,
|
11221
|
-
onRenderMessageStatus,
|
11222
|
-
defaultStatusRenderer,
|
11223
|
-
defaultChatMessageRenderer,
|
11224
|
-
strings,
|
11225
|
-
theme,
|
11226
|
-
chatMessageRenderStyles,
|
11227
|
-
participantCount,
|
11228
|
-
readCountForHoveredIndicator,
|
11229
|
-
onRenderMessage,
|
11230
|
-
onUpdateMessage,
|
11231
11328
|
onCancelEditMessage,
|
11232
11329
|
onDeleteMessage,
|
11233
11330
|
onSendMessage,
|
11331
|
+
onUpdateMessage,
|
11234
11332
|
props.disableEditing,
|
11235
|
-
|
11236
|
-
|
11237
|
-
|
11333
|
+
showMessageDate,
|
11334
|
+
showMessageStatus,
|
11335
|
+
strings
|
11238
11336
|
]);
|
11239
11337
|
const classes = useChatStyles();
|
11240
|
-
|
11241
|
-
|
11338
|
+
return (React__default["default"].createElement("div", { className: react.mergeStyles(messageThreadWrapperContainerStyle), ref: chatThreadRef },
|
11339
|
+
existsNewChatMessage && !disableJumpToNewMessageButton && (React__default["default"].createElement("div", { className: react.mergeStyles(newMessageButtonContainerStyle, styles === null || styles === void 0 ? void 0 : styles.newMessageButtonContainer) }, onRenderJumpToNewMessageButton ? (onRenderJumpToNewMessageButton({ text: strings.newMessagesIndicator, onClick: scrollToBottom })) : (React__default["default"].createElement(DefaultJumpToNewMessageButton, { text: strings.newMessagesIndicator, onClick: scrollToBottom })))),
|
11340
|
+
React__default["default"].createElement(LiveAnnouncer, null,
|
11242
11341
|
React__default["default"].createElement(FluentV9ThemeProvider, { v8Theme: theme },
|
11243
11342
|
React__default["default"].createElement(reactChat.Chat
|
11244
11343
|
// styles?.chatContainer used in className and style prop as style prop can't handle CSS selectors
|
11245
11344
|
, {
|
11246
11345
|
// styles?.chatContainer used in className and style prop as style prop can't handle CSS selectors
|
11247
|
-
className: reactComponents.mergeClasses(classes.root, react.mergeStyles(styles === null || styles === void 0 ? void 0 : styles.chatContainer)), ref: chatScrollDivRef, style: Object.assign({}, createStyleFromV8Style(styles === null || styles === void 0 ? void 0 : styles.chatContainer)) }, messagesToDisplay)
|
11248
|
-
|
11249
|
-
|
11250
|
-
|
11251
|
-
|
11252
|
-
|
11253
|
-
|
11254
|
-
|
11255
|
-
|
11256
|
-
|
11346
|
+
className: reactComponents.mergeClasses(classes.root, react.mergeStyles(styles === null || styles === void 0 ? void 0 : styles.chatContainer)), ref: chatScrollDivRef, style: Object.assign({}, createStyleFromV8Style(styles === null || styles === void 0 ? void 0 : styles.chatContainer)) }, messagesToDisplay.map((message) => {
|
11347
|
+
return (React__default["default"].createElement(MemoChatMessageComponentWrapper, Object.assign({}, message, { userId: userId, key: message.key, styles: styles, shouldOverlapAvatarAndMessage: isNarrow, strings: strings, onRenderAvatar: onRenderAvatar, onRenderMessage: onRenderMessage, onRenderMessageStatus: onRenderMessageStatus, defaultStatusRenderer: defaultStatusRenderer, onActionButtonClick: onActionButtonClickMemo, readCount: readCountForHoveredIndicator, participantCount: participantCount,
|
11348
|
+
/* @conditional-compile-remove(file-sharing) */
|
11349
|
+
fileDownloadHandler: props.fileDownloadHandler,
|
11350
|
+
/* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
|
11351
|
+
onFetchInlineAttachment: onFetchInlineAttachment,
|
11352
|
+
/* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
|
11353
|
+
inlineAttachments: inlineAttachments,
|
11354
|
+
/* @conditional-compile-remove(image-gallery) */
|
11355
|
+
onInlineImageClicked: onInlineImageClicked,
|
11356
|
+
/* @conditional-compile-remove(date-time-customization) */
|
11357
|
+
onDisplayDateTimeString: onDisplayDateTimeString,
|
11358
|
+
/* @conditional-compile-remove(mention) */
|
11359
|
+
mentionOptions: mentionOptions,
|
11360
|
+
/* @conditional-compile-remove(file-sharing) */
|
11361
|
+
onRenderFileDownloads: onRenderFileDownloads })));
|
11362
|
+
}))))));
|
11363
|
+
};
|
11364
|
+
const MemoChatMessageComponentWrapper = React__default["default"].memo((obj) => {
|
11365
|
+
return React__default["default"].createElement(ChatMessageComponentWrapper, Object.assign({}, obj));
|
11366
|
+
});
|
11257
11367
|
|
11258
11368
|
// Copyright (c) Microsoft Corporation.
|
11259
11369
|
/**
|
@@ -14122,13 +14232,13 @@ const OverflowGallery = (props) => {
|
|
14122
14232
|
const scrollableHorizontalGalleryContainerStyles = React.useMemo(() => {
|
14123
14233
|
if (isNarrow && parentWidth) {
|
14124
14234
|
return {
|
14125
|
-
width:
|
14126
|
-
? `${_convertPxToRem(parentWidth) - 1}rem`
|
14127
|
-
: `${_convertPxToRem(parentWidth) -
|
14235
|
+
width: shouldFloatLocalVideo
|
14236
|
+
? `${_convertPxToRem(parentWidth) - SMALL_FLOATING_MODAL_SIZE_REM.width - 1}rem`
|
14237
|
+
: `${_convertPxToRem(parentWidth) - 1}rem`
|
14128
14238
|
};
|
14129
14239
|
}
|
14130
14240
|
return undefined;
|
14131
|
-
}, [isNarrow, parentWidth,
|
14241
|
+
}, [isNarrow, parentWidth, shouldFloatLocalVideo]);
|
14132
14242
|
/* @conditional-compile-remove(vertical-gallery) */
|
14133
14243
|
if (overflowGalleryPosition === 'verticalRight') {
|
14134
14244
|
return (React__default["default"].createElement(ResponsiveVerticalGallery, { key: "responsive-vertical-gallery", containerStyles: containerStyles, verticalGalleryStyles: galleryStyles, controlBarHeightRem: HORIZONTAL_GALLERY_BUTTON_WIDTH, gapHeightRem: HORIZONTAL_GALLERY_GAP, isShort: isShort, onFetchTilesToRender: onFetchTilesToRender, onChildrenPerPageChange: onChildrenPerPageChange }, overflowGalleryElements ? overflowGalleryElements : [React__default["default"].createElement(React__default["default"].Fragment, null)]));
|
@@ -14210,9 +14320,7 @@ const DefaultLayout = (props) => {
|
|
14210
14320
|
/* @conditional-compile-remove(vertical-gallery) */
|
14211
14321
|
overflowGalleryPosition: overflowGalleryPosition, onFetchTilesToRender: setIndexesToRender, onChildrenPerPageChange: (n) => {
|
14212
14322
|
childrenPerPage.current = n;
|
14213
|
-
},
|
14214
|
-
/* @conditional-compile-remove(gallery-layouts) */
|
14215
|
-
layout: 'default', parentWidth: parentWidth }));
|
14323
|
+
}, parentWidth: parentWidth }));
|
14216
14324
|
}, [
|
14217
14325
|
isNarrow,
|
14218
14326
|
/* @conditional-compile-remove(vertical-gallery) */ isShort,
|
@@ -15076,7 +15184,7 @@ const FloatingLocalVideoLayout = (props) => {
|
|
15076
15184
|
/* @conditional-compile-remove(vertical-gallery) */
|
15077
15185
|
, {
|
15078
15186
|
/* @conditional-compile-remove(vertical-gallery) */
|
15079
|
-
isShort: isShort, onFetchTilesToRender: setIndexesToRender, isNarrow: isNarrow, shouldFloatLocalVideo:
|
15187
|
+
isShort: isShort, onFetchTilesToRender: setIndexesToRender, isNarrow: isNarrow, shouldFloatLocalVideo: !!localVideoComponent, overflowGalleryElements: overflowGalleryTiles, horizontalGalleryStyles: styles === null || styles === void 0 ? void 0 : styles.horizontalGallery,
|
15080
15188
|
/* @conditional-compile-remove(vertical-gallery) */
|
15081
15189
|
verticalGalleryStyles: styles === null || styles === void 0 ? void 0 : styles.verticalGallery,
|
15082
15190
|
/* @conditional-compile-remove(vertical-gallery) */
|
@@ -15092,7 +15200,8 @@ const FloatingLocalVideoLayout = (props) => {
|
|
15092
15200
|
/* @conditional-compile-remove(vertical-gallery) */ overflowGalleryPosition,
|
15093
15201
|
setIndexesToRender,
|
15094
15202
|
/* @conditional-compile-remove(vertical-gallery) */ styles === null || styles === void 0 ? void 0 : styles.verticalGallery,
|
15095
|
-
parentWidth
|
15203
|
+
parentWidth,
|
15204
|
+
localVideoComponent
|
15096
15205
|
]);
|
15097
15206
|
return (React__default["default"].createElement(react.Stack, { styles: rootLayoutStyle },
|
15098
15207
|
wrappedLocalVideoComponent,
|
@@ -15205,7 +15314,7 @@ const SpeakerVideoLayout = (props) => {
|
|
15205
15314
|
/* @conditional-compile-remove(vertical-gallery) */
|
15206
15315
|
, {
|
15207
15316
|
/* @conditional-compile-remove(vertical-gallery) */
|
15208
|
-
isShort: isShort, onFetchTilesToRender: setIndexesToRender, isNarrow: isNarrow, shouldFloatLocalVideo:
|
15317
|
+
isShort: isShort, onFetchTilesToRender: setIndexesToRender, isNarrow: isNarrow, shouldFloatLocalVideo: !!localVideoComponent, overflowGalleryElements: overflowGalleryTiles, horizontalGalleryStyles: styles === null || styles === void 0 ? void 0 : styles.horizontalGallery,
|
15209
15318
|
/* @conditional-compile-remove(vertical-gallery) */
|
15210
15319
|
verticalGalleryStyles: styles === null || styles === void 0 ? void 0 : styles.verticalGallery,
|
15211
15320
|
/* @conditional-compile-remove(vertical-gallery) */
|
@@ -15221,7 +15330,8 @@ const SpeakerVideoLayout = (props) => {
|
|
15221
15330
|
/* @conditional-compile-remove(vertical-gallery) */ overflowGalleryPosition,
|
15222
15331
|
setIndexesToRender,
|
15223
15332
|
/* @conditional-compile-remove(vertical-gallery) */ styles === null || styles === void 0 ? void 0 : styles.verticalGallery,
|
15224
|
-
parentWidth
|
15333
|
+
parentWidth,
|
15334
|
+
localVideoComponent
|
15225
15335
|
]);
|
15226
15336
|
return (React__default["default"].createElement(react.Stack, { styles: rootLayoutStyle },
|
15227
15337
|
wrappedLocalVideoComponent,
|
@@ -22642,9 +22752,15 @@ const ChatScreen = (props) => {
|
|
22642
22752
|
const onRenderAvatarCallback = React.useCallback((userId, defaultOptions) => {
|
22643
22753
|
return (React__default["default"].createElement(AvatarPersona, Object.assign({ userId: userId, hidePersonaDetails: true }, defaultOptions, { dataProvider: onFetchAvatarPersonaData })));
|
22644
22754
|
}, [onFetchAvatarPersonaData]);
|
22645
|
-
const messageThreadStyles =
|
22646
|
-
|
22647
|
-
|
22755
|
+
const messageThreadStyles = React.useMemo(() => {
|
22756
|
+
return Object.assign({}, messageThreadChatCompositeStyles(theme.semanticColors.bodyBackground), styles === null || styles === void 0 ? void 0 : styles.messageThread);
|
22757
|
+
}, [styles === null || styles === void 0 ? void 0 : styles.messageThread, theme.semanticColors.bodyBackground]);
|
22758
|
+
const typingIndicatorStyles = React.useMemo(() => {
|
22759
|
+
return Object.assign({}, styles === null || styles === void 0 ? void 0 : styles.typingIndicator);
|
22760
|
+
}, [styles === null || styles === void 0 ? void 0 : styles.typingIndicator]);
|
22761
|
+
const sendBoxStyles = React.useMemo(() => {
|
22762
|
+
return Object.assign({}, styles === null || styles === void 0 ? void 0 : styles.sendBox);
|
22763
|
+
}, [styles === null || styles === void 0 ? void 0 : styles.sendBox]);
|
22648
22764
|
const userId = toFlatCommunicationIdentifier(adapter.getState().userId);
|
22649
22765
|
const fileUploadButtonOnChange = React.useCallback((files) => {
|
22650
22766
|
if (!files) {
|
@@ -22795,21 +22911,12 @@ const ChatScreen = (props) => {
|
|
22795
22911
|
const ChatComposite = (props) => {
|
22796
22912
|
const { adapter, options, onFetchAvatarPersonaData, onRenderTypingIndicator, onRenderMessage, onFetchParticipantMenuItems } = props;
|
22797
22913
|
const formFactor = props['formFactor'] || 'desktop';
|
22798
|
-
/**
|
22799
|
-
* @TODO Remove this function and pass the props directly when file-sharing is promoted to stable.
|
22800
|
-
* @private
|
22801
|
-
*/
|
22802
|
-
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
22803
|
-
const fileSharingOptions = () => {
|
22804
|
-
/* @conditional-compile-remove(file-sharing) */
|
22805
|
-
return {
|
22806
|
-
fileSharing: options === null || options === void 0 ? void 0 : options.fileSharing
|
22807
|
-
};
|
22808
|
-
};
|
22809
22914
|
return (React__default["default"].createElement("div", { className: chatScreenContainerStyle },
|
22810
22915
|
React__default["default"].createElement(BaseProvider, Object.assign({}, props),
|
22811
22916
|
React__default["default"].createElement(ChatAdapterProvider, { adapter: adapter },
|
22812
|
-
React__default["default"].createElement(ChatScreen,
|
22917
|
+
React__default["default"].createElement(ChatScreen, { formFactor: formFactor, options: options, onFetchAvatarPersonaData: onFetchAvatarPersonaData, onRenderTypingIndicator: onRenderTypingIndicator, onRenderMessage: onRenderMessage, onFetchParticipantMenuItems: onFetchParticipantMenuItems,
|
22918
|
+
/* @conditional-compile-remove(file-sharing) */
|
22919
|
+
fileSharing: options === null || options === void 0 ? void 0 : options.fileSharing })))));
|
22813
22920
|
};
|
22814
22921
|
|
22815
22922
|
// Copyright (c) Microsoft Corporation.
|
@@ -26054,7 +26161,7 @@ const SidePane = (props) => {
|
|
26054
26161
|
props.onPeopleButtonClicked,
|
26055
26162
|
props.disablePeopleButton,
|
26056
26163
|
props.disableChatButton,
|
26057
|
-
sidePaneRenderer,
|
26164
|
+
sidePaneRenderer === null || sidePaneRenderer === void 0 ? void 0 : sidePaneRenderer.id,
|
26058
26165
|
closePane
|
26059
26166
|
]);
|
26060
26167
|
const HeaderToRender = props.mobileView && (overrideSidePaneId === 'chat' || (sidePaneRenderer === null || sidePaneRenderer === void 0 ? void 0 : sidePaneRenderer.id) === 'people') ? LegacyHeader : Header();
|
@@ -30117,11 +30224,11 @@ const CALL_REJECTED_CODE = 603;
|
|
30117
30224
|
* @private
|
30118
30225
|
*/
|
30119
30226
|
class CallingSoundSubscriber {
|
30120
|
-
constructor(call,
|
30227
|
+
constructor(call, callee, sounds) {
|
30121
30228
|
this.onCallStateChanged = () => {
|
30122
30229
|
this.call.on('stateChanged', () => {
|
30123
30230
|
var _a, _b, _c, _d, _e;
|
30124
|
-
if (
|
30231
|
+
if (isPSTNCall(this.call, this.callee) && ((_a = this.soundsLoaded) === null || _a === void 0 ? void 0 : _a.callRingingSound)) {
|
30125
30232
|
this.soundsLoaded.callRingingSound.loop = true;
|
30126
30233
|
this.playSound(this.soundsLoaded.callRingingSound);
|
30127
30234
|
}
|
@@ -30141,7 +30248,7 @@ class CallingSoundSubscriber {
|
|
30141
30248
|
});
|
30142
30249
|
};
|
30143
30250
|
this.call = call;
|
30144
|
-
this.
|
30251
|
+
this.callee = callee;
|
30145
30252
|
if (sounds) {
|
30146
30253
|
this.soundsLoaded = this.loadSounds(sounds);
|
30147
30254
|
this.subscribeCallSoundEvents();
|
@@ -30161,17 +30268,17 @@ class CallingSoundSubscriber {
|
|
30161
30268
|
var _a, _b, _c;
|
30162
30269
|
let callEndedSound;
|
30163
30270
|
if (sounds === null || sounds === void 0 ? void 0 : sounds.callEnded) {
|
30164
|
-
callEndedSound = new Audio((_a = sounds === null || sounds === void 0 ? void 0 : sounds.callEnded) === null || _a === void 0 ? void 0 : _a.
|
30271
|
+
callEndedSound = new Audio((_a = sounds === null || sounds === void 0 ? void 0 : sounds.callEnded) === null || _a === void 0 ? void 0 : _a.url);
|
30165
30272
|
callEndedSound.preload = 'auto';
|
30166
30273
|
}
|
30167
30274
|
let callRingingSound;
|
30168
30275
|
if (sounds === null || sounds === void 0 ? void 0 : sounds.callRinging) {
|
30169
|
-
callRingingSound = new Audio((_b = sounds === null || sounds === void 0 ? void 0 : sounds.callRinging) === null || _b === void 0 ? void 0 : _b.
|
30276
|
+
callRingingSound = new Audio((_b = sounds === null || sounds === void 0 ? void 0 : sounds.callRinging) === null || _b === void 0 ? void 0 : _b.url);
|
30170
30277
|
callRingingSound.preload = 'auto';
|
30171
30278
|
}
|
30172
30279
|
let callBusySound;
|
30173
30280
|
if (sounds === null || sounds === void 0 ? void 0 : sounds.callBusy) {
|
30174
|
-
callBusySound = new Audio((_c = sounds === null || sounds === void 0 ? void 0 : sounds.callBusy) === null || _c === void 0 ? void 0 : _c.
|
30281
|
+
callBusySound = new Audio((_c = sounds === null || sounds === void 0 ? void 0 : sounds.callBusy) === null || _c === void 0 ? void 0 : _c.url);
|
30175
30282
|
callBusySound.preload = 'auto';
|
30176
30283
|
}
|
30177
30284
|
return {
|
@@ -30190,12 +30297,11 @@ class CallingSoundSubscriber {
|
|
30190
30297
|
* Helper function to allow the calling sound subscriber to determine when to play the ringing
|
30191
30298
|
* sound when making an outbound call.
|
30192
30299
|
*/
|
30193
|
-
const
|
30300
|
+
const isPSTNCall = (call, callee) => {
|
30194
30301
|
/* @conditional-compile-remove(calling-sounds) */
|
30195
|
-
|
30196
|
-
|
30197
|
-
|
30198
|
-
!communicationCommon.isPhoneNumberIdentifier(fromFlatCommunicationIdentifier(callee[0])) &&
|
30302
|
+
if (callee &&
|
30303
|
+
callee.length >= 1 &&
|
30304
|
+
!communicationCommon.isPhoneNumberIdentifier(callee[0]) &&
|
30199
30305
|
(call.state === 'Ringing' || call.state === 'Connecting')) {
|
30200
30306
|
return true;
|
30201
30307
|
}
|
@@ -30220,7 +30326,7 @@ class CallContext {
|
|
30220
30326
|
constructor(clientState, isTeamsCall,
|
30221
30327
|
/* @conditional-compile-remove(rooms) */
|
30222
30328
|
isRoomsCall, options) {
|
30223
|
-
var _a, _b, _c, _d
|
30329
|
+
var _a, _b, _c, _d;
|
30224
30330
|
this.emitter = new EventEmitter.EventEmitter();
|
30225
30331
|
this.state = {
|
30226
30332
|
isLocalPreviewMicrophoneEnabled: false,
|
@@ -30228,6 +30334,7 @@ class CallContext {
|
|
30228
30334
|
displayName: (_a = clientState.callAgent) === null || _a === void 0 ? void 0 : _a.displayName,
|
30229
30335
|
devices: clientState.deviceManager,
|
30230
30336
|
call: undefined,
|
30337
|
+
/* @conditional-compile-remove(calling-sounds) */ targetCallees: undefined,
|
30231
30338
|
page: 'configuration',
|
30232
30339
|
latestErrors: clientState.latestErrors,
|
30233
30340
|
isTeamsCall,
|
@@ -30240,9 +30347,9 @@ class CallContext {
|
|
30240
30347
|
onResolveVideoEffectDependency: (_c = options === null || options === void 0 ? void 0 : options.videoBackgroundOptions) === null || _c === void 0 ? void 0 : _c.onResolveDependency,
|
30241
30348
|
/* @conditional-compile-remove(video-background-effects) */ selectedVideoBackgroundEffect: undefined,
|
30242
30349
|
cameraStatus: undefined,
|
30243
|
-
/* @conditional-compile-remove(calling-sounds) */ sounds:
|
30350
|
+
/* @conditional-compile-remove(calling-sounds) */ sounds: options === null || options === void 0 ? void 0 : options.callingSounds
|
30244
30351
|
};
|
30245
|
-
this.emitter.setMaxListeners((
|
30352
|
+
this.emitter.setMaxListeners((_d = options === null || options === void 0 ? void 0 : options.maxListeners) !== null && _d !== void 0 ? _d : 50);
|
30246
30353
|
this.bindPublicMethods();
|
30247
30354
|
this.displayNameModifier = (options === null || options === void 0 ? void 0 : options.onFetchProfile)
|
30248
30355
|
? createProfileStateModifier(options.onFetchProfile, () => {
|
@@ -30274,6 +30381,10 @@ class CallContext {
|
|
30274
30381
|
setCurrentCallId(callId) {
|
30275
30382
|
this.callId = callId;
|
30276
30383
|
}
|
30384
|
+
/* @conditional-compile-remove(calling-sounds) */
|
30385
|
+
setTargetCallee(targetCallees) {
|
30386
|
+
this.setState(Object.assign(Object.assign({}, this.state), { targetCallees }));
|
30387
|
+
}
|
30277
30388
|
onCallEnded(handler) {
|
30278
30389
|
this.emitter.on('callEnded', handler);
|
30279
30390
|
}
|
@@ -30888,6 +30999,8 @@ class AzureCommunicationCallAdapter {
|
|
30888
30999
|
}
|
30889
31000
|
return backendId;
|
30890
31001
|
});
|
31002
|
+
/* @conditional-compile-remove(calling-sounds) */
|
31003
|
+
this.context.setTargetCallee(idsToAdd);
|
30891
31004
|
const call = this.handlers.onStartCall(idsToAdd, options);
|
30892
31005
|
if (!call) {
|
30893
31006
|
throw new Error('Unable to start call.');
|
@@ -31026,7 +31139,7 @@ class AzureCommunicationCallAdapter {
|
|
31026
31139
|
var _a, _b, _c, _d, _e, _f, _g, _h;
|
31027
31140
|
/* @conditional-compile-remove(calling-sounds) */
|
31028
31141
|
if (this.call) {
|
31029
|
-
this.callingSoundSubscriber = new CallingSoundSubscriber(this.call, this.
|
31142
|
+
this.callingSoundSubscriber = new CallingSoundSubscriber(this.call, this.getState().targetCallees, this.getState().sounds);
|
31030
31143
|
}
|
31031
31144
|
(_a = this.call) === null || _a === void 0 ? void 0 : _a.on('remoteParticipantsUpdated', this.onRemoteParticipantsUpdated.bind(this));
|
31032
31145
|
(_b = this.call) === null || _b === void 0 ? void 0 : _b.on('isMutedChanged', this.isMyMutedChanged.bind(this));
|
@@ -31149,6 +31262,7 @@ class AzureCommunicationCallAdapter {
|
|
31149
31262
|
if (((_a = this.call) === null || _a === void 0 ? void 0 : _a.role) === 'Consumer') {
|
31150
31263
|
(_b = this.call) === null || _b === void 0 ? void 0 : _b.feature(communicationCalling.Features.RaiseHand).lowerHand();
|
31151
31264
|
}
|
31265
|
+
this.emitter.emit('roleChanged');
|
31152
31266
|
}
|
31153
31267
|
callIdChanged() {
|
31154
31268
|
var _a;
|
@@ -31982,10 +32096,8 @@ const CallWithChatScreen = (props) => {
|
|
31982
32096
|
callWithChatAdapter.offStateChange(updateCallWithChatPage);
|
31983
32097
|
};
|
31984
32098
|
}, [callWithChatAdapter]);
|
31985
|
-
const
|
31986
|
-
return
|
31987
|
-
adapter: new CallWithChatBackedChatAdapter(callWithChatAdapter)
|
31988
|
-
};
|
32099
|
+
const chatAdapter = React.useMemo(() => {
|
32100
|
+
return new CallWithChatBackedChatAdapter(callWithChatAdapter);
|
31989
32101
|
}, [callWithChatAdapter]);
|
31990
32102
|
/** Constant setting of id for the parent stack of the composite */
|
31991
32103
|
const compositeParentDivId = reactHooks.useId('callWithChatCompositeParentDiv-internal');
|
@@ -32034,7 +32146,7 @@ const CallWithChatScreen = (props) => {
|
|
32034
32146
|
disabled: chatButtonDisabled
|
32035
32147
|
}
|
32036
32148
|
: undefined, [chatButtonDisabled, mobileView, toggleChat, showChatButton]);
|
32037
|
-
const unreadChatMessagesCount = useUnreadMessagesTracker(
|
32149
|
+
const unreadChatMessagesCount = useUnreadMessagesTracker(chatAdapter, isChatOpen);
|
32038
32150
|
const customChatButton = React.useCallback((args) => ({
|
32039
32151
|
placement: mobileView ? 'primary' : 'secondary',
|
32040
32152
|
onRenderButton: () => (React__default["default"].createElement(ChatButtonWithUnreadMessagesBadge, { checked: isChatOpen, showLabel: args.displayType !== 'compact', onClick: toggleChat, disabled: chatButtonDisabled, strings: chatButtonStrings, styles: commonButtonStyles, newMessageLabel: callWithChatStrings.chatButtonNewMessageNotificationLabel, unreadChatMessagesCount: unreadChatMessagesCount,
|
@@ -32108,14 +32220,14 @@ const CallWithChatScreen = (props) => {
|
|
32108
32220
|
/* @conditional-compile-remove(custom-branding) */
|
32109
32221
|
props.backgroundImage
|
32110
32222
|
]);
|
32111
|
-
const onRenderChatContent = React.useCallback(() => (React__default["default"].createElement(ChatComposite,
|
32223
|
+
const onRenderChatContent = React.useCallback(() => (React__default["default"].createElement(ChatComposite, { adapter: chatAdapter, fluentTheme: theme, options: {
|
32112
32224
|
topic: false,
|
32113
32225
|
/* @conditional-compile-remove(chat-composite-participant-pane) */
|
32114
32226
|
participantPane: false,
|
32115
32227
|
/* @conditional-compile-remove(file-sharing) */
|
32116
32228
|
fileSharing: props.fileSharing
|
32117
|
-
}, onFetchAvatarPersonaData: props.onFetchAvatarPersonaData }))
|
32118
|
-
|
32229
|
+
}, onFetchAvatarPersonaData: props.onFetchAvatarPersonaData })), [
|
32230
|
+
chatAdapter,
|
32119
32231
|
/* @conditional-compile-remove(file-sharing) */ props.fileSharing,
|
32120
32232
|
props.onFetchAvatarPersonaData,
|
32121
32233
|
theme
|