Skip to content

Commit f2622cc

Browse files
ColorSliderGroup - refactor (#3009)
* GradientSliderGroup - move ColorSlider, SliderGroup to main component. GradientSlider - change to useContext instead of asSliderGroupChild, fix typo and change useEffect to useDidUpdate. * cleanup * gradient cleanup * SliderGroup - fix updates + example * GradientSlider - remove state * remove console * Slider - fix flag note * remove redundant forwardRef * fix screen * remove color prop passed to GradientSlider - works with context * GradientSlider - fix context usage * fix group sliders jump * fix screen * fix custom thumb style * thumb bg dependency * replace asBaseComponent with useThemeProps --------- Co-authored-by: Ethan Sharabi <[email protected]>
1 parent 8a7a304 commit f2622cc

File tree

8 files changed

+93
-186
lines changed

8 files changed

+93
-186
lines changed

demo/src/screens/incubatorScreens/IncubatorSliderScreen.tsx

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const MAX = 350;
1010
const INITIAL_MIN = 30;
1111
const INITIAL_MAX = 270;
1212
const COLOR = Colors.blue30;
13+
const GROUP_COLOR = Colors.yellow30;
1314

1415
const IncubatorSliderScreen = () => {
1516
const [disableRTL, setDisableRTL] = useState<boolean>(false);
@@ -21,7 +22,7 @@ const IncubatorSliderScreen = () => {
2122
const [sliderMaxValue, setSliderMaxValue] = useState(INITIAL_MAX);
2223

2324
const [color, setColor] = useState(COLOR);
24-
const [groupColor, setGroupColor] = useState(Colors.yellow30);
25+
const [groupColor, setGroupColor] = useState(GROUP_COLOR);
2526
const [alpha, setAlpha] = useState(1);
2627

2728
const slider = useRef<Incubator.SliderRef>(null);
@@ -53,8 +54,11 @@ const IncubatorSliderScreen = () => {
5354
setSliderMinValue(value.min);
5455
}, []);
5556

56-
const onGradientValueChange = useCallback((value: string, alpha: number) => {
57+
const onGradientValueChange = useCallback((value: string, _: number) => {
5758
setColor(value);
59+
}, []);
60+
61+
const onGradientAlphaValueChange = useCallback((_: string, alpha: number) => {
5862
setAlpha(alpha);
5963
}, []);
6064

@@ -201,7 +205,7 @@ const IncubatorSliderScreen = () => {
201205
<GradientSlider
202206
color={color}
203207
containerStyle={styles.gradientSliderContainer}
204-
onValueChange={onGradientValueChange}
208+
onValueChange={onGradientAlphaValueChange}
205209
// @ts-expect-error
206210
ref={this.gradientSlider}
207211
migrate
@@ -216,7 +220,7 @@ const IncubatorSliderScreen = () => {
216220
</Text>
217221
<GradientSlider
218222
type={GradientSlider.types.HUE}
219-
color={COLOR}
223+
color={color}
220224
containerStyle={styles.gradientSliderContainer}
221225
onValueChange={onGradientValueChange}
222226
migrate
@@ -236,7 +240,7 @@ const IncubatorSliderScreen = () => {
236240
Color Slider Group
237241
</Text>
238242
<ColorSliderGroup
239-
initialColor={groupColor}
243+
initialColor={GROUP_COLOR}
240244
sliderContainerStyle={styles.slider}
241245
containerStyle={[styles.group, {borderWidth: 12, borderColor: groupColor}]}
242246
showLabels
@@ -283,6 +287,7 @@ const styles = StyleSheet.create({
283287
customThumb: {
284288
width: 14,
285289
height: 14,
290+
borderWidth: 0.5,
286291
borderRadius: 7,
287292
backgroundColor: Colors.black,
288293
borderColor: Colors.black

src/components/slider/ColorSlider.tsx

Lines changed: 0 additions & 43 deletions
This file was deleted.

src/components/slider/ColorSliderGroup.tsx

Lines changed: 50 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import _ from 'lodash';
2-
import React, {useState, useEffect, useCallback, useMemo} from 'react';
2+
import React, {useState, useCallback, useMemo} from 'react';
33
import {Colors} from '../../style';
44
import {useThemeProps} from '../../hooks';
5+
import View from '../view';
6+
import Text from '../text';
7+
import {ColorSliderGroupProps, HSLA, GradientSliderTypes} from './types';
8+
import SliderContext from './SliderContext';
59
import GradientSlider from './GradientSlider';
6-
import SliderGroup from './context/SliderGroup';
7-
import ColorSlider from './ColorSlider';
8-
import {ColorSliderGroupProps, HSLA} from './types';
910

1011
/**
1112
* @description: A Gradient Slider component
@@ -14,27 +15,58 @@ import {ColorSliderGroupProps, HSLA} from './types';
1415
*/
1516
const ColorSliderGroup = <T extends string | HSLA = string>(props: ColorSliderGroupProps<T>) => {
1617
const themeProps = useThemeProps(props, 'ColorSliderGroup');
17-
const {initialColor, containerStyle, onValueChange, ...others} = themeProps;
18+
const {
19+
initialColor,
20+
onValueChange,
21+
containerStyle,
22+
sliderContainerStyle,
23+
showLabels,
24+
labels = {hue: 'Hue', lightness: 'Lightness', saturation: 'Saturation', default: ''},
25+
labelsStyle,
26+
accessible,
27+
migrate
28+
} = themeProps;
29+
1830
const _initialColor = useMemo<HSLA>(() => {
1931
return _.isString(initialColor) ? Colors.getHSL(initialColor) : initialColor;
2032
}, [initialColor]);
21-
const [color, setColor] = useState<HSLA>(_initialColor);
2233

23-
useEffect(() => {
24-
setColor(_initialColor);
25-
}, [_initialColor]);
34+
const [value, setValue] = useState(_initialColor);
2635

27-
const _onValueChange = useCallback((value: HSLA) => {
28-
const _value = _.isString(initialColor) ? Colors.getHexString(value) : value;
29-
onValueChange?.(_value as T);
30-
}, [onValueChange, initialColor]);
36+
const _setValue = useCallback((value: HSLA) => {
37+
setValue(value);
38+
const newValue = _.isString(initialColor) ? Colors.getHexString(value) : value;
39+
onValueChange?.(newValue as T);
40+
}, [initialColor, onValueChange]);
41+
42+
const contextProviderValue = useMemo(() => ({value, setValue: _setValue}), [value, _setValue]);
43+
44+
const renderSlider = (type: GradientSliderTypes) => {
45+
return (
46+
<>
47+
{showLabels && labels && (
48+
<Text recorderTag={'unmask'} $textNeutral text80 style={labelsStyle} accessible={accessible}>
49+
{labels[type]}
50+
</Text>
51+
)}
52+
<GradientSlider
53+
type={type}
54+
containerStyle={sliderContainerStyle}
55+
accessible={accessible}
56+
migrate={migrate}
57+
/>
58+
</>
59+
);
60+
};
3161

3262
return (
33-
<SliderGroup style={containerStyle} color={color} onValueChange={_onValueChange}>
34-
<ColorSlider type={GradientSlider.types.HUE} initialColor={_initialColor} {...others}/>
35-
<ColorSlider type={GradientSlider.types.SATURATION} initialColor={_initialColor} {...others}/>
36-
<ColorSlider type={GradientSlider.types.LIGHTNESS} initialColor={_initialColor} {...others}/>
37-
</SliderGroup>
63+
<View style={containerStyle}>
64+
<SliderContext.Provider value={contextProviderValue}>
65+
{renderSlider(GradientSlider.types.HUE)}
66+
{renderSlider(GradientSlider.types.SATURATION)}
67+
{renderSlider(GradientSlider.types.LIGHTNESS)}
68+
</SliderContext.Provider>
69+
</View>
3870
);
3971
};
4072

src/components/slider/GradientSlider.tsx

Lines changed: 26 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,46 @@
11
import _ from 'lodash';
2-
import React, {useCallback, useEffect, useState, useMemo} from 'react';
3-
import {asBaseComponent, forwardRef, ForwardRefInjectedProps} from '../../commons/new';
2+
import React, {useCallback, useMemo, useContext} from 'react';
3+
import {forwardRef, ForwardRefInjectedProps} from '../../commons/new';
44
import {ComponentStatics} from '../../typings/common';
5+
import {useThemeProps} from '../../hooks';
56
import {Colors} from '../../style';
67
import {Slider as NewSlider} from '../../incubator';
78
import Gradient from '../gradient';
89
import {GradientSliderProps, GradientSliderTypes, HSLA} from './types';
910
import Slider from './index';
10-
import {SliderContextProps} from './context/SliderContext';
11-
import asSliderGroupChild from './context/asSliderGroupChild';
11+
import SliderContext from './SliderContext';
1212

13-
type GradientSliderComponentProps<T> = {
14-
sliderContext: SliderContextProps;
15-
} & GradientSliderProps<T>;
16-
17-
type Props<T> = GradientSliderComponentProps<T> & ForwardRefInjectedProps;
13+
type Props<T> = GradientSliderProps<T> & ForwardRefInjectedProps;
1814

1915
/**
2016
* @description: A Gradient Slider component
2117
* @example: https://github.com/wix/react-native-ui-lib/blob/master/demo/src/screens/componentScreens/SliderScreen.tsx
2218
* @gif: https://github.com/wix/react-native-ui-lib/blob/master/demo/showcase/GradientSlider/GradientSlider.gif?raw=true
2319
*/
2420
const GradientSlider = <T extends string | HSLA = string>(props: Props<T>) => {
21+
const themeProps = useThemeProps(props, 'GradientSlider');
2522
const {
2623
type = GradientSliderTypes.DEFAULT,
2724
gradientSteps = 120,
28-
color: propsColors = Colors.$backgroundPrimaryHeavy,
29-
sliderContext,
30-
onValueChange: _onValueChange,
25+
color,
26+
onValueChange,
3127
migrate,
3228
containerStyle,
3329
disabled,
3430
accessible,
3531
forwardedRef,
3632
...others
37-
} = props;
33+
} = themeProps;
34+
const sliderContext = useContext(SliderContext);
35+
const defaultColor = Colors.getHSL(Colors.$backgroundPrimaryHeavy);
3836

39-
const initialColor = useMemo((): HSLA => {
40-
return _.isString(propsColors) ? Colors.getHSL(propsColors) : propsColors;
41-
}, [propsColors]);
42-
const [color, setColor] = useState(initialColor);
43-
44-
useEffect(() => {
45-
setColor(initialColor);
46-
}, [initialColor]);
37+
const initialColor = useMemo((): HSLA | undefined => {
38+
return _.isString(color) ? Colors.getHSL(color) : color;
39+
}, [color]);
4740

4841
const getColor = useCallback(() => {
49-
return color || sliderContext.value;
50-
}, [color, sliderContext.value]);
42+
return initialColor || sliderContext.value || defaultColor;
43+
}, [initialColor, sliderContext.value, defaultColor]);
5144

5245
const hueColor = useMemo(() => {
5346
const color = getColor();
@@ -75,26 +68,19 @@ const GradientSlider = <T extends string | HSLA = string>(props: Props<T>) => {
7568
return <Gradient type={Gradient.types.SATURATION} color={hueColor} numberOfSteps={gradientSteps}/>;
7669
}, [hueColor, gradientSteps]);
7770

78-
const onValueChange = useCallback((value: string, alpha: number) => {
79-
// alpha returns for type.DEFAULT
80-
_onValueChange?.(value, alpha);
81-
},
82-
[_onValueChange]);
83-
8471
const updateColor = useCallback((color: HSLA) => {
8572
if (!_.isEmpty(sliderContext)) {
8673
sliderContext.setValue?.(color);
8774
} else {
88-
setColor(color);
89-
const hex = Colors.getHexString(color);
90-
onValueChange(hex, color.a);
75+
const hex = Colors.getHexString(color); // alpha returns for type.DEFAULT
76+
onValueChange?.(hex, color.a);
9177
}
9278
},
9379
[sliderContext, onValueChange]);
9480

9581
const reset = useCallback(() => {
96-
updateColor(initialColor);
97-
}, [initialColor, updateColor]);
82+
updateColor(initialColor || defaultColor);
83+
}, [initialColor, updateColor, defaultColor]);
9884

9985
const updateAlpha = useCallback((a: number) => {
10086
const color = getColor();
@@ -122,25 +108,26 @@ const GradientSlider = <T extends string | HSLA = string>(props: Props<T>) => {
122108

123109
let step = 0.01;
124110
let maximumValue = 1;
125-
let value = color.a;
111+
const initialValue = useMemo(() => getColor(), []);
112+
let value = initialValue.a;
126113
let renderTrack = renderDefaultGradient;
127114
let sliderOnValueChange = updateAlpha;
128115

129116
switch (type) {
130117
case GradientSliderTypes.HUE:
131118
step = 1;
132119
maximumValue = 359;
133-
value = initialColor.h;
120+
value = initialValue.h;
134121
renderTrack = renderHueGradient;
135122
sliderOnValueChange = updateHue;
136123
break;
137124
case GradientSliderTypes.LIGHTNESS:
138-
value = initialColor.l;
125+
value = initialValue.l;
139126
renderTrack = renderLightnessGradient;
140127
sliderOnValueChange = updateLightness;
141128
break;
142129
case GradientSliderTypes.SATURATION:
143-
value = initialColor.s;
130+
value = initialValue.s;
144131
renderTrack = renderSaturationGradient;
145132
sliderOnValueChange = updateSaturation;
146133
break;
@@ -170,8 +157,4 @@ const GradientSlider = <T extends string | HSLA = string>(props: Props<T>) => {
170157

171158
GradientSlider.displayName = 'GradientSlider';
172159
GradientSlider.types = GradientSliderTypes;
173-
// @ts-expect-error
174-
export default asBaseComponent<GradientSliderProps, ComponentStatics<typeof GradientSlider>>(
175-
// @ts-expect-error
176-
forwardRef(asSliderGroupChild(forwardRef(GradientSlider)))
177-
);
160+
export default forwardRef<GradientSliderProps<string | HSLA>, ComponentStatics<typeof GradientSlider>>(GradientSlider);
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import React from 'react';
2-
import {HSLA} from '../types';
2+
import {HSLA} from './types';
33

4-
export interface SliderContextProps {
4+
export interface SliderContextType {
55
value?: HSLA;
66
setValue?: (value: HSLA) => void;
77
}
88

9-
const SliderContext: React.Context<SliderContextProps> = React.createContext({});
9+
const SliderContext: React.Context<SliderContextType> = React.createContext({});
1010
SliderContext.displayName = 'IGNORE';
1111
export default SliderContext;

src/components/slider/context/SliderGroup.tsx

Lines changed: 0 additions & 34 deletions
This file was deleted.

0 commit comments

Comments
 (0)