# DatePicker

> Calendar-driven date picker with single or range mode, day / month / year views, optional time picker with configurable defaults, min/max constraints, and Turkish or English locales.

- Available in: `@sisyphos-ui/react`, `@sisyphos-ui/vue`, `@sisyphos-ui/angular`
- Docs: https://sisyphosui.com/docs/components/datepicker

## Installation

Pick the framework binding that matches your stack:

```bash
pnpm add @sisyphos-ui/react   # React 18+
pnpm add @sisyphos-ui/vue     # Vue 3+
pnpm add @sisyphos-ui/angular # Angular 17+
```

## Import

```tsx
import "@sisyphos-ui/react/styles.css";
import { DatePicker } from "@sisyphos-ui/react";
```

## Framework usage

### React 18+

```tsx
import { useState } from "react";
import { DatePicker } from "@sisyphos-ui/react";

export const Birthday = () => {
  const [date, setDate] = useState<Date | null>(null);
  return <DatePicker label="Birthday" value={date} onChange={setDate} />;
};
```

### Vue 3+

```vue
<script setup lang="ts">
import { ref } from "vue";
import { DatePicker } from "@sisyphos-ui/vue";
const date = ref<Date | null>(null);
</script>

<template>
  <DatePicker label="Birthday" v-model="date" />
</template>
```

### Angular 17+

```ts
import { Component, signal } from "@angular/core";
import { DatePicker } from "@sisyphos-ui/angular";

@Component({
  selector: "app-birthday",
  standalone: true,
  imports: [DatePicker],
  template: `<sui-datepicker label="Birthday" [(value)]="date" />`,
})
export class BirthdayComponent {
  date = signal<Date | null>(null);
}
```

## Examples

### Default

```tsx
import { useState } from "react";
import { DatePicker } from "@sisyphos-ui/react";

export function Example() {
  const [date, setDate] = useState<Date | null>(null);

  return (
    <div className="w-full max-w-[260px]">
      <DatePicker label="Start date" value={date} onChange={setDate} />
    </div>
  );
}
```

### Range mode

Add `isRange` and a `[Date | null, Date | null]` value.

```tsx
import { useState } from "react";
import { DatePicker } from "@sisyphos-ui/react";

export function Example() {
  const [range, setRange] = useState<[Date | null, Date | null]>([null, null]);

  return (
    <div className="w-full max-w-[320px]">
      <DatePicker isRange label="Booking window" value={range} onChange={setRange} />
    </div>
  );
}
```

### Min/max bounds

Restrict selectable dates with `minDate` / `maxDate`.

```tsx
import { useState } from "react";
import { DatePicker } from "@sisyphos-ui/react";

export function Example() {
  const [date, setDate] = useState<Date | null>(new Date());
  const today = new Date();
  const min = new Date(today.getFullYear(), today.getMonth(), today.getDate());
  const max = new Date(today.getFullYear(), today.getMonth() + 3, today.getDate());

  return (
    <DatePicker
      label="Booking date"
      value={date}
      onChange={setDate}
      minDate={min}
      maxDate={max}
    />
  );
}
```

### Custom format & locale

`format` controls the display string; `locale` drives weekday and month names.

```tsx
import { useState } from "react";
import { DatePicker } from "@sisyphos-ui/react";

export function Example() {
  const [date, setDate] = useState<Date | null>(new Date());

  return (
    <DatePicker
      label="Event date (US format)"
      value={date}
      onChange={setDate}
      format="MM/dd/yyyy"
      locale="en"
    />
  );
}
```

### With time picker

`showTime` adds hour/minute selectors with configurable `minuteStep`.

```tsx
import { useState } from "react";
import { DatePicker } from "@sisyphos-ui/react";

export function Example() {
  const [date, setDate] = useState<Date | null>(new Date());

  return (
    <DatePicker
      label="Start"
      value={date}
      onChange={setDate}
      showTime
      format="dd.MM.yyyy HH:mm"
      minuteStep={15}
    />
  );
}
```

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| value | `Date \| null  \|  [Date \| null, Date \| null]` | — | Selected date, or `[start, end]` when `isRange` is true. |
| onChange | `(value) => void` | — | Called with the next value. |
| isRange | `boolean` | `false` | Switches between single-date and range modes. |
| label | `string` | — | Field label rendered above the trigger. |
| placeholder | `string` | — | Trigger placeholder. Localized default. |
| variant | `"standard" \| "outlined"` | `"outlined"` | Visual treatment. |
| size | `"sm" \| "md" \| "lg"` | `"md"` | Field height + typography scale. |
| minDate | `Date` | — | Earliest selectable date. |
| maxDate | `Date` | — | Latest selectable date. |
| format | `string` | — | Trigger format. Supports `yyyy/MM/dd/HH/mm`. Defaults to `dd.MM.yyyy` (or with time). |
| locale | `"tr" \| "en"` | `"tr"` | Locale for weekday and month names. |
| showTime | `boolean` | `false` | Adds an hour/minute picker below the calendar. |
| minuteStep | `number` | `15` | Minute increments inside the time picker. |
| defaultHour | `number` | `0` | Hour applied on the first date pick when no time is set yet. |
| defaultMinute | `number` | `0` | Minute applied alongside `defaultHour`. |
| defaultStartHour | `number` | — | Range mode: default hour for the start date. Falls back to `defaultHour`. |
| defaultStartMinute | `number` | — | Range mode: default minute for the start date. Falls back to `defaultMinute`. |
| defaultEndHour | `number` | — | Range mode: default hour for the end date. Falls back to `defaultHour`. |
| defaultEndMinute | `number` | — | Range mode: default minute for the end date. Falls back to `defaultMinute`. |
| allowClear | `boolean` | `false` | Show a clear button on the trigger when a value is present. |
| fullWidth | `boolean` | `false` | Stretch the trigger to its container. |
| calendarIcon | `ReactNode` | — | Override the default calendar icon. |
| placement | `Placement` | `"bottom-start"` | Initial popover placement (auto-flips when needed). |
| error | `boolean` | `false` | Marks the field as invalid for styling and ARIA. |
| errorMessage | `string` | — | Message shown below the field when `error` is true. |

## Keyboard interactions

- **Tab** — Moves focus through the trigger and the in-popover controls.
- **ArrowUp + ArrowDown** — Steps through months in the months view, decades in the years view.
- **Esc** — Closes the popover.

## Accessibility notes

- Trigger input wires `aria-haspopup="dialog"`, `aria-expanded`, and a unique `id`/`aria-controls` link to the popover.
- The popover uses `role="dialog"` and is portal-mounted with auto-flip placement.
- `aria-invalid` mirrors `error`; the error message uses `role="alert"`.
- Calendar navigation buttons carry descriptive `aria-label`s.

<!-- exports: { "DatePicker": "@sisyphos-ui/react" } -->