@hh.ru/magritte-ui-scrollable-container 5.3.0 → 6.0.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.
Files changed (47) hide show
  1. package/ObservableValue.d.ts +13 -0
  2. package/ObservableValue.js +24 -0
  3. package/ObservableValue.js.map +1 -0
  4. package/ScrollStateProvider.d.ts +35 -0
  5. package/ScrollStateProvider.js +22 -0
  6. package/ScrollStateProvider.js.map +1 -0
  7. package/ScrollableContainer.d.ts +19 -12
  8. package/ScrollableContainer.js +48 -104
  9. package/ScrollableContainer.js.map +1 -1
  10. package/ScrollableContainerButton.d.ts +4 -0
  11. package/ScrollableContainerButton.js +28 -0
  12. package/ScrollableContainerButton.js.map +1 -0
  13. package/ScrollableContainerDefaultLayout.d.ts +3 -0
  14. package/ScrollableContainerDefaultLayout.js +72 -0
  15. package/ScrollableContainerDefaultLayout.js.map +1 -0
  16. package/ScrollableContainerDotPages.d.ts +3 -0
  17. package/ScrollableContainerDotPages.js +67 -0
  18. package/ScrollableContainerDotPages.js.map +1 -0
  19. package/ScrollableContainerGallery.d.ts +4 -0
  20. package/ScrollableContainerGallery.js +76 -0
  21. package/ScrollableContainerGallery.js.map +1 -0
  22. package/ScrollableItem.d.ts +3 -2
  23. package/ScrollableItem.js +15 -10
  24. package/ScrollableItem.js.map +1 -1
  25. package/index.css +18 -44
  26. package/index.d.ts +5 -3
  27. package/index.js +16 -6
  28. package/index.js.map +1 -1
  29. package/index.mock.d.ts +5 -4
  30. package/index.mock.js +35 -11
  31. package/index.mock.js.map +1 -1
  32. package/package.json +4 -3
  33. package/scrollableContainer-CsVTi8_Q.js +5 -0
  34. package/scrollableContainer-CsVTi8_Q.js.map +1 -0
  35. package/types.d.ts +61 -83
  36. package/types.js.map +1 -1
  37. package/useScrollContainer.d.ts +20 -13
  38. package/useScrollContainer.js +190 -7
  39. package/useScrollContainer.js.map +1 -1
  40. package/useScrollableControls.d.ts +4 -0
  41. package/useScrollableControls.js +57 -0
  42. package/useScrollableControls.js.map +1 -0
  43. package/utils.d.ts +80 -0
  44. package/utils.js +277 -1
  45. package/utils.js.map +1 -1
  46. package/useScrollContainer-DvtB6-c_.js +0 -491
  47. package/useScrollContainer-DvtB6-c_.js.map +0 -1
