import { clamp } from "./chunk.HF7GESMZ.js"; import { AutoplayController } from "./chunk.F4VGSDIW.js"; import { carousel_styles_default } from "./chunk.3UTP7VYR.js"; import { waitForEvent } from "./chunk.B4BZKR24.js"; import { prefersReducedMotion } from "./chunk.SRECDZMQ.js"; import { LocalizeController } from "./chunk.2SU6QBUU.js"; import { SlIcon } from "./chunk.AGWHFEOF.js"; import { e } from "./chunk.3RBSSBZT.js"; import { watch } from "./chunk.JMZM2TDT.js"; import { component_styles_default } from "./chunk.INZSKSLC.js"; import { ShoelaceElement, e as e2, n, r, t } from "./chunk.OGQ452CI.js"; import { x } from "./chunk.OOP2EFQH.js"; import { __decorateClass } from "./chunk.W27M6RDR.js"; // node_modules/lit-html/directives/map.js function* o(o3, f) { if (void 0 !== o3) { let i = 0; for (const t2 of o3) yield f(t2, i++); } } // node_modules/lit-html/directives/range.js function* o2(o3, t2, e3 = 1) { const i = void 0 === t2 ? 0 : o3; t2 != null ? t2 : t2 = o3; for (let o4 = i; e3 > 0 ? o4 < t2 : t2 < o4; o4 += e3) yield o4; } // src/components/carousel/carousel.component.ts var SlCarousel = class extends ShoelaceElement { constructor() { super(...arguments); this.loop = false; this.navigation = false; this.pagination = false; this.autoplay = false; this.autoplayInterval = 3e3; this.slidesPerPage = 1; this.slidesPerMove = 1; this.orientation = "horizontal"; this.mouseDragging = false; this.activeSlide = 0; this.scrolling = false; this.dragging = false; this.autoplayController = new AutoplayController(this, () => this.next()); this.dragStartPosition = [-1, -1]; this.localize = new LocalizeController(this); this.pendingSlideChange = false; this.handleMouseDrag = (event) => { if (!this.dragging) { this.scrollContainer.style.setProperty("scroll-snap-type", "none"); this.dragging = true; this.dragStartPosition = [event.clientX, event.clientY]; } this.scrollContainer.scrollBy({ left: -event.movementX, top: -event.movementY, behavior: "instant" }); }; this.handleMouseDragEnd = () => { const scrollContainer = this.scrollContainer; document.removeEventListener("pointermove", this.handleMouseDrag, { capture: true }); const startLeft = scrollContainer.scrollLeft; const startTop = scrollContainer.scrollTop; scrollContainer.style.removeProperty("scroll-snap-type"); scrollContainer.style.setProperty("overflow", "hidden"); const finalLeft = scrollContainer.scrollLeft; const finalTop = scrollContainer.scrollTop; scrollContainer.style.removeProperty("overflow"); scrollContainer.style.setProperty("scroll-snap-type", "none"); scrollContainer.scrollTo({ left: startLeft, top: startTop, behavior: "instant" }); requestAnimationFrame(async () => { if (startLeft !== finalLeft || startTop !== finalTop) { scrollContainer.scrollTo({ left: finalLeft, top: finalTop, behavior: prefersReducedMotion() ? "auto" : "smooth" }); await waitForEvent(scrollContainer, "scrollend"); } scrollContainer.style.removeProperty("scroll-snap-type"); this.dragging = false; this.dragStartPosition = [-1, -1]; this.handleScrollEnd(); }); }; this.handleSlotChange = (mutations) => { const needsInitialization = mutations.some( (mutation) => [...mutation.addedNodes, ...mutation.removedNodes].some( (el) => this.isCarouselItem(el) && !el.hasAttribute("data-clone") ) ); if (needsInitialization) { this.initializeSlides(); } this.requestUpdate(); }; } connectedCallback() { super.connectedCallback(); this.setAttribute("role", "region"); this.setAttribute("aria-label", this.localize.term("carousel")); } disconnectedCallback() { var _a; super.disconnectedCallback(); (_a = this.mutationObserver) == null ? void 0 : _a.disconnect(); } firstUpdated() { this.initializeSlides(); this.mutationObserver = new MutationObserver(this.handleSlotChange); this.mutationObserver.observe(this, { childList: true, subtree: true }); } willUpdate(changedProperties) { if (changedProperties.has("slidesPerMove") || changedProperties.has("slidesPerPage")) { this.slidesPerMove = Math.min(this.slidesPerMove, this.slidesPerPage); } } getPageCount() { const slidesCount = this.getSlides().length; const { slidesPerPage, slidesPerMove, loop } = this; const pages = loop ? slidesCount / slidesPerMove : (slidesCount - slidesPerPage) / slidesPerMove + 1; return Math.ceil(pages); } getCurrentPage() { return Math.ceil(this.activeSlide / this.slidesPerMove); } canScrollNext() { return this.loop || this.getCurrentPage() < this.getPageCount() - 1; } canScrollPrev() { return this.loop || this.getCurrentPage() > 0; } /** @internal Gets all carousel items. */ getSlides({ excludeClones = true } = {}) { return [...this.children].filter( (el) => this.isCarouselItem(el) && (!excludeClones || !el.hasAttribute("data-clone")) ); } handleClick(event) { if (this.dragging && this.dragStartPosition[0] > 0 && this.dragStartPosition[1] > 0) { const deltaX = Math.abs(this.dragStartPosition[0] - event.clientX); const deltaY = Math.abs(this.dragStartPosition[1] - event.clientY); const delta = Math.sqrt(deltaX * deltaX + deltaY * deltaY); if (delta >= 10) { event.preventDefault(); } } } handleKeyDown(event) { if (["ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown", "Home", "End"].includes(event.key)) { const target = event.target; const isRtl = this.localize.dir() === "rtl"; const isFocusInPagination = target.closest('[part~="pagination-item"]') !== null; const isNext = event.key === "ArrowDown" || !isRtl && event.key === "ArrowRight" || isRtl && event.key === "ArrowLeft"; const isPrevious = event.key === "ArrowUp" || !isRtl && event.key === "ArrowLeft" || isRtl && event.key === "ArrowRight"; event.preventDefault(); if (isPrevious) { this.previous(); } if (isNext) { this.next(); } if (event.key === "Home") { this.goToSlide(0); } if (event.key === "End") { this.goToSlide(this.getSlides().length - 1); } if (isFocusInPagination) { this.updateComplete.then(() => { var _a; const activePaginationItem = (_a = this.shadowRoot) == null ? void 0 : _a.querySelector( '[part~="pagination-item--active"]' ); if (activePaginationItem) { activePaginationItem.focus(); } }); } } } handleMouseDragStart(event) { const canDrag = this.mouseDragging && event.button === 0; if (canDrag) { event.preventDefault(); document.addEventListener("pointermove", this.handleMouseDrag, { capture: true, passive: true }); document.addEventListener("pointerup", this.handleMouseDragEnd, { capture: true, once: true }); } } handleScroll() { this.scrolling = true; if (!this.pendingSlideChange) { this.synchronizeSlides(); } } /** @internal Synchronizes the slides with the IntersectionObserver API. */ synchronizeSlides() { const io = new IntersectionObserver( (entries) => { io.disconnect(); for (const entry of entries) { const slide = entry.target; slide.toggleAttribute("inert", !entry.isIntersecting); slide.classList.toggle("--in-view", entry.isIntersecting); slide.setAttribute("aria-hidden", entry.isIntersecting ? "false" : "true"); } const firstIntersecting = entries.find((entry) => entry.isIntersecting); if (!firstIntersecting) { return; } const slidesWithClones = this.getSlides({ excludeClones: false }); const slidesCount = this.getSlides().length; const slideIndex = slidesWithClones.indexOf(firstIntersecting.target); const normalizedIndex = this.loop ? slideIndex - this.slidesPerPage : slideIndex; this.activeSlide = (Math.ceil(normalizedIndex / this.slidesPerMove) * this.slidesPerMove + slidesCount) % slidesCount; if (!this.scrolling) { if (this.loop && firstIntersecting.target.hasAttribute("data-clone")) { const clonePosition = Number(firstIntersecting.target.getAttribute("data-clone")); this.goToSlide(clonePosition, "instant"); } } }, { root: this.scrollContainer, threshold: 0.6 } ); this.getSlides({ excludeClones: false }).forEach((slide) => { io.observe(slide); }); } handleScrollEnd() { if (!this.scrolling || this.dragging) return; this.scrolling = false; this.pendingSlideChange = false; this.synchronizeSlides(); } isCarouselItem(node) { return node instanceof Element && node.tagName.toLowerCase() === "sl-carousel-item"; } initializeSlides() { this.getSlides({ excludeClones: false }).forEach((slide, index) => { slide.classList.remove("--in-view"); slide.classList.remove("--is-active"); slide.setAttribute("role", "group"); slide.setAttribute("aria-label", this.localize.term("slideNum", index + 1)); if (this.pagination) { slide.setAttribute("id", `slide-${index + 1}`); slide.setAttribute("role", "tabpanel"); slide.removeAttribute("aria-label"); slide.setAttribute("aria-labelledby", `tab-${index + 1}`); } if (slide.hasAttribute("data-clone")) { slide.remove(); } }); this.updateSlidesSnap(); if (this.loop) { this.createClones(); } this.goToSlide(this.activeSlide, "auto"); this.synchronizeSlides(); } createClones() { const slides = this.getSlides(); const slidesPerPage = this.slidesPerPage; const lastSlides = slides.slice(-slidesPerPage); const firstSlides = slides.slice(0, slidesPerPage); lastSlides.reverse().forEach((slide, i) => { const clone = slide.cloneNode(true); clone.setAttribute("data-clone", String(slides.length - i - 1)); this.prepend(clone); }); firstSlides.forEach((slide, i) => { const clone = slide.cloneNode(true); clone.setAttribute("data-clone", String(i)); this.append(clone); }); } handleSlideChange() { const slides = this.getSlides(); slides.forEach((slide, i) => { slide.classList.toggle("--is-active", i === this.activeSlide); }); if (this.hasUpdated) { this.emit("sl-slide-change", { detail: { index: this.activeSlide, slide: slides[this.activeSlide] } }); } } updateSlidesSnap() { const slides = this.getSlides(); const slidesPerMove = this.slidesPerMove; slides.forEach((slide, i) => { const shouldSnap = (i + slidesPerMove) % slidesPerMove === 0; if (shouldSnap) { slide.style.removeProperty("scroll-snap-align"); } else { slide.style.setProperty("scroll-snap-align", "none"); } }); } handleAutoplayChange() { this.autoplayController.stop(); if (this.autoplay) { this.autoplayController.start(this.autoplayInterval); } } /** * Move the carousel backward by `slides-per-move` slides. * * @param behavior - The behavior used for scrolling. */ previous(behavior = "smooth") { this.goToSlide(this.activeSlide - this.slidesPerMove, behavior); } /** * Move the carousel forward by `slides-per-move` slides. * * @param behavior - The behavior used for scrolling. */ next(behavior = "smooth") { this.goToSlide(this.activeSlide + this.slidesPerMove, behavior); } /** * Scrolls the carousel to the slide specified by `index`. * * @param index - The slide index. * @param behavior - The behavior used for scrolling. */ goToSlide(index, behavior = "smooth") { const { slidesPerPage, loop } = this; const slides = this.getSlides(); const slidesWithClones = this.getSlides({ excludeClones: false }); if (!slides.length) { return; } const newActiveSlide = loop ? (index + slides.length) % slides.length : clamp(index, 0, slides.length - slidesPerPage); this.activeSlide = newActiveSlide; const isRtl = this.localize.dir() === "rtl"; const nextSlideIndex = clamp( index + (loop ? slidesPerPage : 0) + (isRtl ? slidesPerPage - 1 : 0), 0, slidesWithClones.length - 1 ); const nextSlide = slidesWithClones[nextSlideIndex]; this.scrollToSlide(nextSlide, prefersReducedMotion() ? "auto" : behavior); } scrollToSlide(slide, behavior = "smooth") { this.pendingSlideChange = true; window.requestAnimationFrame(() => { if (!this.scrollContainer) { return; } const scrollContainer = this.scrollContainer; const scrollContainerRect = scrollContainer.getBoundingClientRect(); const nextSlideRect = slide.getBoundingClientRect(); const nextLeft = nextSlideRect.left - scrollContainerRect.left; const nextTop = nextSlideRect.top - scrollContainerRect.top; if (nextLeft || nextTop) { this.pendingSlideChange = true; scrollContainer.scrollTo({ left: nextLeft + scrollContainer.scrollLeft, top: nextTop + scrollContainer.scrollTop, behavior }); } else { this.pendingSlideChange = false; } }); } render() { const { slidesPerMove, scrolling } = this; const pagesCount = this.getPageCount(); const currentPage = this.getCurrentPage(); const prevEnabled = this.canScrollPrev(); const nextEnabled = this.canScrollNext(); const isLtr = this.localize.dir() === "ltr"; return x`