Skip to content
This repository has been archived by the owner on Mar 4, 2019. It is now read-only.

Commit

Permalink
refactor: extract slider parts to separate component
Browse files Browse the repository at this point in the history
  • Loading branch information
lukewalczak committed Jan 10, 2019
1 parent a891da1 commit c6af82f
Show file tree
Hide file tree
Showing 3 changed files with 166 additions and 118 deletions.
98 changes: 9 additions & 89 deletions src/Slider/Slider.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ import { View } from 'react-native';
import MultiSlider from 'react-native-multi-slider';

import Marker from './Marker';
import SliderParts from './SliderParts';
import { Text } from '../Text';
import { StyleSheet } from '../PlatformStyleSheet';

const LABEL_LENGTH = 200;
const TRACK_HEIGHT = 4;

type Props = {|
Expand Down Expand Up @@ -79,46 +79,6 @@ export default class Slider extends React.Component<Props, State> {
onValuesChange && onValuesChange();
};

calculateOffset = (value: number) => {
const { minValue, maxValue } = this.props;
const { width } = this.state;
return (value * width) / (maxValue - minValue) - LABEL_LENGTH / 2;
};

createParts = () => {
const { numOfParts = 1, minValue, maxValue } = this.props;
const step = (maxValue - minValue) / numOfParts;

const parts = [];
let i;

if (numOfParts != null && numOfParts < 1) {
console.error('numOfParts cannot be lower than 1');
}

for (i = 0; i <= numOfParts; i++) {
const valuePerStep = Math.floor(step * i);

parts.push(
<View
key={i}
style={[
styles.partStyle,
{
left: this.calculateOffset(valuePerStep),
},
]}
>
<View style={styles.partBorder} />
<Text size="small" style={styles.labelText}>
{valuePerStep + minValue}
</Text>
</View>
);
}
return parts;
};

onLayout = ({ nativeEvent }: OnLayout) => {
const { sliderLength } = this.props;
this.setState({
Expand All @@ -137,14 +97,10 @@ export default class Slider extends React.Component<Props, State> {
customMarker,
onValuesChangeFinish,
onValuesChangeStart,
numOfParts,
} = this.props;
const { multiSliderValues, width, singleSliderValue } = this.state;

const typeLineStyle =
type === 'single' && singleSliderValue[0] >= minValue
? styles.selected
: styles.unselected;

const labelValue =
type === 'multi'
? `${multiSliderValues[0]} - ${multiSliderValues[1]}`
Expand Down Expand Up @@ -174,26 +130,13 @@ export default class Slider extends React.Component<Props, State> {
<View onLayout={this.onLayout}>
<View style={styles.contentContainer}>
<View>
<View>{this.createParts()}</View>
<View
style={[
styles.trackLine,
typeLineStyle,
{
right: 0,
width: width + 10,
},
]}
/>
<View
style={[
styles.trackLine,
styles.unselected,
{
left: 0,
width: width + 10,
},
]}
<SliderParts
width={width}
minValue={minValue}
maxValue={maxValue}
numOfParts={numOfParts}
type={type}
singleSliderValue={singleSliderValue}
/>
<MultiSlider
values={values}
Expand Down Expand Up @@ -240,34 +183,11 @@ const styles = StyleSheet.create({
unselected: {
backgroundColor: defaultTokens.paletteInkLighter,
},
trackLine: {
borderRadius: 5,
height: TRACK_HEIGHT,
position: 'absolute',
top: 25 - TRACK_HEIGHT / 2,
alignSelf: 'center',
},
partStyle: {
position: 'absolute',
width: LABEL_LENGTH,
alignItems: 'center',
},
partBorder: {
position: 'absolute',
borderStartWidth: 2,
borderStartColor: defaultTokens.paletteCloudLightHover,
height: 34,
top: 8,
},
labelContainer: {
paddingHorizontal: 20,
flexDirection: 'row',
alignItems: 'center',
},
labelText: {
top: 50,
position: 'absolute',
},
resultContainer: {
flexDirection: 'row',
backgroundColor: defaultTokens.paletteBlueNormal,
Expand Down
58 changes: 29 additions & 29 deletions src/Slider/Slider.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,34 +16,6 @@ import { Slider } from '.';

storiesOf('Slider', module)
.addDecorator(withKnobs)
.add('Playground', () => {
const minValue = number('Min value', 0);
const maxValue = number('Max value', 10000);
const startValue = number('Start value', 2000);
const endValue = number('End value', 8000);
const label = text('Label', 'Price');
const type = select('Type', ['multi', 'single'], 'single');
const snapped = boolean('Snapped', false);
const numOfParts = number('Number of parts', 5);
const sliderLength = number('Slider length', 315);

return (
<Slider
minValue={minValue}
maxValue={maxValue}
startValue={startValue}
endValue={endValue}
label={label}
type={type}
snapped={snapped}
numOfParts={numOfParts}
sliderLength={sliderLength}
onValuesChange={action('change')}
onValuesChangeFinish={action('finish')}
onValuesChangeStart={action('start')}
/>
);
})
.add('Default', () => (
<ScrollView style={{ flex: 1 }}>
<Slider
Expand Down Expand Up @@ -105,4 +77,32 @@ storiesOf('Slider', module)
numOfParts={5}
/>
</ScrollView>
));
))
.add('Playground', () => {
const minValue = number('Min value', 0);
const maxValue = number('Max value', 10000);
const startValue = number('Start value', 2000);
const endValue = number('End value', 8000);
const label = text('Label', 'Price');
const type = select('Type', ['multi', 'single'], 'single');
const snapped = boolean('Snapped', false);
const numOfParts = number('Number of parts', 5);
const sliderLength = number('Slider length', 315);

return (
<Slider
minValue={minValue}
maxValue={maxValue}
startValue={startValue}
endValue={endValue}
label={label}
type={type}
snapped={snapped}
numOfParts={numOfParts}
sliderLength={sliderLength}
onValuesChange={action('change')}
onValuesChangeFinish={action('finish')}
onValuesChangeStart={action('start')}
/>
);
});
128 changes: 128 additions & 0 deletions src/Slider/SliderParts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
// @flow

import * as React from 'react';
import { defaultTokens } from '@kiwicom/orbit-design-tokens';
import { View } from 'react-native';

import { Text } from '../Text';
import { StyleSheet } from '../PlatformStyleSheet';

const LABEL_LENGTH = 200;
const TRACK_HEIGHT = 4;

type Props = {|
+type: 'multi' | 'single',
+minValue: number,
+maxValue: number,
+numOfParts?: number,
+singleSliderValue: Array<number>,
+width: number,
|};

export default function SliderParts({
minValue,
maxValue,
width,
numOfParts = 1,
singleSliderValue,
type,
}: Props) {
const calculateOffset = (value: number) =>
(value * width) / (maxValue - minValue) - LABEL_LENGTH / 2;

const createParts = () => {
const step = (maxValue - minValue) / numOfParts;

const parts = [];
let i;

if (numOfParts != null && numOfParts < 1) {
console.error('numOfParts cannot be lower than 1');
}

for (i = 0; i <= numOfParts; i++) {
const valuePerStep = Math.floor(step * i);

parts.push(
<View
key={i}
style={[
styles.partStyle,
{
left: calculateOffset(valuePerStep),
},
]}
>
<View style={styles.partBorder} />
<Text size="small" style={styles.labelText}>
{valuePerStep + minValue}
</Text>
</View>
);
}
return parts;
};

const typeLineStyle =
type === 'single' && singleSliderValue[0] >= minValue
? styles.selected
: styles.unselected;

return (
<View>
<View>{createParts()}</View>
<View
style={[
styles.trackLine,
typeLineStyle,
{
right: 0,
width: width + 10,
},
]}
/>
<View
style={[
styles.trackLine,
styles.unselected,
{
left: 0,
width: width + 10,
},
]}
/>
</View>
);
}

const styles = StyleSheet.create({
selected: {
backgroundColor: defaultTokens.paletteBlueNormal,
},
unselected: {
backgroundColor: defaultTokens.paletteInkLighter,
},
trackLine: {
borderRadius: 5,
height: TRACK_HEIGHT,
position: 'absolute',
top: 25 - TRACK_HEIGHT / 2,
alignSelf: 'center',
},
partStyle: {
position: 'absolute',
width: LABEL_LENGTH,
alignItems: 'center',
},
partBorder: {
position: 'absolute',
borderStartWidth: 2,
borderStartColor: defaultTokens.paletteCloudLightHover,
height: 34,
top: 8,
},
labelText: {
top: 50,
position: 'absolute',
},
});

0 comments on commit c6af82f

Please sign in to comment.