stories/atoms/components/button/Button.stories.mdx

Summary

Maintainability
Test Coverage
import { ArgsTable, Meta, Story, Canvas } from '@storybook/addon-docs'
import { useState } from 'react'
import { useTheme } from 'hook/useTheme'
import { Button } from 'ui/atoms/button/Button'
import { ThemeProvider } from 'ui/atoms/theme/ThemeProvider'
import { ThemeSwitcher } from 'ui/atoms/theme/ThemeSwitcher'
import { Icon } from 'ui/atoms/icon/Icon'
import { Toast } from 'ui/atoms/toast/Toast'
import { Typography } from 'ui/atoms/typography/Typography'
import '../component.scss'

<Meta
  title="Atoms/Button"
  component={Button}
  decorators={[
    Story => (
      <ThemeProvider>
        <div className="story-theme-switcher">
          <ThemeSwitcher />
        </div>
        <div className="component-story-main">
          <Story />
        </div>
      </ThemeProvider>
    )
  ]}
/>

# Button

> Communicates actions that users can take.

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

## Description

Buttons are mainly used to give the user options to act. They help users to find
the most important actions through the UI and enable them to perform these actions.

By using one or more of the button properties, it's possible to create appealing and intuitive buttons
that will help users to find the action they're looking for.

## Overview

<Story
  name="Overview"
  argTypes={{
    icon: { control: false, table: { type: { summary: 'Node' } } },
    leftIcon: { control: false, table: { type: { summary: 'Node' } } },
    rightIcon: { control: false, table: { type: { summary: 'Node' } } }
  }}
  args={{
    label: 'Connect wallet',
    variant: 'primary',
    size: 'medium',
    backgroundColor: 'primary',
    disabled: false
  }}
>
  {args => {
    const { theme } = useTheme()
    const isLightTheme = theme === 'light'
    return (
      <div
        style={{
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'center',
          gap: '25px'
        }}
      >
        <Button {...args} icon={<Icon name="wallet" size={22} invertColor={isLightTheme} />} />
      </div>
    )
  }}
</Story>

## Properties

<ArgsTable story="Overview" />

## Label

The `label` is the text description of Button that helps communicate what happens after the click.
If Button is an **icon** `variant`, the `label` is not shown, however it is still there as a title
attribut used for the [tooltip](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/Tooltip_Role)
(as you can see by hovering your mouse over the icon button below).

The `label` can have any length however Button width will never exceed 273px.

<Canvas>
  <Story name="Label">
    {() => {
      const { theme } = useTheme()
      const isLightTheme = theme === 'light'
      return (
        <div
          style={{
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'center',
            flexWrap: 'wrap',
            gap: '50px'
          }}
        >
          <Button label="Short label" />
          <Button label="Here is how the button acts when it has a long label" />
          <Button
            label="I'm the label of the icon button"
            variant="icon"
            icon={<Icon name="profile" size={22} invertColor={isLightTheme} />}
          />
        </div>
      )
    }}
  </Story>
</Canvas>

## Icon

`Icon` turns the button into a more concise, unlabeled element. For that, you can pass the icon of your choice as a value.

Requires Button to be an **icon** `variant`. Without it, the button content will remain `label`.

<Canvas>
  <Story name="Icon">
    {() => {
      const { theme } = useTheme()
      const isLightTheme = theme === 'light'
      return (
        <div
          style={{
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'center',
            flexWrap: 'wrap',
            gap: '50px'
          }}
        >
          <Button
            label="icon button"
            icon={<Icon name="calendar" size={22} invertColor={isLightTheme} />}
            variant="icon"
          />
          <Button
            label="Icon passed without the icon variant"
            icon={<Icon name="calendar" size={22} />}
          />
        </div>
      )
    }}
  </Story>
</Canvas>

## Variants

Button is available in three styled versions:

- **primary** (default): A rectangular version, symbol of the brand and which reinforces the cosmic atmosphere.
- **secondary**: A rounded version, softer, allowing to adapt in particular to smaller screens.
- **icon**: Sets the button to be an icon button, requires you to supply an `icon` property.

<Canvas>
  <Story name="Variants">
    {() => {
      const { theme } = useTheme()
      const isLightTheme = theme === 'light'
      return (
        <div
          style={{
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'center',
            flexWrap: 'wrap',
            gap: '50px'
          }}
        >
          <Button backgroundColor="primary" variant="primary" label="Primary" size="medium" />
          <Button backgroundColor="primary" variant="secondary" label="Secondary" size="medium" />
          <Button
            backgroundColor="primary"
            variant="icon"
            label="Icon"
            size="medium"
            icon={<Icon name="alert" size={22} invertColor={isLightTheme} />}
          />
        </div>
      )
    }}
  </Story>
