Skip to content

Slider - adding 'migrate' prop to allow using Incubator.Silder #2592

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

Merged
merged 12 commits into from
May 16, 2023
Merged
9 changes: 8 additions & 1 deletion demo/src/screens/componentScreens/SliderScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,13 @@ export default class SliderScreen extends Component<SliderScreenProps, SliderScr
Disabled
</Text>
<Slider minimumValue={100} maximumValue={200} value={120} containerStyle={styles.slider} disabled/>
</Fragment>
);
}

renderCustomSlider() {
return (
<>
<Text $textDefault text70BO marginT-15>
Custom with Steps
</Text>
Expand All @@ -174,7 +180,7 @@ export default class SliderScreen extends Component<SliderScreenProps, SliderScr
minimumTrackTintColor={Colors.violet40}
maximumTrackTintColor={Colors.violet70}
/>
</Fragment>
</>
);
}

Expand Down Expand Up @@ -317,6 +323,7 @@ export default class SliderScreen extends Component<SliderScreenProps, SliderScr
{this.renderDefaultSliderExample()}
{this.renderNegativeSliderExample()}
{this.renderDisabledSliderExample()}
{this.renderCustomSlider()}
{this.renderRangeSliderExample()}
{this.renderRangeSliderWithValuesExample()}
{this.renderGradientSlidersExample()}
Expand Down
97 changes: 96 additions & 1 deletion demo/src/screens/incubatorScreens/IncubatorSliderScreen.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, {useState, useRef, useCallback} from 'react';
import {StyleSheet, ScrollView} from 'react-native';
import {Constants, Colors, View, Text, Button, Incubator} from 'react-native-ui-lib'; //eslint-disable-line
import {Constants, Colors, View, Text, Button, Incubator, GradientSlider, ColorSliderGroup} from 'react-native-ui-lib'; //eslint-disable-line
import {renderBooleanOption} from '../ExampleScreenPresenter';

const VALUE = 20;
Expand All @@ -9,6 +9,7 @@ const MIN = 0;
const MAX = Constants.screenWidth - 40; // horizontal margins 20
const INITIAL_MIN = 30;
const INITIAL_MAX = 270;
const COLOR = Colors.blue30;

