@faststore/ui 2.0.122-alpha.0 → 2.0.132-alpha.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/dist/index.d.ts +0 -6
- package/dist/index.js +0 -4
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/components/atoms/Button/styles.scss +103 -63
- package/src/components/molecules/Accordion/styles.scss +3 -1
- package/src/components/molecules/Alert/styles.scss +2 -15
- package/src/components/molecules/Banner/styles.scss +1 -1
- package/src/components/molecules/BuyButton/styles.scss +9 -5
- package/src/components/molecules/Carousel/styles.scss +82 -56
- package/src/components/molecules/InputField/styles.scss +3 -9
- package/src/components/molecules/LinkButton/styles.scss +1 -2
- package/src/components/molecules/NavbarLinks/styles.scss +12 -9
- package/src/components/molecules/QuantitySelector/styles.scss +20 -75
- package/src/components/molecules/RegionBar/styles.scss +12 -9
- package/src/components/molecules/SearchInputField/styles.scss +16 -30
- package/src/components/organisms/Filter/styles.scss +11 -10
- package/src/components/organisms/Hero/styles.scss +4 -2
- package/src/components/organisms/ImageGallery/styles.scss +33 -20
- package/src/components/organisms/ProductShelf/styles.scss +2 -3
- package/src/index.ts +0 -16
- package/dist/components/molecules/Bullets/Bullets.d.ts +0 -35
- package/dist/components/molecules/Bullets/Bullets.js +0 -12
- package/dist/components/molecules/Bullets/Bullets.js.map +0 -1
- package/dist/components/molecules/Bullets/index.d.ts +0 -2
- package/dist/components/molecules/Bullets/index.js +0 -2
- package/dist/components/molecules/Bullets/index.js.map +0 -1
- package/dist/components/molecules/Carousel/Arrows.d.ts +0 -12
- package/dist/components/molecules/Carousel/Arrows.js +0 -6
- package/dist/components/molecules/Carousel/Arrows.js.map +0 -1
- package/dist/components/molecules/Carousel/Carousel.d.ts +0 -54
- package/dist/components/molecules/Carousel/Carousel.js +0 -183
- package/dist/components/molecules/Carousel/Carousel.js.map +0 -1
- package/dist/components/molecules/Carousel/CarouselItem.d.ts +0 -11
- package/dist/components/molecules/Carousel/CarouselItem.js +0 -18
- package/dist/components/molecules/Carousel/CarouselItem.js.map +0 -1
- package/dist/components/molecules/Carousel/hooks/useSlideVisibility.d.ts +0 -9
- package/dist/components/molecules/Carousel/hooks/useSlideVisibility.js +0 -29
- package/dist/components/molecules/Carousel/hooks/useSlideVisibility.js.map +0 -1
- package/dist/components/molecules/Carousel/index.d.ts +0 -2
- package/dist/components/molecules/Carousel/index.js +0 -3
- package/dist/components/molecules/Carousel/index.js.map +0 -1
- package/dist/hooks/useSlider/index.d.ts +0 -2
- package/dist/hooks/useSlider/index.js +0 -3
- package/dist/hooks/useSlider/index.js.map +0 -1
- package/dist/hooks/useSlider/useSlider.d.ts +0 -64
- package/dist/hooks/useSlider/useSlider.js +0 -103
- package/dist/hooks/useSlider/useSlider.js.map +0 -1
- package/src/components/molecules/Bullets/Bullets.tsx +0 -88
- package/src/components/molecules/Bullets/index.ts +0 -2
- package/src/components/molecules/Carousel/Arrows.tsx +0 -58
- package/src/components/molecules/Carousel/Carousel.tsx +0 -387
- package/src/components/molecules/Carousel/CarouselItem.tsx +0 -54
- package/src/components/molecules/Carousel/hooks/useSlideVisibility.ts +0 -59
- package/src/components/molecules/Carousel/index.ts +0 -2
- package/src/hooks/useSlider/index.ts +0 -2
- package/src/hooks/useSlider/useSlider.ts +0 -209
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
|
-
|
|
3
|
-
interface IconProps {
|
|
4
|
-
size?: {
|
|
5
|
-
width: number
|
|
6
|
-
height: number
|
|
7
|
-
}
|
|
8
|
-
viewBox?: string
|
|
9
|
-
color?: string
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export const LeftArrowIcon = ({
|
|
13
|
-
size = { width: 25, height: 25 },
|
|
14
|
-
viewBox = '0 0 16 16',
|
|
15
|
-
color = 'currentColor',
|
|
16
|
-
}: IconProps) => (
|
|
17
|
-
<svg
|
|
18
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
19
|
-
xmlnsXlink="http://www.w3.org/1999/xlink"
|
|
20
|
-
viewBox={viewBox}
|
|
21
|
-
width={size.width}
|
|
22
|
-
height={size.height}
|
|
23
|
-
>
|
|
24
|
-
<path
|
|
25
|
-
d="M11 1L4 8L11 15"
|
|
26
|
-
strokeWidth="2"
|
|
27
|
-
strokeMiterlimit="10"
|
|
28
|
-
strokeLinecap="round"
|
|
29
|
-
strokeLinejoin="round"
|
|
30
|
-
stroke={color}
|
|
31
|
-
fill="none"
|
|
32
|
-
/>
|
|
33
|
-
</svg>
|
|
34
|
-
)
|
|
35
|
-
|
|
36
|
-
export const RightArrowIcon = ({
|
|
37
|
-
size = { width: 25, height: 25 },
|
|
38
|
-
viewBox = '0 0 16 16',
|
|
39
|
-
color = 'currentColor',
|
|
40
|
-
}: IconProps) => (
|
|
41
|
-
<svg
|
|
42
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
43
|
-
xmlnsXlink="http://www.w3.org/1999/xlink"
|
|
44
|
-
viewBox={viewBox}
|
|
45
|
-
width={size.width}
|
|
46
|
-
height={size.height}
|
|
47
|
-
>
|
|
48
|
-
<path
|
|
49
|
-
d="M5 15L12 8L5 1"
|
|
50
|
-
strokeWidth="2"
|
|
51
|
-
strokeMiterlimit="10"
|
|
52
|
-
strokeLinecap="round"
|
|
53
|
-
strokeLinejoin="round"
|
|
54
|
-
stroke={color}
|
|
55
|
-
fill="none"
|
|
56
|
-
/>
|
|
57
|
-
</svg>
|
|
58
|
-
)
|
|
@@ -1,387 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
UIEvent,
|
|
3
|
-
ReactNode,
|
|
4
|
-
CSSProperties,
|
|
5
|
-
KeyboardEvent,
|
|
6
|
-
PropsWithChildren,
|
|
7
|
-
} from 'react'
|
|
8
|
-
import React, { useMemo, useRef } from 'react'
|
|
9
|
-
import type { SwipeableProps } from 'react-swipeable'
|
|
10
|
-
|
|
11
|
-
import { RightArrowIcon, LeftArrowIcon } from './Arrows'
|
|
12
|
-
import CarouselItem from './CarouselItem'
|
|
13
|
-
import useSlider from '../../../hooks/useSlider/useSlider'
|
|
14
|
-
import Bullets from '../Bullets'
|
|
15
|
-
import { IconButton } from '../../../'
|
|
16
|
-
|
|
17
|
-
const createTransformValues = (infinite: boolean, totalItems: number) => {
|
|
18
|
-
const transformMap: Record<number, number> = {}
|
|
19
|
-
const slideWidth = 100 / totalItems
|
|
20
|
-
|
|
21
|
-
for (let idx = 0; idx < totalItems; ++idx) {
|
|
22
|
-
const currIdx = infinite ? idx - 1 : idx
|
|
23
|
-
const transformValue = -(slideWidth * idx)
|
|
24
|
-
|
|
25
|
-
transformMap[currIdx] = transformValue
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
return transformMap
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export interface CarouselProps extends SwipeableProps {
|
|
32
|
-
/**
|
|
33
|
-
* ID of the current instance of the component.
|
|
34
|
-
*/
|
|
35
|
-
id?: string
|
|
36
|
-
/**
|
|
37
|
-
* ID to find this component in testing tools (e.g.: cypress, testing library, and jest).
|
|
38
|
-
*/
|
|
39
|
-
testId?: string
|
|
40
|
-
/**
|
|
41
|
-
* Returns the value of element's class content attribute.
|
|
42
|
-
*/
|
|
43
|
-
className?: string
|
|
44
|
-
/**
|
|
45
|
-
* Whether or not the Carousel is infinite slide/scroll. Only for the `slide` variant.
|
|
46
|
-
* @default true
|
|
47
|
-
*/
|
|
48
|
-
infiniteMode?: boolean
|
|
49
|
-
/**
|
|
50
|
-
* Specifies which navigation elements should be visible.
|
|
51
|
-
* @default complete
|
|
52
|
-
*/
|
|
53
|
-
controls?: 'complete' | 'navigationArrows' | 'paginationBullets'
|
|
54
|
-
/**
|
|
55
|
-
* Specifies the slide transition. Only for the `slide` variant
|
|
56
|
-
*/
|
|
57
|
-
transition?: {
|
|
58
|
-
duration: number
|
|
59
|
-
property: string
|
|
60
|
-
delay?: number
|
|
61
|
-
timing?: string
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* Specifies the number of items per page.
|
|
65
|
-
* @default 1
|
|
66
|
-
*/
|
|
67
|
-
itemsPerPage?: number
|
|
68
|
-
/**
|
|
69
|
-
* Specifies the Carousel track variant.
|
|
70
|
-
* @default slide
|
|
71
|
-
*/
|
|
72
|
-
variant?: 'slide' | 'scroll'
|
|
73
|
-
/**
|
|
74
|
-
* Specifies the navigation icons.
|
|
75
|
-
*/
|
|
76
|
-
navigationIcons?: {
|
|
77
|
-
left?: ReactNode
|
|
78
|
-
right?: ReactNode
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
function Carousel({
|
|
83
|
-
infiniteMode = true,
|
|
84
|
-
controls = 'complete',
|
|
85
|
-
testId = 'store-carousel',
|
|
86
|
-
transition = {
|
|
87
|
-
duration: 400,
|
|
88
|
-
property: 'transform',
|
|
89
|
-
},
|
|
90
|
-
children,
|
|
91
|
-
className,
|
|
92
|
-
id = 'store-carousel',
|
|
93
|
-
variant = 'slide',
|
|
94
|
-
itemsPerPage = 1,
|
|
95
|
-
navigationIcons = undefined,
|
|
96
|
-
...swipeableConfigOverrides
|
|
97
|
-
}: PropsWithChildren<CarouselProps>) {
|
|
98
|
-
const carouselTrackRef = useRef<HTMLUListElement>(null)
|
|
99
|
-
const isSlideCarousel = variant === 'slide'
|
|
100
|
-
const isScrollCarousel = variant === 'scroll'
|
|
101
|
-
const childrenArray = React.Children.toArray(children)
|
|
102
|
-
const childrenCount = childrenArray.length
|
|
103
|
-
const numberOfSlides = infiniteMode ? childrenCount + 2 : childrenCount
|
|
104
|
-
const slidingTransition = `${transition.property} ${transition.duration}ms ${
|
|
105
|
-
transition.timing ?? ''
|
|
106
|
-
} ${transition.delay ?? ''}`
|
|
107
|
-
|
|
108
|
-
const showNavigationArrows =
|
|
109
|
-
controls === 'complete' || controls === 'navigationArrows'
|
|
110
|
-
|
|
111
|
-
const showPaginationBullets =
|
|
112
|
-
controls === 'complete' || controls === 'paginationBullets'
|
|
113
|
-
|
|
114
|
-
const transformValues = useMemo(
|
|
115
|
-
() => createTransformValues(infiniteMode, numberOfSlides),
|
|
116
|
-
[numberOfSlides, infiniteMode]
|
|
117
|
-
)
|
|
118
|
-
|
|
119
|
-
const { handlers, slide, sliderState, sliderDispatch } = useSlider({
|
|
120
|
-
itemsPerPage,
|
|
121
|
-
infiniteMode,
|
|
122
|
-
totalItems: childrenCount,
|
|
123
|
-
shouldSlideOnSwipe: isSlideCarousel,
|
|
124
|
-
...swipeableConfigOverrides,
|
|
125
|
-
})
|
|
126
|
-
|
|
127
|
-
const postRenderedSlides =
|
|
128
|
-
infiniteMode && children ? childrenArray.slice(0, 1) : []
|
|
129
|
-
|
|
130
|
-
const preRenderedSlides =
|
|
131
|
-
infiniteMode && children ? childrenArray.slice(childrenCount - 1) : []
|
|
132
|
-
|
|
133
|
-
const slides = preRenderedSlides.concat(
|
|
134
|
-
(children as any) ?? [],
|
|
135
|
-
postRenderedSlides
|
|
136
|
-
)
|
|
137
|
-
|
|
138
|
-
const slideCarouselTrackStyle: CSSProperties = useMemo(
|
|
139
|
-
() => ({
|
|
140
|
-
display: 'flex',
|
|
141
|
-
width: `${numberOfSlides * 100}%`,
|
|
142
|
-
transition: sliderState.sliding ? slidingTransition : undefined,
|
|
143
|
-
transform: `translate3d(${
|
|
144
|
-
transformValues[sliderState.currentPage]
|
|
145
|
-
}%, 0, 0)`,
|
|
146
|
-
}),
|
|
147
|
-
[
|
|
148
|
-
numberOfSlides,
|
|
149
|
-
transformValues,
|
|
150
|
-
slidingTransition,
|
|
151
|
-
sliderState.sliding,
|
|
152
|
-
sliderState.currentPage,
|
|
153
|
-
]
|
|
154
|
-
)
|
|
155
|
-
|
|
156
|
-
const scrollCarouselTrackStyle: CSSProperties = useMemo(
|
|
157
|
-
() => ({
|
|
158
|
-
width: '100%',
|
|
159
|
-
display: 'block',
|
|
160
|
-
overflowX: 'scroll',
|
|
161
|
-
whiteSpace: 'nowrap',
|
|
162
|
-
}),
|
|
163
|
-
[]
|
|
164
|
-
)
|
|
165
|
-
|
|
166
|
-
const carouselTrackStyle =
|
|
167
|
-
((isSlideCarousel && slideCarouselTrackStyle) as CSSProperties) ||
|
|
168
|
-
((isScrollCarousel && scrollCarouselTrackStyle) as CSSProperties)
|
|
169
|
-
|
|
170
|
-
const slidePrevious = () => {
|
|
171
|
-
if (
|
|
172
|
-
sliderState.sliding ||
|
|
173
|
-
(!infiniteMode && sliderState.currentPage === 0)
|
|
174
|
-
) {
|
|
175
|
-
return
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
slide('previous', sliderDispatch)
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
const slideNext = () => {
|
|
182
|
-
if (
|
|
183
|
-
sliderState.sliding ||
|
|
184
|
-
(!infiniteMode && sliderState.currentPage === childrenCount - 1)
|
|
185
|
-
) {
|
|
186
|
-
return
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
slide('next', sliderDispatch)
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
const onScrollTrack = (event: UIEvent) => {
|
|
193
|
-
if (isSlideCarousel || itemsPerPage > 1) {
|
|
194
|
-
return
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
const itemWidth = Number(event.currentTarget.firstElementChild?.scrollWidth)
|
|
198
|
-
const scrollOffset = event.currentTarget?.scrollLeft
|
|
199
|
-
const formatter = scrollOffset > itemWidth / 2 ? Math.round : Math.floor
|
|
200
|
-
const page = formatter(scrollOffset / itemWidth)
|
|
201
|
-
|
|
202
|
-
slide(page, sliderDispatch)
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
const onTransitionTrackEnd = () => {
|
|
206
|
-
sliderDispatch({
|
|
207
|
-
type: 'STOP_SLIDE',
|
|
208
|
-
})
|
|
209
|
-
|
|
210
|
-
if (infiniteMode && sliderState.currentItem >= childrenCount) {
|
|
211
|
-
sliderDispatch({
|
|
212
|
-
type: 'GO_TO_PAGE',
|
|
213
|
-
payload: {
|
|
214
|
-
pageIndex: 0,
|
|
215
|
-
shouldSlide: false,
|
|
216
|
-
},
|
|
217
|
-
})
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
if (infiniteMode && sliderState.currentItem < 0) {
|
|
221
|
-
sliderDispatch({
|
|
222
|
-
type: 'GO_TO_PAGE',
|
|
223
|
-
payload: {
|
|
224
|
-
pageIndex: sliderState.totalPages - 1,
|
|
225
|
-
shouldSlide: false,
|
|
226
|
-
},
|
|
227
|
-
})
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
const onScrollPagination = async (
|
|
232
|
-
index: number,
|
|
233
|
-
slideDirection?: 'previous' | 'next'
|
|
234
|
-
) => {
|
|
235
|
-
if (slideDirection === 'previous' && sliderState.currentPage === 0) {
|
|
236
|
-
return
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
if (
|
|
240
|
-
slideDirection === 'next' &&
|
|
241
|
-
sliderState.currentPage === sliderState.totalPages - 1
|
|
242
|
-
) {
|
|
243
|
-
return
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
let scrollOffset
|
|
247
|
-
const carouselItemsWidth = Number(
|
|
248
|
-
carouselTrackRef.current?.firstElementChild?.clientWidth
|
|
249
|
-
)
|
|
250
|
-
|
|
251
|
-
if (itemsPerPage > 1) {
|
|
252
|
-
scrollOffset = index * carouselItemsWidth * itemsPerPage
|
|
253
|
-
} else {
|
|
254
|
-
scrollOffset = index * carouselItemsWidth - carouselItemsWidth * 0.125
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
carouselTrackRef.current?.scrollTo({
|
|
258
|
-
left: scrollOffset,
|
|
259
|
-
behavior: 'smooth',
|
|
260
|
-
})
|
|
261
|
-
|
|
262
|
-
slide(index, sliderDispatch)
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
// accessible behavior for tablist
|
|
266
|
-
const handleBulletsKeyDown = (event: KeyboardEvent) => {
|
|
267
|
-
switch (event.key) {
|
|
268
|
-
case 'ArrowLeft': {
|
|
269
|
-
isSlideCarousel && slidePrevious()
|
|
270
|
-
isScrollCarousel &&
|
|
271
|
-
onScrollPagination(sliderState.currentPage - 1, 'previous')
|
|
272
|
-
break
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
case 'ArrowRight': {
|
|
276
|
-
isSlideCarousel && slideNext()
|
|
277
|
-
isScrollCarousel &&
|
|
278
|
-
onScrollPagination(sliderState.currentPage + 1, 'next')
|
|
279
|
-
break
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
case 'Home': {
|
|
283
|
-
slide(0, sliderDispatch)
|
|
284
|
-
break
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
case 'End': {
|
|
288
|
-
slide(childrenCount - 1, sliderDispatch)
|
|
289
|
-
break
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
default:
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
return (
|
|
297
|
-
<section
|
|
298
|
-
id={id}
|
|
299
|
-
data-fs-carousel
|
|
300
|
-
className={className}
|
|
301
|
-
data-testid={testId}
|
|
302
|
-
aria-label="carousel"
|
|
303
|
-
aria-roledescription="carousel"
|
|
304
|
-
>
|
|
305
|
-
<div
|
|
306
|
-
data-fs-carousel-track-container
|
|
307
|
-
style={{
|
|
308
|
-
width: '100%',
|
|
309
|
-
overflow: 'hidden',
|
|
310
|
-
display: isScrollCarousel ? 'block' : undefined,
|
|
311
|
-
}}
|
|
312
|
-
{...handlers}
|
|
313
|
-
>
|
|
314
|
-
<ul
|
|
315
|
-
aria-live="polite"
|
|
316
|
-
ref={carouselTrackRef}
|
|
317
|
-
style={carouselTrackStyle}
|
|
318
|
-
data-fs-carousel-track
|
|
319
|
-
onScroll={onScrollTrack}
|
|
320
|
-
onTransitionEnd={onTransitionTrackEnd}
|
|
321
|
-
>
|
|
322
|
-
{slides.map((currentSlide, idx) => (
|
|
323
|
-
<CarouselItem
|
|
324
|
-
index={idx}
|
|
325
|
-
key={String(idx)}
|
|
326
|
-
state={sliderState}
|
|
327
|
-
totalItems={childrenCount}
|
|
328
|
-
infiniteMode={infiniteMode}
|
|
329
|
-
isScrollCarousel={isScrollCarousel}
|
|
330
|
-
>
|
|
331
|
-
{currentSlide}
|
|
332
|
-
</CarouselItem>
|
|
333
|
-
))}
|
|
334
|
-
</ul>
|
|
335
|
-
</div>
|
|
336
|
-
|
|
337
|
-
{showNavigationArrows && (
|
|
338
|
-
<div data-fs-carousel-controls>
|
|
339
|
-
<IconButton
|
|
340
|
-
data-fs-carousel-control="left"
|
|
341
|
-
aria-controls={id}
|
|
342
|
-
aria-label="previous"
|
|
343
|
-
icon={navigationIcons?.left ?? <LeftArrowIcon />}
|
|
344
|
-
onClick={() => {
|
|
345
|
-
isSlideCarousel && slidePrevious()
|
|
346
|
-
isScrollCarousel &&
|
|
347
|
-
onScrollPagination(sliderState.currentPage - 1, 'previous')
|
|
348
|
-
}}
|
|
349
|
-
/>
|
|
350
|
-
<IconButton
|
|
351
|
-
data-fs-carousel-control="right"
|
|
352
|
-
aria-controls={id}
|
|
353
|
-
aria-label="next"
|
|
354
|
-
icon={navigationIcons?.right ?? <RightArrowIcon />}
|
|
355
|
-
onClick={() => {
|
|
356
|
-
isSlideCarousel && slideNext()
|
|
357
|
-
isScrollCarousel &&
|
|
358
|
-
onScrollPagination(sliderState.currentPage + 1, 'next')
|
|
359
|
-
}}
|
|
360
|
-
/>
|
|
361
|
-
</div>
|
|
362
|
-
)}
|
|
363
|
-
|
|
364
|
-
{showPaginationBullets && (
|
|
365
|
-
<div data-fs-carousel-bullets>
|
|
366
|
-
<Bullets
|
|
367
|
-
tabIndex={0}
|
|
368
|
-
activeBullet={sliderState.currentPage}
|
|
369
|
-
totalQuantity={Math.ceil(childrenCount / sliderState.itemsPerPage)}
|
|
370
|
-
onKeyDown={handleBulletsKeyDown}
|
|
371
|
-
onClick={async (_, idx) => {
|
|
372
|
-
isSlideCarousel &&
|
|
373
|
-
!sliderState.sliding &&
|
|
374
|
-
slide(idx, sliderDispatch)
|
|
375
|
-
|
|
376
|
-
isScrollCarousel && onScrollPagination(idx)
|
|
377
|
-
}}
|
|
378
|
-
onFocus={(event) => event.currentTarget.focus()}
|
|
379
|
-
ariaControlsGenerator={(idx) => `carousel-item-${idx}`}
|
|
380
|
-
/>
|
|
381
|
-
</div>
|
|
382
|
-
)}
|
|
383
|
-
</section>
|
|
384
|
-
)
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
export default Carousel
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
|
-
import type { CSSProperties, PropsWithChildren, HTMLAttributes } from 'react'
|
|
3
|
-
import type { SliderState } from '../../../hooks/useSlider/useSlider'
|
|
4
|
-
|
|
5
|
-
import useSlideVisibility from './hooks/useSlideVisibility'
|
|
6
|
-
|
|
7
|
-
interface CarouselItemProps extends HTMLAttributes<HTMLLIElement> {
|
|
8
|
-
index: number
|
|
9
|
-
totalItems: number
|
|
10
|
-
state: SliderState
|
|
11
|
-
infiniteMode: boolean
|
|
12
|
-
isScrollCarousel: boolean
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
function CarouselItem({
|
|
16
|
-
index,
|
|
17
|
-
state,
|
|
18
|
-
children,
|
|
19
|
-
totalItems,
|
|
20
|
-
infiniteMode,
|
|
21
|
-
isScrollCarousel,
|
|
22
|
-
}: PropsWithChildren<CarouselItemProps>) {
|
|
23
|
-
const { isItemVisible, shouldRenderItem } = useSlideVisibility({
|
|
24
|
-
totalItems,
|
|
25
|
-
currentSlide: state.currentItem,
|
|
26
|
-
itemsPerPage: state.itemsPerPage,
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
const style =
|
|
30
|
-
((!isScrollCarousel && { width: '100%' }) as CSSProperties) ||
|
|
31
|
-
((isScrollCarousel && {
|
|
32
|
-
maxWidth: '80%',
|
|
33
|
-
display: 'inline-block',
|
|
34
|
-
}) as CSSProperties)
|
|
35
|
-
|
|
36
|
-
const shouldDisplayItem =
|
|
37
|
-
isScrollCarousel || shouldRenderItem(index - Number(infiniteMode))
|
|
38
|
-
|
|
39
|
-
return (
|
|
40
|
-
<li
|
|
41
|
-
style={style}
|
|
42
|
-
data-fs-carousel-item
|
|
43
|
-
aria-roledescription="slide"
|
|
44
|
-
id={`carousel-item-${index}`}
|
|
45
|
-
data-fs-carousel-item-visible={
|
|
46
|
-
isItemVisible(index - Number(infiniteMode)) || undefined
|
|
47
|
-
}
|
|
48
|
-
>
|
|
49
|
-
{shouldDisplayItem ? children : null}
|
|
50
|
-
</li>
|
|
51
|
-
)
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export default CarouselItem
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { useRef, useEffect } from 'react'
|
|
2
|
-
|
|
3
|
-
export interface UseSlideVisibilityArgs {
|
|
4
|
-
currentSlide: number
|
|
5
|
-
itemsPerPage: number
|
|
6
|
-
totalItems: number
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
interface IsSlideVisibleArgs {
|
|
10
|
-
itemsPerPage: number
|
|
11
|
-
currentSlide: number
|
|
12
|
-
slideIdx: number
|
|
13
|
-
totalItems: number
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
function isSlideVisible({
|
|
17
|
-
itemsPerPage,
|
|
18
|
-
currentSlide,
|
|
19
|
-
slideIdx,
|
|
20
|
-
totalItems,
|
|
21
|
-
}: IsSlideVisibleArgs) {
|
|
22
|
-
const isClonedSlide = currentSlide < 0 || currentSlide >= totalItems
|
|
23
|
-
const isVisible =
|
|
24
|
-
slideIdx >= currentSlide && slideIdx < currentSlide + itemsPerPage
|
|
25
|
-
|
|
26
|
-
return isClonedSlide || isVisible
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export default function useSlideVisibility({
|
|
30
|
-
currentSlide,
|
|
31
|
-
itemsPerPage,
|
|
32
|
-
totalItems,
|
|
33
|
-
}: UseSlideVisibilityArgs) {
|
|
34
|
-
/** Keeps track of slides that have been visualized before.
|
|
35
|
-
* We want to keep rendering them because the issue is mostly rendering
|
|
36
|
-
* slides that might never be viewed; On the other hand, hiding slides
|
|
37
|
-
* that were visible causes visual glitches */
|
|
38
|
-
const visitedSlides = useRef<Set<number>>(new Set())
|
|
39
|
-
|
|
40
|
-
useEffect(() => {
|
|
41
|
-
for (let i = 0; i < itemsPerPage; i++) {
|
|
42
|
-
visitedSlides.current.add(currentSlide + i)
|
|
43
|
-
}
|
|
44
|
-
}, [currentSlide, itemsPerPage])
|
|
45
|
-
|
|
46
|
-
const isItemVisible = (index: number) =>
|
|
47
|
-
isSlideVisible({
|
|
48
|
-
slideIdx: index,
|
|
49
|
-
currentSlide,
|
|
50
|
-
itemsPerPage,
|
|
51
|
-
totalItems,
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
const shouldRenderItem = (index: number) => {
|
|
55
|
-
return visitedSlides.current.has(index) || isItemVisible(index)
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return { shouldRenderItem, isItemVisible }
|
|
59
|
-
}
|