or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

date-field-state.mddate-picker-state.mddate-range-picker-state.mdindex.mdtime-field-state.md

index.mddocs/

0

# @react-stately/datepicker

1

2

@react-stately/datepicker is a React state management library that provides hooks for date picker components as part of Adobe's React Spectrum ecosystem. It offers cross-platform state management functionality through hooks that handle date selection, validation, formatting, and overlay state management with full internationalization support.

3

4

## Package Information

5

6

- **Package Name**: @react-stately/datepicker

7

- **Package Type**: npm

8

- **Language**: TypeScript

9

- **Installation**: `npm install @react-stately/datepicker`

10

11

## Core Imports

12

13

```typescript

14

import {

15

useDatePickerState,

16

useDateFieldState,

17

useDateRangePickerState,

18

useTimeFieldState,

19

type DatePickerState,

20

type DatePickerStateOptions,

21

type DateFieldState,

22

type DateFieldStateOptions,

23

type DateRangePickerState,

24

type DateRangePickerStateOptions,

25

type TimeFieldState,

26

type TimeFieldStateOptions,

27

type DateSegment,

28

type SegmentType,

29

type FormatterOptions

30

} from "@react-stately/datepicker";

31

```

32

33

For CommonJS:

34

35

```javascript

36

const {

37

useDatePickerState,

38

useDateFieldState,

39

useDateRangePickerState,

40

useTimeFieldState

41

} = require("@react-stately/datepicker");

42

```

43

44

## Basic Usage

45

46

```typescript

47

import { useDatePickerState, useDateFieldState } from "@react-stately/datepicker";

48

import { CalendarDate, createCalendar } from "@internationalized/date";

49

50

function MyDatePicker() {

51

const state = useDatePickerState({

52

defaultValue: new CalendarDate(2023, 6, 15),

53

onChange: (value) => console.log("Selected:", value?.toString()),

54

granularity: 'day'

55

});

56

57

return (

58

<div>

59

<button onClick={() => state.setOpen(!state.isOpen)}>

60

{state.value?.toString() || "Select date"}

61

</button>

62

{state.isOpen && (

63

<div>Calendar would be rendered here</div>

64

)}

65

</div>

66

);

67

}

68

69

function MyDateField() {

70

const state = useDateFieldState({

71

locale: 'en-US',

72

createCalendar,

73

defaultValue: new CalendarDate(2023, 6, 15),

74

onChange: (value) => console.log("Field value:", value?.toString())

75

});

76

77

return (

78

<div>

79

{state.segments.map((segment, i) => (

80

<span key={i} aria-label={segment.type}>

81

{segment.text}

82

</span>

83

))}

84

</div>

85

);

86

}

87

```

88

89

## Architecture

90

91

@react-stately/datepicker is built around several key components:

92

93

- **State Management Hooks**: Four specialized hooks for different date/time input scenarios

94

- **Internationalization Support**: Built on @internationalized/date for cross-calendar system support

95

- **Form Integration**: Extends @react-stately/form for validation and error handling

96

- **Overlay Management**: Integrates with @react-stately/overlays for popover state

97

- **Segment-based Editing**: Individual editable segments for precise date/time input

98

- **Type Safety**: Full TypeScript support with generic date value types

99

100

## Capabilities

101

102

### Date Picker State

103

104

Core state management for date picker components that combine a text field with a calendar popover. Handles date selection, time selection, validation, and overlay state.

105

106

