Repository: marigold-ui/marigold
Pull request #1868 (2022-03-15 10:44:06)

feat(comp): renew Container component
#1860 

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

Latest commit: abfea0755aae3817c37db17a891a46e7d9e23cff

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/improve-container?filename=.changeset/smooth-ligers-dream.md&value=---%0A%22%40marigold%2Fdocs%22%3A%20patch%0A%22%40marigold%2Fcomponents%22%3A%20patch%0A---%0A%0Afeat(comp)%3A%20renew%20Container%20component%0A)



Patch:
diff --git a/.changeset/loud-birds-bathe.md b/.changeset/loud-birds-bathe.md
new file mode 100644
index 000000000..4542a8c8a
--- /dev/null
+++ b/.changeset/loud-birds-bathe.md
@@ -0,0 +1,7 @@
+---
+"@marigold/theme-b2b": patch
+"@marigold/theme-core": patch
+"@marigold/theme-unicorn": patch
+---
+
+feat: add size scale to themes
diff --git a/.changeset/smooth-ligers-dream.md b/.changeset/smooth-ligers-dream.md
new file mode 100644
index 000000000..77a09b93f
--- /dev/null
+++ b/.changeset/smooth-ligers-dream.md
@@ -0,0 +1,6 @@
+---
+"@marigold/docs": minor
+"@marigold/components": minor
+---
+
+feat(comp): renew Container component
diff --git a/docs/content/components/container.mdx b/docs/content/components/container.mdx
index 8ba9e7fcc..d3b8dbce9 100644
--- a/docs/content/components/container.mdx
+++ b/docs/content/components/container.mdx
@@ -2,30 +2,139 @@
 title: Container
 ---
 
+import { Box, Container, Text } from '@marigold/components';
+
 # Container
 
 ## Description
 
-Primitive layout component to embed other elements.
+Containers width is based on used font and is optimized for readability. You can use `header`or `content`as content type and set the `maxWidth` to `small`, `medium` or `large`.
 
-## Import
+## Usage
 
 ```tsx onlyCode
 import { Container } from '@marigold/components';
 ```
 
-## Live-Code Example
+<Box
+  as={Container}
+  __baseCSS={{ border: '1px dashed gray', borderBottom: 'none' }}
+  p="xsmall"
+  contentType="header"
+>
+  <Text as="h5" variant="headline5">
+    Medium sized container header
+  </Text>
+</Box>
+<Box as={Container} border="1px dashed gray" p="xsmall" height="180px">
+  <Text>Medium sized container content</Text>
+</Box>
 
-```tsx expandCode
-<Container>
-  <Text>Example Container</Text>
+## Properties (API)
+
+| Property      | Type                   | Default   |
+| :------------ | :--------------------- | :-------- |
+| `contentType` | `content, header`      | `content` |
+| `size`        | `small, medium, large` | `medium`  |
+| `align`       | `left, center, right`  | `left`    |
+
+## Variants
+
+### Small header
+
+```tsx
+<Container contentType="header" size="small">
+  <Text as="h2" variant="headline2">
+    Star Wars - The Empire Strikes Back
+  </Text>
 </Container>
 ```
 
-## Usage
+### Medium header
+
+```tsx
+<Container contentType="header">
+  <Text as="h2" variant="headline2">
+    Star Wars - The Empire Strikes Back
+  </Text>
+</Container>
+```
+
+### Large header
+
+```tsx
+<Container contentType="header" size="large">
+  <Text as="h2" variant="headline2">
+    Star Wars - The Empire Strikes Back
+  </Text>
+</Container>
+```
+
+### Small content
+
+```tsx
+<Container size="small">
+  <Text>
+    It is a dark time for the Rebellion. Although the Death Star has been
+    destroyed, Imperial troops have driven the Rebel forces from their hidden
+    base and pursued them across the galaxy.
+  </Text>
+</Container>
+```
+
+### Medium content
 
 ```tsx
 <Container>
