Skip to content

Commit 4f6459b

Browse files
kararadebernardodiasc
authored andcommitted
Move CustomSelect from XP-Reg to XP-UI (#523)
* move CustomSelector and rename SkillsSelectorOption to SelectorOption * fix lint * fix flow * add more props * clean props * rebuild * update stories
1 parent 731ef88 commit 4f6459b

8 files changed

+338
-39
lines changed

src/components/ui/CustomSelector.js

+162
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
// @flow
2+
import React, { PureComponent } from 'react'
3+
import Select from 'react-select'
4+
5+
import SelectorOption from './SelectorOption'
6+
7+
import '../../assets/react-select.css'
8+
9+
import theme from '../../styles/theme'
10+
import typo from '../../styles/typo'
11+
12+
const cmz = require('cmz')
13+
14+
const cx = {
15+
select: cmz(
16+
typo.baseText,
17+
`
18+
& {
19+
font-size: 18px
20+
text-rendering: optimizeLegibility
21+
-webkit-font-smoothing: antialiased
22+
color: ${theme.typoParagraph}
23+
border: 1px solid transparent
24+
}
25+
26+
& .Select-control {
27+
display: flex
28+
border: 1px solid ${theme.lineSilver2}
29+
height: auto
30+
padding: 14px 16px
31+
border-radius: 0
32+
cursor: pointer
33+
}
34+
35+
&.is-focused .Select-control {
36+
border: 1px solid ${theme.lineRed} !important
37+
box-shadow: 0 0 3px ${theme.lineRed} !important
38+
}
39+
40+
&.is-disabled:hover {
41+
border: 1px solid transparent
42+
box-shadow: none
43+
}
44+
45+
& .Select-multi-value-wrapper {
46+
white-space: nowrap
47+
flex: 1
48+
overflow-x: auto
49+
overflow-y: hidden
50+
display: flex
51+
align-items: center
52+
height: 18px
53+
}
54+
55+
& .Select-placeholder,
56+
& .Select-control .Select-value {
57+
padding: 21px 18px !important
58+
line-height: 1 !important
59+
white-space: nowrap !important
60+
overflow: hidden !important
61+
text-overflow: ellipsis !important
62+
}
63+
64+
& .Select-input {
65+
padding: 0 3px !important
66+
position: absolute !important
67+
top: 11px !important
68+
}
69+
70+
& .Select-input:focus {
71+
background: transparent !important
72+
}
73+
74+
& .Select-control > *:last-child {
75+
padding: 0
76+
margin-right: -5px
77+
}
78+
79+
& .Select-menu-outer {
80+
top: calc(100% + 5px)
81+
max-height: 270px
82+
background: ${theme.baseBrighter}
83+
border: 1px solid rgba(0, 0, 0, 0.15)
84+
box-shadow: 0 5px 12px rgba(0, 0, 0, 0.15)
85+
border-radius: 0
86+
}
87+
88+
& .Select-menu {
89+
max-height: 270px
90+
}
91+
92+
& .Select-option {
93+
padding: 0
94+
border-bottom: 1px solid ${theme.lineSilver2}
95+
}
96+
`
97+
)
98+
}
99+
100+
type Option = {
101+
value: string | number,
102+
label: string
103+
}
104+
105+
type Props = {
106+
placeholder?: string,
107+
options?: Array<Option> | null,
108+
disabled?: boolean,
109+
clearable?: boolean,
110+
searchable?: boolean,
111+
value?: any,
112+
onChange?: any
113+
}
114+
115+
type State = {
116+
selectedOption: Option | null
117+
}
118+
119+
class CustomSelector extends PureComponent<Props, State> {
120+
static defaultProps = {
121+
placeholder: '',
122+
options: null,
123+
disabled: false,
124+
clearable: false,
125+
searchable: false,
126+
value: null,
127+
onChange: null
128+
}
129+
130+
state: State = {
131+
selectedOption: null
132+
}
133+
134+
handleSelection = (selectedOption: Option) => {
135+
this.setState({ selectedOption })
136+
}
137+
138+
render () {
139+
const { placeholder, options, disabled, clearable, searchable, value, onChange } = this.props
140+
const { selectedOption } = this.state
141+
142+
return (
143+
<div>
144+
<Select
145+
{...this.props}
146+
name={'customSelector'}
147+
className={cx.select.toString()}
148+
optionRenderer={SelectorOption}
149+
placeholder={placeholder || 'Select...'}
150+
options={options}
151+
disabled={disabled}
152+
clearable={clearable}
153+
searchable={searchable}
154+
value={value || selectedOption}
155+
onChange={onChange || this.handleSelection}
156+
/>
157+
</div>
158+
)
159+
}
160+
}
161+
162+
export default CustomSelector
+133
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
// @flow
2+
/* globals alert */
3+
4+
import React from 'react'
5+
import { storiesOf } from '@storybook/react'
6+
7+
import CustomSelector from './CustomSelector'
8+
9+
const months = [
10+
{ label: 'January', value: 1 },
11+
{ label: 'February', value: 2 },
12+
{ label: 'March', value: 3 },
13+
{ label: 'April', value: 4 },
14+
{ label: 'May', value: 5 },
15+
{ label: 'June', value: 6 },
16+
{ label: 'July', value: 7 },
17+
{ label: 'August', value: 8 },
18+
{ label: 'September', value: 9 },
19+
{ label: 'October', value: 10 },
20+
{ label: 'November', value: 11 },
21+
{ label: 'December', value: 12 }
22+
]
23+
24+
const customOnChange = (selectedOption) => {
25+
alert(`Custom onChange() > Selected option label: ${selectedOption.label}`)
26+
}
27+
28+
storiesOf('Core Components|Form Components/CustomSelector', module)
29+
.add('basic usage', () => (
30+
<CustomSelector
31+
placeholder={'Month'}
32+
options={months}
33+
/>
34+
))
35+
36+
storiesOf('Core Components|Form Components/CustomSelector/States', module)
37+
.add('clearable', () => (
38+
<CustomSelector
39+
placeholder={'Month'}
40+
options={months}
41+
clearable
42+
/>
43+
))
44+
.add('searchable', () => (
45+
<CustomSelector
46+
placeholder={'Month'}
47+
options={months}
48+
searchable
49+
/>
50+
))
51+
.add('clearable + searchable', () => (
52+
<CustomSelector
53+
placeholder={'Month'}
54+
options={months}
55+
clearable
56+
searchable
57+
/>
58+
))
59+
.add('enabled', () => (
60+
<CustomSelector
61+
placeholder={'Month'}
62+
options={months}
63+
/>
64+
))
65+
.add('disabled', () => (
66+
<CustomSelector
67+
placeholder={'Month'}
68+
options={months}
69+
disabled
70+
/>
71+
))
72+
73+
storiesOf('Core Components|Form Components/CustomSelector/Debug', module)
74+
.add('missing props', () => (
75+
<CustomSelector />
76+
))
77+
.add('without the required "placeholder"', () => (
78+
<CustomSelector
79+
options={months}
80+
/>
81+
))
82+
.add('without the required "options"', () => (
83+
<CustomSelector
84+
placeholder={'Month'}
85+
/>
86+
))
87+
.add('custom "onChange" function', () => (
88+
<CustomSelector
89+
placeholder={'Month'}
90+
options={months}
91+
onChange={customOnChange}
92+
/>
93+
))
94+
.add('custom "value"', () => (
95+
<CustomSelector
96+
placeholder={'Month'}
97+
options={months}
98+
value={{ label: 'Custom Label', value: 'custom value' }}
99+
/>
100+
))
101+
.add('stacked selectors', () => (
102+
<div>
103+
<CustomSelector
104+
placeholder={'Month'}
105+
options={months}
106+
/>
107+
108+
<CustomSelector
109+
placeholder={'Month'}
110+
options={months}
111+
/>
112+
113+
<CustomSelector
114+
placeholder={'Month'}
115+
options={months}
116+
/>
117+
118+
<CustomSelector
119+
placeholder={'Month'}
120+
options={months}
121+
/>
122+
123+
<CustomSelector
124+
placeholder={'Month'}
125+
options={months}
126+
/>
127+
128+
<CustomSelector
129+
placeholder={'Month'}
130+
options={months}
131+
/>
132+
</div>
133+
))

src/components/ui/SkillsSelectorOption.js renamed to src/components/ui/SelectorOption.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,12 @@ type Props = {
3737
label?: string
3838
}
3939

40-
const SkillsSelectorOption = ({ label }: Props) => label ? (
40+
const SelectorOption = ({ label }: Props) => label ? (
4141
<div className={cx.option}>
4242
<div className={cx.optionLabel}>
4343
{label}
4444
</div>
4545
</div>
4646
) : null
4747

48-
export default SkillsSelectorOption
48+
export default SelectorOption
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// @flow
2+
3+
import React from 'react'
4+
import { storiesOf } from '@storybook/react'
5+
6+
import SelectorOption from './SelectorOption'
7+
8+
const Body = ({ children }) => (
9+
<div style={{ height: '100vh' }}>
10+
<style dangerouslySetInnerHTML={{ __html: `
11+
html, body { margin: 0; height: 100%; padding: 30px 50px; }
12+
` }} />
13+
{children}
14+
</div>
15+
)
16+
17+
storiesOf('Core Components|Form Components/SelectorOption', module)
18+
.add('basic usage', () => (
19+
<Body>
20+
<SelectorOption label='JavaScript' />
21+
</Body>
22+
))
23+
24+
storiesOf('Core Components|Form Components/SelectorOption/Debug', module)
25+
.add('many options stacked', () => (
26+
<Body>
27+
<SelectorOption label='JavaScript' />
28+
<SelectorOption label='JavaScript' />
29+
<SelectorOption label='JavaScript' />
30+
<SelectorOption label='JavaScript' />
31+
</Body>
32+
))
33+
.add('missing props', () => (
34+
<SelectorOption />
35+
))

src/components/ui/SkillsSelector.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import differenceBy from 'lodash.differenceby'
55
import Select from 'react-select'
66

77
import SvgIcon from './SvgIcon'
8-
import SkillsSelectorOption from './SkillsSelectorOption'
8+
import SelectorOption from './SelectorOption'
99

1010
import '../../assets/react-select.css'
1111

@@ -205,7 +205,7 @@ class SkillsSelector extends Component<Props, State> {
205205
clearable={false}
206206
arrowRenderer={null}
207207
onChange={this.handleSkillSelection}
208-
optionRenderer={SkillsSelectorOption}
208+
optionRenderer={SelectorOption}
209209
/>
210210
<div className={cx.tags}>
211211
{selectedSkills.map(this.renderTag)}

0 commit comments

Comments
 (0)