Skip to content

Commit

Permalink
WRQ-30517: Create a slider type for webOS ColorPicker (part2) (#1661)
Browse files Browse the repository at this point in the history
* Fixed problem with knob size and added a version of HSL for ColorPickerSlider.

* Small fix

* Review fixes
  • Loading branch information
alexandrumorariu authored Aug 9, 2024
1 parent 716f51b commit 834dd8f
Show file tree
Hide file tree
Showing 4 changed files with 376 additions and 31 deletions.
3 changes: 2 additions & 1 deletion ColorPickerPOC/ColorPickerPOC.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import Skinnable from '../Skinnable';
import TabLayout, {Tab} from '../TabLayout';

import ColorPickerGrid from './ColorPickerGrid';
import ColorPickerSlider from './ColorPickerSlider';
import ColorPickerSlider, {ColorPickerSliderHSL} from './ColorPickerSlider'; // eslint-disable-line no-unused-vars
import ColorPickerSpectrum from './ColorPickerSpectrum';
import {generateOppositeColor} from './utils';

Expand Down Expand Up @@ -201,6 +201,7 @@ const ColorPickerPOCBase = ({color = '#eb4034', colors = [], css, onChangeColor,
<Tab style={{width: ri.scaleToRem(400)}} title={'Sliders'}>
<div className={componentsCss.colorPicker}>
<ColorPickerSlider selectedColor={selectedColor} selectedColorHandler={setSelectedColor} />
{/* <ColorPickerSliderHSL selectedColor={selectedColor} selectedColorHandler={setSelectedColor} />*/}
</div>
</Tab>
</TabLayout>
Expand Down
252 changes: 226 additions & 26 deletions ColorPickerPOC/ColorPickerSlider.js
Original file line number Diff line number Diff line change
@@ -1,90 +1,281 @@
import {Cell, Row} from '@enact/ui/Layout';
import PropTypes from 'prop-types';
import {useCallback} from 'react';
import {useCallback, useState} from 'react';

import Slider from '../Slider';

import {generateOppositeColor, hexToRGB, rgbObjectToHex} from './utils';
import {generateOppositeColor, hexToHSL, hexToRGB, hslToHex, hslToRGBString, rgbObjectToHex} from './utils';

import componentCss from './ColorPickerSlider.module.less';

const hueGradient = (saturation, lightness) => {
return `linear-gradient(to right,
hsla(0, ${saturation}%, ${lightness}%, 1),
hsla(10, ${saturation}%, ${lightness}%, 1),
hsla(20, ${saturation}%, ${lightness}%, 1),
hsla(30, ${saturation}%, ${lightness}%, 1),
hsla(40, ${saturation}%, ${lightness}%, 1),
hsla(50, ${saturation}%, ${lightness}%, 1),
hsla(60, ${saturation}%, ${lightness}%, 1),
hsla(70, ${saturation}%, ${lightness}%, 1),
hsla(80, ${saturation}%, ${lightness}%, 1),
hsla(90, ${saturation}%, ${lightness}%, 1),
hsla(100, ${saturation}%, ${lightness}%, 1),
hsla(110, ${saturation}%, ${lightness}%, 1),
hsla(120, ${saturation}%, ${lightness}%, 1),
hsla(130, ${saturation}%, ${lightness}%, 1),
hsla(140, ${saturation}%, ${lightness}%, 1),
hsla(150, ${saturation}%, ${lightness}%, 1),
hsla(160, ${saturation}%, ${lightness}%, 1),
hsla(170, ${saturation}%, ${lightness}%, 1),
hsla(180, ${saturation}%, ${lightness}%, 1),
hsla(190, ${saturation}%, ${lightness}%, 1),
hsla(200, ${saturation}%, ${lightness}%, 1),
hsla(210, ${saturation}%, ${lightness}%, 1),
hsla(220, ${saturation}%, ${lightness}%, 1),
hsla(230, ${saturation}%, ${lightness}%, 1),
hsla(240, ${saturation}%, ${lightness}%, 1),
hsla(250, ${saturation}%, ${lightness}%, 1),
hsla(260, ${saturation}%, ${lightness}%, 1),
hsla(270, ${saturation}%, ${lightness}%, 1),
hsla(280, ${saturation}%, ${lightness}%, 1),
hsla(290, ${saturation}%, ${lightness}%, 1),
hsla(300, ${saturation}%, ${lightness}%, 1),
hsla(310, ${saturation}%, ${lightness}%, 1),
hsla(320, ${saturation}%, ${lightness}%, 1),
hsla(330, ${saturation}%, ${lightness}%, 1),
hsla(340, ${saturation}%, ${lightness}%, 1),
hsla(350, ${saturation}%, ${lightness}%, 1),
hsla(360, ${saturation}%, ${lightness}%, 1))`;
};

const lightnessGradient = (hue, saturation) => {
return `linear-gradient(to right,
hsla(${hue}, ${saturation}%, 0%, 1),
hsla(${hue}, ${saturation}%, 20%, 1),
hsla(${hue}, ${saturation}%, 40%, 1),
hsla(${hue}, ${saturation}%, 60%, 1),
hsla(${hue}, ${saturation}%, 80%, 1),
hsla(${hue}, ${saturation}%, 100%, 1))`;
};

const ColorPickerSlider = ({selectedColor, selectedColorHandler, ...props}) => {
const {red, green, blue} = hexToRGB(selectedColor);
const [localRed, setLocalRed] = useState(red);
const [localGreen, setLocalGreen] = useState(green);
const [localBlue, setLocalBlue] = useState(blue);

const changeValueRed = useCallback((ev) => {
selectedColorHandler(rgbObjectToHex({red: ev.value, green, blue}));
}, [blue, green, selectedColorHandler]);
setLocalRed(ev.value);
}, []);

const changeValueGreen = useCallback((ev) => {
selectedColorHandler(rgbObjectToHex({red, green: ev.value, blue}));
}, [blue, red, selectedColorHandler]);
setLocalGreen(ev.value);
}, []);

