Skip to content

Commit

Permalink
fix(document): track HTMLInputElement.setRangeText() (#984)
Browse files Browse the repository at this point in the history
  • Loading branch information
ph-fritsche committed Jul 14, 2022
1 parent 0a3fe4f commit 73443ec
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/document/index.ts
@@ -1,6 +1,7 @@
import {dispatchUIEvent} from '../event'
import {Config} from '../setup'
import {prepareSelectionInterceptor} from './selection'
import {prepareRangeTextInterceptor} from './setRangeText'
import {
clearInitialValue,
getInitialValue,
Expand Down Expand Up @@ -69,6 +70,7 @@ function prepareElement(el: Node | HTMLInputElement) {
if ('value' in el) {
prepareValueInterceptor(el)
prepareSelectionInterceptor(el)
prepareRangeTextInterceptor(el)
}

el[isPrepared] = isPrepared
Expand Down
7 changes: 7 additions & 0 deletions src/document/selection.ts
Expand Up @@ -144,3 +144,10 @@ export function getUISelection(
endOffset: Math.max(sel.anchorOffset, sel.focusOffset),
}
}

/** Flag the IDL selection as clean. This does not change the selection. */
export function setUISelectionClean(
element: HTMLInputElement | HTMLTextAreaElement,
) {
element[UISelection] = undefined
}
21 changes: 21 additions & 0 deletions src/document/setRangeText.ts
@@ -0,0 +1,21 @@
import {prepareInterceptor} from './interceptor'
import {setUISelectionClean} from './selection'
import {setUIValueClean} from './value'

export function prepareRangeTextInterceptor(
element: HTMLInputElement | HTMLTextAreaElement,
) {
prepareInterceptor(
element,
'setRangeText',
function interceptorImpl(...realArgs) {
return {
realArgs,
then: () => {
setUIValueClean(element)
setUISelectionClean(element)
},
}
},
)
}
7 changes: 7 additions & 0 deletions src/document/value.ts
Expand Up @@ -81,6 +81,13 @@ export function getUIValue(element: HTMLInputElement | HTMLTextAreaElement) {
: String(element[UIValue])
}

/** Flag the IDL value as clean. This does not change the value.*/
export function setUIValueClean(
element: HTMLInputElement | HTMLTextAreaElement,
) {
element[UIValue] = undefined
}

export function clearInitialValue(
element: HTMLInputElement | HTMLTextAreaElement,
) {
Expand Down
19 changes: 19 additions & 0 deletions tests/document/index.ts
Expand Up @@ -183,3 +183,22 @@ test('select input without selectionRange support', () => {
expect(getUISelection(element)).toHaveProperty('startOffset', 0)
expect(getUISelection(element)).toHaveProperty('endOffset', 3)
})

test('track changes to value and selection per setRangeText', () => {
const {element} = render<HTMLInputElement>(`<input/>`)
prepare(element)
setUIValue(element, 'abcd')
setUISelection(element, {focusOffset: 3})

element.setRangeText('X', 1, 2)
expect(element).toHaveValue('aXcd')
expect(element).toHaveProperty('selectionStart', 3)
expect(getUIValue(element)).toBe('aXcd')
expect(getUISelection(element)).toHaveProperty('focusOffset', 3)

element.setRangeText('Y', 1, 2, 'start')
expect(element).toHaveValue('aYcd')
expect(element).toHaveProperty('selectionEnd', 1)
expect(getUIValue(element)).toBe('aYcd')
expect(getUISelection(element)).toHaveProperty('focusOffset', 1)
})

0 comments on commit 73443ec

Please sign in to comment.