@dxos/react-ui-calendar 0.8.4-main.422d1c7879 → 0.8.4-main.43cb759274

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/LICENSE CHANGED
@@ -1,8 +1,105 @@
1
- MIT License
2
- Copyright (c) 2022 DXOS
1
+ # Functional Source License, Version 1.1, ALv2 Future License
3
2
 
4
- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
3
+ ## Abbreviation
5
4
 
6
- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
5
+ FSL-1.1-Apache-2.0
7
6
 
8
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
7
+ ## Notice
8
+
9
+ Copyright 2026 DXOS
10
+
11
+ ## Terms and Conditions
12
+
13
+ ### Licensor ("We")
14
+
15
+ The party offering the Software under these Terms and Conditions.
16
+
17
+ ### The Software
18
+
19
+ The "Software" is each version of the software that we make available under
20
+ these Terms and Conditions, as indicated by our inclusion of these Terms and
21
+ Conditions with the Software.
22
+
23
+ ### License Grant
24
+
25
+ Subject to your compliance with this License Grant and the Patents,
26
+ Redistribution and Trademark clauses below, we hereby grant you the right to
27
+ use, copy, modify, create derivative works, publicly perform, publicly display
28
+ and redistribute the Software for any Permitted Purpose identified below.
29
+
30
+ ### Permitted Purpose
31
+
32
+ A Permitted Purpose is any purpose other than a Competing Use. A Competing Use
33
+ means making the Software available to others in a commercial product or
34
+ service that:
35
+
36
+ 1. substitutes for the Software;
37
+
38
+ 2. substitutes for any other product or service we offer using the Software
39
+ that exists as of the date we make the Software available; or
40
+
41
+ 3. offers the same or substantially similar functionality as the Software.
42
+
43
+ Permitted Purposes specifically include using the Software:
44
+
45
+ 1. for your internal use and access;
46
+
47
+ 2. for non-commercial education;
48
+
49
+ 3. for non-commercial research; and
50
+
51
+ 4. in connection with professional services that you provide to a licensee
52
+ using the Software in accordance with these Terms and Conditions.
53
+
54
+ ### Patents
55
+
56
+ To the extent your use for a Permitted Purpose would necessarily infringe our
57
+ patents, the license grant above includes a license under our patents. If you
58
+ make a claim against any party that the Software infringes or contributes to
59
+ the infringement of any patent, then your patent license to the Software ends
60
+ immediately.
61
+
62
+ ### Redistribution
63
+
64
+ The Terms and Conditions apply to all copies, modifications and derivatives of
65
+ the Software.
66
+
67
+ If you redistribute any copies, modifications or derivatives of the Software,
68
+ you must include a copy of or a link to these Terms and Conditions and not
69
+ remove any copyright notices provided in or with the Software.
70
+
71
+ ### Disclaimer
72
+
73
+ THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR
74
+ IMPLIED, INCLUDING WITHOUT LIMITATION WARRANTIES OF FITNESS FOR A PARTICULAR
75
+ PURPOSE, MERCHANTABILITY, TITLE OR NON-INFRINGEMENT.
76
+
77
+ IN NO EVENT WILL WE HAVE ANY LIABILITY TO YOU ARISING OUT OF OR RELATED TO THE
78
+ SOFTWARE, INCLUDING INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES,
79
+ EVEN IF WE HAVE BEEN INFORMED OF THEIR POSSIBILITY IN ADVANCE.
80
+
81
+ ### Trademarks
82
+
83
+ Except for displaying the License Details and identifying us as the origin of
84
+ the Software, you have no right under these Terms and Conditions to use our
85
+ trademarks, trade names, service marks or product names.
86
+
87
+ ## Grant of Future License
88
+
89
+ We hereby irrevocably grant you an additional license to use the Software under
90
+ the Apache License, Version 2.0 that is effective on the second anniversary of
91
+ the date we make the Software available. On or after that date, you may use the
92
+ Software under the Apache License, Version 2.0, in which case the following
93
+ will apply:
94
+
95
+ Licensed under the Apache License, Version 2.0 (the "License"); you may not use
96
+ this file except in compliance with the License.
97
+
98
+ You may obtain a copy of the License at
99
+
100
+ http://www.apache.org/licenses/LICENSE-2.0
101
+
102
+ Unless required by applicable law or agreed to in writing, software distributed
103
+ under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
104
+ CONDITIONS OF ANY KIND, either express or implied. See the License for the
105
+ specific language governing permissions and limitations under the License.
@@ -1,26 +1,17 @@
1
1
  // src/components/Calendar/Calendar.tsx