const changeValueBlue = useCallback((ev) => {
selectedColorHandler(rgbObjectToHex({red, green, blue: ev.value}));
}, [green, red, selectedColorHandler]);
setLocalBlue(ev.value);
}, []);

const changeSelectedColor = useCallback(() => {
selectedColorHandler(rgbObjectToHex({red: localRed, green: localGreen, blue: localBlue}));
}, [localBlue, localGreen, localRed, selectedColorHandler]);

return (
<div {...props} className={componentCss.sliderContainer}>
<Cell>
<Cell className={componentCss.labelText}>Red</Cell>
<Row>
<Cell size="83%">
<Cell
className={componentCss.sliderCell}
size="80%"
style={{backgroundImage: `linear-gradient(to right, rgb(0,${localGreen},${localBlue}), rgb(255,${localGreen},${localBlue}))`}}
>
<Slider
className={componentCss.slider}
css={componentCss}
max={255}
min={0}
noFill
onBlur={changeSelectedColor}
onChange={changeValueRed}
onPointerUp={changeSelectedColor}
style={{
'--sand-slider-knob-border-color': generateOppositeColor(selectedColor),
backgroundImage: `linear-gradient(to right, rgb(0,${green},${blue}), rgb(255,${green},${blue}))`
'--sand-slider-knob-border-color': generateOppositeColor(rgbObjectToHex({red: localRed, green: localGreen, blue: localBlue})),
'--sand-focus-bg-color-rgb': `${localRed},${localGreen},${localBlue}`,
'--sand-progress-slider-color': rgbObjectToHex({red: localRed, green: localGreen, blue: localBlue})
}}
value={red}
value={localRed}
/>
</Cell>
<Cell
className={componentCss.outputText}
>{red}</Cell>
>{localRed}</Cell>
</Row>
</Cell>
<Cell className={componentCss.cellElement}>
<Cell className={componentCss.labelText}>Green</Cell>
<Row>
<Cell size="83%">
<Cell
className={componentCss.sliderCell}
size="80%"
style={{backgroundImage: `linear-gradient(to right, rgb(${localRed},0,${localBlue}), rgb(${localRed},255,${localBlue}))`}}
>
<Slider
className={componentCss.slider}
css={componentCss}
max={255}
min={0}
noFill
onBlur={changeSelectedColor}
onChange={changeValueGreen}
onPointerUp={changeSelectedColor}
style={{
'--sand-slider-knob-border-color': generateOppositeColor(selectedColor),
backgroundImage: `linear-gradient(to right, rgb(${red},0,${blue}), rgb(${red},255,${blue}))`
'--sand-slider-knob-border-color': generateOppositeColor(rgbObjectToHex({red: localRed, green: localGreen, blue: localBlue})),
'--sand-focus-bg-color-rgb': `${localRed},${localGreen},${localBlue}`,
'--sand-progress-slider-color': rgbObjectToHex({red: localRed, green: localGreen, blue: localBlue})
}}
value={green}
value={localGreen}
/>
</Cell>
<Cell className={componentCss.outputText}>{green}</Cell>
<Cell className={componentCss.outputText}>{localGreen}</Cell>
</Row>
</Cell>
<Cell className={componentCss.cellElement}>
<Cell className={componentCss.labelText}>Blue</Cell>
<Row>
<Cell size="83%">
<Cell
className={componentCss.sliderCell}
size="80%"
style={{backgroundImage: `linear-gradient(to right, rgb(${localRed},${localGreen},0), rgb(${localRed},${localGreen},255))`}}
>
<Slider
className={componentCss.slider}
css={componentCss}
max={255}
min={0}
noFill
onBlur={changeSelectedColor}
onChange={changeValueBlue}
onPointerUp={changeSelectedColor}
style={{
'--sand-slider-knob-border-color': generateOppositeColor(selectedColor),
backgroundImage: `linear-gradient(to right, rgb(${red},${green},0), rgb(${red},${green},255))`
'--sand-slider-knob-border-color': generateOppositeColor(rgbObjectToHex({red: localRed, green: localGreen, blue: localBlue})),
'--sand-focus-bg-color-rgb': `${localRed},${localGreen},${localBlue}`,
'--sand-progress-slider-color': rgbObjectToHex({red: localRed, green: localGreen, blue: localBlue})
}}
value={blue}
value={localBlue}
/>
</Cell>
<Cell className={componentCss.outputText}>{blue}</Cell>
<Cell className={componentCss.outputText}>{localBlue}</Cell>
</Row>
</Cell>
</div>
);
};

