Skip to content

Commit 9610401

Browse files
authored
fix: change event should provider correct selection data (#65)
* fix: selection * test: add test case
1 parent e643b06 commit 9610401

File tree

3 files changed

+40
-21
lines changed

3 files changed

+40
-21
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,4 @@ dist/
4040
# dumi
4141
.dumi/tmp
4242
.dumi/tmp-production
43+
.node

src/utils/commonUtils.ts

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,30 @@ export function hasPrefixSuffix(props: BaseInputProps | InputProps) {
99
return !!(props.prefix || props.suffix || props.allowClear);
1010
}
1111

12+
// TODO: It's better to use `Proxy` replace the `element.value`. But we still need support IE11.
13+
function cloneEvent<
14+
EventType extends React.SyntheticEvent<any, any>,
15+
Element extends HTMLInputElement | HTMLTextAreaElement,
16+
>(event: EventType, target: Element, value: any): EventType {
17+
// A bug report filed on WebKit's Bugzilla tracker, dating back to 2009, specifically addresses the issue of cloneNode() not copying files of <input type="file"> elements.
18+
// As of the last update, this bug was still marked as "NEW," indicating that it might not have been resolved yet​​.
19+
// https://bugs.webkit.org/show_bug.cgi?id=28123
20+
const currentTarget = target.cloneNode(true) as Element;
21+
22+
// click clear icon
23+
const newEvent = Object.create(event, {
24+
target: { value: currentTarget },
25+
currentTarget: { value: currentTarget },
26+
});
27+
28+
// Fill data
29+
currentTarget.value = value;
30+
currentTarget.selectionStart = target.selectionStart;
31+
currentTarget.selectionEnd = target.selectionEnd;
32+
33+
return newEvent;
34+
}
35+
1236
export function resolveOnChange<
1337
E extends HTMLInputElement | HTMLTextAreaElement,
1438
>(
@@ -38,18 +62,8 @@ export function resolveOnChange<
3862
// }}
3963
// />
4064

41-
// A bug report filed on WebKit's Bugzilla tracker, dating back to 2009, specifically addresses the issue of cloneNode() not copying files of <input type="file"> elements.
42-
// As of the last update, this bug was still marked as "NEW," indicating that it might not have been resolved yet​​.
43-
// https://bugs.webkit.org/show_bug.cgi?id=28123
44-
const currentTarget = target.cloneNode(true) as E;
45-
46-
// click clear icon
47-
event = Object.create(e, {
48-
target: { value: currentTarget },
49-
currentTarget: { value: currentTarget },
50-
});
65+
event = cloneEvent(e, target, '');
5166

52-
currentTarget.value = '';
5367
onChange(event as React.ChangeEvent<E>);
5468
return;
5569
}
@@ -58,16 +72,7 @@ export function resolveOnChange<
5872
// https://github.com/ant-design/ant-design/issues/45737
5973
// https://github.com/ant-design/ant-design/issues/46598
6074
if (target.type !== 'file' && targetValue !== undefined) {
61-
// A bug report filed on WebKit's Bugzilla tracker, dating back to 2009, specifically addresses the issue of cloneNode() not copying files of <input type="file"> elements.
62-
// As of the last update, this bug was still marked as "NEW," indicating that it might not have been resolved yet​​.
63-
// https://bugs.webkit.org/show_bug.cgi?id=28123
64-
const currentTarget = target.cloneNode(true) as E;
65-
66-
event = Object.create(e, {
67-
target: { value: currentTarget },
68-
currentTarget: { value: currentTarget },
69-
});
70-
currentTarget.value = targetValue;
75+
event = cloneEvent(e, target, targetValue);
7176
onChange(event as React.ChangeEvent<E>);
7277
return;
7378
}

tests/index.test.tsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,19 @@ describe('Input ref', () => {
349349
inputSpy.mockRestore();
350350
});
351351

352+
it('selectionXXX should pass', () => {
353+
const onChange = jest.fn();
354+
const { container } = render(<Input onChange={onChange} />);
355+
356+
const inputEl = container.querySelector('input')!;
357+
fireEvent.change(inputEl, { target: { value: 'test' } });
358+
359+
expect(onChange).toHaveBeenCalled();
360+
const event = onChange.mock.calls[0][0];
361+
expect(event.target.selectionStart).toBe(4);
362+
expect(event.target.selectionEnd).toBe(4);
363+
});
364+
352365
it('input should work', () => {
353366
const ref = React.createRef<InputRef>();
354367
const { container } = render(<Input ref={ref} defaultValue="light" />);

0 commit comments

Comments
 (0)