@azure/communication-react 1.17.0-alpha-202405170014 → 1.17.0-alpha-202405180013
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/dist-cjs/communication-react/{ChatMessageComponentAsRichTextEditBox-BLFNaheX.js → ChatMessageComponentAsRichTextEditBox-r0U_8d3I.js} +22 -17
- package/dist/dist-cjs/communication-react/ChatMessageComponentAsRichTextEditBox-r0U_8d3I.js.map +1 -0
- package/dist/dist-cjs/communication-react/{RichTextSendBoxWrapper-BhTpuspw.js → RichTextSendBoxWrapper-DNlYAgO2.js} +6 -8
- package/dist/dist-cjs/communication-react/{RichTextSendBoxWrapper-BhTpuspw.js.map → RichTextSendBoxWrapper-DNlYAgO2.js.map} +1 -1
- package/dist/dist-cjs/communication-react/{index-C9I6Mcil.js → index-BLj9R9ms.js} +894 -462
- package/dist/dist-cjs/communication-react/index-BLj9R9ms.js.map +1 -0
- package/dist/dist-cjs/communication-react/index.js +5 -7
- 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/MyMessageComponents/ChatMessageComponentAsRichTextEditBox.js +17 -10
- package/dist/dist-esm/react-components/src/components/ChatMessage/MyMessageComponents/ChatMessageComponentAsRichTextEditBox.js.map +1 -1
- package/dist/dist-esm/react-components/src/components/InputBoxComponent.js +1 -1
- package/dist/dist-esm/react-components/src/components/InputBoxComponent.js.map +1 -1
- package/dist/dist-esm/react-components/src/components/RichTextEditor/Plugins/ContextMenuPlugin.d.ts +9 -0
- package/dist/dist-esm/react-components/src/components/RichTextEditor/Plugins/ContextMenuPlugin.js +29 -0
- package/dist/dist-esm/react-components/src/components/RichTextEditor/Plugins/ContextMenuPlugin.js.map +1 -0
- package/dist/dist-esm/react-components/src/components/RichTextEditor/Plugins/CopyPastePlugin.d.ts +1 -1
- package/dist/dist-esm/react-components/src/components/RichTextEditor/Plugins/CopyPastePlugin.js +15 -20
- package/dist/dist-esm/react-components/src/components/RichTextEditor/Plugins/CopyPastePlugin.js.map +1 -1
- package/dist/dist-esm/react-components/src/components/RichTextEditor/Plugins/KeyboardInputPlugin.d.ts +12 -0
- package/dist/dist-esm/react-components/src/components/RichTextEditor/Plugins/KeyboardInputPlugin.js +23 -0
- package/dist/dist-esm/react-components/src/components/RichTextEditor/Plugins/KeyboardInputPlugin.js.map +1 -0
- package/dist/dist-esm/react-components/src/components/RichTextEditor/Plugins/PlaceholderPlugin.d.ts +15 -0
- package/dist/dist-esm/react-components/src/components/RichTextEditor/Plugins/PlaceholderPlugin.js +39 -0
- package/dist/dist-esm/react-components/src/components/RichTextEditor/Plugins/PlaceholderPlugin.js.map +1 -0
- package/dist/dist-esm/react-components/src/components/RichTextEditor/Plugins/RichTextToolbarPlugin.d.ts +24 -0
- package/dist/dist-esm/react-components/src/components/RichTextEditor/Plugins/RichTextToolbarPlugin.js +66 -0
- package/dist/dist-esm/react-components/src/components/RichTextEditor/Plugins/RichTextToolbarPlugin.js.map +1 -0
- package/dist/dist-esm/react-components/src/components/RichTextEditor/Plugins/TableEditContextMenuProvider.d.ts +20 -0
- package/dist/dist-esm/react-components/src/components/RichTextEditor/Plugins/TableEditContextMenuProvider.js +46 -0
- package/dist/dist-esm/react-components/src/components/RichTextEditor/Plugins/TableEditContextMenuProvider.js.map +1 -0
- package/dist/dist-esm/react-components/src/components/RichTextEditor/Plugins/UpdateContentPlugin.d.ts +29 -0
- package/dist/dist-esm/react-components/src/components/RichTextEditor/Plugins/UpdateContentPlugin.js +71 -0
- package/dist/dist-esm/react-components/src/components/RichTextEditor/Plugins/UpdateContentPlugin.js.map +1 -0
- package/dist/dist-esm/react-components/src/components/RichTextEditor/RichTextEditor.d.ts +7 -10
- package/dist/dist-esm/react-components/src/components/RichTextEditor/RichTextEditor.js +170 -91
- package/dist/dist-esm/react-components/src/components/RichTextEditor/RichTextEditor.js.map +1 -1
- package/dist/dist-esm/react-components/src/components/RichTextEditor/RichTextInputBoxComponent.d.ts +0 -1
- package/dist/dist-esm/react-components/src/components/RichTextEditor/RichTextInputBoxComponent.js +29 -12
- package/dist/dist-esm/react-components/src/components/RichTextEditor/RichTextInputBoxComponent.js.map +1 -1
- package/dist/dist-esm/react-components/src/components/RichTextEditor/RichTextSendBox.js +12 -46
- package/dist/dist-esm/react-components/src/components/RichTextEditor/RichTextSendBox.js.map +1 -1
- package/dist/dist-esm/react-components/src/components/RichTextEditor/Toolbar/RichTextToolbar.d.ts +19 -0
- package/dist/dist-esm/react-components/src/components/RichTextEditor/Toolbar/RichTextToolbar.js +209 -0
- package/dist/dist-esm/react-components/src/components/RichTextEditor/Toolbar/RichTextToolbar.js.map +1 -0
- package/dist/dist-esm/react-components/src/components/RichTextEditor/Toolbar/Table/RichTextInsertTableCommandBarItem.d.ts +7 -0
- package/dist/dist-esm/react-components/src/components/RichTextEditor/Toolbar/Table/RichTextInsertTableCommandBarItem.js +49 -0
- package/dist/dist-esm/react-components/src/components/RichTextEditor/Toolbar/Table/RichTextInsertTableCommandBarItem.js.map +1 -0
- package/dist/dist-esm/react-components/src/components/RichTextEditor/{Buttons → Toolbar}/Table/RichTextInsertTablePane.d.ts +2 -2
- package/dist/dist-esm/react-components/src/components/RichTextEditor/{Buttons → Toolbar}/Table/RichTextInsertTablePane.js +3 -3
- package/dist/dist-esm/react-components/src/components/RichTextEditor/Toolbar/Table/RichTextInsertTablePane.js.map +1 -0
- package/dist/dist-esm/react-components/src/components/RichTextEditor/Toolbar/Table/RichTextToolbarTableIcon.d.ts +6 -0
- package/dist/dist-esm/react-components/src/components/RichTextEditor/Toolbar/Table/RichTextToolbarTableIcon.js +13 -0
- package/dist/dist-esm/react-components/src/components/RichTextEditor/Toolbar/Table/RichTextToolbarTableIcon.js.map +1 -0
- package/dist/dist-esm/react-components/src/components/TextFieldWithMention/TextFieldWithMention.js +1 -1
- package/dist/dist-esm/react-components/src/components/TextFieldWithMention/TextFieldWithMention.js.map +1 -1
- package/dist/dist-esm/react-components/src/components/styles/MessageThread.styles.js +3 -1
- package/dist/dist-esm/react-components/src/components/styles/MessageThread.styles.js.map +1 -1
- package/dist/dist-esm/react-components/src/components/styles/RichTextEditor.styles.d.ts +3 -3
- package/dist/dist-esm/react-components/src/components/styles/RichTextEditor.styles.js +4 -5
- package/dist/dist-esm/react-components/src/components/styles/RichTextEditor.styles.js.map +1 -1
- package/dist/dist-esm/react-components/src/components/utils/RichTextEditorUtils.d.ts +37 -0
- package/dist/dist-esm/react-components/src/components/utils/RichTextEditorUtils.js +60 -0
- package/dist/dist-esm/react-components/src/components/utils/RichTextEditorUtils.js.map +1 -0
- package/dist/dist-esm/react-components/src/components/utils/RichTextTableUtils.d.ts +11 -0
- package/dist/dist-esm/react-components/src/components/utils/RichTextTableUtils.js +95 -0
- package/dist/dist-esm/react-components/src/components/utils/RichTextTableUtils.js.map +1 -1
- package/dist/dist-esm/react-components/src/components/utils.d.ts +1 -1
- package/dist/dist-esm/react-components/src/components/utils.js +1 -3
- package/dist/dist-esm/react-components/src/components/utils.js.map +1 -1
- package/package.json +6 -8
- package/dist/dist-cjs/communication-react/ChatMessageComponentAsRichTextEditBox-BLFNaheX.js.map +0 -1
- package/dist/dist-cjs/communication-react/index-C9I6Mcil.js.map +0 -1
- package/dist/dist-esm/react-components/src/components/RichTextEditor/Buttons/RichTextRibbonButtons.d.ts +0 -7
- package/dist/dist-esm/react-components/src/components/RichTextEditor/Buttons/RichTextRibbonButtons.js +0 -86
- package/dist/dist-esm/react-components/src/components/RichTextEditor/Buttons/RichTextRibbonButtons.js.map +0 -1
- package/dist/dist-esm/react-components/src/components/RichTextEditor/Buttons/Table/RichTextInsertTableButton.d.ts +0 -7
- package/dist/dist-esm/react-components/src/components/RichTextEditor/Buttons/Table/RichTextInsertTableButton.js +0 -55
- package/dist/dist-esm/react-components/src/components/RichTextEditor/Buttons/Table/RichTextInsertTableButton.js.map +0 -1
- package/dist/dist-esm/react-components/src/components/RichTextEditor/Buttons/Table/RichTextInsertTablePane.js.map +0 -1
- package/dist/dist-esm/react-components/src/components/RichTextEditor/Buttons/Table/RichTextTableContextMenu.d.ts +0 -8
- package/dist/dist-esm/react-components/src/components/RichTextEditor/Buttons/Table/RichTextTableContextMenu.js +0 -66
- package/dist/dist-esm/react-components/src/components/RichTextEditor/Buttons/Table/RichTextTableContextMenu.js.map +0 -1
- package/dist/dist-esm/react-components/src/components/RichTextEditor/Buttons/Table/insertTableAction.d.ts +0 -9
- package/dist/dist-esm/react-components/src/components/RichTextEditor/Buttons/Table/insertTableAction.js +0 -56
- package/dist/dist-esm/react-components/src/components/RichTextEditor/Buttons/Table/insertTableAction.js.map +0 -1
- package/dist/dist-esm/react-components/src/components/utils/RichTextEditorStringsUtils.d.ts +0 -15
- package/dist/dist-esm/react-components/src/components/utils/RichTextEditorStringsUtils.js +0 -39
- package/dist/dist-esm/react-components/src/components/utils/RichTextEditorStringsUtils.js.map +0 -1
@@ -15,12 +15,10 @@ var reactComponents = require('@fluentui/react-components');
|
|
15
15
|
var useDebounce = require('use-debounce');
|
16
16
|
var reactFileTypeIcons = require('@fluentui/react-file-type-icons');
|
17
17
|
var react$1 = require('@griffel/react');
|
18
|
-
var
|
19
|
-
var
|
20
|
-
var
|
21
|
-
var
|
22
|
-
var roosterjsEditorDom = require('roosterjs-editor-dom');
|
23
|
-
var roosterjsEditorApi = require('roosterjs-editor-api');
|
18
|
+
var roosterjsContentModelCore = require('roosterjs-content-model-core');
|
19
|
+
var roosterjsContentModelDom = require('roosterjs-content-model-dom');
|
20
|
+
var roosterjsContentModelPlugins = require('roosterjs-content-model-plugins');
|
21
|
+
var roosterjsContentModelApi = require('roosterjs-content-model-api');
|
24
22
|
var reactChat = require('@fluentui-contrib/react-chat');
|
25
23
|
var uuid = require('uuid');
|
26
24
|
var parse = require('html-react-parser');
|
@@ -176,7 +174,7 @@ function getDefaultExportFromCjs (x) {
|
|
176
174
|
// Copyright (c) Microsoft Corporation.
|
177
175
|
// Licensed under the MIT License.
|
178
176
|
// GENERATED FILE. DO NOT EDIT MANUALLY.
|
179
|
-
var telemetryVersion = '1.17.0-alpha-
|
177
|
+
var telemetryVersion = '1.17.0-alpha-202405180013';
|
180
178
|
|
181
179
|
|
182
180
|
var telemetryVersion$1 = /*@__PURE__*/getDefaultExportFromCjs(telemetryVersion);
|
@@ -6132,9 +6130,7 @@ const SAFARI_COMPOSITION_KEYCODE = 229;
|
|
6132
6130
|
*/
|
6133
6131
|
const isEnterKeyEventFromCompositionSession = (e) =>
|
6134
6132
|
// Uses KeyCode 229 and which code 229 to determine if the press of the enter key is from a composition session or not (Safari only)
|
6135
|
-
e.
|
6136
|
-
e.nativeEvent.keyCode === SAFARI_COMPOSITION_KEYCODE ||
|
6137
|
-
e.nativeEvent.which === SAFARI_COMPOSITION_KEYCODE;
|
6133
|
+
e.isComposing || e.keyCode === SAFARI_COMPOSITION_KEYCODE || e.which === SAFARI_COMPOSITION_KEYCODE;
|
6138
6134
|
/**
|
6139
6135
|
* @private
|
6140
6136
|
*/
|
@@ -8147,7 +8143,7 @@ const TextFieldWithMention = (props) => {
|
|
8147
8143
|
// as onMouseUp can be triggered before or after onSelect event
|
8148
8144
|
// because its order depends on mouse events not selection.
|
8149
8145
|
setShouldHandleOnMouseDownDuringSelect(false);
|
8150
|
-
if (isEnterKeyEventFromCompositionSession(ev)) {
|
8146
|
+
if (isEnterKeyEventFromCompositionSession(ev.nativeEvent)) {
|
8151
8147
|
return;
|
8152
8148
|
}
|
8153
8149
|
let isActiveSuggestionIndexUpdated = false;
|
@@ -8617,7 +8613,7 @@ const InputBoxComponent = (props) => {
|
|
8617
8613
|
}
|
8618
8614
|
});
|
8619
8615
|
const onTextFieldKeyDown = React.useCallback((ev) => {
|
8620
|
-
if (isEnterKeyEventFromCompositionSession(ev)) {
|
8616
|
+
if (isEnterKeyEventFromCompositionSession(ev.nativeEvent)) {
|
8621
8617
|
return;
|
8622
8618
|
}
|
8623
8619
|
if (ev.key === 'Enter' && (ev.shiftKey === false || !supportNewline)) {
|
@@ -9949,7 +9945,6 @@ const richTextEditorWrapperStyle = (theme, addTopOffset) => {
|
|
9949
9945
|
paddingTop: `${addTopOffset ? '0.5rem' : '0'}`,
|
9950
9946
|
paddingInlineStart: `0.75rem`,
|
9951
9947
|
paddingInlineEnd: `0.75rem`,
|
9952
|
-
lineHeight: '1.25rem',
|
9953
9948
|
maxWidth: '100%',
|
9954
9949
|
color: theme.palette.neutralPrimary,
|
9955
9950
|
'& table': {
|
@@ -10050,7 +10045,7 @@ const ribbonButtonRootStyles = (theme) => {
|
|
10050
10045
|
/**
|
10051
10046
|
* @private
|
10052
10047
|
*/
|
10053
|
-
const
|
10048
|
+
const toolbarButtonStyle = (theme) => {
|
10054
10049
|
return {
|
10055
10050
|
icon: { color: theme.palette.neutralPrimary, height: 'auto' },
|
10056
10051
|
menuIcon: { color: theme.palette.neutralPrimary, height: 'auto' },
|
@@ -10071,7 +10066,7 @@ const rootRibbonTableButtonStyle = (theme) => {
|
|
10071
10066
|
/**
|
10072
10067
|
* @private
|
10073
10068
|
*/
|
10074
|
-
const
|
10069
|
+
const toolbarTableButtonStyle = (theme) => {
|
10075
10070
|
return {
|
10076
10071
|
icon: { height: 'auto' },
|
10077
10072
|
menuIcon: { height: 'auto' },
|
@@ -10119,9 +10114,9 @@ const ribbonDividerStyle = (theme) => {
|
|
10119
10114
|
/**
|
10120
10115
|
* @private
|
10121
10116
|
*/
|
10122
|
-
const
|
10117
|
+
const richTextToolbarStyle = {
|
10123
10118
|
// Override for the default white color of the Ribbon component
|
10124
|
-
root: { backgroundColor: 'transparent' }
|
10119
|
+
root: { backgroundColor: 'transparent', padding: '0px' }
|
10125
10120
|
};
|
10126
10121
|
/**
|
10127
10122
|
* @private
|
@@ -10211,55 +10206,217 @@ const tableContextMenuIconStyles = react.mergeStyles({
|
|
10211
10206
|
|
10212
10207
|
// Copyright (c) Microsoft Corporation.
|
10213
10208
|
// Licensed under the MIT License.
|
10214
|
-
|
10215
|
-
|
10216
|
-
*
|
10217
|
-
|
10218
|
-
|
10219
|
-
|
10220
|
-
|
10221
|
-
|
10222
|
-
|
10223
|
-
|
10224
|
-
|
10225
|
-
|
10226
|
-
|
10227
|
-
|
10228
|
-
|
10229
|
-
|
10230
|
-
|
10231
|
-
|
10232
|
-
|
10233
|
-
|
10234
|
-
|
10235
|
-
|
10236
|
-
|
10237
|
-
|
10238
|
-
|
10239
|
-
|
10240
|
-
|
10241
|
-
|
10242
|
-
|
10243
|
-
|
10244
|
-
|
10245
|
-
|
10246
|
-
|
10247
|
-
|
10248
|
-
|
10249
|
-
|
10250
|
-
|
10251
|
-
|
10252
|
-
|
10209
|
+
/**
|
10210
|
+
* Plugin event type for RoosterJS plugins
|
10211
|
+
* @private
|
10212
|
+
*/
|
10213
|
+
var PluginEventType;
|
10214
|
+
(function (PluginEventType) {
|
10215
|
+
PluginEventType["EditorReady"] = "editorReady";
|
10216
|
+
PluginEventType["BeforeDispose"] = "beforeDispose";
|
10217
|
+
PluginEventType["ContentChanged"] = "contentChanged";
|
10218
|
+
PluginEventType["Input"] = "input";
|
10219
|
+
PluginEventType["KeyDown"] = "keyDown";
|
10220
|
+
PluginEventType["BeforePaste"] = "beforePaste";
|
10221
|
+
PluginEventType["ZoomChanged"] = "zoomChanged";
|
10222
|
+
PluginEventType["MouseUp"] = "mouseUp";
|
10223
|
+
})(PluginEventType || (PluginEventType = {}));
|
10224
|
+
/**
|
10225
|
+
* ContentChanged event source for RoosterJS
|
10226
|
+
* @private
|
10227
|
+
*/
|
10228
|
+
var ContentChangedEventSource;
|
10229
|
+
(function (ContentChangedEventSource) {
|
10230
|
+
ContentChangedEventSource["Paste"] = "Paste";
|
10231
|
+
})(ContentChangedEventSource || (ContentChangedEventSource = {}));
|
10232
|
+
/**
|
10233
|
+
* Applies the border format to the specified element.
|
10234
|
+
* If the element is an HTMLTableCellElement, it skips setting editing info
|
10235
|
+
* and to use classes instead of inline styles.
|
10236
|
+
* For all other cases, the default format applier is used.
|
10237
|
+
*/
|
10238
|
+
const borderApplier = (format, element, context) => {
|
10239
|
+
if (element instanceof HTMLTableCellElement) ;
|
10240
|
+
else if (context.defaultFormatAppliers.border) {
|
10241
|
+
// apply default formats for all other cases
|
10242
|
+
context.defaultFormatAppliers.border(format, element, context);
|
10243
|
+
}
|
10244
|
+
};
|
10245
|
+
/**
|
10246
|
+
* Applies the dataset format to the given HTML element.
|
10247
|
+
* If the element is an HTMLTableElement, it skips setting editing info
|
10248
|
+
* and to use classes instead of inline styles.
|
10249
|
+
* For all other cases, it applies the default formats.
|
10250
|
+
*/
|
10251
|
+
const dataSetApplier = (format, element, context) => {
|
10252
|
+
if (element instanceof HTMLTableElement) ;
|
10253
|
+
else if (context.defaultFormatAppliers.dataset) {
|
10254
|
+
// apply default formats for all other cases
|
10255
|
+
context.defaultFormatAppliers.dataset(format, element, context);
|
10256
|
+
}
|
10253
10257
|
};
|
10254
|
-
|
10255
|
-
|
10256
|
-
|
10258
|
+
|
10259
|
+
/**
|
10260
|
+
* CopyPastePlugin is a plugin for handling copy and paste events in the editor.
|
10261
|
+
*/
|
10262
|
+
class CopyPastePlugin {
|
10263
|
+
constructor() {
|
10264
|
+
this.editor = null;
|
10257
10265
|
}
|
10258
|
-
|
10259
|
-
return '
|
10266
|
+
getName() {
|
10267
|
+
return 'CopyPastePlugin';
|
10260
10268
|
}
|
10261
|
-
|
10262
|
-
|
10269
|
+
initialize(editor) {
|
10270
|
+
this.editor = editor;
|
10271
|
+
}
|
10272
|
+
dispose() { }
|
10273
|
+
onPluginEvent(event) {
|
10274
|
+
removeImageElement(event);
|
10275
|
+
if (this.editor !== null && !this.editor.isDisposed()) {
|
10276
|
+
// scroll the editor to the correct position after pasting content
|
10277
|
+
scrollToBottomAfterContentPaste(event, this.editor);
|
10278
|
+
}
|
10279
|
+
}
|
10280
|
+
}
|
10281
|
+
/**
|
10282
|
+
* @internal
|
10283
|
+
* Exported only for unit testing
|
10284
|
+
*/
|
10285
|
+
const removeImageElement = (event) => {
|
10286
|
+
// We don't support the pasting options such as paste as image yet.
|
10287
|
+
if (event.eventType === PluginEventType.BeforePaste && event.pasteType === 'normal') {
|
10288
|
+
event.fragment.querySelectorAll('img').forEach((image) => {
|
10289
|
+
// If the image is the only child of its parent, remove all the parents of this img element.
|
10290
|
+
let parentNode = image.parentElement;
|
10291
|
+
let currentNode = image;
|
10292
|
+
while ((parentNode === null || parentNode === void 0 ? void 0 : parentNode.childNodes.length) === 1) {
|
10293
|
+
currentNode = parentNode;
|
10294
|
+
parentNode = parentNode.parentElement;
|
10295
|
+
}
|
10296
|
+
currentNode === null || currentNode === void 0 ? void 0 : currentNode.remove();
|
10297
|
+
});
|
10298
|
+
}
|
10299
|
+
};
|
10300
|
+
/**
|
10301
|
+
* Scrolls the editor's scroll container to the bottom after content is pasted.
|
10302
|
+
* @param event - The plugin event.
|
10303
|
+
* @param editor - The editor instance.
|
10304
|
+
*/
|
10305
|
+
const scrollToBottomAfterContentPaste = (event, editor) => {
|
10306
|
+
if (event.eventType === PluginEventType.ContentChanged && event.source === ContentChangedEventSource.Paste) {
|
10307
|
+
const scrollContainer = editor.getScrollContainer();
|
10308
|
+
// get current selection for the editor
|
10309
|
+
const selection = document.getSelection();
|
10310
|
+
// if selection exists
|
10311
|
+
if (selection && selection.rangeCount > 0) {
|
10312
|
+
// the range for the selection
|
10313
|
+
const range = selection.getRangeAt(0);
|
10314
|
+
// the selection position relative to the viewport
|
10315
|
+
const cursorRect = range.getBoundingClientRect();
|
10316
|
+
// the scrollContainer position relative to the viewport
|
10317
|
+
const scrollContainerRect = scrollContainer.getBoundingClientRect();
|
10318
|
+
// 1. scrollContainer.scrollTop represents the number of pixels that the content of scrollContainer is scrolled upward.
|
10319
|
+
// 2. subtract the top position of the scrollContainer element (scrollContainerRect.top) to
|
10320
|
+
// translate the scroll position from being relative to the document to being relative to the viewport.
|
10321
|
+
// 3. add the top position of the cursor (containerRect.top) to moves the scroll position to the cursor's position.
|
10322
|
+
const updatedScrollTop = scrollContainer.scrollTop - scrollContainerRect.top + cursorRect.top;
|
10323
|
+
scrollContainer.scrollTo({
|
10324
|
+
top: updatedScrollTop,
|
10325
|
+
behavior: 'smooth'
|
10326
|
+
});
|
10327
|
+
}
|
10328
|
+
}
|
10329
|
+
};
|
10330
|
+
|
10331
|
+
// Copyright (c) Microsoft Corporation.
|
10332
|
+
// Licensed under the MIT License.
|
10333
|
+
/**
|
10334
|
+
* KeyboardInputPlugin is a plugin for handling keyboard events in the editor.
|
10335
|
+
*/
|
10336
|
+
class KeyboardInputPlugin {
|
10337
|
+
constructor() {
|
10338
|
+
// don't set callback in constructor to be able to update callback without plugin recreation
|
10339
|
+
this.onKeyDown = null;
|
10340
|
+
}
|
10341
|
+
getName() {
|
10342
|
+
return 'KeyboardInputPlugin';
|
10343
|
+
}
|
10344
|
+
initialize() { }
|
10345
|
+
dispose() { }
|
10346
|
+
onPluginEvent(event) {
|
10347
|
+
if (this.onKeyDown && event.eventType === PluginEventType.KeyDown && event.rawEvent instanceof KeyboardEvent) {
|
10348
|
+
this.onKeyDown(event.rawEvent);
|
10349
|
+
}
|
10350
|
+
}
|
10351
|
+
}
|
10352
|
+
|
10353
|
+
// Copyright (c) Microsoft Corporation.
|
10354
|
+
// Licensed under the MIT License.
|
10355
|
+
/**
|
10356
|
+
* An update mode to indicate when the content update happens
|
10357
|
+
*/
|
10358
|
+
var UpdateEvent;
|
10359
|
+
(function (UpdateEvent) {
|
10360
|
+
UpdateEvent["Init"] = "Init";
|
10361
|
+
UpdateEvent["Dispose"] = "Dispose";
|
10362
|
+
UpdateEvent["ContentChanged"] = "ContentChanged";
|
10363
|
+
UpdateEvent["UserInput"] = "UserInput";
|
10364
|
+
UpdateEvent["Blur"] = "Blur";
|
10365
|
+
})(UpdateEvent || (UpdateEvent = {}));
|
10366
|
+
/**
|
10367
|
+
* A plugin to handle content update
|
10368
|
+
*/
|
10369
|
+
class UpdateContentPlugin {
|
10370
|
+
constructor() {
|
10371
|
+
this.editor = null;
|
10372
|
+
this.disposer = null;
|
10373
|
+
// don't set callback in constructor to be able to update callback without plugin recreation
|
10374
|
+
this.onUpdate = null;
|
10375
|
+
this.onBlur = () => {
|
10376
|
+
if (this.onUpdate === null) {
|
10377
|
+
return;
|
10378
|
+
}
|
10379
|
+
this.onUpdate(UpdateEvent.Blur);
|
10380
|
+
};
|
10381
|
+
}
|
10382
|
+
getName() {
|
10383
|
+
return 'UpdateContentPlugin';
|
10384
|
+
}
|
10385
|
+
/**
|
10386
|
+
* Initialize this plugin
|
10387
|
+
* @param editor The editor instance
|
10388
|
+
*/
|
10389
|
+
initialize(editor) {
|
10390
|
+
this.editor = editor;
|
10391
|
+
this.disposer = this.editor.attachDomEvent({
|
10392
|
+
blur: { beforeDispatch: this.onBlur }
|
10393
|
+
});
|
10394
|
+
}
|
10395
|
+
dispose() {
|
10396
|
+
this.editor = null;
|
10397
|
+
if (this.disposer) {
|
10398
|
+
this.disposer();
|
10399
|
+
this.disposer = null;
|
10400
|
+
}
|
10401
|
+
}
|
10402
|
+
onPluginEvent(event) {
|
10403
|
+
if (this.onUpdate === null) {
|
10404
|
+
return;
|
10405
|
+
}
|
10406
|
+
switch (event.eventType) {
|
10407
|
+
case PluginEventType.EditorReady:
|
10408
|
+
this.onUpdate(UpdateEvent.Init);
|
10409
|
+
break;
|
10410
|
+
case PluginEventType.BeforeDispose:
|
10411
|
+
this.onUpdate(UpdateEvent.Dispose);
|
10412
|
+
break;
|
10413
|
+
case PluginEventType.ContentChanged:
|
10414
|
+
this.onUpdate(UpdateEvent.ContentChanged);
|
10415
|
+
break;
|
10416
|
+
case PluginEventType.Input:
|
10417
|
+
this.onUpdate(UpdateEvent.UserInput);
|
10418
|
+
break;
|
10419
|
+
}
|
10263
10420
|
}
|
10264
10421
|
}
|
10265
10422
|
|
@@ -10291,6 +10448,99 @@ function parseKey(key) {
|
|
10291
10448
|
column: parseInt(column)
|
10292
10449
|
};
|
10293
10450
|
}
|
10451
|
+
/**
|
10452
|
+
* Returns an array of context menu items for editing a rich text table.
|
10453
|
+
*
|
10454
|
+
* @param editor - The editor instance.
|
10455
|
+
* @param strings - An object containing localized strings for the context menu items.
|
10456
|
+
* @returns An array of context menu items.
|
10457
|
+
*/
|
10458
|
+
const getTableEditContextMenuItems = (editor, strings) => {
|
10459
|
+
return [
|
10460
|
+
{
|
10461
|
+
key: 'RichTextTableEditMenuTableInsert',
|
10462
|
+
text: strings.richTextInsertRowOrColumnMenu,
|
10463
|
+
ariaLabel: strings.richTextInsertRowOrColumnMenu,
|
10464
|
+
iconProps: {
|
10465
|
+
iconName: 'RichTextTableInsertMenuIcon',
|
10466
|
+
styles: { root: tableContextMenuIconStyles }
|
10467
|
+
},
|
10468
|
+
subMenuProps: {
|
10469
|
+
items: [
|
10470
|
+
{
|
10471
|
+
key: 'RichTextTableEditMenuTableInsertRowAbove',
|
10472
|
+
text: strings.richTextInsertRowAboveMenu,
|
10473
|
+
ariaLabel: strings.richTextInsertRowAboveMenu,
|
10474
|
+
onClick: () => {
|
10475
|
+
roosterjsContentModelApi.editTable(editor, 'insertAbove');
|
10476
|
+
}
|
10477
|
+
},
|
10478
|
+
{
|
10479
|
+
key: 'RichTextTableEditMenuTableInsertRowBelow',
|
10480
|
+
text: strings.richTextInsertRowBelowMenu,
|
10481
|
+
ariaLabel: strings.richTextInsertRowBelowMenu,
|
10482
|
+
onClick: () => {
|
10483
|
+
roosterjsContentModelApi.editTable(editor, 'insertBelow');
|
10484
|
+
}
|
10485
|
+
},
|
10486
|
+
{
|
10487
|
+
key: 'RichTextTableEditMenuTableInsertColumnLeft',
|
10488
|
+
text: strings.richTextInsertColumnLeftMenu,
|
10489
|
+
ariaLabel: strings.richTextInsertColumnLeftMenu,
|
10490
|
+
onClick: () => {
|
10491
|
+
roosterjsContentModelApi.editTable(editor, 'insertLeft');
|
10492
|
+
}
|
10493
|
+
},
|
10494
|
+
{
|
10495
|
+
key: 'RichTextTableEditMenuTableInsertColumnRight',
|
10496
|
+
text: strings.richTextInsertColumnRightMenu,
|
10497
|
+
ariaLabel: strings.richTextInsertColumnRightMenu,
|
10498
|
+
onClick: () => {
|
10499
|
+
roosterjsContentModelApi.editTable(editor, 'insertRight');
|
10500
|
+
}
|
10501
|
+
}
|
10502
|
+
]
|
10503
|
+
}
|
10504
|
+
},
|
10505
|
+
{
|
10506
|
+
key: 'RichTextTableEditMenuTableDelete',
|
10507
|
+
text: strings.richTextDeleteRowOrColumnMenu,
|
10508
|
+
ariaLabel: strings.richTextDeleteRowOrColumnMenu,
|
10509
|
+
iconProps: {
|
10510
|
+
iconName: 'RichTextTableDeleteMenuIcon',
|
10511
|
+
styles: { root: tableContextMenuIconStyles }
|
10512
|
+
},
|
10513
|
+
subMenuProps: {
|
10514
|
+
items: [
|
10515
|
+
{
|
10516
|
+
key: 'RichTextTableEditMenuTableDeleteRow',
|
10517
|
+
text: strings.richTextDeleteRowMenu,
|
10518
|
+
ariaLabel: strings.richTextDeleteRowMenu,
|
10519
|
+
onClick: () => {
|
10520
|
+
roosterjsContentModelApi.editTable(editor, 'deleteRow');
|
10521
|
+
}
|
10522
|
+
},
|
10523
|
+
{
|
10524
|
+
key: 'RichTextTableEditMenuTableDeleteColumn',
|
10525
|
+
text: strings.richTextDeleteColumnMenu,
|
10526
|
+
ariaLabel: strings.richTextDeleteColumnMenu,
|
10527
|
+
onClick: () => {
|
10528
|
+
roosterjsContentModelApi.editTable(editor, 'deleteColumn');
|
10529
|
+
}
|
10530
|
+
},
|
10531
|
+
{
|
10532
|
+
key: 'RichTextTableEditMenuTableDeleteTable',
|
10533
|
+
text: strings.richTextDeleteTableMenu,
|
10534
|
+
ariaLabel: strings.richTextDeleteTableMenu,
|
10535
|
+
onClick: () => {
|
10536
|
+
roosterjsContentModelApi.editTable(editor, 'deleteTable');
|
10537
|
+
}
|
10538
|
+
}
|
10539
|
+
]
|
10540
|
+
}
|
10541
|
+
}
|
10542
|
+
];
|
10543
|
+
};
|
10294
10544
|
|
10295
10545
|
// Copyright (c) Microsoft Corporation.
|
10296
10546
|
// Licensed under the MIT License.
|
@@ -10321,9 +10571,9 @@ const RichTextInsertTablePane = (props) => {
|
|
10321
10571
|
const onMouseEnter = React.useCallback((e) => {
|
10322
10572
|
updateSize(e.target);
|
10323
10573
|
}, [updateSize]);
|
10324
|
-
const onClickButton = React.useCallback((
|
10325
|
-
onClick(
|
10326
|
-
}, [row, column, onClick
|
10574
|
+
const onClickButton = React.useCallback(() => {
|
10575
|
+
onClick(createKey(formatRowColumnText(row), formatRowColumnText(column)));
|
10576
|
+
}, [row, column, onClick]);
|
10327
10577
|
const items = React.useMemo(() => {
|
10328
10578
|
var _a;
|
10329
10579
|
const items = [];
|
@@ -10353,310 +10603,435 @@ const formatRowColumnText = (value) => {
|
|
10353
10603
|
|
10354
10604
|
// Copyright (c) Microsoft Corporation.
|
10355
10605
|
// Licensed under the MIT License.
|
10356
|
-
// This file uses RoosterJS React package implementation with updates to UI components and styles.
|
10357
10606
|
/**
|
10358
|
-
*
|
10607
|
+
* Renders the icon component for the insert table button in the rich text editor toolbar.
|
10359
10608
|
*/
|
10360
|
-
const
|
10361
|
-
return
|
10362
|
-
key: 'buttonNameInsertTable',
|
10363
|
-
unlocalizedText: 'Insert table',
|
10364
|
-
// Icon will be set in onRenderIcon callback
|
10365
|
-
iconName: '',
|
10366
|
-
onClick: (editor, key) => {
|
10367
|
-
const { row, column } = parseKey(key);
|
10368
|
-
insertTable(editor, column, row);
|
10369
|
-
},
|
10370
|
-
dropDownMenu: {
|
10371
|
-
items: {
|
10372
|
-
// the key of the item is also used as a key for localization
|
10373
|
-
insertTablePane: `Insert ${ColumnRowReplaceString} table`
|
10374
|
-
},
|
10375
|
-
itemRender: (item, onClick) => {
|
10376
|
-
return (React.createElement(RichTextInsertTablePane, { item: item, onClick: onClick, maxColumnsNumber: maxColumnsNumber, maxRowsNumber: maxRowsNumber }));
|
10377
|
-
},
|
10378
|
-
commandBarSubMenuProperties: {
|
10379
|
-
className: insertTableMenuTablePane
|
10380
|
-
}
|
10381
|
-
},
|
10382
|
-
commandBarProperties: {
|
10383
|
-
// hide the chevron icon
|
10384
|
-
menuIconProps: {
|
10385
|
-
hidden: true
|
10386
|
-
},
|
10387
|
-
onRenderIcon: () => {
|
10388
|
-
return React.createElement(TableIcon, null);
|
10389
|
-
},
|
10390
|
-
buttonStyles: ribbonTableButtonStyle(theme),
|
10391
|
-
canCheck: false
|
10392
|
-
}
|
10393
|
-
};
|
10394
|
-
};
|
10395
|
-
const TableIcon = () => {
|
10396
|
-
return (
|
10397
|
-
// update the visibility of the Table Icon with css classes that are triggered by command bar's state
|
10398
|
-
React.createElement(react.Stack, null,
|
10609
|
+
const RichTextToolbarTableIcon = () => {
|
10610
|
+
return (React.createElement(react.Stack, null,
|
10399
10611
|
React.createElement(react.Icon, { iconName: "RichTextInsertTableFilledIcon", className: 'ribbon-table-button-filled-icon' }),
|
10400
10612
|
React.createElement(react.Icon, { iconName: "RichTextInsertTableRegularIcon", className: 'ribbon-table-button-regular-icon' })));
|
10401
10613
|
};
|
10402
10614
|
|
10403
10615
|
// Copyright (c) Microsoft Corporation.
|
10404
10616
|
// Licensed under the MIT License.
|
10405
|
-
const MaxRowsNumber = 5;
|
10406
|
-
const MaxColumnsNumber = 5;
|
10407
|
-
const dividerRibbonButton = (theme, key) => {
|
10408
|
-
return {
|
10409
|
-
key: key,
|
10410
|
-
// the icon will be set in `onRender` callback
|
10411
|
-
// this is needed to make the divider unavailable for keyboard navigation
|
10412
|
-
iconName: '',
|
10413
|
-
// no text is needed here as we don't want to show a tooltip for the divider
|
10414
|
-
unlocalizedText: '',
|
10415
|
-
onClick: () => { },
|
10416
|
-
isDisabled: () => true,
|
10417
|
-
commandBarProperties: {
|
10418
|
-
// show the item correctly for the overflow menu
|
10419
|
-
itemType: react.ContextualMenuItemType.Divider,
|
10420
|
-
// this is still needed to remove checkmark icon space even though it is a divider
|
10421
|
-
canCheck: false,
|
10422
|
-
onRender: () => React.createElement(react.Icon, { iconName: "RichTextDividerIcon", className: ribbonDividerStyle(theme) })
|
10423
|
-
}
|
10424
|
-
};
|
10425
|
-
};
|
10426
|
-
const boldButton = (theme) => {
|
10427
|
-
return createKnownRibbonButton(roosterjsReact.KnownRibbonButtonKey.Bold, theme, 'RichTextBoldButtonIcon');
|
10428
|
-
};
|
10429
|
-
const italicButton = (theme) => {
|
10430
|
-
return createKnownRibbonButton(roosterjsReact.KnownRibbonButtonKey.Italic, theme, 'RichTextItalicButtonIcon');
|
10431
|
-
};
|
10432
|
-
const underlineButton = (theme) => {
|
10433
|
-
return createKnownRibbonButton(roosterjsReact.KnownRibbonButtonKey.Underline, theme, 'RichTextUnderlineButtonIcon');
|
10434
|
-
};
|
10435
|
-
const bulletListButton = (theme) => {
|
10436
|
-
return createKnownRibbonButton(roosterjsReact.KnownRibbonButtonKey.BulletedList, theme, 'RichTextBulletListButtonIcon');
|
10437
|
-
};
|
10438
|
-
const numberListButton = (theme) => {
|
10439
|
-
return createKnownRibbonButton(roosterjsReact.KnownRibbonButtonKey.NumberedList, theme, 'RichTextNumberListButtonIcon');
|
10440
|
-
};
|
10441
|
-
const indentIncreaseButton = (theme) => {
|
10442
|
-
return createKnownRibbonButton(roosterjsReact.KnownRibbonButtonKey.IncreaseIndent, theme, 'RichTextIndentIncreaseButtonIcon');
|
10443
|
-
};
|
10444
|
-
const indentDecreaseButton = (theme) => {
|
10445
|
-
return createKnownRibbonButton(roosterjsReact.KnownRibbonButtonKey.DecreaseIndent, theme, 'RichTextIndentDecreaseButtonIcon');
|
10446
|
-
};
|
10447
|
-
const createKnownRibbonButton = (key, theme, icon) => {
|
10448
|
-
var _a;
|
10449
|
-
const buttons = roosterjsReact.getButtons([key]);
|
10450
|
-
if (buttons.length > 0) {
|
10451
|
-
const button = buttons[0];
|
10452
|
-
// AllButtonStringKeys is a union of all the string keys of all the buttons
|
10453
|
-
const result = buttons[0];
|
10454
|
-
button.iconName = icon;
|
10455
|
-
button.commandBarProperties = Object.assign(Object.assign({}, button.commandBarProperties), { buttonStyles: Object.assign(Object.assign({}, (_a = button.commandBarProperties) === null || _a === void 0 ? void 0 : _a.buttonStyles), ribbonButtonStyle(theme)), canCheck: false });
|
10456
|
-
return result;
|
10457
|
-
}
|
10458
|
-
return undefined;
|
10459
|
-
};
|
10460
10617
|
/**
|
10461
|
-
*
|
10618
|
+
* "Insert table" command bar item for the rich text toolbar
|
10462
10619
|
*/
|
10463
|
-
const
|
10464
|
-
|
10465
|
-
|
10466
|
-
|
10467
|
-
|
10468
|
-
|
10469
|
-
|
10470
|
-
|
10471
|
-
|
10472
|
-
|
10473
|
-
|
10474
|
-
|
10475
|
-
|
10476
|
-
|
10477
|
-
|
10478
|
-
|
10620
|
+
const richTextInsertTableCommandBarItem = (theme, maxRowsNumber, maxColumnsNumber, strings, onClick) => {
|
10621
|
+
return {
|
10622
|
+
'data-testid': 'rich-text-toolbar-insert-table-button',
|
10623
|
+
key: 'RichTextToolbarInsertTableButton',
|
10624
|
+
text: strings.richTextInsertTableTooltip,
|
10625
|
+
ariaLabel: strings.richTextInsertTableTooltip,
|
10626
|
+
// hide the chevron icon
|
10627
|
+
menuIconProps: {
|
10628
|
+
hidden: true
|
10629
|
+
},
|
10630
|
+
onRenderIcon: () => {
|
10631
|
+
return React.createElement(RichTextToolbarTableIcon, null);
|
10632
|
+
},
|
10633
|
+
buttonStyles: toolbarTableButtonStyle(theme),
|
10634
|
+
canCheck: false,
|
10635
|
+
iconOnly: true,
|
10636
|
+
subMenuProps: {
|
10637
|
+
calloutProps: { isBeakVisible: false },
|
10638
|
+
shouldFocusOnMount: true,
|
10639
|
+
className: insertTableMenuTablePane,
|
10640
|
+
focusZoneProps: { direction: react.FocusZoneDirection.bidirectional },
|
10641
|
+
items: [
|
10642
|
+
{
|
10643
|
+
key: 'RichTextToolbarInsertTableMenu',
|
10644
|
+
text: strings.richTextInsertTableMenuTitle,
|
10645
|
+
canCheck: false,
|
10646
|
+
onRender: (item) => {
|
10647
|
+
return (React.createElement(RichTextInsertTablePane, { item: item, onClick: (key) => {
|
10648
|
+
const { row, column } = parseKey(key);
|
10649
|
+
onClick(column, row);
|
10650
|
+
}, maxColumnsNumber: maxColumnsNumber, maxRowsNumber: maxRowsNumber }));
|
10651
|
+
}
|
10652
|
+
}
|
10653
|
+
]
|
10479
10654
|
}
|
10480
|
-
}
|
10481
|
-
return buttons;
|
10655
|
+
};
|
10482
10656
|
};
|
10483
10657
|
|
10484
10658
|
// Copyright (c) Microsoft Corporation.
|
10485
10659
|
// Licensed under the MIT License.
|
10660
|
+
const MaxRowsNumber = 5;
|
10661
|
+
const MaxColumnsNumber = 5;
|
10486
10662
|
/**
|
10487
|
-
*
|
10663
|
+
* A component to display rich text toolbar.
|
10488
10664
|
*
|
10489
|
-
*
|
10665
|
+
* @beta
|
10490
10666
|
*/
|
10491
|
-
const
|
10667
|
+
const RichTextToolbar = (props) => {
|
10668
|
+
const { plugin, strings } = props;
|
10669
|
+
const theme = useTheme();
|
10670
|
+
// need to re-render the buttons when format state changes
|
10671
|
+
const [formatState, setFormatState] = React.useState(undefined);
|
10672
|
+
React.useEffect(() => {
|
10673
|
+
// update the format state on editor events
|
10674
|
+
plugin.onFormatChanged = setFormatState;
|
10675
|
+
}, [plugin]);
|
10676
|
+
const boldButton = React.useMemo(() => {
|
10677
|
+
return getCommandBarItem({
|
10678
|
+
dataTestId: 'rich-text-toolbar-bold-button',
|
10679
|
+
key: 'RichTextToolbarBoldButton',
|
10680
|
+
icon: 'RichTextBoldButtonIcon',
|
10681
|
+
onClick: () => {
|
10682
|
+
plugin.onToolbarButtonClick((editor) => {
|
10683
|
+
roosterjsContentModelApi.toggleBold(editor);
|
10684
|
+
});
|
10685
|
+
},
|
10686
|
+
text: strings.richTextBoldTooltip,
|
10687
|
+
checked: formatState !== undefined && formatState.isBold === true,
|
10688
|
+
theme: theme
|
10689
|
+
});
|
10690
|
+
}, [formatState, plugin, strings.richTextBoldTooltip, theme]);
|
10691
|
+
const italicButton = React.useMemo(() => {
|
10692
|
+
return getCommandBarItem({
|
10693
|
+
dataTestId: 'rich-text-toolbar-italic-button',
|
10694
|
+
key: 'RichTextToolbarItalicButton',
|
10695
|
+
icon: 'RichTextItalicButtonIcon',
|
10696
|
+
onClick: () => {
|
10697
|
+
plugin.onToolbarButtonClick((editor) => {
|
10698
|
+
roosterjsContentModelApi.toggleItalic(editor);
|
10699
|
+
});
|
10700
|
+
},
|
10701
|
+
text: strings.richTextItalicTooltip,
|
10702
|
+
checked: formatState !== undefined && (formatState === null || formatState === void 0 ? void 0 : formatState.isItalic) === true,
|
10703
|
+
theme: theme
|
10704
|
+
});
|
10705
|
+
}, [formatState, plugin, strings.richTextItalicTooltip, theme]);
|
10706
|
+
const underlineButton = React.useMemo(() => {
|
10707
|
+
return getCommandBarItem({
|
10708
|
+
dataTestId: 'rich-text-toolbar-underline-button',
|
10709
|
+
key: 'RichTextToolbarUnderlineButton',
|
10710
|
+
icon: 'RichTextUnderlineButtonIcon',
|
10711
|
+
onClick: () => {
|
10712
|
+
plugin.onToolbarButtonClick((editor) => {
|
10713
|
+
roosterjsContentModelApi.toggleUnderline(editor);
|
10714
|
+
});
|
10715
|
+
},
|
10716
|
+
text: strings.richTextUnderlineTooltip,
|
10717
|
+
checked: formatState !== undefined && (formatState === null || formatState === void 0 ? void 0 : formatState.isUnderline) === true,
|
10718
|
+
theme: theme
|
10719
|
+
});
|
10720
|
+
}, [formatState, plugin, strings.richTextUnderlineTooltip, theme]);
|
10721
|
+
const bulletListButton = React.useMemo(() => {
|
10722
|
+
return getCommandBarItem({
|
10723
|
+
dataTestId: 'rich-text-toolbar-bullet-list-button',
|
10724
|
+
key: 'RichTextToolbarBulletListButton',
|
10725
|
+
icon: 'RichTextBulletListButtonIcon',
|
10726
|
+
onClick: () => {
|
10727
|
+
plugin.onToolbarButtonClick((editor) => {
|
10728
|
+
roosterjsContentModelApi.toggleBullet(editor);
|
10729
|
+
});
|
10730
|
+
},
|
10731
|
+
text: strings.richTextBulletListTooltip,
|
10732
|
+
checked: formatState !== undefined && (formatState === null || formatState === void 0 ? void 0 : formatState.isBullet) === true,
|
10733
|
+
theme: theme
|
10734
|
+
});
|
10735
|
+
}, [formatState, plugin, strings.richTextBulletListTooltip, theme]);
|
10736
|
+
const numberListButton = React.useMemo(() => {
|
10737
|
+
return getCommandBarItem({
|
10738
|
+
dataTestId: 'rich-text-toolbar-number-list-button',
|
10739
|
+
key: 'RichTextToolbarNumberListButton',
|
10740
|
+
icon: 'RichTextNumberListButtonIcon',
|
10741
|
+
onClick: () => {
|
10742
|
+
plugin.onToolbarButtonClick((editor) => {
|
10743
|
+
roosterjsContentModelApi.toggleNumbering(editor);
|
10744
|
+
});
|
10745
|
+
},
|
10746
|
+
text: strings.richTextNumberListTooltip,
|
10747
|
+
checked: formatState !== undefined && (formatState === null || formatState === void 0 ? void 0 : formatState.isNumbering) === true,
|
10748
|
+
theme: theme
|
10749
|
+
});
|
10750
|
+
}, [formatState, plugin, strings.richTextNumberListTooltip, theme]);
|
10751
|
+
const indentDecreaseButton = React.useMemo(() => {
|
10752
|
+
return getCommandBarItem({
|
10753
|
+
dataTestId: 'rich-text-toolbar-indent-decrease-button',
|
10754
|
+
key: 'RichTextToolbarIndentDecreaseButton',
|
10755
|
+
icon: 'RichTextIndentDecreaseButtonIcon',
|
10756
|
+
onClick: () => {
|
10757
|
+
plugin.onToolbarButtonClick((editor) => {
|
10758
|
+
roosterjsContentModelApi.setIndentation(editor, 'outdent');
|
10759
|
+
});
|
10760
|
+
},
|
10761
|
+
text: strings.richTextDecreaseIndentTooltip,
|
10762
|
+
canCheck: false,
|
10763
|
+
theme: theme
|
10764
|
+
});
|
10765
|
+
}, [plugin, strings.richTextDecreaseIndentTooltip, theme]);
|
10766
|
+
const indentIncreaseButton = React.useMemo(() => {
|
10767
|
+
return getCommandBarItem({
|
10768
|
+
dataTestId: 'rich-text-toolbar-indent-increase-button',
|
10769
|
+
key: 'RichTextToolbarIndentIncreaseButton',
|
10770
|
+
icon: 'RichTextIndentIncreaseButtonIcon',
|
10771
|
+
onClick: () => {
|
10772
|
+
plugin.onToolbarButtonClick((editor) => {
|
10773
|
+
roosterjsContentModelApi.setIndentation(editor, 'indent');
|
10774
|
+
});
|
10775
|
+
},
|
10776
|
+
text: strings.richTextIncreaseIndentTooltip,
|
10777
|
+
canCheck: false,
|
10778
|
+
theme: theme
|
10779
|
+
});
|
10780
|
+
}, [plugin, strings.richTextIncreaseIndentTooltip, theme]);
|
10781
|
+
const divider = React.useCallback((key) => {
|
10782
|
+
return dividerCommandBarItem(theme, key);
|
10783
|
+
}, [theme]);
|
10784
|
+
const tableButton = React.useMemo(() => {
|
10785
|
+
return richTextInsertTableCommandBarItem(theme, MaxRowsNumber, MaxColumnsNumber, strings, (column, row) => {
|
10786
|
+
plugin.onToolbarButtonClick((editor) => {
|
10787
|
+
//add format
|
10788
|
+
roosterjsContentModelApi.insertTable(editor, column, row);
|
10789
|
+
// when subMenuProps is used and the menu is dismissed, focus is set to the command bar item that opened the menu
|
10790
|
+
// set focus to editor on next re-render
|
10791
|
+
setTimeout(() => {
|
10792
|
+
editor.focus();
|
10793
|
+
});
|
10794
|
+
});
|
10795
|
+
});
|
10796
|
+
}, [plugin, strings, theme]);
|
10797
|
+
const buttons = React.useMemo(() => {
|
10798
|
+
return [
|
10799
|
+
boldButton,
|
10800
|
+
italicButton,
|
10801
|
+
underlineButton,
|
10802
|
+
divider('RichTextRibbonTextFormatDivider'),
|
10803
|
+
bulletListButton,
|
10804
|
+
numberListButton,
|
10805
|
+
indentDecreaseButton,
|
10806
|
+
indentIncreaseButton,
|
10807
|
+
divider('RichTextRibbonTableDivider'),
|
10808
|
+
tableButton
|
10809
|
+
];
|
10810
|
+
}, [
|
10811
|
+
boldButton,
|
10812
|
+
italicButton,
|
10813
|
+
underlineButton,
|
10814
|
+
divider,
|
10815
|
+
bulletListButton,
|
10816
|
+
numberListButton,
|
10817
|
+
indentDecreaseButton,
|
10818
|
+
indentIncreaseButton,
|
10819
|
+
tableButton
|
10820
|
+
]);
|
10821
|
+
const overflowButtonProps = React.useMemo(() => {
|
10822
|
+
return {
|
10823
|
+
ariaLabel: strings.richTextToolbarMoreButtonAriaLabel,
|
10824
|
+
styles: toolbarButtonStyle(theme),
|
10825
|
+
menuProps: {
|
10826
|
+
items: [], // CommandBar will determine items rendered in overflow
|
10827
|
+
isBeakVisible: false,
|
10828
|
+
styles: ribbonOverflowButtonStyle(theme)
|
10829
|
+
}
|
10830
|
+
};
|
10831
|
+
}, [strings.richTextToolbarMoreButtonAriaLabel, theme]);
|
10832
|
+
return (React.createElement(react.CommandBar, { items: buttons, "data-testid": 'rich-text-editor-toolbar', styles: richTextToolbarStyle, overflowButtonProps: overflowButtonProps }));
|
10833
|
+
};
|
10834
|
+
const getCommandBarItem = ({ key, icon, onClick, text, canCheck = true, checked = false, disabled = false, theme, dataTestId }) => {
|
10492
10835
|
return {
|
10493
|
-
|
10494
|
-
|
10495
|
-
|
10496
|
-
|
10497
|
-
|
10498
|
-
|
10499
|
-
|
10500
|
-
|
10501
|
-
|
10836
|
+
'data-testid': dataTestId,
|
10837
|
+
key: key,
|
10838
|
+
iconProps: { iconName: icon },
|
10839
|
+
onClick: onClick,
|
10840
|
+
text: text,
|
10841
|
+
ariaLabel: text,
|
10842
|
+
iconOnly: true,
|
10843
|
+
canCheck: canCheck,
|
10844
|
+
buttonStyles: Object.assign({}, toolbarButtonStyle(theme)),
|
10845
|
+
checked: checked,
|
10846
|
+
disabled: disabled
|
10502
10847
|
};
|
10503
10848
|
};
|
10504
|
-
|
10505
|
-
* @private
|
10506
|
-
*
|
10507
|
-
* Strings for the table context menu where key should match `key` prop if any or the name of the item.
|
10508
|
-
*/
|
10509
|
-
const tableContextMenuStrings = (strings) => {
|
10849
|
+
const dividerCommandBarItem = (theme, key) => {
|
10510
10850
|
return {
|
10511
|
-
|
10512
|
-
|
10513
|
-
|
10514
|
-
|
10515
|
-
|
10516
|
-
|
10517
|
-
|
10518
|
-
menuNameTableDeleteRow: strings.richTextDeleteRowMenu,
|
10519
|
-
menuNameTableDeleteTable: strings.richTextDeleteTableMenu
|
10851
|
+
key: key,
|
10852
|
+
disabled: true,
|
10853
|
+
// show the item correctly for the overflow menu
|
10854
|
+
itemType: react.ContextualMenuItemType.Divider,
|
10855
|
+
// this is still needed to remove checkmark icon space even though it is a divider
|
10856
|
+
canCheck: false,
|
10857
|
+
onRender: () => React.createElement(react.Icon, { iconName: "RichTextDividerIcon", className: ribbonDividerStyle(theme) })
|
10520
10858
|
};
|
10521
10859
|
};
|
10522
10860
|
|
10523
|
-
// Copyright (c) Microsoft Corporation.
|
10524
|
-
// Licensed under the MIT License.
|
10525
|
-
const onClick = (key, editor) => {
|
10526
|
-
editor.focus();
|
10527
|
-
const operation = TableEditOperationMap[key];
|
10528
|
-
if (typeof operation === 'number') {
|
10529
|
-
roosterjsEditorApi.editTable(editor, operation);
|
10530
|
-
}
|
10531
|
-
};
|
10532
|
-
const TableEditOperationMap = {
|
10533
|
-
menuNameTableInsertAbove: roosterjsEditorTypesCompatible.CompatibleTableOperation.InsertAbove,
|
10534
|
-
menuNameTableInsertBelow: roosterjsEditorTypesCompatible.CompatibleTableOperation.InsertBelow,
|
10535
|
-
menuNameTableInsertLeft: roosterjsEditorTypesCompatible.CompatibleTableOperation.InsertLeft,
|
10536
|
-
menuNameTableInsertRight: roosterjsEditorTypesCompatible.CompatibleTableOperation.InsertRight,
|
10537
|
-
menuNameTableDeleteTable: roosterjsEditorTypesCompatible.CompatibleTableOperation.DeleteTable,
|
10538
|
-
menuNameTableDeleteColumn: roosterjsEditorTypesCompatible.CompatibleTableOperation.DeleteColumn,
|
10539
|
-
menuNameTableDeleteRow: roosterjsEditorTypesCompatible.CompatibleTableOperation.DeleteRow
|
10540
|
-
};
|
10541
|
-
const tableEditInsertMenuItem = {
|
10542
|
-
key: 'menuNameTableInsert',
|
10543
|
-
unlocalizedText: 'Insert',
|
10544
|
-
subItems: {
|
10545
|
-
menuNameTableInsertAbove: 'Insert above',
|
10546
|
-
menuNameTableInsertBelow: 'Insert below',
|
10547
|
-
menuNameTableInsertLeft: 'Insert left',
|
10548
|
-
menuNameTableInsertRight: 'Insert right'
|
10549
|
-
},
|
10550
|
-
onClick,
|
10551
|
-
iconProps: {
|
10552
|
-
iconName: 'RichTextTableInsertMenuIcon',
|
10553
|
-
styles: { root: tableContextMenuIconStyles }
|
10554
|
-
}
|
10555
|
-
};
|
10556
|
-
const tableEditDeleteMenuItem = {
|
10557
|
-
key: 'menuNameTableDelete',
|
10558
|
-
unlocalizedText: 'Delete',
|
10559
|
-
subItems: {
|
10560
|
-
menuNameTableDeleteColumn: 'Delete column',
|
10561
|
-
menuNameTableDeleteRow: 'Delete row',
|
10562
|
-
menuNameTableDeleteTable: 'Delete table'
|
10563
|
-
},
|
10564
|
-
onClick,
|
10565
|
-
iconProps: {
|
10566
|
-
iconName: 'RichTextTableDeleteMenuIcon',
|
10567
|
-
styles: { root: tableContextMenuIconStyles }
|
10568
|
-
}
|
10569
|
-
};
|
10570
|
-
const tableActions = [tableEditInsertMenuItem, tableEditDeleteMenuItem];
|
10571
|
-
/**
|
10572
|
-
* Create a new instance of ContextMenuProvider to support table editing functionalities in context menu
|
10573
|
-
* @returns A new ContextMenuProvider
|
10574
|
-
*/
|
10575
|
-
const createTableEditMenuProvider = (strings) => {
|
10576
|
-
return roosterjsReact.createContextMenuProvider('tableEdit', tableActions, tableContextMenuStrings(strings !== null && strings !== void 0 ? strings : {}), (editor, node) => !!getEditingTable(editor, node));
|
10577
|
-
};
|
10578
|
-
const getEditingTable = (editor, node) => {
|
10579
|
-
const td = editor.getElementAtCursor('TD,TH', node);
|
10580
|
-
const table = td && editor.getElementAtCursor('table', td);
|
10581
|
-
return (table === null || table === void 0 ? void 0 : table.isContentEditable) ? { table, td } : null;
|
10582
|
-
};
|
10583
|
-
|
10584
10861
|
// Copyright (c) Microsoft Corporation.
|
10585
10862
|
// Licensed under the MIT License.
|
10586
10863
|
/**
|
10587
|
-
*
|
10864
|
+
* KeyboardInputPlugin is a plugin for handling keyboard events in the editor.
|
10588
10865
|
*/
|
10589
|
-
class
|
10866
|
+
class RichTextToolbarPlugin {
|
10590
10867
|
constructor() {
|
10868
|
+
this.formatState = null;
|
10591
10869
|
this.editor = null;
|
10870
|
+
this.onFormatChanged = null;
|
10592
10871
|
}
|
10593
10872
|
getName() {
|
10594
|
-
return '
|
10873
|
+
return 'RichTextToolbarPlugin';
|
10595
10874
|
}
|
10596
10875
|
initialize(editor) {
|
10597
10876
|
this.editor = editor;
|
10598
10877
|
}
|
10599
|
-
dispose() {
|
10878
|
+
dispose() {
|
10879
|
+
this.editor = null;
|
10880
|
+
}
|
10600
10881
|
onPluginEvent(event) {
|
10601
|
-
|
10602
|
-
|
10603
|
-
|
10604
|
-
|
10882
|
+
switch (event.eventType) {
|
10883
|
+
// KeyDown and MouseUp are used to update the state when the editor is already shown and focused by the user
|
10884
|
+
case PluginEventType.EditorReady:
|
10885
|
+
case PluginEventType.ContentChanged:
|
10886
|
+
case PluginEventType.ZoomChanged:
|
10887
|
+
case PluginEventType.KeyDown:
|
10888
|
+
case PluginEventType.MouseUp:
|
10889
|
+
this.updateFormat();
|
10890
|
+
break;
|
10891
|
+
}
|
10892
|
+
}
|
10893
|
+
/**
|
10894
|
+
* Handles the click event of a toolbar button.
|
10895
|
+
* @param buttonAction - The action to be performed when the button is clicked.
|
10896
|
+
*/
|
10897
|
+
onToolbarButtonClick(buttonAction) {
|
10898
|
+
if (this.editor && !this.editor.isDisposed()) {
|
10899
|
+
buttonAction(this.editor);
|
10900
|
+
this.updateFormat();
|
10901
|
+
}
|
10902
|
+
}
|
10903
|
+
/**
|
10904
|
+
* Updates the format state of the rich text editor and triggers the `onFormatChanged` callback
|
10905
|
+
* if there is any difference between the new and the current format states.
|
10906
|
+
*/
|
10907
|
+
updateFormat() {
|
10908
|
+
if (this.editor && this.onFormatChanged) {
|
10909
|
+
const newFormatState = roosterjsContentModelApi.getFormatState(this.editor);
|
10910
|
+
// use keys from the format that has more keys or the new format state if there is no current format state
|
10911
|
+
const keys = !this.formatState || roosterjsContentModelDom.getObjectKeys(newFormatState).length > roosterjsContentModelDom.getObjectKeys(this.formatState).length
|
10912
|
+
? roosterjsContentModelDom.getObjectKeys(newFormatState)
|
10913
|
+
: roosterjsContentModelDom.getObjectKeys(this.formatState);
|
10914
|
+
// check if there is any difference between the new format state and the current format state
|
10915
|
+
// otherwise the states will produce new objects every time even when the format state is the same
|
10916
|
+
if (!this.formatState || keys.some((key) => { var _a; return newFormatState[key] !== ((_a = this.formatState) === null || _a === void 0 ? void 0 : _a[key]); })) {
|
10917
|
+
this.formatState = newFormatState;
|
10918
|
+
this.onFormatChanged(newFormatState);
|
10919
|
+
}
|
10605
10920
|
}
|
10606
10921
|
}
|
10607
10922
|
}
|
10923
|
+
|
10924
|
+
// Copyright (c) Microsoft Corporation.
|
10925
|
+
// Licensed under the MIT License.
|
10608
10926
|
/**
|
10609
|
-
*
|
10610
|
-
* Exported only for unit testing
|
10927
|
+
* Represents a plugin that adds a context menu to the rich text editor.
|
10611
10928
|
*/
|
10612
|
-
|
10613
|
-
|
10614
|
-
|
10615
|
-
|
10616
|
-
|
10617
|
-
|
10618
|
-
|
10619
|
-
|
10620
|
-
|
10621
|
-
|
10929
|
+
class ContextMenuPlugin extends roosterjsContentModelPlugins.ContextMenuPluginBase {
|
10930
|
+
constructor(onRender, onDismiss) {
|
10931
|
+
super({
|
10932
|
+
/**
|
10933
|
+
* Renders the context menu in the specified container with the provided items.
|
10934
|
+
* @param container - The container element where the context menu should be rendered.
|
10935
|
+
* @param items - The items to be displayed in the context menu.
|
10936
|
+
* @param onDismiss - Callback function to be called when the context menu is dismissed. It will call `dismiss` method.
|
10937
|
+
*/
|
10938
|
+
render: (container, items, onDismissCallback) => {
|
10939
|
+
const filteredItems = items.filter((item) => item !== null);
|
10940
|
+
onRender(container, filteredItems, onDismissCallback);
|
10941
|
+
},
|
10942
|
+
/**
|
10943
|
+
* Dismisses the context menu.
|
10944
|
+
*/
|
10945
|
+
dismiss: () => {
|
10946
|
+
onDismiss();
|
10622
10947
|
}
|
10623
|
-
currentNode === null || currentNode === void 0 ? void 0 : currentNode.remove();
|
10624
10948
|
});
|
10625
10949
|
}
|
10626
|
-
}
|
10950
|
+
}
|
10951
|
+
|
10627
10952
|
/**
|
10628
|
-
*
|
10629
|
-
* @param event - The plugin event.
|
10630
|
-
* @param editor - The editor instance.
|
10953
|
+
* Provides a context menu for editing tables in the rich text editor.
|
10631
10954
|
*/
|
10632
|
-
|
10633
|
-
|
10634
|
-
|
10635
|
-
|
10636
|
-
|
10637
|
-
|
10638
|
-
|
10639
|
-
|
10640
|
-
|
10641
|
-
|
10642
|
-
|
10643
|
-
|
10644
|
-
|
10645
|
-
|
10646
|
-
|
10647
|
-
|
10648
|
-
|
10649
|
-
|
10650
|
-
|
10651
|
-
|
10652
|
-
|
10653
|
-
|
10654
|
-
|
10655
|
-
|
10955
|
+
class TableEditContextMenuProvider {
|
10956
|
+
constructor() {
|
10957
|
+
this.editor = null;
|
10958
|
+
this.strings = {};
|
10959
|
+
this.items = null;
|
10960
|
+
}
|
10961
|
+
updateStrings(strings) {
|
10962
|
+
this.strings = strings;
|
10963
|
+
if (this.editor) {
|
10964
|
+
this.items = getTableEditContextMenuItems(this.editor, this.strings);
|
10965
|
+
}
|
10966
|
+
}
|
10967
|
+
getName() {
|
10968
|
+
return 'TableEditContextMenuProvider';
|
10969
|
+
}
|
10970
|
+
initialize(editor) {
|
10971
|
+
this.editor = editor;
|
10972
|
+
this.items = getTableEditContextMenuItems(editor, this.strings);
|
10973
|
+
}
|
10974
|
+
/**
|
10975
|
+
* Dispose this plugin
|
10976
|
+
*/
|
10977
|
+
dispose() {
|
10978
|
+
this.editor = null;
|
10979
|
+
}
|
10980
|
+
getContextMenuItems(node) {
|
10981
|
+
// return this.items;
|
10982
|
+
if (this.editor && isTableEditable(this.editor, node)) {
|
10983
|
+
return this.items;
|
10984
|
+
}
|
10985
|
+
else {
|
10986
|
+
return null;
|
10656
10987
|
}
|
10657
10988
|
}
|
10989
|
+
}
|
10990
|
+
const isTableEditable = (editor, node) => {
|
10991
|
+
const domHelper = editor.getDOMHelper();
|
10992
|
+
const td = domHelper.findClosestElementAncestor(node, 'TD,TH');
|
10993
|
+
const table = td && domHelper.findClosestElementAncestor(td, 'table');
|
10994
|
+
return (table === null || table === void 0 ? void 0 : table.isContentEditable) === true;
|
10658
10995
|
};
|
10659
10996
|
|
10997
|
+
// Copyright (c) Microsoft Corporation.
|
10998
|
+
// Licensed under the MIT License.
|
10999
|
+
/**
|
11000
|
+
* PlaceholderPlugin is a plugin for displaying placeholder and handle localization for it in the editor.
|
11001
|
+
*/
|
11002
|
+
class PlaceholderPlugin extends roosterjsContentModelPlugins.WatermarkPlugin {
|
11003
|
+
constructor() {
|
11004
|
+
super(...arguments);
|
11005
|
+
this.isPlaceholderShown = false;
|
11006
|
+
this.editorValue = null;
|
11007
|
+
}
|
11008
|
+
updatePlaceholder(placeholder) {
|
11009
|
+
this.watermark = placeholder;
|
11010
|
+
// hide and show the placeholder to show the latest one
|
11011
|
+
// this needs to be done only if the placeholder is currently shown
|
11012
|
+
if (this.editorValue && this.isPlaceholderShown) {
|
11013
|
+
this.hide(this.editorValue);
|
11014
|
+
this.show(this.editorValue);
|
11015
|
+
}
|
11016
|
+
}
|
11017
|
+
initialize(editor) {
|
11018
|
+
this.editorValue = editor;
|
11019
|
+
super.initialize(editor);
|
11020
|
+
}
|
11021
|
+
dispose() {
|
11022
|
+
this.editorValue = null;
|
11023
|
+
super.dispose();
|
11024
|
+
}
|
11025
|
+
show(editor) {
|
11026
|
+
super.show(editor);
|
11027
|
+
this.isPlaceholderShown = true;
|
11028
|
+
}
|
11029
|
+
hide(editor) {
|
11030
|
+
super.hide(editor);
|
11031
|
+
this.isPlaceholderShown = false;
|
11032
|
+
}
|
11033
|
+
}
|
11034
|
+
|
10660
11035
|
// Copyright (c) Microsoft Corporation.
|
10661
11036
|
// Licensed under the MIT License.
|
10662
11037
|
/**
|
@@ -10665,10 +11040,11 @@ const scrollToBottomAfterContentPaste = (event, editor) => {
|
|
10665
11040
|
* @beta
|
10666
11041
|
*/
|
10667
11042
|
const RichTextEditor = React.forwardRef((props, ref) => {
|
10668
|
-
const { initialContent, onChange, placeholderText, strings, showRichTextEditorFormatting,
|
11043
|
+
const { initialContent, onChange, placeholderText, strings, showRichTextEditorFormatting, autoFocus, onKeyDown, onContentModelUpdate, contentModel } = props;
|
10669
11044
|
const editor = React.useRef(null);
|
10670
|
-
const
|
11045
|
+
const editorDiv = React.useRef(null);
|
10671
11046
|
const theme = useTheme();
|
11047
|
+
const [contextMenuProps, setContextMenuProps] = React.useState(null);
|
10672
11048
|
React.useImperativeHandle(ref, () => {
|
10673
11049
|
return {
|
10674
11050
|
focus() {
|
@@ -10678,108 +11054,179 @@ const RichTextEditor = React.forwardRef((props, ref) => {
|
|
10678
11054
|
},
|
10679
11055
|
setEmptyContent() {
|
10680
11056
|
if (editor.current) {
|
10681
|
-
editor
|
11057
|
+
// remove all content from the editor and update the model
|
11058
|
+
// ContentChanged event will be sent by RoosterJS automatically
|
11059
|
+
editor.current.formatContentModel((model) => {
|
11060
|
+
model.blocks = [];
|
11061
|
+
return true;
|
11062
|
+
});
|
11063
|
+
//reset content model
|
11064
|
+
onContentModelUpdate && onContentModelUpdate(undefined);
|
10682
11065
|
}
|
10683
11066
|
},
|
10684
11067
|
getPlainContent() {
|
10685
|
-
|
10686
|
-
|
11068
|
+
if (editor.current) {
|
11069
|
+
return roosterjsContentModelCore.exportContent(editor.current, 'PlainTextFast');
|
11070
|
+
}
|
11071
|
+
else {
|
11072
|
+
return undefined;
|
11073
|
+
}
|
10687
11074
|
}
|
10688
11075
|
};
|
11076
|
+
}, [onContentModelUpdate]);
|
11077
|
+
const toolbarPlugin = React.useMemo(() => {
|
11078
|
+
return new RichTextToolbarPlugin();
|
10689
11079
|
}, []);
|
10690
|
-
const
|
10691
|
-
return
|
10692
|
-
}, []);
|
10693
|
-
|
10694
|
-
|
10695
|
-
|
10696
|
-
|
10697
|
-
if (contentValue.current !== undefined && contentValue.current.length > 0) {
|
10698
|
-
// in case if initialContent is not empty, RoosterJS doesn't set caret position to the end.
|
10699
|
-
focusAndUpdateContent(editorValue, contentValue.current);
|
10700
|
-
}
|
10701
|
-
else if (initialContent !== undefined && initialContent.length > 0) {
|
10702
|
-
// changing layout in rich text send box cause the editor to be recreated
|
10703
|
-
// to keep the content, we need to set messageContent to the current content
|
10704
|
-
focusAndUpdateContent(editorValue, initialContent);
|
10705
|
-
}
|
10706
|
-
editor.current = editorValue;
|
10707
|
-
return editorValue;
|
10708
|
-
},
|
10709
|
-
// trigger force editor reset when strings are changed to update context menu strings
|
10710
|
-
// see RosterJS documentation for 'editorCreator' for more details
|
10711
|
-
// the editorCreator callback shouldn't be updated when the initialContent is changed
|
10712
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
10713
|
-
[strings]);
|
11080
|
+
const isDarkThemedValue = React.useMemo(() => {
|
11081
|
+
return isDarkThemed(theme);
|
11082
|
+
}, [theme]);
|
11083
|
+
React.useEffect(() => {
|
11084
|
+
var _a;
|
11085
|
+
(_a = editor.current) === null || _a === void 0 ? void 0 : _a.setDarkModeState(isDarkThemedValue);
|
11086
|
+
}, [isDarkThemedValue]);
|
10714
11087
|
const placeholderPlugin = React.useMemo(() => {
|
10715
|
-
return new
|
11088
|
+
return new PlaceholderPlugin('');
|
10716
11089
|
}, []);
|
10717
11090
|
React.useEffect(() => {
|
10718
11091
|
if (placeholderText !== undefined) {
|
10719
|
-
placeholderPlugin.
|
11092
|
+
placeholderPlugin.updatePlaceholder(placeholderText);
|
10720
11093
|
}
|
10721
11094
|
}, [placeholderPlugin, placeholderText]);
|
10722
|
-
const
|
10723
|
-
|
10724
|
-
|
10725
|
-
|
10726
|
-
|
10727
|
-
|
10728
|
-
|
11095
|
+
const toolbar = React.useMemo(() => {
|
11096
|
+
return React.createElement(RichTextToolbar, { plugin: toolbarPlugin, strings: strings });
|
11097
|
+
}, [strings, toolbarPlugin]);
|
11098
|
+
const updatePlugin = React.useMemo(() => {
|
11099
|
+
return new UpdateContentPlugin();
|
11100
|
+
}, []);
|
11101
|
+
React.useEffect(() => {
|
11102
|
+
// don't set callback in plugin constructor to update callback without plugin recreation
|
11103
|
+
updatePlugin.onUpdate = (event) => {
|
11104
|
+
if (editor.current === null) {
|
11105
|
+
return;
|
11106
|
+
}
|
11107
|
+
if (event === UpdateEvent.Blur || event === UpdateEvent.Dispose) {
|
11108
|
+
onContentModelUpdate && onContentModelUpdate(editor.current.getContentModelCopy('disconnected'));
|
11109
|
+
}
|
11110
|
+
else {
|
11111
|
+
onChange && onChange(roosterjsContentModelCore.exportContent(editor.current));
|
11112
|
+
}
|
11113
|
+
};
|
11114
|
+
}, [onChange, onContentModelUpdate, updatePlugin]);
|
11115
|
+
const keyboardInputPlugin = React.useMemo(() => {
|
11116
|
+
return new KeyboardInputPlugin();
|
11117
|
+
}, []);
|
11118
|
+
React.useEffect(() => {
|
11119
|
+
// don't set callback in plugin constructor to update callback without plugin recreation
|
11120
|
+
keyboardInputPlugin.onKeyDown = onKeyDown;
|
11121
|
+
}, [keyboardInputPlugin, onKeyDown]);
|
11122
|
+
const tableContextMenuPlugin = React.useMemo(() => {
|
11123
|
+
return new TableEditContextMenuProvider();
|
11124
|
+
}, []);
|
11125
|
+
React.useEffect(() => {
|
11126
|
+
tableContextMenuPlugin.updateStrings(strings);
|
11127
|
+
}, [tableContextMenuPlugin, strings]);
|
11128
|
+
const onContextMenuRender = React.useCallback((container, items, onDismiss) => {
|
11129
|
+
setContextMenuProps({
|
11130
|
+
items: items,
|
11131
|
+
target: container,
|
11132
|
+
onDismiss: onDismiss
|
10729
11133
|
});
|
11134
|
+
}, []);
|
11135
|
+
const onContextMenuDismiss = React.useCallback(() => {
|
11136
|
+
setContextMenuProps(null);
|
11137
|
+
}, []);
|
11138
|
+
const plugins = React.useMemo(() => {
|
11139
|
+
const contentEdit = new roosterjsContentModelPlugins.EditPlugin();
|
11140
|
+
// AutoFormatPlugin previously was a part of the edit plugin
|
11141
|
+
const autoFormatPlugin = new roosterjsContentModelPlugins.AutoFormatPlugin({ autoBullet: true, autoNumbering: true, autoLink: true });
|
10730
11142
|
const copyPastePlugin = new CopyPastePlugin();
|
11143
|
+
const roosterPastePlugin = new roosterjsContentModelPlugins.PastePlugin(false);
|
11144
|
+
const shortcutPlugin = new roosterjsContentModelPlugins.ShortcutPlugin();
|
11145
|
+
const contextMenuPlugin = new ContextMenuPlugin(onContextMenuRender, onContextMenuDismiss);
|
10731
11146
|
return [
|
10732
|
-
contentEdit,
|
10733
11147
|
placeholderPlugin,
|
10734
|
-
|
10735
|
-
|
10736
|
-
|
10737
|
-
|
10738
|
-
copyPastePlugin
|
11148
|
+
keyboardInputPlugin,
|
11149
|
+
contentEdit,
|
11150
|
+
autoFormatPlugin,
|
11151
|
+
updatePlugin,
|
11152
|
+
copyPastePlugin,
|
11153
|
+
roosterPastePlugin,
|
11154
|
+
toolbarPlugin,
|
11155
|
+
shortcutPlugin,
|
11156
|
+
// contextPlugin and tableEditMenuProvider allow to show insert/delete menu for the table
|
11157
|
+
contextMenuPlugin,
|
11158
|
+
tableContextMenuPlugin
|
10739
11159
|
];
|
10740
|
-
}, [
|
10741
|
-
|
10742
|
-
|
10743
|
-
|
10744
|
-
|
10745
|
-
|
10746
|
-
|
10747
|
-
|
10748
|
-
|
11160
|
+
}, [
|
11161
|
+
onContextMenuRender,
|
11162
|
+
onContextMenuDismiss,
|
11163
|
+
placeholderPlugin,
|
11164
|
+
keyboardInputPlugin,
|
11165
|
+
updatePlugin,
|
11166
|
+
toolbarPlugin,
|
11167
|
+
tableContextMenuPlugin
|
11168
|
+
]);
|
11169
|
+
React.useEffect(() => {
|
11170
|
+
var _a;
|
11171
|
+
const initialModel = createEditorInitialModel(initialContent, contentModel);
|
11172
|
+
if (editorDiv.current) {
|
11173
|
+
editor.current = new roosterjsContentModelCore.Editor(editorDiv.current, {
|
11174
|
+
inDarkMode: isDarkThemedValue,
|
11175
|
+
// doNotAdjustEditorColor is used to disable default color and background color for Rooster component
|
11176
|
+
doNotAdjustEditorColor: true,
|
11177
|
+
// TODO: confirm the color during inline images implementation
|
11178
|
+
imageSelectionBorderColor: 'blue',
|
11179
|
+
plugins: plugins,
|
11180
|
+
initialModel: initialModel,
|
11181
|
+
defaultModelToDomOptions: {
|
11182
|
+
formatApplierOverride: {
|
11183
|
+
// apply border and dataset formats for table
|
11184
|
+
border: borderApplier,
|
11185
|
+
dataset: dataSetApplier
|
11186
|
+
}
|
10749
11187
|
}
|
10750
|
-
}
|
10751
|
-
|
10752
|
-
|
10753
|
-
|
10754
|
-
|
10755
|
-
|
10756
|
-
|
10757
|
-
|
11188
|
+
});
|
11189
|
+
}
|
11190
|
+
if (autoFocus === 'sendBoxTextField') {
|
11191
|
+
(_a = editor.current) === null || _a === void 0 ? void 0 : _a.focus();
|
11192
|
+
}
|
11193
|
+
return () => {
|
11194
|
+
if (editor.current) {
|
11195
|
+
editor.current.dispose();
|
11196
|
+
editor.current = null;
|
11197
|
+
}
|
10758
11198
|
};
|
11199
|
+
// don't update the editor on deps update as everything is handled in separate hooks or plugins
|
11200
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
10759
11201
|
}, []);
|
10760
11202
|
return (React.createElement("div", { "data-testid": 'rich-text-editor-wrapper' },
|
10761
|
-
showRichTextEditorFormatting &&
|
11203
|
+
showRichTextEditorFormatting && toolbar,
|
10762
11204
|
React.createElement("div", { className: richTextEditorWrapperStyle(theme, !showRichTextEditorFormatting) },
|
10763
|
-
React.createElement(
|
10764
|
-
|
10765
|
-
imageSelectionBorderColor: 'blue',
|
10766
|
-
// doNotAdjustEditorColor is used to fix the default background color for Rooster component
|
10767
|
-
doNotAdjustEditorColor: true, "data-testid": 'rooster-rich-text-editor',
|
10768
|
-
// if we don't use 'allowKeyboardEventPropagation' only the enter key is caught
|
10769
|
-
onKeyDown: props.onKeyDown, focusOnInit: autoFocus === 'sendBoxTextField' }))));
|
11205
|
+
React.createElement("div", { ref: editorDiv, tabIndex: 0, role: "textbox", "aria-multiline": "true", "data-testid": 'rooster-rich-text-editor', className: richTextEditorStyle(props.styles) })),
|
11206
|
+
contextMenuProps && React.createElement(react.ContextualMenu, Object.assign({}, contextMenuProps, { calloutProps: { isBeakVisible: false } }))));
|
10770
11207
|
});
|
10771
|
-
const
|
10772
|
-
|
10773
|
-
|
10774
|
-
|
10775
|
-
|
10776
|
-
|
10777
|
-
|
10778
|
-
|
10779
|
-
|
10780
|
-
|
10781
|
-
|
10782
|
-
|
11208
|
+
const createEditorInitialModel = (initialContent, contentModel) => {
|
11209
|
+
if (contentModel) {
|
11210
|
+
// contentModel is the current content of the editor
|
11211
|
+
return contentModel;
|
11212
|
+
}
|
11213
|
+
else {
|
11214
|
+
const initialContentValue = initialContent;
|
11215
|
+
const initialModel = initialContentValue && initialContentValue.length > 0 ? roosterjsContentModelCore.createModelFromHtml(initialContentValue) : undefined;
|
11216
|
+
if (initialModel && initialModel.blocks.length > 0) {
|
11217
|
+
// lastBlock should have blockType = paragraph, otherwise add a new paragraph
|
11218
|
+
// to set focus to the end of the content
|
11219
|
+
let lastBlock = initialModel.blocks[initialModel.blocks.length - 1];
|
11220
|
+
if ((lastBlock === null || lastBlock === void 0 ? void 0 : lastBlock.blockType) === 'Paragraph') ;
|
11221
|
+
else {
|
11222
|
+
lastBlock = roosterjsContentModelDom.createParagraph(true);
|
11223
|
+
initialModel.blocks.push(lastBlock);
|
11224
|
+
}
|
11225
|
+
const marker = roosterjsContentModelDom.createSelectionMarker();
|
11226
|
+
lastBlock.segments.push(marker);
|
11227
|
+
roosterjsContentModelDom.setSelection(initialModel, marker);
|
11228
|
+
}
|
11229
|
+
return initialModel;
|
10783
11230
|
}
|
10784
11231
|
};
|
10785
11232
|
|
@@ -10825,37 +11272,50 @@ const RichTextInputBoxComponent = (props) => {
|
|
10825
11272
|
/* @conditional-compile-remove(attachment-upload) */
|
10826
11273
|
onRenderAttachmentUploads,
|
10827
11274
|
/* @conditional-compile-remove(attachment-upload) */
|
10828
|
-
hasAttachments, richTextEditorStyleProps, isHorizontalLayoutDisabled = false,
|
11275
|
+
hasAttachments, richTextEditorStyleProps, isHorizontalLayoutDisabled = false, autoFocus, onTyping } = props;
|
10829
11276
|
const theme = useTheme();
|
10830
|
-
|
10831
|
-
const
|
11277
|
+
// undefined is used to indicate that the rich text editor toolbar state wasn't changed yet
|
11278
|
+
const [showRichTextEditorFormatting, setShowRichTextEditorFormatting] = React.useState(undefined);
|
11279
|
+
const [contentModel, setContentModel] = React.useState(undefined);
|
11280
|
+
const onRenderRichTextEditorIcon = React.useCallback((isHover) => {
|
11281
|
+
const isRichTextEditorToolbarShown = showRichTextEditorFormatting === true;
|
11282
|
+
return (React.createElement(react.Icon, { iconName: isHover || isRichTextEditorToolbarShown ? 'RichTextEditorButtonIconFilled' : 'RichTextEditorButtonIcon', className: richTextFormatButtonIconStyle(theme, !disabled && (isHover || isRichTextEditorToolbarShown)) }));
|
11283
|
+
}, [disabled, showRichTextEditorFormatting, theme]);
|
11284
|
+
React.useEffect(() => {
|
11285
|
+
var _a;
|
11286
|
+
if (showRichTextEditorFormatting !== undefined) {
|
11287
|
+
// Focus the editor when toolbar shown/hidden
|
11288
|
+
(_a = editorComponentRef.current) === null || _a === void 0 ? void 0 : _a.focus();
|
11289
|
+
}
|
11290
|
+
// we don't need execute this useEffect if editorComponentRef is changed
|
11291
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
11292
|
+
}, [showRichTextEditorFormatting]);
|
10832
11293
|
const actionButtons = React.useMemo(() => {
|
10833
11294
|
return (React.createElement(react.Stack.Item, { align: "end", className: richTextActionButtonsStackStyle },
|
10834
11295
|
React.createElement(react.Stack, { horizontal: true },
|
10835
11296
|
React.createElement(InputBoxButton, { onRenderIcon: onRenderRichTextEditorIcon, onClick: (e) => {
|
10836
|
-
|
10837
|
-
setShowRichTextEditorFormatting(!
|
10838
|
-
(_a = editorComponentRef.current) === null || _a === void 0 ? void 0 : _a.focus();
|
11297
|
+
const isRichTextEditorToolbarShown = showRichTextEditorFormatting === true;
|
11298
|
+
setShowRichTextEditorFormatting(!isRichTextEditorToolbarShown);
|
10839
11299
|
e.stopPropagation(); // Prevents the click from bubbling up and triggering a focus event on the chat.
|
10840
11300
|
}, ariaLabel: strings.richTextFormatButtonTooltip, tooltipContent: strings.richTextFormatButtonTooltip, className: richTextActionButtonsStyle, "data-testId": 'rich-text-input-box-format-button' }),
|
10841
11301
|
React.createElement(react.Icon, { iconName: "RichTextDividerIcon", className: richTextActionButtonsDividerStyle(theme) }),
|
10842
11302
|
actionComponents)));
|
10843
11303
|
}, [
|
10844
11304
|
actionComponents,
|
10845
|
-
editorComponentRef,
|
10846
11305
|
onRenderRichTextEditorIcon,
|
10847
11306
|
showRichTextEditorFormatting,
|
10848
11307
|
strings.richTextFormatButtonTooltip,
|
10849
11308
|
theme
|
10850
11309
|
]);
|
10851
11310
|
const richTextEditorStyle = React.useMemo(() => {
|
10852
|
-
return richTextEditorStyleProps(showRichTextEditorFormatting);
|
11311
|
+
return richTextEditorStyleProps(showRichTextEditorFormatting === true);
|
10853
11312
|
}, [richTextEditorStyleProps, showRichTextEditorFormatting]);
|
10854
11313
|
const onKeyDown = React.useCallback((ev) => {
|
10855
11314
|
if (isEnterKeyEventFromCompositionSession(ev)) {
|
10856
11315
|
return;
|
10857
11316
|
}
|
10858
|
-
|
11317
|
+
const isRichTextEditorToolbarShown = showRichTextEditorFormatting === true;
|
11318
|
+
if (ev.key === 'Enter' && ev.shiftKey === false && !isRichTextEditorToolbarShown) {
|
10859
11319
|
ev.preventDefault();
|
10860
11320
|
onEnterKeyDown && onEnterKeyDown();
|
10861
11321
|
}
|
@@ -10864,14 +11324,18 @@ const RichTextInputBoxComponent = (props) => {
|
|
10864
11324
|
}
|
10865
11325
|
}, [onEnterKeyDown, showRichTextEditorFormatting, onTyping]);
|
10866
11326
|
const useHorizontalLayout = React.useMemo(() => {
|
11327
|
+
const isRichTextEditorToolbarShown = showRichTextEditorFormatting === true;
|
10867
11328
|
return (!isHorizontalLayoutDisabled &&
|
10868
|
-
!
|
11329
|
+
!isRichTextEditorToolbarShown &&
|
10869
11330
|
/* @conditional-compile-remove(attachment-upload) */ !hasAttachments);
|
10870
11331
|
}, [
|
10871
11332
|
isHorizontalLayoutDisabled,
|
10872
11333
|
showRichTextEditorFormatting,
|
10873
11334
|
/* @conditional-compile-remove(attachment-upload) */ hasAttachments
|
10874
11335
|
]);
|
11336
|
+
const onContentModelUpdate = React.useCallback((contentModel) => {
|
11337
|
+
setContentModel(contentModel);
|
11338
|
+
}, []);
|
10875
11339
|
return (React.createElement("div", { className: richTextBorderBoxStyle({
|
10876
11340
|
theme: theme,
|
10877
11341
|
disabled: !!disabled
|
@@ -10879,7 +11343,7 @@ const RichTextInputBoxComponent = (props) => {
|
|
10879
11343
|
React.createElement(react.Stack, { grow: true, horizontal: useHorizontalLayout, horizontalAlign: useHorizontalLayout ? 'end' : 'space-between', className: inputBoxContentStackStyle, wrap: useHorizontalLayout },
|
10880
11344
|
React.createElement(react.Stack, { grow: true, className: inputBoxRichTextStackStyle },
|
10881
11345
|
React.createElement(react.Stack.Item, { className: inputBoxRichTextStackItemStyle },
|
10882
|
-
React.createElement(RichTextEditor, {
|
11346
|
+
React.createElement(RichTextEditor, { contentModel: contentModel, initialContent: initialContent, placeholderText: placeholderText, onChange: onChange, onKeyDown: onKeyDown, ref: editorComponentRef, strings: strings, showRichTextEditorFormatting: showRichTextEditorFormatting === true, styles: richTextEditorStyle, autoFocus: autoFocus, onContentModelUpdate: onContentModelUpdate })),
|
10883
11347
|
/* @conditional-compile-remove(attachment-upload) */ onRenderAttachmentUploads &&
|
10884
11348
|
onRenderAttachmentUploads()),
|
10885
11349
|
actionButtons)));
|
@@ -10986,6 +11450,13 @@ const RichTextSendBox = (props) => {
|
|
10986
11450
|
setContentValueOverflow(isMessageTooLong(newValue.length));
|
10987
11451
|
setContentValue(newValue);
|
10988
11452
|
}, []);
|
11453
|
+
const hasContent = React.useMemo(() => {
|
11454
|
+
var _a;
|
11455
|
+
// get plain text content from the editor to check if the message is empty
|
11456
|
+
// as the content may contain tags even when the content is empty
|
11457
|
+
const plainTextContent = (_a = editorComponentRef.current) === null || _a === void 0 ? void 0 : _a.getPlainContent();
|
11458
|
+
return sanitizeText(contentValue !== null && contentValue !== void 0 ? contentValue : '').length > 0 && sanitizeText(plainTextContent !== null && plainTextContent !== void 0 ? plainTextContent : '').length > 0;
|
11459
|
+
}, [contentValue]);
|
10989
11460
|
/* @conditional-compile-remove(attachment-upload) */
|
10990
11461
|
const toAttachmentMetadata = React.useCallback((attachmentsWithProgress) => {
|
10991
11462
|
return attachmentsWithProgress === null || attachmentsWithProgress === void 0 ? void 0 : attachmentsWithProgress.filter((attachment) => {
|
@@ -11001,7 +11472,7 @@ const RichTextSendBox = (props) => {
|
|
11001
11472
|
});
|
11002
11473
|
}, []);
|
11003
11474
|
const sendMessageOnClick = React.useCallback(() => {
|
11004
|
-
var _a, _b
|
11475
|
+
var _a, _b;
|
11005
11476
|
if (disabled || contentValueOverflow) {
|
11006
11477
|
return;
|
11007
11478
|
}
|
@@ -11014,14 +11485,6 @@ const RichTextSendBox = (props) => {
|
|
11014
11485
|
return;
|
11015
11486
|
}
|
11016
11487
|
const message = contentValue;
|
11017
|
-
// get plain text content from the editor to check if the message is empty
|
11018
|
-
// as the content may contain tags even when the content is empty
|
11019
|
-
const plainTextContent = (_a = editorComponentRef.current) === null || _a === void 0 ? void 0 : _a.getPlainContent();
|
11020
|
-
const hasContent = !isContentEmpty({
|
11021
|
-
plainTextContent,
|
11022
|
-
content: message,
|
11023
|
-
placeholder: strings.placeholderText
|
11024
|
-
});
|
11025
11488
|
// we don't want to send empty messages including spaces, newlines, tabs
|
11026
11489
|
// Message can be empty if there is a valid attachment upload
|
11027
11490
|
if (hasContent || /* @conditional-compile-remove(attachment-upload) */ isAttachmentUploadCompleted(attachments)) {
|
@@ -11034,8 +11497,8 @@ const RichTextSendBox = (props) => {
|
|
11034
11497
|
type: 'html'
|
11035
11498
|
});
|
11036
11499
|
setContentValue('');
|
11037
|
-
(
|
11038
|
-
(
|
11500
|
+
(_a = editorComponentRef.current) === null || _a === void 0 ? void 0 : _a.setEmptyContent();
|
11501
|
+
(_b = editorComponentRef.current) === null || _b === void 0 ? void 0 : _b.focus();
|
11039
11502
|
}
|
11040
11503
|
}, [
|
11041
11504
|
disabled,
|
@@ -11043,7 +11506,7 @@ const RichTextSendBox = (props) => {
|
|
11043
11506
|
/* @conditional-compile-remove(attachment-upload) */
|
11044
11507
|
attachments,
|
11045
11508
|
contentValue,
|
11046
|
-
|
11509
|
+
hasContent,
|
11047
11510
|
/* @conditional-compile-remove(attachment-upload) */
|
11048
11511
|
strings.attachmentUploadsPendingError,
|
11049
11512
|
onSendMessage,
|
@@ -11066,17 +11529,6 @@ const RichTextSendBox = (props) => {
|
|
11066
11529
|
attachmentUploadsPendingError,
|
11067
11530
|
systemMessage
|
11068
11531
|
]);
|
11069
|
-
const hasContent = React.useMemo(() => {
|
11070
|
-
var _a;
|
11071
|
-
// get plain text content from the editor to check if the message is empty
|
11072
|
-
// as the content may contain tags even when the content is empty
|
11073
|
-
const plainTextContent = (_a = editorComponentRef.current) === null || _a === void 0 ? void 0 : _a.getPlainContent();
|
11074
|
-
return !isContentEmpty({
|
11075
|
-
plainTextContent: plainTextContent,
|
11076
|
-
content: contentValue,
|
11077
|
-
placeholder: strings.placeholderText
|
11078
|
-
});
|
11079
|
-
}, [contentValue, strings.placeholderText]);
|
11080
11532
|
const onRenderSendIcon = React.useCallback((isHover) => {
|
11081
11533
|
return (React.createElement(react.Icon, { iconName: isHover && hasContent ? 'SendBoxSendHovered' : 'SendBoxSend', className: sendIconStyle({
|
11082
11534
|
theme,
|
@@ -11152,34 +11604,12 @@ const RichTextSendBox = (props) => {
|
|
11152
11604
|
}, [attachments]);
|
11153
11605
|
return (React.createElement(react.Stack, null,
|
11154
11606
|
React.createElement(RichTextSendBoxErrors, Object.assign({}, sendBoxErrorsProps)),
|
11155
|
-
React.createElement(RichTextInputBoxComponent
|
11156
|
-
// in case when format bar is shown, the editor is re-rendered that causes the content to be lost
|
11157
|
-
// setting the content will ensure that the latest content is used when editor is re-rendered
|
11158
|
-
, {
|
11159
|
-
// in case when format bar is shown, the editor is re-rendered that causes the content to be lost
|
11160
|
-
// setting the content will ensure that the latest content is used when editor is re-rendered
|
11161
|
-
content: contentValue, placeholderText: strings.placeholderText, autoFocus: autoFocus, onChange: setContent, onEnterKeyDown: sendMessageOnClick, onTyping: onTyping, editorComponentRef: editorComponentRef, strings: strings, disabled: disabled, actionComponents: sendButton, richTextEditorStyleProps: sendBoxRichTextEditorStyle,
|
11607
|
+
React.createElement(RichTextInputBoxComponent, { placeholderText: strings.placeholderText, autoFocus: autoFocus, onChange: setContent, onEnterKeyDown: sendMessageOnClick, onTyping: onTyping, editorComponentRef: editorComponentRef, strings: strings, disabled: disabled, actionComponents: sendButton, richTextEditorStyleProps: sendBoxRichTextEditorStyle,
|
11162
11608
|
/* @conditional-compile-remove(attachment-upload) */
|
11163
11609
|
onRenderAttachmentUploads: onRenderAttachmentUploads,
|
11164
11610
|
/* @conditional-compile-remove(attachment-upload) */
|
11165
11611
|
hasAttachments: hasAttachmentUploads })));
|
11166
11612
|
};
|
11167
|
-
/**
|
11168
|
-
* Checks if the content of the rich text editor is empty.
|
11169
|
-
*
|
11170
|
-
* @param {Object} params - The parameters for the function.
|
11171
|
-
* @param {string | undefined} params.plainTextContent - The plain text content of the editor.
|
11172
|
-
* @param {string} params.content - The HTML content of the editor.
|
11173
|
-
* @param {string} params.placeholder - The placeholder text of the editor.
|
11174
|
-
* @returns {boolean} - True if the content is empty, false otherwise.
|
11175
|
-
*/
|
11176
|
-
const isContentEmpty = ({ plainTextContent, content, placeholder }) => {
|
11177
|
-
// RoosterJS returns placeholder text as plain text when the editor is empty and in this case,
|
11178
|
-
// plainTextContent contains only placeholder text but content doesn't include the placeholder text
|
11179
|
-
// this needs to be reviewed after migration to the content model packages.
|
11180
|
-
const plainTextContainsPlaceholderOnly = plainTextContent === placeholder && !content.includes(placeholder);
|
11181
|
-
return plainTextContainsPlaceholderOnly || sanitizeText(plainTextContent !== null && plainTextContent !== void 0 ? plainTextContent : '').length === 0;
|
11182
|
-
};
|
11183
11613
|
|
11184
11614
|
// Copyright (c) Microsoft Corporation.
|
11185
11615
|
// Licensed under the MIT License.
|
@@ -11420,7 +11850,9 @@ const useChatMessageStyles = reactComponents.makeStyles({
|
|
11420
11850
|
}, '& video': {
|
11421
11851
|
maxWidth: '100% !important', // Add !important to make sure it won't be overridden by style defined in element
|
11422
11852
|
height: 'auto !important'
|
11423
|
-
}, '& p': Object.assign({}, reactComponents.shorthands.marginBlock('0.125rem')), '& blockquote': Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ backgroundColor: reactComponents.tokens.colorBrandBackgroundInverted, clear: 'left', minHeight: '2.25rem', width: 'fit-content', marginTop: '7px', marginRight: '0px', marginLeft: '0px', marginBottom: '7px', paddingTop: '7px', paddingRight: '15px', paddingLeft: '15px', paddingBottom: '7px' }, reactComponents.shorthands.border('solid')), reactComponents.shorthands.borderRadius('4px')), reactComponents.shorthands.borderWidth('1px')), reactComponents.shorthands.borderColor(reactComponents.tokens.colorNeutralStroke1Selected)), { borderLeftWidth: '4px' })
|
11853
|
+
}, '& p': Object.assign({}, reactComponents.shorthands.marginBlock('0.125rem')), '& blockquote': Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ backgroundColor: reactComponents.tokens.colorBrandBackgroundInverted, clear: 'left', minHeight: '2.25rem', width: 'fit-content', marginTop: '7px', marginRight: '0px', marginLeft: '0px', marginBottom: '7px', paddingTop: '7px', paddingRight: '15px', paddingLeft: '15px', paddingBottom: '7px' }, reactComponents.shorthands.border('solid')), reactComponents.shorthands.borderRadius('4px')), reactComponents.shorthands.borderWidth('1px')), reactComponents.shorthands.borderColor(reactComponents.tokens.colorNeutralStroke1Selected)), { borderLeftWidth: '4px' }), '& code': {
|
11854
|
+
whiteSpace: 'pre-wrap'
|
11855
|
+
} }),
|
11424
11856
|
bodyWithPlaceholderImage: {
|
11425
11857
|
'& img[src=""]': {
|
11426
11858
|
display: 'block',
|
@@ -13079,7 +13511,7 @@ class _ErrorBoundary extends React.Component {
|
|
13079
13511
|
// Copyright (c) Microsoft Corporation.
|
13080
13512
|
// Licensed under the MIT License.
|
13081
13513
|
/* @conditional-compile-remove(rich-text-editor) */
|
13082
|
-
const ChatMessageComponentAsRichTextEditBox = React.lazy(() => Promise.resolve().then(function () { return require('./ChatMessageComponentAsRichTextEditBox-
|
13514
|
+
const ChatMessageComponentAsRichTextEditBox = React.lazy(() => Promise.resolve().then(function () { return require('./ChatMessageComponentAsRichTextEditBox-r0U_8d3I.js'); }));
|
13083
13515
|
/**
|
13084
13516
|
* @private
|
13085
13517
|
* Use this function to load RoosterJS dependencies early in the lifecycle.
|
@@ -13087,7 +13519,7 @@ const ChatMessageComponentAsRichTextEditBox = React.lazy(() => Promise.resolve()
|
|
13087
13519
|
*
|
13088
13520
|
* @conditional-compile-remove(rich-text-editor)
|
13089
13521
|
*/
|
13090
|
-
const loadChatMessageComponentAsRichTextEditBox = () => Promise.resolve().then(function () { return require('./ChatMessageComponentAsRichTextEditBox-
|
13522
|
+
const loadChatMessageComponentAsRichTextEditBox = () => Promise.resolve().then(function () { return require('./ChatMessageComponentAsRichTextEditBox-r0U_8d3I.js'); });
|
13091
13523
|
/**
|
13092
13524
|
* @private
|
13093
13525
|
*/
|
@@ -27190,7 +27622,7 @@ const AttachmentDownloadErrorBar = (props) => {
|
|
27190
27622
|
/**
|
27191
27623
|
* Wrapper for RichTextSendBox component to allow us to use usePropsFor with richTextSendBox with lazy loading
|
27192
27624
|
*/
|
27193
|
-
const RichTextSendBoxWrapper = React.lazy(() => Promise.resolve().then(function () { return require('./RichTextSendBoxWrapper-
|
27625
|
+
const RichTextSendBoxWrapper = React.lazy(() => Promise.resolve().then(function () { return require('./RichTextSendBoxWrapper-DNlYAgO2.js'); }).then((module) => ({ default: module.RichTextSendBoxWrapper })));
|
27194
27626
|
/**
|
27195
27627
|
* @private
|
27196
27628
|
* Use this function to load RoosterJS dependencies early in the lifecycle.
|
@@ -27198,7 +27630,7 @@ const RichTextSendBoxWrapper = React.lazy(() => Promise.resolve().then(function
|
|
27198
27630
|
*
|
27199
27631
|
/* @conditional-compile-remove(rich-text-editor-composite-support)
|
27200
27632
|
*/
|
27201
|
-
const loadRichTextSendBox = () => Promise.resolve().then(function () { return require('./RichTextSendBoxWrapper-
|
27633
|
+
const loadRichTextSendBox = () => Promise.resolve().then(function () { return require('./RichTextSendBoxWrapper-DNlYAgO2.js'); }).then((module) => ({ default: module.RichTextSendBoxWrapper }));
|
27202
27634
|
/**
|
27203
27635
|
* @private
|
27204
27636
|
*/
|
@@ -39878,4 +40310,4 @@ exports.useTeamsCall = useTeamsCall;
|
|
39878
40310
|
exports.useTeamsCallAdapter = useTeamsCallAdapter;
|
39879
40311
|
exports.useTeamsCallAgent = useTeamsCallAgent;
|
39880
40312
|
exports.useTheme = useTheme;
|
39881
|
-
//# sourceMappingURL=index-
|
40313
|
+
//# sourceMappingURL=index-BLj9R9ms.js.map
|