```tsx
import type { Selection, Adapter, Grid } from '@gentleduck/calendar'
import { selectDay, applySelection } from '@gentleduck/calendar'
```

## Functions

### `selectDay`

Compute the new selection value when a user clicks a day. Pure function - does not mutate state.

```tsx
selectDay(adapter: Adapter.IDateAdapter<TDate>, mode: Selection.SelectionMode, current: Selection.CalendarValue<TDate, M>, date: TDate, options?: { shiftKey?: boolean }) => Selection.CalendarValue<TDate, M>
```

| Param | Type | Description |
| :--- | :--- | :--- |
| `adapter` | `Adapter.IDateAdapter<TDate>` | Date adapter |
| `mode` | `Selection.SelectionMode` | `'single'`, `'range'`, `'multi'`, or `'multi-range'` |
| `current` | `Selection.CalendarValue<TDate, M>` | Current selection value |
| `date` | `TDate` | The clicked date |
| `options` | `{ shiftKey?: boolean }` | Optional. When `shiftKey` is true in `multi-range` mode, extends the last range |

**Returns** the updated selection value. Shape depends on mode:

| Mode | Type | Description |
| :--- | :--- | :--- |
| `'single'` | `TDate \| null` | The selected date, or `null` |
| `'range'` | `Selection.DateRange<TDate> \| null` | `{ from, to }` range object |
| `'multi'` | `TDate[]` | Array of selected dates |
| `'multi-range'` | `Selection.DateRange<TDate>[]` | Array of range objects |

***

### `applySelection`

Decorate an array of weeks with selection flags (`isSelected`, `isRangeStart`, `isRangeMiddle`, `isRangeEnd`, `isDisabled`). This is what makes the `data-*` attributes work.

```tsx
applySelection(
  weeks: Grid.ICalendarWeek<TDate>[],
  adapter: Adapter.IDateAdapter<TDate>,
  mode: Selection.SelectionMode,
  selected: Selection.CalendarValue<TDate, M>,
  constraints?: Selection.ISelectionConstraints<TDate> // default: {}
) => Grid.ICalendarWeek<TDate>[]
```

| Param | Type | Description |
| :--- | :--- | :--- |
| `weeks` | `Grid.ICalendarWeek<TDate>[]` | Raw weeks from `buildCalendarMonth` |
| `adapter` | `Adapter.IDateAdapter<TDate>` | Date adapter |
| `mode` | `Selection.SelectionMode` | Selection mode |
| `selected` | `Selection.CalendarValue<TDate, M>` | Current selection |
| `constraints` | `Selection.ISelectionConstraints<TDate>` | Optional. Disabled dates, fromDate, toDate. Defaults to `{}` |

**Selection.ISelectionConstraints:**

| Property | Type | Description |
| :--- | :--- | :--- |
| `disabled` | `TDate[] \| (date) => boolean` | Disabled dates |
| `fromDate` | `TDate` | Earliest selectable date |
| `toDate` | `TDate` | Latest selectable date |

***

## Types

### `Selection.SelectionMode`

```tsx
type Selection.SelectionMode = 'single' | 'range' | 'multi' | 'multi-range'
```

### `Selection.CalendarValue<TDate, M>`

Conditional type that resolves based on the selection mode:

```tsx showLineNumbers
type Selection.CalendarValue<TDate, M extends Selection.SelectionMode> =
  M extends 'single' ? TDate | null :
  M extends 'range' ? Selection.DateRange<TDate> | null :
  M extends 'multi' ? TDate[] :
  M extends 'multi-range' ? Selection.DateRange<TDate>[] :
  never
```

### `Selection.DateRange<TDate>`

```tsx showLineNumbers
type Selection.DateRange<TDate> = {
  from: TDate
  to: TDate | null
}
```