From f43229d96a7392db1178dff0ac2d57eaed1f6bce Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Tue, 28 Apr 2020 12:01:20 +0300 Subject: [PATCH] Add slider --- src/components/slider/index.tsx | 121 +++++++++++++++++++++++ src/index.ts | 3 +- src/styles/slider/styles.module.css | 20 ++++ src/styles/slider/styles.module.css.d.ts | 8 ++ 4 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 src/components/slider/index.tsx create mode 100644 src/styles/slider/styles.module.css create mode 100644 src/styles/slider/styles.module.css.d.ts diff --git a/src/components/slider/index.tsx b/src/components/slider/index.tsx new file mode 100644 index 0000000..d742cc4 --- /dev/null +++ b/src/components/slider/index.tsx @@ -0,0 +1,121 @@ +import React, { + FunctionComponent, + MouseEvent, + useState, + useRef, + useCallback, +} from 'react'; +import { Item, SlideDirection } from '../../types/carousel'; +import styles from '../../styles/slider/styles.module.css'; + +export const Slider: FunctionComponent = ({ + children, + className, +}: SliderProps) => { + const slider = useRef(null); + const [isDown, setIsDown] = useState(false); + const [position, setPosition] = useState({ + startX: 0, + scrollLeft: 0, + }); + + const showArrows = (): Arrows => { + const sliderElement = slider.current; + return { + left: !!sliderElement && sliderElement.scrollLeft > 0, + right: + !!sliderElement && + sliderElement.scrollWidth > + sliderElement.scrollLeft + sliderElement.offsetWidth, + }; + }; + const [showArrow, setShowArrow] = useState(showArrows()); + + const ref = useCallback( + (node) => { + if (node !== null) { + Object.defineProperty(slider, 'current', { value: node }); + setShowArrow(showArrows()); + } + }, + [slider], + ); + + const mouseDown = (e: MouseEvent) => { + setIsDown(true); + setPosition({ + startX: e.pageX - slider.current!.offsetLeft, + scrollLeft: slider.current!.scrollLeft, + }); + }; + + const mouseUp = (_: MouseEvent) => { + setIsDown(false); + setShowArrow(showArrows()); + }; + + const mouseMove = (e: MouseEvent) => { + if (!isDown) return; + e.preventDefault(); + + const eventPosition = e.pageX - slider.current!.offsetLeft; + const slide = eventPosition - position.startX; + + slider.current!.scrollLeft = position.scrollLeft - slide; + }; + + const slide = (direction: SlideDirection) => { + const slideAmount = -1 * direction * slider.current!.offsetWidth * 0.9; + const start = slider.current!.scrollLeft; + smoothHorizontalScroll(500, slideAmount, start); + setShowArrow(showArrows()); + }; + + const smoothHorizontalScroll = (time: number, amount: number, start: number) => { + let curTime = 0; + for (let scrollCounter = 0; curTime <= time; scrollCounter++) { + window.setTimeout( + smoothHorizontalScrollBehavior, + curTime, + (scrollCounter * amount) / 100 + start, + ); + curTime += time / 100; + } + }; + + const smoothHorizontalScrollBehavior = (amount: number) => { + slider.current!.scrollLeft = amount; + setShowArrow(showArrows()); + }; + + return ( +
+ {showArrow.left && ( + + )} + {showArrow.right && ( + + )} +
+ {children} +
+
+ ); +}; + +export interface SliderProps { + children: Item[]; + className?: string; +} + +export type Arrows = { + left: boolean; + right: boolean; +}; diff --git a/src/index.ts b/src/index.ts index b3d1201..9a51a3d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,4 @@ import { Carousel } from './components/carousel'; +import { Slider } from './components/slider'; -export { Carousel }; +export { Carousel, Slider }; diff --git a/src/styles/slider/styles.module.css b/src/styles/slider/styles.module.css new file mode 100644 index 0000000..ffd21e5 --- /dev/null +++ b/src/styles/slider/styles.module.css @@ -0,0 +1,20 @@ +.sliderBase { + width: 100%; + position: relative; +} + +.slider { + display: flex; + overflow-x: auto; + scrollbar-width: none; /* Firefox 64 */ + -ms-overflow-style: none; /* Internet Explorer 11 */ +} + +.slider::-webkit-scrollbar { + /** WebKit */ + display: none; +} + +.slider > * { + flex: 0 0 auto; +} diff --git a/src/styles/slider/styles.module.css.d.ts b/src/styles/slider/styles.module.css.d.ts new file mode 100644 index 0000000..beb1d0c --- /dev/null +++ b/src/styles/slider/styles.module.css.d.ts @@ -0,0 +1,8 @@ +export const sliderBase: string; +export const slider: string; +interface Namespace { + sliderBase: string; + slider: string; +} +declare const stylesModule: Namespace; +export default stylesModule;