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