Skip to content

Commit 7b0643b

Browse files
authored
fix: set initial value when setting UI value (#918)
1 parent 8bc3310 commit 7b0643b

File tree

4 files changed

+33
-14
lines changed

4 files changed

+33
-14
lines changed

src/document/index.ts

+13-8
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ import {dispatchUIEvent} from '../event'
22
import {Config} from '../setup'
33
import {prepareSelectionInterceptor} from './selection'
44
import {
5+
clearInitialValue,
56
getInitialValue,
67
prepareValueInterceptor,
7-
setInitialValue,
88
} from './value'
99

1010
const isPrepared = Symbol('Node prepared with document state workarounds')
@@ -45,8 +45,11 @@ export function prepareDocument(document: Document) {
4545
e => {
4646
const el = e.target as HTMLInputElement
4747
const initialValue = getInitialValue(el)
48-
if (typeof initialValue === 'string' && el.value !== initialValue) {
49-
dispatchUIEvent({} as Config, el, 'change')
48+
if (initialValue !== undefined) {
49+
if (el.value !== initialValue) {
50+
dispatchUIEvent({} as Config, el, 'change')
51+
}
52+
clearInitialValue(el)
5053
}
5154
},
5255
{
@@ -59,10 +62,6 @@ export function prepareDocument(document: Document) {
5962
}
6063

6164
function prepareElement(el: Node | HTMLInputElement) {
62-
if ('value' in el) {
63-
setInitialValue(el)
64-
}
65-
6665
if (el[isPrepared]) {
6766
return
6867
}
@@ -75,6 +74,12 @@ function prepareElement(el: Node | HTMLInputElement) {
7574
el[isPrepared] = isPrepared
7675
}
7776

78-
export {getUIValue, setUIValue, startTrackValue, endTrackValue} from './value'
77+
export {
78+
getUIValue,
79+
setUIValue,
80+
startTrackValue,
81+
endTrackValue,
82+
clearInitialValue,
83+
} from './value'
7984
export {getUISelection, setUISelection} from './selection'
8085
export type {UISelectionRange} from './selection'

src/document/value.ts

+6-3
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,10 @@ export function setUIValue(
6565
element: HTMLInputElement | HTMLTextAreaElement,
6666
value: string,
6767
) {
68+
if (element[InitialValue] === undefined) {
69+
element[InitialValue] = element.value
70+
}
71+
6872
element.value = {
6973
[UIValue]: UIValue,
7074
toString: () => value,
@@ -77,10 +81,10 @@ export function getUIValue(element: HTMLInputElement | HTMLTextAreaElement) {
7781
: String(element[UIValue])
7882
}
7983

80-
export function setInitialValue(
84+
export function clearInitialValue(
8185
element: HTMLInputElement | HTMLTextAreaElement,
8286
) {
83-
element[InitialValue] = element.value
87+
element[InitialValue] = undefined
8488
}
8589

8690
export function getInitialValue(
@@ -122,7 +126,6 @@ function setCleanValue(
122126
v: string,
123127
) {
124128
element[UIValue] = undefined
125-
element[InitialValue] = v
126129

127130
// Programmatically setting the value property
128131
// moves the cursor to the end of the input.

src/utils/edit/input.ts

+2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {
2+
clearInitialValue,
23
endTrackValue,
34
getUIValue,
45
setUIValue,
@@ -169,6 +170,7 @@ function editInputElement(
169170
if (isValidDateOrTimeValue(element, newValue)) {
170171
commitInput(config, element, newOffset, {})
171172
dispatchUIEvent(config, element, 'change')
173+
clearInitialValue(element)
172174
}
173175
} else {
174176
commitInput(config, element, newOffset, {

tests/document/index.ts

+12-3
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ test('keep track of value in UI', async () => {
5050
expect(getUIValue(element)).toBe('3.5')
5151
})
5252

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

6868
element.focus()
69-
// Programmatically changing value sets initial value
69+
// Programmatically changing value is ignored
7070
element.value = '3'
71+
// Value doesn't change
7172
setUIValue(element, '3')
7273
element.blur()
7374

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

7677
element.focus()
78+
setUIValue(element, '2')
79+
// value is reset so there is no change in the end
80+
element.value = '3'
81+
element.blur()
82+
83+
expect(getEvents('change')).toHaveLength(0)
84+
85+
element.focus()
86+
setUIValue(element, '2')
7787
element.value = '2'
78-
setUIValue(element, '3')
7988
element.blur()
8089

8190
expect(getEvents('change')).toHaveLength(1)

0 commit comments

Comments
 (0)