Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

ui/SectionList component #4292

Merged
merged 4 commits into from
Jan 25, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions js/src/ui/SectionList/index.js
Original file line number Diff line number Diff line change
@@ -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 changes: 72 additions & 0 deletions js/src/ui/SectionList/sectionList.css
Original file line number Diff line number Diff line change
@@ -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 changes: 95 additions & 0 deletions js/src/ui/SectionList/sectionList.js
Original file line number Diff line number Diff line change
@@ -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 changes: 103 additions & 0 deletions js/src/ui/SectionList/sectionList.spec.js
Original file line number Diff line number Diff line change
@@ -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);
});
});
});
});
4 changes: 3 additions & 1 deletion js/src/ui/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import Page from './Page';
import ParityBackground from './ParityBackground';
import PasswordStrength from './Form/PasswordStrength';
import QrCode from './QrCode';
import SectionList from './SectionList';
import ShortenedHash from './ShortenedHash';
import SignerIcon from './SignerIcon';
import Tags from './Tags';
Expand Down Expand Up @@ -102,8 +103,9 @@ export {
PasswordStrength,
QrCode,
RadioButtons,
ShortenedHash,
Select,
ShortenedHash,
SectionList,
SignerIcon,
Tags,
Tooltip,
Expand Down
26 changes: 26 additions & 0 deletions js/src/util/array.js
Original file line number Diff line number Diff line change
@@ -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 changes: 29 additions & 0 deletions js/src/util/array.spec.js
Original file line number Diff line number Diff line change
@@ -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]]);
});
});
});