1+ require ( './Carousel.scss' )
2+ import classNames from 'classnames'
3+
4+ import React , { Component } from 'react'
5+ import ReactDOM from 'react-dom'
6+
7+ import LeftArrowIcon from '../Icons/LeftArrowIcon'
8+ import RightArrowIcon from '../Icons/RightArrowIcon'
9+
10+ export default class Carousel extends Component {
11+ componentWillMount ( ) {
12+ this . handleResize = this . handleResize . bind ( this )
13+ window . addEventListener ( 'resize' , this . handleResize )
14+ this . handlePageUp = this . handlePageUp . bind ( this )
15+ this . handlePageDown = this . handlePageDown . bind ( this )
16+ this . setState ( { firstVisibleItem : this . props . firstVisibleItem || 0 } )
17+ }
18+
19+ componentWillUnmount ( ) {
20+ window . removeEventListener ( 'resize' , this . handleResize )
21+ }
22+
23+ handleResize ( ) {
24+ this . validatePagers ( )
25+ }
26+
27+ componentDidMount ( ) {
28+ this . validatePagers ( )
29+ }
30+
31+ componentDidUpdate ( ) {
32+ this . validatePagers ( )
33+ }
34+
35+ validatePagers ( ) {
36+ const pageDownClass = classNames (
37+ 'page-down' ,
38+ { hidden : this . state . firstVisibleItem === 0 }
39+ )
40+ const pageUpClass = classNames (
41+ 'page-up' ,
42+ { hidden : this . lastElementVisible ( this . state . firstVisibleItem ) }
43+ )
44+ const node = ReactDOM . findDOMNode ( this )
45+ const pageDownNode = node . querySelector ( '.page-down' )
46+ const pageUpNode = node . querySelector ( '.page-up' )
47+ pageDownNode . className = pageDownClass
48+ pageUpNode . className = pageUpClass
49+ }
50+
51+
52+ lastElementVisible ( firstVisibleItem ) {
53+ const node = ReactDOM . findDOMNode ( this )
54+ const parentNode = node . parentNode
55+ const maxWidth = parentNode . getBoundingClientRect ( ) . width
56+ const visibleAreaNode = node . querySelector ( '.visible-area' )
57+ visibleAreaNode . style . width = maxWidth + 'px'
58+ const itemNodes = visibleAreaNode . children
59+ let width = 0
60+ if ( firstVisibleItem > 0 ) {
61+ // if first item is not visible, account 20px for page-down element
62+ width += 20
63+ // account the right margin for page-down (see Carousel.scss)
64+ width += 15
65+ }
66+ for ( let i = 0 ; i < itemNodes . length ; i ++ ) {
67+ const itemNode = itemNodes [ i ]
68+ width += itemNode . getBoundingClientRect ( ) . width
69+ if ( i < itemNodes . length - 1 ) {
70+ // account 30px for every carousel-item (see Carousel.scss)
71+ width += 30
72+ }
73+ if ( width > maxWidth ) {
74+ return false
75+ }
76+ }
77+ return true
78+ }
79+
80+ handlePageUp ( ) {
81+ if ( ! this . lastElementVisible ( this . state . firstVisibleItem + 1 ) ) {
82+ const nextFirstVisibleItem = this . state . firstVisibleItem + 1
83+ this . setState ( { firstVisibleItem : nextFirstVisibleItem } )
84+ }
85+ }
86+
87+ handlePageDown ( ) {
88+ if ( this . state . firstVisibleItem > 0 ) {
89+ const nextFirstVisibleItem = this . state . firstVisibleItem - 1
90+ this . setState ( { firstVisibleItem : nextFirstVisibleItem } )
91+ }
92+ }
93+
94+ render ( ) {
95+ const carouselItem = ( item , idx ) => {
96+ if ( idx < this . state . firstVisibleItem ) {
97+ return
98+ }
99+
100+ return (
101+ < div key = { idx } className = "carousel-item" >
102+ { item }
103+ </ div >
104+ )
105+ }
106+
107+ return (
108+ < div className = "Carousel" >
109+ < div className = "page-down" onClick = { this . handlePageDown } >
110+ < LeftArrowIcon fill = "#FFFFFF" />
111+ </ div >
112+ < div className = "visible-area" >
113+ { this . props . children . map ( carouselItem ) }
114+ </ div >
115+ < div className = "page-up" onClick = { this . handlePageUp } >
116+ < RightArrowIcon fill = "#FFFFFF" />
117+ </ div >
118+ </ div >
119+ )
120+ }
121+ }
0 commit comments