33import React , {
44 useCallback ,
55 useEffect ,
6+ useMemo ,
67 useRef ,
78 useState
89} from 'react' ;
@@ -37,9 +38,20 @@ const HorizontalCards = (props: Props) => {
3738 const ref = useRef ( ) ;
3839
3940 /**
40- * Sets the number of pages and total page width on the state.
41+ * Sets the flex-box style based on the page width.
42+ *
43+ * @type {function(): {flex: string} }
4144 */
42- useEffect ( ( ) => {
45+ const cardStyle = useMemo ( ( ) => ( {
46+ flex : `0 0 ${ ( pageWidth / props . perPage ) - marginWidth } px`
47+ } ) , [ pageWidth , marginWidth , props . perPage ] ) ;
48+
49+ /**
50+ * Initializes the page width and scroll pages on the sate.
51+ *
52+ * @type {(function(*=): void)|* }
53+ */
54+ const initialize = useCallback ( ( event ) => {
4355 const instance = ref . current ;
4456
4557 if ( instance ) {
@@ -48,6 +60,10 @@ const HorizontalCards = (props: Props) => {
4860 setPageWidth ( clientWidth ) ;
4961 setScrollPages ( Math . ceil ( scrollWidth / clientWidth ) ) ;
5062
63+ if ( ! event ) {
64+ setScrollPage ( 0 ) ;
65+ }
66+
5167 const child = instance . firstChild ;
5268 if ( child ) {
5369 const style = window . getComputedStyle ( child ) ;
@@ -57,8 +73,39 @@ const HorizontalCards = (props: Props) => {
5773 setMarginWidth ( leftMargin + rightMargin ) ;
5874 }
5975 }
76+ } , [ ref , props . items ] ) ;
77+
78+ /**
79+ * Sets the current page number on the state.
80+ *
81+ * @type {function(*): void }
82+ */
83+ const onPageChange = useCallback ( ( increment ) => {
84+ let nextPage = scrollPage + increment ;
85+
86+ if ( nextPage < 0 ) {
87+ nextPage = scrollPages ;
88+ } else if ( nextPage >= scrollPages ) {
89+ nextPage = 0 ;
90+ }
91+
92+ setScrollPage ( nextPage ) ;
93+ } , [ scrollPage , scrollPages ] ) ;
94+
95+ /**
96+ * Sets the window resize event listener.
97+ */
98+ useEffect ( ( ) => {
99+ window . addEventListener ( 'resize' , initialize ) ;
100+
101+ return ( ) => window . removeEventListener ( 'resize' , initialize ) ;
60102 } , [ ] ) ;
61103
104+ /**
105+ * Re-initialize the component if the items change.
106+ */
107+ useEffect ( ( ) => initialize ( ) , [ initialize , props . items ] ) ;
108+
62109 /**
63110 * Sets the total number of pages on the state.
64111 */
@@ -82,32 +129,6 @@ const HorizontalCards = (props: Props) => {
82129 }
83130 } , [ scrollPage , pageWidth ] ) ;
84131
85- /**
86- * Sets the current page number on the state.
87- *
88- * @type {function(*): void }
89- */
90- const onPageChange = useCallback ( ( increment ) => {
91- let nextPage = scrollPage + increment ;
92-
93- if ( nextPage < 0 ) {
94- nextPage = scrollPages ;
95- } else if ( nextPage >= scrollPages ) {
96- nextPage = 0 ;
97- }
98-
99- setScrollPage ( nextPage ) ;
100- } , [ scrollPage , scrollPages ] ) ;
101-
102- /**
103- * Returns the flex-box style based on the page width.
104- *
105- * @type {function(): {flex: string} }
106- */
107- const getCardStyle = useCallback ( ( ) => ( {
108- flex : `0 0 ${ ( pageWidth / props . perPage ) - marginWidth } px`
109- } ) , [ pageWidth , marginWidth , props . perPage ] ) ;
110-
111132 /**
112133 * Renders the card component. If a "route" prop is passed, the component is wrapped in a Link.
113134 *
@@ -119,35 +140,33 @@ const HorizontalCards = (props: Props) => {
119140 const renderCard = ( item , index ) => (
120141 < Card
121142 link
122- onClick = { ( ) => {
123- if ( props . onClick ) {
124- props . onClick ( item , index ) ;
125- }
126- } }
127- style = { getCardStyle ( ) }
143+ onClick = { props . onClick && props . onClick . bind ( this , item , index ) }
144+ style = { cardStyle }
128145 >
129146 { ! props . inlineImage && renderImage ( item ) }
130- < Card . Content >
131- { props . inlineImage && renderImage ( item ) }
132- { props . renderHeader && (
133- < Card . Header
134- as = { Header }
135- size = 'small'
136- >
137- { props . renderHeader ( item ) }
138- </ Card . Header >
139- ) }
140- { props . renderMeta && (
141- < Card . Meta >
142- { props . renderMeta ( item ) }
143- </ Card . Meta >
144- ) }
145- { props . renderDescription && (
146- < Card . Description >
147- { props . renderDescription ( item ) }
148- </ Card . Description >
149- ) }
150- </ Card . Content >
147+ { ( props . renderHeader || props . renderMeta || props . renderDescription ) && (
148+ < Card . Content >
149+ { props . inlineImage && renderImage ( item ) }
150+ { props . renderHeader && (
151+ < Card . Header
152+ as = { Header }
153+ size = 'small'
154+ >
155+ { props . renderHeader ( item ) }
156+ </ Card . Header >
157+ ) }
158+ { props . renderMeta && (
159+ < Card . Meta >
160+ { props . renderMeta ( item ) }
161+ </ Card . Meta >
162+ ) }
163+ { props . renderDescription && (
164+ < Card . Description >
165+ { props . renderDescription ( item ) }
166+ </ Card . Description >
167+ ) }
168+ </ Card . Content >
169+ ) }
151170 { props . renderExtra && (
152171 < Card . Content
153172 extra
0 commit comments