Browse Source

Merge pull request #595 from gre/remove-legacy-select

Remove legacy select
master
Meriadec Pillet 7 years ago
committed by GitHub
parent
commit
0d34d36ba7
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 8
      src/components/SelectAccount/index.js
  2. 26
      src/components/base/InputCurrency/index.js
  3. 347
      src/components/base/LegacySelect/index.js
  4. 117
      src/components/base/LegacySelect/stories.js
  5. 4
      src/components/base/Select/index.js
  6. 14
      src/components/modals/AccountSettingRenderBody.js

8
src/components/SelectAccount/index.js

@ -56,14 +56,16 @@ type Props = {
t: T,
}
const getOptionValue = account => account.id
const RawSelectAccount = ({ accounts, onChange, value, t, ...props }: Props) => {
const options = accounts.map(a => ({ ...a, value: a.id, label: a.name }))
const selectedOption = value ? options.find(o => o.value === value.id) : null
const selectedOption = value ? accounts.find(o => o.id === value.id) : null
return (
<Select
{...props}
value={selectedOption}
options={options}
options={accounts}
getOptionValue={getOptionValue}
renderValue={renderOption}
renderOption={renderOption}
placeholder={t('app:common.selectAccount')}

26
src/components/base/InputCurrency/index.js

@ -9,10 +9,12 @@ import noop from 'lodash/noop'
import Box from 'components/base/Box'
import Input from 'components/base/Input'
import Select from 'components/base/LegacySelect'
import Select from 'components/base/Select'
import type { Unit } from '@ledgerhq/live-common/lib/types'
const unitGetOptionValue = unit => unit.magnitude
// TODO move this back to live common
const numbers = '0123456789'
const sanitizeValueString = (
@ -64,15 +66,9 @@ const Currencies = styled(Box)`
position: relative;
top: -1px;
right: -1px;
width: 100px;
`
const Currency = styled(Box).attrs({
color: 'grey',
fontSize: 2,
pl: 2,
pr: 1,
})``
function stopPropagation(e) {
e.stopPropagation()
}
@ -167,9 +163,9 @@ class InputCurrency extends PureComponent<Props, State> {
})
}
renderItem = item => item.code
renderOption = item => item.data.code
renderSelected = item => <Currency>{item.code}</Currency>
renderValue = item => item.data.code
renderListUnits = () => {
const { units, onChangeUnit, unit } = this.props
@ -182,14 +178,12 @@ class InputCurrency extends PureComponent<Props, State> {
return (
<Currencies onClick={stopPropagation}>
<Select
bg="lightGraphite"
keyProp="code"
flatLeft
onChange={onChangeUnit}
items={units}
options={units}
value={unit}
renderItem={this.renderItem}
renderSelected={this.renderSelected}
getOptionValue={unitGetOptionValue}
renderOption={this.renderOption}
renderValue={this.renderValue}
fakeFocusRight={isFocused}
/>
</Currencies>

347
src/components/base/LegacySelect/index.js

@ -1,347 +0,0 @@
// @flow
import React, { PureComponent } from 'react'
import Downshift from 'downshift'
import styled from 'styled-components'
import { space } from 'styled-system'
import { translate } from 'react-i18next'
import type { T } from 'types/common'
import Box from 'components/base/Box'
import GrowScroll from 'components/base/GrowScroll'
import Input from 'components/base/Input'
import Search from 'components/base/Search'
import Text from 'components/base/Text'
import IconCheck from 'icons/Check'
type Props = {
bg?: string,
flatLeft?: boolean,
flatRight?: boolean,
fakeFocusRight?: boolean,
fuseOptions?: Object,
highlight?: boolean,
items: Array<any>,
itemToString?: Function,
keyProp?: string,
maxHeight?: number,
onChange?: Function,
placeholder?: string,
renderHighlight?: string => React$Node,
renderItem?: (*) => React$Node,
renderSelected?: any => React$Node,
searchable?: boolean,
value?: *,
disabled: boolean,
small?: boolean,
t: T,
}
const Container = styled(Box).attrs({ relative: true, color: 'graphite' })``
const TriggerBtn = styled(Box).attrs({
alignItems: 'center',
ff: p => (p.small ? 'Open Sans' : 'Open Sans|SemiBold'),
flow: 2,
fontSize: p => (p.small ? 3 : 4),
horizontal: true,
px: 3,
})`
${space};
height: ${p => (p.small ? '34' : '40')}px;
background: ${p => (p.disabled ? p.theme.colors.lightGrey : p.bg || p.theme.colors.white)};
border-bottom-left-radius: ${p => (p.flatLeft ? 0 : p.theme.radii[1])}px;
border-bottom-right-radius: ${p => (p.flatRight ? 0 : p.theme.radii[1])}px;
border-top-left-radius: ${p => (p.flatLeft ? 0 : p.theme.radii[1])}px;
border-top-right-radius: ${p => (p.flatRight ? 0 : p.theme.radii[1])}px;
border: 1px solid ${p => p.theme.colors.fog};
color: ${p => p.theme.colors.graphite};
cursor: ${p => (p.disabled ? 'cursor' : 'pointer')};
display: flex;
width: 100%;
&:focus {
outline: none;
${p =>
p.disabled
? ''
: `
border-color: ${p.theme.colors.wallet};
box-shadow: rgba(0, 0, 0, 0.05) 0 2px 2px;`};
}
${p => {
const c = p.theme.colors.wallet
return p.fakeFocusRight
? `
border-top: 1px solid ${c};
border-right: 1px solid ${c};
border-bottom: 1px solid ${c};
`
: ''
}};
`
const Item = styled(Box).attrs({
alignItems: 'center',
fontSize: 4,
ff: p => `Open Sans|${p.selected ? 'SemiBold' : 'Regular'}`,
px: 3,
py: 2,
color: 'dark',
})`
background: ${p => (p.highlighted ? p.theme.colors.lightGrey : p.theme.colors.white)};
${p =>
p.first &&
`
border-top-left-radius: ${p.theme.radii[1]}px;
border-top-right-radius: ${p.theme.radii[1]}px;
`} ${p =>
p.last &&
`
border-bottom-left-radius: ${p.theme.radii[1]}px;
border-bottom-right-radius: ${p.theme.radii[1]}px;
`};
`
const Dropdown = styled(Box).attrs({
mt: 1,
})`
border-radius: ${p => p.theme.radii[1]}px;
border: 1px solid ${p => p.theme.colors.fog};
box-shadow: rgba(0, 0, 0, 0.05) 0 2px 2px;
left: 0;
position: absolute;
right: 0;
top: 100%;
z-index: 1;
`
const IconSelected = styled(Box).attrs({
color: 'wallet',
alignItems: 'center',
justifyContent: 'center',
})`
height: 12px;
width: 12px;
opacity: ${p => (p.selected ? 1 : 0)};
`
const AngleDown = props => (
<Box color="grey" alignItems="center" justifyContent="center" {...props}>
<svg viewBox="0 0 16 16" width="16" height="16">
<path
fill="currentColor"
d="M7.70785815 10.86875l-5.08670521-4.5875c-.16153725-.146875-.16153725-.384375 0-.53125l.68051867-.61875c.16153726-.146875.42274645-.146875.58428371 0L8 8.834375l4.1140447-3.703125c.1615372-.146875.4227464-.146875.5842837 0l.6805187.61875c.1615372.146875.1615372.384375 0 .53125l-5.08670525 4.5875c-.16153726.146875-.42274644.146875-.5842837 0z"
/>
</svg>
</Box>
)
const renderSelectedItem = ({ selectedItem, renderSelected, placeholder }: any) =>
selectedItem && renderSelected ? (
renderSelected(selectedItem)
) : (
<Text color="fog">{placeholder}</Text>
)
class LegacySelect extends PureComponent<Props> {
static defaultProps = {
bg: undefined,
disabled: false,
small: false,
fakeFocusRight: false,
flatLeft: false,
flatRight: false,
itemToString: (item: Object) => item && item.name,
keyProp: undefined,
maxHeight: 300,
}
_scrollToSelectedItem = true
_oldHighlightedIndex = 0
_useKeyboard = false
_children = {}
renderItems = (items: Array<Object>, selectedItem: any, downshiftProps: Object) => {
const { renderItem, maxHeight, keyProp, t } = this.props
const { getItemProps, highlightedIndex } = downshiftProps
const selectedItemIndex = items.indexOf(selectedItem)
return (
<Dropdown>
{items.length ? (
<GrowScroll
maxHeight={maxHeight}
onUpdate={scrollbar => {
const currentHighlighted = this._children[highlightedIndex]
const currentSelectedItem = this._children[selectedItemIndex]
if (this._useKeyboard && currentHighlighted) {
scrollbar.scrollIntoView(currentHighlighted, {
alignToTop: highlightedIndex < this._oldHighlightedIndex,
offsetTop: -1,
onlyScrollIfNeeded: true,
})
} else if (this._scrollToSelectedItem && currentSelectedItem) {
window.requestAnimationFrame(() =>
scrollbar.scrollIntoView(currentSelectedItem, {
offsetTop: -1,
}),
)
this._scrollToSelectedItem = false
}
this._oldHighlightedIndex = highlightedIndex
}}
>
{items.map((item, i) => (
<Box
key={keyProp ? item[keyProp] : item.key}
innerRef={n => (this._children[i] = n)}
{...getItemProps({ item })}
>
<Item
first={i === 0}
last={i === items.length - 1}
highlighted={i === highlightedIndex}
selected={selectedItem === item}
horizontal
flow={3}
>
<Box grow>
{renderItem ? (
renderItem(item)
) : (
<span>{item.name_highlight || item.name}</span>
)}
</Box>
<Box>
<IconSelected selected={selectedItem === item}>
<IconCheck size={12} />
</IconSelected>
</Box>
</Item>
</Box>
))}
</GrowScroll>
) : (
<Box>
<Item>{t('app:error.noResults')}</Item>
</Box>
)}
</Dropdown>
)
}
render() {
const {
disabled,
fakeFocusRight,
flatLeft,
flatRight,
fuseOptions,
highlight,
items,
itemToString,
onChange,
placeholder,
renderHighlight,
renderSelected,
searchable,
value,
small,
...props
} = this.props
return (
<Downshift
selectedItem={value}
itemToString={itemToString}
onChange={onChange}
render={({
getInputProps,
getToggleButtonProps,
getRootProps,
isOpen,
inputValue,
openMenu,
selectedItem,
...downshiftProps
}) => {
if (!isOpen) {
this._scrollToSelectedItem = true
}
if (disabled) {
return (
<Container {...getRootProps({ refKey: 'innerRef' })}>
<TriggerBtn disabled bg={props.bg} tabIndex={0} small={small}>
{renderSelectedItem({ selectedItem, renderSelected, placeholder })}
</TriggerBtn>
</Container>
)
}
return (
<Container
{...getRootProps({ refKey: 'innerRef' })}
{...props}
horizontal
onKeyDown={() => (this._useKeyboard = true)}
onKeyUp={() => (this._useKeyboard = false)}
>
{searchable ? (
<Box grow>
<Input
small
keepEvent
onClick={openMenu}
renderRight={<AngleDown mr={2} />}
{...getInputProps({ placeholder })}
/>
</Box>
) : (
<TriggerBtn
{...getToggleButtonProps()}
bg={props.bg}
fakeFocusRight={fakeFocusRight}
flatLeft={flatLeft}
flatRight={flatRight}
tabIndex={0}
small={small}
>
<Box grow>
{renderSelectedItem({ selectedItem, renderSelected, placeholder })}
</Box>
<AngleDown mr={-1} />
</TriggerBtn>
)}
<div hidden={!isOpen}>
{searchable ? (
<Search
value={inputValue}
items={items}
fuseOptions={fuseOptions}
highlight={highlight}
renderHighlight={renderHighlight}
render={items => this.renderItems(items, selectedItem, downshiftProps)}
/>
) : (
this.renderItems(items, selectedItem, downshiftProps)
)}
</div>
</Container>
)
}}
/>
)
}
}
export default translate()(LegacySelect)

117
src/components/base/LegacySelect/stories.js

@ -1,117 +0,0 @@
// @flow
import React, { PureComponent } from 'react'
import { storiesOf } from '@storybook/react'
import { boolean } from '@storybook/addon-knobs'
import Box from 'components/base/Box'
import LegacySelect from 'components/base/LegacySelect'
import Text from 'components/base/Text'
const stories = storiesOf('Components/base/LegacySelect', module)
const itemsChessPlayers = [
{ key: 'aleksandr-grichtchouk', name: 'Aleksandr Grichtchouk' },
{ key: 'fabiano-caruana', name: 'Fabiano Caruana' },
{ key: 'garry-kasparov', name: 'Garry Kasparov' },
{ key: 'hikaru-nakamura', name: 'Hikaru Nakamura' },
{ key: 'levon-aronian', name: 'Levon Aronian' },
{ key: 'magnus-carlsen', name: 'Magnus Carlsen' },
{ key: 'maxime-vachier-lagrave', name: 'Maxime Vachier-Lagrave' },
{ key: 'shakhriyar-mamedyarov', name: 'Shakhriyar Mamedyarov' },
{ key: 'veselin-topalov', name: 'Veselin Topalov' },
{ key: 'viswanathan-anand', name: 'Viswanathan Anand' },
{ key: 'vladimir-kramnik', name: 'Vladimir Kramnik' },
]
type State = {
item: Object | null,
}
class Wrapper extends PureComponent<any, State> {
state = {
item: null,
}
handleChange = item => this.setState({ item })
render() {
const { children } = this.props
const { item } = this.state
return (
<div>
{children(this.handleChange)}
{item && (
<Box mt={2}>
<pre>
{'You selected:'}
{JSON.stringify(item)}
</pre>
</Box>
)}
</div>
)
}
}
stories.add('basic', () => (
<Wrapper>
{onChange => (
<LegacySelect
disabled={boolean('disabled', false)}
placeholder="Choose a chess player..."
items={itemsChessPlayers}
renderSelected={item => item.name}
onChange={onChange}
/>
)}
</Wrapper>
))
stories.add('searchable', () => (
<LegacySelect
placeholder="Choose a chess player..."
items={itemsChessPlayers}
searchable
highlight
fuseOptions={{ keys: ['name'] }}
itemToString={item => (item ? item.name : '')}
renderHighlight={(text, key) => (
<Text key={key} fontWeight="bold">
{text}
</Text>
)}
/>
))
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', () => (
<LegacySelect
placeholder="Choose a color..."
items={itemsColors}
highlight
searchable
fuseOptions={{ keys: ['name', 'color'] }}
itemToString={item => (item ? item.name : '')}
renderHighlight={(text, key) => (
<Text key={key} fontWeight="bold">
{text}
</Text>
)}
renderItem={item => (
<Box horizontal flow={2}>
<Box bg={item.color} style={{ width: 20, height: 20 }} />
<span>{item.name_highlight || item.name}</span>
</Box>
)}
/>
))

4
src/components/base/Select/index.js

@ -1,6 +1,6 @@
// @flow
import React, { Component } from 'react'
import React, { PureComponent } from 'react'
import ReactSelect from 'react-select'
import { translate } from 'react-i18next'
@ -34,7 +34,7 @@ export type Option = {
data: any,
}
class Select extends Component<Props> {
class Select extends PureComponent<Props> {
handleChange = (value, { action }) => {
const { onChange } = this.props
if (action === 'select-option') {

14
src/components/modals/AccountSettingRenderBody.js

@ -19,7 +19,8 @@ import CryptoCurrencyIcon from 'components/CryptoCurrencyIcon'
import Box from 'components/base/Box'
import Button from 'components/base/Button'
import Input from 'components/base/Input'
import Select from 'components/base/LegacySelect'
import Select from 'components/base/Select'
import {
ModalBody,
ModalTitle,
@ -44,6 +45,9 @@ type Props = {
data: any,
}
const unitGetOptionValue = unit => unit.magnitude
const renderUnitItemCode = item => item.data.code
const mapDispatchToProps = {
setDataModal,
updateAccount,
@ -166,12 +170,12 @@ class HelperComp extends PureComponent<Props, State> {
</Box>
<Box style={{ width: 180 }}>
<Select
keyProp="code"
onChange={this.handleChangeUnit}
renderSelected={item => item && item.code}
renderItem={item => item && item.code}
getOptionValue={unitGetOptionValue}
renderValue={renderUnitItemCode}
renderOption={renderUnitItemCode}
value={accountUnit || account.unit}
items={account.currency.units}
options={account.currency.units}
/>
</Box>
</Container>

Loading…
Cancel
Save