@@ -20,19 +20,20 @@ export default class SortableList extends Component {
2020 contentContainerStyle : View . propTypes . style ,
2121 sortingEnabled : PropTypes . bool ,
2222 scrollEnabled : PropTypes . bool ,
23+ horizontal : PropTypes . bool ,
2324
2425 renderRow : PropTypes . func . isRequired ,
2526
2627 onChangeOrder : PropTypes . func ,
2728 onActivateRow : PropTypes . func ,
2829 onReleaseRow : PropTypes . func ,
29- autoscrollAreaHeight : PropTypes . number ,
30+ autoscrollAreaSize : PropTypes . number ,
3031 } ;
3132
3233 static defaultProps = {
3334 sortingEnabled : true ,
3435 scrollEnabled : true ,
35- autoscrollAreaHeight : 60 ,
36+ autoscrollAreaSize : 60 ,
3637 }
3738
3839 /**
@@ -97,62 +98,79 @@ export default class SortableList extends Component {
9798 }
9899 }
99100
100- scrollBy ( { dy = 0 , animated = false } ) {
101- this . _contentOffset = {
102- x : this . _contentOffset . x ,
103- y : this . _contentOffset . y + dy ,
104- } ;
101+ scrollBy ( { dx = 0 , dy = 0 , animated = false } ) {
102+ if ( this . props . horizontal ) {
103+ this . _contentOffset . x += dx ;
104+ } else {
105+ this . _contentOffset . y += dy ;
106+ }
107+
105108 this . _scroll ( animated ) ;
106109 }
107110
108- scrollTo ( { y = 0 , animated = false } ) {
109- this . _contentOffset = {
110- x : this . _contentOffset . x ,
111- y,
112- } ;
111+ scrollTo ( { x = 0 , y = 0 , animated = false } ) {
112+ if ( this . props . horizontal ) {
113+ this . _contentOffset . x = x ;
114+ } else {
115+ this . _contentOffset . y = y ;
116+ }
117+
113118 this . _scroll ( animated ) ;
114119 }
115120
116121 scrollToRowKey ( { key, animated = false } ) {
117122 const { order, containerLayout, rowsLayouts} = this . state ;
118123
124+ let keyX = 0 ;
119125 let keyY = 0 ;
120126
121- for ( let rowKey of order ) {
127+ for ( const rowKey of order ) {
122128 if ( rowKey === key ) {
123129 break ;
124130 }
125131
132+ keyX += rowsLayouts [ rowKey ] . width ;
126133 keyY += rowsLayouts [ rowKey ] . height ;
127134 }
128135
129136 // Scroll if the row is not visible.
130137 if (
131- keyY < this . _contentOffset . y ||
132- keyY > this . _contentOffset . y + containerLayout . height
138+ this . props . horizontal
139+ ? ( keyX < this . _contentOffset . x || keyX > this . _contentOffset . x + containerLayout . width )
140+ : ( keyY < this . _contentOffset . y || keyY > this . _contentOffset . y + containerLayout . height )
133141 ) {
134- this . _contentOffset = {
135- x : this . _contentOffset . x ,
136- y : keyY ,
137- } ;
142+ if ( this . props . horizontal ) {
143+ this . _contentOffset . x = keyX ;
144+ } else {
145+ this . _contentOffset . y = keyY ;
146+ }
147+
138148 this . _scroll ( animated ) ;
139149 }
140150 }
141151
142152 render ( ) {
143- const { contentContainerStyle} = this . props ;
144- const { contentHeight, scrollEnabled} = this . state ;
145- const containerStyle = StyleSheet . flatten ( [ styles . container , this . props . style , this . state . style ] ) ;
153+ const { contentContainerStyle, horizontal} = this . props ;
154+ const { contentHeight, contentWidth, scrollEnabled} = this . state ;
155+ const containerStyle = StyleSheet . flatten ( [ this . props . style , this . state . style ] ) ;
156+ const innerContainerStyle = [ styles . container ] ;
157+
158+ if ( horizontal ) {
159+ innerContainerStyle . push ( { width : contentWidth } ) ;
160+ } else {
161+ innerContainerStyle . push ( { height : contentHeight } ) ;
162+ }
146163
147164 return (
148165 < Animated . View style = { containerStyle } ref = { this . _onRefContainer } >
149166 < ScrollView
150167 ref = { this . _onRefScrollView }
168+ horizontal = { horizontal }
151169 contentContainerStyle = { contentContainerStyle }
152170 scrollEventThrottle = { 2 }
153171 scrollEnabled = { scrollEnabled }
154172 onScroll = { this . _onScroll } >
155- < View style = { [ styles . container , { height : contentHeight } ] } >
173+ < View style = { innerContainerStyle } >
156174 { this . _renderRows ( ) }
157175 </ View >
158176 </ ScrollView >
@@ -161,12 +179,20 @@ export default class SortableList extends Component {
161179 }
162180
163181 _renderRows ( ) {
164- const { sortingEnabled, renderRow} = this . props ;
182+ const { horizontal , sortingEnabled, renderRow} = this . props ;
165183 const { order, data, activeRowKey, releasedRowKey, rowsLayouts} = this . state ;
166184
167- const rowWidth = rowsLayouts && Math . max (
168- ...Object . keys ( rowsLayouts ) . map ( ( key ) => rowsLayouts [ key ] . width )
169- ) ;
185+ let rowHeight = 0 ;
186+ let rowWidth = 0 ;
187+
188+ if ( rowsLayouts ) {
189+ Object . keys ( rowsLayouts ) . forEach ( ( key ) => {
190+ rowHeight = Math . max ( rowHeight , rowsLayouts [ key ] . height ) ;
191+ rowWidth = Math . max ( rowWidth , rowsLayouts [ key ] . width ) ;
192+ } ) ;
193+ }
194+
195+ let nextX = 0 ;
170196 let nextY = 0 ;
171197
172198 return order . map ( ( key , index ) => {
@@ -175,9 +201,15 @@ export default class SortableList extends Component {
175201 let resolveLayout ;
176202
177203 if ( rowsLayouts ) {
178- style . width = rowWidth ;
179- location . y = nextY ;
180- nextY += rowsLayouts [ key ] . height ;
204+ if ( horizontal ) {
205+ style . height = rowHeight ;
206+ location . x = nextX ;
207+ nextX += rowsLayouts [ key ] . width ;
208+ } else {
209+ style . width = rowWidth ;
210+ location . y = nextY ;
211+ nextY += rowsLayouts [ key ] . height ;
212+ }
181213 } else {
182214 this . _rowsLayouts . push ( new Promise ( ( resolve ) => ( resolveLayout = resolve ) ) ) ;
183215 }
@@ -193,6 +225,7 @@ export default class SortableList extends Component {
193225 < Row
194226 key = { uniqueRowKey ( key ) }
195227 ref = { this . _onRefRow . bind ( this , key ) }
228+ horizontal = { horizontal }
196229 animated = { this . _areRowsAnimated && ! active }
197230 disabled = { ! sortingEnabled }
198231 style = { style }
@@ -221,16 +254,19 @@ export default class SortableList extends Component {
221254 this . _container . measure ( ( x , y , width , height , pageX , pageY ) => {
222255 const rowsLayoutsByKey = { } ;
223256 let contentHeight = 0 ;
257+ let contentWidth = 0 ;
224258
225259 rowsLayouts . forEach ( ( { rowKey, layout} ) => {
226260 rowsLayoutsByKey [ rowKey ] = layout ;
227261 contentHeight += layout . height ;
262+ contentWidth += layout . width ;
228263 } ) ;
229264
230265 this . setState ( {
231266 containerLayout : { x, y, width, height, pageX, pageY} ,
232267 rowsLayouts : rowsLayoutsByKey ,
233268 contentHeight,
269+ contentWidth,
234270 } , ( ) => {
235271 this . _animateRowsAppearance ( ( ) => ( this . _areRowsAnimated = true ) ) ;
236272 } ) ;
@@ -304,13 +340,16 @@ export default class SortableList extends Component {
304340 * Finds a row, which was covered with the moving row’s half.
305341 */
306342 _findRowUnderActiveRow ( ) {
343+ const { horizontal} = this . props ;
307344 const { rowsLayouts, activeRowKey, activeRowIndex, order} = this . state ;
308345 const movingRowLayout = rowsLayouts [ activeRowKey ] ;
346+ const rowLeftX = this . _activeRowLocation . x
347+ const rowRightX = rowLeftX + movingRowLayout . width ;
309348 const rowTopY = this . _activeRowLocation . y ;
310349 const rowBottomY = rowTopY + movingRowLayout . height ;
311350
312351 for (
313- let currentRowIndex = 0 , y = 0 , rowsCount = order . length ;
352+ let currentRowIndex = 0 , x = 0 , y = 0 , rowsCount = order . length ;
314353 currentRowIndex < rowsCount - 1 ;
315354 currentRowIndex ++
316355 ) {
@@ -319,20 +358,23 @@ export default class SortableList extends Component {
319358 const nextRowIndex = currentRowIndex + 1 ;
320359 const nextRowLayout = rowsLayouts [ order [ nextRowIndex ] ] ;
321360
322- y = y + currentRowLayout . height ;
361+ x += currentRowLayout . width ;
362+ y += currentRowLayout . height ;
323363
324- if ( currentRowKey !== activeRowKey &&
325- ( y - currentRowLayout . height <= rowTopY || currentRowIndex === 0 ) &&
326- rowTopY <= y - currentRowLayout . height / 3
327- ) {
364+ if ( currentRowKey !== activeRowKey && (
365+ horizontal
366+ ? ( ( x - currentRowLayout . width <= rowLeftX || currentRowIndex === 0 ) && rowLeftX <= x - currentRowLayout . width / 3 )
367+ : ( ( y - currentRowLayout . height <= rowTopY || currentRowIndex === 0 ) && rowTopY <= y - currentRowLayout . height / 3 )
368+ ) ) {
328369 return {
329370 rowKey : order [ currentRowIndex ] ,
330371 rowIndex : currentRowIndex ,
331372 } ;
332373 }
333374
334- if ( y + nextRowLayout . height / 3 <= rowBottomY &&
335- ( rowBottomY <= y + nextRowLayout . height || nextRowIndex === rowsCount - 1 )
375+ if ( horizontal
376+ ? ( x + nextRowLayout . width / 3 <= rowRightX && ( rowRightX <= x + nextRowLayout . width || nextRowIndex === rowsCount - 1 ) )
377+ : ( y + nextRowLayout . height / 3 <= rowBottomY && ( rowBottomY <= y + nextRowLayout . height || nextRowIndex === rowsCount - 1 ) )
336378 ) {
337379 return {
338380 rowKey : order [ nextRowIndex ] ,
@@ -345,13 +387,22 @@ export default class SortableList extends Component {
345387 }
346388
347389 _scrollOnMove ( e ) {
348- const { pageY} = e . nativeEvent ;
390+ const { pageX, pageY} = e . nativeEvent ;
391+ const { horizontal} = this . props ;
349392 const { containerLayout} = this . state ;
350- const inAutoScrollUpArea = pageY < containerLayout . pageY + this . props . autoscrollAreaHeight ;
351- const inAutoScrollDownArea = pageY > containerLayout . pageY + containerLayout . height - this . props . autoscrollAreaHeight ;
393+ let inAutoScrollBeginArea = false ;
394+ let inAutoScrollEndArea = false ;
395+
396+ if ( horizontal ) {
397+ inAutoScrollBeginArea = pageX < containerLayout . pageX + this . props . autoscrollAreaSize ;
398+ inAutoScrollEndArea = pageX > containerLayout . pageX + containerLayout . width - this . props . autoscrollAreaSize ;
399+ } else {
400+ inAutoScrollBeginArea = pageY < containerLayout . pageY + this . props . autoscrollAreaSize ;
401+ inAutoScrollEndArea = pageY > containerLayout . pageY + containerLayout . height - this . props . autoscrollAreaSize ;
402+ }
352403
353- if ( ! inAutoScrollUpArea &&
354- ! inAutoScrollDownArea &&
404+ if ( ! inAutoScrollBeginArea &&
405+ ! inAutoScrollEndArea &&
355406 this . _autoScrollInterval !== null
356407 ) {
357408 this . _stopAutoScroll ( ) ;
@@ -362,33 +413,42 @@ export default class SortableList extends Component {
362413 return ;
363414 }
364415
365- if ( inAutoScrollUpArea ) {
416+ if ( inAutoScrollBeginArea ) {
366417 this . _startAutoScroll ( {
367418 direction : - 1 ,
368- shouldScroll : ( ) => this . _contentOffset . y > 0 ,
419+ shouldScroll : ( ) => this . _contentOffset [ horizontal ? 'x' : 'y' ] > 0 ,
369420 getScrollStep : ( stepIndex ) => {
370421 const nextStep = this . _getScrollStep ( stepIndex ) ;
422+ const contentOffset = this . _contentOffset [ horizontal ? 'x' : 'y' ] ;
371423
372- return this . _contentOffset . y - nextStep < 0
373- ? this . _contentOffset . y
374- : nextStep ;
424+ return contentOffset - nextStep < 0 ? contentOffset : nextStep ;
375425 } ,
376426 } ) ;
377- } else if ( inAutoScrollDownArea ) {
427+ } else if ( inAutoScrollEndArea ) {
378428 this . _startAutoScroll ( {
379429 direction : 1 ,
380430 shouldScroll : ( ) => {
381- const { contentHeight, containerLayout} = this . state ;
431+ const { contentHeight, contentWidth , containerLayout} = this . state ;
382432
383- return this . _contentOffset . y < contentHeight - containerLayout . height ;
433+ if ( horizontal ) {
434+ return this . _contentOffset . x < contentWidth - containerLayout . width
435+ } else {
436+ return this . _contentOffset . y < contentHeight - containerLayout . height ;
437+ }
384438 } ,
385439 getScrollStep : ( stepIndex ) => {
386440 const nextStep = this . _getScrollStep ( stepIndex ) ;
387- const { contentHeight, containerLayout} = this . state ;
388-
389- return this . _contentOffset . y + nextStep > contentHeight - containerLayout . height
390- ? contentHeight - containerLayout . height - this . _contentOffset . y
391- : nextStep ;
441+ const { contentHeight, contentWidth, containerLayout} = this . state ;
442+
443+ if ( horizontal ) {
444+ return this . _contentOffset . x + nextStep > contentWidth - containerLayout . width
445+ ? contentWidth - containerLayout . width - this . _contentOffset . x
446+ : nextStep ;
447+ } else {
448+ return this . _contentOffset . y + nextStep > contentHeight - containerLayout . height
449+ ? contentHeight - containerLayout . height - this . _contentOffset . y
450+ : nextStep ;
451+ }
392452 } ,
393453 } ) ;
394454 }
@@ -404,13 +464,17 @@ export default class SortableList extends Component {
404464 }
405465
406466 const { activeRowKey} = this . state ;
467+ const { horizontal} = this . props ;
407468 let counter = 0 ;
408469
409470 this . _autoScrollInterval = setInterval ( ( ) => {
410471 if ( shouldScroll ( ) ) {
411- const dy = direction * getScrollStep ( counter ++ ) ;
412- this . scrollBy ( { dy} ) ;
413- this . _rows [ activeRowKey ] . moveBy ( { dy} ) ;
472+ const movement = {
473+ [ horizontal ? 'dx' : 'dy' ] : direction * getScrollStep ( counter ++ ) ,
474+ } ;
475+
476+ this . scrollBy ( movement ) ;
477+ this . _rows [ activeRowKey ] . moveBy ( movement ) ;
414478 } else {
415479 this . _stopAutoScroll ( ) ;
416480 }
@@ -462,11 +526,14 @@ export default class SortableList extends Component {
462526 } ;
463527
464528 _onMoveRow = ( e , gestureState , location ) => {
529+ const prevMovingRowX = this . _activeRowLocation . x ;
465530 const prevMovingRowY = this . _activeRowLocation . y ;
466531 const prevMovingDirection = this . _movingDirection ;
467532
468533 this . _activeRowLocation = location ;
469- this . _movingDirection = prevMovingRowY < this . _activeRowLocation . y ;
534+ this . _movingDirection = this . props . horizontal
535+ ? prevMovingRowX < this . _activeRowLocation . x
536+ : prevMovingRowY < this . _activeRowLocation . y ;
470537
471538 this . _movingDirectionChanged = prevMovingDirection !== this . _movingDirection ;
472539 this . _setOrderOnMove ( ) ;
0 commit comments