</Canvas>

## Sizes

There are three different sizes to allow Button to be used according to its location within the interface.

- **small**: Suitable for small screens and must not saturate the space. This size should also be used for integrations in content spaces such as cards, footers, etc.
- **medium** (default): Makes it possible to adapt to a greater number of uses.
- **large**: Appropriate for large screens or in conjonction with `leftIcon` / `rightIcon` properties.

<Canvas>
  <Story name="Sizes">
    <div
      style={{
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
        flexWrap: 'wrap',
        gap: '50px'
      }}
    >
      <Button backgroundColor="primary" variant="primary" label="Small" size="small" />
      <Button backgroundColor="primary" variant="primary" label="Medium" size="medium" />
      <Button backgroundColor="primary" variant="primary" label="Large" size="large" />
    </div>
  </Story>
</Canvas>

## Background colors

Button has a palette of background colors to choose from and allows to better mark a user action.
The background color can be a visual aid as to what type of action the button executes.

By default `backgroundColor` is **primary**.

<Canvas>
  <Story name="Background colors">
    <div
      style={{
        display: 'flex',
        justifyContent: 'center',
        gap: '25px',
        flexWrap: 'wrap'
      }}
    >
      <Button backgroundColor="primary" variant="primary" label="Primary" size="medium" />
      <Button backgroundColor="secondary" variant="primary" label="Secondary" size="medium" />
      <Button backgroundColor="success" variant="primary" label="Success" size="medium" />
      <Button backgroundColor="error" variant="primary" label="Error" size="medium" />
      <Button backgroundColor="warning" variant="primary" label="Warning" size="medium" />
      <Button backgroundColor="info" variant="primary" label="Info" size="medium" />
    </div>
  </Story>
</Canvas>

## Disabled

Button can be `disabled` at any time, thus preventing any user interaction. This is indicated by a change in background color
and cursor.

<Canvas>
  <Story name="Disabled">
    <div
      style={{
        display: 'flex',
        justifyContent: 'center'
      }}
    >
      <Button disabled variant="primary" label="I'm disabled" size="medium" />
    </div>
  </Story>
</Canvas>

## Left / Right Icon

`leftIcon` and `rightIcon` are auxilliary elements giving great freedom to embellish the button
together with the `label`.

<Canvas>
  <Story name="Left / right Icon">
    {() => {
      const { theme } = useTheme()
      const isLightTheme = theme === 'light'
      return (
        <div
          style={{
            display: 'flex',
            justifyContent: 'center',
            flexWrap: 'wrap',
            gap: '50px'
          }}
        >
          <Button
            leftIcon={<Icon name="wallet" size={22} invertColor={isLightTheme} />}
            label="Get wallet address"
          />
          <Button
            label="Add wallet"
            rightIcon={<Icon name="add" size={22} invertColor={isLightTheme} />}
          />
        </div>
      )
    }}
  </Story>
</Canvas>

## OnClick

`onClick` is what makes the magic happen, without it the button has no corresponding action.
It is triggered when a click is registered on the button.

<Canvas>
  <Story name="OnClick">
    {() => {
      const [isOpened, setIsOpened] = useState(false)
      const handleOpen = () => {
        setIsOpened(prevState => !prevState)
      }
      return (
        <div>
          <div
            style={{
              display: 'flex',
              justifyContent: 'center'
            }}
          >
            <Button label="Click me!" onClick={handleOpen} />
          </div>
          <Toast
            description={
              <div style={{ display: 'flex', flexDirection: 'column' }}>
                <Typography color="inverted-text" fontSize="small" fontWeight="light">
                  {`Like this component? See `}
                  <Typography color="inverted-text" fontSize="small" fontWeight="bold">
                    <a
                      href="/?path=/docs/atoms-toast--overview"
                      rel="author noreferrer"
                      target="_blank"
                      style={{ color: 'inherit' }}
                    >
                      Toast
                    </a>
                  </Typography>
                </Typography>
              </div>
            }
            isOpened={isOpened}
            onOpenChange={handleOpen}
            title={
              <Typography color="inverted-text" fontSize="small" fontWeight="bold">
                Button clicked!
              </Typography>
            }
            severityLevel="info"
          />
        </div>
      )
    }}
  </Story>
</Canvas>

## Prerequisites

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

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

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

export const App: React.FC = () => (
  <React.StrictMode>
    <ThemeProvider>
      <Button label="Super label" />
    </ThemeProvider>
  </React.StrictMode>
)
```