@@ -35,10 +35,14 @@ const containerClasses = [
3535 scrollSnap && styles .snap
3636]
3737
38+ const getItemsPerSlide = () => typeof itemsPerSlide === ' number'
39+ ? itemsPerSlide
40+ : itemsPerSlide .default || 1
41+
3842const wrapperClasses = [
3943 styles .wrapper ,
4044 effect && styles [effect ],
41- itemsPerSlide > 1 && styles [' no-snap' ],
45+ getItemsPerSlide () > 1 && styles [' no-snap' ],
4246 wrapperClassName
4347]
4448
@@ -52,10 +56,10 @@ const paginationClasses = classNames([
5256 ! subText && paginationClassName
5357])
5458
55- const totalPages = Math .ceil (items / itemsPerSlide )
59+ const totalPages = Math .ceil (items / getItemsPerSlide () )
5660const subTextValue = subText ?.match (/ \{ 0\} | \{ 1\} / g ) ? subText : undefined
57- const style = itemsPerSlide > 1
58- ? ` --w-slide-width: calc(${100 / itemsPerSlide }% - 5px); `
61+ const style = getItemsPerSlide () > 1
62+ ? ` --w-slide-width: calc(${100 / getItemsPerSlide () }% - 5px); `
5963 : null
6064---
6165
@@ -68,7 +72,8 @@ const style = itemsPerSlide > 1
6872 <ul
6973 class:list ={ wrapperClasses }
7074 style ={ style }
71- data-visible-items ={ itemsPerSlide > 1 ? itemsPerSlide : null }
75+ data-visible-items ={ getItemsPerSlide () > 1 ? getItemsPerSlide () : null }
76+ data-breakpoint-items ={ typeof itemsPerSlide !== ' number' ? JSON .stringify (itemsPerSlide ) : null }
7277 >
7378 <slot />
7479 </ul >
@@ -101,6 +106,7 @@ const style = itemsPerSlide > 1
101106<script >
102107 import { debounce } from '../../utils/debounce'
103108 import { listen } from '../../utils/event'
109+ import { getBreakpoint } from '../../utils/getBreakpoint'
104110
105111 const addEventListeners = () => {
106112 const carousels = Array.from(document.querySelectorAll('[data-id="w-carousel"]'))
@@ -127,7 +133,7 @@ const style = itemsPerSlide > 1
127133 }
128134
129135 for (let i = 0; i < diff; i++) {
130- triggerButton.click()
136+ triggerButton? .click()
131137 }
132138
133139 Array.from(carouselElement.children).forEach(li => {
@@ -140,12 +146,72 @@ const style = itemsPerSlide > 1
140146 }
141147 }
142148
149+ const updateOnResize = (entries: ResizeObserverEntry[]) => {
150+ const target = entries[0].target
151+ const carousel = target.querySelector<HTMLUListElement>('ul')
152+ const pagination = target.parentElement?.querySelector<HTMLUListElement>('[data-id="w-pagination"]')
153+ const breakpoint = getBreakpoint()
154+
155+ if (!target || !carousel || !pagination) {
156+ return
157+ }
158+
159+ if (carousel.dataset.currentBreakpoint === breakpoint) {
160+ return
161+ }
162+
163+ const progress = target.parentElement?.querySelector<HTMLDivElement>('.w-carousel-progress')
164+ const prevPageButton = pagination.querySelector<HTMLButtonElement>('[data-page="prev"]')
165+ const nextPageButton = pagination.querySelector<HTMLButtonElement>('[data-page="next"]')
166+ const subText = pagination.nextElementSibling
167+ const breakpoints = JSON.parse(carousel.dataset.breakpointItems || '')
168+ const itemsPerSlide = breakpoints[breakpoint] || breakpoints.default
169+ const totalItems = carousel.children.length
170+ const totalPages = Math.ceil(totalItems / itemsPerSlide)
171+
172+ carousel.dataset.currentBreakpoint = breakpoint
173+ carousel.dataset.visibleItems = itemsPerSlide
174+ carousel.children[0].scrollIntoView({ behavior: 'smooth', block: 'nearest' })
175+ carousel.style.setProperty('--w-slide-width', `calc(${100 / itemsPerSlide}% - 5px)`)
176+
177+ pagination.dataset.totalPages = String(totalPages)
178+
179+ if (!(prevPageButton && nextPageButton)) {
180+ pagination.innerHTML = Array.from({ length: totalPages }, (_, i) => i + 1)
181+ .map(i => `
182+ <li>
183+ <button
184+ data-active="${i - 1 === 0}"
185+ data-page="${i}"
186+ aria-label="${`page ${i}`}"
187+ ></button>
188+ </li>
189+ `).join('')
190+ }
191+
192+ if (progress && progress.children[0] instanceof HTMLDivElement) {
193+ progress.children[0].style.setProperty('--w-progress-width', '0%')
194+ }
195+
196+ if (subText instanceof HTMLSpanElement && subText?.dataset.text) {
197+ subText.innerText = subText.dataset.text
198+ .replace('{0}', '1')
199+ .replace('{1}', String(totalPages))
200+ }
201+ }
202+
143203 carousels.forEach(carousel => {
144204 const carouselElement = carousel as HTMLDivElement
205+ const carouselList = carousel.querySelector<HTMLUListElement>('ul')
206+ const observer = new ResizeObserver(updateOnResize)
145207 const debounceAmount = carouselElement.dataset.debounce
146208 ? Number(carouselElement.dataset.debounce)
147209 : 20
148210
211+ if (carouselList?.dataset.breakpointItems) {
212+ observer.observe(carouselElement)
213+ }
214+
149215 carousel.addEventListener('scroll', debounce((event: Event) => {
150216 scroll(event)
151217 }, debounceAmount))
@@ -169,6 +235,10 @@ const style = itemsPerSlide > 1
169235 .filter(index => index < totalItems)
170236 })
171237
238+ if (indexes.length < event.page) {
239+ return
240+ }
241+
172242 const pageIndex = event.direction === 'prev'
173243 ? indexes[event.page - 1][0]
174244 : indexes[event.page - 1][indexes[event.page - 1].length - 1]
@@ -194,15 +264,15 @@ const style = itemsPerSlide > 1
194264 }
195265
196266 if (event.trusted) {
197- const carouselContaienr = target.closest('section').querySelector('[data-id="w-carousel"]')
267+ const carouselContainer = target.closest('section').querySelector('[data-id="w-carousel"]')
198268
199269 liElement.scrollIntoView({ behavior: 'smooth', block: 'nearest' })
200270 liElement.dataset.active = 'true'
201271
202- carouselContaienr .dataset.paginated = 'true'
272+ carouselContainer .dataset.paginated = 'true'
203273
204274 setTimeout(() => {
205- carouselContaienr .removeAttribute('data-paginated')
275+ carouselContainer .removeAttribute('data-paginated')
206276 }, 300)
207277 }
208278 })
0 commit comments