Skip to content

Commit

Permalink
fix: set initial value when setting UI value (#918)
Browse files Browse the repository at this point in the history
  • Loading branch information
ph-fritsche committed Apr 11, 2022
1 parent 8bc3310 commit 7b0643b
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 14 deletions.
21 changes: 13 additions & 8 deletions src/document/index.ts
Expand Up @@ -2,9 +2,9 @@ import {dispatchUIEvent} from '../event'
import {Config} from '../setup'
import {prepareSelectionInterceptor} from './selection'
import {
clearInitialValue,
getInitialValue,
prepareValueInterceptor,
setInitialValue,
} from './value'

const isPrepared = Symbol('Node prepared with document state workarounds')
Expand Down Expand Up @@ -45,8 +45,11 @@ export function prepareDocument(document: Document) {
e => {
const el = e.target as HTMLInputElement
const initialValue = getInitialValue(el)
if (typeof initialValue === 'string' && el.value !== initialValue) {
dispatchUIEvent({} as Config, el, 'change')
if (initialValue !== undefined) {
if (el.value !== initialValue) {
dispatchUIEvent({} as Config, el, 'change')
}
clearInitialValue(el)
}
},
{
Expand All @@ -59,10 +62,6 @@ export function prepareDocument(document: Document) {
}

function prepareElement(el: Node | HTMLInputElement) {
if ('value' in el) {
setInitialValue(el)
}

if (el[isPrepared]) {
return
}
Expand All @@ -75,6 +74,12 @@ function prepareElement(el: Node | HTMLInputElement) {
el[isPrepared] = isPrepared
}

export {getUIValue, setUIValue, startTrackValue, endTrackValue} from './value'
export {
getUIValue,
setUIValue,
startTrackValue,
endTrackValue,
clearInitialValue,
} from './value'
export {getUISelection, setUISelection} from './selection'
export type {UISelectionRange} from './selection'
9 changes: 6 additions & 3 deletions src/document/value.ts
Expand Up @@ -65,6 +65,10 @@ export function setUIValue(
element: HTMLInputElement | HTMLTextAreaElement,
value: string,
) {
if (element[InitialValue] === undefined) {
element[InitialValue] = element.value
}

element.value = {
[UIValue]: UIValue,
toString: () => value,
Expand All @@ -77,10 +81,10 @@ export function getUIValue(element: HTMLInputElement | HTMLTextAreaElement) {
: String(element[UIValue])
}

export function setInitialValue(
export function clearInitialValue(
element: HTMLInputElement | HTMLTextAreaElement,
) {
element[InitialValue] = element.value
element[InitialValue] = undefined
}

export function getInitialValue(
Expand Down Expand Up @@ -122,7 +126,6 @@ function setCleanValue(
v: string,
) {
element[UIValue] = undefined
element[InitialValue] = v

// Programmatically setting the value property
// moves the cursor to the end of the input.
Expand Down
2 changes: 2 additions & 0 deletions src/utils/edit/input.ts
@@ -1,4 +1,5 @@
import {
clearInitialValue,
endTrackValue,
getUIValue,
setUIValue,
Expand Down Expand Up @@ -169,6 +170,7 @@ function editInputElement(
if (isValidDateOrTimeValue(element, newValue)) {
commitInput(config, element, newOffset, {})
dispatchUIEvent(config, element, 'change')
clearInitialValue(element)
}
} else {
commitInput(config, element, newOffset, {
Expand Down
15 changes: 12 additions & 3 deletions tests/document/index.ts
Expand Up @@ -50,7 +50,7 @@ test('keep track of value in UI', async () => {
expect(getUIValue(element)).toBe('3.5')
})

test('trigger `change` event if value changed since focus/set', async () => {
test('trigger `change` event if value changed per user input', async () => {
const {element, getEvents} = render<HTMLInputElement>(
`<input type="number"/>`,
{focus: false},
Expand All @@ -66,16 +66,25 @@ test('trigger `change` event if value changed since focus/set', async () => {
expect(getEvents('change')).toHaveLength(0)

element.focus()
// Programmatically changing value sets initial value
// Programmatically changing value is ignored
element.value = '3'
// Value doesn't change
setUIValue(element, '3')
element.blur()

expect(getEvents('change')).toHaveLength(0)

element.focus()
setUIValue(element, '2')
// value is reset so there is no change in the end
element.value = '3'
element.blur()

expect(getEvents('change')).toHaveLength(0)

element.focus()
setUIValue(element, '2')
element.value = '2'
setUIValue(element, '3')
element.blur()

expect(getEvents('change')).toHaveLength(1)
Expand Down

0 comments on commit 7b0643b

Please sign in to comment.