import React from 'react';
import { PanResponder, Platform } from 'react-native';
import {
FormControlContext,
IFormControlContext,
} from '../../composites/FormControl';
import Box from '../Box';
import { useThemeProps } from '../../../hooks';
import type { ISliderProps } from './types';
import { SliderContext } from './Context';
type StateType = {
barSize: number | null;
deltaValue: number;
value: number;
};
class NBSlider extends React.PureComponent<
ISliderProps & {
thumbSize?: number;
sliderSize?: number;
activeColor?: string;
},
StateType
> {
static contextType = SliderContext;
state = {
barSize: null,
deltaValue: 0,
value: this.props.defaultValue || 0,
};
panResponder = PanResponder.create({
onMoveShouldSetPanResponderCapture: () => true,
onPanResponderMove: (_event, gestureState) =>
!(this.props.isDisabled || this.props.isReadOnly) &&
this.onMove(gestureState),
onPanResponderRelease: () => this.onEndMove(),
onPanResponderTerminate: () => {},
});
onMove(gestureState: any) {
const { barSize } = this.state;
const { min = 0, max = 100 } = this.props;
const newDeltaValue = this.getValueFromStartOffset(
this.props.orientation === 'vertical'
? -gestureState.dy
: gestureState.dx,
barSize,
this.props.min || 0,
this.props.max || 100
);
this.props.onChange &&
this.props.onChange(
this.capValueWithinRange(this.state.value + newDeltaValue, [min, max])
);
this.setState({
deltaValue: newDeltaValue,
});
}
onEndMove() {
const { value, deltaValue } = this.state;
const { min = 0, max = 100 } = this.props;
const cappedVal = this.capValueWithinRange(value + deltaValue, [min, max]);
this.props.onChangeEnd && this.props.onChangeEnd(cappedVal);
this.setState({ value: cappedVal, deltaValue: 0 });
}
onBarLayout = (event: any) => {
const { width, height } = event.nativeEvent.layout;
const barSize = this.props.orientation === 'vertical' ? height : width;
this.setState({ barSize });
};
capValueWithinRange = (value: number, range: number[]) => {
if (value < range[0]) return range[0];
if (value > range[1]) return range[1];
return value;
};
getValueFromStartOffset = (
offset: number,
barSize: number | null,
rangeMin: number,
rangeMax: number
) => {
if (barSize === null) return 0;
return ((rangeMax - rangeMin) * offset) / barSize;
};
getOffsetFromValue = (
value: number,
rangeMin: number,
rangeMax: number,
barSize: number | null
) => {
if (barSize === null) return 0;
const valueOffset = value - rangeMin;
const totalRange = rangeMax - rangeMin;
const percentage = valueOffset / totalRange;
return barSize * percentage;
};
onAccessibilityAction = (event: any) => {
const max = this.props.max ?? 100;
const min = this.props.min ?? 0;
const incrementStep = this.props.accessibilityIncrementSteps ?? max / 10;
const decrementStep = this.props.accessibilityDecrementSteps ?? max / 10;
switch (event.nativeEvent.actionName) {
case 'increment':
this.setState({
value: Math.min(this.state.value + incrementStep, max),
});
break;
case 'decrement':
this.setState({
value: Math.max(this.state.value - decrementStep, min),
});
break;
default:
break;
}
};
render() {
const { value, deltaValue, barSize } = this.state;
const min = this.props.min ?? 0;
const max = this.props.max ?? 100;
const cappedValue = this.capValueWithinRange(value + deltaValue, [
min,
max,
]);
const sliderOffset = this.getOffsetFromValue(
cappedValue,
min,
max,
barSize
);
return (
{this.state.barSize && this.props.children}
);
}
}
const Slider = ({ ...props }: ISliderProps) => {
const formControlContext: IFormControlContext = React.useContext(
FormControlContext
);
const newProps = useThemeProps('Slider', {
...formControlContext,
...props,
});
return ;
};
export default React.memo(Slider);