```typescript { .api }

107

function useDatePickerState<T extends DateValue = DateValue>(

108

props: DatePickerStateOptions<T>

109

): DatePickerState;

110

111

interface DatePickerStateOptions<T extends DateValue> extends DatePickerProps<T> {

112

/**

113

* Determines whether the date picker popover should close automatically when a date is selected.

114

* @default true

115

*/

116

shouldCloseOnSelect?: boolean | (() => boolean);

117

}

118

119

interface DatePickerState extends OverlayTriggerState, FormValidationState {

120

/** The currently selected date. */

121

value: DateValue | null;

122

/** The default date. */

123

defaultValue: DateValue | null;

124

/** Sets the selected date. */

125

setValue(value: DateValue | null): void;

126

/**

127

* The date portion of the value. This may be set prior to `value` if the user has

128

* selected a date but has not yet selected a time.

129

*/

130

dateValue: DateValue | null;

131

/** Sets the date portion of the value. */

132

setDateValue(value: DateValue): void;

133

/**

134

* The time portion of the value. This may be set prior to `value` if the user has

135

* selected a time but has not yet selected a date.

136

*/

137

timeValue: TimeValue | null;

138

/** Sets the time portion of the value. */

139

setTimeValue(value: TimeValue): void;

140

/** The granularity for the field, based on the `granularity` prop and current value. */

141

granularity: Granularity;

142

/** Whether the date picker supports selecting a time, according to the `granularity` prop and current value. */

143

hasTime: boolean;

144

/** Whether the calendar popover is currently open. */

145

isOpen: boolean;

146

/** Sets whether the calendar popover is open. */

147

setOpen(isOpen: boolean): void;

148

/**

149

* The current validation state of the date picker, based on the `validationState`, `minValue`, and `maxValue` props.

150

* @deprecated Use `isInvalid` instead.

151

*/

152

validationState: ValidationState | null;

153

/** Whether the date picker is invalid, based on the `isInvalid`, `minValue`, and `maxValue` props. */

154

isInvalid: boolean;

155

/** Formats the selected value using the given options. */

156

formatValue(locale: string, fieldOptions: FieldOptions): string;

157

/** Gets a formatter based on state's props. */

158

getDateFormatter(locale: string, formatOptions: FormatterOptions): DateFormatter;

159

}

160

```

161

162

[Date Picker State](./date-picker-state.md)

163

164

### Date Field State

165

166

State management for date field components with individually editable segments. Each part of a date value is displayed in a separate editable segment (year, month, day, etc.).

167

168

```typescript { .api }

169

function useDateFieldState<T extends DateValue = DateValue>(

170

props: DateFieldStateOptions<T>

171

): DateFieldState;

172

173

interface DateFieldStateOptions<T extends DateValue = DateValue> extends DatePickerProps<T> {

174

/**

175

* The maximum unit to display in the date field.

176

* @default 'year'

177

*/

178

maxGranularity?: 'year' | 'month' | Granularity;

179

/** The locale to display and edit the value according to. */

180

locale: string;

181

/**

182

* A function that creates a Calendar object for a given calendar identifier.

183

* Such a function may be imported from the @internationalized/date package.

184

*/

185

createCalendar: (name: CalendarIdentifier) => Calendar;

186

}

187

188

interface DateFieldState extends FormValidationState {

189

/** The current field value. */

190

value: DateValue | null;

191

/** The default field value. */

192

defaultValue: DateValue | null;

193

/** The current value, converted to a native JavaScript Date object. */

194

dateValue: Date;

195

/** The calendar system currently in use. */

196

calendar: Calendar;

197

/** Sets the field's value. */

198

setValue(value: DateValue | null): void;

199

/** A list of segments for the current value. */

200

segments: DateSegment[];

201

/** A date formatter configured for the current locale and format. */

202

dateFormatter: DateFormatter;

203

/**

204

* The current validation state of the date field, based on the `validationState`, `minValue`, and `maxValue` props.

205

* @deprecated Use `isInvalid` instead.

206

*/

207

validationState: ValidationState | null;

208

/** Whether the date field is invalid, based on the `isInvalid`, `minValue`, and `maxValue` props. */

209

isInvalid: boolean;

210

/** The granularity for the field, based on the `granularity` prop and current value. */

211

granularity: Granularity;

212

/** The maximum date or time unit that is displayed in the field. */

213

maxGranularity: 'year' | 'month' | Granularity;

214

/** Whether the field is disabled. */

215

isDisabled: boolean;

216

/** Whether the field is read only. */

217

isReadOnly: boolean;

218

/** Whether the field is required. */

219

isRequired: boolean;

220

/** Increments the given segment. Upon reaching the minimum or maximum value, the value wraps around to the opposite limit. */

221

increment(type: SegmentType): void;

222

/** Decrements the given segment. Upon reaching the minimum or maximum value, the value wraps around to the opposite limit. */

223

decrement(type: SegmentType): void;

224

/**

225

* Increments the given segment by a larger amount, rounding it to the nearest increment.

226

* The amount to increment by depends on the field, for example 15 minutes, 7 days, and 5 years.

227

* Upon reaching the minimum or maximum value, the value wraps around to the opposite limit.

228

*/

229

incrementPage(type: SegmentType): void;

230

/**

231

* Decrements the given segment by a larger amount, rounding it to the nearest increment.

232

* The amount to decrement by depends on the field, for example 15 minutes, 7 days, and 5 years.

233

* Upon reaching the minimum or maximum value, the value wraps around to the opposite limit.

234

*/

235

decrementPage(type: SegmentType): void;

236

/** Sets the value of the given segment. */

237

setSegment(type: 'era', value: string): void;

238

setSegment(type: SegmentType, value: number): void;

239

/** Updates the remaining unfilled segments with the placeholder value. */

240

confirmPlaceholder(): void;

241

/** Clears the value of the given segment, reverting it to the placeholder. */

242

clearSegment(type: SegmentType): void;

243

/** Formats the current date value using the given options. */

244

formatValue(fieldOptions: FieldOptions): string;

245

/** Gets a formatter based on state's props. */

246

getDateFormatter(locale: string, formatOptions: FormatterOptions): DateFormatter;

247

}

248

```

