Skip to content

Commit 8ead6d5

Browse files
authored
Feat/carousel allow selected card (#668)
* Carousel - take props from pageControlProps and not props * Carousel - move to getThemeProps + change to getItemSpacings instead of defaultProp * Carousel - allow adding sideSpacing (marginHorizontal) * Refactor name sideSpacing --> containerHorizontalMargin * containerHorizontalMargin --> containerMarginHorizontal * Add containerPaddingVertical * For some reason overflow={'visible'} does not work for iOS as well, compensate for that with a possible negative marginBottom * Fix style order to allow overriding * Remove overflow * Add TODO
1 parent 97f0708 commit 8ead6d5

File tree

2 files changed

+66
-44
lines changed

2 files changed

+66
-44
lines changed

demo/src/screens/componentScreens/CarouselScreen.js

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,6 @@ class CarouselScreen extends Component {
4141
this.carousel.goToPage(index, true);
4242
};
4343

44-
toggleLimitShownPages = limitShownPages => {
45-
this.setState({limitShownPages});
46-
};
47-
48-
setNumberOfPagesShown = ({value: numberOfPagesShown}) => {
49-
this.setState({numberOfPagesShown, currentPage: INITIAL_PAGE});
50-
};
51-
5244
render() {
5345
const {limitShownPages, numberOfPagesShown} = this.state;
5446

src/components/carousel/index.js

Lines changed: 66 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import Text from '../text';
1010
import PageControl from '../pageControl';
1111
import * as presenter from './CarouselPresenter';
1212

13-
1413
const PAGE_CONTROL_POSITIONS = {
1514
OVER: 'over',
1615
UNDER: 'under'
@@ -40,6 +39,15 @@ export default class Carousel extends BaseComponent {
4039
* the spacing between the items
4140
*/
4241
itemSpacings: PropTypes.number,
42+
/**
43+
* Horizontal margin for the container
44+
*/
45+
containerMarginHorizontal: PropTypes.number,
46+
/**
47+
* Vertical padding for the container.
48+
* Sometimes needed when there are overflows that are cut in Android.
49+
*/
50+
containerPaddingVertical: PropTypes.number,
4351
/**
4452
* if true, will have infinite scroll
4553
*/
@@ -84,7 +92,6 @@ export default class Carousel extends BaseComponent {
8492

8593
static defaultProps = {
8694
initialPage: 0,
87-
itemSpacings: 16,
8895
pagingEnabled: true
8996
};
9097

@@ -95,7 +102,7 @@ export default class Carousel extends BaseComponent {
95102

96103
this.carousel = React.createRef();
97104
const defaultPageWidth = props.loop ?
98-
Constants.screenWidth : props.pageWidth + props.itemSpacings || Constants.screenWidth;
105+
Constants.screenWidth : props.pageWidth + this.getItemSpacings(props) || Constants.screenWidth;
99106

100107
this.state = {
101108
containerWidth: undefined,
@@ -115,21 +122,39 @@ export default class Carousel extends BaseComponent {
115122
}
116123

117124
onOrientationChanged = () => {
118-
if (!this.props.pageWidth || this.props.loop) {
125+
const {pageWidth, loop} = this.getThemeProps();
126+
if (!pageWidth || loop) {
119127
this.orientationChange = true;
120128
// HACK: setting to containerWidth for Android's call when view disappear
121129
this.setState({pageWidth: this.state.containerWidth || Constants.screenWidth});
122130
}
123131
};
124132

125133
generateStyles() {
126-
this.styles = createStyles(this.props);
134+
this.styles = createStyles(this.getThemeProps());
135+
}
136+
137+
getItemSpacings(props) {
138+
const {itemSpacings = 16} = props;
139+
return itemSpacings;
140+
}
141+
142+
getContainerMarginHorizontal = () => {
143+
const {containerMarginHorizontal = 0} = this.getThemeProps();
144+
return containerMarginHorizontal;
145+
}
146+
147+
// TODO: RN 61.5 - try to remove this from the children and move to the ScrollView's contentContainerStyle
148+
// style={{overflow: 'visible'}} does not work in ScrollView on Android, maybe it will be fixed in the future
149+
getContainerPaddingVertical = () => {
150+
const {containerPaddingVertical = 0} = this.getThemeProps();
151+
return containerPaddingVertical;
127152
}
128153

129154
updateOffset = (animated = false) => {
130155
const centerOffset = Constants.isIOS && this.shouldUsePageWidth() ?
131156
(Constants.screenWidth - this.state.pageWidth) / 2 : 0;
132-
const x = presenter.calcOffset(this.props, this.state) - centerOffset;
157+
const x = presenter.calcOffset(this.getThemeProps(), this.state) - centerOffset;
133158

134159
if (this.carousel) {
135160
this.carousel.current.scrollTo({x, animated});
@@ -157,45 +182,47 @@ export default class Carousel extends BaseComponent {
157182
}
158183

159184
getSnapToOffsets = () => {
160-
const {itemSpacings} = this.props;
161185
const {containerWidth, pageWidth} = this.state;
162186

163187
if (this.shouldEnablePagination()) {
164188
return undefined;
165189
}
166190

167191
if (containerWidth) {
168-
const spacings = pageWidth === containerWidth ? 0 : itemSpacings;
192+
const spacings = pageWidth === containerWidth ? 0 : this.getItemSpacings(this.getThemeProps());
169193
const initialBreak = pageWidth - (containerWidth - pageWidth - spacings) / 2;
170-
const snapToOffsets = _.times(presenter.getChildrenLength(this.props), index => initialBreak + index * pageWidth);
194+
const snapToOffsets = _.times(presenter.getChildrenLength(this.props),
195+
index => initialBreak + index * pageWidth + this.getContainerMarginHorizontal());
171196
return snapToOffsets;
172197
}
173198
};
174199

175200
shouldUsePageWidth() {
176-
const {loop, pageWidth} = this.props;
201+
const {loop, pageWidth} = this.getThemeProps();
177202
return !loop && pageWidth;
178203
}
179204

180205
shouldEnablePagination() {
181-
const {pagingEnabled} = this.props;
206+
const {pagingEnabled} = this.getThemeProps();
182207
return pagingEnabled && !this.shouldUsePageWidth();
183208
}
184209

185210
onContainerLayout = ({nativeEvent: {layout: {width: containerWidth}}}) => {
186211
const update = {containerWidth};
212+
const {pageWidth} = this.getThemeProps();
187213

188-
if (!this.props.pageWidth) {
214+
if (!pageWidth) {
189215
update.pageWidth = containerWidth;
190216
update.initialOffset = {
191-
x: presenter.calcOffset(this.props, {currentPage: this.state.currentPage, pageWidth: containerWidth})
217+
x: presenter.calcOffset(this.getThemeProps(), {currentPage: this.state.currentPage, pageWidth: containerWidth})
192218
};
193219
}
194220
this.setState(update);
195221
};
196222

197223
shouldAllowAccessibilityLayout() {
198-
return this.props.allowAccessibleLayout && Constants.accessibility.isScreenReaderEnabled;
224+
const {allowAccessibleLayout} = this.getThemeProps();
225+
return allowAccessibleLayout && Constants.accessibility.isScreenReaderEnabled;
199226
}
200227

201228
onContentSizeChange = () => {
@@ -222,13 +249,13 @@ export default class Carousel extends BaseComponent {
222249
return;
223250
}
224251

225-
const {loop} = this.props;
252+
const {loop} = this.getThemeProps();
226253
const {pageWidth} = this.state;
227254
const offsetX = event.nativeEvent.contentOffset.x;
228255

229256
if (offsetX >= 0) {
230257
if (!this.orientationChange) { // Avoid new calculation on orientation change
231-
const newPage = presenter.calcPageIndex(offsetX, this.props, pageWidth);
258+
const newPage = presenter.calcPageIndex(offsetX, this.getThemeProps(), pageWidth);
232259
this.setState({currentPage: newPage});
233260
}
234261
this.orientationChange = false;
@@ -243,12 +270,20 @@ export default class Carousel extends BaseComponent {
243270

244271
renderChild = (child, key) => {
245272
if (child) {
246-
const paddingLeft = this.shouldUsePageWidth() ? this.props.itemSpacings : undefined;
273+
const paddingLeft = this.shouldUsePageWidth() ? this.getItemSpacings(this.getThemeProps()) : undefined;
247274
const index = Number(key);
248275
const length = presenter.getChildrenLength(this.props);
276+
const containerMarginHorizontal = this.getContainerMarginHorizontal();
277+
const marginLeft = index === 0 ? containerMarginHorizontal : 0;
278+
const marginRight = index === length - 1 ? containerMarginHorizontal : 0;
279+
const paddingVertical = this.getContainerPaddingVertical();
249280

250281
return (
251-
<View style={{width: this.state.pageWidth, paddingLeft}} key={key} collapsable={false}>
282+
<View
283+
style={{width: this.state.pageWidth, paddingLeft, marginLeft, marginRight, paddingVertical}}
284+
key={key}
285+
collapsable={false}
286+
>
252287
{this.shouldAllowAccessibilityLayout() && !Number.isNaN(index) &&
253288
<View style={this.styles.hiddenText}>
254289
<Text>{`page ${index + 1} out of ${length}`}</Text>
@@ -261,7 +296,7 @@ export default class Carousel extends BaseComponent {
261296
};
262297

263298
renderChildren() {
264-
const {children, loop} = this.props;
299+
const {children, loop} = this.getThemeProps();
265300
const length = presenter.getChildrenLength(this.props);
266301

267302
const childrenArray = React.Children.map(children, (child, index) => {
@@ -277,16 +312,10 @@ export default class Carousel extends BaseComponent {
277312
}
278313

279314
renderPageControl() {
280-
const {
281-
pageControlPosition,
282-
pageControlProps,
283-
size = 6,
284-
spacing = 8,
285-
color = Colors.dark20,
286-
inactiveColor = Colors.dark60
287-
} = this.getThemeProps();
288-
315+
const {pageControlPosition, pageControlProps = {}} = this.getThemeProps();
316+
289317
if (pageControlPosition) {
318+
const {size = 6, spacing = 8, color = Colors.dark20, inactiveColor = Colors.dark60, ...others} = pageControlProps;
290319
const pagesCount = presenter.getChildrenLength(this.props);
291320
const containerStyle =
292321
pageControlPosition === PAGE_CONTROL_POSITIONS.UNDER
@@ -300,7 +329,7 @@ export default class Carousel extends BaseComponent {
300329
containerStyle={containerStyle}
301330
inactiveColor={inactiveColor}
302331
color={color}
303-
{...pageControlProps}
332+
{...others}
304333
numOfPages={pagesCount}
305334
currentPage={this.getCalcIndex(this.state.currentPage)}
306335
/>
@@ -309,7 +338,7 @@ export default class Carousel extends BaseComponent {
309338
}
310339

311340
renderCounter() {
312-
const {pageWidth, showCounter, counterTextStyle} = this.props;
341+
const {pageWidth, showCounter, counterTextStyle} = this.getThemeProps();
313342
const {currentPage} = this.state;
314343
const pagesCount = presenter.getChildrenLength(this.props);
315344

@@ -325,7 +354,7 @@ export default class Carousel extends BaseComponent {
325354
}
326355

327356
renderAccessibleLayout() {
328-
const {containerStyle, children} = this.props;
357+
const {containerStyle, children} = this.getThemeProps();
329358

330359
return (
331360
<View style={containerStyle} onLayout={this.onContainerLayout}>
@@ -346,13 +375,14 @@ export default class Carousel extends BaseComponent {
346375
}
347376

348377
renderCarousel() {
349-
const {containerStyle, itemSpacings, ...others} = this.props;
378+
const {containerStyle, ...others} = this.getThemeProps();
350379
const {initialOffset} = this.state;
351-
const scrollContainerStyle = this.shouldUsePageWidth() ? {paddingRight: itemSpacings} : undefined;
380+
const scrollContainerStyle = this.shouldUsePageWidth() ? {paddingRight: this.getItemSpacings(this.getThemeProps())} : undefined;
352381
const snapToOffsets = this.getSnapToOffsets();
382+
const marginBottom = Math.max(0, this.getContainerPaddingVertical() - 16);
353383

354384
return (
355-
<View style={containerStyle} onLayout={this.onContainerLayout}>
385+
<View style={[{marginBottom}, containerStyle]} onLayout={this.onContainerLayout}>
356386
<ScrollView
357387
{...others}
358388
ref={this.carousel}
@@ -381,7 +411,7 @@ export default class Carousel extends BaseComponent {
381411
}
382412
}
383413

384-
function createStyles() {
414+
function createStyles({containerPaddingVertical = 0}) {
385415
return StyleSheet.create({
386416
counter: {
387417
paddingHorizontal: 8,
@@ -398,7 +428,7 @@ function createStyles() {
398428
alignSelf: 'center'
399429
},
400430
pageControlContainerStyleUnder: {
401-
marginVertical: 16
431+
marginVertical: 16 - containerPaddingVertical
402432
},
403433
hiddenText: {
404434
position: 'absolute',

0 commit comments

Comments
 (0)