@gobrand/calendar-core 0.0.18 → 0.0.20

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
@@ -3,441 +3,40 @@
3
3
  [![npm version](https://img.shields.io/npm/v/@gobrand/calendar-core.svg)](https://www.npmjs.com/package/@gobrand/calendar-core)
4
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
5
 
6
- Framework-agnostic calendar utilities built with the [Temporal API](https://tc39.es/proposal-temporal/docs/). Simple, composable functions for building month, week, and day views with full timezone support.
6
+ **Framework-agnostic calendar utilities built with the Temporal API.** Simple, composable functions for building month, week, and day views.
7
7
 
8
- > **For React users:** Check out [@gobrand/react-calendar](https://www.npmjs.com/package/@gobrand/react-calendar) for a ready-to-use hook with state management built on top of this core library.
8
+ 👉 **[Documentation](https://eng.gobrand.app/calendar)**
9
9
 
10
- ## Installation
11
-
12
- ```bash
13
- npm install @gobrand/calendar-core
14
- # or
15
- pnpm add @gobrand/calendar-core
16
- ```
17
-
18
- ## Why @gobrand/calendar-core?
19
-
20
- Building calendars is complex: timezone handling, DST transitions, date arithmetic, and data mapping. **@gobrand/calendar-core** provides pure, framework-agnostic functions for calendar logic:
21
-
22
- - **🌍 Timezone-aware** - Native timezone support with Temporal API primitives
23
- - **🎯 Data-agnostic** - Works with any data type through accessor pattern
24
- - **⚡️ Type-safe** - Full TypeScript support with proper Temporal types
25
- - **📦 Minimal** - Simple, composable functions with no unnecessary abstractions
26
- - **🔧 Zero config** - Sensible defaults, customize only what you need
27
- - **🪄 Framework-agnostic** - Use with React, Vue, Angular, Svelte, or vanilla JavaScript
28
-
29
- **Key features:**
30
- - ✅ Built exclusively on Temporal API (no Date objects, no moment.js, no date-fns)
31
- - ✅ Automatic DST handling and timezone conversions
32
- - ✅ Calendar-aware arithmetic (leap years, month-end dates)
33
- - ✅ Flexible accessor pattern for any data structure
34
- - ✅ Polyfill included for browser compatibility
35
-
36
- **Perfect for:**
37
- - Building custom calendar UIs in any framework
38
- - Server-side calendar generation
39
- - Event calendars and schedulers
40
- - Booking systems and appointment managers
41
- - Task management with due dates
42
- - Analytics dashboards with date ranges
43
-
44
- ## Quick Start
10
+ - **Built on Temporal API** - No Date objects, no moment.js, no date-fns
11
+ - **Timezone-aware** - Native DST handling with IANA timezones
12
+ - **Type-safe** - Full TypeScript with proper Temporal types
13
+ - **Framework-agnostic** - Use with React, Vue, Svelte, or vanilla JS
14
+ - **Data-agnostic** - Works with any data type through accessor pattern
45
15
 
46
16
  ```typescript
47
- import { buildMonth, createCalendarAccessor, getWeekdays, getMonthName } from '@gobrand/calendar-core';
48
- import { Temporal } from '@js-temporal/polyfill';
49
-
50
- type Event = {
51
- id: string;
52
- date: Temporal.PlainDate;
53
- title: string;
54
- };
55
-
56
- const events: Event[] = [
57
- { id: '1', date: Temporal.PlainDate.from('2025-01-20'), title: 'Team Meeting' },
58
- { id: '2', date: Temporal.PlainDate.from('2025-01-22'), title: 'Code Review' },
59
- ];
17
+ import { buildMonth, createCalendarAccessor, getWeekdays } from '@gobrand/calendar-core';
60
18
 
61
19
  const accessor = createCalendarAccessor<Event>({
62
- getDate: (event) => event.date,
63
- });
64
-
65
- const month = buildMonth(2025, 1, {
66
- weekStartsOn: 1,
67
- data: events,
68
- accessor,
69
- });
70
-
71
- console.log(getMonthName(month.month)); // "January"
72
- console.log(getWeekdays(1)); // ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
73
-
74
- month.weeks.forEach(week => {
75
- week.forEach(day => {
76
- console.log(
77
- day.date.toString(),
78
- day.isCurrentMonth,
79
- day.isToday,
80
- `${day.items.length} events`
81
- );
82
- });
83
- });
84
- ```
85
-
86
- ## API
87
-
88
- ### Accessor Pattern
89
-
90
- #### `createCalendarAccessor(accessor)`
91
-
92
- Create a type-safe accessor for mapping your data to calendar dates. This is a type-identity function for TypeScript inference.
93
-
94
- **Parameters:**
95
- - `accessor` (CalendarAccessor<TItem>): Accessor configuration
96
- - `getDate` (required): Extract PlainDate from item
97
- - `getStart` (optional): Extract ZonedDateTime start time
98
- - `getEnd` (optional): Extract ZonedDateTime end time
99
-
100
- **Returns:** Same accessor object with proper types
101
-
102
- **Example:**
103
- ```tsx
104
- // Simple date-based items (tasks, posts)
105
- type Task = {
106
- id: string;
107
- name: string;
108
- dueDate: Temporal.PlainDate;
109
- };
110
-
111
- const taskAccessor = createCalendarAccessor<Task>({
112
- getDate: (task) => task.dueDate,
113
- });
114
-
115
- // Time-based items with start time (events, appointments)
116
- type Event = {
117
- id: string;
118
- title: string;
119
- start: Temporal.ZonedDateTime;
120
- };
121
-
122
- const eventAccessor = createCalendarAccessor<Event>({
123
- getDate: (event) => event.start.toPlainDate(),
124
- getStart: (event) => event.start,
125
- });
126
-
127
- // Items with start and end times (meetings, bookings)
128
- type Meeting = {
129
- id: string;
130
- title: string;
131
- start: Temporal.ZonedDateTime;
132
- end: Temporal.ZonedDateTime;
133
- };
134
-
135
- const meetingAccessor = createCalendarAccessor<Meeting>({
136
- getDate: (meeting) => meeting.start.toPlainDate(),
137
- getStart: (meeting) => meeting.start,
138
- getEnd: (meeting) => meeting.end,
139
- });
140
- ```
141
-
142
- ### Building Calendars
143
-
144
- Low-level functions for building calendar grids without state management.
145
-
146
- #### `buildMonth(year, month, options?)`
147
-
148
- Build a month grid for any year and month.
149
-
150
- **Parameters:**
151
- - `year` (number): Year (e.g., 2025)
152
- - `month` (number): Month (1-12)
153
- - `options` (object, optional):
154
- - `weekStartsOn` (0-6): First day of week
155
- - `today` (PlainDate): Override today's date
156
- - `data` (TItem[]): Items to include
157
- - `accessor` (CalendarAccessor<TItem>): Data accessor
158
-
159
- **Returns:** `CalendarMonth<TItem>`
160
-
161
- **Example:**
162
- ```typescript
163
- import { buildMonth, createCalendarAccessor } from '@gobrand/calendar-core';
164
-
165
- const month = buildMonth(2025, 1, {
166
- weekStartsOn: 1,
167
- data: events,
168
- accessor: createCalendarAccessor({
169
- getDate: (event) => event.date
170
- })
171
- });
172
- ```
173
-
174
- #### `buildWeek(date, options?)`
175
-
176
- Build a week view for a specific date.
177
-
178
- **Parameters:**
179
- - `date` (PlainDate): Any date in the target week
180
- - `options` (object, optional):
181
- - `weekStartsOn` (0-6): First day of week
182
- - `startHour` (number): Start hour for time slots
183
- - `endHour` (number): End hour for time slots
184
- - `slotDuration` (number): Minutes per slot
185
- - `today` (PlainDate): Override today's date
186
- - `data` (TItem[]): Items to include
187
- - `accessor` (CalendarAccessor<TItem>): Data accessor
188
-
189
- **Returns:** `CalendarWeekView<TItem>`
190
-
191
- #### `buildDay(date, options?)`
192
-
193
- Build a day view with time slots.
194
-
195
- **Parameters:**
196
- - `date` (PlainDate): The target date
197
- - `options` (object, optional):
198
- - `startHour` (number): Start hour for time slots
199
- - `endHour` (number): End hour for time slots
200
- - `slotDuration` (number): Minutes per slot
201
- - `today` (PlainDate): Override today's date
202
- - `data` (TItem[]): Items to include
203
- - `accessor` (CalendarAccessor<TItem>): Data accessor
204
-
205
- **Returns:** `CalendarDayView<TItem>`
206
-
207
- ### Formatting Utilities
208
-
209
- #### `getWeekdays(weekStartsOn?, locale?, format?)`
210
-
211
- Get localized weekday names.
212
-
213
- **Parameters:**
214
- - `weekStartsOn` (0-6, optional): First day of week (default: 0 = Sunday)
215
- - `locale` (string, optional): BCP 47 locale (default: system locale)
216
- - `format` ('long' | 'short' | 'narrow', optional): Name format (default: 'short')
217
-
218
- **Returns:** `string[]` - Array of 7 weekday names
219
-
220
- **Example:**
221
- ```typescript
222
- import { getWeekdays } from '@gobrand/calendar-core';
223
-
224
- getWeekdays(1); // ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
225
- getWeekdays(0); // ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
226
- getWeekdays(1, 'es-ES'); // ["lun", "mar", "mié", "jue", "vie", "sáb", "dom"]
227
- getWeekdays(1, 'en-US', 'long'); // ["Monday", "Tuesday", ...]
228
- getWeekdays(1, 'en-US', 'narrow'); // ["M", "T", "W", "T", "F", "S", "S"]
229
- ```
230
-
231
- #### `getMonthName(month, locale?)`
232
-
233
- Get localized month name.
234
-
235
- **Parameters:**
236
- - `month` (PlainYearMonth): The month to format
237
- - `locale` (string, optional): BCP 47 locale
238
-
239
- **Returns:** `string` - Formatted month name
240
-
241
- **Example:**
242
- ```typescript
243
- import { getMonthName } from '@gobrand/calendar-core';
244
- import { Temporal } from '@js-temporal/polyfill';
245
-
246
- const month = Temporal.PlainYearMonth.from('2025-01');
247
- getMonthName(month); // "January"
248
- getMonthName(month, 'es-ES'); // "enero"
249
- getMonthName(month, 'ja-JP'); // "1月"
250
- ```
251
-
252
- #### `formatTime(time, locale?)`
253
-
254
- Format a PlainTime as a localized time string.
255
-
256
- **Parameters:**
257
- - `time` (PlainTime): Time to format
258
- - `locale` (string, optional): BCP 47 locale
259
-
260
- **Returns:** `string` - Formatted time
261
-
262
- **Example:**
263
- ```typescript
264
- import { formatTime } from '@gobrand/calendar-core';
265
- import { Temporal } from '@js-temporal/polyfill';
266
-
267
- const time = Temporal.PlainTime.from('14:30');
268
- formatTime(time); // "2:30 PM" (en-US)
269
- formatTime(time, 'en-GB'); // "14:30"
270
- formatTime(time, 'es-ES'); // "14:30"
271
- ```
272
-
273
- ### Timezone Utilities
274
-
275
- #### `getMonthRange(timeZone?, weekStartsOn?)`
276
-
277
- Get the date range for the current month, week-aligned in a specific timezone.
278
-
279
- **Parameters:**
280
- - `timeZone` (string, optional): IANA timezone (default: system timezone)
281
- - `weekStartsOn` (0-6, optional): First day of week (default: 1)
282
-
283
- **Returns:** `{ start: Temporal.PlainDate; end: Temporal.PlainDate }` - Start/end dates for the week-aligned month
284
-
285
- **Example:**
286
- ```typescript
287
- import { getMonthRange } from '@gobrand/calendar-core';
288
-
289
- const range = getMonthRange('America/New_York', 1);
290
- // Returns week-aligned range for current month in New York time
291
- console.log(range.start, range.end);
292
- ```
293
-
294
- #### `getWeekRange(timeZone?, weekStartsOn?)`
295
-
296
- Get the date range for the current week in a specific timezone.
297
-
298
- **Parameters:**
299
- - `timeZone` (string, optional): IANA timezone (default: system timezone)
300
- - `weekStartsOn` (0-6, optional): First day of week (default: 1)
301
-
302
- **Returns:** `{ start: Temporal.PlainDate; end: Temporal.PlainDate }` - Start/end dates for the week
303
-
304
- #### `getDayRange(timeZone?)`
305
-
306
- Get the date range for today in a specific timezone.
307
-
308
- **Parameters:**
309
- - `timeZone` (string, optional): IANA timezone (default: system timezone)
310
-
311
- **Returns:** `{ start: Temporal.PlainDate; end: Temporal.PlainDate }` - Start/end dates for today (same date)
312
-
313
- #### `getCurrentTimeZone()`
314
-
315
- Get the system's current IANA timezone identifier.
316
-
317
- **Returns:** `string` - IANA timezone (e.g., "America/New_York")
318
-
319
- #### `convertToTimezone(zdt, timeZone)`
320
-
321
- Convert a ZonedDateTime to a different timezone.
322
-
323
- **Parameters:**
324
- - `zdt` (ZonedDateTime): Source ZonedDateTime
325
- - `timeZone` (string): Target IANA timezone
326
-
327
- **Returns:** `ZonedDateTime` - Same instant in new timezone
328
-
329
- #### `createZonedDateTime(date, time, timeZone)`
330
-
331
- Create a ZonedDateTime from a PlainDate and PlainTime.
332
-
333
- **Parameters:**
334
- - `date` (PlainDate): The date
335
- - `time` (PlainTime): The time
336
- - `timeZone` (string): IANA timezone
337
-
338
- **Returns:** `ZonedDateTime`
339
-
340
- ## Real World Examples
341
-
342
- ### Example 1: HTML Calendar Generator
343
-
344
- Using core functions without React for maximum flexibility.
345
-
346
- ```typescript
347
- import {
348
- buildMonth,
349
- createCalendarAccessor,
350
- getWeekdays,
351
- getMonthName
352
- } from '@gobrand/calendar-core';
353
- import { Temporal } from '@js-temporal/polyfill';
354
-
355
- type BlogPost = {
356
- id: string;
357
- title: string;
358
- publishedAt: Temporal.PlainDate;
359
- };
360
-
361
- const posts: BlogPost[] = [
362
- { id: '1', title: 'Getting Started with Temporal', publishedAt: Temporal.PlainDate.from('2025-01-15') },
363
- { id: '2', title: 'Building Calendars', publishedAt: Temporal.PlainDate.from('2025-01-20') },
364
- ];
365
-
366
- const accessor = createCalendarAccessor<BlogPost>({
367
- getDate: (post) => post.publishedAt,
20
+ getDate: (e) => e.date,
368
21
  });
369
22
 
370
- // Build January 2025 calendar
371
- const month = buildMonth(2025, 1, {
372
- weekStartsOn: 1,
373
- data: posts,
374
- accessor,
375
- });
23
+ const month = buildMonth(2025, 1, { weekStartsOn: 1, data: events, accessor });
376
24
 
377
- // Render to HTML
378
- const weekdays = getWeekdays(1);
379
- const monthName = getMonthName(month.month);
380
-
381
- let html = `<h2>${monthName} ${month.month.year}</h2>`;
382
- html += '<table><thead><tr>';
383
- weekdays.forEach(day => {
384
- html += `<th>${day}</th>`;
385
- });
386
- html += '</tr></thead><tbody>';
387
-
388
- month.weeks.forEach(week => {
389
- html += '<tr>';
390
- week.forEach(day => {
391
- const className = day.isCurrentMonth ? '' : 'other-month';
392
- html += `<td class="${className}">`;
393
- html += `<div>${day.date.day}</div>`;
394
- day.items.forEach(post => {
395
- html += `<div class="post">${post.title}</div>`;
396
- });
397
- html += '</td>';
398
- });
399
- html += '</tr>';
25
+ month.weeks.flat().forEach(day => {
26
+ console.log(day.date.toString(), day.items.length);
400
27
  });
401
-
402
- html += '</tbody></table>';
403
- document.getElementById('calendar')!.innerHTML = html;
404
- ```
405
-
406
- ## Browser Support
407
-
408
- The Temporal API is a Stage 3 TC39 proposal. The polyfill `@js-temporal/polyfill` is included as a dependency, ensuring compatibility across all modern browsers and Node.js environments.
409
-
410
- ```typescript
411
- import { Temporal } from '@js-temporal/polyfill';
412
28
  ```
413
29
 
414
- ## Development
30
+ ## Install
415
31
 
416
32
  ```bash
417
- # Install dependencies
418
- pnpm install
419
-
420
- # Build all packages
421
- pnpm build
422
-
423
- # Run tests
424
- pnpm test --run
425
-
426
- # Type check
427
- pnpm typecheck
428
-
429
- # Release new version
430
- pnpm release <patch|minor|major>
33
+ pnpm add @gobrand/calendar-core
431
34
  ```
432
35
 
433
- ## Contributing
36
+ ## Docs
434
37
 
435
- Contributions are welcome! Please feel free to submit a Pull Request.
38
+ **[eng.gobrand.app/calendar](https://eng.gobrand.app/calendar)** Full API reference, examples, and guides.
436
39
 
437
40
  ## License
438
41
 
439
- MIT
440
-
441
- ## Built by Go Brand
442
-
443
- temporal-calendar is built and maintained by [Go Brand](https://gobrand.app) - a modern social media management platform.
42
+ MIT © [Ruben Costa](https://x.com/PonziChad) / [Go Brand](https://gobrand.app)
package/dist/index.cjs CHANGED
@@ -177,6 +177,7 @@ function buildMonth(year, month, options) {
177
177
  }
178
178
  const dateKey = currentDate.toString();
179
179
  weeks[weeks.length - 1].push({
180
+ id: `${yearMonth.toString()}-${dateKey}`,
180
181
  date: currentDate,
181
182
  isCurrentMonth: currentDate.month === month,
182
183
  isToday: import_polyfill2.Temporal.PlainDate.compare(currentDate, today) === 0,
@@ -218,6 +219,7 @@ function buildDay(date, options) {
218
219
  }
219
220
  }
220
221
  const timeSlots = [];
222
+ const dateStr = date.toString();
221
223
  let currentHour = startHour;
222
224
  let currentMinute = 0;
223
225
  while (currentHour < endHour) {
@@ -244,6 +246,7 @@ function buildDay(date, options) {
244
246
  }
245
247
  }
246
248
  timeSlots.push({
249
+ id: `${dateStr}-${String(currentHour).padStart(2, "0")}:${String(currentMinute).padStart(2, "0")}`,
247
250
  hour: currentHour,
248
251
  minute: currentMinute,
249
252
  time: slotStart,
@@ -256,6 +259,7 @@ function buildDay(date, options) {
256
259
  }
257
260
  }
258
261
  return {
262
+ id: dateStr,
259
263
  date,
260
264
  isToday: import_polyfill3.Temporal.PlainDate.compare(date, today) === 0,
261
265
  timeSlots,
@@ -302,6 +306,7 @@ function buildWeek(date, options) {
302
306
  timeSlots = dayView.timeSlots;
303
307
  }
304
308
  days.push({
309
+ id: `${weekStart.toString()}-${dateKey}`,
305
310
  date: currentDate,
306
311
  isToday: import_polyfill4.Temporal.PlainDate.compare(currentDate, today) === 0,
307
312
  items: itemsByDate.get(dateKey) ?? [],
package/dist/index.d.cts CHANGED
@@ -7,6 +7,8 @@ type CalendarAccessor<TItem> = {
7
7
  getEnd?: (item: TItem) => Temporal.ZonedDateTime;
8
8
  };
9
9
  type CalendarDay<TItem = unknown> = {
10
+ /** Unique identifier for this day within the view context. Use as React/Vue key. */
11
+ id: string;
10
12
  date: Temporal.PlainDate;
11
13
  isCurrentMonth: boolean;
12
14
  isToday: boolean;
@@ -18,6 +20,8 @@ type CalendarMonth<TItem = unknown> = {
18
20
  month: Temporal.PlainYearMonth;
19
21
  };
20
22
  type WeekDay<TItem = unknown> = {
23
+ /** Unique identifier for this day within the view context. Use as React/Vue key. */
24
+ id: string;
21
25
  date: Temporal.PlainDate;
22
26
  isToday: boolean;
23
27
  items: TItem[];
@@ -29,12 +33,16 @@ type CalendarWeekView<TItem = unknown> = {
29
33
  weekEnd: Temporal.PlainDate;
30
34
  };
31
35
  type TimeSlot<TItem = unknown> = {
36
+ /** Unique identifier for this time slot. Use as React/Vue key. */
37
+ id: string;
32
38
  hour: number;
33
39
  minute: number;
34
40
  time: Temporal.PlainTime;
35
41
  items: TItem[];
36
42
  };
37
43
  type CalendarDayView<TItem = unknown> = {
44
+ /** Unique identifier for this day view. Use as React/Vue key. */
45
+ id: string;
38
46
  date: Temporal.PlainDate;
39
47
  isToday: boolean;
40
48
  timeSlots: TimeSlot<TItem>[];
package/dist/index.d.ts CHANGED
@@ -7,6 +7,8 @@ type CalendarAccessor<TItem> = {
7
7
  getEnd?: (item: TItem) => Temporal.ZonedDateTime;
8
8
  };
9
9
  type CalendarDay<TItem = unknown> = {
10
+ /** Unique identifier for this day within the view context. Use as React/Vue key. */
11
+ id: string;
10
12
  date: Temporal.PlainDate;
11
13
  isCurrentMonth: boolean;
12
14
  isToday: boolean;
@@ -18,6 +20,8 @@ type CalendarMonth<TItem = unknown> = {
18
20
  month: Temporal.PlainYearMonth;
19
21
  };
20
22
  type WeekDay<TItem = unknown> = {
23
+ /** Unique identifier for this day within the view context. Use as React/Vue key. */
24
+ id: string;
21
25
  date: Temporal.PlainDate;
22
26
  isToday: boolean;
23
27
  items: TItem[];
@@ -29,12 +33,16 @@ type CalendarWeekView<TItem = unknown> = {
29
33
  weekEnd: Temporal.PlainDate;
30
34
  };
31
35
  type TimeSlot<TItem = unknown> = {
36
+ /** Unique identifier for this time slot. Use as React/Vue key. */
37
+ id: string;
32
38
  hour: number;
33
39
  minute: number;
34
40
  time: Temporal.PlainTime;
35
41
  items: TItem[];
36
42
  };
37
43
  type CalendarDayView<TItem = unknown> = {
44
+ /** Unique identifier for this day view. Use as React/Vue key. */
45
+ id: string;
38
46
  date: Temporal.PlainDate;
39
47
  isToday: boolean;
40
48
  timeSlots: TimeSlot<TItem>[];
package/dist/index.js CHANGED
@@ -123,6 +123,7 @@ function buildMonth(year, month, options) {
123
123
  }
124
124
  const dateKey = currentDate.toString();
125
125
  weeks[weeks.length - 1].push({
126
+ id: `${yearMonth.toString()}-${dateKey}`,
126
127
  date: currentDate,
127
128
  isCurrentMonth: currentDate.month === month,
128
129
  isToday: Temporal2.PlainDate.compare(currentDate, today) === 0,
@@ -164,6 +165,7 @@ function buildDay(date, options) {
164
165
  }
165
166
  }
166
167
  const timeSlots = [];
168
+ const dateStr = date.toString();
167
169
  let currentHour = startHour;
168
170
  let currentMinute = 0;
169
171
  while (currentHour < endHour) {
@@ -190,6 +192,7 @@ function buildDay(date, options) {
190
192
  }
191
193
  }
192
194
  timeSlots.push({
195
+ id: `${dateStr}-${String(currentHour).padStart(2, "0")}:${String(currentMinute).padStart(2, "0")}`,
193
196
  hour: currentHour,
194
197
  minute: currentMinute,
195
198
  time: slotStart,
@@ -202,6 +205,7 @@ function buildDay(date, options) {
202
205
  }
203
206
  }
204
207
  return {
208
+ id: dateStr,
205
209
  date,
206
210
  isToday: Temporal3.PlainDate.compare(date, today) === 0,
207
211
  timeSlots,
@@ -248,6 +252,7 @@ function buildWeek(date, options) {
248
252
  timeSlots = dayView.timeSlots;
249
253
  }
250
254
  days.push({
255
+ id: `${weekStart.toString()}-${dateKey}`,
251
256
  date: currentDate,
252
257
  isToday: Temporal4.PlainDate.compare(currentDate, today) === 0,
253
258
  items: itemsByDate.get(dateKey) ?? [],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gobrand/calendar-core",
3
- "version": "0.0.18",
3
+ "version": "0.0.20",
4
4
  "description": "Lightweight utility library for building calendars using the Temporal API",
5
5
  "private": false,
6
6
  "publishConfig": {
@@ -31,7 +31,7 @@
31
31
  "bugs": {
32
32
  "url": "https://github.com/go-brand/calendar/issues"
33
33
  },
34
- "homepage": "https://github.com/go-brand/calendar#readme",
34
+ "homepage": "https://eng.gobrand.app/calendar",
35
35
  "dependencies": {
36
36
  "@js-temporal/polyfill": "^0.5.1",
37
37
  "@tanstack/store": "^0.8.0"