@gobrand/react-calendar 0.0.10 → 0.0.11
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 +117 -5
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -74,7 +74,7 @@ function MyCalendar() {
|
|
|
74
74
|
const calendar = useCalendar({
|
|
75
75
|
data: events,
|
|
76
76
|
views: createCalendarViews<Event>()({
|
|
77
|
-
month: {
|
|
77
|
+
month: { accessor },
|
|
78
78
|
}),
|
|
79
79
|
});
|
|
80
80
|
|
|
@@ -155,8 +155,8 @@ const calendar = useCalendar({
|
|
|
155
155
|
data: events,
|
|
156
156
|
timeZone: 'America/New_York',
|
|
157
157
|
views: createCalendarViews<Event>()({
|
|
158
|
-
month: {
|
|
159
|
-
week: {
|
|
158
|
+
month: { accessor },
|
|
159
|
+
week: { startHour: 8, endHour: 18, accessor },
|
|
160
160
|
day: { startHour: 8, endHour: 18, slotDuration: 30, accessor },
|
|
161
161
|
}),
|
|
162
162
|
});
|
|
@@ -456,7 +456,120 @@ For detailed documentation and examples, see [@gobrand/calendar-core](https://ww
|
|
|
456
456
|
|
|
457
457
|
## Real World Examples
|
|
458
458
|
|
|
459
|
-
### Example 1:
|
|
459
|
+
### Example 1: Fetching Calendar Data with useQuery and Date-Range Pagination
|
|
460
|
+
|
|
461
|
+
This is the most common real-world pattern: fetching data from an API based on the visible calendar date range. As users navigate the calendar (month/week/day), new data is automatically fetched for that time period.
|
|
462
|
+
|
|
463
|
+
```tsx
|
|
464
|
+
import { useQuery } from '@tanstack/react-query';
|
|
465
|
+
import { toZonedTime, now } from '@gobrand/tiempo';
|
|
466
|
+
import {
|
|
467
|
+
useCalendar,
|
|
468
|
+
createCalendarViews,
|
|
469
|
+
createCalendarAccessor,
|
|
470
|
+
type DateRange,
|
|
471
|
+
getMonthDateRange,
|
|
472
|
+
} from '@gobrand/react-calendar';
|
|
473
|
+
import { useState } from 'react';
|
|
474
|
+
|
|
475
|
+
type Post = {
|
|
476
|
+
id: string;
|
|
477
|
+
title: string;
|
|
478
|
+
publishedAt: string; // UTC ISO 8601 string from API
|
|
479
|
+
status: 'draft' | 'scheduled' | 'published';
|
|
480
|
+
};
|
|
481
|
+
|
|
482
|
+
type PostWithDateTime = Post & {
|
|
483
|
+
zonedDateTime: Temporal.ZonedDateTime;
|
|
484
|
+
};
|
|
485
|
+
|
|
486
|
+
const TIME_ZONE = 'America/New_York';
|
|
487
|
+
|
|
488
|
+
function PostCalendar() {
|
|
489
|
+
// Track the current visible date range
|
|
490
|
+
const [dateRange, setDateRange] = useState<DateRange>(() =>
|
|
491
|
+
getMonthDateRange(now(TIME_ZONE).toPlainDate(), TIME_ZONE)
|
|
492
|
+
);
|
|
493
|
+
|
|
494
|
+
// Fetch posts for the visible date range
|
|
495
|
+
const { data: posts = [], isLoading } = useQuery({
|
|
496
|
+
queryKey: ['posts', dateRange?.start.toString(), dateRange?.end.toString()],
|
|
497
|
+
queryFn: async () => {
|
|
498
|
+
if (!dateRange) return [];
|
|
499
|
+
|
|
500
|
+
// Convert date range to UTC ISO strings for API
|
|
501
|
+
const filters = {
|
|
502
|
+
dateRange: {
|
|
503
|
+
start: dateRange.start.toInstant().toString(),
|
|
504
|
+
end: dateRange.end.toInstant().toString(),
|
|
505
|
+
},
|
|
506
|
+
};
|
|
507
|
+
|
|
508
|
+
return getPosts(filters);
|
|
509
|
+
},
|
|
510
|
+
// Convert UTC strings to ZonedDateTime for calendar
|
|
511
|
+
select: (posts) =>
|
|
512
|
+
posts.map((post) => ({
|
|
513
|
+
...post,
|
|
514
|
+
zonedDateTime: toZonedTime(post.publishedAt, TIME_ZONE),
|
|
515
|
+
})),
|
|
516
|
+
enabled: !!dateRange,
|
|
517
|
+
});
|
|
518
|
+
|
|
519
|
+
const calendar = useCalendar({
|
|
520
|
+
data: posts,
|
|
521
|
+
timeZone: TIME_ZONE,
|
|
522
|
+
views: createCalendarViews<PostWithDateTime>()({
|
|
523
|
+
month: {
|
|
524
|
+
accessor: createCalendarAccessor({
|
|
525
|
+
getDate: (post) => post.zonedDateTime.toPlainDate(),
|
|
526
|
+
getStart: (post) => post.zonedDateTime,
|
|
527
|
+
}),
|
|
528
|
+
},
|
|
529
|
+
}),
|
|
530
|
+
// Sync date range when calendar navigation changes
|
|
531
|
+
onStateChange: (updater) => {
|
|
532
|
+
const newState =
|
|
533
|
+
typeof updater === 'function' ? updater(calendar.getState()) : updater;
|
|
534
|
+
setDateRange(newState.dateRange);
|
|
535
|
+
},
|
|
536
|
+
});
|
|
537
|
+
|
|
538
|
+
const month = calendar.getMonth();
|
|
539
|
+
|
|
540
|
+
return (
|
|
541
|
+
<div>
|
|
542
|
+
<header>
|
|
543
|
+
<button onClick={calendar.previousMonth}>←</button>
|
|
544
|
+
<h2>{calendar.getTitle('month')}</h2>
|
|
545
|
+
<button onClick={calendar.nextMonth}>→</button>
|
|
546
|
+
{isLoading && <span>Loading...</span>}
|
|
547
|
+
</header>
|
|
548
|
+
|
|
549
|
+
<div className="calendar-grid">
|
|
550
|
+
{month.weeks.flat().map((day) => (
|
|
551
|
+
<div key={day.date.toString()}>
|
|
552
|
+
<div>{day.date.day}</div>
|
|
553
|
+
{day.items.map((post) => (
|
|
554
|
+
<div key={post.id}>{post.title}</div>
|
|
555
|
+
))}
|
|
556
|
+
</div>
|
|
557
|
+
))}
|
|
558
|
+
</div>
|
|
559
|
+
</div>
|
|
560
|
+
);
|
|
561
|
+
}
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
**Key points:**
|
|
565
|
+
- `dateRange` state tracks the currently visible calendar period
|
|
566
|
+
- `useQuery` automatically refetches when `dateRange` changes (navigation)
|
|
567
|
+
- Date range is converted to UTC ISO strings for the API request
|
|
568
|
+
- `select` transforms API responses (UTC ISO strings) to `ZonedDateTime` for the calendar
|
|
569
|
+
- `onStateChange` syncs calendar navigation with the date range state
|
|
570
|
+
- This pattern works for infinite scroll, cursor-based pagination, or any date-range filtering
|
|
571
|
+
|
|
572
|
+
### Example 2: Event Calendar with Multi-View Support
|
|
460
573
|
|
|
461
574
|
A complete event calendar with month, week, and day views, timezone support, and type-safe view switching.
|
|
462
575
|
|
|
@@ -669,7 +782,6 @@ function TaskCalendar() {
|
|
|
669
782
|
data: tasks,
|
|
670
783
|
views: createCalendarViews<Task>()({
|
|
671
784
|
month: {
|
|
672
|
-
weekStartsOn: 1,
|
|
673
785
|
accessor: createCalendarAccessor({
|
|
674
786
|
getDate: (task) => task.dueDate,
|
|
675
787
|
})
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gobrand/react-calendar",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.11",
|
|
4
4
|
"description": "React hooks and components for building calendars using the Temporal API",
|
|
5
5
|
"private": false,
|
|
6
6
|
"publishConfig": {
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
41
|
"@js-temporal/polyfill": "^0.5.1",
|
|
42
|
-
"@gobrand/calendar-core": "^0.0.
|
|
42
|
+
"@gobrand/calendar-core": "^0.0.10"
|
|
43
43
|
},
|
|
44
44
|
"peerDependencies": {
|
|
45
45
|
"react": "^18.0.0 || ^19.0.0"
|