@cloud-ru/uikit-product-mobile-carousel 0.1.12 → 0.1.14

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 (46) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/cjs/components/AdaptiveCarousel/AdaptiveCarousel.d.ts +5 -0
  3. package/dist/cjs/components/AdaptiveCarousel/AdaptiveCarousel.js +22 -0
  4. package/dist/cjs/components/AdaptiveCarousel/index.d.ts +1 -0
  5. package/dist/cjs/components/AdaptiveCarousel/index.js +17 -0
  6. package/dist/cjs/components/MobileCarousel/MobileCarousel.d.ts +3 -0
  7. package/dist/cjs/components/MobileCarousel/MobileCarousel.js +38 -0
  8. package/dist/cjs/components/MobileCarousel/components/ItemList/ItemList.d.ts +12 -0
  9. package/dist/cjs/components/MobileCarousel/components/ItemList/ItemList.js +110 -0
  10. package/dist/cjs/components/MobileCarousel/components/ItemList/index.d.ts +1 -0
  11. package/dist/cjs/components/MobileCarousel/components/ItemList/index.js +17 -0
  12. package/dist/cjs/components/MobileCarousel/components/ItemList/styles.module.css +27 -0
  13. package/dist/cjs/components/MobileCarousel/components/index.d.ts +1 -0
  14. package/dist/cjs/components/MobileCarousel/components/index.js +17 -0
  15. package/dist/cjs/components/MobileCarousel/index.d.ts +1 -0
  16. package/dist/cjs/components/MobileCarousel/index.js +17 -0
  17. package/dist/cjs/components/MobileCarousel/styles.module.css +21 -0
  18. package/dist/cjs/components/index.d.ts +2 -0
  19. package/dist/cjs/components/index.js +18 -0
  20. package/dist/cjs/index.d.ts +1 -0
  21. package/dist/cjs/index.js +17 -0
  22. package/dist/cjs/testIds.d.ts +7 -0
  23. package/dist/cjs/testIds.js +10 -0
  24. package/dist/esm/components/AdaptiveCarousel/AdaptiveCarousel.d.ts +5 -0
  25. package/dist/esm/components/AdaptiveCarousel/AdaptiveCarousel.js +19 -0
  26. package/dist/esm/components/AdaptiveCarousel/index.d.ts +1 -0
  27. package/dist/esm/components/AdaptiveCarousel/index.js +1 -0
  28. package/dist/esm/components/MobileCarousel/MobileCarousel.d.ts +3 -0
  29. package/dist/esm/components/MobileCarousel/MobileCarousel.js +32 -0
  30. package/dist/esm/components/MobileCarousel/components/ItemList/ItemList.d.ts +12 -0
  31. package/dist/esm/components/MobileCarousel/components/ItemList/ItemList.js +104 -0
  32. package/dist/esm/components/MobileCarousel/components/ItemList/index.d.ts +1 -0
  33. package/dist/esm/components/MobileCarousel/components/ItemList/index.js +1 -0
  34. package/dist/esm/components/MobileCarousel/components/ItemList/styles.module.css +27 -0
  35. package/dist/esm/components/MobileCarousel/components/index.d.ts +1 -0
  36. package/dist/esm/components/MobileCarousel/components/index.js +1 -0
  37. package/dist/esm/components/MobileCarousel/index.d.ts +1 -0
  38. package/dist/esm/components/MobileCarousel/index.js +1 -0
  39. package/dist/esm/components/MobileCarousel/styles.module.css +21 -0
  40. package/dist/esm/components/index.d.ts +2 -0
  41. package/dist/esm/components/index.js +2 -0
  42. package/dist/esm/index.d.ts +1 -0
  43. package/dist/esm/index.js +1 -0
  44. package/dist/esm/testIds.d.ts +7 -0
  45. package/dist/esm/testIds.js +7 -0
  46. package/package.json +4 -3
