import React from 'react' import { Slider as RNSlider } from '@miblanchard/react-native-slider' import { TypeGuards } from '@codeleap/types' import { onUpdate } from '@codeleap/hooks' import { SliderProps, TrackMarkProps } from './types' import { InputBase, selectInputBaseProps } from '../InputBase' import { Text } from '../Text' import { View } from '../View' import { Touchable } from '../Touchable' import { AnyRecord, IJSX, StyledComponentProps } from '@codeleap/styles' import { MobileStyleRegistry } from '../../Registry' import { useStylesFor } from '../../hooks' import { useInputBase } from '../InputBase/useInputBase' import { fields } from '@codeleap/form' import { useInputBasePartialStyles } from '../InputBase/useInputBasePartialStyles' export * from './styles' export * from './types' const DefaultSliderTrackMark = (props: TrackMarkProps) => { const { style, onPress } = props if (!TypeGuards.isString(props.content)) { return <> {props.content} } return } const minimumValue = 0 const maximumValue = 100 export const Slider = (props: SliderProps) => { const { inputBaseProps: { label: _label, description: _description, ..._inputBaseProps }, others, } = selectInputBaseProps({ ...Slider.defaultProps, ...props, }) const { debounce = null, field, label, description, debugName, style, disabled, trackMarks, trackMarksClickable, labelClickable, updateImmediately = false, trackMarkComponent: SliderTrackMark, value, onValueChange, ...sliderProps } = others const { wrapperRef, inputValue, onInputValueChange, } = useInputBase(field, fields.number, { value, onValueChange }) /** * When `updateImmediately` is false, the committed value is only written on `onSlidingComplete` * to avoid flooding the form/state store with every pixel of movement; `_value` is the local * thumb position and `inputValue` is the last committed value. */ const [_value, _setValue] = updateImmediately ? [inputValue, onInputValueChange] : React.useState>(0) onUpdate(() => { if (updateImmediately) return if (inputValue !== _value) { _setValue(inputValue) } }, [inputValue]) const styles = useStylesFor(Slider.styleRegistryName, style) const partialStyles = useInputBasePartialStyles( styles, ['thumb', 'track', 'selectedTrack', 'unselectedTrack', 'sliderContainer', 'trackMark'], { disabled } ) const trackMarksHaveContent = !(TypeGuards.isArray(trackMarks) || TypeGuards.isNil(trackMarks)) const trackMarksProp = React.useMemo(() => { if (!trackMarksHaveContent) { return trackMarks } return Object.keys(trackMarks).map((key) => Number(key)) }, [trackMarksHaveContent]) return ( {label || description ? ( {label ? ( labelClickable ? onInputValueChange(sliderProps?.minimumValue || minimumValue) : null} style={styles.labelBtn} debugName='slider title' > ) : null} {description ? ( labelClickable ? onInputValueChange(sliderProps?.maximumValue || maximumValue) : null} style={styles?.descriptionBtn} debugName='slider description' > ) : null} ) : null} {/* @ts-ignore */} { if (updateImmediately) return onInputValueChange(_value) }} disabled={disabled} {...sliderProps} trackMarks={trackMarksProp} /> { trackMarksProp ? ( { trackMarksProp.map((_, idx) => { let idxStyle = {} if (idx === 0) { idxStyle = styles?.firstTrackMark } else if (idx === trackMarksProp.length - 1) { idxStyle = styles?.lastTrackMark } const style = [partialStyles?.trackMark, idxStyle] if (!trackMarksHaveContent) { return trackMarksClickable ? onInputValueChange(trackMarksProp[idx]) : null} /> } const relativeValue = trackMarksProp[idx] const content = trackMarks[relativeValue] return trackMarksClickable ? onInputValueChange(trackMarksProp[idx]) : null} /> }) } ) : null } ) } Slider.styleRegistryName = 'Slider' Slider.rootElement = 'wrapper' Slider.elements = [ ...InputBase.elements, 'thumb', 'track', 'selectedTrack', 'unselectedTrack', 'firstTrackMark', 'lastTrackMark', 'sliderContainer', 'labelBtn', 'descriptionBtn', ] Slider.withVariantTypes = (styles: S) => { return Slider as (props: StyledComponentProps) => IJSX } Slider.defaultProps = { trackMarksClickable: false, labelClickable: false, trackMarkComponent: DefaultSliderTrackMark, } as Partial MobileStyleRegistry.registerComponent(Slider)