@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.
Files changed (2) hide show
  1. package/README.md +117 -5
  2. 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: { weekStartsOn: 1, accessor },
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: { weekStartsOn: 1, accessor },
159
- week: { weekStartsOn: 1, startHour: 8, endHour: 18, accessor },
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: Event Calendar with Multi-View Support
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.10",
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.6"
42
+ "@gobrand/calendar-core": "^0.0.10"
43
43
  },
44
44
  "peerDependencies": {
45
45
  "react": "^18.0.0 || ^19.0.0"