Teact: Preserve caret at end in controlled inputs
This commit is contained in:
parent
e9c2df4beb
commit
f272f63afc
@ -23,9 +23,15 @@ import { DEBUG } from '../../config';
|
|||||||
import { addEventListener, removeAllDelegatedListeners, removeEventListener } from './dom-events';
|
import { addEventListener, removeAllDelegatedListeners, removeEventListener } from './dom-events';
|
||||||
import { unique } from '../../util/iteratees';
|
import { unique } from '../../util/iteratees';
|
||||||
|
|
||||||
type VirtualDomHead = {
|
interface VirtualDomHead {
|
||||||
children: [VirtualElement] | [];
|
children: [VirtualElement] | [];
|
||||||
};
|
}
|
||||||
|
|
||||||
|
interface SelectionState {
|
||||||
|
selectionStart: number | null;
|
||||||
|
selectionEnd: number | null;
|
||||||
|
isCaretAtEnd: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
const FILTERED_ATTRIBUTES = new Set(['key', 'ref', 'teactFastList', 'teactOrderKey']);
|
const FILTERED_ATTRIBUTES = new Set(['key', 'ref', 'teactFastList', 'teactOrderKey']);
|
||||||
const HTML_ATTRIBUTES = new Set(['dir', 'role', 'form']);
|
const HTML_ATTRIBUTES = new Set(['dir', 'role', 'form']);
|
||||||
@ -558,20 +564,18 @@ function processControlled(tag: string, props: AnyLiteral) {
|
|||||||
onInput?.(e);
|
onInput?.(e);
|
||||||
onChange?.(e);
|
onChange?.(e);
|
||||||
|
|
||||||
if (value !== undefined) {
|
if (value !== undefined && value !== e.currentTarget.value) {
|
||||||
const { selectionStart, selectionEnd } = e.currentTarget;
|
const { selectionStart, selectionEnd } = e.currentTarget;
|
||||||
|
const isCaretAtEnd = selectionStart === selectionEnd && selectionEnd === e.currentTarget.value.length;
|
||||||
|
|
||||||
if (e.currentTarget.value !== value) {
|
e.currentTarget.value = value;
|
||||||
e.currentTarget.value = value;
|
|
||||||
|
|
||||||
if (selectionStart !== undefined && selectionEnd !== undefined) {
|
if (typeof selectionStart === 'number' && typeof selectionEnd === 'number') {
|
||||||
e.currentTarget.setSelectionRange(selectionStart, selectionEnd);
|
e.currentTarget.setSelectionRange(selectionStart, selectionEnd);
|
||||||
|
|
||||||
// eslint-disable-next-line no-underscore-dangle
|
const selectionState: SelectionState = { selectionStart, selectionEnd, isCaretAtEnd };
|
||||||
e.currentTarget.dataset.__teactSelectionStart = String(selectionStart);
|
// eslint-disable-next-line no-underscore-dangle
|
||||||
// eslint-disable-next-line no-underscore-dangle
|
e.currentTarget.dataset.__teactSelectionState = JSON.stringify(selectionState);
|
||||||
e.currentTarget.dataset.__teactSelectionEnd = String(selectionEnd);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -630,15 +634,22 @@ function setAttribute(element: HTMLElement, key: string, value: any) {
|
|||||||
element.className = value;
|
element.className = value;
|
||||||
// An optimization attempt
|
// An optimization attempt
|
||||||
} else if (key === 'value') {
|
} else if (key === 'value') {
|
||||||
if ((element as HTMLInputElement).value !== value) {
|
const inputEl = element as HTMLInputElement;
|
||||||
const {
|
|
||||||
__teactSelectionStart: selectionStart, __teactSelectionEnd: selectionEnd,
|
|
||||||
} = (element as HTMLInputElement).dataset;
|
|
||||||
|
|
||||||
(element as HTMLInputElement).value = value;
|
if (inputEl.value !== value) {
|
||||||
|
inputEl.value = value;
|
||||||
|
|
||||||
if (selectionStart !== undefined && selectionEnd !== undefined) {
|
// eslint-disable-next-line no-underscore-dangle
|
||||||
(element as HTMLInputElement).setSelectionRange(Number(selectionStart), Number(selectionEnd));
|
const selectionStateJson = inputEl.dataset.__teactSelectionState;
|
||||||
|
if (selectionStateJson) {
|
||||||
|
const { selectionStart, selectionEnd, isCaretAtEnd } = JSON.parse(selectionStateJson) as SelectionState;
|
||||||
|
|
||||||
|
if (isCaretAtEnd) {
|
||||||
|
const length = inputEl.value.length;
|
||||||
|
inputEl.setSelectionRange(length, length);
|
||||||
|
} else if (typeof selectionStart === 'number' && typeof selectionEnd === 'number') {
|
||||||
|
inputEl.setSelectionRange(selectionStart, selectionEnd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (key === 'style') {
|
} else if (key === 'style') {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user