Skip to content
Snippets Groups Projects
Commit a27fac13 authored by Yannis Barlas's avatar Yannis Barlas
Browse files

Merge branch 'state-list' into 'master'

State list

See merge request pubsweet/pubsweet!32
parents b44aab21 9dcf0fb9
No related branches found
No related tags found
No related merge requests found
{
"name": "@pubsweet/ui",
"version": "0.1.3",
"version": "0.1.2",
"files": ["docs", "dist", "src"],
"main": "src",
"jsnext:main": "src",
......
import PropTypes from 'prop-types'
import React from 'react'
import classNames from 'classnames'
import classes from './StateItem.local.scss'
const StateItem = ({ disabled, name, update, values, index }) => {
const handleInteraction = () => {
if (disabled) return
const nextIndex = arrayShift(values, index)
update(name, nextIndex)
}
const arrayShift = (array, i) => (i === array.length - 1 ? 0 : i + 1)
return (
<span
className={classNames(classes.root, {
[classes.disabled]: disabled,
})}
disabled={disabled}
onClick={handleInteraction}
onKeyPress={handleInteraction}
role="button"
tabIndex="0"
>
{values[index]}
</span>
)
}
StateItem.propTypes = {
disabled: PropTypes.bool,
index: PropTypes.number.isRequired,
name: PropTypes.string.isRequired,
update: PropTypes.func.isRequired,
values: PropTypes.arrayOf(PropTypes.string).isRequired,
}
StateItem.defaultProps = {
disabled: false,
}
export default StateItem
$dark-grey: #404040;
$light-grey: #b3b3b3;
.root {
cursor: pointer;
font-family: var(--font-interface);
font-size: 16px;
font-style: italic;
padding: 0;
&:focus {
outline: none;
}
&:hover {
color: $dark-grey;
transition: 0.25s ease-in-out 0s;
}
}
.disabled {
color: $light-grey;
cursor: default;
&:hover {
color: $light-grey;
}
}
An interactive element which upon click changes its text content. The available text values should be provided as an array of strings. The actual operation which takes place is a right shift on the array of provided values
```js
const data = {
values: ['To Clean', 'Cleaning', 'Cleaned'],
index: 0,
disabled: false,
name: 'clean',
}
const update = value => {
console.log('value', value)
}
;<StateItem
values={data.values}
disabled={data.disabled}
update={update}
index={data.index}
name={data.name}
/>
```
import PropTypes from 'prop-types'
import React from 'react'
import { map, uniqueId, keys, last } from 'lodash'
import { ChevronRight } from 'react-feather'
import classes from './StateList.local.scss'
import StateItem from '../atoms/StateItem'
const StateList = ({ currentValues, update, values }) => {
const progressIds = keys(values)
const lastItem = last(progressIds)
// TODO: Placeholder -- to be implemented with authsome
const canAct = key => true
const handleUpdate = (name, index) => {
update(name, index)
}
const items = map(values, (valueList, name) => {
let delimiter
const currentValueIndex = currentValues[name]
if (name !== lastItem) {
delimiter = <ChevronRight className={classes.delimiter} size={16} />
}
return (
<div className={classes.itemContainer} key={uniqueId()}>
<StateItem
disabled={!canAct(name)}
index={currentValueIndex}
name={name}
update={handleUpdate}
values={valueList}
/>
{delimiter}
</div>
)
})
return <div className={classes.stateListContainer}>{items}</div>
}
StateList.propTypes = {
currentValues: PropTypes.objectOf(PropTypes.number).isRequired,
update: PropTypes.func.isRequired,
values: PropTypes.objectOf(PropTypes.arrayOf(PropTypes.string)).isRequired,
}
export default StateList
.stateListContainer {
align-items: center;
display: flex;
flex-direction: row;
}
.itemContainer {
align-items: center;
display: flex;
flex-direction: row;
}
.delimiter {
margin-left: 5px;
margin-right: 5px;
}
A list of State Items separated by a delimiter.
```js
const current = {
style: 0,
edit: 0,
clean: 0,
review: 0,
}
const stateValues = {
clean: ['To Clean', 'Cleaning', 'Cleaned'],
edit: ['To Edit', 'Editing', 'Edited'],
review: ['To Review', 'Reviewing', 'Reviewed'],
style: ['To Style', 'Styling', 'Styled'],
}
const update = data => {
console.log('data', data)
}
;<StateList currentValues={current} values={stateValues} update={update} />
```
import React from 'react'
import { clone } from 'lodash'
import { shallow, render } from 'enzyme'
import renderer from 'react-test-renderer'
import StateItem from '../src/atoms/StateItem'
const myMock = jest.fn()
const props = {
values: ['To Clean', 'Cleaning', 'Cleaned'],
disabled: false,
update: myMock,
index: 1,
name: 'clean',
}
const wrapper = shallow(<StateItem {...props} />)
const wrapperRendered = render(<StateItem {...props} />)
describe('StateItem', () => {
test('is rendered correctly', () => {
const tree = renderer.create(<StateItem {...props} />).toJSON()
expect(tree).toMatchSnapshot()
})
test('with default props class disabled should not exist', () => {
expect(wrapper.is('.disabled')).toBe(false)
})
test('with given props should be disabled', () => {
const newProps = clone(props)
newProps.disabled = true
const newWrapper = shallow(<StateItem {...newProps} />)
expect(newWrapper.is('.disabled')).toBe(true)
})
test('should render the value Cleaning', () => {
expect(wrapperRendered.text()).toEqual(props.values[props.index])
})
test('update method should be triggered upon click', () => {
wrapper.simulate('click')
expect(wrapper.instance().props.update).toHaveBeenCalled()
})
})
import React from 'react'
import { forIn } from 'lodash'
import { shallow } from 'enzyme'
import renderer from 'react-test-renderer'
import StateItem from '../src/atoms/StateItem'
import StateList from '../src/molecules/StateList'
const currentValues = {
style: 0,
edit: 0,
clean: 0,
review: 0,
}
const stateValues = {
clean: ['To Clean', 'Cleaning', 'Cleaned'],
edit: ['To Edit', 'Editing', 'Edited'],
review: ['To Review', 'Reviewing', 'Reviewed'],
style: ['To Style', 'Styling', 'Styled'],
}
const props = {
currentValues,
values: stateValues,
update: () => null,
}
const wrapper = shallow(<StateList {...props} />)
const stateItems = wrapper.find(StateItem)
describe('StateList', () => {
test('is rendered correctly', () => {
const tree = renderer.create(<StateList {...props} />).toJSON()
expect(tree).toMatchSnapshot()
})
test('should contain four State Item children', () => {
const itemsNumber = Object.keys(stateValues).length
expect(stateItems.exists()).toEqual(true)
expect(stateItems).toHaveLength(itemsNumber)
})
test('gets the correct props', () => {
let i = 0
const stateItemComp = stateItems.getElements()
forIn(stateValues, (value, key) => {
const stateItem = stateItemComp[i]
const stateItemProps = stateItem.props
expect(stateItemProps.disabled).toEqual(false)
expect(stateItemProps.index).toEqual(props.currentValues[key])
expect(stateItemProps.name).toEqual(key)
expect(stateItemProps.values).toEqual(props.values[key])
i += 1
})
})
})
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`StateItem is rendered correctly 1`] = `
<span
className="root"
disabled={false}
onClick={[Function]}
onKeyPress={[Function]}
role="button"
tabIndex="0"
>
Cleaning
</span>
`;
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`StateList is rendered correctly 1`] = `
<div
className="stateListContainer"
>
<div
className="itemContainer"
>
<span
className="root"
disabled={false}
onClick={[Function]}
onKeyPress={[Function]}
role="button"
tabIndex="0"
>
To Clean
</span>
<svg
className="delimiter"
fill="none"
height={16}
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
viewBox="0 0 24 24"
width={16}
xmlns="http://www.w3.org/2000/svg"
>
<polyline
points="9 18 15 12 9 6"
/>
</svg>
</div>
<div
className="itemContainer"
>
<span
className="root"
disabled={false}
onClick={[Function]}
onKeyPress={[Function]}
role="button"
tabIndex="0"
>
To Edit
</span>
<svg
className="delimiter"
fill="none"
height={16}
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
viewBox="0 0 24 24"
width={16}
xmlns="http://www.w3.org/2000/svg"
>
<polyline
points="9 18 15 12 9 6"
/>
</svg>
</div>
<div
className="itemContainer"
>
<span
className="root"
disabled={false}
onClick={[Function]}
onKeyPress={[Function]}
role="button"
tabIndex="0"
>
To Review
</span>
<svg
className="delimiter"
fill="none"
height={16}
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
viewBox="0 0 24 24"
width={16}
xmlns="http://www.w3.org/2000/svg"
>
<polyline
points="9 18 15 12 9 6"
/>
</svg>
</div>
<div
className="itemContainer"
>
<span
className="root"
disabled={false}
onClick={[Function]}
onKeyPress={[Function]}
role="button"
tabIndex="0"
>
To Style
</span>
</div>
</div>
`;
......@@ -55,35 +55,6 @@
lodash "^4.2.0"
to-fast-properties "^2.0.0"
"@pubsweet/db-manager@^0.0.10":
version "0.0.10"
resolved "https://registry.yarnpkg.com/@pubsweet/db-manager/-/db-manager-0.0.10.tgz#19d2613aa05f135fbe313b2842345d4cdac73c0e"
dependencies:
"@pubsweet/logger" "^0.1.0"
fs-extra "^4.0.2"
isomorphic-fetch "^2.2.1"
joi "^11.0.2"
pouchdb "^6.3.4"
pubsweet-server "^1.0.2"
"@pubsweet/db-manager@^0.0.8":
version "0.0.8"
resolved "https://registry.yarnpkg.com/@pubsweet/db-manager/-/db-manager-0.0.8.tgz#f0d2d48ab393aa7958d6bcd8c97f0500686653bf"
dependencies:
"@pubsweet/logger" "0.0.1"
fs-extra "^4.0.2"
isomorphic-fetch "^2.2.1"
joi "^11.0.2"
pouchdb "^6.3.4"
pubsweet-server "^1.0.0-beta.2"
"@pubsweet/logger@0.0.1":
version "0.0.1"
resolved "https://registry.yarnpkg.com/@pubsweet/logger/-/logger-0.0.1.tgz#ec0c15f04e0c64232c29173848ffe6da8190c9c2"
dependencies:
config "^1.26.2"
joi "^10.6.0"
"@pubsweet/starter@git+https://gitlab.coko.foundation/pubsweet/pubsweet-starter.git":
version "1.0.0-alpha.1"
resolved "git+https://gitlab.coko.foundation/pubsweet/pubsweet-starter.git#2a2a5c197a90befc2c60a6cf226b699353a6daae"
......@@ -5534,10 +5505,6 @@ isemail@1.x.x:
version "1.2.0"
resolved "https://registry.yarnpkg.com/isemail/-/isemail-1.2.0.tgz#be03df8cc3e29de4d2c5df6501263f1fa4595e9a"
isemail@2.x.x:
version "2.2.1"
resolved "https://registry.yarnpkg.com/isemail/-/isemail-2.2.1.tgz#0353d3d9a62951080c262c2aa0a42b8ea8e9e2a6"
isemail@3.x.x:
version "3.0.0"
resolved "https://registry.yarnpkg.com/isemail/-/isemail-3.0.0.tgz#c89a46bb7a3361e1759f8028f9082488ecce3dff"
......@@ -5638,10 +5605,6 @@ istanbul-reports@^1.1.3:
dependencies:
handlebars "^4.0.3"
items@2.x.x:
version "2.1.1"
resolved "https://registry.yarnpkg.com/items/-/items-2.1.1.tgz#8bd16d9c83b19529de5aea321acaada78364a198"
javascript-stringify@^1.6.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/javascript-stringify/-/javascript-stringify-1.6.0.tgz#142d111f3a6e3dae8f4a9afd77d45855b5a9cce3"
......@@ -5875,23 +5838,6 @@ joi-browser@^13.0.1:
version "13.0.1"
resolved "https://registry.yarnpkg.com/joi-browser/-/joi-browser-13.0.1.tgz#06a7b782d94bca6fa0f107138846ea16588b2e7b"
joi@^10.0.6, joi@^10.4.1, joi@^10.6.0:
version "10.6.0"
resolved "https://registry.yarnpkg.com/joi/-/joi-10.6.0.tgz#52587f02d52b8b75cdb0c74f0b164a191a0e1fc2"
dependencies:
hoek "4.x.x"
isemail "2.x.x"
items "2.x.x"
topo "2.x.x"
joi@^11.0.2:
version "11.4.0"
resolved "https://registry.yarnpkg.com/joi/-/joi-11.4.0.tgz#f674897537b625e9ac3d0b7e1604c828ad913ccb"
dependencies:
hoek "4.x.x"
isemail "3.x.x"
topo "2.x.x"
joi@^13.1.0:
version "13.1.0"
resolved "https://registry.yarnpkg.com/joi/-/joi-13.1.0.tgz#59e7b8714b932a1e342c3583d5841d7169ff1822"
......@@ -8600,15 +8546,6 @@ public-encrypt@^4.0.0:
parse-asn1 "^5.0.0"
randombytes "^2.0.1"
pubsweet-component-form-group@0.1.5:
version "0.1.5"
resolved "https://registry.yarnpkg.com/pubsweet-component-form-group/-/pubsweet-component-form-group-0.1.5.tgz#392d76f8a9506731c82a7027ba95ab562f6c90ca"
dependencies:
joi-browser "^13.0.1"
prop-types "^15.5.10"
pubsweet-server "^1.0.3"
react-bootstrap "^0.31.3"
pubsweet-component-posts-manager@0.6.5:
version "0.6.5"
resolved "https://registry.yarnpkg.com/pubsweet-component-posts-manager/-/pubsweet-component-posts-manager-0.6.5.tgz#d35ac7f74bf198d652ff81e9a790ea006ec3719c"
......@@ -8622,67 +8559,6 @@ pubsweet-component-posts-manager@0.6.5:
react-router-dom "^4.2.2"
redux "^3.7.2"
pubsweet-server@1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/pubsweet-server/-/pubsweet-server-1.0.2.tgz#3c48267c6e010ddea6c380599c341aadd465f541"
dependencies:
"@pubsweet/logger" "^0.1.0"
authsome "0.0.9"
bcrypt "^1.0.2"
bluebird "^3.5.1"
body-parser "^1.15.2"
colors "^1.1.2"
config "^1.26.2"
cookie-parser "^1.4.3"
dotenv "^4.0.0"
express "^4.16.1"
helmet "^3.8.1"
http-status-codes "^1.0.6"
joi "^10.0.6"
jsonwebtoken "^7.1.7"
lodash "^4.0.0"
minimist "^1.2.0"
morgan "^1.8.2"
multer "^1.1.0"
passport "^0.3.2"
passport-anonymous "^1.0.1"
passport-http-bearer "^1.0.1"
passport-local "^1.0.0"
pouchdb-adapter-http "^6.2.0"
pouchdb-adapter-leveldb "^6.1.1"
pouchdb-adapter-memory "^6.1.1"
pouchdb-core "^6.1.1"
pouchdb-find "^0.10.3"
pouchdb-upsert "^2.0.0"
promise-queue "^2.2.3"
prompt "^1.0.0"
pubsweet-sse "^0.1.4"
relational-pouch "^1.4.5"
uuid "^3.0.1"
winston "^2.2.0"
pubsweet@1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/pubsweet/-/pubsweet-1.1.2.tgz#398e8570fae5dd925599f720094dad76c05c2353"
dependencies:
"@pubsweet/db-manager" "^0.0.8"
"@pubsweet/logger" "^0.1.0"
bluebird "^3.5.0"
colors "^1.1.2"
commander "^2.9.0"
express "^4.15.3"
forever-monitor "^1.7.0"
fs-extra "^4.0.2"
inflection "^1.12.0"
joi "^10.4.1"
prompt flatiron/prompt#1c95d1d8d333b5fbc13fa5f0619f3dcf0d514f87
pubsweet-server "^1.0.2"
require-relative "^0.8.7"
uuid "^3.0.1"
webpack "^3.8.1"
webpack-dev-middleware "^1.12.0"
webpack-hot-middleware "^2.20.0"
pump@^1.0.0:
version "1.0.3"
resolved "https://registry.yarnpkg.com/pump/-/pump-1.0.3.tgz#5dfe8311c33bbf6fc18261f9f34702c47c08a954"
......@@ -10850,12 +10726,6 @@ topo@1.x.x:
dependencies:
hoek "2.x.x"
topo@2.x.x:
version "2.0.2"
resolved "https://registry.yarnpkg.com/topo/-/topo-2.0.2.tgz#cd5615752539057c0dc0491a621c3bc6fbe1d182"
dependencies:
hoek "4.x.x"
topo@3.x.x:
version "3.0.0"
resolved "https://registry.yarnpkg.com/topo/-/topo-3.0.0.tgz#37e48c330efeac784538e0acd3e62ca5e231fe7a"
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment