index.tsx 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. import React, {
  2. useEffect, useState, useRef,
  3. } from 'react';
  4. import { fromEvent } from 'rxjs';
  5. import {
  6. throttleTime,
  7. } from 'rxjs/operators';
  8. import {
  9. OuterWrapper, Wrapper, Rail, Track,
  10. } from './styled';
  11. type Props = {
  12. color?: 'primary' | 'secondary';
  13. minimum?: number;
  14. maximum?: number;
  15. defaultValue?: number;
  16. value?: number;
  17. disabled?: boolean;
  18. onChange?: (value: number) => void;
  19. };
  20. const Sliders: React.FC<Props> = ({
  21. defaultValue = 0,
  22. value = 0,
  23. onChange,
  24. // minimum = 0,
  25. maximum = 100,
  26. }: Props) => {
  27. const sliderRef = useRef<HTMLDivElement>(null);
  28. const [valueState, setValueState] = useState(defaultValue);
  29. const [isActive, setActive] = useState(false);
  30. let mouseSubscription: any = null;
  31. let touchSubscription: any = null;
  32. const parseValueToPercent = (val: number): number => Math.floor(val * 100);
  33. const getFingerMoveValue = (event: any): void => {
  34. const { current: slider } = sliderRef;
  35. let clientX = 0;
  36. if (event.touches) {
  37. const touches = event.touches[0];
  38. ({ clientX } = touches);
  39. } else {
  40. ({ clientX } = event);
  41. }
  42. if (slider) {
  43. const { width, left } = slider.getBoundingClientRect();
  44. const moveDistance = clientX - left;
  45. const moveRate = moveDistance / width;
  46. let percent = parseValueToPercent(moveRate);
  47. if (percent <= 0) {
  48. percent = 0;
  49. } else if (percent >= 100) {
  50. percent = 100;
  51. }
  52. if (onChange) {
  53. const val = Math.floor(percent * (maximum * 0.01));
  54. onChange(val);
  55. }
  56. }
  57. };
  58. const handleTouchMove = (event: any): void => {
  59. event.preventDefault();
  60. getFingerMoveValue(event);
  61. };
  62. const handleTouchEnd = (event: MouseEvent): void => {
  63. event.preventDefault();
  64. setActive(false);
  65. mouseSubscription.unsubscribe();
  66. touchSubscription.unsubscribe();
  67. };
  68. const handleMouseDown = (
  69. event: React.MouseEvent<HTMLElement> | React.TouchEvent<HTMLElement>,
  70. ): void => {
  71. event.preventDefault();
  72. getFingerMoveValue(event);
  73. setActive(true);
  74. mouseSubscription = fromEvent(document.body, 'mousemove').pipe(throttleTime(35)).subscribe(handleTouchMove);
  75. touchSubscription = fromEvent(document.body, 'touchmove').pipe(throttleTime(35)).subscribe(handleTouchMove);
  76. document.body.addEventListener('mouseup', handleTouchEnd);
  77. };
  78. const setPercent = (): void => {
  79. const percent = parseValueToPercent((defaultValue || value) / maximum);
  80. setValueState(percent);
  81. };
  82. useEffect(() => {
  83. setPercent();
  84. }, []);
  85. useEffect(() => {
  86. setPercent();
  87. }, [value]);
  88. return (
  89. <OuterWrapper>
  90. <Wrapper
  91. ref={sliderRef}
  92. onMouseDown={handleMouseDown}
  93. onTouchStart={handleMouseDown}
  94. >
  95. <Rail track={valueState} />
  96. <Track
  97. track={valueState}
  98. isActive={isActive}
  99. />
  100. </Wrapper>
  101. </OuterWrapper>
  102. );
  103. };
  104. export default Sliders;