249

250

[Date Field State](./date-field-state.md)

251

252

### Date Range Picker State

253

254

State management for date range picker components that allow users to select a start and end date. Combines two date fields with a range calendar popover.

255

256

```typescript { .api }

257

function useDateRangePickerState<T extends DateValue = DateValue>(

258

props: DateRangePickerStateOptions<T>

259

): DateRangePickerState;

260

261

interface DateRangePickerStateOptions<T extends DateValue = DateValue> extends DateRangePickerProps<T> {

262

/**

263

* Determines whether the date range picker popover should close automatically when a date range is selected.

264

* @default true

265

*/

266

shouldCloseOnSelect?: boolean | (() => boolean);

267

}

268

269

interface DateRangePickerState extends OverlayTriggerState, FormValidationState {

270

/** The currently selected date range. */

271

value: RangeValue<DateValue | null>;

272

/** The default date range. */

273

defaultValue: DateRange | null;

274

/** Sets the selected date range. */

275

setValue(value: DateRange | null): void;

276

/** The date range portion of the value. This may be set prior to `value` if the user has selected dates but not times. */

277

dateRange: RangeValue<DateValue | null> | null;

278

/** Sets the date range portion of the value. */

279

setDateRange(value: DateRange): void;

280

/** The time range portion of the value. This may be set prior to `value` if the user has selected times but not dates. */

281

timeRange: RangeValue<TimeValue | null> | null;

282

/** Sets the time range portion of the value. */

283

setTimeRange(value: TimeRange): void;

284

/** Sets the date for either the start or end of the range. */

285

setDate(part: 'start' | 'end', value: DateValue | null): void;

286

/** Sets the time for either the start or end of the range. */

287

setTime(part: 'start' | 'end', value: TimeValue | null): void;

288

/** Sets the date and time for either the start or end of the range. */

289

setDateTime(part: 'start' | 'end', value: DateValue | null): void;

290

/** The granularity for the field, based on the `granularity` prop and current value. */

291

granularity: Granularity;

292

/** Whether the date range picker supports selecting a time, according to the `granularity` prop and current value. */

293

hasTime: boolean;

294

/** Whether the calendar popover is currently open. */

295

isOpen: boolean;

296

/** Sets whether the calendar popover is open. */

297

setOpen(isOpen: boolean): void;

298

/**

299

* The current validation state of the date range picker, based on the `validationState`, `minValue`, and `maxValue` props.

300

* @deprecated Use `isInvalid` instead.

301

*/

302

validationState: ValidationState | null;

303

/** Whether the date range picker is invalid, based on the `isInvalid`, `minValue`, and `maxValue` props. */

304

isInvalid: boolean;

305

/** Formats the selected value using the given options. */

306

formatValue(locale: string, fieldOptions: FieldOptions): {start: string, end: string} | null;

307

/** Gets a formatter based on state's props. */

308

getDateFormatter(locale: string, formatOptions: FormatterOptions): DateFormatter;

309

}

310

```

