diff --git a/.sass-lint.yml b/.sass-lint.yml index 174275eba..964332061 100644 --- a/.sass-lint.yml +++ b/.sass-lint.yml @@ -42,7 +42,9 @@ rules: force-pseudo-nesting: 2 # Name Formats - class-name-format: 2 + # TODO: When inline linting is supported set as error (https://github.com/sasstools/sass-lint/pull/402) and ignore + # in Select.scss + class-name-format: 1 function-name-format: 2 mixin-name-format: 2 placeholder-name-format: 2 diff --git a/package.json b/package.json index 67d9385ea..0b36a4727 100644 --- a/package.json +++ b/package.json @@ -90,6 +90,7 @@ "dependencies": { "lodash": "^3.10.1", "react": "^0.14.6", - "react-dom": "^0.14.6" + "react-dom": "^0.14.6", + "react-select": "^1.0.0-beta8" } } diff --git a/src/components/Main.js b/src/components/Main.js index 56e657303..166d7562a 100644 --- a/src/components/Main.js +++ b/src/components/Main.js @@ -8,21 +8,50 @@ import { Tab, Radio, RadioGroup, + Select, Toggle, } from './distributionEntry'; require('styles/App.scss'); +const selectCountriesOptions = [ + { value: 'au', label: 'Australia' }, + { value: 'uk', label: 'United Kingdom' }, + { value: 'us', label: 'United States' }, + { value: 'lt', label: 'Lesotho', disabled: true }, +]; + +const selectFlavoursOptions = [ + { label: 'Chocolate', value: 'chocolate' }, + { label: 'Vanilla', value: 'vanilla' }, + { label: 'Strawberry', value: 'strawberry' }, + { label: 'Caramel', value: 'caramel' }, + { label: 'Cookies and Cream', value: 'cookiescream' }, + { label: 'Peppermint', value: 'peppermint' }, +]; + class AppComponent extends React.Component { constructor(props) { super(props); + this.setSelectedCountry = this.setSelectedCountry.bind(this); + this.setSelectedFlavours = this.setSelectedFlavours.bind(this); this.toggleSimpleModal = this.toggleSimpleModal.bind(this); this.state = { + selectedCountry: 'au', + selectedFlavours: 'vanilla', showSimpleModal: false, }; } + setSelectedCountry(newValue) { + this.setState({ selectedCountry: newValue.value }); + } + + setSelectedFlavours(newValue) { + this.setState({ selectedFlavours: newValue }); + } + toggleSimpleModal() { this.setState({ showSimpleModal: !this.state.showSimpleModal }); } @@ -107,52 +136,73 @@ class AppComponent extends React.Component { +

Checkboxes

-
- -
-
- -
-
- -
-
- -
+ +
+ +
+ +
+ + +

Radio Buttons

-
- - - - -
-
- - - - -
+ + + + +
+ + + + +

Toggle

-
- -
+ Left Right + + +

Select

