Skip to content

Commit

Permalink
Merge pull request #353 from reactioncommerce/feat-346-nnnnat-multi-s…
Browse files Browse the repository at this point in the history
…elect

feat: 346 nnnnat multi select
  • Loading branch information
aldeed authored Nov 2, 2018
2 parents 78181f6 + aafe162 commit 5c3ee7f
Show file tree
Hide file tree
Showing 9 changed files with 1,146 additions and 2 deletions.
625 changes: 625 additions & 0 deletions package/src/components/MultiSelect/v1/MultiSelect.js

Large diffs are not rendered by default.

234 changes: 234 additions & 0 deletions package/src/components/MultiSelect/v1/MultiSelect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
### Overview

Multi Selects are form elements that allow the user to choose multiple values from a set of options.

### Usage

There are two basic types of multi selects: simple and searchable.

#### Simple multi select

The simple multi select can be used in cases where there are fewer than 10 options.

```jsx
const options = [
{ value: 'chocolate', label: 'Chocolate' },
{ value: 'darkchocolate', label: 'Dark Chocolate' },
{ value: 'mintchip', label: 'Mint Chip' },
{ value: 'strawberry', label: 'Strawberry' },
{ value: 'vanilla', label: 'Vanilla' },
];

<MultiSelect options={options} />
```

#### Searchable multi select

A searchable multi select should be used when there are more than 10 options or when the options are not known until the user starts typing.

```jsx
const options = [
{ value: 'chocolate', label: 'Chocolate' },
{ value: 'strawberry', label: 'Strawberry' },
{ value: 'vanilla', label: 'Vanilla' }
];

<MultiSelect options={options} isSearchable />
```

In cases where you want a smaller width for the multi select, set `maxWidth` property to a number of pixels based on how much space your longest option label needs.

```jsx
const options = [
{ value: 'chocolate', label: 'Chocolate' },
{ value: 'strawberry', label: 'Strawberry' },
{ value: 'vanilla', label: 'Vanilla' }
];

<MultiSelect options={options} maxWidth={350} />
```

#### Alphabetizing multi select options

By default the `MultiSelect` will inherit the order of provided options.
To alphabetize by option label apply the `alphabetize` prop.

```jsx
const options = [
{ value: 'mintchip', label: 'Mint Chip' },
{ value: 'chocolate', label: 'Chocolate' },
{ value: 'strawberry', label: 'Strawberry' },
{ value: 'vanilla', label: 'Vanilla' },
{ value: 'darkchocolate', label: 'Dark Chocolate' }
];

<MultiSelect options={options} alphabetize />
```

#### Nested multi select options

```jsx
const options = [{
optgroup: 'Transportation',
options: [{
value: "car",
label: 'Car'
},
{
value: "bike",
label: "Bike"
},
{
value: "jetpack",
label: "Jetpack"
}
]
},
{
optgroup: 'Plants',
options: [{
value: 'tree',
label: "Tree"
},
{
value: "cactus",
label: "Cactus"
},
{
value: "lily",
label: "Lily"
}
]
},
{
optgroup: 'Athletes',
options: [{
value: 'lebron',
label: 'Lebron James'
},
{
value: "embiid",
label: "Joel Embiid"
},
{
value: "antetokounmpo",
label: "Giannis Antetokounmpo"
}
]
}
];

<MultiSelect options={options} alphabetize />
```

#### Default multi select values
```jsx
const options = [
{ value: 'mintchip', label: 'Mint Chip' },
{ value: 'chocolate', label: 'Chocolate' },
{ value: 'strawberry', label: 'Strawberry' },
{ value: 'vanilla', label: 'Vanilla' },
{ value: 'darkchocolate', label: 'Dark Chocolate' }
];

<MultiSelect options={options} defaultValue={[{ value: 'vanilla', label: 'Vanilla' }, { value: 'darkchocolate', label: 'Dark Chocolate' }]} />
```

### States

A multi select can be in one of three states: normal, invalid, or valid. Normal state is as shown previously

#### Invalid state

When used within a form, a selected value might be deemed invalid, either because the user has not selected a value or because the user has selected a value that is not allowed based on other information entered in the same form. In this case, one or more error objects can be passed in the `errors` prop and will cause the multi select to appear as invalid.

```jsx
const options = [
{ value: 'chocolate', label: 'Chocolate' },
{ value: 'strawberry', label: 'Strawberry' },
{ value: 'vanilla', label: 'Vanilla' }
];

<MultiSelect name="flavor" options={options} errors={[{ name: "flavor", message: "Please choose one" }]} />
```

#### Valid state

When used within a form, a selected value might be deemed valid after its value has been checked. If the `errors` prop is empty and the `hasBeenValidated` prop is true and there is a selected value, the multi select will appear valid.

```jsx
const options = [
{ value: 'mintchip', label: 'Mint Chip' },
{ value: 'chocolate', label: 'Chocolate' },
{ value: 'strawberry', label: 'Strawberry' },
{ value: 'vanilla', label: 'Vanilla' },
{ value: 'darkchocolate', label: 'Dark Chocolate' }
];

<MultiSelect options={options} value={["vanilla", "mintchip"]} hasBeenValidated />
```

### Theme

