# @spark-web/date-picker — AI Context

## What this package is

A single-date picker that combines a masked text input (`dd/MM/yyyy`) with a
pop-up month calendar. Users can either type a date in `dd/MM/yyyy` format or
click the calendar button to open a one-month view and select a day. The
calendar header offers month and year dropdowns (as well as the prev/next
arrows) for quickly jumping across months and years. Exports a single component,
`DatePicker`. It is a controlled component — you own `value` (a
`Date | undefined`) and update it from `onChange`.

## What this is NOT

- Not a native `<input type="date">` — it renders a `@spark-web/text-input` with
  a custom masked format and a popper-positioned calendar, not the browser's
  native date control; do not expect native date semantics
- Not a date-range picker — `value` is a single `Date`; there is no start/end
  range API
- Not a date-time picker — it selects a calendar day only, with no time
  component
- Not its own labelled field — like the other form inputs it relies on a
  wrapping `@spark-web/field` for the label and disabled state (it reads
  `disabled` from `useFieldContext`)

## Props interface

`DatePicker` is the intersection of three groups. The calendar/value props are
its own; the remaining input props are forwarded to the underlying
`@spark-web/text-input` (`DateInputProps` minus the props the picker controls
itself — `buttonOnClick`, `buttonRef`, `children`, `onChange`, `value`).

| Prop                | Type                                    | Default | Notes                                                                                                                                   |
| ------------------- | --------------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| `value`             | `Date \| undefined`                     | —       | Controlled value of the field (required)                                                                                                |
| `onChange`          | `(day: Date \| undefined) => void`      | —       | Fired on calendar select or valid typed input                                                                                           |
| `minDate?`          | `Date`                                  | —       | Days before this date are not selectable                                                                                                |
| `maxDate?`          | `Date`                                  | —       | Days after this date are not selectable                                                                                                 |
| `initialMonth?`     | `Date`                                  | —       | Calendar month shown initially when no `value` set                                                                                      |
| `fromYear?`         | `number`                                | —       | Earliest year in the caption's year dropdown. Defaults to `minDate`'s year, else 100 years before now. Does not restrict day navigation |
| `toYear?`           | `number`                                | —       | Latest year in the caption's year dropdown. Defaults to `maxDate`'s year, else 10 years after now. Does not restrict day navigation     |
| `data?`             | `DataAttributeMap`                      | —       | Sets data attributes on the root `Stack`                                                                                                |
| `name?`             | `string`                                | —       | Forwarded to the text input                                                                                                             |
| `placeholder?`      | `string`                                | —       | Forwarded; defaults internally to `DD/MM/YYYY`                                                                                          |
| `required?`         | `boolean`                               | —       | Forwarded to the text input                                                                                                             |
| `autoComplete?`     | `HTMLInputAutoCompleteAttribute`        | —       | Forwarded to the text input                                                                                                             |
| `overflowStrategy?` | `'nowrap' \| 'truncate' \| 'breakword'` | —       | Manages text overflow on the input                                                                                                      |
| `onBlur?`           | `FocusEventHandler<HTMLInputElement>`   | —       | Forwarded (note: the component also sets its own blur logic)                                                                            |
| `onFocus?`          | `FocusEventHandler<HTMLInputElement>`   | —       | Forwarded (note: the component also sets its own focus logic)                                                                           |
| `onInput?`          | `FormEventHandler<HTMLInputElement>`    | —       | Forwarded to the text input                                                                                                             |

`type`, `pattern`, `inputMode`, and `children` are stripped from the forwarded
text-input props — they are fixed by the component.

## Token usage

`DatePicker` itself sets no raw color/spacing; it composes
`@spark-web/text-input` (which carries the field tokens) and renders the
calendar popover. Calendar positioning is handled by `react-popper`
(`placement: 'bottom-start'`, 8px offset) with `zIndex: 1` on the floating
layer. The trailing calendar trigger is a `BaseButton` (`@spark-web/button`)
with a `CalendarIcon` whose tone is `'disabled'` when the field is disabled,
else `'neutral'`. All visual tokens come from the composed Spark components and
the active theme.

## Composition

- Built from `Stack` (`@spark-web/stack`), `TextInput` + `InputAdornment`
  (`@spark-web/text-input`), `BaseButton` (`@spark-web/button`), `CalendarIcon`
  (`@spark-web/icon`), `useFieldContext` (`@spark-web/field`)
- The calendar is `CalendarSingle`, built on `react-day-picker`; positioning
  uses `react-popper`
- The calendar header (arrow nav + month/year dropdowns) is a custom `Caption`
  override (`calendar-caption.tsx`, `MonthYearCaption`). Arrows call
  `useNavigation().goToMonth(previous/nextMonth)`; tapping the month/year opens
  a full-card overlay list (also navigating via `goToMonth`). That list is a
  `react-select` instance rendered inline (no body portal) and styled with Spark
  tokens (`theme.components.textInput.menuOption`), matching the
  `@spark-web/combobox` react-select approach. The year range only bounds the
  dropdown list — it does not restrict day-by-day navigation
- Date parsing/formatting uses `date-fns` with the fixed format `dd/MM/yyyy`
- `disabled` is sourced from the surrounding `Field` via `useFieldContext`, not
  a direct prop

### Role in the vendor-admin patterns

In the vendor-admin patterns `DatePicker` serves two roles: a date filter on the
list page and a date field on the form page. In both cases it is wrapped in a
`@spark-web/field` so the label and disabled state resolve correctly, and it is
driven as a controlled input from local/form state.

## Correct usage

### A date field inside a Field (form-page pattern)

```tsx
import { DatePicker } from '@spark-web/date-picker';
import { Field } from '@spark-web/field';
import { useState } from 'react';

function StartDateField() {
  const [value, setValue] = useState<Date | undefined>();
  return (
    <Field label="Start date">
      <DatePicker value={value} onChange={setValue} />
    </Field>
  );
}
```

### Constrained to a selectable window

```tsx
import { addDays, subDays } from 'date-fns';

<Field label="Appointment date">
  <DatePicker
    value={value}
    onChange={setValue}
    minDate={subDays(new Date(), 7)}
    maxDate={addDays(new Date(), 30)}
  />
</Field>;
```

### Empty calendar opening on a specific month

```tsx
<Field label="Birth date">
  <DatePicker
    value={value}
    onChange={setValue}
    initialMonth={new Date('1990-01-01')}
  />
</Field>
```

## Do NOTs

- NEVER use `DatePicker` outside a `@spark-web/field` — it reads `disabled` from
  `useFieldContext`, and the label/accessibility come from `Field`
- NEVER treat it as uncontrolled — `value` and `onChange` are required; without
  them the typed/selected date has nowhere to go
- NEVER expect a non-`dd/MM/yyyy` mask — the input format is fixed in source; do
  not pass `pattern`/`type`/`inputMode` to change it (they are stripped)
- NEVER use it for date ranges or date-times — `value` is a single `Date`; use a
  range/time solution outside this package
- NEVER pass a string to `value` — it must be a `Date | undefined`; the string
  masking is an internal detail of the input

## Component gaps / known limitations

- Single date only — no range or multi-date selection, and no time-of-day
- The mask is hard-coded to `dd/MM/yyyy`; there is no locale/format prop
- `disabled` cannot be set directly on `DatePicker` — it must come from the
  enclosing `Field` context
- Consumer `onFocus`/`onBlur` are forwarded but the component attaches its own
  focus/blur behaviour (placeholder seeding, cursor positioning), so custom
  handlers run alongside that internal logic