+ ); } diff --git a/src/components/distributionEntry.js b/src/components/distributionEntry.js index 139609bee..ee9e027f6 100644 --- a/src/components/distributionEntry.js +++ b/src/components/distributionEntry.js @@ -2,6 +2,7 @@ require('styles/_bootstrap-custom.scss'); require('styles/_icheck-custom.scss'); +require('styles/_react-select-custom.scss'); require('styles/_react-toggle-custom.scss'); import Button from 'react-bootstrap/lib/Button'; @@ -24,6 +25,8 @@ import { Totals, } from 'alexandria-adslot'; +import Select from 'react-select'; + module.exports = { Alert, Breadcrumb, @@ -37,6 +40,7 @@ module.exports = { Radio, RadioGroup, Search, + Select, Slicey, Tab, Tabs, diff --git a/src/styles/App.scss b/src/styles/App.scss index 1dccc6b15..781d4ef98 100644 --- a/src/styles/App.scss +++ b/src/styles/App.scss @@ -23,4 +23,8 @@ body { > .btn-panel + .btn-panel { margin-top: $spacing-etalon; } + + > br { + line-height: $spacing-etalon; + } } diff --git a/src/styles/_react-select-custom.scss b/src/styles/_react-select-custom.scss new file mode 100644 index 000000000..8b3c9291c --- /dev/null +++ b/src/styles/_react-select-custom.scss @@ -0,0 +1,83 @@ +@import 'variable'; + +// control options +$select-input-border-color: $color-border-lighter; +$select-input-border-radius: $border-radius-base; +$select-input-border-focus: $select-input-border-color; +$select-input-height: 30px; +$select-padding-vertical: 4px; +$select-padding-horizontal: 7px; +$select-text-color: $color-text; + +// menu options +$select-option-color: $color-text-light; +$select-option-focused-color: $select-option-color; +$select-option-focused-bg: $color-gray-white; + +// clear "x" button +$select-clear-color: $color-text-light; +$select-clear-hover-color: $color-negative; + +// arrow indicator +$select-arrow-color: $color-text-light; +$select-arrow-color-hover: $color-text; + +// multi-select item +$select-item-gutter: 4px; +$select-item-color: $color-text-inverse; +$select-item-hover-color: $color-text-light; +$select-item-bg: $color-gray-darker; +$select-item-hover-bg: $select-item-bg; +$select-item-font-size: 11px; +$select-item-padding-vertical: 0; +$select-item-padding-horizontal: 5px; +$select-item-border-radius: 0; + + +@import '../../node_modules/react-select/scss/default'; + + +.Select { + &:not(.is-disabled) { + .Select-control { + box-shadow: 0 1px $color-border-light; + + &:hover, + &:focus { + box-shadow: 0 2px $color-border-light; + } + } + + &.is-open, + &.is-focused { + &:not(.is-open) { + > .Select-control { + border-color: $color-border-lighter; + } + } + } + } + + &--multi { + $multi-select-value-height: $select-input-height - ($select-item-padding-horizontal * 2); + + .Select-value { + border: 0; + height: $multi-select-value-height; + + &-icon, + &-label { + line-height: 1; + margin-top: 3px; + } + + &-icon { + border: 0; + float: right; + font-size: $font-size-subheader; + text-align: left; + width: 13px; + } + } + } +} diff --git a/src/styles/bootstrapOverrides/Button.scss b/src/styles/bootstrapOverrides/Button.scss index cd7ab52b5..54fb6e091 100644 --- a/src/styles/bootstrapOverrides/Button.scss +++ b/src/styles/bootstrapOverrides/Button.scss @@ -67,7 +67,7 @@ } .btn { - box-shadow: 0 1px 0 $color-border-light; + box-shadow: 0 1px $color-border-light; margin-right: 5px; // Make border the same colour as the fill. @@ -86,7 +86,7 @@ &:hover, &:focus { - box-shadow: 0 2px 0 $color-border-light; + box-shadow: 0 2px $color-border-light; transform: translateY(-1px); } diff --git a/test/components/MainTest.js b/test/components/MainTest.js index 378301327..7129aac8a 100644 --- a/test/components/MainTest.js +++ b/test/components/MainTest.js @@ -3,11 +3,13 @@ import createComponent from 'helpers/shallowRenderHelper'; import Main from 'components/Main'; -import { isElementOfType } from 'react-addons-test-utils'; +import React from 'react'; +import { isElementOfType, createRenderer } from 'react-addons-test-utils'; import { Checkbox, Radio, RadioGroup, + Select, Toggle, } from '../../src/components/distributionEntry'; @@ -51,4 +53,60 @@ describe('MainComponent', () => { const toggleComponent = toggleExampleContainer.props.children; expect(isElementOfType(toggleComponent, Toggle)).to.equal(true); }); + + it('should set and change values for single select', () => { + const getRenderOutputAndCheck = ({ renderer, expectedValue }) => { + const componentRenderOutput = renderer.getRenderOutput(); + + const selectElContainer = componentRenderOutput.props.children[20]; + const selectComponent = selectElContainer.props.children; + expect(isElementOfType(selectComponent, Select)).to.equal(true); + expect(selectComponent.props.value).to.equal(expectedValue); + + return { selectComponent }; + }; + + const renderer = createRenderer(); + renderer.render(
); + + const { selectComponent } = getRenderOutputAndCheck({ + renderer, + expectedValue: 'au', + }); + + selectComponent.props.onChange({ value: 'uk' }); + + getRenderOutputAndCheck({ + renderer, + expectedValue: 'uk', + }); + }); + + it('should set and change values for multi select', () => { + const getRenderOutputAndCheck = ({ renderer, expectedValue }) => { + const componentRenderOutput = renderer.getRenderOutput(); + + const selectElContainer = componentRenderOutput.props.children[21]; + const selectComponent = selectElContainer.props.children; + expect(isElementOfType(selectComponent, Select)).to.equal(true); + expect(selectComponent.props.value).to.eql(expectedValue); + + return { selectComponent }; + }; + + const renderer = createRenderer(); + renderer.render(
); + + const { selectComponent } = getRenderOutputAndCheck({ + renderer, + expectedValue: 'vanilla', + }); + + selectComponent.props.onChange('vanilla,chocolate'); + + getRenderOutputAndCheck({ + renderer, + expectedValue: 'vanilla,chocolate', + }); + }); });