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 c555063 commit 44aab0a
Show file tree
Hide file tree
Showing 5 changed files with 171 additions and 121 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"license": "MIT",
"dependencies": {
"@kiwicom/orbit-design-tokens": "^0.2.5",
"react-native-multi-slider": "https://github.com/lukewalczak/react-native-multi-slider.git#feat/block-overlap",
"react-native-multi-slider": "https://github.com/lukewalczak/react-native-multi-slider.git#180b479ecf01eca852d6c00a430fd6a65e178600",
"react-native-status-bar-height": "^2.2.0",
"styled-components": "^4.1.2"
},
Expand Down
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
60 changes: 31 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,34 @@ 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);
const step = number('Step', 1000);

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')}
step={step}
/>
);
});
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',
},
});
4 changes: 2 additions & 2 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -9996,8 +9996,8 @@ react-native-modal@^5.4.0:
react-native-animatable "^1.2.4"

"react-native-multi-slider@https://github.com/lukewalczak/react-native-multi-slider.git#feat/block-overlap":
version "2.0.0"
resolved "https://github.com/lukewalczak/react-native-multi-slider.git#920046a4a6ab49f7f163d0e00ae34993b9778807"
version "2.0.2"
resolved "https://github.com/lukewalczak/react-native-multi-slider.git#ad977facbc402dce725efc3ac537778531d944df"

react-native-status-bar-height@^2.2.0:
version "2.2.0"
Expand Down

0 comments on commit 44aab0a

Please sign in to comment.