# Flying Button

A button with thruster pods under it. Hover it (or click it, or tap it on touch) and the jets spool up, the button climbs on a WebGL2 fluid smoke plume, hovers while a flight controller fights gusts, then descends and lands in the cloud it kicked up. The cursor rides along with it. Grab the button while it flies and drag it anywhere; it lands where you let go. Turn on `ramp` and a click drives it up a loop ramp, along the ceiling and off the end in a flip.

<demo-flying-button>



</demo-flying-button>

## Installation

```bash
npx shadcn-vue@latest add "https://nxui.geoql.in/r/flying-button.json"
```

## Usage

```vue
<script setup lang="ts">
  import FlyingButton from '~/components/ui/flying-button/FlyingButton.vue';

  function onTakeOff() {
    console.log('clicked');
  }
</script>

<template>
  <div class="relative h-110 w-full overflow-hidden">
    <FlyingButton
      theme="dark"
      size="medium"
      trigger="hover"
      thrust-color="#8ec5ff"
      :altitude="170"
      :hover-time="2.4"
      :jets="2"
      @click="onTakeOff"
    >
      Take off
    </FlyingButton>
  </div>
</template>
```

The component fills its parent (minimum 240px tall) and flies inside it, so give the parent a real height. The smoke is a small GPU fluid simulation (advection, vorticity, pressure solve) that only runs while something is moving and pauses when the component is offscreen.

## Props

<table>
<thead>
  <tr>
    <th>
      Prop
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Default
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        label
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        'Take off'
      </code>
    </td>
    
    <td>
      Button label. The default slot overrides it.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        theme
      </code>
    </td>
    
    <td>
      <code>
        'dark' | 'light'
      </code>
    </td>
    
    <td>
      <code>
        'dark'
      </code>
    </td>
    
    <td>
      Shades the smoke for a dark or a light page and picks the matching default colours.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        size
      </code>
    </td>
    
    <td>
      <code>
        'small' | 'medium' | 'large' | 'extra-large'
      </code>
    </td>
    
    <td>
      <code>
        'medium'
      </code>
    </td>
    
    <td>
      Button size. The pods, jets, flames and smoke scale with it.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        radius
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        undefined
      </code>
    </td>
    
    <td>
      Corner radius in pixels. Fully rounded when unset.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        altitude
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        170
      </code>
    </td>
    
    <td>
      How high the button climbs, in pixels. Capped by the container height.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        hover-time
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        2.4
      </code>
    </td>
    
    <td>
      Seconds it hovers at altitude before it comes back down and lands.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        jets
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        2
      </code>
    </td>
    
    <td>
      Number of exhaust jets under the button, from 1 to 4.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        thrusters
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      Shows thruster pods under the button. Off, the jets fire straight out of its underside.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        trigger
      </code>
    </td>
    
    <td>
      <code>
        'hover' | 'click'
      </code>
    </td>
    
    <td>
      <code>
        'hover'
      </code>
    </td>
    
    <td>
      Whether hovering or clicking starts the flight. Touch always starts it on tap. With the ramp on, a click rides.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        carry-cursor
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      Carries the cursor up with the button while you hover it, and sets it back down on landing.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        smoke
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        1
      </code>
    </td>
    
    <td>
      How much smoke the jets and the ground blast put out.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        turbulence
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        1
      </code>
    </td>
    
    <td>
      How much the smoke curls and billows.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        wobble
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        1
      </code>
    </td>
    
    <td>
      Strength of the gusts the flight controller fights while it hovers. <code>
        0
      </code>
      
       flies dead steady.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        ramp
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        false
      </code>
    </td>
    
    <td>
      Adds a loop ramp on the right. A click drives the button up the wall and along the ceiling, then it flips off.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        thrust-color
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      theme
    </td>
    
    <td>
      Colour of the jet flames and the light they cast. <code>
        #8ec5ff
      </code>
      
       dark, <code>
        #4f8cff
      </code>
      
       light.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        smoke-color
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      theme
    </td>
    
    <td>
      Base colour of the smoke. Its shadows are derived from it.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        button-color
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      theme
    </td>
    
    <td>
      Button fill. <code>
        #27272a
      </code>
      
       dark, <code>
        #18181b
      </code>
      
       light.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        text-color
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      theme
    </td>
    
    <td>
      Label colour.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        ramp-color
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      theme
    </td>
    
    <td>
      Ramp colour. Defaults to a raised surface for the theme.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        class
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        undefined
      </code>
    </td>
    
    <td>
      Extra classes for the root.
    </td>
  </tr>
</tbody>
</table>

## Events

<table>
<thead>
  <tr>
    <th>
      Event
    </th>
    
    <th>
      Payload
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        click
      </code>
    </td>
    
    <td>
      <code>
        MouseEvent | PointerEvent
      </code>
    </td>
    
    <td>
      Fires on click, including clicks while it is in the air. A drag of the flying button never emits.
    </td>
  </tr>
</tbody>
</table>

## Slots

<table>
<thead>
  <tr>
    <th>
      Slot
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        default
      </code>
    </td>
    
    <td>
      Button content. Falls back to the <code>
        label
      </code>
      
       prop.
    </td>
  </tr>
</tbody>
</table>

## Accessibility

- It is a real `<button type="button">`, so Tab focuses it and Enter or Space clicks it, with a visible focus ring.
- The smoke canvas, ramp, pods and the carried cursor are `aria-hidden`.
- With `prefers-reduced-motion: reduce` the button never takes off; it stays a normal button.
- Ported from [React Bits](https://reactbits.dev/micro/flying-button) by David Haz.
