# Hover and press

The examples that import `shape-aware-morph` use the npm package. It is in progress. See [Install](https://shapcn.com/docs/install.md).

An icon can react to the pointer. Set `hover` and the icon plays when the pointer enters its button, or when the button gets focus. Set `press` and the icon plays when the pointer goes down (a mouse press or a tap), and when the user presses Enter or Space. The button's `click` still fires. The icon looks the same at the end. It never turns into another icon, unless you ask for that (see "Change the icon on click").

```html
<button type="button" aria-label="Notifications"><morph-icon name="bell" hover="grow"></morph-icon></button>
<button type="button" aria-label="Delete"><morph-icon name="trash" press="burst"></morph-icon></button>
```

Hover over the first icon and click the second one.

```html
<button type="button" aria-label="Notifications"><morph-icon name="bell" size="40" hover="grow"></morph-icon></button>
<button type="button" aria-label="Delete"><morph-icon name="trash" size="40" press="burst"></morph-icon></button>
```

Every style works on any icon of any family. The engine reads the shape, so the motion fits the icon. No point goes more than 3 units outside the 24 box. The stroke width never changes. Nothing fades. Strokes that touch each other stay joined, except in `cascade` (it draws the strokes in order) and in the ripple move of `wiggle`.

## Attributes

| Attribute | Values | Default |
| --- | --- | --- |
| `hover` | `wiggle`, `grow`, `bend`, `bold`, `cascade`, `move`, or `none` | none |
| `press` | `pop`, `squash`, `squat-jump`, `burst`, or `none` | none |
| `hover-strength`, `press-strength` | A number from 0.5 to 3. | `1.5` |
| `hover-duration`, `press-duration` | Milliseconds. | The style's own time. |

The old names still work: `hover="alive"` is `wiggle`, and `press="anticipate-jump"` is `squat-jump`. The default strength of `alive` is now 1.5 (in 0.1.0 it was 1). Set `hover-strength="1"` for the old size. A value that is not a style name does nothing. To turn a style off, set it to `none`. If you remove an attribute, the element keeps the last value.

## Hover styles

Hover over each icon. On a touch screen, tap it.

### wiggle

The engine picks one of four moves from the shape of the icon: `radiate`, `ripple`, `swing`, or `pop`. The bell swings, the sun radiates, and the heart pops. It lasts 600 ms.

```html
<button type="button" aria-label="Notifications"><morph-icon name="bell" size="40" hover="wiggle"></morph-icon></button>
<button type="button" aria-label="Brightness"><morph-icon name="sun" size="40" hover="wiggle"></morph-icon></button>
<button type="button" aria-label="Favorite"><morph-icon name="heart" size="40" hover="wiggle"></morph-icon></button>
```

### grow

The parts move out from the middle of the icon. The farther a part is from the middle, the more it moves. Then they spring back. It lasts 400 ms.

```html
<button type="button" aria-label="Home"><morph-icon name="house" size="40" hover="grow"></morph-icon></button>
<button type="button" aria-label="Search"><morph-icon name="search" size="40" hover="grow"></morph-icon></button>
<button type="button" aria-label="Profile"><morph-icon name="user" size="40" hover="grow"></morph-icon></button>
```

### bend

The lines bend like soft wire, and spring back. It lasts 400 ms.

```html
<button type="button" aria-label="Mail"><morph-icon name="mail" size="40" hover="bend"></morph-icon></button>
<button type="button" aria-label="Settings"><morph-icon name="settings" size="40" hover="bend"></morph-icon></button>
<button type="button" aria-label="Star"><morph-icon name="star" size="40" hover="bend"></morph-icon></button>
```

### bold

The strokes get heavier and stay heavy while the pointer is over the icon. When the pointer leaves, they go back from where they are. The swell takes 250 ms. On a touch screen, tap the icon to hold it and tap it again to let go.

```html
<button type="button" aria-label="Favorite"><morph-icon name="heart" size="40" hover="bold"></morph-icon></button>
<button type="button" aria-label="Bookmark"><morph-icon name="bookmark" size="40" hover="bold"></morph-icon></button>
<button type="button" aria-label="Share"><morph-icon name="share" size="40" hover="bold"></morph-icon></button>
```

### cascade

The strokes erase along their own path and draw again, one after another. The body comes first and the parts follow. At least a part of every stroke stays drawn, so the icon is never empty. It lasts 500 ms.

```html
<button type="button" aria-label="Send"><morph-icon name="send" size="40" hover="cascade"></morph-icon></button>
<button type="button" aria-label="Trash"><morph-icon name="trash" size="40" hover="cascade"></morph-icon></button>
<button type="button" aria-label="Play"><morph-icon name="play" size="40" hover="cascade"></morph-icon></button>
```

### move

The icon hangs from its top (a bell) or stands on its base (a house, a trash can). It sways with the speed of the pointer, live. Move the pointer across the icon slowly and fast. When the pointer leaves, the icon swings back and settles quickly. The default time is 900 ms.

```html
<button type="button" aria-label="Notifications"><morph-icon name="bell" size="40" hover="move"></morph-icon></button>
<button type="button" aria-label="Trash"><morph-icon name="trash" size="40" hover="move"></morph-icon></button>
<button type="button" aria-label="Home"><morph-icon name="house" size="40" hover="move"></morph-icon></button>
```

## Press styles

Press each icon with the mouse, or tap it.

### pop

The icon grows a little and settles. It lasts 300 ms.

```html
<button type="button" aria-label="Like"><morph-icon name="heart" size="40" press="pop"></morph-icon></button>
<button type="button" aria-label="Save"><morph-icon name="bookmark" size="40" press="pop"></morph-icon></button>
```

### squash

The icon squashes down and springs back with a small stretch. It lasts 300 ms.

```html
<button type="button" aria-label="Like"><morph-icon name="star" size="40" press="squash"></morph-icon></button>
<button type="button" aria-label="Mail"><morph-icon name="mail" size="40" press="squash"></morph-icon></button>
```

### squat-jump

The icon squats, jumps, and lands with a small squash. It lasts 500 ms.

```html
<button type="button" aria-label="Follow"><morph-icon name="user-plus" size="40" press="squat-jump"></morph-icon></button>
<button type="button" aria-label="Play"><morph-icon name="play" size="40" press="squat-jump"></morph-icon></button>
```

### burst

The parts fly out from the middle of the icon and snap back. It lasts 500 ms.

```html
<button type="button" aria-label="Delete"><morph-icon name="trash" size="40" press="burst"></morph-icon></button>
<button type="button" aria-label="Settings"><morph-icon name="settings" size="40" press="burst"></morph-icon></button>
```

## Change the icon on click

A press can change the icon. The new icon morphs while the press plays, so the click and the change are one motion. Call `pressTo(name)` on the element. Or set the `name` attribute while the press runs. The press starts on pointer down, and the click comes a moment later, so setting `name` in a click handler joins the press that plays.

```html
<button type="button" id="delete-demo" aria-label="Delete"><morph-icon name="trash" size="40" press="burst"></morph-icon></button>
<script type="module">
  const button = document.getElementById('delete-demo');
  const icon = button.querySelector('morph-icon');
  let done = false;
  button.addEventListener('click', () => {
    done = !done;
    icon.pressTo(done ? 'check' : 'trash');
  });
</script>
```

The press style comes from the `press` attribute. Without it, `pressTo` uses `squash`. The Promise gives `true` when the run ends.

## Strength and time

`hover-strength` and `press-strength` set how far the motion goes. The range is 0.5 to 3. The default is 1.5. The engine keeps every style inside the 3 unit limit, so a high strength on a big icon gives a little less than you ask for.

```html
<button type="button" aria-label="Mail"><morph-icon name="mail" size="40" hover="bend" hover-strength="0.5"></morph-icon></button>
<button type="button" aria-label="Mail"><morph-icon name="mail" size="40" hover="bend" hover-strength="1.5"></morph-icon></button>
<button type="button" aria-label="Mail"><morph-icon name="mail" size="40" hover="bend" hover-strength="3"></morph-icon></button>
```

`hover-duration` and `press-duration` set the time in milliseconds. Each style has its own default time (see the lists above).

## Focus, touch and reduced motion

- Hover also plays when the button gets keyboard focus. The handler goes on the nearest `button`, `a`, `input`, `select`, `textarea`, or element with `tabindex` or `role="button"`. If there is none, it goes on the icon.
- Press also plays on Enter and Space.
- A touch screen has no hover. A tap plays the hover style once. A tap on a `bold` icon holds it until a second tap or a tap elsewhere.
- With `prefers-reduced-motion: reduce`, hover and press do nothing. A press that changes the icon changes it at once.
- A morph that runs wins over a hover. A press replaces a hover that runs.
- When the pointer leaves in the middle of a hover, the icon goes back to rest from where it is. It does not jump. When the pointer comes back, it goes on from where it is. Two styles finish their short run instead: `wiggle` and `cascade`.

## In code

Each style is a plan with `frame(t)`, like `planMorph`. At `t = 0` and `t = 1` the plan draws the rest icon. With `to`, it draws the old icon at `t = 0` and the new icon at `t = 1`.

```js
import { registerLucide, planAlive, planPress, createSway } from 'shape-aware-morph';

await registerLucide();
console.log(planAlive('house', { style: 'grow' }).frame(0.3).length > 0);
console.log(planPress('trash', { style: 'burst', to: 'check' }).frame(0.5).length > 0);
const sway = createSway('bell');   // the live sway of hover="move"
sway.push(0.8);                    // the pointer came in fast, to the right
console.log(sway.frame(16).length > 0);
```

`createSway(name)` runs frame by frame. Call `sway.setInput(vx)` while the pointer moves over the icon (`vx` from -1 to 1), `sway.release()` when it leaves, and `sway.frame(now)` on every animation frame until `sway.atRest` is `true`. The element does this for you.

`planAlive(name, { style, strength })` takes a hover style. `planPress(name, { style, strength, to })` takes a press style. The export `HOVER_STYLES` lists the hover styles, and `PRESS_STYLES` lists the press styles. Both are in the npm package. The script tag build also has them on `window.shapcn`, together with `planPress` and `createSway`.
