Basic dropdown

This commit is contained in:
John Lyon-Smith
2018-03-26 07:37:41 -07:00
parent cb708c720f
commit 90a920264b
7 changed files with 242 additions and 16 deletions

View File

@@ -3,7 +3,7 @@ import PropTypes from 'prop-types'
import autobind from 'autobind-decorator'
import { regExpPattern } from 'regexp-pattern'
import { api } from 'src/API'
import { Row, Column, BoundInput, BoundButton, BoundCheckbox, BoundEmailIcon } from 'ui'
import { Row, Column, BoundInput, BoundButton, BoundCheckbox, BoundEmailIcon, DropdownList } from 'ui'
import { FormBinder } from 'react-form-binder'
import { sizeInfo } from 'ui/style'
@@ -144,6 +144,13 @@ export class UserForm extends React.Component {
</Row.Item>
</Row>
</Column.Item>
<Column.Item>
<DropdownList render={(item) => (
<DropdownList.Item style={{ paddingLeft: 8 }}>
<DropdownList.Text>Team Name</DropdownList.Text>
</DropdownList.Item>
)} />
</Column.Item>
<Column.Item height={sizeInfo.formColumnSpacing} />
<Column.Item minHeight={sizeInfo.buttonHeight}>
<Row>

View File

@@ -32,7 +32,7 @@ export class Users extends Component {
api.listUsers().then((list) => {
list.items.sort((userA, userB) => (userA.lastName.localeCompare(userB.lastName)))
this.setState({ users: list.items })
this.setState({ users: list.items, selectedUser: list.items[0] }) // TODO: <- Remove
}).catch((error) => {
this.setState({
messageModal: {
@@ -276,10 +276,10 @@ export class Users extends Component {
<Box border={{ width: sizeInfo.headerBorderWidth, color: colorInfo.headerBorder }} radius={sizeInfo.formBoxRadius}>
{
this.state.selectedUser
? <UserForm user={this.state.selectedUser} onSave={this.handleSave}
onRemove={this.handleRemove} onModifiedChanged={this.handleModifiedChanged}
onChangeEmail={this.handleChangeEmail} onResendEmail={this.handleResendEmail} />
: <UserFormPlaceholder />
? <UserForm user={this.state.selectedUser} onSave={this.handleSave}
onRemove={this.handleRemove} onModifiedChanged={this.handleModifiedChanged}
onChangeEmail={this.handleChangeEmail} onResendEmail={this.handleResendEmail} />
: <UserFormPlaceholder />
}
</Box>
</Row.Item>

View File

@@ -10,7 +10,11 @@ export class Box extends Component {
borderRight: PropTypes.object,
borderLeft: PropTypes.object,
border: PropTypes.object,
radius: PropTypes.number,
radius: PropTypes.oneOfType([PropTypes.number, PropTypes.object]),
radiusTopLeft: PropTypes.number,
radiusTopRight: PropTypes.number,
radiusBottomLeft: PropTypes.number,
radiusBottomRight: PropTypes.number,
background: PropTypes.string,
style: PropTypes.object,
children: PropTypes.node,
@@ -20,8 +24,9 @@ export class Box extends Component {
let {
children, background,
borderTop, borderBottom, borderLeft, borderRight,
border, radius, style } = this.props
const flatten = (border) => {
border, style, radius,
radiusTopLeft, radiusTopRight, radiusBottomLeft, radiusBottomRight } = this.props
const stringify = (border) => {
if (!border) {
return null
}
@@ -34,19 +39,48 @@ export class Box extends Component {
}
if (border) {
borderTop = borderBottom = borderLeft = borderRight = flatten(border)
borderTop = borderBottom = borderLeft = borderRight = stringify(border)
} else {
borderTop = flatten(borderTop)
borderBottom = flatten(borderBottom)
borderLeft = flatten(borderLeft)
borderRight = flatten(borderRight)
borderTop = stringify(borderTop)
borderBottom = stringify(borderBottom)
borderLeft = stringify(borderLeft)
borderRight = stringify(borderRight)
}
let borderTopLeftRadius, borderTopRightRadius, borderBottomLeftRadius, borderBottomRightRadius
if (radius) {
if (typeof radius === 'number') {
borderTopLeftRadius = borderTopRightRadius = borderBottomLeftRadius = borderBottomRightRadius = radius
} else {
borderTopLeftRadius = radius.topLeft
borderTopRightRadius = radius.topRight
borderBottomLeftRadius = radius.bottomLeft
borderBottomRightRadius = radius.bottomRight
}
} else {
borderTopLeftRadius = radiusTopLeft
borderTopRightRadius = radiusTopRight
borderBottomLeftRadius = radiusBottomLeft
borderBottomRightRadius = radiusBottomRight
}
return (
<div style={[
{ height: '100%', width: '100%', boxSizing: 'border-box', borderTop, borderBottom, borderLeft, borderRight },
{
height: '100%',
width: '100%',
boxSizing: 'border-box',
borderTop,
borderBottom,
borderLeft,
borderRight,
borderTopLeftRadius,
borderTopRightRadius,
borderBottomLeftRadius,
borderBottomRightRadius,
},
background && { backgroundColor: background },
radius && { borderRadius: radius },
style,
]}>
{children}

View File

@@ -0,0 +1,156 @@
import Radium from 'radium'
import PropTypes from 'prop-types'
import React, { Component } from 'react'
import { Box, Icon } from '.'
import { sizeInfo, colorInfo, fontInfo } from './style'
import downArrowImage from './images/down-arrow.svg'
import upArrowImage from './images/up-arrow.svg'
import autobind from 'autobind-decorator'
@Radium
export class DropdownList extends Component {
static propTypes = {
data: PropTypes.array,
render: PropTypes.func.isRequired,
}
constructor(props) {
super(props)
this.state = {
open: false,
}
}
@autobind
handleClick(e) {
this.setState({ open: !this.state.open })
}
render() {
const { data, render } = this.props
const { open } = this.state
const dropDownIconSize = 20
const dropdownIconMargin = 8
const dropdownBackground = 'white'
const selectedItem = data ? data[0] : <span />
const border = { width: sizeInfo.listBorderWidth, color: colorInfo.listBorder }
let dropdown = null
if (open) {
dropdown = (
<Box
borderLeft={border}
borderRight={border}
borderBottom={border}
radius={{ bottomLeft: sizeInfo.formBoxRadius, bottomRight: sizeInfo.formBoxRadius }}
background={dropdownBackground}
style={{
height: 200,
zIndex: 100,
position: 'absolute',
}}
/>
)
}
return (
<div>
<Box
borderTop={border}
borderLeft={border}
borderRight={border}
borderBottom={open ? { width: sizeInfo.listBorderWidth, color: 'transparent' } : { width: sizeInfo.listBorderWidth, color: colorInfo.listBorder }}
radius={open ? { topLeft: sizeInfo.formBoxRadius, topRight: sizeInfo.formBoxRadius } : sizeInfo.formBoxRadius}
style={{
display: 'flex',
alignItems: 'center',
fontSize: fontInfo.size.large,
fontFamily: fontInfo.family,
}}>
<div style={{ flexGrow: 1 }}>
{render(selectedItem)}
</div>
<div>
<img src={open ? upArrowImage : downArrowImage}
style={{
verticalAlign: 'middle',
width: dropDownIconSize,
height: dropDownIconSize,
margin: dropdownIconMargin,
}}
onClick={this.handleClick} />
</div>
</Box>
{dropdown}
</div>
)
}
}
DropdownList.Item = Radium(class ListItem extends Component {
static propTypes = {
children: PropTypes.node,
active: PropTypes.bool,
onClick: PropTypes.func,
}
render() {
const { children, active, onClick } = this.props
return (
<div
style={{
width: '100%',
height: '100%',
background: active ? colorInfo.listBackgroundActive : 'transparent',
':hover': {
background: colorInfo.listBackgroundHover
},
}} onClick={onClick}>
{children}
</div>
)
}
})
DropdownList.Icon = Radium(class ListIcon extends Component {
static propTypes = {
name: PropTypes.string,
size: PropTypes.number,
}
render() {
const { size, name } = this.props
let source = Icon.svgs[name] || Icon.svgs['placeholder']
return (
<img src={source} style={{
verticalAlign: 'middle',
width: size,
height: size,
margin: sizeInfo.listIconMargin,
}} />
)
}
})
DropdownList.Text = Radium(class ListText extends Component {
static propTypes = {
children: PropTypes.node,
}
render() {
const { children } = this.props
return (
<span style={{
color: fontInfo.color.normal,
align: 'left',
textAlign: 'left',
cursor: 'default',
paddingLeft: 8,
}}>{children}</span>
)
}
})

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="76px" height="76px" viewBox="0 0 76 76" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 49.1 (51147) - http://www.bohemiancoding.com/sketch -->
<title>down-arrow</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Login" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Home" transform="translate(-121.000000, -304.000000)" fill="#9C9C9C">
<g id="down-arrow" transform="translate(121.000000, 304.000000)">
<path d="M6.29010254,25 L67.709898,25 C68.2621828,25 68.709898,25.4477153 68.709898,26 C68.709898,26.2697399 68.6009273,26.5280401 68.4077205,26.7162707 L37.6978228,56.6352081 C37.3095159,57.0135138 36.6904847,57.0135138 36.3021777,56.6352081 L5.59228001,26.7162707 C5.19669462,26.330874 5.18843509,25.6977629 5.57383183,25.3021775 C5.7620624,25.1089707 6.02036264,25 6.29010254,25 Z"></path>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="76px" height="76px" viewBox="0 0 76 76" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 49.1 (51147) - http://www.bohemiancoding.com/sketch -->
<title>up-arrow</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Login" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Home" transform="translate(-220.000000, -304.000000)" fill="#9C9C9C">
<g id="up-arrow" transform="translate(220.000000, 304.000000)">
<path d="M6.29010254,25 L67.709898,25 C68.2621828,25 68.709898,25.4477153 68.709898,26 C68.709898,26.2697399 68.6009273,26.5280401 68.4077205,26.7162707 L37.6978228,56.6352081 C37.3095159,57.0135138 36.6904847,57.0135138 36.3021777,56.6352081 L5.59228001,26.7162707 C5.19669462,26.330874 5.18843509,25.6977629 5.57383183,25.3021775 C5.7620624,25.1089707 6.02036264,25 6.29010254,25 Z" transform="translate(37.000000, 40.959469) scale(1, -1) translate(-37.000000, -40.959469) "></path>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -11,6 +11,7 @@ export { Text } from './Text'
export { Link } from './Link'
export { Icon } from './Icon'
export { List } from './List'
export { DropdownList } from './DropdownList'
export { Modal } from './Modal'
export { Dimmer } from './Dimmer'
export { Loader } from './Loader'