<script setup>
import Button from '~/components/ui/Button.vue'
import Layout from '~/components/ui/Layout.vue'

const click = () => new Promise(resolve => setTimeout(resolve, 1000))
</script>

# Button

Buttons are UI elements that users can interact with to perform actions. Funkwhale uses buttons in many contexts.

| Prop           | Data type | Required? | Default | Description                                    |
| -------------- | --------- | --------- | ------- | ---------------------------------------------- |
| `shadow`       | Boolean   | No        | `false` | Whether to render the button with a shadow     |
| `round`        | Boolean   | No        | `false` | Whether to render the button as a round button |
| `icon`         | String    | No        |         | The icon attached to the button                |
| `aria-pressed` | Boolean   | No        | `false` | Whether the button is in an active state       |
| `is-loading`   | Boolean   | No        | `false` | Whether the button is in a loading state       |

In addition, use [Colors] and [Variants]

## Button colors

Buttons come in different types depending on the type of action they represent.

### Primary

Primary buttons represent **positive** actions such as uploading, confirming, and accepting changes.

::: info
This is the default type. If you don't specify a type, a primary button is rendered.
:::

```vue-html
<Button primary>
  Primary button
</Button>
```

<Button primary>
  Primary button
</Button>

### Secondary

Secondary buttons represent **neutral** actions such as cancelling a change or dismissing a notification.

```vue-html
<Button secondary>
  Secondary button
</Button>
```

<Button secondary>
  Secondary button
</Button>

### Destructive

Desctrutive buttons represent **dangerous** actions including deleting items or purging domain information.

```vue-html
<Button destructive>
  Destructive button
</Button>
```

<Button destructive>
  Destructive button
</Button>

## Button variants

Buttons come in different styles that you can use depending on the location of the button.

### Solid

Solid buttons have a filled background. Use these to emphasize the action the button performs.

::: info
This is the default style. If you don't specify a style, a solid button is rendered.
:::

```vue-html
<Button>
  Filled button
</Button>

<Button solid>
  Also filled button
</Button>
```

<Button>
  Filled button
</Button>

<Button solid>
  Also filled button
</Button>

### Outline

Outline buttons have a transparent background. Use these to deemphasize the action the button performs.

```vue-html
<Button outline secondary>
  Outline button
</Button>
```

<Button outline secondary>
  Outline button
</Button>

### Ghost

Ghost buttons have a transparent background and border. Use these to deemphasize the action the button performs.

```vue-html
<Button ghost secondary>
  Ghost button
</Button>
```

<Button ghost secondary>
  Ghost button
</Button>

## Button styles

### Shadow

You can give a button a shadow to add depth.

```vue-html
<Button shadow>
  Shadow button
</Button>
```

<Button shadow>
  Shadow button
</Button>

## Button shapes

You can choose different shapes for buttons depending on their location and use.

### Normal

Normal buttons are slightly rounded rectangles.

::: info
This is the default shape. If you don't specify a type, a normal button is rendered.
:::

```vue-html
<Button>
  Normal button
</Button>
```

<Button>
  Normal button
</Button>

### Round

Round buttons have fully rounded edges.

```vue-html
<Button round>
  Round button
</Button>
```

<Button round>
  Round button
</Button>

## Button states

You can pass a state to indicate whether a user can interact with a button.

### Active

You can force an active state by passing an `aria-pressed` prop.

This can be useful for toggle buttons (if you don't want to use a [Toggle component](toggle))

```vue-html
<Button aria-pressed>
  Active button
</Button>
```

**Secondary (default):**

<Button>
  Inactive button
</Button>

<Button aria-pressed>
  Active button
</Button>

---

**Primary:**

<Button primary>
  Inactive button
</Button>

<Button primary aria-pressed>
  Active button
</Button>

### Disabled

Disabled buttons are non-interactive and inherit a less bold color than the one provided. You can apply a disabled state by passing a `disabled` prop.

```vue-html
<Button disabled>
  Disabled button
</Button>
```

<Button disabled>
  Disabled button
</Button>

### Loading

If a user can't interact with a button until something has finished loading, you can add a spinner by passing the `is-loading` prop.

```vue-html
<Button is-loading>
  Loading button
</Button>
```

<Button is-loading>
  Loading button
</Button>

### Promise handling in `@click`

When a function passed to `@click` returns a promise, the button automatically toggles a loading state on click. When the promise resolves or is rejected, the loading state turns off.

::: danger
There is no promise rejection mechanism implemented in the `<Button>` component. Make sure the `@click` handler never rejects.
:::

```vue
<script setup lang="ts">
const click = () => new Promise((resolve) => setTimeout(resolve, 1000));
</script>

<template>
  <Button @click="click"> Click me </Button>
</template>
```

<Button @click="click">
Click me
</Button>

You can override the promise state by passing a false `is-loading` prop.

```vue-html
<Button :is-loading="false">
  Click me
</Button>
```

<Button :is-loading="false">
  Click me
</Button>

## Icons

You can use [Bootstrap Icons](https://icons.getbootstrap.com/) in your button component

::: info
Icon buttons shrink down to the icon size if you don't pass any content. If you want to keep the button at full width with just an icon, add `&nbsp;` into the slot.
:::

```vue-html
<Button color="secondary" icon="bi-three-dots-vertical" />

<Button color="secondary" is-round icon="bi-x" />

<Button icon="bi-save" />

<Button color="destructive" icon="bi-trash">
  Delete
</Button>
```

<Button icon="bi-three-dots-vertical" />
<Button round icon="bi-x" />
<Button primary icon="bi-save" width="standard" />
<Button destructive icon="bi-trash">
  Delete
</Button>

## Width and alignment

<Layout flex>

```vue-html
    <Button width="auto">·</Button>
    <Button width="standard">·</Button>
    <Button width="full">·</Button>

    <hr />

    <Button alignSelf="start">·</Button>
    <Button alignSelf="center">·</Button>
    <Button alignSelf="end">·</Button>

    <hr />

    <Button alignText="left">·</Button>
    <Button alignText="center">·</Button>
    <Button alignText="right">·</Button>
```

  <Layout class="preview solid secondary" stack no-gap>
    <Button width="auto">·</Button>
    <Button width="standard">·</Button>
    <Button width="full">·</Button>
    <hr />
    <Button alignSelf="start">·</Button>
    <Button alignSelf="center">·</Button>
    <Button alignSelf="end">·</Button>
    <hr />
    <Button alignText="left">·</Button>
    <Button alignText="center">·</Button>
    <Button alignText="right">·</Button>
    (Text to stretch the column)
  </Layout>
</Layout>
