import { clamp } from "./chunk.HF7GESMZ.js"; import { AutoplayController } from "./chunk.F4VGSDIW.js"; import { carousel_styles_default } from "./chunk.52AUVIIS.js"; import { waitForEvent } from "./chunk.B4BZKR24.js"; import { prefersReducedMotion } from "./chunk.S7GYYU7Z.js"; import { LocalizeController } from "./chunk.NH3SRVOC.js"; import { e } from "./chunk.UZVKBFXH.js"; import { SlIcon } from "./chunk.UZYAV5H6.js"; import { watch } from "./chunk.FA5RT4K4.js"; import { ShoelaceElement, e as e2, n, r, t } from "./chunk.SEXBCYCU.js"; import { x } from "./chunk.CXZZ2LVK.js"; import { __decorateClass } from "./chunk.KIILAQWQ.js"; // src/internal/scrollend-polyfill.ts var debounce = (fn, delay) => { let timerId = 0; return function(...args) { window.clearTimeout(timerId); timerId = window.setTimeout(() => { fn.call(this, ...args); }, delay); }; }; var decorate = (proto, method, decorateFn) => { const superFn = proto[method]; proto[method] = function(...args) { superFn.call(this, ...args); decorateFn.call(this, superFn, ...args); }; }; var isSupported = "onscrollend" in window; if (!isSupported) { const pointers = /* @__PURE__ */ new Set(); const scrollHandlers = /* @__PURE__ */ new WeakMap(); const handlePointerDown = (event) => { for (const touch of event.changedTouches) { pointers.add(touch.identifier); } }; const handlePointerUp = (event) => { for (const touch of event.changedTouches) { pointers.delete(touch.identifier); } }; document.addEventListener("touchstart", handlePointerDown, true); document.addEventListener("touchend", handlePointerUp, true); document.addEventListener("touchcancel", handlePointerUp, true); decorate(EventTarget.prototype, "addEventListener", function(addEventListener, type) { if (type !== "scrollend") return; const handleScrollEnd = debounce(() => { if (!pointers.size) { this.dispatchEvent(new Event("scrollend")); } else { handleScrollEnd(); } }, 100); addEventListener.call(this, "scroll", handleScrollEnd, { passive: true }); scrollHandlers.set(this, handleScrollEnd); }); decorate(EventTarget.prototype, "removeEventListener", function(removeEventListener, type) { if (type !== "scrollend") return; const scrollHandler = scrollHandlers.get(this); if (scrollHandler) { removeEventListener.call(this, "scroll", scrollHandler, { passive: true }); } }); } // 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()); // determines which slide is displayed // A map containing the state of all the slides this.intersectionObserverEntries = /* @__PURE__ */ new Map(); this.localize = new LocalizeController(this); this.handleMouseDrag = (event) => { if (!this.dragging) { this.scrollContainer.style.setProperty("scroll-snap-type", "none"); this.dragging = true; } 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.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")); const intersectionObserver = new IntersectionObserver( (entries) => { entries.forEach((entry) => { this.intersectionObserverEntries.set(entry.target, entry); const slide = entry.target; slide.toggleAttribute("inert", !entry.isIntersecting); slide.classList.toggle("--in-view", entry.isIntersecting); slide.setAttribute("aria-hidden", entry.isIntersecting ? "false" : "true"); }); }, { root: this, threshold: 0.6 } ); this.intersectionObserver = intersectionObserver; intersectionObserver.takeRecords().forEach((entry) => { this.intersectionObserverEntries.set(entry.target, entry); }); } disconnectedCallback() { super.disconnectedCallback(); this.intersectionObserver.disconnect(); this.mutationObserver.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")) ); } 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; } handleScrollEnd() { if (!this.scrolling || this.dragging) return; const entries = [...this.intersectionObserverEntries.values()]; const firstIntersecting = entries.find((entry) => entry.isIntersecting); if (this.loop && (firstIntersecting == null ? void 0 : firstIntersecting.target.hasAttribute("data-clone"))) { const clonePosition = Number(firstIntersecting.target.getAttribute("data-clone")); this.goToSlide(clonePosition, "instant"); } else if (firstIntersecting) { const slides = this.getSlides(); const slideIndex = slides.indexOf(firstIntersecting.target); this.activeSlide = Math.ceil(slideIndex / this.slidesPerMove) * this.slidesPerMove; } this.scrolling = false; } isCarouselItem(node) { return node instanceof Element && node.tagName.toLowerCase() === "sl-carousel-item"; } initializeSlides() { const intersectionObserver = this.intersectionObserver; this.intersectionObserverEntries.clear(); this.getSlides({ excludeClones: false }).forEach((slide, index) => { intersectionObserver.unobserve(slide); slide.classList.remove("--in-view"); slide.classList.remove("--is-active"); slide.setAttribute("aria-label", this.localize.term("slideNum", index + 1)); if (slide.hasAttribute("data-clone")) { slide.remove(); } }); this.updateSlidesSnap(); if (this.loop) { this.createClones(); } this.getSlides({ excludeClones: false }).forEach((slide) => { intersectionObserver.observe(slide); }); this.goToSlide(this.activeSlide, "auto"); } 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); }); } handelSlideChange() { 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 - 1); this.activeSlide = newActiveSlide; const nextSlideIndex = clamp(index + (loop ? slidesPerPage : 0), 0, slidesWithClones.length - 1); const nextSlide = slidesWithClones[nextSlideIndex]; this.scrollToSlide(nextSlide, prefersReducedMotion() ? "auto" : behavior); } async scrollToSlide(slide, behavior = "smooth") { 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 !== scrollContainer.scrollLeft || nextTop !== scrollContainer.scrollTop) { scrollContainer.scrollTo({ left: nextLeft + scrollContainer.scrollLeft, top: nextTop + scrollContainer.scrollTop, behavior }); await waitForEvent(scrollContainer, "scrollend"); } } 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`