webcoreui 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/README.md +9 -1
  2. package/astro.d.ts +5 -0
  3. package/astro.js +2 -0
  4. package/components/BottomNavigation/BottomNavigation.astro +1 -3
  5. package/components/Breadcrumb/Breadcrumb.astro +1 -3
  6. package/components/Carousel/Carousel.astro +79 -9
  7. package/components/Carousel/Carousel.svelte +40 -9
  8. package/components/Carousel/Carousel.tsx +46 -11
  9. package/components/Carousel/carousel.ts +3 -1
  10. package/components/Copy/Copy.astro +3 -5
  11. package/components/Copy/Copy.svelte +1 -1
  12. package/components/Copy/Copy.tsx +1 -1
  13. package/components/Input/input.ts +62 -62
  14. package/components/Modal/Modal.astro +75 -75
  15. package/components/Modal/modal.ts +25 -25
  16. package/components/OTPInput/OTPInput.astro +194 -96
  17. package/components/OTPInput/OTPInput.svelte +141 -26
  18. package/components/OTPInput/OTPInput.tsx +140 -36
  19. package/components/OTPInput/otpinput.module.scss +59 -85
  20. package/components/Pagination/Pagination.astro +3 -3
  21. package/components/Pagination/Pagination.svelte +4 -4
  22. package/components/Pagination/pagination.module.scss +3 -3
  23. package/components/RangeSlider/RangeSlider.astro +270 -0
  24. package/components/RangeSlider/RangeSlider.svelte +188 -0
  25. package/components/RangeSlider/RangeSlider.tsx +205 -0
  26. package/components/RangeSlider/rangeslider.module.scss +143 -0
  27. package/components/RangeSlider/rangeslider.ts +37 -0
  28. package/components/Sidebar/Sidebar.astro +1 -3
  29. package/components/Stepper/Stepper.astro +1 -3
  30. package/index.d.ts +23 -4
  31. package/index.js +2 -0
  32. package/package.json +109 -103
  33. package/react.d.ts +5 -0
  34. package/react.js +2 -0
  35. package/scss/global/breakpoints.scss +15 -0
  36. package/scss/setup.scss +7 -1
  37. package/svelte.d.ts +5 -0
  38. package/svelte.js +2 -0
  39. package/utils/DOMUtils.ts +27 -2
  40. package/utils/bodyFreeze.ts +1 -1
  41. package/utils/context.ts +2 -2
  42. package/utils/getBreakpoint.ts +17 -0
  43. package/utils/isOneOf.ts +5 -0
  44. package/utils/modal.ts +54 -55
  45. package/utils/toast.ts +1 -1
package/README.md CHANGED
@@ -86,7 +86,7 @@ You can use our CLI tool to create a new Webcore project, or integrate it into a
86
86
  npm create webcore@latest
87
87
 
88
88
  # Update configuration files for an existing Astro project
89
- npm create webcore@lates config
89
+ npm create webcore@latest config
90
90
 
91
91
  # Create a new Webcore project with a specific template
92
92
  npm create webcore@latest template [TemplateName] [destination]
