import React from 'react' import { StyleSheet, View, ViewProps } from 'react-native' import useRounding from '../hooks/useRounding' import { useEvent } from '../hooks/useEvent' import { THUMB_SIZE } from './Thumb' type SliderType = 'slider' | 'range' type SliderValue = T extends 'slider' ? number : [number, number] export type CustomMarkType = React.ComponentType<{ stepMarked: boolean; currentValue: SliderValue; index: number; min: number; max: number; markValue: number }>; const styleSheet = StyleSheet.create({ container: { position: 'absolute', left: 0, height: '100%', width: '100%', top: 0, margin: 'auto', overflow: 'visible' }, mark: { alignItems: 'center', justifyContent: 'center', width: 0, height: 0, pointerEvents: 'none', zIndex: 1, overflow: 'visible' } }) type MarkProps = { StepMarker: CustomMarkType stepMarked: boolean markValue: number index: number min: number max: number left: number top: number currentValue: SliderValue } const Mark = ({ StepMarker, left, top, ...props }: MarkProps) => { const style = React.useMemo(() => ([styleSheet.mark, { top, left }]), [top, left]) return } type CustomMarksProps = { StepMarker?: CustomMarkType minimumValue: number maximumValue: number step: number activeValue: SliderValue type: T inverted: boolean vertical: boolean } const Marks = (props: CustomMarksProps) => { const { StepMarker, step, minimumValue, maximumValue, inverted, vertical, activeValue } = props const [sliderWidth, setSliderWidth] = React.useState(0) const [sliderHeight, setSliderHeight] = React.useState(0) const onLayoutUpdateMarks = useEvent>((event) => { const { width, height } = event.nativeEvent.layout setSliderWidth(width) setSliderHeight(height) }) const round = useRounding({ step, minimumValue, maximumValue }) const marks = React.useMemo(() => { // We cannot render marks if there is no step as we cannot render an infinite amount of marks if (!StepMarker || !step) return null const markCount = Math.round((maximumValue - minimumValue) / step) + 1 return Array(markCount).fill(0).map((_, index) => { const markValue = round(index * step + minimumValue) const advance = ((vertical ? sliderHeight : sliderWidth) - THUMB_SIZE) * (markValue - minimumValue) / ((maximumValue - minimumValue) || 1) + THUMB_SIZE / 2 const padding = (vertical ? sliderWidth : sliderHeight) / 2 const x = inverted ? (vertical ? sliderHeight : sliderWidth) - advance : advance const y = padding return }) }, [StepMarker, activeValue, inverted, maximumValue, minimumValue, round, sliderHeight, sliderWidth, step, vertical]) return {marks} } export default Marks