Picker with pluggable colour modes

by mcsf

HTML

<div id="app"></div>

CSS

-webkit-background-origin: ;
background-origin: ;dy {
  background: #20262E;
  padding: 20px;
  font-family: Helvetica;
}

#app {
  background: #fff;
  border-radius: 4px;
  padding: 20px;
  transition: all 0.2s;
}

li {
  margin: 8px 0;
}

h2 {
  font-weight: bold;
  margin-bottom: 15px;
}

.done {
  color: rgba(0, 0, 0, 0.3);
  text-decoration: line-through;
}

input {
  margin-right: 5px;
}

React

// Pluggable modes. Should easily support modes with a different amount of fields, e.g. rgba.
const COLOR_MODES = [
  {
  	fields: ['hex'],
    encode: x => [x],
    decode: ([x]) => x,
    fieldType: 'text',
  },
	{
  	fields: ['r', 'g', 'b'],
    encode: hex2rgb,
    decode: rgb2hex,
	},
  {
  	fields: ['h', 's', 'l'],
    encode: hex2hsl,
    decode: hsl2hex,
	},
]

const HEX = 0
const RGB = 1
const HSL = 2

function convert(src, dst, values) {
	if (src === dst) return values
	const srcMode = COLOR_MODES[src]
  const dstMode = COLOR_MODES[dst]
  return dstMode.encode(srcMode.decode(values))
}

class Picker extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
			mode: HEX,
			values: ['#000000'],
    }
  }
  
  setMode = (mode) => {
  	this.setState({mode})
  }
  
  setValues = (values) => {
  	this.setState({values})
  }
  
	switchMode = () => {
		const mode = (this.state.mode + 1) % COLOR_MODES.length
    const values = convert(
    	this.state.mode,
      mode,
      this.state.values
		)
		this.setState({mode, values})
  }
 
  render() {
  	const color = COLOR_MODES[this.state.mode]
    	.decode(this.state.values)

    return (
      <div>
        <Color
          color={color} />
        <HueSlider
          mode={this.state.mode}
          values={this.state.values}
          setValues={this.setValues} />
        <PickerForm
          values={this.state.values}
          mode={this.state.mode}
          setValues={this.setValues} />
        <button onClick={this.switchMode}>Change mode</button>
      </div>
    )
  }
}

function Color({color, onColorChange}) {
	const style = { backgroundColor: color }
	return <div style={style}>&nbsp;</div>
}

function HueSlider({mode, setMode, values, setValues}) {
	let hslValues = convert(mode, HSL, values)
  
	function onHueChange(event) {
  	const hue = event.target.value
    const newHslValues = [...hslValues]
    newHslValues[0] = hue
		let values = convert(HSL, mode, newHslValues)   ...