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.
- package/README.md +9 -1
- package/astro.d.ts +5 -0
- package/astro.js +2 -0
- package/components/BottomNavigation/BottomNavigation.astro +1 -3
- package/components/Breadcrumb/Breadcrumb.astro +1 -3
- package/components/Carousel/Carousel.astro +79 -9
- package/components/Carousel/Carousel.svelte +40 -9
- package/components/Carousel/Carousel.tsx +46 -11
- package/components/Carousel/carousel.ts +3 -1
- package/components/Copy/Copy.astro +3 -5
- package/components/Copy/Copy.svelte +1 -1
- package/components/Copy/Copy.tsx +1 -1
- package/components/Input/input.ts +62 -62
- package/components/Modal/Modal.astro +75 -75
- package/components/Modal/modal.ts +25 -25
- package/components/OTPInput/OTPInput.astro +194 -96
- package/components/OTPInput/OTPInput.svelte +141 -26
- package/components/OTPInput/OTPInput.tsx +140 -36
- package/components/OTPInput/otpinput.module.scss +59 -85
- package/components/Pagination/Pagination.astro +3 -3
- package/components/Pagination/Pagination.svelte +4 -4
- package/components/Pagination/pagination.module.scss +3 -3
- package/components/RangeSlider/RangeSlider.astro +270 -0
- package/components/RangeSlider/RangeSlider.svelte +188 -0
- package/components/RangeSlider/RangeSlider.tsx +205 -0
- package/components/RangeSlider/rangeslider.module.scss +143 -0
- package/components/RangeSlider/rangeslider.ts +37 -0
- package/components/Sidebar/Sidebar.astro +1 -3
- package/components/Stepper/Stepper.astro +1 -3
- package/index.d.ts +23 -4
- package/index.js +2 -0
- package/package.json +109 -103
- package/react.d.ts +5 -0
- package/react.js +2 -0
- package/scss/global/breakpoints.scss +15 -0
- package/scss/setup.scss +7 -1
- package/svelte.d.ts +5 -0
- package/svelte.js +2 -0
- package/utils/DOMUtils.ts +27 -2
- package/utils/bodyFreeze.ts +1 -1
- package/utils/context.ts +2 -2
- package/utils/getBreakpoint.ts +17 -0
- package/utils/isOneOf.ts +5 -0
- package/utils/modal.ts +54 -55
- 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@
|
|
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
|
|
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
|
|
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
|
-
|
|
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 /
|
|
59
|
+
const totalPages = Math.ceil(items / getItemsPerSlide())
|
|
56
60
|
const subTextValue = subText?.match(/\{0\}|\{1\}/g) ? subText : undefined
|
|
57
|
-
const style =
|
|
58
|
-
? `--w-slide-width: calc(${100 /
|
|
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={
|
|
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
|
|
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
|
|
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
|
-
|
|
272
|
+
carouselContainer.dataset.paginated = 'true'
|
|
203
273
|
|
|
204
274
|
setTimeout(() => {
|
|
205
|
-
|
|
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
|
-
|
|
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 /
|
|
108
|
-
return Array.from({ length:
|
|
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
|
-
|
|
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 /
|
|
110
|
-
return Array.from({ length:
|
|
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
|
|
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
|
|
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
|
|
72
|
+
navigator.clipboard.writeText(text || '')
|
|
75
73
|
}, true)
|
|
76
74
|
}
|
|
77
75
|
|