package/CHANGELOG.md CHANGED
@@ -3,6 +3,26 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## 0.1.14 (2025-11-13)
7
+
8
+ ### Only dependencies have been changed
9
+ * [@cloud-ru/uikit-product-utils@7.0.2](https://gitverse.ru/cloud-ru-tech/uikit-product/-/blob/master/packages/utils/CHANGELOG.md)
10
+
11
+
12
+
13
+
14
+
15
+ ## 0.1.13 (2025-11-12)
16
+
17
+
18
+ ### Bug Fixes
19
+
20
+ * **PD-3377:** contributors update to publish all packages ([719fd3e](https://gitverse.ru/cloud-ru-tech/uikit-product/commits/719fd3e1249e247443b125c47ea408d92c8395c3))
21
+
22
+
23
+
24
+
25
+
6
26
  ## 0.1.12 (2025-11-12)
7
27
 
8
28
  ### Only dependencies have been changed
@@ -0,0 +1,5 @@
1
+ import { WithLayoutType } from '@sbercloud/uikit-product-utils';
2
+ import { CarouselProps } from '@snack-uikit/carousel';
3
+ export type AdaptiveCarouselProps = WithLayoutType<CarouselProps>;
4
+ export declare function AdaptiveCarousel({ layoutType, ...props }: AdaptiveCarouselProps): import("react/jsx-runtime").JSX.Element;
5
+ export type { CarouselProps };
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ var __rest = (this && this.__rest) || function (s, e) {
3
+ var t = {};
4
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
5
+ t[p] = s[p];
6
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
7
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
8
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
9
+ t[p[i]] = s[p[i]];
10
+ }
11
+ return t;
12
+ };
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.AdaptiveCarousel = AdaptiveCarousel;
15
+ const jsx_runtime_1 = require("react/jsx-runtime");
16
+ const carousel_1 = require("@snack-uikit/carousel");
17
+ const MobileCarousel_1 = require("../MobileCarousel");
18
+ function AdaptiveCarousel(_a) {
19
+ var { layoutType } = _a, props = __rest(_a, ["layoutType"]);
20
+ const isMobile = layoutType === 'mobile';
21
+ return isMobile ? (0, jsx_runtime_1.jsx)(MobileCarousel_1.MobileCarousel, Object.assign({}, props)) : (0, jsx_runtime_1.jsx)(carousel_1.Carousel, Object.assign({}, props));
22
+ }
@@ -0,0 +1 @@
1
+ export * from './AdaptiveCarousel';
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./AdaptiveCarousel"), exports);
@@ -0,0 +1,3 @@
1
+ import { CarouselProps } from '@snack-uikit/carousel';
2
+ export type MobileCarouselProps = Omit<CarouselProps, 'transition' | 'swipe' | 'swipeActivateLength' | 'arrows' | 'state'>;
3
+ export declare function MobileCarousel({ children: items, showItems, scrollBy: scrollByProp, className, gap, pagination, infiniteScroll, autoSwipe, ...rest }: MobileCarouselProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ var __rest = (this && this.__rest) || function (s, e) {
3
+ var t = {};
4
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
5
+ t[p] = s[p];
6
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
7
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
8
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
9
+ t[p[i]] = s[p[i]];
10
+ }
11
+ return t;
12
+ };
13
+ var __importDefault = (this && this.__importDefault) || function (mod) {
14
+ return (mod && mod.__esModule) ? mod : { "default": mod };
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.MobileCarousel = MobileCarousel;
18
+ const jsx_runtime_1 = require("react/jsx-runtime");
19
+ const classnames_1 = __importDefault(require("classnames"));
20
+ const react_1 = require("react");
21
+ const uikit_product_utils_1 = require("@sbercloud/uikit-product-utils");
22
+ const pagination_1 = require("@snack-uikit/pagination");
23
+ const testIds_1 = require("../../testIds");
24
+ const components_1 = require("./components");
25
+ const styles_module_scss_1 = __importDefault(require('./styles.module.css'));
26
+ const noop = () => { };
27
+ function MobileCarousel(_a) {
28
+ var { children: items, showItems = 1.1, scrollBy: scrollByProp, className, gap, pagination, infiniteScroll = false, autoSwipe } = _a, rest = __rest(_a, ["children", "showItems", "scrollBy", "className", "gap", "pagination", "infiniteScroll", "autoSwipe"]);
29
+ const scrollBy = (0, react_1.useMemo)(() => scrollByProp !== null && scrollByProp !== void 0 ? scrollByProp : Math.trunc(showItems), [showItems, scrollByProp]);
30
+ const [page, setPage] = (0, react_1.useState)(0);
31
+ const total = (0, react_1.useMemo)(() => {
32
+ if (items.length <= showItems) {
33
+ return 1;
34
+ }
35
+ return 1 + Math.ceil((items.length - showItems) / scrollBy);
36
+ }, [items.length, scrollBy, showItems]);
37
+ return ((0, jsx_runtime_1.jsxs)("div", Object.assign({ className: (0, classnames_1.default)(styles_module_scss_1.default.carousel, className) }, (0, uikit_product_utils_1.extractSupportProps)(rest), { children: [(0, jsx_runtime_1.jsx)("div", { className: styles_module_scss_1.default.carouselBase, children: (0, jsx_runtime_1.jsx)(components_1.ItemList, { showItems: showItems, scrollBy: scrollBy, items: items, gap: gap, autoSwipe: autoSwipe, infiniteScroll: infiniteScroll, totalPages: total, onPageChange: setPage }) }), pagination && ((0, jsx_runtime_1.jsx)("div", { className: styles_module_scss_1.default.pagination, children: (0, jsx_runtime_1.jsx)(pagination_1.PaginationSlider, { "data-test-id": testIds_1.TEST_IDS.pagination, page: page + 1, onChange: noop, total: total }) }))] })));
38
+ }
@@ -0,0 +1,12 @@
1
+ import { ReactElement } from 'react';
2
+ export type ItemProviderProps = {
3
+ items: ReactElement[];
4
+ showItems: number;
5
+ scrollBy: number;
6
+ gap?: string;
7
+ autoSwipe?: number;
8
+ infiniteScroll?: boolean;
9
+ totalPages: number;
10
+ onPageChange(page: number): void;
11
+ };
12
+ export declare function ItemList({ items, showItems, scrollBy, gap, autoSwipe, infiniteScroll, totalPages, onPageChange, }: ItemProviderProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,110 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ItemList = ItemList;
7
+ const jsx_runtime_1 = require("react/jsx-runtime");
8
+ const lodash_debounce_1 = __importDefault(require("lodash.debounce"));
9
+ const react_1 = require("react");
10
+ const testIds_1 = require("../../../../testIds");
11
+ const styles_module_scss_1 = __importDefault(require('./styles.module.css'));
12
+ const DELTA = 5;
13
+ function ItemList({ items, showItems, scrollBy, gap, autoSwipe, infiniteScroll, totalPages, onPageChange, }) {
14
+ const timerRef = (0, react_1.useRef)();
15
+ const containerRef = (0, react_1.useRef)(null);
16
+ const [scrollLeft, setScrollLeft] = (0, react_1.useState)(0);
17
+ const [computedValues, setComputedValues] = (0, react_1.useState)({ itemWidth: 0, gap: 0 });
18
+ const [canDoInfiniteScroll, setCanDoInfiniteScroll] = (0, react_1.useState)(true);
19
+ const recalculateItemsSize = (0, react_1.useCallback)(() => {
20
+ const containerElement = containerRef.current;
21
+ if (!containerElement) {
22
+ return;
23
+ }
24
+ const styles = getComputedStyle(containerElement);
25
+ const gap = Number.parseFloat(styles.getPropertyValue('--mobile-carousel--list-gap'));
26
+ const paddingLeft = Number.parseFloat(styles.getPropertyValue('padding-left'));
27
+ const paddingRight = Number.parseFloat(styles.getPropertyValue('padding-right'));
28
+ const itemWidth = (containerElement.getBoundingClientRect().width -
29
+ (Math.trunc(showItems) - 1) * gap -
30
+ paddingLeft -
31
+ paddingRight) /
32
+ showItems;
33
+ setComputedValues({ itemWidth, gap });
34
+ }, [showItems]);
35
+ (0, react_1.useEffect)(() => {
36
+ const node = containerRef.current;
37
+ if (!node) {
38
+ return;
39
+ }
40
+ recalculateItemsSize();
41
+ const observer = new ResizeObserver((0, lodash_debounce_1.default)(recalculateItemsSize, 100));
42
+ observer.observe(node);
43
+ return () => observer.disconnect();
44
+ }, [recalculateItemsSize]);
45
+ const itemWidth = (0, react_1.useMemo)(() => {
46
+ if (computedValues.itemWidth > 0) {
47
+ return computedValues.itemWidth;
48
+ }
49
+ const fallbackWidth = Math.floor(100 / showItems);
50
+ return `${fallbackWidth}%`;
51
+ }, [computedValues.itemWidth, showItems]);
52
+ (0, react_1.useEffect)(() => {
53
+ if (!autoSwipe) {
54
+ return;
55
+ }
56
+ const handleAutoSwipe = () => {
57
+ const deltaWidth = computedValues.itemWidth * scrollBy;
58
+ if (containerRef.current) {
59
+ const newLeft = containerRef.current.scrollLeft + deltaWidth;
60
+ containerRef.current.scrollTo({
61
+ left: newLeft > containerRef.current.scrollWidth - deltaWidth ? 0 : newLeft,
62
+ behavior: 'smooth',
63
+ });
64
+ }
65
+ };
66
+ timerRef.current = setInterval(() => handleAutoSwipe(), autoSwipe * 1000);
67
+ return () => clearInterval(timerRef.current);
68
+ }, [autoSwipe, computedValues.itemWidth, scrollBy, scrollLeft]);
69
+ /**
70
+ * Устанавливает номер текущей страницы.
71
+ * Текущей страницей считается та, над которой располагается центр контейнера.
72
+ * Странице принадлежит ее правый гап, если по центру контейнера он, то текущей страницей считается та что слева от этого gap-а
73
+ */
74
+ const setCurrentPage = event => {
75
+ var _a, _b;
76
+ const scrollLeft = event.currentTarget.scrollLeft;
77
+ setScrollLeft(scrollLeft);
78
+ const pageWith = scrollBy > 1
79
+ ? computedValues.itemWidth * scrollBy + computedValues.gap * (scrollBy - 1) // scrollBy=3 [item + gap + item + gap + item]
80
+ : computedValues.itemWidth; // scrollBy=1 [item]
81
+ const centerOfScrollContainer = scrollLeft + ((_b = (_a = containerRef.current) === null || _a === void 0 ? void 0 : _a.offsetWidth) !== null && _b !== void 0 ? _b : 0) / 2;
82
+ for (let i = 0; i < totalPages; i++) {
83
+ const pageStart = i * pageWith;
84
+ const pageEnd = pageStart + pageWith + computedValues.gap;
85
+ if (centerOfScrollContainer >= pageStart && centerOfScrollContainer <= pageEnd) {
86
+ onPageChange(Math.max(0, Math.min(totalPages - 1, i)));
87
+ return;
88
+ }
89
+ }
90
+ };
91
+ const isScrolledLeft = () => Boolean(containerRef.current && containerRef.current.scrollLeft <= DELTA);
92
+ const isScrolledRight = () => Boolean(containerRef.current &&
93
+ containerRef.current.scrollWidth - containerRef.current.scrollLeft - containerRef.current.offsetWidth <= DELTA);
94
+ const handleTouchStart = () => {
95
+ setCanDoInfiniteScroll(isScrolledLeft() || isScrolledRight());
96
+ };
97
+ const handleTouchEnd = () => {
98
+ const scrollArea = containerRef.current;
99
+ if (!canDoInfiniteScroll || !infiniteScroll || !scrollArea) {
100
+ return;
101
+ }
102
+ if (isScrolledLeft()) {
103
+ scrollArea.scrollTo({ left: scrollArea.scrollWidth, behavior: 'smooth' });
104
+ }
105
+ else if (isScrolledRight()) {
106
+ scrollArea.scrollTo({ left: 0, behavior: 'smooth' });
107
+ }
108
+ };
109
+ return ((0, jsx_runtime_1.jsx)("div", { ref: containerRef, className: styles_module_scss_1.default.itemList, "data-gap": gap, style: Object.assign({}, (gap ? { '--mobile-carousel--list-gap': gap } : {})), onScroll: setCurrentPage, onTouchStart: handleTouchStart, onTouchEnd: handleTouchEnd, children: items.map((item, i) => ((0, jsx_runtime_1.jsx)("div", { style: { width: itemWidth }, className: styles_module_scss_1.default.itemContainer, role: 'group', "data-test-id": testIds_1.TEST_IDS.trackItem, children: item }, i))) }));
110
+ }
@@ -0,0 +1 @@
1
+ export * from './ItemList';
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./ItemList"), exports);
@@ -0,0 +1,27 @@
1
+ .itemList{
2
+ --mobile-carousel--list-gap:var(--dimension-2m, 16px);
3
+ scrollbar-width:none;
4
+ scroll-snap-type:x mandatory;
5
+ scroll-snap-stop:always;
6
+ overflow-x:scroll;
7
+ padding-top:var(--space-carousel-content-layout-padding, 4px);
8
+ padding-bottom:var(--space-carousel-content-layout-padding, 4px);
9
+ padding-left:var(--space-carousel-content-layout-padding, 4px);
10
+ padding-right:var(--space-carousel-content-layout-padding, 4px);
11
+ width:100%;
12
+ height:100%;
13
+ display:flex;
14
+ flex:none;
15
+ flex-flow:row nowrap;
16
+ gap:var(--mobile-carousel--list-gap, var(--dimension-2m, 16px));
17
+ }
18
+ .itemList ::-webkit-scrollbar{
19
+ display:none;
20
+ }
21
+
22
+ .itemContainer{
23
+ scroll-snap-align:start;
24
+ flex:none;
25
+ width:calc(100% - 1px);
26
+ margin:1px;
27
+ }
@@ -0,0 +1 @@
1
+ export * from './ItemList';
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./ItemList"), exports);
@@ -0,0 +1 @@
1
+ export * from './MobileCarousel';
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./MobileCarousel"), exports);
@@ -0,0 +1,21 @@
1
+ .carouselBase{
2
+ position:relative;
3
+ display:flex;
4
+ box-sizing:border-box;
5
+ width:100%;
6
+ outline:none;
7
+ }
8
+
9
+ .carousel{
10
+ display:flex;
11
+ flex-direction:column;
12
+ align-items:center;
13
+ box-sizing:border-box;
14
+ }
15
+
16
+ .pagination{
17
+ padding-top:var(--space-carousel-sliders-wrap-padding-top, 8px);
18
+ display:flex;
19
+ justify-content:center;
20
+ box-sizing:border-box;
21
+ }
@@ -0,0 +1,2 @@
1
+ export * from './AdaptiveCarousel';
2
+ export * from './MobileCarousel';
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./AdaptiveCarousel"), exports);
18
+ __exportStar(require("./MobileCarousel"), exports);
@@ -0,0 +1 @@
1
+ export * from './components';
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./components"), exports);
@@ -0,0 +1,7 @@
1
+ export declare const TEST_IDS: {
2
+ arrowNext: string;
3
+ arrowPrev: string;
4
+ pagination: string;
5
+ trackLine: string;
6
+ trackItem: string;
7
+ };
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TEST_IDS = void 0;
4
+ exports.TEST_IDS = {
5
+ arrowNext: 'carousel__arrow-next',
6
+ arrowPrev: 'carousel__arrow-prev',
7
+ pagination: 'carousel__pagination',
8
+ trackLine: 'carousel__track-line',
9
+ trackItem: 'carousel__track-item',
10
+ };
@@ -0,0 +1,5 @@
1
+ import { WithLayoutType } from '@sbercloud/uikit-product-utils';
2
+ import { CarouselProps } from '@snack-uikit/carousel';
3
+ export type AdaptiveCarouselProps = WithLayoutType<CarouselProps>;
4
+ export declare function AdaptiveCarousel({ layoutType, ...props }: AdaptiveCarouselProps): import("react/jsx-runtime").JSX.Element;
5
+ export type { CarouselProps };
@@ -0,0 +1,19 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
12
+ import { jsx as _jsx } from "react/jsx-runtime";
13
+ import { Carousel } from '@snack-uikit/carousel';
14
+ import { MobileCarousel } from '../MobileCarousel';
15
+ export function AdaptiveCarousel(_a) {
16
+ var { layoutType } = _a, props = __rest(_a, ["layoutType"]);
17
+ const isMobile = layoutType === 'mobile';
18
+ return isMobile ? _jsx(MobileCarousel, Object.assign({}, props)) : _jsx(Carousel, Object.assign({}, props));
19
+ }
@@ -0,0 +1 @@
1
+ export * from './AdaptiveCarousel';
@@ -0,0 +1 @@
1
+ export * from './AdaptiveCarousel';
@@ -0,0 +1,3 @@
1
+ import { CarouselProps } from '@snack-uikit/carousel';
2
+ export type MobileCarouselProps = Omit<CarouselProps, 'transition' | 'swipe' | 'swipeActivateLength' | 'arrows' | 'state'>;
3
+ export declare function MobileCarousel({ children: items, showItems, scrollBy: scrollByProp, className, gap, pagination, infiniteScroll, autoSwipe, ...rest }: MobileCarouselProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,32 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
12
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
13
+ import cn from 'classnames';
14
+ import { useMemo, useState } from 'react';
15
+ import { extractSupportProps } from '@sbercloud/uikit-product-utils';
16
+ import { PaginationSlider } from '@snack-uikit/pagination';
17
+ import { TEST_IDS } from '../../testIds';
18
+ import { ItemList } from './components';
19
+ import styles from './styles.module.css';
20
+ const noop = () => { };
21
+ export function MobileCarousel(_a) {
22
+ var { children: items, showItems = 1.1, scrollBy: scrollByProp, className, gap, pagination, infiniteScroll = false, autoSwipe } = _a, rest = __rest(_a, ["children", "showItems", "scrollBy", "className", "gap", "pagination", "infiniteScroll", "autoSwipe"]);
23
+ const scrollBy = useMemo(() => scrollByProp !== null && scrollByProp !== void 0 ? scrollByProp : Math.trunc(showItems), [showItems, scrollByProp]);
24
+ const [page, setPage] = useState(0);
25
+ const total = useMemo(() => {
26
+ if (items.length <= showItems) {
27
+ return 1;
28
+ }
29
+ return 1 + Math.ceil((items.length - showItems) / scrollBy);
30
+ }, [items.length, scrollBy, showItems]);
31
+ return (_jsxs("div", Object.assign({ className: cn(styles.carousel, className) }, extractSupportProps(rest), { children: [_jsx("div", { className: styles.carouselBase, children: _jsx(ItemList, { showItems: showItems, scrollBy: scrollBy, items: items, gap: gap, autoSwipe: autoSwipe, infiniteScroll: infiniteScroll, totalPages: total, onPageChange: setPage }) }), pagination && (_jsx("div", { className: styles.pagination, children: _jsx(PaginationSlider, { "data-test-id": TEST_IDS.pagination, page: page + 1, onChange: noop, total: total }) }))] })));
32
+ }
@@ -0,0 +1,12 @@
1
+ import { ReactElement } from 'react';
2
+ export type ItemProviderProps = {
3
+ items: ReactElement[];
4
+ showItems: number;
5
+ scrollBy: number;
6
+ gap?: string;
7
+ autoSwipe?: number;
8
+ infiniteScroll?: boolean;
9
+ totalPages: number;
10
+ onPageChange(page: number): void;
11
+ };
12
+ export declare function ItemList({ items, showItems, scrollBy, gap, autoSwipe, infiniteScroll, totalPages, onPageChange, }: ItemProviderProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,104 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import debounce from 'lodash.debounce';
3
+ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
4
+ import { TEST_IDS } from '../../../../testIds';
5
+ import styles from './styles.module.css';
6
+ const DELTA = 5;
7
+ export function ItemList({ items, showItems, scrollBy, gap, autoSwipe, infiniteScroll, totalPages, onPageChange, }) {
8
+ const timerRef = useRef();
9
+ const containerRef = useRef(null);
10
+ const [scrollLeft, setScrollLeft] = useState(0);
11
+ const [computedValues, setComputedValues] = useState({ itemWidth: 0, gap: 0 });
12
+ const [canDoInfiniteScroll, setCanDoInfiniteScroll] = useState(true);
13
+ const recalculateItemsSize = useCallback(() => {
14
+ const containerElement = containerRef.current;
15
+ if (!containerElement) {
16
+ return;
17
+ }
18
+ const styles = getComputedStyle(containerElement);
19
+ const gap = Number.parseFloat(styles.getPropertyValue('--mobile-carousel--list-gap'));
20
+ const paddingLeft = Number.parseFloat(styles.getPropertyValue('padding-left'));
21
+ const paddingRight = Number.parseFloat(styles.getPropertyValue('padding-right'));
22
+ const itemWidth = (containerElement.getBoundingClientRect().width -
23
+ (Math.trunc(showItems) - 1) * gap -
24
+ paddingLeft -
25
+ paddingRight) /
26
+ showItems;
27
+ setComputedValues({ itemWidth, gap });
28
+ }, [showItems]);
29
+ useEffect(() => {
30
+ const node = containerRef.current;
31
+ if (!node) {
32
+ return;
33
+ }
34
+ recalculateItemsSize();
35
+ const observer = new ResizeObserver(debounce(recalculateItemsSize, 100));
36
+ observer.observe(node);
37
+ return () => observer.disconnect();
38
+ }, [recalculateItemsSize]);
39
+ const itemWidth = useMemo(() => {
40
+ if (computedValues.itemWidth > 0) {
41
+ return computedValues.itemWidth;
42
+ }
43
+ const fallbackWidth = Math.floor(100 / showItems);
44
+ return `${fallbackWidth}%`;
45
+ }, [computedValues.itemWidth, showItems]);
46
+ useEffect(() => {
47
+ if (!autoSwipe) {
48
+ return;
49
+ }
50
+ const handleAutoSwipe = () => {
51
+ const deltaWidth = computedValues.itemWidth * scrollBy;
52
+ if (containerRef.current) {
53
+ const newLeft = containerRef.current.scrollLeft + deltaWidth;
54
+ containerRef.current.scrollTo({
55
+ left: newLeft > containerRef.current.scrollWidth - deltaWidth ? 0 : newLeft,
56
+ behavior: 'smooth',
57
+ });
58
+ }
59
+ };
60
+ timerRef.current = setInterval(() => handleAutoSwipe(), autoSwipe * 1000);
61
+ return () => clearInterval(timerRef.current);
62
+ }, [autoSwipe, computedValues.itemWidth, scrollBy, scrollLeft]);
63
+ /**
64
+ * Устанавливает номер текущей страницы.
65
+ * Текущей страницей считается та, над которой располагается центр контейнера.
66
+ * Странице принадлежит ее правый гап, если по центру контейнера он, то текущей страницей считается та что слева от этого gap-а
67
+ */
68
+ const setCurrentPage = event => {
69
+ var _a, _b;
70
+ const scrollLeft = event.currentTarget.scrollLeft;
71
+ setScrollLeft(scrollLeft);
72
+ const pageWith = scrollBy > 1
73
+ ? computedValues.itemWidth * scrollBy + computedValues.gap * (scrollBy - 1) // scrollBy=3 [item + gap + item + gap + item]
74
+ : computedValues.itemWidth; // scrollBy=1 [item]
75
+ const centerOfScrollContainer = scrollLeft + ((_b = (_a = containerRef.current) === null || _a === void 0 ? void 0 : _a.offsetWidth) !== null && _b !== void 0 ? _b : 0) / 2;
76
+ for (let i = 0; i < totalPages; i++) {
77
+ const pageStart = i * pageWith;
78
+ const pageEnd = pageStart + pageWith + computedValues.gap;
79
+ if (centerOfScrollContainer >= pageStart && centerOfScrollContainer <= pageEnd) {
80
+ onPageChange(Math.max(0, Math.min(totalPages - 1, i)));
81
+ return;
82
+ }
83
+ }
84
+ };
85
+ const isScrolledLeft = () => Boolean(containerRef.current && containerRef.current.scrollLeft <= DELTA);
86
+ const isScrolledRight = () => Boolean(containerRef.current &&
87
+ containerRef.current.scrollWidth - containerRef.current.scrollLeft - containerRef.current.offsetWidth <= DELTA);
88
+ const handleTouchStart = () => {
89
+ setCanDoInfiniteScroll(isScrolledLeft() || isScrolledRight());
90
+ };
91
+ const handleTouchEnd = () => {
92
+ const scrollArea = containerRef.current;
93
+ if (!canDoInfiniteScroll || !infiniteScroll || !scrollArea) {
94
+ return;
95
+ }
96
+ if (isScrolledLeft()) {
97
+ scrollArea.scrollTo({ left: scrollArea.scrollWidth, behavior: 'smooth' });
98
+ }
99
+ else if (isScrolledRight()) {
100
+ scrollArea.scrollTo({ left: 0, behavior: 'smooth' });
101
+ }
102
+ };
103
+ return (_jsx("div", { ref: containerRef, className: styles.itemList, "data-gap": gap, style: Object.assign({}, (gap ? { '--mobile-carousel--list-gap': gap } : {})), onScroll: setCurrentPage, onTouchStart: handleTouchStart, onTouchEnd: handleTouchEnd, children: items.map((item, i) => (_jsx("div", { style: { width: itemWidth }, className: styles.itemContainer, role: 'group', "data-test-id": TEST_IDS.trackItem, children: item }, i))) }));
104
+ }
@@ -0,0 +1 @@
1
+ export * from './ItemList';
@@ -0,0 +1 @@
1
+ export * from './ItemList';
@@ -0,0 +1,27 @@
1
+ .itemList{
2
+ --mobile-carousel--list-gap:var(--dimension-2m, 16px);
3
+ scrollbar-width:none;
4
+ scroll-snap-type:x mandatory;
5
+ scroll-snap-stop:always;
6
+ overflow-x:scroll;
7
+ padding-top:var(--space-carousel-content-layout-padding, 4px);
8
+ padding-bottom:var(--space-carousel-content-layout-padding, 4px);
9
+ padding-left:var(--space-carousel-content-layout-padding, 4px);
10
+ padding-right:var(--space-carousel-content-layout-padding, 4px);
11
+ width:100%;
12
+ height:100%;
13
+ display:flex;
14
+ flex:none;
15
+ flex-flow:row nowrap;
16
+ gap:var(--mobile-carousel--list-gap, var(--dimension-2m, 16px));
17
+ }
18
+ .itemList ::-webkit-scrollbar{
19
+ display:none;
20
+ }
21
+
22
+ .itemContainer{
23
+ scroll-snap-align:start;
24
+ flex:none;
25
+ width:calc(100% - 1px);
26
+ margin:1px;
27
+ }
@@ -0,0 +1 @@
1
+ export * from './ItemList';
@@ -0,0 +1 @@
1
+ export * from './ItemList';
@@ -0,0 +1 @@
1
+ export * from './MobileCarousel';
@@ -0,0 +1 @@
1
+ export * from './MobileCarousel';
@@ -0,0 +1,21 @@
1
+ .carouselBase{
2
+ position:relative;
3
+ display:flex;
4
+ box-sizing:border-box;
5
+ width:100%;
6
+ outline:none;
7
+ }
8
+
9
+ .carousel{
10
+ display:flex;
11
+ flex-direction:column;
12
+ align-items:center;
13
+ box-sizing:border-box;
14
+ }
15
+
16
+ .pagination{
17
+ padding-top:var(--space-carousel-sliders-wrap-padding-top, 8px);
18
+ display:flex;
19
+ justify-content:center;
20
+ box-sizing:border-box;
21
+ }
@@ -0,0 +1,2 @@
1
+ export * from './AdaptiveCarousel';
2
+ export * from './MobileCarousel';
@@ -0,0 +1,2 @@
1
+ export * from './AdaptiveCarousel';
2
+ export * from './MobileCarousel';
@@ -0,0 +1 @@
1
+ export * from './components';
@@ -0,0 +1 @@
1
+ export * from './components';
@@ -0,0 +1,7 @@
1
+ export declare const TEST_IDS: {
2
+ arrowNext: string;
3
+ arrowPrev: string;
4
+ pagination: string;
5
+ trackLine: string;
6
+ trackItem: string;
7
+ };
@@ -0,0 +1,7 @@
1
+ export const TEST_IDS = {
2
+ arrowNext: 'carousel__arrow-next',
3
+ arrowPrev: 'carousel__arrow-prev',
4
+ pagination: 'carousel__pagination',
5
+ trackLine: 'carousel__track-line',
6
+ trackItem: 'carousel__track-item',
7
+ };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cloud-ru/uikit-product-mobile-carousel",
3
3
  "title": "Mobile Carousel",
4
- "version": "0.1.12",
4
+ "version": "0.1.14",
5
5
  "sideEffects": [
6
6
  "*.css",
7
7
  "*.woff",
@@ -30,13 +30,14 @@
30
30
  "name": "Akhremenko Grigorii",
31
31
  "url": "https://github.com/AGrigorii"
32
32
  },
33
+ "contributors": [],
33
34
  "license": "Apache-2.0",
34
35
  "publishConfig": {
35
36
  "access": "public"
36
37
  },
37
38
  "scripts": {},
38
39
  "dependencies": {
39
- "@cloud-ru/uikit-product-utils": "7.0.0",
40
+ "@cloud-ru/uikit-product-utils": "7.0.2",
40
41
  "@snack-uikit/carousel": "0.6.4",
41
42
  "@snack-uikit/pagination": "0.10.18",
42
43
  "classnames": "2.5.1",
@@ -45,5 +46,5 @@
45
46
  "devDependencies": {
46
47
  "@types/lodash.debounce": "4.0.9"
47
48
  },
48
- "gitHead": "e8bd79bc92b26a8f52611972eec98a867536ccd3"
49
+ "gitHead": "bf479ecf7238ef20b78f20acaef439efa535d1a1"
49
50
  }