@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.
- package/ObservableValue.d.ts +13 -0
- package/ObservableValue.js +24 -0
- package/ObservableValue.js.map +1 -0
- package/ScrollStateProvider.d.ts +35 -0
- package/ScrollStateProvider.js +22 -0
- package/ScrollStateProvider.js.map +1 -0
- package/ScrollableContainer.d.ts +19 -12
- package/ScrollableContainer.js +48 -104
- package/ScrollableContainer.js.map +1 -1
- package/ScrollableContainerButton.d.ts +4 -0
- package/ScrollableContainerButton.js +28 -0
- package/ScrollableContainerButton.js.map +1 -0
- package/ScrollableContainerDefaultLayout.d.ts +3 -0
- package/ScrollableContainerDefaultLayout.js +72 -0
- package/ScrollableContainerDefaultLayout.js.map +1 -0
- package/ScrollableContainerDotPages.d.ts +3 -0
- package/ScrollableContainerDotPages.js +67 -0
- package/ScrollableContainerDotPages.js.map +1 -0
- package/ScrollableContainerGallery.d.ts +4 -0
- package/ScrollableContainerGallery.js +76 -0
- package/ScrollableContainerGallery.js.map +1 -0
- package/ScrollableItem.d.ts +3 -2
- package/ScrollableItem.js +15 -10
- package/ScrollableItem.js.map +1 -1
- package/index.css +18 -44
- package/index.d.ts +5 -3
- package/index.js +16 -6
- package/index.js.map +1 -1
- package/index.mock.d.ts +5 -4
- package/index.mock.js +35 -11
- package/index.mock.js.map +1 -1
- package/package.json +4 -3
- package/scrollableContainer-CsVTi8_Q.js +5 -0
- package/scrollableContainer-CsVTi8_Q.js.map +1 -0
- package/types.d.ts +61 -83
- package/types.js.map +1 -1
- package/useScrollContainer.d.ts +20 -13
- package/useScrollContainer.js +190 -7
- package/useScrollContainer.js.map +1 -1
- package/useScrollableControls.d.ts +4 -0
- package/useScrollableControls.js +57 -0
- package/useScrollableControls.js.map +1 -0
- package/utils.d.ts +80 -0
- package/utils.js +277 -1
- package/utils.js.map +1 -1
- package/useScrollContainer-DvtB6-c_.js +0 -491
- package/useScrollContainer-DvtB6-c_.js.map +0 -1
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface ObservableValueInterface<T> {
|
|
2
|
+
get(): T;
|
|
3
|
+
set(value: T): void;
|
|
4
|
+
on(event: 'change', callback: (value: T) => void): VoidFunction;
|
|
5
|
+
}
|
|
6
|
+
export declare class ObservableValue<T> implements ObservableValueInterface<T> {
|
|
7
|
+
private value;
|
|
8
|
+
private listeners;
|
|
9
|
+
constructor(initial: T);
|
|
10
|
+
get(): T;
|
|
11
|
+
set(value: T): void;
|
|
12
|
+
on(_event: 'change', callback: (value: T) => void): VoidFunction;
|
|
13
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import './index.css';
|
|
2
|
+
class ObservableValue {
|
|
3
|
+
value;
|
|
4
|
+
listeners = new Set();
|
|
5
|
+
constructor(initial) {
|
|
6
|
+
this.value = initial;
|
|
7
|
+
}
|
|
8
|
+
get() {
|
|
9
|
+
return this.value;
|
|
10
|
+
}
|
|
11
|
+
set(value) {
|
|
12
|
+
if (this.value !== value || Array.isArray(this.value)) {
|
|
13
|
+
this.value = value;
|
|
14
|
+
this.listeners.forEach((listener) => listener(value));
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
on(_event, callback) {
|
|
18
|
+
this.listeners.add(callback);
|
|
19
|
+
return () => this.listeners.delete(callback);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export { ObservableValue };
|
|
24
|
+
//# sourceMappingURL=ObservableValue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ObservableValue.js","sources":["../src/ObservableValue.ts"],"sourcesContent":["export interface ObservableValueInterface<T> {\n get(): T;\n set(value: T): void;\n on(event: 'change', callback: (value: T) => void): VoidFunction;\n}\n\nexport class ObservableValue<T> implements ObservableValueInterface<T> {\n private value: T;\n private listeners = new Set<(value: T) => void>();\n\n constructor(initial: T) {\n this.value = initial;\n }\n\n get(): T {\n return this.value;\n }\n\n set(value: T): void {\n if (this.value !== value || Array.isArray(this.value)) {\n this.value = value;\n this.listeners.forEach((listener) => listener(value));\n }\n }\n\n on(_event: 'change', callback: (value: T) => void): VoidFunction {\n this.listeners.add(callback);\n return () => this.listeners.delete(callback);\n }\n}\n"],"names":[],"mappings":"MAMa,eAAe,CAAA;AAChB,IAAA,KAAK,CAAI;AACT,IAAA,SAAS,GAAG,IAAI,GAAG,EAAsB,CAAC;AAElD,IAAA,WAAA,CAAY,OAAU,EAAA;AAClB,QAAA,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC;KACxB;IAED,GAAG,GAAA;QACC,OAAO,IAAI,CAAC,KAAK,CAAC;KACrB;AAED,IAAA,GAAG,CAAC,KAAQ,EAAA;AACR,QAAA,IAAI,IAAI,CAAC,KAAK,KAAK,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE;AACnD,YAAA,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;AACnB,YAAA,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;SACzD;KACJ;IAED,EAAE,CAAC,MAAgB,EAAE,QAA4B,EAAA;AAC7C,QAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC7B,OAAO,MAAM,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;KAChD;AACJ;;;;"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type RefObject } from 'react';
|
|
2
|
+
import { MotionValue } from 'motion/react';
|
|
3
|
+
import { ObservableValue } from '@hh.ru/magritte-ui-scrollable-container/ObservableValue';
|
|
4
|
+
import { type ItemWithOffset, type ScrollSnapAlign } from '@hh.ru/magritte-ui-scrollable-container/types';
|
|
5
|
+
export interface ScrollState {
|
|
6
|
+
/** ширина контента, которая складывается из ширины элементов галереи */
|
|
7
|
+
contentWidth: ObservableValue<number>;
|
|
8
|
+
/** ширина вьюпорта для просмотра галереи */
|
|
9
|
+
viewportWidth: ObservableValue<number>;
|
|
10
|
+
/** элементы галереи */
|
|
11
|
+
items: ObservableValue<RefObject<HTMLElement & ItemWithOffset>[]>;
|
|
12
|
+
/** текущая позиция */
|
|
13
|
+
scrollPosition: MotionValue<number>;
|
|
14
|
+
/** Определяет, как ближайший элемент будет размещён во вьюпорте при автоматическом скролле */
|
|
15
|
+
scrollSnapAlign: ScrollSnapAlign;
|
|
16
|
+
/**
|
|
17
|
+
* флаг коррекции "по умолчанию"
|
|
18
|
+
* возникает при использовании "стандартных" (по спеке) кнопок в fade
|
|
19
|
+
*/
|
|
20
|
+
defaultButtonsCorrection: ObservableValue<number>;
|
|
21
|
+
/** значения коррекции */
|
|
22
|
+
leftCorrection: ObservableValue<number>;
|
|
23
|
+
rightCorrection: ObservableValue<number>;
|
|
24
|
+
/** индекс элемента для отложенного скролла */
|
|
25
|
+
indexForDeferScroll: number;
|
|
26
|
+
/**
|
|
27
|
+
* флаг наличия взаимодействия с компонентом (скролл или подскролл к какому-либо элементу).
|
|
28
|
+
* Используется для пересчета размеров в случае, когда родительский контейнер открывается с анимацией (например, в modal)
|
|
29
|
+
* Если взаимодействие было, то пересчитывать размеры не нужно (считаем, что анимации появления родительского контейнера)
|
|
30
|
+
*/
|
|
31
|
+
wasContainerInteracted: boolean;
|
|
32
|
+
}
|
|
33
|
+
export declare const createScrollState: () => ScrollState;
|
|
34
|
+
export declare const ScrollStateContext: import("react").Context<ScrollState>;
|
|
35
|
+
export declare const useScrollState: () => ScrollState;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import './index.css';
|
|
2
|
+
import { createContext, useContext } from 'react';
|
|
3
|
+
import { MotionValue } from 'motion/react';
|
|
4
|
+
import { ObservableValue } from './ObservableValue.js';
|
|
5
|
+
|
|
6
|
+
const createScrollState = () => ({
|
|
7
|
+
contentWidth: new ObservableValue(0),
|
|
8
|
+
viewportWidth: new ObservableValue(0),
|
|
9
|
+
items: new ObservableValue([]),
|
|
10
|
+
scrollPosition: new MotionValue(0),
|
|
11
|
+
defaultButtonsCorrection: new ObservableValue(0),
|
|
12
|
+
leftCorrection: new ObservableValue(0),
|
|
13
|
+
rightCorrection: new ObservableValue(0),
|
|
14
|
+
indexForDeferScroll: -1,
|
|
15
|
+
wasContainerInteracted: false,
|
|
16
|
+
scrollSnapAlign: 'none',
|
|
17
|
+
});
|
|
18
|
+
const ScrollStateContext = createContext(createScrollState());
|
|
19
|
+
const useScrollState = () => useContext(ScrollStateContext);
|
|
20
|
+
|
|
21
|
+
export { ScrollStateContext, createScrollState, useScrollState };
|
|
22
|
+
//# sourceMappingURL=ScrollStateProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ScrollStateProvider.js","sources":["../src/ScrollStateProvider.tsx"],"sourcesContent":["import { type RefObject, createContext, useContext } from 'react';\nimport { MotionValue } from 'motion/react';\n\nimport { ObservableValue } from '@hh.ru/magritte-ui-scrollable-container/ObservableValue';\nimport { type ItemWithOffset, type ScrollSnapAlign } from '@hh.ru/magritte-ui-scrollable-container/types';\n\nexport interface ScrollState {\n /** ширина контента, которая складывается из ширины элементов галереи */\n contentWidth: ObservableValue<number>;\n /** ширина вьюпорта для просмотра галереи */\n viewportWidth: ObservableValue<number>;\n /** элементы галереи */\n items: ObservableValue<RefObject<HTMLElement & ItemWithOffset>[]>;\n /** текущая позиция */\n scrollPosition: MotionValue<number>;\n /** Определяет, как ближайший элемент будет размещён во вьюпорте при автоматическом скролле */\n scrollSnapAlign: ScrollSnapAlign;\n /**\n * флаг коррекции \"по умолчанию\"\n * возникает при использовании \"стандартных\" (по спеке) кнопок в fade\n */\n defaultButtonsCorrection: ObservableValue<number>;\n /** значения коррекции */\n leftCorrection: ObservableValue<number>;\n rightCorrection: ObservableValue<number>;\n /** индекс элемента для отложенного скролла */\n indexForDeferScroll: number;\n /**\n * флаг наличия взаимодействия с компонентом (скролл или подскролл к какому-либо элементу).\n * Используется для пересчета размеров в случае, когда родительский контейнер открывается с анимацией (например, в modal)\n * Если взаимодействие было, то пересчитывать размеры не нужно (считаем, что анимации появления родительского контейнера)\n */\n wasContainerInteracted: boolean;\n}\n\nexport const createScrollState = (): ScrollState => ({\n contentWidth: new ObservableValue(0),\n viewportWidth: new ObservableValue(0),\n items: new ObservableValue<RefObject<HTMLElement & ItemWithOffset>[]>([]),\n scrollPosition: new MotionValue(0),\n defaultButtonsCorrection: new ObservableValue(0),\n leftCorrection: new ObservableValue(0),\n rightCorrection: new ObservableValue(0),\n indexForDeferScroll: -1,\n wasContainerInteracted: false,\n scrollSnapAlign: 'none',\n});\n\nexport const ScrollStateContext = createContext<ScrollState>(createScrollState());\n\nexport const useScrollState = (): ScrollState => useContext(ScrollStateContext);\n"],"names":[],"mappings":";;;;AAmCa,MAAA,iBAAiB,GAAG,OAAoB;AACjD,IAAA,YAAY,EAAE,IAAI,eAAe,CAAC,CAAC,CAAC;AACpC,IAAA,aAAa,EAAE,IAAI,eAAe,CAAC,CAAC,CAAC;AACrC,IAAA,KAAK,EAAE,IAAI,eAAe,CAA4C,EAAE,CAAC;AACzE,IAAA,cAAc,EAAE,IAAI,WAAW,CAAC,CAAC,CAAC;AAClC,IAAA,wBAAwB,EAAE,IAAI,eAAe,CAAC,CAAC,CAAC;AAChD,IAAA,cAAc,EAAE,IAAI,eAAe,CAAC,CAAC,CAAC;AACtC,IAAA,eAAe,EAAE,IAAI,eAAe,CAAC,CAAC,CAAC;IACvC,mBAAmB,EAAE,CAAC,CAAC;AACvB,IAAA,sBAAsB,EAAE,KAAK;AAC7B,IAAA,eAAe,EAAE,MAAM;AAC1B,CAAA,EAAE;MAEU,kBAAkB,GAAG,aAAa,CAAc,iBAAiB,EAAE,EAAE;AAErE,MAAA,cAAc,GAAG,MAAmB,UAAU,CAAC,kBAAkB;;;;"}
|
package/ScrollableContainer.d.ts
CHANGED
|
@@ -1,13 +1,20 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import { ScrollableContainerLeft, ScrollableContainerRight } from '@hh.ru/magritte-ui-scrollable-container/ScrollableContainerButton';
|
|
2
|
+
import { ScrollableContainerDefaultLayout } from '@hh.ru/magritte-ui-scrollable-container/ScrollableContainerDefaultLayout';
|
|
3
|
+
import { ScrollableContainerDotPages } from '@hh.ru/magritte-ui-scrollable-container/ScrollableContainerDotPages';
|
|
4
|
+
import { ScrollableContainerGallery } from '@hh.ru/magritte-ui-scrollable-container/ScrollableContainerGallery';
|
|
5
|
+
import { ScrollableItem } from '@hh.ru/magritte-ui-scrollable-container/ScrollableItem';
|
|
6
|
+
import { ScrollableControls } from '@hh.ru/magritte-ui-scrollable-container/types';
|
|
7
|
+
export interface ScrollableContainerComponents {
|
|
8
|
+
Left: typeof ScrollableContainerLeft;
|
|
9
|
+
Right: typeof ScrollableContainerRight;
|
|
10
|
+
Item: typeof ScrollableItem;
|
|
11
|
+
DefaultLayout: typeof ScrollableContainerDefaultLayout;
|
|
12
|
+
Gallery: typeof ScrollableContainerGallery;
|
|
13
|
+
DotPages: typeof ScrollableContainerDotPages;
|
|
7
14
|
}
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
export {};
|
|
15
|
+
declare const ScrollableContainerComponent: import("react").ForwardRefExoticComponent<import("@hh.ru/magritte-ui-scrollable-container/types").SpacingCorrectionProps & {
|
|
16
|
+
children: import("react").ReactNode;
|
|
17
|
+
scrollSnapAlign?: import("@hh.ru/magritte-ui-scrollable-container/types").ScrollSnapAlign;
|
|
18
|
+
} & import("react").HTMLAttributes<HTMLDivElement> & import("react").RefAttributes<ScrollableControls>>;
|
|
19
|
+
declare const ScrollableContainer: typeof ScrollableContainerComponent & ScrollableContainerComponents;
|
|
20
|
+
export { ScrollableContainer };
|
package/ScrollableContainer.js
CHANGED
|
@@ -1,81 +1,32 @@
|
|
|
1
1
|
import './index.css';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { jsx } from 'react/jsx-runtime';
|
|
3
|
+
import { forwardRef, useMemo, useImperativeHandle } from 'react';
|
|
4
4
|
import classnames from 'classnames';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
5
|
+
import { useBreakpoint } from '@hh.ru/magritte-ui-breakpoint';
|
|
6
|
+
import { ScrollStateContext, createScrollState } from './ScrollStateProvider.js';
|
|
7
|
+
import { ScrollableContainerLeft, ScrollableContainerRight } from './ScrollableContainerButton.js';
|
|
8
|
+
import { ScrollableContainerDefaultLayout } from './ScrollableContainerDefaultLayout.js';
|
|
9
|
+
import { ScrollableContainerDotPages } from './ScrollableContainerDotPages.js';
|
|
10
|
+
import { ScrollableContainerGallery } from './ScrollableContainerGallery.js';
|
|
11
|
+
import { ScrollableItem } from './ScrollableItem.js';
|
|
12
|
+
import { useScrollableControlsWithState } from './useScrollableControls.js';
|
|
13
|
+
import { getActualCorrection, useInitOnce } from './utils.js';
|
|
14
|
+
import { s as styles } from './scrollableContainer-CsVTi8_Q.js';
|
|
15
|
+
import 'motion/react';
|
|
16
|
+
import './ObservableValue.js';
|
|
17
|
+
import '@hh.ru/magritte-ui-icon/icon';
|
|
18
|
+
import '@hh.ru/magritte-internal-custom-scroll/initScrollHandlers';
|
|
19
|
+
import '@hh.ru/magritte-ui-dot-pages';
|
|
20
|
+
import './types.js';
|
|
21
|
+
import '@hh.ru/magritte-ui-spacing';
|
|
22
|
+
import './useScrollContainer.js';
|
|
10
23
|
import '@hh.ru/magritte-common-func-utils';
|
|
11
24
|
import '@hh.ru/magritte-internal-custom-scroll';
|
|
12
|
-
import './types.js';
|
|
13
|
-
import './utils.js';
|
|
14
25
|
|
|
15
|
-
|
|
16
|
-
const noopFunc = () => { };
|
|
17
|
-
const ScrollContext = createContext({
|
|
18
|
-
registerItem: noopFunc,
|
|
19
|
-
removeItem: noopFunc,
|
|
20
|
-
scrollToItem: noopFunc,
|
|
21
|
-
});
|
|
22
|
-
const useScrollContext = () => useContext(ScrollContext);
|
|
23
|
-
const BREAKPOINTS_LIST = [Breakpoint.XS, Breakpoint.S, Breakpoint.M, Breakpoint.L, Breakpoint.XL, Breakpoint.XXL];
|
|
24
|
-
const NO_BUTTONS_START_FROM_BREAKPOINT = Breakpoint.S;
|
|
25
|
-
const NO_TRANSLATE = { transform: 'translate3d(0px, 0, 0)' };
|
|
26
|
-
/**
|
|
27
|
-
* По переданным параметрам коррекции возвращает значения отступов для текущего брейкпоинта
|
|
28
|
-
* @param props Параметры коррекции
|
|
29
|
-
* @param breakpoint Текуший брейкпоинт
|
|
30
|
-
* @returns Объект содержащий значения отступов
|
|
31
|
-
*/
|
|
32
|
-
const getActualCorrection = (props, breakpoint) => {
|
|
33
|
-
const breakpointIndex = BREAKPOINTS_LIST.indexOf(breakpoint);
|
|
34
|
-
let leftCorrection;
|
|
35
|
-
let rightCorrection;
|
|
36
|
-
// Проходимся по всем брейкпоинтам, начиная с текущего в сторону меньших разрешений
|
|
37
|
-
for (let i = breakpointIndex; i >= 0; i--) {
|
|
38
|
-
const breakpointName = BREAKPOINTS_LIST[i].toUpperCase();
|
|
39
|
-
// Ключи, которые могут быть в параметрах коррекции (SpacingCorrectionProps)
|
|
40
|
-
const leftCorrectionKey = `correctionLeft${breakpointName}`;
|
|
41
|
-
const rightCorrectionKey = `correctionRight${breakpointName}`;
|
|
42
|
-
const commonCorrectionKey = `correction${breakpointName}`;
|
|
43
|
-
// Если для текущего брейкпоинта есть параметры коррекции для левой/правой стороны, то берем их
|
|
44
|
-
props[leftCorrectionKey] !== undefined &&
|
|
45
|
-
leftCorrection === undefined &&
|
|
46
|
-
(leftCorrection = props[leftCorrectionKey]);
|
|
47
|
-
props[rightCorrectionKey] !== undefined &&
|
|
48
|
-
rightCorrection === undefined &&
|
|
49
|
-
(rightCorrection = props[rightCorrectionKey]);
|
|
50
|
-
// Если для левой или правой стороны не найден параметр коррекции, то пробуем взять параметр correction для
|
|
51
|
-
// брейкпоинта который сейчас обрабатываем в цикле, например correctionM
|
|
52
|
-
if (props[commonCorrectionKey] !== undefined) {
|
|
53
|
-
leftCorrection === undefined && (leftCorrection = props[commonCorrectionKey]);
|
|
54
|
-
rightCorrection === undefined && (rightCorrection = props[commonCorrectionKey]);
|
|
55
|
-
}
|
|
56
|
-
// Если нашли значения для обеих сторон - возращаем
|
|
57
|
-
if (leftCorrection !== undefined && rightCorrection !== undefined) {
|
|
58
|
-
return { leftCorrection, rightCorrection };
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
// Если не нашли значение для какой то из сторон, то берем значение из correction, без уточнения брейкпоинта
|
|
62
|
-
return {
|
|
63
|
-
leftCorrection: leftCorrection === undefined ? props.correction || 0 : leftCorrection,
|
|
64
|
-
rightCorrection: rightCorrection === undefined ? props.correction || 0 : rightCorrection,
|
|
65
|
-
};
|
|
66
|
-
};
|
|
67
|
-
const ScrollableContainerComponent = ({ children, disableButtons: _disableButtons, correction = 0, correctionXS, correctionS, correctionM, correctionL, correctionXL, correctionXXL, correctionLeftXS, correctionLeftS, correctionLeftM, correctionLeftL, correctionLeftXL, correctionLeftXXL, correctionRightXS, correctionRightS, correctionRightM, correctionRightL, correctionRightXL, correctionRightXXL, showDotPages, dotPagesProps, snapToNearestItem, onChangeDot, onScroll, ...rest }, controlsRef) => {
|
|
26
|
+
const ScrollableContainerComponent = forwardRef(({ children, scrollSnapAlign = 'none', correction = 0, correctionXS, correctionS, correctionM, correctionL, correctionXL, correctionXXL, correctionLeftXS, correctionLeftS, correctionLeftM, correctionLeftL, correctionLeftXL, correctionLeftXXL, correctionRightXS, correctionRightS, correctionRightM, correctionRightL, correctionRightXL, correctionRightXXL, style, ...props }, controlsRef) => {
|
|
68
27
|
const breakpoint = useBreakpoint();
|
|
69
|
-
const breakpointIndex = BREAKPOINTS_LIST.indexOf(breakpoint.breakpoint);
|
|
70
|
-
const noButtonBreakpointIndex = BREAKPOINTS_LIST.indexOf(NO_BUTTONS_START_FROM_BREAKPOINT);
|
|
71
|
-
// use corrections and cast container to mobile view
|
|
72
|
-
const disableButtons = _disableButtons || breakpointIndex <= noButtonBreakpointIndex;
|
|
73
28
|
const spacingCorrectionStyles = useMemo(() => {
|
|
74
|
-
|
|
75
|
-
if (!disableButtons) {
|
|
76
|
-
return { paddingLeft: 0, paddingRight: 0 };
|
|
77
|
-
}
|
|
78
|
-
const correctionProps = {
|
|
29
|
+
const correctionValue = getActualCorrection({
|
|
79
30
|
correction,
|
|
80
31
|
correctionXS,
|
|
81
32
|
correctionS,
|
|
@@ -95,8 +46,7 @@ const ScrollableContainerComponent = ({ children, disableButtons: _disableButton
|
|
|
95
46
|
correctionRightL,
|
|
96
47
|
correctionRightXL,
|
|
97
48
|
correctionRightXXL,
|
|
98
|
-
};
|
|
99
|
-
const correctionValue = getActualCorrection(correctionProps, breakpoint.breakpoint);
|
|
49
|
+
}, breakpoint.breakpoint);
|
|
100
50
|
return {
|
|
101
51
|
marginLeft: -correctionValue.leftCorrection,
|
|
102
52
|
marginRight: -correctionValue.rightCorrection,
|
|
@@ -104,7 +54,6 @@ const ScrollableContainerComponent = ({ children, disableButtons: _disableButton
|
|
|
104
54
|
paddingRight: correctionValue.rightCorrection,
|
|
105
55
|
};
|
|
106
56
|
}, [
|
|
107
|
-
disableButtons,
|
|
108
57
|
correction,
|
|
109
58
|
correctionXS,
|
|
110
59
|
correctionS,
|
|
@@ -126,35 +75,30 @@ const ScrollableContainerComponent = ({ children, disableButtons: _disableButton
|
|
|
126
75
|
correctionRightXXL,
|
|
127
76
|
breakpoint.breakpoint,
|
|
128
77
|
]);
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
[styles.noButtons]: disableButtons,
|
|
154
|
-
}), ...rest, children: [jsx("div", { className: styles.scrollableContainer, style: disableButtons ? spacingCorrectionStyles : {}, ref: containerRef, "data-qa": "scrollable-container__overflow-container", children: jsx("div", { "data-qa": "scrollable-container__position-container", className: styles.positionContainer, style: NO_TRANSLATE, ref: positionContainerRef, children: jsx(ScrollContext.Provider, { value: { registerItem, removeItem, scrollToItem }, children: children }) }) }), !disableButtons && (jsxs(Fragment, { children: [jsx("div", { className: classnames(styles.scrollButton, styles.scrollButtonLeft), children: jsx(ChevronLeftOutlinedSize24, { tabIndex: -1, padding: 8, borderRadius: "halfHeight", initialColor: "secondary", onClick: () => scrollSide(), backgroundStyle: "secondary", "data-qa": "scrollable-container__scroll-button-left" }) }), jsx("div", { className: classnames(styles.scrollButton, styles.scrollButtonRight), children: jsx(ChevronRightOutlinedSize24, { tabIndex: -1, padding: 8, borderRadius: "halfHeight", initialColor: "secondary", backgroundStyle: "secondary", onClick: () => scrollSide(true), "data-qa": "scrollable-container__scroll-button-right" }) })] }))] }), showDotPages && countItems > 1 && (jsxs("div", { children: [jsx(VSpacing, { default: 8 }), jsx("div", { className: styles.dotContainer, children: jsx(DotPages, { active: activeDot, count: countItems, "data-qa": "scrollable-container__dot-pages", ...dotPagesProps }) })] }))] }));
|
|
155
|
-
};
|
|
156
|
-
const ScrollableContainer = forwardRef(ScrollableContainerComponent);
|
|
157
|
-
ScrollableContainer.displayName = 'ScrollableContainer';
|
|
78
|
+
const scrollState = useInitOnce(createScrollState);
|
|
79
|
+
scrollState.scrollSnapAlign = scrollSnapAlign;
|
|
80
|
+
scrollState.leftCorrection.set(spacingCorrectionStyles.paddingLeft);
|
|
81
|
+
scrollState.rightCorrection.set(spacingCorrectionStyles.paddingRight);
|
|
82
|
+
const controls = useScrollableControlsWithState(scrollState);
|
|
83
|
+
useImperativeHandle(controlsRef, () => controls, [controls]);
|
|
84
|
+
return (jsx("div", { "data-qa": "scrollable-container__wrapper", className: classnames(styles.scrollWrapper), style: {
|
|
85
|
+
...{
|
|
86
|
+
'--magritte-ui-scrollabe-container-ml': `${spacingCorrectionStyles.marginLeft}px`,
|
|
87
|
+
'--magritte-ui-scrollabe-container-mr': `${spacingCorrectionStyles.marginRight}px`,
|
|
88
|
+
'--magritte-ui-scrollabe-container-pl': `${spacingCorrectionStyles.paddingLeft}px`,
|
|
89
|
+
'--magritte-ui-scrollabe-container-pr': `${spacingCorrectionStyles.paddingRight}px`,
|
|
90
|
+
},
|
|
91
|
+
...(style || {}),
|
|
92
|
+
}, ...props, children: jsx(ScrollStateContext.Provider, { value: scrollState, children: children }) }));
|
|
93
|
+
});
|
|
94
|
+
ScrollableContainerComponent.displayName = 'ScrollableContainer';
|
|
95
|
+
const ScrollableContainer = ScrollableContainerComponent;
|
|
96
|
+
ScrollableContainer.Left = ScrollableContainerLeft;
|
|
97
|
+
ScrollableContainer.Right = ScrollableContainerRight;
|
|
98
|
+
ScrollableContainer.Item = ScrollableItem;
|
|
99
|
+
ScrollableContainer.Gallery = ScrollableContainerGallery;
|
|
100
|
+
ScrollableContainer.DefaultLayout = ScrollableContainerDefaultLayout;
|
|
101
|
+
ScrollableContainer.DotPages = ScrollableContainerDotPages;
|
|
158
102
|
|
|
159
|
-
export { ScrollableContainer
|
|
103
|
+
export { ScrollableContainer };
|
|
160
104
|
//# sourceMappingURL=ScrollableContainer.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScrollableContainer.js","sources":["../src/ScrollableContainer.tsx"],"sourcesContent":["import {\n createContext,\n RefObject,\n useEffect,\n useMemo,\n useContext,\n forwardRef,\n useImperativeHandle,\n ForwardedRef,\n ReactElement,\n PropsWithChildren,\n} from 'react';\nimport classnames from 'classnames';\n\nimport { useBreakpoint, Breakpoint } from '@hh.ru/magritte-ui-breakpoint';\nimport { DotPages } from '@hh.ru/magritte-ui-dot-pages';\nimport { ChevronRightOutlinedSize24, ChevronLeftOutlinedSize24 } from '@hh.ru/magritte-ui-icon/icon';\nimport {\n SpacingCorrectionProps,\n ScrollableControls,\n ScrollableContainerProps,\n} from '@hh.ru/magritte-ui-scrollable-container/types';\nimport { useScrollContainer } from '@hh.ru/magritte-ui-scrollable-container/useScrollContainer';\nimport { VSpacing } from '@hh.ru/magritte-ui-spacing';\n\nimport styles from './scrollableContainer.less';\n\ninterface ScrollContextType {\n registerItem: (ref: RefObject<HTMLElement>) => void;\n removeItem: (ref: RefObject<HTMLElement>) => void;\n scrollToItem: (ref: RefObject<HTMLElement>) => void;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-empty-function\nconst noopFunc = () => {};\nconst ScrollContext = createContext<ScrollContextType>({\n registerItem: noopFunc,\n removeItem: noopFunc,\n scrollToItem: noopFunc,\n});\n\nexport const useScrollContext = (): ScrollContextType => useContext(ScrollContext);\n\nconst BREAKPOINTS_LIST = [Breakpoint.XS, Breakpoint.S, Breakpoint.M, Breakpoint.L, Breakpoint.XL, Breakpoint.XXL];\nconst NO_BUTTONS_START_FROM_BREAKPOINT = Breakpoint.S;\nconst NO_TRANSLATE = { transform: 'translate3d(0px, 0, 0)' };\n\n/**\n * По переданным параметрам коррекции возвращает значения отступов для текущего брейкпоинта\n * @param props Параметры коррекции\n * @param breakpoint Текуший брейкпоинт\n * @returns Объект содержащий значения отступов\n */\nconst getActualCorrection = (props: SpacingCorrectionProps, breakpoint: Breakpoint) => {\n const breakpointIndex = BREAKPOINTS_LIST.indexOf(breakpoint);\n let leftCorrection: number | undefined;\n let rightCorrection: number | undefined;\n // Проходимся по всем брейкпоинтам, начиная с текущего в сторону меньших разрешений\n for (let i = breakpointIndex; i >= 0; i--) {\n const breakpointName = BREAKPOINTS_LIST[i].toUpperCase();\n // Ключи, которые могут быть в параметрах коррекции (SpacingCorrectionProps)\n const leftCorrectionKey = `correctionLeft${breakpointName}` as keyof SpacingCorrectionProps;\n const rightCorrectionKey = `correctionRight${breakpointName}` as keyof SpacingCorrectionProps;\n const commonCorrectionKey = `correction${breakpointName}` as keyof SpacingCorrectionProps;\n // Если для текущего брейкпоинта есть параметры коррекции для левой/правой стороны, то берем их\n props[leftCorrectionKey] !== undefined &&\n leftCorrection === undefined &&\n (leftCorrection = props[leftCorrectionKey]);\n props[rightCorrectionKey] !== undefined &&\n rightCorrection === undefined &&\n (rightCorrection = props[rightCorrectionKey]);\n\n // Если для левой или правой стороны не найден параметр коррекции, то пробуем взять параметр correction для\n // брейкпоинта который сейчас обрабатываем в цикле, например correctionM\n if (props[commonCorrectionKey] !== undefined) {\n leftCorrection === undefined && (leftCorrection = props[commonCorrectionKey]);\n rightCorrection === undefined && (rightCorrection = props[commonCorrectionKey]);\n }\n\n // Если нашли значения для обеих сторон - возращаем\n if (leftCorrection !== undefined && rightCorrection !== undefined) {\n return { leftCorrection, rightCorrection };\n }\n }\n\n // Если не нашли значение для какой то из сторон, то берем значение из correction, без уточнения брейкпоинта\n return {\n leftCorrection: leftCorrection === undefined ? props.correction || 0 : leftCorrection,\n rightCorrection: rightCorrection === undefined ? props.correction || 0 : rightCorrection,\n };\n};\n\nexport const ScrollableContainerComponent = (\n {\n children,\n disableButtons: _disableButtons,\n correction = 0,\n correctionXS,\n correctionS,\n correctionM,\n correctionL,\n correctionXL,\n correctionXXL,\n correctionLeftXS,\n correctionLeftS,\n correctionLeftM,\n correctionLeftL,\n correctionLeftXL,\n correctionLeftXXL,\n correctionRightXS,\n correctionRightS,\n correctionRightM,\n correctionRightL,\n correctionRightXL,\n correctionRightXXL,\n showDotPages,\n dotPagesProps,\n snapToNearestItem,\n onChangeDot,\n onScroll,\n ...rest\n }: PropsWithChildren<ScrollableContainerProps>,\n controlsRef?: ForwardedRef<ScrollableControls>\n): ReactElement => {\n const breakpoint = useBreakpoint();\n const breakpointIndex = BREAKPOINTS_LIST.indexOf(breakpoint.breakpoint);\n const noButtonBreakpointIndex = BREAKPOINTS_LIST.indexOf(NO_BUTTONS_START_FROM_BREAKPOINT);\n\n // use corrections and cast container to mobile view\n const disableButtons = _disableButtons || breakpointIndex <= noButtonBreakpointIndex;\n\n const spacingCorrectionStyles = useMemo(() => {\n // component use default button\n if (!disableButtons) {\n return { paddingLeft: 0, paddingRight: 0 };\n }\n const correctionProps = {\n correction,\n correctionXS,\n correctionS,\n correctionM,\n correctionL,\n correctionXL,\n correctionXXL,\n correctionLeftXS,\n correctionLeftS,\n correctionLeftM,\n correctionLeftL,\n correctionLeftXL,\n correctionLeftXXL,\n correctionRightXS,\n correctionRightS,\n correctionRightM,\n correctionRightL,\n correctionRightXL,\n correctionRightXXL,\n };\n const correctionValue = getActualCorrection(correctionProps, breakpoint.breakpoint);\n return {\n marginLeft: -correctionValue.leftCorrection,\n marginRight: -correctionValue.rightCorrection,\n paddingLeft: correctionValue.leftCorrection,\n paddingRight: correctionValue.rightCorrection,\n };\n }, [\n disableButtons,\n correction,\n correctionXS,\n correctionS,\n correctionM,\n correctionL,\n correctionXL,\n correctionXXL,\n correctionLeftXS,\n correctionLeftS,\n correctionLeftM,\n correctionLeftL,\n correctionLeftXL,\n correctionLeftXXL,\n correctionRightXS,\n correctionRightS,\n correctionRightM,\n correctionRightL,\n correctionRightXL,\n correctionRightXXL,\n breakpoint.breakpoint,\n ]);\n\n const {\n containerRef,\n positionContainerRef,\n wrapperRef,\n registerItem,\n removeItem,\n scrollToItem,\n scrollToFirstItem,\n scrollToLastItem,\n scrollSide,\n initScrollHandlers,\n countItems,\n isScrollRightDisabled,\n isScrollLeftDisabled,\n activeDot,\n scrollToIndex,\n } = useScrollContainer(\n spacingCorrectionStyles.paddingLeft,\n spacingCorrectionStyles.paddingRight,\n disableButtons,\n breakpoint.isMobile,\n snapToNearestItem || showDotPages,\n onScroll\n );\n\n useEffect(initScrollHandlers, [initScrollHandlers]);\n\n useImperativeHandle(\n controlsRef,\n () => ({\n scrollLeft: () => scrollSide(),\n scrollRight: () => scrollSide(true),\n scrollToFirstItem,\n scrollToLastItem,\n isScrollRightDisabled,\n isScrollLeftDisabled,\n scrollToIndex,\n scrollToItem,\n }),\n [\n scrollSide,\n scrollToFirstItem,\n scrollToLastItem,\n isScrollRightDisabled,\n isScrollLeftDisabled,\n scrollToIndex,\n scrollToItem,\n ]\n );\n\n useEffect(() => {\n onChangeDot?.(activeDot);\n }, [onChangeDot, activeDot]);\n\n return (\n <div>\n <div\n ref={wrapperRef}\n data-qa=\"scrollable-container__wrapper\"\n className={classnames(styles.scrollWrapper, {\n [styles.noButtons]: disableButtons,\n })}\n {...rest}\n >\n <div\n className={styles.scrollableContainer}\n style={disableButtons ? spacingCorrectionStyles : {}}\n ref={containerRef}\n data-qa=\"scrollable-container__overflow-container\"\n >\n <div\n data-qa=\"scrollable-container__position-container\"\n className={styles.positionContainer}\n style={NO_TRANSLATE}\n ref={positionContainerRef}\n >\n <ScrollContext.Provider value={{ registerItem, removeItem, scrollToItem }}>\n {children}\n </ScrollContext.Provider>\n </div>\n </div>\n {!disableButtons && (\n <>\n <div className={classnames(styles.scrollButton, styles.scrollButtonLeft)}>\n <ChevronLeftOutlinedSize24\n tabIndex={-1}\n padding={8}\n borderRadius=\"halfHeight\"\n initialColor=\"secondary\"\n onClick={() => scrollSide()}\n backgroundStyle=\"secondary\"\n data-qa=\"scrollable-container__scroll-button-left\"\n />\n </div>\n <div className={classnames(styles.scrollButton, styles.scrollButtonRight)}>\n <ChevronRightOutlinedSize24\n tabIndex={-1}\n padding={8}\n borderRadius=\"halfHeight\"\n initialColor=\"secondary\"\n backgroundStyle=\"secondary\"\n onClick={() => scrollSide(true)}\n data-qa=\"scrollable-container__scroll-button-right\"\n />\n </div>\n </>\n )}\n </div>\n {showDotPages && countItems > 1 && (\n <div>\n <VSpacing default={8} />\n <div className={styles.dotContainer}>\n <DotPages\n active={activeDot}\n count={countItems}\n data-qa=\"scrollable-container__dot-pages\"\n {...dotPagesProps}\n />\n </div>\n </div>\n )}\n </div>\n );\n};\n\nexport const ScrollableContainer = forwardRef(ScrollableContainerComponent);\n\nScrollableContainer.displayName = 'ScrollableContainer';\n"],"names":["_jsxs","_jsx","_Fragment"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ScrollableContainer.js","sources":["../src/ScrollableContainer.tsx"],"sourcesContent":["import { forwardRef, useImperativeHandle, useMemo, type CSSProperties } from 'react';\nimport classnames from 'classnames';\n\nimport { useBreakpoint } from '@hh.ru/magritte-ui-breakpoint';\nimport { ScrollStateContext, createScrollState } from '@hh.ru/magritte-ui-scrollable-container/ScrollStateProvider';\nimport {\n ScrollableContainerLeft,\n ScrollableContainerRight,\n} from '@hh.ru/magritte-ui-scrollable-container/ScrollableContainerButton';\nimport { ScrollableContainerDefaultLayout } from '@hh.ru/magritte-ui-scrollable-container/ScrollableContainerDefaultLayout';\nimport { ScrollableContainerDotPages } from '@hh.ru/magritte-ui-scrollable-container/ScrollableContainerDotPages';\nimport { ScrollableContainerGallery } from '@hh.ru/magritte-ui-scrollable-container/ScrollableContainerGallery';\nimport { ScrollableItem } from '@hh.ru/magritte-ui-scrollable-container/ScrollableItem';\nimport { ScrollableContainerProps, ScrollableControls } from '@hh.ru/magritte-ui-scrollable-container/types';\nimport { useScrollableControlsWithState } from '@hh.ru/magritte-ui-scrollable-container/useScrollableControls';\nimport { getActualCorrection, useInitOnce } from '@hh.ru/magritte-ui-scrollable-container/utils';\n\nimport styles from './scrollableContainer.less';\n\nexport interface ScrollableContainerComponents {\n Left: typeof ScrollableContainerLeft;\n Right: typeof ScrollableContainerRight;\n Item: typeof ScrollableItem;\n DefaultLayout: typeof ScrollableContainerDefaultLayout;\n Gallery: typeof ScrollableContainerGallery;\n DotPages: typeof ScrollableContainerDotPages;\n}\n\nconst ScrollableContainerComponent = forwardRef<ScrollableControls, ScrollableContainerProps>(\n (\n {\n children,\n scrollSnapAlign = 'none',\n correction = 0,\n correctionXS,\n correctionS,\n correctionM,\n correctionL,\n correctionXL,\n correctionXXL,\n correctionLeftXS,\n correctionLeftS,\n correctionLeftM,\n correctionLeftL,\n correctionLeftXL,\n correctionLeftXXL,\n correctionRightXS,\n correctionRightS,\n correctionRightM,\n correctionRightL,\n correctionRightXL,\n correctionRightXXL,\n style,\n ...props\n },\n controlsRef\n ) => {\n const breakpoint = useBreakpoint();\n const spacingCorrectionStyles = useMemo(() => {\n const correctionValue = getActualCorrection(\n {\n correction,\n correctionXS,\n correctionS,\n correctionM,\n correctionL,\n correctionXL,\n correctionXXL,\n correctionLeftXS,\n correctionLeftS,\n correctionLeftM,\n correctionLeftL,\n correctionLeftXL,\n correctionLeftXXL,\n correctionRightXS,\n correctionRightS,\n correctionRightM,\n correctionRightL,\n correctionRightXL,\n correctionRightXXL,\n },\n breakpoint.breakpoint\n );\n return {\n marginLeft: -correctionValue.leftCorrection,\n marginRight: -correctionValue.rightCorrection,\n paddingLeft: correctionValue.leftCorrection,\n paddingRight: correctionValue.rightCorrection,\n };\n }, [\n correction,\n correctionXS,\n correctionS,\n correctionM,\n correctionL,\n correctionXL,\n correctionXXL,\n correctionLeftXS,\n correctionLeftS,\n correctionLeftM,\n correctionLeftL,\n correctionLeftXL,\n correctionLeftXXL,\n correctionRightXS,\n correctionRightS,\n correctionRightM,\n correctionRightL,\n correctionRightXL,\n correctionRightXXL,\n breakpoint.breakpoint,\n ]);\n\n const scrollState = useInitOnce(createScrollState);\n scrollState.scrollSnapAlign = scrollSnapAlign;\n scrollState.leftCorrection.set(spacingCorrectionStyles.paddingLeft);\n scrollState.rightCorrection.set(spacingCorrectionStyles.paddingRight);\n\n const controls = useScrollableControlsWithState(scrollState);\n useImperativeHandle(controlsRef, () => controls, [controls]);\n\n return (\n <div\n data-qa=\"scrollable-container__wrapper\"\n className={classnames(styles.scrollWrapper)}\n style={{\n ...({\n '--magritte-ui-scrollabe-container-ml': `${spacingCorrectionStyles.marginLeft}px`,\n '--magritte-ui-scrollabe-container-mr': `${spacingCorrectionStyles.marginRight}px`,\n '--magritte-ui-scrollabe-container-pl': `${spacingCorrectionStyles.paddingLeft}px`,\n '--magritte-ui-scrollabe-container-pr': `${spacingCorrectionStyles.paddingRight}px`,\n } as CSSProperties),\n ...(style || {}),\n }}\n {...props}\n >\n <ScrollStateContext.Provider value={scrollState}>{children}</ScrollStateContext.Provider>\n </div>\n );\n }\n);\n\nScrollableContainerComponent.displayName = 'ScrollableContainer';\n\nconst ScrollableContainer = ScrollableContainerComponent as typeof ScrollableContainerComponent &\n ScrollableContainerComponents;\n\nScrollableContainer.Left = ScrollableContainerLeft;\nScrollableContainer.Right = ScrollableContainerRight;\nScrollableContainer.Item = ScrollableItem;\nScrollableContainer.Gallery = ScrollableContainerGallery;\nScrollableContainer.DefaultLayout = ScrollableContainerDefaultLayout;\nScrollableContainer.DotPages = ScrollableContainerDotPages;\n\nexport { ScrollableContainer };\n"],"names":["_jsx"],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type FC } from 'react';
|
|
2
|
+
import type { ScrollableContainerButtonProps } from '@hh.ru/magritte-ui-scrollable-container/types';
|
|
3
|
+
export declare const ScrollableContainerLeft: FC<ScrollableContainerButtonProps>;
|
|
4
|
+
export declare const ScrollableContainerRight: FC<ScrollableContainerButtonProps>;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import './index.css';
|
|
2
|
+
import { jsx } from 'react/jsx-runtime';
|
|
3
|
+
import { isValidElement, cloneElement } from 'react';
|
|
4
|
+
import { useScrollableControls } from './useScrollableControls.js';
|
|
5
|
+
import '@hh.ru/magritte-internal-custom-scroll';
|
|
6
|
+
import './ScrollStateProvider.js';
|
|
7
|
+
import 'motion/react';
|
|
8
|
+
import './ObservableValue.js';
|
|
9
|
+
import './utils.js';
|
|
10
|
+
import '@hh.ru/magritte-ui-breakpoint';
|
|
11
|
+
import './types.js';
|
|
12
|
+
|
|
13
|
+
const ScrolllableContainerScrollButton = ({ children, toRight = false, }) => {
|
|
14
|
+
const { scrollLeft, scrollRight } = useScrollableControls();
|
|
15
|
+
if (!isValidElement(children)) {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
const defaultDataQa = `scrollable-container__scroll-button-${toRight ? 'right' : 'left'}`;
|
|
19
|
+
return cloneElement(children, {
|
|
20
|
+
'data-qa': children.props['data-qa'] || defaultDataQa,
|
|
21
|
+
onClick: () => (toRight ? scrollRight() : scrollLeft()),
|
|
22
|
+
});
|
|
23
|
+
};
|
|
24
|
+
const ScrollableContainerLeft = ({ children }) => (jsx(ScrolllableContainerScrollButton, { children: children }));
|
|
25
|
+
const ScrollableContainerRight = ({ children }) => (jsx(ScrolllableContainerScrollButton, { toRight: true, children: children }));
|
|
26
|
+
|
|
27
|
+
export { ScrollableContainerLeft, ScrollableContainerRight };
|
|
28
|
+
//# sourceMappingURL=ScrollableContainerButton.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ScrollableContainerButton.js","sources":["../src/ScrollableContainerButton.tsx"],"sourcesContent":["import { cloneElement, isValidElement, type FC } from 'react';\n\nimport type { ControlWithClick, ScrollableContainerButtonProps } from '@hh.ru/magritte-ui-scrollable-container/types';\nimport { useScrollableControls } from '@hh.ru/magritte-ui-scrollable-container/useScrollableControls';\n\nconst ScrolllableContainerScrollButton: FC<ScrollableContainerButtonProps & { toRight?: boolean }> = ({\n children,\n toRight = false,\n}) => {\n const { scrollLeft, scrollRight } = useScrollableControls();\n if (!isValidElement<ControlWithClick>(children)) {\n return null;\n }\n const defaultDataQa = `scrollable-container__scroll-button-${toRight ? 'right' : 'left'}`;\n return cloneElement(children, {\n 'data-qa': children.props['data-qa'] || defaultDataQa,\n onClick: () => (toRight ? scrollRight() : scrollLeft()),\n });\n};\n\nexport const ScrollableContainerLeft: FC<ScrollableContainerButtonProps> = ({ children }) => (\n <ScrolllableContainerScrollButton>{children}</ScrolllableContainerScrollButton>\n);\n\nexport const ScrollableContainerRight: FC<ScrollableContainerButtonProps> = ({ children }) => (\n <ScrolllableContainerScrollButton toRight>{children}</ScrolllableContainerScrollButton>\n);\n"],"names":["_jsx"],"mappings":";;;;;;;;;;;AAKA,MAAM,gCAAgC,GAA+D,CAAC,EAClG,QAAQ,EACR,OAAO,GAAG,KAAK,GAClB,KAAI;IACD,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,GAAG,qBAAqB,EAAE,CAAC;AAC5D,IAAA,IAAI,CAAC,cAAc,CAAmB,QAAQ,CAAC,EAAE;AAC7C,QAAA,OAAO,IAAI,CAAC;KACf;AACD,IAAA,MAAM,aAAa,GAAG,CAAuC,oCAAA,EAAA,OAAO,GAAG,OAAO,GAAG,MAAM,EAAE,CAAC;IAC1F,OAAO,YAAY,CAAC,QAAQ,EAAE;QAC1B,SAAS,EAAE,QAAQ,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,aAAa;AACrD,QAAA,OAAO,EAAE,OAAO,OAAO,GAAG,WAAW,EAAE,GAAG,UAAU,EAAE,CAAC;AAC1D,KAAA,CAAC,CAAC;AACP,CAAC,CAAC;AAEW,MAAA,uBAAuB,GAAuC,CAAC,EAAE,QAAQ,EAAE,MACpFA,GAAC,CAAA,gCAAgC,cAAE,QAAQ,EAAA,CAAoC,EACjF;MAEW,wBAAwB,GAAuC,CAAC,EAAE,QAAQ,EAAE,MACrFA,GAAA,CAAC,gCAAgC,EAAC,EAAA,OAAO,kBAAE,QAAQ,EAAA,CAAoC;;;;"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import './index.css';
|
|
2
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
3
|
+
import { useEffect } from 'react';
|
|
4
|
+
import classnames from 'classnames';
|
|
5
|
+
import { useMotionValue, motion } from 'motion/react';
|
|
6
|
+
import { useBreakpoint } from '@hh.ru/magritte-ui-breakpoint';
|
|
7
|
+
import { ChevronLeftOutlinedSize24, ChevronRightOutlinedSize24 } from '@hh.ru/magritte-ui-icon/icon';
|
|
8
|
+
import { useScrollState } from './ScrollStateProvider.js';
|
|
9
|
+
import { ScrollableContainerLeft, ScrollableContainerRight } from './ScrollableContainerButton.js';
|
|
10
|
+
import { BREAKPOINTS_LIST, NO_BUTTONS_START_FROM_BREAKPOINT, useInitOnce } from './utils.js';
|
|
11
|
+
import { s as styles } from './scrollableContainer-CsVTi8_Q.js';
|
|
12
|
+
import './ObservableValue.js';
|
|
13
|
+
import './useScrollableControls.js';
|
|
14
|
+
import '@hh.ru/magritte-internal-custom-scroll';
|
|
15
|
+
import './types.js';
|
|
16
|
+
|
|
17
|
+
const BUTTON_WIDTH = 44;
|
|
18
|
+
const ScrollableContainerDefaultLayout = ({ children }) => {
|
|
19
|
+
const scrollState = useScrollState();
|
|
20
|
+
const displayLeftButton = useMotionValue('none');
|
|
21
|
+
const displayRightButton = useMotionValue('none');
|
|
22
|
+
const mask = useMotionValue('none');
|
|
23
|
+
const breakpoint = useBreakpoint();
|
|
24
|
+
const breakpointIndex = BREAKPOINTS_LIST.indexOf(breakpoint.breakpoint);
|
|
25
|
+
const noButtonBreakpointIndex = BREAKPOINTS_LIST.indexOf(NO_BUTTONS_START_FROM_BREAKPOINT);
|
|
26
|
+
const enableDefaultButtonsByBreakpoint = breakpointIndex > noButtonBreakpointIndex;
|
|
27
|
+
const updateFadeAndButtons = useInitOnce(() => () => {
|
|
28
|
+
const position = scrollState.scrollPosition.get();
|
|
29
|
+
const contentWidth = scrollState.contentWidth.get();
|
|
30
|
+
const viewportWidth = scrollState.viewportWidth.get();
|
|
31
|
+
const showLeftButton = position < 0;
|
|
32
|
+
const showRightButton = Math.abs(position) < Math.max(0, contentWidth - viewportWidth);
|
|
33
|
+
displayLeftButton.set(showLeftButton ? 'block' : 'none');
|
|
34
|
+
displayRightButton.set(showRightButton ? 'block' : 'none');
|
|
35
|
+
if (showLeftButton && showRightButton) {
|
|
36
|
+
mask.set('var(--both-sides-mask)');
|
|
37
|
+
}
|
|
38
|
+
else if (showLeftButton) {
|
|
39
|
+
mask.set('var(--left-fade-mask)');
|
|
40
|
+
}
|
|
41
|
+
else if (showRightButton) {
|
|
42
|
+
mask.set('var(--right-fade-mask)');
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
mask.set('none');
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
useEffect(() => {
|
|
49
|
+
updateFadeAndButtons();
|
|
50
|
+
const unsubscribe = [
|
|
51
|
+
scrollState.scrollPosition.on('change', updateFadeAndButtons),
|
|
52
|
+
scrollState.contentWidth.on('change', updateFadeAndButtons),
|
|
53
|
+
scrollState.viewportWidth.on('change', updateFadeAndButtons),
|
|
54
|
+
];
|
|
55
|
+
return () => {
|
|
56
|
+
unsubscribe.forEach((fn) => fn());
|
|
57
|
+
};
|
|
58
|
+
}, [scrollState, updateFadeAndButtons]);
|
|
59
|
+
useEffect(() => {
|
|
60
|
+
scrollState.defaultButtonsCorrection.set(enableDefaultButtonsByBreakpoint ? BUTTON_WIDTH : 0);
|
|
61
|
+
return () => {
|
|
62
|
+
scrollState.defaultButtonsCorrection.set(0);
|
|
63
|
+
};
|
|
64
|
+
}, [scrollState, enableDefaultButtonsByBreakpoint]);
|
|
65
|
+
return (jsxs("div", { className: styles.scrollButtonsContainer, children: [jsx(motion.div, { className: styles.scrollButtons, style: {
|
|
66
|
+
WebkitMask: enableDefaultButtonsByBreakpoint ? mask : 'none',
|
|
67
|
+
mask: enableDefaultButtonsByBreakpoint ? mask : 'none',
|
|
68
|
+
}, "data-qa": "scrollable-container__fade", children: children }), jsx(motion.div, { className: classnames(styles.scrollButton, styles.scrollButtonLeft), style: { display: enableDefaultButtonsByBreakpoint ? displayLeftButton : 'none' }, children: jsx(ScrollableContainerLeft, { children: jsx(ChevronLeftOutlinedSize24, { tabIndex: -1, padding: 8, borderRadius: "halfHeight", initialColor: "secondary", backgroundStyle: "secondary" }) }) }), jsx(motion.div, { className: classnames(styles.scrollButton, styles.scrollButtonRight), style: { display: enableDefaultButtonsByBreakpoint ? displayRightButton : 'none' }, children: jsx(ScrollableContainerRight, { children: jsx(ChevronRightOutlinedSize24, { tabIndex: -1, padding: 8, borderRadius: "halfHeight", initialColor: "secondary", backgroundStyle: "secondary" }) }) })] }));
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export { ScrollableContainerDefaultLayout };
|
|
72
|
+
//# sourceMappingURL=ScrollableContainerDefaultLayout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ScrollableContainerDefaultLayout.js","sources":["../src/ScrollableContainerDefaultLayout.tsx"],"sourcesContent":["import { type FC, useEffect } from 'react';\nimport classnames from 'classnames';\nimport { useMotionValue, motion } from 'motion/react';\n\nimport { useBreakpoint } from '@hh.ru/magritte-ui-breakpoint';\nimport { ChevronRightOutlinedSize24, ChevronLeftOutlinedSize24 } from '@hh.ru/magritte-ui-icon/icon';\nimport { useScrollState } from '@hh.ru/magritte-ui-scrollable-container/ScrollStateProvider';\nimport {\n ScrollableContainerLeft,\n ScrollableContainerRight,\n} from '@hh.ru/magritte-ui-scrollable-container/ScrollableContainerButton';\nimport type { ScrollableContainerDefaultLayoutProps } from '@hh.ru/magritte-ui-scrollable-container/types';\nimport {\n BREAKPOINTS_LIST,\n NO_BUTTONS_START_FROM_BREAKPOINT,\n useInitOnce,\n} from '@hh.ru/magritte-ui-scrollable-container/utils';\n\nimport styles from './scrollableContainer.less';\n\nconst BUTTON_WIDTH = 44;\n\nexport const ScrollableContainerDefaultLayout: FC<ScrollableContainerDefaultLayoutProps> = ({ children }) => {\n const scrollState = useScrollState();\n const displayLeftButton = useMotionValue<'none' | 'block'>('none');\n const displayRightButton = useMotionValue<'none' | 'block'>('none');\n const mask = useMotionValue<string | number>('none');\n\n const breakpoint = useBreakpoint();\n const breakpointIndex = BREAKPOINTS_LIST.indexOf(breakpoint.breakpoint);\n const noButtonBreakpointIndex = BREAKPOINTS_LIST.indexOf(NO_BUTTONS_START_FROM_BREAKPOINT);\n const enableDefaultButtonsByBreakpoint = breakpointIndex > noButtonBreakpointIndex;\n\n const updateFadeAndButtons = useInitOnce(() => () => {\n const position = scrollState.scrollPosition.get();\n const contentWidth = scrollState.contentWidth.get();\n const viewportWidth = scrollState.viewportWidth.get();\n\n const showLeftButton = position < 0;\n const showRightButton = Math.abs(position) < Math.max(0, contentWidth - viewportWidth);\n\n displayLeftButton.set(showLeftButton ? 'block' : 'none');\n displayRightButton.set(showRightButton ? 'block' : 'none');\n\n if (showLeftButton && showRightButton) {\n mask.set('var(--both-sides-mask)');\n } else if (showLeftButton) {\n mask.set('var(--left-fade-mask)');\n } else if (showRightButton) {\n mask.set('var(--right-fade-mask)');\n } else {\n mask.set('none');\n }\n });\n\n useEffect(() => {\n updateFadeAndButtons();\n const unsubscribe = [\n scrollState.scrollPosition.on('change', updateFadeAndButtons),\n scrollState.contentWidth.on('change', updateFadeAndButtons),\n scrollState.viewportWidth.on('change', updateFadeAndButtons),\n ];\n return () => {\n unsubscribe.forEach((fn) => fn());\n };\n }, [scrollState, updateFadeAndButtons]);\n\n useEffect(() => {\n scrollState.defaultButtonsCorrection.set(enableDefaultButtonsByBreakpoint ? BUTTON_WIDTH : 0);\n return () => {\n scrollState.defaultButtonsCorrection.set(0);\n };\n }, [scrollState, enableDefaultButtonsByBreakpoint]);\n\n return (\n <div className={styles.scrollButtonsContainer}>\n <motion.div\n className={styles.scrollButtons}\n style={{\n WebkitMask: enableDefaultButtonsByBreakpoint ? mask : 'none',\n mask: enableDefaultButtonsByBreakpoint ? mask : 'none',\n }}\n data-qa=\"scrollable-container__fade\"\n >\n {children}\n </motion.div>\n <motion.div\n className={classnames(styles.scrollButton, styles.scrollButtonLeft)}\n style={{ display: enableDefaultButtonsByBreakpoint ? displayLeftButton : 'none' }}\n >\n <ScrollableContainerLeft>\n <ChevronLeftOutlinedSize24\n tabIndex={-1}\n padding={8}\n borderRadius=\"halfHeight\"\n initialColor=\"secondary\"\n backgroundStyle=\"secondary\"\n />\n </ScrollableContainerLeft>\n </motion.div>\n <motion.div\n className={classnames(styles.scrollButton, styles.scrollButtonRight)}\n style={{ display: enableDefaultButtonsByBreakpoint ? displayRightButton : 'none' }}\n >\n <ScrollableContainerRight>\n <ChevronRightOutlinedSize24\n tabIndex={-1}\n padding={8}\n borderRadius=\"halfHeight\"\n initialColor=\"secondary\"\n backgroundStyle=\"secondary\"\n />\n </ScrollableContainerRight>\n </motion.div>\n </div>\n );\n};\n"],"names":["_jsxs","_jsx"],"mappings":"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"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import './index.css';
|
|
2
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
3
|
+
import { useState, useRef, useEffect } from 'react';
|
|
4
|
+
import { clamp } from '@hh.ru/magritte-internal-custom-scroll/initScrollHandlers';
|
|
5
|
+
import { DotPages } from '@hh.ru/magritte-ui-dot-pages';
|
|
6
|
+
import { useScrollState } from './ScrollStateProvider.js';
|
|
7
|
+
import { OFFSET_ATTR } from './types.js';
|
|
8
|
+
import { useInitOnce, findIndexNearestToSnapPoint } from './utils.js';
|
|
9
|
+
import { VSpacing } from '@hh.ru/magritte-ui-spacing';
|
|
10
|
+
import { s as styles } from './scrollableContainer-CsVTi8_Q.js';
|
|
11
|
+
import 'motion/react';
|
|
12
|
+
import './ObservableValue.js';
|
|
13
|
+
import '@hh.ru/magritte-internal-custom-scroll';
|
|
14
|
+
import '@hh.ru/magritte-ui-breakpoint';
|
|
15
|
+
|
|
16
|
+
const DEFAULT_DOT = 1;
|
|
17
|
+
const ScrollableContainerDotPages = ({ onChangeDot, dotPagesProps, offsetTop = 8, }) => {
|
|
18
|
+
const scrollState = useScrollState();
|
|
19
|
+
const [activeDot, setActiveDot] = useState(DEFAULT_DOT);
|
|
20
|
+
const [itemsCount, setItemsCount] = useState(0);
|
|
21
|
+
const activeDotRef = useRef(DEFAULT_DOT);
|
|
22
|
+
const onChangeDotRef = useRef(onChangeDot);
|
|
23
|
+
onChangeDotRef.current = onChangeDot;
|
|
24
|
+
const setDotAndEmitOnChange = useInitOnce(() => (dot) => {
|
|
25
|
+
if (dot === activeDotRef.current) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
setActiveDot(dot);
|
|
29
|
+
onChangeDotRef.current?.(dot);
|
|
30
|
+
activeDotRef.current = dot;
|
|
31
|
+
});
|
|
32
|
+
const updateActiveDot = useInitOnce(() => () => {
|
|
33
|
+
const { viewportWidth, scrollPosition, items } = scrollState;
|
|
34
|
+
const center = viewportWidth.get() / 2 + Math.abs(scrollPosition.get());
|
|
35
|
+
const activeDotItem = items.get()[activeDotRef.current - 1]?.current;
|
|
36
|
+
if (!activeDotItem ||
|
|
37
|
+
!activeDotItem[OFFSET_ATTR] ||
|
|
38
|
+
(activeDotItem[OFFSET_ATTR].left <= center && activeDotItem[OFFSET_ATTR].right >= center)) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
setDotAndEmitOnChange(findIndexNearestToSnapPoint(scrollState) + 1);
|
|
42
|
+
});
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
const unsubscribe = [
|
|
45
|
+
scrollState.scrollPosition.on('change', updateActiveDot),
|
|
46
|
+
scrollState.items.on('change', (items) => {
|
|
47
|
+
setItemsCount(items.length);
|
|
48
|
+
// удалили последний элемент и он был активный
|
|
49
|
+
if (activeDotRef.current > items.length && items.length !== 0) {
|
|
50
|
+
setDotAndEmitOnChange(clamp(activeDotRef.current, 0, items.length - 1));
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
updateActiveDot();
|
|
54
|
+
}),
|
|
55
|
+
];
|
|
56
|
+
return () => {
|
|
57
|
+
unsubscribe.forEach((fn) => fn());
|
|
58
|
+
};
|
|
59
|
+
}, [scrollState, updateActiveDot, setDotAndEmitOnChange]);
|
|
60
|
+
if (itemsCount === 0) {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
return (jsxs("div", { children: [jsx(VSpacing, { default: offsetTop }), jsx("div", { className: styles.dotContainer, children: jsx(DotPages, { active: activeDot, count: itemsCount, "data-qa": dotPagesProps?.['data-qa'] || 'scrollable-container__dot-pages', ...dotPagesProps }) })] }));
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export { ScrollableContainerDotPages };
|
|
67
|
+
//# sourceMappingURL=ScrollableContainerDotPages.js.map
|