import { useState } from "react";
import {
  Meta,
  Canvas,
  ArgsTable,
  Story,
  SourceState,
} from "@storybook/blocks";
import { ComponentHeading, Accessibility } from "../../storybook-components";
import {
  Checkbox,
  Text,
  IntegrationLogo,
  Icon,
  ICON_TYPE,
  Box,
  Flex,
  Banner,
  STATUS_VARIANT,
} from "../..";
import { Accordion } from "./Accordion";

<Meta title="Components/Disclosure/Accordion" component={Accordion} />

<ComponentHeading
  componentName="Accordion"
  description="A component that expands/collapses vertically when clicked"
  sourcePath="src/components/Accordion/Accordion.tsx"
  waiAriaPath="https://www.w3.org/TR/wai-aria-1.2/#accordion"
/>

An accordion is a vertically stacked set of interactive headings that each
contain a title and content snippet. The headings function as controls that
enable users to show or hide their associated sections of content. Accordions
are commonly used to reduce the need to scroll when presenting multiple sections
of content on a single page.

## Installation

```jsx
import { Accordion } from "@conveyorhq/arrow-ds";
```

## Basic usage

<Canvas withSource={SourceState.OPEN}>
  <Story name="Accordion">
    {() => {
      const [checked, setChecked] = useState(true);
      return (
        <Accordion.Group defaultValue="item one">
          <Accordion title="Accordion Item One" value="item one">
            This is the content
          </Accordion>
          <Accordion
            title="Accordion Item Two"
            isActive={checked}
            value="item two"
          >
            <Checkbox
              label="This is some interactive content"
              checked={checked}
              onChange={() => setChecked(!checked)}
            />
          </Accordion>
          <Accordion title="Accordion Item Three" value="item three">
            <span role="img" aria-label="hello friend">
              👀
            </span>
          </Accordion>
        </Accordion.Group>
      );
    }}
  </Story>
</Canvas>

## API

### Accordion

<Banner title="Deprecation Notice" variant={STATUS_VARIANT.DANGER}>
  Usage of Accordion as a standalone component has been deprecated. It was
  initially built for a specific use-case, provides no composability and should
  be avoided if possible.
</Banner>

An implementation of `Accordion.Item` with opinionated styles and specific props.
Provides the least amount of flexibility and no composability; don’t use this if
you need an accordion with custom styles (see “custom implementation” below).

<ArgsTable of={Accordion} />

### Accordion.Group

Use to wrap each child of `Accordion` or `Accordion.Item`. Optional `spacing`
can be provided to add space between each child.

<ArgsTable of={Accordion.Group} />

### Accordion.Item

Declares a single accordion item by wrapping each `Accordion.Button` and
`Accordion.Content`. Extends `BoxProps`.

<ArgsTable of={Accordion.Item} />

### Accordion.Button

Label representing a section of content that also serves as a control for
showing and hiding the corresponding section of content. Extends
`React.ButtonHTMLAttributes<HTMLButtonElement>`.

<ArgsTable of={Accordion.Button} />

### Accordion.Icon

A chevron icon that rotates based on the expanded/collapsed state.

<ArgsTable of={Accordion.Icon} />

### Accordion.Content

Section of content associated with an `Accordion.Header`.

<ArgsTable of={Accordion.Content} />

<Accessibility
  description={
    <>
      Adheres to the{" "}
      <a href="https://www.w3.org/TR/wai-aria-practices-1.2/#accordion">
        accordion requirements
      </a>
      .<br />
      <br />
      To improve the usability of the component, a roving tabindex pattern will be
      implemented. This will allow up and down arrow keys to cycle through the items.
    </>
  }
  keyboardInteractions={[
    {
      key: "Enter",
      description:
        "When focus is on the accordion header for a collapsed panel, expands the associated panel. Conversely, it collapses the panel if expanded.",
    },
    {
      key: "Space",
      description:
        "When focus is on the accordion header for a collapsed panel, expands the associated panel. Conversely, it collapses the panel if expanded.",
    },
    {
      key: "Tab",
      description:
        "Moves focus to the next focusable element; all focusable elements in the accordion are included in the page tab sequence.",
    },
    {
      key: "Shift + Tab",
      description:
        "Moves focus to the previous focusable element; all focusable elements in the accordion are included in the page Tab sequence.",
    },
  ]}
