Skip to content
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

Fix stepMarked prop of the StepMarker when the step props is not defa… #581

Merged
merged 1 commit into from
Jun 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 114 additions & 8 deletions example/src/Examples.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
import React, {useState} from 'react';
import {Text, View, StyleSheet} from 'react-native';
import Slider, {SliderProps} from '@react-native-community/slider';
import React, {FC, useState} from 'react';
import {Text, View, StyleSheet, Image} from 'react-native';
import Slider, {MarkerProps, SliderProps} from '@react-native-community/slider';

export interface Props {
title: string;
render(): JSX.Element;
platform?: string;
}

const CONSTANTS = {
MAX_VALUE: 100,
MIN_VALUE: 10,
STEP: 10,
DEFAULT_STEP_RESOLUTION: 100,
} as const;

const SliderExample = (props: SliderProps) => {
const [value, setValue] = useState(props.value ?? 0);
return (
Expand Down Expand Up @@ -262,20 +269,113 @@ const SlidingCustomStepsThumbImageWithNumbersAndDifferentWidth = (
);
};

const MyStepMarker: FC<MarkerProps> = ({stepMarked, currentValue}) => {
return stepMarked ? (
<View style={styles.background}>
<View style={styles.separator} />
<View style={styles.label}>
{currentValue !== undefined ? (
<Text>{currentValue}</Text>
) : (
<Text>{'-'}</Text>
)}
<Image
style={styles.tinyLogo}
source={Image.resolveAssetSource(
require('./resources/twitter-small.png'),
)}
/>
</View>
</View>
) : (
<View style={styles.divider} />
);
};

const SliderExampleWithCustomMarker = (props: SliderProps) => {
const [value, setValue] = useState(props.value ?? CONSTANTS.MIN_VALUE);

return (
<View>
<Text style={styles.text}>{value && +value.toFixed(3)}</Text>
<Slider
step={CONSTANTS.STEP}
style={[styles.slider, props.style]}
minimumValue={CONSTANTS.MIN_VALUE}
maximumValue={CONSTANTS.MAX_VALUE}
thumbImage={require('./resources/empty.png')}
tapToSeek
{...props}
value={value}
onValueChange={setValue}
lowerLimit={1}
StepMarker={MyStepMarker}
minimumTrackTintColor={'#00629A'}
maximumTrackTintColor={'#979EA4'}
/>
</View>
);
};

export default SliderExample;

const styles = StyleSheet.create({
slider: {
width: 300,
opacity: 1,
marginTop: 10,
},
text: {
fontSize: 14,
textAlign: 'center',
fontWeight: '500',
margin: 0,
},
divider: {
width: 2,
height: 20,
backgroundColor: '#ffffff',
justifyContent: 'center',
alignItems: 'center',
},
separator: {
width: 2,
height: 20,
backgroundColor: '#00629A',
justifyContent: 'center',
alignItems: 'center',
},
label: {
marginTop: 10,
width: 45,
paddingVertical: 5,
paddingHorizontal: 10,
backgroundColor: '#ffffff',
shadowColor: '#000000',
shadowOffset: {
width: 0,
height: 1,
},
shadowOpacity: 0.4,
shadowRadius: 4,
justifyContent: 'center',
alignItems: 'center',
},
background: {
justifyContent: 'center',
alignItems: 'center',
},
tinyLogo: {
marginVertical: 5,
aspectRatio: 1,
flex: 1,
height: '100%',
width: '100%',
},
minMaxLabel: {
flexDirection: 'row',
zIndex: -1,
},
slider: {
width: 300,
opacity: 1,
marginTop: 10,
},
outer: {
width: 20,
height: 20,
Expand Down Expand Up @@ -502,6 +602,12 @@ export const examples: Props[] = [
return <InvertedSliderWithStepMarker />;
},
},
{
title: 'Custom step marker settings',
render() {
return <SliderExampleWithCustomMarker />;
},
},
{
title: 'Inverted slider direction',
render() {
Expand Down
Binary file added example/src/resources/empty.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 6 additions & 7 deletions package/src/Slider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -216,16 +216,15 @@ const SliderComponent = (
);
const [width, setWidth] = useState(0);

const step = localProps.step
? localProps.step
: constants.DEFAULT_STEP_RESOLUTION;

const options = Array.from(
{
length:
(localProps.maximumValue! - localProps.minimumValue!) /
(localProps.step
? localProps.step
: constants.DEFAULT_STEP_RESOLUTION) +
1,
length: (localProps.maximumValue! - localProps.minimumValue!) / step + 1,
Copy link
Member

Choose a reason for hiding this comment

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

This is the only thing that bothers me in this PR: What if minimumValue or maximumValue are not given? We have the default ones, maybe we should use those defaults here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have to ask what do you mean under the default minimumValue and maximumValue? The value which are defined under the SliderWithRef.defaultProps ?

I removed my defined max and min values and if I defined the step as 1 the custom marker works as expected.

Code from the modified Example code:

const SliderExampleWithCustomMarker = (props: SliderProps) => {
  const [value, setValue] = useState(props.value ?? CONSTANTS.MIN_VALUE);

  return (
    <View>
      <Text style={styles.text}>{value && +value.toFixed(3)}</Text>
      <Slider
        step={1}
        style={[styles.slider, props.style]}
        thumbImage={require('./resources/slider-left.png')}
        renderStepNumber
        tapToSeek
        {...props}
        value={value}
        onValueChange={setValue}
        StepMarker={MyStepMarker}
        minimumTrackTintColor={'#00629A'}
        maximumTrackTintColor={'#979EA4'}
      />
    </View>
  );
};

However unfortunately if the step is the default one (100 as DEFAULT_STEP_RESOLUTION) my logic is broken. Also if the step is for example 0.2 because the division. Do you have any suggestion how we can resolve that?

Copy link
Member

@BartoszKlonowski BartoszKlonowski Apr 26, 2024

Choose a reason for hiding this comment

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

I think that is because of the value map calculation here:
(_, index) => localProps.minimumValue! + index * step done in line 227.
Thing (means: issue root cause) here is that when having the default step it defaults to 0. So in the end, in line 227, we get minimumValue + 100 for each step.
I don't want to modify the 0 as default step value, but we can try to adjust that according to the default resolution.

Copy link
Member

Choose a reason for hiding this comment

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

@betko ☝️ (forgot to mention/ping)

},
(_, index) => index,
(_, index) => localProps.minimumValue! + index * step,
);

const defaultStyle =
Expand Down
26 changes: 26 additions & 0 deletions package/src/__tests__/Slider.test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as React from 'react';
import renderer from 'react-test-renderer';
import Slider from '../Slider';
import {View} from 'react-native';

describe('<Slider />', () => {
it('renders enabled slider', () => {
Expand Down Expand Up @@ -60,4 +61,29 @@ describe('<Slider />', () => {

expect(tree).toMatchSnapshot();
});

it('renders a slider with custom stepMaker', () => {
const tree = renderer
.create(
<Slider
value={2}
minimumValue={0}
maximumValue={4}
StepMarker={({stepMarked}) => {
return stepMarked ? (
<View>
<View style={{width: '10px', backgroundColor: 'red'}} />
</View>
) : (
<View>
<View style={{width: '10px', backgroundColor: 'green'}} />
</View>
);
}}
/>,
)
.toJSON();

expect(tree).toMatchSnapshot();
});
});
157 changes: 157 additions & 0 deletions package/src/__tests__/__snapshots__/Slider.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,163 @@ exports[`<Slider /> renders a slider with custom props 1`] = `
</View>
`;

exports[`<Slider /> renders a slider with custom stepMaker 1`] = `
<View
onLayout={[Function]}
style={
[
{
"defaultIndicatorIdle": {
"backgroundColor": "#C0C0C0",
"height": 10,
"width": 2,
},
"defaultIndicatorMarked": {
"backgroundColor": "#CCCCCC",
"height": 20,
"width": 5,
},
"defaultSlider": {},
"defaultSlideriOS": {
"height": 40,
},
"sliderMainContainer": {
"width": "100%",
"zIndex": 1,
},
"stepIndicatorElement": {
"alignContent": "center",
"alignItems": "center",
},
"stepNumber": {
"alignItems": "center",
"marginTop": 20,
"position": "absolute",
},
"stepsIndicator": {
"flex": 1,
"flexDirection": "row",
"justifyContent": "space-between",
"top": 10,
"zIndex": 2,
},
"thumbImage": {
"alignContent": "center",
"alignItems": "center",
"position": "absolute",
},
"thumbImageContainer": {
"alignContent": "center",
"alignItems": "center",
"justifyContent": "center",
"position": "absolute",
"zIndex": 3,
},
"trackMarkContainer": {
"alignContent": "center",
"alignItems": "center",
"alignSelf": "center",
"justifyContent": "center",
"position": "absolute",
"zIndex": 3,
},
},
{
"height": 40,
},
{
"justifyContent": "center",
},
]
}
>
<View
pointerEvents="none"
style={
[
{
"flex": 1,
"flexDirection": "row",
"justifyContent": "space-between",
"top": 10,
"zIndex": 2,
},
{
"marginHorizontal": 0,
},
]
}
>
<View
style={
{
"alignContent": "center",
"alignItems": "center",
}
}
>
<View
style={
{
"alignContent": "center",
"alignItems": "center",
"alignSelf": "center",
"justifyContent": "center",
"position": "absolute",
"zIndex": 3,
}
}
>
<View>
<View
style={
{
"backgroundColor": "green",
"width": "10px",
}
}
/>
</View>
</View>
</View>
</View>
<RNCSlider
StepMarker={[Function]}
disabled={false}
inverted={false}
lowerLimit={-9007199254740991}
maximumValue={4}
minimumValue={0}
onChange={[Function]}
onRNCSliderAccessibilityAction={null}
onRNCSliderSlidingComplete={null}
onRNCSliderSlidingStart={null}
onRNCSliderValueChange={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
step={0}
style={
[
{
"width": 0,
"zIndex": 1,
},
{
"height": 40,
},
{
"alignContent": "center",
"alignItems": "center",
},
]
}
tapToSeek={false}
upperLimit={9007199254740991}
value={2}
/>
</View>
`;

exports[`<Slider /> renders disabled slider 1`] = `
<View
onLayout={[Function]}
Expand Down
1 change: 1 addition & 0 deletions package/src/components/StepsIndicator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export const StepsIndicator = ({
isTrue={currentValue === i}
thumbImage={thumbImage}
StepMarker={StepMarker}
currentValue={currentValue}
/>
{renderStepNumber ? (
<StepNumber
Expand Down
Loading