311

312

[Date Range Picker State](./date-range-picker-state.md)

313

314

### Time Field State

315

316

State management for time field components that allow users to enter and edit time values. Each part of a time value is displayed in individually editable segments.

317

318

```typescript { .api }

319

function useTimeFieldState<T extends TimeValue = TimeValue>(

320

props: TimeFieldStateOptions<T>

321

): TimeFieldState;

322

323

interface TimeFieldStateOptions<T extends TimeValue = TimeValue> extends TimePickerProps<T> {

324

/** The locale to display and edit the value according to. */

325

locale: string;

326

}

327

328

interface TimeFieldState extends DateFieldState {

329

/** The current time value as a Time object. */

330

timeValue: Time;

331

}

332

```

333

334

[Time Field State](./time-field-state.md)

335

336

## Props Interfaces

337

338

```typescript { .api }

339

// Base props interfaces from @react-types/datepicker

340

interface DatePickerProps<T extends DateValue> {

341

/** The current value (controlled). */

342

value?: T | null;

343

/** The default value (uncontrolled). */

344

defaultValue?: T | null;

345

/** Handler that is called when the value changes. */

346

onChange?: (value: MappedDateValue<T> | null) => void;

347

/** The minimum allowed date that a user may select. */

348

minValue?: DateValue;

349

/** The maximum allowed date that a user may select. */

350

maxValue?: DateValue;

351

/** Callback that is called for each date of the calendar. If true, the date is unavailable. */

352

isDateUnavailable?: (date: DateValue) => boolean;

353

/** Whether the calendar is disabled. */

354

isDisabled?: boolean;

355

/** Whether the calendar is read only. */

356

isReadOnly?: boolean;

357

/** A placeholder date that influences the format of the placeholder shown when no value is selected. */

358

placeholderValue?: T;

359

/** Determines the smallest unit that is displayed in the date picker. */

360

granularity?: Granularity;

361

/** Whether to hide the time zone abbreviation. */

362

hideTimeZone?: boolean;

363

/** Whether to display the time in 12 or 24 hour format. */

364

hourCycle?: 12 | 24;

365

/** Whether to always show leading zeros in the month, day, and hour fields. */

366

shouldForceLeadingZeros?: boolean;

367

/** Whether the element should receive focus on render. */

368

autoFocus?: boolean;

369

/** The name of the input element, used when submitting an HTML form. */

370

name?: string;

371

/** Whether user input is required on the input before form submission. */

372

isRequired?: boolean;

373

/** Whether the input value is invalid. */

374

isInvalid?: boolean;

375

/** The current validation state of the date picker. */

376

validationState?: ValidationState;

377

/** Controls the behavior of paging. */

378

pageBehavior?: 'visible' | 'single';

379

/** The day that starts the week. */

380

firstDayOfWeek?: 'sun' | 'mon' | 'tue' | 'wed' | 'thu' | 'fri' | 'sat';

381

}

382

383

interface DateRangePickerProps<T extends DateValue> {

384

/** The current value (controlled). */

385

value?: RangeValue<T> | null;

386

/** The default value (uncontrolled). */

387

defaultValue?: RangeValue<T> | null;

388

/** Handler that is called when the value changes. */

389

onChange?: (value: RangeValue<MappedDateValue<T>> | null) => void;

390

/** The minimum allowed date that a user may select. */

391

minValue?: DateValue;

392

/** The maximum allowed date that a user may select. */

393

maxValue?: DateValue;

394

/** Callback that is called for each date of the calendar. If true, the date is unavailable. */

395

isDateUnavailable?: (date: DateValue) => boolean;

396

/** Whether non-contiguous ranges, i.e. ranges containing unavailable dates, may be selected. */

397

allowsNonContiguousRanges?: boolean;

398

/** Whether the calendar is disabled. */

399

isDisabled?: boolean;

400

/** Whether the calendar is read only. */

401

isReadOnly?: boolean;

402

/** A placeholder date that influences the format of the placeholder shown when no value is selected. */

403

placeholderValue?: T;

404

/** Determines the smallest unit that is displayed in the date picker. */

405

granularity?: Granularity;

406

/** Whether to hide the time zone abbreviation. */

407

hideTimeZone?: boolean;

408

/** Whether to display the time in 12 or 24 hour format. */

409

hourCycle?: 12 | 24;

410

/** Whether to always show leading zeros in the month, day, and hour fields. */

411

shouldForceLeadingZeros?: boolean;

412

/** Whether the element should receive focus on render. */

413

autoFocus?: boolean;

414

/** The name of the start date input element, used when submitting an HTML form. */

415

startName?: string;

416

/** The name of the end date input element, used when submitting an HTML form. */

417

endName?: string;

418

/** Whether user input is required on the input before form submission. */

419

isRequired?: boolean;

420

/** Whether the input value is invalid. */

421

isInvalid?: boolean;

422

/** The current validation state of the date range picker. */

423

validationState?: ValidationState;

424

/** Controls the behavior of paging. */

425

pageBehavior?: 'visible' | 'single';

426

/** The day that starts the week. */

427

firstDayOfWeek?: 'sun' | 'mon' | 'tue' | 'wed' | 'thu' | 'fri' | 'sat';

428

}

429

430

interface TimePickerProps<T extends TimeValue> {

431

/** The current value (controlled). */

432

value?: T | null;

433

/** The default value (uncontrolled). */

434

defaultValue?: T | null;

435

/** Handler that is called when the value changes. */

436

onChange?: (value: MappedTimeValue<T> | null) => void;

437

/** Whether to display the time in 12 or 24 hour format. */

438

hourCycle?: 12 | 24;

439

/** Determines the smallest unit that is displayed in the time picker. */

440

granularity?: 'hour' | 'minute' | 'second';

441

/** Whether to hide the time zone abbreviation. */

442

hideTimeZone?: boolean;

443

/** Whether to always show leading zeros in the hour field. */

444

shouldForceLeadingZeros?: boolean;

445

/** A placeholder time that influences the format of the placeholder shown when no value is selected. */

446

placeholderValue?: T;

447

/** The minimum allowed time that a user may select. */

448

minValue?: TimeValue | null;

449

/** The maximum allowed time that a user may select. */

450

maxValue?: TimeValue | null;

451

/** Whether the field is disabled. */

452

isDisabled?: boolean;

453

/** Whether the field is read only. */

454

isReadOnly?: boolean;

455

/** Whether the element should receive focus on render. */

456

autoFocus?: boolean;

457

/** The name of the input element, used when submitting an HTML form. */

458

name?: string;

459

/** Whether user input is required on the input before form submission. */

460

isRequired?: boolean;

461

/** Whether the input value is invalid. */

462

isInvalid?: boolean;

463

/** The current validation state of the time picker. */

464

validationState?: ValidationState;

465

}

466

```

