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

Alternative Slider component #97

Closed
wants to merge 9 commits into from
Closed
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
9 changes: 9 additions & 0 deletions .storybook/webpack.config.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
const path = require('path');

module.exports = {
module: {
rules: [
Expand All @@ -6,6 +8,13 @@ module.exports = {
use:
'react-native-web-image-loader?name=[name].[ext]&scalings[@2x]=2&scalings[-3x]=3',
},
{
test: /\.js$/,
include: [
path.join(__dirname, '../node_modules/react-native-multi-slider'),
],
use: 'babel-loader',
},
],
},
resolve: {
Expand Down
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@
"author": "kiwi.com",
"license": "MIT",
"dependencies": {
"@kiwicom/orbit-design-tokens": "^0.2.5"
"@kiwicom/orbit-design-tokens": "^0.2.5",
"react-native-multi-slider": "https://github.com/lukewalczak/react-native-multi-slider.git#feat/labels"
},
"peerDependencies": {
"react": "16.6.1",
Expand Down Expand Up @@ -61,6 +62,8 @@
"flow-bin": "0.78.0",
"jest": "^23.6.0",
"metro-react-native-babel-preset": "^0.49.1",
"patch-package": "^5.1.1",
"postinstall-prepare": "^1.0.1",
"prettier": "^1.15.2",
"prettier-eslint-cli": "^4.7.1",
"react": "16.6.1",
Expand Down
157 changes: 157 additions & 0 deletions src/Slider/Slider.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
// @flow

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

import StyleSheet from '../PlatformStyleSheet';
import type { StylePropType } from '../PlatformStyleSheet/StyleTypes';

type Props = {|
+onChange: (number[]) => void,
+min: number,
+max: number,
+startValue: number,
+endValue?: number,
+snapped?: boolean,
+style?: StylePropType,
+startLabel?: React.Node,
+endLabel?: React.Node,
|};

type State = {|
width: number,
|};

type OnLayout = {
+nativeEvent: {
+layout: {
+x: number,
+y: number,
+width: number,
+height: number,
},
},
};

export default class Slider extends React.Component<Props, State> {
state = {
width: 0,
};

onLayout = ({ nativeEvent }: OnLayout) => {
this.setState({ width: nativeEvent.layout.width });
};

getMaxMinAndEnabled = () => {
const { max, min, startValue, endValue } = this.props;

if (max === min && max === startValue && max === endValue) {
// If all values are equal, expand max and min values by one
// to make dot appear on the center and disable sliding.
return {
max: max + 1,
min: min - 1,
enabledOne: false,
enabledTwo: false,
};
}

return {
max,
min,
enabledOne: true,
enabledTwo: true,
};
};

render() {
const {
startValue,
endValue,
snapped,
style,
onChange,
startLabel,
endLabel,
} = this.props;
const { width } = this.state;

const { max, min, enabledOne, enabledTwo } = this.getMaxMinAndEnabled();
const values = [startValue];

if (endValue) {
values.push(endValue);
}

return (
<View onLayout={this.onLayout} style={styles.sliderContainer}>
<MultiSlider
values={values}
min={min}
max={max}
snapped={snapped}
allowOverlap
selectedStyle={styles.selected}
sliderLength={width}
touchDimensions={{
height: 30,
width: 30,
borderRadius: 0,
slipDisplacement: 500,
}}
unselectedStyle={styles.unselected}
trackStyle={styles.track}
markerStyle={styles.marker}
pressedMarkerStyle={styles.marker}
containerStyle={[styles.container, style]}
onValuesChange={onChange}
enabledOne={enabledOne}
enabledTwo={enabledTwo}
startLabel={startLabel}
endLabel={endLabel}
/>
</View>
);
}
}

const styles = StyleSheet.create({
sliderContainer: {
alignSelf: 'center',
width: '85%',
},
selected: {
backgroundColor: defaultTokens.paletteBlueNormal,
},
unselected: {
backgroundColor: defaultTokens.paletteInkLighter,
},
track: {
borderRadius: 5,
height: 4,
},
marker: {
height: 30,
width: 30,
borderRadius: 15,
backgroundColor: defaultTokens.paletteWhite,
borderWidth: 1,
borderColor: defaultTokens.paletteInkLighter,
shadowColor: defaultTokens.paletteInkDark,
shadowOffset: {
width: 0,
height: 2,
},
shadowOpacity: 0.1,
shadowRadius: 4,
margin: 3, // necessary to see the Android elevation properly
android: {
elevation: 1,
},
},
container: {
paddingTop: 15,
},
});
48 changes: 48 additions & 0 deletions src/Slider/Slider.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// @flow

import React from 'react';
import { View } from 'react-native';
import { storiesOf } from '@storybook/react-native';
import { withKnobs, number, boolean } from '@storybook/addon-knobs';
import Slider from './Slider';

const noop = () => {};
storiesOf('Slider', module)
.addDecorator(withKnobs)
.add('Default', () => (
<View>
<Slider
min={0}
max={100000}
startValue={5266}
endValue={19289}
onChange={noop}
/>
</View>
))
.add('Playground', () => {
const min = number('Min value', 0);
const max = number('Max value', 100000);
const start = number('Start value', 20000);
const end = number('End value', 80000);
const snapped = boolean('Snapped', false);

return (
<View>
<Slider
min={min}
max={max}
startValue={start}
endValue={end}
snapped={snapped}
onChange={noop}
/>
</View>
);
})

.add('Only one marker', () => (
<View>
<Slider min={0} max={10} startValue={2} onChange={noop} />
</View>
));
12 changes: 12 additions & 0 deletions src/Slider/SliderTypes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// @flow

export type OnLayout = {
+nativeEvent: {
+layout: {
+x: number,
+y: number,
+width: number,
+height: number,
},
},
};
3 changes: 3 additions & 0 deletions src/Slider/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// @flow

export { default as Slider } from './Slider';
46 changes: 46 additions & 0 deletions storybook.native/story-loader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@

// Auto-generated file created by react-native-storybook-loader
// Do not edit.
//
// https://github.com/elderfo/react-native-storybook-loader.git

function loadStories() {
require('../src/Badge/Badge.stories');
require('../src/Button/Button.stories');
require('../src/Card/Card.stories');
require('../src/Checkbox/Checkbox.stories');
require('../src/FilterButton/FilterButton.stories');
require('../src/Icon/Icon.stories');
require('../src/Loader/Loader.stories');
require('../src/RadioButton/RadioButton.stories');
require('../src/Rating/Rating.stories');
require('../src/ServiceLogo/ServiceLogo.stories');
require('../src/Slider/Slider.stories');
require('../src/Stepper/Stepper.stories');
require('../src/Text/Text.stories');
require('../src/TextInput/TextInput.stories');

}

const stories = [
'../src/Badge/Badge.stories',
'../src/Button/Button.stories',
'../src/Card/Card.stories',
'../src/Checkbox/Checkbox.stories',
'../src/FilterButton/FilterButton.stories',
'../src/Icon/Icon.stories',
'../src/Loader/Loader.stories',
'../src/RadioButton/RadioButton.stories',
'../src/Rating/Rating.stories',
'../src/ServiceLogo/ServiceLogo.stories',
'../src/Slider/Slider.stories',
'../src/Stepper/Stepper.stories',
'../src/Text/Text.stories',
'../src/TextInput/TextInput.stories',

];

module.exports = {
loadStories,
stories,
};
Loading