react-spring-carousel 1.9.29-beta1 → 1.9.29-beta13

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/dist/index.umd.js CHANGED
@@ -93,98 +93,140 @@
93
93
  return typeof window !== 'undefined';
94
94
  }
95
95
 
96
- function useThumbsModule({ items, withThumbs, thumbsSlideAxis = 'x', springConfig, thumbsWrapperRef, prepareThumbsData, }) {
96
+ const InternalWrapper = react.forwardRef(({ children, ...rest }, ref) => {
97
+ return (jsxRuntime.jsx(reactSpring.animated.div, Object.assign({}, rest, { ref: ref }, { children: children }), void 0));
98
+ });
99
+ function useThumbsModule({ items, withThumbs, thumbsSlideAxis = 'x', springConfig, prepareThumbsData, itemsPerSlide, getFluidWrapperScrollValue = () => 0, getSlideValue = () => 0, CustomThumbsWrapperComponent, }) {
97
100
  const internalThumbsWrapperRef = react.useRef(null);
98
101
  const [thumbListStyles, setThumbListStyles] = reactSpring.useSpring(() => ({
99
- [thumbsSlideAxis]: 0,
102
+ x: 0,
103
+ y: 0,
100
104
  config: springConfig,
105
+ onChange: ({ value }) => {
106
+ if (internalThumbsWrapperRef.current) {
107
+ internalThumbsWrapperRef.current[thumbsSlideAxis === 'x' ? 'scrollLeft' : 'scrollTop'] = Math.abs(value[thumbsSlideAxis]);
108
+ }
109
+ },
101
110
  }));
102
111
  useMount(() => {
103
- if (withThumbs) {
104
- const missingThumbs = items.some(item => !item.renderThumb);
105
- if (missingThumbs) {
106
- throw new Error('The renderThumb property is missing in one or more items. You need to add the renderThumb property to every item of the carousel when the prop withThumbs={true} or eventually set withThumbs={false}.');
107
- }
112
+ if (withThumbs && !internalThumbsWrapperRef.current) {
113
+ throw new Error("The thumbs wrapper is not defined. If you've passed a Functional component, be sure to wrap your component in forwardRef.");
108
114
  }
109
115
  });
110
- function handleThumbsScroll(activeItem) {
111
- function getOffsetDirection() {
112
- return thumbsSlideAxis === 'x' ? 'offsetLeft' : 'offsetTop';
113
- }
114
- function getOffsetDimension() {
115
- return thumbsSlideAxis === 'x' ? 'offsetWidth' : 'offsetHeight';
116
- }
117
- function getScrollDirecton() {
118
- return thumbsSlideAxis === 'x' ? 'scrollLeft' : 'scrollTop';
119
- }
120
- function getThumbNode() {
121
- return internalThumbsWrapperRef.current.querySelector(`#thumb-${items[activeItem].id}`);
122
- }
123
- function getThumbOffsetPosition({ thumbNode, offsetDirection, offsetDimension, }) {
124
- return thumbNode[offsetDirection] + thumbNode[offsetDimension] / 2;
125
- }
126
- function getThumbScrollDimension({ thumbWrapper, offsetDimension, }) {
127
- return thumbWrapper[offsetDimension] / 2;
128
- }
129
- function getScrollFromValue({ thumbWrapper, scrollDirection, }) {
130
- return thumbWrapper[scrollDirection];
131
- }
132
- function getScrollToValue({ thumbWrapper, thumbOffsetPosition, thumbScrollDimension, offsetDimension, }) {
133
- const scrollDimensionProperty = thumbsSlideAxis === 'x' ? 'scrollWidth' : 'scrollHeight';
134
- if (activeItem === items.length - 1 ||
135
- thumbOffsetPosition - thumbScrollDimension >
136
- thumbWrapper[scrollDimensionProperty] - thumbWrapper[offsetDimension]) {
137
- return thumbWrapper[scrollDimensionProperty] - thumbWrapper[offsetDimension];
116
+ function getCurrentThumbScrollValue() {
117
+ return internalThumbsWrapperRef.current[thumbsSlideAxis === 'x' ? 'scrollLeft' : 'scrollTop'];
118
+ }
119
+ function getThumbsTotalScrollableValue() {
120
+ return Math.round(Number(internalThumbsWrapperRef.current?.[thumbsSlideAxis === 'x' ? 'scrollWidth' : 'scrollHeight']) -
121
+ internalThumbsWrapperRef.current.getBoundingClientRect()[thumbsSlideAxis === 'x' ? 'width' : 'height']);
122
+ }
123
+ function getThumbSlideValue() {
124
+ const thumbSlideTotal = Math.round(getFluidWrapperScrollValue() / getSlideValue());
125
+ const totalScrollableValue = getThumbsTotalScrollableValue();
126
+ return totalScrollableValue / thumbSlideTotal;
127
+ }
128
+ function handleThumbsScroll(activeItem, actionType) {
129
+ if (itemsPerSlide === 'fluid') {
130
+ const totalScrollableValue = getThumbsTotalScrollableValue();
131
+ if (actionType === 'next') {
132
+ const nextValue = getCurrentThumbScrollValue() + getThumbSlideValue();
133
+ setThumbListStyles.start({
134
+ from: {
135
+ [thumbsSlideAxis]: getCurrentThumbScrollValue(),
136
+ },
137
+ to: {
138
+ [thumbsSlideAxis]: nextValue > totalScrollableValue ? totalScrollableValue : nextValue,
139
+ },
140
+ });
138
141
  }
139
- if (activeItem === 0) {
140
- return 0;
142
+ if (actionType === 'prev') {
143
+ const nextValue = getCurrentThumbScrollValue() - getThumbSlideValue();
144
+ setThumbListStyles.start({
145
+ from: {
146
+ [thumbsSlideAxis]: getCurrentThumbScrollValue(),
147
+ },
148
+ to: {
149
+ [thumbsSlideAxis]: nextValue < 0 ? 0 : nextValue,
150
+ },
151
+ });
141
152
  }
142
- return thumbOffsetPosition - thumbScrollDimension;
143
153
  }
144
- if (thumbsWrapperRef && thumbsWrapperRef.current) {
145
- internalThumbsWrapperRef.current = thumbsWrapperRef.current;
146
- }
147
- const thumbNode = getThumbNode();
148
- if (thumbNode) {
149
- const thumbWrapper = internalThumbsWrapperRef.current;
150
- const offsetDirection = getOffsetDirection();
151
- const offsetDimension = getOffsetDimension();
152
- const scrollDirection = getScrollDirecton();
153
- const thumbOffsetPosition = getThumbOffsetPosition({
154
- thumbNode,
155
- offsetDimension,
156
- offsetDirection,
157
- });
158
- const thumbScrollDimension = getThumbScrollDimension({
159
- thumbWrapper,
160
- offsetDimension,
161
- });
162
- setThumbListStyles.start({
163
- from: {
164
- [thumbsSlideAxis]: getScrollFromValue({
165
- thumbWrapper,
166
- scrollDirection,
167
- }),
168
- },
169
- to: {
170
- [thumbsSlideAxis]: getScrollToValue({
171
- thumbWrapper,
172
- thumbOffsetPosition,
173
- thumbScrollDimension,
174
- offsetDimension,
175
- }),
176
- },
177
- onChange: val => {
178
- if (thumbsSlideAxis === 'x') {
179
- // @ts-ignore
180
- internalThumbsWrapperRef.current.scrollLeft = val.x;
181
- }
182
- else {
183
- // @ts-ignore
184
- internalThumbsWrapperRef.current.scrollTop = val.y;
185
- }
186
- },
187
- });
154
+ else {
155
+ function getOffsetDirection() {
156
+ return thumbsSlideAxis === 'x' ? 'offsetLeft' : 'offsetTop';
157
+ }
158
+ function getOffsetDimension() {
159
+ return thumbsSlideAxis === 'x' ? 'offsetWidth' : 'offsetHeight';
160
+ }
161
+ function getScrollDirecton() {
162
+ return thumbsSlideAxis === 'x' ? 'scrollLeft' : 'scrollTop';
163
+ }
164
+ function getThumbNode() {
165
+ return internalThumbsWrapperRef.current.querySelector(`#thumb-${items[activeItem].id}`);
166
+ }
167
+ function getThumbOffsetPosition({ thumbNode, offsetDirection, offsetDimension, }) {
168
+ return thumbNode[offsetDirection] + thumbNode[offsetDimension] / 2;
169
+ }
170
+ function getThumbScrollDimension({ thumbWrapper, offsetDimension, }) {
171
+ return thumbWrapper[offsetDimension] / 2;
172
+ }
173
+ function getScrollFromValue({ thumbWrapper, scrollDirection, }) {
174
+ return thumbWrapper[scrollDirection];
175
+ }
176
+ function getScrollToValue({ thumbWrapper, thumbOffsetPosition, thumbScrollDimension, offsetDimension, }) {
177
+ const scrollDimensionProperty = thumbsSlideAxis === 'x' ? 'scrollWidth' : 'scrollHeight';
178
+ if (activeItem === items.length - 1 ||
179
+ thumbOffsetPosition - thumbScrollDimension >
180
+ thumbWrapper[scrollDimensionProperty] - thumbWrapper[offsetDimension]) {
181
+ return thumbWrapper[scrollDimensionProperty] - thumbWrapper[offsetDimension];
182
+ }
183
+ if (activeItem === 0) {
184
+ return 0;
185
+ }
186
+ return thumbOffsetPosition - thumbScrollDimension;
187
+ }
188
+ const thumbNode = getThumbNode();
189
+ if (thumbNode) {
190
+ const thumbWrapper = internalThumbsWrapperRef.current;
191
+ const offsetDirection = getOffsetDirection();
192
+ const offsetDimension = getOffsetDimension();
193
+ const scrollDirection = getScrollDirecton();
194
+ const thumbOffsetPosition = getThumbOffsetPosition({
195
+ thumbNode,
196
+ offsetDimension,
197
+ offsetDirection,
198
+ });
199
+ const thumbScrollDimension = getThumbScrollDimension({
200
+ thumbWrapper,
201
+ offsetDimension,
202
+ });
203
+ setThumbListStyles.start({
204
+ from: {
205
+ [thumbsSlideAxis]: getScrollFromValue({
206
+ thumbWrapper,
207
+ scrollDirection,
208
+ }),
209
+ },
210
+ to: {
211
+ [thumbsSlideAxis]: getScrollToValue({
212
+ thumbWrapper,
213
+ thumbOffsetPosition,
214
+ thumbScrollDimension,
215
+ offsetDimension,
216
+ }),
217
+ },
218
+ onChange: val => {
219
+ if (thumbsSlideAxis === 'x') {
220
+ // @ts-ignore
221
+ internalThumbsWrapperRef.current.scrollLeft = val.x;
222
+ }
223
+ else {
224
+ // @ts-ignore
225
+ internalThumbsWrapperRef.current.scrollTop = val.y;
226
+ }
227
+ },
228
+ });
229
+ }
188
230
  }
189
231
  }
190
232
  function handlePrepareThumbsDate() {
@@ -199,19 +241,12 @@
199
241
  }
200
242
  return getPreparedItems(items);
201
243
  }
202
- function getScrollDirectionSpringValue() {
203
- if (thumbsSlideAxis === 'x') {
204
- return {
205
- // @ts-ignore
206
- scrollLeft: thumbListStyles.x,
207
- };
208
- }
209
- return {
210
- // @ts-ignore
211
- scrollTop: thumbListStyles.y,
212
- };
213
- }
214
- const thumbsFragment = withThumbs ? (jsxRuntime.jsx(reactSpring.animated.div, Object.assign({ ref: internalThumbsWrapperRef }, getScrollDirectionSpringValue(), { style: {
244
+ const Wrapper = CustomThumbsWrapperComponent
245
+ ? reactSpring.animated(CustomThumbsWrapperComponent)
246
+ : InternalWrapper;
247
+ const thumbsFragment = withThumbs ? (jsxRuntime.jsx(Wrapper, Object.assign({ ref: internalThumbsWrapperRef, className: "use-spring-carousel-thumbs-wrapper", onWheel: () => {
248
+ thumbListStyles[thumbsSlideAxis].stop();
249
+ }, style: {
215
250
  display: 'flex',
216
251
  flex: 1,
217
252
  position: 'relative',
@@ -233,22 +268,14 @@
233
268
  }
234
269
 
235
270
  const UseSpringCarouselContext = react.createContext(undefined);
236
- function useSpringCarouselContext() {
237
- const context = react.useContext(UseSpringCarouselContext);
238
- if (!context) {
239
- throw new Error(`useSpringCarouselContext isn't being used within the useSringCarousel context;
240
- use the context only inside a component that is rendered within the Carousel.`);
241
- }
242
- return context;
243
- }
244
- function useSpringCarousel({ items, withLoop = false, draggingSlideTreshold = 140, springConfig = reactSpring.config.default, shouldResizeOnWindowResize = true, withThumbs = false, enableThumbsWrapperScroll = true, carouselSlideAxis = 'x', thumbsSlideAxis = 'x', thumbsWrapperRef, prepareThumbsData, itemsPerSlide = 1, initialActiveItem = 0, initialStartingPosition = 'start', disableGestures = false, gutter = 0, startEndGutter = 0, touchAction = 'none', slideAmount, }) {
271
+ function useSpringCarousel({ itemsPerSlide = 1, items, withLoop = false, draggingSlideTreshold = 140, springConfig = reactSpring.config.default, shouldResizeOnWindowResize = true, withThumbs = false, enableThumbsWrapperScroll = true, carouselSlideAxis = 'x', thumbsSlideAxis = 'x', prepareThumbsData, initialActiveItem = 0, initialStartingPosition = 'start', disableGestures = false, gutter = 0, startEndGutter = 0, touchAction, slideAmount, freeScroll = false, CustomThumbsWrapperComponent, }) {
245
272
  function getItems() {
246
273
  if (withLoop) {
247
274
  return [...items, ...items, ...items];
248
275
  }
249
276
  return items;
250
277
  }
251
- const slideActionType = react.useRef('next');
278
+ const slideActionType = react.useRef('initial');
252
279
  const internalItems = getItems();
253
280
  const activeItem = react.useRef(initialActiveItem);
254
281
  const mainCarouselWrapperRef = react.useRef(null);
@@ -259,33 +286,51 @@
259
286
  const currentWindowWidth = react.useRef(0);
260
287
  const fluidTotalWrapperScrollValue = react.useRef(0);
261
288
  const slideFluidEndReached = react.useRef(false);
262
- const currentSlidedValue = react.useRef(0);
263
- const currentStepSlideValue = react.useRef(0);
264
- function getCarouselItem() {
265
- return carouselTrackWrapperRef.current?.querySelector('.use-spring-carousel-item');
266
- }
267
- const getFluidWrapperScrollValue = react.useCallback(() => {
268
- return Math.round(Number(carouselTrackWrapperRef.current?.[carouselSlideAxis === 'x' ? 'scrollWidth' : 'scrollHeight']) -
269
- carouselTrackWrapperRef.current.getBoundingClientRect()[carouselSlideAxis === 'x' ? 'width' : 'height']);
270
- }, [carouselSlideAxis]);
289
+ const initialWindowWidth = react.useRef(0);
271
290
  const [carouselStyles, setCarouselStyles] = reactSpring.useSpring(() => ({
272
291
  y: 0,
273
292
  x: 0,
274
293
  config: springConfig,
275
- onRest: ({ value }) => {
276
- currentSlidedValue.current = value[carouselSlideAxis];
277
- currentStepSlideValue.current = value[carouselSlideAxis];
294
+ onChange: ({ value }) => {
295
+ if (mainCarouselWrapperRef.current && freeScroll) {
296
+ mainCarouselWrapperRef.current[carouselSlideAxis === 'x' ? 'scrollLeft' : 'scrollTop'] = Math.abs(value[carouselSlideAxis]);
297
+ }
278
298
  },
279
299
  }));
280
- const getSlideValue = react.useCallback(() => {
281
- if (!carouselTrackWrapperRef.current) {
282
- return 0;
300
+ function getCarouselItem() {
301
+ return carouselTrackWrapperRef.current?.querySelector('.use-spring-carousel-item');
302
+ }
303
+ const getMainCarouselWrapperWidth = react.useCallback(() => {
304
+ if (!mainCarouselWrapperRef.current) {
305
+ throw new Error('mainCarouselWrapperRef is not available');
283
306
  }
307
+ return mainCarouselWrapperRef.current.getBoundingClientRect()[carouselSlideAxis === 'x' ? 'width' : 'height'];
308
+ }, [carouselSlideAxis]);
309
+ const getCarouselItemWidth = react.useCallback(() => {
284
310
  const carouselItem = getCarouselItem();
285
311
  if (!carouselItem) {
286
312
  throw Error('No carousel items available!');
287
313
  }
288
- const itemVal = carouselItem.getBoundingClientRect()[carouselSlideAxis === 'x' ? 'width' : 'height'] + gutter;
314
+ return (carouselItem.getBoundingClientRect()[carouselSlideAxis === 'x' ? 'width' : 'height'] + gutter);
315
+ }, [carouselSlideAxis, gutter]);
316
+ const getCurrentSlidedValue = react.useCallback(() => {
317
+ return carouselStyles[carouselSlideAxis].get();
318
+ }, [carouselSlideAxis, carouselStyles]);
319
+ const getIfItemsNotFillTheCarousel = react.useCallback(() => {
320
+ return getCarouselItemWidth() * items.length < getMainCarouselWrapperWidth();
321
+ }, [getCarouselItemWidth, getMainCarouselWrapperWidth, items.length]);
322
+ const getFluidWrapperScrollValue = react.useCallback(() => {
323
+ return Math.round(Number(carouselTrackWrapperRef.current?.[carouselSlideAxis === 'x' ? 'scrollWidth' : 'scrollHeight']) -
324
+ carouselTrackWrapperRef.current.getBoundingClientRect()[carouselSlideAxis === 'x' ? 'width' : 'height']);
325
+ }, [carouselSlideAxis]);
326
+ const getIsFirstItem = react.useCallback(() => {
327
+ return getCurrentActiveItem() === 0;
328
+ }, []);
329
+ const getSlideValue = react.useCallback(() => {
330
+ if (!carouselTrackWrapperRef.current) {
331
+ return 0;
332
+ }
333
+ const itemVal = getCarouselItemWidth();
289
334
  if (itemsPerSlide === 'fluid' && typeof slideAmount === 'number') {
290
335
  if (slideAmount < itemVal) {
291
336
  throw new Error('slideAmount must be greater than the width of a single item.');
@@ -293,21 +338,23 @@
293
338
  return slideAmount;
294
339
  }
295
340
  return itemVal;
296
- }, [carouselSlideAxis, gutter, itemsPerSlide, slideAmount]);
341
+ }, [getCarouselItemWidth, itemsPerSlide, slideAmount]);
297
342
  const adjustCarouselWrapperPosition = react.useCallback((ref) => {
298
- if (itemsPerSlide !== 'fluid' && typeof itemsPerSlide === 'number') {
299
- const positionProperty = carouselSlideAxis === 'x' ? 'left' : 'top';
300
- function getDefaultPositionValue() {
301
- return getSlideValue() * items.length;
302
- }
303
- function setPosition(v) {
304
- ref.style.top = '0px';
305
- ref.style.left = '0px';
343
+ const positionProperty = carouselSlideAxis === 'x' ? 'left' : 'top';
344
+ function getDefaultPositionValue() {
345
+ return getCarouselItemWidth() * items.length;
346
+ }
347
+ function setPosition(v) {
348
+ ref.style.top = '0px';
349
+ ref.style.left = '0px';
350
+ if (withLoop) {
306
351
  ref.style[positionProperty] = `-${v - startEndGutter}px`;
307
352
  }
308
- function setStartPosition() {
309
- setPosition(getDefaultPositionValue());
310
- }
353
+ }
354
+ function setStartPosition() {
355
+ setPosition(getDefaultPositionValue());
356
+ }
357
+ if (itemsPerSlide !== 'fluid' && typeof itemsPerSlide === 'number') {
311
358
  function setCenterPosition() {
312
359
  setPosition(getDefaultPositionValue() -
313
360
  getSlideValue() * Math.round((itemsPerSlide - 1) / 2));
@@ -337,33 +384,49 @@
337
384
  setStartPosition();
338
385
  }
339
386
  }
387
+ else {
388
+ setStartPosition();
389
+ }
340
390
  }, [
341
- startEndGutter,
342
391
  carouselSlideAxis,
392
+ itemsPerSlide,
393
+ getCarouselItemWidth,
394
+ items.length,
395
+ startEndGutter,
343
396
  getSlideValue,
344
397
  initialStartingPosition,
345
- items.length,
346
- itemsPerSlide,
398
+ withLoop,
347
399
  ]);
348
400
  const handleResize = react.useCallback(() => {
349
- if (window.innerWidth === currentWindowWidth.current) {
401
+ if (window.innerWidth === currentWindowWidth.current || freeScroll) {
350
402
  return;
351
403
  }
352
404
  currentWindowWidth.current = window.innerWidth;
353
405
  if (itemsPerSlide === 'fluid') {
406
+ if (getIfItemsNotFillTheCarousel()) {
407
+ setCarouselStyles.start({
408
+ immediate: true,
409
+ [carouselSlideAxis]: 0,
410
+ });
411
+ return;
412
+ }
354
413
  fluidTotalWrapperScrollValue.current = getFluidWrapperScrollValue();
414
+ const diff = currentWindowWidth.current - initialWindowWidth.current;
355
415
  if (slideFluidEndReached.current) {
416
+ const nextValue = -fluidTotalWrapperScrollValue.current;
356
417
  setCarouselStyles.start({
357
418
  immediate: true,
358
- [carouselSlideAxis]: -fluidTotalWrapperScrollValue.current,
419
+ [carouselSlideAxis]: nextValue,
359
420
  });
360
421
  }
361
422
  else {
362
- const lastItem = document.querySelector('.use-spring-carousel-item:last-of-type');
363
- console.log({
364
- lastItem: lastItem.offsetLeft,
423
+ const nextValue = getCurrentSlidedValue() + diff;
424
+ setCarouselStyles.start({
425
+ immediate: true,
426
+ [carouselSlideAxis]: nextValue,
365
427
  });
366
428
  }
429
+ initialWindowWidth.current = window.innerWidth;
367
430
  }
368
431
  else {
369
432
  setCarouselStyles.start({
@@ -376,17 +439,17 @@
376
439
  [carouselSlideAxis]: -(getSlideValue() * getCurrentActiveItem()),
377
440
  });
378
441
  }
379
- if (withLoop) {
380
- adjustCarouselWrapperPosition(carouselTrackWrapperRef.current);
381
- }
442
+ adjustCarouselWrapperPosition(carouselTrackWrapperRef.current);
382
443
  }, [
383
- adjustCarouselWrapperPosition,
384
- carouselSlideAxis,
385
- getSlideValue,
386
- setCarouselStyles,
387
- withLoop,
388
444
  itemsPerSlide,
445
+ getIfItemsNotFillTheCarousel,
389
446
  getFluidWrapperScrollValue,
447
+ freeScroll,
448
+ setCarouselStyles,
449
+ carouselSlideAxis,
450
+ getCurrentSlidedValue,
451
+ getSlideValue,
452
+ adjustCarouselWrapperPosition,
390
453
  ]);
391
454
  // Custom modules
392
455
  const { useListenToCustomEvent, emitObservable } = useCustomEventsModule();
@@ -400,18 +463,29 @@
400
463
  items,
401
464
  thumbsSlideAxis,
402
465
  springConfig,
403
- thumbsWrapperRef,
404
466
  prepareThumbsData,
467
+ itemsPerSlide,
468
+ getFluidWrapperScrollValue,
469
+ getSlideValue,
470
+ CustomThumbsWrapperComponent,
405
471
  });
406
- function getCurrentSlidedValue() {
407
- return carouselStyles[carouselSlideAxis].get();
472
+ function getWrapperScrollDirection() {
473
+ if (!mainCarouselWrapperRef.current) {
474
+ throw new Error('Missing mainCarouselWrapperRef.current');
475
+ }
476
+ return mainCarouselWrapperRef.current[carouselSlideAxis === 'x' ? 'scrollLeft' : 'scrollTop'];
408
477
  }
409
478
  const bindDrag = react$1.useDrag(props => {
410
479
  const isDragging = props.dragging;
411
480
  const movement = props.movement[carouselSlideAxis === 'x' ? 0 : 1];
412
481
  function resetAnimation() {
413
482
  if (itemsPerSlide === 'fluid') {
414
- if (getIsFirstItem()) {
483
+ if (getIfItemsNotFillTheCarousel()) {
484
+ setCarouselStyles.start({
485
+ [carouselSlideAxis]: 0,
486
+ });
487
+ }
488
+ else if (getIsFirstItem()) {
415
489
  slideToPrevItem();
416
490
  }
417
491
  else if (slideFluidEndReached.current) {
@@ -421,7 +495,7 @@
421
495
  }
422
496
  else {
423
497
  setCarouselStyles.start({
424
- [carouselSlideAxis]: currentStepSlideValue.current,
498
+ [carouselSlideAxis]: getCurrentSlidedValue(),
425
499
  });
426
500
  }
427
501
  }
@@ -431,24 +505,46 @@
431
505
  });
432
506
  }
433
507
  }
434
- if (props.first) {
435
- currentSlidedValue.current = getCurrentSlidedValue();
436
- }
437
508
  if (isDragging) {
438
509
  setIsDragging(true);
439
510
  emitObservable({
440
511
  eventName: 'onDrag',
441
512
  ...props,
442
513
  });
443
- setCarouselStyles.start({
444
- [carouselSlideAxis]: currentSlidedValue.current + movement,
445
- });
514
+ if (freeScroll) {
515
+ const direction = props.direction[carouselSlideAxis === 'x' ? 0 : 1];
516
+ if (getWrapperScrollDirection() === 0 && direction > 0) {
517
+ props.cancel();
518
+ }
519
+ else {
520
+ setCarouselStyles.start({
521
+ from: {
522
+ [carouselSlideAxis]: getWrapperScrollDirection(),
523
+ },
524
+ to: {
525
+ [carouselSlideAxis]: direction > 0
526
+ ? getWrapperScrollDirection() - Math.abs(movement)
527
+ : getWrapperScrollDirection() + Math.abs(movement),
528
+ },
529
+ });
530
+ }
531
+ }
532
+ else {
533
+ setCarouselStyles.start({
534
+ [carouselSlideAxis]: getCurrentSlidedValue() + movement,
535
+ });
536
+ }
446
537
  const prevItemTreshold = movement > draggingSlideTreshold;
447
538
  const nextItemTreshold = movement < -draggingSlideTreshold;
448
539
  if (mainCarouselWrapperRef.current.getBoundingClientRect().width >=
449
540
  items.length * getSlideValue()) {
450
541
  slideFluidEndReached.current = true;
451
542
  }
543
+ if ((prevItemTreshold || nextItemTreshold) && getIfItemsNotFillTheCarousel()) {
544
+ props.cancel();
545
+ resetAnimation();
546
+ return;
547
+ }
452
548
  if (slideFluidEndReached.current && movement < 0) {
453
549
  if (nextItemTreshold) {
454
550
  props.cancel();
@@ -476,7 +572,7 @@
476
572
  }
477
573
  }
478
574
  }
479
- if (props.last && !props.pressed) {
575
+ if (props.last && !props.pressed && !freeScroll) {
480
576
  resetAnimation();
481
577
  }
482
578
  }, {
@@ -521,6 +617,7 @@
521
617
  }
522
618
  });
523
619
  useMount(() => {
620
+ initialWindowWidth.current = window.innerWidth;
524
621
  if (initialActiveItem > 0 && initialActiveItem <= items.length) {
525
622
  slideToItem({
526
623
  to: initialActiveItem,
@@ -530,10 +627,13 @@
530
627
  }
531
628
  });
532
629
  react.useEffect(() => {
630
+ function resize() {
631
+ setTimeout(handleResize);
632
+ }
533
633
  if (shouldResizeOnWindowResize) {
534
- window.addEventListener('resize', handleResize);
634
+ window.addEventListener('resize', resize);
535
635
  return () => {
536
- window.removeEventListener('resize', handleResize);
636
+ window.removeEventListener('resize', resize);
537
637
  };
538
638
  }
539
639
  }, [handleResize, shouldResizeOnWindowResize]);
@@ -604,18 +704,21 @@
604
704
  function findItemIndex(id) {
605
705
  return items.findIndex(item => item.id === id);
606
706
  }
607
- function slideToItem({ from, to, customTo, immediate = false, onRest = () => { }, }) {
707
+ function slideToItem({ from, to = -1, customTo, immediate = false, onRest = () => { }, }) {
608
708
  if (!immediate) {
609
709
  setActiveItem(to);
610
710
  setIsAnimating(true);
611
711
  emitObservable({
612
712
  eventName: 'onSlideStartChange',
613
- nextItem: to,
614
713
  slideActionType: getSlideActionType(),
714
+ nextItem: {
715
+ index: to,
716
+ id: items[to].id,
717
+ },
615
718
  });
616
719
  }
617
720
  function getFromValue() {
618
- if (from) {
721
+ if (typeof from === 'number') {
619
722
  return {
620
723
  from: {
621
724
  [carouselSlideAxis]: from,
@@ -625,7 +728,7 @@
625
728
  return {};
626
729
  }
627
730
  function getToValue() {
628
- if (customTo) {
731
+ if (typeof customTo === 'number') {
629
732
  return {
630
733
  [carouselSlideAxis]: customTo,
631
734
  };
@@ -646,67 +749,68 @@
646
749
  if (!immediate) {
647
750
  emitObservable({
648
751
  eventName: 'onSlideChange',
649
- currentItem: getCurrentActiveItem(),
650
752
  slideActionType: getSlideActionType(),
753
+ currentItem: {
754
+ index: getCurrentActiveItem(),
755
+ id: items[getCurrentActiveItem()].id,
756
+ },
651
757
  });
652
758
  }
653
759
  }
654
760
  },
655
761
  });
656
762
  if (enableThumbsWrapperScroll && withThumbs && !immediate) {
657
- handleThumbsScroll(to);
658
- }
659
- }
660
- function getWrapperFromValue(element) {
661
- if (element.style.transform === 'none') {
662
- return 0;
763
+ handleThumbsScroll(to, getSlideActionType());
663
764
  }
664
- const values = element.style.transform.split(/\w+\(|\);?/);
665
- return Number(values[1].split(/,\s?/g)[carouselSlideAxis === 'x' ? 0 : 1].replace('px', ''));
666
- }
667
- function getIsFirstItem() {
668
- return getCurrentActiveItem() === 0;
669
765
  }
670
766
  function getIsLastItem() {
671
767
  return getCurrentActiveItem() === items.length - 1;
672
768
  }
673
769
  function slideToPrevItem() {
674
- if (itemsPerSlide === 'fluid' && !withLoop) {
675
- const currentSlideVal = getWrapperFromValue(carouselTrackWrapperRef.current);
676
- const nextPrevValue = currentSlideVal + getSlideValue() + 100;
677
- if (getIsFirstItem()) {
678
- slideToItem({
679
- to: 0,
680
- });
770
+ setSlideActionType('prev');
771
+ if (itemsPerSlide === 'fluid') {
772
+ if (getIfItemsNotFillTheCarousel()) {
681
773
  return;
682
774
  }
683
- if (nextPrevValue >= 0) {
775
+ const nextPrevValue = getCurrentSlidedValue() + getSlideValue() + 200;
776
+ if (freeScroll) {
777
+ const nextValue = mainCarouselWrapperRef.current.scrollLeft - getSlideValue();
684
778
  slideToItem({
685
- to: 0,
779
+ customTo: nextValue < 0 ? 0 : nextValue,
780
+ from: mainCarouselWrapperRef.current.scrollLeft,
686
781
  });
687
- currentStepSlideValue.current = 0;
782
+ }
783
+ else if (nextPrevValue >= 0) {
784
+ if (withLoop) {
785
+ slideToItem({
786
+ from: getCurrentSlidedValue() - getCarouselItemWidth() * items.length,
787
+ customTo: getCurrentSlidedValue() -
788
+ getCarouselItemWidth() * items.length +
789
+ getSlideValue(),
790
+ });
791
+ }
792
+ else {
793
+ slideToItem({
794
+ customTo: 0,
795
+ });
796
+ }
688
797
  }
689
798
  else {
690
- const nextVal = currentStepSlideValue.current + getSlideValue();
691
- currentStepSlideValue.current = nextVal;
692
799
  slideToItem({
693
- to: getPrevItem(),
694
- customTo: nextVal,
800
+ customTo: getCurrentSlidedValue() + getSlideValue(),
695
801
  });
696
802
  }
697
803
  if (slideFluidEndReached.current) {
698
804
  slideFluidEndReached.current = false;
699
805
  }
700
806
  }
701
- else if ((!withLoop && getCurrentActiveItem() === 0) || windowIsHidden.current) {
702
- return;
703
- }
704
807
  else {
705
- setSlideActionType('prev');
808
+ if ((!withLoop && getCurrentActiveItem() === 0) || windowIsHidden.current) {
809
+ return;
810
+ }
706
811
  if (getIsFirstItem()) {
707
812
  slideToItem({
708
- from: -(Math.abs(getWrapperFromValue(carouselTrackWrapperRef.current)) +
709
- getSlideValue() * items.length),
813
+ from: getCurrentSlidedValue() - getSlideValue() * items.length,
710
814
  to: items.length - 1,
711
815
  });
712
816
  }
@@ -718,58 +822,51 @@
718
822
  }
719
823
  }
720
824
  function slideToNextItem() {
721
- if (itemsPerSlide === 'fluid' && !withLoop) {
722
- const willGoAfterLastFluidItem = Math.abs(getNextItem() * getSlideValue()) + 100 >=
825
+ setSlideActionType('next');
826
+ if (itemsPerSlide === 'fluid') {
827
+ if (getIfItemsNotFillTheCarousel()) {
828
+ return;
829
+ }
830
+ const willGoAfterLastFluidItem = Math.abs(getCurrentSlidedValue() - getSlideValue()) + 100 >=
723
831
  fluidTotalWrapperScrollValue.current;
724
- function getDefaultNextValue() {
725
- return -(getNextItem() * getSlideValue());
832
+ if (freeScroll) {
833
+ slideToItem({
834
+ customTo: mainCarouselWrapperRef.current.scrollLeft + getSlideValue(),
835
+ from: mainCarouselWrapperRef.current.scrollLeft,
836
+ });
726
837
  }
727
- console.log(getDefaultNextValue());
728
- if (mainCarouselWrapperRef.current.getBoundingClientRect().width >=
729
- items.length * getSlideValue()) {
730
- slideFluidEndReached.current = true;
838
+ else if (withLoop &&
839
+ Math.abs(getCurrentSlidedValue() - getSlideValue()) >=
840
+ items.length * getCarouselItemWidth()) {
841
+ const currentWidth = getCarouselItemWidth() * items.length;
842
+ slideToItem({
843
+ from: getCurrentSlidedValue() + currentWidth,
844
+ customTo: getCurrentSlidedValue() + currentWidth - getSlideValue(),
845
+ });
731
846
  }
732
- if (slideFluidEndReached.current) {
847
+ else if (slideFluidEndReached.current) {
733
848
  return;
734
849
  }
735
- if (willGoAfterLastFluidItem) {
736
- const nextValue = -fluidTotalWrapperScrollValue.current;
850
+ else if (willGoAfterLastFluidItem) {
737
851
  slideFluidEndReached.current = true;
738
- currentStepSlideValue.current = nextValue;
739
852
  slideToItem({
740
- customTo: nextValue,
741
- to: getNextItem(),
853
+ customTo: -fluidTotalWrapperScrollValue.current,
742
854
  });
743
855
  }
744
856
  else {
745
- const isPure = Math.abs(currentStepSlideValue.current % getSlideValue()) === 0;
746
- if (!isPure) {
747
- const nextValue = currentStepSlideValue.current - getSlideValue();
748
- currentStepSlideValue.current = nextValue;
749
- slideToItem({
750
- to: getNextItem(),
751
- customTo: nextValue,
752
- });
753
- }
754
- else {
755
- currentStepSlideValue.current = getDefaultNextValue();
756
- slideToItem({
757
- to: getNextItem(),
758
- customTo: getDefaultNextValue(),
759
- });
760
- }
857
+ slideToItem({
858
+ customTo: getCurrentSlidedValue() - getSlideValue(),
859
+ });
761
860
  }
762
861
  }
763
- else if ((!withLoop && getCurrentActiveItem() === internalItems.length - 1) ||
764
- windowIsHidden.current) {
765
- return;
766
- }
767
862
  else {
768
- setSlideActionType('next');
863
+ if ((!withLoop && getCurrentActiveItem() === internalItems.length - 1) ||
864
+ windowIsHidden.current) {
865
+ return;
866
+ }
769
867
  if (getIsLastItem()) {
770
868
  slideToItem({
771
- from: getWrapperFromValue(carouselTrackWrapperRef.current) +
772
- getSlideValue() * items.length,
869
+ from: getCurrentSlidedValue() + getSlideValue() * items.length,
773
870
  to: 0,
774
871
  });
775
872
  }
@@ -818,14 +915,18 @@
818
915
  getIsPrevItem,
819
916
  slideToPrevItem,
820
917
  slideToNextItem,
821
- slideToItem: _slideToItem,
822
- getIsActiveItem: id => {
823
- return findItemIndex(id) === getCurrentActiveItem();
824
- },
825
- getCurrentActiveItem: () => ({
826
- id: items[getCurrentActiveItem()].id,
827
- index: getCurrentActiveItem(),
828
- }),
918
+ ...(typeof itemsPerSlide === 'number'
919
+ ? {
920
+ slideToItem: _slideToItem,
921
+ getIsActiveItem: (id) => {
922
+ return findItemIndex(id) === getCurrentActiveItem();
923
+ },
924
+ getCurrentActiveItem: () => ({
925
+ id: items[getCurrentActiveItem()].id,
926
+ index: getCurrentActiveItem(),
927
+ }),
928
+ }
929
+ : {}),
829
930
  };
830
931
  function getItemStyles() {
831
932
  if (typeof itemsPerSlide === 'number') {
@@ -849,28 +950,59 @@
849
950
  height: carouselSlideAxis === 'y' ? percentValue : '100%',
850
951
  };
851
952
  }
852
- const carouselFragment = (jsxRuntime.jsx(UseSpringCarouselContext.Provider, Object.assign({ value: contextProps }, { children: jsxRuntime.jsx("div", Object.assign({ ref: mainCarouselWrapperRef, "data-testid": "use-spring-carousel-wrapper", style: {
953
+ function handleCarouselFragmentRef(ref) {
954
+ if (ref) {
955
+ carouselTrackWrapperRef.current = ref;
956
+ adjustCarouselWrapperPosition(ref);
957
+ }
958
+ }
959
+ function getOverflowStyles() {
960
+ if (freeScroll) {
961
+ if (carouselSlideAxis === 'x') {
962
+ return {
963
+ overflowX: 'auto',
964
+ };
965
+ }
966
+ return {
967
+ overflowY: 'auto',
968
+ };
969
+ }
970
+ return {};
971
+ }
972
+ function getWheelEvent() {
973
+ if (freeScroll) {
974
+ return {
975
+ onWheel() {
976
+ carouselStyles[carouselSlideAxis].stop();
977
+ },
978
+ };
979
+ }
980
+ return {};
981
+ }
982
+ function getTouchAction() {
983
+ if (!touchAction) {
984
+ if (carouselSlideAxis === 'x') {
985
+ return 'pan-y';
986
+ }
987
+ return 'pan-x';
988
+ }
989
+ return touchAction;
990
+ }
991
+ const carouselFragment = (jsxRuntime.jsx(UseSpringCarouselContext.Provider, Object.assign({ value: contextProps }, { children: jsxRuntime.jsx("div", Object.assign({ ref: mainCarouselWrapperRef, className: "use-spring-carousel-main-wrapper", "data-testid": "use-spring-carousel-wrapper" }, getWheelEvent(), {
992
+ // @ts-ignore
993
+ style: {
853
994
  display: 'flex',
854
995
  position: 'relative',
855
996
  width: '100%',
856
997
  height: '100%',
857
- overflow: 'hidden',
858
- } }, { children: jsxRuntime.jsx(reactSpring.animated.div, Object.assign({}, bindDrag(), { "data-testid": "use-spring-carousel-animated-wrapper", style: {
998
+ ...getOverflowStyles(),
999
+ } }, { children: jsxRuntime.jsx(reactSpring.animated.div, Object.assign({}, bindDrag(), { className: "use-spring-carousel-track-wrapper", "data-testid": "use-spring-carousel-animated-wrapper", ref: handleCarouselFragmentRef, style: {
859
1000
  display: 'flex',
860
- top: 0,
861
- left: 0,
862
1001
  position: 'relative',
863
- touchAction,
1002
+ touchAction: getTouchAction(),
864
1003
  flexDirection: carouselSlideAxis === 'x' ? 'row' : 'column',
865
1004
  ...getAnimatedWrapperStyles(),
866
- ...carouselStyles,
867
- }, ref: ref => {
868
- if (ref) {
869
- carouselTrackWrapperRef.current = ref;
870
- if (withLoop) {
871
- adjustCarouselWrapperPosition(ref);
872
- }
873
- }
1005
+ ...(freeScroll ? {} : carouselStyles),
874
1006
  } }, { children: internalItems.map(({ id, renderItem }, index) => {
875
1007
  return (jsxRuntime.jsx("div", Object.assign({ className: "use-spring-carousel-item", "data-testid": "use-spring-carousel-item-wrapper", style: {
876
1008
  display: 'flex',
@@ -880,10 +1012,17 @@
880
1012
  }) }), void 0) }), void 0) }), void 0));
881
1013
  const thumbsFragment = (jsxRuntime.jsx(UseSpringCarouselContext.Provider, Object.assign({ value: contextProps }, { children: _thumbsFragment }), void 0));
882
1014
  return {
1015
+ ...contextProps,
883
1016
  carouselFragment,
884
1017
  thumbsFragment,
885
- ...contextProps,
886
1018
  };
1019
+ }
1020
+ function useSpringCarouselContext() {
1021
+ const context = react.useContext(UseSpringCarouselContext);
1022
+ if (!context) {
1023
+ throw new Error('useSpringCarouselContext must be used only inside a component that is rendered inside the Carousel.');
1024
+ }
1025
+ return context;
887
1026
  }
888
1027
 
889
1028
  const UseTransitionCarouselContext = react.createContext(undefined);
@@ -895,7 +1034,7 @@
895
1034
  }
896
1035
  return context;
897
1036
  }
898
- function useTransitionCarousel({ items, withLoop = false, withThumbs = false, springConfig = reactSpring.config.default, thumbsSlideAxis = 'x', enableThumbsWrapperScroll = true, draggingSlideTreshold = 50, prepareThumbsData, toPrevItemSpringProps, toNextItemSpringProps, disableGestures = false, springAnimationProps = {
1037
+ function useTransitionCarousel({ items, withLoop = false, withThumbs = false, springConfig = reactSpring.config.default, thumbsSlideAxis = 'x', enableThumbsWrapperScroll = true, draggingSlideTreshold = 50, prepareThumbsData, toPrevItemSpringProps, toNextItemSpringProps, disableGestures = false, CustomThumbsWrapperComponent, springAnimationProps = {
899
1038
  initial: {
900
1039
  opacity: 1,
901
1040
  position: 'relative',
@@ -928,6 +1067,7 @@
928
1067
  thumbsSlideAxis,
929
1068
  springConfig,
930
1069
  prepareThumbsData,
1070
+ CustomThumbsWrapperComponent,
931
1071
  });
932
1072
  const bindSwipe = react$1.useDrag(({ last, movement: [mx] }) => {
933
1073
  if (getIsAnimating()) {
@@ -1019,8 +1159,11 @@
1019
1159
  setIsAnimating(false);
1020
1160
  emitObservable({
1021
1161
  eventName: 'onSlideChange',
1022
- currentItem: activeItem,
1023
1162
  slideActionType: getSlideActionType(),
1163
+ currentItem: {
1164
+ index: activeItem,
1165
+ id: items[activeItem].id,
1166
+ },
1024
1167
  });
1025
1168
  }
1026
1169
  },
@@ -1062,8 +1205,11 @@
1062
1205
  const newActiveItem = findItemIndex(items[itemIndex].id);
1063
1206
  emitObservable({
1064
1207
  eventName: 'onSlideStartChange',
1065
- nextItem: newActiveItem,
1066
1208
  slideActionType: getSlideActionType(),
1209
+ nextItem: {
1210
+ index: newActiveItem,
1211
+ id: items[itemIndex].id,
1212
+ },
1067
1213
  });
1068
1214
  if (newActiveItem > currentItem) {
1069
1215
  setSlideActionType('next');
@@ -1083,16 +1229,22 @@
1083
1229
  if (isLastItem) {
1084
1230
  emitObservable({
1085
1231
  eventName: 'onSlideStartChange',
1086
- nextItem: 0,
1087
1232
  slideActionType: getSlideActionType(),
1233
+ nextItem: {
1234
+ index: 0,
1235
+ id: items[0].id,
1236
+ },
1088
1237
  });
1089
1238
  setActiveItem(0);
1090
1239
  }
1091
1240
  else {
1092
1241
  emitObservable({
1093
1242
  eventName: 'onSlideStartChange',
1094
- nextItem: activeItem + 1,
1095
1243
  slideActionType: getSlideActionType(),
1244
+ nextItem: {
1245
+ index: activeItem + 1,
1246
+ id: items[activeItem + 1].id,
1247
+ },
1096
1248
  });
1097
1249
  setActiveItem(activeItem + 1);
1098
1250
  }
@@ -1101,8 +1253,11 @@
1101
1253
  if (!isLastItem) {
1102
1254
  emitObservable({
1103
1255
  eventName: 'onSlideStartChange',
1104
- nextItem: activeItem + 1,
1105
1256
  slideActionType: getSlideActionType(),
1257
+ nextItem: {
1258
+ index: activeItem + 1,
1259
+ id: items[activeItem + 1].id,
1260
+ },
1106
1261
  });
1107
1262
  setSlideActionType('next');
1108
1263
  setActiveItem(activeItem + 1);
@@ -1116,16 +1271,22 @@
1116
1271
  if (isFirstItem) {
1117
1272
  emitObservable({
1118
1273
  eventName: 'onSlideStartChange',
1119
- nextItem: items.length - 1,
1120
1274
  slideActionType: getSlideActionType(),
1275
+ nextItem: {
1276
+ index: activeItem - 1,
1277
+ id: items[activeItem - 1].id,
1278
+ },
1121
1279
  });
1122
1280
  setActiveItem(items.length - 1);
1123
1281
  }
1124
1282
  else {
1125
1283
  emitObservable({
1126
1284
  eventName: 'onSlideStartChange',
1127
- nextItem: activeItem - 1,
1128
1285
  slideActionType: getSlideActionType(),
1286
+ nextItem: {
1287
+ index: activeItem - 1,
1288
+ id: items[activeItem - 1].id,
1289
+ },
1129
1290
  });
1130
1291
  setActiveItem(activeItem - 1);
1131
1292
  }
@@ -1135,8 +1296,11 @@
1135
1296
  setSlideActionType('prev');
1136
1297
  emitObservable({
1137
1298
  eventName: 'onSlideStartChange',
1138
- nextItem: activeItem - 1,
1139
1299
  slideActionType: getSlideActionType(),
1300
+ nextItem: {
1301
+ index: activeItem - 1,
1302
+ id: items[activeItem - 1].id,
1303
+ },
1140
1304
  });
1141
1305
  setActiveItem(activeItem - 1);
1142
1306
  }