diff --git a/fixtures/dom/src/components/Header.js b/fixtures/dom/src/components/Header.js index 77c1ecfc30da6..c2a8c8d945030 100644 --- a/fixtures/dom/src/components/Header.js +++ b/fixtures/dom/src/components/Header.js @@ -71,6 +71,7 @@ class Header extends React.Component { Text Inputs Number Input Password Input + Email Input Selects Textareas diff --git a/fixtures/dom/src/components/fixtures/email-inputs/EmailDisabledAttributesTestCase.js b/fixtures/dom/src/components/fixtures/email-inputs/EmailDisabledAttributesTestCase.js new file mode 100644 index 0000000000000..a844578550e8e --- /dev/null +++ b/fixtures/dom/src/components/fixtures/email-inputs/EmailDisabledAttributesTestCase.js @@ -0,0 +1,39 @@ +import Fixture from '../../Fixture'; + +const React = window.React; + +class EmailDisabledAttributesTestCase extends React.Component { + state = {value: 'a@fb.com'}; + onChange = event => { + this.setState({value: event.target.value}); + }; + render() { + return ( + + {this.props.children} + + + + Controlled + + + {' '} + Value: {JSON.stringify(this.state.value)} + + + + + Uncontrolled + + + + + ); + } +} + +export default EmailDisabledAttributesTestCase; diff --git a/fixtures/dom/src/components/fixtures/email-inputs/EmailEnabledAttributesTestCase.js b/fixtures/dom/src/components/fixtures/email-inputs/EmailEnabledAttributesTestCase.js new file mode 100644 index 0000000000000..e5448a2b9b9b0 --- /dev/null +++ b/fixtures/dom/src/components/fixtures/email-inputs/EmailEnabledAttributesTestCase.js @@ -0,0 +1,48 @@ +import Fixture from '../../Fixture'; + +const React = window.React; + +class EmailAttributesTestCase extends React.Component { + state = {value: 'a@fb.com'}; + onChange = event => { + this.setState({value: event.target.value}); + }; + render() { + return ( + + {this.props.children} + + + + Controlled + + + {' '} + Value: {JSON.stringify(this.state.value)} + + + + + Uncontrolled + + + + + ); + } +} + +export default EmailAttributesTestCase; diff --git a/fixtures/dom/src/components/fixtures/email-inputs/JumpingCursorTestCase.js b/fixtures/dom/src/components/fixtures/email-inputs/JumpingCursorTestCase.js new file mode 100644 index 0000000000000..e95653967448d --- /dev/null +++ b/fixtures/dom/src/components/fixtures/email-inputs/JumpingCursorTestCase.js @@ -0,0 +1,39 @@ +import Fixture from '../../Fixture'; + +const React = window.React; + +class JumpingCursorTestCase extends React.Component { + state = {value: ''}; + onChange = event => { + this.setState({value: event.target.value}); + }; + render() { + return ( + + {this.props.children} + + + + Controlled + + + {' '} + Value: {JSON.stringify(this.state.value)} + + + + + Uncontrolled + + + + + ); + } +} + +export default JumpingCursorTestCase; diff --git a/fixtures/dom/src/components/fixtures/email-inputs/index.js b/fixtures/dom/src/components/fixtures/email-inputs/index.js new file mode 100644 index 0000000000000..1af9d2b2fa5fb --- /dev/null +++ b/fixtures/dom/src/components/fixtures/email-inputs/index.js @@ -0,0 +1,68 @@ +import FixtureSet from '../../FixtureSet'; +import TestCase from '../../TestCase'; +import JumpingCursorTestCase from './JumpingCursorTestCase'; +import EmailEnabledAttributesTestCase from './EmailEnabledAttributesTestCase'; +import EmailDisabledAttributesTestCase from './EmailDisabledAttributesTestCase'; + +const React = window.React; + +function EmailInputs() { + return ( + + + + Type space and character + Type character, space, character, delete last character + + + Cursor not moving. + + + + + + + Type after existing text ',b@tt.com' + Try to type spaces after typed text + + + + Spaces not added. When cursor hovered over input, popup "Please match + the requested format." is showed. + + + + + + + + Type after existing text ',b@tt.com' + Try to type spaces after typed text + + + + Spaces are added freely. When cursor hovered over input, popup "A part + following '@' should not contain the symbol ','." is showed. + + + + + + ); +} + +export default EmailInputs; diff --git a/packages/react-dom/src/client/ReactDOMInput.js b/packages/react-dom/src/client/ReactDOMInput.js index 884c2ad9dfe2f..77b908112a360 100644 --- a/packages/react-dom/src/client/ReactDOMInput.js +++ b/packages/react-dom/src/client/ReactDOMInput.js @@ -410,8 +410,8 @@ export function setDefaultValue( value: *, ) { if ( - // Focused number inputs synchronize on blur. See ChangeEventPlugin.js - type !== 'number' || + // Focused number and email inputs synchronize on blur. See ChangeEventPlugin.js + (type !== 'number' && type !== 'email') || node.ownerDocument.activeElement !== node ) { if (value == null) { diff --git a/packages/react-dom/src/events/ChangeEventPlugin.js b/packages/react-dom/src/events/ChangeEventPlugin.js index 18a30258132bc..d4ee86c95ea0f 100644 --- a/packages/react-dom/src/events/ChangeEventPlugin.js +++ b/packages/react-dom/src/events/ChangeEventPlugin.js @@ -236,13 +236,17 @@ function getTargetInstForInputOrChangeEvent(topLevelType, targetInst) { function handleControlledInputBlur(node) { let state = node._wrapperState; - if (!state || !state.controlled || node.type !== 'number') { + if ( + !state || + !state.controlled || + (node.type !== 'number' && node.type !== 'email') + ) { return; } if (!disableInputAttributeSyncing) { // If controlled, assign the value attribute to the current value on blur - setDefaultValue(node, 'number', node.value); + setDefaultValue(node, node.type, node.value); } }