Assume that any theme prop that does not begin with "rui" is within `rui_components`. See [Theming Components](./#!/Theming%20Components).

| Theme Prop | Default | Description |
| --------------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------- |
| `Input.backgroundColor_dark` | white | Background color when `isDarkBackground` |
| `Input.backgroundColor_default` | black02 | Background color when not `isDarkBackground` |
| `Input.borderColor_default` | black20 | Border color in "default" state |
| `Input.borderColor_error` | red | Border color in "error" state |
| `Input.borderColor_focus` | teal | Border color in "focus" state |
| `Input.borderColor_success` | teal | Border color in "success" state |
| `Input.borderRadius` | 2px | Border radius for all corners |
| `Input.clearButtonColor` | coolGrey | Icon color for the clear button |
| `Input.clearButtonLargeBackgroundColor` | white | Background color for the large clear button |
| `Input.clearButtonLargeBorderColor` | coolGrey | Border color for the large clear button |
| `Input.color_default` | coolGrey500 | Input text color when in "default" state |
| `Input.color_disabled` | black25 | Input text color when in "disabled" state |
| `Input.color_error` | red | Input text color when in "error" state |
| `Input.color_focus` | coolGrey500 | Input text color when in "focus" state |
| `Input.color_success` | black55 | Input text color when in "success" state |
| `Input.fontFamily` | `'Source Sans Pro', 'Helvetica Neue', Helvetica, sans-serif` | Input text font |
| `Input.fontSize` | 14px | Input text font size |
| `Input.horizontalPadding` | 10px | Left and right padding |
| `Input.iconColor_default` | black55 | Icon color when in "default" state |
| `Input.iconColor_disabled` | black25 | Icon color when in "disabled" state |
| `Input.iconColor_error` | red | Icon color when in "error" state |
| `Input.iconColor_success` | forestGreen | Icon color when in "success" state |
| `Input.iconWrapperSize` | 1.429em | Height and width of the input icon |
| `Input.lineHeight` | 1 | Input line height |
| `Input.placeholderColor` | black20 | Placeholder text color |
| `Input.verticalPadding` | 8px | Top and bottom padding |
| `MultiSelect.borderBottomLeftRadius` | 2px | Border bottom left radius |
| `Select.borderBottomRightRadius` | 0 | Border bottom right radius |
| `Select.borderTopLeftRadius` | 0 | Border top left radius |
| `Select.borderTopRightRadius` | 2px | Border top right radius |
| `Select.indicatorColor` | coolGrey500 | Color of the indicator icon |
| `Select.letterSpacing` | 0.3px | Letter spacing |
| `Select.optionHoverColor` | reactionBlue100 | Background color of a menu option while hovering on it |
| `Select.selectedOptionBackgroundColor` | reactionBlue200 | Background color of the currently selected option in the menu |
| `Select.textColor` | coolGrey500 | Color of all text in the component |
| `SelectMenu.borderBottomColor` | black20 | Color of the bottom border of the options menu |
| `SelectMenu.borderBottomLeftRadius` | 2px | Border radius for the bottom left corner of the menu |
| `SelectMenu.borderBottomRightRadius` | 0 | Border radius for the bottom right corner of the menu |
| `SelectMenu.borderBottomWidth` | 1px | Width of the bottom border of the options menu |
| `SelectMenu.borderLeftColor` | black20 | Color of the left border of the options menu |
| `SelectMenu.borderLeftWidth` | 1px | Width of the left border of the options menu |
| `SelectMenu.borderRightColor` | black20 | Color of the right border of the options menu |
| `SelectMenu.borderRightWidth` | 1px | Width of the right border of the options menu |
| `SelectMenu.borderTopLeftRadius` | 0 | Border radius for the top left corner of the menu |
| `SelectMenu.borderTopRightRadius` | 2px | Border radius for the top right corner of the menu |
| `Select.multiValueBackgroundColor` | reactiionBlue100 | Background color for selected values |
| `Select.multiValueBorderStyle` | "solid" | Border style for selected values |
| `Select.multiValueBorderWidth` | 1px | Border width for selected values |
| `Select.multiValueBorderColor` | coolGrey300 | Border color for selected values |
| `Select.multiValueBorderRadius` | 2px | Border radius for selected values |
| `Select.multiValueLabelColor` | black65 | Text color for selected values |
| `Select.multiValueRemoveLeftSpacing` | 5px | Spacing between text and remove icon for selected values |
| `Select.multiValueRemoveBackgroundcolor` | coolGrey300 | Remove icon hover background color for selected values |
| `Select.multiValueRemoveLeftSpacing` | reactionBlue100 | Remove icon hover color for selected values |

#### Typography

None
33 changes: 33 additions & 0 deletions package/src/components/MultiSelect/v1/MultiSelect.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React from "react";
import renderer from "react-test-renderer";
import MultiSelect from "./MultiSelect";

const OPTIONS = [
{ label: "A", value: "a" },
{ label: "B", value: "b" },
{ label: "C", value: "c" }
];

const PROPS = {
className: "react-select",
classNamePrefix: "react-select",
menuIsOpen: true
};

test("basic snapshot", () => {
const component = renderer.create(<MultiSelect {...PROPS} options={OPTIONS} />);
const tree = component.toJSON();
expect(tree).toMatchSnapshot();
});

test("alphabetize option snapshot", () => {
const UNORDERED_OPTIONS = [
{ label: "C", value: "c" },
{ label: "A", value: "a" },
{ label: "Z", value: "z" },
{ label: "E", value: "e" }
];
const component = renderer.create(<MultiSelect {...PROPS} alphabetize options={UNORDERED_OPTIONS} />);
const tree = component.toJSON();
expect(tree).toMatchSnapshot();
});
Loading

0 comments on commit 5c3ee7f

Please sign in to comment.