From 668a34ad5ccccad84765e6dd6d3cef66f04857a6 Mon Sep 17 00:00:00 2001 From: Alexandru Munteanu <alexandru.munt@gmail.com> Date: Wed, 15 Aug 2018 13:08:56 +0300 Subject: [PATCH] feat(styleguide): add contextual box container --- .../component-faraday-ui/src/ContextualBox.js | 74 ++++++++++++ .../component-faraday-ui/src/ContextualBox.md | 113 ++++++++++++++++++ .../src/pending/Accordion.js | 100 ++++++++++++++++ packages/component-wizard/package.json | 2 +- packages/components-faraday/package.json | 2 +- .../hindawi-theme/src/elements/Accordion.js | 12 +- packages/hindawi-theme/src/elements/Icon.js | 1 + packages/hindawi-theme/src/index.js | 3 +- packages/styleguide/package.json | 2 +- packages/xpub-faraday/package.json | 2 +- yarn.lock | 24 ---- 11 files changed, 303 insertions(+), 32 deletions(-) create mode 100644 packages/component-faraday-ui/src/ContextualBox.js create mode 100644 packages/component-faraday-ui/src/ContextualBox.md create mode 100644 packages/component-faraday-ui/src/pending/Accordion.js diff --git a/packages/component-faraday-ui/src/ContextualBox.js b/packages/component-faraday-ui/src/ContextualBox.js new file mode 100644 index 000000000..44d46148e --- /dev/null +++ b/packages/component-faraday-ui/src/ContextualBox.js @@ -0,0 +1,74 @@ +import React from 'react' +import { Icon, H3 } from '@pubsweet/ui' +import styled from 'styled-components' +import { override, th } from '@pubsweet/ui-toolkit' + +import Accordion from './pending/Accordion' + +const CustomHeader = ({ + label, + toggle, + expanded, + transparent, + rightChildren, + ...props +}) => ( + <Header + expanded={expanded} + hasChildren={rightChildren} + onClick={toggle} + transparent={transparent} + > + <div> + <Icon secondary size={2}> + {expanded ? 'minus' : 'plus'} + </Icon> + <H3>{label}</H3> + </div> + {typeof rightChildren === 'function' + ? rightChildren({ ...props, expanded, transparent }) + : rightChildren} + </Header> +) + +const ContextualBox = ({ + label, + children, + transparent, + rightChildren, + ...props +}) => ( + <Accordion + header={CustomHeader} + label={label} + rightChildren={rightChildren} + transparent={transparent} + {...props} + > + {children} + </Accordion> +) + +export default ContextualBox + +// #region styles +const Header = styled.div.attrs({ + 'data-test-id': props => props['data-test-id'] || 'accordion-header', +})` + align-items: center; + cursor: pointer; + display: flex; + justify-content: ${props => + props.hasChildren ? 'space-between' : 'flex-start'}; + ${override('ui.Accordion.Header')}; + + ${H3} { + margin: ${th('gridUnit')} 0; + } + + & div { + align-items: center; + display: flex; + } +` +// #endregion diff --git a/packages/component-faraday-ui/src/ContextualBox.md b/packages/component-faraday-ui/src/ContextualBox.md new file mode 100644 index 000000000..dc2b6e300 --- /dev/null +++ b/packages/component-faraday-ui/src/ContextualBox.md @@ -0,0 +1,113 @@ +A collapseable contextual box. + +```js +<ContextualBox label="Reviewer reports"> + <div + style={{ + padding: 16, + backgroundColor: 'lavenderblush', + }} + > + What is Lorem Ipsum? Lorem Ipsum is simply dummy text of the printing and + typesetting industry. Lorem Ipsum has been the industry's standard dummy + text ever since the 1500s, when an unknown printer took a galley of type and + scrambled it to make a type specimen book. It has survived not only five + centuries, but also the leap into electronic typesetting, remaining + essentially unchanged. It was popularised in the 1960s with the release of + Letraset sheets containing Lorem Ipsum passages, and more recently with + desktop publishing software like Aldus PageMaker including versions of Lorem + Ipsum. Why do we use it? It is a long established fact that a reader will be + distracted by the readable content of a page when looking at its layout. The + point of using Lorem Ipsum is that it has a more-or-less normal distribution + of letters, as opposed to using 'Content here, content here', making it look + like readable English. Many desktop publishing packages and web page editors + now use Lorem Ipsum as their default model text, and a search for 'lorem + ipsum' will uncover many web sites still in their infancy. Various versions + have evolved over the years, sometimes by accident, sometimes on purpose + (injected humour and the like). + </div> +</ContextualBox> +``` + +A contextual box without border, shadow and no backgrounds. + +```js +<ContextualBox label="Files" transparent> + <div> + <FileItem file={{ id: '1', name: 'myfile.pdf', size: 123123 }} /> + <FileItem file={{ id: '2', name: 'myfile2.pdf', size: 1123 }} /> + </div> +</ContextualBox> +``` + +Render custom components on the right side of the header. + +```js +<ContextualBox + label="Plain html on the right side" + rightChildren={<div>1 invited, 0 accepted</div>} +> + <div + style={{ + padding: 16, + backgroundColor: 'lavenderblush', + }} + > + What is Lorem Ipsum? Lorem Ipsum is simply dummy text of the printing and + typesetting industry. Lorem Ipsum has been the industry's standard dummy + text ever since the 1500s, when an unknown printer took a galley of type and + scrambled it to make a type specimen book. It has survived not only five + centuries, but also the leap into electronic typesetting, remaining + essentially unchanged. It was popularised in the 1960s with the release of + Letraset sheets containing Lorem Ipsum passages, and more recently with + desktop publishing software like Aldus PageMaker including versions of Lorem + Ipsum. Why do we use it? It is a long established fact that a reader will be + distracted by the readable content of a page when looking at its layout. The + point of using Lorem Ipsum is that it has a more-or-less normal distribution + of letters, as opposed to using 'Content here, content here', making it look + like readable English. Many desktop publishing packages and web page editors + now use Lorem Ipsum as their default model text, and a search for 'lorem + ipsum' will uncover many web sites still in their infancy. Various versions + have evolved over the years, sometimes by accident, sometimes on purpose + (injected humour and the like). + </div> +</ContextualBox> +``` + +React components can be passed as right children too. All the props provided to the contextual box are also passed to the right header children. + +```js + +const MyRightComponent = ({headLabel}) => <div>{headLabel}: 1 accepted, 4 denied</div>; + +<ContextualBox + headLabel="I am the right header * " + label="React component to the right" + rightChildren={MyRightComponent} +> + <div + style={{ + padding: 16, + backgroundColor: 'lavenderblush', + }} + > + What is Lorem Ipsum? Lorem Ipsum is simply dummy text of the printing and + typesetting industry. Lorem Ipsum has been the industry's standard dummy + text ever since the 1500s, when an unknown printer took a galley of type and + scrambled it to make a type specimen book. It has survived not only five + centuries, but also the leap into electronic typesetting, remaining + essentially unchanged. It was popularised in the 1960s with the release of + Letraset sheets containing Lorem Ipsum passages, and more recently with + desktop publishing software like Aldus PageMaker including versions of Lorem + Ipsum. Why do we use it? It is a long established fact that a reader will be + distracted by the readable content of a page when looking at its layout. The + point of using Lorem Ipsum is that it has a more-or-less normal distribution + of letters, as opposed to using 'Content here, content here', making it look + like readable English. Many desktop publishing packages and web page editors + now use Lorem Ipsum as their default model text, and a search for 'lorem + ipsum' will uncover many web sites still in their infancy. Various versions + have evolved over the years, sometimes by accident, sometimes on purpose + (injected humour and the like). + </div> +</ContextualBox> +``` diff --git a/packages/component-faraday-ui/src/pending/Accordion.js b/packages/component-faraday-ui/src/pending/Accordion.js new file mode 100644 index 000000000..e8037b3fa --- /dev/null +++ b/packages/component-faraday-ui/src/pending/Accordion.js @@ -0,0 +1,100 @@ +/* eslint-disable react/require-default-props */ + +import React from 'react' +import PropTypes from 'prop-types' +import { Icon } from '@pubsweet/ui' +import styled from 'styled-components' +import { th, override } from '@pubsweet/ui-toolkit' +import { withState, withHandlers, compose } from 'recompose' + +// #region styles +const Root = styled.div` + cursor: pointer; + display: flex; + flex-direction: column; + transition: all ${th('transitionDuration')}; + + ${override('ui.Accordion')}; +` + +const Header = styled.div.attrs({ + 'data-test-id': props => props['data-test-id'] || 'accordion-header', +})` + align-items: center; + cursor: pointer; + display: flex; + justify-content: flex-start; + + ${override('ui.Accordion.Header')}; +` + +const HeaderLabel = styled.span` + color: ${th('colorPrimary')}; + font-family: ${th('fontHeading')}; + font-size: ${th('fontSizeBase')}; + + ${override('ui.Accordion.Header.Label')}; +` + +const HeaderIcon = styled.div` + align-items: center; + display: flex; + justify-content: center; + + transform: ${({ expanded }) => `rotateZ(${expanded ? 0 : 180}deg)`}; + transition: transform ${th('transitionDuration')}; + + ${override('ui.Accordion.Header.Icon')}; +` +// #endregion + +const HeaderComponent = ({ icon, label, toggle, expanded, ...props }) => ( + <Header expanded={expanded} onClick={toggle} {...props}> + <HeaderIcon expanded={expanded}> + <Icon primary size={3}> + {icon} + </Icon> + </HeaderIcon> + <HeaderLabel>{label}</HeaderLabel> + </Header> +) + +const Accordion = ({ + toggle, + expanded, + children, + icon = 'chevron_up', + header: Header = HeaderComponent, + ...props +}) => ( + <Root expanded={expanded} {...props}> + <Header expanded={expanded} icon={icon} toggle={toggle} {...props} /> + {expanded && children} + </Root> +) + +Accordion.propTypes = { + /** Header icon, from the [Feather](https://feathericons.com/) icon set. */ + icon: PropTypes.string, + /** Initial state of the accordion. */ + startExpanded: PropTypes.bool, + /** Function called when toggling the accordion. The new state is passed as a paremeter. */ + onToggle: PropTypes.func, +} + +Accordion.defaultProps = { + onToggle: null, + startExpanded: false, +} + +export default compose( + withState('expanded', 'setExpanded', ({ startExpanded }) => startExpanded), + withHandlers({ + toggle: ({ expanded, setExpanded, onToggle }) => () => { + setExpanded(!expanded) + if (typeof onToggle === 'function') { + onToggle(!expanded) + } + }, + }), +)(Accordion) diff --git a/packages/component-wizard/package.json b/packages/component-wizard/package.json index 830db5fae..f02ab6d8e 100644 --- a/packages/component-wizard/package.json +++ b/packages/component-wizard/package.json @@ -9,7 +9,7 @@ "dist" ], "dependencies": { - "@pubsweet/ui": "8.2.0", + "@pubsweet/ui": "^8.3.0", "@pubsweet/styleguide": "3.1.4", "@pubsweet/ui-toolkit": "latest", "moment": "^2.20.1", diff --git a/packages/components-faraday/package.json b/packages/components-faraday/package.json index 5e7fe0068..b9825e9f4 100644 --- a/packages/components-faraday/package.json +++ b/packages/components-faraday/package.json @@ -4,7 +4,7 @@ "main": "src", "license": "MIT", "dependencies": { - "@pubsweet/ui": "8.2.0", + "@pubsweet/ui": "^8.3.0", "@pubsweet/ui-toolkit": "latest", "@pubsweet/styleguide": "3.1.4", "moment": "^2.22.1", diff --git a/packages/hindawi-theme/src/elements/Accordion.js b/packages/hindawi-theme/src/elements/Accordion.js index 8668a2387..12da34b3a 100644 --- a/packages/hindawi-theme/src/elements/Accordion.js +++ b/packages/hindawi-theme/src/elements/Accordion.js @@ -3,14 +3,20 @@ import { th } from '@pubsweet/ui-toolkit' export default { Root: css` - background-color: ${th('accordion.backgroundColor')}; + background-color: ${props => + props.transparent ? 'transparent' : th('accordion.backgroundColor')}; border-radius: ${th('borderRadius')}; - box-shadow: ${th('boxShadow')}; + box-shadow: ${props => + props.transparent ? 'transparent' : th('boxShadow')}; `, Header: { Root: css` + background-color: ${th('accordion.headerBackgroundColor')}; + border-radius: ${props => (props.expanded ? 0 : th('borderRadius'))}; + borde-border-top-left-radius: ${th('borderRadius')}; + border-top-right-radius: ${th('borderRadius')}; border-bottom: ${props => - props.expanded ? th('accordion.border') : 'none'}; + props.expanded && !props.transparent ? th('accordion.border') : 'none'}; `, Label: css` color: ${th('colorText')}; diff --git a/packages/hindawi-theme/src/elements/Icon.js b/packages/hindawi-theme/src/elements/Icon.js index 2f7a0c7f1..1eeadbf2c 100644 --- a/packages/hindawi-theme/src/elements/Icon.js +++ b/packages/hindawi-theme/src/elements/Icon.js @@ -10,4 +10,5 @@ export default css` stroke: ${props => darken(props.color, 0.2)}; } } + display: initial; ` diff --git a/packages/hindawi-theme/src/index.js b/packages/hindawi-theme/src/index.js index 3b3bd5ac5..1cc12a853 100644 --- a/packages/hindawi-theme/src/index.js +++ b/packages/hindawi-theme/src/index.js @@ -39,7 +39,8 @@ const hindawiTheme = { colorWarning: '#FC6A4B', accordion: { - backgroundColor: '#ffffff', + headerBackgroundColor: '#ffffff', + backgroundColor: '#f6f6f6', headerFontSize: '16px', headerFontFamily: "'Myriad Pro'", border: '1px solid #dbdbdb', diff --git a/packages/styleguide/package.json b/packages/styleguide/package.json index 852fd2a89..ecf81552a 100644 --- a/packages/styleguide/package.json +++ b/packages/styleguide/package.json @@ -19,7 +19,7 @@ "webpack-node-externals": "^1.6.0" }, "dependencies": { - "@pubsweet/ui": "8.2.0", + "@pubsweet/ui": "^8.3.0", "@pubsweet/ui-toolkit": "^1.2.0", "hindawi-theme": "^1.0.1", "react": "^16.4.2", diff --git a/packages/xpub-faraday/package.json b/packages/xpub-faraday/package.json index 3cc0c2dc9..20715cf44 100644 --- a/packages/xpub-faraday/package.json +++ b/packages/xpub-faraday/package.json @@ -8,7 +8,7 @@ "url": "https://gitlab.coko.foundation/xpub/xpub-faraday" }, "dependencies": { - "@pubsweet/ui": "8.2.0", + "@pubsweet/ui": "^8.3.0", "@pubsweet/styleguide": "3.1.4", "@pubsweet/ui-toolkit": "latest", "@pubsweet/component-aws-s3": "^1.2.0", diff --git a/yarn.lock b/yarn.lock index c8427675f..a2075c160 100644 --- a/yarn.lock +++ b/yarn.lock @@ -183,30 +183,6 @@ lodash "^4.17.4" styled-components "^3.2.5" -"@pubsweet/ui@8.2.0": - version "8.2.0" - resolved "https://registry.yarnpkg.com/@pubsweet/ui/-/ui-8.2.0.tgz#fbd4b5eb08ceee430c5bfb4287d4c5f0883e31e6" - dependencies: - "@pubsweet/ui-toolkit" "^1.1.3" - babel-jest "^21.2.0" - classnames "^2.2.5" - enzyme "^3.2.0" - enzyme-adapter-react-16 "^1.1.1" - invariant "^2.2.3" - lodash "^4.17.4" - moment "^2.22.1" - prop-types "^15.5.10" - react "^16.2.0" - react-dom "^16.2.0" - react-feather "^1.0.8" - react-redux "^5.0.2" - react-router-dom "^4.2.2" - react-tag-autocomplete "^5.5.0" - recompose "^0.26.0" - redux "^3.6.0" - redux-form "^7.0.3" - styled-components "^3.2.5" - "@pubsweet/ui@^8.2.0", "@pubsweet/ui@^8.3.0": version "8.3.0" resolved "https://registry.yarnpkg.com/@pubsweet/ui/-/ui-8.3.0.tgz#b8da7be8d9110594abdd18476e3808c9606a74b4" -- GitLab