RangeSlider.tsx 4.0 KB
Newer Older
P
Peter Pan 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/**
 * Copyright 2020 Baidu Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

17
import InputRange, {Range} from 'react-input-range';
18
import React, {FunctionComponent, useCallback} from 'react';
P
Peter Pan 已提交
19
import {WithStyled, em, half, position, sameBorder, size, transitionProps} from '~/utils/style';
20

21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
import styled from 'styled-components';

const height = em(20);
const railHeight = em(4);
const thumbSize = em(12);

const Wrapper = styled.div<{disabled?: boolean}>`
    height: ${height};

    .input-range {
        height: 100%;
        position: relative;

        &__label {
            display: none;
        }

P
Peter Pan 已提交
38
        --color: var(--primary-color);
P
Peter Pan 已提交
39 40

        &:hover {
P
Peter Pan 已提交
41
            --color: var(--primary-focused-color);
P
Peter Pan 已提交
42 43 44
        }

        &:active {
P
Peter Pan 已提交
45
            --color: var(--primary-active-color);
P
Peter Pan 已提交
46 47
        }

48 49 50 51
        &__track {
            cursor: ${props => (props.disabled ? 'not-allowed' : 'pointer')};

            &--background {
52 53
                ${size(railHeight, '100%')}
                ${position('absolute', '50%', null, null, null)}
54
                margin-top: -${half(railHeight)};
P
Peter Pan 已提交
55
                background-color: var(--slider-rail-color);
56
                border-radius: ${half(railHeight)};
P
Peter Pan 已提交
57
                ${transitionProps('background-color')}
58 59 60 61 62
            }

            &--active {
                height: ${railHeight};
                position: absolute;
P
Peter Pan 已提交
63
                background-color: ${props => (props.disabled ? 'var(--text-lighter-color)' : 'var(--color)')};
64 65
                border-radius: ${half(railHeight)};
                outline: none;
P
Peter Pan 已提交
66
                ${transitionProps('background-color')}
67 68 69 70
            }
        }

        &__slider-container {
71
            top: -${half(`${thumbSize} - ${railHeight}`)};
72 73 74 75 76
            margin-left: -${half(thumbSize)};
        }

        &__slider {
            ${size(thumbSize)}
77 78 79
            ${props =>
                sameBorder({
                    width: em(3),
P
Peter Pan 已提交
80
                    color: props.disabled ? 'var(--text-lighter-color)' : 'var(--color)',
81 82
                    radius: half(thumbSize)
                })}
P
Peter Pan 已提交
83 84
            background-color: var(--slider-gripper-color);
            ${transitionProps(['border-color', 'background-color'])}
85 86 87 88 89 90 91 92 93 94 95
        }
    }
`;

type RangeSliderProps = {
    min?: number;
    max?: number;
    step?: number;
    value?: number;
    disabled?: boolean;
    onChange?: (value: number) => unknown;
P
Peter Pan 已提交
96
    onChangeStart?: () => unknown;
97 98 99 100 101
    onChangeComplete?: () => unknown;
};

const RangeSlider: FunctionComponent<RangeSliderProps & WithStyled> = ({
    onChange,
P
Peter Pan 已提交
102
    onChangeStart,
103 104 105 106 107 108 109 110
    onChangeComplete,
    className,
    min,
    max,
    step,
    value,
    disabled
}) => {
111
    const onChangeRange = useCallback((range: number | Range) => onChange?.(range as number), [onChange]);
112 113 114 115 116 117 118 119 120 121 122 123 124 125

    return (
        <Wrapper className={className} disabled={disabled}>
            <InputRange
                minValue={min}
                maxValue={max}
                // there may be a warning when `minValue` equals `maxValue` though `allSameValue` is set to TRUE
                // this is a bug of react-input-range
                // ignore for now
                allowSameValues
                step={step}
                disabled={disabled}
                value={value as number}
                onChange={onChangeRange}
P
Peter Pan 已提交
126
                onChangeStart={() => onChangeStart?.()}
127 128 129 130 131 132 133 134 135 136 137 138 139 140
                onChangeComplete={() => onChangeComplete?.()}
            />
        </Wrapper>
    );
};

RangeSlider.defaultProps = {
    min: 0,
    max: 100,
    step: 1,
    value: 50
};

export default RangeSlider;