@azure/communication-react 1.16.0-alpha-202404160012 → 1.16.0-alpha-202404170013

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.
Files changed (30) hide show
  1. package/dist/dist-cjs/communication-react/{ChatMessageComponentAsRichTextEditBox-CmrzlNzS.js → ChatMessageComponentAsRichTextEditBox-DZWR3o3q.js} +3 -3
  2. package/dist/dist-cjs/communication-react/{ChatMessageComponentAsRichTextEditBox-CmrzlNzS.js.map → ChatMessageComponentAsRichTextEditBox-DZWR3o3q.js.map} +1 -1
  3. package/dist/dist-cjs/communication-react/{index-CC43HCUd.js → index-pky6z3v4.js} +94 -60
  4. package/dist/dist-cjs/communication-react/index-pky6z3v4.js.map +1 -0
  5. package/dist/dist-cjs/communication-react/index.js +2 -2
  6. package/dist/dist-esm/acs-ui-common/src/telemetryVersion.js +1 -1
  7. package/dist/dist-esm/acs-ui-common/src/telemetryVersion.js.map +1 -1
  8. package/dist/dist-esm/react-components/src/components/RichTextEditor/Buttons/RichTextRibbonButtons.js +8 -4
  9. package/dist/dist-esm/react-components/src/components/RichTextEditor/Buttons/RichTextRibbonButtons.js.map +1 -1
  10. package/dist/dist-esm/react-components/src/components/RichTextEditor/RichTextEditor.d.ts +14 -0
  11. package/dist/dist-esm/react-components/src/components/RichTextEditor/RichTextEditor.js +5 -0
  12. package/dist/dist-esm/react-components/src/components/RichTextEditor/RichTextEditor.js.map +1 -1
  13. package/dist/dist-esm/react-components/src/components/RichTextEditor/RichTextSendBox.js +49 -13
  14. package/dist/dist-esm/react-components/src/components/RichTextEditor/RichTextSendBox.js.map +1 -1
  15. package/dist/dist-esm/react-components/src/components/VideoGallery/DefaultLayout.js +3 -2
  16. package/dist/dist-esm/react-components/src/components/VideoGallery/DefaultLayout.js.map +1 -1
  17. package/dist/dist-esm/react-components/src/components/VideoGallery/FloatingLocalVideoLayout.js +3 -2
  18. package/dist/dist-esm/react-components/src/components/VideoGallery/FloatingLocalVideoLayout.js.map +1 -1
  19. package/dist/dist-esm/react-components/src/components/VideoGallery/LargeGalleryLayout.js +1 -2
  20. package/dist/dist-esm/react-components/src/components/VideoGallery/LargeGalleryLayout.js.map +1 -1
  21. package/dist/dist-esm/react-components/src/components/VideoGallery/SpeakerVideoLayout.js +1 -1
  22. package/dist/dist-esm/react-components/src/components/VideoGallery/SpeakerVideoLayout.js.map +1 -1
  23. package/dist/dist-esm/react-components/src/components/VideoGallery/utils/videoGalleryLayoutUtils.d.ts +5 -1
  24. package/dist/dist-esm/react-components/src/components/VideoGallery/utils/videoGalleryLayoutUtils.js +17 -17
  25. package/dist/dist-esm/react-components/src/components/VideoGallery/utils/videoGalleryLayoutUtils.js.map +1 -1
  26. package/dist/dist-esm/react-components/src/components/styles/RichTextEditor.styles.d.ts +1 -1
  27. package/dist/dist-esm/react-components/src/components/styles/RichTextEditor.styles.js +10 -21
  28. package/dist/dist-esm/react-components/src/components/styles/RichTextEditor.styles.js.map +1 -1
  29. package/package.json +1 -1
  30. package/dist/dist-cjs/communication-react/index-CC43HCUd.js.map +0 -1
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var index = require('./index-CC43HCUd.js');
3
+ var index = require('./index-pky6z3v4.js');
4
4
  require('react');
5
5
  require('@fluentui/react');
6
6
  require('@fluentui/react-components');
@@ -20,9 +20,9 @@ require('@fluentui/react-file-type-icons');
20
20
  require('@griffel/react');
21
21
  require('roosterjs-editor-plugins');
22
22
  require('roosterjs-editor-core');
23
+ require('roosterjs-editor-types-compatible');
23
24
  require('roosterjs-react');
24
25
  require('roosterjs-editor-dom');
25
- require('roosterjs-editor-types-compatible');
26
26
  require('roosterjs-editor-api');
27
27
  require('uuid');
28
28
  require('html-react-parser');
@@ -2,5 +2,5 @@
2
2
  // Copyright (c) Microsoft Corporation.
3
3
  // Licensed under the MIT License.
4
4
  // GENERATED FILE. DO NOT EDIT MANUALLY.
5
- module.exports = '1.16.0-alpha-202404160012';
5
+ module.exports = '1.16.0-alpha-202404170013';
6
6
  //# sourceMappingURL=telemetryVersion.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"telemetryVersion.js","sourceRoot":"","sources":["../../../../../acs-ui-common/src/telemetryVersion.js"],"names":[],"mappings":";AAAA,uCAAuC;AACvC,kCAAkC;AAElC,wCAAwC;AAExC,MAAM,CAAC,OAAO,GAAG,2BAA2B,CAAC","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\n// GENERATED FILE. DO NOT EDIT MANUALLY.\n\nmodule.exports = '1.16.0-alpha-202404160012';\n"]}
1
+ {"version":3,"file":"telemetryVersion.js","sourceRoot":"","sources":["../../../../../acs-ui-common/src/telemetryVersion.js"],"names":[],"mappings":";AAAA,uCAAuC;AACvC,kCAAkC;AAElC,wCAAwC;AAExC,MAAM,CAAC,OAAO,GAAG,2BAA2B,CAAC","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\n// GENERATED FILE. DO NOT EDIT MANUALLY.\n\nmodule.exports = '1.16.0-alpha-202404170013';\n"]}
@@ -1,24 +1,28 @@
1
1
  // Copyright (c) Microsoft Corporation.
2
2
  // Licensed under the MIT License.
3
- import { ContextualMenuItemType } from '@fluentui/react';
3
+ import { ContextualMenuItemType, Icon } from '@fluentui/react';
4
4
  import { KnownRibbonButtonKey, getButtons } from 'roosterjs-react';
5
5
  import { ribbonButtonStyle, ribbonDividerStyle } from '../../styles/RichTextEditor.styles';
6
6
  import { insertTableButton } from './Table/RichTextInsertTableButton';
7
+ import React from 'react';
7
8
  const MaxRowsNumber = 5;
8
9
  const MaxColumnsNumber = 5;
9
10
  const dividerRibbonButton = (theme, key) => {
10
11
  return {
11
12
  key: key,
12
- iconName: 'RichTextDividerIcon',
13
+ // the icon will be set in `onRender` callback
14
+ // this is needed to make the divider unavailable for keyboard navigation
15
+ iconName: '',
16
+ // no text is needed here as we don't want to show a tooltip for the divider
13
17
  unlocalizedText: '',
14
18
  onClick: () => { },
15
19
  isDisabled: () => true,
16
20
  commandBarProperties: {
17
21
  // show the item correctly for the overflow menu
18
22
  itemType: ContextualMenuItemType.Divider,
19
- buttonStyles: ribbonDividerStyle(theme),
20
23
  // this is still needed to remove checkmark icon space even though it is a divider
21
- canCheck: false
24
+ canCheck: false,
25
+ onRender: () => React.createElement(Icon, { iconName: "RichTextDividerIcon", className: ribbonDividerStyle(theme) })
22
26
  }
23
27
  };
24
28
  };
