From e3c10314848c93ee809b9937bc4b895106f5a312 Mon Sep 17 00:00:00 2001 From: sajjad Date: Mon, 4 Sep 2023 10:10:12 +0200 Subject: [PATCH] Add autoPlay --- README.md | 17 ++++++++-------- package.json | 2 +- src/components/Carousel.tsx | 39 ++++++++++++++++++++++++++++++------- src/dev/Playground.tsx | 28 +++++++++++++++----------- 4 files changed, 59 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index a0f9edd..3a7ed86 100644 --- a/README.md +++ b/README.md @@ -78,11 +78,12 @@ And you're all set. You can also use props for better control of how the carouse ## Props -| Name | Default value | Description | -| --------------- | -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| slides | --- | An array containing elements of the form `{ key, content, onClick? }` where key holds any unique value and content holds a reference to a JSX `` to be displayed. onClick is an optional property that may be used to pass a callback method which will be invoked when the slide is clicked. | -| goToSlide | `null` | Setting this prop will cause the carousel to animate towards the provided index in the slides array. If `showNavigation` is set to false this prop is how you're expected to control the carousel. | -| goToSlideDelay | `200` | The amount of milliseconds to delay each slide before moving to the next one while animating towards the index provided in `goToSlide`. | -| offsetRadius | `2` | Number of carousel elements to display to the sides of the current slide, this value is clamped between `1` and `Math.floor(slides.length/2)`, and defaults to 2 when it's possible (if there are enough slide elements). | -| animationConfig | `{ tension: 120, friction: 14 }` | A config object passed to the slides' Spring element to control the nature of their animation, for more information check the [react-spring docs](http://react-spring.surge.sh/#/api#configs). | -| offsetFn | `undefined` | An optional callback function invoked with `(offsetFromRadius: number, index: number)` by each slide per animation to override its style in relation to its current offset (negative numbers are to the left of the center, positive are to the right, with 0 being the center) and index. Should return an object `{ transform?: string; left?: string \| number; opacity?: number }`. Any missing key within the object would trigger the default style behaviours. e.g. `(offsetFromCenter) => ({ opacity: 1 - Math.abs(offsetFromCenter) / 10 })` would change the way the opacity is rendered but not affect `transform` or `left`. +| Name | Default value | Description | +| --------------- | -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| slides | --- | An array containing elements of the form `{ key, content, onClick? }` where key holds any unique value and content holds a reference to a JSX `` to be displayed. onClick is an optional property that may be used to pass a callback method which will be invoked when the slide is clicked. | +| goToSlide | `null` | Setting this prop will cause the carousel to animate towards the provided index in the slides array. If `showNavigation` is set to false this prop is how you're expected to control the carousel. | +| goToSlideDelay | `200` | The amount of milliseconds to delay each slide before moving to the next one while animating towards the index provided in `goToSlide`. | +| offsetRadius | `2` | Number of carousel elements to display to the sides of the current slide, this value is clamped between `1` and `Math.floor(slides.length/2)`, and defaults to 2 when it's possible (if there are enough slide elements). | +| animationConfig | `{ tension: 120, friction: 14 }` | A config object passed to the slides' Spring element to control the nature of their animation, for more information check the [react-spring docs](http://react-spring.surge.sh/#/api#configs). | +| offsetFn | `undefined` | An optional callback function invoked with `(offsetFromRadius: number, index: number)` by each slide per animation to override its style in relation to its current offset (negative numbers are to the left of the center, positive are to the right, with 0 being the center) and index. Should return an object `{ transform?: string; left?: string \| number; opacity?: number }`. Any missing key within the object would trigger the default style behaviours. e.g. `(offsetFromCenter) => ({ opacity: 1 - Math.abs(offsetFromCenter) / 10 })` would change the way the opacity is rendered but not affect `transform` or `left`. | +| autoPlay | `undefined` | The amount of milliseconds to delay each slide before moving to the next one automatically. | diff --git a/package.json b/package.json index 054cb6b..dafc590 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-spring-3d-carousel", - "version": "1.3.4", + "version": "1.3.5", "repository": { "type": "git", "url": "git+https://github.com/gutiguy/react-spring-3d-carousel" diff --git a/src/components/Carousel.tsx b/src/components/Carousel.tsx index 1045544..d412c9f 100644 --- a/src/components/Carousel.tsx +++ b/src/components/Carousel.tsx @@ -28,15 +28,16 @@ const NavigationButtons = styled.div` const DEFAULT_GO_TO_SLIDE_DELAY = 200; export type OffsetFn = ( - offsetFromCenter: number, - index: number - ) => { transform?: string; left?: string | number; opacity?: number }; + offsetFromCenter: number, + index: number +) => { transform?: string; left?: string | number; opacity?: number }; interface IState { index: number; goToSlide: number | null; prevPropsGoToSlide: number; newSlide: boolean; + mouseIn: boolean; } interface IProps { @@ -46,7 +47,8 @@ interface IProps { offsetRadius: number; animationConfig: object; goToSlideDelay: number; - offsetFn?: OffsetFn + autoPlay?: number; + offsetFn?: OffsetFn; } function mod(a: number, b: number): number { @@ -59,9 +61,11 @@ class Carousel extends Component { goToSlide: null, prevPropsGoToSlide: 0, newSlide: false, + mouseIn: false, }; goToIn?: number; + autoInterval?: any; static propTypes = { slides: PropTypes.arrayOf( @@ -76,6 +80,7 @@ class Carousel extends Component { animationConfig: PropTypes.object, goToSlideDelay: PropTypes.number, offsetFn: PropTypes.func, + autoPlay: PropTypes.number, }; static defaultProps = { @@ -95,7 +100,7 @@ class Carousel extends Component { } componentDidUpdate() { - const { goToSlideDelay } = this.props; + const { goToSlideDelay, autoPlay } = this.props; const { index, goToSlide, newSlide } = this.state; if (typeof goToSlide === "number") { if (newSlide) { @@ -107,12 +112,28 @@ class Carousel extends Component { window.clearTimeout(this.goToIn); } } + if (autoPlay && !this.state.mouseIn) { + if (!this.autoInterval) + this.autoInterval = setInterval(() => this.moveSlide(1), autoPlay); + } else { + clearInterval(this.autoInterval); + this.autoInterval = null; + } + } + + componentDidMount(): void { + const { autoPlay } = this.props; + if (autoPlay && !this.state.mouseIn && !this.autoInterval) { + this.autoInterval = setInterval(() => this.moveSlide(1), autoPlay); + } } componentWillUnmount() { if (typeof window !== "undefined") { window.clearTimeout(this.goToIn); } + clearInterval(this.autoInterval); + this.autoInterval = null; } modBySlidesLength = (index: number): number => { @@ -190,7 +211,8 @@ class Carousel extends Component { } render() { - const { animationConfig, offsetRadius, showNavigation, offsetFn } = this.props; + const { animationConfig, offsetRadius, showNavigation, offsetFn } = + this.props; let navigationButtons = null; if (showNavigation) { @@ -212,7 +234,10 @@ class Carousel extends Component { } return ( - + this.setState((s) => ({ ...s, mouseIn: true }))} + onMouseLeave={() => this.setState((s) => ({ ...s, mouseIn: false }))} + > {this.getPresentableSlides().map( (slide: Slide, presentableIndex: number) => ( + content: 1, }, { key: uuidv4(), - content: 2 + content: 2, }, { key: uuidv4(), - content: 3 + content: 3, }, { key: uuidv4(), - content: 4 + content: 4, }, { key: uuidv4(), - content: 6 + content: 6, }, { key: uuidv4(), - content: 7 + content: 7, }, { key: uuidv4(), - content: 8 + content: 8, }, { key: uuidv4(), - content: 9 - } + content: 9, + }, ].map((slide, index) => { return { ...slide, onClick: () => this.setState({ goToSlide: index }) }; }); onChangeInput = (e: React.ChangeEvent) => { this.setState({ - [e.target.name]: parseInt(e.target.value, 10) || 0 + [e.target.name]: parseInt(e.target.value, 10) || 0, }); }; @@ -65,6 +66,7 @@ export default class Example extends Component { offsetRadius={this.state.offsetRadius} showNavigation={this.state.showNavigation} animationConfig={this.state.config} + autoPlay={this.state.autoPlay} />
@@ -87,6 +89,10 @@ export default class Example extends Component {
+
+ + +