const IncubatorSliderScreen = () => {
const [disableRTL, setDisableRTL] = useState<boolean>(false);
Expand All @@ -19,6 +20,9 @@ const IncubatorSliderScreen = () => {
const [sliderMinValue, setSliderMinValue] = useState(INITIAL_MIN);
const [sliderMaxValue, setSliderMaxValue] = useState(INITIAL_MAX);

const [color, setColor] = useState(COLOR);
const [alpha, setAlpha] = useState(1);

const slider = useRef<typeof Incubator.Slider>();
const customSlider = useRef<typeof Incubator.Slider>();
const negativeSlider = useRef<typeof Incubator.Slider>();
Expand Down Expand Up @@ -48,6 +52,15 @@ const IncubatorSliderScreen = () => {
setSliderMinValue(value.min);
}, []);

const onGradientValueChange = useCallback((value: string, alpha: number) => {
setColor(value);
setAlpha(alpha);
}, []);

const onGroupValueChange = (value: string) => {
console.log('onGroupValueChange: ', value);
};

const renderValuesBox = (min: number, max?: number) => {
if (max !== undefined) {
return (
Expand Down Expand Up @@ -179,6 +192,65 @@ const IncubatorSliderScreen = () => {
);
};

const renderGradientSlidersExample = () => {
return (
<View marginH-20>
<Text margin-10 text70BL $textDefault>
Gradient Sliders
</Text>
<View row centerV>
<Text text90 $textNeutral>
DEFAULT
</Text>
<GradientSlider
color={color}
containerStyle={styles.gradientSliderContainer}
onValueChange={onGradientValueChange}
// @ts-expect-error
ref={this.gradientSlider}
migrate
/>
<View style={styles.box}>
<View style={{flex: 1, backgroundColor: color, opacity: alpha}}/>
</View>
</View>
<View row centerV>
<Text text90 $textNeutral>
HUE
</Text>
<GradientSlider
type={GradientSlider.types.HUE}
color={COLOR}
containerStyle={styles.gradientSliderContainer}
onValueChange={onGradientValueChange}
migrate
/>
<View style={styles.box}>
<View style={{flex: 1, backgroundColor: color}}/>
</View>
</View>
</View>
);
};

const renderColorSliderGroupExample = () => {
return (
<>
<Text margin-10 text70BL $textDefault>
Color Slider Group
</Text>
<ColorSliderGroup
initialColor={color}
sliderContainerStyle={styles.slider}
containerStyle={styles.group}
showLabels
onValueChange={onGroupValueChange}
migrate
/>
</>
);
};

return (
<ScrollView showsVerticalScrollIndicator={false} style={{backgroundColor: Colors.$backgroundDefault}}>
<View row spread margin-20>
Expand All @@ -196,6 +268,8 @@ const IncubatorSliderScreen = () => {
{renderCustomSliderExample()}
{renderNegativeSliderExample()}
{renderRangeSliderExample()}
{renderGradientSlidersExample()}
{renderColorSliderGroupExample()}
</ScrollView>
);
};
Expand All @@ -221,5 +295,26 @@ const styles = StyleSheet.create({
backgroundColor: Colors.red30,
borderWidth: 2,
borderColor: Colors.red70
},
gradientSliderContainer: {
flex: 1, // NOTE: to place a slider in a row layout you must set flex in its 'containerStyle'!!!
marginHorizontal: 20,
marginVertical: 10
},
box: {
width: 20,
height: 20,
borderRadius: 4,
borderWidth: 1,
borderColor: Colors.$outlineDefault
},
slider: {
marginVertical: 6
},
group: {
backgroundColor: Colors.$backgroundNeutralMedium,
padding: 20,
margin: 20,
borderRadius: 6
}
});
7 changes: 6 additions & 1 deletion src/components/slider/ColorSliderGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ export type ColorSliderGroupProps = {
* If true the component will have accessibility features enabled
*/
accessible?: boolean;
/**
* Whether to use the new Slider implementation using Reanimated
*/
migrate?: boolean;
};

interface ColorSliderGroupState {
Expand Down Expand Up @@ -79,7 +83,7 @@ class ColorSliderGroup extends PureComponent<ColorSliderGroupProps, ColorSliderG
};

renderSlider = (type: GradientSliderTypes) => {
const {sliderContainerStyle, showLabels, labelsStyle, accessible, labels} = this.props;
const {sliderContainerStyle, showLabels, labelsStyle, accessible, labels, migrate} = this.props;

return (
<>
Expand All @@ -93,6 +97,7 @@ class ColorSliderGroup extends PureComponent<ColorSliderGroupProps, ColorSliderG
type={type}
containerStyle={sliderContainerStyle}
accessible={accessible}
migrate={migrate}
/>
</>
);
Expand Down
8 changes: 6 additions & 2 deletions src/components/slider/GradientSlider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {StyleProp, ViewStyle} from 'react-native';
import {Colors} from '../../style';
import {asBaseComponent, forwardRef, ForwardRefInjectedProps} from '../../commons/new';
import Slider, {SliderProps} from './index';
import {Slider as NewSlider} from '../../incubator';
import {SliderContextProps} from './context/SliderContext';
import asSliderGroupChild from './context/asSliderGroupChild';
import Gradient from '../gradient';
Expand Down Expand Up @@ -184,7 +185,7 @@ class GradientSlider extends Component<Props, GradientSliderState> {
};

render() {
const {type, containerStyle, disabled, accessible, forwardedRef, ...others} = this.props;
const {type, containerStyle, disabled, accessible, forwardedRef, migrate, ...others} = this.props;
const initialColor = this.state.initialColor;
const color = this.getColor();
const thumbTintColor = Colors.getHexString(color);
Expand Down Expand Up @@ -216,9 +217,12 @@ class GradientSlider extends Component<Props, GradientSliderState> {
break;
}

const SliderComponent = migrate ? NewSlider : Slider;

return (
<Slider
<SliderComponent
{...others}
//@ts-expect-error
ref={forwardedRef}
onReset={this.reset}
renderTrack={renderTrack}
Expand Down
4 changes: 3 additions & 1 deletion src/components/slider/context/SliderGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ export default class SliderGroup extends Component<SliderGroupProps, SliderGroup
render() {
return (
<View {...this.props}>
<SliderContext.Provider value={this.getContextProviderValue()}>{this.props.children}</SliderContext.Provider>
<SliderContext.Provider value={this.getContextProviderValue()}>
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think that if you prettify this there'll be no changes (if not then we get different results 😨 )

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I did it on purpose, I think it's clearer this way

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think it's against the rules 📏 but I'll leave it up to you

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I'm ok with that :)

{this.props.children}
</SliderContext.Provider>
</View>
);
}
Expand Down
11 changes: 10 additions & 1 deletion src/components/slider/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
} from 'react-native';
import {Constants} from '../../commons/new';
import {Colors} from '../../style';
import IncubatorSlider from '../../incubator/Slider';
import View from '../view';
import Thumb, {ThumbProps} from './Thumb';
import {extractAccessibilityProps} from '../../commons/modifiers';
Expand Down Expand Up @@ -120,6 +121,10 @@ export type SliderProps = Omit<ThumbProps, 'ref'> & {
* The slider's test identifier
*/
testID?: string;
/**
* Whether to use the new Slider implementation using Reanimated
*/
migrate?: boolean;
} & typeof defaultProps;

interface State {
Expand Down Expand Up @@ -739,7 +744,11 @@ export default class Slider extends PureComponent<SliderProps, State> {
}

render() {
const {containerStyle, testID} = this.props;
const {containerStyle, testID, migrate} = this.props;

if (migrate) {
return <IncubatorSlider {...this.props}/>;
}

return (
<View
Expand Down
3 changes: 2 additions & 1 deletion src/components/slider/slider.api.json
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@
"type": "boolean",
"description": "If true the component will have accessibility features enabled"
},
{"name": "testID", "type": "string", "description": "The component test id"}
{"name": "testID", "type": "string", "description": "The component test id"},
{"name": "migrate", "type": "boolean", "description": "Temporary prop required for migration to the Slider's new implementation"}
],
"snippet": [
"<Slider",
Expand Down
38 changes: 23 additions & 15 deletions src/incubator/Slider/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,11 +95,17 @@ const Slider = React.memo((props: Props) => {
const end = useSharedValue(0);
const defaultThumbOffset = useSharedValue(0);
const rangeThumbOffset = useSharedValue(0);

const defaultThumbStyle: StyleProp<ViewStyle> = useMemo(() => [
styles.thumb, {backgroundColor: disabled ? Colors.$backgroundDisabled : thumbTintColor}
const thumbBackground: StyleProp<ViewStyle> = useMemo(() => [
{backgroundColor: disabled ? Colors.$backgroundDisabled : thumbTintColor}
], [disabled, thumbTintColor]);
const _thumbStyle = useSharedValue(StyleUtils.unpackStyle(thumbStyle || defaultThumbStyle, {flatten: true}));
const defaultThumbStyle: StyleProp<ViewStyle> = useMemo(() => [
styles.thumb, thumbBackground
], [thumbBackground]);
const customThumbStyle: StyleProp<ViewStyle> = useMemo(() => [
thumbStyle, thumbBackground
], [thumbStyle, thumbBackground]);
const _thumbStyle = useSharedValue(StyleUtils.unpackStyle(customThumbStyle || defaultThumbStyle, {flatten: true}));
const _activeThumbStyle = useSharedValue(StyleUtils.unpackStyle(activeThumbStyle, {flatten: true}));

useEffect(() => {
Expand Down Expand Up @@ -142,17 +148,19 @@ const Slider = React.memo((props: Props) => {
useAnimatedReaction(() => {
return Math.round(defaultThumbOffset.value);
},
(offset, _prevOffset) => {
const value = getValueForOffset(offset, trackSize.value.width, minimumValue, maximumValue, stepXValue.value);
if (useRange) {
const maxValue = getValueForOffset(rangeThumbOffset.value,
trackSize.value.width,
minimumValue,
maximumValue,
stepXValue.value);
runOnJS(onRangeChangeThrottled)(value, maxValue);
} else {
runOnJS(onValueChangeThrottled)(value);
(offset, prevOffset) => {
if (offset !== prevOffset) {
const value = getValueForOffset(offset, trackSize.value.width, minimumValue, maximumValue, stepXValue.value);
if (useRange) {
const maxValue = getValueForOffset(rangeThumbOffset.value,
trackSize.value.width,
minimumValue,
maximumValue,
stepXValue.value);
runOnJS(onRangeChangeThrottled)(value, maxValue);
} else {
runOnJS(onValueChangeThrottled)(value);
}
}
});

Expand Down