mirror of
https://github.com/react95-io/React95.git
synced 2026-04-26 03:00:18 -04:00
styled Select, added hooks
This commit is contained in:
@@ -5,13 +5,19 @@ import { action } from "@storybook/addon-actions";
|
||||
import AppBar from "./AppBar";
|
||||
import Toolbar from "../Toolbar/Toolbar";
|
||||
import Menu from "../Menu/Menu";
|
||||
import TextField from "../TextField/TextField";
|
||||
|
||||
export const actions = { onClick: action("onClick") };
|
||||
|
||||
storiesOf("AppBar", module).add("default", () => (
|
||||
<AppBar>
|
||||
<Toolbar>
|
||||
<Toolbar style={{ justifyContent: "space-between" }}>
|
||||
<Menu />
|
||||
<TextField
|
||||
placeholder="Search..."
|
||||
width={150}
|
||||
style={{ marginLeft: 4 }}
|
||||
/>
|
||||
</Toolbar>
|
||||
</AppBar>
|
||||
));
|
||||
|
||||
@@ -20,8 +20,13 @@ const StyledList = styled.ul`
|
||||
padding: 2px 4px 4px 2px;
|
||||
${createBorderStyles()}
|
||||
${createBoxStyles()}
|
||||
display: ${props => (props.inline ? "inline-flex" : "inline-block")};
|
||||
|
||||
/* display: ${props => (props.inline ? "inline-flex" : "inline-block")}; */
|
||||
${props =>
|
||||
props.inline &&
|
||||
`
|
||||
align-items: center;
|
||||
display: inline-flex;
|
||||
`}
|
||||
list-style: none;
|
||||
position: relative;
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import { action } from "@storybook/addon-actions";
|
||||
|
||||
import List from "./List";
|
||||
import ListItem from "../ListItem/ListItem";
|
||||
import Bar from "../Bar/Bar";
|
||||
|
||||
export const actions = { onClick: action("onClick") };
|
||||
|
||||
@@ -27,7 +28,8 @@ storiesOf("List", module)
|
||||
))
|
||||
.add("inline", () => (
|
||||
<List inline={true}>
|
||||
<ListItem>Item 1</ListItem>
|
||||
<ListItem square>🌿</ListItem>
|
||||
<Bar />
|
||||
<ListItem>Item 2</ListItem>
|
||||
<ListItem>Item 3</ListItem>
|
||||
</List>
|
||||
|
||||
@@ -55,7 +55,7 @@ storiesOf("ListItem", module)
|
||||
<List>
|
||||
<ListItem {...actions}>Normal item</ListItem>
|
||||
<ListItem {...actions} as="a" href="https://expensive.toys">
|
||||
Link!
|
||||
🔗 Link!
|
||||
</ListItem>
|
||||
</List>
|
||||
));
|
||||
|
||||
@@ -1,86 +1,148 @@
|
||||
import React from "react";
|
||||
import React, { useState } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import cx from "classnames";
|
||||
|
||||
import "./Select.css";
|
||||
import Button from "../Button/Button";
|
||||
|
||||
import SelectItem from "./SelectItem/SelectItem";
|
||||
import styled from "styled-components";
|
||||
import { shadow } from "../common";
|
||||
import {
|
||||
blockSizes,
|
||||
fontSizes,
|
||||
padding,
|
||||
colors
|
||||
} from "../common/theme.variables";
|
||||
import { StyledCutout } from "../common";
|
||||
|
||||
import Cutout from "../Cutout/Cutout";
|
||||
const StyledSelectWrapper = styled(StyledCutout)`
|
||||
height: ${blockSizes.md};
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background: ${colors.light};
|
||||
font-size: ${fontSizes.md};
|
||||
`;
|
||||
const StyledSelectContent = styled.div`
|
||||
width: 100%;
|
||||
padding-left: ${padding.sm};
|
||||
overflow: hidden;
|
||||
`;
|
||||
const StyledDropdownButton = styled(Button)`
|
||||
height: 100%;
|
||||
width: 30px;
|
||||
padding: 0;
|
||||
z-index: 1;
|
||||
flex-shrink: 0;
|
||||
border-left-color: ${colors.lightGray};
|
||||
border-top-color: ${colors.lightGray};
|
||||
box-shadow: inset 1px 1px 0px 1px ${colors.light},
|
||||
inset -1px -1px 0 1px ${colors.darkGray};
|
||||
`;
|
||||
const StyledDropdownIcon = styled.span`
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 0px;
|
||||
height: 0px;
|
||||
border-left: 6px solid transparent;
|
||||
border-right: 6px solid transparent;
|
||||
display: inline-block;
|
||||
border-top: 6px solid #050608;
|
||||
`;
|
||||
|
||||
export class Select extends React.Component {
|
||||
static propTypes = {
|
||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
className: PropTypes.string,
|
||||
width: PropTypes.number,
|
||||
height: PropTypes.number,
|
||||
selectedIndex: PropTypes.number,
|
||||
noShadow: PropTypes.bool,
|
||||
onSelect: PropTypes.func.isRequired
|
||||
};
|
||||
static defaultProps = {
|
||||
style: {},
|
||||
noShadow: false,
|
||||
selectedIndex: 0
|
||||
};
|
||||
const StyledDropdownList = styled.ul`
|
||||
font-size: ${fontSizes.md};
|
||||
position: absolute;
|
||||
bottom: -2px;
|
||||
width: calc(100% - 2px);
|
||||
transform: translateY(100%);
|
||||
left: 0px;
|
||||
background: ${colors.light};
|
||||
border: 2px solid ${colors.dark};
|
||||
border-top: none;
|
||||
box-shadow: ${props => (props.shadow ? shadow : "none")};
|
||||
cursor: default;
|
||||
z-index: 99;
|
||||
`;
|
||||
const StyledDropdownListItem = styled.li`
|
||||
height: calc(${blockSizes.md} - 8px);
|
||||
width: 100%;
|
||||
padding-left: ${padding.sm};
|
||||
|
||||
state = {
|
||||
items: this.props.items || [],
|
||||
open: false,
|
||||
selectedItem: this.props.selectedIndex || 0
|
||||
};
|
||||
|
||||
toggle = () => this.setState(prevState => ({ open: !prevState.open }));
|
||||
|
||||
handleSelect = index => {
|
||||
this.props.onSelect(this.state.items[index].value);
|
||||
this.setState({ selectedItem: index, open: false });
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
noShadow,
|
||||
width,
|
||||
height,
|
||||
otherProps,
|
||||
className,
|
||||
style
|
||||
} = this.props;
|
||||
const { items, selectedItem, open } = this.state;
|
||||
const baseClass = "Select";
|
||||
|
||||
const rootClass = cx(baseClass, {
|
||||
[`${baseClass}--noShadow`]: noShadow,
|
||||
[`${baseClass}--fixedHeight`]: height
|
||||
});
|
||||
return (
|
||||
<div
|
||||
className={cx(`${baseClass}-wrapper`, className)}
|
||||
style={{ ...style, width: width ? width : "auto" }}
|
||||
>
|
||||
<Cutout>
|
||||
<button onClick={this.toggle} className={`${baseClass}-header`}>
|
||||
{items.length ? items[selectedItem].title : ""}
|
||||
<span className={`${baseClass}-button`}>
|
||||
<span className={`${baseClass}-button__icon`} />
|
||||
</span>
|
||||
</button>
|
||||
</Cutout>
|
||||
{open && (
|
||||
<ul
|
||||
className={rootClass}
|
||||
{...otherProps}
|
||||
style={{ height: height ? height : "auto" }}
|
||||
>
|
||||
{items.map((item, i) => (
|
||||
<SelectItem key={i} onClick={() => this.handleSelect(i)}>
|
||||
{item.title}
|
||||
</SelectItem>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
line-height: calc(${blockSizes.md} - 8px);
|
||||
font-size: ${fontSizes.md};
|
||||
white-space: nowrap;
|
||||
&:hover {
|
||||
background: ${colors.navy};
|
||||
color: ${colors.light};
|
||||
}
|
||||
}
|
||||
`;
|
||||
const Select = ({
|
||||
items,
|
||||
selectedIndex,
|
||||
shadow,
|
||||
width,
|
||||
height,
|
||||
otherProps,
|
||||
className,
|
||||
onSelect,
|
||||
style
|
||||
}) => {
|
||||
const [index, setIndex] = useState(selectedIndex);
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
const handleSelect = i => {
|
||||
onSelect(items[i].value);
|
||||
setIndex(i);
|
||||
};
|
||||
return (
|
||||
<StyledSelectWrapper
|
||||
className={className}
|
||||
onClick={() => setOpen(!open)}
|
||||
style={{ ...style, width }}
|
||||
shadow={shadow}
|
||||
{...otherProps}
|
||||
>
|
||||
<StyledSelectContent>
|
||||
{items.length ? items[index].title : ""}
|
||||
</StyledSelectContent>
|
||||
<StyledDropdownButton>
|
||||
<StyledDropdownIcon />
|
||||
</StyledDropdownButton>
|
||||
{open && (
|
||||
<StyledDropdownList
|
||||
shadow={shadow}
|
||||
style={height && { overflowY: "scroll", height }}
|
||||
>
|
||||
{items.map((item, i) => (
|
||||
<StyledDropdownListItem
|
||||
key={i}
|
||||
onClick={e => {
|
||||
handleSelect(i);
|
||||
}}
|
||||
>
|
||||
{item.title}
|
||||
</StyledDropdownListItem>
|
||||
))}
|
||||
</StyledDropdownList>
|
||||
)}
|
||||
</StyledSelectWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
Select.propTypes = {
|
||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
className: PropTypes.string,
|
||||
width: PropTypes.number,
|
||||
height: PropTypes.number,
|
||||
selectedIndex: PropTypes.number,
|
||||
shadow: PropTypes.bool,
|
||||
style: PropTypes.object,
|
||||
onSelect: PropTypes.func.isRequired
|
||||
};
|
||||
Select.defaultProps = {
|
||||
style: {},
|
||||
shadow: true,
|
||||
selectedIndex: 0
|
||||
};
|
||||
export default Select;
|
||||
|
||||
@@ -9,7 +9,11 @@ export const actions = { onClick: action("onClick") };
|
||||
const items = [
|
||||
{ value: 1, title: 1 },
|
||||
{ value: 2, title: 2 },
|
||||
{ value: 3, title: 3 }
|
||||
{ value: 3, title: 3 },
|
||||
{ value: 4, title: 4 },
|
||||
{ value: 5, title: 5 },
|
||||
{ value: 6, title: 6 },
|
||||
{ value: 7, title: 7 }
|
||||
];
|
||||
const onSelect = value => console.log(value);
|
||||
storiesOf("Select", module)
|
||||
@@ -23,7 +27,12 @@ storiesOf("Select", module)
|
||||
{story()}
|
||||
</div>
|
||||
))
|
||||
.add("default", () => (
|
||||
.add("fixed width", () => (
|
||||
<Select items={items} onSelect={onSelect} width={140} />
|
||||
))
|
||||
.add("noShadow", () => <Select noShadow items={items} onSelect={onSelect} />);
|
||||
.add("fixed height", () => (
|
||||
<Select items={items} onSelect={onSelect} height={100} width={140} />
|
||||
))
|
||||
.add("no shadow", () => (
|
||||
<Select shadow={false} items={items} onSelect={onSelect} />
|
||||
));
|
||||
|
||||
@@ -39,6 +39,7 @@ const TextField = ({
|
||||
width,
|
||||
className,
|
||||
type,
|
||||
style,
|
||||
shadow,
|
||||
...otherProps
|
||||
}) => {
|
||||
@@ -53,7 +54,7 @@ const TextField = ({
|
||||
<StyledInputWrapper
|
||||
shadow={shadow}
|
||||
isDisabled={disabled}
|
||||
style={{ width: width ? width : "auto" }}
|
||||
style={{ ...style, width: width ? width : "auto" }}
|
||||
>
|
||||
<StyledInput
|
||||
onChange={disabled ? undefined : onValueChange}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { colors, fontSizes } from "./theme.variables";
|
||||
|
||||
const { bg, light, dark, lightGray, darkGray } = colors;
|
||||
|
||||
const shadow = `4px 4px 10px 0 rgba(0, 0, 0, 0.35)`;
|
||||
export const shadow = `4px 4px 10px 0 rgba(0, 0, 0, 0.35)`;
|
||||
|
||||
export const StyledMaterial = styled.div`
|
||||
box-sizing: border-box;
|
||||
|
||||
Reference in New Issue
Block a user