chrona-react 0.2.0 → 0.3.0
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/AGENTS.md +8 -2
- package/README.md +230 -7
- package/dist/calendar.js +3 -2
- package/dist/{chunk-JNQXKZO3.js → chunk-27APJXNX.js} +23 -9
- package/dist/chunk-27APJXNX.js.map +1 -0
- package/dist/{chunk-QQANBK5G.js → chunk-GXQA645Q.js} +9 -5
- package/dist/chunk-GXQA645Q.js.map +1 -0
- package/dist/{chunk-RCWVBOO6.js → chunk-I46LC4EZ.js} +12 -3
- package/dist/chunk-I46LC4EZ.js.map +1 -0
- package/dist/{chunk-2GZMCFFY.js → chunk-RTDRFDYG.js} +3 -2
- package/dist/{chunk-2GZMCFFY.js.map → chunk-RTDRFDYG.js.map} +1 -1
- package/dist/{chunk-GN2YCKFZ.js → chunk-SDDSKOYU.js} +3 -1
- package/dist/{chunk-GN2YCKFZ.js.map → chunk-SDDSKOYU.js.map} +1 -1
- package/dist/{chunk-ROJQDSGQ.js → chunk-WMHLPJBG.js} +3 -2
- package/dist/{chunk-ROJQDSGQ.js.map → chunk-WMHLPJBG.js.map} +1 -1
- package/dist/{chunk-U4LLSRIH.js → chunk-YMCXDNWB.js} +5 -4
- package/dist/{chunk-U4LLSRIH.js.map → chunk-YMCXDNWB.js.map} +1 -1
- package/dist/date-field.js +4 -3
- package/dist/date-picker.js +6 -5
- package/dist/index.js +8 -7
- package/dist/range-calendar.js +4 -3
- package/dist/time-field.js +4 -3
- package/package.json +3 -3
- package/dist/calendar.d.ts +0 -142
- package/dist/chunk-JNQXKZO3.js.map +0 -1
- package/dist/chunk-QQANBK5G.js.map +0 -1
- package/dist/chunk-RCWVBOO6.js.map +0 -1
- package/dist/date-field.d.ts +0 -74
- package/dist/date-picker.d.ts +0 -69
- package/dist/field-DayikvR6.d.ts +0 -11
- package/dist/form-BCAGbNh-.d.ts +0 -20
- package/dist/index.d.ts +0 -10
- package/dist/range-calendar.d.ts +0 -233
- package/dist/time-field.d.ts +0 -74
package/AGENTS.md
CHANGED
|
@@ -14,8 +14,14 @@ https://github.com/devlinduldulao/chrona#readme
|
|
|
14
14
|
3. **Server Components.** These components hold state: mark their module
|
|
15
15
|
`"use client"`. The polyfill import is a side effect, so it must reach the
|
|
16
16
|
client bundle — put it at the top of a `"use client"` module that always
|
|
17
|
-
loads (a providers file), not in a Server Component.
|
|
18
|
-
4. **
|
|
17
|
+
loads (a providers file), not in a Server Component. That covers hydration.
|
|
18
|
+
4. **SSR module init.** The providers import does not order Node module
|
|
19
|
+
evaluation. If another `"use client"` file reads `Temporal` at module scope
|
|
20
|
+
(`const reference = Temporal.PlainDate.from(...)` at the top of `page.tsx`),
|
|
21
|
+
Next.js may evaluate that file during SSR before `providers.tsx` has run and
|
|
22
|
+
throw `ReferenceError: Temporal is not defined`. Import the polyfill at the
|
|
23
|
+
top of *that* file too, or move the call inside the component body.
|
|
24
|
+
5. **Values are Temporal objects.** Strings and `Date` are rejected with a
|
|
19
25
|
`ChronaError`; there is no parsing layer.
|
|
20
26
|
|
|
21
27
|
## Anatomy
|
package/README.md
CHANGED
|
@@ -6,8 +6,9 @@ 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.
|
|
10
|
-
> frozen for v1
|
|
9
|
+
> **Status: experimental 0.3.0.** Public APIs and styling attributes are not
|
|
10
|
+
> frozen for v1. 0.3.0 changes when a field reports a value and leaves `today`
|
|
11
|
+
> to the client; 0.2.0 changed the Calendar cell anatomy. See the
|
|
11
12
|
> [changelog](./CHANGELOG.md). Automated axe checks pass, but no screen-reader
|
|
12
13
|
> compatibility certification is claimed.
|
|
13
14
|
|
|
@@ -28,6 +29,15 @@ it is not native, load a polyfill before rendering:
|
|
|
28
29
|
import "temporal-polyfill/global";
|
|
29
30
|
```
|
|
30
31
|
|
|
32
|
+
`temporal-polyfill` 1.x installs itself only where Temporal is missing, and its
|
|
33
|
+
default entry carries the ISO calendar alone. Node 24+ and current Chrome have
|
|
34
|
+
native Temporal, so on those the import does nothing — and native Temporal in
|
|
35
|
+
Node cannot yet do arithmetic on non-ISO calendars, `gregory` among them. A
|
|
36
|
+
Calendar given `calendar="gregory"` or a Gregorian value renders in the browser
|
|
37
|
+
and throws `RangeError: Temporal error: Not yet implemented.` during SSR. Keep
|
|
38
|
+
values in `iso8601` unless you have verified the server runtime, and reach for
|
|
39
|
+
`temporal-polyfill/full/global` when you need other calendar systems.
|
|
40
|
+
|
|
31
41
|
The TypeScript types come along for free: `chrona-core`'s declarations reference
|
|
32
42
|
`temporal-spec/global`, so importing anything from this package puts the ambient
|
|
33
43
|
`Temporal` namespace in scope, exactly as the examples below assume.
|
|
@@ -138,6 +148,148 @@ Hidden inputs serialize with `.toString()` and are never read back.
|
|
|
138
148
|
inputs do not take part in browser constraint validation — validate required,
|
|
139
149
|
incomplete, or invalid values in your form layer before submission.
|
|
140
150
|
|
|
151
|
+
## With shadcn/ui
|
|
152
|
+
|
|
153
|
+
Chrona does not replace shadcn. Keep `Button`, `Popover`, `Label`, and `cn`.
|
|
154
|
+
Replace the `react-day-picker` calendar and the native `<input type="time">`.
|
|
155
|
+
Values stay `Temporal.PlainDate` / `Temporal.PlainTime` — do not convert through
|
|
156
|
+
`Date`. Style days as `[data-part="cell-trigger"]`.
|
|
157
|
+
|
|
158
|
+
```tsx
|
|
159
|
+
"use client";
|
|
160
|
+
|
|
161
|
+
import { useState } from "react";
|
|
162
|
+
import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react";
|
|
163
|
+
import { Calendar as ChronaCalendar, TimeField } from "chrona-react";
|
|
164
|
+
import { Button } from "@/components/ui/button";
|
|
165
|
+
import { Label } from "@/components/ui/label";
|
|
166
|
+
import {
|
|
167
|
+
Popover,
|
|
168
|
+
PopoverContent,
|
|
169
|
+
PopoverTrigger,
|
|
170
|
+
} from "@/components/ui/popover";
|
|
171
|
+
import { cn } from "@/lib/utils";
|
|
172
|
+
|
|
173
|
+
const calendarClassName = cn(
|
|
174
|
+
"bg-background p-3",
|
|
175
|
+
"[&_[data-part=header]]:mb-2 [&_[data-part=header]]:flex [&_[data-part=header]]:items-center [&_[data-part=header]]:justify-between",
|
|
176
|
+
"[&_[data-part=heading]]:text-sm [&_[data-part=heading]]:font-medium",
|
|
177
|
+
"[&_[data-part=grid-header]]:grid [&_[data-part=grid-header]]:grid-cols-7",
|
|
178
|
+
"[&_[data-part=header-cell]]:text-muted-foreground [&_[data-part=header-cell]]:text-center [&_[data-part=header-cell]]:text-[0.8rem]",
|
|
179
|
+
"[&_[data-part=row]]:grid [&_[data-part=row]]:grid-cols-7",
|
|
180
|
+
"[&_[data-part=cell-trigger]]:size-8 [&_[data-part=cell-trigger]]:w-full [&_[data-part=cell-trigger]]:rounded-md [&_[data-part=cell-trigger]]:text-sm",
|
|
181
|
+
"[&_[data-part=cell-trigger][data-selected]]:bg-primary [&_[data-part=cell-trigger][data-selected]]:text-primary-foreground",
|
|
182
|
+
"[&_[data-part=cell-trigger][data-today]]:bg-accent",
|
|
183
|
+
"[&_[data-part=cell-trigger][data-outside-month]]:text-muted-foreground [&_[data-part=cell-trigger][data-outside-month]]:opacity-50",
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
export function ShadcnCalendar({
|
|
187
|
+
value,
|
|
188
|
+
onChange,
|
|
189
|
+
placeholderValue,
|
|
190
|
+
className,
|
|
191
|
+
}: {
|
|
192
|
+
value: Temporal.PlainDate | null;
|
|
193
|
+
onChange: (value: Temporal.PlainDate | null) => void;
|
|
194
|
+
placeholderValue: Temporal.PlainDate;
|
|
195
|
+
className?: string;
|
|
196
|
+
}) {
|
|
197
|
+
return (
|
|
198
|
+
<ChronaCalendar.Root
|
|
199
|
+
value={value}
|
|
200
|
+
onChange={onChange}
|
|
201
|
+
placeholderValue={placeholderValue}
|
|
202
|
+
fixedWeeks
|
|
203
|
+
className={cn(calendarClassName, className)}
|
|
204
|
+
>
|
|
205
|
+
<ChronaCalendar.Header>
|
|
206
|
+
<ChronaCalendar.PrevButton asChild>
|
|
207
|
+
<Button variant="ghost" size="icon" className="size-8 p-0">
|
|
208
|
+
<ChevronLeftIcon className="size-4" />
|
|
209
|
+
</Button>
|
|
210
|
+
</ChronaCalendar.PrevButton>
|
|
211
|
+
<ChronaCalendar.Heading />
|
|
212
|
+
<ChronaCalendar.NextButton asChild>
|
|
213
|
+
<Button variant="ghost" size="icon" className="size-8 p-0">
|
|
214
|
+
<ChevronRightIcon className="size-4" />
|
|
215
|
+
</Button>
|
|
216
|
+
</ChronaCalendar.NextButton>
|
|
217
|
+
</ChronaCalendar.Header>
|
|
218
|
+
<ChronaCalendar.Grid>
|
|
219
|
+
<ChronaCalendar.GridHeader />
|
|
220
|
+
<ChronaCalendar.GridBody />
|
|
221
|
+
</ChronaCalendar.Grid>
|
|
222
|
+
<ChronaCalendar.LiveRegion className="sr-only" />
|
|
223
|
+
</ChronaCalendar.Root>
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
export function ShadcnDateTimePicker() {
|
|
228
|
+
const reference = Temporal.PlainDate.from({ year: 2026, month: 9, day: 16 });
|
|
229
|
+
const [open, setOpen] = useState(false);
|
|
230
|
+
const [date, setDate] = useState<Temporal.PlainDate | null>(null);
|
|
231
|
+
const [time, setTime] = useState<Temporal.PlainTime | null>(
|
|
232
|
+
Temporal.PlainTime.from("09:30:00"),
|
|
233
|
+
);
|
|
234
|
+
|
|
235
|
+
return (
|
|
236
|
+
<div className="flex gap-4">
|
|
237
|
+
<div className="flex flex-col gap-3">
|
|
238
|
+
<Label className="px-1">Date</Label>
|
|
239
|
+
<Popover open={open} onOpenChange={setOpen}>
|
|
240
|
+
<PopoverTrigger asChild>
|
|
241
|
+
<Button variant="outline" className="w-40 justify-start font-normal">
|
|
242
|
+
{date
|
|
243
|
+
? date.toLocaleString("en-US", { dateStyle: "medium" })
|
|
244
|
+
: "Pick a date"}
|
|
245
|
+
</Button>
|
|
246
|
+
</PopoverTrigger>
|
|
247
|
+
<PopoverContent className="w-auto p-0" align="start">
|
|
248
|
+
<ShadcnCalendar
|
|
249
|
+
value={date}
|
|
250
|
+
placeholderValue={reference}
|
|
251
|
+
onChange={(next) => {
|
|
252
|
+
setDate(next);
|
|
253
|
+
setOpen(false);
|
|
254
|
+
}}
|
|
255
|
+
/>
|
|
256
|
+
</PopoverContent>
|
|
257
|
+
</Popover>
|
|
258
|
+
</div>
|
|
259
|
+
<TimeField.Root value={time} onChange={setTime} hourCycle="h23" granularity="second">
|
|
260
|
+
<TimeField.Label className="px-1">Time</TimeField.Label>
|
|
261
|
+
<TimeField.Field className="border-input bg-background inline-flex h-9 items-center rounded-md border px-3 text-sm shadow-xs [&_[data-part=segment]]:w-6 [&_[data-part=segment]]:bg-transparent [&_[data-part=segment]]:text-center" />
|
|
262
|
+
</TimeField.Root>
|
|
263
|
+
</div>
|
|
264
|
+
);
|
|
265
|
+
}
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
Chrona's `DatePicker` already owns a native `<dialog>` — do not wrap it in
|
|
269
|
+
shadcn `Popover`. Use `DatePicker.Trigger asChild` with `Button` instead:
|
|
270
|
+
|
|
271
|
+
```tsx
|
|
272
|
+
import { CalendarIcon } from "lucide-react";
|
|
273
|
+
import { DatePicker } from "chrona-react";
|
|
274
|
+
|
|
275
|
+
<DatePicker.Root value={date} onChange={setDate} placeholderValue={reference}>
|
|
276
|
+
<DatePicker.Label asChild>
|
|
277
|
+
<Label>Appointment</Label>
|
|
278
|
+
</DatePicker.Label>
|
|
279
|
+
<DatePicker.Field className="border-input inline-flex h-9 items-center rounded-md border px-3 text-sm" />
|
|
280
|
+
<DatePicker.Trigger asChild>
|
|
281
|
+
<Button variant="outline" size="icon">
|
|
282
|
+
<CalendarIcon className="size-4" />
|
|
283
|
+
</Button>
|
|
284
|
+
</DatePicker.Trigger>
|
|
285
|
+
<DatePicker.Popover className="bg-popover text-popover-foreground rounded-md border p-3 shadow-md">
|
|
286
|
+
<DatePicker.Calendar />
|
|
287
|
+
</DatePicker.Popover>
|
|
288
|
+
</DatePicker.Root>
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
`asChild` uses the child's children, so pass an icon (or omit `asChild` and keep Chrona's default glyph).
|
|
292
|
+
|
|
141
293
|
## Notes
|
|
142
294
|
|
|
143
295
|
- ESM with declarations and source maps, targeting ES2022.
|
|
@@ -146,14 +298,22 @@ incomplete, or invalid values in your form layer before submission.
|
|
|
146
298
|
the year are zero-padded, so a field keeps one width as it fills.
|
|
147
299
|
- Typed digits are literal and stepping clamps: 29 February is reachable before
|
|
148
300
|
the year is typed, and a finished date the calendar cannot hold reports
|
|
149
|
-
`onInvalid("nonexistent")` instead of sliding to the 28th.
|
|
150
|
-
|
|
301
|
+
`onInvalid("nonexistent")` instead of sliding to the 28th. A segment is a draft
|
|
302
|
+
until its last digit lands: a half-typed year neither reports a value nor
|
|
303
|
+
raises `onInvalid`, and blur settles whatever is there.
|
|
151
304
|
- Use `value`/`onChange` or `defaultValue`/`onChange` — do not switch modes
|
|
152
305
|
during a component's lifetime.
|
|
306
|
+
- Field segments take digits from the keyboard and from soft keyboards that only
|
|
307
|
+
report an input event. The AM/PM segment also accepts its locale's own label,
|
|
308
|
+
so it can be set from a touch keyboard; it has no pointer affordance of its
|
|
309
|
+
own, so give readers a keyboard path to it.
|
|
153
310
|
|
|
154
311
|
## Server Rendering
|
|
155
312
|
|
|
156
|
-
These
|
|
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.
|
|
157
317
|
|
|
158
318
|
The polyfill import is a side effect, so it has to reach the *client* bundle.
|
|
159
319
|
Importing `temporal-polyfill/global` from a Server Component file installs
|
|
@@ -172,15 +332,78 @@ export function Providers({ children }: { children: React.ReactNode }) {
|
|
|
172
332
|
}
|
|
173
333
|
```
|
|
174
334
|
|
|
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:
|
|
341
|
+
|
|
342
|
+
```tsx
|
|
343
|
+
"use client";
|
|
344
|
+
|
|
345
|
+
import "temporal-polyfill/global";
|
|
346
|
+
import { Calendar } from "chrona-react";
|
|
347
|
+
|
|
348
|
+
const REFERENCE = Temporal.PlainDate.from({ year: 2026, month: 9, day: 16 });
|
|
349
|
+
```
|
|
350
|
+
|
|
175
351
|
Pass the same reference date, value, locale, and time zone on server and client.
|
|
176
|
-
|
|
177
|
-
|
|
352
|
+
|
|
353
|
+
### Today
|
|
354
|
+
|
|
355
|
+
A server cannot know the reader's today: it may be in another time zone, and a
|
|
356
|
+
statically prerendered page can be served days after it was built. `Calendar`
|
|
357
|
+
therefore leaves `data-today` and `aria-current="date"` out of the server HTML
|
|
358
|
+
and resolves them on the client, right after hydration. The marker is correct
|
|
359
|
+
for the reader and the markup hydrates cleanly; the cost is that it appears one
|
|
360
|
+
frame late. Pass `today` yourself when you want it in the server HTML:
|
|
361
|
+
|
|
362
|
+
```tsx
|
|
363
|
+
<Calendar.Root today={Temporal.PlainDate.from("2026-09-16")} />
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
### Give every calendar a reference date
|
|
367
|
+
|
|
368
|
+
With no `value`, `defaultValue`, `focusedValue`, `defaultFocusedValue` or
|
|
369
|
+
`placeholderValue`, a calendar opens on the month of *its own* today — the
|
|
370
|
+
server's on the server, the reader's in the browser. When those differ the
|
|
371
|
+
focused cell, and at a month boundary the whole grid, will not match, and React
|
|
372
|
+
reports a hydration mismatch it cannot patch up. Supply `placeholderValue` (or
|
|
373
|
+
a value) on any calendar that is server-rendered.
|
|
374
|
+
|
|
375
|
+
### Segments report once
|
|
376
|
+
|
|
377
|
+
A `DateField` segment is a draft until its last digit lands. Typing `2026` calls
|
|
378
|
+
`onChange` once with that year, not four times on the way through 2, 20 and 202,
|
|
379
|
+
so a handler that writes to a route, a server action or a store is not handed
|
|
380
|
+
dates nobody typed. Leaving the field early settles the draft literally: `20`
|
|
381
|
+
becomes the year 20.
|
|
178
382
|
|
|
179
383
|
Segment literals are normalized before they reach the DOM: `Intl` emits U+202F
|
|
180
384
|
before AM/PM on newer ICU data and a plain space on older data, and Node and the
|
|
181
385
|
browser rarely ship the same ICU. Chrona collapses both to a plain space, so a
|
|
182
386
|
12-hour `TimeField` hydrates cleanly without forcing `hourCycle="h23"`.
|
|
183
387
|
|
|
388
|
+
Two things it does not cover:
|
|
389
|
+
|
|
390
|
+
- Dates before the Gregorian reform of 1582. Labels go through the `gregory`
|
|
391
|
+
calendar, which ICU treats as Julian before the cutover, and runtimes disagree
|
|
392
|
+
about the shift — Node labels ISO `0001-01-01` "January 3, 1" where Chrome
|
|
393
|
+
says "January 1, 1". Historical ranges that reach back past 1582 will both
|
|
394
|
+
mislabel cells and mismatch on hydration.
|
|
395
|
+
- Cell labels in `ja-JP` and `zh-CN` when the server and the browser run
|
|
396
|
+
*different* Temporal implementations. V8 renders a date-only `dateStyle` as
|
|
397
|
+
`2026/9/16水曜日`; `temporal-polyfill` renders `2026年9月16日水曜日`. Node 24+
|
|
398
|
+
and current Chrome are both native, so they agree — but a Node 22 server is
|
|
399
|
+
polyfilled while its Chrome client is not, and every cell's accessible name
|
|
400
|
+
then differs. Run the same implementation on both sides.
|
|
401
|
+
|
|
402
|
+
Load exactly one Temporal implementation, too. Two copies of a polyfill, or a
|
|
403
|
+
mix of its default and `full` entry points, each install their own
|
|
404
|
+
`globalThis.Temporal`; values built by the loser are refused with a
|
|
405
|
+
`TEMPORAL_MISMATCH` `ChronaError` naming that cause.
|
|
406
|
+
|
|
184
407
|
Full documentation lives in the [repository README](https://github.com/devlinduldulao/chrona#readme).
|
|
185
408
|
|
|
186
409
|
## License
|
package/dist/calendar.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
import {
|
|
2
3
|
Calendar,
|
|
3
4
|
CalendarRoot,
|
|
4
5
|
CalendarSurface,
|
|
5
6
|
useCalendar
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
7
|
+
} from "./chunk-I46LC4EZ.js";
|
|
8
|
+
import "./chunk-SDDSKOYU.js";
|
|
8
9
|
export {
|
|
9
10
|
Calendar,
|
|
10
11
|
CalendarRoot,
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
import {
|
|
2
3
|
Part,
|
|
3
4
|
composeEvent,
|
|
4
5
|
useChronaConfig,
|
|
5
6
|
useFormReset
|
|
6
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-SDDSKOYU.js";
|
|
7
8
|
|
|
8
9
|
// src/field.tsx
|
|
9
10
|
import * as React from "react";
|
|
10
|
-
import { connectField, createField, createStore, digitValue, fieldHourCycle, transitionField, translations } from "chrona-core";
|
|
11
|
+
import { connectField, createField, createStore, dayPeriodValue, digitValue, fieldHourCycle, transitionField, translations } from "chrona-core";
|
|
11
12
|
import { jsx } from "react/jsx-runtime";
|
|
12
13
|
function equalValues(first, second) {
|
|
13
14
|
return first === null || second === null ? first === second : first.equals(second);
|
|
@@ -63,6 +64,7 @@ function useField(kind, props) {
|
|
|
63
64
|
const [labelled, setLabelled] = React.useState(false);
|
|
64
65
|
return { id, state, options, send, reset, moveFocus, groupRef, announcement, registerLabel: setLabelled, api: connectField(state, { ...options, id, labelId: labelled ? `${id}-label` : void 0 }) };
|
|
65
66
|
}
|
|
67
|
+
var isInsertion = (type) => type === "insertText" || type === "insertCompositionText" || type === "insertReplacementText";
|
|
66
68
|
function createFieldComponents(kind) {
|
|
67
69
|
const Context = React.createContext(null);
|
|
68
70
|
function useContext2() {
|
|
@@ -107,10 +109,19 @@ function createFieldComponents(kind) {
|
|
|
107
109
|
onDrop: composeEvent(onDrop, (event) => event.preventDefault()),
|
|
108
110
|
onChange: (event) => {
|
|
109
111
|
const native = event.nativeEvent;
|
|
110
|
-
const
|
|
112
|
+
const data = native.data ?? "";
|
|
111
113
|
event.currentTarget.value = display;
|
|
112
|
-
if (native.inputType
|
|
113
|
-
|
|
114
|
+
if (isInsertion(native.inputType)) {
|
|
115
|
+
if (type === "dayPeriod") {
|
|
116
|
+
const period = dayPeriodValue(data, options.locale, fieldHourCycle(options));
|
|
117
|
+
if (period !== null) send({ type: "PERIOD", value: period });
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
const digit = digitValue(data, options.locale);
|
|
121
|
+
if (digit !== null) send({ type: "DIGIT", segment: type, digit });
|
|
122
|
+
} else if (native.inputType === "deleteContentBackward" || native.inputType === "deleteContentForward") {
|
|
123
|
+
send({ type: "CLEAR", segment: type });
|
|
124
|
+
}
|
|
114
125
|
},
|
|
115
126
|
onKeyDown: composeEvent(onKeyDown, (event) => {
|
|
116
127
|
if (event.altKey || event.ctrlKey || event.metaKey || event.nativeEvent.isComposing) return;
|
|
@@ -142,11 +153,14 @@ function createFieldComponents(kind) {
|
|
|
142
153
|
event.preventDefault();
|
|
143
154
|
moveFocus(type, (event.key === "ArrowRight" ? 1 : -1) * (dir === "rtl" ? -1 : 1));
|
|
144
155
|
break;
|
|
145
|
-
default:
|
|
146
|
-
if (type
|
|
156
|
+
default: {
|
|
157
|
+
if (type !== "dayPeriod" || event.key.length !== 1) return;
|
|
158
|
+
const period = dayPeriodValue(event.key, options.locale, fieldHourCycle(options));
|
|
159
|
+
if (period !== null) {
|
|
147
160
|
event.preventDefault();
|
|
148
|
-
send({ type: "PERIOD", value:
|
|
161
|
+
send({ type: "PERIOD", value: period });
|
|
149
162
|
}
|
|
163
|
+
}
|
|
150
164
|
}
|
|
151
165
|
})
|
|
152
166
|
}
|
|
@@ -181,4 +195,4 @@ export {
|
|
|
181
195
|
useField,
|
|
182
196
|
createFieldComponents
|
|
183
197
|
};
|
|
184
|
-
//# sourceMappingURL=chunk-
|
|
198
|
+
//# sourceMappingURL=chunk-27APJXNX.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/field.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { connectField, createField, createStore, dayPeriodValue, digitValue, fieldHourCycle, transitionField, translations, type FieldEvent, type FieldInvalidReason, type FieldKind, type FieldOptions, type FieldValue, type SegmentType } from \"chrona-core\";\nimport { Part, composeEvent, type PartProps } from \"./part\";\nimport { useChronaConfig } from \"./provider\";\nimport { useFormReset, type HiddenInputProps } from \"./form\";\n\nexport interface FieldProps<Kind extends FieldKind> extends FieldOptions<Kind> {\n defaultValue?: FieldValue<Kind> | null;\n onChange?: (value: FieldValue<Kind> | null) => void;\n onInvalid?: (reason: FieldInvalidReason) => void;\n id?: string;\n describedBy?: string;\n}\n\nfunction equalValues(first: { equals: (other: never) => boolean } | null, second: { equals: (other: never) => boolean } | null) {\n return first === null || second === null ? first === second : first.equals(second as never);\n}\n\nexport function useField<Kind extends FieldKind>(kind: Kind, props: FieldProps<Kind>) {\n const options = useChronaConfig(props);\n const generatedId = React.useId();\n const id = props.id ?? generatedId;\n const [store] = React.useState(() => createStore(createField(kind, { ...options, value: props.value !== undefined ? props.value : props.defaultValue })));\n const snapshot = React.useSyncExternalStore(store.subscribe, store.getSnapshot, store.getServerSnapshot);\n const value = props.value !== undefined ? props.value : snapshot.value;\n const placeholderValue = options.placeholderValue ?? snapshot.reference;\n const { minValue, maxValue, locale, hourCycle, granularity } = options;\n const configured = React.useMemo(() => createField(kind, { value, placeholderValue, minValue, maxValue, locale, hourCycle, granularity }), [kind, value, placeholderValue, minValue, maxValue, locale, hourCycle, granularity]);\n const cycle = fieldHourCycle(options);\n const configuration = `${cycle}:${props.granularity ?? \"minute\"}`;\n const previousConfiguration = React.useRef(configuration);\n const state = props.value !== undefined && !equalValues(snapshot.value, props.value)\n ? configured\n : kind === \"time\" && configuration !== previousConfiguration.current\n ? configured\n : snapshot;\n React.useEffect(() => {\n if (previousConfiguration.current !== configuration) {\n previousConfiguration.current = configuration;\n store.setState(state);\n }\n }, [configuration, state, store]);\n const groupRef = React.useRef<HTMLElement | null>(null);\n const [invalidReason, setInvalidReason] = React.useState<FieldInvalidReason | null>(null);\n const announcementKey = { range: \"invalidRange\", unavailable: \"unavailable\", nonexistent: \"nonexistentDate\" } as const;\n const announcement = invalidReason === null ? \"\" : options.translations?.[announcementKey[invalidReason]] ?? translations[announcementKey[invalidReason]];\n\n function moveFocus(segment: SegmentType, offset: number) {\n const elements = Array.from(groupRef.current?.querySelectorAll<HTMLInputElement>(\"input[data-segment]\") ?? []);\n const index = elements.findIndex((element) => element.dataset.segment === segment);\n elements[index + offset]?.focus();\n }\n\n function send(event: FieldEvent) {\n const result = transitionField(state, event, options);\n store.setState(result.state);\n if (!result.state.invalid) setInvalidReason(null);\n for (const effect of result.effects) {\n if (effect.type === \"change\") props.onChange?.(effect.value);\n if (effect.type === \"invalid\") { setInvalidReason(effect.reason); props.onInvalid?.(effect.reason); }\n if (effect.type === \"advance\") queueMicrotask(() => moveFocus(effect.segment, 1));\n }\n }\n\n function reset() {\n setInvalidReason(null);\n const value = props.defaultValue ?? null;\n store.setState(createField(kind, { ...options, value }));\n if (!equalValues(state.value, value)) props.onChange?.(value);\n }\n\n const [labelled, setLabelled] = React.useState(false);\n return { id, state, options, send, reset, moveFocus, groupRef, announcement, registerLabel: setLabelled, api: connectField(state, { ...options, id, labelId: labelled ? `${id}-label` : undefined }) };\n}\n\n/** Insertion `inputType`s a soft keyboard or IME can use for a single character. */\nconst isInsertion = (type: string) => type === \"insertText\" || type === \"insertCompositionText\" || type === \"insertReplacementText\";\n\nexport function createFieldComponents<Kind extends FieldKind>(kind: Kind) {\n const Context = React.createContext<ReturnType<typeof useField<Kind>> | null>(null);\n function useContext() {\n const context = React.useContext(Context);\n if (!context) throw new Error(`${kind === \"date\" ? \"DateField\" : \"TimeField\"} parts must be inside their Root.`);\n return context;\n }\n\n function Root({ children, asChild, className, style, ...props }: FieldProps<Kind> & Pick<PartProps, \"children\" | \"asChild\" | \"className\" | \"style\">) {\n const context = useField(kind, props);\n return <Context.Provider value={context}><Part asChild={asChild} className={className} style={style} id={props.id} dir={context.options.dir} data-scope={`${kind}-field`} data-part=\"root\">{children}</Part></Context.Provider>;\n }\n\n const Label = React.forwardRef<HTMLElement, PartProps>(function Label(props, ref) {\n const { id, registerLabel } = useContext();\n React.useEffect(() => {\n registerLabel(true);\n return () => registerLabel(false);\n }, [registerLabel]);\n return <Part as=\"span\" {...props} ref={ref} id={`${id}-label`} data-scope={`${kind}-field`} data-part=\"label\" />;\n });\n\n const Segment = React.forwardRef<HTMLInputElement, Omit<React.ComponentPropsWithoutRef<\"input\">, \"type\" | \"value\" | \"defaultValue\" | \"onChange\" | \"children\"> & { type: SegmentType }>(function Segment({ type, onKeyDown, onFocus, onBlur, onPaste, onDrop, ...props }, ref) {\n const { state, api, options, send, moveFocus, groupRef } = useContext();\n if (!(type in state.parts)) throw new Error(`The ${type} segment is not enabled in this field.`);\n const { display, ...segmentProps } = api.getSegmentProps(type);\n return <input {...props} {...segmentProps} ref={ref} type=\"text\" inputMode={type === \"dayPeriod\" ? \"text\" : \"numeric\"} autoComplete=\"off\" spellCheck={false} value={display} disabled={options.disabled} readOnly={options.readOnly}\n onFocus={composeEvent(onFocus, (event) => { event.currentTarget.select(); })}\n onBlur={composeEvent(onBlur, () => send({ type: \"BLUR\" }))}\n onPaste={composeEvent(onPaste, (event) => event.preventDefault())}\n onDrop={composeEvent(onDrop, (event) => event.preventDefault())}\n onChange={(event) => {\n // Soft keyboards do not produce a usable `key`, and Android delivers most text as a\n // composition, so the input event is the only signal there. Nothing is parsed: the\n // inserted text still has to read as one digit, or as this locale's AM/PM label.\n const native = event.nativeEvent as InputEvent;\n const data = native.data ?? \"\";\n event.currentTarget.value = display;\n if (isInsertion(native.inputType)) {\n if (type === \"dayPeriod\") {\n const period = dayPeriodValue(data, options.locale, fieldHourCycle(options));\n if (period !== null) send({ type: \"PERIOD\", value: period });\n return;\n }\n const digit = digitValue(data, options.locale);\n if (digit !== null) send({ type: \"DIGIT\", segment: type, digit });\n } else if (native.inputType === \"deleteContentBackward\" || native.inputType === \"deleteContentForward\") {\n send({ type: \"CLEAR\", segment: type });\n }\n }}\n onKeyDown={composeEvent(onKeyDown, (event) => {\n if (event.altKey || event.ctrlKey || event.metaKey || event.nativeEvent.isComposing) return;\n const digit = digitValue(event.key, options.locale);\n const dir = options.dir ?? (groupRef.current?.closest(\"[dir]\")?.getAttribute(\"dir\") === \"rtl\" ? \"rtl\" : \"ltr\");\n if (digit !== null) { event.preventDefault(); send({ type: \"DIGIT\", segment: type, digit }); return; }\n switch (event.key) {\n case \"ArrowUp\": case \"ArrowDown\": event.preventDefault(); send({ type: \"STEP\", segment: type, direction: event.key === \"ArrowUp\" ? 1 : -1 }); break;\n case \"Home\": case \"End\": event.preventDefault(); send({ type: \"EDGE\", segment: type, edge: event.key === \"Home\" ? \"min\" : \"max\" }); break;\n case \"Backspace\": case \"Delete\": event.preventDefault(); send({ type: \"CLEAR\", segment: type }); break;\n case \"ArrowLeft\": case \"ArrowRight\": event.preventDefault(); moveFocus(type, (event.key === \"ArrowRight\" ? 1 : -1) * (dir === \"rtl\" ? -1 : 1)); break;\n default: {\n if (type !== \"dayPeriod\" || event.key.length !== 1) return;\n const period = dayPeriodValue(event.key, options.locale, fieldHourCycle(options));\n if (period !== null) { event.preventDefault(); send({ type: \"PERIOD\", value: period }); }\n }\n }\n })} />;\n });\n\n const Field = React.forwardRef<HTMLElement, PartProps>(function Field({ children, ...props }, ref) {\n const { api, groupRef } = useContext();\n return <Part {...props} {...api.getGroupProps()} ref={(node) => {\n groupRef.current = node;\n if (typeof ref === \"function\") ref(node); else if (ref) ref.current = node;\n }}>{children ?? api.segments.map((segment, index) => segment.type === \"literal\" ? <span key={index} aria-hidden=\"true\" data-scope={`${kind}-field`} data-part=\"literal\">{segment.value}</span> : <Segment key={segment.type} type={segment.type} />)}</Part>;\n });\n\n function HiddenInput(props: HiddenInputProps) {\n const { state, options, reset } = useContext();\n const input = React.useRef<HTMLInputElement>(null);\n useFormReset(input, props.form, reset);\n return <input {...props} ref={input} type=\"hidden\" value={state.value?.toString() ?? \"\"} disabled={options.disabled || props.disabled} data-scope={`${kind}-field`} data-part=\"hidden-input\" />;\n }\n\n const ClearButton = React.forwardRef<HTMLElement, React.ComponentPropsWithoutRef<\"button\"> & { asChild?: boolean }>(function ClearButton({ onClick, ...props }, ref) {\n const { options, send } = useContext();\n return <Part as=\"button\" {...props} ref={ref} type=\"button\" aria-label={options.translations?.clear ?? translations.clear} disabled={options.disabled || options.readOnly} data-scope={`${kind}-field`} data-part=\"clear-button\" onClick={composeEvent(onClick, () => send({ type: \"CLEAR\" }))} />;\n });\n\n const LiveRegion = React.forwardRef<HTMLElement, PartProps>(function LiveRegion(props, ref) {\n const { announcement } = useContext();\n return <Part {...props} ref={ref} role=\"status\" aria-live=\"polite\" aria-atomic=\"true\" data-scope={`${kind}-field`} data-part=\"live-region\">{announcement}</Part>;\n });\n\n return { Root, Label, Field, Segment, HiddenInput, ClearButton, LiveRegion };\n}"],"mappings":"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","names":["value","useContext","Label","Segment","Field","ClearButton","LiveRegion"]}
|
|
@@ -1,19 +1,23 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
import {
|
|
2
3
|
Calendar,
|
|
3
4
|
CalendarSurface,
|
|
4
5
|
useCalendar
|
|
5
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-I46LC4EZ.js";
|
|
6
7
|
import {
|
|
7
8
|
Part,
|
|
8
9
|
composeEvent,
|
|
9
10
|
useChronaConfig,
|
|
10
11
|
useFormReset
|
|
11
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-SDDSKOYU.js";
|
|
12
13
|
|
|
13
14
|
// src/range-calendar.tsx
|
|
14
15
|
import * as React from "react";
|
|
15
|
-
import { createRange, createStore, formatDate, getRangeCellProps, getRangeCellTriggerProps, transitionRange, translations, validateRange } from "chrona-core";
|
|
16
|
+
import { createRange, createStore, formatDate, getRangeCellProps, getRangeCellTriggerProps, sameDate, transitionRange, translations, validateRange } from "chrona-core";
|
|
16
17
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
18
|
+
function sameRange(first, second) {
|
|
19
|
+
return first === null || second === null ? first === second : sameDate(first.start, second.start) && sameDate(first.end, second.end);
|
|
20
|
+
}
|
|
17
21
|
function useRangeCalendar(input = {}) {
|
|
18
22
|
const props = useChronaConfig(input);
|
|
19
23
|
const [store] = React.useState(() => createStore(createRange(props.value !== void 0 ? props.value : props.defaultValue)));
|
|
@@ -63,7 +67,7 @@ function useRangeCalendar(input = {}) {
|
|
|
63
67
|
reset() {
|
|
64
68
|
const value = props.defaultValue ?? null;
|
|
65
69
|
store.setState(createRange(value));
|
|
66
|
-
props.onChange?.(value);
|
|
70
|
+
if (!sameRange(state.value, value)) props.onChange?.(value);
|
|
67
71
|
},
|
|
68
72
|
calendar: { ...calendar, api }
|
|
69
73
|
};
|
|
@@ -113,4 +117,4 @@ export {
|
|
|
113
117
|
useRangeCalendar,
|
|
114
118
|
RangeCalendar
|
|
115
119
|
};
|
|
116
|
-
//# sourceMappingURL=chunk-
|
|
120
|
+
//# sourceMappingURL=chunk-GXQA645Q.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/range-calendar.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { createRange, createStore, formatDate, getRangeCellProps, getRangeCellTriggerProps, sameDate, transitionRange, translations, validateRange, type DateRange, type PlainDate, type RangeEvent } from \"chrona-core\";\nimport { Calendar, CalendarSurface, useCalendar, type CalendarProps } from \"./calendar\";\nimport { Part, composeEvent, type PartProps } from \"./part\";\nimport { useFormReset, type HiddenInputProps } from \"./form\";\nimport { useChronaConfig } from \"./provider\";\n\nexport interface RangeCalendarProps extends Omit<CalendarProps, \"value\" | \"defaultValue\" | \"onChange\"> {\n value?: DateRange | null;\n defaultValue?: DateRange | null;\n onChange?: (value: DateRange | null) => void;\n onRangeStartChange?: (value: PlainDate | null) => void;\n onInvalid?: () => void;\n}\n\nfunction sameRange(first: DateRange | null, second: DateRange | null): boolean {\n return first === null || second === null\n ? first === second\n : sameDate(first.start, second.start) && sameDate(first.end, second.end);\n}\n\nexport function useRangeCalendar(input: RangeCalendarProps = {}) {\n const props = useChronaConfig(input);\n const [store] = React.useState(() => createStore(createRange(props.value !== undefined ? props.value : props.defaultValue)));\n const snapshot = React.useSyncExternalStore(store.subscribe, store.getSnapshot, store.getServerSnapshot);\n if (props.value) validateRange(props.value);\n const state = { ...snapshot, value: props.value === undefined ? snapshot.value : props.value };\n const [announcement, setAnnouncement] = React.useState(\"\");\n function send(event: RangeEvent) {\n const result = transitionRange(state, event, props);\n store.setState(result.state);\n for (const effect of result.effects) {\n if (effect.type === \"change\") {\n props.onChange?.(effect.value);\n setAnnouncement(effect.value ? [effect.value.start, effect.value.end].map((date) => formatDate(date, props.locale, { dateStyle: \"long\" })).join(props.translations?.rangeSeparator ?? translations.rangeSeparator) : \"\");\n }\n if (effect.type === \"rangeStart\") {\n props.onRangeStartChange?.(effect.value);\n if (effect.value) setAnnouncement(formatDate(effect.value, props.locale, { dateStyle: \"long\" }));\n }\n if (effect.type === \"invalid\") { props.onInvalid?.(); setAnnouncement(props.translations?.unavailable ?? translations.unavailable); }\n }\n }\n const calendar = useCalendar({ ...props, value: null, defaultValue: null, placeholderValue: props.placeholderValue ?? state.value?.start, onChange: (date) => { if (date) send({ type: \"SELECT\", date }); }, onFocusedValueChange: (date) => { props.onFocusedValueChange?.(date); if (state.anchor) send({ type: \"PREVIEW\", date }); } });\n const baseApi = calendar.api;\n const api = {\n ...baseApi,\n getCellProps: (date: PlainDate, month?: PlainDate) => ({ ...baseApi.getCellProps(date, month), ...getRangeCellProps(state, date) }),\n getCellTriggerProps: (date: PlainDate, month?: PlainDate) => ({ ...baseApi.getCellTriggerProps(date, month), ...getRangeCellTriggerProps(state, date) }),\n };\n return {\n state, send, announcement, props, options: props, api, rootRef: calendar.rootRef, months: calendar.months,\n reset() {\n const value = props.defaultValue ?? null;\n store.setState(createRange(value));\n if (!sameRange(state.value, value)) props.onChange?.(value);\n },\n calendar: { ...calendar, api },\n };\n}\n\nconst Context = React.createContext<ReturnType<typeof useRangeCalendar> | null>(null);\nfunction useContext() {\n const value = React.useContext(Context);\n if (!value) throw new Error(\"RangeCalendar parts must be inside RangeCalendar.Root.\");\n return value;\n}\n\nfunction Root({ children, asChild, className, style, ...props }: RangeCalendarProps & Pick<PartProps, \"children\" | \"asChild\" | \"className\" | \"style\">) {\n const context = useRangeCalendar(props);\n return <Context.Provider value={context}><CalendarSurface calendar={context.calendar} asChild={asChild} className={className} style={style} data-scope=\"range-calendar\" onKeyDown={(event) => { if (event.key === \"Escape\" && context.state.anchor) { event.preventDefault(); context.send({ type: \"CANCEL\" }); } }}>{children}</CalendarSurface></Context.Provider>;\n}\n\nconst Cell = React.forwardRef<HTMLElement, React.ComponentPropsWithoutRef<typeof Calendar.Cell>>(function Cell({ date, onPointerEnter, ...props }, ref) {\n const { send } = useContext();\n return <Calendar.Cell {...props} ref={ref} date={date} onPointerEnter={composeEvent(onPointerEnter, () => send({ type: \"PREVIEW\", date }))} />;\n});\n\nconst GridBody = React.forwardRef<HTMLElement, React.ComponentPropsWithoutRef<typeof Calendar.GridBody>>(function GridBody({ children, ...props }, ref) {\n return <Calendar.GridBody {...props} ref={ref}>{children ?? ((date) => <Cell date={date} />)}</Calendar.GridBody>;\n});\n\nconst LiveRegion = React.forwardRef<HTMLElement, PartProps>(function LiveRegion(props, ref) {\n const { announcement } = useContext();\n return <Part {...props} ref={ref} role=\"status\" aria-live=\"polite\" aria-atomic=\"true\" data-scope=\"range-calendar\" data-part=\"live-region\">{announcement}</Part>;\n});\n\nconst ClearButton = React.forwardRef<HTMLElement, React.ComponentPropsWithoutRef<typeof Calendar.ClearButton>>(function ClearButton({ onClick, ...props }, ref) {\n const { send, props: options } = useContext();\n return <Part as=\"button\" {...props} ref={ref} type=\"button\" disabled={options.disabled || options.readOnly} aria-label={options.translations?.clear ?? translations.clear} data-scope=\"range-calendar\" data-part=\"clear-button\" onClick={composeEvent(onClick, () => send({ type: \"CLEAR\" }))} />;\n});\n\nfunction HiddenInput({ name, form, id, disabled, ...inputProps }: HiddenInputProps & { name: string }) {\n const { state, props, reset } = useContext();\n const input = React.useRef<HTMLInputElement>(null);\n useFormReset(input, form, reset);\n return <><input {...inputProps} id={id ? `${id}-start` : undefined} ref={input} type=\"hidden\" name={`${name}.start`} form={form} value={state.value?.start.toString() ?? \"\"} disabled={props.disabled || disabled} data-scope=\"range-calendar\" data-part=\"hidden-input\" /><input {...inputProps} id={id ? `${id}-end` : undefined} type=\"hidden\" name={`${name}.end`} form={form} value={state.value?.end.toString() ?? \"\"} disabled={props.disabled || disabled} data-scope=\"range-calendar\" data-part=\"hidden-input\" /></>;\n}\n\nexport const RangeCalendar = { ...Calendar, Root, Cell, GridBody, LiveRegion, ClearButton, HiddenInput };"],"mappings":";;;;;;;;;;;;;;AAAA,YAAY,WAAW;AACvB,SAAS,aAAa,aAAa,YAAY,mBAAmB,0BAA0B,UAAU,iBAAiB,cAAc,qBAAsE;AAqE9J,SA0BlC,UA1BkC,KA0BlC,YA1BkC;AAvD7C,SAAS,UAAU,OAAyB,QAAmC;AAC3E,SAAO,UAAU,QAAQ,WAAW,OAC9B,UAAU,SACV,SAAS,MAAM,OAAO,OAAO,KAAK,KAAK,SAAS,MAAM,KAAK,OAAO,GAAG;AAC/E;AAEO,SAAS,iBAAiB,QAA4B,CAAC,GAAG;AAC7D,QAAM,QAAQ,gBAAgB,KAAK;AACnC,QAAM,CAAC,KAAK,IAAU,eAAS,MAAM,YAAY,YAAY,MAAM,UAAU,SAAY,MAAM,QAAQ,MAAM,YAAY,CAAC,CAAC;AAC3H,QAAM,WAAiB,2BAAqB,MAAM,WAAW,MAAM,aAAa,MAAM,iBAAiB;AACvG,MAAI,MAAM,MAAO,eAAc,MAAM,KAAK;AAC1C,QAAM,QAAQ,EAAE,GAAG,UAAU,OAAO,MAAM,UAAU,SAAY,SAAS,QAAQ,MAAM,MAAM;AAC7F,QAAM,CAAC,cAAc,eAAe,IAAU,eAAS,EAAE;AACzD,WAAS,KAAK,OAAmB;AAC7B,UAAM,SAAS,gBAAgB,OAAO,OAAO,KAAK;AAClD,UAAM,SAAS,OAAO,KAAK;AAC3B,eAAW,UAAU,OAAO,SAAS;AACjC,UAAI,OAAO,SAAS,UAAU;AAC1B,cAAM,WAAW,OAAO,KAAK;AAC7B,wBAAgB,OAAO,QAAQ,CAAC,OAAO,MAAM,OAAO,OAAO,MAAM,GAAG,EAAE,IAAI,CAAC,SAAS,WAAW,MAAM,MAAM,QAAQ,EAAE,WAAW,OAAO,CAAC,CAAC,EAAE,KAAK,MAAM,cAAc,kBAAkB,aAAa,cAAc,IAAI,EAAE;AAAA,MAC3N;AACA,UAAI,OAAO,SAAS,cAAc;AAC9B,cAAM,qBAAqB,OAAO,KAAK;AACvC,YAAI,OAAO,MAAO,iBAAgB,WAAW,OAAO,OAAO,MAAM,QAAQ,EAAE,WAAW,OAAO,CAAC,CAAC;AAAA,MACnG;AACA,UAAI,OAAO,SAAS,WAAW;AAAE,cAAM,YAAY;AAAG,wBAAgB,MAAM,cAAc,eAAe,aAAa,WAAW;AAAA,MAAG;AAAA,IACxI;AAAA,EACJ;AACA,QAAM,WAAW,YAAY,EAAE,GAAG,OAAO,OAAO,MAAM,cAAc,MAAM,kBAAkB,MAAM,oBAAoB,MAAM,OAAO,OAAO,UAAU,CAAC,SAAS;AAAE,QAAI,KAAM,MAAK,EAAE,MAAM,UAAU,KAAK,CAAC;AAAA,EAAG,GAAG,sBAAsB,CAAC,SAAS;AAAE,UAAM,uBAAuB,IAAI;AAAG,QAAI,MAAM,OAAQ,MAAK,EAAE,MAAM,WAAW,KAAK,CAAC;AAAA,EAAG,EAAE,CAAC;AACzU,QAAM,UAAU,SAAS;AACzB,QAAM,MAAM;AAAA,IACR,GAAG;AAAA,IACH,cAAc,CAAC,MAAiB,WAAuB,EAAE,GAAG,QAAQ,aAAa,MAAM,KAAK,GAAG,GAAG,kBAAkB,OAAO,IAAI,EAAE;AAAA,IACjI,qBAAqB,CAAC,MAAiB,WAAuB,EAAE,GAAG,QAAQ,oBAAoB,MAAM,KAAK,GAAG,GAAG,yBAAyB,OAAO,IAAI,EAAE;AAAA,EAC1J;AACA,SAAO;AAAA,IACH;AAAA,IAAO;AAAA,IAAM;AAAA,IAAc;AAAA,IAAO,SAAS;AAAA,IAAO;AAAA,IAAK,SAAS,SAAS;AAAA,IAAS,QAAQ,SAAS;AAAA,IACnG,QAAQ;AACJ,YAAM,QAAQ,MAAM,gBAAgB;AACpC,YAAM,SAAS,YAAY,KAAK,CAAC;AACjC,UAAI,CAAC,UAAU,MAAM,OAAO,KAAK,EAAG,OAAM,WAAW,KAAK;AAAA,IAC9D;AAAA,IACA,UAAU,EAAE,GAAG,UAAU,IAAI;AAAA,EACjC;AACJ;AAEA,IAAM,UAAgB,oBAA0D,IAAI;AACpF,SAASA,cAAa;AAClB,QAAM,QAAc,iBAAW,OAAO;AACtC,MAAI,CAAC,MAAO,OAAM,IAAI,MAAM,wDAAwD;AACpF,SAAO;AACX;AAEA,SAAS,KAAK,EAAE,UAAU,SAAS,WAAW,OAAO,GAAG,MAAM,GAAyF;AACnJ,QAAM,UAAU,iBAAiB,KAAK;AACtC,SAAO,oBAAC,QAAQ,UAAR,EAAiB,OAAO,SAAS,8BAAC,mBAAgB,UAAU,QAAQ,UAAU,SAAkB,WAAsB,OAAc,cAAW,kBAAiB,WAAW,CAAC,UAAU;AAAE,QAAI,MAAM,QAAQ,YAAY,QAAQ,MAAM,QAAQ;AAAE,YAAM,eAAe;AAAG,cAAQ,KAAK,EAAE,MAAM,SAAS,CAAC;AAAA,IAAG;AAAA,EAAE,GAAI,UAAS,GAAkB;AACrV;AAEA,IAAM,OAAa,iBAA8E,SAASC,MAAK,EAAE,MAAM,gBAAgB,GAAG,MAAM,GAAG,KAAK;AACpJ,QAAM,EAAE,KAAK,IAAID,YAAW;AAC5B,SAAO,oBAAC,SAAS,MAAT,EAAe,GAAG,OAAO,KAAU,MAAY,gBAAgB,aAAa,gBAAgB,MAAM,KAAK,EAAE,MAAM,WAAW,KAAK,CAAC,CAAC,GAAG;AAChJ,CAAC;AAED,IAAM,WAAiB,iBAAkF,SAASE,UAAS,EAAE,UAAU,GAAG,MAAM,GAAG,KAAK;AACpJ,SAAO,oBAAC,SAAS,UAAT,EAAmB,GAAG,OAAO,KAAW,uBAAa,CAAC,SAAS,oBAAC,QAAK,MAAY,IAAI;AACjG,CAAC;AAED,IAAM,aAAmB,iBAAmC,SAASC,YAAW,OAAO,KAAK;AACxF,QAAM,EAAE,aAAa,IAAIH,YAAW;AACpC,SAAO,oBAAC,QAAM,GAAG,OAAO,KAAU,MAAK,UAAS,aAAU,UAAS,eAAY,QAAO,cAAW,kBAAiB,aAAU,eAAe,wBAAa;AAC5J,CAAC;AAED,IAAM,cAAoB,iBAAqF,SAASI,aAAY,EAAE,SAAS,GAAG,MAAM,GAAG,KAAK;AAC5J,QAAM,EAAE,MAAM,OAAO,QAAQ,IAAIJ,YAAW;AAC5C,SAAO,oBAAC,QAAK,IAAG,UAAU,GAAG,OAAO,KAAU,MAAK,UAAS,UAAU,QAAQ,YAAY,QAAQ,UAAU,cAAY,QAAQ,cAAc,SAAS,aAAa,OAAO,cAAW,kBAAiB,aAAU,gBAAe,SAAS,aAAa,SAAS,MAAM,KAAK,EAAE,MAAM,QAAQ,CAAC,CAAC,GAAG;AACnS,CAAC;AAED,SAAS,YAAY,EAAE,MAAM,MAAM,IAAI,UAAU,GAAG,WAAW,GAAwC;AACnG,QAAM,EAAE,OAAO,OAAO,MAAM,IAAIA,YAAW;AAC3C,QAAM,QAAc,aAAyB,IAAI;AACjD,eAAa,OAAO,MAAM,KAAK;AAC/B,SAAO,iCAAE;AAAA,wBAAC,WAAO,GAAG,YAAY,IAAI,KAAK,GAAG,EAAE,WAAW,QAAW,KAAK,OAAO,MAAK,UAAS,MAAM,GAAG,IAAI,UAAU,MAAY,OAAO,MAAM,OAAO,MAAM,SAAS,KAAK,IAAI,UAAU,MAAM,YAAY,UAAU,cAAW,kBAAiB,aAAU,gBAAe;AAAA,IAAE,oBAAC,WAAO,GAAG,YAAY,IAAI,KAAK,GAAG,EAAE,SAAS,QAAW,MAAK,UAAS,MAAM,GAAG,IAAI,QAAQ,MAAY,OAAO,MAAM,OAAO,IAAI,SAAS,KAAK,IAAI,UAAU,MAAM,YAAY,UAAU,cAAW,kBAAiB,aAAU,gBAAe;AAAA,KAAE;AAC7f;AAEO,IAAM,gBAAgB,EAAE,GAAG,UAAU,MAAM,MAAM,UAAU,YAAY,aAAa,YAAY;","names":["useContext","Cell","GridBody","LiveRegion","ClearButton"]}
|
|
@@ -1,14 +1,22 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
import {
|
|
2
3
|
Part,
|
|
3
4
|
composeEvent,
|
|
4
5
|
useChronaConfig,
|
|
5
6
|
useFormReset
|
|
6
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-SDDSKOYU.js";
|
|
7
8
|
|
|
8
9
|
// src/calendar.tsx
|
|
9
10
|
import * as React from "react";
|
|
10
11
|
import { calendarKeys, connectCalendar, createCalendar, createStore, formatDate, getNumberFormatter, resolveWeekStart, sameDate, syncCalendar, temporal, transitionCalendar, translations, weeksInMonthView } from "chrona-core";
|
|
11
12
|
import { jsx } from "react/jsx-runtime";
|
|
13
|
+
var noStoreUpdates = () => () => {
|
|
14
|
+
};
|
|
15
|
+
var noServerToday = () => null;
|
|
16
|
+
function useToday(options) {
|
|
17
|
+
const iso = React.useSyncExternalStore(noStoreUpdates, () => temporal().Now.plainDateISO(options.timeZone).toString(), noServerToday);
|
|
18
|
+
return options.today ?? (iso === null ? void 0 : temporal().PlainDate.from(iso));
|
|
19
|
+
}
|
|
12
20
|
function useCalendar(props = {}) {
|
|
13
21
|
const options = useChronaConfig(props);
|
|
14
22
|
const generatedId = React.useId();
|
|
@@ -19,6 +27,7 @@ function useCalendar(props = {}) {
|
|
|
19
27
|
React.useEffect(() => {
|
|
20
28
|
store.setState(state);
|
|
21
29
|
});
|
|
30
|
+
const today = useToday(options);
|
|
22
31
|
const rootRef = React.useRef(null);
|
|
23
32
|
const pendingFocus = React.useRef(false);
|
|
24
33
|
const [announcement, setAnnouncement] = React.useState("");
|
|
@@ -50,7 +59,7 @@ function useCalendar(props = {}) {
|
|
|
50
59
|
send,
|
|
51
60
|
rootRef,
|
|
52
61
|
announcement,
|
|
53
|
-
api: connectCalendar(state, { ...options, id, today
|
|
62
|
+
api: connectCalendar(state, { ...options, id, today }),
|
|
54
63
|
months: Array.from({ length: options.numberOfMonths ?? 1 }, (_, index) => state.visibleMonth.add({ months: index }))
|
|
55
64
|
};
|
|
56
65
|
}
|
|
@@ -165,4 +174,4 @@ export {
|
|
|
165
174
|
CalendarSurface,
|
|
166
175
|
Calendar
|
|
167
176
|
};
|
|
168
|
-
//# sourceMappingURL=chunk-
|
|
177
|
+
//# sourceMappingURL=chunk-I46LC4EZ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/calendar.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { calendarKeys, connectCalendar, createCalendar, createStore, formatDate, getNumberFormatter, resolveWeekStart, sameDate, syncCalendar, temporal, transitionCalendar, translations, weeksInMonthView, type CalendarEvent, type CalendarOptions, type PlainDate } from \"chrona-core\";\nimport { Part, composeEvent, type PartProps } from \"./part\";\nimport { useChronaConfig } from \"./provider\";\nimport { useFormReset, type HiddenInputProps } from \"./form\";\n\nexport interface CalendarProps extends CalendarOptions {\n defaultValue?: PlainDate | null;\n defaultFocusedValue?: PlainDate;\n onChange?: (value: PlainDate | null) => void;\n onSelect?: (value: PlainDate) => void;\n onFocusedValueChange?: (value: PlainDate) => void;\n id?: string;\n}\n\n/**\n * `today` depends on when and where the page is rendered, so a server render — including a page\n * prerendered at build time and served days later — cannot know the reader's. Resolving it through\n * `useSyncExternalStore` keeps the hydrating markup identical to the server's (no marker) and lets\n * React correct it right after, instead of leaving the server's day marked for good. Applications\n * that need the marker in the server HTML pass `today` themselves.\n */\nconst noStoreUpdates = () => () => {};\nconst noServerToday = () => null;\nfunction useToday(options: CalendarOptions): PlainDate | undefined {\n const iso = React.useSyncExternalStore(noStoreUpdates, () => temporal().Now.plainDateISO(options.timeZone).toString(), noServerToday);\n return options.today ?? (iso === null ? undefined : temporal().PlainDate.from(iso));\n}\n\nexport function useCalendar(props: CalendarProps = {}) {\n const options = useChronaConfig(props);\n const generatedId = React.useId();\n const id = props.id ?? generatedId;\n const [store] = React.useState(() => createStore(createCalendar({ ...options, value: props.value !== undefined ? props.value : props.defaultValue, focusedValue: props.focusedValue ?? props.defaultFocusedValue })));\n const snapshot = React.useSyncExternalStore(store.subscribe, store.getSnapshot, store.getServerSnapshot);\n // The store is the single source of truth; controlled props are reconciled into it by syncCalendar.\n const state = syncCalendar(snapshot, { ...options, value: props.value, focusedValue: props.focusedValue });\n React.useEffect(() => { store.setState(state); });\n const today = useToday(options);\n const rootRef = React.useRef<HTMLElement | null>(null);\n const pendingFocus = React.useRef(false);\n const [announcement, setAnnouncement] = React.useState(\"\");\n\n React.useEffect(() => {\n if (pendingFocus.current) {\n pendingFocus.current = false;\n rootRef.current?.querySelector<HTMLElement>('[data-part=\"cell-trigger\"][tabindex=\"0\"]')?.focus();\n }\n });\n\n function send(event: CalendarEvent) {\n const dir = options.dir ?? (rootRef.current?.closest(\"[dir]\")?.getAttribute(\"dir\") === \"rtl\" ? \"rtl\" : \"ltr\");\n const result = transitionCalendar(state, event, { ...options, dir });\n store.setState(result.state);\n for (const effect of result.effects) {\n if (effect.type === \"focus\") {\n pendingFocus.current = true;\n if (!sameDate(effect.value, state.focusedValue)) props.onFocusedValueChange?.(effect.value);\n } else if (effect.type === \"change\") {\n props.onChange?.(effect.value);\n setAnnouncement(effect.value ? (options.translations?.selected ?? translations.selected)(formatDate(effect.value, options.locale, { dateStyle: \"full\" })) : \"\");\n } else {\n props.onSelect?.(effect.value);\n }\n }\n }\n\n return {\n state, options, send, rootRef, announcement,\n api: connectCalendar(state, { ...options, id, today }),\n months: Array.from({ length: options.numberOfMonths ?? 1 }, (_, index) => state.visibleMonth.add({ months: index })),\n };\n}\n\ntype CalendarContextValue = ReturnType<typeof useCalendar>;\nconst Context = React.createContext<CalendarContextValue | null>(null);\nconst MonthContext = React.createContext<PlainDate | null>(null);\n\nfunction useContext() {\n const value = React.useContext(Context);\n if (!value) throw new Error(\"Calendar parts must be inside Calendar.Root.\");\n return value;\n}\n\nexport function CalendarRoot({ children, asChild, className, style, ...props }: CalendarProps & Pick<PartProps, \"children\" | \"asChild\" | \"className\" | \"style\">) {\n const calendar = useCalendar(props);\n return <CalendarSurface calendar={calendar} id={props.id} asChild={asChild} className={className} style={style}>{children}</CalendarSurface>;\n}\n\nexport function CalendarSurface({ calendar, ...props }: PartProps & { calendar: CalendarContextValue }) {\n return <Context.Provider value={calendar}><Part {...calendar.api.getRootProps()} {...props} ref={calendar.rootRef} /></Context.Provider>;\n}\n\nconst Header = React.forwardRef<HTMLElement, PartProps>(function Header(props, ref) {\n return <Part {...props} ref={ref} data-scope=\"calendar\" data-part=\"header\" />;\n});\n\nconst Heading = React.forwardRef<HTMLElement, PartProps>(function Heading({ children, ...props }, ref) {\n const { months, options } = useContext();\n const month = React.useContext(MonthContext);\n return <Part as=\"h2\" {...props} ref={ref} data-scope=\"calendar\" data-part=\"heading\" aria-live=\"polite\" aria-atomic=\"true\">{children ?? (month ? [month] : months).map((date) => formatDate(date, options.locale, { month: \"long\", year: \"numeric\" })).join(options.translations?.rangeSeparator ?? translations.rangeSeparator)}</Part>;\n});\n\ntype ButtonProps = React.ComponentPropsWithoutRef<\"button\"> & { asChild?: boolean };\n\n/**\n * Paging buttons carry an `aria-label` but no text, so without a default they render as blank\n * chrome for sighted users. The arrow points the way the button pages in the resolved direction.\n */\nfunction Chevron({ towards }: { towards: \"start\" | \"end\" }) {\n const points = towards === \"start\" ? \"15 4 7 12 15 20\" : \"9 4 17 12 9 20\";\n return <svg aria-hidden=\"true\" focusable=\"false\" viewBox=\"0 0 24 24\" width=\"1em\" height=\"1em\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" data-scope=\"calendar\" data-part=\"chevron\"><polyline points={points} /></svg>;\n}\n\nconst PrevButton = React.forwardRef<HTMLElement, ButtonProps>(function PrevButton({ onClick, children, ...props }, ref) {\n const { api, send, options } = useContext();\n return <Part as=\"button\" {...props} {...api.getPrevButtonProps()} ref={ref} onClick={composeEvent(onClick, () => send({ type: \"PAGE\", direction: -1 }))}>{children ?? <Chevron towards={options.dir === \"rtl\" ? \"end\" : \"start\"} />}</Part>;\n});\n\nconst NextButton = React.forwardRef<HTMLElement, ButtonProps>(function NextButton({ onClick, children, ...props }, ref) {\n const { api, send, options } = useContext();\n return <Part as=\"button\" {...props} {...api.getNextButtonProps()} ref={ref} onClick={composeEvent(onClick, () => send({ type: \"PAGE\", direction: 1 }))}>{children ?? <Chevron towards={options.dir === \"rtl\" ? \"start\" : \"end\"} />}</Part>;\n});\n\nconst Grid = React.forwardRef<HTMLElement, PartProps & { monthIndex?: number }>(function Grid({ monthIndex = 0, children, ...props }, ref) {\n const { api, months } = useContext();\n const month = months[monthIndex];\n if (!month) throw new Error(\"Calendar.Grid monthIndex is outside numberOfMonths.\");\n return <MonthContext.Provider value={month}><Part {...props} {...api.getGridProps(month)} ref={ref}>{children}</Part></MonthContext.Provider>;\n});\n\nfunction useMonth() {\n const context = useContext();\n const month = React.useContext(MonthContext) ?? context.state.visibleMonth;\n return { ...context, month, weeks: weeksInMonthView(month.toPlainYearMonth(), resolveWeekStart(context.options.locale, context.options.firstDayOfWeek), context.options.fixedWeeks) };\n}\n\nexport interface Weekday { date: PlainDate; label: string }\n\nconst GridHeader = React.forwardRef<HTMLElement, Omit<PartProps, \"children\"> & { children?: (day: Weekday) => React.ReactNode }>(function GridHeader({ children, ...props }, ref) {\n const { weeks, options } = useMonth();\n return <Part {...props} ref={ref} role=\"row\" data-scope=\"calendar\" data-part=\"grid-header\">{weeks[0]!.map((date) => {\n const day = { date, label: formatDate(date, options.locale, { weekday: \"short\" }) };\n return <React.Fragment key={date.toString()}>{children ? children(day) : <HeaderCell day={day} />}</React.Fragment>;\n })}</Part>;\n});\n\nconst HeaderCell = React.forwardRef<HTMLElement, PartProps & { day: Weekday }>(function HeaderCell({ day, children, ...props }, ref) {\n const { options } = useContext();\n return <Part {...props} ref={ref} role=\"columnheader\" aria-label={formatDate(day.date, options.locale, { weekday: \"long\" })} data-scope=\"calendar\" data-part=\"header-cell\">{children ?? day.label}</Part>;\n});\n\nconst GridBody = React.forwardRef<HTMLElement, Omit<PartProps, \"children\"> & { children?: (date: PlainDate) => React.ReactNode }>(function GridBody({ children, ...props }, ref) {\n const { weeks } = useMonth();\n return <Part {...props} ref={ref} role=\"rowgroup\" data-scope=\"calendar\" data-part=\"grid-body\">{weeks.map((week) => <div key={week[0]!.toString()} role=\"row\" data-scope=\"calendar\" data-part=\"row\">{week.map((date) => <React.Fragment key={date.toString()}>{children ? children(date) : <Cell date={date} />}</React.Fragment>)}</div>)}</Part>;\n});\n\nconst CellContext = React.createContext<PlainDate | null>(null);\n\nconst CellTrigger = React.forwardRef<HTMLElement, ButtonProps>(function CellTrigger({ children, onClick, onKeyDown, onFocus, ...props }, ref) {\n const { api, send, month, options } = useMonth();\n const date = React.useContext(CellContext);\n if (!date) throw new Error(\"Calendar.CellTrigger must be inside Calendar.Cell.\");\n // aria-disabled instead of native disabled keeps out-of-range dates discoverable by screen readers.\n return <Part as=\"button\" {...props} {...api.getCellTriggerProps(date, month)} ref={ref}\n onFocus={composeEvent(onFocus, () => { if (!options.disabled) send({ type: \"FOCUS\", date }); })}\n onClick={composeEvent(onClick, () => send({ type: \"SELECT\", date }))}\n onKeyDown={composeEvent(onKeyDown, (event) => {\n if (!calendarKeys.has(event.key) || event.altKey || event.ctrlKey || event.metaKey) return;\n event.preventDefault();\n send({ type: \"KEY_DOWN\", key: event.key, shiftKey: event.shiftKey });\n })}>{children ?? getNumberFormatter(options.locale, { useGrouping: false }).format(date.day)}</Part>;\n});\n\n/** The grid semantics live on the cell; the button inside it stays a button. */\nconst Cell = React.forwardRef<HTMLElement, PartProps & { date: PlainDate }>(function Cell({ date, children, ...props }, ref) {\n const { api, month } = useMonth();\n return <CellContext.Provider value={date}><Part {...props} {...api.getCellProps(date, month)} ref={ref}>{children ?? <CellTrigger />}</Part></CellContext.Provider>;\n});\n\nconst LiveRegion = React.forwardRef<HTMLElement, PartProps>(function LiveRegion(props, ref) {\n const { announcement } = useContext();\n return <Part {...props} ref={ref} role=\"status\" aria-live=\"polite\" aria-atomic=\"true\" data-scope=\"calendar\" data-part=\"live-region\">{announcement}</Part>;\n});\n\nconst ClearButton = React.forwardRef<HTMLElement, ButtonProps>(function ClearButton({ onClick, ...props }, ref) {\n const { options, send, state } = useContext();\n return <Part as=\"button\" {...props} ref={ref} type=\"button\" data-scope=\"calendar\" data-part=\"clear-button\" aria-label={options.translations?.clear ?? translations.clear} disabled={options.disabled || options.readOnly || state.value === null} onClick={composeEvent(onClick, () => send({ type: \"CLEAR\" }))} />;\n});\n\nfunction HiddenInput(props: HiddenInputProps) {\n const { state, options, send } = useContext();\n const input = React.useRef<HTMLInputElement>(null);\n useFormReset(input, props.form, () => send({ type: \"RESET\", value: options.defaultValue ?? null }));\n return <input {...props} ref={input} type=\"hidden\" disabled={options.disabled || props.disabled} value={state.value?.toString() ?? \"\"} data-scope=\"calendar\" data-part=\"hidden-input\" />;\n}\n\nexport const Calendar = { Root: CalendarRoot, Header, Heading, PrevButton, NextButton, Grid, GridHeader, HeaderCell, GridBody, Cell, CellTrigger, LiveRegion, ClearButton, HiddenInput };"],"mappings":"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","names":["useContext","Header","Heading","PrevButton","NextButton","Grid","GridHeader","HeaderCell","GridBody","CellTrigger","Cell","LiveRegion","ClearButton"]}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
import {
|
|
2
3
|
createFieldComponents,
|
|
3
4
|
useField
|
|
4
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-27APJXNX.js";
|
|
5
6
|
|
|
6
7
|
// src/date-field.tsx
|
|
7
8
|
var DateField = createFieldComponents("date");
|
|
@@ -13,4 +14,4 @@ export {
|
|
|
13
14
|
DateField,
|
|
14
15
|
useDateField
|
|
15
16
|
};
|
|
16
|
-
//# sourceMappingURL=chunk-
|
|
17
|
+
//# sourceMappingURL=chunk-RTDRFDYG.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/date-field.tsx"],"sourcesContent":["import { createFieldComponents, useField, type FieldProps } from \"./field\";\n\nexport type DateFieldProps = FieldProps<\"date\">;\nexport const DateField = createFieldComponents(\"date\");\nexport function useDateField(props: DateFieldProps = {}) { return useField(\"date\", props); }"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../src/date-field.tsx"],"sourcesContent":["import { createFieldComponents, useField, type FieldProps } from \"./field\";\n\nexport type DateFieldProps = FieldProps<\"date\">;\nexport const DateField = createFieldComponents(\"date\");\nexport function useDateField(props: DateFieldProps = {}) { return useField(\"date\", props); }"],"mappings":";;;;;;;AAGO,IAAM,YAAY,sBAAsB,MAAM;AAC9C,SAAS,aAAa,QAAwB,CAAC,GAAG;AAAE,SAAO,SAAS,QAAQ,KAAK;AAAG;","names":[]}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
1
3
|
// src/part.tsx
|
|
2
4
|
import * as React from "react";
|
|
3
5
|
function setRef(ref, value) {
|
|
@@ -95,4 +97,4 @@ export {
|
|
|
95
97
|
useChronaConfig,
|
|
96
98
|
useFormReset
|
|
97
99
|
};
|
|
98
|
-
//# sourceMappingURL=chunk-
|
|
100
|
+
//# sourceMappingURL=chunk-SDDSKOYU.js.map
|