/>

## Component tree

Each piece of the `Accordion` component can be used individually to create a
component with a custom layout.

The component tree is as follows:

```jsx
<Accordion.Group>
  <Accordion.Item>
    <Accordion.Button>
      <Accordion.Icon />
    </Accordion.Button>
    <Accordion.Content />
  </Accordion.Item>
</Accordion.Group>
```

## Demos

### Building a custom implementation

This example shows how you can create a custom accordion. This is the
recommended way to implement an accordion.

A few notes:

- `Accordion.Button` children can be rendered as a `React.ReactNode` or a
  function with render props that returns a `React.ReactNode`. The render props
  give you access to the `isOpen` prop; use it if you need to adjust the button
  style based on the visibility of the content.
- `Accordion.Content` accepts both `className` and `style` props, but if you
  need padding on the content, you should put it on the children. This will allow
  the transition to run more smoothly.
- To expand a single item on initial render, give each `Accordion.Item` a unique
  value, wrap all `Accordion.Item` components with `Accordion.Group` and give the
  group a `defaultValue` which matches the value of the item you want to expand.

<Canvas withSource={SourceState.OPEN}>
  <Story name="Custom implementation">
    <Accordion.Group defaultValue={ICON_TYPE.ENVELOPE}>
      {[
        {
          color: "#ffd883",
          icon: ICON_TYPE.CALCULATOR,
        },
        {
          color: "#c8b3e8",
          icon: ICON_TYPE.ENVELOPE,
        },
        {
          color: "#a1d8f1",
          icon: ICON_TYPE.PAPERCLIP,
          disabled: true,
        },
        {
          color: "#ffc3a1",
          icon: ICON_TYPE.KEY,
        },
      ].map((item) => {
        return (
          <Accordion.Item
            key={item.icon}
            value={item.icon}
            style={{ backgroundColor: item.color }}
          >
            <Accordion.Button
              className={`p-4 w-full text-left flex items-center justify-between${
                item.disabled ? " cursor-not-allowed" : ""
              }`}
              disabled={item.disabled}
            >
              <>
                <Flex
                  className={`items-center gap-x-2${
                    item.disabled ? ` text-${item.color}-400` : ""
                  }`}
                >
                  <Icon icon={item.icon} />
                  <Text className="font-medium">{item.icon} icon</Text>
                </Flex>
                <Accordion.Icon />
              </>
            </Accordion.Button>
            <Accordion.Content>
              <Box className={`p-4 border-t border-${item.color}-300`}>
                <Text className="leading-normal">
                  Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed
                  sit amet dapibus risus. Mauris blandit arcu quis malesuada
                  sagittis. Maecenas at enim quis urna gravida aliquet. Maecenas
                  lectus nibh, mollis ut egestas vel, tempor nec tortor. Nunc
                  interdum non purus in congue. Duis tortor neque, cursus non
                  molestie ac, aliquam non velit. Nunc non iaculis nunc. Donec
                  purus mauris, accumsan ut enim vitae, consectetur varius eros.
                  Nullam sagittis justo a nibh lobortis imperdiet. Sed tristique
                  mauris quis posuere fermentum. Cras maximus mattis tempus.
                </Text>
              </Box>
            </Accordion.Content>
          </Accordion.Item>
        );
      })}
    </Accordion.Group>
  </Story>
</Canvas>

### Allow expanding only one item at time in a custom implementation

By default, more than one accordion item can be opened at once, but sometimes
this might not be desired. Set `allowMultiple` to `false` to allow only one
accordion item to be opened at a time.

