From caaba9272fbf52b52715a9e43cad288a8e91353b Mon Sep 17 00:00:00 2001 From: jiangbo11 Date: Wed, 20 Oct 2021 11:14:22 +0800 Subject: [PATCH] feat: dots --- .DS_Store | Bin 0 -> 6148 bytes CHANGELOG.md | 8 ++++ README.md | 51 ++++++++++++++---------- package.json | 8 ++-- src/arrow.tsx | 33 ++++++++++++++++ src/carousel.tsx | 101 ++++++++++++----------------------------------- src/dots.tsx | 38 ++++++++++++++++++ src/slider.tsx | 29 ++++++++++++++ src/types.ts | 35 ++++++++++++++++ 9 files changed, 203 insertions(+), 100 deletions(-) create mode 100644 .DS_Store create mode 100644 src/arrow.tsx create mode 100644 src/dots.tsx create mode 100644 src/slider.tsx create mode 100644 src/types.ts diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..fc5ba3b575b9a703b7a3d4d27230f9f983e825a4 GIT binary patch literal 6148 zcmeHK%}N6?5Kh{v*^1bMV2`!Ckl@gOX<9=r)FdQfS1*t^o@K1 zU&omwEtV>H60tKd`6iQ@gnYYX62=&Bjr|&9CB~QlMa)^yd?7fFx+FQ{LF71xm&QYH z5P8slTZ$&fUt|EkU4i*5U@=QRe?Mpq=lsbuoAf+#u|YRC3_=AmsWo2>mE+MdQ$q)jWh;5lY#i366**}(s};H5IG9c?vAb70I_=&)JWigb&o7!)4nLrhZG$s-1!KO! zduJ35qVN`cv-nvYAu&J<5Cbd3fH?xi<_hhZwn_{T13zN`&j$&LXdBEls-puMyguT1 z0TBgkd`loogSNp;BaDD>oeHQ^xp`u6oeq9!;%tMNMxD;MS{ddsD|7Qg;c9j8OBK$z zt&v({fEZY0Ag{Y6tp6w9zyBALs7DMC1OJKvUT8b*7HrAX)}_s1t(Bl%P!x>IG|p4N iP^B1Ru@sj ( export default App; ``` +## images carousel + +`img` element should add `draggable=false` + +```jsx +
+ + {[1, 2, 3, 4].map((item, i) => ( + + ))} + +
+``` + ## Example [Live Demo](https://carousel-app-772051431.vercel.app) ![example](https://raw.githubusercontent.com/jiangbo2015/framer-motion-carousel/main/img.jpg) -## Use your arrows -``` -renderArrowLeft: ({handlePrev, activeIndex}) => React.ReactNode -``` - -``` -renderArrowRight: ({handleNext, activeIndex}) => React.ReactNode -``` - -```jsx -const App = () => ( -
}> - ... - -) -``` +## props -## Todo +| props | type | default | description | +|------------------|--------------------------------------------------------------------------------------|---------|--------------------| +| autoPlay | boolean | true | auto play | +| interval | number | 2000 | auto play interval | +| renderArrowLeft | ({handlePrev: () => void, activeIndex: number}) => React.ReactNode | null | custom your arrows | +| renderArrowRight | ({handleNext: () => void, activeIndex: number}) => React.ReactNode | null | custom your arrows | +| renderDots | ({activeIndex: number, setActiveIndex: (index: number) => void;}) => React.ReactNode | null | custom your dots | -- dots -- custom dots ## Development diff --git a/package.json b/package.json index 1b2dcee..44892a4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "framer-motion-carousel", - "version": "1.0.3", + "version": "1.0.5", "description": "A simple framer motion carousel component for React", "keywords": [ "react", @@ -8,8 +8,10 @@ "carousel", "motion", "framer", - "collapse", - "framer motion" + "swipe", + "image gallary", + "framer motion", + "chakra ui" ], "author": "jiangbo2015 ", "homepage": "https://github.com/jiangbo2015/framer-motion-carousel.git#readme", diff --git a/src/arrow.tsx b/src/arrow.tsx new file mode 100644 index 0000000..a4baada --- /dev/null +++ b/src/arrow.tsx @@ -0,0 +1,33 @@ +import React from 'react' +import {ArrowProps} from './types' + +const baseArrowStyle: React.CSSProperties = { + position: "absolute", + width: "50px", + height: "50px", + backgroundColor: "rgba(0,0,0,0.5)", + top: "50%", + transform: "translateY(-50%)", + borderRadius: "50%", + color: "#fff", + fontSize: "20px", + display: "flex", + alignItems: "center", + justifyContent: "center", + cursor: "pointer", +} + +const Arrow = ({ left = false, children, onClick }: ArrowProps) => ( +
+ {children} +
+) + +export default Arrow \ No newline at end of file diff --git a/src/carousel.tsx b/src/carousel.tsx index 9fa8636..5ef3531 100755 --- a/src/carousel.tsx +++ b/src/carousel.tsx @@ -4,11 +4,15 @@ import { AnimationOptions, motion, MotionStyle, - MotionValue, PanInfo, useMotionValue, } from "framer-motion" +import { CarouselProps } from "./types" +import Arrow from "./arrow" +import Slider from "./slider" +import Dots from "./dots" + const containerStyle: React.CSSProperties = { position: "relative", width: "100%", @@ -17,13 +21,6 @@ const containerStyle: React.CSSProperties = { display: "flex", } -const pageStyle: MotionStyle = { - width: "100%", - height: "100%", - display: "inline-block", - flex: "none", -} - const transition: AnimationOptions = { type: "spring", bounce: 0, @@ -38,78 +35,13 @@ const Contaier = React.forwardRef<
)) -type SliderProps = { - x: MotionValue - i: number - children: React.ReactNode - onDragEnd: (e: Event, dragProps: PanInfo) => void -} -const Slider = ({ x, i, onDragEnd, children }: SliderProps) => ( - - {children} - -) - -const baseArrowStyle: React.CSSProperties = { - position: "absolute", - width: "50px", - height: "50px", - backgroundColor: "rgba(0,0,0,0.5)", - top: "50%", - transform: "translateY(-50%)", - borderRadius: "50%", - color: "#fff", - fontSize: "20px", - display: "flex", - alignItems: "center", - justifyContent: "center", - cursor: "pointer", -} - -type ArrowProps = { - onClick: () => void - left?: boolean - children: React.ReactNode -} - -const Arrow = ({ left = false, children, onClick }: ArrowProps) => ( -
- {children} -
-) - -type CarouselProps = { - children: React.ReactNode - renderArrowLeft?: (args: { - handlePrev: () => void - activeIndex: number - }) => void - renderArrowRight?: (args: { - handleNext: () => void - activeIndex: number - }) => void -} export const Carousel = ({ children, renderArrowLeft, renderArrowRight, + renderDots, + autoPlay = true, + interval = 2000, }: CarouselProps) => { const x = useMotionValue(0) const containerRef = React.useRef(null) @@ -147,6 +79,14 @@ export const Carousel = ({ return controls.stop }, [index]) + React.useEffect(() => { + if(!autoPlay) { + return; + } + const timer = setInterval(() => handleNext(), interval) + return clearInterval(timer) + }, [handleNext, interval]) + return ( {childrens.map((child, i) => ( @@ -154,6 +94,7 @@ export const Carousel = ({ {child} ))} + {/* left arrow */} {renderArrowLeft ? ( renderArrowLeft({ handlePrev, activeIndex: index }) ) : ( @@ -162,11 +103,19 @@ export const Carousel = ({ )} + {/* right arrow */} {renderArrowRight ? ( renderArrowRight({ handleNext, activeIndex: index }) ) : ( )} + + {/* dots */} + {renderDots ? ( + renderDots({ setActiveIndex: setIndex, activeIndex: index }) + ) : ( + + )} ) } diff --git a/src/dots.tsx b/src/dots.tsx new file mode 100644 index 0000000..e87684a --- /dev/null +++ b/src/dots.tsx @@ -0,0 +1,38 @@ +import React from "react" +import { DotProps } from "./types" + +const dotWrapStyle: React.CSSProperties = { + position: "absolute", + bottom: "10px", + left: "50%", + transform: "translateX(-50%)", +} + +const dotItemStyle: React.CSSProperties = { + width: "20px", + height: "20px", + borderRadius: "50%", + margin: "0 10px", + display: "inline-block", + cursor: "pointer", +} + +const Dots = ({ length, activeIndex, setActiveIndex }: DotProps) => { + return ( +
+ {new Array(length).fill("").map((_, i) => ( + setActiveIndex(i)} + key={i} + style={{ + ...dotItemStyle, + background: i === activeIndex ? "#000" : "#999", + transform: `scale(${i === activeIndex ? 1.3 : 1})`, + }} + > + ))} +
+ ) +} + +export default Dots diff --git a/src/slider.tsx b/src/slider.tsx new file mode 100644 index 0000000..b583af8 --- /dev/null +++ b/src/slider.tsx @@ -0,0 +1,29 @@ + +import React from 'react' +import { motion, MotionStyle } from 'framer-motion' +import { SliderProps } from './types' + +const pageStyle: MotionStyle = { + width: "100%", + height: "100%", + display: "inline-block", + flex: "none", +} + +const Slider = ({ x, i, onDragEnd, children }: SliderProps) => ( + + {children} + +) + +export default Slider \ No newline at end of file diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000..06fef2c --- /dev/null +++ b/src/types.ts @@ -0,0 +1,35 @@ +import { MotionValue, PanInfo } from "framer-motion" + +export type CarouselProps = { + children: React.ReactNode + renderArrowLeft?: (args: { + handlePrev: () => void + activeIndex: number + }) => React.ReactNode + renderArrowRight?: (args: { + handleNext: () => void + activeIndex: number + }) => React.ReactNode + renderDots?: (args: Omit) => React.ReactNode + autoPlay: boolean + interval: number +} + +export type ArrowProps = { + onClick: () => void + left?: boolean + children: React.ReactNode +} + +export type SliderProps = { + x: MotionValue + i: number + children: React.ReactNode + onDragEnd: (e: Event, dragProps: PanInfo) => void +} + +export type DotProps = { + length: number + activeIndex: number + setActiveIndex: (index: number) => void; +}