lumecss
Version:
LumeCss is a modern, lightweight, and flexible CSS library designed for building fast and responsive user interfaces. Built with SCSS and TypeScript, LumeCss provides utility-first classes, customizable themes, and reusable components to speed up your dev
985 lines (764 loc) • 36.5 kB
text/typescript
// Get an array of carousel objects
const carouselArray: HTMLElement[] = Array.from(document.querySelectorAll('.carousel'));
// Declare the startPosition and endPosition variables used for the touch-enabled carousel
let startPosition: number = 0;
let endPosition: number = 0;
// Iterate of each carousel in the carouselArray
carouselArray.forEach((carousel: HTMLElement): void => {
// Get an array of the carousel items
const carouselItemsArray: HTMLElement[] = Array.from(document.querySelectorAll('.carousel-item'));
/* Define the isFadeCarousel variable, which can be either true or false,
and specifies whether the carousel uses a fade effect */
const isFadeCarousel: boolean = carousel.classList.contains('carousel-fade');
// Make sure the carouselItemsArray is not empty
if (carouselItemsArray.length < 1) return;
// Call the setDefaultPosition function
setDefaultPosition(carouselItemsArray);
// Call the addIndicatorButtons function
addIndicatorButtons(carousel, carouselItemsArray);
// Call the loadCarouselItemImage function
loadCarouselItemImage(carouselItemsArray);
if (!isFadeCarousel) {
// Call the moveCarouselToDefaultPosition function if the carousel is not fade-carousel
moveCarouselToDefaultPosition(carousel, carouselItemsArray);
}
// Add event listeners to the carousel navigation buttons
addEventListenersToNavigationButtons(carousel, carouselItemsArray, isFadeCarousel);
});
function addIndicatorButtons(
carousel: HTMLElement,
carouselItemsArray: HTMLElement[]
): void {
/* The function is responsible for adding indicator buttons to
* the carousel indicator wrapper if the indicator wrapper exists.
*
* Attributes:
* - carousel: The carousel HTML object which is used to get carousel indicators wrapper
* - carouselItemsArray: An array of the carousel item objects
* */
// Define the defaultSlideIsSpecified variable
let defaultSlideIsSpecified: boolean = false;
// Get the carousel indicators wrapper or null if it does not exist
const indicatorsWrapper: HTMLElement | null = carousel.querySelector('.carousel-indicators');
// Make sure the indicatorsWrapper exists (is not null)
if (!indicatorsWrapper) return;
// Iterate over each item in the carouselItemsArray
carouselItemsArray.forEach((item: HTMLElement, index: number): void => {
// Create the indicator button object
const indicatorBtn: HTMLSpanElement = document.createElement("span");
// Add the 'carousel-indicator' class to the indicatorBtn
indicatorBtn.classList.add('carousel-indicator');
// Add the 'data-carousel-slide-index' attribute to the indicatorBtn
indicatorBtn.setAttribute('data-carousel-slide-index', `${index}`);
// Add the 'active' class to the indicatorBtn if the item object contains the 'active' class
if (item.classList.contains('active') && !defaultSlideIsSpecified) {
indicatorBtn.classList.add('active');
defaultSlideIsSpecified = true;
}
// Append the indicatorBtn into the indicatorsWrapper
indicatorsWrapper.appendChild(indicatorBtn);
});
}
function loadCarouselItemImage(carouselItemsArray: HTMLElement[]): void {
/* The function iterates over each carousel item in the carouselItemsArray, looks
* for the .carousel-img tag, and if it exists, it takes the image src link and adds it
* as a background-image style to the carousel item using the found src.
*
* Attributes:
* - carouselItemsArray: An array of the carousel item objects
* */
// Iterate over each item in the carouselItemsArray
carouselItemsArray.forEach((item: HTMLElement): void => {
// Retrieve the .carousel-img or null if it does not exist
const carouselItemImage: HTMLImageElement | null = item.querySelector('.carousel-img');
// Make sure the carouselItemImage exists (is not null)
if (!carouselItemImage) return;
// Retrieve the image src or null if it is not provided
const src: string | null = carouselItemImage.getAttribute('src') ? carouselItemImage.getAttribute('src') : null;
// Make sure the image's src is not null
if (!src) return;
// Update the carousel item background-image CSS property
item.style.backgroundImage = `url(${src})`;
});
}
function moveCarouselToDefaultPosition(
carousel: HTMLElement,
carouselItemsArray: HTMLElement[]
): void {
/* The function is responsible for moving the carousel to its initial
* position when the web page is loaded.
*
* Attributes:
* - carousel: The carousel HTML object is used to get the carousel inner element
* - carouselItemsArray: An array of the carousel item objects
* */
// Retrieve the carousel inner HTML object or null if it does not exist
const carouselInner: HTMLElement | null = carousel.querySelector('.carousel-inner');
// Make sure the carouselInner exists (is not null)
if (!carouselInner) return;
// Iterate over each item in the carouselItemsArray
for (let index: number = 0; index < carouselItemsArray.length; index++) {
const item: HTMLElement = carouselItemsArray[index];
// Check if the item contains the 'active' class
if (item.classList.contains('active')) {
// Get the computed style of the element
let style: CSSStyleDeclaration = window.getComputedStyle(carouselInner);
// Retrieve the transition property value
let transition: string = style.transition;
// Disable the carouselInner transition property for a while
carouselInner.style.transition = 'none';
// Update the carousel inner position
carouselInner.style.left = `-${index * 100}%`;
// Enable the carouselInner transition property after a while
setTimeout((): void => {
carouselInner.style.transition = transition
}, 100);
// End the function execution
return;
}
}
};
function setDefaultPosition(carouselItemsArray: HTMLElement[]): void {
/* The function is responsible for setting the default active slide if it
* is not specified by the user.
*
* Attributes:
* - carouselItemsArray: An array of the carousel item objects
* */
// Define the defaultSlideIsSpecified variable
let defaultSlideIsSpecified: boolean = false;
// Iterate over each item in the carouselItemsArray
carouselItemsArray.forEach((item: HTMLElement, index: number): void => {
// Check if the item contains the 'active' class
if (item.classList.contains('active')) defaultSlideIsSpecified = true;
});
// Make sure the defaultSlideIsSpecified is not true
if (defaultSlideIsSpecified) return;
// Make the first item default by adding the 'active' class
carouselItemsArray[0].classList.add('active');
}
function updateCarouselCurrentIndex(
carouselItemsArray: HTMLElement[],
carouselDirection: 'forward' | 'backward' | null,
newIndex: number | null
): { previousIndex: number | null, currentIndex: number | null } {
/* The function is responsible for updating the carousel's current index
* and returns the previousIndex and currentIndex.
*
* Attributes:
* - carouselItemsArray: An array of the carousel item objects
* - carouselDirection: It indicates whether the currentIndex should
* be increased or decreased by one
* - newIndex: The new current position
* */
// Define the currentIndex, and previousIndex variable
let currentIndex: number | null = null;
let previousIndex: number | null = null;
// Define the numberOfCarouselItems variable
const numberOfCarouselItems: number = carouselItemsArray.length;
// Make sure the numberOfCarouselItems is grater than 0
if (numberOfCarouselItems <= 0) return { previousIndex: null, currentIndex: null };
// Iterate over each item in the carouselItemsArray
for (let index: number = 0; index < carouselItemsArray.length; index++) {
// Check if the carousel item contains the 'active' class
if (carouselItemsArray[index].classList.contains('active')) {
// Update the current index
currentIndex = index;
break; // End the loop execution
}
}
// Make sure the currentIndex is not null
if (currentIndex === null) return { previousIndex: null, currentIndex: null };
// Check if the carouselDirection is specified
if (carouselDirection) {
// Check the state of the carouselDirection
if (carouselDirection === 'forward') {
// Make sure the currentIndex is lower than the numberOfCarouselItems
if (currentIndex + 1 >= numberOfCarouselItems) {
previousIndex = currentIndex; // Specify the previous index
currentIndex = 0; // Reset the currentIndex
} else {
previousIndex = currentIndex; // Specify the previous index
currentIndex++; // Update the currentIndex
}
} else if (carouselDirection === 'backward') {
// Make sure the currentIndex is greater than or equal to 0
if (currentIndex <= 0) {
previousIndex = currentIndex; // Specify the previous index
currentIndex = numberOfCarouselItems - 1; // Update the currentIndex
} else {
previousIndex = currentIndex; // Specify the previous index
currentIndex--; // Update the currentIndex
}
}
// End the function execution
return { previousIndex, currentIndex };
}
// Check if the newIndex is provided
if (newIndex != null) {
previousIndex = currentIndex; // Specify the previous index
currentIndex = newIndex; // Update the currentIndex
// End the function execution
return { previousIndex, currentIndex };
}
return { previousIndex: null, currentIndex: null };
}
function addEventListenersToNavigationButtons(
carousel: HTMLElement,
carouselItemsArray: HTMLElement[],
isFadeCarousel: boolean
): void {
/* The function adds event listeners to the carousel navigation buttons.
*
* Attributes:
* - carousel: The main carousel wrapper
* - carouselItemsArray: An array of the carousel item objects
* - isFadeCarousel: it specifies whether the carousel uses a fade effect
* */
/* Define the carouselIsMoving variable; it is used to prevent the user
from spamming the carousel navigation buttons.*/
let carouselIsMoving: boolean = false;
// Define the carousel previousIndex and nextIndex variables
let previousIndex: number | null = null;
let nextIndex: number | null = null;
// Retrieve the carousel carousel-control-prev button or null if it does not exist
const prevButton: HTMLElement | null = carousel.querySelector('.carousel-control-prev');
// Retrieve the carousel carousel-control-next button or null if it does not exist
const nextButton: HTMLElement | null = carousel.querySelector('.carousel-control-next');
// Retrieve an array of the carousel indicator buttons
const indicatorButtonsArray: HTMLElement[] = Array.from(carousel.querySelectorAll('.carousel-indicator'));
const updateCarouselIsMoving: () => void = (): void => {
// Assign true to the carouselIsMoving variable if the carousel does not use a fade effect
if (!isFadeCarousel) {
carouselIsMoving = true;
// Assign false to the carouselIsMoving after 500 milliseconds
setTimeout((): void => {carouselIsMoving = false}, 500);
}
}
// Add an array listener to the prevButton if it exists (is not null)
if (prevButton) {
prevButton.addEventListener('click', (event: MouseEvent): void => {
event.preventDefault();
// Make sure the carouselIsMoving variable is false
if (carouselIsMoving) return;
// Call the updateCarouselCurrentIndex function
const { previousIndex: prev, currentIndex: next } = updateCarouselCurrentIndex(
carouselItemsArray, 'backward', null
);
// Retrieve the carousel previousIndex and nextIndex
previousIndex = prev;
nextIndex = next;
// Make sure the previousIndex and nextIndex are not null
if (previousIndex != null && nextIndex != null) {
manageCarouselMovement(carousel, carouselItemsArray, previousIndex, nextIndex, 'backward');
}
// Call the updateCarouselIsMoving function
updateCarouselIsMoving();
});
}
// Add an array listener to the nextButton if it exists (is not null)
if (nextButton) {
nextButton.addEventListener('click', (event: MouseEvent): void => {
event.preventDefault();
// Make sure the carouselIsMoving variable is false
if (carouselIsMoving) return;
// Call the updateCarouselCurrentIndex function
const { previousIndex: prev, currentIndex: next } = updateCarouselCurrentIndex(
carouselItemsArray, 'forward', null
);
// Retrieve the carousel previousIndex and nextIndex
previousIndex = prev;
nextIndex = next;
// Make sure the previousIndex and nextIndex are not null
if (previousIndex != null && nextIndex != null) {
manageCarouselMovement(carousel, carouselItemsArray, previousIndex, nextIndex, 'forward');
}
// Call the updateCarouselIsMoving function
updateCarouselIsMoving();
});
}
// Add event listeners to the indicator buttons if the indicatorButtonsArray is not empty
if (indicatorButtonsArray.length > 0) {
// Iterate over each item in the indicatorButtonsArray
indicatorButtonsArray.forEach((item: HTMLElement, index: number): void => {
item.addEventListener('click', (event: MouseEvent): void => {
event.preventDefault();
// Make sure the carouselIsMoving variable is false
if (carouselIsMoving) return;
// Call the updateCarouselCurrentIndex function
const { previousIndex: prev, currentIndex: next } = updateCarouselCurrentIndex(
carouselItemsArray, null, index
);
// Retrieve the carousel previousIndex and nextIndex
previousIndex = prev;
nextIndex = next;
// Make sure the previousIndex and nextIndex are not null
if (previousIndex != null && nextIndex != null) {
manageCarouselMovement(
carousel,
carouselItemsArray,
previousIndex,
nextIndex,
getCarouselMovementDirection(previousIndex, nextIndex)
);
}
// Call the updateCarouselIsMoving function
updateCarouselIsMoving();
});
});
}
// Handle the movement of the touch-enabled carousel
carousel.addEventListener('touchstart', (event: TouchEvent): void => {
event.preventDefault();
// Make sure the carouselIsMoving variable is false
if (carouselIsMoving) return;
// Store the horizontal position where the touch started
const touch: Touch = event.touches[0];
startPosition = touch.clientX;
});
carousel.addEventListener('touchend', (event: TouchEvent): void => {
event.preventDefault();
// Make sure the carouselIsMoving variable is false
if (carouselIsMoving) return;
// Store the horizontal position where the touch started
const touch: Touch = event.changedTouches[0];
endPosition = touch.clientX;
// Define the swipeDirection variable
const swipeDirection: 'forward' | 'backward' | null = calculateTouchDirection(
carousel.offsetWidth/3,
startPosition,
endPosition
);
// Make sure the swipeDirection is not null
if (!swipeDirection) return;
// Call the updateCarouselCurrentIndex function
const { previousIndex: prev, currentIndex: next } = updateCarouselCurrentIndex(
carouselItemsArray, swipeDirection, null
);
// Retrieve the carousel previousIndex and nextIndex
previousIndex = prev;
nextIndex = next;
// Fire the handleCarouselMovement function
manageCarouselMovement(
carousel,
carouselItemsArray,
previousIndex,
nextIndex,
swipeDirection,
);
});
// Handle the movement of the mouse-enabled carousel
carousel.addEventListener('mousedown', (event: MouseEvent): void => {
event.preventDefault();
// Make sure the carouselIsMoving variable is false
if (carouselIsMoving) return;
// Store the horizontal position where the mouse click started
startPosition = event.clientX;
const onMouseUp: (event: MouseEvent) => void = (event: MouseEvent): void => {
// Store the horizontal position where the mouse was released
endPosition = event.clientX;
// Define the swipeDirection variable
const swipeDirection: 'forward' | 'backward' | null = calculateTouchDirection(
carousel.offsetWidth/3,
startPosition,
endPosition
);
// Make sure the swipeDirection is not null
if (!swipeDirection) return;
// Call the updateCarouselCurrentIndex function
const { previousIndex: prev, currentIndex: next } = updateCarouselCurrentIndex(
carouselItemsArray, swipeDirection, null
);
// Retrieve the carousel previousIndex and nextIndex
previousIndex = prev;
nextIndex = next;
// Fire the handleCarouselMovement function
manageCarouselMovement(
carousel,
carouselItemsArray,
previousIndex,
nextIndex,
swipeDirection,
);
// Remove the mouseup listener
document.removeEventListener('mouseup', onMouseUp);
};
// Attach mouseup event to the document
document.addEventListener('mouseup', onMouseUp);
});
// Retrieve the 'data-carousel-move-interval' attribute value from the carousel element, or return null if it doesn't exist
const carouselMoveInterval: number | null = carousel.hasAttribute('data-carousel-move-interval')
? parseInt(carousel.getAttribute('data-carousel-move-interval')!)
: null;
// Check if the carouselMoveInterval exists (is not null)
if (carouselMoveInterval != null) {
/* Define the isHovering variable, which indicates whether the
user's cursor is hovering over the carousel container. */
let isHovering: boolean = false;
setInterval((): void => {
// Make sure the carouselIsMoving and isHovering variables are false
if (carouselIsMoving || isHovering) return;
// Call the updateCarouselCurrentIndex function
const { previousIndex: prev, currentIndex: next } = updateCarouselCurrentIndex(
carouselItemsArray, 'forward', null
);
// Retrieve the carousel previousIndex and nextIndex
previousIndex = prev;
nextIndex = next;
// Make sure the previousIndex and nextIndex are not null
if (previousIndex != null && nextIndex != null) {
manageCarouselMovement(carousel, carouselItemsArray, previousIndex, nextIndex, 'forward');
}
// Call the updateCarouselIsMoving function
updateCarouselIsMoving();
}, carouselMoveInterval);
// Clear the carouselMovingInterval if the user hovers over the carousel or touch it.
carousel.addEventListener('mouseenter', (event: MouseEvent): void => {
// Assign true to the isHovering variable
isHovering = true;
});
carousel.addEventListener('touchstart', (event: TouchEvent): void => {
// Assign true to the isHovering variable
isHovering = true;
});
// Restore the carouselMovingInterval if the user's cursor leaves the carousel block or untouch it
carousel.addEventListener('mouseleave', (event: MouseEvent): void => {
// Assign false to the isHovering varialble after carouselMoveInterval milliseconds
setTimeout((): void => {
isHovering = false;
}, carouselMoveInterval);
});
carousel.addEventListener('touchend', (event: TouchEvent): void => {
// Assign false to the isHovering variable after carouselMoveInterval milliseconds
setTimeout((): void => {
isHovering = false;
}, carouselMoveInterval);
});
}
}
function manageCarouselMovement(
carousel: HTMLElement,
carouselItemsArray: HTMLElement[],
previousIndex: number | null,
nextIndex: number | null,
carouselMovementDirection: 'forward' | 'backward'
): void {
/* The function manages the carousel movement based on the provided
* attributes of the HTML tags.
*
* Attributes:
* - carousel: The carousel HTML object is used to get carousel attributes
* - carouselItemsArray: An array of the carousel items
* - previousIndex: Previous carousel's items position
* - nextIndex: Next carousel's items position
* - carouselMovementDirection: It specifies the carousel movement direction
* */
// Make sure the previousIndex and nextIndex are not null
if (previousIndex == null || nextIndex == null) return;
// Call the updateCarouselItemActiveClass function
updateCarouselItemActiveClass(carouselItemsArray, previousIndex, nextIndex);
// Call the updateCarouselIndicatorActiveClass function
updateCarouselIndicatorActiveClass(carousel, previousIndex, nextIndex);
/* Define the isSlideCarousel variable, which can be either true or false,
and specifies whether the carousel uses a slide effect */
const isSlideCarousel: boolean = carousel.classList.contains('carousel-slide');
/* Define the isInfinitySlideCarousel variable, which can be either true or false,
and specifies whether the carousel uses an infinity slider loop effect */
const isInfinitySlideCarousel: boolean = carousel.classList.contains('infinity');
// Move the carousel inner if the isSlideCarousel variable is true
if (isSlideCarousel) {
// Check if the isInfinitySlideCarousel is true
if (isInfinitySlideCarousel) {
// Call the handleCarouselInfinityMovement function
handleCarouselInfinityMovement(
carousel,
carouselItemsArray,
previousIndex,
nextIndex,
carouselMovementDirection
);
return;
}
// Call the moveCarouselInner function to create a carousel movement animation
moveCarouselInner(carousel, nextIndex);
}
}
function updateCarouselItemActiveClass(
carouselItemsArray: HTMLElement[],
previousIndex: number,
nextIndex: number
): void {
/* The function is responsible for removing the 'active' class from the carousel
* item based on the provided previousIndex and adding the 'active' class to the
* carousel item based on the provided nextIndex.
*
* Attributes:
* - carouselItemsArray: An array of the carousel item objects
* - previousIndex: Previous carousel's items position
* - nextIndex: Next carousel's items position
* */
/* Make sure the carousel item at the provided previousIndex
contains the 'active' class */
if (!carouselItemsArray[previousIndex].classList.contains('active')) return;
// Remove the 'active' class to the carouselItemsArray[previousIndex]
carouselItemsArray[previousIndex].classList.remove('active');
// Add the 'active' class to the carouselItemsArray[nextIndex]
carouselItemsArray[nextIndex].classList.add('active');
}
function updateCarouselIndicatorActiveClass(
carousel: HTMLElement,
previousIndex: number,
nextIndex: number
): void {
/* The function is responsible for assigning the active class to the carousel
* indicator buttons, if they exist.
*
* Attributes:
* - carousel: The carousel HTML object is used to get the carousel indicator buttons
* - previousIndex: Previous carousel's items position
* - nextIndex: Next carousel's items position
* */
// Get an array of the carousel indicator buttons
const indicatorButtonsArray: HTMLElement[] = Array.from(carousel.querySelectorAll('.carousel-indicator'));
// Make sure the indicatorButtonsArray is not empty
if (indicatorButtonsArray.length < 1) return;
// Remove the 'active' class from the indicator button corresponding to the previousIndex
indicatorButtonsArray[previousIndex].classList.remove('active');
// Add the 'active' class to the indicator button corresponding to the nextIndex
indicatorButtonsArray[nextIndex].classList.add('active');
}
function moveCarouselInner(
carousel: HTMLElement,
nextIndex: number,
): void {
/* The function is responsible for moving the carousel inner element
* to correspond with the next index.
*
* Attributes:
* - carousel: The carousel HTML object is used to get carouselInner
* - nextIndex: Next carousel's items position
* */
// Get the carouselInner object or null if it does not exist
const carouselInner: HTMLElement | null = carousel.querySelector('.carousel-inner');
// Make sure the carouselInner exists (is not null)
if (!carouselInner) return;
// Update the carouselInner style, imitating the movement
carouselInner.style.left = `-${nextIndex * 100}%`;
}
function handleCarouselInfinityMovement(
carousel: HTMLElement,
carouselItemsArray: HTMLElement[],
previousIndex: number,
nextIndex: number,
carouselMovementDirection: 'forward' | 'backward'
): void {
/* The function is responsible for managing the infinite loop movement
* of the carousel. It applies the display: none CSS property to all
* carousel items that do not correspond to the previousIndex or nextIndex,
* then moves the carousel inner element accordingly.
*
* Attributes:
* - carousel: The carousel HTML object is used to get the carouselInner
* - carouselItemsArray: An array of the carousel items
* - previousIndex: Previous carousel's items position
* - nextIndex: Next carousel's items position
* - carouselMovementDirection: It specifies the carousel movement direction
* */
// Retrieve the carousel inner object or null if it does not exist
const carouselInner: HTMLElement | null = carousel.querySelector('.carousel-inner');
// Make sure the carouselInner exists (is not null)
if (!carouselInner) return;
// Call the hideNonAdjacentItems function
hideNonAdjacentItems(carouselInner, carouselItemsArray);
// Call the moveCarouselInnerToSpecificDirection function
moveCarouselInnerToSpecificDirection(
carouselInner,
carouselMovementDirection,
carouselItemsArray,
previousIndex,
nextIndex,
);
}
function hideNonAdjacentItems(
carouselInner: HTMLElement,
carouselItemsArray: HTMLElement[]
): void {
/* The function is responsible for applying the display: none CSS property to all
* carousel items
*
* Attributes:
* - carouselInner: The carouselInner HTML object is used for the carousel movement
* - carouselItemsArray: An array of the carousel items
* */
// Apply the display: none CSS property to all carousel items
carouselItemsArray.forEach((item: HTMLElement): string => item.style.display = 'none');
// Retrieve an array of the carousel temporary items
const temporaryItems: HTMLElement[] = Array.from(carouselInner.querySelectorAll('.temporary-item'));
// Make sure the temporaryItems array is not empty
if (temporaryItems.length < 1) return;
// Delete all items in the temporaryItems array
temporaryItems.forEach((item: HTMLElement): void => item.remove());
}
function getCarouselMovementDirection(
previousIndex: number,
nextIndex: number,
): 'forward' | 'backward' {
/* The function is responsible for determining and returning the carousel movement
* direction by comparing the previousIndex and nextIndex.
*
* Attributes:
* - previousIndex: Previous carousel's items position
* - nextIndex: Next carousel's items position
* */
return nextIndex > previousIndex ? 'forward' : 'backward';
}
function moveCarouselInnerToSpecificDirection(
carouselInner: HTMLElement,
carouselMovementDirection: 'forward' | 'backward',
carouselItemsArray: HTMLElement[],
previousIndex: number,
nextIndex: number,
): void {
/* The function is responsible for moving the inner carousel corresponding
* to the carousel movement direction.
*
* Attributes:
* - carouselInner: The carouselInner HTML object is used for the carousel movement
* - carouselMovementDirection: It specifies the carousel movement direction
* - carouselItemsArray: An array of the carousel items
* - previousIndex: Previous carousel's items position
* - nextIndex: Next carousel's items position
* */
// Get computed styles
const computedStyles: CSSStyleDeclaration = window.getComputedStyle(carouselInner);
// Get the transition property
const transitionStyle: string = computedStyles.transition;
// Disable the carouselInner transition style
carouselInner.style.transition = 'none';
if (carouselMovementDirection === 'forward') {
// Update the carouselInner CSS left property to imitate movement forward
// Call the appendCarouselItemAfterCurrent function
appendCarouselItemAfterCurrent(
carouselInner,
carouselItemsArray,
previousIndex,
nextIndex,
);
// Set the default inner position of the carousel
carouselInner.style.left = `0`;
setTimeout((): void => {
// Enable the carouselInner transition style
carouselInner.style.transition = transitionStyle;
// Update the carousel inner position
carouselInner.style.left = '-100%';
}, 10);
} else if (carouselMovementDirection === 'backward') {
// Update the carouselInner CSS left property to imitate movement backward
// Call the appendCarouselItemBeforeCurrent function
appendCarouselItemBeforeCurrent(
carouselInner,
carouselItemsArray,
previousIndex,
nextIndex,
);
// Set the default inner position of the carousel
carouselInner.style.left = '-100%';
setTimeout((): void => {
// Enable the carouselInner transition style
carouselInner.style.transition = transitionStyle;
// Update the carousel inner position
carouselInner.style.left = '0';
}, 10);
}
}
function appendCarouselItemAfterCurrent(
carouselInner: HTMLElement,
carouselItemsArray: HTMLElement[],
previousIndex: number,
nextIndex: number
): void {
/* The function is responsible for appending the carousel item corresponding to
* the nextIndex after the current carousel item.
*
* Attributes:
* - carouselInner: The carouselInner HTML object is used for the carousel movement
* - carouselItemsArray: An array of the carousel items
* - previousIndex: Previous carousel's items position
* - nextIndex: Next carousel's items position
* */
// Get the carouselItemsArray length
const carouselItemsArrayLength: number = carouselItemsArray.length;
// Make sure the carouselItemsArrayLength is grater than zero
if (carouselItemsArrayLength < 1) return;
// Append the current carousel item to the end of the carousel-inner object
const currentItem = carouselItemsArray[previousIndex].cloneNode(true) as HTMLElement;
// Add the display flex CSS property to the currentItem
currentItem.style.display = 'flex';
// Add the 'temporary-item' class to the currentItem
currentItem.classList.add('temporary-item');
carouselInner.appendChild(currentItem);
// Append the next carousel item after the currentItem
const nextItem = carouselItemsArray[nextIndex].cloneNode(true) as HTMLElement;
// Add the display flex CSS property to the nextItem
nextItem.style.display = 'flex';
// Add the 'temporary-item' class to the nextItem
nextItem.classList.add('temporary-item');
carouselInner.appendChild(nextItem);
}
function appendCarouselItemBeforeCurrent(
carouselInner: HTMLElement,
carouselItemsArray: HTMLElement[],
previousIndex: number,
nextIndex: number
): void {
/* The function is responsible for appending the carousel item corresponding to
* the nextIndex before the current carousel item.
*
* Attributes:
* - carouselInner: The carouselInner HTML object is used for the carousel movement
* - carouselItemsArray: An array of the carousel items
* - previousIndex: Previous carousel's items position
* - nextIndex: Next carousel's items position
* */
// Get the carouselItemsArray length
const carouselItemsArrayLength: number = carouselItemsArray.length;
// Make sure the carouselItemsArrayLength is grater than zero
if (carouselItemsArrayLength < 1) return;
// Append the next carousel item to the end of the carousel-inner object
const nextItem = carouselItemsArray[nextIndex].cloneNode(true) as HTMLElement;
// Add the display flex CSS property to the nextItem
nextItem.style.display = 'flex';
// Add the 'temporary-item' class to the nextItem
nextItem.classList.add('temporary-item');
carouselInner.appendChild(nextItem);
// Append the current carousel item after the nextItem
const currentItem = carouselItemsArray[previousIndex].cloneNode(true) as HTMLElement;
// Add the display flex CSS property to the currentItem
currentItem.style.display = 'flex';
// Add the 'temporary-item' class to the currentItem
currentItem.classList.add('temporary-item');
carouselInner.appendChild(currentItem);
}
function calculateTouchDirection(
carouselWrapperWidth: number,
startPosition: number,
endPosition: number
): 'forward' | 'backward' | null {
/* The function is responsible for returning 'forward' or 'backward' after calculating the touch movement
*
* Attributes:
* - carouselWrapperWidth: The width of the carousel wrapper element divided by three, used to check whether
* the difference between the start position and the end position exceeds this value.
* - startPosition: The initial position of the touch, as obtained by the touchstart event listener
* - endPosition: Final position of the touch, captured when the touchend event is triggered
* */
/* Determine swipe direction based on how far the user swiped.
If the horizontal swipe distance exceeds half the width of the carousel,
return 'forward' for a left swipe or 'backward' for a right swipe. */
if (startPosition - endPosition > carouselWrapperWidth) {
return 'forward';
} else if (endPosition - startPosition > carouselWrapperWidth) {
return 'backward';
}
return null;
}