Skip to content

Commit

Permalink
Add Section and Header components, and height prop to Container
Browse files Browse the repository at this point in the history
  • Loading branch information
moroshko committed Jan 15, 2020
1 parent bc077b9 commit 6acff0b
Show file tree
Hide file tree
Showing 52 changed files with 590 additions and 158 deletions.
30 changes: 26 additions & 4 deletions src/components/Container.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@ import useTheme from "../hooks/useTheme";
import { ContainerProvider } from "../hooks/useContainer";
import {
responsiveMarginType,
responsivePaddingType
responsivePaddingType,
responsiveHeightType
} from "../hooks/useResponsiveProp";
import useResponsivePropsCSS from "../hooks/useResponsivePropsCSS";
import {
responsiveMargin,
responsivePadding,
responsiveHeight,
mergeResponsiveCSS
} from "../utils/css";
import tokens from "../themes/tokens";

export const BACKGROUNDS = [
"white",
Expand All @@ -21,17 +24,20 @@ export const BACKGROUNDS = [
"primary.blue.t100"
];

export const BOX_SHADOWS = ["header"];

export const DEFAULT_PROPS = {
hasBreakpointWidth: false
};

function Container(_props) {
const props = { ...DEFAULT_PROPS, ..._props };
const { bg, hasBreakpointWidth, children } = props;
const { bg, boxShadow, hasBreakpointWidth, children } = props;
const theme = useTheme();
const responsivePropsCSS = useResponsivePropsCSS(props, {
margin: responsiveMargin,
padding: responsivePadding
padding: responsivePadding,
height: responsiveHeight
});
const responsiveCSS = hasBreakpointWidth
? mergeResponsiveCSS(
Expand All @@ -57,14 +63,28 @@ function Container(_props) {
responsivePropsCSS
)
: responsivePropsCSS;
const boxShadowCSS =
boxShadow === "header"
? {
"::after": {
content: "''",
display: "block",
height: tokens.borderWidths[1],
boxShadow: tokens.shadows.header
}
}
: {
boxShadow: tokens.shadows[boxShadow] || null
};

return (
<ContainerProvider value={{ bg }}>
<div
css={{
boxSizing: "border-box",
backgroundColor: theme.getColor(bg),
...responsiveCSS
...responsiveCSS,
...boxShadowCSS
}}
>
{children}
Expand All @@ -75,8 +95,10 @@ function Container(_props) {

Container.propTypes = {
bg: PropTypes.oneOf(BACKGROUNDS),
boxShadow: PropTypes.oneOf(BOX_SHADOWS),
...responsiveMarginType,
...responsivePaddingType,
...responsiveHeightType,
hasBreakpointWidth: PropTypes.bool,
children: PropTypes.node
};
Expand Down
36 changes: 20 additions & 16 deletions src/components/Footer.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,36 @@ import Container from "./Container";
import Text from "./Text";
import Link from "./Link";
import useTheme from "../hooks/useTheme";
import LatitudeLogo from "../logos/latitude";
import GemLogo from "../logos/gem";
import Logo, { NAMES as LOGO_NAMES } from "./internal/Logo";
import tokens from "../themes/tokens";

const LOGO_NAMES = ["latitude", "gem"];

function HeaderLogo({ name = "latitude" }) {
switch (name) {
case "gem":
return <GemLogo />;
function HeaderLogo({ name }) {
const theme = useTheme();

case "latitude":
default:
return <LatitudeLogo />;
}
const css = {
display: "flex",
alignItems: "center",
height: tokens.sizes[15],
[theme.minMediaQueries.lg]: {
height: tokens.sizes[14]
}
};
return (
<div css={css}>
<Logo name={name} color="white" />
</div>
);
}

HeaderLogo.propTypes = {
name: PropTypes.oneOf(LOGO_NAMES)
name: PropTypes.oneOf(LOGO_NAMES).isRequired
};

function Header({ children }) {
return (
<Container bg="primary.blue.t100">
<Container bg="primary.blue.t100" padding="6 0" hasBreakpointWidth={true}>
{children}
<Container bg="primary.blue.t100" hasBreakpointWidth={true}>
<div css={{ display: "flex", alignItems: "center" }}>{children}</div>
</Container>
</Container>
);
Expand Down Expand Up @@ -112,7 +116,7 @@ Legal.propTypes = {
};

function Footer({ children }) {
return children;
return <footer>{children}</footer>;
}

Footer.propTypes = {
Expand Down
36 changes: 36 additions & 0 deletions src/components/Header.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React from "react";
import PropTypes from "prop-types";
import Container from "./Container";
import Logo, { NAMES as LOGO_NAMES } from "./internal/Logo";

function HeaderLogo({ name }) {
return (
<Logo name={name} color="primary.blue.t100" height="5" height-xs="7" />
);
}

HeaderLogo.propTypes = {
name: PropTypes.oneOf(LOGO_NAMES).isRequired
};

function Header({ children }) {
return (
<header>
<Container bg="white" height="10" height-lg="13" boxShadow="header">
<Container hasBreakpointWidth={true} height="100%">
<div css={{ display: "flex", height: "100%", alignItems: "center" }}>
{children}
</div>
</Container>
</Container>
</header>
);
}

Header.propTypes = {
children: PropTypes.node.isRequired
};

Header.Logo = HeaderLogo;

export default Header;
37 changes: 37 additions & 0 deletions src/components/Section.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React from "react";
import PropTypes from "prop-types";
import Container, { BACKGROUNDS as CONTAINER_BACKGROUNDS } from "./Container";
import Grid from "./Grid";
import { responsivePaddingType } from "../hooks/useResponsiveProp";
import useAllResponsiveProps from "../hooks/useAllResponsiveProps";

export const BACKGROUNDS = CONTAINER_BACKGROUNDS;

export const DEFAULT_PROPS = {
debug: false
};

function Section(_props) {
const props = { ...DEFAULT_PROPS, ..._props };
const { bg, debug, children } = props;
const paddingProps = useAllResponsiveProps(props, "padding");

return (
<Container bg={bg} {...paddingProps}>
<Container hasBreakpointWidth>
<Grid cols={4} cols-sm={8} cols-lg={12} colsGutter="30px" debug={debug}>
{children}
</Grid>
</Container>
</Container>
);
}

Section.propTypes = {
bg: PropTypes.oneOf(BACKGROUNDS),
...responsivePaddingType,
debug: PropTypes.bool,
children: PropTypes.node
};

export default Section;
43 changes: 43 additions & 0 deletions src/components/internal/Logo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React from "react";
import PropTypes from "prop-types";
import LatitudeLogo from "../../logos/latitude";
import GemLogo from "../../logos/gem";
import { responsiveHeightType } from "../../hooks/useResponsiveProp";
import useAllResponsiveProps from "../../hooks/useAllResponsiveProps";

export const NAMES = ["latitude", "gem"];
export const COLORS = ["primary.blue.t100", "black", "white"];

export const DEFAULT_PROPS = {};

function Logo(_props) {
const props = { ...DEFAULT_PROPS, ..._props };
const { name, color } = props;
const heightProps = useAllResponsiveProps(props, "height");
const logoProps = {
color,
...heightProps
};

switch (name) {
case "latitude": {
return <LatitudeLogo {...logoProps} />;
}

case "gem": {
return <GemLogo {...logoProps} />;
}

default: {
return null;
}
}
}

Logo.propTypes = {
name: PropTypes.oneOf(NAMES).isRequired,
color: PropTypes.oneOf(COLORS).isRequired,
...responsiveHeightType
};

export default Logo;
36 changes: 36 additions & 0 deletions src/hooks/useAllResponsiveProps.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import useTheme from "./useTheme";
import { getPropName } from "./useResponsiveProp";

function useAllResponsiveProps(props, propName) {
const theme = useTheme();
const breakpoints = Object.keys(theme.breakpoints);
const result = {};

/*
ESLint complains about:
props.hasOwnProperty[prop]
See: https://eslint.org/docs/rules/no-prototype-builtins
*/
if (Object.prototype.hasOwnProperty.call(props, propName)) {
result[propName] = props[propName];
}

breakpoints.forEach(bp => {
const prop = getPropName(propName, bp);

/*
ESLint complains about:
props.hasOwnProperty[prop]
See: https://eslint.org/docs/rules/no-prototype-builtins
*/
if (Object.prototype.hasOwnProperty.call(props, prop)) {
result[prop] = props[prop];
}
});

return result;
}

export default useAllResponsiveProps;
47 changes: 47 additions & 0 deletions src/hooks/useAllResponsiveProps.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { renderHook } from "@testing-library/react-hooks";
import useAllResponsiveProps from "./useAllResponsiveProps";
import { TestWrapper } from "../utils/test";

describe("useAllResponsiveProps", () => {
it("collects all the responsive props", () => {
const props = {
padding: "4",
"padding-xs": 5,
"padding-sm": "0",
"padding-md": "6",
"padding-lg": "1 2 3",
"padding-xl": "0 8",
anotherProp: "some value"
};
const { result } = renderHook(
() => useAllResponsiveProps(props, "padding"),
{ wrapper: TestWrapper }
);

expect(result.current).toStrictEqual({
padding: "4",
"padding-xs": 5,
"padding-sm": "0",
"padding-md": "6",
"padding-lg": "1 2 3",
"padding-xl": "0 8"
});
});

it("drops responsive props that do not exist", () => {
const props = {
"padding-xs": 5,
"padding-md": "6",
anotherProp: "some value"
};
const { result } = renderHook(
() => useAllResponsiveProps(props, "padding"),
{ wrapper: TestWrapper }
);

expect(result.current).toStrictEqual({
"padding-xs": 5,
"padding-md": "6"
});
});
});
7 changes: 6 additions & 1 deletion src/hooks/useResponsiveProp.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import useBreakpoint from "./useBreakpoint";
import defaultTheme from "../themes/default";
import { DEFAULT_BREAKPOINT } from "../utils/css";

function getPropName(name, breakpoint) {
export function getPropName(name, breakpoint) {
return `${name}-${breakpoint}`;
}

Expand Down Expand Up @@ -38,6 +38,11 @@ export const responsivePaddingType = responsivePropType(
PropTypes.oneOfType([PropTypes.number, PropTypes.string])
);

export const responsiveHeightType = responsivePropType(
"height",
PropTypes.oneOfType([PropTypes.number, PropTypes.string])
);

function useResponsiveProp(props, propName) {
const theme = useTheme();
const breakpoint = useBreakpoint();
Expand Down
Loading

0 comments on commit 6acff0b

Please sign in to comment.