From 9d050f1646079a9d40e493e97b6668714fa3c0c5 Mon Sep 17 00:00:00 2001 From: Oscar Martinez Date: Mon, 10 Sep 2018 17:10:24 -0700 Subject: [PATCH] feat(Drawer): Drawer for mobile menu --- catalog/pages/nav_bar/index.js | 4 +- catalog/pages/nav_bar/index.md | 88 +- src/components/Drawer/Context.js | 3 + src/components/Drawer/Drawer.styles.js | 67 + src/components/Drawer/Provider.js | 77 + .../Drawer/__tests__/Provider.spec.js | 87 + .../__snapshots__/Provider.spec.js.snap | 37 + .../__snapshots__/index.spec.js.snap | 1836 +++++++++++++++++ src/components/Drawer/__tests__/index.spec.js | 56 + src/components/Drawer/index.js | 101 + src/components/Icons/HamburgerIcon.js | 76 + src/components/NavBar/ButtonBase.js | 111 + src/components/NavBar/Buttons.js | 79 +- src/components/NavBar/DrawerMenu.js | 59 + src/components/NavBar/Links.js | 3 + src/components/NavBar/MenuButton.js | 24 + .../NavBar/__tests__/DrawerMenu.spec.js | 20 + .../__snapshots__/DrawerMenu.spec.js.snap | 313 +++ .../__snapshots__/index.spec.js.snap | 288 ++- src/components/NavBar/__tests__/index.spec.js | 20 - src/components/NavBar/index.js | 184 +- src/index.js | 1 + src/utils/__tests__/omitKeys.spec.js | 8 + src/utils/omitKeys.js | 8 + 24 files changed, 3136 insertions(+), 414 deletions(-) create mode 100644 src/components/Drawer/Context.js create mode 100644 src/components/Drawer/Drawer.styles.js create mode 100644 src/components/Drawer/Provider.js create mode 100644 src/components/Drawer/__tests__/Provider.spec.js create mode 100644 src/components/Drawer/__tests__/__snapshots__/Provider.spec.js.snap create mode 100644 src/components/Drawer/__tests__/__snapshots__/index.spec.js.snap create mode 100644 src/components/Drawer/__tests__/index.spec.js create mode 100644 src/components/Drawer/index.js create mode 100644 src/components/Icons/HamburgerIcon.js create mode 100644 src/components/NavBar/ButtonBase.js create mode 100644 src/components/NavBar/DrawerMenu.js create mode 100644 src/components/NavBar/MenuButton.js create mode 100644 src/components/NavBar/__tests__/DrawerMenu.spec.js create mode 100644 src/components/NavBar/__tests__/__snapshots__/DrawerMenu.spec.js.snap create mode 100644 src/utils/__tests__/omitKeys.spec.js create mode 100644 src/utils/omitKeys.js diff --git a/catalog/pages/nav_bar/index.js b/catalog/pages/nav_bar/index.js index 203bd2b7b..e392cb3b9 100644 --- a/catalog/pages/nav_bar/index.js +++ b/catalog/pages/nav_bar/index.js @@ -9,6 +9,7 @@ import Column from "../../../src/components/Grid/Column"; import Row from "../../../src/components/Grid/Row"; import DeviceSizeProvider from "../../../src/components/DeviceSize/Provider"; import DisplayFor from "../../../src/components/DeviceSize"; +import DrawerProvider from "../../../src/components/Drawer/Provider"; export default { path: "/nav_bar", @@ -22,7 +23,8 @@ export default { Column, Row, DeviceSizeProvider, - DisplayFor + DisplayFor, + DrawerProvider }, content: pageLoader(() => import("./index.md")) }; diff --git a/catalog/pages/nav_bar/index.md b/catalog/pages/nav_bar/index.md index 2a4bc7b2f..c2adfb776 100644 --- a/catalog/pages/nav_bar/index.md +++ b/catalog/pages/nav_bar/index.md @@ -1,49 +1,53 @@ ### Default ```react -responsive: true +responsive: false span: 6 state: { invert: false } --- - -
- - - - - - Aurora - - - - Link 1 - Link 2 - Link 3 - - More - - Link 4 - Link 5 - Link 6 - Link 7 With Really Long Content - - - - - - - - - -
- - - - - - - - - -
+ + +
+ + + Aurora + + + + Link 1 + Link 2 + Link 3 + + More + + Link 4 + Link 5 + Link 6 + Link 7 With Really Long Content + + + + + + + + + + Some Menu Content + + + + +
+ + + + + + + + + +
+
``` diff --git a/src/components/Drawer/Context.js b/src/components/Drawer/Context.js new file mode 100644 index 000000000..a64419c27 --- /dev/null +++ b/src/components/Drawer/Context.js @@ -0,0 +1,3 @@ +import React from "react"; + +export const { Provider, Consumer } = React.createContext({ isOpen: false }); diff --git a/src/components/Drawer/Drawer.styles.js b/src/components/Drawer/Drawer.styles.js new file mode 100644 index 000000000..bfd31c007 --- /dev/null +++ b/src/components/Drawer/Drawer.styles.js @@ -0,0 +1,67 @@ +import styled from "styled-components"; + +import constants from "../../theme/constants"; +import spacing from "../../theme/spacing"; +import getThemeValue from "../../utils/getThemeValue"; + +export const DrawerContainer = styled.div` + background-color: ${getThemeValue("onyx", "base")}; + color: ${getThemeValue("white", "base")}; + height: 100%; + position: fixed; + top: 0; + left: 0; + bottom: 0; + right: 0; + visibility: hidden; + transform: translateY(-100%); + opacity: 0; + transition: opacity 0.3ms ${constants.easing.easeInOutQuad}; + overflow: hidden; + z-index: -1; + + &.drawer__content--open { + transform: translateY(0); + visibility: visible; + opacity: 1; + } +`; + +export const DrawerContent = styled.div` + display: flex; + flex-direction: column; + position: relative; + width: 100%; + height: 100vh; + overflow-y: scroll; + -webkit-overflow-scrolling: touch; + overflow-x: hidden; +`; + +export const HeaderContent = styled.div` + display: flex; + flex-direction: row; + flex-wrap: nowrap; + justify-content: space-between; + align-items: center; + height: 60px; + padding-left: ${spacing.moderate}; +`; + +export const CloseButton = styled.button` + appearance: none; + cursor: pointer; + border: 0; + outline: 0; + background: transparent; + display: flex; + align-items: center; + height: 60px; + padding: 0 ${spacing.moderate}; +`; + +export const ContentWrapper = styled.div` + &.drawer--open { + overflow: hidden; + } +`; diff --git a/src/components/Drawer/Provider.js b/src/components/Drawer/Provider.js new file mode 100644 index 000000000..daac826be --- /dev/null +++ b/src/components/Drawer/Provider.js @@ -0,0 +1,77 @@ +/* global window: true */ +/* eslint react/sort-comp: off, react/no-unused-state: off */ +import React, { Children } from "react"; +import PropTypes from "prop-types"; +import classNames from "classnames"; + +import { Provider } from "./Context"; +import { ContentWrapper } from "./Drawer.styles"; +import Portal from "../Portal"; + +export default class DrawerProvider extends React.Component { + static propTypes = { + children: PropTypes.element.isRequired, + className: PropTypes.string + }; + + static defaultProps = { className: "" }; + + contentContainer = React.createRef(); + + scrollPosition = 0; + + shouldComponentUpdate(prevProps, prevState) { + return ( + prevState.isOpen !== this.state.isOpen || + prevState.content !== this.state.content || + prevProps.children !== this.props.children + ); + } + + componentDidUpdate() { + const { isOpen } = this.state; + /* istanbul ignore next */ + if ( + !isOpen && + typeof window !== "undefined" && + typeof window.scrollTo === "function" + ) { + window.scrollTo(0, this.scrollPosition); + } + } + + setContent = content => this.setState(() => ({ content })); + + toggleDrawer = () => { + this.setState(({ isOpen }) => { + /* istanbul ignore else */ + if (typeof window !== "undefined" && !isOpen) { + this.scrollPosition = window.pageYOffset; + } + return { isOpen: !isOpen }; + }); + }; + + state = { + isOpen: false, + toggleDrawer: this.toggleDrawer, + setContent: this.setContent, + content: null + }; + + render() { + const { className, children } = this.props; + const { isOpen, content } = this.state; + return ( + + + {Children.only(children)} + {content && {content}} + + + ); + } +} diff --git a/src/components/Drawer/__tests__/Provider.spec.js b/src/components/Drawer/__tests__/Provider.spec.js new file mode 100644 index 000000000..23f169c25 --- /dev/null +++ b/src/components/Drawer/__tests__/Provider.spec.js @@ -0,0 +1,87 @@ +/* global window: true */ +import React from "react"; +import { render, Simulate } from "react-testing-library"; + +import DrawerProvider from "../Provider"; +import { Consumer } from "../Context"; + +describe("DrawerProvider", () => { + beforeEach(() => { + window.scrollTo = jest.fn(); + const modalRoot = global.document.createElement("div"); + modalRoot.setAttribute("id", "modal-root"); + const body = global.document.querySelector("body"); + body.appendChild(modalRoot); + }); + + afterEach(() => { + const body = global.document.querySelector("body"); + const modalRoot = global.document.getElementById("modal-root"); + body.removeChild(modalRoot); + }); + it("renders child elements", () => { + const { container } = render( + +
Content
+
+ ); + expect(container.innerHTML).toMatchSnapshot(); + }); + + it("sets content", () => { + const { getByTestId, container } = render( + +
+ + {({ setContent }) => ( + + )} + + Content +
+
+ ); + + Simulate.click(getByTestId("button")); + + expect(container).toMatchSnapshot(); + }); + + it("toggles drawer", () => { + const { getByTestId, container } = render( + +
+ + {({ setContent, toggleDrawer }) => ( + + )} + + Content +
+
+ ); + + Simulate.click(getByTestId("button")); + + expect(container).toMatchSnapshot(); + }); +}); diff --git a/src/components/Drawer/__tests__/__snapshots__/Provider.spec.js.snap b/src/components/Drawer/__tests__/__snapshots__/Provider.spec.js.snap new file mode 100644 index 000000000..3f3328c73 --- /dev/null +++ b/src/components/Drawer/__tests__/__snapshots__/Provider.spec.js.snap @@ -0,0 +1,37 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`DrawerProvider renders child elements 1`] = `"
Content
"`; + +exports[`DrawerProvider sets content 1`] = ` +
+
+
+ + Content +
+
+
+`; + +exports[`DrawerProvider toggles drawer 1`] = ` +
+
+
+ + Content +
+
+
+`; diff --git a/src/components/Drawer/__tests__/__snapshots__/index.spec.js.snap b/src/components/Drawer/__tests__/__snapshots__/index.spec.js.snap new file mode 100644 index 000000000..c3b54d770 --- /dev/null +++ b/src/components/Drawer/__tests__/__snapshots__/index.spec.js.snap @@ -0,0 +1,1836 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Drawer renders default drawer 1`] = ` +.c0 { + background-color: rgba(38,38,38,1); + color: rgba(255,255,255,1); + height: 100%; + position: fixed; + top: 0; + left: 0; + bottom: 0; + right: 0; + visibility: hidden; + -webkit-transform: translateY(-100%); + -ms-transform: translateY(-100%); + transform: translateY(-100%); + opacity: 0; + -webkit-transition: opacity 0.3ms cubic-bezier(0.455,0.03,0.515,0.955); + transition: opacity 0.3ms cubic-bezier(0.455,0.03,0.515,0.955); + overflow: hidden; + z-index: -1; +} + +.c0.drawer__content--open { + -webkit-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + visibility: visible; + opacity: 1; +} + +.c1 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + position: relative; + width: 100%; + height: 100vh; + overflow-y: scroll; + -webkit-overflow-scrolling: touch; + overflow-x: hidden; +} + +.c6 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -webkit-flex-wrap: nowrap; + -ms-flex-wrap: nowrap; + flex-wrap: nowrap; + -webkit-box-pack: justify; + -webkit-justify-content: space-between; + -ms-flex-pack: justify; + justify-content: space-between; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + height: 60px; + padding-left: 16px; +} + +.c7 { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + cursor: pointer; + border: 0; + outline: 0; + background: transparent; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + height: 60px; + padding: 0 16px; +} + +.c4 { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + width: auto; + height: 100%; +} + +.c5 { + position: absolute; + right: 0; + bottom: 0; + height: 100%; + width: auto; +} + +.c2 { + z-index: 1; + width: 100%; + background-image: linear-gradient(256deg,rgb(0,45,161),rgba(2,108,223,1) 55%,rgb(0,45,161)); +} + +.c2.gradient--overlay:after, +.c2.gradient--underlay:after { + height: 100%; + content: ""; + top: 0; + left: 0; + right: 0; + position: absolute; +} + +.c2.gradient--underlay.gradient--spotlight:after { + z-index: -1; + opacity: 0.8; + background-image: linear-gradient(256deg,rgb(0,45,161),rgba(2,108,223,1) 55%,rgb(0,45,161)); +} + +.c2:not(.gradient--spotlight).gradient--overlay:after { + z-index: 2; + opacity: 0.4; + background-image: linear-gradient(77deg,rgba(0,0,0,0),#000000); +} + +.c2:not(.gradient--spotlight).gradient--underlay:after { + z-index: -1; + opacity: 0.8; + background-image: linear-gradient(256deg,rgb(0,45,161),rgba(2,108,223,1) 55%,rgb(0,45,161)); +} + +.c3 { + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + overflow: hidden; +} + +.c9 { + border-radius: 2px; + overflow: hidden; + height: 3px; + background-color: rgba(255,255,255,1); + width: 100%; + display: block; + -webkit-transition: all 300ms cubic-bezier(0.455,0.03,0.515,0.955); + transition: all 300ms cubic-bezier(0.455,0.03,0.515,0.955); +} + +.c9:before, +.c9:after { + content: ""; + border-radius: 2px; + height: 3px; + background-color: rgba(255,255,255,1); + width: 100%; + display: block; + position: absolute; + -webkit-transform: rotate(0deg); + -ms-transform: rotate(0deg); + transform: rotate(0deg); + -webkit-transform-origin: right center; + -ms-transform-origin: right center; + transform-origin: right center; + -webkit-transition: -webkit-transform 300ms cubic-bezier(0.455,0.03,0.515,0.955), background-color 300ms cubic-bezier(0.455,0.03,0.515,0.955); + -webkit-transition: transform 300ms cubic-bezier(0.455,0.03,0.515,0.955), background-color 300ms cubic-bezier(0.455,0.03,0.515,0.955); + transition: transform 300ms cubic-bezier(0.455,0.03,0.515,0.955), background-color 300ms cubic-bezier(0.455,0.03,0.515,0.955); +} + +.c9:before { + top: 0; + left: 0; +} + +.c9:after { + bottom: 0; + left: 0; +} + +.nav--inverted .c9 { + background-color: rgba(38,38,38,1); +} + +.nav--inverted .c9:before, +.nav--inverted .c9:after { + background-color: rgba(38,38,38,1); +} + +.hamburger--opened .c9 { + background-color: transparent; +} + +.hamburger--opened .c9:before { + -webkit-transform: rotate(-45deg); + -ms-transform: rotate(-45deg); + transform: rotate(-45deg); +} + +.hamburger--opened .c9:after { + -webkit-transform: rotate(45deg); + -ms-transform: rotate(45deg); + transform: rotate(45deg); +} + +.c8 { + height: 17px; + width: 20px; + position: relative; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; +} + +@media screen and (min-width:768px) { + .c2 { + background-image: linear-gradient(260deg,rgb(0,45,161),rgba(2,108,223,1) 55%,rgb(0,45,161)); + } +} + +@media screen and (min-width:1024px) { + .c2 { + background-image: linear-gradient(262deg,rgb(0,45,161),rgba(2,108,223,1) 55%,rgb(0,45,161)); + } +} + +@media screen and (min-width:1024px) { + .c2.gradient--spotlight { + box-shadow: inset 0 1px 40px 10px rgba(0,0,0,0.15); + } +} + +@media screen and (min-width:768px) { + .c2.gradient--underlay.gradient--spotlight:after { + background-image: linear-gradient(260deg,rgb(0,45,161),rgba(2,108,223,1) 55%,rgb(0,45,161)); + } +} + +@media screen and (min-width:1024px) { + .c2.gradient--underlay.gradient--spotlight:after { + background-image: linear-gradient(262deg,rgb(0,45,161),rgba(2,108,223,1) 55%,rgb(0,45,161)); + } +} + +@media screen and (min-width:768px) { + .c2:not(.gradient--spotlight).gradient--overlay:after { + background-image: linear-gradient(82deg,rgba(0,0,0,0),#000000); + } +} + +@media screen and (min-width:1024px) { + .c2:not(.gradient--spotlight).gradient--overlay:after { + background-image: linear-gradient(86deg,rgba(0,0,0,0),#000000); + } +} + +@media screen and (min-width:768px) { + .c2:not(.gradient--spotlight).gradient--underlay:after { + background-image: linear-gradient(260deg,rgb(0,45,161),rgba(2,108,223,1) 55%,rgb(0,45,161)); + } +} + +@media screen and (min-width:1024px) { + .c2:not(.gradient--spotlight).gradient--underlay:after { + background-image: linear-gradient(262deg,rgb(0,45,161),rgba(2,108,223,1) 55%,rgb(0,45,161)); + } +} + +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+ +
+
+`; + +exports[`Drawer renders header elements 1`] = ` +.c0 { + background-color: rgba(38,38,38,1); + color: rgba(255,255,255,1); + height: 100%; + position: fixed; + top: 0; + left: 0; + bottom: 0; + right: 0; + visibility: hidden; + -webkit-transform: translateY(-100%); + -ms-transform: translateY(-100%); + transform: translateY(-100%); + opacity: 0; + -webkit-transition: opacity 0.3ms cubic-bezier(0.455,0.03,0.515,0.955); + transition: opacity 0.3ms cubic-bezier(0.455,0.03,0.515,0.955); + overflow: hidden; + z-index: -1; +} + +.c0.drawer__content--open { + -webkit-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + visibility: visible; + opacity: 1; +} + +.c1 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + position: relative; + width: 100%; + height: 100vh; + overflow-y: scroll; + -webkit-overflow-scrolling: touch; + overflow-x: hidden; +} + +.c6 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -webkit-flex-wrap: nowrap; + -ms-flex-wrap: nowrap; + flex-wrap: nowrap; + -webkit-box-pack: justify; + -webkit-justify-content: space-between; + -ms-flex-pack: justify; + justify-content: space-between; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + height: 60px; + padding-left: 16px; +} + +.c7 { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + cursor: pointer; + border: 0; + outline: 0; + background: transparent; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + height: 60px; + padding: 0 16px; +} + +.c4 { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + width: auto; + height: 100%; +} + +.c5 { + position: absolute; + right: 0; + bottom: 0; + height: 100%; + width: auto; +} + +.c2 { + z-index: 1; + width: 100%; + background-image: linear-gradient(256deg,rgb(0,45,161),rgba(2,108,223,1) 55%,rgb(0,45,161)); +} + +.c2.gradient--overlay:after, +.c2.gradient--underlay:after { + height: 100%; + content: ""; + top: 0; + left: 0; + right: 0; + position: absolute; +} + +.c2.gradient--underlay.gradient--spotlight:after { + z-index: -1; + opacity: 0.8; + background-image: linear-gradient(256deg,rgb(0,45,161),rgba(2,108,223,1) 55%,rgb(0,45,161)); +} + +.c2:not(.gradient--spotlight).gradient--overlay:after { + z-index: 2; + opacity: 0.4; + background-image: linear-gradient(77deg,rgba(0,0,0,0),#000000); +} + +.c2:not(.gradient--spotlight).gradient--underlay:after { + z-index: -1; + opacity: 0.8; + background-image: linear-gradient(256deg,rgb(0,45,161),rgba(2,108,223,1) 55%,rgb(0,45,161)); +} + +.c3 { + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + overflow: hidden; +} + +.c9 { + border-radius: 2px; + overflow: hidden; + height: 3px; + background-color: rgba(255,255,255,1); + width: 100%; + display: block; + -webkit-transition: all 300ms cubic-bezier(0.455,0.03,0.515,0.955); + transition: all 300ms cubic-bezier(0.455,0.03,0.515,0.955); +} + +.c9:before, +.c9:after { + content: ""; + border-radius: 2px; + height: 3px; + background-color: rgba(255,255,255,1); + width: 100%; + display: block; + position: absolute; + -webkit-transform: rotate(0deg); + -ms-transform: rotate(0deg); + transform: rotate(0deg); + -webkit-transform-origin: right center; + -ms-transform-origin: right center; + transform-origin: right center; + -webkit-transition: -webkit-transform 300ms cubic-bezier(0.455,0.03,0.515,0.955), background-color 300ms cubic-bezier(0.455,0.03,0.515,0.955); + -webkit-transition: transform 300ms cubic-bezier(0.455,0.03,0.515,0.955), background-color 300ms cubic-bezier(0.455,0.03,0.515,0.955); + transition: transform 300ms cubic-bezier(0.455,0.03,0.515,0.955), background-color 300ms cubic-bezier(0.455,0.03,0.515,0.955); +} + +.c9:before { + top: 0; + left: 0; +} + +.c9:after { + bottom: 0; + left: 0; +} + +.nav--inverted .c9 { + background-color: rgba(38,38,38,1); +} + +.nav--inverted .c9:before, +.nav--inverted .c9:after { + background-color: rgba(38,38,38,1); +} + +.hamburger--opened .c9 { + background-color: transparent; +} + +.hamburger--opened .c9:before { + -webkit-transform: rotate(-45deg); + -ms-transform: rotate(-45deg); + transform: rotate(-45deg); +} + +.hamburger--opened .c9:after { + -webkit-transform: rotate(45deg); + -ms-transform: rotate(45deg); + transform: rotate(45deg); +} + +.c8 { + height: 17px; + width: 20px; + position: relative; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; +} + +@media screen and (min-width:768px) { + .c2 { + background-image: linear-gradient(260deg,rgb(0,45,161),rgba(2,108,223,1) 55%,rgb(0,45,161)); + } +} + +@media screen and (min-width:1024px) { + .c2 { + background-image: linear-gradient(262deg,rgb(0,45,161),rgba(2,108,223,1) 55%,rgb(0,45,161)); + } +} + +@media screen and (min-width:1024px) { + .c2.gradient--spotlight { + box-shadow: inset 0 1px 40px 10px rgba(0,0,0,0.15); + } +} + +@media screen and (min-width:768px) { + .c2.gradient--underlay.gradient--spotlight:after { + background-image: linear-gradient(260deg,rgb(0,45,161),rgba(2,108,223,1) 55%,rgb(0,45,161)); + } +} + +@media screen and (min-width:1024px) { + .c2.gradient--underlay.gradient--spotlight:after { + background-image: linear-gradient(262deg,rgb(0,45,161),rgba(2,108,223,1) 55%,rgb(0,45,161)); + } +} + +@media screen and (min-width:768px) { + .c2:not(.gradient--spotlight).gradient--overlay:after { + background-image: linear-gradient(82deg,rgba(0,0,0,0),#000000); + } +} + +@media screen and (min-width:1024px) { + .c2:not(.gradient--spotlight).gradient--overlay:after { + background-image: linear-gradient(86deg,rgba(0,0,0,0),#000000); + } +} + +@media screen and (min-width:768px) { + .c2:not(.gradient--spotlight).gradient--underlay:after { + background-image: linear-gradient(260deg,rgb(0,45,161),rgba(2,108,223,1) 55%,rgb(0,45,161)); + } +} + +@media screen and (min-width:1024px) { + .c2:not(.gradient--spotlight).gradient--underlay:after { + background-image: linear-gradient(262deg,rgb(0,45,161),rgba(2,108,223,1) 55%,rgb(0,45,161)); + } +} + +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + Some Title Element + +
+ +
+
+ + Content + +
+
+`; + +exports[`Drawer renders multiple child elements 1`] = ` +.c0 { + background-color: rgba(38,38,38,1); + color: rgba(255,255,255,1); + height: 100%; + position: fixed; + top: 0; + left: 0; + bottom: 0; + right: 0; + visibility: hidden; + -webkit-transform: translateY(-100%); + -ms-transform: translateY(-100%); + transform: translateY(-100%); + opacity: 0; + -webkit-transition: opacity 0.3ms cubic-bezier(0.455,0.03,0.515,0.955); + transition: opacity 0.3ms cubic-bezier(0.455,0.03,0.515,0.955); + overflow: hidden; + z-index: -1; +} + +.c0.drawer__content--open { + -webkit-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + visibility: visible; + opacity: 1; +} + +.c1 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + position: relative; + width: 100%; + height: 100vh; + overflow-y: scroll; + -webkit-overflow-scrolling: touch; + overflow-x: hidden; +} + +.c6 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -webkit-flex-wrap: nowrap; + -ms-flex-wrap: nowrap; + flex-wrap: nowrap; + -webkit-box-pack: justify; + -webkit-justify-content: space-between; + -ms-flex-pack: justify; + justify-content: space-between; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + height: 60px; + padding-left: 16px; +} + +.c7 { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + cursor: pointer; + border: 0; + outline: 0; + background: transparent; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + height: 60px; + padding: 0 16px; +} + +.c4 { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + width: auto; + height: 100%; +} + +.c5 { + position: absolute; + right: 0; + bottom: 0; + height: 100%; + width: auto; +} + +.c2 { + z-index: 1; + width: 100%; + background-image: linear-gradient(256deg,rgb(0,45,161),rgba(2,108,223,1) 55%,rgb(0,45,161)); +} + +.c2.gradient--overlay:after, +.c2.gradient--underlay:after { + height: 100%; + content: ""; + top: 0; + left: 0; + right: 0; + position: absolute; +} + +.c2.gradient--underlay.gradient--spotlight:after { + z-index: -1; + opacity: 0.8; + background-image: linear-gradient(256deg,rgb(0,45,161),rgba(2,108,223,1) 55%,rgb(0,45,161)); +} + +.c2:not(.gradient--spotlight).gradient--overlay:after { + z-index: 2; + opacity: 0.4; + background-image: linear-gradient(77deg,rgba(0,0,0,0),#000000); +} + +.c2:not(.gradient--spotlight).gradient--underlay:after { + z-index: -1; + opacity: 0.8; + background-image: linear-gradient(256deg,rgb(0,45,161),rgba(2,108,223,1) 55%,rgb(0,45,161)); +} + +.c3 { + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + overflow: hidden; +} + +.c9 { + border-radius: 2px; + overflow: hidden; + height: 3px; + background-color: rgba(255,255,255,1); + width: 100%; + display: block; + -webkit-transition: all 300ms cubic-bezier(0.455,0.03,0.515,0.955); + transition: all 300ms cubic-bezier(0.455,0.03,0.515,0.955); +} + +.c9:before, +.c9:after { + content: ""; + border-radius: 2px; + height: 3px; + background-color: rgba(255,255,255,1); + width: 100%; + display: block; + position: absolute; + -webkit-transform: rotate(0deg); + -ms-transform: rotate(0deg); + transform: rotate(0deg); + -webkit-transform-origin: right center; + -ms-transform-origin: right center; + transform-origin: right center; + -webkit-transition: -webkit-transform 300ms cubic-bezier(0.455,0.03,0.515,0.955), background-color 300ms cubic-bezier(0.455,0.03,0.515,0.955); + -webkit-transition: transform 300ms cubic-bezier(0.455,0.03,0.515,0.955), background-color 300ms cubic-bezier(0.455,0.03,0.515,0.955); + transition: transform 300ms cubic-bezier(0.455,0.03,0.515,0.955), background-color 300ms cubic-bezier(0.455,0.03,0.515,0.955); +} + +.c9:before { + top: 0; + left: 0; +} + +.c9:after { + bottom: 0; + left: 0; +} + +.nav--inverted .c9 { + background-color: rgba(38,38,38,1); +} + +.nav--inverted .c9:before, +.nav--inverted .c9:after { + background-color: rgba(38,38,38,1); +} + +.hamburger--opened .c9 { + background-color: transparent; +} + +.hamburger--opened .c9:before { + -webkit-transform: rotate(-45deg); + -ms-transform: rotate(-45deg); + transform: rotate(-45deg); +} + +.hamburger--opened .c9:after { + -webkit-transform: rotate(45deg); + -ms-transform: rotate(45deg); + transform: rotate(45deg); +} + +.c8 { + height: 17px; + width: 20px; + position: relative; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; +} + +@media screen and (min-width:768px) { + .c2 { + background-image: linear-gradient(260deg,rgb(0,45,161),rgba(2,108,223,1) 55%,rgb(0,45,161)); + } +} + +@media screen and (min-width:1024px) { + .c2 { + background-image: linear-gradient(262deg,rgb(0,45,161),rgba(2,108,223,1) 55%,rgb(0,45,161)); + } +} + +@media screen and (min-width:1024px) { + .c2.gradient--spotlight { + box-shadow: inset 0 1px 40px 10px rgba(0,0,0,0.15); + } +} + +@media screen and (min-width:768px) { + .c2.gradient--underlay.gradient--spotlight:after { + background-image: linear-gradient(260deg,rgb(0,45,161),rgba(2,108,223,1) 55%,rgb(0,45,161)); + } +} + +@media screen and (min-width:1024px) { + .c2.gradient--underlay.gradient--spotlight:after { + background-image: linear-gradient(262deg,rgb(0,45,161),rgba(2,108,223,1) 55%,rgb(0,45,161)); + } +} + +@media screen and (min-width:768px) { + .c2:not(.gradient--spotlight).gradient--overlay:after { + background-image: linear-gradient(82deg,rgba(0,0,0,0),#000000); + } +} + +@media screen and (min-width:1024px) { + .c2:not(.gradient--spotlight).gradient--overlay:after { + background-image: linear-gradient(86deg,rgba(0,0,0,0),#000000); + } +} + +@media screen and (min-width:768px) { + .c2:not(.gradient--spotlight).gradient--underlay:after { + background-image: linear-gradient(260deg,rgb(0,45,161),rgba(2,108,223,1) 55%,rgb(0,45,161)); + } +} + +@media screen and (min-width:1024px) { + .c2:not(.gradient--spotlight).gradient--underlay:after { + background-image: linear-gradient(262deg,rgb(0,45,161),rgba(2,108,223,1) 55%,rgb(0,45,161)); + } +} + +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+ + + Content + + + Content + + + Content + +
+
+`; + +exports[`Drawer renders string header header 1`] = ` +.c0 { + background-color: rgba(38,38,38,1); + color: rgba(255,255,255,1); + height: 100%; + position: fixed; + top: 0; + left: 0; + bottom: 0; + right: 0; + visibility: hidden; + -webkit-transform: translateY(-100%); + -ms-transform: translateY(-100%); + transform: translateY(-100%); + opacity: 0; + -webkit-transition: opacity 0.3ms cubic-bezier(0.455,0.03,0.515,0.955); + transition: opacity 0.3ms cubic-bezier(0.455,0.03,0.515,0.955); + overflow: hidden; + z-index: -1; +} + +.c0.drawer__content--open { + -webkit-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + visibility: visible; + opacity: 1; +} + +.c1 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + position: relative; + width: 100%; + height: 100vh; + overflow-y: scroll; + -webkit-overflow-scrolling: touch; + overflow-x: hidden; +} + +.c6 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -webkit-flex-wrap: nowrap; + -ms-flex-wrap: nowrap; + flex-wrap: nowrap; + -webkit-box-pack: justify; + -webkit-justify-content: space-between; + -ms-flex-pack: justify; + justify-content: space-between; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + height: 60px; + padding-left: 16px; +} + +.c7 { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + cursor: pointer; + border: 0; + outline: 0; + background: transparent; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + height: 60px; + padding: 0 16px; +} + +.c4 { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + width: auto; + height: 100%; +} + +.c5 { + position: absolute; + right: 0; + bottom: 0; + height: 100%; + width: auto; +} + +.c2 { + z-index: 1; + width: 100%; + background-image: linear-gradient(256deg,rgb(0,45,161),rgba(2,108,223,1) 55%,rgb(0,45,161)); +} + +.c2.gradient--overlay:after, +.c2.gradient--underlay:after { + height: 100%; + content: ""; + top: 0; + left: 0; + right: 0; + position: absolute; +} + +.c2.gradient--underlay.gradient--spotlight:after { + z-index: -1; + opacity: 0.8; + background-image: linear-gradient(256deg,rgb(0,45,161),rgba(2,108,223,1) 55%,rgb(0,45,161)); +} + +.c2:not(.gradient--spotlight).gradient--overlay:after { + z-index: 2; + opacity: 0.4; + background-image: linear-gradient(77deg,rgba(0,0,0,0),#000000); +} + +.c2:not(.gradient--spotlight).gradient--underlay:after { + z-index: -1; + opacity: 0.8; + background-image: linear-gradient(256deg,rgb(0,45,161),rgba(2,108,223,1) 55%,rgb(0,45,161)); +} + +.c3 { + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + overflow: hidden; +} + +.c9 { + border-radius: 2px; + overflow: hidden; + height: 3px; + background-color: rgba(255,255,255,1); + width: 100%; + display: block; + -webkit-transition: all 300ms cubic-bezier(0.455,0.03,0.515,0.955); + transition: all 300ms cubic-bezier(0.455,0.03,0.515,0.955); +} + +.c9:before, +.c9:after { + content: ""; + border-radius: 2px; + height: 3px; + background-color: rgba(255,255,255,1); + width: 100%; + display: block; + position: absolute; + -webkit-transform: rotate(0deg); + -ms-transform: rotate(0deg); + transform: rotate(0deg); + -webkit-transform-origin: right center; + -ms-transform-origin: right center; + transform-origin: right center; + -webkit-transition: -webkit-transform 300ms cubic-bezier(0.455,0.03,0.515,0.955), background-color 300ms cubic-bezier(0.455,0.03,0.515,0.955); + -webkit-transition: transform 300ms cubic-bezier(0.455,0.03,0.515,0.955), background-color 300ms cubic-bezier(0.455,0.03,0.515,0.955); + transition: transform 300ms cubic-bezier(0.455,0.03,0.515,0.955), background-color 300ms cubic-bezier(0.455,0.03,0.515,0.955); +} + +.c9:before { + top: 0; + left: 0; +} + +.c9:after { + bottom: 0; + left: 0; +} + +.nav--inverted .c9 { + background-color: rgba(38,38,38,1); +} + +.nav--inverted .c9:before, +.nav--inverted .c9:after { + background-color: rgba(38,38,38,1); +} + +.hamburger--opened .c9 { + background-color: transparent; +} + +.hamburger--opened .c9:before { + -webkit-transform: rotate(-45deg); + -ms-transform: rotate(-45deg); + transform: rotate(-45deg); +} + +.hamburger--opened .c9:after { + -webkit-transform: rotate(45deg); + -ms-transform: rotate(45deg); + transform: rotate(45deg); +} + +.c8 { + height: 17px; + width: 20px; + position: relative; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; +} + +@media screen and (min-width:768px) { + .c2 { + background-image: linear-gradient(260deg,rgb(0,45,161),rgba(2,108,223,1) 55%,rgb(0,45,161)); + } +} + +@media screen and (min-width:1024px) { + .c2 { + background-image: linear-gradient(262deg,rgb(0,45,161),rgba(2,108,223,1) 55%,rgb(0,45,161)); + } +} + +@media screen and (min-width:1024px) { + .c2.gradient--spotlight { + box-shadow: inset 0 1px 40px 10px rgba(0,0,0,0.15); + } +} + +@media screen and (min-width:768px) { + .c2.gradient--underlay.gradient--spotlight:after { + background-image: linear-gradient(260deg,rgb(0,45,161),rgba(2,108,223,1) 55%,rgb(0,45,161)); + } +} + +@media screen and (min-width:1024px) { + .c2.gradient--underlay.gradient--spotlight:after { + background-image: linear-gradient(262deg,rgb(0,45,161),rgba(2,108,223,1) 55%,rgb(0,45,161)); + } +} + +@media screen and (min-width:768px) { + .c2:not(.gradient--spotlight).gradient--overlay:after { + background-image: linear-gradient(82deg,rgba(0,0,0,0),#000000); + } +} + +@media screen and (min-width:1024px) { + .c2:not(.gradient--spotlight).gradient--overlay:after { + background-image: linear-gradient(86deg,rgba(0,0,0,0),#000000); + } +} + +@media screen and (min-width:768px) { + .c2:not(.gradient--spotlight).gradient--underlay:after { + background-image: linear-gradient(260deg,rgb(0,45,161),rgba(2,108,223,1) 55%,rgb(0,45,161)); + } +} + +@media screen and (min-width:1024px) { + .c2:not(.gradient--spotlight).gradient--underlay:after { + background-image: linear-gradient(262deg,rgb(0,45,161),rgba(2,108,223,1) 55%,rgb(0,45,161)); + } +} + +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ Some Title +
+ +
+
+ Content +
+
+`; diff --git a/src/components/Drawer/__tests__/index.spec.js b/src/components/Drawer/__tests__/index.spec.js new file mode 100644 index 000000000..9fae9860f --- /dev/null +++ b/src/components/Drawer/__tests__/index.spec.js @@ -0,0 +1,56 @@ +import React from "react"; +import renderer from "react-test-renderer"; + +import Drawer from "../index"; + +describe("Drawer", () => { + it("renders default drawer", () => { + expect(renderer.create().toJSON()).toMatchSnapshot(); + }); + + it("renders multiple child elements", () => { + expect( + renderer + .create( + + Content + Content + Content + + ) + .toJSON() + ).toMatchSnapshot(); + }); + + it("calls a function as child", () => { + const children = jest.fn(() => "Content"); + renderer.create({children}); + + expect(children).toHaveBeenCalled(); + }); + + it("renders string header header", () => { + expect( + renderer.create(Content).toJSON() + ).toMatchSnapshot(); + }); + + it("renders header elements", () => { + expect( + renderer + .create( + Some Title Element}> + Content + + ) + .toJSON() + ).toMatchSnapshot(); + }); + + it("calls header as function", () => { + const header = jest.fn(() => "Header Content"); + renderer.create(Content); + + expect(header).toHaveBeenCalled(); + }); +}); diff --git a/src/components/Drawer/index.js b/src/components/Drawer/index.js new file mode 100644 index 000000000..df6161c94 --- /dev/null +++ b/src/components/Drawer/index.js @@ -0,0 +1,101 @@ +import React from "react"; +import PropTypes from "prop-types"; +import classNames from "classnames"; + +import { Consumer } from "./Context"; +import { + DrawerContainer, + DrawerContent, + HeaderContent, + CloseButton +} from "./Drawer.styles"; +import Gradient from "../Gradient"; +import Text from "../Text/Base"; +import HamburgerIcon from "../Icons/HamburgerIcon"; +import omitKeys from "../../utils/omitKeys"; + +export default class Drawer extends React.Component { + static propTypes = { + children: PropTypes.oneOfType([ + PropTypes.node, + PropTypes.element, + PropTypes.func + ]), + header: PropTypes.oneOfType([ + PropTypes.node, + PropTypes.func, + PropTypes.string + ]) + }; + + static defaultProps = { children: null, header: null }; + + renderChildren = props => { + const { children } = this.props; + if (typeof children === "function") return children(props); + + return children; + }; + + renderHeader = ({ toggleDrawer, isOpen }) => { + const { header } = this.props; + + if (typeof header === "function") return header({ toggleDrawer, isOpen }); + + return ( + + +
+ {typeof content === "string" ? ( + + {header} + + ) : ( + header + )} +
+ + + +
+
+ ); + }; + + render() { + const { className, ...rest } = this.props; + return ( + + {({ isOpen, toggleDrawer }) => ( + + + {this.renderHeader({ + toggleDrawer, + isOpen + })} + {this.renderChildren({ + toggleDrawer, + isOpen + })} + + + )} + + ); + } +} diff --git a/src/components/Icons/HamburgerIcon.js b/src/components/Icons/HamburgerIcon.js new file mode 100644 index 000000000..156e53e66 --- /dev/null +++ b/src/components/Icons/HamburgerIcon.js @@ -0,0 +1,76 @@ +import React from "react"; +import styled from "styled-components"; + +import constants from "../../theme/constants"; +import getThemeValue from "../../utils/getThemeValue"; + +const HamburgerContent = styled.span` + border-radius: ${constants.borderRadius.small}; + overflow: hidden; + height: 3px; + background-color: ${getThemeValue("white", "base")}; + width: 100%; + display: block; + transition: all 300ms ${constants.easing.easeInOutQuad}; + + &:before, + &:after { + content: ""; + border-radius: ${constants.borderRadius.small}; + height: 3px; + background-color: ${getThemeValue("white", "base")}; + width: 100%; + display: block; + position: absolute; + transform: rotate(0deg); + transform-origin: right center; + transition: transform 300ms ${constants.easing.easeInOutQuad}, + background-color 300ms ${constants.easing.easeInOutQuad}; + } + + &:before { + top: 0; + left: 0; + } + + &:after { + bottom: 0; + left: 0; + } + + .nav--inverted & { + background-color: ${getThemeValue("onyx", "base")}; + + &:before, + &:after { + background-color: ${getThemeValue("onyx", "base")}; + } + } + + .hamburger--opened & { + background-color: transparent; + &:before { + transform: rotate(-45deg); + } + + &:after { + transform: rotate(45deg); + } + } +`; + +const HamburgerIconWrapper = styled.span` + height: 17px; + width: 20px; + position: relative; + display: flex; + align-items: center; +`; + +const HamburgerIcon = props => ( + + + +); + +export default HamburgerIcon; diff --git a/src/components/NavBar/ButtonBase.js b/src/components/NavBar/ButtonBase.js new file mode 100644 index 000000000..13ef93d65 --- /dev/null +++ b/src/components/NavBar/ButtonBase.js @@ -0,0 +1,111 @@ +import React from "react"; +import PropTypes from "prop-types"; +import styled from "styled-components"; +import classNames from "classnames"; + +import colors from "../../theme/colors"; +import spacing from "../../theme/spacing"; +import typography from "../../theme/typography"; +import constants from "../../theme/constants"; +import { smallAndUp } from "../../theme/mediaQueries"; +import getRelByTarget from "../../utils/link"; + +const BaseButton = styled.button` + backface-visibility: hidden; + display: flex; + align-items: center; + flex: 0 1 auto; + background-color: transparent; + text-decoration: none; + border: 0; + height: 60px; + outline: 0; + appearance: none; + padding-right: ${spacing.gutters.small / 2}px; + padding-left: ${spacing.gutters.small / 2}px; + color: ${colors.white.base}; + font-size: ${typography.size.kilo}; + font-weight: ${typography.weight.semiBold}; + transition: all 0.3ms ${constants.easing.easeInOutQuad}; + .nav--inverted & { + color: ${colors.onyx.base}; + font-weight: ${typography.weight.regular}; + } + + &.nav-button--last { + padding-right: ${spacing.gutters.small}px; + } + + &.nav-button--first { + padding-left: ${spacing.gutters.small}px; + } + + ${smallAndUp` + padding-right: ${parseInt(spacing.normal, 10) / 2}px; + padding-left: ${parseInt(spacing.normal, 10) / 2}px; + + &.nav-button--last { + padding-right: ${spacing.gutters.mediumAndUp}px; + } + + &.nav-button--first { + padding-left: ${spacing.gutters.mediumAndUp}px; + } + `}; +`; + +const Anchor = BaseButton.withComponent("a"); + +const Button = ({ + children, + href, + target, + rel, + className, + isFirst, + isLast, + ...props +}) => { + if (href) { + return ( + + {children} + + ); + } + + return ( + + {children} + + ); +}; + +Button.propTypes = { + children: PropTypes.node, + href: PropTypes.string, + target: PropTypes.string, + rel: PropTypes.string, + isFirst: PropTypes.bool, + isLast: PropTypes.bool +}; + +Button.defaultProps = { + children: null, + href: null, + isFirst: false, + isLast: false, + target: "_self", + rel: null +}; + +export default Button; diff --git a/src/components/NavBar/Buttons.js b/src/components/NavBar/Buttons.js index 27a5561dd..3860c8880 100644 --- a/src/components/NavBar/Buttons.js +++ b/src/components/NavBar/Buttons.js @@ -2,89 +2,12 @@ import React from "react"; import PropTypes from "prop-types"; import styled from "styled-components"; +import Button from "./ButtonBase"; import Menu from "../Icons/Menu"; import Search from "../Icons/Search"; import User from "../Icons/User"; -import colors from "../../theme/colors"; import spacing from "../../theme/spacing"; -import typography from "../../theme/typography"; import { mediumAndUp, smallAndUp } from "../../theme/mediaQueries"; -import getRelByTarget from "../../utils/link"; - -const BaseButton = styled.button` - display: flex; - align-items: center; - flex: 0 1 auto; - background-color: transparent; - text-decoration: none; - border: 0; - height: 60px; - outline: 0; - appearance: none; - padding-right: ${({ isLast }) => - isLast ? spacing.gutters.small : spacing.gutters.small / 2}px; - padding-left: ${({ isFirst }) => - isFirst ? spacing.gutters.small : spacing.gutters.small / 2}px; - color: ${colors.white.base}; - font-size: ${typography.size.kilo}; - font-weight: ${typography.weight.semiBold}; - .nav--inverted & { - color: ${colors.onyx.base}; - font-weight: ${typography.weight.regular}; - } - - ${smallAndUp` - padding-right: ${({ isLast }) => - isLast - ? spacing.gutters.mediumAndUp - : parseInt(spacing.normal, 10) / 2}px; - padding-left: ${({ isFirst }) => - isFirst - ? spacing.gutters.mediumAndUp - : parseInt(spacing.normal, 10) / 2}px; - `}; -`; - -const Anchor = BaseButton.withComponent("a"); - -const Button = ({ children, href, target, rel, ...props }) => { - if (href) { - return ( - - {children} - - ); - } - - return ( - - {children} - - ); -}; - -Button.propTypes = { - children: PropTypes.node, - href: PropTypes.string, - target: PropTypes.string, - rel: PropTypes.string, - isFirst: PropTypes.bool, - isLast: PropTypes.bool -}; - -Button.defaultProps = { - children: null, - href: null, - isFirst: false, - isLast: false, - target: "_self", - rel: null -}; const LogoBtn = styled(Button)` padding-left: ${spacing.gutters.small / 2}px; diff --git a/src/components/NavBar/DrawerMenu.js b/src/components/NavBar/DrawerMenu.js new file mode 100644 index 000000000..bec35bc42 --- /dev/null +++ b/src/components/NavBar/DrawerMenu.js @@ -0,0 +1,59 @@ +import React from "react"; +import PropTypes from "prop-types"; +import classNames from "classnames"; + +import MenuButton from "./MenuButton"; +import Drawer from "../Drawer"; +import { Consumer } from "../Drawer/Context"; +import composeEventHandlers from "../../utils/composeEventHandlers"; +import omitKeys from "../../utils/omitKeys"; + +const noop = () => {}; + +class DrawerMenu extends React.Component { + static propTypes = { + onClick: PropTypes.func, + children: PropTypes.node, + setContent: PropTypes.func.isRequired, + toggleDrawer: PropTypes.func.isRequired, + isOpen: PropTypes.bool.isRequired + }; + + static defaultProps = { onClick: noop, children: null }; + + componentDidMount() { + const { children, ...rest } = this.props; + this.props.setContent( + + {children} + + ); + } + + render() { + const { onClick, toggleDrawer, isOpen } = this.props; + + return ( + + ); + } +} + +const DrawerMenuWrapper = props => ( + + {({ isOpen = false, setContent = noop, toggleDrawer = noop } = {}) => ( + + )} + +); + +export default DrawerMenuWrapper; diff --git a/src/components/NavBar/Links.js b/src/components/NavBar/Links.js index 615ff3516..af439a60d 100644 --- a/src/components/NavBar/Links.js +++ b/src/components/NavBar/Links.js @@ -9,6 +9,7 @@ import { import colors from "../../theme/colors"; import typography from "../../theme/typography"; import spacing from "../../theme/spacing"; +import constants from "../../theme/constants"; const LinkRow = LinkRowBase.extend` height: 60px; @@ -27,6 +28,8 @@ const Link = styled(LinkItem)` color: ${colors.white.base}; font-size: ${typography.size.kilo}; font-weight: ${typography.weight.semiBold}; + text-shadow: 1px 0px 0px transparent; + transition: all 300ms ${constants.easing.easeInOutQuad}; .nav--inverted &, .links__list & { diff --git a/src/components/NavBar/MenuButton.js b/src/components/NavBar/MenuButton.js new file mode 100644 index 000000000..89d8f57cc --- /dev/null +++ b/src/components/NavBar/MenuButton.js @@ -0,0 +1,24 @@ +import React from "react"; +import PropTypes from "prop-types"; +import classNames from "classnames"; + +import Button from "./ButtonBase"; +import HamburgerIcon from "../Icons/HamburgerIcon"; + +const MenuButton = ({ iconClassName, className, ...props }) => ( + +); + +MenuButton.propTypes = { + isLast: PropTypes.bool, + className: PropTypes.string +}; + +MenuButton.defaultProps = { + isLast: true, + className: "" +}; + +export default MenuButton; diff --git a/src/components/NavBar/__tests__/DrawerMenu.spec.js b/src/components/NavBar/__tests__/DrawerMenu.spec.js new file mode 100644 index 000000000..7d467bf9e --- /dev/null +++ b/src/components/NavBar/__tests__/DrawerMenu.spec.js @@ -0,0 +1,20 @@ +import React from "react"; +import renderer from "react-test-renderer"; + +import MobileMenu from "../DrawerMenu"; + +describe("MobileMenu", () => { + it("renders default", () => { + expect(renderComponent().toJSON()).toMatchSnapshot(); + }); + + it("accepts children as menu content", () => { + expect( + renderComponent({ children:
Some Content
}).toJSON() + ).toMatchSnapshot(); + }); + + function renderComponent(props = {}, render = renderer.create) { + return render(); + } +}); diff --git a/src/components/NavBar/__tests__/__snapshots__/DrawerMenu.spec.js.snap b/src/components/NavBar/__tests__/__snapshots__/DrawerMenu.spec.js.snap new file mode 100644 index 000000000..18c6fc20c --- /dev/null +++ b/src/components/NavBar/__tests__/__snapshots__/DrawerMenu.spec.js.snap @@ -0,0 +1,313 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`MobileMenu accepts children as menu content 1`] = ` +.c0 { + -webkit-backface-visibility: hidden; + backface-visibility: hidden; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-flex: 0 1 auto; + -ms-flex: 0 1 auto; + flex: 0 1 auto; + background-color: transparent; + -webkit-text-decoration: none; + text-decoration: none; + border: 0; + height: 60px; + outline: 0; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + padding-right: 8px; + padding-left: 8px; + color: rgba(255,255,255,1); + font-size: 16px; + font-weight: 600; + -webkit-transition: all 0.3ms cubic-bezier(0.455,0.03,0.515,0.955); + transition: all 0.3ms cubic-bezier(0.455,0.03,0.515,0.955); +} + +.nav--inverted .c0 { + color: rgba(38,38,38,1); + font-weight: 400; +} + +.c0.nav-button--last { + padding-right: 16px; +} + +.c0.nav-button--first { + padding-left: 16px; +} + +.c2 { + border-radius: 2px; + overflow: hidden; + height: 3px; + background-color: rgba(255,255,255,1); + width: 100%; + display: block; + -webkit-transition: all 300ms cubic-bezier(0.455,0.03,0.515,0.955); + transition: all 300ms cubic-bezier(0.455,0.03,0.515,0.955); +} + +.c2:before, +.c2:after { + content: ""; + border-radius: 2px; + height: 3px; + background-color: rgba(255,255,255,1); + width: 100%; + display: block; + position: absolute; + -webkit-transform: rotate(0deg); + -ms-transform: rotate(0deg); + transform: rotate(0deg); + -webkit-transform-origin: right center; + -ms-transform-origin: right center; + transform-origin: right center; + -webkit-transition: -webkit-transform 300ms cubic-bezier(0.455,0.03,0.515,0.955), background-color 300ms cubic-bezier(0.455,0.03,0.515,0.955); + -webkit-transition: transform 300ms cubic-bezier(0.455,0.03,0.515,0.955), background-color 300ms cubic-bezier(0.455,0.03,0.515,0.955); + transition: transform 300ms cubic-bezier(0.455,0.03,0.515,0.955), background-color 300ms cubic-bezier(0.455,0.03,0.515,0.955); +} + +.c2:before { + top: 0; + left: 0; +} + +.c2:after { + bottom: 0; + left: 0; +} + +.nav--inverted .c2 { + background-color: rgba(38,38,38,1); +} + +.nav--inverted .c2:before, +.nav--inverted .c2:after { + background-color: rgba(38,38,38,1); +} + +.hamburger--opened .c2 { + background-color: transparent; +} + +.hamburger--opened .c2:before { + -webkit-transform: rotate(-45deg); + -ms-transform: rotate(-45deg); + transform: rotate(-45deg); +} + +.hamburger--opened .c2:after { + -webkit-transform: rotate(45deg); + -ms-transform: rotate(45deg); + transform: rotate(45deg); +} + +.c1 { + height: 17px; + width: 20px; + position: relative; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; +} + +@media screen and (min-width:480px) { + .c0 { + padding-right: 12px; + padding-left: 12px; + } + + .c0.nav-button--last { + padding-right: 24px; + } + + .c0.nav-button--first { + padding-left: 24px; + } +} + + +`; + +exports[`MobileMenu renders default 1`] = ` +.c0 { + -webkit-backface-visibility: hidden; + backface-visibility: hidden; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-flex: 0 1 auto; + -ms-flex: 0 1 auto; + flex: 0 1 auto; + background-color: transparent; + -webkit-text-decoration: none; + text-decoration: none; + border: 0; + height: 60px; + outline: 0; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + padding-right: 8px; + padding-left: 8px; + color: rgba(255,255,255,1); + font-size: 16px; + font-weight: 600; + -webkit-transition: all 0.3ms cubic-bezier(0.455,0.03,0.515,0.955); + transition: all 0.3ms cubic-bezier(0.455,0.03,0.515,0.955); +} + +.nav--inverted .c0 { + color: rgba(38,38,38,1); + font-weight: 400; +} + +.c0.nav-button--last { + padding-right: 16px; +} + +.c0.nav-button--first { + padding-left: 16px; +} + +.c2 { + border-radius: 2px; + overflow: hidden; + height: 3px; + background-color: rgba(255,255,255,1); + width: 100%; + display: block; + -webkit-transition: all 300ms cubic-bezier(0.455,0.03,0.515,0.955); + transition: all 300ms cubic-bezier(0.455,0.03,0.515,0.955); +} + +.c2:before, +.c2:after { + content: ""; + border-radius: 2px; + height: 3px; + background-color: rgba(255,255,255,1); + width: 100%; + display: block; + position: absolute; + -webkit-transform: rotate(0deg); + -ms-transform: rotate(0deg); + transform: rotate(0deg); + -webkit-transform-origin: right center; + -ms-transform-origin: right center; + transform-origin: right center; + -webkit-transition: -webkit-transform 300ms cubic-bezier(0.455,0.03,0.515,0.955), background-color 300ms cubic-bezier(0.455,0.03,0.515,0.955); + -webkit-transition: transform 300ms cubic-bezier(0.455,0.03,0.515,0.955), background-color 300ms cubic-bezier(0.455,0.03,0.515,0.955); + transition: transform 300ms cubic-bezier(0.455,0.03,0.515,0.955), background-color 300ms cubic-bezier(0.455,0.03,0.515,0.955); +} + +.c2:before { + top: 0; + left: 0; +} + +.c2:after { + bottom: 0; + left: 0; +} + +.nav--inverted .c2 { + background-color: rgba(38,38,38,1); +} + +.nav--inverted .c2:before, +.nav--inverted .c2:after { + background-color: rgba(38,38,38,1); +} + +.hamburger--opened .c2 { + background-color: transparent; +} + +.hamburger--opened .c2:before { + -webkit-transform: rotate(-45deg); + -ms-transform: rotate(-45deg); + transform: rotate(-45deg); +} + +.hamburger--opened .c2:after { + -webkit-transform: rotate(45deg); + -ms-transform: rotate(45deg); + transform: rotate(45deg); +} + +.c1 { + height: 17px; + width: 20px; + position: relative; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; +} + +@media screen and (min-width:480px) { + .c0 { + padding-right: 12px; + padding-left: 12px; + } + + .c0.nav-button--last { + padding-right: 24px; + } + + .c0.nav-button--first { + padding-left: 24px; + } +} + + +`; diff --git a/src/components/NavBar/__tests__/__snapshots__/index.spec.js.snap b/src/components/NavBar/__tests__/__snapshots__/index.spec.js.snap index 844e0a3b2..924d8996b 100644 --- a/src/components/NavBar/__tests__/__snapshots__/index.spec.js.snap +++ b/src/components/NavBar/__tests__/__snapshots__/index.spec.js.snap @@ -77,6 +77,9 @@ exports[`NavBar renders fixed 1`] = ` color: rgba(255,255,255,1); font-size: 16px; font-weight: 600; + text-shadow: 1px 0px 0px transparent; + -webkit-transition: all 300ms cubic-bezier(0.455,0.03,0.515,0.955); + transition: all 300ms cubic-bezier(0.455,0.03,0.515,0.955); } .nav--inverted .c6, @@ -111,6 +114,8 @@ exports[`NavBar renders fixed 1`] = ` } .c2 { + -webkit-backface-visibility: hidden; + backface-visibility: hidden; display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; @@ -132,10 +137,12 @@ exports[`NavBar renders fixed 1`] = ` -moz-appearance: none; appearance: none; padding-right: 8px; - padding-left: 16px; + padding-left: 8px; color: rgba(255,255,255,1); font-size: 16px; font-weight: 600; + -webkit-transition: all 0.3ms cubic-bezier(0.455,0.03,0.515,0.955); + transition: all 0.3ms cubic-bezier(0.455,0.03,0.515,0.955); } .nav--inverted .c2 { @@ -143,7 +150,17 @@ exports[`NavBar renders fixed 1`] = ` font-weight: 400; } +.c2.nav-button--last { + padding-right: 16px; +} + +.c2.nav-button--first { + padding-left: 16px; +} + .c4 { + -webkit-backface-visibility: hidden; + backface-visibility: hidden; display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; @@ -169,6 +186,8 @@ exports[`NavBar renders fixed 1`] = ` color: rgba(255,255,255,1); font-size: 16px; font-weight: 600; + -webkit-transition: all 0.3ms cubic-bezier(0.455,0.03,0.515,0.955); + transition: all 0.3ms cubic-bezier(0.455,0.03,0.515,0.955); } .nav--inverted .c4 { @@ -176,6 +195,14 @@ exports[`NavBar renders fixed 1`] = ` font-weight: 400; } +.c4.nav-button--last { + padding-right: 16px; +} + +.c4.nav-button--first { + padding-left: 16px; +} + .c3 { padding-left: 8px; padding-right: 8px; @@ -191,6 +218,9 @@ exports[`NavBar renders fixed 1`] = ` background-color: transparent; color: rgba(255,255,255,1); font-weight: 600; + border-bottom: 1px solid transparent; + -webkit-transition: all 300ms cubic-bezier(0.455,0.03,0.515,0.955); + transition: all 300ms cubic-bezier(0.455,0.03,0.515,0.955); } .c0.nav--relative { @@ -205,19 +235,9 @@ exports[`NavBar renders fixed 1`] = ` position: fixed; } -.c0 .linkItem:visited { - color: rgba(255,255,255,1); -} - .c0.nav--inverted { background-color: rgba(255,255,255,1); border-bottom: 1px solid #D1D1D1; - color: rgba(38,38,38,1); - font-weight: 400; -} - -.c0.nav--inverted .linkItem:visited { - color: rgba(38,38,38,1); } .c0.nav--overlay:after { @@ -232,16 +252,6 @@ exports[`NavBar renders fixed 1`] = ` background-image: linear-gradient(77deg,rgba(0,0,0,0),#000000); } -.c0.nav--fade-in { - -webkit-animation: fadeIn 0.3s ease-in-out; - animation: fadeIn 0.3s ease-in-out; -} - -.c0.nav--fade-out { - -webkit-animation: fadeOut 0.3s ease-in-out; - animation: fadeOut 0.3s ease-in-out; -} - .c1 { width: 100%; height: 60px; @@ -266,6 +276,14 @@ exports[`NavBar renders fixed 1`] = ` @media screen and (min-width:480px) { .c2 { padding-right: 12px; + padding-left: 12px; + } + + .c2.nav-button--last { + padding-right: 24px; + } + + .c2.nav-button--first { padding-left: 24px; } } @@ -275,6 +293,14 @@ exports[`NavBar renders fixed 1`] = ` padding-right: 12px; padding-left: 12px; } + + .c4.nav-button--last { + padding-right: 24px; + } + + .c4.nav-button--first { + padding-left: 24px; + } } @media screen and (min-width:480px) { @@ -308,14 +334,14 @@ exports[`NavBar renders fixed 1`] = ` } } -@media (min-width:1440px) { +@media screen and (min-width:1440px) { .c1 { padding: 0 44px; } }