@faststore/components 2.0.122-alpha.0 → 2.0.128-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/atoms/Icon/Icon.d.ts +13 -1
- package/dist/atoms/Icon/Icon.js +1 -1
- package/dist/atoms/Icon/Icon.js.map +1 -1
- package/dist/hooks/index.d.ts +3 -0
- package/dist/hooks/index.js +2 -0
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/useSlideVisibility.d.ts +9 -0
- package/dist/hooks/useSlideVisibility.js +29 -0
- package/dist/hooks/useSlideVisibility.js.map +1 -0
- package/dist/hooks/useSlider.d.ts +64 -0
- package/dist/hooks/useSlider.js +103 -0
- package/dist/hooks/useSlider.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/molecules/Carousel/Carousel.d.ts +54 -0
- package/dist/molecules/Carousel/Carousel.js +184 -0
- package/dist/molecules/Carousel/Carousel.js.map +1 -0
- package/dist/molecules/Carousel/CarouselBullets.d.ts +35 -0
- package/dist/molecules/Carousel/CarouselBullets.js +12 -0
- package/dist/molecules/Carousel/CarouselBullets.js.map +1 -0
- package/dist/molecules/Carousel/CarouselItem.d.ts +11 -0
- package/dist/molecules/Carousel/CarouselItem.js +18 -0
- package/dist/molecules/Carousel/CarouselItem.js.map +1 -0
- package/dist/molecules/Carousel/index.d.ts +6 -0
- package/dist/molecules/Carousel/index.js +4 -0
- package/dist/molecules/Carousel/index.js.map +1 -0
- package/package.json +2 -2
- package/src/atoms/Icon/Icon.tsx +14 -2
- package/src/hooks/index.ts +10 -0
- package/src/hooks/useSlideVisibility.ts +59 -0
- package/src/hooks/useSlider.ts +209 -0
- package/src/index.ts +12 -0
- package/src/molecules/Carousel/Carousel.tsx +396 -0
- package/src/molecules/Carousel/CarouselBullets.tsx +90 -0
- package/src/molecules/Carousel/CarouselItem.tsx +52 -0
- package/src/molecules/Carousel/index.ts +8 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React, { forwardRef, useMemo } from 'react';
|
|
2
|
+
import { Button } from '../..';
|
|
3
|
+
const defaultAriaLabel = (idx, isActive) => isActive ? 'Current page' : `Go to page ${idx + 1}`;
|
|
4
|
+
const CarouselBullets = forwardRef(function Bullets({ totalQuantity, activeBullet, onClick, testId = 'fs-carousel-bullets', ariaLabelGenerator = defaultAriaLabel, ariaControlsGenerator, ...otherProps }, ref) {
|
|
5
|
+
const bulletIndexes = useMemo(() => Array(totalQuantity).fill(0), [totalQuantity]);
|
|
6
|
+
return (React.createElement("div", { ref: ref, "data-fs-carousel-bullets": true, "data-testid": testId, role: "tablist", ...otherProps }, bulletIndexes.map((_, idx) => {
|
|
7
|
+
const isActive = activeBullet === idx;
|
|
8
|
+
return (React.createElement(Button, { key: idx, role: "tab", tabIndex: -1, "data-fs-carousel-bullet": true, testId: `${testId}-bullet`, onClick: (e) => onClick(e, idx), "aria-label": ariaLabelGenerator(idx, isActive), "aria-controls": ariaControlsGenerator?.(idx), "aria-selected": isActive }));
|
|
9
|
+
})));
|
|
10
|
+
});
|
|
11
|
+
export default CarouselBullets;
|
|
12
|
+
//# sourceMappingURL=CarouselBullets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CarouselBullets.js","sourceRoot":"","sources":["../../../src/molecules/Carousel/CarouselBullets.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,OAAO,CAAA;AAElD,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,CAAA;AAmC9B,MAAM,gBAAgB,GAAG,CAAC,GAAW,EAAE,QAAiB,EAAE,EAAE,CAC1D,QAAQ,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,cAAc,GAAG,GAAG,CAAC,EAAE,CAAA;AAErD,MAAM,eAAe,GAAG,UAAU,CAChC,SAAS,OAAO,CACd,EACE,aAAa,EACb,YAAY,EACZ,OAAO,EACP,MAAM,GAAG,qBAAqB,EAC9B,kBAAkB,GAAG,gBAAgB,EACrC,qBAAqB,EACrB,GAAG,UAAU,EACd,EACD,GAAG;IAEH,MAAM,aAAa,GAAG,OAAO,CAC3B,GAAG,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAClC,CAAC,aAAa,CAAC,CAChB,CAAA;IAED,OAAO,CACL,6BACE,GAAG,EAAE,GAAG,mDAEK,MAAM,EACnB,IAAI,EAAC,SAAS,KACV,UAAU,IAEb,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE;QAC5B,MAAM,QAAQ,GAAG,YAAY,KAAK,GAAG,CAAA;QAErC,OAAO,CACL,oBAAC,MAAM,IACL,GAAG,EAAE,GAAG,EACR,IAAI,EAAC,KAAK,EACV,QAAQ,EAAE,CAAC,CAAC,mCAEZ,MAAM,EAAE,GAAG,MAAM,SAAS,EAC1B,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE,GAAG,CAAC,gBACnB,kBAAkB,CAAC,GAAG,EAAE,QAAQ,CAAC,mBAC9B,qBAAqB,EAAE,CAAC,GAAG,CAAC,mBAC5B,QAAQ,GACvB,CACH,CAAA;IACH,CAAC,CAAC,CACE,CACP,CAAA;AACH,CAAC,CACF,CAAA;AAED,eAAe,eAAe,CAAA"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { PropsWithChildren, HTMLAttributes } from 'react';
|
|
2
|
+
import { SliderState } from '../../hooks';
|
|
3
|
+
export interface CarouselItemProps extends HTMLAttributes<HTMLLIElement> {
|
|
4
|
+
index: number;
|
|
5
|
+
totalItems: number;
|
|
6
|
+
state: SliderState;
|
|
7
|
+
infiniteMode: boolean;
|
|
8
|
+
isScrollCarousel: boolean;
|
|
9
|
+
}
|
|
10
|
+
declare function CarouselItem({ index, state, children, totalItems, infiniteMode, isScrollCarousel, }: PropsWithChildren<CarouselItemProps>): JSX.Element;
|
|
11
|
+
export default CarouselItem;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { useSlideVisibility } from '../../hooks';
|
|
3
|
+
function CarouselItem({ index, state, children, totalItems, infiniteMode, isScrollCarousel, }) {
|
|
4
|
+
const { isItemVisible, shouldRenderItem } = useSlideVisibility({
|
|
5
|
+
totalItems,
|
|
6
|
+
currentSlide: state.currentItem,
|
|
7
|
+
itemsPerPage: state.itemsPerPage,
|
|
8
|
+
});
|
|
9
|
+
const style = (!isScrollCarousel && { width: '100%' }) ||
|
|
10
|
+
(isScrollCarousel && {
|
|
11
|
+
maxWidth: '60%',
|
|
12
|
+
display: 'inline-block',
|
|
13
|
+
});
|
|
14
|
+
const shouldDisplayItem = isScrollCarousel || shouldRenderItem(index - Number(infiniteMode));
|
|
15
|
+
return (React.createElement("li", { style: style, "data-fs-carousel-item": true, "aria-roledescription": "slide", id: `carousel-item-${index}`, "data-fs-carousel-item-visible": isItemVisible(index - Number(infiniteMode)) || undefined }, shouldDisplayItem ? children : null));
|
|
16
|
+
}
|
|
17
|
+
export default CarouselItem;
|
|
18
|
+
//# sourceMappingURL=CarouselItem.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CarouselItem.js","sourceRoot":"","sources":["../../../src/molecules/Carousel/CarouselItem.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,EAAE,kBAAkB,EAAe,MAAM,aAAa,CAAA;AAU7D,SAAS,YAAY,CAAC,EACpB,KAAK,EACL,KAAK,EACL,QAAQ,EACR,UAAU,EACV,YAAY,EACZ,gBAAgB,GACqB;IACrC,MAAM,EAAE,aAAa,EAAE,gBAAgB,EAAE,GAAG,kBAAkB,CAAC;QAC7D,UAAU;QACV,YAAY,EAAE,KAAK,CAAC,WAAW;QAC/B,YAAY,EAAE,KAAK,CAAC,YAAY;KACjC,CAAC,CAAA;IAEF,MAAM,KAAK,GACR,CAAC,CAAC,gBAAgB,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,CAAmB;QAC1D,CAAC,gBAAgB,IAAI;YACpB,QAAQ,EAAE,KAAK;YACf,OAAO,EAAE,cAAc;SACxB,CAAmB,CAAA;IAEtB,MAAM,iBAAiB,GACrB,gBAAgB,IAAI,gBAAgB,CAAC,KAAK,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC,CAAA;IAEpE,OAAO,CACL,4BACE,KAAK,EAAE,KAAK,yDAES,OAAO,EAC5B,EAAE,EAAE,iBAAiB,KAAK,EAAE,mCAE1B,aAAa,CAAC,KAAK,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC,IAAI,SAAS,IAGzD,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CACjC,CACN,CAAA;AACH,CAAC;AAED,eAAe,YAAY,CAAA"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { default } from './Carousel';
|
|
2
|
+
export type { CarouselProps } from './Carousel';
|
|
3
|
+
export { default as CarouselItem } from './CarouselItem';
|
|
4
|
+
export type { CarouselItemProps } from './CarouselItem';
|
|
5
|
+
export { default as CarouselBullets } from './CarouselBullets';
|
|
6
|
+
export type { CarouselBulletsProps } from './CarouselBullets';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/molecules/Carousel/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAGpC,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAGxD,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,mBAAmB,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@faststore/components",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.128-alpha.0",
|
|
4
4
|
"module": "dist/index.js",
|
|
5
5
|
"typings": "dist/index.d.ts",
|
|
6
6
|
"author": "Emerson Laurentino @emersonlaurentino",
|
|
@@ -30,5 +30,5 @@
|
|
|
30
30
|
"node": "16.18.0",
|
|
31
31
|
"yarn": "1.19.1"
|
|
32
32
|
},
|
|
33
|
-
"gitHead": "
|
|
33
|
+
"gitHead": "45fb6de9e708a927326715d9de3b46a8030dc3bd"
|
|
34
34
|
}
|
package/src/atoms/Icon/Icon.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { SVGProps } from 'react'
|
|
2
|
-
import React, { forwardRef } from
|
|
2
|
+
import React, { forwardRef } from 'react'
|
|
3
3
|
|
|
4
4
|
type IconWeight = 'thin' | 'light' | 'regular' | 'bold'
|
|
5
5
|
|
|
@@ -27,13 +27,25 @@ export interface IconProps extends SVGProps<SVGSVGElement> {
|
|
|
27
27
|
* @default 'regular'
|
|
28
28
|
*/
|
|
29
29
|
weight?: IconWeight
|
|
30
|
+
/**
|
|
31
|
+
* SVG width.
|
|
32
|
+
*
|
|
33
|
+
* @default '24'
|
|
34
|
+
*/
|
|
35
|
+
width?: number
|
|
36
|
+
/**
|
|
37
|
+
* SVG height.
|
|
38
|
+
*
|
|
39
|
+
* @default '24'
|
|
40
|
+
*/
|
|
41
|
+
height?: number
|
|
30
42
|
}
|
|
31
43
|
|
|
32
44
|
const Icon = forwardRef<SVGSVGElement, IconProps>(function Icon(
|
|
33
45
|
{ testId = 'fs-icon', name, weight = 'regular', ...otherProps }: IconProps,
|
|
34
46
|
ref
|
|
35
47
|
) {
|
|
36
|
-
const {width, height} = otherProps
|
|
48
|
+
const { width, height } = otherProps
|
|
37
49
|
return (
|
|
38
50
|
<svg
|
|
39
51
|
ref={ref}
|
package/src/hooks/index.ts
CHANGED
|
@@ -3,3 +3,13 @@ export { useFadeEffect } from './useFadeEffect'
|
|
|
3
3
|
export { useTrapFocus } from './useTrapFocus'
|
|
4
4
|
export { useSearch } from './useSearch'
|
|
5
5
|
export { useScrollDirection } from './useScrollDirection'
|
|
6
|
+
export { useSlider } from './useSlider'
|
|
7
|
+
export type {
|
|
8
|
+
UseSliderArgs,
|
|
9
|
+
SliderState,
|
|
10
|
+
SliderDispatch,
|
|
11
|
+
SlideDirection,
|
|
12
|
+
} from './useSlider'
|
|
13
|
+
export { useSlideVisibility } from './useSlideVisibility'
|
|
14
|
+
|
|
15
|
+
|
|
@@ -0,0 +1,59 @@
|
|
|
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 const 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
|
+
}
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import type { Dispatch } from 'react'
|
|
2
|
+
import { useReducer } from 'react'
|
|
3
|
+
import type { SwipeableProps } from 'react-swipeable'
|
|
4
|
+
import { useSwipeable } from 'react-swipeable'
|
|
5
|
+
|
|
6
|
+
export type SlideDirection = 'next' | 'previous'
|
|
7
|
+
|
|
8
|
+
interface NextPageAction {
|
|
9
|
+
type: 'NEXT_PAGE'
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
interface PreviousPageAction {
|
|
13
|
+
type: 'PREVIOUS_PAGE'
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface GoToPageAction {
|
|
17
|
+
type: 'GO_TO_PAGE'
|
|
18
|
+
payload: {
|
|
19
|
+
pageIndex: number
|
|
20
|
+
shouldSlide: boolean
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface StopSlideAction {
|
|
25
|
+
type: 'STOP_SLIDE'
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export type Action =
|
|
29
|
+
| NextPageAction
|
|
30
|
+
| PreviousPageAction
|
|
31
|
+
| StopSlideAction
|
|
32
|
+
| GoToPageAction
|
|
33
|
+
|
|
34
|
+
export type SliderDispatch = Dispatch<Action>
|
|
35
|
+
|
|
36
|
+
export interface SliderState {
|
|
37
|
+
/**
|
|
38
|
+
* The `currentItem` in a Slider with multiple items in a single page is
|
|
39
|
+
* always **the one with the lowest index** in the current page.
|
|
40
|
+
*/
|
|
41
|
+
currentItem: number
|
|
42
|
+
/** Currently active page */
|
|
43
|
+
currentPage: number
|
|
44
|
+
/**
|
|
45
|
+
* Whether or not the Slider is currently sliding. This is useful to
|
|
46
|
+
* manipulate the `transition` property in a component.
|
|
47
|
+
*/
|
|
48
|
+
sliding: boolean
|
|
49
|
+
/** The direction in which the Slider is sliding. */
|
|
50
|
+
slideDirection: SlideDirection
|
|
51
|
+
/** The total number of unique items in the slider. */
|
|
52
|
+
totalItems: number
|
|
53
|
+
/** The number of items in a single page. */
|
|
54
|
+
itemsPerPage: number
|
|
55
|
+
/** The total number of pages in the slider. */
|
|
56
|
+
totalPages: number
|
|
57
|
+
/** Whether or not the slider is infinite. */
|
|
58
|
+
infinite: boolean
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export const nextPage = (current: number, total: number) =>
|
|
62
|
+
(current + 1) % total
|
|
63
|
+
|
|
64
|
+
export const previousPage = (current: number, total: number) =>
|
|
65
|
+
(total - ((total - current + 1) % total)) % total
|
|
66
|
+
|
|
67
|
+
function reducer(state: SliderState, action: Action): SliderState {
|
|
68
|
+
switch (action.type) {
|
|
69
|
+
case 'NEXT_PAGE': {
|
|
70
|
+
// If `state.infinite` is true, we need to take into account an extra
|
|
71
|
+
// page in the calculation. This extra page is a clone of the first page.
|
|
72
|
+
const adjustedTotalPages = state.infinite
|
|
73
|
+
? state.totalPages + 1
|
|
74
|
+
: state.totalPages
|
|
75
|
+
|
|
76
|
+
const nextPageIndex = nextPage(state.currentPage, adjustedTotalPages)
|
|
77
|
+
|
|
78
|
+
const nextItemIndex =
|
|
79
|
+
(nextPageIndex % adjustedTotalPages) * state.itemsPerPage
|
|
80
|
+
|
|
81
|
+
return {
|
|
82
|
+
...state,
|
|
83
|
+
sliding: true,
|
|
84
|
+
slideDirection: 'next',
|
|
85
|
+
currentItem: nextItemIndex,
|
|
86
|
+
currentPage: nextPageIndex,
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
case 'PREVIOUS_PAGE': {
|
|
91
|
+
// If `state.infinite` is true, we need to take into account an extra
|
|
92
|
+
// page in the calculation. This extra page is a clone of the first page.
|
|
93
|
+
const adjustedTotalPages = state.infinite
|
|
94
|
+
? state.totalPages + 1
|
|
95
|
+
: state.totalPages
|
|
96
|
+
|
|
97
|
+
// If `state.infinite` is true and we're currently on page 0, we need to
|
|
98
|
+
// let the slider go to page -1. This -1 page is a clone of the last page.
|
|
99
|
+
const shouldGoToClone = state.infinite && state.currentPage === 0
|
|
100
|
+
const previousPageIndex = shouldGoToClone
|
|
101
|
+
? -1
|
|
102
|
+
: previousPage(state.currentPage, state.totalPages)
|
|
103
|
+
|
|
104
|
+
return {
|
|
105
|
+
...state,
|
|
106
|
+
sliding: true,
|
|
107
|
+
slideDirection: 'previous',
|
|
108
|
+
currentItem:
|
|
109
|
+
(previousPageIndex % adjustedTotalPages) * state.itemsPerPage,
|
|
110
|
+
currentPage: previousPageIndex,
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
case 'GO_TO_PAGE': {
|
|
115
|
+
if (action.payload.pageIndex === state.currentPage) {
|
|
116
|
+
return state
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return {
|
|
120
|
+
...state,
|
|
121
|
+
sliding: action.payload.shouldSlide,
|
|
122
|
+
slideDirection:
|
|
123
|
+
action.payload.pageIndex > state.currentPage ? 'next' : 'previous',
|
|
124
|
+
currentItem:
|
|
125
|
+
(action.payload.pageIndex % state.totalPages) * state.itemsPerPage,
|
|
126
|
+
currentPage: action.payload.pageIndex,
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
case 'STOP_SLIDE':
|
|
131
|
+
return { ...state, sliding: false }
|
|
132
|
+
|
|
133
|
+
default:
|
|
134
|
+
return state
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const defaultSliderState = (
|
|
139
|
+
totalItems: number,
|
|
140
|
+
itemsPerPage: number,
|
|
141
|
+
infinite: boolean
|
|
142
|
+
): SliderState => ({
|
|
143
|
+
currentItem: 0,
|
|
144
|
+
currentPage: 0,
|
|
145
|
+
sliding: false,
|
|
146
|
+
slideDirection: 'next',
|
|
147
|
+
totalItems,
|
|
148
|
+
itemsPerPage,
|
|
149
|
+
totalPages: Math.ceil(totalItems / itemsPerPage),
|
|
150
|
+
infinite,
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
const slide = (page: SlideDirection | number, dispatch: Dispatch<Action>) => {
|
|
154
|
+
if (page === 'next') {
|
|
155
|
+
dispatch({ type: 'NEXT_PAGE' })
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (page === 'previous') {
|
|
159
|
+
dispatch({ type: 'PREVIOUS_PAGE' })
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (typeof page === 'number') {
|
|
163
|
+
dispatch({
|
|
164
|
+
type: 'GO_TO_PAGE',
|
|
165
|
+
payload: {
|
|
166
|
+
pageIndex: page,
|
|
167
|
+
shouldSlide: true,
|
|
168
|
+
},
|
|
169
|
+
})
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export interface UseSliderArgs extends SwipeableProps {
|
|
174
|
+
/** The total number of unique items in the slider. */
|
|
175
|
+
totalItems: number
|
|
176
|
+
/** The number of items in a single slider page. */
|
|
177
|
+
itemsPerPage?: number
|
|
178
|
+
/** Whether or not the slider is infinite. */
|
|
179
|
+
infiniteMode?: boolean
|
|
180
|
+
/** Whether or not slide after swiping left/right. */
|
|
181
|
+
shouldSlideOnSwipe?: boolean
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export const useSlider = ({
|
|
185
|
+
totalItems,
|
|
186
|
+
itemsPerPage = 1,
|
|
187
|
+
infiniteMode = false,
|
|
188
|
+
shouldSlideOnSwipe = true,
|
|
189
|
+
...swipeableConfigOverrides
|
|
190
|
+
}: UseSliderArgs) => {
|
|
191
|
+
const [sliderState, sliderDispatch] = useReducer(reducer, undefined, () =>
|
|
192
|
+
defaultSliderState(totalItems, itemsPerPage, infiniteMode)
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
const handlers = useSwipeable({
|
|
196
|
+
onSwipedRight: () =>
|
|
197
|
+
shouldSlideOnSwipe && slide('previous', sliderDispatch),
|
|
198
|
+
onSwipedLeft: () => shouldSlideOnSwipe && slide('next', sliderDispatch),
|
|
199
|
+
trackMouse: true,
|
|
200
|
+
...swipeableConfigOverrides,
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
return {
|
|
204
|
+
handlers,
|
|
205
|
+
slide,
|
|
206
|
+
sliderState,
|
|
207
|
+
sliderDispatch,
|
|
208
|
+
}
|
|
209
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -55,6 +55,18 @@ export type {
|
|
|
55
55
|
BreadcrumbProps,
|
|
56
56
|
} from './molecules/Breadcrumb'
|
|
57
57
|
export { default as BuyButton } from './molecules/BuyButton'
|
|
58
|
+
|
|
59
|
+
export {
|
|
60
|
+
default as Carousel,
|
|
61
|
+
CarouselItem,
|
|
62
|
+
CarouselBullets,
|
|
63
|
+
} from './molecules/Carousel'
|
|
64
|
+
export type {
|
|
65
|
+
CarouselProps,
|
|
66
|
+
CarouselItemProps,
|
|
67
|
+
CarouselBulletsProps,
|
|
68
|
+
} from './molecules/Carousel'
|
|
69
|
+
|
|
58
70
|
export {
|
|
59
71
|
default as CartItem,
|
|
60
72
|
CartItemImage,
|