diff --git a/lib/update-props.js b/lib/update-props.js
index bbf5ea8..cd9434b 100644
--- a/lib/update-props.js
+++ b/lib/update-props.js
@@ -55,17 +55,23 @@ function updateProps (domNode, oldVirtualNode, oldProps, newVirtualNode, newProp
updateNestedProps(domNode.style, oldValue, newValue, true)
} else if (name === 'attributes') {
updateAttributes(domNode, oldValue, newValue)
- } else {
- if (newValue !== oldValue) {
- if (name !== 'innerHTML' && newVirtualNode && SVG_TAGS.has(newVirtualNode.tag)) {
- domNode.setAttribute(SVG_ATTRIBUTE_TRANSLATIONS.get(name) || name, newValue)
- } else if (newVirtualNode && newVirtualNode.tag === 'input'
- && name === 'value' && domNode[name] === newValue) {
- // Do not update `value` of an `input` unless it differs.
- // Every change will reset the cursor position.
- } else {
- domNode[name] = newValue
- }
+ } else if (
+ name === 'value' &&
+ newVirtualNode && (
+ newVirtualNode.tag === 'input' ||
+ newVirtualNode.tag === 'select'
+ )
+ ) {
+ // Do not update `value` of an `input` unless it differs.
+ // Every change will reset the cursor position.
+ if (domNode[name] !== newValue) {
+ domNode[name] = newValue
+ }
+ } else if (newValue !== oldValue) {
+ if (name !== 'innerHTML' && newVirtualNode && SVG_TAGS.has(newVirtualNode.tag)) {
+ domNode.setAttribute(SVG_ATTRIBUTE_TRANSLATIONS.get(name) || name, newValue)
+ } else {
+ domNode[name] = newValue
}
}
}
diff --git a/test/unit/patch.test.js b/test/unit/patch.test.js
index 826e666..3d499bc 100644
--- a/test/unit/patch.test.js
+++ b/test/unit/patch.test.js
@@ -66,26 +66,72 @@ describe('patch (oldVirtualNode, newVirtualNode)', () => {
assert(!newNode.className)
})
- it('correctly updates the `input.value` property', function () {
+ describe('`input.value` property', function () {
+ it('conserves the selection when possible', function () {
+ const virtualNode1 =
+ const element = render(virtualNode1)
+
+ // Assume the user changed the value to `ping` by
+ // moving the cursor after the `i` and adding `n`.
+ // The new value is now `ping` and the cursor
+ // position is after the `n` on index 3
+ element.value = 'ping'
+ element.selectionStart = 3
+ element.selectionEnd = 3
+
+ // Assume that the input is a "controlled" input so
+ // it updates the virtual node with the same value
+ const virtualNode2 =
+ patch(virtualNode1, virtualNode2)
+
+ // the selection should have stayed in the same position
+ assert.equal(element.selectionStart, 3)
+ assert.equal(element.selectionEnd, 3)
+ })
+
+ it('correctly updates the `select.value` property', function () {
+ const virtualNode1 = (
+
+ )
+ const element = render(virtualNode1)
+
+ // Assume the user changed the value to `b`.
+ element.value = 'b'
+
+ // Assume that the select is a "controlled" select and
+ // the changes have been rejected, so the virtual node
+ // remains the same
+ const virtualNode2 = (
+
+ )
+ patch(virtualNode1, virtualNode2)
+
+ // the value should have been reverted
+ assert.equal(element.value, 'a')
+ })
+ })
+
+ it('reverts when change is rejected', function () {
const virtualNode1 =
const element = render(virtualNode1)
- // Assume the user changed the value to `ping` by
- // moving the cursor after the `i` and adding `n`.
- // The new value is now `ping` and the cursor
- // position is after the `n` on index 3
+ // Assume the user changed the value to `ping`.
element.value = 'ping'
- element.selectionStart = 3
- element.selectionEnd = 3
- // Assume that the input is a "controlled" input so
- // it updates the virtual node with the same value
- const virtualNode2 =
+ // Assume that the input is a "controlled" input and
+ // the changes have been rejected, so the virtual node
+ // remains the same
+ const virtualNode2 =
patch(virtualNode1, virtualNode2)
- // the selection should have stayed in the same position
- assert.equal(element.selectionStart, 3)
- assert.equal(element.selectionEnd, 3)
+ // the value should have been reverted
+ assert.equal(element.value, 'pig')
})
it('allows attributes to be updated via the special `attributes` property', () => {