# Stay Picker

Pick a stay night by night, with prices in the grid. A range cannot cross a booked night.

Tier: Free

## Installation

```bash
npx shadcn add @fetaui/stay-picker
```

## Usage

```tsx
import { useState } from 'react'
import { StayPicker, type StaySelection } from '@/components/fetaui/stay-picker'

export function Example() {
  const [stay, setStay] = useState<StaySelection>({ from: null, to: null })
  return <StayPicker month={month} priceFor={nightlyPrice} value={stay} onChange={setStay} onReserve={reserve} />
}
```

## API

| Prop | Type | Default |
|---|---|---|
| month | Date | required |
| priceFor | (night) => number or null | required |
| currency | string | $ |
| currencyName | string | USD |
| value | { from, to } with Date or null |  |
| defaultValue | { from, to } with Date or null | nothing picked |
| onChange | (value) => void |  |
| minNights | number | 1 |
| maxNights | number |  |
| onReserve | (stay, total) => void or Promise |  |
| failedMessage | string | Could not reserve these nights. Try again. |
| locale | string | en-US |
| animated | boolean | true |
| className | string |  |

## When to use

- For bookings priced per night.
- When a stay has a minimum or maximum length.

## When not to use

- For dates with no prices: use Date Picker.

## Accessibility

- Each night reads its date, its price or full, and whether it is the check-in or check-out.
- Booked nights are aria-disabled but stay focusable, and a click on one explains why it is refused.
- Refusals and totals are announced.

## Motion

- Hover or focus previews a valid range at 4%.
- A refused pick rings that night in danger and slides a message in.
- Reserved turns the button secondary with a check and the total green.
- With reduced motion, these changes are instant.