-  <Text>Example #1</Text>
+  <Text>
+    Evading the dreaded Imperial Starfleet, a group of freedom fighters led by
+    Luke Skywalker has established a new secret base on the remote ice world of
+    Hoth.
+  </Text>
 </Container>
 ```
+
+### Large content
+
+```tsx
+<Container size="large">
+  <Text>
+    The evil lord Darth Vader, obsessed with finding young Skywalker, has
+    dispatched thousands of remote probes into the far reaches of space....
+  </Text>
+</Container>
+```
+
+## Align content center
+
+In some cases, the width of the content can be smaller than the container's width. You can use the align prop to align the content left, center or right.
+
+```tsx
+<Box as={Container} bg="blue10" align="center" p="small">
+  <Text as="h2" variant="headline2">
+    Star Wars - The Empire Strikes Back
+  </Text>
+  <Box pt="xsmall" width="100%">
+    <Text>
+      It is a dark time for the Rebellion. Although the Death Star has been
+      destroyed, Imperial troops have driven the Rebel forces from their hidden
+      base and pursued them across the galaxy. Evading the dreaded Imperial
+      Starfleet, a group of freedom fighters led by Luke Skywalker has
+      established a new secret base on the remote ice world of Hoth. The evil
+      lord Darth Vader, obsessed with finding young Skywalker, has dispatched
+      thousands of remote probes into the far reaches of space....
+    </Text>
+  </Box>
+  <Box width="20ch">
+    <ul>
+      <li>Luke</li>
+      <li>Leia</li>
+      <li>Han Solo</li>
+      <li>Chewbacca</li>
+      <li>R2D2</li>
+      <li>C3PO</li>
+      <li>Darth Vader</li>
+    </ul>
+  </Box>
+</Box>
+```
diff --git a/packages/components/src/Container/Container.stories.tsx b/packages/components/src/Container/Container.stories.tsx
index e9568eac4..128138b33 100644
--- a/packages/components/src/Container/Container.stories.tsx
+++ b/packages/components/src/Container/Container.stories.tsx
@@ -1,14 +1,100 @@
 import React from 'react';
 import type { Meta, ComponentStory } from '@storybook/react';
+
+import { Box } from '../Box';
 import { Container } from './Container';
 import { Text } from '../Text';
 
 export default {
   title: 'Components/Container',
+  argTypes: {
+    contentType: {
+      control: {
+        type: 'select',
+      },
+      options: ['content', 'header'],
+      description: 'choose between content and header',
+      table: {
+        defaultValue: {
+          summary: 'content',
+        },
+      },
+    },
+    size: {
+      control: {
+        type: 'select',
+      },
+      options: ['small', 'medium', 'large'],
+      description: 'choose between small, medium and large size',
+      table: {
+        defaultValue: {
+          summary: 'medium',
+        },
+      },
+    },
+    align: {
+      control: {
+        type: 'select',
+      },
+      options: ['left', 'center', 'right'],
+      description: 'choose between left, center and right alignment',
+      table: {
+        defaultValue: {
+          summary: 'left',
+        },
+      },
+    },
+  },
 } as Meta;
 
-export const Basic: ComponentStory<typeof Container> = args => (
+export const Content: ComponentStory<typeof Container> = args => (
   <Container {...args}>
-    <Text>Container with width=100%</Text>
+    <Text>
+      It is a dark time for the Rebellion. Although the Death Star has been
+      destroyed, Imperial troops have driven the Rebel forces from their hidden
+      base and pursued them across the galaxy. Evading the dreaded Imperial
+      Starfleet, a group of freedom fighters led by Luke Skywalker has
+      established a new secret base on the remote ice world of Hoth. The evil
+      lord Darth Vader, obsessed with finding young Skywalker, has dispatched
+      thousands of remote probes into the far reaches of space....
+    </Text>
+  </Container>
+);
+
+export const Header: ComponentStory<typeof Container> = args => (
+  <Container contentType="header" {...args}>
+    <Text as="h2" variant="headline2">
+      Star Wars - The Empire Strikes Back
+    </Text>
   </Container>
 );
+
+export const InnerContent: ComponentStory<typeof Container> = args => (
+  <Box as={Container} bg="blue10" p="small" {...args}>
+    <Text as="h2" variant="headline2">
+      Star Wars - The Empire Strikes Back
+    </Text>
+    <Box pt="xsmall" width="100%">
+      <Text>
+        It is a dark time for the Rebellion. Although the Death Star has been
+        destroyed, Imperial troops have driven the Rebel forces from their
+        hidden base and pursued them across the galaxy. Evading the dreaded
+        Imperial Starfleet, a group of freedom fighters led by Luke Skywalker
+        has established a new secret base on the remote ice world of Hoth. The
+        evil lord Darth Vader, obsessed with finding young Skywalker, has
+        dispatched thousands of remote probes into the far reaches of space....
+      </Text>
+    </Box>
+    <Box width="20ch">
+      <ul>
+        <li>Luke</li>
+        <li>Leia</li>
+        <li>Han Solo</li>
+        <li>Chewbacca</li>
+        <li>R2D2</li>
+        <li>C3PO</li>
+        <li>Darth Vader</li>
+      </ul>
+    </Box>
+  </Box>
+);
diff --git a/packages/components/src/Container/Container.tsx b/packages/components/src/Container/Container.tsx
index 3f5b78e1f..25e60b737 100755
--- a/packages/components/src/Container/Container.tsx
+++ b/packages/components/src/Container/Container.tsx
@@ -1,12 +1,35 @@
 import React from 'react';
 import { ComponentProps } from '@marigold/types';
+import { size as tokenSize } from '@marigold/tokens';
 
 import { Box } from '../Box';
 
-export interface ContainerProps extends ComponentProps<'div'> {}
+export interface ContainerProps extends ComponentProps<'div'> {
+  contentType?: 'content' | 'header';
+  size?: keyof typeof tokenSize.content | keyof typeof tokenSize.header;
+  align?: 'left' | 'right' | 'center';
+}
 
-export const Container: React.FC<ContainerProps> = ({ children, ...props }) => (
-  <Box {...props} width="100%">
+const ALIGNMENT = {
+  left: 'flex-start',
+  center: 'center',
+  right: 'flex-end',
+};
+
+export const Container: React.FC<ContainerProps> = ({
+  contentType = 'content',
+  size = 'medium',
+  align = 'left',
+  children,
+  ...props
+}) => (
+  <Box
+    display="flex"
+    flexDirection="column"
+    maxWidth={tokenSize[contentType][size]}
+    alignItems={ALIGNMENT[align]}
+    {...props}
+  >
     {children}
   </Box>
 );
diff --git a/themes/theme-b2b/src/index.ts b/themes/theme-b2b/src/index.ts
index 7f66629c0..1c6212f76 100644
--- a/themes/theme-b2b/src/index.ts
+++ b/themes/theme-b2b/src/index.ts
@@ -14,6 +14,18 @@ const theme: Theme = {
     xlarge: 40,
     xxlarge: 48,
   },
+  sizes: {
+    none: 0,
+    xxsmall: 16,
+    xsmall: 32,
+    small: 40,
+    medium: 80,
+    large: 120,
+    xlarge: 160,
+    xxlarge: 240,
+    huge: 320,
+    epic: 480,
+  },
   colors: {
     ...colors,
     text: colors.gray70,
diff --git a/themes/theme-core/src/index.ts b/themes/theme-core/src/index.ts
index 2debeafbc..72f6b6c09 100644
--- a/themes/theme-core/src/index.ts
+++ b/themes/theme-core/src/index.ts
@@ -14,6 +14,18 @@ const theme: Theme = {
     xlarge: 40,
     xxlarge: 48,
   },
+  sizes: {
+    none: 0,
+    xxsmall: 16,
+    xsmall: 32,
+    small: 40,
+    medium: 80,
+    large: 120,
+    xlarge: 160,
+    xxlarge: 240,
+    huge: 320,
+    epic: 480,
+  },
   colors: {
     ...colors,
     text: '#511e04',
diff --git a/themes/theme-unicorn/src/index.ts b/themes/theme-unicorn/src/index.ts
index 53f4006ba..5a9dee089 100644
--- a/themes/theme-unicorn/src/index.ts
+++ b/themes/theme-unicorn/src/index.ts
@@ -14,6 +14,18 @@ const theme: Theme = {
     xlarge: 42,
     xxlarge: 64,
   },
+  sizes: {
+    none: 0,
+    xxsmall: 16,
+    xsmall: 32,
+    small: 40,
+    medium: 80,
+    large: 120,
+    xlarge: 160,
+    xxlarge: 240,
+    huge: 320,
+    epic: 480,
+  },
   colors: {
     ...colors,
     text: colors.gray90,


Test patch:
diff --git a/packages/components/src/Container/Container.test.tsx b/packages/components/src/Container/Container.test.tsx
index 7bb3b9829..72e3a4889 100644
--- a/packages/components/src/Container/Container.test.tsx
+++ b/packages/components/src/Container/Container.test.tsx
@@ -4,22 +4,102 @@ import { render, screen } from '@testing-library/react';
 import { Container } from './Container';
 import { Text } from '../Text';
 
-test('renders correct HTML element', () => {
+test('supports default contentType content', () => {
   render(
     <Container data-testid="container">
       <Text>sdf</Text>
     </Container>
   );
   const container = screen.getByTestId(/container/);
-  expect(container instanceof HTMLDivElement).toBeTruthy();
+  expect(container).toHaveStyle(`maxWidth: 45ch`);
+});
+
+test('supports contentType header', () => {
+  render(
+    <Container contentType="header" data-testid="container">
+      <Text>sdf</Text>
+    </Container>
+  );
+  const container = screen.getByTestId(/container/);
+  expect(container).toHaveStyle(`maxWidth: 25ch`);
 });
 
-test('has default width', () => {
+test('supports default size', () => {
   render(
     <Container data-testid="container">
-      <Text>text</Text>
+      <Text>sdf</Text>
+    </Container>
+  );
+  const container = screen.getByTestId(/container/);
+  expect(container).toHaveStyle(`maxWidth: 45ch`);
+});
+
+test('supports size small', () => {
+  render(
+    <Container size="small" data-testid="container">
+      <Text>sdf</Text>
+    </Container>
+  );
+  const container = screen.getByTestId(/container/);
+  expect(container).toHaveStyle(`maxWidth: 20ch`);
+});
+
+test('supports size large', () => {
+  render(
+    <Container size="large" data-testid="container">
+      <Text>sdf</Text>
     </Container>
   );
   const container = screen.getByTestId(/container/);
-  expect(container).toHaveStyle(`width: 100%`);
+  expect(container).toHaveStyle(`maxWidth: 60ch`);
+});
+
+test('supports size and contentType', () => {
+  render(
+    <Container size="large" contentType="header" data-testid="container">
+      <Text>sdf</Text>
+    </Container>
+  );
+  const container = screen.getByTestId(/container/);
+  expect(container).toHaveStyle(`maxWidth: 35ch`);
+});
+
+test('supports default align left', () => {
+  render(
+    <Container data-testid="container">
+      <Text>sdf</Text>
+    </Container>
+  );
+  const container = screen.getByTestId(/container/);
+  expect(container).toHaveStyle(`alignItems: flex-start`);
+});
+
+test('supports align center', () => {
+  render(
+    <Container align="center" data-testid="container">
+      <Text>sdf</Text>
+    </Container>
+  );
+  const container = screen.getByTestId(/container/);
+  expect(container).toHaveStyle(`alignItems: center`);
+});
+
+test('supports align right', () => {
+  render(
+    <Container align="right" data-testid="container">
+      <Text>sdf</Text>
+    </Container>
+  );
+  const container = screen.getByTestId(/container/);
+  expect(container).toHaveStyle(`alignItems: flex-end`);
+});
+
+test('renders correct HTML element', () => {
+  render(
+    <Container data-testid="container">
+      <Text>sdf</Text>
+    </Container>
+  );
+  const container = screen.getByTestId(/container/);
+  expect(container instanceof HTMLDivElement).toBeTruthy();
 });