From 3dfe9a775488b485ac8d233f0af006557593bbc4 Mon Sep 17 00:00:00 2001 From: meriadec Date: Wed, 17 Jan 2018 17:20:23 +0100 Subject: [PATCH 1/4] Make the Select explicitely searchable --- src/components/base/Search/index.js | 6 +- src/components/base/Select/index.js | 112 ++++++++++++++++++-------- src/components/base/Select/stories.js | 82 ++++++++++++++++++- 3 files changed, 161 insertions(+), 39 deletions(-) diff --git a/src/components/base/Search/index.js b/src/components/base/Search/index.js index f1945bb5..d8927ccf 100644 --- a/src/components/base/Search/index.js +++ b/src/components/base/Search/index.js @@ -42,7 +42,8 @@ class Search extends PureComponent { componentWillReceiveProps(nextProps: Props) { if (nextProps.value !== this.props.value) { if (this._fuse) { - this.formatResults(this._fuse.search(nextProps.value), nextProps) + const results = this._fuse.search(nextProps.value) + this.formatResults(results, nextProps) } } if (nextProps.highlight !== this.props.highlight) { @@ -63,7 +64,8 @@ class Search extends PureComponent { includeMatches: highlight, }) - this.formatResults(this._fuse.search(value), props) + const results = this._fuse.search(value) + this.formatResults(results, props) } formatResults(results: Array, props: Props) { diff --git a/src/components/base/Select/index.js b/src/components/base/Select/index.js index ae98ff35..d72b218e 100644 --- a/src/components/base/Select/index.js +++ b/src/components/base/Select/index.js @@ -3,6 +3,7 @@ import React, { PureComponent } from 'react' import Downshift from 'downshift' import styled from 'styled-components' +import { space } from 'styled-system' import type { Element } from 'react' @@ -16,14 +17,29 @@ type Props = { onChange: Function, fuseOptions?: Object, highlight?: boolean, + searchable?: boolean, renderHighlight?: string => Element<*>, + renderItem?: (*) => Element<*>, } const Container = styled(Box).attrs({ relative: true, color: 'steel' })`` -const SearchInput = styled(Input)` +const TriggerBtn = styled(Box).attrs({ + p: 2, +})` + ${space}; + border: 1px solid ${p => p.theme.colors.mouse}; + border-radius: 3px; + display: flex; + width: 100%; + color: ${p => p.theme.colors.steel}; + background: ${p => p.theme.colors.white}; border-bottom-left-radius: ${p => (p.isOpen ? 0 : '')}; border-bottom-right-radius: ${p => (p.isOpen ? 0 : '')}; + &:focus { + outline: none; + box-shadow: rgba(0, 0, 0, 0.05) 0 2px 2px; + } ` const Item = styled(Box).attrs({ @@ -38,65 +54,93 @@ const ItemWrapper = styled(Box)` } ` -const Dropdown = styled(Box)` +const Dropdown = styled(Box).attrs({ + mt: 1, +})` position: absolute; top: 100%; left: 0; right: 0; border: 1px solid ${p => p.theme.colors.mouse}; - border-top: none; max-height: 300px; overflow-y: auto; - border-bottom-left-radius: 3px; - border-bottom-right-radius: 3px; + border-radius: 3px; box-shadow: rgba(0, 0, 0, 0.05) 0 2px 2px; ` class Select extends PureComponent { + renderItems = (items: Array, downshiftProps: Object) => { + const { renderItem } = this.props + const { getItemProps, highlightedIndex } = downshiftProps + return ( + + {items.length ? ( + items.map((item, i) => ( + + + {renderItem ? renderItem(item) : {item.name_highlight || item.name}} + + + )) + ) : ( + + {'No results'} + + )} + + ) + } + render() { - const { items, itemToString, fuseOptions, highlight, renderHighlight, onChange } = this.props + const { + items, + searchable, + itemToString, + fuseOptions, + highlight, + renderHighlight, + onChange, + } = this.props + return ( ( - - {isOpen && ( - - items.length ? ( - - {items.map((item, i) => ( - - - {item.name_highlight || item.name} - - - ))} - - ) : null - } + {searchable ? ( + + ) : ( + + lablala + )} + {isOpen && + (searchable ? ( + this.renderItems(items, downshiftProps)} + /> + ) : ( + this.renderItems(items, downshiftProps) + ))} )} /> diff --git a/src/components/base/Select/stories.js b/src/components/base/Select/stories.js index 8c35a4fe..e7fb9110 100644 --- a/src/components/base/Select/stories.js +++ b/src/components/base/Select/stories.js @@ -1,12 +1,14 @@ -import React from 'react' +import React, { PureComponent } from 'react' +import PropTypes from 'prop-types' import { storiesOf } from '@storybook/react' +import Box from 'components/base/Box' import Select from 'components/base/Select' import Text from 'components/base/Text' const stories = storiesOf('Select', module) -const items = [ +const itemsChessPlayers = [ { key: 'aleksandr-grichtchouk', name: 'Aleksandr Grichtchouk' }, { key: 'fabiano-caruana', name: 'Fabiano Caruana' }, { key: 'garry-kasparov', name: 'Garry Kasparov' }, @@ -20,9 +22,52 @@ const items = [ { key: 'vladimir-kramnik', name: 'Vladimir Kramnik' }, ] +class Wrapper extends PureComponent { + static propTypes = { + children: PropTypes.func.isRequired, + } + + state = { + item: null, + } + + handleChange = item => this.setState({ item }) + + render() { + const { children } = this.props + const { item } = this.state + return ( +
+ {children(this.handleChange)} + {item && ( + +
+              {'You selected:'}
+              {JSON.stringify(item)}
+            
+
+ )} +
+ ) + } +} + stories.add('basic', () => ( + + {onChange => ( + (item ? item.name : '')} @@ -33,3 +78,34 @@ stories.add('basic', () => ( )} /> )) + +const itemsColors = [ + { key: 'absolute zero', name: 'Absolute Zero', color: '#0048BA' }, + { key: 'acid green', name: 'Acid Green', color: '#B0BF1A' }, + { key: 'aero', name: 'Aero', color: '#7CB9E8' }, + { key: 'aero blue', name: 'Aero Blue', color: '#C9FFE5' }, + { key: 'african violet', name: 'African Violet', color: '#B284BE' }, + { key: 'air force blue (usaf)', name: 'Air Force Blue (USAF)', color: '#00308F' }, + { key: 'air superiority blue', name: 'Air Superiority Blue', color: '#72A0C1' }, +] + +stories.add('custom render', () => ( + + ) : ( - - lablala + + {renderSelected(selectedItem)} + )} {isOpen && diff --git a/src/components/base/Select/stories.js b/src/components/base/Select/stories.js index e7fb9110..e73a0344 100644 --- a/src/components/base/Select/stories.js +++ b/src/components/base/Select/stories.js @@ -58,6 +58,7 @@ stories.add('basic', () => ( + ) : ( - {renderSelected(selectedItem)} + + {selectedItem ? ( + renderSelected(selectedItem) + ) : ( + {placeholder} + )} + )} diff --git a/src/components/base/Select/stories.js b/src/components/base/Select/stories.js index e73a0344..fbb49b55 100644 --- a/src/components/base/Select/stories.js +++ b/src/components/base/Select/stories.js @@ -56,9 +56,9 @@ stories.add('basic', () => ( {onChange => ( Date: Wed, 17 Jan 2018 18:06:21 +0100 Subject: [PATCH 4/4] Unified triangles positionning in searchable/unsearchable Selects --- src/components/base/Select/index.js | 22 +++++++++++++++++++++- src/components/base/Select/stories.js | 1 + 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/components/base/Select/index.js b/src/components/base/Select/index.js index cfe22a14..5591e59b 100644 --- a/src/components/base/Select/index.js +++ b/src/components/base/Select/index.js @@ -71,6 +71,21 @@ const Dropdown = styled(Box).attrs({ box-shadow: rgba(0, 0, 0, 0.05) 0 2px 2px; ` +const FloatingTriangles = styled(Box).attrs({ + align: 'center', + justify: 'center', + mr: 2, +})` + position: absolute; + top: 0; + right: 0; + bottom: 0; + + // to "simulate" border to make arrows appears at the exact same place as + // the no-input version + padding-right: 1px; +` + class Select extends PureComponent { renderItems = (items: Array, downshiftProps: Object) => { const { renderItem } = this.props @@ -123,7 +138,12 @@ class Select extends PureComponent { }) => ( {searchable ? ( - + + + + + + ) : ( diff --git a/src/components/base/Select/stories.js b/src/components/base/Select/stories.js index fbb49b55..ab2f826a 100644 --- a/src/components/base/Select/stories.js +++ b/src/components/base/Select/stories.js @@ -93,6 +93,7 @@ const itemsColors = [ stories.add('custom render', () => (