@@ -1 +1 @@
1
- {"version":3,"file":"RichTextRibbonButtons.js","sourceRoot":"","sources":["../../../../../../../../react-components/src/components/RichTextEditor/Buttons/RichTextRibbonButtons.tsx"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAElC,OAAO,EAAE,sBAAsB,EAAS,MAAM,iBAAiB,CAAC;AAChE,OAAO,EAAE,oBAAoB,EAAgB,UAAU,EAAE,MAAM,iBAAiB,CAAC;AACjF,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AAC3F,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AAEtE,MAAM,aAAa,GAAG,CAAC,CAAC;AACxB,MAAM,gBAAgB,GAAG,CAAC,CAAC;AAE3B,MAAM,mBAAmB,GAAG,CAAC,KAAY,EAAE,GAAW,EAAwB,EAAE;IAC9E,OAAO;QACL,GAAG,EAAE,GAAG;QACR,QAAQ,EAAE,qBAAqB;QAC/B,eAAe,EAAE,EAAE;QACnB,OAAO,EAAE,GAAG,EAAE,GAAE,CAAC;QACjB,UAAU,EAAE,GAAG,EAAE,CAAC,IAAI;QACtB,oBAAoB,EAAE;YACpB,gDAAgD;YAChD,QAAQ,EAAE,sBAAsB,CAAC,OAAO;YACxC,YAAY,EAAE,kBAAkB,CAAC,KAAK,CAAC;YACvC,kFAAkF;YAClF,QAAQ,EAAE,KAAK;SAChB;KACF,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,UAAU,GAAG,CAAC,KAAY,EAAoC,EAAE;IACpE,OAAO,uBAAuB,CAAC,oBAAoB,CAAC,IAAI,EAAE,KAAK,EAAE,wBAAwB,CAAC,CAAC;AAC7F,CAAC,CAAC;AAEF,MAAM,YAAY,GAAG,CAAC,KAAY,EAAoC,EAAE;IACtE,OAAO,uBAAuB,CAAC,oBAAoB,CAAC,MAAM,EAAE,KAAK,EAAE,0BAA0B,CAAC,CAAC;AACjG,CAAC,CAAC;AAEF,MAAM,eAAe,GAAG,CAAC,KAAY,EAAoC,EAAE;IACzE,OAAO,uBAAuB,CAAC,oBAAoB,CAAC,SAAS,EAAE,KAAK,EAAE,6BAA6B,CAAC,CAAC;AACvG,CAAC,CAAC;AAEF,MAAM,gBAAgB,GAAG,CAAC,KAAY,EAAoC,EAAE;IAC1E,OAAO,uBAAuB,CAAC,oBAAoB,CAAC,YAAY,EAAE,KAAK,EAAE,8BAA8B,CAAC,CAAC;AAC3G,CAAC,CAAC;AAEF,MAAM,gBAAgB,GAAG,CAAC,KAAY,EAAoC,EAAE;IAC1E,OAAO,uBAAuB,CAAC,oBAAoB,CAAC,YAAY,EAAE,KAAK,EAAE,8BAA8B,CAAC,CAAC;AAC3G,CAAC,CAAC;AAEF,MAAM,oBAAoB,GAAG,CAAC,KAAY,EAAoC,EAAE;IAC9E,OAAO,uBAAuB,CAAC,oBAAoB,CAAC,cAAc,EAAE,KAAK,EAAE,kCAAkC,CAAC,CAAC;AACjH,CAAC,CAAC;AAEF,MAAM,oBAAoB,GAAG,CAAC,KAAY,EAAoC,EAAE;IAC9E,OAAO,uBAAuB,CAAC,oBAAoB,CAAC,cAAc,EAAE,KAAK,EAAE,kCAAkC,CAAC,CAAC;AACjH,CAAC,CAAC;AAEF,MAAM,uBAAuB,GAAG,CAC9B,GAAyB,EACzB,KAAY,EACZ,IAAY,EACsB,EAAE;;IACpC,MAAM,OAAO,GAAG,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAClC,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QAC1B,2EAA2E;QAC3E,MAAM,MAAM,GAAG,OAAO,CAAC,CAAC,CAAoC,CAAC;QAC7D,MAAM,CAAC,QAAQ,GAAG,IAAI,CAAC;QACvB,MAAM,CAAC,oBAAoB,mCACtB,MAAM,CAAC,oBAAoB,KAC9B,YAAY,kCACP,MAAA,MAAM,CAAC,oBAAoB,0CAAE,YAAY,GACzC,iBAAiB,CAAC,KAAK,CAAC,GAE7B,QAAQ,EAAE,KAAK,GAChB,CAAC;QACF,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,KAAY,EAA0B,EAAE;IACpE,MAAM,OAAO,GAA2B,EAAE,CAAC;IAC3C;QACE,UAAU,CAAC,KAAK,CAAC;QACjB,YAAY,CAAC,KAAK,CAAC;QACnB,eAAe,CAAC,KAAK,CAAC;QACtB,mBAAmB,CAAC,KAAK,EAAE,iCAAiC,CAAC;QAC7D,gBAAgB,CAAC,KAAK,CAAC;QACvB,gBAAgB,CAAC,KAAK,CAAC;QACvB,oBAAoB,CAAC,KAAK,CAAC;QAC3B,oBAAoB,CAAC,KAAK,CAAC;QAC3B,mBAAmB,CAAC,KAAK,EAAE,4BAA4B,CAAC;QACxD,iBAAiB,CAAC,KAAK,EAAE,aAAa,EAAE,gBAAgB,CAAC;KAC1D,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;QACjB,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrB,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,OAAO,CAAC;AACjB,CAAC,CAAC","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport { ContextualMenuItemType, Theme } from '@fluentui/react';\nimport { KnownRibbonButtonKey, RibbonButton, getButtons } from 'roosterjs-react';\nimport { ribbonButtonStyle, ribbonDividerStyle } from '../../styles/RichTextEditor.styles';\nimport { insertTableButton } from './Table/RichTextInsertTableButton';\n\nconst MaxRowsNumber = 5;\nconst MaxColumnsNumber = 5;\n\nconst dividerRibbonButton = (theme: Theme, key: string): RibbonButton<string> => {\n return {\n key: key,\n iconName: 'RichTextDividerIcon',\n unlocalizedText: '',\n onClick: () => {},\n isDisabled: () => true,\n commandBarProperties: {\n // show the item correctly for the overflow menu\n itemType: ContextualMenuItemType.Divider,\n buttonStyles: ribbonDividerStyle(theme),\n // this is still needed to remove checkmark icon space even though it is a divider\n canCheck: false\n }\n };\n};\n\nconst boldButton = (theme: Theme): RibbonButton<string> | undefined => {\n return createKnownRibbonButton(KnownRibbonButtonKey.Bold, theme, 'RichTextBoldButtonIcon');\n};\n\nconst italicButton = (theme: Theme): RibbonButton<string> | undefined => {\n return createKnownRibbonButton(KnownRibbonButtonKey.Italic, theme, 'RichTextItalicButtonIcon');\n};\n\nconst underlineButton = (theme: Theme): RibbonButton<string> | undefined => {\n return createKnownRibbonButton(KnownRibbonButtonKey.Underline, theme, 'RichTextUnderlineButtonIcon');\n};\n\nconst bulletListButton = (theme: Theme): RibbonButton<string> | undefined => {\n return createKnownRibbonButton(KnownRibbonButtonKey.BulletedList, theme, 'RichTextBulletListButtonIcon');\n};\n\nconst numberListButton = (theme: Theme): RibbonButton<string> | undefined => {\n return createKnownRibbonButton(KnownRibbonButtonKey.NumberedList, theme, 'RichTextNumberListButtonIcon');\n};\n\nconst indentIncreaseButton = (theme: Theme): RibbonButton<string> | undefined => {\n return createKnownRibbonButton(KnownRibbonButtonKey.IncreaseIndent, theme, 'RichTextIndentIncreaseButtonIcon');\n};\n\nconst indentDecreaseButton = (theme: Theme): RibbonButton<string> | undefined => {\n return createKnownRibbonButton(KnownRibbonButtonKey.DecreaseIndent, theme, 'RichTextIndentDecreaseButtonIcon');\n};\n\nconst createKnownRibbonButton = (\n key: KnownRibbonButtonKey,\n theme: Theme,\n icon: string\n): RibbonButton<string> | undefined => {\n const buttons = getButtons([key]);\n if (buttons.length > 0) {\n const button = buttons[0];\n // AllButtonStringKeys is a union of all the string keys of all the buttons\n const result = buttons[0] as RibbonButton<typeof button.key>;\n button.iconName = icon;\n button.commandBarProperties = {\n ...button.commandBarProperties,\n buttonStyles: {\n ...button.commandBarProperties?.buttonStyles,\n ...ribbonButtonStyle(theme)\n },\n canCheck: false\n };\n return result;\n }\n return undefined;\n};\n\n/**\n * @private\n */\nexport const ribbonButtons = (theme: Theme): RibbonButton<string>[] => {\n const buttons: RibbonButton<string>[] = [];\n [\n boldButton(theme),\n italicButton(theme),\n underlineButton(theme),\n dividerRibbonButton(theme, 'RichTextRibbonTextFormatDivider'),\n bulletListButton(theme),\n numberListButton(theme),\n indentDecreaseButton(theme),\n indentIncreaseButton(theme),\n dividerRibbonButton(theme, 'RichTextRibbonTableDivider'),\n insertTableButton(theme, MaxRowsNumber, MaxColumnsNumber)\n ].forEach((item) => {\n if (item !== undefined) {\n buttons.push(item);\n }\n });\n\n return buttons;\n};\n"]}
1
+ {"version":3,"file":"RichTextRibbonButtons.js","sourceRoot":"","sources":["../../../../../../../../react-components/src/components/RichTextEditor/Buttons/RichTextRibbonButtons.tsx"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport { ContextualMenuItemType, Icon, Theme } from '@fluentui/react';\nimport { KnownRibbonButtonKey, RibbonButton, getButtons } from 'roosterjs-react';\nimport { ribbonButtonStyle, ribbonDividerStyle } from '../../styles/RichTextEditor.styles';\nimport { insertTableButton } from './Table/RichTextInsertTableButton';\nimport React from 'react';\n\nconst MaxRowsNumber = 5;\nconst MaxColumnsNumber = 5;\n\nconst dividerRibbonButton = (theme: Theme, key: string): RibbonButton<string> => {\n return {\n key: key,\n // the icon will be set in `onRender` callback\n // this is needed to make the divider unavailable for keyboard navigation\n iconName: '',\n // no text is needed here as we don't want to show a tooltip for the divider\n unlocalizedText: '',\n onClick: () => {},\n isDisabled: () => true,\n commandBarProperties: {\n // show the item correctly for the overflow menu\n itemType: ContextualMenuItemType.Divider,\n // this is still needed to remove checkmark icon space even though it is a divider\n canCheck: false,\n onRender: () => <Icon iconName=\"RichTextDividerIcon\" className={ribbonDividerStyle(theme)} />\n }\n };\n};\n\nconst boldButton = (theme: Theme): RibbonButton<string> | undefined => {\n return createKnownRibbonButton(KnownRibbonButtonKey.Bold, theme, 'RichTextBoldButtonIcon');\n};\n\nconst italicButton = (theme: Theme): RibbonButton<string> | undefined => {\n return createKnownRibbonButton(KnownRibbonButtonKey.Italic, theme, 'RichTextItalicButtonIcon');\n};\n\nconst underlineButton = (theme: Theme): RibbonButton<string> | undefined => {\n return createKnownRibbonButton(KnownRibbonButtonKey.Underline, theme, 'RichTextUnderlineButtonIcon');\n};\n\nconst bulletListButton = (theme: Theme): RibbonButton<string> | undefined => {\n return createKnownRibbonButton(KnownRibbonButtonKey.BulletedList, theme, 'RichTextBulletListButtonIcon');\n};\n\nconst numberListButton = (theme: Theme): RibbonButton<string> | undefined => {\n return createKnownRibbonButton(KnownRibbonButtonKey.NumberedList, theme, 'RichTextNumberListButtonIcon');\n};\n\nconst indentIncreaseButton = (theme: Theme): RibbonButton<string> | undefined => {\n return createKnownRibbonButton(KnownRibbonButtonKey.IncreaseIndent, theme, 'RichTextIndentIncreaseButtonIcon');\n};\n\nconst indentDecreaseButton = (theme: Theme): RibbonButton<string> | undefined => {\n return createKnownRibbonButton(KnownRibbonButtonKey.DecreaseIndent, theme, 'RichTextIndentDecreaseButtonIcon');\n};\n\nconst createKnownRibbonButton = (\n key: KnownRibbonButtonKey,\n theme: Theme,\n icon: string\n): RibbonButton<string> | undefined => {\n const buttons = getButtons([key]);\n if (buttons.length > 0) {\n const button = buttons[0];\n // AllButtonStringKeys is a union of all the string keys of all the buttons\n const result = buttons[0] as RibbonButton<typeof button.key>;\n button.iconName = icon;\n button.commandBarProperties = {\n ...button.commandBarProperties,\n buttonStyles: {\n ...button.commandBarProperties?.buttonStyles,\n ...ribbonButtonStyle(theme)\n },\n canCheck: false\n };\n return result;\n }\n return undefined;\n};\n\n/**\n * @private\n */\nexport const ribbonButtons = (theme: Theme): RibbonButton<string>[] => {\n const buttons: RibbonButton<string>[] = [];\n [\n boldButton(theme),\n italicButton(theme),\n underlineButton(theme),\n dividerRibbonButton(theme, 'RichTextRibbonTextFormatDivider'),\n bulletListButton(theme),\n numberListButton(theme),\n indentDecreaseButton(theme),\n indentIncreaseButton(theme),\n dividerRibbonButton(theme, 'RichTextRibbonTableDivider'),\n insertTableButton(theme, MaxRowsNumber, MaxColumnsNumber)\n ].forEach((item) => {\n if (item !== undefined) {\n buttons.push(item);\n }\n });\n\n return buttons;\n};\n"]}
@@ -30,9 +30,23 @@ export interface RichTextEditorProps {
30
30
  *
31
31
  * @beta
32
32
  */
33
+ /**
34
+ * Represents a reference to the RichTextEditor component.
35
+ */
33
36
  export interface RichTextEditorComponentRef {
37
+ /**
38
+ * Sets focus on the RichTextEditor component.
39
+ */
34
40
  focus: () => void;
41
+ /**
42
+ * Sets the content of the RichTextEditor component to an empty string.
43
+ */
35
44
  setEmptyContent: () => void;
45
+ /**
46
+ * Retrieves the plain text content of the RichTextEditor component.
47
+ * @returns The plain text content of the RichTextEditor component, or undefined if the editor isn't available.
48
+ */
49
+ getPlainContent: () => string | undefined;
36
50
  }
37
51
  /**
38
52
  * A component to wrap RoosterJS Rich Text Editor.
@@ -3,6 +3,7 @@
3
3
  import React, { useCallback, useEffect, useImperativeHandle, useMemo, useRef } from 'react';
4
4
  import { ContentEdit, Watermark } from 'roosterjs-editor-plugins';
5
5
  import { Editor } from 'roosterjs-editor-core';
6
+ import { CompatibleGetContentMode } from 'roosterjs-editor-types-compatible';
6
7
  import { Rooster, createUpdateContentPlugin, UpdateMode, createRibbonPlugin, Ribbon, createContextMenuPlugin } from 'roosterjs-react';
7
8
  import { ribbonButtonStyle, ribbonOverflowButtonStyle, ribbonStyle, richTextEditorWrapperStyle, richTextEditorStyle } from '../styles/RichTextEditor.styles';
8
9
  import { useTheme } from '../../theming';
@@ -32,6 +33,10 @@ export const RichTextEditor = React.forwardRef((props, ref) => {
32
33
  if (editor.current) {
33
34
  editor.current.setContent('');
34
35
  }
36
+ },
37
+ getPlainContent() {
38
+ var _a;
39
+ return (_a = editor === null || editor === void 0 ? void 0 : editor.current) === null || _a === void 0 ? void 0 : _a.getContent(CompatibleGetContentMode.PlainTextFast);
35
40
  }
36
41
  };
37
42
  }, []);
@@ -1 +1 @@
1
- {"version":3,"file":"RichTextEditor.js","sourceRoot":"","sources":["../../../../../../../react-components/src/components/RichTextEditor/RichTextEditor.tsx"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\nimport React, { useCallback, useEffect, useImperativeHandle, useMemo, useRef } from 'react';\nimport { ContentEdit, Watermark } from 'roosterjs-editor-plugins';\nimport { Editor } from 'roosterjs-editor-core';\nimport type { DefaultFormat, EditorOptions, IEditor } from 'roosterjs-editor-types-compatible';\nimport {\n Rooster,\n createUpdateContentPlugin,\n UpdateMode,\n createRibbonPlugin,\n Ribbon,\n createContextMenuPlugin\n} from 'roosterjs-react';\nimport {\n ribbonButtonStyle,\n ribbonOverflowButtonStyle,\n ribbonStyle,\n richTextEditorWrapperStyle,\n richTextEditorStyle\n} from '../styles/RichTextEditor.styles';\nimport { useTheme } from '../../theming';\nimport { ribbonButtons } from './Buttons/RichTextRibbonButtons';\nimport { RichTextSendBoxStrings } from './RichTextSendBox';\nimport { isDarkThemed } from '../../theming/themeUtils';\nimport { ribbonButtonsStrings } from '../utils/RichTextEditorStringsUtils';\nimport { createTableEditMenuProvider } from './Buttons/Table/RichTextTableContextMenu';\nimport CopyPastePlugin from './Plugins/CopyPastePlugin';\n\n/**\n * Props for {@link RichTextEditor}.\n *\n * @private\n */\nexport interface RichTextEditorStyleProps {\n minHeight: string;\n maxHeight: string;\n}\n\n/**\n * Props for {@link RichTextEditor}.\n *\n * @private\n */\nexport interface RichTextEditorProps {\n // the initial content of editor that is set when editor is created (e.g. when editing a message)\n initialContent?: string;\n // the current content of the editor\n content?: string;\n onChange: (newValue?: string) => void;\n onKeyDown?: (ev: React.KeyboardEvent<HTMLElement>) => void;\n placeholderText?: string;\n strings: Partial<RichTextSendBoxStrings>;\n showRichTextEditorFormatting: boolean;\n styles: RichTextEditorStyleProps;\n autoFocus?: 'sendBoxTextField';\n}\n\n/**\n * Props for {@link RichTextEditor}.\n *\n * @beta\n */\nexport interface RichTextEditorComponentRef {\n focus: () => void;\n setEmptyContent: () => void;\n}\n\n/**\n * A component to wrap RoosterJS Rich Text Editor.\n *\n * @beta\n */\nexport const RichTextEditor = React.forwardRef<RichTextEditorComponentRef, RichTextEditorProps>((props, ref) => {\n const { initialContent, onChange, placeholderText, strings, showRichTextEditorFormatting, content, autoFocus } =\n props;\n const editor = useRef<IEditor | null>(null);\n const contentValue = useRef<string | undefined>(content);\n const theme = useTheme();\n useImperativeHandle(\n ref,\n () => {\n return {\n focus() {\n if (editor.current) {\n editor.current.focus();\n }\n },\n setEmptyContent() {\n if (editor.current) {\n editor.current.setContent('');\n }\n }\n };\n },\n []\n );\n\n const ribbonPlugin = React.useMemo(() => {\n return createRibbonPlugin();\n }, []);\n\n const editorCreator = useCallback(\n (div: HTMLDivElement, options: EditorOptions) => {\n const editorValue = new Editor(div, options);\n // this is to fix issue when editor is created or re-rendered and has existing text\n // Content model package has a correct behavior and this fix can be deleted\n if (contentValue.current !== undefined && contentValue.current.length > 0) {\n // in case if initialContent is not empty, RoosterJS doesn't set caret position to the end.\n focusAndUpdateContent(editorValue, contentValue.current);\n } else if (initialContent !== undefined && initialContent.length > 0) {\n // changing layout in rich text send box cause the editor to be recreated\n // to keep the content, we need to set messageContent to the current content\n focusAndUpdateContent(editorValue, initialContent);\n }\n editor.current = editorValue;\n return editorValue;\n },\n // trigger force editor reset when strings are changed to update context menu strings\n // see RosterJS documentation for 'editorCreator' for more details\n // the editorCreator callback shouldn't be updated when the initialContent is changed\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [strings]\n );\n\n const placeholderPlugin = React.useMemo(() => {\n return new Watermark('');\n }, []);\n\n useEffect(() => {\n if (placeholderText !== undefined) {\n placeholderPlugin.updateWatermark(placeholderText);\n }\n }, [placeholderPlugin, placeholderText]);\n\n const plugins = useMemo(() => {\n // contextPlugin and tableEditMenuProvider allow to show insert/delete menu for the table\n const contextPlugin = createContextMenuPlugin();\n const tableEditMenuProvider = createTableEditMenuProvider(strings);\n const contentEdit = new ContentEdit();\n const updateContentPlugin = createUpdateContentPlugin(\n UpdateMode.OnContentChangedEvent | UpdateMode.OnUserInput,\n (content: string) => {\n onChange && onChange(content);\n }\n );\n const copyPastePlugin = new CopyPastePlugin();\n return [\n contentEdit,\n placeholderPlugin,\n updateContentPlugin,\n ribbonPlugin,\n contextPlugin,\n tableEditMenuProvider,\n copyPastePlugin\n ];\n }, [onChange, placeholderPlugin, ribbonPlugin, strings]);\n\n const ribbon = useMemo(() => {\n const buttons = ribbonButtons(theme);\n\n return (\n <Ribbon\n styles={ribbonStyle}\n buttons={buttons}\n plugin={ribbonPlugin}\n overflowButtonProps={{\n styles: ribbonButtonStyle(theme),\n menuProps: {\n items: [], // CommandBar will determine items rendered in overflow\n isBeakVisible: false,\n styles: ribbonOverflowButtonStyle(theme)\n }\n }}\n strings={ribbonButtonsStrings(strings)}\n data-testid={'rich-text-editor-ribbon'}\n />\n );\n }, [strings, ribbonPlugin, theme]);\n\n const defaultFormat: DefaultFormat = useMemo(() => {\n // without setting any styles, text input is not handled properly for tables (when insert or paste one in the editor)\n // because of https://github.com/microsoft/roosterjs/blob/14dbb947e3ae94580109cbd05e48ceb05327c4dc/packages/roosterjs-editor-core/lib/corePlugins/TypeInContainerPlugin.ts#L75\n // this issue is fixed for content model package\n return {\n backgroundColor: 'transparent'\n };\n }, []);\n\n return (\n <div data-testid={'rich-text-editor-wrapper'}>\n {showRichTextEditorFormatting && ribbon}\n <div className={richTextEditorWrapperStyle(theme, !showRichTextEditorFormatting)}>\n <Rooster\n defaultFormat={defaultFormat}\n inDarkMode={isDarkThemed(theme)}\n plugins={plugins}\n className={richTextEditorStyle(props.styles)}\n editorCreator={editorCreator}\n // TODO: confirm the color during inline images implementation\n imageSelectionBorderColor={'blue'}\n // doNotAdjustEditorColor is used to fix the default background color for Rooster component\n doNotAdjustEditorColor={true}\n data-testid={'rooster-rich-text-editor'}\n // if we don't use 'allowKeyboardEventPropagation' only the enter key is caught\n onKeyDown={props.onKeyDown}\n focusOnInit={autoFocus === 'sendBoxTextField'}\n />\n </div>\n </div>\n );\n});\n\nconst focusAndUpdateContent = (editor: Editor, content: string): void => {\n // focus the editor to set correct selection position\n editor.focus();\n // set initial content\n editor.setContent(content);\n};\n"]}
1
+ {"version":3,"file":"RichTextEditor.js","sourceRoot":"","sources":["../../../../../../../react-components/src/components/RichTextEditor/RichTextEditor.tsx"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\nimport React, { useCallback, useEffect, useImperativeHandle, useMemo, useRef } from 'react';\nimport { ContentEdit, Watermark } from 'roosterjs-editor-plugins';\nimport { Editor } from 'roosterjs-editor-core';\nimport type { DefaultFormat, EditorOptions, IEditor } from 'roosterjs-editor-types-compatible';\nimport { CompatibleGetContentMode } from 'roosterjs-editor-types-compatible';\nimport {\n Rooster,\n createUpdateContentPlugin,\n UpdateMode,\n createRibbonPlugin,\n Ribbon,\n createContextMenuPlugin\n} from 'roosterjs-react';\nimport {\n ribbonButtonStyle,\n ribbonOverflowButtonStyle,\n ribbonStyle,\n richTextEditorWrapperStyle,\n richTextEditorStyle\n} from '../styles/RichTextEditor.styles';\nimport { useTheme } from '../../theming';\nimport { ribbonButtons } from './Buttons/RichTextRibbonButtons';\nimport { RichTextSendBoxStrings } from './RichTextSendBox';\nimport { isDarkThemed } from '../../theming/themeUtils';\nimport { ribbonButtonsStrings } from '../utils/RichTextEditorStringsUtils';\nimport { createTableEditMenuProvider } from './Buttons/Table/RichTextTableContextMenu';\nimport CopyPastePlugin from './Plugins/CopyPastePlugin';\n\n/**\n * Props for {@link RichTextEditor}.\n *\n * @private\n */\nexport interface RichTextEditorStyleProps {\n minHeight: string;\n maxHeight: string;\n}\n\n/**\n * Props for {@link RichTextEditor}.\n *\n * @private\n */\nexport interface RichTextEditorProps {\n // the initial content of editor that is set when editor is created (e.g. when editing a message)\n initialContent?: string;\n // the current content of the editor\n content?: string;\n onChange: (newValue?: string) => void;\n onKeyDown?: (ev: React.KeyboardEvent<HTMLElement>) => void;\n placeholderText?: string;\n strings: Partial<RichTextSendBoxStrings>;\n showRichTextEditorFormatting: boolean;\n styles: RichTextEditorStyleProps;\n autoFocus?: 'sendBoxTextField';\n}\n\n/**\n * Props for {@link RichTextEditor}.\n *\n * @beta\n */\n/**\n * Represents a reference to the RichTextEditor component.\n */\nexport interface RichTextEditorComponentRef {\n /**\n * Sets focus on the RichTextEditor component.\n */\n focus: () => void;\n\n /**\n * Sets the content of the RichTextEditor component to an empty string.\n */\n setEmptyContent: () => void;\n\n /**\n * Retrieves the plain text content of the RichTextEditor component.\n * @returns The plain text content of the RichTextEditor component, or undefined if the editor isn't available.\n */\n getPlainContent: () => string | undefined;\n}\n\n/**\n * A component to wrap RoosterJS Rich Text Editor.\n *\n * @beta\n */\nexport const RichTextEditor = React.forwardRef<RichTextEditorComponentRef, RichTextEditorProps>((props, ref) => {\n const { initialContent, onChange, placeholderText, strings, showRichTextEditorFormatting, content, autoFocus } =\n props;\n const editor = useRef<IEditor | null>(null);\n const contentValue = useRef<string | undefined>(content);\n const theme = useTheme();\n useImperativeHandle(\n ref,\n () => {\n return {\n focus() {\n if (editor.current) {\n editor.current.focus();\n }\n },\n setEmptyContent() {\n if (editor.current) {\n editor.current.setContent('');\n }\n },\n getPlainContent() {\n return editor?.current?.getContent(CompatibleGetContentMode.PlainTextFast);\n }\n };\n },\n []\n );\n\n const ribbonPlugin = React.useMemo(() => {\n return createRibbonPlugin();\n }, []);\n\n const editorCreator = useCallback(\n (div: HTMLDivElement, options: EditorOptions) => {\n const editorValue = new Editor(div, options);\n // this is to fix issue when editor is created or re-rendered and has existing text\n // Content model package has a correct behavior and this fix can be deleted\n if (contentValue.current !== undefined && contentValue.current.length > 0) {\n // in case if initialContent is not empty, RoosterJS doesn't set caret position to the end.\n focusAndUpdateContent(editorValue, contentValue.current);\n } else if (initialContent !== undefined && initialContent.length > 0) {\n // changing layout in rich text send box cause the editor to be recreated\n // to keep the content, we need to set messageContent to the current content\n focusAndUpdateContent(editorValue, initialContent);\n }\n editor.current = editorValue;\n return editorValue;\n },\n // trigger force editor reset when strings are changed to update context menu strings\n // see RosterJS documentation for 'editorCreator' for more details\n // the editorCreator callback shouldn't be updated when the initialContent is changed\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [strings]\n );\n\n const placeholderPlugin = React.useMemo(() => {\n return new Watermark('');\n }, []);\n\n useEffect(() => {\n if (placeholderText !== undefined) {\n placeholderPlugin.updateWatermark(placeholderText);\n }\n }, [placeholderPlugin, placeholderText]);\n\n const plugins = useMemo(() => {\n // contextPlugin and tableEditMenuProvider allow to show insert/delete menu for the table\n const contextPlugin = createContextMenuPlugin();\n const tableEditMenuProvider = createTableEditMenuProvider(strings);\n const contentEdit = new ContentEdit();\n const updateContentPlugin = createUpdateContentPlugin(\n UpdateMode.OnContentChangedEvent | UpdateMode.OnUserInput,\n (content: string) => {\n onChange && onChange(content);\n }\n );\n const copyPastePlugin = new CopyPastePlugin();\n return [\n contentEdit,\n placeholderPlugin,\n updateContentPlugin,\n ribbonPlugin,\n contextPlugin,\n tableEditMenuProvider,\n copyPastePlugin\n ];\n }, [onChange, placeholderPlugin, ribbonPlugin, strings]);\n\n const ribbon = useMemo(() => {\n const buttons = ribbonButtons(theme);\n\n return (\n <Ribbon\n styles={ribbonStyle}\n buttons={buttons}\n plugin={ribbonPlugin}\n overflowButtonProps={{\n styles: ribbonButtonStyle(theme),\n menuProps: {\n items: [], // CommandBar will determine items rendered in overflow\n isBeakVisible: false,\n styles: ribbonOverflowButtonStyle(theme)\n }\n }}\n strings={ribbonButtonsStrings(strings)}\n data-testid={'rich-text-editor-ribbon'}\n />\n );\n }, [strings, ribbonPlugin, theme]);\n\n const defaultFormat: DefaultFormat = useMemo(() => {\n // without setting any styles, text input is not handled properly for tables (when insert or paste one in the editor)\n // because of https://github.com/microsoft/roosterjs/blob/14dbb947e3ae94580109cbd05e48ceb05327c4dc/packages/roosterjs-editor-core/lib/corePlugins/TypeInContainerPlugin.ts#L75\n // this issue is fixed for content model package\n return {\n backgroundColor: 'transparent'\n };\n }, []);\n\n return (\n <div data-testid={'rich-text-editor-wrapper'}>\n {showRichTextEditorFormatting && ribbon}\n <div className={richTextEditorWrapperStyle(theme, !showRichTextEditorFormatting)}>\n <Rooster\n defaultFormat={defaultFormat}\n inDarkMode={isDarkThemed(theme)}\n plugins={plugins}\n className={richTextEditorStyle(props.styles)}\n editorCreator={editorCreator}\n // TODO: confirm the color during inline images implementation\n imageSelectionBorderColor={'blue'}\n // doNotAdjustEditorColor is used to fix the default background color for Rooster component\n doNotAdjustEditorColor={true}\n data-testid={'rooster-rich-text-editor'}\n // if we don't use 'allowKeyboardEventPropagation' only the enter key is caught\n onKeyDown={props.onKeyDown}\n focusOnInit={autoFocus === 'sendBoxTextField'}\n />\n </div>\n </div>\n );\n});\n\nconst focusAndUpdateContent = (editor: Editor, content: string): void => {\n // focus the editor to set correct selection position\n editor.focus();\n // set initial content\n editor.setContent(content);\n};\n"]}
@@ -53,7 +53,7 @@ export const RichTextSendBox = (props) => {
53
53
  setContentValue(newValue);
54
54
  }, []);
55
55
  const sendMessageOnClick = useCallback(() => {
56
- var _a, _b;
56
+ var _a, _b, _c;
57
57
  if (disabled || contentValueOverflow) {
58
58
  return;
59
59
  }
@@ -66,20 +66,29 @@ export const RichTextSendBox = (props) => {
66
66
  return;
67
67
  }
68
68
  const message = contentValue;
69
+ // get plain text content from the editor to check if the message is empty
70
+ // as the content may contain tags even when the content is empty
71
+ const plainTextContent = (_a = editorComponentRef.current) === null || _a === void 0 ? void 0 : _a.getPlainContent();
72
+ const hasContent = !isContentEmpty({
73
+ plainTextContent,
74
+ content: message,
75
+ placeholder: strings.placeholderText
76
+ });
69
77
  // we don't want to send empty messages including spaces, newlines, tabs
70
78
  // Message can be empty if there is a valid attachment upload
71
- if (sanitizeText(message).length > 0 ||
79
+ if (hasContent ||
72
80
  /* @conditional-compile-remove(attachment-upload) */ hasCompletedAttachmentUploads(activeAttachmentUploads)) {
73
81
  onSendMessage(message);
74
82
  setContentValue('');
75
- (_a = editorComponentRef.current) === null || _a === void 0 ? void 0 : _a.setEmptyContent();
83
+ (_b = editorComponentRef.current) === null || _b === void 0 ? void 0 : _b.setEmptyContent();
76
84
  }
77
- (_b = editorComponentRef.current) === null || _b === void 0 ? void 0 : _b.focus();
85
+ (_c = editorComponentRef.current) === null || _c === void 0 ? void 0 : _c.focus();
78
86
  }, [
79
87
  contentValue,
80
88
  contentValueOverflow,
81
89
  disabled,
82
90
  onSendMessage,
91
+ strings.placeholderText,
83
92
  /* @conditional-compile-remove(attachment-upload) */ activeAttachmentUploads,
84
93
  /* @conditional-compile-remove(attachment-upload) */ strings.attachmentUploadsPendingError
85
94
  ]);
@@ -99,15 +108,26 @@ export const RichTextSendBox = (props) => {
99
108
  attachmentUploadsPendingError,
100
109
  systemMessage
101
110
  ]);
102
- const onRenderSendIcon = useCallback((isHover) => (React.createElement(Icon, { iconName: isHover && contentValue ? 'SendBoxSendHovered' : 'SendBoxSend', className: sendIconStyle({
103
- theme,
104
- hasText: !!contentValue,
105
- /* @conditional-compile-remove(attachment-upload) */
106
- hasAttachment: false,
107
- hasErrorMessage: hasErrorMessage,
108
- defaultTextColor: theme.palette.neutralSecondary,
109
- disabled: disabled
110
- }) })), [contentValue, disabled, hasErrorMessage, theme]);
111
+ const onRenderSendIcon = useCallback((isHover) => {
112
+ var _a;
113
+ // get plain text content from the editor to check if the message is empty
114
+ // as the content may contain tags even when the content is empty
115
+ const plainTextContent = (_a = editorComponentRef.current) === null || _a === void 0 ? void 0 : _a.getPlainContent();
116
+ const hasContent = !isContentEmpty({
117
+ plainTextContent: plainTextContent,
118
+ content: contentValue,
119
+ placeholder: strings.placeholderText
120
+ });
121
+ return (React.createElement(Icon, { iconName: isHover && hasContent ? 'SendBoxSendHovered' : 'SendBoxSend', className: sendIconStyle({
122
+ theme,
123
+ hasText: hasContent,
124
+ /* @conditional-compile-remove(attachment-upload) */
125
+ hasAttachment: false,
126
+ hasErrorMessage: hasErrorMessage,
127
+ defaultTextColor: theme.palette.neutralSecondary,
128
+ disabled: disabled
129
+ }) }));
130
+ }, [contentValue, disabled, hasErrorMessage, strings.placeholderText, theme]);
111
131
  const sendBoxErrorsProps = useMemo(() => {
112
132
  var _a;
113
133
  return {
@@ -169,4 +189,20 @@ export const RichTextSendBox = (props) => {
169
189
  /* @conditional-compile-remove(attachment-upload) */
170
190
  hasAttachments: hasAttachmentUploads })));
171
191
  };
192
+ /**
193
+ * Checks if the content of the rich text editor is empty.
194
+ *
195
+ * @param {Object} params - The parameters for the function.
196
+ * @param {string | undefined} params.plainTextContent - The plain text content of the editor.
197
+ * @param {string} params.content - The HTML content of the editor.
198
+ * @param {string} params.placeholder - The placeholder text of the editor.
199
+ * @returns {boolean} - True if the content is empty, false otherwise.
200
+ */
201
+ const isContentEmpty = ({ plainTextContent, content, placeholder }) => {
202
+ // RoosterJS returns placeholder text as plain text when the editor is empty and in this case,
203
+ // plainTextContent contains only placeholder text but content doesn't include the placeholder text
204
+ // this needs to be reviewed after migration to the content model packages.
205
+ const plainTextContainsPlaceholderOnly = plainTextContent === placeholder && !content.includes(placeholder);
206
+ return plainTextContainsPlaceholderOnly || sanitizeText(plainTextContent !== null && plainTextContent !== void 0 ? plainTextContent : '').length === 0;
207
+ };
172
208
  //# sourceMappingURL=RichTextSendBox.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"RichTextSendBox.js","sourceRoot":"","sources":["../../../../../../../react-components/src/components/RichTextEditor/RichTextSendBox.tsx"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport React, { useCallback, useMemo, useRef, useState } from 'react';\nimport { RichTextInputBoxComponent } from './RichTextInputBoxComponent';\nimport { Icon, Stack } from '@fluentui/react';\nimport { useLocale } from '../../localization';\nimport { SendBoxStrings } from '../SendBox';\nimport { sendIconStyle } from '../styles/SendBox.styles';\nimport { InputBoxButton } from '../InputBoxButton';\nimport { RichTextSendBoxErrors, RichTextSendBoxErrorsProps } from './RichTextSendBoxErrors';\nimport { isMessageTooLong, sanitizeText } from '../utils/SendBoxUtils';\nimport { RichTextEditorComponentRef } from './RichTextEditor';\nimport { useTheme } from '../../theming';\nimport { richTextActionButtonsStyle, sendBoxRichTextEditorStyle } from '../styles/RichTextEditor.styles';\n/* @conditional-compile-remove(attachment-upload) */\nimport { _AttachmentUploadCards } from '../AttachmentUploadCards';\n/* @conditional-compile-remove(attachment-upload) */\nimport { AttachmentMetadata } from '../../types/Attachment';\n/* @conditional-compile-remove(attachment-upload) */\nimport { hasCompletedAttachmentUploads, hasIncompleteAttachmentUploads } from '../utils/SendBoxUtils';\n/* @conditional-compile-remove(attachment-upload) */\nimport { SendBoxErrorBarError } from '../SendBoxErrorBar';\n/* @conditional-compile-remove(attachment-upload) */\nimport { attachmentUploadCardsStyles } from '../styles/SendBox.styles';\n/* @conditional-compile-remove(attachment-upload) */\nimport { FluentV9ThemeProvider } from '../../theming/FluentV9ThemeProvider';\n\n/**\n * Strings of {@link RichTextSendBox} that can be overridden.\n *\n * @beta\n */\nexport interface RichTextSendBoxStrings extends SendBoxStrings {\n /**\n * Tooltip text for the bold button.\n */\n boldTooltip: string;\n /**\n * Tooltip text for the italic button.\n */\n italicTooltip: string;\n /**\n * Tooltip text for the underline button.\n */\n underlineTooltip: string;\n /**\n * Tooltip text for the bullet list button.\n */\n bulletListTooltip: string;\n /**\n * Tooltip text for the number list button.\n */\n numberListTooltip: string;\n /**\n * Tooltip text for the increase indent button.\n */\n increaseIndentTooltip: string;\n /**\n * Tooltip text for the decrease indent button.\n */\n decreaseIndentTooltip: string;\n /**\n * Tooltip text insert table button.\n */\n insertTableTooltip: string;\n /**\n * Tooltip text for the rich text format button button.\n */\n richTextFormatButtonTooltip: string;\n /**\n * Text for the insert menu item.\n */\n insertRowOrColumnMenu: string;\n /**\n * Title for the insert table menu.\n */\n insertTableMenuTitle: string;\n /**\n * Text for the insert menu item to insert row above the current selection.\n */\n insertRowAboveMenu: string;\n /**\n * Text for the insert menu item to insert row below the current selection.\n */\n insertRowBelowMenu: string;\n /**\n * Text for the insert menu item to insert column to the left from the current selection.\n */\n insertColumnLeftMenu: string;\n /**\n * Text for the insert menu item to insert column to the right from the current selection.\n */\n insertColumnRightMenu: string;\n /**\n * Text for the delete row or column menu.\n */\n deleteRowOrColumnMenu: string;\n /**\n * Text for the delete column menu.\n */\n deleteColumnMenu: string;\n /**\n * Text for the delete row menu.\n */\n deleteRowMenu: string;\n /**\n * Text for the delete table menu.\n */\n deleteTableMenu: string;\n}\n\n/**\n * Props for {@link RichTextSendBox}.\n *\n * @beta\n */\nexport interface RichTextSendBoxProps {\n /**\n * Optional boolean to disable text box\n * @defaultValue false\n */\n disabled?: boolean;\n /**\n * Optional strings to override in component\n */\n strings?: Partial<RichTextSendBoxStrings>;\n /**\n * Optional text for system message above the text box\n */\n systemMessage?: string;\n /* @conditional-compile-remove(attachment-upload) */\n /**\n * Optional array of active attachment uploads where each object has attributes\n * of a attachment upload like name, progress, errorMessage etc.\n * @beta\n */\n activeAttachmentUploads?: AttachmentMetadata[];\n /**\n * enumerable to determine if the input box has focus on render or not.\n * When undefined nothing has focus on render\n */\n autoFocus?: 'sendBoxTextField';\n /* @conditional-compile-remove(attachment-upload) */\n /**\n * Optional callback to remove the attachment upload before sending by clicking on\n * cancel icon.\n * @beta\n */\n onCancelAttachmentUpload?: (attachmentId: string) => void;\n /**\n * Callback function used when the send button is clicked.\n */\n onSendMessage: (content: string) => Promise<void>;\n /**\n * Optional callback called when user is typing\n */\n onTyping?: () => Promise<void>;\n}\n\n/**\n * A component to render SendBox with Rich Text Editor support.\n *\n * @beta\n */\nexport const RichTextSendBox = (props: RichTextSendBoxProps): JSX.Element => {\n const {\n disabled = false,\n systemMessage,\n autoFocus,\n onSendMessage,\n onTyping,\n /* @conditional-compile-remove(attachment-upload) */\n activeAttachmentUploads,\n /* @conditional-compile-remove(attachment-upload) */\n onCancelAttachmentUpload\n } = props;\n\n const theme = useTheme();\n const locale = useLocale();\n\n const localeStrings = useMemo(() => {\n /* @conditional-compile-remove(rich-text-editor) */\n return locale.strings.richTextSendBox;\n return locale.strings.sendBox;\n }, [/* @conditional-compile-remove(rich-text-editor) */ locale.strings.richTextSendBox, locale.strings.sendBox]);\n\n const strings = useMemo(() => {\n return { ...localeStrings, ...props.strings };\n }, [localeStrings, props.strings]);\n\n const [contentValue, setContentValue] = useState('');\n const [contentValueOverflow, setContentValueOverflow] = useState(false);\n /* @conditional-compile-remove(attachment-upload) */\n const [attachmentUploadsPendingError, setAttachmentUploadsPendingError] = useState<SendBoxErrorBarError | undefined>(\n undefined\n );\n const editorComponentRef = useRef<RichTextEditorComponentRef>(null);\n\n const contentTooLongMessage = useMemo(\n () => (contentValueOverflow ? strings.textTooLong : undefined),\n [contentValueOverflow, strings.textTooLong]\n );\n\n const setContent = useCallback((newValue?: string): void => {\n if (newValue === undefined) {\n return;\n }\n\n setContentValueOverflow(isMessageTooLong(newValue.length));\n setContentValue(newValue);\n }, []);\n\n const sendMessageOnClick = useCallback((): void => {\n if (disabled || contentValueOverflow) {\n return;\n }\n // Don't send message until all attachments have been uploaded successfully\n /* @conditional-compile-remove(attachment-upload) */\n setAttachmentUploadsPendingError(undefined);\n\n /* @conditional-compile-remove(attachment-upload) */\n if (hasIncompleteAttachmentUploads(activeAttachmentUploads)) {\n setAttachmentUploadsPendingError({ message: strings.attachmentUploadsPendingError, timestamp: Date.now() });\n return;\n }\n\n const message = contentValue;\n // we don't want to send empty messages including spaces, newlines, tabs\n // Message can be empty if there is a valid attachment upload\n if (\n sanitizeText(message).length > 0 ||\n /* @conditional-compile-remove(attachment-upload) */ hasCompletedAttachmentUploads(activeAttachmentUploads)\n ) {\n onSendMessage(message);\n setContentValue('');\n editorComponentRef.current?.setEmptyContent();\n }\n editorComponentRef.current?.focus();\n }, [\n contentValue,\n contentValueOverflow,\n disabled,\n onSendMessage,\n /* @conditional-compile-remove(attachment-upload) */ activeAttachmentUploads,\n /* @conditional-compile-remove(attachment-upload) */ strings.attachmentUploadsPendingError\n ]);\n\n const hasErrorMessage = useMemo(() => {\n return (\n !!systemMessage ||\n !!contentTooLongMessage ||\n /* @conditional-compile-remove(attachment-upload) */\n !!attachmentUploadsPendingError ||\n /* @conditional-compile-remove(attachment-upload) */\n !!activeAttachmentUploads?.filter((attachmentUpload) => attachmentUpload.uploadError).pop()?.uploadError\n );\n }, [\n /* @conditional-compile-remove(attachment-upload) */\n activeAttachmentUploads,\n contentTooLongMessage,\n /* @conditional-compile-remove(attachment-upload) */\n attachmentUploadsPendingError,\n systemMessage\n ]);\n\n const onRenderSendIcon = useCallback(\n (isHover: boolean) => (\n <Icon\n iconName={isHover && contentValue ? 'SendBoxSendHovered' : 'SendBoxSend'}\n className={sendIconStyle({\n theme,\n hasText: !!contentValue,\n /* @conditional-compile-remove(attachment-upload) */\n hasAttachment: false,\n hasErrorMessage: hasErrorMessage,\n defaultTextColor: theme.palette.neutralSecondary,\n disabled: disabled\n })}\n />\n ),\n [contentValue, disabled, hasErrorMessage, theme]\n );\n\n const sendBoxErrorsProps: RichTextSendBoxErrorsProps = useMemo(() => {\n return {\n /* @conditional-compile-remove(attachment-upload) */\n attachmentUploadsPendingError: attachmentUploadsPendingError,\n /* @conditional-compile-remove(attachment-upload) */\n attachmentUploadError: activeAttachmentUploads?.filter((attachmentUpload) => attachmentUpload.uploadError).pop()\n ?.uploadError,\n systemMessage: systemMessage,\n textTooLongMessage: contentTooLongMessage\n };\n }, [\n /* @conditional-compile-remove(attachment-upload) */\n activeAttachmentUploads,\n contentTooLongMessage,\n /* @conditional-compile-remove(attachment-upload) */\n attachmentUploadsPendingError,\n systemMessage\n ]);\n\n /* @conditional-compile-remove(attachment-upload) */\n const onRenderAttachmentUploads = useCallback(() => {\n return (\n <Stack className={attachmentUploadCardsStyles}>\n <FluentV9ThemeProvider v8Theme={theme}>\n <_AttachmentUploadCards\n activeAttachmentUploads={activeAttachmentUploads}\n onCancelAttachmentUpload={onCancelAttachmentUpload}\n strings={{\n removeAttachment: strings.removeAttachment,\n uploading: strings.uploading,\n uploadCompleted: strings.uploadCompleted,\n attachmentMoreMenu: strings.attachmentMoreMenu\n }}\n />\n </FluentV9ThemeProvider>\n </Stack>\n );\n }, [\n activeAttachmentUploads,\n onCancelAttachmentUpload,\n strings.removeAttachment,\n strings.uploadCompleted,\n strings.uploading,\n strings.attachmentMoreMenu,\n theme\n ]);\n\n const sendButton = useMemo(() => {\n return (\n <InputBoxButton\n onRenderIcon={onRenderSendIcon}\n onClick={(e) => {\n sendMessageOnClick();\n e.stopPropagation(); // Prevents the click from bubbling up and triggering a focus event on the chat.\n }}\n className={richTextActionButtonsStyle}\n ariaLabel={localeStrings.sendButtonAriaLabel}\n tooltipContent={localeStrings.sendButtonAriaLabel}\n />\n );\n }, [localeStrings.sendButtonAriaLabel, onRenderSendIcon, sendMessageOnClick]);\n\n /* @conditional-compile-remove(attachment-upload) */\n const hasAttachmentUploads = useMemo(() => {\n return (\n hasCompletedAttachmentUploads(activeAttachmentUploads) || hasIncompleteAttachmentUploads(activeAttachmentUploads)\n );\n }, [activeAttachmentUploads]);\n\n return (\n <Stack>\n <RichTextSendBoxErrors {...sendBoxErrorsProps} />\n <RichTextInputBoxComponent\n // in case when format bar is shown, the editor is re-rendered that causes the content to be lost\n // setting the content will ensure that the latest content is used when editor is re-rendered\n content={contentValue}\n placeholderText={strings.placeholderText}\n autoFocus={autoFocus}\n onChange={setContent}\n onEnterKeyDown={sendMessageOnClick}\n onTyping={onTyping}\n editorComponentRef={editorComponentRef}\n strings={strings}\n disabled={disabled}\n actionComponents={sendButton}\n richTextEditorStyleProps={sendBoxRichTextEditorStyle}\n /* @conditional-compile-remove(attachment-upload) */\n onRenderAttachmentUploads={onRenderAttachmentUploads}\n /* @conditional-compile-remove(attachment-upload) */\n hasAttachments={hasAttachmentUploads}\n />\n </Stack>\n );\n};\n"]}
1
+ {"version":3,"file":"RichTextSendBox.js","sourceRoot":"","sources":["../../../../../../../react-components/src/components/RichTextEditor/RichTextSendBox.tsx"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport React, { useCallback, useMemo, useRef, useState } from 'react';\nimport { RichTextInputBoxComponent } from './RichTextInputBoxComponent';\nimport { Icon, Stack } from '@fluentui/react';\nimport { useLocale } from '../../localization';\nimport { SendBoxStrings } from '../SendBox';\nimport { sendIconStyle } from '../styles/SendBox.styles';\nimport { InputBoxButton } from '../InputBoxButton';\nimport { RichTextSendBoxErrors, RichTextSendBoxErrorsProps } from './RichTextSendBoxErrors';\nimport { isMessageTooLong, sanitizeText } from '../utils/SendBoxUtils';\nimport { RichTextEditorComponentRef } from './RichTextEditor';\nimport { useTheme } from '../../theming';\nimport { richTextActionButtonsStyle, sendBoxRichTextEditorStyle } from '../styles/RichTextEditor.styles';\n/* @conditional-compile-remove(attachment-upload) */\nimport { _AttachmentUploadCards } from '../AttachmentUploadCards';\n/* @conditional-compile-remove(attachment-upload) */\nimport { AttachmentMetadata } from '../../types/Attachment';\n/* @conditional-compile-remove(attachment-upload) */\nimport { hasCompletedAttachmentUploads, hasIncompleteAttachmentUploads } from '../utils/SendBoxUtils';\n/* @conditional-compile-remove(attachment-upload) */\nimport { SendBoxErrorBarError } from '../SendBoxErrorBar';\n/* @conditional-compile-remove(attachment-upload) */\nimport { attachmentUploadCardsStyles } from '../styles/SendBox.styles';\n/* @conditional-compile-remove(attachment-upload) */\nimport { FluentV9ThemeProvider } from '../../theming/FluentV9ThemeProvider';\n\n/**\n * Strings of {@link RichTextSendBox} that can be overridden.\n *\n * @beta\n */\nexport interface RichTextSendBoxStrings extends SendBoxStrings {\n /**\n * Tooltip text for the bold button.\n */\n boldTooltip: string;\n /**\n * Tooltip text for the italic button.\n */\n italicTooltip: string;\n /**\n * Tooltip text for the underline button.\n */\n underlineTooltip: string;\n /**\n * Tooltip text for the bullet list button.\n */\n bulletListTooltip: string;\n /**\n * Tooltip text for the number list button.\n */\n numberListTooltip: string;\n /**\n * Tooltip text for the increase indent button.\n */\n increaseIndentTooltip: string;\n /**\n * Tooltip text for the decrease indent button.\n */\n decreaseIndentTooltip: string;\n /**\n * Tooltip text insert table button.\n */\n insertTableTooltip: string;\n /**\n * Tooltip text for the rich text format button button.\n */\n richTextFormatButtonTooltip: string;\n /**\n * Text for the insert menu item.\n */\n insertRowOrColumnMenu: string;\n /**\n * Title for the insert table menu.\n */\n insertTableMenuTitle: string;\n /**\n * Text for the insert menu item to insert row above the current selection.\n */\n insertRowAboveMenu: string;\n /**\n * Text for the insert menu item to insert row below the current selection.\n */\n insertRowBelowMenu: string;\n /**\n * Text for the insert menu item to insert column to the left from the current selection.\n */\n insertColumnLeftMenu: string;\n /**\n * Text for the insert menu item to insert column to the right from the current selection.\n */\n insertColumnRightMenu: string;\n /**\n * Text for the delete row or column menu.\n */\n deleteRowOrColumnMenu: string;\n /**\n * Text for the delete column menu.\n */\n deleteColumnMenu: string;\n /**\n * Text for the delete row menu.\n */\n deleteRowMenu: string;\n /**\n * Text for the delete table menu.\n */\n deleteTableMenu: string;\n}\n\n/**\n * Props for {@link RichTextSendBox}.\n *\n * @beta\n */\nexport interface RichTextSendBoxProps {\n /**\n * Optional boolean to disable text box\n * @defaultValue false\n */\n disabled?: boolean;\n /**\n * Optional strings to override in component\n */\n strings?: Partial<RichTextSendBoxStrings>;\n /**\n * Optional text for system message above the text box\n */\n systemMessage?: string;\n /* @conditional-compile-remove(attachment-upload) */\n /**\n * Optional array of active attachment uploads where each object has attributes\n * of a attachment upload like name, progress, errorMessage etc.\n * @beta\n */\n activeAttachmentUploads?: AttachmentMetadata[];\n /**\n * enumerable to determine if the input box has focus on render or not.\n * When undefined nothing has focus on render\n */\n autoFocus?: 'sendBoxTextField';\n /* @conditional-compile-remove(attachment-upload) */\n /**\n * Optional callback to remove the attachment upload before sending by clicking on\n * cancel icon.\n * @beta\n */\n onCancelAttachmentUpload?: (attachmentId: string) => void;\n /**\n * Callback function used when the send button is clicked.\n */\n onSendMessage: (content: string) => Promise<void>;\n /**\n * Optional callback called when user is typing\n */\n onTyping?: () => Promise<void>;\n}\n\n/**\n * A component to render SendBox with Rich Text Editor support.\n *\n * @beta\n */\nexport const RichTextSendBox = (props: RichTextSendBoxProps): JSX.Element => {\n const {\n disabled = false,\n systemMessage,\n autoFocus,\n onSendMessage,\n onTyping,\n /* @conditional-compile-remove(attachment-upload) */\n activeAttachmentUploads,\n /* @conditional-compile-remove(attachment-upload) */\n onCancelAttachmentUpload\n } = props;\n\n const theme = useTheme();\n const locale = useLocale();\n\n const localeStrings = useMemo(() => {\n /* @conditional-compile-remove(rich-text-editor) */\n return locale.strings.richTextSendBox;\n return locale.strings.sendBox;\n }, [/* @conditional-compile-remove(rich-text-editor) */ locale.strings.richTextSendBox, locale.strings.sendBox]);\n\n const strings = useMemo(() => {\n return { ...localeStrings, ...props.strings };\n }, [localeStrings, props.strings]);\n\n const [contentValue, setContentValue] = useState('');\n const [contentValueOverflow, setContentValueOverflow] = useState(false);\n /* @conditional-compile-remove(attachment-upload) */\n const [attachmentUploadsPendingError, setAttachmentUploadsPendingError] = useState<SendBoxErrorBarError | undefined>(\n undefined\n );\n const editorComponentRef = useRef<RichTextEditorComponentRef>(null);\n\n const contentTooLongMessage = useMemo(\n () => (contentValueOverflow ? strings.textTooLong : undefined),\n [contentValueOverflow, strings.textTooLong]\n );\n\n const setContent = useCallback((newValue?: string): void => {\n if (newValue === undefined) {\n return;\n }\n\n setContentValueOverflow(isMessageTooLong(newValue.length));\n setContentValue(newValue);\n }, []);\n\n const sendMessageOnClick = useCallback((): void => {\n if (disabled || contentValueOverflow) {\n return;\n }\n // Don't send message until all attachments have been uploaded successfully\n /* @conditional-compile-remove(attachment-upload) */\n setAttachmentUploadsPendingError(undefined);\n\n /* @conditional-compile-remove(attachment-upload) */\n if (hasIncompleteAttachmentUploads(activeAttachmentUploads)) {\n setAttachmentUploadsPendingError({ message: strings.attachmentUploadsPendingError, timestamp: Date.now() });\n return;\n }\n\n const message = contentValue;\n // get plain text content from the editor to check if the message is empty\n // as the content may contain tags even when the content is empty\n const plainTextContent = editorComponentRef.current?.getPlainContent();\n const hasContent = !isContentEmpty({\n plainTextContent,\n content: message,\n placeholder: strings.placeholderText\n });\n // we don't want to send empty messages including spaces, newlines, tabs\n // Message can be empty if there is a valid attachment upload\n if (\n hasContent ||\n /* @conditional-compile-remove(attachment-upload) */ hasCompletedAttachmentUploads(activeAttachmentUploads)\n ) {\n onSendMessage(message);\n setContentValue('');\n editorComponentRef.current?.setEmptyContent();\n }\n editorComponentRef.current?.focus();\n }, [\n contentValue,\n contentValueOverflow,\n disabled,\n onSendMessage,\n strings.placeholderText,\n /* @conditional-compile-remove(attachment-upload) */ activeAttachmentUploads,\n /* @conditional-compile-remove(attachment-upload) */ strings.attachmentUploadsPendingError\n ]);\n\n const hasErrorMessage = useMemo(() => {\n return (\n !!systemMessage ||\n !!contentTooLongMessage ||\n /* @conditional-compile-remove(attachment-upload) */\n !!attachmentUploadsPendingError ||\n /* @conditional-compile-remove(attachment-upload) */\n !!activeAttachmentUploads?.filter((attachmentUpload) => attachmentUpload.uploadError).pop()?.uploadError\n );\n }, [\n /* @conditional-compile-remove(attachment-upload) */\n activeAttachmentUploads,\n contentTooLongMessage,\n /* @conditional-compile-remove(attachment-upload) */\n attachmentUploadsPendingError,\n systemMessage\n ]);\n\n const onRenderSendIcon = useCallback(\n (isHover: boolean) => {\n // get plain text content from the editor to check if the message is empty\n // as the content may contain tags even when the content is empty\n const plainTextContent = editorComponentRef.current?.getPlainContent();\n const hasContent = !isContentEmpty({\n plainTextContent: plainTextContent,\n content: contentValue,\n placeholder: strings.placeholderText\n });\n return (\n <Icon\n iconName={isHover && hasContent ? 'SendBoxSendHovered' : 'SendBoxSend'}\n className={sendIconStyle({\n theme,\n hasText: hasContent,\n /* @conditional-compile-remove(attachment-upload) */\n hasAttachment: false,\n hasErrorMessage: hasErrorMessage,\n defaultTextColor: theme.palette.neutralSecondary,\n disabled: disabled\n })}\n />\n );\n },\n [contentValue, disabled, hasErrorMessage, strings.placeholderText, theme]\n );\n\n const sendBoxErrorsProps: RichTextSendBoxErrorsProps = useMemo(() => {\n return {\n /* @conditional-compile-remove(attachment-upload) */\n attachmentUploadsPendingError: attachmentUploadsPendingError,\n /* @conditional-compile-remove(attachment-upload) */\n attachmentUploadError: activeAttachmentUploads?.filter((attachmentUpload) => attachmentUpload.uploadError).pop()\n ?.uploadError,\n systemMessage: systemMessage,\n textTooLongMessage: contentTooLongMessage\n };\n }, [\n /* @conditional-compile-remove(attachment-upload) */\n activeAttachmentUploads,\n contentTooLongMessage,\n /* @conditional-compile-remove(attachment-upload) */\n attachmentUploadsPendingError,\n systemMessage\n ]);\n\n /* @conditional-compile-remove(attachment-upload) */\n const onRenderAttachmentUploads = useCallback(() => {\n return (\n <Stack className={attachmentUploadCardsStyles}>\n <FluentV9ThemeProvider v8Theme={theme}>\n <_AttachmentUploadCards\n activeAttachmentUploads={activeAttachmentUploads}\n onCancelAttachmentUpload={onCancelAttachmentUpload}\n strings={{\n removeAttachment: strings.removeAttachment,\n uploading: strings.uploading,\n uploadCompleted: strings.uploadCompleted,\n attachmentMoreMenu: strings.attachmentMoreMenu\n }}\n />\n </FluentV9ThemeProvider>\n </Stack>\n );\n }, [\n activeAttachmentUploads,\n onCancelAttachmentUpload,\n strings.removeAttachment,\n strings.uploadCompleted,\n strings.uploading,\n strings.attachmentMoreMenu,\n theme\n ]);\n\n const sendButton = useMemo(() => {\n return (\n <InputBoxButton\n onRenderIcon={onRenderSendIcon}\n onClick={(e) => {\n sendMessageOnClick();\n e.stopPropagation(); // Prevents the click from bubbling up and triggering a focus event on the chat.\n }}\n className={richTextActionButtonsStyle}\n ariaLabel={localeStrings.sendButtonAriaLabel}\n tooltipContent={localeStrings.sendButtonAriaLabel}\n />\n );\n }, [localeStrings.sendButtonAriaLabel, onRenderSendIcon, sendMessageOnClick]);\n\n /* @conditional-compile-remove(attachment-upload) */\n const hasAttachmentUploads = useMemo(() => {\n return (\n hasCompletedAttachmentUploads(activeAttachmentUploads) || hasIncompleteAttachmentUploads(activeAttachmentUploads)\n );\n }, [activeAttachmentUploads]);\n\n return (\n <Stack>\n <RichTextSendBoxErrors {...sendBoxErrorsProps} />\n <RichTextInputBoxComponent\n // in case when format bar is shown, the editor is re-rendered that causes the content to be lost\n // setting the content will ensure that the latest content is used when editor is re-rendered\n content={contentValue}\n placeholderText={strings.placeholderText}\n autoFocus={autoFocus}\n onChange={setContent}\n onEnterKeyDown={sendMessageOnClick}\n onTyping={onTyping}\n editorComponentRef={editorComponentRef}\n strings={strings}\n disabled={disabled}\n actionComponents={sendButton}\n richTextEditorStyleProps={sendBoxRichTextEditorStyle}\n /* @conditional-compile-remove(attachment-upload) */\n onRenderAttachmentUploads={onRenderAttachmentUploads}\n /* @conditional-compile-remove(attachment-upload) */\n hasAttachments={hasAttachmentUploads}\n />\n </Stack>\n );\n};\n\n/**\n * Checks if the content of the rich text editor is empty.\n *\n * @param {Object} params - The parameters for the function.\n * @param {string | undefined} params.plainTextContent - The plain text content of the editor.\n * @param {string} params.content - The HTML content of the editor.\n * @param {string} params.placeholder - The placeholder text of the editor.\n * @returns {boolean} - True if the content is empty, false otherwise.\n */\nconst isContentEmpty = ({\n plainTextContent,\n content,\n placeholder\n}: {\n plainTextContent: string | undefined;\n content: string;\n placeholder: string;\n}): boolean => {\n // RoosterJS returns placeholder text as plain text when the editor is empty and in this case,\n // plainTextContent contains only placeholder text but content doesn't include the placeholder text\n // this needs to be reviewed after migration to the content model packages.\n const plainTextContainsPlaceholderOnly = plainTextContent === placeholder && !content.includes(placeholder);\n return plainTextContainsPlaceholderOnly || sanitizeText(plainTextContent ?? '').length === 0;\n};\n"]}
@@ -7,7 +7,7 @@ import { isNarrowWidth } from '../utils/responsive';
7
7
  import { isShortHeight } from '../utils/responsive';
8
8
  import { rootLayoutStyle } from './styles/DefaultLayout.styles';
9
9
  import { videoGalleryLayoutGap } from './styles/Layout.styles';
10
- import { useOrganizedParticipants } from './utils/videoGalleryLayoutUtils';
10
+ import { MAX_GRID_PARTICIPANTS_NOT_LARGE_GALLERY, useOrganizedParticipants } from './utils/videoGalleryLayoutUtils';
11
11
  import { OverflowGallery } from './OverflowGallery';
12
12
  /**
13
13
  * DefaultLayout displays remote participants, local video component, and screen sharing component in
@@ -24,11 +24,12 @@ export const DefaultLayout = (props) => {
24
24
  // This number will be used for the maxOverflowGalleryDominantSpeakers when organizing the remote participants.
25
25
  // We need to add the local participant to the pinned participant count so we are placing the speakers correctly.
26
26
  const childrenPerPage = useRef(4);
27
+ const remoteVideosOn = remoteParticipants.filter((p) => { var _a; return (_a = p.videoStream) === null || _a === void 0 ? void 0 : _a.isAvailable; }).length > 0;
27
28
  const { gridParticipants, overflowGalleryParticipants } = useOrganizedParticipants({
28
29
  remoteParticipants,
29
30
  localParticipant,
30
31
  dominantSpeakers,
31
- maxRemoteVideoStreams,
32
+ maxGridParticipants: remoteVideosOn ? maxRemoteVideoStreams : MAX_GRID_PARTICIPANTS_NOT_LARGE_GALLERY,
32
33
  isScreenShareActive: !!screenShareComponent,
33
34
  maxOverflowGalleryDominantSpeakers: screenShareComponent
34
35
  ? childrenPerPage.current - ((pinnedParticipantUserIds.length + 1) % childrenPerPage.current)
@@ -1 +1 @@
1
- {"version":3,"file":"DefaultLayout.js","sourceRoot":"","sources":["../../../../../../../react-components/src/components/VideoGallery/DefaultLayout.tsx"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport { Stack } from '@fluentui/react';\nimport React, { useMemo, useState, useRef } from 'react';\nimport { GridLayout } from '../GridLayout';\nimport { isNarrowWidth } from '../utils/responsive';\nimport { isShortHeight } from '../utils/responsive';\nimport { LayoutProps } from './Layout';\nimport { rootLayoutStyle } from './styles/DefaultLayout.styles';\nimport { videoGalleryLayoutGap } from './styles/Layout.styles';\nimport { useOrganizedParticipants } from './utils/videoGalleryLayoutUtils';\nimport { OverflowGallery } from './OverflowGallery';\n\n/**\n * Props for {@link DefaultLayout}.\n *\n * @private\n */\nexport type DefaultLayoutProps = LayoutProps;\n\n/**\n * DefaultLayout displays remote participants, local video component, and screen sharing component in\n * a grid an overflow gallery.\n *\n * @private\n */\nexport const DefaultLayout = (props: DefaultLayoutProps): JSX.Element => {\n const {\n remoteParticipants = [],\n localParticipant,\n dominantSpeakers,\n localVideoComponent,\n screenShareComponent,\n onRenderRemoteParticipant,\n styles,\n maxRemoteVideoStreams,\n parentWidth,\n parentHeight,\n pinnedParticipantUserIds = [],\n overflowGalleryPosition = 'horizontalBottom',\n /* @conditional-compile-remove(spotlight) */ spotlightedParticipantUserIds = []\n } = props;\n\n const isNarrow = parentWidth ? isNarrowWidth(parentWidth) : false;\n\n const isShort = parentHeight ? isShortHeight(parentHeight) : false;\n\n // This is for tracking the number of children in the first page of overflow gallery.\n // This number will be used for the maxOverflowGalleryDominantSpeakers when organizing the remote participants.\n // We need to add the local participant to the pinned participant count so we are placing the speakers correctly.\n const childrenPerPage = useRef(4);\n const { gridParticipants, overflowGalleryParticipants } = useOrganizedParticipants({\n remoteParticipants,\n localParticipant,\n dominantSpeakers,\n maxRemoteVideoStreams,\n isScreenShareActive: !!screenShareComponent,\n maxOverflowGalleryDominantSpeakers: screenShareComponent\n ? childrenPerPage.current - ((pinnedParticipantUserIds.length + 1) % childrenPerPage.current)\n : childrenPerPage.current,\n pinnedParticipantUserIds,\n layout: 'default',\n /* @conditional-compile-remove(spotlight) */ spotlightedParticipantUserIds\n });\n\n let activeVideoStreams = 0;\n\n let gridTiles = gridParticipants.map((p) => {\n return onRenderRemoteParticipant(\n p,\n maxRemoteVideoStreams && maxRemoteVideoStreams >= 0\n ? p.videoStream?.isAvailable && activeVideoStreams++ < maxRemoteVideoStreams\n : p.videoStream?.isAvailable\n );\n });\n\n /**\n * instantiate indexes available to render with indexes available that would be on first page\n *\n * For some components which do not strictly follow the order of the array, we might\n * re-render the initial tiles -> dispose them -> create new tiles, we need to take care of\n * this case when those components are here\n */\n const [indexesToRender, setIndexesToRender] = useState<number[]>([]);\n\n let overflowGalleryTiles = overflowGalleryParticipants.map((p, i) => {\n return onRenderRemoteParticipant(\n p,\n maxRemoteVideoStreams && maxRemoteVideoStreams >= 0\n ? p.videoStream?.isAvailable && indexesToRender.includes(i) && activeVideoStreams++ < maxRemoteVideoStreams\n : p.videoStream?.isAvailable\n );\n });\n\n if (localVideoComponent) {\n if (screenShareComponent || /* @conditional-compile-remove(spotlight) */ spotlightedParticipantUserIds.length > 0) {\n overflowGalleryTiles = [localVideoComponent].concat(overflowGalleryTiles);\n } else {\n gridTiles = [localVideoComponent].concat(gridTiles);\n }\n }\n\n const overflowGallery = useMemo(() => {\n if (overflowGalleryTiles.length === 0) {\n return null;\n }\n return (\n <OverflowGallery\n isNarrow={isNarrow}\n isShort={isShort}\n shouldFloatLocalVideo={false}\n overflowGalleryElements={overflowGalleryTiles}\n horizontalGalleryStyles={styles?.horizontalGallery}\n verticalGalleryStyles={styles?.verticalGallery}\n overflowGalleryPosition={overflowGalleryPosition}\n onFetchTilesToRender={setIndexesToRender}\n onChildrenPerPageChange={(n: number) => {\n childrenPerPage.current = n;\n }}\n parentWidth={parentWidth}\n />\n );\n }, [\n isNarrow,\n isShort,\n overflowGalleryTiles,\n styles?.horizontalGallery,\n overflowGalleryPosition,\n setIndexesToRender,\n styles?.verticalGallery,\n parentWidth\n ]);\n\n return (\n <Stack\n horizontal={overflowGalleryPosition === 'verticalRight'}\n styles={rootLayoutStyle}\n tokens={videoGalleryLayoutGap}\n >\n {props.overflowGalleryPosition === 'horizontalTop' ? overflowGallery : <></>}\n {screenShareComponent ? (\n screenShareComponent\n ) : (\n <GridLayout key=\"grid-layout\" styles={styles?.gridLayout}>\n {gridTiles}\n </GridLayout>\n )}\n {overflowGalleryTrampoline(overflowGallery, props.overflowGalleryPosition)}\n </Stack>\n );\n};\n\nconst overflowGalleryTrampoline = (\n gallery: JSX.Element | null,\n galleryPosition?: 'horizontalBottom' | 'verticalRight' | 'horizontalTop'\n): JSX.Element | null => {\n return galleryPosition !== 'horizontalTop' ? gallery : <></>;\n return gallery;\n};\n"]}
1
+ {"version":3,"file":"DefaultLayout.js","sourceRoot":"","sources":["../../../../../../../react-components/src/components/VideoGallery/DefaultLayout.tsx"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport { Stack } from '@fluentui/react';\nimport React, { useMemo, useState, useRef } from 'react';\nimport { GridLayout } from '../GridLayout';\nimport { isNarrowWidth } from '../utils/responsive';\nimport { isShortHeight } from '../utils/responsive';\nimport { LayoutProps } from './Layout';\nimport { rootLayoutStyle } from './styles/DefaultLayout.styles';\nimport { videoGalleryLayoutGap } from './styles/Layout.styles';\nimport { MAX_GRID_PARTICIPANTS_NOT_LARGE_GALLERY, useOrganizedParticipants } from './utils/videoGalleryLayoutUtils';\nimport { OverflowGallery } from './OverflowGallery';\n\n/**\n * Props for {@link DefaultLayout}.\n *\n * @private\n */\nexport type DefaultLayoutProps = LayoutProps;\n\n/**\n * DefaultLayout displays remote participants, local video component, and screen sharing component in\n * a grid an overflow gallery.\n *\n * @private\n */\nexport const DefaultLayout = (props: DefaultLayoutProps): JSX.Element => {\n const {\n remoteParticipants = [],\n localParticipant,\n dominantSpeakers,\n localVideoComponent,\n screenShareComponent,\n onRenderRemoteParticipant,\n styles,\n maxRemoteVideoStreams,\n parentWidth,\n parentHeight,\n pinnedParticipantUserIds = [],\n overflowGalleryPosition = 'horizontalBottom',\n /* @conditional-compile-remove(spotlight) */ spotlightedParticipantUserIds = []\n } = props;\n\n const isNarrow = parentWidth ? isNarrowWidth(parentWidth) : false;\n\n const isShort = parentHeight ? isShortHeight(parentHeight) : false;\n\n // This is for tracking the number of children in the first page of overflow gallery.\n // This number will be used for the maxOverflowGalleryDominantSpeakers when organizing the remote participants.\n // We need to add the local participant to the pinned participant count so we are placing the speakers correctly.\n const childrenPerPage = useRef(4);\n const remoteVideosOn = remoteParticipants.filter((p) => p.videoStream?.isAvailable).length > 0;\n const { gridParticipants, overflowGalleryParticipants } = useOrganizedParticipants({\n remoteParticipants,\n localParticipant,\n dominantSpeakers,\n maxGridParticipants: remoteVideosOn ? maxRemoteVideoStreams : MAX_GRID_PARTICIPANTS_NOT_LARGE_GALLERY,\n isScreenShareActive: !!screenShareComponent,\n maxOverflowGalleryDominantSpeakers: screenShareComponent\n ? childrenPerPage.current - ((pinnedParticipantUserIds.length + 1) % childrenPerPage.current)\n : childrenPerPage.current,\n pinnedParticipantUserIds,\n layout: 'default',\n /* @conditional-compile-remove(spotlight) */ spotlightedParticipantUserIds\n });\n\n let activeVideoStreams = 0;\n\n let gridTiles = gridParticipants.map((p) => {\n return onRenderRemoteParticipant(\n p,\n maxRemoteVideoStreams && maxRemoteVideoStreams >= 0\n ? p.videoStream?.isAvailable && activeVideoStreams++ < maxRemoteVideoStreams\n : p.videoStream?.isAvailable\n );\n });\n\n /**\n * instantiate indexes available to render with indexes available that would be on first page\n *\n * For some components which do not strictly follow the order of the array, we might\n * re-render the initial tiles -> dispose them -> create new tiles, we need to take care of\n * this case when those components are here\n */\n const [indexesToRender, setIndexesToRender] = useState<number[]>([]);\n\n let overflowGalleryTiles = overflowGalleryParticipants.map((p, i) => {\n return onRenderRemoteParticipant(\n p,\n maxRemoteVideoStreams && maxRemoteVideoStreams >= 0\n ? p.videoStream?.isAvailable && indexesToRender.includes(i) && activeVideoStreams++ < maxRemoteVideoStreams\n : p.videoStream?.isAvailable\n );\n });\n\n if (localVideoComponent) {\n if (screenShareComponent || /* @conditional-compile-remove(spotlight) */ spotlightedParticipantUserIds.length > 0) {\n overflowGalleryTiles = [localVideoComponent].concat(overflowGalleryTiles);\n } else {\n gridTiles = [localVideoComponent].concat(gridTiles);\n }\n }\n\n const overflowGallery = useMemo(() => {\n if (overflowGalleryTiles.length === 0) {\n return null;\n }\n return (\n <OverflowGallery\n isNarrow={isNarrow}\n isShort={isShort}\n shouldFloatLocalVideo={false}\n overflowGalleryElements={overflowGalleryTiles}\n horizontalGalleryStyles={styles?.horizontalGallery}\n verticalGalleryStyles={styles?.verticalGallery}\n overflowGalleryPosition={overflowGalleryPosition}\n onFetchTilesToRender={setIndexesToRender}\n onChildrenPerPageChange={(n: number) => {\n childrenPerPage.current = n;\n }}\n parentWidth={parentWidth}\n />\n );\n }, [\n isNarrow,\n isShort,\n overflowGalleryTiles,\n styles?.horizontalGallery,\n overflowGalleryPosition,\n setIndexesToRender,\n styles?.verticalGallery,\n parentWidth\n ]);\n\n return (\n <Stack\n horizontal={overflowGalleryPosition === 'verticalRight'}\n styles={rootLayoutStyle}\n tokens={videoGalleryLayoutGap}\n >\n {props.overflowGalleryPosition === 'horizontalTop' ? overflowGallery : <></>}\n {screenShareComponent ? (\n screenShareComponent\n ) : (\n <GridLayout key=\"grid-layout\" styles={styles?.gridLayout}>\n {gridTiles}\n </GridLayout>\n )}\n {overflowGalleryTrampoline(overflowGallery, props.overflowGalleryPosition)}\n </Stack>\n );\n};\n\nconst overflowGalleryTrampoline = (\n gallery: JSX.Element | null,\n galleryPosition?: 'horizontalBottom' | 'verticalRight' | 'horizontalTop'\n): JSX.Element | null => {\n return galleryPosition !== 'horizontalTop' ? gallery : <></>;\n return gallery;\n};\n"]}
@@ -12,7 +12,7 @@ import { LARGE_FLOATING_MODAL_SIZE_REM, localVideoTileContainerStyle, localVideo
12
12
  import { SHORT_VERTICAL_GALLERY_FLOATING_MODAL_SIZE_REM, VERTICAL_GALLERY_FLOATING_MODAL_SIZE_REM } from './styles/FloatingLocalVideo.styles';
13
13
  import { innerLayoutStyle, layerHostStyle, rootLayoutStyle } from './styles/FloatingLocalVideoLayout.styles';
14
14
  import { videoGalleryLayoutGap } from './styles/Layout.styles';
15
- import { useOrganizedParticipants } from './utils/videoGalleryLayoutUtils';
15
+ import { MAX_GRID_PARTICIPANTS_NOT_LARGE_GALLERY, useOrganizedParticipants } from './utils/videoGalleryLayoutUtils';
16
16
  import { OverflowGallery } from './OverflowGallery';
17
17
  /**
18
18
  * FloatingLocalVideoLayout displays remote participants and a screen sharing component in
@@ -29,10 +29,11 @@ export const FloatingLocalVideoLayout = (props) => {
29
29
  // This is for tracking the number of children in the first page of overflow gallery.
30
30
  // This number will be used for the maxOverflowGalleryDominantSpeakers when organizing the remote participants.
31
31
  const childrenPerPage = useRef(4);
32
+ const remoteVideosOn = remoteParticipants.filter((p) => { var _a; return (_a = p.videoStream) === null || _a === void 0 ? void 0 : _a.isAvailable; }).length > 0;
32
33
  const { gridParticipants, overflowGalleryParticipants } = useOrganizedParticipants({
33
34
  remoteParticipants,
34
35
  dominantSpeakers,
35
- maxRemoteVideoStreams,
36
+ maxGridParticipants: remoteVideosOn ? maxRemoteVideoStreams : MAX_GRID_PARTICIPANTS_NOT_LARGE_GALLERY,
36
37
  isScreenShareActive: !!screenShareComponent,
37
38
  maxOverflowGalleryDominantSpeakers: screenShareComponent
38
39
  ? childrenPerPage.current - (pinnedParticipantUserIds.length % childrenPerPage.current)
@@ -1 +1 @@
1
- {"version":3,"file":"FloatingLocalVideoLayout.js","sourceRoot":"","sources":["../../../../../../../react-components/src/components/VideoGallery/FloatingLocalVideoLayout.tsx"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAElC,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAChE,OAAO,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAC9C,OAAO,KAAK,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE1D,OAAO,EACL,6BAA6B,EAC7B,4BAA4B,EAC5B,wCAAwC,EACxC,uBAAuB,EACvB,6BAA6B,EAC9B,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EACL,8CAA8C,EAC9C,wCAAwC,EACzC,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,0CAA0C,CAAC;AAC7G,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;AAC3E,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAuBpD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,KAAoC,EAAe,EAAE;IAC5F,MAAM,EACJ,kBAAkB,GAAG,EAAE,EACvB,gBAAgB,EAChB,mBAAmB,EACnB,oBAAoB,EACpB,yBAAyB,EACzB,MAAM,EACN,qBAAqB,EACrB,gCAAgC,EAChC,WAAW,EACX,YAAY,EACZ,uBAAuB,GAAG,kBAAkB,EAC5C,wBAAwB,GAAG,EAAE,EAC7B,kBAAkB;IAClB,4CAA4C,CAAC,6BAA6B,EAC3E,GAAG,KAAK,CAAC;IAEV,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAC;IAEzB,MAAM,QAAQ,GAAG,WAAW,CAAC,CAAC,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IAElE,MAAM,OAAO,GAAG,YAAY,CAAC,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IAEnE,qFAAqF;IACrF,+GAA+G;IAC/G,MAAM,eAAe,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;IAClC,MAAM,EAAE,gBAAgB,EAAE,2BAA2B,EAAE,GAAG,wBAAwB,CAAC;QACjF,kBAAkB;QAClB,gBAAgB;QAChB,qBAAqB;QACrB,mBAAmB,EAAE,CAAC,CAAC,oBAAoB;QAC3C,kCAAkC,EAAE,oBAAoB;YACtD,CAAC,CAAC,eAAe,CAAC,OAAO,GAAG,CAAC,wBAAwB,CAAC,MAAM,GAAG,eAAe,CAAC,OAAO,CAAC;YACvF,CAAC,CAAC,eAAe,CAAC,OAAO;QAC3B,wBAAwB;QACxB,MAAM,EAAE,oBAAoB;QAC5B,4CAA4C,CAAC,6BAA6B;KAC3E,CAAC,CAAC;IAEH,IAAI,kBAAkB,GAAG,CAAC,CAAC;IAE3B,MAAM,SAAS,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;;QAC3C,OAAO,yBAAyB,CAC9B,CAAC,EACD,qBAAqB,IAAI,qBAAqB,IAAI,CAAC;YACjD,CAAC,CAAC,CAAA,MAAA,CAAC,CAAC,WAAW,0CAAE,WAAW,KAAI,kBAAkB,EAAE,GAAG,qBAAqB;YAC5E,CAAC,CAAC,MAAA,CAAC,CAAC,WAAW,0CAAE,WAAW,CAC/B,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,MAAM,qBAAqB,GAAG,kBAAkB,CAAC,MAAM,GAAG,CAAC,CAAC;IAE5D,IAAI,CAAC,qBAAqB,IAAI,mBAAmB,EAAE,CAAC;QAClD,SAAS,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;IACtC,CAAC;IAED;;;;;;OAMG;IACH,MAAM,CAAC,eAAe,EAAE,kBAAkB,CAAC,GAAG,QAAQ,CAAW,EAAE,CAAC,CAAC;IAErE,MAAM,oBAAoB,GAAG,2BAA2B,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;;QACpE,OAAO,yBAAyB,CAC9B,CAAC,EACD,qBAAqB,IAAI,qBAAqB,IAAI,CAAC;YACjD,CAAC,CAAC,CAAA,MAAA,CAAC,CAAC,WAAW,0CAAE,WAAW;gBACxB,eAAe;gBACf,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC;gBAC3B,kBAAkB,EAAE,GAAG,qBAAqB;YAChD,CAAC,CAAC,MAAA,CAAC,CAAC,WAAW,0CAAE,WAAW,CAC/B,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,MAAM,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC,CAAC;IAEvC,MAAM,iBAAiB,GAAG,OAAO,CAAC,GAAG,EAAE;QACrC,IAAI,QAAQ,IAAI,kBAAkB,KAAK,MAAM,EAAE,CAAC;YAC9C,OAAO,6BAA6B,CAAC;QACvC,CAAC;QACD,IAAI,CAAC,oBAAoB,CAAC,MAAM,GAAG,CAAC,IAAI,oBAAoB,CAAC,IAAI,uBAAuB,KAAK,eAAe,EAAE,CAAC;YAC7G,OAAO,QAAQ;gBACb,CAAC,CAAC,6BAA6B;gBAC/B,CAAC,CAAC,OAAO;oBACT,CAAC,CAAC,8CAA8C;oBAChD,CAAC,CAAC,wCAAwC,CAAC;QAC/C,CAAC;QACD,IAAI,CAAC,oBAAoB,CAAC,MAAM,GAAG,CAAC,IAAI,oBAAoB,CAAC,IAAI,uBAAuB,KAAK,kBAAkB,EAAE,CAAC;YAChH,OAAO,kBAAkB,KAAK,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,6BAA6B,CAAC,CAAC,CAAC,6BAA6B,CAAC;QACpH,CAAC;QACD,OAAO,6BAA6B,CAAC;IACvC,CAAC,EAAE;QACD,oBAAoB,CAAC,MAAM;QAC3B,QAAQ;QACR,oBAAoB;QACpB,OAAO;QACP,uBAAuB;QACvB,kBAAkB;KACnB,CAAC,CAAC;IAEH,MAAM,0BAA0B,GAC9B,CAAC,mBAAmB,IAAI,qBAAqB,CAAC,IAAI,CAAC,oBAAoB,IAAI,mBAAmB,CAAC,CAAC,CAAC,CAAC;IAChG,kGAAkG;IAClG,gCAAgC,CAAC,CAAC,CAAC,CACjC,oBAAC,KAAK,IACJ,SAAS,EAAE,WAAW,CAAC,wCAAwC,CAAC,KAAK,EAAE,iBAAiB,CAAC,EAAE;YACzF,SAAS,EAAE,KAAK,CAAC,OAAO,CAAC,UAAU;YACnC,MAAM,EAAE,uBAAuB;SAChC,CAAC,IAED,mBAAmB,CACd,CACT,CAAC,CAAC,CAAC,oBAAoB,CAAC,MAAM,GAAG,CAAC,IAAI,oBAAoB,CAAC,CAAC,CAAC,CAC5D,oBAAC,KAAK,IACJ,SAAS,EAAE,WAAW,CACpB,4BAA4B,CAAC,KAAK,EAAE,iBAAiB,EAAE,CAAC,CAAC,oBAAoB,EAAE,uBAAuB,CAAC,CACxG,IAEA,mBAAmB,CACd,CACT,CAAC,CAAC,CAAC,CACF,oBAAC,kBAAkB,IACjB,mBAAmB,EAAE,mBAAmB,EACxC,WAAW,EAAE,WAAW,EACxB,iBAAiB,EAAE,iBAAiB,EACpC,WAAW,EAAE,WAAW,EACxB,YAAY,EAAE,YAAY,GAC1B,CACH,CACF,CAAC,CAAC,CAAC,SAAS,CAAC;IAEhB,MAAM,eAAe,GAAG,OAAO,CAAC,GAAG,EAAE;QACnC,IAAI,oBAAoB,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,oBAAoB,EAAE,CAAC;YAC/D,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,CACL,oBAAC,eAAe,IACd,OAAO,EAAE,OAAO,EAChB,oBAAoB,EAAE,kBAAkB,EACxC,QAAQ,EAAE,QAAQ,EAClB,qBAAqB,EAAE,CAAC,CAAC,mBAAmB,EAC5C,uBAAuB,EAAE,oBAAoB,EAC7C,uBAAuB,EAAE,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,iBAAiB,EAClD,qBAAqB,EAAE,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,eAAe,EAC9C,uBAAuB,EAAE,uBAAuB,EAChD,uBAAuB,EAAE,CAAC,CAAS,EAAE,EAAE;gBACrC,eAAe,CAAC,OAAO,GAAG,CAAC,CAAC;YAC9B,CAAC,EACD,WAAW,EAAE,WAAW,GACxB,CACH,CAAC;IACJ,CAAC,EAAE;QACD,QAAQ;QACR,OAAO;QACP,oBAAoB;QACpB,oBAAoB;QACpB,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,iBAAiB;QACzB,uBAAuB;QACvB,kBAAkB;QAClB,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,eAAe;QACvB,WAAW;QACX,mBAAmB;KACpB,CAAC,CAAC;IAEH,OAAO,CACL,oBAAC,KAAK,IAAC,MAAM,EAAE,eAAe;QAC3B,0BAA0B;QAC3B,oBAAC,SAAS,IAAC,EAAE,EAAE,WAAW,EAAE,SAAS,EAAE,WAAW,CAAC,cAAc,CAAC,GAAI;QACtE,oBAAC,KAAK,IACJ,UAAU,EAAE,uBAAuB,KAAK,eAAe,EACvD,MAAM,EAAE,gBAAgB,EACxB,MAAM,EAAE,qBAAqB;YAE5B,KAAK,CAAC,uBAAuB,KAAK,eAAe,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,yCAAK;YAC3E,oBAAoB,CAAC,CAAC,CAAC,CACtB,oBAAoB,CACrB,CAAC,CAAC,CAAC,CACF,oBAAC,UAAU,IAAC,GAAG,EAAC,aAAa,EAAC,MAAM,EAAE,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,UAAU,IACrD,SAAS,CACC,CACd;YACA,yBAAyB,CAAC,eAAe,EAAE,KAAK,CAAC,uBAAuB,CAAC,CACpE,CACF,CACT,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,yBAAyB,GAAG,CAChC,OAA2B,EAC3B,eAAwE,EACpD,EAAE;IACtB,OAAO,eAAe,KAAK,eAAe,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,yCAAK,CAAC;IAC7D,OAAO,OAAO,CAAC;AACjB,CAAC,CAAC","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport { LayerHost, mergeStyles, Stack } from '@fluentui/react';\nimport { useId } from '@fluentui/react-hooks';\nimport React, { useMemo, useRef, useState } from 'react';\nimport { useTheme } from '../../theming';\nimport { GridLayout } from '../GridLayout';\nimport { isNarrowWidth } from '../utils/responsive';\nimport { isShortHeight } from '../utils/responsive';\nimport { FloatingLocalVideo } from './FloatingLocalVideo';\nimport { LayoutProps } from './Layout';\nimport {\n LARGE_FLOATING_MODAL_SIZE_REM,\n localVideoTileContainerStyle,\n localVideoTileWithControlsContainerStyle,\n LOCAL_VIDEO_TILE_ZINDEX,\n SMALL_FLOATING_MODAL_SIZE_REM\n} from './styles/FloatingLocalVideo.styles';\nimport {\n SHORT_VERTICAL_GALLERY_FLOATING_MODAL_SIZE_REM,\n VERTICAL_GALLERY_FLOATING_MODAL_SIZE_REM\n} from './styles/FloatingLocalVideo.styles';\nimport { innerLayoutStyle, layerHostStyle, rootLayoutStyle } from './styles/FloatingLocalVideoLayout.styles';\nimport { videoGalleryLayoutGap } from './styles/Layout.styles';\nimport { useOrganizedParticipants } from './utils/videoGalleryLayoutUtils';\nimport { OverflowGallery } from './OverflowGallery';\nimport { LocalVideoTileSize } from '../VideoGallery';\n\n/**\n * Props for {@link FloatingLocalVideoLayout}.\n *\n * @private\n */\nexport interface FloatingLocalVideoLayoutProps extends LayoutProps {\n /**\n * Whether to display the local video camera switcher button\n */\n showCameraSwitcherInLocalPreview?: boolean;\n /**\n * Height of parent element\n */\n parentHeight?: number;\n /**\n * Local video tile mode\n */\n localVideoTileSize?: LocalVideoTileSize;\n}\n\n/**\n * FloatingLocalVideoLayout displays remote participants and a screen sharing component in\n * a grid and overflow gallery while floating the local video\n *\n * @private\n */\nexport const FloatingLocalVideoLayout = (props: FloatingLocalVideoLayoutProps): JSX.Element => {\n const {\n remoteParticipants = [],\n dominantSpeakers,\n localVideoComponent,\n screenShareComponent,\n onRenderRemoteParticipant,\n styles,\n maxRemoteVideoStreams,\n showCameraSwitcherInLocalPreview,\n parentWidth,\n parentHeight,\n overflowGalleryPosition = 'horizontalBottom',\n pinnedParticipantUserIds = [],\n localVideoTileSize,\n /* @conditional-compile-remove(spotlight) */ spotlightedParticipantUserIds\n } = props;\n\n const theme = useTheme();\n\n const isNarrow = parentWidth ? isNarrowWidth(parentWidth) : false;\n\n const isShort = parentHeight ? isShortHeight(parentHeight) : false;\n\n // This is for tracking the number of children in the first page of overflow gallery.\n // This number will be used for the maxOverflowGalleryDominantSpeakers when organizing the remote participants.\n const childrenPerPage = useRef(4);\n const { gridParticipants, overflowGalleryParticipants } = useOrganizedParticipants({\n remoteParticipants,\n dominantSpeakers,\n maxRemoteVideoStreams,\n isScreenShareActive: !!screenShareComponent,\n maxOverflowGalleryDominantSpeakers: screenShareComponent\n ? childrenPerPage.current - (pinnedParticipantUserIds.length % childrenPerPage.current)\n : childrenPerPage.current,\n pinnedParticipantUserIds,\n layout: 'floatingLocalVideo',\n /* @conditional-compile-remove(spotlight) */ spotlightedParticipantUserIds\n });\n\n let activeVideoStreams = 0;\n\n const gridTiles = gridParticipants.map((p) => {\n return onRenderRemoteParticipant(\n p,\n maxRemoteVideoStreams && maxRemoteVideoStreams >= 0\n ? p.videoStream?.isAvailable && activeVideoStreams++ < maxRemoteVideoStreams\n : p.videoStream?.isAvailable\n );\n });\n\n const shouldFloatLocalVideo = remoteParticipants.length > 0;\n\n if (!shouldFloatLocalVideo && localVideoComponent) {\n gridTiles.push(localVideoComponent);\n }\n\n /**\n * instantiate indexes available to render with indexes available that would be on first page\n *\n * For some components which do not strictly follow the order of the array, we might\n * re-render the initial tiles -> dispose them -> create new tiles, we need to take care of\n * this case when those components are here\n */\n const [indexesToRender, setIndexesToRender] = useState<number[]>([]);\n\n const overflowGalleryTiles = overflowGalleryParticipants.map((p, i) => {\n return onRenderRemoteParticipant(\n p,\n maxRemoteVideoStreams && maxRemoteVideoStreams >= 0\n ? p.videoStream?.isAvailable &&\n indexesToRender &&\n indexesToRender.includes(i) &&\n activeVideoStreams++ < maxRemoteVideoStreams\n : p.videoStream?.isAvailable\n );\n });\n\n const layerHostId = useId('layerhost');\n\n const localVideoSizeRem = useMemo(() => {\n if (isNarrow || localVideoTileSize === '9:16') {\n return SMALL_FLOATING_MODAL_SIZE_REM;\n }\n if ((overflowGalleryTiles.length > 0 || screenShareComponent) && overflowGalleryPosition === 'verticalRight') {\n return isNarrow\n ? SMALL_FLOATING_MODAL_SIZE_REM\n : isShort\n ? SHORT_VERTICAL_GALLERY_FLOATING_MODAL_SIZE_REM\n : VERTICAL_GALLERY_FLOATING_MODAL_SIZE_REM;\n }\n if ((overflowGalleryTiles.length > 0 || screenShareComponent) && overflowGalleryPosition === 'horizontalBottom') {\n return localVideoTileSize === '16:9' || !isNarrow ? LARGE_FLOATING_MODAL_SIZE_REM : SMALL_FLOATING_MODAL_SIZE_REM;\n }\n return LARGE_FLOATING_MODAL_SIZE_REM;\n }, [\n overflowGalleryTiles.length,\n isNarrow,\n screenShareComponent,\n isShort,\n overflowGalleryPosition,\n localVideoTileSize\n ]);\n\n const wrappedLocalVideoComponent =\n (localVideoComponent && shouldFloatLocalVideo) || (screenShareComponent && localVideoComponent) ? (\n // When we use showCameraSwitcherInLocalPreview it disables dragging to allow keyboard navigation.\n showCameraSwitcherInLocalPreview ? (\n <Stack\n className={mergeStyles(localVideoTileWithControlsContainerStyle(theme, localVideoSizeRem), {\n boxShadow: theme.effects.elevation8,\n zIndex: LOCAL_VIDEO_TILE_ZINDEX\n })}\n >\n {localVideoComponent}\n </Stack>\n ) : overflowGalleryTiles.length > 0 || screenShareComponent ? (\n <Stack\n className={mergeStyles(\n localVideoTileContainerStyle(theme, localVideoSizeRem, !!screenShareComponent, overflowGalleryPosition)\n )}\n >\n {localVideoComponent}\n </Stack>\n ) : (\n <FloatingLocalVideo\n localVideoComponent={localVideoComponent}\n layerHostId={layerHostId}\n localVideoSizeRem={localVideoSizeRem}\n parentWidth={parentWidth}\n parentHeight={parentHeight}\n />\n )\n ) : undefined;\n\n const overflowGallery = useMemo(() => {\n if (overflowGalleryTiles.length === 0 && !screenShareComponent) {\n return null;\n }\n return (\n <OverflowGallery\n isShort={isShort}\n onFetchTilesToRender={setIndexesToRender}\n isNarrow={isNarrow}\n shouldFloatLocalVideo={!!localVideoComponent}\n overflowGalleryElements={overflowGalleryTiles}\n horizontalGalleryStyles={styles?.horizontalGallery}\n verticalGalleryStyles={styles?.verticalGallery}\n overflowGalleryPosition={overflowGalleryPosition}\n onChildrenPerPageChange={(n: number) => {\n childrenPerPage.current = n;\n }}\n parentWidth={parentWidth}\n />\n );\n }, [\n isNarrow,\n isShort,\n screenShareComponent,\n overflowGalleryTiles,\n styles?.horizontalGallery,\n overflowGalleryPosition,\n setIndexesToRender,\n styles?.verticalGallery,\n parentWidth,\n localVideoComponent\n ]);\n\n return (\n <Stack styles={rootLayoutStyle}>\n {wrappedLocalVideoComponent}\n <LayerHost id={layerHostId} className={mergeStyles(layerHostStyle)} />\n <Stack\n horizontal={overflowGalleryPosition === 'verticalRight'}\n styles={innerLayoutStyle}\n tokens={videoGalleryLayoutGap}\n >\n {props.overflowGalleryPosition === 'horizontalTop' ? overflowGallery : <></>}\n {screenShareComponent ? (\n screenShareComponent\n ) : (\n <GridLayout key=\"grid-layout\" styles={styles?.gridLayout}>\n {gridTiles}\n </GridLayout>\n )}\n {overflowGalleryTrampoline(overflowGallery, props.overflowGalleryPosition)}\n </Stack>\n </Stack>\n );\n};\n\nconst overflowGalleryTrampoline = (\n gallery: JSX.Element | null,\n galleryPosition?: 'horizontalBottom' | 'verticalRight' | 'horizontalTop'\n): JSX.Element | null => {\n return galleryPosition !== 'horizontalTop' ? gallery : <></>;\n return gallery;\n};\n"]}
1
+ {"version":3,"file":"FloatingLocalVideoLayout.js","sourceRoot":"","sources":["../../../../../../../react-components/src/components/VideoGallery/FloatingLocalVideoLayout.tsx"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport { LayerHost, mergeStyles, Stack } from '@fluentui/react';\nimport { useId } from '@fluentui/react-hooks';\nimport React, { useMemo, useRef, useState } from 'react';\nimport { useTheme } from '../../theming';\nimport { GridLayout } from '../GridLayout';\nimport { isNarrowWidth } from '../utils/responsive';\nimport { isShortHeight } from '../utils/responsive';\nimport { FloatingLocalVideo } from './FloatingLocalVideo';\nimport { LayoutProps } from './Layout';\nimport {\n LARGE_FLOATING_MODAL_SIZE_REM,\n localVideoTileContainerStyle,\n localVideoTileWithControlsContainerStyle,\n LOCAL_VIDEO_TILE_ZINDEX,\n SMALL_FLOATING_MODAL_SIZE_REM\n} from './styles/FloatingLocalVideo.styles';\nimport {\n SHORT_VERTICAL_GALLERY_FLOATING_MODAL_SIZE_REM,\n VERTICAL_GALLERY_FLOATING_MODAL_SIZE_REM\n} from './styles/FloatingLocalVideo.styles';\nimport { innerLayoutStyle, layerHostStyle, rootLayoutStyle } from './styles/FloatingLocalVideoLayout.styles';\nimport { videoGalleryLayoutGap } from './styles/Layout.styles';\nimport { MAX_GRID_PARTICIPANTS_NOT_LARGE_GALLERY, useOrganizedParticipants } from './utils/videoGalleryLayoutUtils';\nimport { OverflowGallery } from './OverflowGallery';\nimport { LocalVideoTileSize } from '../VideoGallery';\n\n/**\n * Props for {@link FloatingLocalVideoLayout}.\n *\n * @private\n */\nexport interface FloatingLocalVideoLayoutProps extends LayoutProps {\n /**\n * Whether to display the local video camera switcher button\n */\n showCameraSwitcherInLocalPreview?: boolean;\n /**\n * Height of parent element\n */\n parentHeight?: number;\n /**\n * Local video tile mode\n */\n localVideoTileSize?: LocalVideoTileSize;\n}\n\n/**\n * FloatingLocalVideoLayout displays remote participants and a screen sharing component in\n * a grid and overflow gallery while floating the local video\n *\n * @private\n */\nexport const FloatingLocalVideoLayout = (props: FloatingLocalVideoLayoutProps): JSX.Element => {\n const {\n remoteParticipants = [],\n dominantSpeakers,\n localVideoComponent,\n screenShareComponent,\n onRenderRemoteParticipant,\n styles,\n maxRemoteVideoStreams,\n showCameraSwitcherInLocalPreview,\n parentWidth,\n parentHeight,\n overflowGalleryPosition = 'horizontalBottom',\n pinnedParticipantUserIds = [],\n localVideoTileSize,\n /* @conditional-compile-remove(spotlight) */ spotlightedParticipantUserIds\n } = props;\n\n const theme = useTheme();\n\n const isNarrow = parentWidth ? isNarrowWidth(parentWidth) : false;\n\n const isShort = parentHeight ? isShortHeight(parentHeight) : false;\n\n // This is for tracking the number of children in the first page of overflow gallery.\n // This number will be used for the maxOverflowGalleryDominantSpeakers when organizing the remote participants.\n const childrenPerPage = useRef(4);\n const remoteVideosOn = remoteParticipants.filter((p) => p.videoStream?.isAvailable).length > 0;\n const { gridParticipants, overflowGalleryParticipants } = useOrganizedParticipants({\n remoteParticipants,\n dominantSpeakers,\n maxGridParticipants: remoteVideosOn ? maxRemoteVideoStreams : MAX_GRID_PARTICIPANTS_NOT_LARGE_GALLERY,\n isScreenShareActive: !!screenShareComponent,\n maxOverflowGalleryDominantSpeakers: screenShareComponent\n ? childrenPerPage.current - (pinnedParticipantUserIds.length % childrenPerPage.current)\n : childrenPerPage.current,\n pinnedParticipantUserIds,\n layout: 'floatingLocalVideo',\n /* @conditional-compile-remove(spotlight) */ spotlightedParticipantUserIds\n });\n\n let activeVideoStreams = 0;\n\n const gridTiles = gridParticipants.map((p) => {\n return onRenderRemoteParticipant(\n p,\n maxRemoteVideoStreams && maxRemoteVideoStreams >= 0\n ? p.videoStream?.isAvailable && activeVideoStreams++ < maxRemoteVideoStreams\n : p.videoStream?.isAvailable\n );\n });\n\n const shouldFloatLocalVideo = remoteParticipants.length > 0;\n\n if (!shouldFloatLocalVideo && localVideoComponent) {\n gridTiles.push(localVideoComponent);\n }\n\n /**\n * instantiate indexes available to render with indexes available that would be on first page\n *\n * For some components which do not strictly follow the order of the array, we might\n * re-render the initial tiles -> dispose them -> create new tiles, we need to take care of\n * this case when those components are here\n */\n const [indexesToRender, setIndexesToRender] = useState<number[]>([]);\n\n const overflowGalleryTiles = overflowGalleryParticipants.map((p, i) => {\n return onRenderRemoteParticipant(\n p,\n maxRemoteVideoStreams && maxRemoteVideoStreams >= 0\n ? p.videoStream?.isAvailable &&\n indexesToRender &&\n indexesToRender.includes(i) &&\n activeVideoStreams++ < maxRemoteVideoStreams\n : p.videoStream?.isAvailable\n );\n });\n\n const layerHostId = useId('layerhost');\n\n const localVideoSizeRem = useMemo(() => {\n if (isNarrow || localVideoTileSize === '9:16') {\n return SMALL_FLOATING_MODAL_SIZE_REM;\n }\n if ((overflowGalleryTiles.length > 0 || screenShareComponent) && overflowGalleryPosition === 'verticalRight') {\n return isNarrow\n ? SMALL_FLOATING_MODAL_SIZE_REM\n : isShort\n ? SHORT_VERTICAL_GALLERY_FLOATING_MODAL_SIZE_REM\n : VERTICAL_GALLERY_FLOATING_MODAL_SIZE_REM;\n }\n if ((overflowGalleryTiles.length > 0 || screenShareComponent) && overflowGalleryPosition === 'horizontalBottom') {\n return localVideoTileSize === '16:9' || !isNarrow ? LARGE_FLOATING_MODAL_SIZE_REM : SMALL_FLOATING_MODAL_SIZE_REM;\n }\n return LARGE_FLOATING_MODAL_SIZE_REM;\n }, [\n overflowGalleryTiles.length,\n isNarrow,\n screenShareComponent,\n isShort,\n overflowGalleryPosition,\n localVideoTileSize\n ]);\n\n const wrappedLocalVideoComponent =\n (localVideoComponent && shouldFloatLocalVideo) || (screenShareComponent && localVideoComponent) ? (\n // When we use showCameraSwitcherInLocalPreview it disables dragging to allow keyboard navigation.\n showCameraSwitcherInLocalPreview ? (\n <Stack\n className={mergeStyles(localVideoTileWithControlsContainerStyle(theme, localVideoSizeRem), {\n boxShadow: theme.effects.elevation8,\n zIndex: LOCAL_VIDEO_TILE_ZINDEX\n })}\n >\n {localVideoComponent}\n </Stack>\n ) : overflowGalleryTiles.length > 0 || screenShareComponent ? (\n <Stack\n className={mergeStyles(\n localVideoTileContainerStyle(theme, localVideoSizeRem, !!screenShareComponent, overflowGalleryPosition)\n )}\n >\n {localVideoComponent}\n </Stack>\n ) : (\n <FloatingLocalVideo\n localVideoComponent={localVideoComponent}\n layerHostId={layerHostId}\n localVideoSizeRem={localVideoSizeRem}\n parentWidth={parentWidth}\n parentHeight={parentHeight}\n />\n )\n ) : undefined;\n\n const overflowGallery = useMemo(() => {\n if (overflowGalleryTiles.length === 0 && !screenShareComponent) {\n return null;\n }\n return (\n <OverflowGallery\n isShort={isShort}\n onFetchTilesToRender={setIndexesToRender}\n isNarrow={isNarrow}\n shouldFloatLocalVideo={!!localVideoComponent}\n overflowGalleryElements={overflowGalleryTiles}\n horizontalGalleryStyles={styles?.horizontalGallery}\n verticalGalleryStyles={styles?.verticalGallery}\n overflowGalleryPosition={overflowGalleryPosition}\n onChildrenPerPageChange={(n: number) => {\n childrenPerPage.current = n;\n }}\n parentWidth={parentWidth}\n />\n );\n }, [\n isNarrow,\n isShort,\n screenShareComponent,\n overflowGalleryTiles,\n styles?.horizontalGallery,\n overflowGalleryPosition,\n setIndexesToRender,\n styles?.verticalGallery,\n parentWidth,\n localVideoComponent\n ]);\n\n return (\n <Stack styles={rootLayoutStyle}>\n {wrappedLocalVideoComponent}\n <LayerHost id={layerHostId} className={mergeStyles(layerHostStyle)} />\n <Stack\n horizontal={overflowGalleryPosition === 'verticalRight'}\n styles={innerLayoutStyle}\n tokens={videoGalleryLayoutGap}\n >\n {props.overflowGalleryPosition === 'horizontalTop' ? overflowGallery : <></>}\n {screenShareComponent ? (\n screenShareComponent\n ) : (\n <GridLayout key=\"grid-layout\" styles={styles?.gridLayout}>\n {gridTiles}\n </GridLayout>\n )}\n {overflowGalleryTrampoline(overflowGallery, props.overflowGalleryPosition)}\n </Stack>\n </Stack>\n );\n};\n\nconst overflowGalleryTrampoline = (\n gallery: JSX.Element | null,\n galleryPosition?: 'horizontalBottom' | 'verticalRight' | 'horizontalTop'\n): JSX.Element | null => {\n return galleryPosition !== 'horizontalTop' ? gallery : <></>;\n return gallery;\n};\n"]}
@@ -29,7 +29,6 @@ export const LargeGalleryLayout = (props) => {
29
29
  return parentWidth && parentHeight
30
30
  ? calculateMaxTilesInLargeGrid(parentWidth, parentHeight)
31
31
  : maxRemoteVideoStreams;
32
- return maxRemoteVideoStreams;
33
32
  };
34
33
  // This is for tracking the number of children in the first page of overflow gallery.
35
34
  // This number will be used for the maxOverflowGalleryDominantSpeakers when organizing the remote participants.
@@ -39,7 +38,7 @@ export const LargeGalleryLayout = (props) => {
39
38
  remoteParticipants,
40
39
  localParticipant,
41
40
  dominantSpeakers,
42
- maxRemoteVideoStreams: maxStreamsTrampoline(),
41
+ maxGridParticipants: maxStreamsTrampoline(),
43
42
  isScreenShareActive: !!screenShareComponent,
44
43
  maxOverflowGalleryDominantSpeakers: screenShareComponent
45
44
  ? childrenPerPage.current - ((pinnedParticipantUserIds.length + 1) % childrenPerPage.current)