Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions src/PickerInput/Selector/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ const Input = React.forwardRef<InputRef, InputProps>((props, ref) => {
// ========================= Refs =========================
const holderRef = React.useRef<HTMLDivElement>(null);
const inputRef = React.useRef<HTMLInputElement>(null);
// When mousedown get focus, defer selection to mouseUp so click position is used
const mouseDownRef = React.useRef(false);

React.useImperativeHandle(ref, () => ({
nativeElement: holderRef.current,
Expand Down Expand Up @@ -153,6 +155,12 @@ const Input = React.forwardRef<InputRef, InputProps>((props, ref) => {
};

const onFormatPaste: React.ClipboardEventHandler<HTMLInputElement> = (event) => {
// Block paste until selection is set (after mouseUp when focus was by mousedown)
if (mouseDownRef.current) {
event.preventDefault();
return;
}

// Get paste text
const pasteText = event.clipboardData.getData('text');

Expand All @@ -164,8 +172,6 @@ const Input = React.forwardRef<InputRef, InputProps>((props, ref) => {
// ======================== Mouse =========================
// When `mouseDown` get focus, it's better to not to change the selection
// Since the up position maybe not is the first cell
const mouseDownRef = React.useRef(false);

const onFormatMouseDown: React.MouseEventHandler<HTMLInputElement> = () => {
mouseDownRef.current = true;
};
Expand Down Expand Up @@ -221,6 +227,12 @@ const Input = React.forwardRef<InputRef, InputProps>((props, ref) => {
};

const onFormatKeyDown: React.KeyboardEventHandler<HTMLInputElement> = (event) => {
// Block key input until selection is set (after mouseUp when focus was by mousedown)
if (mouseDownRef.current) {
event.preventDefault();
return;
}

onSharedKeyDown(event);

const { key } = event;
Expand Down
55 changes: 54 additions & 1 deletion tests/new-range.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// In theory, all RangePicker test cases should be paired with SinglePicker
import { act, fireEvent, render } from '@testing-library/react';
import { act, createEvent, fireEvent, render } from '@testing-library/react';
import dayjs, { type Dayjs } from 'dayjs';
import 'dayjs/locale/ar';
import { spyElementPrototype } from '@rc-component/util/lib/test/domHook';
Expand Down Expand Up @@ -995,6 +995,27 @@ describe('NewPicker.Range', () => {
expect(onChange).toHaveBeenCalledWith(expect.anything(), ['20200903', '20200905']);
});

it('blocks paste while mouse is down', () => {
const { container } = render(<Demo />);

const startInput = container.querySelectorAll<HTMLInputElement>('input')[0];

// Simulate focus gained by mousedown, then paste before mouse up.
fireEvent.mouseDown(startInput);
fireEvent.focus(startInput);

const pasteEvent = createEvent.paste(startInput, {
clipboardData: {
getData: () => '20200903',
},
});
pasteEvent.preventDefault = jest.fn();
fireEvent(startInput, pasteEvent);

// Guard in Input should prevent default while mouse is down
expect(pasteEvent.preventDefault).toHaveBeenCalled();
});

it('click to change selection cell', () => {
const { container } = render(<Demo />);

Expand All @@ -1010,6 +1031,38 @@ describe('NewPicker.Range', () => {
expect(startInput.selectionEnd).toEqual(6);
});

it('blocks key input while mouse is down', () => {
const { container } = render(<Demo />);

const startInput = container.querySelectorAll<HTMLInputElement>('input')[0];

// Simulate focus gained by mousedown, then key input before mouse up.
fireEvent.mouseDown(startInput);
fireEvent.focus(startInput);

const keyDownEvent = createEvent.keyDown(startInput, {
key: '1',
});
keyDownEvent.preventDefault = jest.fn();
fireEvent(startInput, keyDownEvent);

// Guard in Input should prevent default while mouse is down
expect(keyDownEvent.preventDefault).toHaveBeenCalled();
});

it('focus by mousedown defers selection sync to mouseUp', () => {
const { container } = render(<Demo />);

const startInput = container.querySelectorAll<HTMLInputElement>('input')[0];

fireEvent.mouseDown(startInput);
fireEvent.focus(startInput);

fireEvent.mouseUp(startInput);
expect(startInput.selectionStart).toBeDefined();
expect(startInput.selectionEnd).toBeDefined();
});

it('blur to reset back text', async () => {
const { container } = render(<Demo />);

Expand Down
Loading