Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Polish Label Color Picker #12464

Merged
merged 12 commits into from
Mar 11, 2019
Next Next commit
WIP introduce color picker component
  • Loading branch information
alexpaxton committed Mar 8, 2019
commit c1175d37845a6b2a1ac58980da524cd7667b0542
74 changes: 74 additions & 0 deletions ui/src/clockface/components/color_picker/ColorPicker.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
@import 'src/style/modules';

/*
Color Picker Widget
------------------------------------------------------------------------------
*/

$color-picker--margin: 0;

.color-picker {
display: flex;
flex-direction: column;
align-items: stretch;
width: 240px;
background-color: $g2-kevlar;
padding: $ix-marg-b;
}

.color-picker--swatches {
margin-bottom: $ix-marg-b;
position: relative;
padding: $color-picker--margin;
border-radius: $radius;
overflow: hidden;
}

.color-picker--swatch {
width: 10%;
padding-bottom: 10%;
position: relative;
float: left;
opacity: 1;
transition: opacity 0.25s ease;

> span {
position: absolute;
top: $color-picker--margin;
left: $color-picker--margin;
right: $color-picker--margin;
bottom: $color-picker--margin;
}

&:hover {
cursor: pointer;
opacity: 0.5;
}
}

.color-picker--form {
display: flex;
align-items: center;
position: relative;
}

.input.color-picker--input {
flex: 1 0 0;
margin-right: $ix-marg-a;

> input {
padding-left: $ix-marg-d;
}
}

.color-picker--selected {
pointer-events: none;
z-index: 2;
position: absolute;
top: 50%;
left: $ix-marg-c;
transform: translate(-50%, -50%);
width: 18px;
height: 18px;
border-radius: 50%;
}
141 changes: 141 additions & 0 deletions ui/src/clockface/components/color_picker/ColorPicker.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
// Libraries
import React, {Component, ChangeEvent} from 'react'
import _ from 'lodash'

// Components
import {Button, IconFont, ButtonShape} from '@influxdata/clockface'
import {Input} from 'src/clockface'
import Swatch from 'src/clockface/components/color_picker/ColorPickerSwatch'

// Constants
import {colors} from 'src/clockface/constants/colors'

// Styles
import 'src/clockface/components/color_picker/ColorPicker.scss'

interface Props {
selectedHex: string
onSelect: (hex: string) => void
maintainInputFocus?: boolean
}

interface State {
inputValue: string
}

export default class ColorPicker extends Component<Props, State> {
constructor(props: Props) {
super(props)

this.state = {
inputValue: this.props.selectedHex || '',
}
}

componentDidUpdate(prevProps) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should prevProps be typed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

YES

if (prevProps.selectedHex !== this.props.selectedHex) {
this.setState({inputValue: this.props.selectedHex})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it necessary to keep track of the hex value in state? it seems like this will be creating two sources of truth? could all the places that state instead call the onSelect() prop?

}
}

render() {
const {maintainInputFocus} = this.props
const {inputValue} = this.state

return (
<div className="color-picker">
<div className="color-picker--swatches">
{colors.map(color => (
<Swatch
key={color.name}
hex={color.hex}
name={color.name}
onClick={this.handleSwatchClick}
/>
))}
</div>
<div className="color-picker--form">
{this.selectedColor}
<Input
customClass="color-picker--input"
placeholder="#000000"
value={inputValue}
onChange={this.handleInputChange}
maxLength={7}
onBlur={this.handleInputBlur}
autoFocus={maintainInputFocus}
/>
<Button
icon={IconFont.Refresh}
shape={ButtonShape.Square}
onClick={this.handleRandomizeColor}
/>
</div>
</div>
)
}

private handleSwatchClick = (hex: string): void => {
const {onSelect} = this.props

this.setState({inputValue: hex})
onSelect(hex)
}

private handleInputChange = (e: ChangeEvent<HTMLInputElement>) => {
const acceptedChars = [
'#',
'a',
'b',
'c',
'd',
'e',
'f',
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
]

const trimmedValue = e.target.value.trim()
const inputValue = trimmedValue
.split('')
.filter(char => acceptedChars.includes(char.toLowerCase()))
.join('')

this.setState({inputValue})
}

private handleInputBlur = (e: ChangeEvent<HTMLInputElement>) => {
const {maintainInputFocus} = this.props

if (maintainInputFocus) {
e.target.focus()
}
}

private handleRandomizeColor = (): void => {
const {onSelect} = this.props
const {hex} = _.sample(colors)

this.setState({inputValue: hex})
onSelect(hex)
}

private get selectedColor(): JSX.Element {
const {inputValue} = this.state

return (
<div
className="color-picker--selected"
style={{backgroundColor: inputValue}}
/>
)
}
}
27 changes: 27 additions & 0 deletions ui/src/clockface/components/color_picker/ColorPickerSwatch.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Libraries
import React, {Component} from 'react'

interface Props {
name: string
hex: string
onClick: (hex: string) => void
}

export default class ColorPickerSwatch extends Component<Props> {
render() {
const {name, hex} = this.props
return (
<div
className="color-picker--swatch"
title={name}
onClick={this.handleClick}
>
<span style={{backgroundColor: hex}} />
</div>
)
}

private handleClick = (): void => {
this.props.onClick(this.props.hex)
}
}
Loading