@@ -145,6 +145,7 @@ The `setup` mixin can also accept the following options:
145
145
  | `includeUtilities` | `true` | Adds utility classes for CSS. Read more about the available utility classes [here](https://webcoreui.dev/docs/layout). |
146
146
  | `includeTooltip` | `true` | Adds styles for using tooltips.
147
147
  | `includeScrollbarStyles` | `true` | Adds styles for scrollbars.
148
+ | `includeBreakpoints` | `true` | Exposes breakpoint variables in CSS for JS. Used by components for responsiveness.
148
149
 
149
150
  Default component styles can be changed by overriding the following CSS variables:
150
151
 
@@ -178,6 +179,11 @@ html body {
178
179
  // Radio component
179
180
  --w-radio-color: var(--w-color-primary);
180
181
 
182
+ // RangeSlider component
183
+ --w-range-slider-background: var(--w-color-primary-50);
184
+ --w-range-slider-color: var(--w-color-primary);
185
+ --w-range-slider-thumb: var(--w-color-primary-50);
186
+
181
187
  // Rating component
182
188
  --w-rating-color: var(--w-color-primary);
183
189
  --w-rating-empty-color: var(--w-color-primary);
@@ -298,6 +304,7 @@ import { Accordion } from 'webcoreui/react'
298
304
  - [Popover](https://github.com/Frontendland/webcoreui/tree/main/src/components/Popover)
299
305
  - [Progress](https://github.com/Frontendland/webcoreui/tree/main/src/components/Progress)
300
306
  - [Radio](https://github.com/Frontendland/webcoreui/tree/main/src/components/Radio)
307
+ - [RangeSlider](https://github.com/Frontendland/webcoreui/tree/main/src/components/RangeSlider)
301
308
  - [Rating](https://github.com/Frontendland/webcoreui/tree/main/src/components/Rating)
302
309
  - [Ribbon](https://github.com/Frontendland/webcoreui/tree/main/src/components/Ribbon)
303
310
  - [Select](https://github.com/Frontendland/webcoreui/tree/main/src/components/Select)
@@ -321,6 +328,7 @@ import { Accordion } from 'webcoreui/react'
321
328
  ## Blocks
322
329
 
323
330
  - [Author](https://github.com/Frontendland/webcoreui/tree/main/src/blocks/Author)
331
+ - [AvatarWithRating](https://github.com/Frontendland/webcoreui/tree/main/src/blocks/AvatarWithRating)
324
332
  - [BlogCard](https://github.com/Frontendland/webcoreui/tree/main/src/blocks/BlogCard)
325
333
  - [ComponentMap](https://github.com/Frontendland/webcoreui/tree/main/src/blocks/ComponentMap)
326
334
  - [DeviceMockup](https://github.com/Frontendland/webcoreui/tree/main/src/blocks/DeviceMockup)
package/astro.d.ts CHANGED
@@ -31,6 +31,7 @@ import type { PaginationProps as WPaginationProps } from './components/Paginatio
31
31
  import type { PopoverProps as WPopoverProps } from './components/Popover/popover'
32
32
  import type { ProgressProps as WProgressProps } from './components/Progress/progress'
33
33
  import type { RadioProps as WRadioProps } from './components/Radio/radio'
34
+ import type { RangeSliderProps as WRangeSliderProps } from './components/RangeSlider/rangeslider'
34
35
  import type { RatingProps as WRatingProps } from './components/Rating/rating'
35
36
  import type { RibbonProps as WRibbonProps } from './components/Ribbon/ribbon'
36
37
  import type { SelectProps as WSelectProps } from './components/Select/select'
@@ -54,6 +55,7 @@ import type { ToastProps as WToastProps } from './components/Toast/toast'
54
55
  import type { DataTableEventType as WDataTableEventType, HeadingObject as WHeadingObject } from './components/DataTable/datatable.ts'
55
56
  import type { ListEventType as WListEventType } from './components/List/list.ts'
56
57
  import type { PaginationEventType as WPaginationEventType } from './components/Pagination/pagination.ts'
58
+ import type { RangeSliderEventType as WRangeSliderEventType } from './components/RangeSlider/rangeslider.ts'
57
59
  import type { SelectEventType as WSelectEventType } from './components/Select/select.ts'
58
60
 
59
61
  declare module 'webcoreui/astro' {
@@ -90,6 +92,7 @@ declare module 'webcoreui/astro' {
90
92
  export function Popover(_props: WPopoverProps): any
91
93
  export function Progress(_props: WProgressProps): any
92
94
  export function Radio(_props: WRadioProps): any
95
+ export function RangeSlider(_props: WRangeSliderProps): any
93
96
  export function Rating(_props: WRatingProps): any
94
97
  export function Ribbon(_props: WRibbonProps): any
95
98
  export function Select(_props: WSelectProps): any
@@ -143,6 +146,7 @@ declare module 'webcoreui/astro' {
143
146
  export type PopoverProps = WPopoverProps
144
147
  export type ProgressProps = WProgressProps
145
148
  export type RadioProps = WRadioProps
149
+ export type RangeSliderProps = WRangeSliderProps
146
150
  export type RatingProps = WRatingProps
147
151
  export type RibbonProps = WRibbonProps
148
152
  export type SelectProps = WSelectProps
@@ -167,5 +171,6 @@ declare module 'webcoreui/astro' {
167
171
  export type HeadingObject = WHeadingObject
168
172
  export type ListEventType = WListEventType
169
173
  export type PaginationEventType = WPaginationEventType
174
+ export type RangeSliderEventType = WRangeSliderEventType
170
175
  export type SelectEventType = WSelectEventType
171
176
  }
package/astro.js CHANGED
@@ -31,6 +31,7 @@ import PaginationComponent from './components/Pagination/Pagination.astro'
31
31
  import PopoverComponent from './components/Popover/Popover.astro'
32
32
  import ProgressComponent from './components/Progress/Progress.astro'
33
33
  import RadioComponent from './components/Radio/Radio.astro'
34
+ import RangeSliderComponent from './components/RangeSlider/RangeSlider.astro'
34
35
  import RatingComponent from './components/Rating/Rating.astro'
35
36
  import RibbonComponent from './components/Ribbon/Ribbon.astro'
36
37
  import SelectComponent from './components/Select/Select.astro'
@@ -84,6 +85,7 @@ export const Pagination = PaginationComponent
84
85
  export const Popover = PopoverComponent
85
86
  export const Progress = ProgressComponent
86
87
  export const Radio = RadioComponent
88
+ export const RangeSlider = RangeSliderComponent
87
89
  export const Rating = RatingComponent
88
90
  export const Ribbon = RibbonComponent
89
91
  export const Select = SelectComponent
@@ -5,8 +5,6 @@ import Icon from '../Icon/Icon.astro'
5
5
 
6
6
  import styles from './bottomnavigation.module.scss'
7
7
 
8
- import type { IconProps } from '../Icon/icon'
9
-
10
8
  interface Props extends BottomNavigationProps {}
11
9
 
12
10
  const {
@@ -39,7 +37,7 @@ const styleVariable = maxWidth
39
37
  <Fragment>
40
38
  {item.icon?.startsWith('<svg')
41
39
  ? <Fragment set:html={item.icon} />
42
- : <Icon type={item.icon as IconProps['type']} />
40
+ : <Icon type={item.icon} />
43
41
  }
44
42
  </Fragment>
45
43
  )}
@@ -6,8 +6,6 @@ import Icon from '../Icon/Icon.astro'
6
6
 
7
7
  import styles from './breadcrumb.module.scss'
8
8
 
9
- import type { IconProps } from '../Icon/icon'
10
-
11
9
  interface Props extends BreadcrumbProps {}
12
10
 
13
11
  const {
@@ -33,7 +31,7 @@ const classes = [
33
31
  <Fragment>
34
32
  {item.icon.startsWith('<svg')
35
33
  ? <Fragment set:html={item.icon} />
36
- : <Icon type={item.icon as IconProps['type']} />
34
+ : <Icon type={item.icon} />
37
35
  }
38
36
  </Fragment>
39
37
  )}
@@ -35,10 +35,14 @@ const containerClasses = [
35
35
  scrollSnap && styles.snap
36
36
  ]
37
37
 
38
+ const getItemsPerSlide = () => typeof itemsPerSlide === 'number'
39
+ ? itemsPerSlide
40
+ : itemsPerSlide.default || 1
41
+
38
42
  const wrapperClasses = [
39
43
  styles.wrapper,
40
44
  effect && styles[effect],
41
- itemsPerSlide > 1 && styles['no-snap'],
45
+ getItemsPerSlide() > 1 && styles['no-snap'],
42
46
  wrapperClassName
43
47
  ]
44
48
 
@@ -52,10 +56,10 @@ const paginationClasses = classNames([
52
56
  !subText && paginationClassName
53
57
  ])
54
58
 
55
- const totalPages = Math.ceil(items / itemsPerSlide)
59
+ const totalPages = Math.ceil(items / getItemsPerSlide())
56
60
  const 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);`
59
63
  : null
60
64
  ---
61
65
 
@@ -68,7 +72,8 @@ const style = itemsPerSlide > 1
68
72
  <ul
69
73
  class:list={wrapperClasses}
70
74
  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}
72
77
  >
73
78
  <slot />
74
79
  </ul>
@@ -101,6 +106,7 @@ const style = itemsPerSlide > 1
101
106
  <script>
102
107
  import { debounce } from '../../utils/debounce'
103
108
  import { listen } from '../../utils/event'
109
+ import { getBreakpoint } from '../../utils/getBreakpoint'
104
110
 
105
111
  const addEventListeners = () => {
106
112
  const carousels = Array.from(document.querySelectorAll('[data-id="w-carousel"]'))
@@ -127,7 +133,7 @@ const style = itemsPerSlide > 1
127
133
  }
128
134
 
129
135
  for (let i = 0; i < diff; i++) {
130
- triggerButton.click()
136
+ triggerButton?.click()
131
137
  }
132
138
 
133
139
  Array.from(carouselElement.children).forEach(li => {
@@ -140,12 +146,72 @@ const style = itemsPerSlide > 1
140
146
  }
141
147
  }
142
148
 
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
+
143
203
  carousels.forEach(carousel => {
144
204
  const carouselElement = carousel as HTMLDivElement
205
+ const carouselList = carousel.querySelector<HTMLUListElement>('ul')
206
+ const observer = new ResizeObserver(updateOnResize)
145
207
  const debounceAmount = carouselElement.dataset.debounce
146
208
  ? Number(carouselElement.dataset.debounce)
147
209
  : 20
148
210
 
211
+ if (carouselList?.dataset.breakpointItems) {
212
+ observer.observe(carouselElement)
213
+ }
214
+
149
215
  carousel.addEventListener('scroll', debounce((event: Event) => {
150
216
  scroll(event)
151
217
  }, debounceAmount))
@@ -169,6 +235,10 @@ const style = itemsPerSlide > 1
169
235
  .filter(index => index < totalItems)
170
236
  })
171
237
 
238
+ if (indexes.length < event.page) {
239
+ return
240
+ }
241
+
172
242
  const pageIndex = event.direction === 'prev'
173
243
  ? indexes[event.page - 1][0]
174
244
  : indexes[event.page - 1][indexes[event.page - 1].length - 1]
@@ -194,15 +264,15 @@ const style = itemsPerSlide > 1
194
264
  }
195
265
 
196
266
  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"]')
198
268
 
199
269
  liElement.scrollIntoView({ behavior: 'smooth', block: 'nearest' })
200
270
  liElement.dataset.active = 'true'
201
271
 
202
- carouselContaienr.dataset.paginated = 'true'
272
+ carouselContainer.dataset.paginated = 'true'
203
273
 
204
274
  setTimeout(() => {
205
- carouselContaienr.removeAttribute('data-paginated')
275
+ carouselContainer.removeAttribute('data-paginated')
206
276
  }, 300)
207
277
  }
208
278
  })
@@ -8,6 +8,7 @@
8
8
 
9
9
  import { classNames } from '../../utils/classNames'
10
10
  import { debounce as debounceScroll } from '../../utils/debounce'
11
+ import { getBreakpoint } from '../../utils/getBreakpoint'
11
12
 
12
13
  import styles from './carousel.module.scss'
13
14
 
@@ -29,12 +30,28 @@
29
30
  onScroll
30
31
  }: SvelteCarouselProps = $props()
31
32
 
33
+ const getItemsPerSlide = () => {
34
+ if (carousel) {
35
+ return typeof itemsPerSlide === 'number'
36
+ ? itemsPerSlide
37
+ : itemsPerSlide[getBreakpoint()] || itemsPerSlide.default || 1
38
+ }
39
+
40
+ return typeof itemsPerSlide === 'number'
41
+ ? itemsPerSlide
42
+ : itemsPerSlide.default || 1
43
+ }
44
+
32
45
  let carouselContainer: HTMLDivElement
33
46
  let carousel: HTMLUListElement
34
47
  let carouselItems: HTMLCollection | NodeListOf<HTMLLIElement>
35
48
  let progressValue = $state(0)
36
49
  let paginated = false
37
50
  let currentPage = $state(1)
51
+ let totalPages = $state(Math.ceil(items / getItemsPerSlide()))
52
+ let style = $state(getItemsPerSlide() > 1
53
+ ? `--w-slide-width: calc(${100 / getItemsPerSlide()}% - 5px);`
54
+ : null)
38
55
 
39
56
  const classes = classNames([
40
57
  styles.carousel,
@@ -49,7 +66,7 @@
49
66
  const wrapperClasses = classNames([
50
67
  styles.wrapper,
51
68
  effect && styles[effect],
52
- itemsPerSlide! > 1 && styles['no-snap'],
69
+ getItemsPerSlide() > 1 && styles['no-snap'],
53
70
  wrapperClassName
54
71
  ])
55
72
 
@@ -63,11 +80,7 @@
63
80
  !subText && paginationClassName
64
81
  ])
65
82
 
66
- const totalPages = Math.ceil(items / itemsPerSlide!)
67
83
  const subTextValue = subText?.match(/\{0\}|\{1\}/g) ? subText : undefined
68
- const style = itemsPerSlide! > 1
69
- ? `--w-slide-width: calc(${100 / itemsPerSlide!}% - 5px);`
70
- : null
71
84
 
72
85
  const updateValues = () => {
73
86
  const activeElement = carouselItems[currentPage - 1] as HTMLLIElement
@@ -104,8 +117,8 @@
104
117
  }, debounce)
105
118
 
106
119
  const paginate = (event: PaginationEventType) => {
107
- const indexes = Array.from({ length: Math.ceil(items / itemsPerSlide!) }, (_, i) => {
108
- return Array.from({ length: itemsPerSlide! }, (_, j) => (i * itemsPerSlide!) + j)
120
+ const indexes = Array.from({ length: Math.ceil(items / getItemsPerSlide()) }, (_, i) => {
121
+ return Array.from({ length: getItemsPerSlide() }, (_, j) => (i * getItemsPerSlide()) + j)
109
122
  .filter(index => index < items)
110
123
  })
111
124
 
@@ -126,15 +139,33 @@
126
139
  }, 300)
127
140
  }
128
141
 
142
+ const updateOnResize = () => {
143
+ currentPage = 1
144
+ progressValue = 0
145
+ totalPages = Math.ceil(items / getItemsPerSlide())
146
+ style = `--w-slide-width: calc(${100 / getItemsPerSlide()}% - 5px);`
147
+
148
+ if (subTextValue) {
149
+ subText = subTextValue
150
+ .replace('{0}', '1')
151
+ .replace('{1}', String(totalPages))
152
+ }
153
+ }
154
+
129
155
  onMount(() => {
130
156
  const usedInAstro = carousel.children[0].nodeName === 'ASTRO-SLOT'
131
-
132
- carouselContainer.addEventListener('scroll', scroll)
157
+ const observer = new ResizeObserver(updateOnResize)
133
158
 
134
159
  carouselItems = usedInAstro
135
160
  ? carousel.querySelectorAll('li')
136
161
  : carousel.children
137
162
 
163
+ carouselContainer.addEventListener('scroll', scroll)
164
+
165
+ if (typeof itemsPerSlide !== 'number') {
166
+ observer.observe(carouselContainer)
167
+ }
168
+
138
169
  return () => {
139
170
  carouselContainer.removeEventListener('scroll', scroll)
140
171
  }
@@ -7,6 +7,7 @@ import Progress from '../Progress/Progress.tsx'
7
7
 
8
8
  import { classNames } from '../../utils/classNames'
9
9
  import { debounce as debounceScroll } from '../../utils/debounce'
10
+ import { getBreakpoint } from '../../utils/getBreakpoint'
10
11
 
11
12
  import styles from './carousel.module.scss'
12
13
 
@@ -27,14 +28,30 @@ const Carousel = ({
27
28
  onScroll,
28
29
  children
29
30
  }: ReactCarouselProps) => {
31
+ const getItemsPerSlide = () => {
32
+ if (carousel.current) {
33
+ return typeof itemsPerSlide === 'number'
34
+ ? itemsPerSlide
35
+ : itemsPerSlide[getBreakpoint()] || itemsPerSlide.default || 1
36
+ }
37
+
38
+ return typeof itemsPerSlide === 'number'
39
+ ? itemsPerSlide
40
+ : itemsPerSlide.default || 1
41
+ }
42
+
30
43
  const carouselContainer = useRef<HTMLDivElement>(null)
31
44
  const carousel = useRef<HTMLUListElement>(null)
32
45
  const carouselItems = useRef<any>(null)
33
46
  const paginated = useRef(false)
34
47
  const currentPage = useRef(1)
48
+ const totalPages = useRef(Math.ceil(items / getItemsPerSlide()))
35
49
 
36
50
  const [progressValue, setProgressValue] = useState(0)
37
51
  const [updatedSubText, setUpdatedSubText] = useState(subText)
52
+ const [style, setStyle] = useState(getItemsPerSlide() > 1
53
+ ? { '--w-slide-width': `calc(${100 / getItemsPerSlide()}% - 5px)` } as React.CSSProperties
54
+ : undefined)
38
55
 
39
56
  const classes = classNames([
40
57
  styles.carousel,
@@ -49,7 +66,7 @@ const Carousel = ({
49
66
  const wrapperClasses = classNames([
50
67
  styles.wrapper,
51
68
  effect && styles[effect],
52
- itemsPerSlide! > 1 && styles['no-snap'],
69
+ getItemsPerSlide() > 1 && styles['no-snap'],
53
70
  wrapperClassName
54
71
  ])
55
72
 
@@ -63,11 +80,7 @@ const Carousel = ({
63
80
  !subText && paginationClassName
64
81
  ])
65
82
 
66
- const totalPages = Math.ceil(items / itemsPerSlide!)
67
83
  const subTextValue = subText?.match(/\{0\}|\{1\}/g) ? subText : undefined
68
- const style = itemsPerSlide > 1
69
- ? { '--w-slide-width': `calc(${100 / itemsPerSlide!}% - 5px);` } as React.CSSProperties
70
- : undefined
71
84
 
72
85
  const updateValues = (page: number) => {
73
86
  const activeElement = carouselItems.current[page - 1]
@@ -79,12 +92,12 @@ const Carousel = ({
79
92
  setUpdatedSubText(
80
93
  subTextValue
81
94
  .replace('{0}', String(page))
82
- .replace('{1}', String(totalPages))
95
+ .replace('{1}', String(totalPages.current))
83
96
  )
84
97
  }
85
98
 
86
99
  if (progress) {
87
- const percentage = (100 / (totalPages - 1))
100
+ const percentage = (100 / (totalPages.current - 1))
88
101
 
89
102
  setProgressValue(percentage * (page - 1))
90
103
  }
@@ -106,8 +119,8 @@ const Carousel = ({
106
119
  }, debounce)
107
120
 
108
121
  const paginate = (event: PaginationEventType) => {
109
- const indexes = Array.from({ length: Math.ceil(items / itemsPerSlide!) }, (_, i) => {
110
- return Array.from({ length: itemsPerSlide! }, (_, j) => (i * itemsPerSlide!) + j)
122
+ const indexes = Array.from({ length: Math.ceil(items / getItemsPerSlide()) }, (_, i) => {
123
+ return Array.from({ length: getItemsPerSlide() }, (_, j) => (i * getItemsPerSlide()) + j)
111
124
  .filter(index => index < items)
112
125
  })
113
126
 
@@ -128,8 +141,26 @@ const Carousel = ({
128
141
  }, 300)
129
142
  }
130
143
 
144
+ const updateOnResize = () => {
145
+ currentPage.current = 1
146
+ setProgressValue(0)
147
+ totalPages.current = Math.ceil(items / getItemsPerSlide())
148
+ setStyle(prevStyle => ({
149
+ ...prevStyle,
150
+ '--w-slide-width': `calc(${100 / getItemsPerSlide()}% - 5px)`
151
+ }) as React.CSSProperties)
152
+
153
+ if (subTextValue) {
154
+ setUpdatedSubText(subTextValue
155
+ .replace('{0}', '1')
156
+ .replace('{1}', String(totalPages.current))
157
+ )
158
+ }
159
+ }
160
+
131
161
  useEffect(() => {
132
162
  const usedInAstro = carousel.current?.children[0].nodeName === 'ASTRO-SLOT'
163
+ const observer = new ResizeObserver(updateOnResize)
133
164
 
134
165
  carouselItems.current = usedInAstro
135
166
  ? carousel.current?.querySelectorAll('li')
@@ -137,6 +168,10 @@ const Carousel = ({
137
168
 
138
169
  carouselContainer.current?.addEventListener('scroll', scroll)
139
170
 
171
+ if (typeof itemsPerSlide !== 'number') {
172
+ observer.observe(carouselContainer.current!)
173
+ }
174
+
140
175
  return () => {
141
176
  carouselContainer.current?.removeEventListener('scroll', scroll)
142
177
  }
@@ -162,7 +197,7 @@ const Carousel = ({
162
197
  type="arrows"
163
198
  {...pagination}
164
199
  currentPage={currentPage.current}
165
- totalPages={totalPages}
200
+ totalPages={totalPages.current}
166
201
  className={paginationClasses}
167
202
  onChange={paginate}
168
203
  />
@@ -170,7 +205,7 @@ const Carousel = ({
170
205
  <span className={styles.subtext}>
171
206
  {updatedSubText
172
207
  .replace('{0}', '1')
173
- .replace('{1}', String(totalPages))
208
+ .replace('{1}', String(totalPages.current))
174
209
  }
175
210
  </span>
176
211
  )}
@@ -1,10 +1,12 @@
1
1
  import type { Snippet } from 'svelte'
2
2
 
3
+ import type { Responsive } from '../../utils/getLayoutClasses'
4
+
3
5
  import type { PaginationProps } from '../Pagination/pagination'
4
6
 
5
7
  export type CarouselProps = {
6
8
  items: number
7
- itemsPerSlide?: number
9
+ itemsPerSlide?: number | Responsive<number>
8
10
  subText?: string
9
11
  autoplay?: boolean
10
12
  vertical?: boolean
@@ -8,8 +8,6 @@ import { classNames } from '../../utils/classNames'
8
8
 
9
9
  import styles from './copy.module.scss'
10
10
 
11
- import type { IconProps } from '../Icon/icon'
12
-
13
11
  interface Props extends CopyProps {}
14
12
 
15
13
  const {
@@ -42,13 +40,13 @@ const classes = classNames([
42
40
  >
43
41
  {copyIcon?.startsWith('<svg')
44
42
  ? <Fragment set:html={copyIcon} />
45
- : <Icon type={copyIcon as IconProps['type']} />
43
+ : <Icon type={copyIcon} />
46
44
  }
47
45
  </button>
48
46
  <span class={styles.copied}>
49
47
  {copiedIcon?.startsWith('<svg')
50
48
  ? <Fragment set:html={copiedIcon} />
51
- : <Icon type={copiedIcon as IconProps['type']} />
49
+ : <Icon type={copiedIcon} />
52
50
  }
53
51
  </span>
54
52
  </div>
@@ -71,7 +69,7 @@ const classes = classNames([
71
69
  copied.style.opacity = '1'
72
70
  badge.removeAttribute('data-tooltip')
73
71
 
74
- navigator.clipboard.writeText(text as string)
72
+ navigator.clipboard.writeText(text || '')
75
73
  }, true)
76
74
  }
77
75
 
@@ -41,7 +41,7 @@
41
41
  copiedButton!.style.opacity = '1'
42
42
  tooltip = ''
43
43
 
44
- navigator.clipboard.writeText(text as string)
44
+ navigator.clipboard.writeText(text || '')
45
45
  }
46
46
  </script>
47
47
 
@@ -42,7 +42,7 @@ const Copy = ({
42
42
 
43
43
  setTooltipText('')
44
44
 
45
- navigator.clipboard.writeText(text as string)
45
+ navigator.clipboard.writeText(text || '')
46
46
  }
47
47
 
48
48
  return (