stories/molecules/components/header/Header.stories.mdx

Summary

Maintainability
Test Coverage
import { ArgsTable, Meta, Story, Canvas, Preview, Props } from '@storybook/addon-docs'
import classNames from 'classnames'
import { ThemeProvider } from 'ui/atoms/theme/ThemeProvider'
import { Header } from 'ui/molecules/header/Header.tsx'
import { Logo } from 'ui/atoms/logo/Logo.tsx'
import BotAnikImage from '../../../assets/botanik-logo.png'
import { Typography } from 'ui/atoms/typography/Typography.tsx'
import { useMediaType } from 'hook/useMediaType'

import './header.scss'

<Meta
  title="Molecules/Header"
  component={Header}
  parameters={{
    actions: {
      argTypesRegex: '^on.*'
    },
    docs: {
      source: {
        type: 'code'
      }
    }
  }}
  decorators={[
    Story => (
      <ThemeProvider>
        <div className="header-story-main">
          <Story />
        </div>
      </ThemeProvider>
    )
  ]}
/>

# Header

> Provides a consistent user experience and helps users navigate the site.

[![stability-unstable](https://img.shields.io/badge/stability-unstable-yellow.svg)](https://github.com/emersion/stability-badges#unstable)

## Description

**Header** is a responsive component which embeds three main elements:

- A `firstElement` that comes first in the reading flow. Typically used for logos. Will resize if larger than max size.
- A `ThemeSwitcher` which allows each application to automatically manage the themes offered by the ØKP4 design system (Blue Stone / Light Stone).
- A `NavigationMenu` that displays the main navigation of your site. This set of links will be wrapped in a burger menu to fit smaller screens.

## Overview

<Story
  name="Overview"
  argTypes={{
    firstElement: {
      control: false,
      table: {
        type: { summary: 'Node' }
      }
    },
    navigationMenu: {
      control: false,
      table: {
        type: {
          summary: `Array<{ menuItem: Node, subMenu?: Node[], isSelectedFromStart?: boolean>}>`
        }
      }
    }
  }}
>
  {() => {
    const FooterSubItem = (
      <Typography as="div" fontSize="small" fontWeight="light">
        <a
          href="https://ui.okp4.space/?path=/docs/molecules-footer--overview"
          target="_blank"
          style={{ wordBreak: 'normal' }}
        >
          Footer
        </a>
      </Typography>
    )
    const SelectSubItem = (
      <Typography as="div" fontSize="small" fontWeight="light">
        <a
          href="https://ui.okp4.space/?path=/docs/molecules-select--overview"
          target="_blank"
          style={{ wordBreak: 'normal' }}
        >
          Select
        </a>
      </Typography>
    )
    const StepperSubItem = (
      <Typography as="div" fontSize="small" fontWeight="light">
        <a
          href="https://ui.okp4.space/?path=/docs/molecules-stepper--overview"
          target="_blank"
          style={{ wordBreak: 'normal' }}
        >
          Stepper
        </a>
      </Typography>
    )
    const FaucetSubItem = (
      <Typography as="div" fontSize="small" fontWeight="light">
        <a
          href="https://ui.okp4.space/?path=/docs/organisms-faucet--overview"
          target="_blank"
          style={{ wordBreak: 'normal' }}
        >
          Faucet
        </a>
      </Typography>
    )
    const FilePickerSubItem = (
      <Typography as="div" fontSize="small" fontWeight="light">
        <a
          href="https://ui.okp4.space/?path=/docs/organisms-filepicker--overview"
          target="_blank"
          style={{ wordBreak: 'normal' }}
        >
          File Picker
        </a>
      </Typography>
    )
    const HomeNavItemSelectedFromStart = {
      menuItem: (
        <Typography as="div" fontSize="small" fontWeight="bold" noWrap>
          Home
        </Typography>
      ),
      isSelectedFromStart: true
    }
    const WelcomeNavItem = {
      menuItem: (
        <Typography as="div" fontSize="small" fontWeight="bold">
          <a
            href="https://ui.okp4.space/?path=/docs/welcome--page"
            target="_blank"
            style={{ wordBreak: 'normal' }}
          >
            Welcome
          </a>
        </Typography>
      )
    }
    const MoleculesNavItem = {
      menuItem: (
        <Typography as="div" fontSize="small" fontWeight="bold" noWrap>
          Molecules
        </Typography>
      ),
      subMenu: [FooterSubItem, SelectSubItem, StepperSubItem]
    }
    const OrganismsNavItem = {
      menuItem: (
        <Typography as="div" fontSize="small" fontWeight="bold" noWrap>
          Organisms
        </Typography>
      ),
      subMenu: [FaucetSubItem, FilePickerSubItem]
    }
    const navigationMenu = [
      HomeNavItemSelectedFromStart,
      WelcomeNavItem,
      MoleculesNavItem,
      OrganismsNavItem
    ]
    return <Header firstElement={<Logo size="small" />} navigationMenu={navigationMenu} />
  }}
</Story>

---

### Properties

<ArgsTable story="Overview" />

## First element

**firstElement** allows the user to put any type of element in the `header`.  
The size of the element is limited to a `max height` of `72px` and a responsive
`max width` of `270px` and `220px` to limit its size, making sure injected
elements conform to the layout.

<Canvas>
  <Story name="First element">
    <Header
      firstElement={
        <div style={{ display: 'flex' }}>
          <img src={BotAnikImage} alt="BotAnik image" />
          <Typography as="h1" size="x-large" color="highlighted-text" fontWeight="black">
            BotAnik Space
          </Typography>
        </div>
      }
    />
  </Story>
</Canvas>

## Navigation menu

The optional `navigationMenu` is used to hightlight the main navigation of your website.  
This responsive menu provides the user with a set of navigable links and greatly improves his experience by providing several easily accessible shortcuts.

You just have to provide it with an array of `NavigationItem` which will then be displayed on a single line on a large or medium screen, or accessible via a burger menu on a smaller or mobile screen.  
Please shorten the window to let the magic happen!

<Canvas>
  <Story name="Navigation menu with sub menus">
    {() => {
      const PhilosophyNavItem = (
        <Typography as="div" fontSize="small" fontWeight="light">
          <a
            href="https://ui.okp4.space/?path=/docs/philosophy--page"
            target="_blank"
            style={{ wordBreak: 'normal' }}
          >
            Philosophy
          </a>
        </Typography>
      )
      const DesignSystemNavItem = (
        <Typography as="div" fontSize="small" fontWeight="light">
          <a
            href="https://ui.okp4.space/?path=/docs/welcome--page"
            target="_blank"
            style={{ wordBreak: 'normal' }}
          >
            The OKP4 Design System
          </a>
        </Typography>
      )
      const StartNavItem = (
        <Typography as="div" fontSize="small" fontWeight="light">
          <a
            href="https://ui.okp4.space/?path=/docs/getting-started--page"
            target="_blank"
            style={{ wordBreak: 'normal' }}
          >
            Launch project
          </a>
        </Typography>
      )
      const ThemesNavItem = (
        <Typography as="div" fontSize="small" fontWeight="light">
          <a
            href="https://ui.okp4.space/?path=/docs/atoms-brand-identity-theming--theming"
            target="_blank"
            style={{ wordBreak: 'normal' }}
          >
            Theming
          </a>
        </Typography>
      )
      const ColorsNavItem = (
        <Typography as="div" fontSize="small" fontWeight="light">
          <a
            href="https://ui.okp4.space/?path=/docs/atoms-brand-identity-colors--page"
            target="_blank"
            style={{ wordBreak: 'normal' }}
          >
            Colors
          </a>
        </Typography>
      )
      const HomeNavItemSelectedFromStart = {
        menuItem: (
          <Typography as="div" fontSize="small" fontWeight="bold" noWrap>
            Home
          </Typography>
        ),
        isSelectedFromStart: true
      }
      const NavItemWithSubMenusA = {
        menuItem: (
          <Typography as="div" fontSize="small" fontWeight="bold" noWrap>
            Prerequisites
          </Typography>
        ),
        subMenu: [PhilosophyNavItem, StartNavItem]
      }
      const NavItemWithSubMenusB = {
        menuItem: (
          <Typography as="div" fontSize="small" fontWeight="bold" noWrap>
            UI
          </Typography>
        ),
        subMenu: [DesignSystemNavItem, ThemesNavItem, ColorsNavItem]
      }
      const NavItemWithoutSubMenus = {
        menuItem: (
          <Typography as="div" fontSize="small" fontWeight="bold" noWrap>
            No SubMenu
          </Typography>
        )
      }
      const navigationMenu = [
        HomeNavItemSelectedFromStart,
        NavItemWithSubMenusA,
        NavItemWithSubMenusB,
        NavItemWithoutSubMenus
      ]
      return (
        <div className="header-story-with-submenu">
          <Header firstElement={<Logo size="small" />} navigationMenu={navigationMenu} />
        </div>
      )
    }}
  </Story>
</Canvas>

### Navigation Items

This `navigationMenu` must respect the `NavigationItem` format which is defined as follows:

```ts
type NavigationItem = {
/**
 * Main item displayed on the header navigation bar
 */
  menuItem: Node
/**
 * The sub-menu attached to the main item
 */
  subMenu?: Node[]
/**
 * Allows to define if the main item must be selected at the beginning
 */
  isSelectedFromStart?: boolean
```

The user will be informed that he has clicked on a `menuItem` because its color will change and two arrows will surround the selected item.

If this item has a sub-menu, it will be displayed. It can be closed in a number of ways:  
by clicking away from the sub-menu, by pressing the **Esc** key or by clicking on the `menuItem` again.

You may decide that a menu item (e.g. `Home`) should be pre-selected to indicate that the user, when arriving at your application, is on the `Home` page.
In this case, simply set the `isSelectedFromStart` property of your `Home` item to `true`.

### Application Routing System

The `isSelectedFromStart` property is also useful when using a router system.  
You might need to check which url the user is on in order to define if the menu item should be selected or not.

For example:

```tsx
const ExploreNavItem: NavigationItem = {
  // If user is on the "explore" page, the Explore menu item will be selected
  isSelectedFromStart: router.pathname === '/explore',
  menuItem: (
    <Typography as="div" fontSize="small" fontWeight="bold">
      <Link href="/explore">Explore</Link>
    </Typography>
  )
}
```

## Responsiveness

The component was built according to the principles of Responsive Web Design (see <a href="?path=/docs/guidelines-responsive-web-design--page">dedicated guideline</a> ) in particular thanks to the use of media queries and a responsive grid.
This allows the component to adapt to any screen size, from the smallest phone to a large desktop screen or television.

## Prerequisites

It is mandatory to wrap the component in a `<ThemeProvider />` for the `<ThemeSwitcher />` to work, like in the code snippet below.  
See <a href="?path=/docs/atoms-brand-identity-theming--theming">Theming</a> for more information.

##### **`app.tsx`**

```tsx
import React from 'react'
import { Header, ThemeProvider, Logo } from '@okp4/ui'

export const App: React.FC = () => (
  <React.StrictMode>
    <ThemeProvider>
      <Header firstElement={<Logo />} />
    </ThemeProvider>
  </React.StrictMode>
)
```