Skip to content

Commit

Permalink
Merge pull request #51 from kenshoo/refactor-component
Browse files Browse the repository at this point in the history
Refactor checkbox L2L component
  • Loading branch information
talyak authored Mar 23, 2018
2 parents 034e5af + f4fc819 commit fe709a1
Show file tree
Hide file tree
Showing 69 changed files with 4,073 additions and 1,372 deletions.
3 changes: 1 addition & 2 deletions .storybook/preview-head.html
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
<link href='https://fonts.googleapis.com/css?family=Roboto:400,700' rel='stylesheet' type='text/css'>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link href='https://fonts.googleapis.com/css?family=Roboto:400,700' rel='stylesheet' type='text/css'>
114 changes: 102 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,27 +77,117 @@ class Example extends Component {
| `messages` | `Object` | {} | custom messages. Please see below for the availabale messages
| `showSearch ` | `boolean` | true | toggle to show search option.
| `showSelectAll` | `boolean` | true | toggle to show select All option in list.
| `searchIcon` | `String` | 'search' | search items icon. Options are available here: https://material.io/icons
| `deleteIcon` | `String` | 'close' | selected items delete icon. Options are available here: https://material.io/icons
| `wrapperClassName` | `String` | '' | wrapper class name. Used for customizing the style
| `listHeight` | `number` | 320 | available items list height
| `selectedListHeight` | `number` | 361 | selected items list height
| `selectedListHeight` | `number` | 40 | list item height
| `height` | `number` | 400 | available items list height
| `itemHeight` | `number` | 40 | the height of an item in the list
| `filterFunction` | `function` | based on label | The function used to filter items based on the search query
| `searchRenderer` | `Component` | | Component to replace the default Search component
| `selectedItemRenderer` | `Component` | | Component to replace the default selected item component in the destination list
| `loaderRenderer` | `Component` | | Component to replace the default loader component
| `selectAllRenderer` | `Component` | | Component to replace the default select all component
| `itemRenderer` | `Component` | | Component to replace the default item component in the source list


## Customization

#### Renderers

You can replace the renderes of the following components:

<br/>

**Item**

Use the `itemRenderer` to replace the default component.

Each item receives the following props:

`item` - holds your item data

`height` - receives the height defined by the list

`onClick` - the event to toggle selection on the component

`checked` - indicates if the item is selected

`indeterminate` - used by the select all component to display indeterminate mode

<br/>

**Select All**

Use the `selectAllRenderer` to replace the default component.

The Select All component receives the following props:

`height` - receives the height defined by the parent

`onClick` - Triggers the select all/clear all event on click

`isAllSelected` - Indicates that all items are selected

`selectAllMessage` - Defines the message for the Select All component

`selectedIds` - holds a list of ids of all the selected items

<br/>

**Selected Item**

Use the `selectAllRenderer` to replace the default component.


The Selected Item component receives the following props:

`item` - holds your item data

`height` - receives the height defined by the list

<br/>

**Search**

Use the `searchRenderer` to replace the default component.

The Search component receives the following props:

`searchPlaceholder` - defines the message to display in the search placeholder

`onChange` - triggers the action of changing the search value

<br/>

**Loader**

Use the `loaderRenderer` to replace the default component.

Does not receive any props.

<br/>

#### Search Function

In order to accomidate complex item filters, you can provide your own filter method in the `filterFunction` prop.

Example (default):
```javascript
value => item =>
String(item.label)
.toLowerCase()
.includes(value.toLowerCase())
```

#### Messages

You can use your own messages. Here is the default messages object :
```jsx
messages: {
"source.search.placeholder": "Search...",
"source.header.selectAll": "Select all",
"source.noItems": "No items...",
"destination.noItems": "No items...",
"destination.header.clearAll": "Clear all",
"destination.header.none": "None",
"destination.header.selected": "Selected"
searchPlaceholder: "Search...",
noItemsMessage: "No Items...",
noneSelectedMessage: "None Selected",
selectedMessage: "delected",
selectAllMessage: "Select All",
clearAllMessage: "Clear All"
}
```

Expand Down
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
"license": "MIT",
"main": "index.js",
"scripts": {
"build": "webpack --config config/webpack/webpack.dev.js",
"build:stats": "NODE_ENV=production webpack --config config/webpack/webpack.prod.js -p --bail --json > stats.json",
"build:production": "webpack --config config/webpack/webpack.prod.js",
"build": "webpack --config config/webpack/webpack.dev.js --mode development",
"build:stats": "NODE_ENV=production webpack --config config/webpack/webpack.prod.js -p --bail --json > stats.json --mode production",
"build:production": "webpack --config config/webpack/webpack.prod.js --mode production",
"test": "cross-env BABEL_DISABLE_CACHE=1 jest --config config/jest/jest.config.json",
"test:watch": "cross-env BABEL_DISABLE_CACHE=1 jest --watchAll --config config/jest/jest.config.json",
"storybook": "start-storybook -p 6006",
Expand Down Expand Up @@ -78,9 +78,9 @@
},
"dependencies": {
"classnames": "2.2.5",
"lodash": "^4.17.5",
"material-ui": "^1.0.0-beta.25",
"prop-types": "^15.5.8",
"react-icons": "^2.2.7",
"react-virtualized": "^9.18.5"
},
"release": {
Expand Down
Binary file modified preview.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions src/components/column/column.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from "react";

import styles from "./column.scss";

const Column = ({ children }) => (
<div className={styles.column}>{children}</div>
);

export default Column;
11 changes: 11 additions & 0 deletions src/components/column/column.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
@import "../../resources/globals";

.column {
display: flex;
flex: 1;
flex-direction: column;
border-right: 1px solid $border-color;
&:last-of-type {
border: 0;
}
}
69 changes: 69 additions & 0 deletions src/components/destination_list.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import React from "react";
import PropTypes from "prop-types";

import Column from "./column/column";
import List from "./list/items_list";
import NoItems from "./items/no_items";
import SelectedItem from "./items/selected_item";
import SelectionStatus from "./selection_status/selection_status";

const DestinationList = ({
selectionStatusRenderer,
selectedIds,
clearAll,
messages,
selectedItems,
itemHeight,
height,
unselectItem,
selectedItemRenderer,
noItemsRenderer
}) => {
const SelectionStatusRenderer = selectionStatusRenderer;
return (
<Column>
<SelectionStatusRenderer
selected={selectedIds}
clearAll={clearAll}
clearAllMessage={messages.clearAllMessage}
selectedMessage={messages.selectedMessage}
noneSelectedMessage={messages.noneSelectedMessage}
/>
<List
items={selectedItems}
itemHeight={itemHeight}
height={height - 45}
onClick={unselectItem}
renderer={selectedItemRenderer}
noItemsRenderer={noItemsRenderer}
noItemsMessage={messages.noItemsMessage}
/>
</Column>
);
};

DestinationList.propTypes = {
selectionStatusRenderer: PropTypes.any,
selectedIds: PropTypes.arrayOf(PropTypes.number),
clearAll: PropTypes.func,
messages: PropTypes.object,
selectedItems: PropTypes.array,
itemHeight: PropTypes.number,
height: PropTypes.number,
unselectItem: PropTypes.func,
selectedItemRenderer: PropTypes.any,
noItemsRenderer: PropTypes.any
};

DestinationList.defaultProps = {
selectionStatusRenderer: SelectionStatus,
selectedIds: [],
messages: {},
selectedItems: [],
itemHeight: 40,
height: 400,
selectedItemRenderer: SelectedItem,
noItemsRenderer: NoItems
};

export default DestinationList;
50 changes: 50 additions & 0 deletions src/components/items/item.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React from "react";
import PropTypes from "prop-types";
import classnames from "classnames";
import Checkbox from "material-ui/Checkbox";

import styles from "./item.scss";

const Item = ({
item,
height,
onClick,
withBorder,
checked,
indeterminate
}) => (
<div
className={classnames(styles.item, {
[styles.with_border]: withBorder,
[styles.selected]: checked
})}
style={{ height }}
onClick={onClick}
>
<Checkbox
type="checkbox"
color="primary"
checked={checked}
indeterminate={indeterminate}
/>
{item.label}
</div>
);

Item.propTypes = {
item: PropTypes.object,
height: PropTypes.number,
withBorder: PropTypes.bool,
checked: PropTypes.bool,
indeterminate: PropTypes.bool
};

Item.defaultProps = {
item: {},
height: 40,
withBorder: false,
checked: false,
indeterminate: false
};

export default Item;
23 changes: 23 additions & 0 deletions src/components/items/item.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
@import "../../resources/globals";

.item {
display: flex;
align-items: center;
transition: background-color 0.2s ease-in-out;
box-sizing: border-box;
cursor: pointer;
.selected {
background-color: $selected-background-color;
}
&:hover:not(.selected) {
background-color: $hover-background-color;
}
}

.selected {
background-color: $selected-background-color;
}

.with_border {
border-bottom: 1px solid $border-color;
}
18 changes: 18 additions & 0 deletions src/components/items/no_items.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React from "react";
import PropTypes from "prop-types";

import styles from "./no_items.scss";

const NoItems = ({ noItemsMessage }) => (
<div className={styles.no_items}>{noItemsMessage}</div>
);

NoItems.propTypes = {
noItemsMessage: PropTypes.string
};

NoItems.defaultProps = {
noItemsMessage: "No Items..."
};

export default NoItems;
11 changes: 11 additions & 0 deletions src/components/items/no_items.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
@import "../../resources/globals";

.no_items {
font-size: $font-large;
color: $placeholder-color;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
}
37 changes: 37 additions & 0 deletions src/components/items/select_all.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React from "react";
import PropTypes from "prop-types";
import Item from "./item";

const SelectAll = ({
height,
onClick,
isAllSelected,
selectAllMessage,
selectedIds
}) => (
<Item
height={height}
onClick={onClick}
withBorder
item={{ label: selectAllMessage }}
checked={isAllSelected}
indeterminate={!isAllSelected && selectedIds.length > 0}
/>
);

SelectAll.propTypes = {
selectAllMessage: PropTypes.string,
height: PropTypes.number,
onClick: PropTypes.func,
isAllSelected: PropTypes.bool,
selectedIds: PropTypes.arrayOf(PropTypes.number)
};

SelectAll.defaultProps = {
selectAllMessage: "Select All",
isAllSelected: false,
height: 40,
selectedIds: []
};

export default SelectAll;
Loading

0 comments on commit fe709a1

Please sign in to comment.