Repository: marigold-ui/marigold
Pull request #2012 (2022-04-19 09:05:23)

feat: Header component

changeset-bot[bot]: ###  ⚠️  No Changeset found

Latest commit: 6c7d8979a4620eb250b2a47afe4a44fbb3a5a722

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. **If these changes should result in a version bump, you need to add a changeset.**

<details><summary>This PR includes no changesets</summary>

  When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

</details>

[Click here to learn what changesets are, and how to add one](https://github.com/changesets/changesets/blob/master/docs/adding-a-changeset.md).

[Click here if you're a maintainer who wants to add a changeset to this PR](https://github.com/marigold-ui/marigold/new/header-component?filename=.changeset/slow-bees-taste.md&value=---%0A%22%40marigold%2Fdocs%22%3A%20patch%0A%22%40marigold%2Fcomponents%22%3A%20patch%0A---%0A%0Afeat%3A%20Header%20component%0A)



Patch:
diff --git a/.changeset/slow-bees-taste.md b/.changeset/slow-bees-taste.md
new file mode 100644
index 000000000..0e8da8a87
--- /dev/null
+++ b/.changeset/slow-bees-taste.md
@@ -0,0 +1,6 @@
+---
+"@marigold/docs": patch
+"@marigold/components": patch
+---
+
+feat: Header component
diff --git a/docs/content/components/header.mdx b/docs/content/components/header.mdx
new file mode 100644
index 000000000..1a62e8d44
--- /dev/null
+++ b/docs/content/components/header.mdx
@@ -0,0 +1,33 @@
+---
+title: Header
+---
+
+# Header
+
+## Description
+
+The `Header` component is used to help structure content components. It's used like the HTML `<header>` tag.
+
+<MarigoldTheme>
+  <Header>This is a Header!</Header>
+</MarigoldTheme>
+
+```tsx onlyCode
+import { Header } from '@marigold/components';
+```
+
+## Props
+
+| Name      | Type     | Default | Description                          |
+| :-------- | :------- | :------ | :----------------------------------- |
+| `variant` | `string` |         | Use a different _variant_ from theme |
+| `size`    | `string` |         | Use a different _size_ from theme    |
+
+## Examples
+
+```tsx
+<Header>
+  <Headline level="3">Header!</Headline>
+  <Text>awesome</Text>
+</Header>
+```
diff --git a/packages/components/src/Header/Header.stories.tsx b/packages/components/src/Header/Header.stories.tsx
new file mode 100644
index 000000000..74a325aa2
--- /dev/null
+++ b/packages/components/src/Header/Header.stories.tsx
@@ -0,0 +1,28 @@
+import React from 'react';
+import type { Meta, ComponentStory } from '@storybook/react';
+import { Container } from '../Container';
+import { Header } from './Header';
+
+export default {
+  title: 'Components/Header',
+  argTypes: {
+    variant: {
+      control: {
+        type: 'text',
+      },
+      description: 'The variant of the header',
+    },
+    size: {
+      control: {
+        type: 'text',
+      },
+      description: 'The size of the header',
+    },
+  },
+} as Meta;
+
+export const Basic: ComponentStory<typeof Header> = args => (
+  <Container contentType="content" size="medium">
+    <Header {...args}>Awsome Header</Header>
+  </Container>
+);
diff --git a/packages/components/src/Header/Header.tsx b/packages/components/src/Header/Header.tsx
new file mode 100644
index 000000000..114f7b199
--- /dev/null
+++ b/packages/components/src/Header/Header.tsx
@@ -0,0 +1,31 @@
+import React, { ReactNode } from 'react';
+import {
+  ThemeComponentProps,
+  ThemeExtension,
+  useComponentStyles,
+} from '@marigold/system';
+import { Box } from '../Box';
+import { ComponentProps } from '@marigold/types';
+
+// Theme Extension
+// ---------------
+export interface HeaderThemeExtension extends ThemeExtension<'Header'> {}
+
+// Props
+// ---------------
+export interface HeaderProps
+  extends ThemeComponentProps,
+    ComponentProps<'header'> {
+  children?: ReactNode;
+}
+
+// Component
+// ---------------
+export const Header = ({ children, variant, size, ...props }: HeaderProps) => {
+  const styles = useComponentStyles('Header', { variant, size });
+  return (
+    <Box as="header" {...props} css={styles}>
+      {children}
+    </Box>
+  );
+};
diff --git a/packages/components/src/Header/index.ts b/packages/components/src/Header/index.ts
new file mode 100644
index 000000000..266dec8a1
--- /dev/null
+++ b/packages/components/src/Header/index.ts
@@ -0,0 +1,1 @@
+export * from './Header';
diff --git a/packages/components/src/index.ts b/packages/components/src/index.ts
index ddfcf467f..70edc836d 100644
--- a/packages/components/src/index.ts
+++ b/packages/components/src/index.ts
@@ -15,6 +15,7 @@ export * from './Dialog';
 export * from './Divider';
 export * from './Footer';
 export * from './VisuallyHidden';
+export * from './Header';
 export * from './Headline';
 export * from './Image';
 export * from './Inline';
diff --git a/packages/components/src/theme.ts b/packages/components/src/theme.ts
index a95bceb28..9c53ad21c 100644
--- a/packages/components/src/theme.ts
+++ b/packages/components/src/theme.ts
@@ -12,6 +12,7 @@ import type { CheckboxThemeExtension } from './Checkbox';
 import type { ContentThemeExtension } from './Content';
 import type { DividerThemeExtension } from './Divider';
 import type { FooterThemeExtension } from './Footer';
+import type { HeaderThemeExtension } from './Header';
 import type { HeadlineThemeExtension } from './Headline';
 import type { HelpTextThemeExtension } from './Field/HelpText';
 import type { ImageThemeExtension } from './Image';
@@ -41,6 +42,7 @@ interface ComponentStyles
     ContentThemeExtension,
     DividerThemeExtension,
     FooterThemeExtension,
+    HeaderThemeExtension,
     HeadlineThemeExtension,
     HelpTextThemeExtension,
     ImageThemeExtension,


Test patch:
diff --git a/packages/components/src/Header/Header.test.tsx b/packages/components/src/Header/Header.test.tsx
new file mode 100644
index 000000000..fcf2d3743
--- /dev/null
+++ b/packages/components/src/Header/Header.test.tsx
@@ -0,0 +1,68 @@
+import React from 'react';
+import { render, screen } from '@testing-library/react';
+import { ThemeProvider } from '@marigold/system';
+
+import { Header } from './Header';
+
+const theme = {
+  space: {
+    none: 0,
+    'small-1': 4,
+    'medium-1': 16,
+  },
+  colors: {
+    grey: '#dee2e6',
+    yellow: '#fff9db',
+  },
+  components: {
+    Header: {
+      base: {
+        p: 'small-1',
+        border: '1px solid',
+        borderColor: 'grey',
+      },
+      variant: {
+        yellow: {
+          bg: 'yellow',
+        },
+      },
+      size: {
+        medium: {
+          p: 'medium-1',
+        },
+      },
+    },
+  },
+};
+
+test('renders as a "header" element', () => {
+  render(
+    <ThemeProvider theme={theme}>
+      <Header data-testid="header" />
+    </ThemeProvider>
+  );
+
+  const header = screen.getByTestId('header');
+  expect(header.tagName).toEqual('HEADER');
+});
+
+test('uses base styling form "header" in theme', () => {
+  render(
+    <ThemeProvider theme={theme}>
+      <Header data-testid="header" />
+    </ThemeProvider>
+  );
+  const header = screen.getByTestId('header');
+  expect(header).toHaveStyle(`padding: ${theme.space['small-1']}px`);
+});
+
+test('header accepts a variant and size', () => {
+  render(
+    <ThemeProvider theme={theme}>
+      <Header data-testid="header" variant="yellow" size="medium" />
+    </ThemeProvider>
+  );
+  const header = screen.getByTestId('header');
+  expect(header).toHaveStyle(`background: ${theme.colors.yellow}`);
+  expect(header).toHaveStyle(`padding: ${theme.space['medium-1']}px`);
+});