From bc7d8874fcd16acdaef5899ba9e7d56194233c98 Mon Sep 17 00:00:00 2001 From: Spyros Ioakeimidis Date: Thu, 1 Feb 2018 20:44:45 +0100 Subject: [PATCH] Do not set selection when prior selection is undefined (#12062) `restoreSelection` did not account for input elements that have changed type after the commit phase. The new `text` input supported selection but the old `email` did not and `setSelection` was incorrectly trying to restore `null` selection state. We also extend input type check in selection capabilities to cover cases where input type is `search`, `tel`, `url`, or `password`. --- .../fixtures/text-inputs/ReplaceEmailInput.js | 33 +++++++++++++ .../components/fixtures/text-inputs/index.js | 16 +++++++ .../src/client/ReactInputSelection.js | 12 ++++- scripts/rollup/results.json | 48 +++++++++---------- 4 files changed, 83 insertions(+), 26 deletions(-) create mode 100644 fixtures/dom/src/components/fixtures/text-inputs/ReplaceEmailInput.js diff --git a/fixtures/dom/src/components/fixtures/text-inputs/ReplaceEmailInput.js b/fixtures/dom/src/components/fixtures/text-inputs/ReplaceEmailInput.js new file mode 100644 index 0000000000000..db9da5c9efa27 --- /dev/null +++ b/fixtures/dom/src/components/fixtures/text-inputs/ReplaceEmailInput.js @@ -0,0 +1,33 @@ +import Fixture from '../../Fixture'; + +const React = window.React; + +class ReplaceEmailInput extends React.Component { + state = { + formSubmitted: false, + }; + + render() { + return ( + +
{ + event.preventDefault(); + this.setState({formSubmitted: true}); + }}> +
+ Email + {!this.state.formSubmitted ? ( + + ) : ( + + )} +
+
+
+ ); + } +} + +export default ReplaceEmailInput; diff --git a/fixtures/dom/src/components/fixtures/text-inputs/index.js b/fixtures/dom/src/components/fixtures/text-inputs/index.js index af71edcbb5cbf..9dffa628f7519 100644 --- a/fixtures/dom/src/components/fixtures/text-inputs/index.js +++ b/fixtures/dom/src/components/fixtures/text-inputs/index.js @@ -2,6 +2,7 @@ import Fixture from '../../Fixture'; import FixtureSet from '../../FixtureSet'; import TestCase from '../../TestCase'; import InputTestCase from './InputTestCase'; +import ReplaceEmailInput from './ReplaceEmailInput'; const React = window.React; @@ -110,6 +111,21 @@ class TextInputFixtures extends React.Component { + + +
  • Type "test@test.com"
  • +
  • Press enter
  • +
    + + + There should be no selection-related error in the console. + + + +
    + diff --git a/packages/react-dom/src/client/ReactInputSelection.js b/packages/react-dom/src/client/ReactInputSelection.js index 506153a118053..6ee2351b46ffb 100644 --- a/packages/react-dom/src/client/ReactInputSelection.js +++ b/packages/react-dom/src/client/ReactInputSelection.js @@ -26,7 +26,12 @@ export function hasSelectionCapabilities(elem) { const nodeName = elem && elem.nodeName && elem.nodeName.toLowerCase(); return ( nodeName && - ((nodeName === 'input' && elem.type === 'text') || + ((nodeName === 'input' && + (elem.type === 'text' || + elem.type === 'search' || + elem.type === 'tel' || + elem.type === 'url' || + elem.type === 'password')) || nodeName === 'textarea' || elem.contentEditable === 'true') ); @@ -52,7 +57,10 @@ export function restoreSelection(priorSelectionInformation) { const priorFocusedElem = priorSelectionInformation.focusedElem; const priorSelectionRange = priorSelectionInformation.selectionRange; if (curFocusedElem !== priorFocusedElem && isInDocument(priorFocusedElem)) { - if (hasSelectionCapabilities(priorFocusedElem)) { + if ( + priorSelectionRange !== null && + hasSelectionCapabilities(priorFocusedElem) + ) { setSelection(priorFocusedElem, priorSelectionRange); } diff --git a/scripts/rollup/results.json b/scripts/rollup/results.json index cecbfdd56c83a..a77a0e52a8a90 100644 --- a/scripts/rollup/results.json +++ b/scripts/rollup/results.json @@ -46,43 +46,43 @@ "filename": "react-dom.development.js", "bundleType": "UMD_DEV", "packageName": "react-dom", - "size": 591513, - "gzip": 138743 + "size": 591647, + "gzip": 138778 }, { "filename": "react-dom.production.min.js", "bundleType": "UMD_PROD", "packageName": "react-dom", - "size": 96778, - "gzip": 31445 + "size": 96862, + "gzip": 31467 }, { "filename": "react-dom.development.js", "bundleType": "NODE_DEV", "packageName": "react-dom", - "size": 575526, - "gzip": 134516 + "size": 575660, + "gzip": 134558 }, { "filename": "react-dom.production.min.js", "bundleType": "NODE_PROD", "packageName": "react-dom", - "size": 95503, - "gzip": 30619 + "size": 95587, + "gzip": 30644 }, { "filename": "ReactDOM-dev.js", "bundleType": "FB_DEV", "packageName": "react-dom", - "size": 594783, - "gzip": 136782 + "size": 594973, + "gzip": 136823 }, { "filename": "ReactDOM-prod.js", "bundleType": "FB_PROD", "packageName": "react-dom", - "size": 279046, - "gzip": 53062 + "size": 279248, + "gzip": 53103 }, { "filename": "react-dom-test-utils.development.js", @@ -401,31 +401,31 @@ }, { "filename": "react-is.development.js", - "bundleType": "NODE_DEV", + "bundleType": "UMD_DEV", "packageName": "react-is", - "size": 3358, - "gzip": 1015 + "size": 3547, + "gzip": 1071 }, { "filename": "react-is.production.min.js", - "bundleType": "NODE_PROD", + "bundleType": "UMD_PROD", "packageName": "react-is", - "size": 1433, - "gzip": 607 + "size": 1515, + "gzip": 670 }, { "filename": "react-is.development.js", - "bundleType": "UMD_DEV", + "bundleType": "NODE_DEV", "packageName": "react-is", - "size": 3547, - "gzip": 1071 + "size": 3358, + "gzip": 1015 }, { "filename": "react-is.production.min.js", - "bundleType": "UMD_PROD", + "bundleType": "NODE_PROD", "packageName": "react-is", - "size": 1515, - "gzip": 670 + "size": 1433, + "gzip": 607 } ] } \ No newline at end of file