-
-
Notifications
You must be signed in to change notification settings - Fork 112
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: implement ColorPicker component
- Loading branch information
Showing
33 changed files
with
1,042 additions
and
33 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import React from 'react'; | ||
import PropTypes from 'prop-types'; | ||
import { StyledAlphaSlider } from './styled'; | ||
import { recomposeColor } from '../../styles/helpers/color'; | ||
import { getAlpha } from './helpers'; | ||
|
||
export default function Alpha(props) { | ||
const { rgbaColor, onChange } = props; | ||
const a = getAlpha(rgbaColor); | ||
|
||
const handleChange = event => { | ||
const alpha = parseInt(event.target.value, 10); | ||
rgbaColor.values[3] = alpha / 100; | ||
onChange(recomposeColor(rgbaColor)); | ||
}; | ||
|
||
return <StyledAlphaSlider value={a} min={0} max={100} onChange={handleChange} />; | ||
} | ||
|
||
Alpha.propTypes = { | ||
rgbaColor: PropTypes.object, | ||
onChange: PropTypes.func, | ||
}; | ||
|
||
Alpha.defaultProps = { | ||
rgbaColor: '', | ||
onChange: () => {}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import React from 'react'; | ||
import PropTypes from 'prop-types'; | ||
import { StyledDefaulColor, StyledColorsContainer } from './styled'; | ||
import { colorToRgba, isValidColor } from '../../styles/helpers/color'; | ||
|
||
const Colors = React.memo(props => { | ||
const { colors, onChange } = props; | ||
|
||
const handleChange = color => { | ||
const rgbaColor = colorToRgba(color); | ||
if (isValidColor(rgbaColor)) { | ||
onChange(rgbaColor); | ||
} | ||
}; | ||
const ListColors = () => | ||
colors.map(color => ( | ||
<StyledDefaulColor key={color} $color={color} onClick={() => handleChange(color)} /> | ||
)); | ||
|
||
return ( | ||
<StyledColorsContainer> | ||
<ListColors /> | ||
</StyledColorsContainer> | ||
); | ||
}); | ||
|
||
Colors.propTypes = { | ||
colors: PropTypes.array, | ||
onChange: PropTypes.func, | ||
}; | ||
|
||
Colors.defaultProps = { | ||
colors: [], | ||
onChange: () => {}, | ||
}; | ||
|
||
export default Colors; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export default function getAlpha(rgbaColor) { | ||
return Math.round(rgbaColor.values[3] * 100); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export { default as getAlpha } from './getAlpha'; | ||
export { default as normalazeColor } from './normalazeColor'; | ||
export { default as isAchromatic } from './isAchromatic'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
export default function isAchromatic(color) { | ||
const [r, g, b] = color.values; | ||
|
||
const max = Math.max(r, g, b); | ||
const min = Math.min(r, g, b); | ||
return max === min; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import { colorToRgba } from '../../../styles/helpers/color'; | ||
|
||
export default function normalazeColor(color) { | ||
const rgbaColor = colorToRgba(color); | ||
return rgbaColor !== '' ? rgbaColor : 'rgba(0, 0, 0, 1)'; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import React, { useState, useEffect } from 'react'; | ||
import PropTypes from 'prop-types'; | ||
import Input from '../Input'; | ||
import { StyledHexColorIcon } from './styled'; | ||
import { hexToRgba } from '../../styles/helpers/color'; | ||
|
||
export default function HexColor(props) { | ||
const { hexColor, onChange } = props; | ||
const [color, setColor] = useState(); | ||
const [isFocused, setIsFocused] = useState(false); | ||
|
||
useEffect(() => { | ||
if (!isFocused) { | ||
setColor(hexColor); | ||
} | ||
}, [hexColor, isFocused]); | ||
|
||
const handleChange = event => { | ||
const value = event.target.value; | ||
setColor(value); | ||
const hex = `#${value}`; | ||
const rgbaColor = hexToRgba(hex); | ||
if (rgbaColor !== '') { | ||
onChange(rgbaColor); | ||
} | ||
}; | ||
|
||
const handleBlur = event => { | ||
setIsFocused(false); | ||
const value = event.target.value; | ||
const hex = `#${value}`; | ||
const rgbaColor = hexToRgba(hex); | ||
if (rgbaColor !== '') { | ||
onChange(rgbaColor); | ||
} | ||
}; | ||
|
||
return ( | ||
<Input | ||
value={color} | ||
bottomHelpText="HEX" | ||
onChange={handleChange} | ||
onFocus={() => setIsFocused(true)} | ||
onBlur={handleBlur} | ||
icon={<StyledHexColorIcon>#</StyledHexColorIcon>} | ||
/> | ||
); | ||
} | ||
|
||
HexColor.propTypes = { | ||
hexColor: PropTypes.string, | ||
onChange: PropTypes.func, | ||
}; | ||
|
||
HexColor.defaultProps = { | ||
hexColor: '', | ||
onChange: () => {}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import React from 'react'; | ||
import PropTypes from 'prop-types'; | ||
import { StyledHueSlider } from './styled'; | ||
import { hsvToRgb, rgbToRgba } from '../../styles/helpers/color'; | ||
|
||
export default function Hue(props) { | ||
const { hsvColor, hue, setHue, alpha, onChange } = props; | ||
|
||
const handleChange = event => { | ||
const value = parseInt(event.target.value, 10); | ||
setHue(value); | ||
hsvColor.values[0] = value; | ||
const rgbColor = hsvToRgb(hsvColor); | ||
const rgbaColor = rgbToRgba(rgbColor, alpha); | ||
onChange(rgbaColor); | ||
}; | ||
|
||
return <StyledHueSlider value={hue} min={0} max={359} onChange={handleChange} />; | ||
} | ||
|
||
Hue.propTypes = { | ||
hsvColor: PropTypes.object, | ||
alpha: PropTypes.number, | ||
hue: PropTypes.number, | ||
setHue: PropTypes.func, | ||
onChange: PropTypes.func, | ||
}; | ||
|
||
Hue.defaultProps = { | ||
hsvColor: undefined, | ||
alpha: undefined, | ||
hue: undefined, | ||
setHue: () => {}, | ||
onChange: () => {}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import { BaseProps } from '../types'; | ||
|
||
export interface ColorPickerProps extends BaseProps { | ||
id?: string; | ||
color?: string; | ||
onChange?: (value: string) => void; | ||
} | ||
|
||
export default function(props: ColorPickerProps): JSX.Element | null; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
import React, { useState, useEffect } from 'react'; | ||
import PropTypes from 'prop-types'; | ||
import RenderIf from '../RenderIf'; | ||
import Saturation from './saturation'; | ||
import RgbaColor from './rgbaColor'; | ||
import HexColor from './hexColor'; | ||
import Alpha from './alpha'; | ||
import Hue from './hue'; | ||
import Colors from './colors'; | ||
import { | ||
StyledContainer, | ||
StyledPreview, | ||
StyledFlexContainer, | ||
StyledLabel, | ||
StyledSaturationContainer, | ||
StyledSlidersContainer, | ||
StyledHexColorContainer, | ||
StyledRgbaColorContainer, | ||
} from './styled'; | ||
import { rgbaToHex, rgbToHsv, decomposeColor } from '../../styles/helpers/color'; | ||
import { normalazeColor, isAchromatic } from './helpers'; | ||
|
||
export default function ColorPicker(props) { | ||
const { id, color: colorProp, colors, label, labelColors, onChange, className, style } = props; | ||
const [hue, setHue] = useState(0); | ||
|
||
const color = normalazeColor(colorProp); | ||
const rgbaColor = decomposeColor(color); | ||
const hexColor = rgbaToHex(rgbaColor); | ||
const hsvColor = decomposeColor(rgbToHsv(color)); | ||
const alpha = rgbaColor.values[3]; | ||
|
||
useEffect(() => { | ||
if (!isAchromatic(rgbaColor)) { | ||
setHue(hsvColor.values[0]); | ||
} | ||
}, [hsvColor.values, rgbaColor]); | ||
|
||
const hasColors = Array.isArray(colors) && colors.length > 0; | ||
|
||
return ( | ||
<StyledContainer className={className} style={style} id={id}> | ||
<StyledLabel>{label}</StyledLabel> | ||
<StyledSaturationContainer> | ||
<Saturation rgbaColor={rgbaColor} hsvColor={hsvColor} onChange={onChange} /> | ||
</StyledSaturationContainer> | ||
<StyledFlexContainer> | ||
<StyledSlidersContainer> | ||
<Hue | ||
hsvColor={hsvColor} | ||
alpha={alpha} | ||
hue={hue} | ||
setHue={setHue} | ||
onChange={onChange} | ||
/> | ||
<Alpha rgbaColor={rgbaColor} onChange={onChange} /> | ||
</StyledSlidersContainer> | ||
<StyledPreview $color={color} /> | ||
</StyledFlexContainer> | ||
|
||
<StyledFlexContainer> | ||
<StyledHexColorContainer> | ||
<HexColor hexColor={hexColor} onChange={onChange} /> | ||
</StyledHexColorContainer> | ||
<StyledRgbaColorContainer> | ||
<RgbaColor rgbaColor={rgbaColor} onChange={onChange} /> | ||
</StyledRgbaColorContainer> | ||
</StyledFlexContainer> | ||
<RenderIf isTrue={hasColors}> | ||
<StyledLabel>{labelColors}</StyledLabel> | ||
<Colors colors={colors} onChange={onChange} /> | ||
</RenderIf> | ||
</StyledContainer> | ||
); | ||
} | ||
|
||
ColorPicker.propTypes = { | ||
/** The id of the outer element. */ | ||
id: PropTypes.string, | ||
/** Specifies the color of ColorPicker. */ | ||
color: PropTypes.string, | ||
/** Specifies the default colors to choice. */ | ||
colors: PropTypes.array, | ||
/** Text label for the input. */ | ||
label: PropTypes.oneOfType([PropTypes.string, PropTypes.node]), | ||
/** Text label for the default colors. */ | ||
labelColors: PropTypes.oneOfType([PropTypes.string, PropTypes.node]), | ||
/** The action triggered when the value changes. */ | ||
onChange: PropTypes.func, | ||
/** A CSS class for the outer element, in addition to the component's base classes. */ | ||
className: PropTypes.string, | ||
/** An object with custom style applied to the outer element. */ | ||
style: PropTypes.object, | ||
}; | ||
|
||
ColorPicker.defaultProps = { | ||
id: undefined, | ||
color: '', | ||
colors: [], | ||
label: 'Color Picker', | ||
labelColors: 'Defualt', | ||
onChange: () => {}, | ||
className: undefined, | ||
style: undefined, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
##### ColorPicker info | ||
|
||
```js | ||
import React, { useState } from 'react'; | ||
import styled from 'styled-components' | ||
import { ColorPicker, Card } from 'react-rainbow-components'; | ||
|
||
const Container = styled.div` | ||
display: flex; | ||
justify-content: center; | ||
align-items: center; | ||
padding: 50px; | ||
`; | ||
|
||
const StyledCard = styled(Card)` | ||
width: 26rem; | ||
height: 27rem; | ||
`; | ||
|
||
const ColorPickerExample = () => { | ||
const [color, setColor] = useState('#ff0'); | ||
const handleChange = value => { | ||
// console.log(value); | ||
setColor(value); | ||
} | ||
return <ColorPicker color={color} onChange={handleChange}/>; | ||
} | ||
|
||
<Container> | ||
<StyledCard> | ||
<ColorPickerExample /> | ||
</StyledCard> | ||
</Container> | ||
``` | ||
|
||
##### ColorPicker with default colors | ||
|
||
```js | ||
import React, {useState, useCallback} from 'react'; | ||
import styled from 'styled-components' | ||
import { ColorPicker, Card } from 'react-rainbow-components'; | ||
|
||
const colors = [ | ||
'#e3aaec', | ||
'#c3dbf7', | ||
'#9fd6ff', | ||
'#9de7da', | ||
'#9ef0bf', | ||
'#fef199', | ||
'#fdd499', | ||
'#d174e0', | ||
'#86baf3', | ||
'#5ebbff', | ||
'#42d8be', | ||
'#3be282', | ||
'#ffe654', | ||
'#ffb758', | ||
'#bd35bd', | ||
'#5779c1', | ||
'#4A90E2', | ||
'#06aea9', | ||
'#3dba4c', | ||
'#f5bc24', | ||
'#f99222', | ||
'#570e8c', | ||
'#021970', | ||
'#0b2399', | ||
'#0d7477', | ||
'#0a6b50', | ||
'#b67e12', | ||
'#b75d0c', | ||
]; | ||
|
||
const Container = styled.div` | ||
display: flex; | ||
justify-content: center; | ||
align-items: center; | ||
padding: 50px; | ||
`; | ||
|
||
const StyledCard = styled(Card)` | ||
width: 26rem; | ||
height: 40rem; | ||
`; | ||
|
||
const ColorPickerExample = () => { | ||
const [color, setColor] = useState('#ff0'); | ||
|
||
return <ColorPicker color={color} onChange={setColor} colors={colors} />; | ||
} | ||
|
||
<Container> | ||
<StyledCard> | ||
<ColorPickerExample /> | ||
</StyledCard> | ||
</Container> | ||
``` |
Oops, something went wrong.