Basic dropdown
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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}
|
||||
|
||||
156
website/src/ui/DropdownList.js
Normal file
156
website/src/ui/DropdownList.js
Normal 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>
|
||||
)
|
||||
}
|
||||
})
|
||||
14
website/src/ui/images/down-arrow.svg
Normal file
14
website/src/ui/images/down-arrow.svg
Normal 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 |
14
website/src/ui/images/up-arrow.svg
Normal file
14
website/src/ui/images/up-arrow.svg
Normal 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 |
@@ -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'
|
||||
|
||||
Reference in New Issue
Block a user