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..716d09018 100644
--- a/package.json
+++ b/package.json
@@ -37,7 +37,7 @@
],
"author": "Adslot",
"devDependencies": {
- "alexandria-adslot": "^0.7.0",
+ "alexandria-adslot": "^0.7.1",
"autoprefixer-loader": "^3.1.0",
"babel-core": "^6.4.0",
"babel-eslint": "^5.0.0-beta6",
@@ -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..1c0c18686 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: 'ca', label: 'Canada' },
+ { value: 'uk', label: 'United Kingdom' },
+ { value: 'jp', label: 'Japan', 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..ce4f4fe71
--- /dev/null
+++ b/src/styles/_react-select-custom.scss
@@ -0,0 +1,96 @@
+@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: 26px;
+$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;
+$select-clear-size: 15px;
+
+// arrow indicator
+$select-arrow-color: $color-text-light;
+$select-arrow-color-hover: $color-text;
+
+// multi-select item
+$select-item-gutter: 2px;
+$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: $font-size-base;
+$select-item-padding-vertical: 2px;
+$select-item-padding-horizontal: 5px;
+
+
+@import '../../node_modules/react-select/scss/default';
+
+
+.Select {
+ $select-input-border-active: $color-border;
+ font-weight: $font-weight-medium;
+
+ &-menu-outer {
+ border-color: $select-input-border-active;
+ }
+
+ &:not(.is-disabled) {
+ .Select-control {
+ box-shadow: 0 1px $color-border-light;
+
+ &:hover,
+ &:focus {
+ border-color: $select-input-border-active;
+ }
+ }
+
+ &.is-open {
+ > .Select-control {
+ border-color: $select-input-border-active;
+ }
+ }
+
+ &.is-focused {
+ &:not(.is-open) {
+ > .Select-control {
+ border-color: $select-input-border-active;
+ }
+ }
+ }
+ }
+
+ &--multi {
+
+ .Select-value {
+ border: 0;
+ margin-top: 1px;
+
+ &-icon + &-label {
+ padding-right: 0;
+ }
+
+ &-icon {
+ border: 0;
+ float: right;
+ font-size: $select-clear-size;
+ font-weight: $font-weight-light;
+ line-height: $select-clear-size;
+ margin: $select-item-padding-vertical $select-item-padding-horizontal $select-item-padding-vertical 0;
+ padding: 0;
+ text-align: center;
+ width: $select-item-font-size;
+ }
+ }
+ }
+}
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..ed5d09d81 100644
--- a/test/components/MainTest.js
+++ b/test/components/MainTest.js
@@ -3,11 +3,14 @@
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,
+ Modal,
Radio,
RadioGroup,
+ Select,
Toggle,
} from '../../src/components/distributionEntry';
@@ -24,22 +27,20 @@ describe('MainComponent', () => {
it('should have a modal component', () => {
const modalComponent = MainComponent.props.children[8];
- expect(modalComponent.props.bsClass).to.equal('modal');
+ expect(isElementOfType(modalComponent, Modal)).to.equal(true);
expect(modalComponent.props.bsSize).to.equal('small');
expect(modalComponent.props.keyboard).to.equal(false);
expect(modalComponent.props.backdrop).to.equal(true);
});
it('should have a checkbox component', () => {
- const checkboxExampleContainer = MainComponent.props.children[10];
- const checkboxComponent = checkboxExampleContainer.props.children;
+ const checkboxComponent = MainComponent.props.children[10];
expect(isElementOfType(checkboxComponent, Checkbox)).to.equal(true);
expect(checkboxComponent.props.label).to.equal('Unchecked');
});
it('should have a radio button component', () => {
- const radioButtonContainer = MainComponent.props.children[15];
- const radioGroupComponent = radioButtonContainer.props.children;
+ const radioGroupComponent = MainComponent.props.children[18];
expect(isElementOfType(radioGroupComponent, RadioGroup)).to.equal(true);
const radioComponent = radioGroupComponent.props.children[0];
expect(isElementOfType(radioComponent, Radio)).to.equal(true);
@@ -47,8 +48,61 @@ describe('MainComponent', () => {
});
it('should have a toggle component', () => {
- const toggleExampleContainer = MainComponent.props.children[18];
- const toggleComponent = toggleExampleContainer.props.children;
+ const toggleComponent = MainComponent.props.children[24];
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 selectComponent = componentRenderOutput.props.children[28];
+ 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 selectComponent = componentRenderOutput.props.children[30];
+ 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',
+ });
+ });
});