<Canvas withSource={SourceState.OPEN}>
  <Story name="Custom implementation allow one">
    <Accordion.Group
      className="border-t"
      defaultValue="First item"
      allowMultiple={false}
    >
      {["First item", "Second item", "Third item", "Fourth item"].map(
        (item) => {
          return (
            <Accordion.Item key={item} value={item}>
              <Accordion.Button className="p-4 w-full text-left flex items-center justify-between bg-gray-100 border-b font-medium">
                {item}
                <Accordion.Icon direction="left" />
              </Accordion.Button>
              <Accordion.Content className="border-b">
                <Box className="p-4 leading-normal">
                  Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed
                  sit amet dapibus risus. Mauris blandit arcu quis malesuada
                  sagittis.
                </Box>
              </Accordion.Content>
            </Accordion.Item>
          );
        },
      )}
    </Accordion.Group>
  </Story>
</Canvas>

### Setting a maximum height

Providing a CSS value to the `maxHeight` prop will keep the Accordion content from exceeding that
height and will scroll if there is more content than will fit.

<Canvas withSource={SourceState.OPEN}>
  <Story name="Accordion max height">
    <Accordion.Group defaultValue="item one">
      <Accordion title="Accordion Item One" maxHeight="100px" value="item one">
        <Text>This is the content.</Text>
        <Text>This is the content.</Text>
        <Text>This is the content.</Text>
        <Text>This is the content.</Text>
        <Text>This is the content.</Text>
        <Text>This is the content.</Text>
        <Text>This is the content.</Text>
        <Text>This is the content.</Text>
        <Text>This is the content.</Text>
        <Text>This is the content.</Text>
        <Text>This is the content.</Text>
        <Text>This is the content.</Text>
        <Text>This is the content.</Text>
        <Text>This is the content.</Text>
        <Text>This is the content.</Text>
        <Text>This is the content.</Text>
        <Text>This is the content.</Text>
        <Text>This is the content.</Text>
        <Text>This is the content.</Text>
      </Accordion>
    </Accordion.Group>
  </Story>
</Canvas>

### Expanding an item on initial render

Allow an accordion to be opened by default.

<Canvas withSource={SourceState.OPEN}>
  <Story name="Accordion defaultIsOpen prop">
    <Accordion.Group defaultValue="item one">
      <Accordion title="Accordion Item One" value="item one">
        <Text>This is the content.</Text>
      </Accordion>
      <Accordion title="Accordion Item Two" value="item two">
        <Text>This is the content.</Text>
      </Accordion>
      <Accordion title="Accordion Item Three" value="item three">
        <Text>This is the content.</Text>
      </Accordion>
    </Accordion.Group>
  </Story>
</Canvas>

### Rendering headers with icons

Add an icon or logo in the header.

<Canvas withSource={SourceState.OPEN}>
  <Story name="Accordion headers with icons">
    <Accordion.Group>
      <Accordion
        title="Accordion Item One"
        iconSlot={<IntegrationLogo logo="aws" size={16} square />}
      >
        <Text>This is the content.</Text>
      </Accordion>
      <Accordion
        title="Accordion Item Two"
        iconSlot={<IntegrationLogo logo="gitlab" size={16} square />}
      >
        <Text>This is the content.</Text>
      </Accordion>
      <Accordion
        title="Accordion Item Three"
        iconSlot={<IntegrationLogo logo="deploy" size={16} square />}
      >
        <Text>This is the content.</Text>
      </Accordion>
      <Accordion
        title="Accordion Item Three"
        iconSlot={<Icon icon={ICON_TYPE.BOLT} />}
      >
        <Text>This is the content.</Text>
      </Accordion>
      <Accordion
        title="Accordion Item Three"
        iconSlot={<Icon icon={ICON_TYPE.COG} />}
      >
        <Text>This is the content.</Text>
      </Accordion>
    </Accordion.Group>
  </Story>
</Canvas>
