# Dial

> [llms.txt](https://zriz.dev/llms.txt)

The ruler that levels a tilted photo, up to 45° each way, like the one in iOS Photos.

The page at https\://zriz.dev/docs/dial runs this cropper: a 3:2 photo, the straighten dial with its value, and open, reset and download in the corners.

## Anatomy

Put `DialTicks` inside `Dial`. `Dial` and `DialValue` go anywhere inside `Root`:

```tsx
<Cropper.DialValue />
<Cropper.Dial aria-label="Straighten">
  <Cropper.DialTicks />
</Cropper.Dial>
```

The stylesheet makes `Dial` 40 px tall and clips its ticks at the sides only, so the zero dot above them stays in view, and fades them out over 48 px at each side. It draws the ticks and the centre line. `DialValue` ships bare.

The demo above shows the angle to one decimal with a degree sign and uses the styles from the zriz site.

## Drag and flick the ruler

The first 10 px of a drag only pick up the ruler. After that, every 4 px turns 1°. A quick flick keeps it gliding after you let go, and past the limit it stretches and springs back. On touch, a vertical swipe scrolls the page instead.

The ruler reads like a ruler, with positive angles to the right of 0°. Drag it left, or press the right arrow, and the angle grows past the centre line.

A drag catches at 0°. Within 1° of it the angle holds at exactly 0°, and past that it carries on from 0° without a jump, so a level horizon takes no fiddling. A flick that comes to rest within 1° lands on 0°. Keys, the wheel and `setRotation` keep the exact angle.

The photo zooms in as the angle grows. One gesture back to 0° restores the zoom. Separate gestures keep it, as in iOS Photos, until `Reset` or `Zoom` takes it back.

## Set the ruler width

`Dial` fills its parent's width. Ticks sit 9 px apart, one every 2.25°, so 361 px fits all 41 ticks:

```tsx
<Cropper.Dial aria-label="Straighten" style={{ maxWidth: 361 }}>
  <Cropper.DialTicks />
</Cropper.Dial>
```

The demo above is 360 px wide, as on the zriz site, so its outermost ticks fall on the edges.

## Add a degree sign

`format` on `DialValue` gets the angle in degrees and returns the text to show:

```tsx
<Cropper.DialValue
  format={(angle) =>
    `${Math.sign(angle) * Math.round(Math.abs(angle))}°`
  }
/>
```

## Make the major ticks taller

Ticks carry no `data-zriz-item`. Select them through `DialTicks`:

```css
[data-zriz-item="dial-ticks"] > [data-major] {
  height: 14px;
}
```

## Change the drag colour

The centre line takes the accent colour while you drag. `--zriz-accent` sets it, and [styling](https://zriz.dev/docs/styling.md) lists its default:

```css
[data-zriz-item="dial"] {
  --zriz-accent: #0a84ff;
}
```

## Keyboard

These keys work while `Dial` has focus:

| Key | What it does |
| - | - |
| `left` or `right` | Lower or raise the angle by 1° |
| `up` or `down` | Raise or lower the angle by 1° |
| `shift` + `arrow keys` | The same by 10° |
| `page up` or `page down` | Raise or lower the angle by 10° |
| `home` or `end` | Go to the lowest or the highest angle, −45° or 45° at most |
| `0` | Straighten to 0° |

On a right-to-left page or with `dir="rtl"` on `Root`, left and right swap. Up and down stay the same. The ticks read the direction when they draw, so after a page flips its `dir` they follow at the next draw. A new `dir` on `Root` redraws them at once.

Escape during a drag cancels it and puts the angle back.

## API

### `Dial`

Renders a `<div role="slider">` anywhere inside `Root`. Every part also takes `className`, `render` and the props of its element, see [composition](https://zriz.dev/docs/composition.md). `className` and `render` get `{ dragging }`.

- `aria-label` `string`

  Names the slider for screen readers. Development builds warn without it
- `format` `Intl.NumberFormatOptions`

  How screen readers hear the angle, merged over the default `"5 degrees"`. An `aria-valuetext` of yours wins over it

| Attribute | When |
| - | - |
| `data-dragging` | While a pointer drags any `Dial` of this cropper, so a second copy lights up too |
| `data-snapped` | While the angle rests at exactly 0°, from the start too. The zero dot hides then. A drag through 0° leaves it as it was until you let go |

| Variable | What it sets |
| - | - |
| `--zriz-line` | Paints the centre line, the zero dot and the major ticks. [Styling](https://zriz.dev/docs/styling.md) lists its light and dark values |
| `--zriz-accent` | Paints the centre line while you drag. [Styling](https://zriz.dev/docs/styling.md) lists its default |

### `DialTicks`

Renders an `aria-hidden` `<div>` of `<span>` ticks inside `Dial`. `className` and `render` get `{ count }`.

- `count` `number` = `41`

  How many ticks to draw, 2.25° apart. 41 spans 45° each way. Use an odd count so one tick sits at 0°

| Attribute | When |
| - | - |
| `data-major` | Every tenth tick from the centre: 0°, 22.5° and 45° each way |
| `data-zero` | The centre tick, at 0° |
| `data-fade` | `"0"`, `"1"` or `"2"` on the last three ticks at each end, outermost `"0"` |

| Variable | What it sets |
| - | - |
| `--zriz-tick` | Paints the minor ticks. [Styling](https://zriz.dev/docs/styling.md) lists its light and dark values |
| `--zriz-tick-index` | On each tick, its index from the left, from 0 to `count` minus 1 |

### `DialValue`

Renders an `aria-hidden` `<span>` anywhere inside `Root`. zriz writes its text, so it takes no children, and neither does a `render` element.

- `format` `(angle: number) => string`

  Turns the angle into the text shown. The default rounds it and adds no unit
