feat(core): add single select component

This commit is contained in:
Rémi DOREAU
2020-09-08 00:13:15 +02:00
parent f7a57e89d0
commit 1ff3fe165c
5 changed files with 280 additions and 0 deletions
@@ -0,0 +1,42 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
import { Select } from '.';
export default {
title: 'Select',
component: Select,
};
const SELECT_ITEMS = [
{
label: "test 1",
value: "test_1"
},
{
label: "test 2",
value: "test_2"
},
{
label: "test 3",
value: "test_3"
}
]
export const Default = () => (
<Select label="Default" items={SELECT_ITEMS} />
);
@@ -0,0 +1,137 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React, { useState } from 'react';
import {
createStyles,
makeStyles,
withStyles,
Theme,
} from '@material-ui/core/styles';
import {
FormControl,
InputLabel,
Select,
MenuItem,
InputBase,
} from '@material-ui/core';
import ClosedDropdown from './static/ClosedDropdown';
import OpenedDropdown from './static/OpenedDropdown';
const BootstrapInput = withStyles((theme: Theme) =>
createStyles({
root: {
'label + &': {
marginTop: theme.spacing(3),
},
},
input: {
borderRadius: 4,
position: 'relative',
backgroundColor: theme.palette.background.paper,
border: '1px solid #ced4da',
fontSize: 16,
padding: '10px 26px 10px 12px',
transition: theme.transitions.create(['border-color', 'box-shadow']),
fontFamily: 'Helvetica Neue',
'&:focus': {
background: theme.palette.background.paper,
borderRadius: 4,
},
},
}),
)(InputBase);
const useStyles = makeStyles((theme: Theme) =>
createStyles({
formControl: {
margin: theme.spacing(1),
minWidth: 315,
},
label: {
transform: 'initial',
fontWeight: 'bold',
fontSize: 14,
fontFamily: theme.typography.fontFamily,
color: theme.palette.text.primary,
'&.Mui-focused': {
color: theme.palette.text.primary,
},
},
}),
);
type Item = {
label: string;
value: string | number;
};
type Props = {
multiple?: boolean;
items: Item[];
label: string;
};
export const SelectComponent = (props: Props) => {
const { multiple, items, label } = props;
const classes = useStyles();
const [value, setValue] = useState('');
const [isOpen, setOpening] = useState(true);
const handleChange = (event: React.ChangeEvent<{ value: unknown }>) => {
setValue(event.target.value as string);
};
return (
<FormControl className={classes.formControl}>
<InputLabel className={classes.label} disableAnimation id="select-label">
{label}
</InputLabel>
<Select
id="select"
value={value}
multiple={multiple}
onChange={handleChange}
onOpen={() => setOpening(false)}
onClose={() => setOpening(true)}
input={<BootstrapInput />}
IconComponent={() => (
isOpen ? <ClosedDropdown /> : <OpenedDropdown />
)}
MenuProps={{
anchorOrigin: {
vertical: 'bottom',
horizontal: 'left',
},
transformOrigin: {
vertical: 'top',
horizontal: 'left',
},
getContentAnchorEl: null,
}}
>
{items &&
items.map(item => (
<MenuItem key={item.value} value={item.value}>
{item.label}
</MenuItem>
))}
</Select>
</FormControl>
);
};
@@ -0,0 +1,17 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { SelectComponent as Select } from './Select';
@@ -0,0 +1,42 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
import { SvgIcon, makeStyles, createStyles } from '@material-ui/core';
const useStyles = makeStyles(() =>
createStyles({
icon: {
position: 'absolute',
right: '4px',
pointerEvents: "none"
},
}),
);
const ClosedDropdown = () => {
const classes = useStyles();
return (
<SvgIcon
className={classes.icon}
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M7.5 8L6 9.5L12.0703 15.5703L18.1406 9.5L16.6406 8L12.0703 12.5703L7.5 8Z" fill="#616161"/>
</SvgIcon>
);
};
export default ClosedDropdown;
@@ -0,0 +1,42 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
import { SvgIcon, makeStyles, createStyles } from '@material-ui/core';
const useStyles = makeStyles(() =>
createStyles({
icon: {
position: 'absolute',
right: '4px',
pointerEvents: 'none',
},
}),
);
const OpenedDropdown = () => {
const classes = useStyles();
return (
<SvgIcon
className={classes.icon}
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M16.5 16L18 14.5L11.9297 8.42969L5.85938 14.5L7.35938 16L11.9297 11.4297L16.5 16Z" fill="#616161"/>
</SvgIcon>
);
};
export default OpenedDropdown;