@codeleap/mobile 4.0.1 → 4.1.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codeleap/mobile",
3
- "version": "4.0.1",
3
+ "version": "4.1.0",
4
4
  "main": "src/index.ts",
5
5
  "license": "UNLICENSED",
6
6
  "repository": {
@@ -9,8 +9,8 @@
9
9
  "directory": "packages/mobile"
10
10
  },
11
11
  "devDependencies": {
12
- "@codeleap/config": "*",
13
- "@codeleap/common": "*"
12
+ "@codeleap/common": "*",
13
+ "@codeleap/config": "*"
14
14
  },
15
15
  "scripts": {
16
16
  "build": "tsc --build",
@@ -28,24 +28,27 @@
28
28
  "@react-navigation/stack": "6.3.11",
29
29
  "react": "18.1.0",
30
30
  "react-native": "0.73.8",
31
+ "react-native-avoid-softinput": "3.1.5",
31
32
  "react-native-calendars": "1.1293.0",
32
33
  "react-native-date-picker": "4.2.13",
33
34
  "react-native-device-info": "10.3.0",
34
35
  "react-native-fast-image": "8.6.3",
35
36
  "react-native-gesture-handler": "2.9.0",
36
37
  "react-native-image-crop-picker": "0.37.2",
37
- "react-native-super-grid": "4.6.1",
38
38
  "react-native-image-viewing": "0.2.2",
39
39
  "react-native-keyboard-aware-scroll-view": "0.9.5",
40
- "typescript": "5.0.4",
41
- "react-native-avoid-softinput": "3.1.5",
42
- "react-native-mmkv": "2.12.2"
40
+ "react-native-mmkv": "2.12.2",
41
+ "react-native-super-grid": "4.6.1",
42
+ "typescript": "5.0.4"
43
43
  },
44
44
  "dependencies": {
45
45
  "@gorhom/portal": "1.0.14",
46
46
  "@miblanchard/react-native-slider": "2.3.1",
47
47
  "date-fns": "2.29.3",
48
+ "react-native-currency-input": "^1.1.1",
49
+ "react-native-drag-sort": "^2.4.4",
48
50
  "react-native-masked-text": "1.13.0",
51
+ "react-native-reanimated-carousel": "^3.5.1",
49
52
  "react-native-uuid": "2.0.1"
50
53
  }
51
54
  }
@@ -1,5 +1,5 @@
1
1
  import React, { useRef } from 'react'
2
- import { TypeGuards, useBooleanToggle, useI18N } from '@codeleap/common'
2
+ import { TypeGuards, useConditionalState, useI18N } from '@codeleap/common'
3
3
  import DatePicker from 'react-native-date-picker'
4
4
  import Modal from '../Modal'
5
5
  import { TextInput } from '../TextInput'
