@hh.ru/magritte-ui-scrollable-container 5.2.60 → 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 +5 -4
  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-JyxpLsxm.js +0 -491
  47. package/useScrollContainer-JyxpLsxm.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;;;;"}
@@ -1,13 +1,20 @@
1
- import { RefObject, ForwardedRef, ReactElement, PropsWithChildren } from 'react';
2
- import { SpacingCorrectionProps, ScrollableControls, ScrollableContainerProps } from '@hh.ru/magritte-ui-scrollable-container/types';
3
- interface ScrollContextType {
4
- registerItem: (ref: RefObject<HTMLElement>) => void;
5
- removeItem: (ref: RefObject<HTMLElement>) => void;
6
- scrollToItem: (ref: RefObject<HTMLElement>) => void;
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
- export declare const useScrollContext: () => ScrollContextType;
9
- export declare const ScrollableContainerComponent: ({ children, disableButtons: _disableButtons, correction, correctionXS, correctionS, correctionM, correctionL, correctionXL, correctionXXL, correctionLeftXS, correctionLeftS, correctionLeftM, correctionLeftL, correctionLeftXL, correctionLeftXXL, correctionRightXS, correctionRightS, correctionRightM, correctionRightL, correctionRightXL, correctionRightXXL, showDotPages, dotPagesProps, snapToNearestItem, onChangeDot, onScroll, ...rest }: PropsWithChildren<ScrollableContainerProps>, controlsRef?: ForwardedRef<ScrollableControls>) => ReactElement;
10
- export declare const ScrollableContainer: import("react").ForwardRefExoticComponent<Omit<import("react").HTMLAttributes<HTMLDivElement>, keyof SpacingCorrectionProps | "disableButtons" | "onScroll"> & import("@hh.ru/magritte-ui-scrollable-container/types").ScrollableContainerBaseProps & SpacingCorrectionProps & {
11
- children?: import("react").ReactNode | undefined;
12
- } & import("react").RefAttributes<ScrollableControls>>;
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 };
@@ -1,81 +1,32 @@
1
1
  import './index.css';
2
- import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
3
- import { createContext, forwardRef, useContext, useMemo, useEffect, useImperativeHandle } from 'react';
2
+ import { jsx } from 'react/jsx-runtime';
3
+ import { forwardRef, useMemo, useImperativeHandle } from 'react';
4
4
  import classnames from 'classnames';
5
- import { Breakpoint, useBreakpoint } from '@hh.ru/magritte-ui-breakpoint';
6
- import { DotPages } from '@hh.ru/magritte-ui-dot-pages';
7
- import { ChevronLeftOutlinedSize24, ChevronRightOutlinedSize24 } from '@hh.ru/magritte-ui-icon/icon';
8
- import { u as useScrollContainer, s as styles } from './useScrollContainer-JyxpLsxm.js';
9
- import { VSpacing } from '@hh.ru/magritte-ui-spacing';
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
- // eslint-disable-next-line @typescript-eslint/no-empty-function
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
- // component use default button
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 { containerRef, positionContainerRef, wrapperRef, registerItem, removeItem, scrollToItem, scrollToFirstItem, scrollToLastItem, scrollSide, initScrollHandlers, countItems, isScrollRightDisabled, isScrollLeftDisabled, activeDot, scrollToIndex, } = useScrollContainer(spacingCorrectionStyles.paddingLeft, spacingCorrectionStyles.paddingRight, disableButtons, breakpoint.isMobile, snapToNearestItem || showDotPages, onScroll);
130
- useEffect(initScrollHandlers, [initScrollHandlers]);
131
- useImperativeHandle(controlsRef, () => ({
132
- scrollLeft: () => scrollSide(),
133
- scrollRight: () => scrollSide(true),
134
- scrollToFirstItem,
135
- scrollToLastItem,
136
- isScrollRightDisabled,
137
- isScrollLeftDisabled,
138
- scrollToIndex,
139
- scrollToItem,
140
- }), [
141
- scrollSide,
142
- scrollToFirstItem,
143
- scrollToLastItem,
144
- isScrollRightDisabled,
145
- isScrollLeftDisabled,
146
- scrollToIndex,
147
- scrollToItem,
148
- ]);
149
- useEffect(() => {
150
- onChangeDot?.(activeDot);
151
- }, [onChangeDot, activeDot]);
152
- return (jsxs("div", { children: [jsxs("div", { ref: wrapperRef, "data-qa": "scrollable-container__wrapper", className: classnames(styles.scrollWrapper, {
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, ScrollableContainerComponent, useScrollContext };
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,3 @@
1
+ import { type FC } from 'react';
2
+ import type { ScrollableContainerDefaultLayoutProps } from '@hh.ru/magritte-ui-scrollable-container/types';
3
+ export declare const ScrollableContainerDefaultLayout: FC<ScrollableContainerDefaultLayoutProps>;
@@ -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,3 @@
1
+ import { type FC } from 'react';
2
+ import { ScrollableContainerDotPagesProps } from '@hh.ru/magritte-ui-scrollable-container/types';
3
+ export declare const ScrollableContainerDotPages: FC<ScrollableContainerDotPagesProps>;
@@ -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