diff --git a/src/components/atoms/core/HTMLElements/index.js b/src/components/atoms/core/HTMLElements/index.js index a98b5238..83fd75fd 100644 --- a/src/components/atoms/core/HTMLElements/index.js +++ b/src/components/atoms/core/HTMLElements/index.js @@ -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 }; diff --git a/src/components/atoms/core/HTMLElements/sectioning/Heading.jsx b/src/components/atoms/core/HTMLElements/sectioning/Heading.jsx new file mode 100644 index 00000000..38357001 --- /dev/null +++ b/src/components/atoms/core/HTMLElements/sectioning/Heading.jsx @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2018-present Arctic Ice Studio + * Copyright (C) 2018-present Sven Greb + * + * Project: Nord Docs + * Repository: https://github.com/arcticicestudio/nord-docs + * License: MIT + */ + +/** + * @author Arctic Ice Studio + * @author Sven Greb + * @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 }; diff --git a/src/components/atoms/core/HTMLElements/sectioning/index.js b/src/components/atoms/core/HTMLElements/sectioning/index.js new file mode 100644 index 00000000..a5cae36b --- /dev/null +++ b/src/components/atoms/core/HTMLElements/sectioning/index.js @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2018-present Arctic Ice Studio + * Copyright (C) 2018-present Sven Greb + * + * 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 + * @author Sven Greb + * @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 }; diff --git a/src/components/atoms/core/HTMLElements/text-content/P.jsx b/src/components/atoms/core/HTMLElements/text/P.jsx similarity index 100% rename from src/components/atoms/core/HTMLElements/text-content/P.jsx rename to src/components/atoms/core/HTMLElements/text/P.jsx diff --git a/src/components/atoms/core/HTMLElements/text-content/index.js b/src/components/atoms/core/HTMLElements/text/index.js similarity index 100% rename from src/components/atoms/core/HTMLElements/text-content/index.js rename to src/components/atoms/core/HTMLElements/text/index.js diff --git a/test/components/atoms/core/HTMLElements/sectioning/Heading.test.jsx b/test/components/atoms/core/HTMLElements/sectioning/Heading.test.jsx new file mode 100644 index 00000000..18cf4111 --- /dev/null +++ b/test/components/atoms/core/HTMLElements/sectioning/Heading.test.jsx @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2018-present Arctic Ice Studio + * Copyright (C) 2018-present Sven Greb + * + * 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( + +

Heading Level 1

+

Heading Level 2

+

Heading Level 3

+

Heading Level 4

+
Heading Level 5
+
Heading Level 6
+
+ ); + expect(container).toMatchSnapshot(); + }); + + test("matches the snapshot with adjusted margin", () => { + const { container } = renderWithTheme( + +

Heading Level 1

+

Heading Level 2

+

Heading Level 3

+

Heading Level 4

+
Heading Level 5
+
Heading Level 6
+
+ ); + expect(container).toMatchSnapshot(); + }); + + test("has explicit font size definitions", () => { + const { container } = renderWithTheme( + +

Heading Level 1

+

Heading Level 2

+

Heading Level 3

+

Heading Level 4

+
Heading Level 5
+
Heading Level 6
+
+ ); + 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(

Nord

); + expect(container.firstChild).toHaveStyleRule("margin-top", "0"); + }); + + test("adjusts bottom margin based on passed props", () => { + const { container } = renderWithTheme(

Nord

); + expect(container.firstChild).toHaveStyleRule("margin-bottom", "0"); + }); + + test("Ensure descending font sizes between all heading levels", () => { + const { container } = renderWithTheme( + +

Heading Level 1

+

Heading Level 2

+

Heading Level 3

+

Heading Level 4

+
Heading Level 5
+
Heading Level 6
+
+ ); + + 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); + }); +}); diff --git a/test/components/atoms/core/HTMLElements/sectioning/__snapshots__/Heading.test.jsx.snap b/test/components/atoms/core/HTMLElements/sectioning/__snapshots__/Heading.test.jsx.snap new file mode 100644 index 00000000..d7582830 --- /dev/null +++ b/test/components/atoms/core/HTMLElements/sectioning/__snapshots__/Heading.test.jsx.snap @@ -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; +} + +
+

+ Heading Level 1 +

+

+ Heading Level 2 +

+

+ Heading Level 3 +

+

+ Heading Level 4 +

+
+ Heading Level 5 +
+
+ Heading Level 6 +
+
+`; + +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; +} + +
+

+ Heading Level 1 +

+

+ Heading Level 2 +

+

+ Heading Level 3 +

+

+ Heading Level 4 +

+
+ Heading Level 5 +
+
+ Heading Level 6 +
+
+`; diff --git a/test/components/atoms/core/HTMLElements/text-content/P.test.jsx b/test/components/atoms/core/HTMLElements/text/P.test.jsx similarity index 100% rename from test/components/atoms/core/HTMLElements/text-content/P.test.jsx rename to test/components/atoms/core/HTMLElements/text/P.test.jsx diff --git a/test/components/atoms/core/HTMLElements/text-content/__snapshots__/P.test.jsx.snap b/test/components/atoms/core/HTMLElements/text/__snapshots__/P.test.jsx.snap similarity index 100% rename from test/components/atoms/core/HTMLElements/text-content/__snapshots__/P.test.jsx.snap rename to test/components/atoms/core/HTMLElements/text/__snapshots__/P.test.jsx.snap