index.tsx 2.9 KB

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