@@ -116,7 +116,8 @@ export const DatePickerModal = (props: DatePickerModalProps) => {
116
116
 
117
117
  const styles = useStylesFor(DatePickerModal.styleRegistryName, style)
118
118
 
119
- const [visible, toggle] = !TypeGuards.isNil(_visible) && !!_toggle ? [_visible, _toggle] : useBooleanToggle(false)
119
+ const [visible, toggle] = useConditionalState(_visible, _toggle, { initialValue: false, isBooleanToggle: true })
120
+
120
121
  const [value, setValue] = [_value, onValueChange]
121
122
 
122
123
  const Wrapper = isCustomModal ? ModalManager.Modal : React.Fragment
@@ -95,12 +95,12 @@ const _FileInput = forwardRef<FileInputRef, FileInputProps>((fileInputProps, ref
95
95
  }
96
96
  }
97
97
 
98
- const openFilePicker = async (imageSource = null) => {
98
+ const openFilePicker = async (imageSource = null, options = {}) => {
99
99
  if (type === 'image') {
100
100
  if (imageSource === 'camera') {
101
- onPress('camera')
101
+ onPress('camera', options)
102
102
  } else if (imageSource === 'library') {
103
- onPress('library')
103
+ onPress('library', options)
104
104
  } else {
105
105
  OSAlert.ask({
106
106
  title: 'Change Image',
@@ -150,8 +150,8 @@ const _FileInput = forwardRef<FileInputRef, FileInputProps>((fileInputProps, ref
150
150
  }
151
151
 
152
152
  useImperativeHandle(ref, () => ({
153
- openFilePicker: (imageSource: FileInputImageSource = null) => {
154
- openFilePicker(imageSource)
153
+ openFilePicker: (imageSource: FileInputImageSource = null, options: Partial<Options> = {}) => {
154
+ openFilePicker(imageSource, options)
155
155
  return new Promise<FileResult[]>((resolve) => {
156
156
  resolveWithFile.current = resolve
157
157
  })
@@ -166,8 +166,8 @@ export const FileInput = _FileInput as unknown as ((props: FileInputProps) => JS
166
166
  export const useFileInput = () => {
167
167
  const inputRef = useRef<FileInputRef>(null)
168
168
 
169
- const openFilePicker = (imageSource: FileInputImageSource = null): Promise<FileResult[]> => {
170
- return inputRef.current?.openFilePicker(imageSource)
169
+ const openFilePicker = (imageSource: FileInputImageSource = null, options: Partial<Options> = {}): Promise<FileResult[]> => {
170
+ return inputRef.current?.openFilePicker(imageSource, options)
171
171
  }
172
172
 
173
173
  return {
@@ -8,7 +8,7 @@ export type FileInputImageSource = 'camera' | 'library' | 'fs'
8
8
  export type FileResult = FormTypes.AnyFile
9
9
 
10
10
  export type FileInputRef = {
11
- openFilePicker: (string?: FileInputImageSource) => Promise<FileResult[]>
11
+ openFilePicker: (source?: FileInputImageSource, options?: Partial<Options>) => Promise<FileResult[]>
12
12
  }
13
13
 
14
14
  export type FileInputProps = {
@@ -11,6 +11,7 @@ import { NumberIncrementProps } from './types'
11
11
  import { AnyRecord, AppIcon, IJSX, StyledComponentProps, StyledComponentWithProps } from '@codeleap/styles'
12
12
  import { MobileStyleRegistry } from '../../Registry'
13
13
  import { useStylesFor } from '../../hooks'
14
+ import CurrencyInput from 'react-native-currency-input'
14
15
 
15
16
  export * from './styles'
16
17
  export * from './types'
@@ -58,6 +59,7 @@ export const NumberIncrement = forwardRef<NativeTextInput, NumberIncrementProps>
58
59
  timeoutActionFocus,
59
60
  mask,
60
61
  actionDebounce,
62
+ precision,
61
63
  ...textInputProps
62
64
  } = others
63
65
 
@@ -73,11 +75,13 @@ export const NumberIncrement = forwardRef<NativeTextInput, NumberIncrementProps>
73
75
 
74
76
  const isFormatted = TypeGuards.isFunction(formatter)
75
77
 
76
- const hasMaskProps = [masking, prefix, suffix, delimiter, separator, mask].some(v => !!v)
78
+ const hasMaskProps = [masking, mask].some(v => !!v)
79
+ const hasCurrencyProps = [prefix, suffix, delimiter, separator, precision].some(v => !!v)
77
80
 
78
- const isMasked = hasMaskProps && !isFormatted
81
+ const isCurrency = hasCurrencyProps
82
+ const isMasked = hasMaskProps && !isFormatted && !isCurrency
79
83
 
80
- const InputElement = isMasked ? MaskedTextInput : NativeTextInput
84
+ const InputElement: any = isMasked ? MaskedTextInput : isCurrency ? CurrencyInput : NativeTextInput
81
85
 
82
86
  // @ts-expect-error - React's ref type system is weird
83
87
  useImperativeHandle(inputRef, () => {
@@ -219,6 +223,19 @@ export const NumberIncrement = forwardRef<NativeTextInput, NumberIncrementProps>
219
223
  },
220
224
  } : {}
221
225
 
226
+ const currencyExtraProps = isCurrency ? {
227
+ value,
228
+ onChangeText: null,
229
+ onChangeValue: onChange,
230
+ prefix: prefix,
231
+ separator: separator ?? '.',
232
+ suffix: suffix,
233
+ delimiter: delimiter ?? ',',
234
+ minValue: min,
235
+ maxValue: max,
236
+ precision,
237
+ } : {}
238
+
222
239
  const onPressInnerWrapper = () => {
223
240
  handleFocus()
224
241
  if (editable) innerInputRef.current?.focus?.()
@@ -270,6 +287,7 @@ export const NumberIncrement = forwardRef<NativeTextInput, NumberIncrementProps>
270
287
  style={inputTextStyle}
271
288
  ref={innerInputRef}
272
289
  {...maskingExtraProps}
290
+ {...currencyExtraProps}
273
291
  />
274
292
  ) : (
275
293
  <Text
@@ -26,6 +26,7 @@ export type NumberIncrementProps =
26
26
  suffix?: MaskOptions['suffixUnit']
27
27
  separator?: MaskOptions['separator']
28
28
  delimiter?: MaskOptions['delimiter']
29
+ precision?: number
29
30
  mask?: MaskOptions['mask']
30
31
  formatter?: (value: string | number) => string
31
32
  parseValue?: (value: string) => number
@@ -0,0 +1,56 @@
1
+ import { AnyFunction, StylesOf } from '@codeleap/common'
2
+ import Animated, { useAnimatedStyle } from 'react-native-reanimated'
3
+ import { Touchable } from '../Touchable'
4
+ import { View } from '../View'
5
+ import { DotComposition } from './styles'
6
+
7
+ export type PagerDot = {
8
+ onPress: AnyFunction
9
+ isActive: boolean
10
+ index: number
11
+ styles: StylesOf<DotComposition>
12
+ }
13
+
14
+ function Dot({ onPress, isActive, index, styles }: PagerDot) {
15
+ const animation = useAnimatedStyle(() => {
16
+ const scale = isActive ? 1 : 0.6
17
+ return {
18
+ transform: [{ scale }],
19
+ ...(isActive ? styles['dot:active'] : styles.dot),
20
+ }
21
+ })
22
+
23
+ return (
24
+ <Touchable
25
+ debugName={`default-pager-dot-touchable-${index}`}
26
+ onPress={onPress}
27
+ noFeedback
28
+ style={[styles.touchable, isActive && styles['touchable:active']]}
29
+ >
30
+ <Animated.View style={[animation, styles.dot]} />
31
+ </Touchable>
32
+ )
33
+ }
34
+
35
+ export type PagerDots = {
36
+ styles: StylesOf<DotComposition>
37
+ currentPage: number
38
+ setCurrentPage: (page: number) => void
39
+ pages: Array<any>
40
+ }
41
+
42
+ export function PagerDots({ styles, currentPage, setCurrentPage, pages }: PagerDots) {
43
+ return (
44
+ <View style={styles.wrapper}>
45
+ {pages?.map((_, i) => (
46
+ <Dot
47
+ key={`default-pager-dots-index-${i}`}
48
+ index={i}
49
+ onPress={() => setCurrentPage(i)}
50
+ isActive={i === currentPage}
51
+ styles={styles}
52
+ />
53
+ ))}
54
+ </View>
55
+ )
56
+ }
@@ -1,207 +1,119 @@
1
- import React, { useCallback, useRef } from 'react'
2
- import { onUpdate, TypeGuards } from '@codeleap/common'
3
- import { AnyRecord, IJSX, StyledComponentProps } from '@codeleap/styles'
4
- import { Dimensions, ScrollView } from 'react-native'
1
+ import React, { useCallback, useRef, useState } from 'react'
2
+ import { ReduceMotion } from 'react-native-reanimated'
3
+ import Carousel, { ICarouselInstance } from 'react-native-reanimated-carousel'
4
+ import { CarouselRenderItemInfo, TCarouselProps } from 'react-native-reanimated-carousel/lib/typescript/types'
5
+ import { Dimensions, LayoutChangeEvent } from 'react-native'
6
+ import { onUpdate, TypeGuards, useConditionalState } from '@codeleap/common'
7
+ import { AnyRecord, IJSX, StyledComponentProps, useNestedStylesByKey } from '@codeleap/styles'
8
+ import { useStylesFor } from '../../hooks'
5
9
  import { MobileStyleRegistry } from '../../Registry'
6
10
  import { View } from '../View'
7
- import { PageProps, PagerProps, ScrollEvent } from './types'
8
- import { useStylesFor } from '../../hooks'
11
+ import { PageProps, PagerProps } from './types'
12
+ import { PagerDots } from './PagerDots'
9
13
 
10
14
  export * from './styles'
11
15
  export * from './types'
16
+ export * from './PagerDots'
17
+
18
+ const window = Dimensions.get('window')
12
19
 
13
- export const Pager = (pagerProps: PagerProps) => {
20
+ export const Pager = <T extends unknown>(props: PagerProps<T>) => {
14
21
  const {
15
- width: widthProp,
22
+ pages,
16
23
  page,
24
+ onChangePage,
25
+ initialPage,
17
26
  style,
18
- returnEarly,
19
- renderPageWrapper,
20
- pageWrapperProps = {},
21
- children,
22
- windowing,
23
- setPage,
24
- scrollEnabled,
25
- scrollLeftEnabled,
26
- scrollRightEnabled,
27
- onScroll,
28
- scrollDirectionThrottle,
29
- onSwipeLastPage,
30
- waitEventDispatchTimeout,
27
+ showDots,
28
+ renderItem: RenderItem,
29
+ footer,
30
+ width: carouselWidth,
31
+ height: carouselHeight,
32
+ autoCalculateFooterHeight,
33
+ ...rest
31
34
  } = {
32
35
  ...Pager.defaultProps,
33
- ...pagerProps,
36
+ ...props,
34
37
  }
35
38
 
36
- const childArr = React.Children.toArray(children)
37
- const scrollRef = useRef<ScrollView>(null)
38
- const [positionX, setPositionX] = React.useState(0)
39
- const [scrollPositionX, setScrollPositionX] = React.useState(0)
40
- const [_scrollEnabled, setScrollEnabled] = React.useState(true)
41
- const waitEventDispatch = useRef(false)
39
+ const [currentPage, setCurrentPage] = useConditionalState(page, onChangePage, { initialValue: initialPage })
40
+ const carouselRef = useRef<ICarouselInstance>(null)
41
+ const [footerHeight, setFooterHeight] = useState(0)
42
42
 
43
43
  const styles = useStylesFor(Pager.styleRegistryName, style)
44
+ const dotStyles = useNestedStylesByKey('dot', styles)
44
45
 
45
- const windowWidth = Dimensions.get('window').width
46
-
47
- // @ts-expect-error
48
- let width = widthProp ?? styles?.wrapper?.width
49
-
50
- const validWidth = TypeGuards.isNumber(width)
51
-
52
- if (!validWidth) {
53
- width = windowWidth
54
- }
55
-
56
- const nChildren = React.Children.count(children)
57
-
58
- const lastPage = nChildren - 1
59
-
60
- const WrapperComponent = renderPageWrapper || View
61
-
62
- const hasScrollDirectionDisabled = !scrollLeftEnabled || !scrollRightEnabled
63
-
64
- const handleScrollEnd = useCallback((event: ScrollEvent) => {
65
- if (!scrollEnabled) return null
66
-
67
- if (waitEventDispatch.current === true) return null
68
-
69
- waitEventDispatch.current = true
70
-
71
- const x = event?.nativeEvent.contentOffset.x
72
- const toPage = Math.floor(((Math.round(x)) / Math.round(width)))
73
-
74
- const length = childArr.length - 1
75
-
76
- if (toPage >= length && TypeGuards.isFunction(onSwipeLastPage) && page >= length) {
77
- onSwipeLastPage?.(event)
78
- } else if (toPage !== page && toPage <= length) {
79
- setPage(toPage)
80
- setPositionX(toPage * width)
81
- }
82
-
83
- setTimeout(() => {
84
- waitEventDispatch.current = false
85
- }, waitEventDispatchTimeout)
86
- }, [childArr, page, setPage, waitEventDispatch.current])
87
-
88
- const handleScroll = (event: ScrollEvent) => {
89
- const scrollX = event?.nativeEvent?.contentOffset?.x
90
-
91
- if (!scrollEnabled) {
92
- if (TypeGuards.isFunction(onScroll)) onScroll?.(event, { x: scrollX })
93
- return null
94
- }
95
-
96
- if (!_scrollEnabled) {
97
- setScrollPositionX(scrollX)
98
- return null
46
+ onUpdate(() => {
47
+ carouselRef.current?.scrollTo({ index: currentPage, animated: true })
48
+ }, [currentPage])
49
+
50
+ const renderItem = useCallback(({ item, index, animationValue }: CarouselRenderItemInfo<any>) => {
51
+ const itemProps: Omit<PageProps<T>, 'item'> = {
52
+ isFirst: index === 0,
53
+ isLast: index === pages?.length - 1,
54
+ isOnly: pages?.length === 1,
55
+ isActive: index === currentPage,
56
+ isNext: index === currentPage + 1,
57
+ isPrevious: index === currentPage - 1,
58
+ index,
59
+ animationValue,
99
60
  }
100
61
 
101
- const isRight = scrollX < scrollPositionX
102
- const isLeft = scrollX > scrollPositionX
103
-
104
- if (TypeGuards.isFunction(onScroll)) onScroll?.(event, { isLeft, isRight, x: scrollX })
105
-
106
- if (hasScrollDirectionDisabled) {
107
- if (isRight && !scrollRightEnabled || isLeft && !scrollLeftEnabled) {
108
- setScrollEnabled(false)
109
-
110
- setTimeout(() => {
111
- scrollRef.current.scrollTo({
112
- x: positionX,
113
- animated: true,
114
- })
115
-
116
- setTimeout(() => {
117
- setScrollEnabled(true)
118
- }, scrollDirectionThrottle)
119
- })
120
- }
62
+ if (TypeGuards.isFunction(item)) {
63
+ const ItemComponent = item
64
+ return <ItemComponent {...itemProps} />
121
65
  }
122
66
 
123
- setScrollPositionX(scrollX)
124
- }
125
-
126
- onUpdate(() => {
127
- const x = width * page
128
- if (scrollRef.current && x !== positionX) {
129
- scrollRef.current.scrollTo({
130
- x,
131
- animated: true,
132
- })
133
- setPositionX(x)
134
- }
135
- }, [page])
67
+ return <RenderItem {...itemProps} item={item} />
68
+ }, [RenderItem, pages?.length, currentPage])
136
69
 
137
70
  return (
138
- <ScrollView
139
- ref={scrollRef}
140
- horizontal
141
- pagingEnabled
142
- onMomentumScrollEnd={handleScrollEnd}
143
- scrollEventThrottle={hasScrollDirectionDisabled ? 2000 : 300}
144
- showsHorizontalScrollIndicator={false}
145
- {...pagerProps}
146
- style={styles?.wrapper}
147
- onScroll={handleScroll}
148
- scrollEnabled={childArr.length > 1 && scrollEnabled && _scrollEnabled}
149
- >
150
- {childArr.map((child: PagerProps['children'][number], index) => {
151
- const isActive = index === page
152
- const isLast = index === lastPage
153
- const isFirst = index === 0
154
- const isNext = index === page + 1
155
- const isPrevious = index === page - 1
156
-
157
- const shouldRender = windowing ? (isActive || isNext || isPrevious) : true
158
-
159
- if (!shouldRender && returnEarly) {
160
- return <View style={{ height: '100%', width }} />
161
- }
162
-
163
- const pageProps: PageProps = {
164
- isLast,
165
- isActive,
166
- isFirst,
167
- isNext,
168
- isPrevious,
169
- index,
170
- page,
171
- }
172
-
173
- const content = typeof child === 'function' ? child(pageProps) : child
174
-
175
- const wrapperProps = {
176
- key: index,
177
- ...pageWrapperProps,
178
- style: [{ height: '100%', width }, styles?.page],
179
- }
180
-
181
- return <WrapperComponent {...wrapperProps}>{content}</WrapperComponent>
182
- })}
183
- </ScrollView>
71
+ <View style={styles.wrapper}>
72
+ <Carousel
73
+ data={pages}
74
+ withAnimation={{
75
+ type: 'timing',
76
+ config: {
77
+ reduceMotion: ReduceMotion.Never
78
+ },
79
+ }}
80
+ autoPlay={false}
81
+ ref={carouselRef}
82
+ loop={false}
83
+ defaultIndex={initialPage}
84
+ onSnapToItem={setCurrentPage}
85
+ maxScrollDistancePerSwipe={carouselWidth}
86
+ width={carouselWidth}
87
+ height={carouselHeight - (autoCalculateFooterHeight ? footerHeight : 0)}
88
+ renderItem={renderItem}
89
+ {...rest as TCarouselProps<T>}
90
+ style={styles.carousel}
91
+ />
92
+
93
+ <View onLayout={(event: LayoutChangeEvent) => setFooterHeight(event.nativeEvent.layout.height)} style={styles.footerWrapper}>
94
+ {footer}
95
+ {showDots ? (
96
+ <PagerDots currentPage={currentPage} pages={pages} setCurrentPage={setCurrentPage} styles={dotStyles} />
97
+ ) : null}
98
+ </View>
99
+ </View>
184
100
  )
185
101
  }
186
102
 
187
103
  Pager.styleRegistryName = 'Pager'
188
- Pager.elements = ['page', 'wrapper']
104
+ Pager.elements = ['carousel', 'wrapper', 'footerWrapper', 'dot']
189
105
  Pager.rootElement = 'wrapper'
190
106
 
191
107
  Pager.withVariantTypes = <S extends AnyRecord>(styles: S) => {
192
- return Pager as (props: StyledComponentProps<PagerProps, typeof styles>) => IJSX
108
+ return Pager as <T extends unknown>(props: StyledComponentProps<PagerProps<T>, typeof styles>) => IJSX
193
109
  }
194
110
 
195
111
  Pager.defaultProps = {
196
- page: 0,
197
- returnEarly: true,
198
- windowing: false,
199
- keyboardShouldPersistTaps: 'handled',
200
- scrollEnabled: true,
201
- scrollRightEnabled: true,
202
- scrollLeftEnabled: true,
203
- scrollDirectionThrottle: 650,
204
- waitEventDispatchTimeout: 250,
205
- } as Partial<PagerProps>
112
+ width: window.width,
113
+ height: window.height,
114
+ showDots: true,
115
+ autoCalculateFooterHeight: true,
116
+ initialPage: 0,
117
+ } as Partial<PagerProps<unknown>>
206
118
 
207
119
  MobileStyleRegistry.registerComponent(Pager)
@@ -1,2 +1,7 @@
1
+ export type DotStates = '' | 'active'
1
2
 
2
- export type PagerComposition = 'page' | 'wrapper'
3
+ export type DotParts = 'wrapper' | `touchable` | `dot`
4
+
5
+ export type DotComposition = DotParts | `${DotParts}:${DotStates}`
6
+
7
+ export type PagerComposition = 'carousel' | 'wrapper' | 'footerWrapper' | `dot${Capitalize<DotParts>}`
@@ -1,37 +1,27 @@
1
+ import React, { ReactNode } from 'react'
1
2
  import { StyledProp } from '@codeleap/styles'
2
- import { ReactNode } from 'react'
3
- import { NativeScrollEvent, NativeSyntheticEvent, ScrollViewProps } from 'react-native'
4
3
  import { PagerComposition } from './styles'
4
+ import { TCarouselProps } from 'react-native-reanimated-carousel'
5
+ import { CarouselRenderItemInfo } from 'react-native-reanimated-carousel/lib/typescript/types'
5
6
 
6
- export type PageProps = {
7
+ export type PageProps<T extends unknown> = CarouselRenderItemInfo<T> & {
7
8
  isLast: boolean
8
9
  isFirst: boolean
9
10
  isActive: boolean
11
+ isOnly: boolean
10
12
  isNext: boolean
11
- page: number
12
13
  index: number
13
14
  isPrevious: boolean
14
15
  }
15
16
 
16
- export type ScrollEvent = NativeSyntheticEvent<NativeScrollEvent>
17
-
18
- export type PagerProps =
19
- Omit<ScrollViewProps, 'style'> &
20
- {
21
- children?: (((pageData: PageProps) => ReactNode) | ReactNode)[]
22
- page?: number
23
- setPage?: (page: number) => void
24
- returnEarly?: boolean
25
- renderPageWrapper?: React.FC<PageProps>
26
- pageWrapperProps?: any
27
- width?: number
28
- onScroll?: (event: ScrollEvent, args: { isLeft?: boolean; isRight?: boolean; x?: number }) => void
29
- /** If TRUE render page, nextPage and prevPage only */
30
- windowing?: boolean
31
- scrollRightEnabled?: boolean
32
- scrollLeftEnabled?: boolean
33
- scrollDirectionThrottle?: number
34
- onSwipeLastPage?: (event: ScrollEvent) => void
35
- waitEventDispatchTimeout?: number
36
- style?: StyledProp<PagerComposition>
37
- }
17
+ export type PagerProps<T extends unknown> = Partial<Omit<TCarouselProps<T>, 'data' | 'renderItem'>> & {
18
+ pages: TCarouselProps<T>['data']
19
+ renderItem?: (props: PageProps<T>) => JSX.Element
20
+ page?: number
21
+ onChangePage?: (page: number) => void
22
+ initialPage?: number
23
+ style?: StyledProp<PagerComposition>
24
+ showDots?: boolean
25
+ footer?: ReactNode
26
+ autoCalculateFooterHeight?: boolean
27
+ }