Skip to content

Commit feeacc7

Browse files
authored
Carousel - migrate to typescript (#1005)
* Rename CarouselPresenter from .js to .tsx * Rename Carouselfrom .js to .tsx * Carousel - move to typescript (waiting for PageControl) * Add PageControlProps to Carousel * Change initialOffset's type to PointPropType (to match ScrollView's contentOffset) * Prettify Carousel and PageControl * Remove manual typings * Rename CarouselScreen .js to .tsx * Carousel - export + fix statics + screen * Remove export for PageControlPosition
1 parent e4e5a7f commit feeacc7

File tree

12 files changed

+401
-234
lines changed

12 files changed

+401
-234
lines changed

demo/src/screens/componentScreens/CarouselScreen.js renamed to demo/src/screens/componentScreens/CarouselScreen.tsx

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,21 @@ const BACKGROUND_COLORS = [
3434
Colors.purple60
3535
];
3636

37-
class CarouselScreen extends Component {
38-
constructor(props) {
37+
interface Props {}
38+
39+
interface State {
40+
orientation: typeof Constants.orientation;
41+
width: number;
42+
limitShownPages: boolean;
43+
numberOfPagesShown: number;
44+
currentPage: number;
45+
autoplay: boolean;
46+
}
47+
48+
class CarouselScreen extends Component<Props ,State> {
49+
carousel = React.createRef<any>();
50+
51+
constructor(props: Props) {
3952
super(props);
4053

4154
this.state = {
@@ -69,12 +82,14 @@ class CarouselScreen extends Component {
6982
return Constants.windowWidth - Spacings.s5 * 2;
7083
};
7184

72-
onChangePage = (currentPage) => {
85+
onChangePage = (currentPage: number) => {
7386
this.setState({currentPage});
7487
};
7588

76-
onPagePress = (index) => {
77-
this.carousel.goToPage(index, true);
89+
onPagePress = (index: number) => {
90+
if (this.carousel && this.carousel.current) {
91+
this.carousel.current.goToPage(index, true);
92+
}
7893
};
7994

8095
render() {
@@ -108,8 +123,7 @@ class CarouselScreen extends Component {
108123

109124
<Carousel
110125
key={numberOfPagesShown}
111-
migrate
112-
ref={(r) => (this.carousel = r)}
126+
ref={this.carousel}
113127
//loop
114128
autoplay={autoplay}
115129
onChangePage={this.onChangePage}
@@ -118,7 +132,7 @@ class CarouselScreen extends Component {
118132
containerMarginHorizontal={Spacings.s2}
119133
initialPage={INITIAL_PAGE}
120134
containerStyle={{height: 160}}
121-
pageControlPosition={'under'}
135+
pageControlPosition={Carousel.pageControlPositions.UNDER}
122136
pageControlProps={{onPagePress: this.onPagePress, limitShownPages}}
123137
// showCounter
124138
allowAccessibleLayout
@@ -172,6 +186,7 @@ class CarouselScreen extends Component {
172186
}
173187
}
174188

189+
// @ts-ignore
175190
const Page = ({children, style, ...others}) => {
176191
return (
177192
<View {...others} style={[styles.page, style]}>
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { CarouselProps, CarouselState } from './types';
2+
export declare function getChildrenLength(props: CarouselProps): number;
3+
export declare function calcOffset(props: CarouselProps, state: Omit<CarouselState, 'initialOffset' | 'prevProps'>): number;
4+
export declare function calcPageIndex(offset: number, props: CarouselProps, pageWidth: number): number;
5+
export declare function isOutOfBounds(offset: number, props: CarouselProps, pageWidth: number): boolean;
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import React, { Component, RefObject, ReactNode, Key } from 'react';
2+
import { ScrollView, LayoutChangeEvent, NativeSyntheticEvent, NativeScrollEvent } from 'react-native';
3+
import { CarouselProps, CarouselState, PageControlPosition } from './types';
4+
export { CarouselProps };
5+
interface DefaultProps extends Partial<CarouselProps> {
6+
}
7+
/**
8+
* @description: Carousel for scrolling pages horizontally
9+
* @gif: https://media.giphy.com/media/l0HU7f8gjpRlMRhKw/giphy.gif, https://media.giphy.com/media/3oFzmcjX9OhpyckhcQ/giphy.gif
10+
* @example: https://github.com/wix/react-native-ui-lib/blob/master/demo/src/screens/componentScreens/CarouselScreen.js
11+
* @extends: ScrollView
12+
* @extendsLink: https://facebook.github.io/react-native/docs/scrollview
13+
* @notes: This is screed width Component
14+
*/
15+
declare class Carousel extends Component<CarouselProps, CarouselState> {
16+
static displayName: string;
17+
static defaultProps: DefaultProps;
18+
static pageControlPositions: typeof PageControlPosition;
19+
carousel: RefObject<ScrollView>;
20+
autoplayTimer?: number;
21+
orientationChange?: boolean;
22+
skippedInitialScroll?: boolean;
23+
constructor(props: CarouselProps);
24+
static getDerivedStateFromProps(nextProps: CarouselProps, prevState: CarouselState): {
25+
pageWidth: number;
26+
initialOffset: {
27+
x: number;
28+
};
29+
prevProps: CarouselProps;
30+
} | {
31+
prevProps: CarouselProps;
32+
pageWidth?: undefined;
33+
initialOffset?: undefined;
34+
} | null;
35+
componentDidMount(): void;
36+
componentWillUnmount(): void;
37+
componentDidUpdate(prevProps: CarouselProps): void;
38+
onOrientationChanged: () => void;
39+
getItemSpacings(props: CarouselProps): number;
40+
getContainerMarginHorizontal: () => number;
41+
getContainerPaddingVertical: () => number;
42+
updateOffset: (animated?: boolean) => void;
43+
startAutoPlay(): void;
44+
stopAutoPlay(): void;
45+
resetAutoPlay(): void;
46+
goToPage(pageIndex: number, animated?: boolean): void;
47+
getCalcIndex(index: number): number;
48+
getSnapToOffsets: () => number[] | undefined;
49+
shouldUsePageWidth(): number | false | undefined;
50+
shouldEnablePagination(): boolean | undefined;
51+
onContainerLayout: ({ nativeEvent: { layout: { width: containerWidth } } }: LayoutChangeEvent) => void;
52+
shouldAllowAccessibilityLayout(): boolean | undefined;
53+
onContentSizeChange: () => void;
54+
onMomentumScrollEnd: () => void;
55+
goToNextPage(): void;
56+
onScroll: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;
57+
renderChild: (child: ReactNode, key: Key) => JSX.Element | undefined;
58+
renderChildren(): JSX.Element[] | null | undefined;
59+
renderPageControl(): JSX.Element | undefined;
60+
renderCounter(): JSX.Element | undefined;
61+
renderAccessibleLayout(): JSX.Element;
62+
renderCarousel(): JSX.Element;
63+
render(): JSX.Element;
64+
}
65+
export { Carousel };
66+
declare const _default: React.ComponentClass<CarouselProps & {
67+
useCustomTheme?: boolean | undefined;
68+
}, any> & typeof Carousel;
69+
export default _default;
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import { StyleProp, ViewStyle, NativeSyntheticEvent, NativeScrollEvent, PointPropType } from 'react-native';
2+
import { PageControlProps } from '../pageControl';
3+
export declare enum PageControlPosition {
4+
OVER = "over",
5+
UNDER = "under"
6+
}
7+
export interface CarouselProps {
8+
/**
9+
* the first page to start with
10+
*/
11+
initialPage?: number;
12+
/**
13+
* the page width (all pages should have the same width). Does not work if passing 'loop' prop
14+
*/
15+
pageWidth?: number;
16+
/**
17+
* the spacing between the items
18+
*/
19+
itemSpacings?: number;
20+
/**
21+
* Horizontal margin for the container
22+
*/
23+
containerMarginHorizontal?: number;
24+
/**
25+
* Vertical padding for the container.
26+
* Sometimes needed when there are overflows that are cut in Android.
27+
*/
28+
containerPaddingVertical?: number;
29+
/**
30+
* if true, will have infinite scroll
31+
*/
32+
loop?: boolean;
33+
/**
34+
* callback for when page has changed
35+
*/
36+
onChangePage?: (newPageIndex: number, oldPageIndex: number) => void;
37+
/**
38+
* callback for onScroll event of the internal ScrollView
39+
*/
40+
onScroll?: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;
41+
/**
42+
* Should the container be animated (send the animation style via containerStyle)
43+
*/
44+
animated?: boolean;
45+
/**
46+
* the carousel style
47+
*/
48+
containerStyle?: StyleProp<ViewStyle>;
49+
/**
50+
* PageControl component props
51+
*/
52+
pageControlProps?: Partial<PageControlProps>;
53+
/**
54+
* The position of the PageControl component ['over', 'under'], otherwise it won't display
55+
*/
56+
pageControlPosition?: PageControlPosition;
57+
/**
58+
* whether to show a page counter (will not work with 'pageWidth' prop)
59+
*/
60+
showCounter?: boolean;
61+
/**
62+
* the counter's text style
63+
*/
64+
counterTextStyle?: StyleProp<ViewStyle>;
65+
/**
66+
* will block multiple pages scroll (will not work with 'pageWidth' prop)
67+
*/
68+
pagingEnabled?: boolean;
69+
/**
70+
* Whether to layout Carousel for accessibility
71+
*/
72+
allowAccessibleLayout?: boolean;
73+
/**
74+
* Whether to switch automatically between the pages
75+
*/
76+
autoplay?: boolean;
77+
/**
78+
* the amount of ms to wait before switching to the next page, in case autoplay is on
79+
*/
80+
autoplayInterval?: number;
81+
}
82+
export interface CarouselState {
83+
containerWidth?: number;
84+
currentPage: number;
85+
currentStandingPage?: number;
86+
pageWidth: number;
87+
initialOffset: PointPropType;
88+
prevProps: CarouselProps;
89+
}

generatedTypes/components/pageControl/index.d.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ import React from 'react';
22
import { StyleProp, ViewStyle } from 'react-native';
33
export interface PageControlProps {
44
/**
5-
* Limit the number of page indicators shown.
6-
* enlargeActive prop is disabled in this state,
7-
* When set to true there will be maximum of 7 shown.
8-
* Only relevant when numOfPages > 5.
9-
*/
5+
* Limit the number of page indicators shown.
6+
* enlargeActive prop is disabled in this state,
7+
* When set to true there will be maximum of 7 shown.
8+
* Only relevant when numOfPages > 5.
9+
*/
1010
limitShownPages?: boolean;
1111
/**
1212
* Additional styles for the top container
@@ -47,6 +47,10 @@ export interface PageControlProps {
4747
* The space between the siblings page indicators
4848
*/
4949
spacing?: number;
50+
/**
51+
* Used to identify the pageControl in tests
52+
*/
53+
testID?: string;
5054
}
5155
declare const _default: React.ComponentClass<PageControlProps & {
5256
useCustomTheme?: boolean | undefined;

generatedTypes/index.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,13 @@ export {default as PanResponderView, PanResponderViewPropTypes} from './componen
5656
export {default as PanDismissibleView, PanDismissibleViewPropTypes, DismissibleAnimationPropTypes} from './components/panningViews/panDismissibleView';
5757
export {default as Dialog, DialogProps} from './components/dialog';
5858
export {default as PageControl, PageControlProps} from './components/pageControl';
59+
export {default as Carousel, CarouselProps} from './components/carousel';
5960

6061
/* All components with manual typings */
6162
export {
6263
ActionSheet,
6364
Badge,
6465
BadgeProps,
65-
Carousel,
6666
ConnectionStatusBar,
6767
Drawer,
6868
ExpandableSection,

src/components/carousel/CarouselPresenter.js renamed to src/components/carousel/CarouselPresenter.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import _ from 'lodash';
2+
import {CarouselProps, CarouselState} from './types';
23

3-
4-
export function getChildrenLength(props) {
4+
export function getChildrenLength(props: CarouselProps): number {
55
const length = _.get(props, 'children.length') || 0;
66
return length;
77
}
88

9-
export function calcOffset(props, state) {
9+
export function calcOffset(props: CarouselProps, state: Omit<CarouselState, 'initialOffset' | 'prevProps'>) {
1010
const {currentPage, pageWidth} = state;
1111
const {loop, containerMarginHorizontal = 0} = props;
1212
const actualCurrentPage = loop ? currentPage + 1 : currentPage;
@@ -16,7 +16,7 @@ export function calcOffset(props, state) {
1616
return offset;
1717
}
1818

19-
export function calcPageIndex(offset, props, pageWidth) {
19+
export function calcPageIndex(offset: number, props: CarouselProps, pageWidth: number) {
2020
const pagesCount = getChildrenLength(props);
2121
const {loop} = props;
2222
const pageIndexIncludingClonedPages = Math.round(offset / pageWidth);
@@ -30,10 +30,10 @@ export function calcPageIndex(offset, props, pageWidth) {
3030
return actualPageIndex;
3131
}
3232

33-
export function isOutOfBounds(offset, props, pageWidth) {
33+
export function isOutOfBounds(offset: number, props: CarouselProps, pageWidth: number) {
3434
const length = getChildrenLength(props);
3535
const minLimit = 1;
36-
const maxLimit = ((length + 1) * pageWidth) - 1;
36+
const maxLimit = (length + 1) * pageWidth - 1;
3737

3838
return !_.inRange(offset, minLimit, maxLimit);
3939
}

0 commit comments

Comments
 (0)