@snack-uikit/carousel 0.6.13 → 0.6.14-preview-4e8bfebd.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/dist/cjs/components/Carousel/Carousel.js +31 -20
- package/dist/cjs/components/Control/Control.js +3 -5
- package/dist/cjs/components/ItemProvider/ItemProvider.js +51 -39
- package/dist/cjs/components/ItemProvider/styles.module.css +3 -5
- package/dist/esm/components/ItemProvider/ItemProvider.js +20 -16
- package/dist/esm/components/ItemProvider/styles.module.css +3 -5
- package/package.json +5 -5
- package/src/components/ItemProvider/ItemProvider.tsx +23 -18
- package/src/components/ItemProvider/styles.module.scss +9 -3
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/esm/slicedToArray"));
|
|
3
5
|
var __rest = void 0 && (void 0).__rest || function (s, e) {
|
|
4
6
|
var t = {};
|
|
5
7
|
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p];
|
|
@@ -29,29 +31,38 @@ const ItemProvider_1 = require("../ItemProvider");
|
|
|
29
31
|
const styles_module_scss_1 = __importDefault(require('./styles.module.css'));
|
|
30
32
|
function Carousel(_a) {
|
|
31
33
|
var _b;
|
|
32
|
-
var
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
34
|
+
var items = _a.children,
|
|
35
|
+
_a$showItems = _a.showItems,
|
|
36
|
+
showItems = _a$showItems === void 0 ? 1 : _a$showItems,
|
|
37
|
+
scrollByProp = _a.scrollBy,
|
|
38
|
+
_a$transition = _a.transition,
|
|
39
|
+
transition = _a$transition === void 0 ? 0.4 : _a$transition,
|
|
40
|
+
_a$swipe = _a.swipe,
|
|
41
|
+
swipe = _a$swipe === void 0 ? true : _a$swipe,
|
|
42
|
+
_a$arrows = _a.arrows,
|
|
43
|
+
arrows = _a$arrows === void 0 ? true : _a$arrows,
|
|
44
|
+
_a$pagination = _a.pagination,
|
|
45
|
+
pagination = _a$pagination === void 0 ? true : _a$pagination,
|
|
46
|
+
className = _a.className,
|
|
47
|
+
gap = _a.gap,
|
|
48
|
+
state = _a.state,
|
|
49
|
+
_a$infiniteScroll = _a.infiniteScroll,
|
|
50
|
+
infiniteScroll = _a$infiniteScroll === void 0 ? false : _a$infiniteScroll,
|
|
51
|
+
_a$swipeActivateLengt = _a.swipeActivateLength,
|
|
52
|
+
swipeActivateLength = _a$swipeActivateLengt === void 0 ? 48 : _a$swipeActivateLengt,
|
|
53
|
+
autoSwipe = _a.autoSwipe,
|
|
54
|
+
_a$controlsVisibility = _a.controlsVisibility,
|
|
55
|
+
controlsVisibility = _a$controlsVisibility === void 0 ? 'hover' : _a$controlsVisibility,
|
|
48
56
|
rest = __rest(_a, ["children", "showItems", "scrollBy", "transition", "swipe", "arrows", "pagination", "className", "gap", "state", "infiniteScroll", "swipeActivateLength", "autoSwipe", "controlsVisibility"]);
|
|
49
57
|
const timerRef = (0, react_1.useRef)();
|
|
50
58
|
const scrollBy = (0, react_1.useMemo)(() => scrollByProp !== null && scrollByProp !== void 0 ? scrollByProp : Math.trunc(showItems), [showItems, scrollByProp]);
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
59
|
+
const _ref = (0, uncontrollable_1.useUncontrolledProp)(state === null || state === void 0 ? void 0 : state.page, (_b = state === null || state === void 0 ? void 0 : state.page) !== null && _b !== void 0 ? _b : 0, newPage => {
|
|
60
|
+
const result = typeof newPage === 'function' ? newPage(page) : newPage;
|
|
61
|
+
state === null || state === void 0 ? void 0 : state.onChange(result);
|
|
62
|
+
}),
|
|
63
|
+
_ref2 = (0, _slicedToArray2.default)(_ref, 2),
|
|
64
|
+
page = _ref2[0],
|
|
65
|
+
setPage = _ref2[1];
|
|
55
66
|
const total = (0, react_1.useMemo)(() => {
|
|
56
67
|
if (items.length <= showItems) {
|
|
57
68
|
return 1;
|
|
@@ -24,11 +24,9 @@ const icons_1 = require("@snack-uikit/icons");
|
|
|
24
24
|
const utils_1 = require("@snack-uikit/utils");
|
|
25
25
|
const styles_module_scss_1 = __importDefault(require('./styles.module.css'));
|
|
26
26
|
exports.Control = (0, react_1.forwardRef)((_a, ref) => {
|
|
27
|
-
var
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
className
|
|
31
|
-
} = _a,
|
|
27
|
+
var onClick = _a.onClick,
|
|
28
|
+
variant = _a.variant,
|
|
29
|
+
className = _a.className,
|
|
32
30
|
rest = __rest(_a, ["onClick", "variant", "className"]);
|
|
33
31
|
return (0, jsx_runtime_1.jsx)("button", Object.assign({
|
|
34
32
|
ref: ref,
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/esm/slicedToArray"));
|
|
3
5
|
var __rest = void 0 && (void 0).__rest || function (s, e) {
|
|
4
6
|
var t = {};
|
|
5
7
|
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p];
|
|
@@ -18,58 +20,67 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
18
20
|
});
|
|
19
21
|
exports.ItemProvider = ItemProvider;
|
|
20
22
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
21
|
-
const
|
|
23
|
+
const lodash_1 = require("lodash");
|
|
22
24
|
const merge_refs_1 = __importDefault(require("merge-refs"));
|
|
23
25
|
const react_1 = require("react");
|
|
24
26
|
const utils_1 = require("@snack-uikit/utils");
|
|
25
27
|
const testIds_1 = require("../../testIds");
|
|
26
28
|
const styles_module_scss_1 = __importDefault(require('./styles.module.css'));
|
|
29
|
+
function parseCssLength(value) {
|
|
30
|
+
const parsed = Number.parseFloat(value);
|
|
31
|
+
return Number.isFinite(parsed) ? parsed : 0;
|
|
32
|
+
}
|
|
27
33
|
function ItemProvider(_ref) {
|
|
28
|
-
let
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
gap
|
|
38
|
-
} = _ref;
|
|
34
|
+
let items = _ref.items,
|
|
35
|
+
showItems = _ref.showItems,
|
|
36
|
+
scrollBy = _ref.scrollBy,
|
|
37
|
+
slideCallback = _ref.slideCallback,
|
|
38
|
+
transition = _ref.transition,
|
|
39
|
+
swipe = _ref.swipe,
|
|
40
|
+
swipeActivateLength = _ref.swipeActivateLength,
|
|
41
|
+
page = _ref.page,
|
|
42
|
+
gap = _ref.gap;
|
|
39
43
|
const containerRef = (0, react_1.useRef)(null);
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
+
const itemsTrackerRef = (0, react_1.useRef)(null);
|
|
45
|
+
const _ref2 = (0, react_1.useState)({
|
|
46
|
+
itemWidth: 0,
|
|
47
|
+
gap: 0
|
|
48
|
+
}),
|
|
49
|
+
_ref3 = (0, _slicedToArray2.default)(_ref2, 2),
|
|
50
|
+
computedValues = _ref3[0],
|
|
51
|
+
setComputedValues = _ref3[1];
|
|
44
52
|
const recalculateItemsSize = (0, react_1.useCallback)(() => {
|
|
45
53
|
const containerElement = containerRef.current;
|
|
46
|
-
|
|
54
|
+
const trackerElement = itemsTrackerRef.current;
|
|
55
|
+
if (!containerElement || !trackerElement) {
|
|
47
56
|
return;
|
|
48
57
|
}
|
|
49
|
-
const
|
|
50
|
-
const
|
|
51
|
-
const
|
|
52
|
-
const
|
|
53
|
-
const
|
|
58
|
+
const containerStyles = getComputedStyle(containerElement);
|
|
59
|
+
const trackerStyles = getComputedStyle(trackerElement);
|
|
60
|
+
const gapValue = gap ? parseCssLength(gap) : parseCssLength(trackerStyles.columnGap || trackerStyles.gap);
|
|
61
|
+
const paddingLeft = parseCssLength(containerStyles.paddingLeft);
|
|
62
|
+
const paddingRight = parseCssLength(containerStyles.paddingRight);
|
|
63
|
+
const gapsCount = Math.max(Math.trunc(showItems) - 1, 0);
|
|
64
|
+
const contentWidth = containerElement.getBoundingClientRect().width - paddingLeft - paddingRight;
|
|
65
|
+
const itemWidth = (contentWidth - gapsCount * gapValue) / showItems;
|
|
54
66
|
setComputedValues({
|
|
55
67
|
itemWidth,
|
|
56
|
-
gap
|
|
68
|
+
gap: gapValue
|
|
57
69
|
});
|
|
58
|
-
}, [showItems]);
|
|
59
|
-
(0,
|
|
70
|
+
}, [showItems, gap]);
|
|
71
|
+
(0, utils_1.useLayoutEffect)(() => {
|
|
60
72
|
const node = containerRef.current;
|
|
61
73
|
if (!node) {
|
|
62
74
|
return;
|
|
63
75
|
}
|
|
64
76
|
recalculateItemsSize();
|
|
65
|
-
const observer = new ResizeObserver((0,
|
|
77
|
+
const observer = new ResizeObserver((0, lodash_1.debounce)(recalculateItemsSize, 100));
|
|
66
78
|
observer.observe(node);
|
|
67
79
|
return () => observer.disconnect();
|
|
68
80
|
}, [recalculateItemsSize]);
|
|
69
|
-
const itemsTrackerRef = (0, react_1.useRef)(null);
|
|
70
81
|
const hideNonVisibleItems = () => {
|
|
71
82
|
var _a;
|
|
72
|
-
(_a = itemsTrackerRef.current) === null || _a === void 0 ? void 0 : _a.querySelectorAll(
|
|
83
|
+
(_a = itemsTrackerRef.current) === null || _a === void 0 ? void 0 : _a.querySelectorAll("[data-test-id=".concat(testIds_1.TEST_IDS.trackItem, "]")).forEach(slide => {
|
|
73
84
|
slide.setAttribute('aria-hidden', '0');
|
|
74
85
|
slide.querySelectorAll('a, button, select, input, textarea, [tabindex="0"]').forEach(focusableElement => {
|
|
75
86
|
focusableElement.setAttribute('tabindex', '-5');
|
|
@@ -79,7 +90,7 @@ function ItemProvider(_ref) {
|
|
|
79
90
|
};
|
|
80
91
|
const showVisibleItems = (slide, page, show) => {
|
|
81
92
|
var _a;
|
|
82
|
-
(_a = itemsTrackerRef.current) === null || _a === void 0 ? void 0 : _a.querySelectorAll(
|
|
93
|
+
(_a = itemsTrackerRef.current) === null || _a === void 0 ? void 0 : _a.querySelectorAll("[data-test-id=".concat(testIds_1.TEST_IDS.trackItem, "]")).forEach((item, i) => {
|
|
83
94
|
if (i >= page * slide && i < page * slide + Math.trunc(show)) {
|
|
84
95
|
item.removeAttribute('aria-hidden');
|
|
85
96
|
item.querySelectorAll('a, button, select, input, textarea, [tabindex="-5"]').forEach(focusableElement => {
|
|
@@ -113,12 +124,15 @@ function ItemProvider(_ref) {
|
|
|
113
124
|
return computedValues.itemWidth;
|
|
114
125
|
}
|
|
115
126
|
const fallbackWidth = Math.floor(100 / showItems);
|
|
116
|
-
return
|
|
127
|
+
return "".concat(fallbackWidth, "%");
|
|
117
128
|
}, [computedValues.itemWidth, showItems]);
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
129
|
+
const _ref4 = (0, react_1.useState)({
|
|
130
|
+
drag: 0,
|
|
131
|
+
pointers: true
|
|
132
|
+
}),
|
|
133
|
+
_ref5 = (0, _slicedToArray2.default)(_ref4, 2),
|
|
134
|
+
drag = _ref5[0],
|
|
135
|
+
setDrag = _ref5[1];
|
|
122
136
|
const handleSwiping = eventData => {
|
|
123
137
|
setDrag({
|
|
124
138
|
drag: eventData.deltaX,
|
|
@@ -146,9 +160,7 @@ function ItemProvider(_ref) {
|
|
|
146
160
|
enabled: swipe,
|
|
147
161
|
availableDirections: ['Left', 'Right']
|
|
148
162
|
}),
|
|
149
|
-
|
|
150
|
-
ref
|
|
151
|
-
} = _a,
|
|
163
|
+
ref = _a.ref,
|
|
152
164
|
swipeProps = __rest(_a, ["ref"]);
|
|
153
165
|
return (0, jsx_runtime_1.jsx)("div", {
|
|
154
166
|
ref: containerRef,
|
|
@@ -163,8 +175,8 @@ function ItemProvider(_ref) {
|
|
|
163
175
|
className: styles_module_scss_1.default.itemTracker,
|
|
164
176
|
"data-test-id": testIds_1.TEST_IDS.trackLine,
|
|
165
177
|
style: {
|
|
166
|
-
transform:
|
|
167
|
-
transition:
|
|
178
|
+
transform: "translateX(".concat(transform + drag.drag, "px)"),
|
|
179
|
+
transition: "transform ".concat(transition, "s ease 0s")
|
|
168
180
|
},
|
|
169
181
|
ref: (0, merge_refs_1.default)(ref, itemsTrackerRef),
|
|
170
182
|
children: items.map((item, i) =>
|
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
.itemProvider{
|
|
2
2
|
--gap:var(--dimension-2m, 16px);
|
|
3
|
-
padding-top:var(--space-carousel-content-layout-padding, 4px);
|
|
4
|
-
padding-bottom:var(--space-carousel-content-layout-padding, 4px);
|
|
5
|
-
padding-left:var(--space-carousel-content-layout-padding, 4px);
|
|
6
|
-
padding-right:var(--space-carousel-content-layout-padding, 4px);
|
|
7
3
|
overflow-x:hidden;
|
|
8
4
|
width:100%;
|
|
9
|
-
margin:calc(0px - var(--space-carousel-content-layout-padding, 4px));
|
|
5
|
+
margin-block:calc(0px - var(--space-carousel-content-layout-padding, 4px));
|
|
6
|
+
padding-block:var(--space-carousel-content-layout-padding, 4px);
|
|
10
7
|
}
|
|
11
8
|
.itemProvider[data-swipe]{
|
|
12
9
|
cursor:grab;
|
|
@@ -22,6 +19,7 @@
|
|
|
22
19
|
.itemContainer{
|
|
23
20
|
flex-shrink:0;
|
|
24
21
|
box-sizing:border-box;
|
|
22
|
+
padding:var(--border-width-card-container, 1px);
|
|
25
23
|
}
|
|
26
24
|
|
|
27
25
|
.itemTracker{
|
|
@@ -10,35 +10,40 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
10
10
|
return t;
|
|
11
11
|
};
|
|
12
12
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
13
|
-
import debounce from 'lodash
|
|
13
|
+
import { debounce } from 'lodash';
|
|
14
14
|
import mergeRefs from 'merge-refs';
|
|
15
15
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
16
|
-
import { useSwipeable } from '@snack-uikit/utils';
|
|
16
|
+
import { useLayoutEffect, useSwipeable } from '@snack-uikit/utils';
|
|
17
17
|
import { TEST_IDS } from '../../testIds';
|
|
18
18
|
import styles from './styles.module.css';
|
|
19
|
+
function parseCssLength(value) {
|
|
20
|
+
const parsed = Number.parseFloat(value);
|
|
21
|
+
return Number.isFinite(parsed) ? parsed : 0;
|
|
22
|
+
}
|
|
19
23
|
export function ItemProvider({ items, showItems, scrollBy, slideCallback, transition, swipe, swipeActivateLength, page, gap, }) {
|
|
20
24
|
const containerRef = useRef(null);
|
|
25
|
+
const itemsTrackerRef = useRef(null);
|
|
21
26
|
const [computedValues, setComputedValues] = useState({
|
|
22
27
|
itemWidth: 0,
|
|
23
28
|
gap: 0,
|
|
24
29
|
});
|
|
25
30
|
const recalculateItemsSize = useCallback(() => {
|
|
26
31
|
const containerElement = containerRef.current;
|
|
27
|
-
|
|
32
|
+
const trackerElement = itemsTrackerRef.current;
|
|
33
|
+
if (!containerElement || !trackerElement) {
|
|
28
34
|
return;
|
|
29
35
|
}
|
|
30
|
-
const
|
|
31
|
-
const
|
|
32
|
-
const
|
|
33
|
-
const
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
useEffect(() => {
|
|
36
|
+
const containerStyles = getComputedStyle(containerElement);
|
|
37
|
+
const trackerStyles = getComputedStyle(trackerElement);
|
|
38
|
+
const gapValue = gap ? parseCssLength(gap) : parseCssLength(trackerStyles.columnGap || trackerStyles.gap);
|
|
39
|
+
const paddingLeft = parseCssLength(containerStyles.paddingLeft);
|
|
40
|
+
const paddingRight = parseCssLength(containerStyles.paddingRight);
|
|
41
|
+
const gapsCount = Math.max(Math.trunc(showItems) - 1, 0);
|
|
42
|
+
const contentWidth = containerElement.getBoundingClientRect().width - paddingLeft - paddingRight;
|
|
43
|
+
const itemWidth = (contentWidth - gapsCount * gapValue) / showItems;
|
|
44
|
+
setComputedValues({ itemWidth, gap: gapValue });
|
|
45
|
+
}, [showItems, gap]);
|
|
46
|
+
useLayoutEffect(() => {
|
|
42
47
|
const node = containerRef.current;
|
|
43
48
|
if (!node) {
|
|
44
49
|
return;
|
|
@@ -48,7 +53,6 @@ export function ItemProvider({ items, showItems, scrollBy, slideCallback, transi
|
|
|
48
53
|
observer.observe(node);
|
|
49
54
|
return () => observer.disconnect();
|
|
50
55
|
}, [recalculateItemsSize]);
|
|
51
|
-
const itemsTrackerRef = useRef(null);
|
|
52
56
|
const hideNonVisibleItems = () => {
|
|
53
57
|
var _a;
|
|
54
58
|
(_a = itemsTrackerRef.current) === null || _a === void 0 ? void 0 : _a.querySelectorAll(`[data-test-id=${TEST_IDS.trackItem}]`).forEach(slide => {
|
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
.itemProvider{
|
|
2
2
|
--gap:var(--dimension-2m, 16px);
|
|
3
|
-
padding-top:var(--space-carousel-content-layout-padding, 4px);
|
|
4
|
-
padding-bottom:var(--space-carousel-content-layout-padding, 4px);
|
|
5
|
-
padding-left:var(--space-carousel-content-layout-padding, 4px);
|
|
6
|
-
padding-right:var(--space-carousel-content-layout-padding, 4px);
|
|
7
3
|
overflow-x:hidden;
|
|
8
4
|
width:100%;
|
|
9
|
-
margin:calc(0px - var(--space-carousel-content-layout-padding, 4px));
|
|
5
|
+
margin-block:calc(0px - var(--space-carousel-content-layout-padding, 4px));
|
|
6
|
+
padding-block:var(--space-carousel-content-layout-padding, 4px);
|
|
10
7
|
}
|
|
11
8
|
.itemProvider[data-swipe]{
|
|
12
9
|
cursor:grab;
|
|
@@ -22,6 +19,7 @@
|
|
|
22
19
|
.itemContainer{
|
|
23
20
|
flex-shrink:0;
|
|
24
21
|
box-sizing:border-box;
|
|
22
|
+
padding:var(--border-width-card-container, 1px);
|
|
25
23
|
}
|
|
26
24
|
|
|
27
25
|
.itemTracker{
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
7
|
-
"version": "0.6.
|
|
7
|
+
"version": "0.6.14-preview-4e8bfebd.0",
|
|
8
8
|
"sideEffects": [
|
|
9
9
|
"*.css",
|
|
10
10
|
"*.woff",
|
|
@@ -36,13 +36,13 @@
|
|
|
36
36
|
"license": "Apache-2.0",
|
|
37
37
|
"scripts": {},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@snack-uikit/icons": "0.27.
|
|
40
|
-
"@snack-uikit/pagination": "0.10.
|
|
39
|
+
"@snack-uikit/icons": "0.27.8-preview-4e8bfebd.0",
|
|
40
|
+
"@snack-uikit/pagination": "0.10.27-preview-4e8bfebd.0",
|
|
41
41
|
"@snack-uikit/utils": "4.0.2",
|
|
42
42
|
"classnames": "2.5.1",
|
|
43
|
-
"lodash
|
|
43
|
+
"lodash": "4.18.1",
|
|
44
44
|
"merge-refs": "1.3.0",
|
|
45
45
|
"uncontrollable": "8.0.4"
|
|
46
46
|
},
|
|
47
|
-
"gitHead": "
|
|
47
|
+
"gitHead": "d52534cac02c3b621615686607bfba56762150ac"
|
|
48
48
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import debounce from 'lodash
|
|
1
|
+
import { debounce } from 'lodash';
|
|
2
2
|
import mergeRefs from 'merge-refs';
|
|
3
3
|
import { MouseEventHandler, ReactElement, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
4
4
|
|
|
5
|
-
import { SwipeCallback, useSwipeable } from '@snack-uikit/utils';
|
|
5
|
+
import { SwipeCallback, useLayoutEffect, useSwipeable } from '@snack-uikit/utils';
|
|
6
6
|
|
|
7
7
|
import { TEST_IDS } from '../../testIds';
|
|
8
8
|
import styles from './styles.module.scss';
|
|
@@ -19,6 +19,12 @@ export type ItemProviderProps = {
|
|
|
19
19
|
gap?: string;
|
|
20
20
|
};
|
|
21
21
|
|
|
22
|
+
function parseCssLength(value: string): number {
|
|
23
|
+
const parsed = Number.parseFloat(value);
|
|
24
|
+
|
|
25
|
+
return Number.isFinite(parsed) ? parsed : 0;
|
|
26
|
+
}
|
|
27
|
+
|
|
22
28
|
export function ItemProvider({
|
|
23
29
|
items,
|
|
24
30
|
showItems,
|
|
@@ -31,6 +37,7 @@ export function ItemProvider({
|
|
|
31
37
|
gap,
|
|
32
38
|
}: ItemProviderProps) {
|
|
33
39
|
const containerRef = useRef<HTMLDivElement>(null);
|
|
40
|
+
const itemsTrackerRef = useRef<HTMLDivElement>(null);
|
|
34
41
|
|
|
35
42
|
const [computedValues, setComputedValues] = useState({
|
|
36
43
|
itemWidth: 0,
|
|
@@ -39,27 +46,27 @@ export function ItemProvider({
|
|
|
39
46
|
|
|
40
47
|
const recalculateItemsSize = useCallback(() => {
|
|
41
48
|
const containerElement = containerRef.current;
|
|
49
|
+
const trackerElement = itemsTrackerRef.current;
|
|
42
50
|
|
|
43
|
-
if (!containerElement) {
|
|
51
|
+
if (!containerElement || !trackerElement) {
|
|
44
52
|
return;
|
|
45
53
|
}
|
|
46
54
|
|
|
47
|
-
const
|
|
55
|
+
const containerStyles = getComputedStyle(containerElement);
|
|
56
|
+
const trackerStyles = getComputedStyle(trackerElement);
|
|
48
57
|
|
|
49
|
-
const
|
|
50
|
-
const paddingLeft =
|
|
51
|
-
const paddingRight =
|
|
58
|
+
const gapValue = gap ? parseCssLength(gap) : parseCssLength(trackerStyles.columnGap || trackerStyles.gap);
|
|
59
|
+
const paddingLeft = parseCssLength(containerStyles.paddingLeft);
|
|
60
|
+
const paddingRight = parseCssLength(containerStyles.paddingRight);
|
|
52
61
|
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
paddingLeft -
|
|
57
|
-
paddingRight) /
|
|
58
|
-
showItems;
|
|
59
|
-
setComputedValues({ itemWidth, gap });
|
|
60
|
-
}, [showItems]);
|
|
62
|
+
const gapsCount = Math.max(Math.trunc(showItems) - 1, 0);
|
|
63
|
+
const contentWidth = containerElement.getBoundingClientRect().width - paddingLeft - paddingRight;
|
|
64
|
+
const itemWidth = (contentWidth - gapsCount * gapValue) / showItems;
|
|
61
65
|
|
|
62
|
-
|
|
66
|
+
setComputedValues({ itemWidth, gap: gapValue });
|
|
67
|
+
}, [showItems, gap]);
|
|
68
|
+
|
|
69
|
+
useLayoutEffect(() => {
|
|
63
70
|
const node = containerRef.current;
|
|
64
71
|
|
|
65
72
|
if (!node) {
|
|
@@ -73,8 +80,6 @@ export function ItemProvider({
|
|
|
73
80
|
return () => observer.disconnect();
|
|
74
81
|
}, [recalculateItemsSize]);
|
|
75
82
|
|
|
76
|
-
const itemsTrackerRef = useRef<HTMLDivElement>(null);
|
|
77
|
-
|
|
78
83
|
const hideNonVisibleItems = () => {
|
|
79
84
|
itemsTrackerRef.current?.querySelectorAll(`[data-test-id=${TEST_IDS.trackItem}]`).forEach(slide => {
|
|
80
85
|
slide.setAttribute('aria-hidden', '0');
|
|
@@ -3,11 +3,14 @@
|
|
|
3
3
|
.itemProvider {
|
|
4
4
|
--gap: #{styles-tokens-carousel.$dimension-2m};
|
|
5
5
|
|
|
6
|
-
@include styles-tokens-carousel.composite-var(styles-tokens-carousel.$carousel-content-layout);
|
|
7
|
-
|
|
8
6
|
overflow-x: hidden;
|
|
9
7
|
width: 100%;
|
|
10
|
-
margin: calc(0px - styles-tokens-carousel.$space-carousel-content-layout-padding);
|
|
8
|
+
margin-block: calc(0px - #{styles-tokens-carousel.$space-carousel-content-layout-padding});
|
|
9
|
+
|
|
10
|
+
// Only block padding: inline padding created a gutter where the next item
|
|
11
|
+
// (and its outline) painted through when gap < padding. Card outline is
|
|
12
|
+
// contained by .itemContainer padding instead.
|
|
13
|
+
padding-block: styles-tokens-carousel.$space-carousel-content-layout-padding;
|
|
11
14
|
|
|
12
15
|
&[data-swipe] {
|
|
13
16
|
cursor: grab;
|
|
@@ -24,6 +27,9 @@
|
|
|
24
27
|
.itemContainer {
|
|
25
28
|
flex-shrink: 0;
|
|
26
29
|
box-sizing: border-box;
|
|
30
|
+
// Reserve space inside the slide for card outline/border so it is not clipped
|
|
31
|
+
// by overflow and does not paint into a shared gutter with the next slide.
|
|
32
|
+
padding: styles-tokens-carousel.$border-width-card-container;
|
|
27
33
|
}
|
|
28
34
|
|
|
29
35
|
.itemTracker {
|