@@ -1,491 +0,0 @@
1
- import './index.css';
2
- import { useState, useRef, useCallback, useEffect, useLayoutEffect } from 'react';
3
- import classnames from 'classnames';
4
- import { requestAnimation } from '@hh.ru/magritte-common-func-utils';
5
- import { initScrollHandlers, clamp } from '@hh.ru/magritte-internal-custom-scroll';
6
- import { OFFSET_ATTR } from './types.js';
7
- import { debounce } from './utils.js';
8
-
9
- var styles = {"scroll-wrapper":"magritte-scroll-wrapper___vTdZl_5-3-0","scrollWrapper":"magritte-scroll-wrapper___vTdZl_5-3-0","scrollable-container":"magritte-scrollable-container___AKIUp_5-3-0","scrollableContainer":"magritte-scrollable-container___AKIUp_5-3-0","fade-both-sides":"magritte-fade-both-sides___pBan7_5-3-0","fadeBothSides":"magritte-fade-both-sides___pBan7_5-3-0","no-buttons":"magritte-no-buttons___eCwO-_5-3-0","noButtons":"magritte-no-buttons___eCwO-_5-3-0","fade-left-side":"magritte-fade-left-side___Hlpre_5-3-0","fadeLeftSide":"magritte-fade-left-side___Hlpre_5-3-0","fade-right-side":"magritte-fade-right-side___Lskyt_5-3-0","fadeRightSide":"magritte-fade-right-side___Lskyt_5-3-0","scroll-button":"magritte-scroll-button___4GQu3_5-3-0","scrollButton":"magritte-scroll-button___4GQu3_5-3-0","scroll-button-left":"magritte-scroll-button-left___UueEY_5-3-0","scrollButtonLeft":"magritte-scroll-button-left___UueEY_5-3-0","scroll-button-right":"magritte-scroll-button-right___wZOn-_5-3-0","scrollButtonRight":"magritte-scroll-button-right___wZOn-_5-3-0","position-container":"magritte-position-container___1A4Bv_5-3-0","positionContainer":"magritte-position-container___1A4Bv_5-3-0","position-container-animated":"magritte-position-container-animated___XuPNW_5-3-0","positionContainerAnimated":"magritte-position-container-animated___XuPNW_5-3-0","dot-container":"magritte-dot-container___ahtlG_5-3-0","dotContainer":"magritte-dot-container___ahtlG_5-3-0"};
10
-
11
- const BUTTON_WIDTH = 44;
12
- const FOCUS_OUTLINE_WIDTH = 4;
13
- const DEFAULT_DOT = 1;
14
- /**
15
- * На базе стейта проверяем возможность использования вычисленного index-а
16
- * @param index значение для проверки
17
- * @param state Состояние скролла
18
- */
19
- const isIncorrectIndex = (index, state) => index < 0 || state.items.length - 1 < index;
20
- /**
21
- * Валидирует значение анимации и устанавливает ее в контейнер
22
- * @param translation значение анимации
23
- * @param state Состояние скролла
24
- */
25
- const setTranslation = (translation, state) => {
26
- const { positionContainerRef, positionContainerWidth, containerWidth } = state;
27
- if (!positionContainerRef.current) {
28
- return;
29
- }
30
- const prevTranslation = state.positionContainerTranslation;
31
- state.positionContainerTranslation = clamp(translation, containerWidth - positionContainerWidth, 0);
32
- positionContainerRef.current.style.transform = `translate3d(${state.positionContainerTranslation}px, 0, 0)`;
33
- if (prevTranslation !== state.positionContainerTranslation) {
34
- state.onScroll?.();
35
- }
36
- };
37
- /**
38
- * Вычисляет нужно ли показывать фейды по краям и скрывать кнопки скролла
39
- * Применяет соответствующие классы к обертке
40
- * Проверяет что сдвиг контейнера позиционирования находится в допустимых пределах и если нет, то корректирует его
41
- * @param state Состояние скролла
42
- */
43
- const applyScrollButtonsUpdate = (state) => {
44
- const { positionContainerRef, wrapperRef, positionContainerWidth, containerWidth } = state;
45
- let { positionContainerTranslation } = state;
46
- if (!positionContainerRef.current || !wrapperRef.current) {
47
- return;
48
- }
49
- if (positionContainerWidth + positionContainerTranslation < containerWidth) {
50
- positionContainerTranslation = containerWidth - positionContainerWidth;
51
- setTranslation(positionContainerTranslation, state);
52
- }
53
- const isFadeLeft = positionContainerTranslation < 0;
54
- const isFadeRight = positionContainerTranslation + positionContainerWidth > containerWidth;
55
- const className = classnames({
56
- [styles.fadeLeftSide]: isFadeLeft && !isFadeRight,
57
- [styles.fadeRightSide]: isFadeRight && !isFadeLeft,
58
- [styles.fadeBothSides]: isFadeRight && isFadeLeft,
59
- });
60
- wrapperRef.current.classList.remove(styles.fadeBothSides, styles.fadeLeftSide, styles.fadeRightSide);
61
- className && wrapperRef.current.classList.add(className);
62
- };
63
- const setAnimated = (state, animated) => {
64
- state.positionContainerRef.current?.classList.toggle(styles.positionContainerAnimated, animated);
65
- if (!animated) {
66
- state.scrollAnimationInProgress = false;
67
- }
68
- };
69
- /**
70
- * Скролл к конкретному элементу группы. Если на момент вызова нет ref контейнера позиционирования, то считаем что
71
- * функция была при маунте компонента и запоминаем элемент на который нужно скроллить. При маунте вызываем эту функцию
72
- * еще раз и скроллим к запомненному элементу без анимации.
73
- * @param state Состояние скролла
74
- * @param item Элемент к которому нужно подскроллить
75
- */
76
- const scrollTo = (state, item) => {
77
- const { positionContainerTranslation, containerWidth, positionContainerRef, scrollToItemInProgress, disableButtons, positionContainerWidth, snapToNearestItem, items, isMobile, } = state;
78
- if (!positionContainerRef.current) {
79
- state.scrollToOnMount = item;
80
- return;
81
- }
82
- if (item.current === scrollToItemInProgress?.current) {
83
- return;
84
- }
85
- state.previousActiveIndexItem = items.indexOf(item);
86
- const offset = item.current[OFFSET_ATTR];
87
- const width = offset.right - offset.left;
88
- const buttonsCorrection = disableButtons ? 0 : BUTTON_WIDTH;
89
- // нужно ли отцентрировать контейнер по текущему item
90
- // актуально для режима showDotPages/snapToNearestItem
91
- // так как контейнер работает как карусель
92
- const needItemCorrection = snapToNearestItem || isMobile;
93
- let translation = positionContainerTranslation;
94
- if (width > containerWidth) {
95
- // элемент шире контейнера, выравниваем его левый край с левым краем контейнера
96
- translation = -offset.left;
97
- }
98
- else if ((offset.left + positionContainerTranslation < buttonsCorrection || needItemCorrection) &&
99
- positionContainerTranslation < 0) {
100
- // контейнер движется вправо
101
- const correction = needItemCorrection ? (containerWidth - width) / 2 : buttonsCorrection;
102
- translation = -offset.left + correction;
103
- }
104
- else if ((offset.right + positionContainerTranslation > containerWidth - buttonsCorrection || needItemCorrection) &&
105
- positionContainerTranslation > containerWidth - positionContainerWidth) {
106
- // контейнер движется влево
107
- const correction = needItemCorrection ? (containerWidth - width) / 2 : buttonsCorrection;
108
- translation = containerWidth - offset.right - correction;
109
- }
110
- translation = clamp(translation, containerWidth - positionContainerWidth, 0);
111
- const isPositionChanged = translation !== positionContainerTranslation;
112
- const needAnimation = !state.scrollToOnMount && isPositionChanged;
113
- // Если это скролл при маунте, или позиция скролла не изменилась, то его не нужно анимировать
114
- setAnimated(state, needAnimation);
115
- setTranslation(translation, state);
116
- if (needAnimation) {
117
- state.scrollAnimationInProgress = true;
118
- state.scrollToItemInProgress = item;
119
- }
120
- applyScrollButtonsUpdate(state);
121
- };
122
- /**
123
- * Если текущий элемент совпадает с новым
124
- * Находим следующий активный элемент по направлению и скролим к нему
125
- */
126
- const scrollToNewItemDebounced = debounce((state, indexNearestToCenter) => {
127
- const { previousActiveIndexItem, items, directionRight } = state;
128
- let index = indexNearestToCenter;
129
- // определяем ситуацию, когда скрола не хватило до следующего элемента
130
- if (previousActiveIndexItem === indexNearestToCenter) {
131
- const indexBasedOnDirection = directionRight ? indexNearestToCenter + 1 : indexNearestToCenter - 1;
132
- // нужно проверить новый индекс, чтобы не выходить за границы
133
- if (!isIncorrectIndex(indexBasedOnDirection, state)) {
134
- index = indexBasedOnDirection;
135
- state.setActiveDot(index + 1);
136
- }
137
- }
138
- const item = items[index];
139
- scrollTo(state, item);
140
- }, 30);
141
- /**
142
- * Скролл к конкретному элементу группы (обернуто в debounce)
143
- */
144
- const scrollToDebounced = debounce((state, index) => scrollTo(state, state.items[index]), 30);
145
- const MAX_OFFSET = { [OFFSET_ATTR]: { left: Number.MAX_SAFE_INTEGER } };
146
- /**
147
- * Пересчитывает позиции элементов и обновляет состояние скролла. Вызывается при изменении размеров контейнера или
148
- * добавлении/удалении элементов. Проходится по всем элементам и вычисляет сдвиг их правой и левой границы относительно
149
- * контейнера позиционирования. Сортирует элементы по возрастанию сдвига левой границы. Вычисляет ширину внешнего
150
- * контейнера и контейнера позиционирования. При вычислении ширины контейнера позиционирования правой его границей
151
- * считается правая граница самого крайнего справа элемента. Это нужно чтобы при переносе элементов на несколько строк
152
- * справа не появлялось лишнее пустое пространство.
153
- * @param state Состояние скролла
154
- */
155
- const recalculateItemPositions = (state) => {
156
- const { positionContainerRef, containerRef, items, snapToNearestItem, setCountItems } = state;
157
- if (!positionContainerRef.current || !containerRef.current) {
158
- return;
159
- }
160
- const offset = positionContainerRef.current.getBoundingClientRect().left || 0;
161
- items.forEach((itemRef) => {
162
- if (!itemRef.current) {
163
- return;
164
- }
165
- const rect = itemRef.current.getBoundingClientRect();
166
- itemRef.current[OFFSET_ATTR] = { left: rect.left - offset, right: rect.right - offset };
167
- });
168
- items.sort((itemA, itemB) => (itemA.current || MAX_OFFSET)[OFFSET_ATTR].left - (itemB.current || MAX_OFFSET)[OFFSET_ATTR].left);
169
- if (snapToNearestItem) {
170
- setCountItems(items.length);
171
- }
172
- state.recalcRequired = false;
173
- // т.к. нам нужна ширина content-box, то вычитаем левую и правую коррекцию, т.к. ей будут равны паддинги
174
- state.containerWidth =
175
- containerRef.current.offsetWidth - state.correction.leftCorrection - state.correction.rightCorrection;
176
- // считаем ширину контейнера позиционирования равной правой границе самого крайнего элемента
177
- state.positionContainerWidth = items.reduce((position, itemRef) => Math.max(position, itemRef.current?.[OFFSET_ATTR]?.right || 0), 0);
178
- if (!state.disableButtons && state.positionContainerWidth > state.containerWidth) {
179
- state.containerWidth -= FOCUS_OUTLINE_WIDTH;
180
- }
181
- // если при маунте, когда у нас еще не было информации об элементах и размерах контейнеров был вызван scrollTo,
182
- // то нужно проскроллить без анимации
183
- if (state.scrollToOnMount) {
184
- scrollTo(state, state.scrollToOnMount);
185
- state.scrollToOnMount = null;
186
- return;
187
- }
188
- if (state.snapToNearestItem &&
189
- state.activeDot &&
190
- items[state.activeDot - 1] &&
191
- items[state.activeDot - 1].current) {
192
- const item = items[state.activeDot - 1].current;
193
- const offset = item[OFFSET_ATTR];
194
- const itemWidth = offset.right - offset.left;
195
- const translation = (state.containerWidth - itemWidth) / 2 - offset.left;
196
- setAnimated(state, false);
197
- setTranslation(translation, state);
198
- }
199
- applyScrollButtonsUpdate(state);
200
- };
201
- /**
202
- * Инициализирует ResizeObserver для отслеживания размеров элементов
203
- */
204
- const initResizeObserver = (state) => {
205
- const { items, containerRef } = state;
206
- const schedulePositionsRecalculation = requestAnimation((_, state) => recalculateItemPositions(state));
207
- const observer = new ResizeObserver(() => schedulePositionsRecalculation(state));
208
- items.forEach((item) => item.current && observer.observe(item.current));
209
- containerRef.current && observer.observe(containerRef.current);
210
- return { cleanup: () => observer.disconnect(), observer };
211
- };
212
- /**
213
- * На базе стейта считает ближайший элемент, который ближе к центру вью контейнера
214
- * Между блоками могут быть отступы, тогда centerPoint в offset-ы ни одного из элементов не попадет
215
- * В этом случае, используем предыдущее значение
216
- * @param state Состояние скролла
217
- * @returns Индекс элемента в массиве state.items
218
- */
219
- const findIndexNearestToCenter = (state) => {
220
- const centerPoint = state.containerWidth / 2 + Math.abs(state.positionContainerTranslation);
221
- const indexNearestToCenter = state.items.findIndex((itemRef) => {
222
- if (!itemRef.current) {
223
- return false;
224
- }
225
- const offset = itemRef.current[OFFSET_ATTR];
226
- return offset.left < centerPoint && offset.right > centerPoint;
227
- });
228
- return indexNearestToCenter !== -1 ? indexNearestToCenter + 1 : state.activeDot;
229
- };
230
- const useScrollContainer = (leftCorrection, rightCorrection, disableButtons, isMobile, snapToNearestItem, onScroll) => {
231
- // need state for dot component
232
- const [activeDot, setActiveDot] = useState(DEFAULT_DOT);
233
- const [countItems, setCountItems] = useState(0);
234
- const scrollStateRef = useRef({
235
- wrapperRef: useRef(null),
236
- positionContainerRef: useRef(null),
237
- containerRef: useRef(null),
238
- positionContainerWidth: 0,
239
- positionContainerTranslation: 0,
240
- containerWidth: 0,
241
- items: [],
242
- correction: { leftCorrection: 0, rightCorrection: 0 },
243
- disableButtons: false,
244
- scrollAnimationInProgress: false,
245
- scrollToOnMount: null,
246
- recalcRequired: false,
247
- scrollToItemInProgress: null,
248
- snapToNearestItem: false,
249
- activeDot: DEFAULT_DOT,
250
- needCorrectionOnScrollEnd: false,
251
- setActiveDot,
252
- setCountItems,
253
- directionRight: false,
254
- previousActiveIndexItem: 0,
255
- onScroll,
256
- wasInteracted: false,
257
- isMobile,
258
- });
259
- scrollStateRef.current.correction = { leftCorrection, rightCorrection };
260
- scrollStateRef.current.disableButtons = disableButtons;
261
- scrollStateRef.current.snapToNearestItem = Boolean(snapToNearestItem);
262
- scrollStateRef.current.activeDot = activeDot;
263
- scrollStateRef.current.onScroll = onScroll;
264
- scrollStateRef.current.isMobile = isMobile;
265
- const resizeOberverRef = useRef();
266
- // eslint-disable-next-line disable-autofix/react-hooks/exhaustive-deps
267
- const recalculateItemPositionsDebounced = useCallback(debounce(() => recalculateItemPositions(scrollStateRef.current), 10), []);
268
- const scrollToItem = useCallback((ref) => {
269
- const index = scrollStateRef.current.items.findIndex((item) => item.current && item.current === ref.current);
270
- if (index < 0) {
271
- return;
272
- }
273
- if (scrollStateRef.current.recalcRequired) {
274
- recalculateItemPositions(scrollStateRef.current);
275
- }
276
- scrollStateRef.current.wasInteracted = true;
277
- // set active dot here because user can click on item
278
- if (scrollStateRef.current.snapToNearestItem) {
279
- scrollStateRef.current.setActiveDot(index + 1);
280
- }
281
- scrollTo(scrollStateRef.current, ref);
282
- }, []);
283
- const scrollToIndex = useCallback((index) => {
284
- if (index < 0 || index > scrollStateRef.current.items.length - 1) {
285
- return;
286
- }
287
- scrollToItem(scrollStateRef.current.items[index]);
288
- }, [scrollToItem]);
289
- const scrollToFirstItem = useCallback(() => {
290
- const { items } = scrollStateRef.current;
291
- items.length > 0 && scrollToItem(items[0]);
292
- }, [scrollToItem]);
293
- const scrollToLastItem = useCallback(() => {
294
- const { items } = scrollStateRef.current;
295
- items.length > 0 && scrollToItem(items[items.length - 1]);
296
- }, [scrollToItem]);
297
- const scrollSide = useCallback((directionRight) => {
298
- const { containerWidth, positionContainerRef, positionContainerTranslation, snapToNearestItem } = scrollStateRef.current;
299
- scrollStateRef.current.wasInteracted = true;
300
- if (!positionContainerRef.current) {
301
- return;
302
- }
303
- if (!snapToNearestItem) {
304
- // move container based on container width
305
- const translation = positionContainerTranslation + (directionRight ? -containerWidth : containerWidth);
306
- setAnimated(scrollStateRef.current, true);
307
- setTranslation(translation, scrollStateRef.current);
308
- applyScrollButtonsUpdate(scrollStateRef.current);
309
- }
310
- else {
311
- // calc new dot and check it
312
- const activeDot = scrollStateRef.current.activeDot;
313
- const newActiveDot = directionRight ? activeDot + 1 : activeDot - 1;
314
- if (!isIncorrectIndex(newActiveDot - 1, scrollStateRef.current)) {
315
- // move container to new select ref
316
- scrollToItem(scrollStateRef.current.items[newActiveDot - 1]);
317
- }
318
- }
319
- }, [scrollToItem]);
320
- const registerItem = useCallback((ref) => {
321
- if (!ref.current) {
322
- return;
323
- }
324
- scrollStateRef.current.items.push(ref);
325
- scrollStateRef.current.recalcRequired = true;
326
- resizeOberverRef.current?.observe(ref.current);
327
- recalculateItemPositions(scrollStateRef.current);
328
- }, []);
329
- const removeItem = useCallback((ref) => {
330
- if (!ref.current) {
331
- return;
332
- }
333
- scrollStateRef.current.items = scrollStateRef.current.items.filter((storedRef) => storedRef.current !== ref.current);
334
- resizeOberverRef.current?.unobserve(ref.current);
335
- recalculateItemPositionsDebounced();
336
- }, [recalculateItemPositionsDebounced]);
337
- useEffect(() => {
338
- const { wrapperRef, positionContainerRef, containerRef } = scrollStateRef.current;
339
- if (!containerRef.current || !positionContainerRef.current || !wrapperRef.current) {
340
- return void 0;
341
- }
342
- const transitionEndHandler = (event) => {
343
- if (event.target !== scrollStateRef.current?.positionContainerRef.current) {
344
- return;
345
- }
346
- setAnimated(scrollStateRef.current, false);
347
- if (scrollStateRef.current) {
348
- scrollStateRef.current.scrollAnimationInProgress = false;
349
- scrollStateRef.current.scrollToItemInProgress = null;
350
- }
351
- };
352
- const positionContainer = scrollStateRef.current?.positionContainerRef.current;
353
- positionContainer?.addEventListener('transitionend', transitionEndHandler);
354
- const { cleanup: resizeObserverCleanup, observer } = initResizeObserver(scrollStateRef.current);
355
- resizeOberverRef.current = observer;
356
- return () => {
357
- resizeObserverCleanup();
358
- resizeOberverRef.current = null;
359
- positionContainer?.removeEventListener('transitionend', transitionEndHandler);
360
- };
361
- }, []);
362
- useLayoutEffect(() => {
363
- recalculateItemPositions(scrollStateRef.current);
364
- if (disableButtons) {
365
- setAnimated(scrollStateRef.current, false);
366
- }
367
- }, [disableButtons, leftCorrection, rightCorrection]);
368
- useEffect(() => {
369
- const wrapperRef = scrollStateRef.current.wrapperRef.current;
370
- if (!wrapperRef) {
371
- return void 0;
372
- }
373
- const handleTouchStartHandler = (event) => {
374
- event.stopPropagation();
375
- };
376
- wrapperRef.addEventListener('touchstart', handleTouchStartHandler);
377
- return () => {
378
- wrapperRef.removeEventListener('touchstart', handleTouchStartHandler);
379
- };
380
- }, []);
381
- useLayoutEffect(() => {
382
- /* Эффект нужен для пересчета размеров в случае, когда родительский контейнер открывается с анимацией,
383
- * на которую не срабатывает ResizeObserver - например, Modal с transition: scale */
384
- const handleParentTransitionEnd = (event) => {
385
- const { wrapperRef, wasInteracted } = scrollStateRef.current;
386
- /* wasInteracted - флаг, было ли взаимодействие с компонентом (скролл или подскролл к какому-либо элементу).
387
- * Если взаимодействие было, то пересчитывать не нужно, тк считаем, что анимации появления родительского контейнера
388
- * завершились */
389
- if (!wasInteracted &&
390
- event.target instanceof Element &&
391
- wrapperRef.current &&
392
- event.target.contains(wrapperRef.current)) {
393
- recalculateItemPositions(scrollStateRef.current);
394
- }
395
- };
396
- document.addEventListener('transitionend', handleParentTransitionEnd);
397
- return () => {
398
- document.removeEventListener('transitionend', handleParentTransitionEnd);
399
- };
400
- }, []);
401
- const onTouchMove = useCallback((event) => {
402
- if (scrollStateRef.current.scrollAnimationInProgress) {
403
- return;
404
- }
405
- scrollStateRef.current.wasInteracted = true;
406
- const { positionContainerTranslation } = scrollStateRef.current;
407
- setTranslation(scrollStateRef.current.positionContainerTranslation + event.delta, scrollStateRef.current);
408
- if (positionContainerTranslation === scrollStateRef.current.positionContainerTranslation) {
409
- event.preventDefault();
410
- }
411
- if (scrollStateRef.current.snapToNearestItem) {
412
- // by touch change active dot
413
- const newActiveDot = findIndexNearestToCenter(scrollStateRef.current);
414
- // update state
415
- scrollStateRef.current.setActiveDot(newActiveDot);
416
- // scheduling correction
417
- scrollStateRef.current.needCorrectionOnScrollEnd = true;
418
- }
419
- }, []);
420
- const onTouchEnd = useCallback(() => {
421
- const { needCorrectionOnScrollEnd, snapToNearestItem, activeDot } = scrollStateRef.current;
422
- if (snapToNearestItem && needCorrectionOnScrollEnd) {
423
- scrollStateRef.current.needCorrectionOnScrollEnd = false;
424
- // center active element
425
- scrollToDebounced(scrollStateRef.current, activeDot - 1);
426
- }
427
- }, []);
428
- const onWheelMove = useCallback((event) => {
429
- const { recalcRequired, scrollAnimationInProgress, positionContainerTranslation, snapToNearestItem } = scrollStateRef.current;
430
- scrollStateRef.current.wasInteracted = true;
431
- if (recalcRequired) {
432
- recalculateItemPositions(scrollStateRef.current);
433
- }
434
- if (scrollAnimationInProgress) {
435
- event.preventDefault();
436
- return;
437
- }
438
- scrollStateRef.current.directionRight = event.delta < 0;
439
- const translation = positionContainerTranslation + event.delta;
440
- setTranslation(translation, scrollStateRef.current);
441
- applyScrollButtonsUpdate(scrollStateRef.current);
442
- // эти значения могут быть не равны только в случае если попытались сдвинуть контейнер дальше
443
- // допустимого значения, это значит что мы уперлись в левую или правую границу, значит дальнейшие события
444
- // скролла можно не обрабатывать
445
- if (translation === scrollStateRef.current.positionContainerTranslation) {
446
- event.preventDefault();
447
- }
448
- if (snapToNearestItem) {
449
- // by wheel change active dot
450
- const newActiveDot = findIndexNearestToCenter(scrollStateRef.current);
451
- scrollStateRef.current.setActiveDot(newActiveDot);
452
- // center active element
453
- scrollToNewItemDebounced(scrollStateRef.current, newActiveDot - 1);
454
- }
455
- }, []);
456
- const _initScrollHandlers = useCallback(() => initScrollHandlers({
457
- axis: 'horizontal',
458
- wrapperRef: scrollStateRef.current.wrapperRef,
459
- onTouchMove,
460
- onTouchEnd,
461
- onWheelMove,
462
- }), [onTouchMove, onTouchEnd, onWheelMove]);
463
- const isScrollRightDisabled = useCallback(() => {
464
- const { positionContainerTranslation, positionContainerWidth, containerWidth } = scrollStateRef.current;
465
- return positionContainerTranslation + positionContainerWidth <= containerWidth;
466
- }, []);
467
- const isScrollLeftDisabled = useCallback(() => {
468
- const { positionContainerTranslation } = scrollStateRef.current;
469
- return positionContainerTranslation >= 0;
470
- }, []);
471
- return {
472
- registerItem,
473
- removeItem,
474
- scrollToItem,
475
- scrollToFirstItem,
476
- scrollToLastItem,
477
- scrollSide,
478
- initScrollHandlers: _initScrollHandlers,
479
- wrapperRef: scrollStateRef.current.wrapperRef,
480
- positionContainerRef: scrollStateRef.current.positionContainerRef,
481
- containerRef: scrollStateRef.current.containerRef,
482
- countItems,
483
- activeDot,
484
- isScrollRightDisabled,
485
- isScrollLeftDisabled,
486
- scrollToIndex,
487
- };
488
- };
489
-
490
- export { styles as s, useScrollContainer as u };
491
- //# sourceMappingURL=useScrollContainer-DvtB6-c_.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"useScrollContainer-DvtB6-c_.js","sources":["../src/useScrollContainer.ts"],"sourcesContent":["import { useRef, useEffect, RefObject, useCallback, useLayoutEffect, useState } from 'react';\nimport classnames from 'classnames';\n\nimport { requestAnimation } from '@hh.ru/magritte-common-func-utils';\nimport { ScrollGestureEvent, initScrollHandlers, clamp } from '@hh.ru/magritte-internal-custom-scroll';\nimport { ScrollInternalState, ItemWithOffset, OFFSET_ATTR } from '@hh.ru/magritte-ui-scrollable-container/types';\nimport { debounce } from '@hh.ru/magritte-ui-scrollable-container/utils';\n\nimport styles from './scrollableContainer.less';\n\nconst BUTTON_WIDTH = 44;\nconst FOCUS_OUTLINE_WIDTH = 4;\nconst DEFAULT_DOT = 1;\n\n/**\n * На базе стейта проверяем возможность использования вычисленного index-а\n * @param index значение для проверки\n * @param state Состояние скролла\n */\nconst isIncorrectIndex = (index: number, state: ScrollInternalState) => index < 0 || state.items.length - 1 < index;\n\n/**\n * Валидирует значение анимации и устанавливает ее в контейнер\n * @param translation значение анимации\n * @param state Состояние скролла\n */\nconst setTranslation = (translation: number, state: ScrollInternalState) => {\n const { positionContainerRef, positionContainerWidth, containerWidth } = state;\n if (!positionContainerRef.current) {\n return;\n }\n const prevTranslation = state.positionContainerTranslation;\n state.positionContainerTranslation = clamp(translation, containerWidth - positionContainerWidth, 0);\n positionContainerRef.current.style.transform = `translate3d(${state.positionContainerTranslation}px, 0, 0)`;\n if (prevTranslation !== state.positionContainerTranslation) {\n state.onScroll?.();\n }\n};\n\n/**\n * Вычисляет нужно ли показывать фейды по краям и скрывать кнопки скролла\n * Применяет соответствующие классы к обертке\n * Проверяет что сдвиг контейнера позиционирования находится в допустимых пределах и если нет, то корректирует его\n * @param state Состояние скролла\n */\nconst applyScrollButtonsUpdate = (state: ScrollInternalState) => {\n const { positionContainerRef, wrapperRef, positionContainerWidth, containerWidth } = state;\n let { positionContainerTranslation } = state;\n\n if (!positionContainerRef.current || !wrapperRef.current) {\n return;\n }\n\n if (positionContainerWidth + positionContainerTranslation < containerWidth) {\n positionContainerTranslation = containerWidth - positionContainerWidth;\n setTranslation(positionContainerTranslation, state);\n }\n const isFadeLeft = positionContainerTranslation < 0;\n const isFadeRight = positionContainerTranslation + positionContainerWidth > containerWidth;\n const className = classnames({\n [styles.fadeLeftSide]: isFadeLeft && !isFadeRight,\n [styles.fadeRightSide]: isFadeRight && !isFadeLeft,\n [styles.fadeBothSides]: isFadeRight && isFadeLeft,\n });\n wrapperRef.current.classList.remove(styles.fadeBothSides, styles.fadeLeftSide, styles.fadeRightSide);\n className && wrapperRef.current.classList.add(className);\n};\n\nconst setAnimated = (state: ScrollInternalState, animated: boolean) => {\n state.positionContainerRef.current?.classList.toggle(styles.positionContainerAnimated, animated);\n if (!animated) {\n state.scrollAnimationInProgress = false;\n }\n};\n\n/**\n * Скролл к конкретному элементу группы. Если на момент вызова нет ref контейнера позиционирования, то считаем что\n * функция была при маунте компонента и запоминаем элемент на который нужно скроллить. При маунте вызываем эту функцию\n * еще раз и скроллим к запомненному элементу без анимации.\n * @param state Состояние скролла\n * @param item Элемент к которому нужно подскроллить\n */\nconst scrollTo = (state: ScrollInternalState, item: RefObject<HTMLElement>) => {\n const {\n positionContainerTranslation,\n containerWidth,\n positionContainerRef,\n scrollToItemInProgress,\n disableButtons,\n positionContainerWidth,\n snapToNearestItem,\n items,\n isMobile,\n } = state;\n if (!positionContainerRef.current) {\n state.scrollToOnMount = item;\n return;\n }\n\n if (item.current === scrollToItemInProgress?.current) {\n return;\n }\n state.previousActiveIndexItem = items.indexOf(item as unknown as RefObject<HTMLElement & ItemWithOffset>);\n const offset = (item.current as unknown as ItemWithOffset)[OFFSET_ATTR];\n const width = offset.right - offset.left;\n const buttonsCorrection = disableButtons ? 0 : BUTTON_WIDTH;\n\n // нужно ли отцентрировать контейнер по текущему item\n // актуально для режима showDotPages/snapToNearestItem\n // так как контейнер работает как карусель\n const needItemCorrection = snapToNearestItem || isMobile;\n let translation = positionContainerTranslation;\n if (width > containerWidth) {\n // элемент шире контейнера, выравниваем его левый край с левым краем контейнера\n translation = -offset.left;\n } else if (\n (offset.left + positionContainerTranslation < buttonsCorrection || needItemCorrection) &&\n positionContainerTranslation < 0\n ) {\n // контейнер движется вправо\n const correction = needItemCorrection ? (containerWidth - width) / 2 : buttonsCorrection;\n translation = -offset.left + correction;\n } else if (\n (offset.right + positionContainerTranslation > containerWidth - buttonsCorrection || needItemCorrection) &&\n positionContainerTranslation > containerWidth - positionContainerWidth\n ) {\n // контейнер движется влево\n const correction = needItemCorrection ? (containerWidth - width) / 2 : buttonsCorrection;\n translation = containerWidth - offset.right - correction;\n }\n\n translation = clamp(translation, containerWidth - positionContainerWidth, 0);\n const isPositionChanged = translation !== positionContainerTranslation;\n const needAnimation = !state.scrollToOnMount && isPositionChanged;\n\n // Если это скролл при маунте, или позиция скролла не изменилась, то его не нужно анимировать\n setAnimated(state, needAnimation);\n setTranslation(translation, state);\n if (needAnimation) {\n state.scrollAnimationInProgress = true;\n state.scrollToItemInProgress = item;\n }\n applyScrollButtonsUpdate(state);\n};\n\n/**\n * Если текущий элемент совпадает с новым\n * Находим следующий активный элемент по направлению и скролим к нему\n */\nconst scrollToNewItemDebounced = debounce((state: ScrollInternalState, indexNearestToCenter: number) => {\n const { previousActiveIndexItem, items, directionRight } = state;\n let index = indexNearestToCenter;\n // определяем ситуацию, когда скрола не хватило до следующего элемента\n if (previousActiveIndexItem === indexNearestToCenter) {\n const indexBasedOnDirection = directionRight ? indexNearestToCenter + 1 : indexNearestToCenter - 1;\n // нужно проверить новый индекс, чтобы не выходить за границы\n if (!isIncorrectIndex(indexBasedOnDirection, state)) {\n index = indexBasedOnDirection;\n state.setActiveDot(index + 1);\n }\n }\n const item: RefObject<HTMLElement> = items[index];\n scrollTo(state, item);\n}, 30);\n\n/**\n * Скролл к конкретному элементу группы (обернуто в debounce)\n */\nconst scrollToDebounced = debounce(\n (state: ScrollInternalState, index: number) => scrollTo(state, state.items[index]),\n 30\n);\n\nconst MAX_OFFSET = { [OFFSET_ATTR]: { left: Number.MAX_SAFE_INTEGER } };\n\n/**\n * Пересчитывает позиции элементов и обновляет состояние скролла. Вызывается при изменении размеров контейнера или\n * добавлении/удалении элементов. Проходится по всем элементам и вычисляет сдвиг их правой и левой границы относительно\n * контейнера позиционирования. Сортирует элементы по возрастанию сдвига левой границы. Вычисляет ширину внешнего\n * контейнера и контейнера позиционирования. При вычислении ширины контейнера позиционирования правой его границей\n * считается правая граница самого крайнего справа элемента. Это нужно чтобы при переносе элементов на несколько строк\n * справа не появлялось лишнее пустое пространство.\n * @param state Состояние скролла\n */\nconst recalculateItemPositions = (state: ScrollInternalState) => {\n const { positionContainerRef, containerRef, items, snapToNearestItem, setCountItems } = state;\n if (!positionContainerRef.current || !containerRef.current) {\n return;\n }\n const offset = positionContainerRef.current.getBoundingClientRect().left || 0;\n items.forEach((itemRef) => {\n if (!itemRef.current) {\n return;\n }\n const rect = itemRef.current.getBoundingClientRect();\n itemRef.current[OFFSET_ATTR] = { left: rect.left - offset, right: rect.right - offset };\n });\n items.sort(\n (itemA, itemB) =>\n (itemA.current || MAX_OFFSET)[OFFSET_ATTR].left - (itemB.current || MAX_OFFSET)[OFFSET_ATTR].left\n );\n\n if (snapToNearestItem) {\n setCountItems(items.length);\n }\n\n state.recalcRequired = false;\n // т.к. нам нужна ширина content-box, то вычитаем левую и правую коррекцию, т.к. ей будут равны паддинги\n state.containerWidth =\n containerRef.current.offsetWidth - state.correction.leftCorrection - state.correction.rightCorrection;\n // считаем ширину контейнера позиционирования равной правой границе самого крайнего элемента\n state.positionContainerWidth = items.reduce(\n (position, itemRef) => Math.max(position, itemRef.current?.[OFFSET_ATTR]?.right || 0),\n 0\n );\n if (!state.disableButtons && state.positionContainerWidth > state.containerWidth) {\n state.containerWidth -= FOCUS_OUTLINE_WIDTH;\n }\n\n // если при маунте, когда у нас еще не было информации об элементах и размерах контейнеров был вызван scrollTo,\n // то нужно проскроллить без анимации\n if (state.scrollToOnMount) {\n scrollTo(state, state.scrollToOnMount);\n state.scrollToOnMount = null;\n return;\n }\n\n if (\n state.snapToNearestItem &&\n state.activeDot &&\n items[state.activeDot - 1] &&\n items[state.activeDot - 1].current\n ) {\n const item = items[state.activeDot - 1].current as HTMLElement & ItemWithOffset;\n const offset = item[OFFSET_ATTR];\n const itemWidth = offset.right - offset.left;\n const translation = (state.containerWidth - itemWidth) / 2 - offset.left;\n\n setAnimated(state, false);\n setTranslation(translation, state);\n }\n\n applyScrollButtonsUpdate(state);\n};\n\n/**\n * Инициализирует ResizeObserver для отслеживания размеров элементов\n */\nconst initResizeObserver = (state: ScrollInternalState) => {\n const { items, containerRef } = state;\n const schedulePositionsRecalculation = requestAnimation((_, state: ScrollInternalState) =>\n recalculateItemPositions(state)\n );\n const observer = new ResizeObserver(() => schedulePositionsRecalculation(state));\n items.forEach((item) => item.current && observer.observe(item.current));\n containerRef.current && observer.observe(containerRef.current);\n\n return { cleanup: () => observer.disconnect(), observer };\n};\n\n/**\n * На базе стейта считает ближайший элемент, который ближе к центру вью контейнера\n * Между блоками могут быть отступы, тогда centerPoint в offset-ы ни одного из элементов не попадет\n * В этом случае, используем предыдущее значение\n * @param state Состояние скролла\n * @returns Индекс элемента в массиве state.items\n */\nconst findIndexNearestToCenter = (state: ScrollInternalState): number => {\n const centerPoint = state.containerWidth / 2 + Math.abs(state.positionContainerTranslation);\n const indexNearestToCenter = state.items.findIndex((itemRef) => {\n if (!itemRef.current) {\n return false;\n }\n const offset = itemRef.current[OFFSET_ATTR];\n return offset.left < centerPoint && offset.right > centerPoint;\n });\n return indexNearestToCenter !== -1 ? indexNearestToCenter + 1 : state.activeDot;\n};\n\ninterface UseScrollContainer {\n registerItem: (ref: RefObject<HTMLElement>) => void;\n removeItem: (ref: RefObject<HTMLElement>) => void;\n scrollToItem: (ref: RefObject<HTMLElement>) => void;\n scrollToFirstItem: VoidFunction;\n scrollToLastItem: VoidFunction;\n scrollSide: (right?: boolean) => void;\n initScrollHandlers: () => VoidFunction;\n wrapperRef: RefObject<HTMLDivElement>;\n positionContainerRef: RefObject<HTMLDivElement>;\n containerRef: RefObject<HTMLDivElement>;\n countItems: number;\n activeDot: number;\n isScrollRightDisabled: () => boolean;\n isScrollLeftDisabled: () => boolean;\n scrollToIndex: (index: number) => void;\n}\n\nexport const useScrollContainer = (\n leftCorrection: number,\n rightCorrection: number,\n disableButtons: boolean,\n isMobile: boolean,\n snapToNearestItem?: boolean,\n onScroll?: () => void\n): UseScrollContainer => {\n // need state for dot component\n const [activeDot, setActiveDot] = useState(DEFAULT_DOT);\n const [countItems, setCountItems] = useState(0);\n const scrollStateRef = useRef<ScrollInternalState>({\n wrapperRef: useRef<HTMLDivElement>(null),\n positionContainerRef: useRef<HTMLDivElement>(null),\n containerRef: useRef<HTMLDivElement>(null),\n positionContainerWidth: 0,\n positionContainerTranslation: 0,\n containerWidth: 0,\n items: [],\n correction: { leftCorrection: 0, rightCorrection: 0 },\n disableButtons: false,\n scrollAnimationInProgress: false,\n scrollToOnMount: null,\n recalcRequired: false,\n scrollToItemInProgress: null,\n snapToNearestItem: false,\n activeDot: DEFAULT_DOT,\n needCorrectionOnScrollEnd: false,\n setActiveDot,\n setCountItems,\n directionRight: false,\n previousActiveIndexItem: 0,\n onScroll,\n wasInteracted: false,\n isMobile,\n });\n\n scrollStateRef.current.correction = { leftCorrection, rightCorrection };\n scrollStateRef.current.disableButtons = disableButtons;\n scrollStateRef.current.snapToNearestItem = Boolean(snapToNearestItem);\n scrollStateRef.current.activeDot = activeDot;\n scrollStateRef.current.onScroll = onScroll;\n scrollStateRef.current.isMobile = isMobile;\n const resizeOberverRef = useRef<ResizeObserver | null>();\n\n // eslint-disable-next-line disable-autofix/react-hooks/exhaustive-deps\n const recalculateItemPositionsDebounced = useCallback(\n debounce(() => recalculateItemPositions(scrollStateRef.current), 10),\n []\n );\n\n const scrollToItem = useCallback((ref: RefObject<HTMLElement>) => {\n const index = scrollStateRef.current.items.findIndex((item) => item.current && item.current === ref.current);\n if (index < 0) {\n return;\n }\n if (scrollStateRef.current.recalcRequired) {\n recalculateItemPositions(scrollStateRef.current);\n }\n scrollStateRef.current.wasInteracted = true;\n // set active dot here because user can click on item\n if (scrollStateRef.current.snapToNearestItem) {\n scrollStateRef.current.setActiveDot(index + 1);\n }\n scrollTo(scrollStateRef.current, ref);\n }, []);\n\n const scrollToIndex = useCallback(\n (index: number) => {\n if (index < 0 || index > scrollStateRef.current.items.length - 1) {\n return;\n }\n\n scrollToItem(scrollStateRef.current.items[index]);\n },\n [scrollToItem]\n );\n\n const scrollToFirstItem = useCallback(() => {\n const { items } = scrollStateRef.current;\n items.length > 0 && scrollToItem(items[0]);\n }, [scrollToItem]);\n\n const scrollToLastItem = useCallback(() => {\n const { items } = scrollStateRef.current;\n items.length > 0 && scrollToItem(items[items.length - 1]);\n }, [scrollToItem]);\n\n const scrollSide = useCallback(\n (directionRight?: boolean) => {\n const { containerWidth, positionContainerRef, positionContainerTranslation, snapToNearestItem } =\n scrollStateRef.current;\n scrollStateRef.current.wasInteracted = true;\n if (!positionContainerRef.current) {\n return;\n }\n if (!snapToNearestItem) {\n // move container based on container width\n const translation = positionContainerTranslation + (directionRight ? -containerWidth : containerWidth);\n setAnimated(scrollStateRef.current, true);\n setTranslation(translation, scrollStateRef.current);\n applyScrollButtonsUpdate(scrollStateRef.current);\n } else {\n // calc new dot and check it\n const activeDot = scrollStateRef.current.activeDot;\n const newActiveDot = directionRight ? activeDot + 1 : activeDot - 1;\n if (!isIncorrectIndex(newActiveDot - 1, scrollStateRef.current)) {\n // move container to new select ref\n scrollToItem(scrollStateRef.current.items[newActiveDot - 1]);\n }\n }\n },\n [scrollToItem]\n );\n\n const registerItem = useCallback((ref: RefObject<HTMLElement>) => {\n if (!ref.current) {\n return;\n }\n\n scrollStateRef.current.items.push(ref as unknown as RefObject<HTMLElement & ItemWithOffset>);\n scrollStateRef.current.recalcRequired = true;\n resizeOberverRef.current?.observe(ref.current);\n recalculateItemPositions(scrollStateRef.current);\n }, []);\n\n const removeItem = useCallback(\n (ref: RefObject<HTMLElement>) => {\n if (!ref.current) {\n return;\n }\n\n scrollStateRef.current.items = scrollStateRef.current.items.filter(\n (storedRef) => storedRef.current !== ref.current\n );\n resizeOberverRef.current?.unobserve(ref.current);\n recalculateItemPositionsDebounced();\n },\n [recalculateItemPositionsDebounced]\n );\n\n useEffect(() => {\n const { wrapperRef, positionContainerRef, containerRef } = scrollStateRef.current;\n if (!containerRef.current || !positionContainerRef.current || !wrapperRef.current) {\n return void 0;\n }\n\n const transitionEndHandler = (event: TransitionEvent) => {\n if (event.target !== scrollStateRef.current?.positionContainerRef.current) {\n return;\n }\n setAnimated(scrollStateRef.current, false);\n if (scrollStateRef.current) {\n scrollStateRef.current.scrollAnimationInProgress = false;\n scrollStateRef.current.scrollToItemInProgress = null;\n }\n };\n const positionContainer = scrollStateRef.current?.positionContainerRef.current;\n positionContainer?.addEventListener('transitionend', transitionEndHandler);\n\n const { cleanup: resizeObserverCleanup, observer } = initResizeObserver(scrollStateRef.current);\n resizeOberverRef.current = observer;\n\n return () => {\n resizeObserverCleanup();\n resizeOberverRef.current = null;\n positionContainer?.removeEventListener('transitionend', transitionEndHandler);\n };\n }, []);\n\n useLayoutEffect(() => {\n recalculateItemPositions(scrollStateRef.current);\n if (disableButtons) {\n setAnimated(scrollStateRef.current, false);\n }\n }, [disableButtons, leftCorrection, rightCorrection]);\n\n useEffect(() => {\n const wrapperRef = scrollStateRef.current.wrapperRef.current;\n if (!wrapperRef) {\n return void 0;\n }\n const handleTouchStartHandler = (event: TouchEvent) => {\n event.stopPropagation();\n };\n wrapperRef.addEventListener('touchstart', handleTouchStartHandler);\n return () => {\n wrapperRef.removeEventListener('touchstart', handleTouchStartHandler);\n };\n }, []);\n\n useLayoutEffect(() => {\n /* Эффект нужен для пересчета размеров в случае, когда родительский контейнер открывается с анимацией,\n * на которую не срабатывает ResizeObserver - например, Modal с transition: scale */\n const handleParentTransitionEnd = (event: TransitionEvent) => {\n const { wrapperRef, wasInteracted } = scrollStateRef.current;\n /* wasInteracted - флаг, было ли взаимодействие с компонентом (скролл или подскролл к какому-либо элементу).\n * Если взаимодействие было, то пересчитывать не нужно, тк считаем, что анимации появления родительского контейнера\n * завершились */\n if (\n !wasInteracted &&\n event.target instanceof Element &&\n wrapperRef.current &&\n event.target.contains(wrapperRef.current)\n ) {\n recalculateItemPositions(scrollStateRef.current);\n }\n };\n\n document.addEventListener('transitionend', handleParentTransitionEnd);\n\n return () => {\n document.removeEventListener('transitionend', handleParentTransitionEnd);\n };\n }, []);\n\n const onTouchMove = useCallback((event: ScrollGestureEvent) => {\n if (scrollStateRef.current.scrollAnimationInProgress) {\n return;\n }\n scrollStateRef.current.wasInteracted = true;\n const { positionContainerTranslation } = scrollStateRef.current;\n setTranslation(scrollStateRef.current.positionContainerTranslation + event.delta, scrollStateRef.current);\n if (positionContainerTranslation === scrollStateRef.current.positionContainerTranslation) {\n event.preventDefault();\n }\n if (scrollStateRef.current.snapToNearestItem) {\n // by touch change active dot\n const newActiveDot = findIndexNearestToCenter(scrollStateRef.current);\n // update state\n scrollStateRef.current.setActiveDot(newActiveDot);\n // scheduling correction\n scrollStateRef.current.needCorrectionOnScrollEnd = true;\n }\n }, []);\n\n const onTouchEnd = useCallback(() => {\n const { needCorrectionOnScrollEnd, snapToNearestItem, activeDot } = scrollStateRef.current;\n if (snapToNearestItem && needCorrectionOnScrollEnd) {\n scrollStateRef.current.needCorrectionOnScrollEnd = false;\n // center active element\n scrollToDebounced(scrollStateRef.current, activeDot - 1);\n }\n }, []);\n\n const onWheelMove = useCallback((event: ScrollGestureEvent) => {\n const { recalcRequired, scrollAnimationInProgress, positionContainerTranslation, snapToNearestItem } =\n scrollStateRef.current;\n scrollStateRef.current.wasInteracted = true;\n if (recalcRequired) {\n recalculateItemPositions(scrollStateRef.current);\n }\n if (scrollAnimationInProgress) {\n event.preventDefault();\n return;\n }\n scrollStateRef.current.directionRight = event.delta < 0;\n const translation = positionContainerTranslation + event.delta;\n setTranslation(translation, scrollStateRef.current);\n applyScrollButtonsUpdate(scrollStateRef.current);\n\n // эти значения могут быть не равны только в случае если попытались сдвинуть контейнер дальше\n // допустимого значения, это значит что мы уперлись в левую или правую границу, значит дальнейшие события\n // скролла можно не обрабатывать\n if (translation === scrollStateRef.current.positionContainerTranslation) {\n event.preventDefault();\n }\n if (snapToNearestItem) {\n // by wheel change active dot\n const newActiveDot = findIndexNearestToCenter(scrollStateRef.current);\n scrollStateRef.current.setActiveDot(newActiveDot);\n // center active element\n scrollToNewItemDebounced(scrollStateRef.current, newActiveDot - 1);\n }\n }, []);\n\n const _initScrollHandlers = useCallback(\n () =>\n initScrollHandlers({\n axis: 'horizontal',\n wrapperRef: scrollStateRef.current.wrapperRef,\n onTouchMove,\n onTouchEnd,\n onWheelMove,\n }),\n [onTouchMove, onTouchEnd, onWheelMove]\n );\n\n const isScrollRightDisabled = useCallback(() => {\n const { positionContainerTranslation, positionContainerWidth, containerWidth } = scrollStateRef.current;\n return positionContainerTranslation + positionContainerWidth <= containerWidth;\n }, []);\n\n const isScrollLeftDisabled = useCallback(() => {\n const { positionContainerTranslation } = scrollStateRef.current;\n return positionContainerTranslation >= 0;\n }, []);\n\n return {\n registerItem,\n removeItem,\n scrollToItem,\n scrollToFirstItem,\n scrollToLastItem,\n scrollSide,\n initScrollHandlers: _initScrollHandlers,\n wrapperRef: scrollStateRef.current.wrapperRef,\n positionContainerRef: scrollStateRef.current.positionContainerRef,\n containerRef: scrollStateRef.current.containerRef,\n countItems,\n activeDot,\n isScrollRightDisabled,\n isScrollLeftDisabled,\n scrollToIndex,\n };\n};\n"],"names":[],"mappings":"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"}