Skip to content

Commit a48e9b9

Browse files
authored
fix: Selection not keep in sync (#52)
* chore: back of selection * test: add test case * chore: lint * chore: lint
1 parent 0dabe82 commit a48e9b9

File tree

3 files changed

+45
-1
lines changed

3 files changed

+45
-1
lines changed

src/Input.tsx

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,11 @@ const Input = forwardRef<InputRef, InputProps>((props, ref) => {
5757
const formatValue =
5858
value === undefined || value === null ? '' : String(value);
5959

60+
// =================== Select Range ===================
61+
const [selection, setSelection] = React.useState<
62+
[start: number, end: number] | null
63+
>(null);
64+
6065
// ====================== Count =======================
6166
const countConfig = useCount(count, showCount);
6267
const mergedMax = countConfig.max || maxLength;
@@ -104,6 +109,13 @@ const Input = forwardRef<InputRef, InputProps>((props, ref) => {
104109
cutValue = countConfig.exceedFormatter(currentValue, {
105110
max: countConfig.max,
106111
});
112+
113+
if (currentValue !== cutValue) {
114+
setSelection([
115+
inputRef.current?.selectionStart || 0,
116+
inputRef.current?.selectionEnd || 0,
117+
]);
118+
}
107119
}
108120
setValue(cutValue);
109121

@@ -112,6 +124,12 @@ const Input = forwardRef<InputRef, InputProps>((props, ref) => {
112124
}
113125
};
114126

127+
React.useEffect(() => {
128+
if (selection) {
129+
inputRef.current?.setSelectionRange(...selection);
130+
}
131+
}, [selection]);
132+
115133
const onInternalChange: React.ChangeEventHandler<HTMLInputElement> = (e) => {
116134
triggerChange(e, e.target.value);
117135
};

tests/count.test.tsx

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,32 @@ describe('Input.Count', () => {
8383
expect(onCompositionEnd).toHaveBeenCalled();
8484
});
8585

86+
it('exceedFormatter selection', () => {
87+
const { container } = render(
88+
<Input
89+
count={{
90+
show: true,
91+
max: 3,
92+
exceedFormatter: (val, { max }) => val.slice(0, max),
93+
}}
94+
defaultValue={'123'}
95+
/>,
96+
);
97+
98+
const input = container.querySelector('input')!;
99+
const setSelectionRange = jest.spyOn(input, 'setSelectionRange');
100+
101+
fireEvent.change(input, {
102+
target: {
103+
selectionStart: 2,
104+
selectionEnd: 2,
105+
value: '1a23',
106+
},
107+
});
108+
109+
expect(setSelectionRange).toHaveBeenCalledWith(2, 2);
110+
});
111+
86112
describe('cls', () => {
87113
it('raw', () => {
88114
const { container } = render(

tsconfig.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"module": "ESNext",
55
"moduleResolution": "node",
66
"baseUrl": "./",
7-
"lib": ["dom", "es2017", "es2022"],
7+
"lib": ["dom", "es2017", "es2022", "esnext"],
88
"jsx": "react",
99
"strict": true,
1010
"esModuleInterop": true,

0 commit comments

Comments
 (0)