chrona-react 0.3.1 → 0.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -6,7 +6,7 @@ values, no free-form date parsing, and no CSS — you own every pixel.
6
6
  Part of [Chrona](https://github.com/devlinduldulao/chrona). Built on
7
7
  [`chrona-core`](https://www.npmjs.com/package/chrona-core).
8
8
 
9
- > **Status: experimental 0.3.1.** Public APIs and styling attributes are not
9
+ > **Status: experimental 0.3.3.** Public APIs and styling attributes are not
10
10
  > frozen for v1. 0.3.0 changes when a field reports a value and leaves `today`
11
11
  > to the client; 0.2.0 changed the Calendar cell anatomy. See the
12
12
  > [changelog](./CHANGELOG.md). Automated axe checks pass, but no screen-reader
@@ -128,6 +128,12 @@ A barrel export is also available. Matching hooks — `useCalendar`,
128
128
 
129
129
  ## Styling And Forms
130
130
 
131
+ There is a starter stylesheet at
132
+ [`docs/starter.css`](https://github.com/devlinduldulao/chrona/blob/main/docs/starter.css)
133
+ — copy it in and edit it. It styles every part these packages emit, takes its
134
+ colours from eight custom properties, and exists so that the first two hundred
135
+ lines of CSS are not yours to write.
136
+
131
137
  Style via `data-scope`, `data-part`, and state attributes: `data-selected`,
132
138
  `data-focused`, `data-today`, `data-disabled`, `data-unavailable`,
133
139
  `data-outside-month`, `data-in-range`, `data-range-start`, `data-range-end`,
@@ -308,17 +314,11 @@ import { DatePicker } from "chrona-react";
308
314
  so it can be set from a touch keyboard; it has no pointer affordance of its
309
315
  own, so give readers a keyboard path to it.
310
316
 
311
- ## Server Rendering
317
+ ## Next.js App Router
312
318
 
313
- These components use state and context, so they carry a `"use client"`
314
- directive. Importing them from a Server Component is safe the framework moves
315
- the import across the boundary — but the module that *renders* them still has to
316
- be a client module, so mark it `"use client"` as usual.
317
-
318
- The polyfill import is a side effect, so it has to reach the *client* bundle.
319
- Importing `temporal-polyfill/global` from a Server Component file installs
320
- Temporal on the server only. Put it at the top of a `"use client"` module that
321
- always loads — a providers file, for example — so it runs before hydration:
319
+ Two files. Both need `"use client"`, and both need the polyfill import that
320
+ second one is the part people lose an afternoon to, so it is explained under
321
+ the code.
322
322
 
323
323
  ```tsx
324
324
  // app/providers.tsx
@@ -328,26 +328,72 @@ import "temporal-polyfill/global";
328
328
  import { ChronaProvider } from "chrona-react";
329
329
 
330
330
  export function Providers({ children }: { children: React.ReactNode }) {
331
- return <ChronaProvider locale="en-US" timeZone="Europe/Copenhagen">{children}</ChronaProvider>;
331
+ return (
332
+ <ChronaProvider locale="en-US" timeZone="Europe/Copenhagen">
333
+ {children}
334
+ </ChronaProvider>
335
+ );
332
336
  }
333
337
  ```
334
338
 
335
- That covers the client bundle before hydration. It does not order Node module
336
- evaluation. If another `"use client"` file reads `Temporal` at module scope
337
- (`const reference = Temporal.PlainDate.from(...)` at the top of `page.tsx`),
338
- Next.js may evaluate that file during SSR before `providers.tsx` has run and
339
- throw `ReferenceError: Temporal is not defined`. Import the polyfill at the top
340
- of that file too, or move the call inside the component body:
339
+ Render that from `app/layout.tsx` which stays a Server Component wrapping
340
+ `{children}`.
341
341
 
342
342
  ```tsx
343
+ // app/booking-form.tsx
343
344
  "use client";
344
345
 
346
+ // Needed here as well as in providers.tsx: this module reads Temporal at module
347
+ // scope, and Next.js does not promise providers.tsx has been evaluated first.
345
348
  import "temporal-polyfill/global";
349
+
350
+ import { useState } from "react";
346
351
  import { Calendar } from "chrona-react";
347
352
 
348
353
  const REFERENCE = Temporal.PlainDate.from({ year: 2026, month: 9, day: 16 });
354
+
355
+ export function BookingForm() {
356
+ const [value, setValue] = useState<Temporal.PlainDate | null>(null);
357
+
358
+ return (
359
+ <Calendar.Root value={value} onChange={setValue} placeholderValue={REFERENCE} fixedWeeks>
360
+ <Calendar.Header>
361
+ <Calendar.PrevButton />
362
+ <Calendar.Heading />
363
+ <Calendar.NextButton />
364
+ </Calendar.Header>
365
+ <Calendar.Grid>
366
+ <Calendar.GridHeader />
367
+ <Calendar.GridBody />
368
+ </Calendar.Grid>
369
+ <Calendar.HiddenInput name="bookingDate" />
370
+ </Calendar.Root>
371
+ );
372
+ }
349
373
  ```
350
374
 
375
+ Why the polyfill appears twice: importing it is a side effect, so it has to
376
+ reach the *client* bundle — importing it from a Server Component installs
377
+ Temporal on the server only. `providers.tsx` covers the client before
378
+ hydration, but it does not order Node's module evaluation during SSR. A
379
+ `"use client"` file that reads `Temporal` at module scope can be evaluated
380
+ before `providers.tsx` and throw `ReferenceError: Temporal is not defined`.
381
+ Import it at the top of that file too, or move the call inside the component.
382
+
383
+ `placeholderValue` is not decoration: it is what a server-rendered calendar
384
+ opens on. See [Give every calendar a reference date](#give-every-calendar-a-reference-date).
385
+
386
+ `chrona-react` also ships an `AGENTS.md`, written for coding agents and short
387
+ enough to be worth reading yourself — it lists the SSR pitfalls, the part
388
+ anatomy, field draft behaviour, and what is deliberately not implemented.
389
+
390
+ ## Server Rendering
391
+
392
+ These components use state and context, so they carry a `"use client"`
393
+ directive. Importing them from a Server Component is safe — the framework moves
394
+ the import across the boundary — but the module that *renders* them still has to
395
+ be a client module.
396
+
351
397
  Pass the same reference date, value, locale, and time zone on server and client.
352
398
 
353
399
  ### Today
@@ -0,0 +1,142 @@
1
+ import * as temporal_spec from 'temporal-spec';
2
+ import { P as PartProps, H as HiddenInputProps, C as ChronaConfig } from './form-BCAGbNh-.js';
3
+ import * as chrona_core from 'chrona-core';
4
+ import { CalendarOptions, PlainDate, CalendarEvent } from 'chrona-core';
5
+ import * as React from 'react';
6
+
7
+ interface CalendarProps extends CalendarOptions {
8
+ defaultValue?: PlainDate | null;
9
+ defaultFocusedValue?: PlainDate;
10
+ onChange?: (value: PlainDate | null) => void;
11
+ onSelect?: (value: PlainDate) => void;
12
+ onFocusedValueChange?: (value: PlainDate) => void;
13
+ id?: string;
14
+ }
15
+ declare function useCalendar(props?: CalendarProps): {
16
+ state: chrona_core.CalendarState;
17
+ options: CalendarProps & ChronaConfig;
18
+ send: (event: CalendarEvent) => void;
19
+ rootRef: React.RefObject<HTMLElement | null>;
20
+ announcement: string;
21
+ api: {
22
+ getRootProps: () => {
23
+ dir: "ltr" | "rtl" | undefined;
24
+ "data-disabled": string | undefined;
25
+ "data-readonly": string | undefined;
26
+ "data-scope": string;
27
+ "data-part": string;
28
+ };
29
+ getGridProps: (month?: temporal_spec.Temporal.PlainDate) => {
30
+ role: "grid";
31
+ "aria-label": string;
32
+ "aria-readonly": true | undefined;
33
+ "aria-disabled": true | undefined;
34
+ "data-scope": string;
35
+ "data-part": string;
36
+ };
37
+ getCellProps: (date: PlainDate, month?: temporal_spec.Temporal.PlainDate) => {
38
+ "data-date": string;
39
+ "data-selected": string | undefined;
40
+ "data-focused": string | undefined;
41
+ "data-disabled": string | undefined;
42
+ "data-unavailable": string | undefined;
43
+ "data-outside-month": string | undefined;
44
+ "data-today": string | undefined;
45
+ role: "gridcell";
46
+ "aria-selected": boolean;
47
+ "aria-disabled": true | undefined;
48
+ "data-scope": string;
49
+ "data-part": string;
50
+ };
51
+ getCellTriggerProps: (date: PlainDate, month?: temporal_spec.Temporal.PlainDate) => {
52
+ "data-date": string;
53
+ "data-selected": string | undefined;
54
+ "data-focused": string | undefined;
55
+ "data-disabled": string | undefined;
56
+ "data-unavailable": string | undefined;
57
+ "data-outside-month": string | undefined;
58
+ "data-today": string | undefined;
59
+ id: string;
60
+ type: "button";
61
+ tabIndex: number;
62
+ "aria-label": string;
63
+ "aria-disabled": true | undefined;
64
+ "aria-current": "date" | undefined;
65
+ "data-scope": string;
66
+ "data-part": string;
67
+ };
68
+ getPrevButtonProps: () => {
69
+ type: "button";
70
+ "aria-label": string;
71
+ disabled: boolean;
72
+ "data-scope": string;
73
+ "data-part": string;
74
+ };
75
+ getNextButtonProps: () => {
76
+ type: "button";
77
+ "aria-label": string;
78
+ disabled: boolean;
79
+ "data-scope": string;
80
+ "data-part": string;
81
+ };
82
+ };
83
+ months: temporal_spec.Temporal.PlainDate[];
84
+ };
85
+ type CalendarContextValue = ReturnType<typeof useCalendar>;
86
+ declare function CalendarRoot({ children, asChild, className, style, ...props }: CalendarProps & Pick<PartProps, "children" | "asChild" | "className" | "style">): React.JSX.Element;
87
+ declare function CalendarSurface({ calendar, ...props }: PartProps & {
88
+ calendar: CalendarContextValue;
89
+ }): React.JSX.Element;
90
+ interface Weekday {
91
+ date: PlainDate;
92
+ label: string;
93
+ }
94
+ declare function HiddenInput(props: HiddenInputProps): React.JSX.Element;
95
+ declare const Calendar: {
96
+ Root: typeof CalendarRoot;
97
+ Header: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLElement> & {
98
+ asChild?: boolean;
99
+ } & React.RefAttributes<HTMLElement>>;
100
+ Heading: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLElement> & {
101
+ asChild?: boolean;
102
+ } & React.RefAttributes<HTMLElement>>;
103
+ PrevButton: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "ref"> & {
104
+ asChild?: boolean;
105
+ } & React.RefAttributes<HTMLElement>>;
106
+ NextButton: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "ref"> & {
107
+ asChild?: boolean;
108
+ } & React.RefAttributes<HTMLElement>>;
109
+ Grid: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLElement> & {
110
+ asChild?: boolean;
111
+ } & {
112
+ monthIndex?: number;
113
+ } & React.RefAttributes<HTMLElement>>;
114
+ GridHeader: React.ForwardRefExoticComponent<Omit<PartProps, "children"> & {
115
+ children?: (day: Weekday) => React.ReactNode;
116
+ } & React.RefAttributes<HTMLElement>>;
117
+ HeaderCell: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLElement> & {
118
+ asChild?: boolean;
119
+ } & {
120
+ day: Weekday;
121
+ } & React.RefAttributes<HTMLElement>>;
122
+ GridBody: React.ForwardRefExoticComponent<Omit<PartProps, "children"> & {
123
+ children?: (date: PlainDate) => React.ReactNode;
124
+ } & React.RefAttributes<HTMLElement>>;
125
+ Cell: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLElement> & {
126
+ asChild?: boolean;
127
+ } & {
128
+ date: PlainDate;
129
+ } & React.RefAttributes<HTMLElement>>;
130
+ CellTrigger: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "ref"> & {
131
+ asChild?: boolean;
132
+ } & React.RefAttributes<HTMLElement>>;
133
+ LiveRegion: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLElement> & {
134
+ asChild?: boolean;
135
+ } & React.RefAttributes<HTMLElement>>;
136
+ ClearButton: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "ref"> & {
137
+ asChild?: boolean;
138
+ } & React.RefAttributes<HTMLElement>>;
139
+ HiddenInput: typeof HiddenInput;
140
+ };
141
+
142
+ export { Calendar, type CalendarProps, CalendarRoot, CalendarSurface, type Weekday, useCalendar };
@@ -0,0 +1,74 @@
1
+ import { P as PartProps, H as HiddenInputProps, C as ChronaConfig } from './form-BCAGbNh-.js';
2
+ import * as chrona_core from 'chrona-core';
3
+ import * as React from 'react';
4
+ import { F as FieldProps } from './field-DayikvR6.js';
5
+
6
+ type DateFieldProps = FieldProps<"date">;
7
+ declare const DateField: {
8
+ Root: ({ children, asChild, className, style, ...props }: FieldProps<"date"> & Pick<PartProps, "className" | "style" | "children" | "asChild">) => React.JSX.Element;
9
+ Label: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLElement> & {
10
+ asChild?: boolean;
11
+ } & React.RefAttributes<HTMLElement>>;
12
+ Field: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLElement> & {
13
+ asChild?: boolean;
14
+ } & React.RefAttributes<HTMLElement>>;
15
+ Segment: React.ForwardRefExoticComponent<Omit<Omit<React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>, "ref">, "defaultValue" | "children" | "onChange" | "type" | "value"> & {
16
+ type: chrona_core.SegmentType;
17
+ } & React.RefAttributes<HTMLInputElement>>;
18
+ HiddenInput: (props: HiddenInputProps) => React.JSX.Element;
19
+ ClearButton: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "ref"> & {
20
+ asChild?: boolean;
21
+ } & React.RefAttributes<HTMLElement>>;
22
+ LiveRegion: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLElement> & {
23
+ asChild?: boolean;
24
+ } & React.RefAttributes<HTMLElement>>;
25
+ };
26
+ declare function useDateField(props?: DateFieldProps): {
27
+ id: string;
28
+ state: chrona_core.FieldState<"date">;
29
+ options: FieldProps<"date"> & ChronaConfig;
30
+ send: (event: chrona_core.FieldEvent) => void;
31
+ reset: () => void;
32
+ moveFocus: (segment: chrona_core.SegmentType, offset: number) => void;
33
+ groupRef: React.RefObject<HTMLElement | null>;
34
+ announcement: string;
35
+ registerLabel: React.Dispatch<React.SetStateAction<boolean>>;
36
+ api: {
37
+ segments: {
38
+ type: chrona_core.SegmentType | "literal";
39
+ value: string;
40
+ }[];
41
+ getGroupProps: () => {
42
+ role: "group";
43
+ "aria-labelledby": string | undefined;
44
+ "aria-describedby": string | undefined;
45
+ "aria-invalid": true | undefined;
46
+ "data-scope": string;
47
+ "data-part": string;
48
+ "data-invalid": string | undefined;
49
+ "data-disabled": string | undefined;
50
+ "data-readonly": string | undefined;
51
+ dir: "ltr" | "rtl" | undefined;
52
+ };
53
+ getSegmentProps: (segment: chrona_core.SegmentType) => {
54
+ role: "spinbutton";
55
+ "aria-label": string;
56
+ "aria-valuemin": number;
57
+ "aria-valuemax": number;
58
+ "aria-valuenow": number | undefined;
59
+ "aria-valuetext": string;
60
+ "aria-required": true | undefined;
61
+ "aria-invalid": true | undefined;
62
+ "aria-describedby": string | undefined;
63
+ "aria-readonly": true | undefined;
64
+ "data-scope": string;
65
+ "data-part": string;
66
+ "data-segment": chrona_core.SegmentName;
67
+ "data-placeholder": string | undefined;
68
+ "data-invalid": string | undefined;
69
+ display: string;
70
+ };
71
+ };
72
+ };
73
+
74
+ export { DateField, type DateFieldProps, useDateField };
@@ -0,0 +1,69 @@
1
+ import { P as PartProps, H as HiddenInputProps } from './form-BCAGbNh-.js';
2
+ import * as chrona_core from 'chrona-core';
3
+ import { PlainDate, PickerEvent } from 'chrona-core';
4
+ import * as React from 'react';
5
+ import { CalendarProps } from './calendar.js';
6
+ import { DateFieldProps } from './date-field.js';
7
+ import 'temporal-spec';
8
+ import './field-DayikvR6.js';
9
+
10
+ interface DatePickerProps extends DateFieldProps {
11
+ open?: boolean;
12
+ defaultOpen?: boolean;
13
+ onOpenChange?: (open: boolean) => void;
14
+ modal?: boolean;
15
+ timeZone?: string;
16
+ firstDayOfWeek?: number;
17
+ fixedWeeks?: boolean;
18
+ numberOfMonths?: number;
19
+ pagedNavigation?: boolean;
20
+ }
21
+ interface PickerContext {
22
+ props: DatePickerProps;
23
+ options: DatePickerProps;
24
+ state: {
25
+ value: PlainDate | null;
26
+ open: boolean;
27
+ };
28
+ id: string;
29
+ value: PlainDate | null;
30
+ change: (value: PlainDate | null) => void;
31
+ open: boolean;
32
+ send: (event: PickerEvent) => void;
33
+ trigger: {
34
+ current: HTMLElement | null;
35
+ };
36
+ labelled: boolean;
37
+ registerLabel: (present: boolean) => void;
38
+ }
39
+ declare function Root({ children, asChild, className, style, ...input }: DatePickerProps & Pick<PartProps, "children" | "asChild" | "className" | "style">): React.JSX.Element;
40
+ declare function useDatePicker(input?: DatePickerProps): PickerContext;
41
+ declare function PickerCalendar({ children, ...props }: Omit<CalendarProps, "value" | "defaultValue" | "onChange"> & Pick<PartProps, "children" | "className" | "style">): React.JSX.Element;
42
+ declare const DatePicker: {
43
+ Root: typeof Root;
44
+ Label: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLElement> & {
45
+ asChild?: boolean;
46
+ } & React.RefAttributes<HTMLElement>>;
47
+ Field: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLElement> & {
48
+ asChild?: boolean;
49
+ } & React.RefAttributes<HTMLElement>>;
50
+ Segment: React.ForwardRefExoticComponent<Omit<Omit<React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>, "ref">, "defaultValue" | "children" | "onChange" | "type" | "value"> & {
51
+ type: chrona_core.SegmentType;
52
+ } & React.RefAttributes<HTMLInputElement>>;
53
+ HiddenInput: (props: HiddenInputProps) => React.JSX.Element;
54
+ ClearButton: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "ref"> & {
55
+ asChild?: boolean;
56
+ } & React.RefAttributes<HTMLElement>>;
57
+ LiveRegion: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLElement> & {
58
+ asChild?: boolean;
59
+ } & React.RefAttributes<HTMLElement>>;
60
+ Trigger: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "ref"> & {
61
+ asChild?: boolean;
62
+ } & React.RefAttributes<HTMLElement>>;
63
+ Popover: React.ForwardRefExoticComponent<Omit<Omit<React.DetailedHTMLProps<React.DialogHTMLAttributes<HTMLDialogElement>, HTMLDialogElement>, "ref">, "open"> & {
64
+ anchored?: boolean;
65
+ } & React.RefAttributes<HTMLDialogElement>>;
66
+ Calendar: typeof PickerCalendar;
67
+ };
68
+
69
+ export { DatePicker, type DatePickerProps, useDatePicker };
@@ -0,0 +1,11 @@
1
+ import { FieldKind, FieldOptions, FieldValue, FieldInvalidReason } from 'chrona-core';
2
+
3
+ interface FieldProps<Kind extends FieldKind> extends FieldOptions<Kind> {
4
+ defaultValue?: FieldValue<Kind> | null;
5
+ onChange?: (value: FieldValue<Kind> | null) => void;
6
+ onInvalid?: (reason: FieldInvalidReason) => void;
7
+ id?: string;
8
+ describedBy?: string;
9
+ }
10
+
11
+ export type { FieldProps as F };
@@ -0,0 +1,20 @@
1
+ import * as React from 'react';
2
+ import { Translations } from 'chrona-core';
3
+
4
+ interface ChronaConfig {
5
+ locale?: string;
6
+ timeZone?: string;
7
+ dir?: "ltr" | "rtl";
8
+ translations?: Partial<Translations>;
9
+ }
10
+ declare function ChronaProvider({ children, ...config }: ChronaConfig & {
11
+ children: React.ReactNode;
12
+ }): React.JSX.Element;
13
+
14
+ type PartProps = React.HTMLAttributes<HTMLElement> & {
15
+ asChild?: boolean;
16
+ };
17
+
18
+ type HiddenInputProps = Omit<React.ComponentPropsWithoutRef<"input">, "type" | "value" | "defaultValue" | "onChange">;
19
+
20
+ export { type ChronaConfig as C, type HiddenInputProps as H, type PartProps as P, ChronaProvider as a };
@@ -0,0 +1,10 @@
1
+ export { Calendar, CalendarProps, CalendarRoot, Weekday, useCalendar } from './calendar.js';
2
+ export { C as ChronaConfig, a as ChronaProvider } from './form-BCAGbNh-.js';
3
+ export { DateField, DateFieldProps, useDateField } from './date-field.js';
4
+ export { TimeField, TimeFieldProps, useTimeField } from './time-field.js';
5
+ export { DatePicker, DatePickerProps, useDatePicker } from './date-picker.js';
6
+ export { RangeCalendar, RangeCalendarProps, useRangeCalendar } from './range-calendar.js';
7
+ import 'temporal-spec';
8
+ import 'chrona-core';
9
+ import 'react';
10
+ import './field-DayikvR6.js';
@@ -0,0 +1,233 @@
1
+ import { CalendarProps, Weekday } from './calendar.js';
2
+ import * as chrona_core from 'chrona-core';
3
+ import { DateRange, PlainDate, RangeEvent } from 'chrona-core';
4
+ import * as temporal_spec from 'temporal-spec';
5
+ import { P as PartProps, H as HiddenInputProps, C as ChronaConfig } from './form-BCAGbNh-.js';
6
+ import * as React from 'react';
7
+
8
+ interface RangeCalendarProps extends Omit<CalendarProps, "value" | "defaultValue" | "onChange"> {
9
+ value?: DateRange | null;
10
+ defaultValue?: DateRange | null;
11
+ onChange?: (value: DateRange | null) => void;
12
+ onRangeStartChange?: (value: PlainDate | null) => void;
13
+ onInvalid?: () => void;
14
+ }
15
+ declare function useRangeCalendar(input?: RangeCalendarProps): {
16
+ state: {
17
+ value: DateRange | null;
18
+ anchor: PlainDate | null;
19
+ preview: PlainDate | null;
20
+ invalid: boolean;
21
+ };
22
+ send: (event: RangeEvent) => void;
23
+ announcement: string;
24
+ props: RangeCalendarProps & ChronaConfig;
25
+ options: RangeCalendarProps & ChronaConfig;
26
+ api: {
27
+ getCellProps: (date: PlainDate, month?: PlainDate) => {
28
+ "data-scope": string;
29
+ "data-selected": string | undefined;
30
+ "data-in-range": string | undefined;
31
+ "data-range-start": string | undefined;
32
+ "data-range-end": string | undefined;
33
+ "data-preview": string | undefined;
34
+ "data-invalid": string | undefined;
35
+ "aria-selected": boolean;
36
+ "data-date": string;
37
+ "data-focused": string | undefined;
38
+ "data-disabled": string | undefined;
39
+ "data-unavailable": string | undefined;
40
+ "data-outside-month": string | undefined;
41
+ "data-today": string | undefined;
42
+ role: "gridcell";
43
+ "aria-disabled": true | undefined;
44
+ "data-part": string;
45
+ };
46
+ getCellTriggerProps: (date: PlainDate, month?: PlainDate) => {
47
+ "data-scope": string;
48
+ "data-selected": string | undefined;
49
+ "data-in-range": string | undefined;
50
+ "data-range-start": string | undefined;
51
+ "data-range-end": string | undefined;
52
+ "data-preview": string | undefined;
53
+ "data-invalid": string | undefined;
54
+ "data-date": string;
55
+ "data-focused": string | undefined;
56
+ "data-disabled": string | undefined;
57
+ "data-unavailable": string | undefined;
58
+ "data-outside-month": string | undefined;
59
+ "data-today": string | undefined;
60
+ id: string;
61
+ type: "button";
62
+ tabIndex: number;
63
+ "aria-label": string;
64
+ "aria-disabled": true | undefined;
65
+ "aria-current": "date" | undefined;
66
+ "data-part": string;
67
+ };
68
+ getRootProps: () => {
69
+ dir: "ltr" | "rtl" | undefined;
70
+ "data-disabled": string | undefined;
71
+ "data-readonly": string | undefined;
72
+ "data-scope": string;
73
+ "data-part": string;
74
+ };
75
+ getGridProps: (month?: temporal_spec.Temporal.PlainDate) => {
76
+ role: "grid";
77
+ "aria-label": string;
78
+ "aria-readonly": true | undefined;
79
+ "aria-disabled": true | undefined;
80
+ "data-scope": string;
81
+ "data-part": string;
82
+ };
83
+ getPrevButtonProps: () => {
84
+ type: "button";
85
+ "aria-label": string;
86
+ disabled: boolean;
87
+ "data-scope": string;
88
+ "data-part": string;
89
+ };
90
+ getNextButtonProps: () => {
91
+ type: "button";
92
+ "aria-label": string;
93
+ disabled: boolean;
94
+ "data-scope": string;
95
+ "data-part": string;
96
+ };
97
+ };
98
+ rootRef: React.RefObject<HTMLElement | null>;
99
+ months: temporal_spec.Temporal.PlainDate[];
100
+ reset(): void;
101
+ calendar: {
102
+ api: {
103
+ getCellProps: (date: PlainDate, month?: PlainDate) => {
104
+ "data-scope": string;
105
+ "data-selected": string | undefined;
106
+ "data-in-range": string | undefined;
107
+ "data-range-start": string | undefined;
108
+ "data-range-end": string | undefined;
109
+ "data-preview": string | undefined;
110
+ "data-invalid": string | undefined;
111
+ "aria-selected": boolean;
112
+ "data-date": string;
113
+ "data-focused": string | undefined;
114
+ "data-disabled": string | undefined;
115
+ "data-unavailable": string | undefined;
116
+ "data-outside-month": string | undefined;
117
+ "data-today": string | undefined;
118
+ role: "gridcell";
119
+ "aria-disabled": true | undefined;
120
+ "data-part": string;
121
+ };
122
+ getCellTriggerProps: (date: PlainDate, month?: PlainDate) => {
123
+ "data-scope": string;
124
+ "data-selected": string | undefined;
125
+ "data-in-range": string | undefined;
126
+ "data-range-start": string | undefined;
127
+ "data-range-end": string | undefined;
128
+ "data-preview": string | undefined;
129
+ "data-invalid": string | undefined;
130
+ "data-date": string;
131
+ "data-focused": string | undefined;
132
+ "data-disabled": string | undefined;
133
+ "data-unavailable": string | undefined;
134
+ "data-outside-month": string | undefined;
135
+ "data-today": string | undefined;
136
+ id: string;
137
+ type: "button";
138
+ tabIndex: number;
139
+ "aria-label": string;
140
+ "aria-disabled": true | undefined;
141
+ "aria-current": "date" | undefined;
142
+ "data-part": string;
143
+ };
144
+ getRootProps: () => {
145
+ dir: "ltr" | "rtl" | undefined;
146
+ "data-disabled": string | undefined;
147
+ "data-readonly": string | undefined;
148
+ "data-scope": string;
149
+ "data-part": string;
150
+ };
151
+ getGridProps: (month?: temporal_spec.Temporal.PlainDate) => {
152
+ role: "grid";
153
+ "aria-label": string;
154
+ "aria-readonly": true | undefined;
155
+ "aria-disabled": true | undefined;
156
+ "data-scope": string;
157
+ "data-part": string;
158
+ };
159
+ getPrevButtonProps: () => {
160
+ type: "button";
161
+ "aria-label": string;
162
+ disabled: boolean;
163
+ "data-scope": string;
164
+ "data-part": string;
165
+ };
166
+ getNextButtonProps: () => {
167
+ type: "button";
168
+ "aria-label": string;
169
+ disabled: boolean;
170
+ "data-scope": string;
171
+ "data-part": string;
172
+ };
173
+ };
174
+ state: chrona_core.CalendarState;
175
+ options: CalendarProps & ChronaConfig;
176
+ send: (event: chrona_core.CalendarEvent) => void;
177
+ rootRef: React.RefObject<HTMLElement | null>;
178
+ announcement: string;
179
+ months: temporal_spec.Temporal.PlainDate[];
180
+ };
181
+ };
182
+ declare function Root({ children, asChild, className, style, ...props }: RangeCalendarProps & Pick<PartProps, "children" | "asChild" | "className" | "style">): React.JSX.Element;
183
+ declare function HiddenInput({ name, form, id, disabled, ...inputProps }: HiddenInputProps & {
184
+ name: string;
185
+ }): React.JSX.Element;
186
+ declare const RangeCalendar: {
187
+ Root: typeof Root;
188
+ Cell: React.ForwardRefExoticComponent<Omit<React.HTMLAttributes<HTMLElement> & {
189
+ asChild?: boolean;
190
+ } & {
191
+ date: PlainDate;
192
+ } & React.RefAttributes<HTMLElement>, "ref"> & React.RefAttributes<HTMLElement>>;
193
+ GridBody: React.ForwardRefExoticComponent<Omit<Omit<PartProps, "children"> & {
194
+ children?: (date: PlainDate) => React.ReactNode;
195
+ } & React.RefAttributes<HTMLElement>, "ref"> & React.RefAttributes<HTMLElement>>;
196
+ LiveRegion: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLElement> & {
197
+ asChild?: boolean;
198
+ } & React.RefAttributes<HTMLElement>>;
199
+ ClearButton: React.ForwardRefExoticComponent<Omit<Omit<React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "ref"> & {
200
+ asChild?: boolean;
201
+ } & React.RefAttributes<HTMLElement>, "ref"> & React.RefAttributes<HTMLElement>>;
202
+ HiddenInput: typeof HiddenInput;
203
+ Header: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLElement> & {
204
+ asChild?: boolean;
205
+ } & React.RefAttributes<HTMLElement>>;
206
+ Heading: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLElement> & {
207
+ asChild?: boolean;
208
+ } & React.RefAttributes<HTMLElement>>;
209
+ PrevButton: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "ref"> & {
210
+ asChild?: boolean;
211
+ } & React.RefAttributes<HTMLElement>>;
212
+ NextButton: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "ref"> & {
213
+ asChild?: boolean;
214
+ } & React.RefAttributes<HTMLElement>>;
215
+ Grid: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLElement> & {
216
+ asChild?: boolean;
217
+ } & {
218
+ monthIndex?: number;
219
+ } & React.RefAttributes<HTMLElement>>;
220
+ GridHeader: React.ForwardRefExoticComponent<Omit<PartProps, "children"> & {
221
+ children?: (day: Weekday) => React.ReactNode;
222
+ } & React.RefAttributes<HTMLElement>>;
223
+ HeaderCell: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLElement> & {
224
+ asChild?: boolean;
225
+ } & {
226
+ day: Weekday;
227
+ } & React.RefAttributes<HTMLElement>>;
228
+ CellTrigger: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "ref"> & {
229
+ asChild?: boolean;
230
+ } & React.RefAttributes<HTMLElement>>;
231
+ };
232
+
233
+ export { RangeCalendar, type RangeCalendarProps, useRangeCalendar };
@@ -0,0 +1,74 @@
1
+ import { P as PartProps, H as HiddenInputProps, C as ChronaConfig } from './form-BCAGbNh-.js';
2
+ import * as chrona_core from 'chrona-core';
3
+ import * as React from 'react';
4
+ import { F as FieldProps } from './field-DayikvR6.js';
5
+
6
+ type TimeFieldProps = FieldProps<"time">;
7
+ declare const TimeField: {
8
+ Root: ({ children, asChild, className, style, ...props }: FieldProps<"time"> & Pick<PartProps, "className" | "style" | "children" | "asChild">) => React.JSX.Element;
9
+ Label: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLElement> & {
10
+ asChild?: boolean;
11
+ } & React.RefAttributes<HTMLElement>>;
12
+ Field: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLElement> & {
13
+ asChild?: boolean;
14
+ } & React.RefAttributes<HTMLElement>>;
15
+ Segment: React.ForwardRefExoticComponent<Omit<Omit<React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>, "ref">, "defaultValue" | "children" | "onChange" | "type" | "value"> & {
16
+ type: chrona_core.SegmentType;
17
+ } & React.RefAttributes<HTMLInputElement>>;
18
+ HiddenInput: (props: HiddenInputProps) => React.JSX.Element;
19
+ ClearButton: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "ref"> & {
20
+ asChild?: boolean;
21
+ } & React.RefAttributes<HTMLElement>>;
22
+ LiveRegion: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLElement> & {
23
+ asChild?: boolean;
24
+ } & React.RefAttributes<HTMLElement>>;
25
+ };
26
+ declare function useTimeField(props?: TimeFieldProps): {
27
+ id: string;
28
+ state: chrona_core.FieldState<"time">;
29
+ options: FieldProps<"time"> & ChronaConfig;
30
+ send: (event: chrona_core.FieldEvent) => void;
31
+ reset: () => void;
32
+ moveFocus: (segment: chrona_core.SegmentType, offset: number) => void;
33
+ groupRef: React.RefObject<HTMLElement | null>;
34
+ announcement: string;
35
+ registerLabel: React.Dispatch<React.SetStateAction<boolean>>;
36
+ api: {
37
+ segments: {
38
+ type: chrona_core.SegmentType | "literal";
39
+ value: string;
40
+ }[];
41
+ getGroupProps: () => {
42
+ role: "group";
43
+ "aria-labelledby": string | undefined;
44
+ "aria-describedby": string | undefined;
45
+ "aria-invalid": true | undefined;
46
+ "data-scope": string;
47
+ "data-part": string;
48
+ "data-invalid": string | undefined;
49
+ "data-disabled": string | undefined;
50
+ "data-readonly": string | undefined;
51
+ dir: "ltr" | "rtl" | undefined;
52
+ };
53
+ getSegmentProps: (segment: chrona_core.SegmentType) => {
54
+ role: "spinbutton";
55
+ "aria-label": string;
56
+ "aria-valuemin": number;
57
+ "aria-valuemax": number;
58
+ "aria-valuenow": number | undefined;
59
+ "aria-valuetext": string;
60
+ "aria-required": true | undefined;
61
+ "aria-invalid": true | undefined;
62
+ "aria-describedby": string | undefined;
63
+ "aria-readonly": true | undefined;
64
+ "data-scope": string;
65
+ "data-part": string;
66
+ "data-segment": chrona_core.SegmentName;
67
+ "data-placeholder": string | undefined;
68
+ "data-invalid": string | undefined;
69
+ display: string;
70
+ };
71
+ };
72
+ };
73
+
74
+ export { TimeField, type TimeFieldProps, useTimeField };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chrona-react",
3
- "version": "0.3.1",
3
+ "version": "0.3.3",
4
4
  "description": "Headless Temporal-native React date and time primitives",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -61,7 +61,7 @@
61
61
  }
62
62
  },
63
63
  "dependencies": {
64
- "chrona-core": "^0.3.1"
64
+ "chrona-core": "^0.3.3"
65
65
  },
66
66
  "peerDependencies": {
67
67
  "react": ">=18.0.0",