react-image-gallery 1.2.11 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.json +42 -19
- package/.github/workflows/eslint.yml +56 -0
- package/README.md +161 -159
- package/babel.config.js +3 -0
- package/build/image-gallery.js +1 -1
- package/jest.config.js +16 -0
- package/package.json +20 -16
- package/src/{ImageGallery.js → components/ImageGallery.jsx} +443 -353
- package/src/components/ImageGallery.test.jsx +22 -0
- package/src/components/Item.jsx +75 -0
- package/src/{SVG.js → components/SVG.jsx} +16 -22
- package/src/{SwipeWrapper.js → components/SwipeWrapper.jsx} +15 -22
- package/src/{controls/Fullscreen.js → components/controls/Fullscreen.jsx} +6 -10
- package/src/{controls/LeftNav.js → components/controls/LeftNav.jsx} +5 -9
- package/src/{controls/PlayPause.js → components/controls/PlayPause.jsx} +6 -10
- package/src/{controls/RightNav.js → components/controls/RightNav.jsx} +5 -9
- package/styles/css/image-gallery.css +1 -1
- package/styles/scss/image-gallery.scss +10 -10
- package/webpack.build.js +61 -62
- package/webpack.config.js +18 -15
- package/.babelrc +0 -1
- package/.notes +0 -2
- package/src/Item.js +0 -78
- package/tests/ImageGallery.test.js +0 -15
- package/tests/__snapshots__/ImageGallery.test.js.snap +0 -3
- package/tests/setupTestFramework.js +0 -4
|
@@ -1,42 +1,31 @@
|
|
|
1
|
-
import clsx from
|
|
2
|
-
import React from
|
|
3
|
-
import throttle from
|
|
4
|
-
import debounce from
|
|
5
|
-
import isEqual from
|
|
6
|
-
import ResizeObserver from
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
import
|
|
14
|
-
|
|
15
|
-
bool,
|
|
16
|
-
func,
|
|
17
|
-
number,
|
|
18
|
-
oneOf,
|
|
19
|
-
shape,
|
|
20
|
-
string,
|
|
21
|
-
} from 'prop-types';
|
|
22
|
-
import Item from 'src/Item';
|
|
23
|
-
import Fullscreen from 'src/controls/Fullscreen';
|
|
24
|
-
import LeftNav from 'src/controls/LeftNav';
|
|
25
|
-
import RightNav from 'src/controls/RightNav';
|
|
26
|
-
import PlayPause from 'src/controls/PlayPause';
|
|
27
|
-
import SwipeWrapper from 'src/SwipeWrapper';
|
|
1
|
+
import clsx from "clsx";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import throttle from "lodash-es/throttle";
|
|
4
|
+
import debounce from "lodash-es/debounce";
|
|
5
|
+
import isEqual from "react-fast-compare";
|
|
6
|
+
import ResizeObserver from "resize-observer-polyfill";
|
|
7
|
+
import { LEFT, RIGHT, UP, DOWN } from "react-swipeable";
|
|
8
|
+
import { arrayOf, bool, func, number, oneOf, shape, string } from "prop-types";
|
|
9
|
+
import Item from "src/components/Item";
|
|
10
|
+
import Fullscreen from "src/components/controls/Fullscreen";
|
|
11
|
+
import LeftNav from "src/components/controls/LeftNav";
|
|
12
|
+
import RightNav from "src/components/controls/RightNav";
|
|
13
|
+
import PlayPause from "src/components/controls/PlayPause";
|
|
14
|
+
import SwipeWrapper from "src/components/SwipeWrapper";
|
|
28
15
|
|
|
29
16
|
const screenChangeEvents = [
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
17
|
+
"fullscreenchange",
|
|
18
|
+
"MSFullscreenChange",
|
|
19
|
+
"mozfullscreenchange",
|
|
20
|
+
"webkitfullscreenchange",
|
|
34
21
|
];
|
|
35
22
|
|
|
36
|
-
const imageSetType = arrayOf(
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
23
|
+
const imageSetType = arrayOf(
|
|
24
|
+
shape({
|
|
25
|
+
srcSet: string,
|
|
26
|
+
media: string,
|
|
27
|
+
})
|
|
28
|
+
);
|
|
40
29
|
|
|
41
30
|
function isEnterOrSpaceKey(event) {
|
|
42
31
|
const key = parseInt(event.keyCode || event.which || 0, 10);
|
|
@@ -91,7 +80,9 @@ class ImageGallery extends React.Component {
|
|
|
91
80
|
// Used to update the throttle if slideDuration changes
|
|
92
81
|
this.unthrottledSlideToIndex = this.slideToIndex;
|
|
93
82
|
this.slideToIndex = throttle(
|
|
94
|
-
this.unthrottledSlideToIndex,
|
|
83
|
+
this.unthrottledSlideToIndex,
|
|
84
|
+
props.slideDuration,
|
|
85
|
+
{ trailing: false }
|
|
95
86
|
);
|
|
96
87
|
|
|
97
88
|
if (props.lazyLoad) {
|
|
@@ -105,12 +96,14 @@ class ImageGallery extends React.Component {
|
|
|
105
96
|
this.play();
|
|
106
97
|
}
|
|
107
98
|
if (useWindowKeyDown) {
|
|
108
|
-
window.addEventListener(
|
|
99
|
+
window.addEventListener("keydown", this.handleKeyDown);
|
|
109
100
|
} else {
|
|
110
|
-
this.imageGallery.current.addEventListener(
|
|
101
|
+
this.imageGallery.current.addEventListener("keydown", this.handleKeyDown);
|
|
111
102
|
}
|
|
112
|
-
window.addEventListener(
|
|
113
|
-
window.addEventListener(
|
|
103
|
+
window.addEventListener("mousedown", this.handleMouseDown);
|
|
104
|
+
window.addEventListener("touchmove", this.handleTouchMove, {
|
|
105
|
+
passive: false,
|
|
106
|
+
});
|
|
114
107
|
// we're using resize observer to help with detecting containers size changes as images load
|
|
115
108
|
this.initSlideWrapperResizeObserver(this.imageGallerySlideWrapper);
|
|
116
109
|
this.initThumbnailWrapperResizeObserver(this.thumbnailsWrapper);
|
|
@@ -132,10 +125,14 @@ class ImageGallery extends React.Component {
|
|
|
132
125
|
const itemsSizeChanged = prevProps.items.length !== items.length;
|
|
133
126
|
const itemsChanged = !isEqual(prevProps.items, items);
|
|
134
127
|
const startIndexUpdated = prevProps.startIndex !== startIndex;
|
|
135
|
-
const thumbnailsPositionChanged =
|
|
128
|
+
const thumbnailsPositionChanged =
|
|
129
|
+
prevProps.thumbnailPosition !== thumbnailPosition;
|
|
136
130
|
const showThumbnailsChanged = prevProps.showThumbnails !== showThumbnails;
|
|
137
131
|
|
|
138
|
-
if (
|
|
132
|
+
if (
|
|
133
|
+
slideInterval !== prevProps.slideInterval ||
|
|
134
|
+
slideDuration !== prevProps.slideDuration
|
|
135
|
+
) {
|
|
139
136
|
// refresh setInterval
|
|
140
137
|
if (isPlaying) {
|
|
141
138
|
this.pause();
|
|
@@ -170,7 +167,9 @@ class ImageGallery extends React.Component {
|
|
|
170
167
|
// if slideDuration changes, update slideToIndex throttle
|
|
171
168
|
if (prevProps.slideDuration !== slideDuration) {
|
|
172
169
|
this.slideToIndex = throttle(
|
|
173
|
-
this.unthrottledSlideToIndex,
|
|
170
|
+
this.unthrottledSlideToIndex,
|
|
171
|
+
slideDuration,
|
|
172
|
+
{ trailing: false }
|
|
174
173
|
);
|
|
175
174
|
}
|
|
176
175
|
if (lazyLoad && (!prevProps.lazyLoad || itemsChanged)) {
|
|
@@ -179,11 +178,17 @@ class ImageGallery extends React.Component {
|
|
|
179
178
|
|
|
180
179
|
if (useWindowKeyDown !== prevProps.useWindowKeyDown) {
|
|
181
180
|
if (useWindowKeyDown) {
|
|
182
|
-
this.imageGallery.current.removeEventListener(
|
|
183
|
-
|
|
181
|
+
this.imageGallery.current.removeEventListener(
|
|
182
|
+
"keydown",
|
|
183
|
+
this.handleKeyDown
|
|
184
|
+
);
|
|
185
|
+
window.addEventListener("keydown", this.handleKeyDown);
|
|
184
186
|
} else {
|
|
185
|
-
window.removeEventListener(
|
|
186
|
-
this.imageGallery.current.addEventListener(
|
|
187
|
+
window.removeEventListener("keydown", this.handleKeyDown);
|
|
188
|
+
this.imageGallery.current.addEventListener(
|
|
189
|
+
"keydown",
|
|
190
|
+
this.handleKeyDown
|
|
191
|
+
);
|
|
187
192
|
}
|
|
188
193
|
}
|
|
189
194
|
|
|
@@ -192,15 +197,15 @@ class ImageGallery extends React.Component {
|
|
|
192
197
|
// do not transition when new items are added
|
|
193
198
|
this.setState({
|
|
194
199
|
currentIndex: startIndex,
|
|
195
|
-
slideStyle: { transition:
|
|
200
|
+
slideStyle: { transition: "none" },
|
|
196
201
|
});
|
|
197
202
|
}
|
|
198
203
|
}
|
|
199
204
|
|
|
200
205
|
componentWillUnmount() {
|
|
201
206
|
const { useWindowKeyDown } = this.props;
|
|
202
|
-
window.removeEventListener(
|
|
203
|
-
window.removeEventListener(
|
|
207
|
+
window.removeEventListener("mousedown", this.handleMouseDown);
|
|
208
|
+
window.removeEventListener("touchmove", this.handleTouchMove);
|
|
204
209
|
this.removeScreenChangeEvent();
|
|
205
210
|
this.removeResizeObserver();
|
|
206
211
|
if (this.playPauseIntervalId) {
|
|
@@ -211,9 +216,12 @@ class ImageGallery extends React.Component {
|
|
|
211
216
|
window.clearTimeout(this.transitionTimer);
|
|
212
217
|
}
|
|
213
218
|
if (useWindowKeyDown) {
|
|
214
|
-
window.removeEventListener(
|
|
219
|
+
window.removeEventListener("keydown", this.handleKeyDown);
|
|
215
220
|
} else {
|
|
216
|
-
this.imageGallery.current.removeEventListener(
|
|
221
|
+
this.imageGallery.current.removeEventListener(
|
|
222
|
+
"keydown",
|
|
223
|
+
this.handleKeyDown
|
|
224
|
+
);
|
|
217
225
|
}
|
|
218
226
|
}
|
|
219
227
|
|
|
@@ -236,15 +244,39 @@ class ImageGallery extends React.Component {
|
|
|
236
244
|
}
|
|
237
245
|
|
|
238
246
|
onThumbnailClick(event, index) {
|
|
239
|
-
const { onThumbnailClick } = this.props;
|
|
247
|
+
const { onThumbnailClick, items } = this.props;
|
|
248
|
+
const { currentIndex } = this.state;
|
|
240
249
|
// blur element to remove outline cause by focus
|
|
241
250
|
event.target.parentNode.parentNode.blur();
|
|
242
|
-
|
|
251
|
+
if (currentIndex !== index) {
|
|
252
|
+
if (items.length === 2) {
|
|
253
|
+
this.slideToIndexWithStyleReset(index, event);
|
|
254
|
+
} else {
|
|
255
|
+
this.slideToIndex(index, event);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
243
258
|
if (onThumbnailClick) {
|
|
244
259
|
onThumbnailClick(event, index);
|
|
245
260
|
}
|
|
246
261
|
}
|
|
247
262
|
|
|
263
|
+
onBulletClick = (event, index) => {
|
|
264
|
+
const { onBulletClick, items } = this.props;
|
|
265
|
+
const { currentIndex } = this.state;
|
|
266
|
+
// blur element to remove outline caused by focus
|
|
267
|
+
event.target.blur();
|
|
268
|
+
if (currentIndex !== index) {
|
|
269
|
+
if (items.length === 2) {
|
|
270
|
+
this.slideToIndexWithStyleReset(index, event);
|
|
271
|
+
} else {
|
|
272
|
+
this.slideToIndex(index, event);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
if (onBulletClick) {
|
|
276
|
+
onBulletClick(event, index);
|
|
277
|
+
}
|
|
278
|
+
};
|
|
279
|
+
|
|
248
280
|
onThumbnailMouseOver(event, index) {
|
|
249
281
|
if (this.thumbnailMouseOverTimer) {
|
|
250
282
|
window.clearTimeout(this.thumbnailMouseOverTimer);
|
|
@@ -290,7 +322,6 @@ class ImageGallery extends React.Component {
|
|
|
290
322
|
|
|
291
323
|
if (disableThumbnailScroll) return 0;
|
|
292
324
|
|
|
293
|
-
|
|
294
325
|
if (thumbsElement) {
|
|
295
326
|
// total scroll required to see the last thumbnail
|
|
296
327
|
if (this.isThumbnailVertical()) {
|
|
@@ -299,7 +330,10 @@ class ImageGallery extends React.Component {
|
|
|
299
330
|
}
|
|
300
331
|
hiddenScroll = thumbsElement.scrollHeight - thumbnailsWrapperHeight;
|
|
301
332
|
} else {
|
|
302
|
-
if (
|
|
333
|
+
if (
|
|
334
|
+
thumbsElement.scrollWidth <= thumbnailsWrapperWidth ||
|
|
335
|
+
thumbnailsWrapperWidth <= 0
|
|
336
|
+
) {
|
|
303
337
|
return 0;
|
|
304
338
|
}
|
|
305
339
|
hiddenScroll = thumbsElement.scrollWidth - thumbnailsWrapperWidth;
|
|
@@ -312,23 +346,50 @@ class ImageGallery extends React.Component {
|
|
|
312
346
|
return 0;
|
|
313
347
|
}
|
|
314
348
|
|
|
349
|
+
getThumbnailPositionClassName(thumbnailPosition) {
|
|
350
|
+
// get the specific thumbnailPosition className
|
|
351
|
+
const leftClassName = "image-gallery-thumbnails-left";
|
|
352
|
+
const rightClassName = "image-gallery-thumbnails-right";
|
|
353
|
+
const bottomClassName = "image-gallery-thumbnails-bottom";
|
|
354
|
+
const topClassName = "image-gallery-thumbnails-top";
|
|
355
|
+
|
|
356
|
+
switch (thumbnailPosition) {
|
|
357
|
+
case "left":
|
|
358
|
+
thumbnailPosition = ` ${leftClassName}`;
|
|
359
|
+
break;
|
|
360
|
+
case "right":
|
|
361
|
+
thumbnailPosition = ` ${rightClassName}`;
|
|
362
|
+
break;
|
|
363
|
+
case "bottom":
|
|
364
|
+
thumbnailPosition = ` ${bottomClassName}`;
|
|
365
|
+
break;
|
|
366
|
+
case "top":
|
|
367
|
+
thumbnailPosition = ` ${topClassName}`;
|
|
368
|
+
break;
|
|
369
|
+
default:
|
|
370
|
+
break;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
return thumbnailPosition;
|
|
374
|
+
}
|
|
375
|
+
|
|
315
376
|
getAlignmentClassName(index) {
|
|
316
377
|
// Necessary for lazing loading
|
|
317
378
|
const { currentIndex } = this.state;
|
|
318
379
|
const { infinite, items } = this.props;
|
|
319
|
-
let alignment =
|
|
320
|
-
const leftClassName =
|
|
321
|
-
const centerClassName =
|
|
322
|
-
const rightClassName =
|
|
380
|
+
let alignment = "";
|
|
381
|
+
const leftClassName = "image-gallery-left";
|
|
382
|
+
const centerClassName = "image-gallery-center";
|
|
383
|
+
const rightClassName = "image-gallery-right";
|
|
323
384
|
|
|
324
385
|
switch (index) {
|
|
325
|
-
case
|
|
386
|
+
case currentIndex - 1:
|
|
326
387
|
alignment = ` ${leftClassName}`;
|
|
327
388
|
break;
|
|
328
|
-
case
|
|
389
|
+
case currentIndex:
|
|
329
390
|
alignment = ` ${centerClassName}`;
|
|
330
391
|
break;
|
|
331
|
-
case
|
|
392
|
+
case currentIndex + 1:
|
|
332
393
|
alignment = ` ${rightClassName}`;
|
|
333
394
|
break;
|
|
334
395
|
default:
|
|
@@ -358,39 +419,44 @@ class ImageGallery extends React.Component {
|
|
|
358
419
|
const secondSlideIsNextSlide = index === 1 && currentIndex === 0;
|
|
359
420
|
const swipingEnded = currentSlideOffset === 0;
|
|
360
421
|
const baseTranslateX = -100 * currentIndex;
|
|
361
|
-
let translateX = baseTranslateX +
|
|
422
|
+
let translateX = baseTranslateX + index * 100 + currentSlideOffset;
|
|
362
423
|
|
|
363
424
|
// keep track of user swiping direction
|
|
364
425
|
// important to understand how to translateX based on last direction
|
|
365
426
|
if (currentSlideOffset > 0) {
|
|
366
|
-
this.direction =
|
|
427
|
+
this.direction = "left";
|
|
367
428
|
} else if (currentSlideOffset < 0) {
|
|
368
|
-
this.direction =
|
|
429
|
+
this.direction = "right";
|
|
369
430
|
}
|
|
370
431
|
|
|
371
|
-
|
|
372
432
|
// when swiping between two slides make sure the next and prev slides
|
|
373
433
|
// are on both left and right
|
|
374
|
-
if (secondSlideIsNextSlide && currentSlideOffset > 0) {
|
|
434
|
+
if (secondSlideIsNextSlide && currentSlideOffset > 0) {
|
|
435
|
+
// swiping right
|
|
375
436
|
translateX = -100 + currentSlideOffset;
|
|
376
437
|
}
|
|
377
|
-
if (firstSlideIsNextSlide && currentSlideOffset < 0) {
|
|
438
|
+
if (firstSlideIsNextSlide && currentSlideOffset < 0) {
|
|
439
|
+
// swiping left
|
|
378
440
|
translateX = 100 + currentSlideOffset;
|
|
379
441
|
}
|
|
380
442
|
|
|
381
443
|
if (indexChanged) {
|
|
382
444
|
// when indexChanged move the slide to the correct side
|
|
383
|
-
if (firstSlideWasPrevSlide && swipingEnded && this.direction ===
|
|
445
|
+
if (firstSlideWasPrevSlide && swipingEnded && this.direction === "left") {
|
|
384
446
|
translateX = 100;
|
|
385
|
-
} else if (
|
|
447
|
+
} else if (
|
|
448
|
+
secondSlideWasPrevSlide &&
|
|
449
|
+
swipingEnded &&
|
|
450
|
+
this.direction === "right"
|
|
451
|
+
) {
|
|
386
452
|
translateX = -100;
|
|
387
453
|
}
|
|
388
454
|
} else {
|
|
389
455
|
// keep the slide on the correct side if the swipe was not successful
|
|
390
|
-
if (secondSlideIsNextSlide && swipingEnded && this.direction ===
|
|
456
|
+
if (secondSlideIsNextSlide && swipingEnded && this.direction === "left") {
|
|
391
457
|
translateX = -100;
|
|
392
458
|
}
|
|
393
|
-
if (firstSlideIsNextSlide && swipingEnded && this.direction ===
|
|
459
|
+
if (firstSlideIsNextSlide && swipingEnded && this.direction === "right") {
|
|
394
460
|
translateX = 100;
|
|
395
461
|
}
|
|
396
462
|
}
|
|
@@ -408,18 +474,14 @@ class ImageGallery extends React.Component {
|
|
|
408
474
|
|
|
409
475
|
getSlideStyle(index) {
|
|
410
476
|
const { currentIndex, currentSlideOffset, slideStyle } = this.state;
|
|
411
|
-
const {
|
|
412
|
-
infinite,
|
|
413
|
-
items,
|
|
414
|
-
useTranslate3D,
|
|
415
|
-
isRTL,
|
|
416
|
-
} = this.props;
|
|
477
|
+
const { infinite, items, useTranslate3D, isRTL } = this.props;
|
|
417
478
|
const baseTranslateX = -100 * currentIndex;
|
|
418
479
|
const totalSlides = items.length - 1;
|
|
419
480
|
|
|
420
481
|
// calculates where the other slides belong based on currentIndex
|
|
421
482
|
// if it is RTL the base line should be reversed
|
|
422
|
-
let translateX =
|
|
483
|
+
let translateX =
|
|
484
|
+
(baseTranslateX + index * 100) * (isRTL ? -1 : 1) + currentSlideOffset;
|
|
423
485
|
|
|
424
486
|
if (infinite && items.length > 2) {
|
|
425
487
|
if (currentIndex === 0 && index === totalSlides) {
|
|
@@ -448,13 +510,13 @@ class ImageGallery extends React.Component {
|
|
|
448
510
|
const isVisible = this.isSlideVisible(index);
|
|
449
511
|
|
|
450
512
|
return {
|
|
451
|
-
display: isVisible ?
|
|
513
|
+
display: isVisible ? "inherit" : "none",
|
|
452
514
|
WebkitTransform: translate,
|
|
453
515
|
MozTransform: translate,
|
|
454
516
|
msTransform: translate,
|
|
455
517
|
OTransform: translate,
|
|
456
518
|
transform: translate,
|
|
457
|
-
...slideStyle
|
|
519
|
+
...slideStyle,
|
|
458
520
|
};
|
|
459
521
|
}
|
|
460
522
|
|
|
@@ -467,7 +529,9 @@ class ImageGallery extends React.Component {
|
|
|
467
529
|
let translate;
|
|
468
530
|
const { useTranslate3D, isRTL } = this.props;
|
|
469
531
|
const { thumbsTranslate, thumbsStyle } = this.state;
|
|
470
|
-
const verticalTranslateValue = isRTL
|
|
532
|
+
const verticalTranslateValue = isRTL
|
|
533
|
+
? thumbsTranslate * -1
|
|
534
|
+
: thumbsTranslate;
|
|
471
535
|
|
|
472
536
|
if (this.isThumbnailVertical()) {
|
|
473
537
|
translate = `translate(0, ${thumbsTranslate}px)`;
|
|
@@ -514,11 +578,13 @@ class ImageGallery extends React.Component {
|
|
|
514
578
|
|
|
515
579
|
items.forEach((item, index) => {
|
|
516
580
|
const alignment = this.getAlignmentClassName(index);
|
|
517
|
-
const originalClass = item.originalClass ? ` ${item.originalClass}` :
|
|
518
|
-
const thumbnailClass = item.thumbnailClass
|
|
581
|
+
const originalClass = item.originalClass ? ` ${item.originalClass}` : "";
|
|
582
|
+
const thumbnailClass = item.thumbnailClass
|
|
583
|
+
? ` ${item.thumbnailClass}`
|
|
584
|
+
: "";
|
|
519
585
|
const handleRenderItem = item.renderItem || renderItem || this.renderItem;
|
|
520
|
-
const handleRenderThumbInner =
|
|
521
|
-
|| renderThumbInner || this.renderThumbInner;
|
|
586
|
+
const handleRenderThumbInner =
|
|
587
|
+
item.renderThumbInner || renderThumbInner || this.renderThumbInner;
|
|
522
588
|
|
|
523
589
|
const showItem = !lazyLoad || alignment || this.lazyLoaded[index];
|
|
524
590
|
if (showItem && lazyLoad && !this.lazyLoaded[index]) {
|
|
@@ -544,7 +610,11 @@ class ImageGallery extends React.Component {
|
|
|
544
610
|
onMouseLeave={onMouseLeave}
|
|
545
611
|
role="button"
|
|
546
612
|
>
|
|
547
|
-
{showItem ?
|
|
613
|
+
{showItem ? (
|
|
614
|
+
handleRenderItem(item)
|
|
615
|
+
) : (
|
|
616
|
+
<div style={{ height: "100%" }} />
|
|
617
|
+
)}
|
|
548
618
|
</div>
|
|
549
619
|
);
|
|
550
620
|
|
|
@@ -553,53 +623,44 @@ class ImageGallery extends React.Component {
|
|
|
553
623
|
// Don't add thumbnails if there is none
|
|
554
624
|
if (showThumbnails && item.thumbnail) {
|
|
555
625
|
const igThumbnailClass = clsx(
|
|
556
|
-
|
|
626
|
+
"image-gallery-thumbnail",
|
|
557
627
|
thumbnailClass,
|
|
558
|
-
{ active: currentIndex === index }
|
|
628
|
+
{ active: currentIndex === index }
|
|
559
629
|
);
|
|
560
630
|
thumbnails.push(
|
|
561
631
|
<button
|
|
562
632
|
key={`thumbnail-${index}`}
|
|
563
633
|
type="button"
|
|
564
634
|
tabIndex="0"
|
|
565
|
-
aria-pressed={currentIndex === index ?
|
|
635
|
+
aria-pressed={currentIndex === index ? "true" : "false"}
|
|
566
636
|
aria-label={`Go to Slide ${index + 1}`}
|
|
567
637
|
className={igThumbnailClass}
|
|
568
|
-
onMouseLeave={
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
638
|
+
onMouseLeave={
|
|
639
|
+
slideOnThumbnailOver ? this.onThumbnailMouseLeave : null
|
|
640
|
+
}
|
|
641
|
+
onMouseOver={(event) => this.handleThumbnailMouseOver(event, index)}
|
|
642
|
+
onFocus={(event) => this.handleThumbnailMouseOver(event, index)}
|
|
643
|
+
onKeyUp={(event) => this.handleThumbnailKeyUp(event, index)}
|
|
644
|
+
onClick={(event) => this.onThumbnailClick(event, index)}
|
|
573
645
|
>
|
|
574
646
|
{handleRenderThumbInner(item)}
|
|
575
|
-
</button
|
|
647
|
+
</button>
|
|
576
648
|
);
|
|
577
649
|
}
|
|
578
650
|
|
|
579
651
|
if (showBullets) {
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
item.bulletOnClick({ item, itemIndex: index, currentIndex });
|
|
584
|
-
}
|
|
585
|
-
// blur element to remove outline caused by focus
|
|
586
|
-
event.target.blur();
|
|
587
|
-
return this.slideToIndex.call(this, index, event);
|
|
588
|
-
};
|
|
589
|
-
const igBulletClass = clsx(
|
|
590
|
-
'image-gallery-bullet',
|
|
591
|
-
item.bulletClass,
|
|
592
|
-
{ active: currentIndex === index },
|
|
593
|
-
);
|
|
652
|
+
const igBulletClass = clsx("image-gallery-bullet", item.bulletClass, {
|
|
653
|
+
active: currentIndex === index,
|
|
654
|
+
});
|
|
594
655
|
bullets.push(
|
|
595
656
|
<button
|
|
596
657
|
type="button"
|
|
597
658
|
key={`bullet-${index}`}
|
|
598
659
|
className={igBulletClass}
|
|
599
|
-
onClick={
|
|
600
|
-
aria-pressed={currentIndex === index ?
|
|
660
|
+
onClick={(event) => this.onBulletClick(event, index)}
|
|
661
|
+
aria-pressed={currentIndex === index ? "true" : "false"}
|
|
601
662
|
aria-label={`Go to Slide ${index + 1}`}
|
|
602
|
-
|
|
663
|
+
/>
|
|
603
664
|
);
|
|
604
665
|
}
|
|
605
666
|
});
|
|
@@ -621,13 +682,20 @@ class ImageGallery extends React.Component {
|
|
|
621
682
|
const totalSlides = items.length - 1;
|
|
622
683
|
|
|
623
684
|
// we want to show the in between slides transition
|
|
624
|
-
const slidingMoreThanOneSlideLeftOrRight =
|
|
625
|
-
|
|
626
|
-
const
|
|
685
|
+
const slidingMoreThanOneSlideLeftOrRight =
|
|
686
|
+
Math.abs(previousIndex - currentIndex) > 1;
|
|
687
|
+
const notGoingFromFirstToLast = !(
|
|
688
|
+
previousIndex === 0 && currentIndex === totalSlides
|
|
689
|
+
);
|
|
690
|
+
const notGoingFromLastToFirst = !(
|
|
691
|
+
previousIndex === totalSlides && currentIndex === 0
|
|
692
|
+
);
|
|
627
693
|
|
|
628
|
-
return
|
|
629
|
-
&&
|
|
630
|
-
&&
|
|
694
|
+
return (
|
|
695
|
+
slidingMoreThanOneSlideLeftOrRight &&
|
|
696
|
+
notGoingFromFirstToLast &&
|
|
697
|
+
notGoingFromLastToFirst
|
|
698
|
+
);
|
|
631
699
|
}
|
|
632
700
|
|
|
633
701
|
isFirstOrLastSlide(index) {
|
|
@@ -638,14 +706,15 @@ class ImageGallery extends React.Component {
|
|
|
638
706
|
return isLastSlide || isFirstSlide;
|
|
639
707
|
}
|
|
640
708
|
|
|
641
|
-
|
|
642
709
|
slideIsTransitioning(index) {
|
|
643
710
|
/*
|
|
644
711
|
returns true if the gallery is transitioning and the index is not the
|
|
645
712
|
previous or currentIndex
|
|
646
713
|
*/
|
|
647
714
|
const { isTransitioning, previousIndex, currentIndex } = this.state;
|
|
648
|
-
const indexIsNotPreviousOrNextSlide = !(
|
|
715
|
+
const indexIsNotPreviousOrNextSlide = !(
|
|
716
|
+
index === previousIndex || index === currentIndex
|
|
717
|
+
);
|
|
649
718
|
return isTransitioning && indexIsNotPreviousOrNextSlide;
|
|
650
719
|
}
|
|
651
720
|
|
|
@@ -662,8 +731,10 @@ class ImageGallery extends React.Component {
|
|
|
662
731
|
so unless were going from first to last or vice versa we don't want the first
|
|
663
732
|
or last slide to show up during the transition
|
|
664
733
|
*/
|
|
665
|
-
return
|
|
666
|
-
|
|
734
|
+
return (
|
|
735
|
+
!this.slideIsTransitioning(index) ||
|
|
736
|
+
(this.ignoreIsTransitioning() && !this.isFirstOrLastSlide(index))
|
|
737
|
+
);
|
|
667
738
|
}
|
|
668
739
|
|
|
669
740
|
slideThumbnailBar() {
|
|
@@ -689,13 +760,13 @@ class ImageGallery extends React.Component {
|
|
|
689
760
|
}
|
|
690
761
|
|
|
691
762
|
canSlideLeft() {
|
|
692
|
-
const { infinite
|
|
693
|
-
return infinite ||
|
|
763
|
+
const { infinite } = this.props;
|
|
764
|
+
return infinite || this.canSlidePrevious();
|
|
694
765
|
}
|
|
695
766
|
|
|
696
767
|
canSlideRight() {
|
|
697
|
-
const { infinite
|
|
698
|
-
return infinite ||
|
|
768
|
+
const { infinite } = this.props;
|
|
769
|
+
return infinite || this.canSlideNext();
|
|
699
770
|
}
|
|
700
771
|
|
|
701
772
|
canSlidePrevious() {
|
|
@@ -711,12 +782,8 @@ class ImageGallery extends React.Component {
|
|
|
711
782
|
|
|
712
783
|
handleSwiping({ event, absX, dir }) {
|
|
713
784
|
const { disableSwipe, stopPropagation } = this.props;
|
|
714
|
-
const {
|
|
715
|
-
|
|
716
|
-
isTransitioning,
|
|
717
|
-
swipingUpDown,
|
|
718
|
-
swipingLeftRight,
|
|
719
|
-
} = this.state;
|
|
785
|
+
const { galleryWidth, isTransitioning, swipingUpDown, swipingLeftRight } =
|
|
786
|
+
this.state;
|
|
720
787
|
|
|
721
788
|
// if the initial swiping is up/down prevent moving the slides until swipe ends
|
|
722
789
|
if ((dir === UP || dir === DOWN || swipingUpDown) && !swipingLeftRight) {
|
|
@@ -740,7 +807,7 @@ class ImageGallery extends React.Component {
|
|
|
740
807
|
if (!isTransitioning) {
|
|
741
808
|
const side = dir === RIGHT ? 1 : -1;
|
|
742
809
|
|
|
743
|
-
let currentSlideOffset = (absX / galleryWidth * 100
|
|
810
|
+
let currentSlideOffset = (absX / galleryWidth) * 100;
|
|
744
811
|
if (Math.abs(currentSlideOffset) >= 100) {
|
|
745
812
|
currentSlideOffset = 100;
|
|
746
813
|
}
|
|
@@ -759,16 +826,8 @@ class ImageGallery extends React.Component {
|
|
|
759
826
|
}
|
|
760
827
|
}
|
|
761
828
|
|
|
762
|
-
handleThumbnailSwiping({
|
|
763
|
-
|
|
764
|
-
absX,
|
|
765
|
-
absY,
|
|
766
|
-
dir,
|
|
767
|
-
}) {
|
|
768
|
-
const {
|
|
769
|
-
stopPropagation,
|
|
770
|
-
swipingThumbnailTransitionDuration,
|
|
771
|
-
} = this.props;
|
|
829
|
+
handleThumbnailSwiping({ event, absX, absY, dir }) {
|
|
830
|
+
const { stopPropagation, swipingThumbnailTransitionDuration } = this.props;
|
|
772
831
|
const {
|
|
773
832
|
thumbsSwipedTranslate,
|
|
774
833
|
thumbnailsWrapperHeight,
|
|
@@ -779,7 +838,10 @@ class ImageGallery extends React.Component {
|
|
|
779
838
|
|
|
780
839
|
if (this.isThumbnailVertical()) {
|
|
781
840
|
// if the initial swiping is left/right, prevent moving the thumbnail bar until swipe ends
|
|
782
|
-
if (
|
|
841
|
+
if (
|
|
842
|
+
(dir === LEFT || dir === RIGHT || swipingLeftRight) &&
|
|
843
|
+
!swipingUpDown
|
|
844
|
+
) {
|
|
783
845
|
if (!swipingLeftRight) {
|
|
784
846
|
this.setState({ swipingLeftRight: true });
|
|
785
847
|
}
|
|
@@ -815,19 +877,21 @@ class ImageGallery extends React.Component {
|
|
|
815
877
|
if (this.isThumbnailVertical()) {
|
|
816
878
|
const slideY = dir === DOWN ? absY : -absY;
|
|
817
879
|
thumbsTranslate = thumbsSwipedTranslate + slideY;
|
|
818
|
-
totalSwipeableLength =
|
|
819
|
-
- thumbnailsWrapperHeight + emptySpaceMargin;
|
|
880
|
+
totalSwipeableLength =
|
|
881
|
+
thumbsElement.scrollHeight - thumbnailsWrapperHeight + emptySpaceMargin;
|
|
820
882
|
hasSwipedPassedEnd = Math.abs(thumbsTranslate) > totalSwipeableLength;
|
|
821
883
|
hasSwipedPassedStart = thumbsTranslate > emptySpaceMargin;
|
|
822
|
-
isThumbnailBarSmallerThanContainer =
|
|
884
|
+
isThumbnailBarSmallerThanContainer =
|
|
885
|
+
thumbsElement.scrollHeight <= thumbnailsWrapperHeight;
|
|
823
886
|
} else {
|
|
824
887
|
const slideX = dir === RIGHT ? absX : -absX;
|
|
825
888
|
thumbsTranslate = thumbsSwipedTranslate + slideX;
|
|
826
|
-
totalSwipeableLength =
|
|
827
|
-
- thumbnailsWrapperWidth + emptySpaceMargin;
|
|
889
|
+
totalSwipeableLength =
|
|
890
|
+
thumbsElement.scrollWidth - thumbnailsWrapperWidth + emptySpaceMargin;
|
|
828
891
|
hasSwipedPassedEnd = Math.abs(thumbsTranslate) > totalSwipeableLength;
|
|
829
892
|
hasSwipedPassedStart = thumbsTranslate > emptySpaceMargin;
|
|
830
|
-
isThumbnailBarSmallerThanContainer =
|
|
893
|
+
isThumbnailBarSmallerThanContainer =
|
|
894
|
+
thumbsElement.scrollWidth <= thumbnailsWrapperWidth;
|
|
831
895
|
}
|
|
832
896
|
|
|
833
897
|
if (isThumbnailBarSmallerThanContainer) {
|
|
@@ -899,7 +963,7 @@ class ImageGallery extends React.Component {
|
|
|
899
963
|
// if it is RTL the direction is reversed
|
|
900
964
|
const swipeDirection = (dir === LEFT ? 1 : -1) * (isRTL ? -1 : 1);
|
|
901
965
|
const isSwipeUpOrDown = dir === UP || dir === DOWN;
|
|
902
|
-
const isLeftRightFlick =
|
|
966
|
+
const isLeftRightFlick = velocity > flickThreshold && !isSwipeUpOrDown;
|
|
903
967
|
this.handleOnSwipedTo(swipeDirection, isLeftRightFlick);
|
|
904
968
|
}
|
|
905
969
|
|
|
@@ -913,8 +977,10 @@ class ImageGallery extends React.Component {
|
|
|
913
977
|
}
|
|
914
978
|
|
|
915
979
|
// If we can't swipe left or right, stay in the current index (noop)
|
|
916
|
-
if (
|
|
917
|
-
|
|
980
|
+
if (
|
|
981
|
+
(swipeDirection === -1 && !this.canSlideLeft()) ||
|
|
982
|
+
(swipeDirection === 1 && !this.canSlideRight())
|
|
983
|
+
) {
|
|
918
984
|
slideTo = currentIndex;
|
|
919
985
|
}
|
|
920
986
|
|
|
@@ -931,14 +997,14 @@ class ImageGallery extends React.Component {
|
|
|
931
997
|
|
|
932
998
|
handleMouseDown() {
|
|
933
999
|
// keep track of mouse vs keyboard usage for a11y
|
|
934
|
-
this.imageGallery.current.classList.add(
|
|
1000
|
+
this.imageGallery.current.classList.add("image-gallery-using-mouse");
|
|
935
1001
|
}
|
|
936
1002
|
|
|
937
1003
|
handleKeyDown(event) {
|
|
938
1004
|
const { disableKeyDown, useBrowserFullscreen } = this.props;
|
|
939
1005
|
const { isFullscreen } = this.state;
|
|
940
1006
|
// keep track of mouse vs keyboard usage for a11y
|
|
941
|
-
this.imageGallery.current.classList.remove(
|
|
1007
|
+
this.imageGallery.current.classList.remove("image-gallery-using-mouse");
|
|
942
1008
|
|
|
943
1009
|
if (disableKeyDown) return;
|
|
944
1010
|
const LEFT_ARROW = 37;
|
|
@@ -977,17 +1043,27 @@ class ImageGallery extends React.Component {
|
|
|
977
1043
|
}
|
|
978
1044
|
|
|
979
1045
|
removeThumbnailsResizeObserver() {
|
|
980
|
-
if (
|
|
981
|
-
|
|
982
|
-
this.
|
|
1046
|
+
if (
|
|
1047
|
+
this.resizeThumbnailWrapperObserver &&
|
|
1048
|
+
this.thumbnailsWrapper &&
|
|
1049
|
+
this.thumbnailsWrapper.current
|
|
1050
|
+
) {
|
|
1051
|
+
this.resizeThumbnailWrapperObserver.unobserve(
|
|
1052
|
+
this.thumbnailsWrapper.current
|
|
1053
|
+
);
|
|
983
1054
|
this.resizeThumbnailWrapperObserver = null;
|
|
984
1055
|
}
|
|
985
1056
|
}
|
|
986
1057
|
|
|
987
1058
|
removeResizeObserver() {
|
|
988
|
-
if (
|
|
989
|
-
|
|
990
|
-
this.
|
|
1059
|
+
if (
|
|
1060
|
+
this.resizeSlideWrapperObserver &&
|
|
1061
|
+
this.imageGallerySlideWrapper &&
|
|
1062
|
+
this.imageGallerySlideWrapper.current
|
|
1063
|
+
) {
|
|
1064
|
+
this.resizeSlideWrapperObserver.unobserve(
|
|
1065
|
+
this.imageGallerySlideWrapper.current
|
|
1066
|
+
);
|
|
991
1067
|
this.resizeSlideWrapperObserver = null;
|
|
992
1068
|
}
|
|
993
1069
|
this.removeThumbnailsResizeObserver();
|
|
@@ -1005,9 +1081,13 @@ class ImageGallery extends React.Component {
|
|
|
1005
1081
|
this.setState({ galleryWidth: this.imageGallery.current.offsetWidth });
|
|
1006
1082
|
}
|
|
1007
1083
|
|
|
1008
|
-
if (
|
|
1084
|
+
if (
|
|
1085
|
+
this.imageGallerySlideWrapper &&
|
|
1086
|
+
this.imageGallerySlideWrapper.current
|
|
1087
|
+
) {
|
|
1009
1088
|
this.setState({
|
|
1010
|
-
gallerySlideWrapperHeight:
|
|
1089
|
+
gallerySlideWrapperHeight:
|
|
1090
|
+
this.imageGallerySlideWrapper.current.offsetHeight,
|
|
1011
1091
|
});
|
|
1012
1092
|
}
|
|
1013
1093
|
|
|
@@ -1018,23 +1098,33 @@ class ImageGallery extends React.Component {
|
|
|
1018
1098
|
initSlideWrapperResizeObserver(element) {
|
|
1019
1099
|
if (element && !element.current) return;
|
|
1020
1100
|
// keeps track of gallery height changes for vertical thumbnail height
|
|
1021
|
-
this.resizeSlideWrapperObserver = new ResizeObserver(
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1101
|
+
this.resizeSlideWrapperObserver = new ResizeObserver(
|
|
1102
|
+
debounce((entries) => {
|
|
1103
|
+
if (!entries) return;
|
|
1104
|
+
entries.forEach((entry) => {
|
|
1105
|
+
this.setState(
|
|
1106
|
+
{ thumbnailsWrapperWidth: entry.contentRect.width },
|
|
1107
|
+
this.handleResize
|
|
1108
|
+
);
|
|
1109
|
+
});
|
|
1110
|
+
}, 50)
|
|
1111
|
+
);
|
|
1027
1112
|
this.resizeSlideWrapperObserver.observe(element.current);
|
|
1028
1113
|
}
|
|
1029
1114
|
|
|
1030
1115
|
initThumbnailWrapperResizeObserver(element) {
|
|
1031
1116
|
if (element && !element.current) return; // thumbnails are not always available
|
|
1032
|
-
this.resizeThumbnailWrapperObserver = new ResizeObserver(
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1117
|
+
this.resizeThumbnailWrapperObserver = new ResizeObserver(
|
|
1118
|
+
debounce((entries) => {
|
|
1119
|
+
if (!entries) return;
|
|
1120
|
+
entries.forEach((entry) => {
|
|
1121
|
+
this.setState(
|
|
1122
|
+
{ thumbnailsWrapperHeight: entry.contentRect.height },
|
|
1123
|
+
this.handleResize
|
|
1124
|
+
);
|
|
1125
|
+
});
|
|
1126
|
+
}, 50)
|
|
1127
|
+
);
|
|
1038
1128
|
this.resizeThumbnailWrapperObserver.observe(element.current);
|
|
1039
1129
|
}
|
|
1040
1130
|
|
|
@@ -1055,16 +1145,16 @@ class ImageGallery extends React.Component {
|
|
|
1055
1145
|
}
|
|
1056
1146
|
}
|
|
1057
1147
|
|
|
1058
|
-
|
|
1059
1148
|
handleScreenChange() {
|
|
1060
1149
|
/*
|
|
1061
1150
|
handles screen change events that the browser triggers e.g. esc key
|
|
1062
1151
|
*/
|
|
1063
1152
|
const { onScreenChange, useBrowserFullscreen } = this.props;
|
|
1064
|
-
const fullScreenElement =
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1153
|
+
const fullScreenElement =
|
|
1154
|
+
document.fullscreenElement ||
|
|
1155
|
+
document.msFullscreenElement ||
|
|
1156
|
+
document.mozFullScreenElement ||
|
|
1157
|
+
document.webkitFullscreenElement;
|
|
1068
1158
|
|
|
1069
1159
|
// check if screenchange element is the gallery
|
|
1070
1160
|
const isFullscreen = this.imageGallery.current === fullScreenElement;
|
|
@@ -1097,51 +1187,63 @@ class ImageGallery extends React.Component {
|
|
|
1097
1187
|
onBeforeSlide(nextIndex);
|
|
1098
1188
|
}
|
|
1099
1189
|
|
|
1100
|
-
this.setState(
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1190
|
+
this.setState(
|
|
1191
|
+
{
|
|
1192
|
+
previousIndex: currentIndex,
|
|
1193
|
+
currentIndex: nextIndex,
|
|
1194
|
+
isTransitioning: nextIndex !== currentIndex,
|
|
1195
|
+
currentSlideOffset: 0,
|
|
1196
|
+
slideStyle: { transition: `all ${slideDuration}ms ease-out` },
|
|
1197
|
+
},
|
|
1198
|
+
this.onSliding
|
|
1199
|
+
);
|
|
1107
1200
|
}
|
|
1108
1201
|
}
|
|
1109
1202
|
|
|
1110
1203
|
slideLeft(event) {
|
|
1111
1204
|
const { isRTL } = this.props;
|
|
1112
|
-
this.slideTo(event, isRTL ?
|
|
1205
|
+
this.slideTo(event, isRTL ? "right" : "left");
|
|
1113
1206
|
}
|
|
1114
1207
|
|
|
1115
1208
|
slideRight(event) {
|
|
1116
1209
|
const { isRTL } = this.props;
|
|
1117
|
-
this.slideTo(event, isRTL ?
|
|
1210
|
+
this.slideTo(event, isRTL ? "left" : "right");
|
|
1118
1211
|
}
|
|
1119
1212
|
|
|
1120
1213
|
slideTo(event, direction) {
|
|
1121
|
-
const { currentIndex,
|
|
1214
|
+
const { currentIndex, isTransitioning } = this.state;
|
|
1122
1215
|
const { items } = this.props;
|
|
1123
|
-
const nextIndex = currentIndex + (direction ===
|
|
1216
|
+
const nextIndex = currentIndex + (direction === "left" ? -1 : 1);
|
|
1124
1217
|
|
|
1125
1218
|
if (isTransitioning) return;
|
|
1126
1219
|
|
|
1127
1220
|
if (items.length === 2) {
|
|
1128
|
-
|
|
1129
|
-
When there are only 2 slides fake a tiny swipe to get the slides
|
|
1130
|
-
on the correct side for transitioning
|
|
1131
|
-
*/
|
|
1132
|
-
this.setState({
|
|
1133
|
-
// this will reset once index changes
|
|
1134
|
-
currentSlideOffset: currentSlideOffset + (direction === 'left' ? 0.001 : -0.001),
|
|
1135
|
-
slideStyle: { transition: 'none' }, // move the slide over instantly
|
|
1136
|
-
}, () => {
|
|
1137
|
-
// add 25ms timeout to avoid delay in moving slides over
|
|
1138
|
-
window.setTimeout(() => this.slideToIndex(nextIndex, event), 25);
|
|
1139
|
-
});
|
|
1221
|
+
this.slideToIndexWithStyleReset(nextIndex, event);
|
|
1140
1222
|
} else {
|
|
1141
1223
|
this.slideToIndex(nextIndex, event);
|
|
1142
1224
|
}
|
|
1143
1225
|
}
|
|
1144
1226
|
|
|
1227
|
+
slideToIndexWithStyleReset(nextIndex, event) {
|
|
1228
|
+
/*
|
|
1229
|
+
When there are only 2 slides fake a tiny swipe to get the slides
|
|
1230
|
+
on the correct side for transitioning
|
|
1231
|
+
*/
|
|
1232
|
+
const { currentIndex, currentSlideOffset } = this.state;
|
|
1233
|
+
this.setState(
|
|
1234
|
+
{
|
|
1235
|
+
// this will reset once index changes
|
|
1236
|
+
currentSlideOffset:
|
|
1237
|
+
currentSlideOffset + (currentIndex > nextIndex ? 0.001 : -0.001),
|
|
1238
|
+
slideStyle: { transition: "none" }, // move the slide over instantly
|
|
1239
|
+
},
|
|
1240
|
+
() => {
|
|
1241
|
+
// add 25ms timeout to avoid delay in moving slides over
|
|
1242
|
+
window.setTimeout(() => this.slideToIndex(nextIndex, event), 25);
|
|
1243
|
+
}
|
|
1244
|
+
);
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1145
1247
|
handleThumbnailMouseOver(event, index) {
|
|
1146
1248
|
const { slideOnThumbnailOver } = this.props;
|
|
1147
1249
|
if (slideOnThumbnailOver) this.onThumbnailMouseOver(event, index);
|
|
@@ -1162,7 +1264,7 @@ class ImageGallery extends React.Component {
|
|
|
1162
1264
|
|
|
1163
1265
|
isThumbnailVertical() {
|
|
1164
1266
|
const { thumbnailPosition } = this.props;
|
|
1165
|
-
return thumbnailPosition ===
|
|
1267
|
+
return thumbnailPosition === "left" || thumbnailPosition === "right";
|
|
1166
1268
|
}
|
|
1167
1269
|
|
|
1168
1270
|
addScreenChangeEvent() {
|
|
@@ -1234,17 +1336,13 @@ class ImageGallery extends React.Component {
|
|
|
1234
1336
|
}
|
|
1235
1337
|
|
|
1236
1338
|
play(shouldCallOnPlay = true) {
|
|
1237
|
-
const {
|
|
1238
|
-
onPlay,
|
|
1239
|
-
slideInterval,
|
|
1240
|
-
slideDuration,
|
|
1241
|
-
} = this.props;
|
|
1339
|
+
const { onPlay, slideInterval, slideDuration } = this.props;
|
|
1242
1340
|
const { currentIndex } = this.state;
|
|
1243
1341
|
if (!this.playPauseIntervalId) {
|
|
1244
1342
|
this.setState({ isPlaying: true });
|
|
1245
1343
|
this.playPauseIntervalId = window.setInterval(
|
|
1246
1344
|
this.pauseOrPlay,
|
|
1247
|
-
Math.max(slideInterval, slideDuration)
|
|
1345
|
+
Math.max(slideInterval, slideDuration)
|
|
1248
1346
|
);
|
|
1249
1347
|
if (onPlay && shouldCallOnPlay) {
|
|
1250
1348
|
onPlay(currentIndex);
|
|
@@ -1329,24 +1427,18 @@ class ImageGallery extends React.Component {
|
|
|
1329
1427
|
loading={item.thumbnailLoading}
|
|
1330
1428
|
onError={handleThumbnailError}
|
|
1331
1429
|
/>
|
|
1332
|
-
{
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
)
|
|
1338
|
-
}
|
|
1430
|
+
{item.thumbnailLabel && (
|
|
1431
|
+
<div className="image-gallery-thumbnail-label">
|
|
1432
|
+
{item.thumbnailLabel}
|
|
1433
|
+
</div>
|
|
1434
|
+
)}
|
|
1339
1435
|
</span>
|
|
1340
1436
|
);
|
|
1341
1437
|
}
|
|
1342
1438
|
|
|
1343
1439
|
render() {
|
|
1344
|
-
const {
|
|
1345
|
-
|
|
1346
|
-
isFullscreen,
|
|
1347
|
-
modalFullscreen,
|
|
1348
|
-
isPlaying,
|
|
1349
|
-
} = this.state;
|
|
1440
|
+
const { currentIndex, isFullscreen, modalFullscreen, isPlaying } =
|
|
1441
|
+
this.state;
|
|
1350
1442
|
|
|
1351
1443
|
const {
|
|
1352
1444
|
additionalClass,
|
|
@@ -1371,120 +1463,114 @@ class ImageGallery extends React.Component {
|
|
|
1371
1463
|
const thumbnailStyle = this.getThumbnailStyle();
|
|
1372
1464
|
const { slides, thumbnails, bullets } = this.getSlideItems();
|
|
1373
1465
|
const slideWrapperClass = clsx(
|
|
1374
|
-
|
|
1375
|
-
thumbnailPosition,
|
|
1376
|
-
{
|
|
1466
|
+
"image-gallery-slide-wrapper",
|
|
1467
|
+
this.getThumbnailPositionClassName(thumbnailPosition),
|
|
1468
|
+
{ "image-gallery-rtl": isRTL }
|
|
1377
1469
|
);
|
|
1378
1470
|
|
|
1379
1471
|
const slideWrapper = (
|
|
1380
1472
|
<div ref={this.imageGallerySlideWrapper} className={slideWrapperClass}>
|
|
1381
1473
|
{renderCustomControls && renderCustomControls()}
|
|
1382
|
-
{
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
}
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
</SwipeWrapper>
|
|
1403
|
-
</React.Fragment>
|
|
1404
|
-
) : (
|
|
1405
|
-
<div className="image-gallery-slides">
|
|
1406
|
-
{slides}
|
|
1407
|
-
</div>
|
|
1408
|
-
)
|
|
1409
|
-
}
|
|
1474
|
+
{this.canSlide() ? (
|
|
1475
|
+
<React.Fragment>
|
|
1476
|
+
{showNav && (
|
|
1477
|
+
<React.Fragment>
|
|
1478
|
+
{renderLeftNav(this.slideLeft, !this.canSlideLeft())}
|
|
1479
|
+
{renderRightNav(this.slideRight, !this.canSlideRight())}
|
|
1480
|
+
</React.Fragment>
|
|
1481
|
+
)}
|
|
1482
|
+
<SwipeWrapper
|
|
1483
|
+
className="image-gallery-swipe"
|
|
1484
|
+
delta={0}
|
|
1485
|
+
onSwiping={this.handleSwiping}
|
|
1486
|
+
onSwiped={this.handleOnSwiped}
|
|
1487
|
+
>
|
|
1488
|
+
<div className="image-gallery-slides">{slides}</div>
|
|
1489
|
+
</SwipeWrapper>
|
|
1490
|
+
</React.Fragment>
|
|
1491
|
+
) : (
|
|
1492
|
+
<div className="image-gallery-slides">{slides}</div>
|
|
1493
|
+
)}
|
|
1410
1494
|
{showPlayButton && renderPlayPauseButton(this.togglePlay, isPlaying)}
|
|
1411
|
-
{
|
|
1412
|
-
|
|
1413
|
-
<div
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
{bullets}
|
|
1420
|
-
</div>
|
|
1421
|
-
</div>
|
|
1422
|
-
)
|
|
1423
|
-
}
|
|
1424
|
-
{showFullscreenButton && renderFullscreenButton(this.toggleFullScreen, isFullscreen)}
|
|
1425
|
-
{
|
|
1426
|
-
showIndex && (
|
|
1427
|
-
<div className="image-gallery-index">
|
|
1428
|
-
<span className="image-gallery-index-current">
|
|
1429
|
-
{currentIndex + 1}
|
|
1430
|
-
</span>
|
|
1431
|
-
<span className="image-gallery-index-separator">
|
|
1432
|
-
{indexSeparator}
|
|
1433
|
-
</span>
|
|
1434
|
-
<span className="image-gallery-index-total">
|
|
1435
|
-
{items.length}
|
|
1436
|
-
</span>
|
|
1495
|
+
{showBullets && (
|
|
1496
|
+
<div className="image-gallery-bullets">
|
|
1497
|
+
<div
|
|
1498
|
+
className="image-gallery-bullets-container"
|
|
1499
|
+
role="navigation"
|
|
1500
|
+
aria-label="Bullet Navigation"
|
|
1501
|
+
>
|
|
1502
|
+
{bullets}
|
|
1437
1503
|
</div>
|
|
1438
|
-
|
|
1439
|
-
}
|
|
1504
|
+
</div>
|
|
1505
|
+
)}
|
|
1506
|
+
{showFullscreenButton &&
|
|
1507
|
+
renderFullscreenButton(this.toggleFullScreen, isFullscreen)}
|
|
1508
|
+
{showIndex && (
|
|
1509
|
+
<div className="image-gallery-index">
|
|
1510
|
+
<span className="image-gallery-index-current">
|
|
1511
|
+
{currentIndex + 1}
|
|
1512
|
+
</span>
|
|
1513
|
+
<span className="image-gallery-index-separator">
|
|
1514
|
+
{indexSeparator}
|
|
1515
|
+
</span>
|
|
1516
|
+
<span className="image-gallery-index-total">{items.length}</span>
|
|
1517
|
+
</div>
|
|
1518
|
+
)}
|
|
1440
1519
|
</div>
|
|
1441
1520
|
);
|
|
1442
1521
|
|
|
1443
|
-
const igClass = clsx(
|
|
1444
|
-
|
|
1522
|
+
const igClass = clsx("image-gallery", additionalClass, {
|
|
1523
|
+
"fullscreen-modal": modalFullscreen,
|
|
1524
|
+
});
|
|
1525
|
+
const igContentClass = clsx(
|
|
1526
|
+
"image-gallery-content",
|
|
1527
|
+
this.getThumbnailPositionClassName(thumbnailPosition),
|
|
1528
|
+
{ fullscreen: isFullscreen }
|
|
1529
|
+
);
|
|
1445
1530
|
const thumbnailWrapperClass = clsx(
|
|
1446
|
-
|
|
1447
|
-
thumbnailPosition,
|
|
1448
|
-
{
|
|
1449
|
-
{
|
|
1450
|
-
|
|
1531
|
+
"image-gallery-thumbnails-wrapper",
|
|
1532
|
+
this.getThumbnailPositionClassName(thumbnailPosition),
|
|
1533
|
+
{ "thumbnails-wrapper-rtl": !this.isThumbnailVertical() && isRTL },
|
|
1534
|
+
{
|
|
1535
|
+
"thumbnails-swipe-horizontal":
|
|
1536
|
+
!this.isThumbnailVertical() && !disableThumbnailSwipe,
|
|
1537
|
+
},
|
|
1538
|
+
{
|
|
1539
|
+
"thumbnails-swipe-vertical":
|
|
1540
|
+
this.isThumbnailVertical() && !disableThumbnailSwipe,
|
|
1541
|
+
}
|
|
1451
1542
|
);
|
|
1452
1543
|
return (
|
|
1453
|
-
<div
|
|
1454
|
-
ref={this.imageGallery}
|
|
1455
|
-
className={igClass}
|
|
1456
|
-
aria-live="polite"
|
|
1457
|
-
>
|
|
1544
|
+
<div ref={this.imageGallery} className={igClass} aria-live="polite">
|
|
1458
1545
|
<div className={igContentClass}>
|
|
1459
|
-
{(thumbnailPosition ===
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1546
|
+
{(thumbnailPosition === "bottom" || thumbnailPosition === "right") &&
|
|
1547
|
+
slideWrapper}
|
|
1548
|
+
{showThumbnails && thumbnails.length > 0 ? (
|
|
1549
|
+
<SwipeWrapper
|
|
1550
|
+
className={thumbnailWrapperClass}
|
|
1551
|
+
delta={0}
|
|
1552
|
+
onSwiping={!disableThumbnailSwipe && this.handleThumbnailSwiping}
|
|
1553
|
+
onSwiped={!disableThumbnailSwipe && this.handleOnThumbnailSwiped}
|
|
1554
|
+
>
|
|
1555
|
+
<div
|
|
1556
|
+
className="image-gallery-thumbnails"
|
|
1557
|
+
ref={this.thumbnailsWrapper}
|
|
1558
|
+
style={this.getThumbnailBarHeight()}
|
|
1467
1559
|
>
|
|
1468
|
-
<
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
style={
|
|
1560
|
+
<nav
|
|
1561
|
+
ref={this.thumbnails}
|
|
1562
|
+
className="image-gallery-thumbnails-container"
|
|
1563
|
+
style={thumbnailStyle}
|
|
1564
|
+
aria-label="Thumbnail Navigation"
|
|
1472
1565
|
>
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
</nav>
|
|
1481
|
-
</div>
|
|
1482
|
-
</SwipeWrapper>
|
|
1483
|
-
) : null
|
|
1484
|
-
}
|
|
1485
|
-
{(thumbnailPosition === 'top' || thumbnailPosition === 'left') && slideWrapper}
|
|
1566
|
+
{thumbnails}
|
|
1567
|
+
</nav>
|
|
1568
|
+
</div>
|
|
1569
|
+
</SwipeWrapper>
|
|
1570
|
+
) : null}
|
|
1571
|
+
{(thumbnailPosition === "top" || thumbnailPosition === "left") &&
|
|
1572
|
+
slideWrapper}
|
|
1486
1573
|
</div>
|
|
1487
|
-
|
|
1488
1574
|
</div>
|
|
1489
1575
|
);
|
|
1490
1576
|
}
|
|
@@ -1492,32 +1578,34 @@ class ImageGallery extends React.Component {
|
|
|
1492
1578
|
|
|
1493
1579
|
ImageGallery.propTypes = {
|
|
1494
1580
|
flickThreshold: number,
|
|
1495
|
-
items: arrayOf(
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1581
|
+
items: arrayOf(
|
|
1582
|
+
shape({
|
|
1583
|
+
bulletClass: string,
|
|
1584
|
+
bulletOnClick: func,
|
|
1585
|
+
description: string,
|
|
1586
|
+
original: string,
|
|
1587
|
+
originalHeight: number,
|
|
1588
|
+
originalWidth: number,
|
|
1589
|
+
loading: string,
|
|
1590
|
+
thumbnailHeight: number,
|
|
1591
|
+
thumbnailWidth: number,
|
|
1592
|
+
thumbnailLoading: string,
|
|
1593
|
+
fullscreen: string,
|
|
1594
|
+
originalAlt: string,
|
|
1595
|
+
originalTitle: string,
|
|
1596
|
+
thumbnail: string,
|
|
1597
|
+
thumbnailAlt: string,
|
|
1598
|
+
thumbnailLabel: string,
|
|
1599
|
+
thumbnailTitle: string,
|
|
1600
|
+
originalClass: string,
|
|
1601
|
+
thumbnailClass: string,
|
|
1602
|
+
renderItem: func,
|
|
1603
|
+
renderThumbInner: func,
|
|
1604
|
+
imageSet: imageSetType,
|
|
1605
|
+
srcSet: string,
|
|
1606
|
+
sizes: string,
|
|
1607
|
+
})
|
|
1608
|
+
).isRequired,
|
|
1521
1609
|
showNav: bool,
|
|
1522
1610
|
autoPlay: bool,
|
|
1523
1611
|
lazyLoad: bool,
|
|
@@ -1534,7 +1622,7 @@ ImageGallery.propTypes = {
|
|
|
1534
1622
|
useBrowserFullscreen: bool,
|
|
1535
1623
|
onErrorImageURL: string,
|
|
1536
1624
|
indexSeparator: string,
|
|
1537
|
-
thumbnailPosition: oneOf([
|
|
1625
|
+
thumbnailPosition: oneOf(["top", "bottom", "left", "right"]),
|
|
1538
1626
|
startIndex: number,
|
|
1539
1627
|
slideDuration: number,
|
|
1540
1628
|
slideInterval: number,
|
|
@@ -1555,6 +1643,7 @@ ImageGallery.propTypes = {
|
|
|
1555
1643
|
onTouchStart: func,
|
|
1556
1644
|
onMouseOver: func,
|
|
1557
1645
|
onMouseLeave: func,
|
|
1646
|
+
onBulletClick: func,
|
|
1558
1647
|
onThumbnailError: func,
|
|
1559
1648
|
onThumbnailClick: func,
|
|
1560
1649
|
renderCustomControls: func,
|
|
@@ -1572,8 +1661,8 @@ ImageGallery.propTypes = {
|
|
|
1572
1661
|
};
|
|
1573
1662
|
|
|
1574
1663
|
ImageGallery.defaultProps = {
|
|
1575
|
-
onErrorImageURL:
|
|
1576
|
-
additionalClass:
|
|
1664
|
+
onErrorImageURL: "",
|
|
1665
|
+
additionalClass: "",
|
|
1577
1666
|
showNav: true,
|
|
1578
1667
|
autoPlay: false,
|
|
1579
1668
|
lazyLoad: false,
|
|
@@ -1592,8 +1681,8 @@ ImageGallery.defaultProps = {
|
|
|
1592
1681
|
useBrowserFullscreen: true,
|
|
1593
1682
|
flickThreshold: 0.4,
|
|
1594
1683
|
stopPropagation: false,
|
|
1595
|
-
indexSeparator:
|
|
1596
|
-
thumbnailPosition:
|
|
1684
|
+
indexSeparator: " / ",
|
|
1685
|
+
thumbnailPosition: "bottom",
|
|
1597
1686
|
startIndex: 0,
|
|
1598
1687
|
slideDuration: 450,
|
|
1599
1688
|
swipingTransitionDuration: 0,
|
|
@@ -1611,6 +1700,7 @@ ImageGallery.defaultProps = {
|
|
|
1611
1700
|
onTouchStart: null,
|
|
1612
1701
|
onMouseOver: null,
|
|
1613
1702
|
onMouseLeave: null,
|
|
1703
|
+
onBulletClick: null,
|
|
1614
1704
|
onThumbnailError: null,
|
|
1615
1705
|
onThumbnailClick: null,
|
|
1616
1706
|
renderCustomControls: null,
|