const ColorPickerSliderHSL = ({selectedColor, selectedColorHandler, ...props}) => {
const {h, s, l} = hexToHSL(selectedColor);

const [hue, setHue] = useState(h);
const [saturation, setSaturation] = useState(s);
const [lightness, setLightness] = useState(l);

const changeValueHue = useCallback((ev) => {
setHue(ev.value);
}, []);

const changeValueSaturation = useCallback((ev) => {
setSaturation(ev.value);
}, []);

const changeValueLightness = useCallback((ev) => {
setLightness(ev.value);
}, []);

const changeSelectedColor = useCallback(() => {
selectedColorHandler(hslToHex({h: hue, s: saturation, l: lightness}));
}, [hue, saturation, lightness, selectedColorHandler]);

return (
<div {...props} className={componentCss.sliderContainer}>
<Cell>
<Cell className={componentCss.labelText}>Hue</Cell>
<Row>
<Cell
className={componentCss.sliderCell}
size="80%"
style={{backgroundImage: hueGradient(saturation, lightness)}}
>
<Slider
css={componentCss}
max={359}
min={0}
noFill
onBlur={changeSelectedColor}
onChange={changeValueHue}
onPointerUp={changeSelectedColor}
style={{
'--sand-slider-knob-border-color': generateOppositeColor(hslToHex({h: hue, s: saturation, l: lightness})),
'--sand-focus-bg-color-rgb': hslToRGBString({h: hue, s: saturation, l: lightness}),
'--sand-progress-slider-color': hslToHex({h: hue, s: saturation, l: lightness})
}}
value={hue}
/>
</Cell>
<Cell
className={componentCss.outputText}
>{hue}</Cell>
</Row>
</Cell>
<Cell className={componentCss.cellElement}>
<Cell className={componentCss.labelText}>Saturation</Cell>
<Row>
<Cell
className={componentCss.sliderCell}
size="80%"
style={{backgroundImage: `linear-gradient(to right, hsl(${hue}, 0%, ${lightness}%), hsl(${hue}, 100%, ${lightness}%))`}}
>
<Slider
css={componentCss}
max={100}
min={0}
noFill
onBlur={changeSelectedColor}
onChange={changeValueSaturation}
onPointerUp={changeSelectedColor}
style={{
'--sand-slider-knob-border-color': generateOppositeColor(hslToHex({h: hue, s: saturation, l: lightness})),
'--sand-focus-bg-color-rgb': hslToRGBString({h: hue, s: saturation, l: lightness}),
'--sand-progress-slider-color': hslToHex({h: hue, s: saturation, l: lightness})
}}
value={saturation}
/>
</Cell>
<Cell className={componentCss.outputTextPercent}>{saturation}%</Cell>
</Row>
</Cell>
<Cell className={componentCss.cellElement}>
<Cell className={componentCss.labelText}>Lightness</Cell>
<Row>
<Cell
className={componentCss.sliderCell}
size="80%"
style={{backgroundImage: lightnessGradient(hue, saturation)}}
>
<Slider
css={componentCss}
max={100}
min={0}
noFill
onBlur={changeSelectedColor}
onChange={changeValueLightness}
onPointerUp={changeSelectedColor}
style={{
'--sand-slider-knob-border-color': generateOppositeColor(hslToHex({h: hue, s: saturation, l: lightness})),
'--sand-focus-bg-color-rgb': hslToRGBString({h: hue, s: saturation, l: lightness}),
'--sand-progress-slider-color': hslToHex({h: hue, s: saturation, l: lightness})
}}
value={lightness}
/>
</Cell>
<Cell className={componentCss.outputTextPercent}>{lightness}%</Cell>
</Row>
</Cell>
</div>
Expand All @@ -96,4 +287,13 @@ ColorPickerSlider.propTypes = {
selectedColorHandler: PropTypes.func
};

ColorPickerSliderHSL.propTypes = {
selectedColor: PropTypes.string,
selectedColorHandler: PropTypes.func
};

export {
ColorPickerSlider,
ColorPickerSliderHSL
};
export default ColorPickerSlider;
31 changes: 27 additions & 4 deletions ColorPickerPOC/ColorPickerSlider.module.less
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

.labelText {
font-size: 42px;
margin-bottom: 12px;
}

.outputText {
Expand All @@ -13,16 +14,38 @@
color: #444444;
display: grid;
justify-content: end;
padding-right: 24px;
margin-left: 30px;
padding-right: 21px;
}

.outputTextPercent {
align-content: center;
background-color: #eeeeee;
border-radius: 12px;
color: #444444;
display: grid;
justify-content: end;
margin-left: 30px;
}

.slider {
--sand-focus-bg-color-rgb: transparent;
--sand-progress-bg-color-rgb: transparent;
--sand-progress-slider-color: transparent;
border-radius: 99px;
height: 42px;
margin-left: 0;
margin-left: 18px;
margin-right: 18px;

.knob {
&::before {
border-radius: 99px;
height: 120px;
width: 120px;
}
}
}

.sliderCell {
border-radius: 99px;
}

.sliderContainer {
Expand Down
Loading

0 comments on commit 834dd8f

Please sign in to comment.