ui/SectionList component (#4292)
* array chunking utility * add SectionList component * Add TODOs to indicate possible future work * Add missing overlay style (as used in dapps at present)
This commit is contained in:
		
							parent
							
								
									1acc8031ce
								
							
						
					
					
						commit
						380c0773d1
					
				
							
								
								
									
										17
									
								
								js/src/ui/SectionList/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								js/src/ui/SectionList/index.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,17 @@ | |||||||
|  | // Copyright 2015, 2016 Parity Technologies (UK) Ltd.
 | ||||||
|  | // This file is part of Parity.
 | ||||||
|  | 
 | ||||||
|  | // Parity is free software: you can redistribute it and/or modify
 | ||||||
|  | // it under the terms of the GNU General Public License as published by
 | ||||||
|  | // the Free Software Foundation, either version 3 of the License, or
 | ||||||
|  | // (at your option) any later version.
 | ||||||
|  | 
 | ||||||
|  | // Parity is distributed in the hope that it will be useful,
 | ||||||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | ||||||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | ||||||
|  | // GNU General Public License for more details.
 | ||||||
|  | 
 | ||||||
|  | // You should have received a copy of the GNU General Public License
 | ||||||
|  | // along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 | ||||||
|  | 
 | ||||||
|  | export default from './sectionList'; | ||||||
							
								
								
									
										72
									
								
								js/src/ui/SectionList/sectionList.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								js/src/ui/SectionList/sectionList.css
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,72 @@ | |||||||
|  | /* Copyright 2015, 2016 Parity Technologies (UK) Ltd. | ||||||
|  | /* This file is part of Parity. | ||||||
|  | /* | ||||||
|  | /* Parity is free software: you can redistribute it and/or modify | ||||||
|  | /* it under the terms of the GNU General Public License as published by | ||||||
|  | /* the Free Software Foundation, either version 3 of the License, or | ||||||
|  | /* (at your option) any later version. | ||||||
|  | /* | ||||||
|  | /* Parity is distributed in the hope that it will be useful, | ||||||
|  | /* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  | /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||||
|  | /* GNU General Public License for more details. | ||||||
|  | /* | ||||||
|  | /* You should have received a copy of the GNU General Public License | ||||||
|  | /* along with Parity.  If not, see <http://www.gnu.org/licenses/>. | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | .section { | ||||||
|  |   margin-bottom: 1em; | ||||||
|  |   position: relative; | ||||||
|  | 
 | ||||||
|  |   .overlay { | ||||||
|  |     background: rgba(0, 0, 0, 0.85); | ||||||
|  |     bottom: 0; | ||||||
|  |     left: 0; | ||||||
|  |     padding: 1.5em; | ||||||
|  |     position: absolute; | ||||||
|  |     right: 0; | ||||||
|  |     top: 0; | ||||||
|  |     z-index: 199; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   .row { | ||||||
|  |     display: flex; | ||||||
|  |     justify-content: center; | ||||||
|  | 
 | ||||||
|  |     /* TODO: As per JS comments, the flex-base could be adjusted in the future to allow for */ | ||||||
|  |     /* case where <> 3 columns are required should the need arrise from a UI pov. */ | ||||||
|  |     .item { | ||||||
|  |       box-sizing: border-box; | ||||||
|  |       cursor: pointer; | ||||||
|  |       flex: 0 1 33.33%; | ||||||
|  |       height: 100%; | ||||||
|  |       opacity: 0.75; | ||||||
|  |       padding: 0.25em; | ||||||
|  |       transition: all 0.75s cubic-bezier(0.23, 1, 0.32, 1); | ||||||
|  | 
 | ||||||
|  |       /* TODO: The hover and no-hover states can be improved to not "just appear" */ | ||||||
|  |       &:not(:hover) { | ||||||
|  |         & [data-hover="hide"] { | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         & [data-hover="show"] { | ||||||
|  |           display: none; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       &:hover { | ||||||
|  |         flex: 0 0 50%; | ||||||
|  |         opacity: 1; | ||||||
|  |         z-index: 100; | ||||||
|  | 
 | ||||||
|  |         & [data-hover="hide"] { | ||||||
|  |           display: none; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         & [data-hover="show"] { | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										95
									
								
								js/src/ui/SectionList/sectionList.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								js/src/ui/SectionList/sectionList.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,95 @@ | |||||||
|  | // Copyright 2015, 2016 Parity Technologies (UK) Ltd.
 | ||||||
|  | // This file is part of Parity.
 | ||||||
|  | 
 | ||||||
|  | // Parity is free software: you can redistribute it and/or modify
 | ||||||
|  | // it under the terms of the GNU General Public License as published by
 | ||||||
|  | // the Free Software Foundation, either version 3 of the License, or
 | ||||||
|  | // (at your option) any later version.
 | ||||||
|  | 
 | ||||||
|  | // Parity is distributed in the hope that it will be useful,
 | ||||||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | ||||||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | ||||||
|  | // GNU General Public License for more details.
 | ||||||
|  | 
 | ||||||
|  | // You should have received a copy of the GNU General Public License
 | ||||||
|  | // along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 | ||||||
|  | 
 | ||||||
|  | import React, { Component, PropTypes } from 'react'; | ||||||
|  | 
 | ||||||
|  | import { chunkArray } from '~/util/array'; | ||||||
|  | import { arrayOrObjectProptype, nodeOrStringProptype } from '~/util/proptypes'; | ||||||
|  | 
 | ||||||
|  | import styles from './sectionList.css'; | ||||||
|  | 
 | ||||||
|  | // TODO: We probably want this to be passed via props - additional work required in that case to
 | ||||||
|  | // support the styling for both the hover and no-hover CSS for the pre/post sizes. Future work only
 | ||||||
|  | // if/when required.
 | ||||||
|  | const ITEMS_PER_ROW = 3; | ||||||
|  | 
 | ||||||
|  | export default class SectionList extends Component { | ||||||
|  |   static propTypes = { | ||||||
|  |     className: PropTypes.string, | ||||||
|  |     items: arrayOrObjectProptype().isRequired, | ||||||
|  |     renderItem: PropTypes.func.isRequired, | ||||||
|  |     overlay: nodeOrStringProptype() | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   render () { | ||||||
|  |     const { className, items } = this.props; | ||||||
|  | 
 | ||||||
|  |     if (!items || !items.length) { | ||||||
|  |       return null; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return ( | ||||||
|  |       <section className={ [styles.section, className].join(' ') }> | ||||||
|  |         { this.renderOverlay() } | ||||||
|  |         { chunkArray(items, ITEMS_PER_ROW).map(this.renderRow) } | ||||||
|  |       </section> | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   renderOverlay () { | ||||||
|  |     const { overlay } = this.props; | ||||||
|  | 
 | ||||||
|  |     if (!overlay) { | ||||||
|  |       return null; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return ( | ||||||
|  |       <div className={ styles.overlay }> | ||||||
|  |         { overlay } | ||||||
|  |       </div> | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   renderRow = (row, index) => { | ||||||
|  |     return ( | ||||||
|  |       <div | ||||||
|  |         className={ styles.row } | ||||||
|  |         key={ `row_${index}` } | ||||||
|  |       > | ||||||
|  |         { row.map(this.renderItem) } | ||||||
|  |       </div> | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   renderItem = (item, index) => { | ||||||
|  |     const { renderItem } = this.props; | ||||||
|  | 
 | ||||||
|  |     // NOTE: Any children that is to be showed or hidden (depending on hover state)
 | ||||||
|  |     // should have the data-hover="show|hide" attributes. For the current implementation
 | ||||||
|  |     // this does the trick, however there may be a case for adding a hover attribute
 | ||||||
|  |     // to an item (mouseEnter/mouseLeave events) and then adjusting the styling with
 | ||||||
|  |     // :root[hover]/:root:not[hover] for the tragetted elements. Currently it is a
 | ||||||
|  |     // CSS-only solution to let the browser do all the work via selectors.
 | ||||||
|  |     return ( | ||||||
|  |       <div | ||||||
|  |         className={ styles.item } | ||||||
|  |         key={ `item_${index}` } | ||||||
|  |       > | ||||||
|  |         { renderItem(item, index) } | ||||||
|  |       </div> | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										103
									
								
								js/src/ui/SectionList/sectionList.spec.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								js/src/ui/SectionList/sectionList.spec.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,103 @@ | |||||||
|  | // Copyright 2015, 2016 Parity Technologies (UK) Ltd.
 | ||||||
|  | // This file is part of Parity.
 | ||||||
|  | 
 | ||||||
|  | // Parity is free software: you can redistribute it and/or modify
 | ||||||
|  | // it under the terms of the GNU General Public License as published by
 | ||||||
|  | // the Free Software Foundation, either version 3 of the License, or
 | ||||||
|  | // (at your option) any later version.
 | ||||||
|  | 
 | ||||||
|  | // Parity is distributed in the hope that it will be useful,
 | ||||||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | ||||||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | ||||||
|  | // GNU General Public License for more details.
 | ||||||
|  | 
 | ||||||
|  | // You should have received a copy of the GNU General Public License
 | ||||||
|  | // along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 | ||||||
|  | 
 | ||||||
|  | import { shallow } from 'enzyme'; | ||||||
|  | import React from 'react'; | ||||||
|  | import sinon from 'sinon'; | ||||||
|  | 
 | ||||||
|  | import SectionList from './'; | ||||||
|  | 
 | ||||||
|  | const ITEMS = ['itemA', 'itemB', 'itemC', 'itemD', 'itemE']; | ||||||
|  | 
 | ||||||
|  | let component; | ||||||
|  | let instance; | ||||||
|  | let renderItem; | ||||||
|  | 
 | ||||||
|  | function render (props = {}) { | ||||||
|  |   renderItem = sinon.stub(); | ||||||
|  |   component = shallow( | ||||||
|  |     <SectionList | ||||||
|  |       className='testClass' | ||||||
|  |       items={ ITEMS } | ||||||
|  |       renderItem={ renderItem } | ||||||
|  |       section='testSection' | ||||||
|  |     /> | ||||||
|  |   ); | ||||||
|  |   instance = component.instance(); | ||||||
|  | 
 | ||||||
|  |   return component; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | describe('SectionList', () => { | ||||||
|  |   beforeEach(() => { | ||||||
|  |     render(); | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   it('renders defaults', () => { | ||||||
|  |     expect(component).to.be.ok; | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   it('adds className as specified', () => { | ||||||
|  |     expect(component.hasClass('testClass')).to.be.true; | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   describe('instance methods', () => { | ||||||
|  |     describe('renderRow', () => { | ||||||
|  |       let row; | ||||||
|  | 
 | ||||||
|  |       beforeEach(() => { | ||||||
|  |         sinon.stub(instance, 'renderItem'); | ||||||
|  |         row = instance.renderRow(['testA', 'testB']); | ||||||
|  |       }); | ||||||
|  | 
 | ||||||
|  |       afterEach(() => { | ||||||
|  |         instance.renderItem.restore(); | ||||||
|  |       }); | ||||||
|  | 
 | ||||||
|  |       it('renders a row', () => { | ||||||
|  |         expect(row).to.be.ok; | ||||||
|  |       }); | ||||||
|  | 
 | ||||||
|  |       it('adds a key for the row', () => { | ||||||
|  |         expect(row.key).to.be.ok; | ||||||
|  |       }); | ||||||
|  | 
 | ||||||
|  |       it('calls renderItem for the items', () => { | ||||||
|  |         expect(instance.renderItem).to.have.been.calledTwice; | ||||||
|  |       }); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     describe('renderItem', () => { | ||||||
|  |       let item; | ||||||
|  | 
 | ||||||
|  |       beforeEach(() => { | ||||||
|  |         item = instance.renderItem('testItem', 50); | ||||||
|  |       }); | ||||||
|  | 
 | ||||||
|  |       it('renders an item', () => { | ||||||
|  |         expect(item).to.be.ok; | ||||||
|  |       }); | ||||||
|  | 
 | ||||||
|  |       it('adds a key for the item', () => { | ||||||
|  |         expect(item.key).to.be.ok; | ||||||
|  |       }); | ||||||
|  | 
 | ||||||
|  |       it('calls the external renderer', () => { | ||||||
|  |         expect(renderItem).to.have.been.calledWith('testItem', 50); | ||||||
|  |       }); | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
|  | }); | ||||||
| @ -47,6 +47,7 @@ import Page from './Page'; | |||||||
| import ParityBackground from './ParityBackground'; | import ParityBackground from './ParityBackground'; | ||||||
| import PasswordStrength from './Form/PasswordStrength'; | import PasswordStrength from './Form/PasswordStrength'; | ||||||
| import QrCode from './QrCode'; | import QrCode from './QrCode'; | ||||||
|  | import SectionList from './SectionList'; | ||||||
| import ShortenedHash from './ShortenedHash'; | import ShortenedHash from './ShortenedHash'; | ||||||
| import SignerIcon from './SignerIcon'; | import SignerIcon from './SignerIcon'; | ||||||
| import Tags from './Tags'; | import Tags from './Tags'; | ||||||
| @ -102,8 +103,9 @@ export { | |||||||
|   PasswordStrength, |   PasswordStrength, | ||||||
|   QrCode, |   QrCode, | ||||||
|   RadioButtons, |   RadioButtons, | ||||||
|   ShortenedHash, |  | ||||||
|   Select, |   Select, | ||||||
|  |   ShortenedHash, | ||||||
|  |   SectionList, | ||||||
|   SignerIcon, |   SignerIcon, | ||||||
|   Tags, |   Tags, | ||||||
|   Tooltip, |   Tooltip, | ||||||
|  | |||||||
							
								
								
									
										26
									
								
								js/src/util/array.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								js/src/util/array.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,26 @@ | |||||||
|  | // Copyright 2015, 2016 Parity Technologies (UK) Ltd.
 | ||||||
|  | // This file is part of Parity.
 | ||||||
|  | 
 | ||||||
|  | // Parity is free software: you can redistribute it and/or modify
 | ||||||
|  | // it under the terms of the GNU General Public License as published by
 | ||||||
|  | // the Free Software Foundation, either version 3 of the License, or
 | ||||||
|  | // (at your option) any later version.
 | ||||||
|  | 
 | ||||||
|  | // Parity is distributed in the hope that it will be useful,
 | ||||||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | ||||||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | ||||||
|  | // GNU General Public License for more details.
 | ||||||
|  | 
 | ||||||
|  | // You should have received a copy of the GNU General Public License
 | ||||||
|  | // along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 | ||||||
|  | 
 | ||||||
|  | // http://stackoverflow.com/questions/11318680/split-array-into-chunks-of-n-length
 | ||||||
|  | export function chunkArray (array, size) { | ||||||
|  |   return array | ||||||
|  |     .map((item, index) => { | ||||||
|  |       return index % size === 0 | ||||||
|  |         ? array.slice(index, index + size) | ||||||
|  |         : null; | ||||||
|  |     }) | ||||||
|  |     .filter((item) => item); | ||||||
|  | } | ||||||
							
								
								
									
										29
									
								
								js/src/util/array.spec.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								js/src/util/array.spec.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,29 @@ | |||||||
|  | // Copyright 2015, 2016 Parity Technologies (UK) Ltd.
 | ||||||
|  | // This file is part of Parity.
 | ||||||
|  | 
 | ||||||
|  | // Parity is free software: you can redistribute it and/or modify
 | ||||||
|  | // it under the terms of the GNU General Public License as published by
 | ||||||
|  | // the Free Software Foundation, either version 3 of the License, or
 | ||||||
|  | // (at your option) any later version.
 | ||||||
|  | 
 | ||||||
|  | // Parity is distributed in the hope that it will be useful,
 | ||||||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | ||||||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | ||||||
|  | // GNU General Public License for more details.
 | ||||||
|  | 
 | ||||||
|  | // You should have received a copy of the GNU General Public License
 | ||||||
|  | // along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 | ||||||
|  | 
 | ||||||
|  | import { chunkArray } from './array'; | ||||||
|  | 
 | ||||||
|  | describe('util/array', () => { | ||||||
|  |   describe('chunkArray', () => { | ||||||
|  |     it('splits array into equal chunks', () => { | ||||||
|  |       expect(chunkArray([1, 2, 3, 4], 2)).to.deep.equal([[1, 2], [3, 4]]); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it('splits array into equal chunks (non-divisible)', () => { | ||||||
|  |       expect(chunkArray([1, 2, 3, 4], 3)).to.deep.equal([[1, 2, 3], [4]]); | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
|  | }); | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user