@skyscanner/backpack-web 38.1.0 → 38.1.1
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/bpk-component-card-list/src/BpkCardListRowRail/BpkCardListCarousel.js +22 -3
- package/bpk-component-card-list/src/BpkCardListRowRail/BpkCardListCarousel.module.css +1 -1
- package/bpk-component-card-list/src/BpkCardListRowRail/BpkCardListRowRailContainer.js +1 -0
- package/bpk-component-card-list/src/common-types.d.ts +2 -1
- package/package.json +1 -1
|
@@ -24,6 +24,7 @@ import { lockScroll, setA11yTabIndex, useScrollToCard, useIntersectionObserver }
|
|
|
24
24
|
import STYLES from "./BpkCardListCarousel.module.css";
|
|
25
25
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
26
26
|
const getClassName = cssModules(STYLES);
|
|
27
|
+
const PAGINATION_INDICATOR_MAX_SHOWN_COUNT = 5;
|
|
27
28
|
const BpkCardListCarousel = props => {
|
|
28
29
|
const {
|
|
29
30
|
carouselLabel = (initiallyShownCards, childrenLength) => `Entering Carousel with ${initiallyShownCards} slides shown at a time, ${childrenLength} slides in total. Please use Pagination below with the Previous and Next buttons to navigate, or the slide dot buttons at the end to jump to slides.`,
|
|
@@ -32,6 +33,7 @@ const BpkCardListCarousel = props => {
|
|
|
32
33
|
initiallyShownCards,
|
|
33
34
|
isMobile = false,
|
|
34
35
|
layout,
|
|
36
|
+
setCurrentIndex,
|
|
35
37
|
slideLabel = (index, childrenLength) => `slide ${index + 1} of ${childrenLength}`
|
|
36
38
|
} = props;
|
|
37
39
|
const shownNumberStyle = {
|
|
@@ -56,7 +58,15 @@ const BpkCardListCarousel = props => {
|
|
|
56
58
|
// Similar to Virtual Scrolling to improve performance
|
|
57
59
|
const firstVisibleIndex = Math.max(0, visibilityList.indexOf(1));
|
|
58
60
|
const lastVisibleIndex = firstVisibleIndex + initiallyShownCards - 1;
|
|
59
|
-
const
|
|
61
|
+
const dynamicRenderBufferSize = useMemo(() => {
|
|
62
|
+
if (childrenLength === 0 || initiallyShownCards === 0 || isMobile) return RENDER_BUFFER_SIZE;
|
|
63
|
+
|
|
64
|
+
// Calculate how many cards to render based on the number of initially shown cards and total children
|
|
65
|
+
const totalPages = Math.ceil(childrenLength / initiallyShownCards);
|
|
66
|
+
const shownIndicatorCount = Math.min(totalPages, PAGINATION_INDICATOR_MAX_SHOWN_COUNT);
|
|
67
|
+
return Math.max(RENDER_BUFFER_SIZE, (shownIndicatorCount - 1) * initiallyShownCards);
|
|
68
|
+
}, [childrenLength, initiallyShownCards, isMobile]);
|
|
69
|
+
const renderList = useMemo(() => visibilityList.map((_, index) => index >= firstVisibleIndex - dynamicRenderBufferSize && index <= lastVisibleIndex + dynamicRenderBufferSize ? 1 : 0), [visibilityList, firstVisibleIndex, lastVisibleIndex, dynamicRenderBufferSize]);
|
|
60
70
|
const cardRefFns = useMemo(() => Array(childrenLength).fill(null).map((_, i) => el => {
|
|
61
71
|
cardRefs.current[i] = el;
|
|
62
72
|
observerVisibility(el, i);
|
|
@@ -91,11 +101,20 @@ const BpkCardListCarousel = props => {
|
|
|
91
101
|
useEffect(() => {
|
|
92
102
|
// update hasBeenVisibleRef to include the range of cards that should be visible
|
|
93
103
|
const start = currentIndex * initiallyShownCards;
|
|
94
|
-
const end = start + initiallyShownCards +
|
|
104
|
+
const end = start + initiallyShownCards + dynamicRenderBufferSize;
|
|
95
105
|
for (let i = start; i < end && i < childrenLength; i += 1) {
|
|
96
106
|
hasBeenVisibleRef.current.add(i);
|
|
97
107
|
}
|
|
98
|
-
}, [currentIndex, initiallyShownCards, childrenLength]);
|
|
108
|
+
}, [currentIndex, initiallyShownCards, childrenLength, dynamicRenderBufferSize]);
|
|
109
|
+
useEffect(() => {
|
|
110
|
+
const firstVisible = visibilityList.indexOf(1);
|
|
111
|
+
if (firstVisible >= 0) {
|
|
112
|
+
const newIndex = Math.floor(firstVisible / initiallyShownCards);
|
|
113
|
+
if (newIndex !== currentIndex) {
|
|
114
|
+
setCurrentIndex(newIndex);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}, [initiallyShownCards]);
|
|
99
118
|
useEffect(() => {
|
|
100
119
|
const handleResize = throttle(() => {
|
|
101
120
|
firstCardWidthRef.current = null;
|
|
@@ -15,4 +15,4 @@
|
|
|
15
15
|
* See the License for the specific language governing permissions and
|
|
16
16
|
* limitations under the License.
|
|
17
17
|
*/
|
|
18
|
-
.bpk-card-list-row-rail__row,.bpk-card-list-row-rail__rail{display:flex;padding-top:.25rem;padding-bottom
|
|
18
|
+
.bpk-card-list-row-rail__row,.bpk-card-list-row-rail__rail{display:flex;padding-top:.25rem;padding-bottom:1.5rem;overflow-x:hidden;box-sizing:border-box;gap:.25rem;scroll-snap-stop:always;scroll-snap-type:x mandatory;scrollbar-width:none}@media(max-width: 32rem){.bpk-card-list-row-rail__row,.bpk-card-list-row-rail__rail{padding-bottom:1rem;overflow-x:scroll}}.bpk-card-list-row-rail__row::-webkit-scrollbar,.bpk-card-list-row-rail__rail::-webkit-scrollbar{display:none}.bpk-card-list-row-rail__row__card,.bpk-card-list-row-rail__rail__card{position:relative;padding:0 .5rem;flex:0 0 calc((100% - .5rem*(var(--initially-shown-cards, 3) - 1))/var(--initially-shown-cards, 3));overflow:visible;box-sizing:border-box;scroll-snap-align:start}@media(max-width: 32rem){.bpk-card-list-row-rail__row__card,.bpk-card-list-row-rail__rail__card{flex:0 0 calc((100% - .5rem*(var(--initially-shown-cards, 3) - 1))/max(1,var(--initially-shown-cards, 3) - .8))}.bpk-card-list-row-rail__row__card:first-child,.bpk-card-list-row-rail__rail__card:first-child{padding-left:.25rem}html[dir=rtl] .bpk-card-list-row-rail__row__card:first-child,html[dir=rtl] .bpk-card-list-row-rail__rail__card:first-child{padding-right:.25rem;padding-left:.5rem}}.bpk-card-list-row-rail__rail{-webkit-overflow-scrolling:touch}
|
|
@@ -51,6 +51,7 @@ const BpkCardListRowRailContainer = props => {
|
|
|
51
51
|
children: [/*#__PURE__*/_jsx(BpkCardListCarousel, {
|
|
52
52
|
initiallyShownCards: initiallyShownCards,
|
|
53
53
|
layout: layout,
|
|
54
|
+
setCurrentIndex: setCurrentIndex,
|
|
54
55
|
currentIndex: currentIndex,
|
|
55
56
|
isMobile: isMobile,
|
|
56
57
|
carouselLabel: accessibilityLabels?.carouselLabel,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ReactElement } from 'react';
|
|
1
|
+
import type { ReactElement, Dispatch, SetStateAction } from 'react';
|
|
2
2
|
declare const LAYOUTS: {
|
|
3
3
|
readonly grid: "grid";
|
|
4
4
|
readonly stack: "stack";
|
|
@@ -70,6 +70,7 @@ type CardListCarouselProps = {
|
|
|
70
70
|
initiallyShownCards: number;
|
|
71
71
|
layout: typeof LAYOUTS.row | typeof LAYOUTS.rail;
|
|
72
72
|
currentIndex: number;
|
|
73
|
+
setCurrentIndex: Dispatch<SetStateAction<number>>;
|
|
73
74
|
isMobile?: boolean;
|
|
74
75
|
carouselLabel?: (initiallyShownCards: number, childrenLength: number) => string;
|
|
75
76
|
slideLabel?: (index: number, childrenLength: number) => string;
|