@faststore/components 2.0.123-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.
Files changed (33) hide show
  1. package/dist/hooks/index.d.ts +3 -0
  2. package/dist/hooks/index.js +2 -0
  3. package/dist/hooks/index.js.map +1 -1
  4. package/dist/hooks/useSlideVisibility.d.ts +9 -0
  5. package/dist/hooks/useSlideVisibility.js +29 -0
  6. package/dist/hooks/useSlideVisibility.js.map +1 -0
  7. package/dist/hooks/useSlider.d.ts +64 -0
  8. package/dist/hooks/useSlider.js +103 -0
  9. package/dist/hooks/useSlider.js.map +1 -0
  10. package/dist/index.d.ts +2 -0
  11. package/dist/index.js +1 -0
  12. package/dist/index.js.map +1 -1
  13. package/dist/molecules/Carousel/Carousel.d.ts +54 -0
  14. package/dist/molecules/Carousel/Carousel.js +184 -0
  15. package/dist/molecules/Carousel/Carousel.js.map +1 -0
  16. package/dist/molecules/Carousel/CarouselBullets.d.ts +35 -0
  17. package/dist/molecules/Carousel/CarouselBullets.js +12 -0
  18. package/dist/molecules/Carousel/CarouselBullets.js.map +1 -0
  19. package/dist/molecules/Carousel/CarouselItem.d.ts +11 -0
  20. package/dist/molecules/Carousel/CarouselItem.js +18 -0
  21. package/dist/molecules/Carousel/CarouselItem.js.map +1 -0
  22. package/dist/molecules/Carousel/index.d.ts +6 -0
  23. package/dist/molecules/Carousel/index.js +4 -0
  24. package/dist/molecules/Carousel/index.js.map +1 -0
  25. package/package.json +2 -2
  26. package/src/hooks/index.ts +10 -0
  27. package/src/hooks/useSlideVisibility.ts +59 -0
  28. package/src/hooks/useSlider.ts +209 -0
  29. package/src/index.ts +12 -0
  30. package/src/molecules/Carousel/Carousel.tsx +396 -0
  31. package/src/molecules/Carousel/CarouselBullets.tsx +90 -0
  32. package/src/molecules/Carousel/CarouselItem.tsx +52 -0
  33. package/src/molecules/Carousel/index.ts +8 -0
@@ -0,0 +1,4 @@
1
+ export { default } from './Carousel';
2
+ export { default as CarouselItem } from './CarouselItem';
3
+ export { default as CarouselBullets } from './CarouselBullets';
4
+ //# sourceMappingURL=index.js.map
@@ -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.123-alpha.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": "1fa54ca9614dde12ba99a2870273e1797986ee16"
33
+ "gitHead": "45fb6de9e708a927326715d9de3b46a8030dc3bd"
34
34
  }
@@ -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,