Skip to content

Commit

Permalink
Merge pull request #214 from acl-services/UX-565-migrate-takeover
Browse files Browse the repository at this point in the history
UX-565 Takeover component migration
  • Loading branch information
Danil Agafonov committed Nov 15, 2019
2 parents e5a66a8 + 8c62a0c commit 2026207
Show file tree
Hide file tree
Showing 27 changed files with 684 additions and 45 deletions.
5 changes: 4 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,10 @@
},
{
"files": ["packages/**/*.spec.js"],
"rules": { "import/no-extraneous-dependencies": "off" }
"rules": { "import/no-extraneous-dependencies": "off" },
"globals": {
"given": true
}
},
{
"files": ["packages/helpers/**/*.js"],
Expand Down
1 change: 1 addition & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module.exports = {
setupFilesAfterEnv: [
"jest-dom/extend-expect",
"@testing-library/react/cleanup-after-each",
"given2/setup",
"./testingHelpers/config.js",
],
};
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
"eslint-plugin-jsx-a11y": "^6.1.1",
"eslint-plugin-react": "^7.11.1",
"eslint-plugin-react-hooks": "^1.6.0",
"given2": "^2.1.7",
"husky": "^2.5.0",
"jest": "^24.1.0",
"jest-cli": "^24.1.0",
Expand Down
4 changes: 3 additions & 1 deletion packages/Button/src/Button.styles.js
Original file line number Diff line number Diff line change
Expand Up @@ -267,8 +267,10 @@ function getIconColor(props) {
}

export const iconStyles = props => css`
align-items: center;
color: ${getIconColor(props)};
display: inline-block;
display: inline-flex;
justify-content: center;
margin: 0 ${tokens.spaceSm} 0 0;
svg {
Expand Down
2 changes: 1 addition & 1 deletion packages/FormElement/src/FormElement.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import React from "react";
import PropTypes from "prop-types";

import { ShirtSizes } from "@paprika/helpers/lib/customPropTypes";
import extractChildren from "@paprika/helpers/lib/extractChildren";
import isNil from "lodash/isNil";
import uuidv4 from "uuid/v4";
import isString from "lodash/isString";

import { extractChildren } from "./helpers/extractChildren";
import Description from "./components/Description";
import Instructions from "./components/Instructions";
import ErrorMessage from "./components/ErrorMessage";
Expand Down
33 changes: 21 additions & 12 deletions packages/SidePanel/src/SidePanel.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import React from "react";
import ReactDOM from "react-dom";
import PropTypes from "prop-types";
import { zValue } from "@paprika/stylers/lib/helpers";
import LockBodyScroll from "@paprika/helpers/lib/components/LockBodyScroll";
import Portal from "@paprika/helpers/lib/components/Portal";
import Dialog from "./components/Dialog";
import Footer from "./components/Footer";
import Header from "./components/Header";
import Overlay from "./components/Overlay";
import Trigger from "./components/Trigger";
import Group from "./components/Group";
import FocusTrap from "./components/FocusTrap";
import LockBodyScroll from "./components/LockBodyScroll";

import { extractChildren } from "./helpers";
import { useOffsetScroll, useEscapeKey } from "./hooks";
import { useOffsetScroll } from "./hooks";

const propTypes = {
/** The content for the SidePanel. */
Expand Down Expand Up @@ -64,7 +64,6 @@ function SidePanel(props) {
// Hooks
const [isVisible, setIsVisible] = React.useState(props.isOpen);
const offsetScroll = useOffsetScroll(offsetY);
useEscapeKey(isOpen, onClose);

// Refs
const refTrigger = React.useRef(null);
Expand Down Expand Up @@ -118,6 +117,14 @@ function SidePanel(props) {
...extendedFocusTrapOptions,
};

function handleEscKey(event) {
if (event.key === "Escape") {
event.stopPropagation();

onClose();
}
}

let sidePanel = null;

if (isVisible) {
Expand All @@ -134,6 +141,7 @@ function SidePanel(props) {
refHeader={refHeader}
offsetY={offsetScroll}
isOpen={isOpen}
onKeyDown={handleEscKey}
{...moreProps}
>
{children}
Expand All @@ -143,14 +151,15 @@ function SidePanel(props) {
if (isInline) {
sidePanel = dialog;
} else {
sidePanel = ReactDOM.createPortal(
<React.Fragment>
<FocusTrap focusTrapOptions={focusTrapOptions}>
<div>{dialog}</div>
</FocusTrap>
{overlayExtracted ? React.cloneElement(overlayExtracted, { onClose }) : null}
</React.Fragment>,
document.body
sidePanel = (
<Portal active={!isInline}>
<React.Fragment>
<FocusTrap focusTrapOptions={focusTrapOptions}>
<div>{dialog}</div>
</FocusTrap>
{overlayExtracted ? React.cloneElement(overlayExtracted, { onClose }) : null}
</React.Fragment>
</Portal>
);
}
}
Expand Down
8 changes: 0 additions & 8 deletions packages/SidePanel/src/components/LockBodyScroll.js

This file was deleted.

1 change: 0 additions & 1 deletion packages/SidePanel/src/hooks/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
export { default as useEscapeKey } from "./useEscapeKey";
export { default as useOffsetScroll } from "./useOffsetScroll";
export { default as useFooterOffset } from "./useFooterOffset";
19 changes: 0 additions & 19 deletions packages/SidePanel/src/hooks/useEscapeKey.js

This file was deleted.

4 changes: 4 additions & 0 deletions packages/Takeover/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
*

!readme.md
!lib/**
34 changes: 34 additions & 0 deletions packages/Takeover/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Takeover

Takeover component can toggle a full-screen view to help the user focus on complex UI tasks.
More information at the design system site: https://design.wegalvanize.com/p/components/takeover

## Components

You can use any of the following components to compose the Takeover:

```jsx
<Takeover.Header />
<Takeover.Content />
<Takeover.FocusTrap />
```

## Basic example

```jsx
<Takeover isOpen={isOpen} onClose={toggle}>
<Takeover.Header>
<Heading level={2}>Header</Heading>
</Takeover.Header>
<Takeover.Content>My content</Takeover.Content>
</Takeover>
```

## Props

- `children` (required)
- `isOpen` (required)
- `onClose`
- `onAfterOpen`
- `onAfterClose`
- `isInline`
31 changes: 31 additions & 0 deletions packages/Takeover/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"name": "@paprika/takeover",
"version": "0.1.0",
"description": "Takeover component",
"author": "@paprika",
"main": "lib/index.js",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/acl-services/paprika/tree/master/packages/Takeover"
},
"publishConfig": {
"access": "public"
},
"dependencies": {
"@babel/runtime-corejs2": "^7.3.1",
"@paprika/button": "^0.2.2",
"@paprika/heading": "^0.2.2",
"@paprika/helpers": "^0.2.3",
"@paprika/stylers": "^0.2.2",
"@paprika/tokens": "^0.1.4",
"focus-trap-react": "^6.0.0",
"prop-types": "^15.7.2",
"react-transition-group": "^4.3.0"
},
"peerDependencies": {
"react": "^16.8.4",
"react-dom": "^16.8.4",
"styled-components": "^4.2.0"
}
}
106 changes: 106 additions & 0 deletions packages/Takeover/src/Takeover.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import React from "react";
import PropTypes from "prop-types";
import { Transition } from "react-transition-group";
import FocusTrapLibrary from "focus-trap-react";
import LockBodyScroll from "@paprika/helpers/lib/components/LockBodyScroll";
import Portal from "@paprika/helpers/lib/components/Portal";
import extractChildren from "@paprika/helpers/lib/extractChildren";
import * as styled from "./Takeover.styles";
import { animationDuration } from "./helpers/tokens";

const propTypes = {
/** The content for the Takeover. */
children: PropTypes.node.isRequired,

/** Control the visibility of the takeover */
isOpen: PropTypes.bool.isRequired,

/** Callback triggered when the takeover needs to be close */
onClose: PropTypes.func,

/** Callback once the takeover has been opened event */
onAfterOpen: PropTypes.func,

/** Callback once the takeover has been closed event */
onAfterClose: PropTypes.func,
};

const defaultProps = {
onAfterClose: () => {},
onClose: () => {},
onAfterOpen: () => {},
};

const Takeover = props => {
const { isOpen, onClose, onAfterClose, onAfterOpen, ...moreProps } = props;

function handleTransitionEnter(node) {
// https://github.com/reactjs/react-transition-group/blob/6dbadb594c7c2a2f15bc47afc6b4374cfd73c7c0/src/CSSTransition.js#L44
// eslint-disable-next-line no-unused-expressions
node.scrollTop;
}

const {
"Takeover.FocusTrap": focusTrapExtracted,
"Takeover.Header": headerExtracted,
"Takeover.Content": contentExtracted,
children,
} = extractChildren(moreProps.children, ["Takeover.FocusTrap", "Takeover.Header", "Takeover.Content"]);

const extendedFocusTrapOptions = focusTrapExtracted ? focusTrapExtracted.props : {};

const focusTrapOptions = {
fallbackFocus: () => document.createElement("div"),
...extendedFocusTrapOptions,
};

function handleEscKey(event) {
if (event.key === "Escape") {
event.stopPropagation();

onClose();
}
}

return (
<>
{isOpen && <LockBodyScroll />}
<Portal>
<Transition
mountOnEnter
unmountOnExit
in={isOpen}
timeout={animationDuration}
onEnter={handleTransitionEnter}
onEntered={onAfterOpen}
onExited={onAfterClose}
>
{state => (
<FocusTrapLibrary focusTrapOptions={focusTrapOptions}>
<styled.Wrapper
state={state}
role="dialog"
tabIndex="-1"
onKeyDown={handleEscKey}
data-pka-anchor="takeover"
>
{headerExtracted && <styled.Header {...headerExtracted.props} onClose={onClose} />}
{contentExtracted && (
<styled.ContentWrapper role="region" tabIndex="0">
{contentExtracted}
</styled.ContentWrapper>
)}
{children}
</styled.Wrapper>
</FocusTrapLibrary>
)}
</Transition>
</Portal>
</>
);
};

Takeover.propTypes = propTypes;
Takeover.defaultProps = defaultProps;

export default Takeover;
41 changes: 41 additions & 0 deletions packages/Takeover/src/Takeover.styles.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import styled, { css } from "styled-components";
import tokens from "@paprika/tokens";
import { animationDuration } from "./helpers/tokens";
import OriginalHeader from "./components/Header";

const openedCss = css`
opacity: 1;
`;

const closedCss = css`
opacity: 0;
`;

const states = {
entering: openedCss,
entered: openedCss,
exiting: closedCss,
exited: closedCss,
};

export const Wrapper = styled.div`
background-color: ${tokens.backgroundColor.level0};
bottom: 0;
display: flex;
flex-direction: column;
left: 0;
position: fixed;
right: 0;
top: 0;
transition: all ${animationDuration}ms ease;
${({ state }) => states[state]};
`;

export const Header = styled(OriginalHeader)`
flex: none;
`;

export const ContentWrapper = styled.div`
flex-grow: 1;
overflow-y: auto;
`;

0 comments on commit 2026207

Please sign in to comment.