2
2
  import { createContext } from "@radix-ui/react-context";
3
- import { addDays, differenceInWeeks, format, startOfDay, startOfWeek } from "date-fns";
3
+ import { addDays, format, startOfDay, startOfWeek } from "date-fns";
4
4
  import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
5
5
  import { useResizeDetector } from "react-resize-detector";
6
6
  import { List } from "react-virtualized";
7
7
  import { Event } from "@dxos/async";
8
8
  import { IconButton, useTranslation } from "@dxos/react-ui";
9
- import { composable, composableProps, mx } from "@dxos/ui-theme";
10
-
11
- // src/translations.ts
12
- var translationKey = "@dxos/react-ui-calendar";
13
- var translations = [
14
- {
15
- "en-US": {
16
- [translationKey]: {
17
- "today.button": "Today"
18
- }
19
- }
20
- }
21
- ];
9
+ import { composable, composableProps } from "@dxos/react-ui";
10
+ import { mx } from "@dxos/ui-theme";
11
+ import { translationKey } from "#translations";
22
12
 
23
13
  // src/components/Calendar/util.ts
14
+ import { differenceInCalendarDays } from "date-fns";
24
15
  var getDate = (start2, weekNumber, dayOfWeek, weekStartsOn) => {
25
16
  const result = new Date(start2);
26
17
  const startDayOfWeek = start2.getDay();
@@ -28,6 +19,13 @@ var getDate = (start2, weekNumber, dayOfWeek, weekStartsOn) => {
28
19
  result.setDate(start2.getDate() - adjustedStartDay + weekNumber * 7 + dayOfWeek);
29
20
  return result;
30
21
  };
22
+ var getRowIndex = (start2, date, weekStartsOn) => {
23
+ const startDayOfWeek = start2.getDay();
24
+ const adjustedStartDay = (startDayOfWeek === 0 ? 7 : startDayOfWeek) - weekStartsOn;
25
+ const row0Start = new Date(start2);
26
+ row0Start.setDate(start2.getDate() - adjustedStartDay);
27
+ return Math.floor(differenceInCalendarDays(date, row0Start) / 7);
28
+ };
31
29
  var isSameDay = (date1, date2) => {
32
30
  return !!date2 && date1.getFullYear() === date2.getFullYear() && date1.getMonth() === date2.getMonth() && date1.getDate() === date2.getDate();
33
31
  };
@@ -35,13 +33,46 @@ var isSameDay = (date1, date2) => {
35
33
  // src/components/Calendar/Calendar.tsx
36
34
  var maxRows = 50 * 100;
37
35
  var start = /* @__PURE__ */ new Date("1970-01-01");
38
- var size = 48;
36
+ var size = 40;
39
37
  var defaultWidth = 7 * size;
38
+ var EDGE_SCROLL_ZONE = 32;
39
+ var EDGE_SCROLL_MAX_SPEED = 12;
40
+ var makeRange = (a, b) => {
41
+ const dayA = startOfDay(a);
42
+ const dayB = startOfDay(b);
43
+ return dayA <= dayB ? {
44
+ from: dayA,
45
+ to: dayB
46
+ } : {
47
+ from: dayB,
48
+ to: dayA
49
+ };
50
+ };
51
+ var isInRange = (date, range) => {
52
+ if (!range) {
53
+ return false;
54
+ }
55
+ const day = startOfDay(date).getTime();
56
+ return day >= range.from.getTime() && day <= range.to.getTime();
57
+ };
58
+ var cellDate = (el) => {
59
+ let current = el;
60
+ while (current && current !== document.body) {
61
+ const iso = current.getAttribute?.("data-date");
62
+ if (iso) {
63
+ return new Date(iso);
64
+ }
65
+ current = current.parentElement;
66
+ }
67
+ return void 0;
68
+ };
40
69
  var [CalendarContextProvider, useCalendarContext] = createContext("Calendar");
41
70
  var CalendarRoot = /* @__PURE__ */ forwardRef(({ children, weekStartsOn = 1 }, forwardedRef) => {
42
71
  const event = useMemo(() => new Event(), []);
43
72
  const [selected, setSelected] = useState();
44
73
  const [index, setIndex] = useState();
74
+ const [range, setRange] = useState();
75
+ const [pendingRange, setPendingRange] = useState();
45
76
  useImperativeHandle(forwardedRef, () => ({
46
77
  scrollTo: (date) => {
47
78
  event.emit({
@@ -58,7 +89,11 @@ var CalendarRoot = /* @__PURE__ */ forwardRef(({ children, weekStartsOn = 1 }, f
58
89
  index,
59
90
  setIndex,
60
91
  selected,
61
- setSelected
92
+ setSelected,
93
+ range,
94
+ setRange,
95
+ pendingRange,
96
+ setPendingRange
62
97
  }, children);
63
98
  });
64
99
  var CALENDAR_TOOLBAR_NAME = "CalendarHeader";
@@ -109,11 +144,12 @@ var CalendarToolbar = composable(({ classNames, ...props }, forwardedRef) => {
109
144
  });
110
145
  CalendarToolbar.displayName = CALENDAR_TOOLBAR_NAME;
111
146
  var CALENDAR_GRID_NAME = "CalendarGrid";
112
- var CalendarGrid = composable(({ classNames, rows, dates = [], onSelect, ...props }, forwardedRef) => {
113
- const { weekStartsOn, event, setIndex, selected, setSelected } = useCalendarContext(CALENDAR_GRID_NAME);
147
+ var CalendarGrid = composable(({ classNames, rows, dates = [], initialDate, onSelect, onSelectRange, ...props }, forwardedRef) => {
148
+ const { weekStartsOn, event, setIndex, selected, setSelected, range, setRange, pendingRange, setPendingRange } = useCalendarContext(CALENDAR_GRID_NAME);
114
149
  const { ref: containerRef, width = 0, height = 0 } = useResizeDetector();
115
150
  const maxHeight = rows ? rows * size : void 0;
116
151
  const listRef = useRef(null);
152
+ const gridRef = useRef(null);
117
153
  const today = useMemo(() => /* @__PURE__ */ new Date(), []);
118
154
  const dateSet = useMemo(() => new Set(dates.map((date) => startOfDay(date).toISOString())), [
119
155
  dates
@@ -123,18 +159,20 @@ var CalendarGrid = composable(({ classNames, rows, dates = [], onSelect, ...prop
123
159
  ]);
124
160
  const [initialized, setInitialized] = useState(false);
125
161
  useEffect(() => {
126
- const index = differenceInWeeks(today, start);
162
+ const index = getRowIndex(start, initialDate ?? today, weekStartsOn);
127
163
  listRef.current?.scrollToRow(index);
128
164
  }, [
129
165
  initialized,
130
166
  start,
131
- today
167
+ today,
168
+ initialDate,
169
+ weekStartsOn
132
170
  ]);
133
171
  useEffect(() => {
134
172
  return event.on((event2) => {
135
173
  switch (event2.type) {
136
174
  case "scroll": {
137
- const index = differenceInWeeks(event2.date, start);
175
+ const index = getRowIndex(start, event2.date, weekStartsOn);
138
176
  listRef.current?.scrollToRow(index);
139
177
  break;
140
178
  }
@@ -154,26 +192,274 @@ var CalendarGrid = composable(({ classNames, rows, dates = [], onSelect, ...prop
154
192
  return format(day, "EEE");
155
193
  });
156
194
  }, []);
157
- const handleDaySelect = useCallback((date) => {
158
- setSelected((current) => isSameDay(date, current) ? void 0 : date);
159
- onSelect?.({
160
- date
195
+ const anchorRef = useRef(void 0);
196
+ const focusRef = useRef(void 0);
197
+ const draggingRef = useRef(false);
198
+ const pointerXRef = useRef(0);
199
+ const pointerYRef = useRef(0);
200
+ const scrollTopRef = useRef(0);
201
+ const scrollRafRef = useRef(void 0);
202
+ const scrollIntoView = useCallback((date) => {
203
+ const targetRow = getRowIndex(start, date, weekStartsOn);
204
+ const visibleHeight = maxHeight ?? height;
205
+ if (!visibleHeight) {
206
+ return;
207
+ }
208
+ const firstFullyVisibleRow = Math.ceil(scrollTopRef.current / size);
209
+ const lastFullyVisibleRow = Math.floor((scrollTopRef.current + visibleHeight) / size) - 1;
210
+ if (targetRow < firstFullyVisibleRow) {
211
+ listRef.current?.scrollToPosition(targetRow * size);
212
+ } else if (targetRow > lastFullyVisibleRow) {
213
+ listRef.current?.scrollToPosition(Math.max(0, (targetRow + 1) * size - visibleHeight));
214
+ }
215
+ }, [
216
+ height,
217
+ maxHeight,
218
+ weekStartsOn
219
+ ]);
220
+ const updateRangeFromAnchor = useCallback((focus, fireRange = false) => {
221
+ const anchor = anchorRef.current;
222
+ if (!anchor) {
223
+ return;
224
+ }
225
+ focusRef.current = focus;
226
+ if (isSameDay(anchor, focus)) {
227
+ setRange(void 0);
228
+ setSelected(anchor);
229
+ } else {
230
+ setSelected(void 0);
231
+ const committed = makeRange(anchor, focus);
232
+ setRange(committed);
233
+ if (fireRange) {
234
+ onSelectRange?.({
235
+ range: committed
236
+ });
237
+ }
238
+ }
239
+ }, [
240
+ onSelectRange,
241
+ setRange,
242
+ setSelected
243
+ ]);
244
+ const prevSelectedRef = useRef(void 0);
245
+ const handleDayPointerDown = useCallback((date, ev) => {
246
+ ev.preventDefault();
247
+ prevSelectedRef.current = selected;
248
+ anchorRef.current = date;
249
+ focusRef.current = date;
250
+ draggingRef.current = true;
251
+ setRange(void 0);
252
+ setPendingRange(void 0);
253
+ setSelected(date);
254
+ gridRef.current?.focus({
255
+ preventScroll: true
256
+ });
257
+ }, [
258
+ selected,
259
+ setPendingRange,
260
+ setRange,
261
+ setSelected
262
+ ]);
263
+ const handleDayPointerEnter = useCallback((date) => {
264
+ if (!draggingRef.current) {
265
+ return;
266
+ }
267
+ const anchor = anchorRef.current;
268
+ if (!anchor) {
269
+ return;
270
+ }
271
+ focusRef.current = date;
272
+ setSelected(void 0);
273
+ setPendingRange(makeRange(anchor, date));
274
+ }, [
275
+ setPendingRange,
276
+ setSelected
277
+ ]);
278
+ const handleDayPointerUp = useCallback((date) => {
279
+ const anchor = anchorRef.current;
280
+ const wasDragging = draggingRef.current;
281
+ draggingRef.current = false;
282
+ setPendingRange(void 0);
283
+ if (!wasDragging || !anchor) {
284
+ return;
285
+ }
286
+ focusRef.current = date;
287
+ if (isSameDay(anchor, date)) {
288
+ if (prevSelectedRef.current && isSameDay(prevSelectedRef.current, date)) {
289
+ setSelected(void 0);
290
+ anchorRef.current = void 0;
291
+ focusRef.current = void 0;
292
+ return;
293
+ }
294
+ setSelected(anchor);
295
+ onSelect?.({
296
+ date
297
+ });
298
+ return;
299
+ }
300
+ const committed = makeRange(anchor, date);
301
+ setRange(committed);
302
+ onSelectRange?.({
303
+ range: committed
161
304
  });
162
305
  }, [
163
- onSelect
306
+ onSelect,
307
+ onSelectRange,
308
+ setPendingRange,
309
+ setRange,
310
+ setSelected
311
+ ]);
312
+ useEffect(() => {
313
+ const cancel = () => {
314
+ if (draggingRef.current) {
315
+ draggingRef.current = false;
316
+ setPendingRange(void 0);
317
+ }
318
+ };
319
+ window.addEventListener("pointerup", cancel);
320
+ window.addEventListener("pointercancel", cancel);
321
+ return () => {
322
+ window.removeEventListener("pointerup", cancel);
323
+ window.removeEventListener("pointercancel", cancel);
324
+ };
325
+ }, [
326
+ setPendingRange
327
+ ]);
328
+ const tickEdgeScroll = useCallback(() => {
329
+ scrollRafRef.current = void 0;
330
+ if (!draggingRef.current) {
331
+ return;
332
+ }
333
+ const rect = containerRef.current?.getBoundingClientRect();
334
+ if (!rect) {
335
+ return;
336
+ }
337
+ const y = pointerYRef.current;
338
+ let delta = 0;
339
+ if (y < rect.top + EDGE_SCROLL_ZONE) {
340
+ delta = -EDGE_SCROLL_MAX_SPEED * Math.min(1, Math.max(0, (rect.top + EDGE_SCROLL_ZONE - y) / EDGE_SCROLL_ZONE));
341
+ } else if (y > rect.bottom - EDGE_SCROLL_ZONE) {
342
+ delta = EDGE_SCROLL_MAX_SPEED * Math.min(1, Math.max(0, (y - (rect.bottom - EDGE_SCROLL_ZONE)) / EDGE_SCROLL_ZONE));
343
+ }
344
+ if (delta !== 0) {
345
+ const newScroll = Math.max(0, scrollTopRef.current + delta);
346
+ listRef.current?.scrollToPosition(newScroll);
347
+ const date = cellDate(document.elementFromPoint(pointerXRef.current, y));
348
+ const anchor = anchorRef.current;
349
+ if (date && anchor) {
350
+ focusRef.current = date;
351
+ if (isSameDay(anchor, date)) {
352
+ setPendingRange(void 0);
353
+ setSelected(anchor);
354
+ } else {
355
+ setSelected(void 0);
356
+ setPendingRange(makeRange(anchor, date));
357
+ }
358
+ }
359
+ scrollRafRef.current = requestAnimationFrame(tickEdgeScroll);
360
+ }
361
+ }, [
362
+ containerRef,
363
+ setPendingRange,
364
+ setSelected
365
+ ]);
366
+ useEffect(() => {
367
+ const handleMove = (ev) => {
368
+ if (!draggingRef.current) {
369
+ return;
370
+ }
371
+ pointerXRef.current = ev.clientX;
372
+ pointerYRef.current = ev.clientY;
373
+ if (scrollRafRef.current === void 0) {
374
+ scrollRafRef.current = requestAnimationFrame(tickEdgeScroll);
375
+ }
376
+ };
377
+ window.addEventListener("pointermove", handleMove);
378
+ return () => {
379
+ window.removeEventListener("pointermove", handleMove);
380
+ if (scrollRafRef.current !== void 0) {
381
+ cancelAnimationFrame(scrollRafRef.current);
382
+ scrollRafRef.current = void 0;
383
+ }
384
+ };
385
+ }, [
386
+ tickEdgeScroll
164
387
  ]);
388
+ const handleKeyDown = useCallback((ev) => {
389
+ let dx = 0;
390
+ switch (ev.key) {
391
+ case "ArrowLeft":
392
+ dx = -1;
393
+ break;
394
+ case "ArrowRight":
395
+ dx = 1;
396
+ break;
397
+ case "ArrowUp":
398
+ dx = -7;
399
+ break;
400
+ case "ArrowDown":
401
+ dx = 7;
402
+ break;
403
+ default:
404
+ return;
405
+ }
406
+ ev.preventDefault();
407
+ if (ev.shiftKey) {
408
+ let anchor = anchorRef.current;
409
+ let focus = focusRef.current;
410
+ if (!anchor) {
411
+ if (selected) {
412
+ anchor = startOfDay(selected);
413
+ focus = anchor;
414
+ } else if (range) {
415
+ anchor = range.from;
416
+ focus = range.to;
417
+ } else {
418
+ anchor = startOfDay(today);
419
+ focus = anchor;
420
+ }
421
+ anchorRef.current = anchor;
422
+ focusRef.current = focus;
423
+ }
424
+ const newFocus = addDays(focus ?? anchor, dx);
425
+ updateRangeFromAnchor(newFocus, true);
426
+ scrollIntoView(newFocus);
427
+ } else {
428
+ const current = selected ?? focusRef.current ?? anchorRef.current ?? today;
429
+ const next = addDays(startOfDay(current), dx);
430
+ anchorRef.current = next;
431
+ focusRef.current = next;
432
+ setRange(void 0);
433
+ setPendingRange(void 0);
434
+ setSelected(next);
435
+ onSelect?.({
436
+ date: next
437
+ });
438
+ scrollIntoView(next);
439
+ }
440
+ }, [
441
+ onSelect,
442
+ range,
443
+ scrollIntoView,
444
+ selected,
445
+ setPendingRange,
446
+ setRange,
447
+ setSelected,
448
+ today,
449
+ updateRangeFromAnchor
450
+ ]);
451
+ const activeRange = pendingRange ?? range;
165
452
  const handleScroll = useCallback((info) => {
453
+ scrollTopRef.current = info.scrollTop;
166
454
  setIndex(Math.round(info.scrollTop / size));
167
455
  }, []);
168
456
  const rowRenderer = useCallback(({ key, index, style }) => {
169
- const getBgColor = (date) => date.getMonth() % 2 === 0 && "bg-modal-surface";
457
+ const getBgColor = (date) => date.getMonth() % 2 === 0 ? "bg-group-surface" : "bg-group-alt-surface";
170
458
  return /* @__PURE__ */ React.createElement("div", {
171
459
  key,
172
- role: "none",
173
460
  style,
174
461
  className: "grid"
175
462
  }, /* @__PURE__ */ React.createElement("div", {
176
- role: "none",
177
463
  className: "grid grid-cols-7 bg-input-surface",
178
464
  style: {
179
465
  gridTemplateColumns: `repeat(7, ${size}px)`
@@ -182,23 +468,30 @@ var CalendarGrid = composable(({ classNames, rows, dates = [], onSelect, ...prop
182
468
  length: 7
183
469
  }).map((_, i) => {
184
470
  const date = getDate(start, index, i, weekStartsOn);
471
+ const inRange = isInRange(date, activeRange);
185
472
  const border = isSameDay(date, selected) ? "border-primary-500" : isSameDay(date, today) ? "border-amber-500" : hasDate(date) ? "border-neutral-700 border-dashed" : void 0;
186
473
  return /* @__PURE__ */ React.createElement("div", {
187
474
  key: i,
188
- role: "none",
189
- className: mx("relative flex justify-center items-center cursor-pointer", getBgColor(date)),
190
- onClick: () => handleDaySelect(date)
191
- }, /* @__PURE__ */ React.createElement("span", {
192
- className: "text-description"
475
+ "data-date": startOfDay(date).toISOString(),
476
+ className: mx("relative flex justify-center items-center cursor-pointer select-none", getBgColor(date)),
477
+ onPointerDown: (ev) => handleDayPointerDown(date, ev),
478
+ onPointerEnter: () => handleDayPointerEnter(date),
479
+ onPointerUp: () => handleDayPointerUp(date)
480
+ }, inRange && /* @__PURE__ */ React.createElement("div", {
481
+ className: "absolute inset-0 bg-primary-500/20"
482
+ }), /* @__PURE__ */ React.createElement("span", {
483
+ className: "relative text-description text-sm"
193
484
  }, date.getDate()), !border && date.getDate() === 1 && /* @__PURE__ */ React.createElement("span", {
194
485
  className: "absolute top-0 text-xs text-description"
195
486
  }, format(date, "MMM")), border && /* @__PURE__ */ React.createElement("div", {
196
- role: "none",
197
487
  className: mx("absolute inset-1 border-2 rounded-full", border)
198
488
  }));
199
489
  })));
200
490
  }, [
201
- handleDaySelect,
491
+ activeRange,
492
+ handleDayPointerDown,
493
+ handleDayPointerEnter,
494
+ handleDayPointerUp,
202
495
  hasDate,
203
496
  selected,
204
497
  weekStartsOn
@@ -207,23 +500,29 @@ var CalendarGrid = composable(({ classNames, rows, dates = [], onSelect, ...prop
207
500
  ...composableProps(props, {
208
501
  role: "none",
209
502
  classNames: [
210
- "flex flex-col h-full w-full justify-center overflow-hidden",
503
+ "flex flex-col h-full w-full justify-center overflow-hidden outline-hidden",
211
504
  classNames
212
505
  ]
213
506
  }),
214
- ref: forwardedRef
507
+ ref: (node) => {
508
+ gridRef.current = node;
509
+ if (typeof forwardedRef === "function") {
510
+ forwardedRef(node);
511
+ } else if (forwardedRef) {
512
+ forwardedRef.current = node;
513
+ }
514
+ },
515
+ tabIndex: 0,
516
+ onKeyDown: handleKeyDown
215
517
  }, /* @__PURE__ */ React.createElement("div", {
216
- role: "none",
217
518
  className: "grid w-full grid-cols-7",
218
519
  style: {
219
520
  width: defaultWidth
220
521
  }
221
522
  }, days.map((date, i) => /* @__PURE__ */ React.createElement("div", {
222
523
  key: i,
223
- role: "none",
224
524
  className: "flex justify-center p-2 text-sm font-thin"
225
525
  }, date))), /* @__PURE__ */ React.createElement("div", {
226
- role: "none",
227
526
  className: "flex flex-col h-full w-full justify-center overflow-hidden",
228
527
  ref: containerRef
229
528
  }, /* @__PURE__ */ React.createElement(List, {