@kubit-ui-web/react-components
Version:
Kubit React Components is a customizable, accessible library of React web components, designed to enhance your application's user experience
149 lines • 7.18 kB
JavaScript
import { CAROUSEL_BUILD_SCREEN_READER_CURRENT_PAGE_KEY, CAROUSEL_BUILD_SCREEN_READER_NUM_PAGES_KEY, } from '../types/carousel';
export const calcXDistanceBetween2Elements = (el1, el2) => {
if (!el1 || !el2) {
return 0;
}
const x0 = el1.offsetLeft;
const x1 = el2.offsetLeft;
return Math.abs(x1 - x0);
};
export const adjustNumElementsToSlide = ({ numElementsPerPage, numElementsToSlide, }) => {
if (!numElementsToSlide) {
return numElementsPerPage;
}
return Math.max(1, Math.min(numElementsToSlide, numElementsPerPage));
};
export const calcNumPages = ({ elementsLength, numElementsPerPage, numElementsToSlide, }) => {
if (elementsLength <= numElementsPerPage) {
return 1;
}
const _numElementsToSlide = adjustNumElementsToSlide({ numElementsToSlide, numElementsPerPage });
const numPages = Math.ceil((elementsLength - numElementsPerPage + _numElementsToSlide) / _numElementsToSlide);
return numPages;
};
export const getFirstAndLastIndexInCarouselView = ({ elementsLength, numElementsPerPage, numElementsToSlide, currentPage, isCircular, }) => {
// When there less elements than numElementsPerPage, return the first and last element index
if (elementsLength <= numElementsPerPage) {
return { firstIndexInView: 0, lastIndexInView: elementsLength - 1 };
}
const _numElementsToSlide = adjustNumElementsToSlide({ numElementsToSlide, numElementsPerPage });
const numPages = calcNumPages({
elementsLength,
numElementsPerPage,
numElementsToSlide: _numElementsToSlide,
});
// Calc last index in the carousel view
let lastIndexInView = currentPage * _numElementsToSlide + numElementsPerPage - 1;
// If isCircular, and we have more than one page, we added elements to the left and right of the carousel to avoid empty spaces
const _isCircular = isCircular && elementsLength > numElementsPerPage;
let numElementsCloned = 0;
// Add extra items previously cloned when circular
if (_isCircular) {
numElementsCloned = numElementsPerPage + 1;
lastIndexInView += numElementsCloned;
}
// Fix last index
if (currentPage === numPages) {
// currentPage === numPages -> Only happens when it is circular
// When overpass last page, go to the first page, taking in mind that the first page has been added to the right of the carousel cloning some elements
// Elements have been cloned at the left and right of the initial elements
lastIndexInView = numElementsCloned + elementsLength + numElementsPerPage - 1;
}
else if (currentPage < 0) {
// When page is less than 0, go to the last page, taking in mind that the last page has been added to the left of the carousel cloning some elements
lastIndexInView = numElementsCloned - 1;
}
else if (lastIndexInView - numElementsCloned > elementsLength - 1) {
// The calculated last index is greather than the number of available index
// At the moment we are not going to let the carousel take this shape. Ex: [8, 9, 0]
// This would break the pagination
lastIndexInView = numElementsCloned + elementsLength - 1;
}
// Calc first index using the lastIndexInView
const firstIndexInView = lastIndexInView - numElementsPerPage + 1;
return { firstIndexInView, lastIndexInView };
};
export const calcNumElementsPerPage = ({ carouselContainer, carouselContent, elementsLength, extraPadding, }) => {
const carouselRoot = carouselContainer.parentElement?.parentElement;
const firstElementChild = carouselContent.firstElementChild;
if (!firstElementChild || !carouselRoot) {
return;
}
// Max width
let maxWidth = carouselRoot.offsetWidth;
// Max width less extra padding for each size
if (extraPadding) {
maxWidth -= 2 * extraPadding;
}
// Max width less left arrow (and gap) width
const leftArrow = carouselContainer.previousElementSibling;
if (leftArrow) {
const leftArrowWidth = carouselContainer.getBoundingClientRect().left - leftArrow.getBoundingClientRect().left;
maxWidth -= leftArrowWidth;
}
// Max width less right arrow (and gap) width
const rightArrow = carouselContainer.nextElementSibling;
if (rightArrow) {
const rightArrowWidth = rightArrow.getBoundingClientRect().right - carouselContainer.getBoundingClientRect().right;
maxWidth -= rightArrowWidth;
}
// Calc numElementsPerPage
let _numElementsPerPage = 0;
const offsetLeftFirstChild = firstElementChild.offsetLeft;
for (let i = 0; i < carouselContent.children.length; i++) {
const element = carouselContent.children[i];
if (offsetLeftFirstChild + element.offsetLeft + element.offsetWidth > maxWidth) {
break;
}
_numElementsPerPage++;
}
return Math.max(Math.min(elementsLength, _numElementsPerPage), 1);
};
export const showArrowsAndPagination = ({ carouselContainer, carouselContent, }) => {
const rootCarousel = carouselContainer.parentElement?.parentElement;
const leftArrow = carouselContainer.previousElementSibling;
const rightArrow = carouselContainer.nextElementSibling;
const pagination = carouselContainer.parentElement?.nextSibling;
rootCarousel?.style.removeProperty('align-items');
carouselContent?.style.removeProperty('justify-content');
leftArrow?.style.removeProperty('display');
rightArrow?.style.removeProperty('display');
pagination?.style.removeProperty('display');
};
export const hideArrowsAndPagination = ({ carouselContainer, carouselContent, onePageAlign, allowModifySliceWidth, }) => {
const leftArrow = carouselContainer.previousElementSibling;
const rightArrow = carouselContainer.nextElementSibling;
const pagination = carouselContainer.parentElement?.nextSibling;
// Set items align
if (allowModifySliceWidth) {
// When allowModifySliceWidth, container width will be set to 100%, and the align should be over the content
carouselContent.style.justifyContent = onePageAlign;
}
else {
// When !allowModifySliceWidth, align should be over the root
const rootCarousel = carouselContainer.parentElement?.parentElement;
if (rootCarousel) {
rootCarousel.style.alignItems = onePageAlign;
}
}
if (leftArrow) {
leftArrow.style.display = 'none';
}
if (rightArrow) {
rightArrow.style.display = 'none';
}
if (pagination) {
pagination.style.display = 'none';
}
};
export const buildScreenReaderText = (currentPage, numPages, screenReaderContentPosition) => {
if (!screenReaderContentPosition) {
return screenReaderContentPosition;
}
const currentPageRegExp = new RegExp(CAROUSEL_BUILD_SCREEN_READER_CURRENT_PAGE_KEY, 'g');
const numPagesRegExp = new RegExp(CAROUSEL_BUILD_SCREEN_READER_NUM_PAGES_KEY, 'g');
return screenReaderContentPosition
.replace(currentPageRegExp, String(currentPage + 1))
.replace(numPagesRegExp, String(numPages));
};
//# sourceMappingURL=carousel.utils.js.map