@dxos/react-ui-calendar 0.9.0 → 0.9.1-main.c7dcc2e112
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/dist/lib/browser/index.mjs +582 -107
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +582 -107
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/components/Calendar/Calendar.d.ts +25 -35
- package/dist/types/src/components/Calendar/Calendar.d.ts.map +1 -1
- package/dist/types/src/components/Calendar/Calendar.stories.d.ts +2 -0
- package/dist/types/src/components/Calendar/Calendar.stories.d.ts.map +1 -1
- package/dist/types/src/components/Calendar/Week.d.ts +30 -0
- package/dist/types/src/components/Calendar/Week.d.ts.map +1 -0
- package/dist/types/src/components/Calendar/Weekdays.d.ts +18 -0
- package/dist/types/src/components/Calendar/Weekdays.d.ts.map +1 -0
- package/dist/types/src/components/Calendar/context.d.ts +40 -0
- package/dist/types/src/components/Calendar/context.d.ts.map +1 -0
- package/dist/types/src/components/Calendar/util.d.ts +36 -0
- package/dist/types/src/components/Calendar/util.d.ts.map +1 -1
- package/dist/types/src/components/Calendar/util.test.d.ts +2 -0
- package/dist/types/src/components/Calendar/util.test.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +12 -12
- package/src/components/Calendar/Calendar.stories.tsx +43 -3
- package/src/components/Calendar/Calendar.tsx +117 -96
- package/src/components/Calendar/Week.tsx +488 -0
- package/src/components/Calendar/Weekdays.tsx +57 -0
- package/src/components/Calendar/context.ts +60 -0
- package/src/components/Calendar/util.test.ts +90 -0
- package/src/components/Calendar/util.ts +92 -1
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
// src/components/Calendar/Calendar.tsx
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
|
|
2
|
+
import { addDays as addDays3, format as format2, startOfDay as startOfDay3 } from "date-fns";
|
|
3
|
+
import React3, { forwardRef, useCallback as useCallback2, useEffect as useEffect2, useImperativeHandle, useMemo as useMemo3, useRef as useRef2, useState as useState2 } from "react";
|
|
5
4
|
import { useResizeDetector } from "react-resize-detector";
|
|
6
5
|
import { List } from "react-virtualized";
|
|
7
6
|
import { Event } from "@dxos/async";
|
|
8
7
|
import { IconButton, useTranslation } from "@dxos/react-ui";
|
|
9
|
-
import { composable, composableProps } from "@dxos/react-ui";
|
|
10
|
-
import { mx } from "@dxos/ui-theme";
|
|
8
|
+
import { composable as composable2, composableProps as composableProps2 } from "@dxos/react-ui";
|
|
9
|
+
import { mx as mx3 } from "@dxos/ui-theme";
|
|
11
10
|
import { translationKey } from "#translations";
|
|
12
11
|
|
|
12
|
+
// src/components/Calendar/context.ts
|
|
13
|
+
import { createContext } from "@radix-ui/react-context";
|
|
14
|
+
var [CalendarContextProvider, useCalendarContext] = createContext("Calendar");
|
|
15
|
+
|
|
13
16
|
// src/components/Calendar/util.ts
|
|
14
|
-
import { differenceInCalendarDays } from "date-fns";
|
|
17
|
+
import { differenceInCalendarDays, startOfDay } from "date-fns";
|
|
18
|
+
var gridEpoch = /* @__PURE__ */ new Date("1970-01-01");
|
|
15
19
|
var getDate = (start2, weekNumber, dayOfWeek, weekStartsOn) => {
|
|
16
20
|
const result = new Date(start2);
|
|
17
21
|
const startDayOfWeek = start2.getDay();
|
|
@@ -29,17 +33,473 @@ var getRowIndex = (start2, date, weekStartsOn) => {
|
|
|
29
33
|
var isSameDay = (date1, date2) => {
|
|
30
34
|
return !!date2 && date1.getFullYear() === date2.getFullYear() && date1.getMonth() === date2.getMonth() && date1.getDate() === date2.getDate();
|
|
31
35
|
};
|
|
36
|
+
var MINUTES_PER_DAY = 24 * 60;
|
|
37
|
+
var SNAP_MINUTES = 15;
|
|
38
|
+
var minutesOfDay = (date) => (date.getTime() - startOfDay(date).getTime()) / 6e4;
|
|
39
|
+
var setMinutesOfDay = (date, minutes) => new Date(startOfDay(date).getTime() + minutes * 6e4);
|
|
40
|
+
var yToMinutes = (y, hourHeight) => y / hourHeight * 60;
|
|
41
|
+
var minutesToY = (minutes, hourHeight) => minutes / 60 * hourHeight;
|
|
42
|
+
var snapMinutes = (minutes, step = SNAP_MINUTES) => {
|
|
43
|
+
const snapped = Math.round(minutes / step) * step;
|
|
44
|
+
return Math.max(0, Math.min(MINUTES_PER_DAY, snapped));
|
|
45
|
+
};
|
|
46
|
+
var layoutDayEvents = (events) => {
|
|
47
|
+
const layout = /* @__PURE__ */ new Map();
|
|
48
|
+
const ordered = events.map((event, index) => ({
|
|
49
|
+
index,
|
|
50
|
+
start: event.start.getTime(),
|
|
51
|
+
end: event.end.getTime()
|
|
52
|
+
})).sort((a, b) => a.start - b.start);
|
|
53
|
+
let cluster = [];
|
|
54
|
+
let clusterMax = -Infinity;
|
|
55
|
+
const flush = () => {
|
|
56
|
+
if (cluster.length === 0) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
const columnEnds = [];
|
|
60
|
+
const assigned = cluster.map(({ index, start: start2, end }) => {
|
|
61
|
+
let column = columnEnds.findIndex((columnEnd) => columnEnd <= start2);
|
|
62
|
+
if (column === -1) {
|
|
63
|
+
column = columnEnds.length;
|
|
64
|
+
}
|
|
65
|
+
columnEnds[column] = end;
|
|
66
|
+
return {
|
|
67
|
+
index,
|
|
68
|
+
column
|
|
69
|
+
};
|
|
70
|
+
});
|
|
71
|
+
const columnCount = columnEnds.length;
|
|
72
|
+
for (const { index, column } of assigned) {
|
|
73
|
+
layout.set(index, {
|
|
74
|
+
columnIndex: column,
|
|
75
|
+
columnCount
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
cluster = [];
|
|
79
|
+
clusterMax = -Infinity;
|
|
80
|
+
};
|
|
81
|
+
for (const entry of ordered) {
|
|
82
|
+
if (cluster.length > 0 && entry.start >= clusterMax) {
|
|
83
|
+
flush();
|
|
84
|
+
}
|
|
85
|
+
cluster.push(entry);
|
|
86
|
+
clusterMax = Math.max(clusterMax, entry.end);
|
|
87
|
+
}
|
|
88
|
+
flush();
|
|
89
|
+
return layout;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
// src/components/Calendar/Week.tsx
|
|
93
|
+
import { addDays as addDays2, startOfDay as startOfDay2, startOfWeek as startOfWeek2 } from "date-fns";
|
|
94
|
+
import React2, { useCallback, useEffect, useLayoutEffect, useMemo as useMemo2, useRef, useState } from "react";
|
|
95
|
+
import { composable, composableProps } from "@dxos/react-ui";
|
|
96
|
+
import { mx as mx2 } from "@dxos/ui-theme";
|
|
97
|
+
|
|
98
|
+
// src/components/Calendar/Weekdays.tsx
|
|
99
|
+
import { addDays, format, startOfWeek } from "date-fns";
|
|
100
|
+
import React, { useMemo } from "react";
|
|
101
|
+
import { mx } from "@dxos/ui-theme";
|
|
102
|
+
var Weekdays = ({ weekStartsOn, columnWidth, gutter, dates }) => {
|
|
103
|
+
const labels = useMemo(() => {
|
|
104
|
+
const weekStart = startOfWeek(/* @__PURE__ */ new Date(), {
|
|
105
|
+
weekStartsOn
|
|
106
|
+
});
|
|
107
|
+
return Array.from({
|
|
108
|
+
length: 7
|
|
109
|
+
}, (_, index) => format(addDays(weekStart, index), "EEE"));
|
|
110
|
+
}, [
|
|
111
|
+
weekStartsOn
|
|
112
|
+
]);
|
|
113
|
+
const today = useMemo(() => /* @__PURE__ */ new Date(), []);
|
|
114
|
+
const columnTemplate = columnWidth ? `repeat(7, ${columnWidth}px)` : "repeat(7, 1fr)";
|
|
115
|
+
return /* @__PURE__ */ React.createElement("div", {
|
|
116
|
+
className: "grid w-full shrink-0",
|
|
117
|
+
style: {
|
|
118
|
+
gridTemplateColumns: gutter ? `${gutter}px ${columnTemplate}` : columnTemplate
|
|
119
|
+
}
|
|
120
|
+
}, gutter != null && /* @__PURE__ */ React.createElement("div", {
|
|
121
|
+
"aria-hidden": true
|
|
122
|
+
}), labels.map((label, index) => {
|
|
123
|
+
const date = dates?.[index];
|
|
124
|
+
const isToday = !!date && isSameDay(date, today);
|
|
125
|
+
return /* @__PURE__ */ React.createElement("div", {
|
|
126
|
+
key: index,
|
|
127
|
+
className: mx("flex flex-col items-center p-2 text-sm font-thin", isToday && "text-accent-text")
|
|
128
|
+
}, /* @__PURE__ */ React.createElement("span", null, label), date && /* @__PURE__ */ React.createElement("span", {
|
|
129
|
+
className: "text-lg font-normal tabular-nums"
|
|
130
|
+
}, date.getDate()));
|
|
131
|
+
}));
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
// src/components/Calendar/Week.tsx
|
|
135
|
+
var CALENDAR_WEEK_NAME = "CalendarWeek";
|
|
136
|
+
var HOUR_HEIGHT = 48;
|
|
137
|
+
var GUTTER_WIDTH = 56;
|
|
138
|
+
var RESIZE_HANDLE = 6;
|
|
139
|
+
var MIN_DURATION = SNAP_MINUTES;
|
|
140
|
+
var INITIAL_HOUR = 8;
|
|
141
|
+
var CalendarWeek = composable(({ classNames, date, events = [], onEventCreate, onEventUpdate, ...props }, forwardedRef) => {
|
|
142
|
+
const { weekStartsOn, event: scrollEvent, setIndex } = useCalendarContext(CALENDAR_WEEK_NAME);
|
|
143
|
+
const today = useMemo2(() => /* @__PURE__ */ new Date(), []);
|
|
144
|
+
const [viewDate, setViewDate] = useState(() => date ?? today);
|
|
145
|
+
useEffect(() => {
|
|
146
|
+
if (date) {
|
|
147
|
+
setViewDate(date);
|
|
148
|
+
}
|
|
149
|
+
}, [
|
|
150
|
+
date
|
|
151
|
+
]);
|
|
152
|
+
useEffect(() => {
|
|
153
|
+
return scrollEvent.on(({ date: date2 }) => setViewDate(date2));
|
|
154
|
+
}, [
|
|
155
|
+
scrollEvent
|
|
156
|
+
]);
|
|
157
|
+
const weekDays = useMemo2(() => {
|
|
158
|
+
const weekStart = startOfWeek2(viewDate, {
|
|
159
|
+
weekStartsOn
|
|
160
|
+
});
|
|
161
|
+
return Array.from({
|
|
162
|
+
length: 7
|
|
163
|
+
}, (_, index) => startOfDay2(addDays2(weekStart, index)));
|
|
164
|
+
}, [
|
|
165
|
+
viewDate,
|
|
166
|
+
weekStartsOn
|
|
167
|
+
]);
|
|
168
|
+
useEffect(() => {
|
|
169
|
+
setIndex(getRowIndex(gridEpoch, weekDays[0], weekStartsOn));
|
|
170
|
+
}, [
|
|
171
|
+
weekDays,
|
|
172
|
+
weekStartsOn,
|
|
173
|
+
setIndex
|
|
174
|
+
]);
|
|
175
|
+
const eventsByDay = useMemo2(() => {
|
|
176
|
+
const byDay = weekDays.map(() => []);
|
|
177
|
+
for (const event of events) {
|
|
178
|
+
const dayIndex = weekDays.findIndex((day) => isSameDay(day, event.start));
|
|
179
|
+
if (dayIndex >= 0) {
|
|
180
|
+
byDay[dayIndex].push(event);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return byDay;
|
|
184
|
+
}, [
|
|
185
|
+
events,
|
|
186
|
+
weekDays
|
|
187
|
+
]);
|
|
188
|
+
const scrollRef = useRef(null);
|
|
189
|
+
useLayoutEffect(() => {
|
|
190
|
+
scrollRef.current?.scrollTo({
|
|
191
|
+
top: minutesToY(INITIAL_HOUR * 60, HOUR_HEIGHT)
|
|
192
|
+
});
|
|
193
|
+
}, []);
|
|
194
|
+
const gestureRef = useRef(void 0);
|
|
195
|
+
const columnsRef = useRef([]);
|
|
196
|
+
const [draft, setDraft] = useState(void 0);
|
|
197
|
+
const pointerMinutes = useCallback((clientY) => {
|
|
198
|
+
const rect = columnsRef.current.find(Boolean)?.getBoundingClientRect();
|
|
199
|
+
if (!rect) {
|
|
200
|
+
return 0;
|
|
201
|
+
}
|
|
202
|
+
return Math.max(0, Math.min(MINUTES_PER_DAY, yToMinutes(clientY - rect.top, HOUR_HEIGHT)));
|
|
203
|
+
}, []);
|
|
204
|
+
const dayFromX = useCallback((clientX) => {
|
|
205
|
+
const index = columnsRef.current.findIndex((node) => {
|
|
206
|
+
const rect = node?.getBoundingClientRect();
|
|
207
|
+
return rect && clientX >= rect.left && clientX < rect.right;
|
|
208
|
+
});
|
|
209
|
+
return index >= 0 ? weekDays[index] : void 0;
|
|
210
|
+
}, [
|
|
211
|
+
weekDays
|
|
212
|
+
]);
|
|
213
|
+
const applyGesture = useCallback((clientX, clientY) => {
|
|
214
|
+
const gesture = gestureRef.current;
|
|
215
|
+
if (!gesture) {
|
|
216
|
+
return void 0;
|
|
217
|
+
}
|
|
218
|
+
const { kind, day, eventId, anchorMinutes, grabOffset, durationMinutes } = gesture;
|
|
219
|
+
const raw = pointerMinutes(clientY);
|
|
220
|
+
switch (kind) {
|
|
221
|
+
case "create": {
|
|
222
|
+
const focus = snapMinutes(raw);
|
|
223
|
+
const from = Math.min(anchorMinutes, focus);
|
|
224
|
+
const to = Math.max(anchorMinutes, focus);
|
|
225
|
+
const end = Math.max(to, from + MIN_DURATION);
|
|
226
|
+
return {
|
|
227
|
+
eventId,
|
|
228
|
+
start: setMinutesOfDay(day, from),
|
|
229
|
+
end: setMinutesOfDay(day, end)
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
case "move": {
|
|
233
|
+
const targetDay = dayFromX(clientX) ?? day;
|
|
234
|
+
let start2 = snapMinutes(raw - grabOffset);
|
|
235
|
+
start2 = Math.max(0, Math.min(MINUTES_PER_DAY - durationMinutes, start2));
|
|
236
|
+
return {
|
|
237
|
+
eventId,
|
|
238
|
+
start: setMinutesOfDay(targetDay, start2),
|
|
239
|
+
end: setMinutesOfDay(targetDay, start2 + durationMinutes)
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
case "resize-start": {
|
|
243
|
+
const start2 = Math.min(snapMinutes(raw), anchorMinutes - MIN_DURATION);
|
|
244
|
+
return {
|
|
245
|
+
eventId,
|
|
246
|
+
start: setMinutesOfDay(day, start2),
|
|
247
|
+
end: setMinutesOfDay(day, anchorMinutes)
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
case "resize-end": {
|
|
251
|
+
const end = Math.max(snapMinutes(raw), anchorMinutes + MIN_DURATION);
|
|
252
|
+
return {
|
|
253
|
+
eventId,
|
|
254
|
+
start: setMinutesOfDay(day, anchorMinutes),
|
|
255
|
+
end: setMinutesOfDay(day, end)
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}, [
|
|
260
|
+
dayFromX,
|
|
261
|
+
pointerMinutes
|
|
262
|
+
]);
|
|
263
|
+
const callbacksRef = useRef({
|
|
264
|
+
onEventCreate,
|
|
265
|
+
onEventUpdate
|
|
266
|
+
});
|
|
267
|
+
callbacksRef.current = {
|
|
268
|
+
onEventCreate,
|
|
269
|
+
onEventUpdate
|
|
270
|
+
};
|
|
271
|
+
const detachRef = useRef(() => {
|
|
272
|
+
});
|
|
273
|
+
const beginGesture = useCallback((gesture, ev) => {
|
|
274
|
+
ev.preventDefault();
|
|
275
|
+
ev.stopPropagation();
|
|
276
|
+
gestureRef.current = gesture;
|
|
277
|
+
setDraft(applyGesture(ev.clientX, ev.clientY));
|
|
278
|
+
const handleMove = (moveEv) => {
|
|
279
|
+
if (gestureRef.current) {
|
|
280
|
+
setDraft(applyGesture(moveEv.clientX, moveEv.clientY));
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
const handleUp = (upEv) => {
|
|
284
|
+
const active = gestureRef.current;
|
|
285
|
+
const result = applyGesture(upEv.clientX, upEv.clientY);
|
|
286
|
+
detachRef.current();
|
|
287
|
+
gestureRef.current = void 0;
|
|
288
|
+
setDraft(void 0);
|
|
289
|
+
if (active && result) {
|
|
290
|
+
if (active.kind === "create") {
|
|
291
|
+
callbacksRef.current.onEventCreate?.({
|
|
292
|
+
start: result.start,
|
|
293
|
+
end: result.end
|
|
294
|
+
});
|
|
295
|
+
} else if (result.eventId) {
|
|
296
|
+
callbacksRef.current.onEventUpdate?.({
|
|
297
|
+
id: result.eventId,
|
|
298
|
+
start: result.start,
|
|
299
|
+
end: result.end
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
};
|
|
304
|
+
detachRef.current = () => {
|
|
305
|
+
window.removeEventListener("pointermove", handleMove);
|
|
306
|
+
window.removeEventListener("pointerup", handleUp);
|
|
307
|
+
window.removeEventListener("pointercancel", handleUp);
|
|
308
|
+
};
|
|
309
|
+
window.addEventListener("pointermove", handleMove);
|
|
310
|
+
window.addEventListener("pointerup", handleUp);
|
|
311
|
+
window.addEventListener("pointercancel", handleUp);
|
|
312
|
+
}, [
|
|
313
|
+
applyGesture
|
|
314
|
+
]);
|
|
315
|
+
useEffect(() => () => detachRef.current(), []);
|
|
316
|
+
const handleColumnPointerDown = useCallback((day, event) => {
|
|
317
|
+
const rect = event.currentTarget.getBoundingClientRect();
|
|
318
|
+
const anchor = snapMinutes(yToMinutes(event.clientY - rect.top, HOUR_HEIGHT));
|
|
319
|
+
beginGesture({
|
|
320
|
+
kind: "create",
|
|
321
|
+
day,
|
|
322
|
+
anchorMinutes: anchor,
|
|
323
|
+
grabOffset: 0,
|
|
324
|
+
durationMinutes: 0
|
|
325
|
+
}, event);
|
|
326
|
+
}, [
|
|
327
|
+
beginGesture
|
|
328
|
+
]);
|
|
329
|
+
const renderEvent = useCallback((event, day, start2, end, columnIndex, columnCount) => /* @__PURE__ */ React2.createElement(EventBlock, {
|
|
330
|
+
key: event.id,
|
|
331
|
+
event,
|
|
332
|
+
start: start2,
|
|
333
|
+
end,
|
|
334
|
+
columnIndex,
|
|
335
|
+
columnCount,
|
|
336
|
+
onMoveStart: (ev) => beginGesture({
|
|
337
|
+
kind: "move",
|
|
338
|
+
day,
|
|
339
|
+
eventId: event.id,
|
|
340
|
+
anchorMinutes: 0,
|
|
341
|
+
grabOffset: pointerMinutes(ev.clientY) - minutesOfDay(event.start),
|
|
342
|
+
durationMinutes: minutesOfDay(event.end) - minutesOfDay(event.start)
|
|
343
|
+
}, ev),
|
|
344
|
+
onResizeStart: (ev) => beginGesture({
|
|
345
|
+
kind: "resize-start",
|
|
346
|
+
day,
|
|
347
|
+
eventId: event.id,
|
|
348
|
+
anchorMinutes: minutesOfDay(event.end),
|
|
349
|
+
grabOffset: 0,
|
|
350
|
+
durationMinutes: 0
|
|
351
|
+
}, ev),
|
|
352
|
+
onResizeEnd: (ev) => beginGesture({
|
|
353
|
+
kind: "resize-end",
|
|
354
|
+
day,
|
|
355
|
+
eventId: event.id,
|
|
356
|
+
anchorMinutes: minutesOfDay(event.start),
|
|
357
|
+
grabOffset: 0,
|
|
358
|
+
durationMinutes: 0
|
|
359
|
+
}, ev)
|
|
360
|
+
}), [
|
|
361
|
+
beginGesture,
|
|
362
|
+
pointerMinutes
|
|
363
|
+
]);
|
|
364
|
+
const draggedEvent = draft?.eventId ? events.find((event) => event.id === draft.eventId) : void 0;
|
|
365
|
+
return /* @__PURE__ */ React2.createElement("div", {
|
|
366
|
+
...composableProps(props, {
|
|
367
|
+
classNames: [
|
|
368
|
+
"flex flex-col h-full w-full overflow-hidden outline-hidden",
|
|
369
|
+
classNames
|
|
370
|
+
]
|
|
371
|
+
}),
|
|
372
|
+
ref: forwardedRef
|
|
373
|
+
}, /* @__PURE__ */ React2.createElement(Weekdays, {
|
|
374
|
+
weekStartsOn,
|
|
375
|
+
gutter: GUTTER_WIDTH,
|
|
376
|
+
dates: weekDays
|
|
377
|
+
}), /* @__PURE__ */ React2.createElement("div", {
|
|
378
|
+
ref: scrollRef,
|
|
379
|
+
className: "flex-1 overflow-y-auto _scrollbar-thin"
|
|
380
|
+
}, /* @__PURE__ */ React2.createElement("div", {
|
|
381
|
+
className: "grid relative",
|
|
382
|
+
style: {
|
|
383
|
+
height: minutesToY(MINUTES_PER_DAY, HOUR_HEIGHT),
|
|
384
|
+
gridTemplateColumns: `${GUTTER_WIDTH}px repeat(7, 1fr)`
|
|
385
|
+
}
|
|
386
|
+
}, /* @__PURE__ */ React2.createElement("div", {
|
|
387
|
+
className: "relative"
|
|
388
|
+
}, Array.from({
|
|
389
|
+
length: 24
|
|
390
|
+
}, (_, hour) => /* @__PURE__ */ React2.createElement("div", {
|
|
391
|
+
key: hour,
|
|
392
|
+
className: "absolute right-1 -translate-y-1/2 text-xs text-description tabular-nums",
|
|
393
|
+
style: {
|
|
394
|
+
top: minutesToY(hour * 60, HOUR_HEIGHT)
|
|
395
|
+
}
|
|
396
|
+
}, hour === 0 ? "" : `${hour.toString().padStart(2, "0")}:00`))), weekDays.map((day, dayIndex) => {
|
|
397
|
+
const dayEvents = eventsByDay[dayIndex];
|
|
398
|
+
const layout = layoutDayEvents(dayEvents);
|
|
399
|
+
const isToday = isSameDay(day, today);
|
|
400
|
+
const draftHere = draft && isSameDay(day, draft.start) ? draft : void 0;
|
|
401
|
+
return /* @__PURE__ */ React2.createElement("div", {
|
|
402
|
+
key: day.toISOString(),
|
|
403
|
+
ref: (node) => {
|
|
404
|
+
columnsRef.current[dayIndex] = node;
|
|
405
|
+
},
|
|
406
|
+
"data-date": day.toISOString(),
|
|
407
|
+
className: mx2("relative border-l border-separator cursor-cell select-none", dayIndex === 6 && "border-r", isToday && "bg-primary-500/5"),
|
|
408
|
+
onPointerDown: (ev) => handleColumnPointerDown(day, ev)
|
|
409
|
+
}, Array.from({
|
|
410
|
+
length: 24
|
|
411
|
+
}, (_, hour) => /* @__PURE__ */ React2.createElement("div", {
|
|
412
|
+
key: hour,
|
|
413
|
+
className: "absolute inset-x-0 border-t border-separator/60",
|
|
414
|
+
style: {
|
|
415
|
+
top: minutesToY(hour * 60, HOUR_HEIGHT)
|
|
416
|
+
}
|
|
417
|
+
})), dayEvents.map((event, index) => {
|
|
418
|
+
const slot = layout.get(index) ?? {
|
|
419
|
+
columnIndex: 0,
|
|
420
|
+
columnCount: 1
|
|
421
|
+
};
|
|
422
|
+
const editing = draft && draft.eventId === event.id ? draft : void 0;
|
|
423
|
+
if (editing && !isSameDay(editing.start, day)) {
|
|
424
|
+
return null;
|
|
425
|
+
}
|
|
426
|
+
const start2 = editing ? editing.start : event.start;
|
|
427
|
+
const end = editing ? editing.end : event.end;
|
|
428
|
+
return renderEvent(event, day, start2, end, slot.columnIndex, slot.columnCount);
|
|
429
|
+
}), draftHere && draggedEvent && !dayEvents.some((event) => event.id === draggedEvent.id) && renderEvent(draggedEvent, day, draftHere.start, draftHere.end, 0, 1), draftHere && !draftHere.eventId && /* @__PURE__ */ React2.createElement(PendingBlock, {
|
|
430
|
+
start: draftHere.start,
|
|
431
|
+
end: draftHere.end
|
|
432
|
+
}));
|
|
433
|
+
}))));
|
|
434
|
+
});
|
|
435
|
+
CalendarWeek.displayName = CALENDAR_WEEK_NAME;
|
|
436
|
+
var formatTime = (date) => {
|
|
437
|
+
const minutes = minutesOfDay(date);
|
|
438
|
+
const hour = Math.floor(minutes / 60);
|
|
439
|
+
const minute = Math.round(minutes % 60);
|
|
440
|
+
return `${hour.toString().padStart(2, "0")}:${minute.toString().padStart(2, "0")}`;
|
|
441
|
+
};
|
|
442
|
+
var EventBlock = ({ event, start: start2, end, columnIndex, columnCount, onMoveStart, onResizeStart, onResizeEnd }) => {
|
|
443
|
+
const top = minutesToY(minutesOfDay(start2), HOUR_HEIGHT);
|
|
444
|
+
const height = Math.max(minutesToY(minutesOfDay(end) - minutesOfDay(start2), HOUR_HEIGHT), RESIZE_HANDLE * 2);
|
|
445
|
+
const widthPct = 100 / columnCount;
|
|
446
|
+
return /* @__PURE__ */ React2.createElement("div", {
|
|
447
|
+
className: "absolute rounded-sm bg-primary-500/80 text-inverse-fg overflow-hidden cursor-move shadow-sm",
|
|
448
|
+
style: {
|
|
449
|
+
top,
|
|
450
|
+
height,
|
|
451
|
+
left: `calc(${columnIndex * widthPct}% + 1px)`,
|
|
452
|
+
width: `calc(${widthPct}% - 2px)`
|
|
453
|
+
},
|
|
454
|
+
onPointerDown: onMoveStart
|
|
455
|
+
}, /* @__PURE__ */ React2.createElement("div", {
|
|
456
|
+
className: "absolute inset-x-0 top-0 cursor-ns-resize",
|
|
457
|
+
style: {
|
|
458
|
+
height: RESIZE_HANDLE
|
|
459
|
+
},
|
|
460
|
+
onPointerDown: onResizeStart
|
|
461
|
+
}), /* @__PURE__ */ React2.createElement("div", {
|
|
462
|
+
className: "px-1 py-0.5 text-xs leading-tight"
|
|
463
|
+
}, /* @__PURE__ */ React2.createElement("div", {
|
|
464
|
+
className: "font-medium truncate"
|
|
465
|
+
}, event.title ?? "(untitled)")), /* @__PURE__ */ React2.createElement("div", {
|
|
466
|
+
className: "absolute inset-x-0 bottom-0 cursor-ns-resize",
|
|
467
|
+
style: {
|
|
468
|
+
height: RESIZE_HANDLE
|
|
469
|
+
},
|
|
470
|
+
onPointerDown: onResizeEnd
|
|
471
|
+
}));
|
|
472
|
+
};
|
|
473
|
+
var PendingBlock = ({ start: start2, end }) => {
|
|
474
|
+
const top = minutesToY(minutesOfDay(start2), HOUR_HEIGHT);
|
|
475
|
+
const height = minutesToY(minutesOfDay(end) - minutesOfDay(start2), HOUR_HEIGHT);
|
|
476
|
+
return /* @__PURE__ */ React2.createElement("div", {
|
|
477
|
+
className: "absolute inset-x-0 rounded bg-primary-500/40 border border-primary-500 pointer-events-none",
|
|
478
|
+
style: {
|
|
479
|
+
top,
|
|
480
|
+
height
|
|
481
|
+
}
|
|
482
|
+
}, /* @__PURE__ */ React2.createElement("div", {
|
|
483
|
+
className: "px-1 py-0.5 text-xs tabular-nums text-inverse-fg"
|
|
484
|
+
}, formatTime(start2), "\u2013", formatTime(end)));
|
|
485
|
+
};
|
|
32
486
|
|
|
33
487
|
// src/components/Calendar/Calendar.tsx
|
|
34
488
|
var maxRows = 50 * 100;
|
|
35
|
-
var start =
|
|
489
|
+
var start = gridEpoch;
|
|
36
490
|
var size = 40;
|
|
37
491
|
var defaultWidth = 7 * size;
|
|
38
492
|
var EDGE_SCROLL_ZONE = 32;
|
|
39
493
|
var EDGE_SCROLL_MAX_SPEED = 12;
|
|
494
|
+
var DATE_CLASS_NAMES = {
|
|
495
|
+
current: "ring-2 ring-primary-500",
|
|
496
|
+
today: "border-2 border-amber-500 bg-amber-500/50 text-inverse-fg",
|
|
497
|
+
busy: "border border-green-700",
|
|
498
|
+
starred: "border-2 border-dashed border-amber-500"
|
|
499
|
+
};
|
|
40
500
|
var makeRange = (a, b) => {
|
|
41
|
-
const dayA =
|
|
42
|
-
const dayB =
|
|
501
|
+
const dayA = startOfDay3(a);
|
|
502
|
+
const dayB = startOfDay3(b);
|
|
43
503
|
return dayA <= dayB ? {
|
|
44
504
|
from: dayA,
|
|
45
505
|
to: dayB
|
|
@@ -52,7 +512,7 @@ var isInRange = (date, range) => {
|
|
|
52
512
|
if (!range) {
|
|
53
513
|
return false;
|
|
54
514
|
}
|
|
55
|
-
const day =
|
|
515
|
+
const day = startOfDay3(date).getTime();
|
|
56
516
|
return day >= range.from.getTime() && day <= range.to.getTime();
|
|
57
517
|
};
|
|
58
518
|
var cellDate = (el) => {
|
|
@@ -66,24 +526,29 @@ var cellDate = (el) => {
|
|
|
66
526
|
}
|
|
67
527
|
return void 0;
|
|
68
528
|
};
|
|
69
|
-
var [CalendarContextProvider, useCalendarContext] = createContext("Calendar");
|
|
70
529
|
var CalendarRoot = /* @__PURE__ */ forwardRef(({ children, weekStartsOn = 1 }, forwardedRef) => {
|
|
71
|
-
const event =
|
|
72
|
-
const [selected, setSelected] =
|
|
73
|
-
const [index, setIndex] =
|
|
74
|
-
const [range, setRange] =
|
|
75
|
-
const [pendingRange, setPendingRange] =
|
|
530
|
+
const event = useMemo3(() => new Event(), []);
|
|
531
|
+
const [selected, setSelected] = useState2();
|
|
532
|
+
const [index, setIndex] = useState2();
|
|
533
|
+
const [range, setRange] = useState2();
|
|
534
|
+
const [pendingRange, setPendingRange] = useState2();
|
|
76
535
|
useImperativeHandle(forwardedRef, () => ({
|
|
77
536
|
scrollTo: (date) => {
|
|
78
537
|
event.emit({
|
|
79
538
|
type: "scroll",
|
|
80
539
|
date
|
|
81
540
|
});
|
|
541
|
+
},
|
|
542
|
+
select: (date) => {
|
|
543
|
+
event.emit({
|
|
544
|
+
type: "select",
|
|
545
|
+
date
|
|
546
|
+
});
|
|
82
547
|
}
|
|
83
548
|
}), [
|
|
84
549
|
event
|
|
85
550
|
]);
|
|
86
|
-
return /* @__PURE__ */
|
|
551
|
+
return /* @__PURE__ */ React3.createElement(CalendarContextProvider, {
|
|
87
552
|
weekStartsOn,
|
|
88
553
|
event,
|
|
89
554
|
index,
|
|
@@ -97,15 +562,15 @@ var CalendarRoot = /* @__PURE__ */ forwardRef(({ children, weekStartsOn = 1 }, f
|
|
|
97
562
|
}, children);
|
|
98
563
|
});
|
|
99
564
|
var CALENDAR_TOOLBAR_NAME = "CalendarHeader";
|
|
100
|
-
var CalendarToolbar =
|
|
565
|
+
var CalendarToolbar = composable2(({ classNames, ...props }, forwardedRef) => {
|
|
101
566
|
const { t } = useTranslation(translationKey);
|
|
102
567
|
const { weekStartsOn, event, index, selected } = useCalendarContext(CALENDAR_TOOLBAR_NAME);
|
|
103
|
-
const top =
|
|
568
|
+
const top = useMemo3(() => getDate(start, index ?? 0, 6, weekStartsOn), [
|
|
104
569
|
index,
|
|
105
570
|
weekStartsOn
|
|
106
571
|
]);
|
|
107
|
-
const today =
|
|
108
|
-
const handleToday =
|
|
572
|
+
const today = useMemo3(() => /* @__PURE__ */ new Date(), []);
|
|
573
|
+
const handleToday = useCallback2(() => {
|
|
109
574
|
event.emit({
|
|
110
575
|
type: "scroll",
|
|
111
576
|
date: today
|
|
@@ -115,91 +580,98 @@ var CalendarToolbar = composable(({ classNames, ...props }, forwardedRef) => {
|
|
|
115
580
|
start,
|
|
116
581
|
today
|
|
117
582
|
]);
|
|
118
|
-
return /* @__PURE__ */
|
|
119
|
-
...
|
|
583
|
+
return /* @__PURE__ */ React3.createElement("div", {
|
|
584
|
+
...composableProps2(props, {
|
|
120
585
|
role: "none",
|
|
121
586
|
classNames: [
|
|
122
587
|
"shrink-0 grid! grid-cols-3 items-center bg-toolbar-surface",
|
|
123
588
|
classNames
|
|
124
589
|
]
|
|
125
590
|
}),
|
|
126
|
-
ref: forwardedRef
|
|
127
|
-
|
|
128
|
-
width: defaultWidth
|
|
129
|
-
}
|
|
130
|
-
}, /* @__PURE__ */ React.createElement("div", {
|
|
591
|
+
ref: forwardedRef
|
|
592
|
+
}, /* @__PURE__ */ React3.createElement("div", {
|
|
131
593
|
className: "flex justify-start"
|
|
132
|
-
}, /* @__PURE__ */
|
|
594
|
+
}, /* @__PURE__ */ React3.createElement(IconButton, {
|
|
133
595
|
variant: "ghost",
|
|
134
596
|
icon: "ph--calendar--regular",
|
|
135
597
|
iconOnly: true,
|
|
136
598
|
classNames: "aspect-square",
|
|
137
599
|
label: t("today.button"),
|
|
138
600
|
onClick: handleToday
|
|
139
|
-
})), /* @__PURE__ */
|
|
601
|
+
})), /* @__PURE__ */ React3.createElement("div", {
|
|
140
602
|
className: "flex justify-center p-2 text-description"
|
|
141
|
-
},
|
|
603
|
+
}, format2(selected ?? top, "MMMM")), /* @__PURE__ */ React3.createElement("div", {
|
|
142
604
|
className: "flex justify-end p-2 text-description"
|
|
143
605
|
}, (selected ?? top).getFullYear()));
|
|
144
606
|
});
|
|
145
607
|
CalendarToolbar.displayName = CALENDAR_TOOLBAR_NAME;
|
|
146
608
|
var CALENDAR_GRID_NAME = "CalendarGrid";
|
|
147
|
-
var CalendarGrid =
|
|
609
|
+
var CalendarGrid = composable2(({ classNames, rows, dates = [], initialDate, scrollMargin = 2, onSelect, onSelectRange, ...props }, forwardedRef) => {
|
|
148
610
|
const { weekStartsOn, event, setIndex, selected, setSelected, range, setRange, pendingRange, setPendingRange } = useCalendarContext(CALENDAR_GRID_NAME);
|
|
149
611
|
const { ref: containerRef, width = 0, height = 0 } = useResizeDetector();
|
|
150
612
|
const maxHeight = rows ? rows * size : void 0;
|
|
151
|
-
const listRef =
|
|
152
|
-
const gridRef =
|
|
153
|
-
const today =
|
|
154
|
-
const
|
|
613
|
+
const listRef = useRef2(null);
|
|
614
|
+
const gridRef = useRef2(null);
|
|
615
|
+
const today = useMemo3(() => /* @__PURE__ */ new Date(), []);
|
|
616
|
+
const dateMarkers = useMemo3(() => {
|
|
617
|
+
const markers = /* @__PURE__ */ new Map();
|
|
618
|
+
for (const { startDate, endDate, tag = "busy" } of dates) {
|
|
619
|
+
const end = endDate ? startOfDay3(endDate) : startOfDay3(startDate);
|
|
620
|
+
for (let date = startOfDay3(startDate); date <= end; date = addDays3(date, 1)) {
|
|
621
|
+
const iso = date.toISOString();
|
|
622
|
+
if (markers.get(iso) !== "star") {
|
|
623
|
+
markers.set(iso, tag);
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
return markers;
|
|
628
|
+
}, [
|
|
155
629
|
dates
|
|
156
630
|
]);
|
|
157
|
-
const
|
|
158
|
-
|
|
631
|
+
const getMarker = useCallback2((date) => {
|
|
632
|
+
const iso = startOfDay3(date).toISOString();
|
|
633
|
+
const tag = dateMarkers.get(iso);
|
|
634
|
+
return tag ? {
|
|
635
|
+
tag
|
|
636
|
+
} : void 0;
|
|
637
|
+
}, [
|
|
638
|
+
dateMarkers
|
|
159
639
|
]);
|
|
160
|
-
const [initialized, setInitialized] =
|
|
161
|
-
|
|
640
|
+
const [initialized, setInitialized] = useState2(false);
|
|
641
|
+
useEffect2(() => {
|
|
162
642
|
const index = getRowIndex(start, initialDate ?? today, weekStartsOn);
|
|
163
|
-
listRef.current?.scrollToRow(index);
|
|
643
|
+
listRef.current?.scrollToRow(Math.max(0, index - scrollMargin));
|
|
164
644
|
}, [
|
|
165
645
|
initialized,
|
|
166
646
|
start,
|
|
167
647
|
today,
|
|
168
648
|
initialDate,
|
|
169
|
-
weekStartsOn
|
|
649
|
+
weekStartsOn,
|
|
650
|
+
scrollMargin
|
|
170
651
|
]);
|
|
171
|
-
|
|
652
|
+
useEffect2(() => {
|
|
172
653
|
return event.on((event2) => {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
const index = getRowIndex(start, event2.date, weekStartsOn);
|
|
176
|
-
listRef.current?.scrollToRow(index);
|
|
177
|
-
break;
|
|
178
|
-
}
|
|
654
|
+
if (event2.type === "select") {
|
|
655
|
+
setSelected(event2.date);
|
|
179
656
|
}
|
|
657
|
+
const index = getRowIndex(start, event2.date, weekStartsOn);
|
|
658
|
+
listRef.current?.scrollToRow(Math.max(0, index - scrollMargin));
|
|
180
659
|
});
|
|
181
660
|
}, [
|
|
182
|
-
event
|
|
661
|
+
event,
|
|
662
|
+
start,
|
|
663
|
+
weekStartsOn,
|
|
664
|
+
scrollMargin,
|
|
665
|
+
setSelected
|
|
183
666
|
]);
|
|
184
|
-
const
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
return format(day, "EEE");
|
|
193
|
-
});
|
|
194
|
-
}, []);
|
|
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) => {
|
|
667
|
+
const anchorRef = useRef2(void 0);
|
|
668
|
+
const focusRef = useRef2(void 0);
|
|
669
|
+
const draggingRef = useRef2(false);
|
|
670
|
+
const pointerXRef = useRef2(0);
|
|
671
|
+
const pointerYRef = useRef2(0);
|
|
672
|
+
const scrollTopRef = useRef2(0);
|
|
673
|
+
const scrollRafRef = useRef2(void 0);
|
|
674
|
+
const scrollIntoView = useCallback2((date) => {
|
|
203
675
|
const targetRow = getRowIndex(start, date, weekStartsOn);
|
|
204
676
|
const visibleHeight = maxHeight ?? height;
|
|
205
677
|
if (!visibleHeight) {
|
|
@@ -217,7 +689,7 @@ var CalendarGrid = composable(({ classNames, rows, dates = [], initialDate, onSe
|
|
|
217
689
|
maxHeight,
|
|
218
690
|
weekStartsOn
|
|
219
691
|
]);
|
|
220
|
-
const updateRangeFromAnchor =
|
|
692
|
+
const updateRangeFromAnchor = useCallback2((focus, fireRange = false) => {
|
|
221
693
|
const anchor = anchorRef.current;
|
|
222
694
|
if (!anchor) {
|
|
223
695
|
return;
|
|
@@ -241,8 +713,8 @@ var CalendarGrid = composable(({ classNames, rows, dates = [], initialDate, onSe
|
|
|
241
713
|
setRange,
|
|
242
714
|
setSelected
|
|
243
715
|
]);
|
|
244
|
-
const prevSelectedRef =
|
|
245
|
-
const handleDayPointerDown =
|
|
716
|
+
const prevSelectedRef = useRef2(void 0);
|
|
717
|
+
const handleDayPointerDown = useCallback2((date, ev) => {
|
|
246
718
|
ev.preventDefault();
|
|
247
719
|
prevSelectedRef.current = selected;
|
|
248
720
|
anchorRef.current = date;
|
|
@@ -260,7 +732,7 @@ var CalendarGrid = composable(({ classNames, rows, dates = [], initialDate, onSe
|
|
|
260
732
|
setRange,
|
|
261
733
|
setSelected
|
|
262
734
|
]);
|
|
263
|
-
const handleDayPointerEnter =
|
|
735
|
+
const handleDayPointerEnter = useCallback2((date) => {
|
|
264
736
|
if (!draggingRef.current) {
|
|
265
737
|
return;
|
|
266
738
|
}
|
|
@@ -275,7 +747,7 @@ var CalendarGrid = composable(({ classNames, rows, dates = [], initialDate, onSe
|
|
|
275
747
|
setPendingRange,
|
|
276
748
|
setSelected
|
|
277
749
|
]);
|
|
278
|
-
const handleDayPointerUp =
|
|
750
|
+
const handleDayPointerUp = useCallback2((date) => {
|
|
279
751
|
const anchor = anchorRef.current;
|
|
280
752
|
const wasDragging = draggingRef.current;
|
|
281
753
|
draggingRef.current = false;
|
|
@@ -309,7 +781,7 @@ var CalendarGrid = composable(({ classNames, rows, dates = [], initialDate, onSe
|
|
|
309
781
|
setRange,
|
|
310
782
|
setSelected
|
|
311
783
|
]);
|
|
312
|
-
|
|
784
|
+
useEffect2(() => {
|
|
313
785
|
const cancel = () => {
|
|
314
786
|
if (draggingRef.current) {
|
|
315
787
|
draggingRef.current = false;
|
|
@@ -325,7 +797,7 @@ var CalendarGrid = composable(({ classNames, rows, dates = [], initialDate, onSe
|
|
|
325
797
|
}, [
|
|
326
798
|
setPendingRange
|
|
327
799
|
]);
|
|
328
|
-
const tickEdgeScroll =
|
|
800
|
+
const tickEdgeScroll = useCallback2(() => {
|
|
329
801
|
scrollRafRef.current = void 0;
|
|
330
802
|
if (!draggingRef.current) {
|
|
331
803
|
return;
|
|
@@ -363,7 +835,7 @@ var CalendarGrid = composable(({ classNames, rows, dates = [], initialDate, onSe
|
|
|
363
835
|
setPendingRange,
|
|
364
836
|
setSelected
|
|
365
837
|
]);
|
|
366
|
-
|
|
838
|
+
useEffect2(() => {
|
|
367
839
|
const handleMove = (ev) => {
|
|
368
840
|
if (!draggingRef.current) {
|
|
369
841
|
return;
|
|
@@ -385,7 +857,7 @@ var CalendarGrid = composable(({ classNames, rows, dates = [], initialDate, onSe
|
|
|
385
857
|
}, [
|
|
386
858
|
tickEdgeScroll
|
|
387
859
|
]);
|
|
388
|
-
const handleKeyDown =
|
|
860
|
+
const handleKeyDown = useCallback2((ev) => {
|
|
389
861
|
let dx = 0;
|
|
390
862
|
switch (ev.key) {
|
|
391
863
|
case "ArrowLeft":
|
|
@@ -409,24 +881,24 @@ var CalendarGrid = composable(({ classNames, rows, dates = [], initialDate, onSe
|
|
|
409
881
|
let focus = focusRef.current;
|
|
410
882
|
if (!anchor) {
|
|
411
883
|
if (selected) {
|
|
412
|
-
anchor =
|
|
884
|
+
anchor = startOfDay3(selected);
|
|
413
885
|
focus = anchor;
|
|
414
886
|
} else if (range) {
|
|
415
887
|
anchor = range.from;
|
|
416
888
|
focus = range.to;
|
|
417
889
|
} else {
|
|
418
|
-
anchor =
|
|
890
|
+
anchor = startOfDay3(today);
|
|
419
891
|
focus = anchor;
|
|
420
892
|
}
|
|
421
893
|
anchorRef.current = anchor;
|
|
422
894
|
focusRef.current = focus;
|
|
423
895
|
}
|
|
424
|
-
const newFocus =
|
|
896
|
+
const newFocus = addDays3(focus ?? anchor, dx);
|
|
425
897
|
updateRangeFromAnchor(newFocus, true);
|
|
426
898
|
scrollIntoView(newFocus);
|
|
427
899
|
} else {
|
|
428
900
|
const current = selected ?? focusRef.current ?? anchorRef.current ?? today;
|
|
429
|
-
const next =
|
|
901
|
+
const next = addDays3(startOfDay3(current), dx);
|
|
430
902
|
anchorRef.current = next;
|
|
431
903
|
focusRef.current = next;
|
|
432
904
|
setRange(void 0);
|
|
@@ -449,17 +921,17 @@ var CalendarGrid = composable(({ classNames, rows, dates = [], initialDate, onSe
|
|
|
449
921
|
updateRangeFromAnchor
|
|
450
922
|
]);
|
|
451
923
|
const activeRange = pendingRange ?? range;
|
|
452
|
-
const handleScroll =
|
|
924
|
+
const handleScroll = useCallback2((info) => {
|
|
453
925
|
scrollTopRef.current = info.scrollTop;
|
|
454
926
|
setIndex(Math.round(info.scrollTop / size));
|
|
455
927
|
}, []);
|
|
456
|
-
const rowRenderer =
|
|
928
|
+
const rowRenderer = useCallback2(({ key, index, style }) => {
|
|
457
929
|
const getBgColor = (date) => date.getMonth() % 2 === 0 ? "bg-group-surface" : "bg-group-alt-surface";
|
|
458
|
-
return /* @__PURE__ */
|
|
930
|
+
return /* @__PURE__ */ React3.createElement("div", {
|
|
459
931
|
key,
|
|
460
932
|
style,
|
|
461
933
|
className: "grid"
|
|
462
|
-
}, /* @__PURE__ */
|
|
934
|
+
}, /* @__PURE__ */ React3.createElement("div", {
|
|
463
935
|
className: "grid grid-cols-7 bg-input-surface",
|
|
464
936
|
style: {
|
|
465
937
|
gridTemplateColumns: `repeat(7, ${size}px)`
|
|
@@ -468,23 +940,26 @@ var CalendarGrid = composable(({ classNames, rows, dates = [], initialDate, onSe
|
|
|
468
940
|
length: 7
|
|
469
941
|
}).map((_, i) => {
|
|
470
942
|
const date = getDate(start, index, i, weekStartsOn);
|
|
943
|
+
const marker = getMarker(date);
|
|
944
|
+
const isToday = isSameDay(date, today);
|
|
945
|
+
const isCurrent = isSameDay(date, selected);
|
|
946
|
+
const dateClassNames = isToday ? DATE_CLASS_NAMES.today : marker?.tag === "star" ? DATE_CLASS_NAMES.starred : marker ? DATE_CLASS_NAMES.busy : void 0;
|
|
471
947
|
const inRange = isInRange(date, activeRange);
|
|
472
|
-
|
|
473
|
-
return /* @__PURE__ */ React.createElement("div", {
|
|
948
|
+
return /* @__PURE__ */ React3.createElement("div", {
|
|
474
949
|
key: i,
|
|
475
|
-
"data-date":
|
|
476
|
-
className:
|
|
950
|
+
"data-date": startOfDay3(date).toISOString(),
|
|
951
|
+
className: mx3("relative flex justify-center cursor-pointer select-none", getBgColor(date)),
|
|
477
952
|
onPointerDown: (ev) => handleDayPointerDown(date, ev),
|
|
478
953
|
onPointerEnter: () => handleDayPointerEnter(date),
|
|
479
954
|
onPointerUp: () => handleDayPointerUp(date)
|
|
480
|
-
}, inRange && /* @__PURE__ */
|
|
955
|
+
}, inRange && /* @__PURE__ */ React3.createElement("div", {
|
|
481
956
|
className: "absolute inset-0 bg-primary-500/20"
|
|
482
|
-
}), /* @__PURE__ */
|
|
483
|
-
className: "relative text-description text-sm"
|
|
484
|
-
}, date.getDate()), !border && date.getDate() === 1 && /* @__PURE__ */ React.createElement("span", {
|
|
957
|
+
}), !dateClassNames && date.getDate() === 1 && /* @__PURE__ */ React3.createElement("span", {
|
|
485
958
|
className: "absolute top-0 text-xs text-description"
|
|
486
|
-
},
|
|
487
|
-
className:
|
|
959
|
+
}, format2(date, "MMM")), /* @__PURE__ */ React3.createElement("div", {
|
|
960
|
+
className: mx3("absolute inset-1 rounded-full flex justify-center items-center text-sm text-description", dateClassNames)
|
|
961
|
+
}, date.getDate()), isCurrent && /* @__PURE__ */ React3.createElement("div", {
|
|
962
|
+
className: mx3("absolute inset-0.5 rounded-full", DATE_CLASS_NAMES.current)
|
|
488
963
|
}));
|
|
489
964
|
})));
|
|
490
965
|
}, [
|
|
@@ -492,12 +967,12 @@ var CalendarGrid = composable(({ classNames, rows, dates = [], initialDate, onSe
|
|
|
492
967
|
handleDayPointerDown,
|
|
493
968
|
handleDayPointerEnter,
|
|
494
969
|
handleDayPointerUp,
|
|
495
|
-
|
|
970
|
+
getMarker,
|
|
496
971
|
selected,
|
|
497
972
|
weekStartsOn
|
|
498
973
|
]);
|
|
499
|
-
return /* @__PURE__ */
|
|
500
|
-
...
|
|
974
|
+
return /* @__PURE__ */ React3.createElement("div", {
|
|
975
|
+
...composableProps2(props, {
|
|
501
976
|
role: "none",
|
|
502
977
|
classNames: [
|
|
503
978
|
"flex flex-col h-full w-full justify-center overflow-hidden outline-hidden",
|
|
@@ -514,18 +989,17 @@ var CalendarGrid = composable(({ classNames, rows, dates = [], initialDate, onSe
|
|
|
514
989
|
},
|
|
515
990
|
tabIndex: 0,
|
|
516
991
|
onKeyDown: handleKeyDown
|
|
517
|
-
}, /* @__PURE__ */
|
|
518
|
-
className: "grid w-full grid-cols-7",
|
|
992
|
+
}, /* @__PURE__ */ React3.createElement("div", {
|
|
519
993
|
style: {
|
|
520
994
|
width: defaultWidth
|
|
521
995
|
}
|
|
522
|
-
},
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
}
|
|
996
|
+
}, /* @__PURE__ */ React3.createElement(Weekdays, {
|
|
997
|
+
weekStartsOn,
|
|
998
|
+
columnWidth: size
|
|
999
|
+
})), /* @__PURE__ */ React3.createElement("div", {
|
|
526
1000
|
className: "flex flex-col h-full w-full justify-center overflow-hidden",
|
|
527
1001
|
ref: containerRef
|
|
528
|
-
}, /* @__PURE__ */
|
|
1002
|
+
}, /* @__PURE__ */ React3.createElement(List, {
|
|
529
1003
|
ref: listRef,
|
|
530
1004
|
role: "none",
|
|
531
1005
|
className: "scrollbar-none outline-hidden",
|
|
@@ -543,7 +1017,8 @@ CalendarGrid.displayName = CALENDAR_GRID_NAME;
|
|
|
543
1017
|
var Calendar = {
|
|
544
1018
|
Root: CalendarRoot,
|
|
545
1019
|
Toolbar: CalendarToolbar,
|
|
546
|
-
Grid: CalendarGrid
|
|
1020
|
+
Grid: CalendarGrid,
|
|
1021
|
+
Week: CalendarWeek
|
|
547
1022
|
};
|
|
548
1023
|
export {
|
|
549
1024
|
Calendar
|