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

Commit 65f9843

Browse files
authored
Add emoji handling for plain text mode (#9727)
Add emoji handling for plain text mode
1 parent 888e69f commit 65f9843

File tree

6 files changed

+53
-24
lines changed

6 files changed

+53
-24
lines changed

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

+2-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export const Editor = memo(
3434
function Editor({ disabled, placeholder, leftComponent, rightComponent }: EditorProps, ref,
3535
) {
3636
const isExpanded = useIsExpanded(ref as MutableRefObject<HTMLDivElement | null>, HEIGHT_BREAKING_POINT);
37-
const { onFocus, onBlur, selectPreviousSelection } = useSelection();
37+
const { onFocus, onBlur, selectPreviousSelection, onInput } = useSelection();
3838

3939
return <div
4040
data-testid="WysiwygComposerEditor"
@@ -59,6 +59,7 @@ export const Editor = memo(
5959
aria-disabled={disabled}
6060
onFocus={onFocus}
6161
onBlur={onBlur}
62+
onInput={onInput}
6263
/>
6364
</div>
6465
{ rightComponent?.(selectPreviousSelection) }

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

+3-2
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,9 @@ export function PlainTextComposer({
5454
rightComponent,
5555
}: PlainTextComposerProps,
5656
) {
57-
const { ref, onInput, onPaste, onKeyDown, content } = usePlainTextListeners(initialContent, onChange, onSend);
58-
const composerFunctions = useComposerFunctions(ref);
57+
const { ref, onInput, onPaste, onKeyDown, content, setContent } =
58+
usePlainTextListeners(initialContent, onChange, onSend);
59+
const composerFunctions = useComposerFunctions(ref, setContent);
5960
usePlainTextInitialization(initialContent, ref);
6061
useSetCursorPosition(disabled, ref);
6162
const { isFocused, onFocus } = useIsFocused();

src/components/views/rooms/wysiwyg_composer/hooks/useComposerFunctions.ts

+18-3
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,30 @@ limitations under the License.
1616

1717
import { RefObject, useMemo } from "react";
1818

19-
export function useComposerFunctions(ref: RefObject<HTMLDivElement>) {
19+
import { setSelection } from "../utils/selection";
20+
21+
export function useComposerFunctions(ref: RefObject<HTMLDivElement>, setContent: (content: string) => void) {
2022
return useMemo(() => ({
2123
clear: () => {
2224
if (ref.current) {
2325
ref.current.innerHTML = '';
2426
}
2527
},
2628
insertText: (text: string) => {
27-
// TODO
29+
const selection = document.getSelection();
30+
31+
if (ref.current && selection) {
32+
const content = ref.current.innerHTML;
33+
const { anchorOffset, focusOffset } = selection;
34+
ref.current.innerHTML = `${content.slice(0, anchorOffset)}${text}${content.slice(focusOffset)}`;
35+
setSelection({
36+
anchorNode: ref.current.firstChild,
37+
anchorOffset: anchorOffset + text.length,
38+
focusNode: ref.current.firstChild,
39+
focusOffset: focusOffset + text.length,
40+
});
41+
setContent(ref.current.innerHTML);
42+
}
2843
},
29-
}), [ref]);
44+
}), [ref, setContent]);
3045
}

src/components/views/rooms/wysiwyg_composer/hooks/usePlainTextListeners.ts

+8-4
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,16 @@ export function usePlainTextListeners(
3636
onSend?.();
3737
}), [ref, onSend]);
3838

39+
const setText = useCallback((text: string) => {
40+
setContent(text);
41+
onChange?.(text);
42+
}, [onChange]);
43+
3944
const onInput = useCallback((event: SyntheticEvent<HTMLDivElement, InputEvent | ClipboardEvent>) => {
4045
if (isDivElement(event.target)) {
41-
setContent(event.target.innerHTML);
42-
onChange?.(event.target.innerHTML);
46+
setText(event.target.innerHTML);
4347
}
44-
}, [onChange]);
48+
}, [setText]);
4549

4650
const isCtrlEnter = useSettingValue<boolean>("MessageComposerInput.ctrlEnterToSend");
4751
const onKeyDown = useCallback((event: KeyboardEvent<HTMLDivElement>) => {
@@ -52,5 +56,5 @@ export function usePlainTextListeners(
5256
}
5357
}, [isCtrlEnter, send]);
5458

55-
return { ref, onInput, onPaste: onInput, onKeyDown, content };
59+
return { ref, onInput, onPaste: onInput, onKeyDown, content, setContent: setText };
5660
}

src/components/views/rooms/wysiwyg_composer/hooks/useSelection.ts

+21-13
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,26 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17-
import { useCallback, useEffect, useRef } from "react";
17+
import { MutableRefObject, useCallback, useEffect, useRef } from "react";
1818

1919
import useFocus from "../../../../../hooks/useFocus";
2020
import { setSelection } from "../utils/selection";
2121

2222
type SubSelection = Pick<Selection, 'anchorNode' | 'anchorOffset' | 'focusNode' | 'focusOffset'>;
2323

24+
function setSelectionRef(selectionRef: MutableRefObject<SubSelection>) {
25+
const selection = document.getSelection();
26+
27+
if (selection) {
28+
selectionRef.current = {
29+
anchorNode: selection.anchorNode,
30+
anchorOffset: selection.anchorOffset,
31+
focusNode: selection.focusNode,
32+
focusOffset: selection.focusOffset,
33+
};
34+
}
35+
}
36+
2437
export function useSelection() {
2538
const selectionRef = useRef<SubSelection>({
2639
anchorNode: null,
@@ -32,16 +45,7 @@ export function useSelection() {
3245

3346
useEffect(() => {
3447
function onSelectionChange() {
35-
const selection = document.getSelection();
36-
37-
if (selection) {
38-
selectionRef.current = {
39-
anchorNode: selection.anchorNode,
40-
anchorOffset: selection.anchorOffset,
41-
focusNode: selection.focusNode,
42-
focusOffset: selection.focusOffset,
43-
};
44-
}
48+
setSelectionRef(selectionRef);
4549
}
4650

4751
if (isFocused) {
@@ -51,9 +55,13 @@ export function useSelection() {
5155
return () => document.removeEventListener('selectionchange', onSelectionChange);
5256
}, [isFocused]);
5357

58+
const onInput = useCallback(() => {
59+
setSelectionRef(selectionRef);
60+
}, []);
61+
5462
const selectPreviousSelection = useCallback(() => {
5563
setSelection(selectionRef.current);
56-
}, [selectionRef]);
64+
}, []);
5765

58-
return { ...focusProps, selectPreviousSelection };
66+
return { ...focusProps, selectPreviousSelection, onInput };
5967
}

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ describe('SendWysiwygComposer', () => {
251251

252252
describe.each([
253253
{ isRichTextEnabled: true },
254-
// TODO { isRichTextEnabled: false },
254+
{ isRichTextEnabled: false },
255255
])('Emoji when %s', ({ isRichTextEnabled }) => {
256256
let emojiButton: HTMLElement;
257257

0 commit comments

Comments
 (0)