From a5a90d91d73c4fcd501ee96fa8bf9f7d8a71184e Mon Sep 17 00:00:00 2001 From: Yifan Ai Date: Tue, 21 Dec 2021 21:48:43 +1100 Subject: [PATCH 1/3] Fix swiping stuck after zoom (issue #44) - second attempt --- src/components/Carousel/Carousel.module.css | 1 + src/utils/useTouch.js | 24 ++++++++++++++------- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/components/Carousel/Carousel.module.css b/src/components/Carousel/Carousel.module.css index 3ea81eb..b12c34f 100644 --- a/src/components/Carousel/Carousel.module.css +++ b/src/components/Carousel/Carousel.module.css @@ -42,6 +42,7 @@ display: flex; justify-content: flex-start; align-items: flex-start; + touch-action: auto; flex: 0 1 auto; } diff --git a/src/utils/useTouch.js b/src/utils/useTouch.js index 3d4f660..cb5b608 100644 --- a/src/utils/useTouch.js +++ b/src/utils/useTouch.js @@ -10,10 +10,7 @@ const getTouchDistinguisher = () => { } function _isPinch(event) { - return ( - (event.touches !== undefined && event.touches.length > 1) || - (event.scale !== undefined && event.scale !== 1) - ); + return event.touches !== undefined && event.touches.length > 1; } function _wasPinch(event) { @@ -50,8 +47,19 @@ const useTouch = (elementRef, { onTouchMove, onTouchEnd, onTap }) => { event.preventDefault(); }; - const shouldOmitEvent = (event) => { - return !!touchDistinguisher.isPinch(event); + const shouldOmitEvent = (event, displacementX = 0) => { + if (touchDistinguisher.isPinch(event)) return true; + + // window.visualViewport is not yet supported on IE + if (!('visualViewport' in window)) return false; + + const { scale, offsetLeft, width } = window.visualViewport; + if (scale <= 1) return false; + // pan right at or beyond the left edge + if (offsetLeft <= 0 && displacementX > 0) return false; + // pan left at or beyond the right edge + if (offsetLeft + width >= width * scale && displacementX < 0) return false; + return true; }; const handleTouchStart = (event) => { @@ -67,7 +75,7 @@ const useTouch = (elementRef, { onTouchMove, onTouchEnd, onTap }) => { event.stopPropagation(); if (!isTouchStarted) return; const displacementX = event.changedTouches[0].clientX - touchStartX; - if (shouldOmitEvent(event)) return; + if (shouldOmitEvent(event, displacementX)) return; const displacementY = event.changedTouches[0].clientY - touchStartY; handleVerticalMovement(event, displacementX, displacementY); onTouchMove(displacementX, displacementY); @@ -83,7 +91,7 @@ const useTouch = (elementRef, { onTouchMove, onTouchEnd, onTap }) => { event.stopPropagation(); if (!isTouchStarted) return; const displacementX = event.changedTouches[0].clientX - touchStartX; - if (shouldOmitEvent(event)) { + if (shouldOmitEvent(event, displacementX)) { onTouchEnd(0, 0, 0); return; } From c732cddc3a79eaf3d3eac48938596b1abe344263 Mon Sep 17 00:00:00 2001 From: Yifan Ai Date: Thu, 23 Dec 2021 16:10:07 +1100 Subject: [PATCH 2/3] Simplify Gatsby example --- .../gatsby-config.js | 2 +- .../src/components/Carousel1.js | 91 -------------- .../src/components/Carousel2.js | 28 ----- .../src/components/Carousel3.js | 27 ---- .../src/components/Carousel4.js | 65 ---------- .../src/components/Carousel5.js | 118 ------------------ .../src/pages/index.js | 36 +----- .../src/styles/index.css | 111 ---------------- .../src/utils/TwoWayMap.js | 19 --- 9 files changed, 4 insertions(+), 493 deletions(-) delete mode 100644 react-gallery-carousel-gatsby/src/components/Carousel1.js delete mode 100644 react-gallery-carousel-gatsby/src/components/Carousel2.js delete mode 100644 react-gallery-carousel-gatsby/src/components/Carousel3.js delete mode 100644 react-gallery-carousel-gatsby/src/components/Carousel4.js delete mode 100644 react-gallery-carousel-gatsby/src/components/Carousel5.js delete mode 100644 react-gallery-carousel-gatsby/src/styles/index.css delete mode 100644 react-gallery-carousel-gatsby/src/utils/TwoWayMap.js diff --git a/react-gallery-carousel-gatsby/gatsby-config.js b/react-gallery-carousel-gatsby/gatsby-config.js index b45f9d6..659b2b9 100644 --- a/react-gallery-carousel-gatsby/gatsby-config.js +++ b/react-gallery-carousel-gatsby/gatsby-config.js @@ -3,7 +3,7 @@ module.exports = { title: 'react-gallery-carousel Gatsby example', description: 'react-gallery-carousel is a mobile-friendly dependency-free React carousel component with support for touch, mouse dragging, lazy loading, thumbnails, modal, keyboard navigation, RTL and pinch to zoom.', - url: 'https://rgc.yifanai.com', + url: 'https://yifanai.com/rgc', image: '/images/icon.png', twitterUsername: '@yifaneye' }, diff --git a/react-gallery-carousel-gatsby/src/components/Carousel1.js b/react-gallery-carousel-gatsby/src/components/Carousel1.js deleted file mode 100644 index 8fef2b7..0000000 --- a/react-gallery-carousel-gatsby/src/components/Carousel1.js +++ /dev/null @@ -1,91 +0,0 @@ -import React from 'react'; -// import TwoWayMap from '../utils/TwoWayMap'; -import Carousel from 'react-gallery-carousel'; -import 'react-gallery-carousel/dist/index.css'; - -const Carousel1 = () => { - // const indexToTitle = new TwoWayMap({ - // 0: 'Introduction', - // 1: 'Get%20Started', - // 2: 'Usage' - // }); - - return ( -
-
-

- Example 1: Customized carousel with user-managed slides{' '} - code -

-

- This example has custom elements in slides (user-managed slides) using - the children prop; and custom widget positions. -

-
-
- { - // const title = indexToTitle.get(curIndex); - // window.history.replaceState( - // undefined, - // undefined, - // `#${title}` - // ); - // document.title = `${title} | react-gallery-carousel`; - // }} // this callback can be set to update the document title and URL hash on index update - style={{ userSelect: 'text' }} - > -
-

Introduction

-

- react-gallery-carousel is a mobile-friendly - dependency-free React carousel component with support for touch, - mouse dragging, lazy loading, thumbnails, modal, keyboard - navigation, RTL and pinch to zoom. -

- Demo - / - - GitHub - - / - - npm - - / - - Documentation - -
-
-

Get Started

- npm install react-gallery-carousel --save -
- or -
- yarn add react-gallery-carousel -
-
-

Usage

-

The default carousel shown below as example 2 is created by:

- {''} -
-
-
-
- ); -}; - -export default Carousel1; diff --git a/react-gallery-carousel-gatsby/src/components/Carousel2.js b/react-gallery-carousel-gatsby/src/components/Carousel2.js deleted file mode 100644 index ece5fd2..0000000 --- a/react-gallery-carousel-gatsby/src/components/Carousel2.js +++ /dev/null @@ -1,28 +0,0 @@ -import React from 'react'; -import Carousel from 'react-gallery-carousel'; -import 'react-gallery-carousel/dist/index.css'; - -const Carousel2 = ({ images }) => { - return ( -
-
-

- Example 2: Default carousel with images{' '} - code -

-

- A default carousel example has lazy loading and preloading (the 2 - adjacent images on either side of the current image); touch swiping - and mouse dragging on the carousel; touch swiping, mouse dragging and - wheel scrolling on the thumbnails; touch swipe down to exit the - maximized carousel; and keyboard navigation. -

-
-
- -
-
- ); -}; - -export default Carousel2; diff --git a/react-gallery-carousel-gatsby/src/components/Carousel3.js b/react-gallery-carousel-gatsby/src/components/Carousel3.js deleted file mode 100644 index c9e01d4..0000000 --- a/react-gallery-carousel-gatsby/src/components/Carousel3.js +++ /dev/null @@ -1,27 +0,0 @@ -import React from 'react'; -import Carousel from 'react-gallery-carousel'; -import 'react-gallery-carousel/dist/index.css'; - -const Carousel3 = ({ images }) => { - return ( -
-
-

- Example 3: Default carousel with images and with right-to-left (RTL){' '} - code -

-

- A default carousel example has lazy loading and preloading; touch - swiping and mouse dragging on the carousel; touch swiping, mouse - dragging and wheel scrolling on the thumbnails; touch swipe down to - exit the maximized carousel; and keyboard navigation. -

-
-
- -
-
- ); -}; - -export default Carousel3; diff --git a/react-gallery-carousel-gatsby/src/components/Carousel4.js b/react-gallery-carousel-gatsby/src/components/Carousel4.js deleted file mode 100644 index 44657c2..0000000 --- a/react-gallery-carousel-gatsby/src/components/Carousel4.js +++ /dev/null @@ -1,65 +0,0 @@ -import React, { useEffect, useState } from 'react'; -import Carousel from 'react-gallery-carousel'; -import 'react-gallery-carousel/dist/index.css'; - -const Carousel4 = ({ images }) => { - const [dynamicImages, setDynamicImages] = useState([]); - - useEffect(() => { - setDynamicImages(images); - }, [setDynamicImages, images]); - - return ( -
-
-

- Example 4: Customized carousel with dynamic images{' '} - (available from v0.1.1){' '} - code -

-

- This example has images dynamically set in the{' '} - useEffect() hook. This customized example additionally - has click to enter and exit the maximized carousel; - custom initial index; custom widget positions; custom thumbnails, - custom dot buttons and captions for the maximized carousel; custom - active and passive dot buttons; and custom styles for the - non-maximized carousel. -

-
-
- - 🔳 - - } - passiveIcon={ - - 🔲 - - } - /> -
-
- ); -}; - -export default Carousel4; diff --git a/react-gallery-carousel-gatsby/src/components/Carousel5.js b/react-gallery-carousel-gatsby/src/components/Carousel5.js deleted file mode 100644 index 532c2cb..0000000 --- a/react-gallery-carousel-gatsby/src/components/Carousel5.js +++ /dev/null @@ -1,118 +0,0 @@ -import React, { useRef } from 'react'; -import Carousel from 'react-gallery-carousel'; -import 'react-gallery-carousel/dist/index.css'; -import { Button } from 'react-responsive-button'; -import 'react-responsive-button/dist/index.css'; - -const Carousel5 = ({ images }) => { - const carouselRef = useRef(null); - - return ( -
-
-

- Example 5: Default carousel with imperative handlers{' '} - (available from v0.2.0){' '} - code -

-

- To customize the carousel in a declarative manner, pass the props - (e.g. isAutoPlaying, isMaximized,{' '} - index). To customize the carousel in an imperative - manner, use the following handlers (on the ref): -

-
-
-
- -
-
- -
-
- -
-
-
-
- -
-
- -
-
- -
-
-
-
- -
-
- -
-
- -
-
-
-
-
- -
-
- ); -}; - -export default Carousel5; diff --git a/react-gallery-carousel-gatsby/src/pages/index.js b/react-gallery-carousel-gatsby/src/pages/index.js index 1a4ee1a..58b3693 100644 --- a/react-gallery-carousel-gatsby/src/pages/index.js +++ b/react-gallery-carousel-gatsby/src/pages/index.js @@ -1,34 +1,4 @@ -import React from 'react'; -import Carousel1 from '../components/Carousel1'; -import Carousel2 from '../components/Carousel2'; -import Carousel3 from '../components/Carousel3'; -import Carousel4 from '../components/Carousel4'; -import Carousel5 from '../components/Carousel5'; -import '../styles/index.css'; +import App from '../../../example/src/App.js'; +import '../../../example/src/index.css'; -const imageIDs = Array(30) // the maximum is currently 149 - .fill(1) - .map((_, i) => i + 1); -const images = imageIDs.map((imageID) => { - return { - src: `https://placedog.net/400/240?id=${imageID}`, - srcset: `https://placedog.net/400/240?id=${imageID} 400w, https://placedog.net/700/420?id=${imageID} 700w, https://placedog.net/1000/600?id=${imageID} 1000w`, - sizes: '(max-width: 1000px) 400px, (max-width: 2000px) 700px, 1000px', - alt: `Dog No. ${imageID}. Dogs are domesticated mammals, not natural wild animals.`, - thumbnail: `https://placedog.net/100/60?id=${imageID}` - }; -}); - -const IndexPage = () => { - return ( -
- - - - - -
- ); -}; - -export default IndexPage; +export default App; diff --git a/react-gallery-carousel-gatsby/src/styles/index.css b/react-gallery-carousel-gatsby/src/styles/index.css deleted file mode 100644 index 0c4ac06..0000000 --- a/react-gallery-carousel-gatsby/src/styles/index.css +++ /dev/null @@ -1,111 +0,0 @@ -body { - margin: 0; - padding: 0; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -code { - font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', - monospace; - padding: 0.2em 0.4em; - margin: 0; - font-size: 85%; - background-color: rgba(27, 31, 35, 0.05); - border-radius: 6px; -} - -.text-slide { - padding: 1rem 50px; -} - -.vertical-separator { - margin: 1em 0; -} - -.carousel-page { - max-width: 1200px; - margin: 0 auto; - overflow: hidden; -} - -.carousel-page-header-container { - width: 100%; -} - -.carousel-page-header { - display: flex; - flex-direction: column; - align-items: center; - padding: 0 1em; -} - -.action-container { - padding: 0 1em; -} - -.star-button-container { - height: 20px; - margin-top: 10px; - margin-bottom: 10px; -} - -.section { - margin-bottom: 60px; -} - -.section-header { - padding: 0 1em; -} - -.carousel-container { - width: 100%; - height: calc(100vw * 0.8); -} - -@media only screen and (min-width: 500px) and (max-width: 1280px) { - .carousel-container { - height: calc(100vw * 0.6); - max-height: 768px; - } -} - -@media only screen and (min-width: 1280px) { - .carousel-container { - height: 768px; - } -} - -.carousel-container.short { - height: 300px; -} - -.buttons { - margin: 10px 0; - display: flex; - flex-wrap: wrap; -} - -.button-container { - margin-bottom: 10px; -} - -.button-container:not(:last-child) { - margin-right: 10px; -} - -.framed-carousel { - border: 5px solid #eee; - overflow: hidden; - border-radius: 10px; - will-change: transform; - mask-image: -webkit-radial-gradient(white, black); - box-sizing: border-box; -} - -.icon-text { - color: white; -} diff --git a/react-gallery-carousel-gatsby/src/utils/TwoWayMap.js b/react-gallery-carousel-gatsby/src/utils/TwoWayMap.js deleted file mode 100644 index afc9af5..0000000 --- a/react-gallery-carousel-gatsby/src/utils/TwoWayMap.js +++ /dev/null @@ -1,19 +0,0 @@ -export default class TwoWayMap { - constructor(map) { - this.map = map; - this.reversedMap = {}; - - Object.keys(map).forEach((key) => { - const value = map[key]; - this.reversedMap[value] = key; - }); - } - - get = (key) => { - return this.map[key]; - }; - - getReversed = (key) => { - return this.reversedMap[key]; - }; -} From 04c969df544b3fd1c7719766fd5a8df4041f77de Mon Sep 17 00:00:00 2001 From: Yifan Ai Date: Fri, 24 Dec 2021 16:28:45 +1100 Subject: [PATCH 3/3] v0.2.8 --- CHANGELOG.md | 10 +++ example/src/components/Footer.js | 2 +- package.json | 2 +- .../__snapshots__/Carousel.test.js.snap | 66 +++++++++---------- 4 files changed, 45 insertions(+), 35 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 63a7652..513ddb8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,16 @@ [![NPM](https://img.shields.io/npm/v/react-gallery-carousel.svg)](https://www.npmjs.com/package/react-gallery-carousel) +## v0.2.8 (2021-12-23) + +### Bug Fixes + +- Second attempt to fix swiping stuck after zoom issue. + ([Issue #44](https://github.com/yifaneye/react-gallery-carousel/issues/44)) + +### Enhancements + +- Simplify Gatsby example ## v0.2.7 (2021-12-18) diff --git a/example/src/components/Footer.js b/example/src/components/Footer.js index 0d7f8bb..3ddfc21 100644 --- a/example/src/components/Footer.js +++ b/example/src/components/Footer.js @@ -5,7 +5,7 @@ const Footer = () => { return (