Skip to content

Commit ca2bd75

Browse files
committed
slide animation
1 parent 7f22375 commit ca2bd75

File tree

4 files changed

+173
-27
lines changed

4 files changed

+173
-27
lines changed

src/controls/carousel/Carousel.module.scss

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,88 @@
11
@import "~office-ui-fabric-react/dist/sass/References.scss";
22

3+
@keyframes slideleft {
4+
0% {
5+
left: 0;
6+
right: 0;
7+
}
8+
100% {
9+
left: -100%;
10+
right: 100%;
11+
}
12+
}
13+
14+
@keyframes slideright {
15+
0% {
16+
left: 0;
17+
right: 0;
18+
}
19+
100% {
20+
left: 100%;
21+
right: -100%;
22+
}
23+
}
24+
25+
@keyframes slidefromright {
26+
0% {
27+
left: 100%;
28+
right: -100%;
29+
}
30+
100% {
31+
left: 0;
32+
right: 0;
33+
}
34+
}
35+
36+
@keyframes slidefromleft {
37+
0% {
38+
left: -100%;
39+
right: 100%;
40+
}
41+
100% {
42+
left: 0;
43+
right: 0;
44+
}
45+
}
46+
347
.container {
448
display: flex;
549

650
// Styles for elements container
751
.contentContainer {
852
flex-grow: 2;
953
position: relative;
54+
overflow: hidden;
55+
56+
.slideWrapper {
57+
position: absolute;
58+
left: 0;
59+
right: 0;
60+
top: 0;
61+
bottom: 0;
62+
63+
&.left {
64+
left: -100%;
65+
right: 100%;
66+
}
67+
68+
&.right {
69+
left: 100%;
70+
right: -100%;
71+
}
72+
73+
&.slideLeft {
74+
animation: slideleft linear 0.6s;
75+
}
76+
&.slideRight {
77+
animation: slideright linear 0.6s;
78+
}
79+
&.slideFromRight {
80+
animation: slidefromright linear 0.6s;
81+
}
82+
&.slideFromLeft {
83+
animation: slidefromleft linear 0.6s;
84+
}
85+
}
1086

1187
.carouselImage {
1288
overflow: hidden;

src/controls/carousel/Carousel.tsx

Lines changed: 80 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ export class Carousel extends React.Component<ICarouselProps, ICarouselState> {
6565
const prevButtonDisabled = processing || this.isCarouselButtonDisabled(false);
6666
const nextButtonDisabled = processing || this.isCarouselButtonDisabled(true);
6767

68-
const element = this.getElementToDisplay();
68+
const element = this.getElementToDisplay(currentIndex);
6969

7070
return (
7171
<div className={this.getMergedStyles(styles.container, containerStyles)}>
@@ -87,7 +87,7 @@ export class Carousel extends React.Component<ICarouselProps, ICarouselState> {
8787
}
8888

8989
{
90-
!processing && element
90+
!processing && this.renderSlide(element)
9191
}
9292
{this.getIndicatorsElement()}
9393
</div>
@@ -104,12 +104,48 @@ export class Carousel extends React.Component<ICarouselProps, ICarouselState> {
104104
);
105105
}
106106

107+
private renderSlide = (element: JSX.Element): JSX.Element[] => {
108+
const isAnimated = this.props.slide !== false && !this.props.triggerPageEvent;
109+
110+
const {
111+
currentIndex,
112+
previousIndex,
113+
slideRight
114+
} = this.state;
115+
116+
if (!isAnimated || previousIndex === undefined) {
117+
return [<div className={styles.slideWrapper}>
118+
{element}
119+
</div>];
120+
}
121+
122+
const previousElement = this.getElementToDisplay(previousIndex);
123+
124+
const result: JSX.Element[] = [];
125+
126+
result.push(<div key={currentIndex} className={css(styles.slideWrapper, {
127+
[styles.slideFromLeft]: slideRight,
128+
[styles.slideFromRight]: !slideRight
129+
})}>{element}</div>);
130+
131+
if (slideRight) {
132+
result.push(<div key={previousIndex} className={css(styles.slideWrapper, styles.slideRight, styles.right)}>{previousElement}</div>);
133+
}
134+
else {
135+
result.unshift(<div key={previousIndex} className={css(styles.slideWrapper, styles.slideLeft, styles.left)}>{previousElement}</div>);
136+
}
137+
138+
return result;
139+
}
140+
107141
private getIndicatorsElement = (): JSX.Element | null => {
108142
const {
109143
indicators,
110144
indicatorShape = CarouselIndicatorShape.rectangle,
111145
onRenderIndicator,
112-
triggerPageEvent
146+
triggerPageEvent,
147+
indicatorClassName,
148+
indicatorStyle
113149
} = this.props;
114150

115151
const {
@@ -129,7 +165,10 @@ export class Carousel extends React.Component<ICarouselProps, ICarouselState> {
129165
}
130166
else {
131167
indicatorElements.push(<li
132-
className={i === currentIndex ? styles.active : undefined}
168+
className={css(indicatorClassName, {
169+
[styles.active]: i === currentIndex
170+
})}
171+
style={indicatorStyle}
133172
onClick={e => this.onIndicatorClick(e, i)}
134173
/>);
135174
}
@@ -157,8 +196,14 @@ export class Carousel extends React.Component<ICarouselProps, ICarouselState> {
157196
this.props.onSelect(index);
158197
}
159198

199+
const {
200+
currentIndex
201+
} = this.state;
202+
160203
this.setState({
161-
currentIndex: index
204+
currentIndex: index,
205+
previousIndex: currentIndex,
206+
slideRight: index < currentIndex
162207
});
163208
}
164209

@@ -258,36 +303,45 @@ export class Carousel extends React.Component<ICarouselProps, ICarouselState> {
258303

259304
// Trigger parent control to update provided element
260305
if (this.props.triggerPageEvent) {
261-
// Index validation needs to be done by the parent control specyfing canMove Next|Prev
262-
nextIndex = nextButtonClicked ? (currentIndex + 1) : (currentIndex - 1);
263306

264-
// Trigger parent to provide new data
265-
this.props.triggerPageEvent(nextIndex);
266-
processingState = ProcessingState.processing;
307+
const canMove = nextButtonClicked ? this.props.canMoveNext !== false : this.props.canMovePrev !== false;
267308

268-
} else {
269-
nextIndex = this.getNextIndex(nextButtonClicked);
270-
const canMoveNext = this.props.canMoveNext != undefined ? this.props.canMoveNext : true;
271-
const canMovePrev = this.props.canMovePrev != undefined ? this.props.canMovePrev : true;
309+
if (canMove) {
310+
// Index validation needs to be done by the parent control specyfing canMove Next|Prev
311+
nextIndex = nextButtonClicked ? (currentIndex + 1) : (currentIndex - 1);
272312

273-
if (canMoveNext && nextButtonClicked && this.props.onMoveNextClicked) {
274-
this.props.onMoveNextClicked(nextIndex);
313+
// Trigger parent to provide new data
314+
this.props.triggerPageEvent(nextIndex);
315+
processingState = ProcessingState.processing;
275316
}
276-
else if (canMovePrev && !nextButtonClicked && this.props.onMovePrevClicked) {
277-
this.props.onMovePrevClicked(nextIndex);
317+
318+
} else {
319+
nextIndex = this.getNextIndex(nextButtonClicked);
320+
if (nextIndex !== currentIndex) {
321+
if (nextButtonClicked) {
322+
this.props.onMoveNextClicked(nextIndex);
323+
}
324+
else {
325+
this.props.onMovePrevClicked(nextIndex);
326+
}
278327
}
279328

280329
processingState = ProcessingState.idle;
281330
}
282331

283-
if (this.props.onSelect) {
284-
this.props.onSelect(nextIndex);
285-
}
286332

287-
this.setState({
288-
currentIndex: nextIndex,
289-
processingState
290-
});
333+
if (nextIndex !== currentIndex) {
334+
if (this.props.onSelect) {
335+
this.props.onSelect(nextIndex);
336+
}
337+
338+
this.setState({
339+
currentIndex: nextIndex,
340+
previousIndex: currentIndex,
341+
slideRight: !nextButtonClicked,
342+
processingState
343+
});
344+
}
291345
}
292346

293347
/**
@@ -328,9 +382,8 @@ export class Carousel extends React.Component<ICarouselProps, ICarouselState> {
328382
/**
329383
* Returns current element to be displayed.
330384
*/
331-
private getElementToDisplay = (): JSX.Element => {
385+
private getElementToDisplay = (currentIndex: number): JSX.Element => {
332386
const { element } = this.props;
333-
const currentIndex = this.state.currentIndex;
334387
let result: JSX.Element = null;
335388
let arrayLen: number;
336389

src/controls/carousel/ICarouselProps.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ export interface ICarouselProps {
144144

145145
/**
146146
* Enables animation on the Carousel as it transitions between slides.
147+
* This property is ignored if triggerPageEvent is in use.
147148
*/
148149
slide?: boolean;
149150

@@ -162,6 +163,16 @@ export interface ICarouselProps {
162163
*/
163164
indicatorShape?: CarouselIndicatorShape;
164165

166+
/**
167+
* Specifies additional class applied to slide position indicators
168+
*/
169+
indicatorClassName?: string;
170+
171+
/**
172+
* Specifies additional styles applied to slide position indicators
173+
*/
174+
indicatorStyle?: React.CSSProperties;
175+
165176
/**
166177
* Function to render indicator element
167178
*/

src/controls/carousel/ICarouselState.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11

2+
import * as React from 'react';
3+
24
export enum ProcessingState {
35
idle,
46
processing
@@ -13,4 +15,8 @@ export interface ICarouselState {
1315
* Specifies internal state of the control.
1416
*/
1517
processingState: ProcessingState;
18+
19+
slideRight?: boolean;
20+
21+
previousIndex?: number;
1622
}

0 commit comments

Comments
 (0)