Fix selection
This commit is contained in:
parent
d001ddebbc
commit
f1610dae3d
7 changed files with 31 additions and 11 deletions
|
@ -19,6 +19,7 @@ import React, { MutableRefObject, ReactNode } from 'react';
|
||||||
import { useComposerFunctions } from '../hooks/useComposerFunctions';
|
import { useComposerFunctions } from '../hooks/useComposerFunctions';
|
||||||
import { usePlainTextInitialization } from '../hooks/usePlainTextInitialization';
|
import { usePlainTextInitialization } from '../hooks/usePlainTextInitialization';
|
||||||
import { usePlainTextListeners } from '../hooks/usePlainTextListeners';
|
import { usePlainTextListeners } from '../hooks/usePlainTextListeners';
|
||||||
|
import { useSetCursorPosition } from '../hooks/useSetCursorPosition';
|
||||||
import { ComposerFunctions } from '../types';
|
import { ComposerFunctions } from '../types';
|
||||||
import { Editor } from "./Editor";
|
import { Editor } from "./Editor";
|
||||||
|
|
||||||
|
@ -40,6 +41,7 @@ export function PlainTextComposer({
|
||||||
const { ref, onInput, onPaste, onKeyDown } = usePlainTextListeners(onChange, onSend);
|
const { ref, onInput, onPaste, onKeyDown } = usePlainTextListeners(onChange, onSend);
|
||||||
const composerFunctions = useComposerFunctions(ref);
|
const composerFunctions = useComposerFunctions(ref);
|
||||||
usePlainTextInitialization(initialContent, ref);
|
usePlainTextInitialization(initialContent, ref);
|
||||||
|
useSetCursorPosition(disabled, ref);
|
||||||
|
|
||||||
return <div className={className} onInput={onInput} onPaste={onPaste} onKeyDown={onKeyDown}>
|
return <div className={className} onInput={onInput} onPaste={onPaste} onKeyDown={onKeyDown}>
|
||||||
<Editor ref={ref} disabled={disabled} />
|
<Editor ref={ref} disabled={disabled} />
|
||||||
|
|
|
@ -48,12 +48,13 @@ export const WysiwygComposer = memo(function WysiwygComposer(
|
||||||
}
|
}
|
||||||
}, [onChange, content, disabled]);
|
}, [onChange, content, disabled]);
|
||||||
|
|
||||||
useSetCursorPosition(isWysiwygReady, ref);
|
const isReady = isWysiwygReady && !disabled;
|
||||||
|
useSetCursorPosition(!isReady, ref);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={className}>
|
<div className={className}>
|
||||||
<FormattingButtons composer={wysiwyg} formattingStates={formattingStates} />
|
<FormattingButtons composer={wysiwyg} formattingStates={formattingStates} />
|
||||||
<Editor ref={ref} disabled={!isWysiwygReady || disabled} />
|
<Editor ref={ref} disabled={!isReady} />
|
||||||
{ children?.(ref, wysiwyg) }
|
{ children?.(ref, wysiwyg) }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -18,10 +18,10 @@ import { RefObject, useEffect } from "react";
|
||||||
|
|
||||||
import { setCursorPositionAtTheEnd } from "./utils";
|
import { setCursorPositionAtTheEnd } from "./utils";
|
||||||
|
|
||||||
export function useSetCursorPosition(isComposerReady: boolean, ref: RefObject<HTMLElement>) {
|
export function useSetCursorPosition(disabled: boolean, ref: RefObject<HTMLElement>) {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (ref.current && isComposerReady) {
|
if (ref.current && !disabled) {
|
||||||
setCursorPositionAtTheEnd(ref.current);
|
setCursorPositionAtTheEnd(ref.current);
|
||||||
}
|
}
|
||||||
}, [ref, isComposerReady]);
|
}, [ref, disabled]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,9 +46,9 @@ export function setCursorPositionAtTheEnd(element: HTMLElement) {
|
||||||
const range = document.createRange();
|
const range = document.createRange();
|
||||||
range.selectNodeContents(element);
|
range.selectNodeContents(element);
|
||||||
range.collapse(false);
|
range.collapse(false);
|
||||||
const sel = document.getSelection();
|
const selection = document.getSelection();
|
||||||
sel.removeAllRanges();
|
selection.removeAllRanges();
|
||||||
sel.addRange(range);
|
selection.addRange(range);
|
||||||
|
|
||||||
element.focus();
|
element.focus();
|
||||||
}
|
}
|
||||||
|
|
|
@ -186,6 +186,7 @@ describe('EditWysiwygComposer', () => {
|
||||||
it('Should focus when receiving an Action.FocusEditMessageComposer action', async () => {
|
it('Should focus when receiving an Action.FocusEditMessageComposer action', async () => {
|
||||||
// Given we don't have focus
|
// Given we don't have focus
|
||||||
customRender();
|
customRender();
|
||||||
|
screen.getByLabelText('Bold').focus();
|
||||||
expect(screen.getByRole('textbox')).not.toHaveFocus();
|
expect(screen.getByRole('textbox')).not.toHaveFocus();
|
||||||
|
|
||||||
// When we send the right action
|
// When we send the right action
|
||||||
|
@ -201,6 +202,7 @@ describe('EditWysiwygComposer', () => {
|
||||||
it('Should not focus when disabled', async () => {
|
it('Should not focus when disabled', async () => {
|
||||||
// Given we don't have focus and we are disabled
|
// Given we don't have focus and we are disabled
|
||||||
customRender(true);
|
customRender(true);
|
||||||
|
screen.getByLabelText('Bold').focus();
|
||||||
expect(screen.getByRole('textbox')).not.toHaveFocus();
|
expect(screen.getByRole('textbox')).not.toHaveFocus();
|
||||||
|
|
||||||
// When we send an action that would cause us to get focus
|
// When we send an action that would cause us to get focus
|
||||||
|
|
|
@ -81,6 +81,7 @@ describe('SendWysiwygComposer', () => {
|
||||||
it('Should focus when receiving an Action.FocusSendMessageComposer action', async () => {
|
it('Should focus when receiving an Action.FocusSendMessageComposer action', async () => {
|
||||||
// Given we don't have focus
|
// Given we don't have focus
|
||||||
customRender(jest.fn(), jest.fn());
|
customRender(jest.fn(), jest.fn());
|
||||||
|
screen.getByLabelText('Bold').focus();
|
||||||
expect(screen.getByRole('textbox')).not.toHaveFocus();
|
expect(screen.getByRole('textbox')).not.toHaveFocus();
|
||||||
|
|
||||||
// When we send the right action
|
// When we send the right action
|
||||||
|
@ -96,6 +97,7 @@ describe('SendWysiwygComposer', () => {
|
||||||
it('Should focus and clear when receiving an Action.ClearAndFocusSendMessageComposer', async () => {
|
it('Should focus and clear when receiving an Action.ClearAndFocusSendMessageComposer', async () => {
|
||||||
// Given we don't have focus
|
// Given we don't have focus
|
||||||
customRender(jest.fn(), jest.fn());
|
customRender(jest.fn(), jest.fn());
|
||||||
|
screen.getByLabelText('Bold').focus();
|
||||||
expect(screen.getByRole('textbox')).not.toHaveFocus();
|
expect(screen.getByRole('textbox')).not.toHaveFocus();
|
||||||
|
|
||||||
// When we send the right action
|
// When we send the right action
|
||||||
|
@ -112,6 +114,7 @@ describe('SendWysiwygComposer', () => {
|
||||||
it('Should focus when receiving a reply_to_event action', async () => {
|
it('Should focus when receiving a reply_to_event action', async () => {
|
||||||
// Given we don't have focus
|
// Given we don't have focus
|
||||||
customRender(jest.fn(), jest.fn());
|
customRender(jest.fn(), jest.fn());
|
||||||
|
screen.getByLabelText('Bold').focus();
|
||||||
expect(screen.getByRole('textbox')).not.toHaveFocus();
|
expect(screen.getByRole('textbox')).not.toHaveFocus();
|
||||||
|
|
||||||
// When we send the right action
|
// When we send the right action
|
||||||
|
|
|
@ -73,11 +73,15 @@ describe('WysiwygComposer', () => {
|
||||||
|
|
||||||
const defaultRoomContext: IRoomState = getRoomContext(mockRoom, {});
|
const defaultRoomContext: IRoomState = getRoomContext(mockRoom, {});
|
||||||
|
|
||||||
const customRender = (onChange = (_content: string) => void 0, onSend = () => void 0, disabled = false) => {
|
const customRender = (
|
||||||
|
onChange = (_content: string) => void 0,
|
||||||
|
onSend = () => void 0,
|
||||||
|
disabled = false,
|
||||||
|
initialContent?: string) => {
|
||||||
return render(
|
return render(
|
||||||
<MatrixClientContext.Provider value={mockClient}>
|
<MatrixClientContext.Provider value={mockClient}>
|
||||||
<RoomContext.Provider value={defaultRoomContext}>
|
<RoomContext.Provider value={defaultRoomContext}>
|
||||||
<WysiwygComposer onChange={onChange} onSend={onSend} disabled={disabled} />
|
<WysiwygComposer onChange={onChange} onSend={onSend} disabled={disabled} initialContent={initialContent} />
|
||||||
</RoomContext.Provider>
|
</RoomContext.Provider>
|
||||||
</MatrixClientContext.Provider>,
|
</MatrixClientContext.Provider>,
|
||||||
);
|
);
|
||||||
|
@ -91,6 +95,14 @@ describe('WysiwygComposer', () => {
|
||||||
expect(screen.getByRole('textbox')).toHaveAttribute('contentEditable', "false");
|
expect(screen.getByRole('textbox')).toHaveAttribute('contentEditable', "false");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Should have focus', () => {
|
||||||
|
// When
|
||||||
|
customRender(jest.fn(), jest.fn(), false);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
expect(screen.getByRole('textbox')).toHaveFocus();
|
||||||
|
});
|
||||||
|
|
||||||
it('Should call onChange handler', (done) => {
|
it('Should call onChange handler', (done) => {
|
||||||
const html = '<b>html</b>';
|
const html = '<b>html</b>';
|
||||||
customRender((content) => {
|
customRender((content) => {
|
||||||
|
@ -104,7 +116,7 @@ describe('WysiwygComposer', () => {
|
||||||
const onSend = jest.fn();
|
const onSend = jest.fn();
|
||||||
customRender(jest.fn(), onSend);
|
customRender(jest.fn(), onSend);
|
||||||
|
|
||||||
// When we tell its inputEventProcesser that the user pressed Enter
|
// When we tell its inputEventProcessor that the user pressed Enter
|
||||||
const event = new InputEvent("insertParagraph", { inputType: "insertParagraph" });
|
const event = new InputEvent("insertParagraph", { inputType: "insertParagraph" });
|
||||||
const wysiwyg = { actions: { clear: () => {} } } as Wysiwyg;
|
const wysiwyg = { actions: { clear: () => {} } } as Wysiwyg;
|
||||||
inputEventProcessor(event, wysiwyg);
|
inputEventProcessor(event, wysiwyg);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue