Skip to content

Commit

Permalink
Implement core atom HTML element component Heading
Browse files Browse the repository at this point in the history
This commit implements the core atom(s) `H1`-`H6` which represent the
content sectioning (1) HTML element `<h1>`-`<h6>` (2).

It uses custom styles instead of browser defaults and allows to disable
the bottom margin via the `noMargin` prop. The font styles like size,
modular scale and family adhere to the "Typography" design concept (3).

References:
  (1) https://developer.mozilla.org/en-US/docs/Web/HTML/Element#Content_sectioning
  (2) https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements
  (3) #2

Associated epics: GH-69, GH-2
GH-81
  • Loading branch information
arcticicestudio committed Dec 17, 2018
1 parent ad995b0 commit 0d629ca
Show file tree
Hide file tree
Showing 9 changed files with 373 additions and 2 deletions.
5 changes: 3 additions & 2 deletions src/components/atoms/core/HTMLElements/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
*/

import { A } from "./inline-text-semantics";
import { P } from "./text-content";
import { H1, H2, H3, H4, H5, H6 } from "./sectioning";
import { P } from "./text";

export { A, P };
export { A, H1, H2, H3, H4, H5, H6, P };
102 changes: 102 additions & 0 deletions src/components/atoms/core/HTMLElements/sectioning/Heading.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*
* Copyright (C) 2018-present Arctic Ice Studio <[email protected]>
* Copyright (C) 2018-present Sven Greb <[email protected]>
*
* Project: Nord Docs
* Repository: https://github.com/arcticicestudio/nord-docs
* License: MIT
*/

/**
* @author Arctic Ice Studio <[email protected]>
* @author Sven Greb <[email protected]>
* @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements
* @since 0.3.0
*/

import PropTypes from "prop-types";
import styled, { css } from "styled-components";

import { ms } from "styles/theme";

const baseHeadingStyles = css`
margin-top: 0;
margin-bottom: ${({ noMargin }) => (noMargin ? 0 : "0.5rem")};
font-weight: 500;
`;

/**
* A base HTML component that represents a level 1 section heading.
*/
const H1 = styled.h1`
${baseHeadingStyles};
font-size: ${ms(6)};
`;

/**
* A base HTML component that represents a level 2 section heading.
*/
const H2 = styled.h2`
${baseHeadingStyles};
font-size: ${ms(5)};
`;

/**
* A base HTML component that represents a level 3 section heading.
*/
const H3 = styled.h3`
${baseHeadingStyles};
font-size: ${ms(4)};
`;

/**
* A base HTML component that represents a level 4 section heading.
*/
const H4 = styled.h4`
${baseHeadingStyles};
font-size: ${ms(3)};
`;

/**
* A base HTML component that represents a level 5 section heading.
*/
const H5 = styled.h5`
${baseHeadingStyles};
font-size: ${ms(2)};
`;

/**
* A base HTML component that represents a level 6 section heading.
*/
const H6 = styled.h6`
${baseHeadingStyles};
font-size: ${ms(1)};
`;

const propTypes = {
hasBottomMargin: PropTypes.bool
};

const defaultProps = {
hasBottomMargin: false
};

H1.propTypes = propTypes;
H1.defaultProps = defaultProps;

H2.propTypes = propTypes;
H2.defaultProps = defaultProps;

H3.propTypes = propTypes;
H3.defaultProps = defaultProps;

H4.propTypes = propTypes;
H4.defaultProps = defaultProps;

H5.propTypes = propTypes;
H5.defaultProps = defaultProps;

H6.propTypes = propTypes;
H6.defaultProps = defaultProps;

export { H1, H2, H3, H4, H5, H6 };
20 changes: 20 additions & 0 deletions src/components/atoms/core/HTMLElements/sectioning/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Copyright (C) 2018-present Arctic Ice Studio <[email protected]>
* Copyright (C) 2018-present Sven Greb <[email protected]>
*
* Project: Nord Docs
* Repository: https://github.com/arcticicestudio/nord-docs
* License: MIT
*/

/**
* @file Provides components that represent basic HTML elements with content sectioning functionality.
* @author Arctic Ice Studio <[email protected]>
* @author Sven Greb <[email protected]>
* @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element#Content_sectioning
* @since 0.3.0
*/

import { H1, H2, H3, H4, H5, H6 } from "./Heading";

export { H1, H2, H3, H4, H5, H6 };
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*
* Copyright (C) 2018-present Arctic Ice Studio <[email protected]>
* Copyright (C) 2018-present Sven Greb <[email protected]>
*
* Project: Nord Docs
* Repository: https://github.com/arcticicestudio/nord-docs
* License: MIT
*/

import React, { Fragment } from "react";
import { stripUnit } from "polished";

import { renderWithTheme } from "nord-docs-test-utils";
import { H1, H2, H3, H4, H5, H6 } from "atoms/core/HTMLElements";

describe("theme styles", () => {
test("matches the snapshot", () => {
const { container } = renderWithTheme(
<Fragment>
<H1>Heading Level 1</H1>
<H2>Heading Level 2</H2>
<H3>Heading Level 3</H3>
<H4>Heading Level 4</H4>
<H5>Heading Level 5</H5>
<H6>Heading Level 6</H6>
</Fragment>
);
expect(container).toMatchSnapshot();
});

test("matches the snapshot with adjusted margin", () => {
const { container } = renderWithTheme(
<Fragment>
<H1 noMargin>Heading Level 1</H1>
<H2 noMargin>Heading Level 2</H2>
<H3 noMargin>Heading Level 3</H3>
<H4 noMargin>Heading Level 4</H4>
<H5 noMargin>Heading Level 5</H5>
<H6 noMargin>Heading Level 6</H6>
</Fragment>
);
expect(container).toMatchSnapshot();
});

test("has explicit font size definitions", () => {
const { container } = renderWithTheme(
<Fragment>
<H1 noMargin>Heading Level 1</H1>
<H2 noMargin>Heading Level 2</H2>
<H3 noMargin>Heading Level 3</H3>
<H4 noMargin>Heading Level 4</H4>
<H5 noMargin>Heading Level 5</H5>
<H6 noMargin>Heading Level 6</H6>
</Fragment>
);
expect(
Object.values(container.children)
.map(headingElement => getComputedStyle(headingElement).fontSize)
.filter(Boolean).length
).toEqual(container.children.length);
});

test("has no top margin", () => {
const { container } = renderWithTheme(<H1>Nord</H1>);
expect(container.firstChild).toHaveStyleRule("margin-top", "0");
});

test("adjusts bottom margin based on passed props", () => {
const { container } = renderWithTheme(<H1 noMargin>Nord</H1>);
expect(container.firstChild).toHaveStyleRule("margin-bottom", "0");
});

test("Ensure descending font sizes between all heading levels", () => {
const { container } = renderWithTheme(
<Fragment>
<H1 noMargin>Heading Level 1</H1>
<H2 noMargin>Heading Level 2</H2>
<H3 noMargin>Heading Level 3</H3>
<H4 noMargin>Heading Level 4</H4>
<H5 noMargin>Heading Level 5</H5>
<H6 noMargin>Heading Level 6</H6>
</Fragment>
);

expect(
/* Get the font sizes as numbers of all heading components in rendered order. */
Object.values(container.children)
.map(headingElement => stripUnit(getComputedStyle(headingElement).fontSize))
/* Ensure descending font sizes by comparing a higher level heading with the next lower one. */
.reduce((acc, cur) => (acc > cur ? cur : 0))
).toBeGreaterThan(0);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`theme styles matches the snapshot 1`] = `
.c0 {
margin-top: 0;
margin-bottom: 0.5rem;
font-weight: 500;
font-size: 2.0272865295410156em;
}
.c1 {
margin-top: 0;
margin-bottom: 0.5rem;
font-weight: 500;
font-size: 1.802032470703125em;
}
.c2 {
margin-top: 0;
margin-bottom: 0.5rem;
font-weight: 500;
font-size: 1.601806640625em;
}
.c3 {
margin-top: 0;
margin-bottom: 0.5rem;
font-weight: 500;
font-size: 1.423828125em;
}
.c4 {
margin-top: 0;
margin-bottom: 0.5rem;
font-weight: 500;
font-size: 1.265625em;
}
.c5 {
margin-top: 0;
margin-bottom: 0.5rem;
font-weight: 500;
font-size: 1.125em;
}
<div>
<h1
class="c0"
>
Heading Level 1
</h1>
<h2
class="c1"
>
Heading Level 2
</h2>
<h3
class="c2"
>
Heading Level 3
</h3>
<h4
class="c3"
>
Heading Level 4
</h4>
<h5
class="c4"
>
Heading Level 5
</h5>
<h6
class="c5"
>
Heading Level 6
</h6>
</div>
`;

exports[`theme styles matches the snapshot with adjusted margin 1`] = `
.c0 {
margin-top: 0;
margin-bottom: 0;
font-weight: 500;
font-size: 2.0272865295410156em;
}
.c1 {
margin-top: 0;
margin-bottom: 0;
font-weight: 500;
font-size: 1.802032470703125em;
}
.c2 {
margin-top: 0;
margin-bottom: 0;
font-weight: 500;
font-size: 1.601806640625em;
}
.c3 {
margin-top: 0;
margin-bottom: 0;
font-weight: 500;
font-size: 1.423828125em;
}
.c4 {
margin-top: 0;
margin-bottom: 0;
font-weight: 500;
font-size: 1.265625em;
}
.c5 {
margin-top: 0;
margin-bottom: 0;
font-weight: 500;
font-size: 1.125em;
}
<div>
<h1
class="c0"
>
Heading Level 1
</h1>
<h2
class="c1"
>
Heading Level 2
</h2>
<h3
class="c2"
>
Heading Level 3
</h3>
<h4
class="c3"
>
Heading Level 4
</h4>
<h5
class="c4"
>
Heading Level 5
</h5>
<h6
class="c5"
>
Heading Level 6
</h6>
</div>
`;

0 comments on commit 0d629ca

Please sign in to comment.