467

468

## Core Types

469

470

```typescript { .api }

471

// Date value types from @internationalized/date

472

type DateValue = CalendarDate | CalendarDateTime | ZonedDateTime;

473

type TimeValue = Time | CalendarDateTime | ZonedDateTime;

474

type Granularity = 'day' | 'hour' | 'minute' | 'second';

475

476

// Mapped types for controlled values

477

type MappedDateValue<T> =

478

T extends ZonedDateTime ? ZonedDateTime :

479

T extends CalendarDateTime ? CalendarDateTime :

480

T extends CalendarDate ? CalendarDate :

481

never;

482

483

type MappedTimeValue<T> =

484

T extends ZonedDateTime ? ZonedDateTime :

485

T extends CalendarDateTime ? CalendarDateTime :

486

T extends Time ? Time :

487

never;

488

489

// Calendar types from @internationalized/date

490

type CalendarIdentifier = 'buddhist' | 'ethiopic' | 'ethioaa' | 'coptic' | 'hebrew' | 'indian' | 'islamic-civil' | 'islamic-tbla' | 'islamic-umalqura' | 'japanese' | 'persian' | 'roc' | 'gregory';

491

492

interface Calendar {

493

identifier: CalendarIdentifier;

494

toDate(date: DateValue): Date;

495

fromDate(date: Date): CalendarDate;

496

getDaysInMonth(date: DateValue): number;

497

getMonthsInYear(date: DateValue): number;

498

getYearsInEra(date: DateValue): number;

499

getEras(): string[];

500

balanceDate(date: DateValue): CalendarDate;

501

}

502

503

interface DateFormatter {

504

formatToParts(date: Date): Intl.DateTimeFormatPart[];

505

format(date: Date): string;

506

formatRange(startDate: Date, endDate: Date): string;

507

formatRangeToParts(startDate: Date, endDate: Date): Intl.DateTimeFormatPart[];

508

}

509

510

// Core classes from @internationalized/date

511

interface CalendarDate {

512

readonly calendar: Calendar;

513

readonly era: string;

514

readonly year: number;

515

readonly month: number;

516

readonly day: number;

517

copy(): CalendarDate;

518

add(duration: DateDuration): CalendarDate;

519

subtract(duration: DateDuration): CalendarDate;

520

set(fields: DateFields): CalendarDate;

521

cycle(field: DateField, amount: number): CalendarDate;

522

toDate(timeZone: string): Date;

523

toString(): string;

524

compare(other: DateValue): number;

525

}

526

527

interface CalendarDateTime {

528

readonly calendar: Calendar;

529

readonly era: string;

530

readonly year: number;

531

readonly month: number;

532

readonly day: number;

533

readonly hour: number;

534

readonly minute: number;

535

readonly second: number;

536

readonly millisecond: number;

537

copy(): CalendarDateTime;

538

add(duration: DateTimeDuration): CalendarDateTime;

539

subtract(duration: DateTimeDuration): CalendarDateTime;

540

set(fields: DateTimeFields): CalendarDateTime;

541

cycle(field: DateField, amount: number): CalendarDateTime;

542

toDate(timeZone: string): Date;

543

toString(): string;

544

compare(other: DateValue): number;

545

}

546

547

interface ZonedDateTime {

548

readonly calendar: Calendar;

549

readonly era: string;

550

readonly year: number;

551

readonly month: number;

552

readonly day: number;

553

readonly hour: number;

554

readonly minute: number;

555

readonly second: number;

556

readonly millisecond: number;

557

readonly timeZone: string;

558

readonly offset: number;

559

copy(): ZonedDateTime;

560

add(duration: DateTimeDuration): ZonedDateTime;

561

subtract(duration: DateTimeDuration): ZonedDateTime;

562

set(fields: DateTimeFields): ZonedDateTime;

563

cycle(field: DateField, amount: number): ZonedDateTime;

564

toDate(): Date;

565

toString(): string;

566

compare(other: DateValue): number;

567

}

568

569

interface Time {

570

readonly hour: number;

571

readonly minute: number;

572

readonly second: number;

573

readonly millisecond: number;

574

copy(): Time;

575

add(duration: TimeDuration): Time;

576

subtract(duration: TimeDuration): Time;

577

set(fields: TimeFields): Time;

578

cycle(field: TimeField, amount: number): Time;

579

toString(): string;

580

compare(other: TimeValue): number;

581

}

582

583

// Duration and field types

584

interface DateDuration {

585

years?: number;

586

months?: number;

587

weeks?: number;

588

days?: number;

589

}

590

591

interface TimeDuration {

592

hours?: number;

593

minutes?: number;

594

seconds?: number;

595

milliseconds?: number;

596

}

597

598

interface DateTimeDuration extends DateDuration, TimeDuration {}

599

600

interface DateFields {

601

era?: string;

602

year?: number;

603

month?: number;

604

day?: number;

605

}

606

607

interface TimeFields {

608

hour?: number;

609

minute?: number;

610

second?: number;

611

millisecond?: number;

612

}

613

614

interface DateTimeFields extends DateFields, TimeFields {}

615

616

type DateField = keyof DateFields;

617

type TimeField = keyof TimeFields;

618

619

// Segment types for date field editing

620

type SegmentType = 'era' | 'year' | 'month' | 'day' | 'hour' | 'minute' | 'second' | 'dayPeriod' | 'literal' | 'timeZoneName';

621

622

interface DateSegment {

623

type: SegmentType;

624

text: string;

625

value?: number;

626

minValue?: number;

627

maxValue?: number;

628

isPlaceholder: boolean;

629

placeholder: string;

630

isEditable: boolean;

631

}

632

633

// Range types for date range pickers

634

interface RangeValue<T> {

635

start: T;

636

end: T;

637

}

638

639

type DateRange = RangeValue<DateValue>;

640

type TimeRange = RangeValue<TimeValue>;

641

642

// Validation and formatting

643

interface FieldOptions {

644

year?: 'numeric' | '2-digit';

645

month?: 'numeric' | '2-digit' | 'narrow' | 'short' | 'long';

646

day?: 'numeric' | '2-digit';

647

hour?: 'numeric' | '2-digit';

648

minute?: 'numeric' | '2-digit';

649

second?: 'numeric' | '2-digit';

650

}

651

652

interface FormatterOptions {

653

timeZone?: string;

654

hideTimeZone?: boolean;

655

granularity?: Granularity;

656

maxGranularity?: 'year' | 'month' | Granularity;

657

hourCycle?: 12 | 24;

658

showEra?: boolean;

659

shouldForceLeadingZeros?: boolean;

660

}

661

662

// Validation and state types from React Stately ecosystem

663

type ValidationState = 'valid' | 'invalid';

664

665

interface FormValidationState {

666

/** Whether the input value is invalid according to validation rules */

667

isInvalid: boolean;

668

/** The current validation state @deprecated Use isInvalid instead */

669

validationState: ValidationState | null;

670

/** Validation errors */

671

validationErrors: string[];

672

/** Commit validation state changes */

673

commitValidation(): void;

674

/** Update validation state */

675

updateValidation(result: ValidationResult): void;

676

/** Display validation state for UI rendering */

677

displayValidation: {

678

isInvalid: boolean;

679

validationErrors: string[];

680

};

681

}

682

683

interface OverlayTriggerState {

684

/** Whether the overlay is currently open */

685

isOpen: boolean;

686

/** Sets whether the overlay is open */

687

setOpen(isOpen: boolean): void;

688

/** Opens the overlay */

689

open(): void;

690

/** Closes the overlay */

691

close(): void;

692

/** Toggles the overlay open/closed state */

693

toggle(): void;

694

}

695

696

interface ValidationResult {

697

/** Whether the value is invalid */

698

isInvalid: boolean;

699

/** Array of validation error messages */

700

validationErrors: string[];

701

/** Detailed validation state for different error types */

702

validationDetails: ValidityState;

703

}

704

```