Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.

Commit 2d13d10

Browse files
committed
Fix ComposerContext unwanted value sharing
1 parent 5061d7e commit 2d13d10

File tree

6 files changed

+48
-37
lines changed

6 files changed

+48
-37
lines changed

src/components/views/rooms/wysiwyg_composer/ComposerContext.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,17 @@ import { createContext, useContext } from "react";
1818

1919
import { SubSelection } from "./types";
2020

21-
export const defaultContext: { selection: SubSelection } = {
22-
selection: { anchorNode: null, anchorOffset: 0, focusNode: null, focusOffset: 0 },
23-
};
21+
export function getDefaultContextValue() {
22+
return {
23+
selection: { anchorNode: null, anchorOffset: 0, focusNode: null, focusOffset: 0 },
24+
};
25+
}
2426

2527
export interface ComposerContextState {
2628
selection: SubSelection;
2729
}
2830

29-
export const ComposerContext = createContext<ComposerContextState>(defaultContext);
31+
export const ComposerContext = createContext<ComposerContextState>(getDefaultContextValue());
3032
ComposerContext.displayName = "ComposerContext";
3133

3234
export function useComposerContext() {

src/components/views/rooms/wysiwyg_composer/EditWysiwygComposer.tsx

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17-
import React, { forwardRef, RefObject } from "react";
17+
import React, { forwardRef, RefObject, useRef } from "react";
1818
import classNames from "classnames";
1919

2020
import EditorStateTransfer from "../../../../utils/EditorStateTransfer";
@@ -23,6 +23,7 @@ import { EditionButtons } from "./components/EditionButtons";
2323
import { useWysiwygEditActionHandler } from "./hooks/useWysiwygEditActionHandler";
2424
import { useEditing } from "./hooks/useEditing";
2525
import { useInitialContent } from "./hooks/useInitialContent";
26+
import { ComposerContext, getDefaultContextValue } from "./ComposerContext";
2627

2728
interface ContentProps {
2829
disabled: boolean;
@@ -44,31 +45,34 @@ interface EditWysiwygComposerProps {
4445
}
4546

4647
export function EditWysiwygComposer({ editorStateTransfer, className, ...props }: EditWysiwygComposerProps) {
48+
const defaultContextValue = useRef(getDefaultContextValue());
4749
const initialContent = useInitialContent(editorStateTransfer);
4850
const isReady = !editorStateTransfer || initialContent !== undefined;
4951

5052
const { editMessage, endEditing, onChange, isSaveDisabled } = useEditing(editorStateTransfer, initialContent);
5153

5254
return (
5355
isReady && (
54-
<WysiwygComposer
55-
className={classNames("mx_EditWysiwygComposer", className)}
56-
initialContent={initialContent}
57-
onChange={onChange}
58-
onSend={editMessage}
59-
{...props}
60-
>
61-
{(ref) => (
62-
<>
63-
<Content disabled={props.disabled} ref={ref} />
64-
<EditionButtons
65-
onCancelClick={endEditing}
66-
onSaveClick={editMessage}
67-
isSaveDisabled={isSaveDisabled}
68-
/>
69-
</>
70-
)}
71-
</WysiwygComposer>
56+
<ComposerContext.Provider value={defaultContextValue.current}>
57+
<WysiwygComposer
58+
className={classNames("mx_EditWysiwygComposer", className)}
59+
initialContent={initialContent}
60+
onChange={onChange}
61+
onSend={editMessage}
62+
{...props}
63+
>
64+
{(ref) => (
65+
<>
66+
<Content disabled={props.disabled} ref={ref} />
67+
<EditionButtons
68+
onCancelClick={endEditing}
69+
onSaveClick={editMessage}
70+
isSaveDisabled={isSaveDisabled}
71+
/>
72+
</>
73+
)}
74+
</WysiwygComposer>
75+
</ComposerContext.Provider>
7276
)
7377
);
7478
}

src/components/views/rooms/wysiwyg_composer/SendWysiwygComposer.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17-
import React, { ForwardedRef, forwardRef, MutableRefObject } from "react";
17+
import React, { ForwardedRef, forwardRef, MutableRefObject, useRef } from "react";
1818

1919
import { useWysiwygSendActionHandler } from "./hooks/useWysiwygSendActionHandler";
2020
import { WysiwygComposer } from "./components/WysiwygComposer";
@@ -24,7 +24,7 @@ import { E2EStatus } from "../../../../utils/ShieldUtils";
2424
import E2EIcon from "../E2EIcon";
2525
import { AboveLeftOf } from "../../../structures/ContextMenu";
2626
import { Emoji } from "./components/Emoji";
27-
import { ComposerContext, defaultContext } from "./ComposerContext";
27+
import { ComposerContext, getDefaultContextValue } from "./ComposerContext";
2828

2929
interface ContentProps {
3030
disabled?: boolean;
@@ -57,9 +57,10 @@ export function SendWysiwygComposer({
5757
...props
5858
}: SendWysiwygComposerProps) {
5959
const Composer = isRichTextEnabled ? WysiwygComposer : PlainTextComposer;
60+
const defaultContextValue = useRef(getDefaultContextValue());
6061

6162
return (
62-
<ComposerContext.Provider value={defaultContext}>
63+
<ComposerContext.Provider value={defaultContextValue.current}>
6364
<Composer
6465
className="mx_SendWysiwygComposer"
6566
leftComponent={e2eStatus && <E2EIcon status={e2eStatus} />}

src/components/views/rooms/wysiwyg_composer/components/FormattingButtons.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import { KeyCombo } from "../../../../../KeyBindingsManager";
3131
import { _td } from "../../../../../languageHandler";
3232
import { ButtonEvent } from "../../../elements/AccessibleButton";
3333
import { openLinkModal } from "./LinkModal";
34+
import { useComposerContext } from "../ComposerContext";
3435

3536
interface TooltipProps {
3637
label: string;
@@ -78,6 +79,8 @@ interface FormattingButtonsProps {
7879
}
7980

8081
export function FormattingButtons({ composer, actionStates }: FormattingButtonsProps) {
82+
const composerContext = useComposerContext();
83+
8184
return (
8285
<div className="mx_FormattingButtons">
8386
<Button
@@ -117,7 +120,7 @@ export function FormattingButtons({ composer, actionStates }: FormattingButtonsP
117120
<Button
118121
isActive={actionStates.link === "reversed"}
119122
label={_td("Link")}
120-
onClick={() => openLinkModal(composer)}
123+
onClick={() => openLinkModal(composer, composerContext)}
121124
icon={<LinkIcon className="mx_FormattingButtons_Icon" />}
122125
/>
123126
</div>

src/components/views/rooms/wysiwyg_composer/components/LinkModal.tsx

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,13 @@ import { _td } from "../../../../../languageHandler";
2121
import Modal from "../../../../../Modal";
2222
import QuestionDialog from "../../../dialogs/QuestionDialog";
2323
import Field from "../../../elements/Field";
24-
import { useComposerContext } from "../ComposerContext";
24+
import { ComposerContextState } from "../ComposerContext";
2525
import { isSelectionEmpty, setSelection } from "../utils/selection";
2626

27-
export function openLinkModal(composer: FormattingFunctions) {
27+
export function openLinkModal(composer: FormattingFunctions, composerContext: ComposerContextState) {
2828
const modal = Modal.createDialog(
2929
LinkModal,
30-
{ composer, onClose: () => modal.close(), isTextEnabled: isSelectionEmpty() },
30+
{ composerContext, composer, onClose: () => modal.close(), isTextEnabled: isSelectionEmpty() },
3131
"mx_CompoundDialog",
3232
false,
3333
true,
@@ -42,11 +42,10 @@ interface LinkModalProps {
4242
composer: FormattingFunctions;
4343
isTextEnabled: boolean;
4444
onClose: () => void;
45+
composerContext: ComposerContextState;
4546
}
4647

47-
export function LinkModal({ composer, isTextEnabled, onClose }: LinkModalProps) {
48-
const composerContext = useComposerContext();
49-
48+
export function LinkModal({ composer, isTextEnabled, onClose, composerContext }: LinkModalProps) {
5049
const [fields, setFields] = useState({ text: "", link: "" });
5150
const isSaveDisabled = (isTextEnabled && isEmpty(fields.text)) || isEmpty(fields.link);
5251

test/components/views/rooms/wysiwyg_composer/components/LinkModal-test.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import { render, screen, waitFor } from "@testing-library/react";
1919
import React from "react";
2020
import userEvent from "@testing-library/user-event";
2121

22-
import { ComposerContext } from "../../../../../../src/components/views/rooms/wysiwyg_composer/ComposerContext";
2322
import { LinkModal } from "../../../../../../src/components/views/rooms/wysiwyg_composer/components/LinkModal";
2423
import { mockPlatformPeg } from "../../../../../test-utils";
2524
import * as selection from "../../../../../../src/components/views/rooms/wysiwyg_composer/utils/selection";
@@ -38,9 +37,12 @@ describe("LinkModal", () => {
3837

3938
const customRender = (isTextEnabled: boolean, onClose: () => void) => {
4039
return render(
41-
<ComposerContext.Provider value={{ selection: defaultValue }}>
42-
<LinkModal composer={composer} isTextEnabled={isTextEnabled} onClose={onClose} />
43-
</ComposerContext.Provider>,
40+
<LinkModal
41+
composer={composer}
42+
isTextEnabled={isTextEnabled}
43+
onClose={onClose}
44+
composerContext={{ selection: defaultValue }}
45+
/>,
4446
);
4547
};
4648

0 commit comments

Comments
 (0)