diff --git a/fixtures/dom/src/components/IssueList.js b/fixtures/dom/src/components/IssueList.js new file mode 100644 index 0000000000000..553fdb3fd8577 --- /dev/null +++ b/fixtures/dom/src/components/IssueList.js @@ -0,0 +1,26 @@ +const React = window.React; + +function csv(string) { + return string.split(/\s*,\s*/); +} + +export default function IssueList({issues}) { + if (!issues) { + return null; + } + + if (typeof issues === 'string') { + issues = csv(issues); + } + + let links = issues.reduce((memo, issue, i) => { + return memo.concat( + i > 0 && i < issues.length ? ', ' : null, + + {issue} + + ); + }, []); + + return {links}; +} diff --git a/fixtures/dom/src/components/TestCase.js b/fixtures/dom/src/components/TestCase.js index e1e6321e269a8..394e61578aa1c 100644 --- a/fixtures/dom/src/components/TestCase.js +++ b/fixtures/dom/src/components/TestCase.js @@ -1,10 +1,12 @@ import cn from 'classnames'; import semver from 'semver'; -import React from 'react'; import PropTypes from 'prop-types'; +import IssueList from './IssueList'; import {parse} from 'query-string'; import {semverString} from './propTypes'; +const React = window.React; + const propTypes = { children: PropTypes.node.isRequired, title: PropTypes.node.isRequired, @@ -36,6 +38,7 @@ class TestCase extends React.Component { resolvedIn, resolvedBy, affectedBrowsers, + relatedIssues, children, } = this.props; @@ -93,6 +96,9 @@ class TestCase extends React.Component { {affectedBrowsers &&
Affected browsers:
} {affectedBrowsers &&
{affectedBrowsers}
} + + {relatedIssues &&
Related Issues:
} + {relatedIssues &&
}

diff --git a/fixtures/dom/src/components/fixtures/selects/index.js b/fixtures/dom/src/components/fixtures/selects/index.js index b89e63314b2dd..a0b34470bfb95 100644 --- a/fixtures/dom/src/components/fixtures/selects/index.js +++ b/fixtures/dom/src/components/fixtures/selects/index.js @@ -1,3 +1,6 @@ +import FixtureSet from '../../FixtureSet'; +import TestCase from '../../TestCase'; + const React = window.React; const ReactDOM = window.ReactDOM; @@ -31,35 +34,73 @@ class SelectFixture extends React.Component { render() { return ( -

-
- Controlled - - Value: {this.state.value} -
-
- Uncontrolled - - -
-
- Controlled in nested subtree -
(this._nestedDOMNode = node)} /> - - This should synchronize in both direction with the one above. - -
-
+ +
+
+ Controlled + + Value: {this.state.value} +
+
+ Uncontrolled + +
+
+ Controlled in nested subtree +
(this._nestedDOMNode = node)} /> + + This should synchronize in both direction with the "Controlled". + +
+
+ + + +
  • Open the select
  • +
  • Select "1"
  • +
  • Attempt to reselect "Please select an item"
  • +
    + + + The initial picked option should be "Please select an + item", however it should not be a selectable option. + + +
    + +
    +
    + + + + The initial picked option value should "0": the first non-disabled option. + + +
    + +
    +
    +
    ); } } diff --git a/fixtures/dom/src/style.css b/fixtures/dom/src/style.css index cb38d9e0fffa5..28e01b611b2fe 100644 --- a/fixtures/dom/src/style.css +++ b/fixtures/dom/src/style.css @@ -8,23 +8,20 @@ html { font-size: 10px; } body { - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", + "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", + sans-serif; font-size: 1.4rem; margin: 0; padding: 0; } -select { - width: 12rem; -} - button { margin: 10px; font-size: 18px; padding: 5px; } - .header { background: #222; box-shadow: inset 0 -1px 3px #000; @@ -34,6 +31,10 @@ button { padding: .8rem 1.6rem; } +.header select { + width: 12rem; +} + .header__inner { display: table; margin: 0 auto; @@ -101,7 +102,8 @@ fieldset { overflow: hidden; } -ul, ol { +ul, +ol { margin: 0 0 2rem 0; } @@ -212,3 +214,7 @@ li { background-color: #f4f4f4; border-top: 1px solid #d9d9d9; } + +.field-group { + overflow: hidden; +} diff --git a/src/renderers/dom/fiber/wrappers/ReactDOMFiberSelect.js b/src/renderers/dom/fiber/wrappers/ReactDOMFiberSelect.js index 6a5599b707224..e31b2b5b4893c 100644 --- a/src/renderers/dom/fiber/wrappers/ReactDOMFiberSelect.js +++ b/src/renderers/dom/fiber/wrappers/ReactDOMFiberSelect.js @@ -101,14 +101,18 @@ function updateOptions( // Do not set `select.value` as exact behavior isn't consistent across all // browsers for all cases. let selectedValue = '' + (propValue: string); + let defaultSelected = null; for (let i = 0; i < options.length; i++) { if (options[i].value === selectedValue) { options[i].selected = true; return; } + if (defaultSelected === null && !options[i].disabled) { + defaultSelected = options[i]; + } } - if (options.length) { - options[0].selected = true; + if (defaultSelected !== null) { + defaultSelected.selected = true; } } } diff --git a/src/renderers/dom/shared/wrappers/__tests__/ReactDOMSelect-test.js b/src/renderers/dom/shared/wrappers/__tests__/ReactDOMSelect-test.js index 95c547b7b9e8d..b4dfa586fb7b1 100644 --- a/src/renderers/dom/shared/wrappers/__tests__/ReactDOMSelect-test.js +++ b/src/renderers/dom/shared/wrappers/__tests__/ReactDOMSelect-test.js @@ -128,6 +128,22 @@ describe('ReactDOMSelect', () => { expect(node.value).toEqual('gorilla'); }); + it('should default to the first non-disabled option', () => { + var stub = ( + + ); + var container = document.createElement('div'); + stub = ReactDOM.render(stub, container); + var node = ReactDOM.findDOMNode(stub); + expect(node.options[0].selected).toBe(false); + expect(node.options[2].selected).toBe(true); + }); + it('should allow setting `value` to __proto__', () => { var stub = (