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