beautify-event 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +382 -0
- package/dist/index.d.mts +217 -0
- package/dist/index.d.ts +217 -0
- package/dist/index.js +2165 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +2130 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +111 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,2165 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var React2 = require('react');
|
|
4
|
+
var clsx = require('clsx');
|
|
5
|
+
var tailwindMerge = require('tailwind-merge');
|
|
6
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
7
|
+
var lucideReact = require('lucide-react');
|
|
8
|
+
var core = require('@dnd-kit/core');
|
|
9
|
+
var dateFns = require('date-fns');
|
|
10
|
+
var locale = require('date-fns/locale');
|
|
11
|
+
var reactSlot = require('@radix-ui/react-slot');
|
|
12
|
+
var classVarianceAuthority = require('class-variance-authority');
|
|
13
|
+
var ToggleGroupPrimitive = require('@radix-ui/react-toggle-group');
|
|
14
|
+
require('@radix-ui/react-toggle');
|
|
15
|
+
|
|
16
|
+
function _interopNamespace(e) {
|
|
17
|
+
if (e && e.__esModule) return e;
|
|
18
|
+
var n = Object.create(null);
|
|
19
|
+
if (e) {
|
|
20
|
+
Object.keys(e).forEach(function (k) {
|
|
21
|
+
if (k !== 'default') {
|
|
22
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
23
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
24
|
+
enumerable: true,
|
|
25
|
+
get: function () { return e[k]; }
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
n.default = e;
|
|
31
|
+
return Object.freeze(n);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
var React2__namespace = /*#__PURE__*/_interopNamespace(React2);
|
|
35
|
+
var ToggleGroupPrimitive__namespace = /*#__PURE__*/_interopNamespace(ToggleGroupPrimitive);
|
|
36
|
+
|
|
37
|
+
var __defProp = Object.defineProperty;
|
|
38
|
+
var __defProps = Object.defineProperties;
|
|
39
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
40
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
41
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
42
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
43
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
44
|
+
var __spreadValues = (a, b) => {
|
|
45
|
+
for (var prop in b || (b = {}))
|
|
46
|
+
if (__hasOwnProp.call(b, prop))
|
|
47
|
+
__defNormalProp(a, prop, b[prop]);
|
|
48
|
+
if (__getOwnPropSymbols)
|
|
49
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
50
|
+
if (__propIsEnum.call(b, prop))
|
|
51
|
+
__defNormalProp(a, prop, b[prop]);
|
|
52
|
+
}
|
|
53
|
+
return a;
|
|
54
|
+
};
|
|
55
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
56
|
+
var __objRest = (source, exclude) => {
|
|
57
|
+
var target = {};
|
|
58
|
+
for (var prop in source)
|
|
59
|
+
if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
|
|
60
|
+
target[prop] = source[prop];
|
|
61
|
+
if (source != null && __getOwnPropSymbols)
|
|
62
|
+
for (var prop of __getOwnPropSymbols(source)) {
|
|
63
|
+
if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
|
|
64
|
+
target[prop] = source[prop];
|
|
65
|
+
}
|
|
66
|
+
return target;
|
|
67
|
+
};
|
|
68
|
+
function cn(...inputs) {
|
|
69
|
+
return tailwindMerge.twMerge(clsx.clsx(inputs));
|
|
70
|
+
}
|
|
71
|
+
function Card(_a) {
|
|
72
|
+
var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
|
|
73
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
74
|
+
"div",
|
|
75
|
+
__spreadValues({
|
|
76
|
+
"data-slot": "card",
|
|
77
|
+
className: cn(
|
|
78
|
+
"bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm",
|
|
79
|
+
className
|
|
80
|
+
)
|
|
81
|
+
}, props)
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
function Spinner(_a) {
|
|
85
|
+
var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
|
|
86
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
87
|
+
lucideReact.Loader2Icon,
|
|
88
|
+
__spreadValues({
|
|
89
|
+
role: "status",
|
|
90
|
+
"aria-label": "Loading",
|
|
91
|
+
className: cn("size-4 animate-spin", className)
|
|
92
|
+
}, props)
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
function useSystemTheme() {
|
|
96
|
+
const [systemTheme, setSystemTheme] = React2__namespace.useState("light");
|
|
97
|
+
React2__namespace.useEffect(() => {
|
|
98
|
+
const mq = window.matchMedia("(prefers-color-scheme: dark)");
|
|
99
|
+
const handler = () => setSystemTheme(mq.matches ? "dark" : "light");
|
|
100
|
+
handler();
|
|
101
|
+
mq.addEventListener("change", handler);
|
|
102
|
+
return () => mq.removeEventListener("change", handler);
|
|
103
|
+
}, []);
|
|
104
|
+
return systemTheme;
|
|
105
|
+
}
|
|
106
|
+
function normalizeThemeVars(vars) {
|
|
107
|
+
if (!vars || Object.keys(vars).length === 0) return {};
|
|
108
|
+
return Object.fromEntries(
|
|
109
|
+
Object.entries(vars).map(([key, value]) => [
|
|
110
|
+
key.startsWith("--") ? key : `--${key}`,
|
|
111
|
+
value
|
|
112
|
+
])
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
function EventCalendarThemeProvider({
|
|
116
|
+
theme = "system",
|
|
117
|
+
themeVars,
|
|
118
|
+
children
|
|
119
|
+
}) {
|
|
120
|
+
const systemTheme = useSystemTheme();
|
|
121
|
+
const resolvedTheme = theme === "system" ? systemTheme : theme;
|
|
122
|
+
const isDark = resolvedTheme === "dark";
|
|
123
|
+
const customStyle = normalizeThemeVars(themeVars);
|
|
124
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
125
|
+
"div",
|
|
126
|
+
{
|
|
127
|
+
className: `event-calendar-root ${isDark ? "dark" : ""}`,
|
|
128
|
+
"data-event-calendar-theme": resolvedTheme,
|
|
129
|
+
style: customStyle,
|
|
130
|
+
children
|
|
131
|
+
}
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
var LOCALE_MAP = {
|
|
135
|
+
en: locale.enUS,
|
|
136
|
+
"en-US": locale.enUS,
|
|
137
|
+
fr: locale.fr,
|
|
138
|
+
ar: locale.ar
|
|
139
|
+
};
|
|
140
|
+
function getDateFnsLocale(localeCode) {
|
|
141
|
+
var _a;
|
|
142
|
+
return (_a = LOCALE_MAP[localeCode]) != null ? _a : locale.enUS;
|
|
143
|
+
}
|
|
144
|
+
function formatDate(date, formatStr, localeCode = "en-US") {
|
|
145
|
+
const locale = getDateFnsLocale(localeCode);
|
|
146
|
+
return dateFns.format(date, formatStr, { locale });
|
|
147
|
+
}
|
|
148
|
+
function getMonthDays(date, weekStartsOn = 0) {
|
|
149
|
+
const start = dateFns.startOfWeek(dateFns.startOfMonth(date), { weekStartsOn });
|
|
150
|
+
const end = dateFns.endOfWeek(dateFns.endOfMonth(date), { weekStartsOn });
|
|
151
|
+
return dateFns.eachDayOfInterval({ start, end });
|
|
152
|
+
}
|
|
153
|
+
function getWeekDays(date, weekStartsOn = 0) {
|
|
154
|
+
const start = dateFns.startOfWeek(date, { weekStartsOn });
|
|
155
|
+
const end = dateFns.endOfWeek(date, { weekStartsOn });
|
|
156
|
+
return dateFns.eachDayOfInterval({ start, end });
|
|
157
|
+
}
|
|
158
|
+
function getTwoDays(date, _weekStartsOn = 0) {
|
|
159
|
+
const start = dateFns.startOfDay(date);
|
|
160
|
+
return [start, dateFns.addDays(start, 1)];
|
|
161
|
+
}
|
|
162
|
+
function getEventsForDay(events, day) {
|
|
163
|
+
return events.filter((event) => {
|
|
164
|
+
const eventStart = dateFns.startOfDay(event.start);
|
|
165
|
+
const eventEnd = dateFns.endOfDay(event.end);
|
|
166
|
+
return dateFns.isWithinInterval(day, { start: eventStart, end: eventEnd }) || dateFns.isSameDay(event.start, day) || dateFns.isSameDay(event.end, day);
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
function navigateDate(date, view, direction) {
|
|
170
|
+
switch (view) {
|
|
171
|
+
case "month":
|
|
172
|
+
return direction === "next" ? dateFns.addMonths(date, 1) : dateFns.subMonths(date, 1);
|
|
173
|
+
case "week":
|
|
174
|
+
case "resource":
|
|
175
|
+
return direction === "next" ? dateFns.addWeeks(date, 1) : dateFns.subWeeks(date, 1);
|
|
176
|
+
case "day":
|
|
177
|
+
return direction === "next" ? dateFns.addDays(date, 1) : dateFns.subDays(date, 1);
|
|
178
|
+
case "2day":
|
|
179
|
+
return direction === "next" ? dateFns.addDays(date, 2) : dateFns.subDays(date, 2);
|
|
180
|
+
default:
|
|
181
|
+
return date;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
function getViewTitle(date, view, weekStartsOn = 0, localeCode = "en-US") {
|
|
185
|
+
const locale = getDateFnsLocale(localeCode);
|
|
186
|
+
const fmt = (d, str) => dateFns.format(d, str, { locale });
|
|
187
|
+
switch (view) {
|
|
188
|
+
case "month":
|
|
189
|
+
return fmt(date, "MMMM yyyy");
|
|
190
|
+
case "week":
|
|
191
|
+
case "resource": {
|
|
192
|
+
const weekStart = dateFns.startOfWeek(date, { weekStartsOn });
|
|
193
|
+
const weekEnd = dateFns.endOfWeek(date, { weekStartsOn });
|
|
194
|
+
return `${fmt(weekStart, "MMM d")} - ${fmt(weekEnd, "MMM d, yyyy")}`;
|
|
195
|
+
}
|
|
196
|
+
case "day":
|
|
197
|
+
return fmt(date, "EEEE, MMMM d, yyyy");
|
|
198
|
+
case "2day": {
|
|
199
|
+
const days = getTwoDays(date, weekStartsOn);
|
|
200
|
+
return `${fmt(days[0], "MMM d")} \u2013 ${fmt(days[1], "MMM d, yyyy")}`;
|
|
201
|
+
}
|
|
202
|
+
default:
|
|
203
|
+
return fmt(date, "MMMM yyyy");
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
function getViewDateRange(date, view, weekStartsOn = 0) {
|
|
207
|
+
switch (view) {
|
|
208
|
+
case "month":
|
|
209
|
+
return {
|
|
210
|
+
start: dateFns.startOfWeek(dateFns.startOfMonth(date), { weekStartsOn }),
|
|
211
|
+
end: dateFns.endOfWeek(dateFns.endOfMonth(date), { weekStartsOn })
|
|
212
|
+
};
|
|
213
|
+
case "week":
|
|
214
|
+
case "resource":
|
|
215
|
+
return {
|
|
216
|
+
start: dateFns.startOfWeek(date, { weekStartsOn }),
|
|
217
|
+
end: dateFns.endOfWeek(date, { weekStartsOn })
|
|
218
|
+
};
|
|
219
|
+
case "day":
|
|
220
|
+
return {
|
|
221
|
+
start: dateFns.startOfDay(date),
|
|
222
|
+
end: dateFns.endOfDay(date)
|
|
223
|
+
};
|
|
224
|
+
case "2day": {
|
|
225
|
+
const days = getTwoDays(date, weekStartsOn);
|
|
226
|
+
return {
|
|
227
|
+
start: dateFns.startOfDay(days[0]),
|
|
228
|
+
end: dateFns.endOfDay(days[1])
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
default:
|
|
232
|
+
return {
|
|
233
|
+
start: dateFns.startOfMonth(date),
|
|
234
|
+
end: dateFns.endOfMonth(date)
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
function getEventPosition(event, hourHeight = 64, startHour = 0) {
|
|
239
|
+
const eventStartHour = dateFns.getHours(event.start);
|
|
240
|
+
const eventStartMinutes = dateFns.getMinutes(event.start);
|
|
241
|
+
const startMinutes = (eventStartHour - startHour) * 60 + eventStartMinutes;
|
|
242
|
+
const duration = dateFns.differenceInMinutes(event.end, event.start);
|
|
243
|
+
const top = startMinutes / 60 * hourHeight;
|
|
244
|
+
const height = Math.max(duration / 60 * hourHeight, 24);
|
|
245
|
+
return { top: Math.max(top, 0), height };
|
|
246
|
+
}
|
|
247
|
+
function createSlotDate(day, hour, minute = 0) {
|
|
248
|
+
return dateFns.setMinutes(dateFns.setHours(day, hour), minute);
|
|
249
|
+
}
|
|
250
|
+
function getWeekdayNames(weekStartsOn = 0, short = true, localeCode = "en-US") {
|
|
251
|
+
const locale = getDateFnsLocale(localeCode);
|
|
252
|
+
const baseDate = new Date(2024, 0, 7);
|
|
253
|
+
const days = [];
|
|
254
|
+
for (let i = 0; i < 7; i++) {
|
|
255
|
+
const dayIndex = (weekStartsOn + i) % 7;
|
|
256
|
+
const date = dateFns.addDays(baseDate, dayIndex);
|
|
257
|
+
days.push(dateFns.format(date, short ? "EEE" : "EEEE", { locale }));
|
|
258
|
+
}
|
|
259
|
+
return days;
|
|
260
|
+
}
|
|
261
|
+
function getHoursArray(startHour = 0, endHour = 24) {
|
|
262
|
+
const hours = [];
|
|
263
|
+
for (let i = startHour; i < endHour; i++) {
|
|
264
|
+
hours.push(i);
|
|
265
|
+
}
|
|
266
|
+
return hours;
|
|
267
|
+
}
|
|
268
|
+
function getCurrentTimeLineTop(now, startHour, endHour, hourHeight, topPadding = 16) {
|
|
269
|
+
const currentHour = dateFns.getHours(now);
|
|
270
|
+
const currentMinute = dateFns.getMinutes(now);
|
|
271
|
+
const currentTimeInHours = currentHour + currentMinute / 60;
|
|
272
|
+
if (currentTimeInHours < startHour || currentTimeInHours >= endHour) return null;
|
|
273
|
+
const top = topPadding + (currentTimeInHours - startHour) * hourHeight;
|
|
274
|
+
return top;
|
|
275
|
+
}
|
|
276
|
+
function formatHour(hour, timeFormat = "12h", localeCode = "en-US") {
|
|
277
|
+
if (timeFormat === "24h") {
|
|
278
|
+
return `${hour.toString().padStart(2, "0")}:00`;
|
|
279
|
+
}
|
|
280
|
+
const locale = getDateFnsLocale(localeCode);
|
|
281
|
+
const d = new Date(2e3, 0, 1, hour, 0, 0);
|
|
282
|
+
return dateFns.format(d, "h a", { locale });
|
|
283
|
+
}
|
|
284
|
+
var defaultConfig = {
|
|
285
|
+
weekStartsOn: 0,
|
|
286
|
+
startHour: 0,
|
|
287
|
+
// 12:00 AM - full day start
|
|
288
|
+
endHour: 24,
|
|
289
|
+
// 11:59 PM - full day end
|
|
290
|
+
hourHeight: 64,
|
|
291
|
+
timeSeriesMaxHeight: 400,
|
|
292
|
+
showCurrentTimeLine: true,
|
|
293
|
+
maxEventsPerDay: 3,
|
|
294
|
+
defaultEventColor: "#3b82f6",
|
|
295
|
+
defaultResourceColor: "#6366f1",
|
|
296
|
+
locale: "en-US",
|
|
297
|
+
timeFormat: "12h"
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
// components/event-calendar/dnd/helpers.ts
|
|
301
|
+
function slotDataToSlotInfo(data, endHour) {
|
|
302
|
+
switch (data.view) {
|
|
303
|
+
case "day":
|
|
304
|
+
case "week": {
|
|
305
|
+
const start = createSlotDate(data.day, data.hour);
|
|
306
|
+
const end = createSlotDate(data.day, data.hour + 1);
|
|
307
|
+
return { start, end };
|
|
308
|
+
}
|
|
309
|
+
case "month": {
|
|
310
|
+
const start = dateFns.startOfDay(data.day);
|
|
311
|
+
const end = dateFns.endOfDay(data.day);
|
|
312
|
+
return { start, end };
|
|
313
|
+
}
|
|
314
|
+
case "resource": {
|
|
315
|
+
const start = createSlotDate(data.day, data.hour);
|
|
316
|
+
const end = createSlotDate(data.day, data.hour + 1);
|
|
317
|
+
return { start, end, resourceId: data.resourceId };
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
function computeCreateSlotInfo(from, to) {
|
|
322
|
+
if (from.view === "month" && to.view === "month") {
|
|
323
|
+
const start = dateFns.startOfDay(to.day);
|
|
324
|
+
const end = dateFns.endOfDay(to.day);
|
|
325
|
+
return { start, end };
|
|
326
|
+
}
|
|
327
|
+
if ((from.view === "day" || from.view === "week") && (to.view === "day" || to.view === "week")) {
|
|
328
|
+
const startDate = from.day.getTime() < to.day.getTime() ? from.day : to.day;
|
|
329
|
+
const endDate = from.day.getTime() < to.day.getTime() ? to.day : from.day;
|
|
330
|
+
const startHour = from.day.getTime() === startDate.getTime() ? from.hour : to.hour;
|
|
331
|
+
const endHour = from.day.getTime() === endDate.getTime() ? from.hour : to.hour;
|
|
332
|
+
const start = createSlotDate(startDate, Math.min(startHour, endHour));
|
|
333
|
+
const end = createSlotDate(endDate, Math.max(startHour, endHour) + 1);
|
|
334
|
+
return { start, end };
|
|
335
|
+
}
|
|
336
|
+
if (from.view === "resource" && to.view === "resource" && from.resourceId === to.resourceId) {
|
|
337
|
+
const startDate = from.day.getTime() < to.day.getTime() ? from.day : to.day;
|
|
338
|
+
const endDate = from.day.getTime() < to.day.getTime() ? to.day : from.day;
|
|
339
|
+
const startHour = from.day.getTime() === startDate.getTime() ? from.hour : to.hour;
|
|
340
|
+
const endHour = from.day.getTime() === endDate.getTime() ? from.hour : to.hour;
|
|
341
|
+
const start = createSlotDate(startDate, Math.min(startHour, endHour));
|
|
342
|
+
const end = createSlotDate(endDate, Math.max(startHour, endHour) + 1);
|
|
343
|
+
return { start, end, resourceId: from.resourceId };
|
|
344
|
+
}
|
|
345
|
+
return slotDataToSlotInfo(to);
|
|
346
|
+
}
|
|
347
|
+
function computeMoveEvent(event, dropData) {
|
|
348
|
+
const duration = dateFns.differenceInMinutes(event.end, event.start);
|
|
349
|
+
switch (dropData.view) {
|
|
350
|
+
case "day":
|
|
351
|
+
case "week": {
|
|
352
|
+
const newStart = createSlotDate(dropData.day, dropData.hour);
|
|
353
|
+
const newEnd = dateFns.addMinutes(newStart, duration);
|
|
354
|
+
return { newStart, newEnd };
|
|
355
|
+
}
|
|
356
|
+
case "month": {
|
|
357
|
+
const newStart = dateFns.setMinutes(
|
|
358
|
+
dateFns.setHours(dropData.day, event.start.getHours()),
|
|
359
|
+
event.start.getMinutes()
|
|
360
|
+
);
|
|
361
|
+
const newEnd = dateFns.addMinutes(newStart, duration);
|
|
362
|
+
return { newStart, newEnd };
|
|
363
|
+
}
|
|
364
|
+
case "resource": {
|
|
365
|
+
const newStart = createSlotDate(dropData.day, dropData.hour);
|
|
366
|
+
const newEnd = dateFns.addMinutes(newStart, duration);
|
|
367
|
+
return { newStart, newEnd, resourceId: dropData.resourceId };
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
function CalendarDragOverlay({
|
|
372
|
+
activeEvent,
|
|
373
|
+
activeCreateSlotInfo,
|
|
374
|
+
defaultEventColor,
|
|
375
|
+
locale = "en-US",
|
|
376
|
+
renderEvent
|
|
377
|
+
}) {
|
|
378
|
+
return /* @__PURE__ */ jsxRuntime.jsx(core.DragOverlay, { dropAnimation: null, children: activeEvent ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-lg border border-border bg-card px-3 py-2 shadow-lg opacity-90", children: renderEvent ? renderEvent(activeEvent, "day") : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
379
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
380
|
+
"div",
|
|
381
|
+
{
|
|
382
|
+
className: "font-semibold text-sm",
|
|
383
|
+
style: {
|
|
384
|
+
color: activeEvent.color || defaultEventColor
|
|
385
|
+
},
|
|
386
|
+
children: activeEvent.title
|
|
387
|
+
}
|
|
388
|
+
),
|
|
389
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs text-muted-foreground mt-0.5", children: [
|
|
390
|
+
formatDate(activeEvent.start, "h:mm a", locale),
|
|
391
|
+
" -",
|
|
392
|
+
" ",
|
|
393
|
+
formatDate(activeEvent.end, "h:mm a", locale)
|
|
394
|
+
] })
|
|
395
|
+
] }) }) : activeCreateSlotInfo ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-lg border-2 border-dashed border-primary/50 bg-primary/10 px-3 py-2 shadow-lg", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-sm font-medium text-primary", children: [
|
|
396
|
+
formatDate(activeCreateSlotInfo.start, "h:mm a", locale),
|
|
397
|
+
" -",
|
|
398
|
+
" ",
|
|
399
|
+
formatDate(activeCreateSlotInfo.end, "h:mm a", locale)
|
|
400
|
+
] }) }) : null });
|
|
401
|
+
}
|
|
402
|
+
function EventCalendarDndProvider({
|
|
403
|
+
enableDragToCreate = false,
|
|
404
|
+
enableDragToMove = false,
|
|
405
|
+
onEventCreate,
|
|
406
|
+
onEventMove,
|
|
407
|
+
defaultEventColor,
|
|
408
|
+
locale = "en-US",
|
|
409
|
+
renderEvent,
|
|
410
|
+
children
|
|
411
|
+
}) {
|
|
412
|
+
const [activeEvent, setActiveEvent] = React2__namespace.useState(null);
|
|
413
|
+
const [activeCreateSlotInfo, setActiveCreateSlotInfo] = React2__namespace.useState(null);
|
|
414
|
+
const handleDragStart = React2__namespace.useCallback(
|
|
415
|
+
(event) => {
|
|
416
|
+
const data = event.active.data.current;
|
|
417
|
+
if (!data) return;
|
|
418
|
+
if (typeof data !== "object" || data === null) return;
|
|
419
|
+
if ("event" in data && data.event) {
|
|
420
|
+
setActiveEvent(data.event);
|
|
421
|
+
} else if ("slotData" in data && data.slotData) {
|
|
422
|
+
const slotData = data.slotData;
|
|
423
|
+
const info = slotDataToSlotInfo(slotData);
|
|
424
|
+
setActiveCreateSlotInfo({ start: info.start, end: info.end });
|
|
425
|
+
}
|
|
426
|
+
},
|
|
427
|
+
[]
|
|
428
|
+
);
|
|
429
|
+
const handleDragEnd = React2__namespace.useCallback(
|
|
430
|
+
(event) => {
|
|
431
|
+
var _a;
|
|
432
|
+
const activeData = event.active.data.current;
|
|
433
|
+
const overData = (_a = event.over) == null ? void 0 : _a.data.current;
|
|
434
|
+
setActiveEvent(null);
|
|
435
|
+
setActiveCreateSlotInfo(null);
|
|
436
|
+
if (!overData || typeof overData !== "object") return;
|
|
437
|
+
const overSlot = overData;
|
|
438
|
+
if (activeData && typeof activeData === "object" && "event" in activeData && enableDragToMove && onEventMove) {
|
|
439
|
+
const eventData = activeData.event;
|
|
440
|
+
const { newStart, newEnd, resourceId } = computeMoveEvent(
|
|
441
|
+
eventData,
|
|
442
|
+
overSlot
|
|
443
|
+
);
|
|
444
|
+
onEventMove({ event: eventData, newStart, newEnd, resourceId });
|
|
445
|
+
} else if (activeData && typeof activeData === "object" && "slotData" in activeData && enableDragToCreate && onEventCreate) {
|
|
446
|
+
const fromSlot = activeData.slotData;
|
|
447
|
+
const slotInfo = computeCreateSlotInfo(fromSlot, overSlot);
|
|
448
|
+
onEventCreate(slotInfo);
|
|
449
|
+
}
|
|
450
|
+
},
|
|
451
|
+
[enableDragToCreate, enableDragToMove, onEventCreate, onEventMove]
|
|
452
|
+
);
|
|
453
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
454
|
+
core.DndContext,
|
|
455
|
+
{
|
|
456
|
+
onDragStart: handleDragStart,
|
|
457
|
+
onDragEnd: handleDragEnd,
|
|
458
|
+
collisionDetection: core.pointerWithin,
|
|
459
|
+
children: [
|
|
460
|
+
children,
|
|
461
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
462
|
+
CalendarDragOverlay,
|
|
463
|
+
{
|
|
464
|
+
activeEvent,
|
|
465
|
+
activeCreateSlotInfo,
|
|
466
|
+
defaultEventColor,
|
|
467
|
+
locale,
|
|
468
|
+
renderEvent
|
|
469
|
+
}
|
|
470
|
+
)
|
|
471
|
+
]
|
|
472
|
+
}
|
|
473
|
+
);
|
|
474
|
+
}
|
|
475
|
+
var BREAKPOINTS = {
|
|
476
|
+
sm: 640,
|
|
477
|
+
md: 768,
|
|
478
|
+
lg: 1024
|
|
479
|
+
};
|
|
480
|
+
function useMediaQuery(breakpoint) {
|
|
481
|
+
const query = `(max-width: ${BREAKPOINTS[breakpoint] - 1}px)`;
|
|
482
|
+
const [matches, setMatches] = React2.useState(false);
|
|
483
|
+
React2.useEffect(() => {
|
|
484
|
+
if (typeof window === "undefined") return;
|
|
485
|
+
const media = window.matchMedia(query);
|
|
486
|
+
setMatches(media.matches);
|
|
487
|
+
const listener = (e) => setMatches(e.matches);
|
|
488
|
+
media.addEventListener("change", listener);
|
|
489
|
+
return () => media.removeEventListener("change", listener);
|
|
490
|
+
}, [query]);
|
|
491
|
+
return matches;
|
|
492
|
+
}
|
|
493
|
+
var CalendarContext = React2.createContext(null);
|
|
494
|
+
function useCalendar() {
|
|
495
|
+
const context = React2.useContext(CalendarContext);
|
|
496
|
+
if (!context) {
|
|
497
|
+
throw new Error("useCalendar must be used within an EventCalendar");
|
|
498
|
+
}
|
|
499
|
+
return context;
|
|
500
|
+
}
|
|
501
|
+
function CalendarProvider({
|
|
502
|
+
children,
|
|
503
|
+
value
|
|
504
|
+
}) {
|
|
505
|
+
return /* @__PURE__ */ jsxRuntime.jsx(CalendarContext.Provider, { value, children });
|
|
506
|
+
}
|
|
507
|
+
var buttonVariants = classVarianceAuthority.cva(
|
|
508
|
+
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
|
|
509
|
+
{
|
|
510
|
+
variants: {
|
|
511
|
+
variant: {
|
|
512
|
+
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
|
513
|
+
outline: "border border-input bg-background shadow-xs hover:bg-accent hover:text-accent-foreground",
|
|
514
|
+
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
515
|
+
ghost: "hover:bg-accent hover:text-accent-foreground"
|
|
516
|
+
},
|
|
517
|
+
size: {
|
|
518
|
+
default: "h-9 px-4 py-2 has-[>svg]:px-3",
|
|
519
|
+
sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
|
|
520
|
+
icon: "size-9",
|
|
521
|
+
"icon-sm": "size-8"
|
|
522
|
+
}
|
|
523
|
+
},
|
|
524
|
+
defaultVariants: {
|
|
525
|
+
variant: "outline",
|
|
526
|
+
size: "default"
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
);
|
|
530
|
+
function Button(_a) {
|
|
531
|
+
var _b = _a, {
|
|
532
|
+
className,
|
|
533
|
+
variant,
|
|
534
|
+
size,
|
|
535
|
+
asChild = false
|
|
536
|
+
} = _b, props = __objRest(_b, [
|
|
537
|
+
"className",
|
|
538
|
+
"variant",
|
|
539
|
+
"size",
|
|
540
|
+
"asChild"
|
|
541
|
+
]);
|
|
542
|
+
const Comp = asChild ? reactSlot.Slot : "button";
|
|
543
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
544
|
+
Comp,
|
|
545
|
+
__spreadValues({
|
|
546
|
+
"data-slot": "button",
|
|
547
|
+
className: cn(buttonVariants({ variant, size, className }))
|
|
548
|
+
}, props)
|
|
549
|
+
);
|
|
550
|
+
}
|
|
551
|
+
var toggleVariants = classVarianceAuthority.cva(
|
|
552
|
+
"inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium hover:bg-muted hover:text-muted-foreground disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] outline-none transition-[color,box-shadow] whitespace-nowrap",
|
|
553
|
+
{
|
|
554
|
+
variants: {
|
|
555
|
+
variant: {
|
|
556
|
+
default: "bg-transparent",
|
|
557
|
+
outline: "border border-input bg-transparent shadow-xs hover:bg-accent hover:text-accent-foreground"
|
|
558
|
+
},
|
|
559
|
+
size: {
|
|
560
|
+
default: "h-9 px-2 min-w-9",
|
|
561
|
+
sm: "h-8 px-1.5 min-w-8"
|
|
562
|
+
}
|
|
563
|
+
},
|
|
564
|
+
defaultVariants: {
|
|
565
|
+
variant: "default",
|
|
566
|
+
size: "default"
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
);
|
|
570
|
+
var ToggleGroupContext = React2__namespace.createContext({
|
|
571
|
+
size: "default",
|
|
572
|
+
variant: "default"
|
|
573
|
+
});
|
|
574
|
+
function ToggleGroup(_a) {
|
|
575
|
+
var _b = _a, {
|
|
576
|
+
className,
|
|
577
|
+
variant,
|
|
578
|
+
size,
|
|
579
|
+
children
|
|
580
|
+
} = _b, props = __objRest(_b, [
|
|
581
|
+
"className",
|
|
582
|
+
"variant",
|
|
583
|
+
"size",
|
|
584
|
+
"children"
|
|
585
|
+
]);
|
|
586
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
587
|
+
ToggleGroupPrimitive__namespace.Root,
|
|
588
|
+
__spreadProps(__spreadValues({
|
|
589
|
+
"data-slot": "toggle-group",
|
|
590
|
+
"data-variant": variant,
|
|
591
|
+
"data-size": size,
|
|
592
|
+
className: cn(
|
|
593
|
+
"group/toggle-group flex w-fit items-center rounded-md data-[variant=outline]:shadow-xs",
|
|
594
|
+
className
|
|
595
|
+
)
|
|
596
|
+
}, props), {
|
|
597
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ToggleGroupContext.Provider, { value: { variant, size }, children })
|
|
598
|
+
})
|
|
599
|
+
);
|
|
600
|
+
}
|
|
601
|
+
function ToggleGroupItem(_a) {
|
|
602
|
+
var _b = _a, {
|
|
603
|
+
className,
|
|
604
|
+
children,
|
|
605
|
+
variant,
|
|
606
|
+
size
|
|
607
|
+
} = _b, props = __objRest(_b, [
|
|
608
|
+
"className",
|
|
609
|
+
"children",
|
|
610
|
+
"variant",
|
|
611
|
+
"size"
|
|
612
|
+
]);
|
|
613
|
+
var _a2, _b2, _c, _d;
|
|
614
|
+
const context = React2__namespace.useContext(ToggleGroupContext);
|
|
615
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
616
|
+
ToggleGroupPrimitive__namespace.Item,
|
|
617
|
+
__spreadProps(__spreadValues({
|
|
618
|
+
"data-slot": "toggle-group-item",
|
|
619
|
+
"data-variant": (_a2 = context.variant) != null ? _a2 : variant,
|
|
620
|
+
"data-size": (_b2 = context.size) != null ? _b2 : size,
|
|
621
|
+
className: cn(
|
|
622
|
+
toggleVariants({
|
|
623
|
+
variant: (_c = context.variant) != null ? _c : variant,
|
|
624
|
+
size: (_d = context.size) != null ? _d : size
|
|
625
|
+
}),
|
|
626
|
+
"min-w-0 flex-1 shrink-0 rounded-none shadow-none first:rounded-l-md last:rounded-r-md focus:z-10 focus-visible:z-10 data-[variant=outline]:border-l-0 data-[variant=outline]:first:border-l",
|
|
627
|
+
className
|
|
628
|
+
)
|
|
629
|
+
}, props), {
|
|
630
|
+
children
|
|
631
|
+
})
|
|
632
|
+
);
|
|
633
|
+
}
|
|
634
|
+
function MobileWeekStrip({
|
|
635
|
+
selectedDate,
|
|
636
|
+
onDaySelect,
|
|
637
|
+
onPrevWeek,
|
|
638
|
+
onNextWeek,
|
|
639
|
+
weekStartsOn = 0,
|
|
640
|
+
locale = "en-US",
|
|
641
|
+
className
|
|
642
|
+
}) {
|
|
643
|
+
const days = getWeekDays(selectedDate, weekStartsOn);
|
|
644
|
+
const today = /* @__PURE__ */ new Date();
|
|
645
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex items-center gap-0.5", className), children: [
|
|
646
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
647
|
+
Button,
|
|
648
|
+
{
|
|
649
|
+
variant: "ghost",
|
|
650
|
+
size: "icon",
|
|
651
|
+
onClick: onPrevWeek,
|
|
652
|
+
className: "h-7 w-7 shrink-0",
|
|
653
|
+
"aria-label": "Previous week",
|
|
654
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronLeft, { className: "h-4 w-4" })
|
|
655
|
+
}
|
|
656
|
+
),
|
|
657
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-1 justify-between gap-0 min-w-0 overflow-visible", children: days.map((day) => {
|
|
658
|
+
const isToday = dateFns.isSameDay(day, today);
|
|
659
|
+
const isSelected = dateFns.isSameDay(day, selectedDate);
|
|
660
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
661
|
+
"button",
|
|
662
|
+
{
|
|
663
|
+
type: "button",
|
|
664
|
+
onClick: () => onDaySelect(day),
|
|
665
|
+
className: cn(
|
|
666
|
+
"flex flex-col items-center justify-center min-w-[32px] flex-1 py-1 px-0.5 text-[11px] font-medium transition-colors overflow-visible",
|
|
667
|
+
!isToday && !isSelected && "text-muted-foreground hover:text-foreground",
|
|
668
|
+
isToday && !isSelected && "text-primary font-semibold",
|
|
669
|
+
isSelected && "text-primary-foreground font-semibold"
|
|
670
|
+
),
|
|
671
|
+
children: [
|
|
672
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
673
|
+
"span",
|
|
674
|
+
{
|
|
675
|
+
className: cn(
|
|
676
|
+
"text-[9px] uppercase leading-tight",
|
|
677
|
+
isSelected ? "text-primary-foreground" : "text-inherit opacity-80"
|
|
678
|
+
),
|
|
679
|
+
children: formatDate(day, "EEE", locale)
|
|
680
|
+
}
|
|
681
|
+
),
|
|
682
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
683
|
+
"span",
|
|
684
|
+
{
|
|
685
|
+
className: cn(
|
|
686
|
+
"mt-0.5 w-6 h-6 shrink-0 flex items-center justify-center rounded-full text-[11px] font-semibold tabular-nums",
|
|
687
|
+
isSelected && "bg-primary text-primary-foreground",
|
|
688
|
+
isToday && !isSelected && "bg-primary/15 text-primary",
|
|
689
|
+
!isSelected && !isToday && "text-foreground"
|
|
690
|
+
),
|
|
691
|
+
children: formatDate(day, "d", locale)
|
|
692
|
+
}
|
|
693
|
+
)
|
|
694
|
+
]
|
|
695
|
+
},
|
|
696
|
+
day.toISOString()
|
|
697
|
+
);
|
|
698
|
+
}) }),
|
|
699
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
700
|
+
Button,
|
|
701
|
+
{
|
|
702
|
+
variant: "ghost",
|
|
703
|
+
size: "icon",
|
|
704
|
+
onClick: onNextWeek,
|
|
705
|
+
className: "h-7 w-7 shrink-0",
|
|
706
|
+
"aria-label": "Next week",
|
|
707
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "h-4 w-4" })
|
|
708
|
+
}
|
|
709
|
+
)
|
|
710
|
+
] });
|
|
711
|
+
}
|
|
712
|
+
function MobileMonthPicker({
|
|
713
|
+
selectedDate,
|
|
714
|
+
onDaySelect,
|
|
715
|
+
weekStartsOn = 0,
|
|
716
|
+
locale = "en-US",
|
|
717
|
+
className
|
|
718
|
+
}) {
|
|
719
|
+
const [viewMonth, setViewMonth] = React2.useState(() => dateFns.startOfMonth(selectedDate));
|
|
720
|
+
React2.useEffect(() => {
|
|
721
|
+
setViewMonth((prev) => {
|
|
722
|
+
const target = dateFns.startOfMonth(selectedDate);
|
|
723
|
+
return dateFns.isSameMonth(prev, target) ? prev : target;
|
|
724
|
+
});
|
|
725
|
+
}, [selectedDate]);
|
|
726
|
+
const days = getMonthDays(viewMonth, weekStartsOn);
|
|
727
|
+
const weekdays = getWeekdayNames(weekStartsOn, true, locale);
|
|
728
|
+
const today = /* @__PURE__ */ new Date();
|
|
729
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col gap-2", className), children: [
|
|
730
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-1", children: [
|
|
731
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
732
|
+
Button,
|
|
733
|
+
{
|
|
734
|
+
variant: "ghost",
|
|
735
|
+
size: "icon",
|
|
736
|
+
onClick: () => setViewMonth((m) => dateFns.subMonths(m, 1)),
|
|
737
|
+
className: "h-8 w-8 shrink-0",
|
|
738
|
+
"aria-label": "Previous month",
|
|
739
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronLeft, { className: "h-4 w-4" })
|
|
740
|
+
}
|
|
741
|
+
),
|
|
742
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium text-foreground", children: formatDate(viewMonth, "MMMM yyyy", locale) }),
|
|
743
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
744
|
+
Button,
|
|
745
|
+
{
|
|
746
|
+
variant: "ghost",
|
|
747
|
+
size: "icon",
|
|
748
|
+
onClick: () => setViewMonth((m) => dateFns.addMonths(m, 1)),
|
|
749
|
+
className: "h-8 w-8 shrink-0",
|
|
750
|
+
"aria-label": "Next month",
|
|
751
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "h-4 w-4" })
|
|
752
|
+
}
|
|
753
|
+
)
|
|
754
|
+
] }),
|
|
755
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-7 gap-0.5", children: weekdays.map((day) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
756
|
+
"div",
|
|
757
|
+
{
|
|
758
|
+
className: "py-1 text-center text-[10px] font-medium text-muted-foreground uppercase",
|
|
759
|
+
children: day
|
|
760
|
+
},
|
|
761
|
+
day
|
|
762
|
+
)) }),
|
|
763
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-7 gap-0.5", children: days.map((day) => {
|
|
764
|
+
const isCurrentMonth = dateFns.isSameMonth(day, viewMonth);
|
|
765
|
+
const isToday = dateFns.isSameDay(day, today);
|
|
766
|
+
const isSelected = dateFns.isSameDay(day, selectedDate);
|
|
767
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
768
|
+
"button",
|
|
769
|
+
{
|
|
770
|
+
type: "button",
|
|
771
|
+
onClick: () => onDaySelect(day),
|
|
772
|
+
className: cn(
|
|
773
|
+
"aspect-square flex items-center justify-center rounded-full text-xs font-medium transition-colors",
|
|
774
|
+
!isCurrentMonth && "text-muted-foreground/50",
|
|
775
|
+
isCurrentMonth && !isToday && !isSelected && "text-foreground hover:bg-muted",
|
|
776
|
+
isToday && !isSelected && "bg-primary/20 text-primary font-semibold",
|
|
777
|
+
isSelected && "bg-primary text-primary-foreground font-semibold"
|
|
778
|
+
),
|
|
779
|
+
children: formatDate(day, "d", locale)
|
|
780
|
+
},
|
|
781
|
+
day.toISOString()
|
|
782
|
+
);
|
|
783
|
+
}) })
|
|
784
|
+
] });
|
|
785
|
+
}
|
|
786
|
+
var VIEW_LABELS = {
|
|
787
|
+
month: "Month",
|
|
788
|
+
week: "Week",
|
|
789
|
+
day: "Day",
|
|
790
|
+
"2day": "2 Day",
|
|
791
|
+
resource: "Resource"
|
|
792
|
+
};
|
|
793
|
+
function CalendarHeader({
|
|
794
|
+
currentDate,
|
|
795
|
+
view,
|
|
796
|
+
views,
|
|
797
|
+
title,
|
|
798
|
+
showNavigation = true,
|
|
799
|
+
showViewSwitcher = true,
|
|
800
|
+
showTodayButton = true,
|
|
801
|
+
isMobile = false,
|
|
802
|
+
showMobileMonthPicker = true,
|
|
803
|
+
weekStartsOn = 0,
|
|
804
|
+
locale = "en-US",
|
|
805
|
+
onNavigate,
|
|
806
|
+
onViewChange,
|
|
807
|
+
onToday,
|
|
808
|
+
onDateSelect,
|
|
809
|
+
onWeekNavigate,
|
|
810
|
+
renderHeader
|
|
811
|
+
}) {
|
|
812
|
+
const [monthPickerExpanded, setMonthPickerExpanded] = React2.useState(false);
|
|
813
|
+
if (renderHeader) {
|
|
814
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: renderHeader({
|
|
815
|
+
date: currentDate,
|
|
816
|
+
view,
|
|
817
|
+
views,
|
|
818
|
+
title,
|
|
819
|
+
onNavigate,
|
|
820
|
+
onViewChange,
|
|
821
|
+
onToday
|
|
822
|
+
}) });
|
|
823
|
+
}
|
|
824
|
+
if (isMobile) {
|
|
825
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
826
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 min-w-0", children: [
|
|
827
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Calendar, { className: "h-4 w-4 text-primary shrink-0" }),
|
|
828
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-0.5 flex-1 min-w-0", children: [
|
|
829
|
+
showMobileMonthPicker && onDateSelect && onWeekNavigate ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
830
|
+
"button",
|
|
831
|
+
{
|
|
832
|
+
type: "button",
|
|
833
|
+
onClick: () => setMonthPickerExpanded((v) => !v),
|
|
834
|
+
className: "text-base font-semibold text-foreground truncate text-left hover:underline",
|
|
835
|
+
children: title
|
|
836
|
+
}
|
|
837
|
+
) : /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-base font-semibold text-foreground truncate", children: title }),
|
|
838
|
+
showMobileMonthPicker && onDateSelect && onWeekNavigate && /* @__PURE__ */ jsxRuntime.jsx(
|
|
839
|
+
Button,
|
|
840
|
+
{
|
|
841
|
+
variant: "ghost",
|
|
842
|
+
size: "icon",
|
|
843
|
+
onClick: () => setMonthPickerExpanded((v) => !v),
|
|
844
|
+
className: "h-7 w-7 shrink-0",
|
|
845
|
+
"aria-expanded": monthPickerExpanded,
|
|
846
|
+
"aria-label": monthPickerExpanded ? "Collapse month view" : "Expand month view",
|
|
847
|
+
children: monthPickerExpanded ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronUp, { className: "h-4 w-4 text-muted-foreground" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "h-4 w-4 text-muted-foreground" })
|
|
848
|
+
}
|
|
849
|
+
)
|
|
850
|
+
] })
|
|
851
|
+
] }),
|
|
852
|
+
showMobileMonthPicker && onDateSelect && onWeekNavigate && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col overflow-hidden", children: [
|
|
853
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
854
|
+
"div",
|
|
855
|
+
{
|
|
856
|
+
className: cn(
|
|
857
|
+
"flex items-center rounded-lg px-1.5 py-1 bg-muted/30",
|
|
858
|
+
monthPickerExpanded && "rounded-b-none"
|
|
859
|
+
),
|
|
860
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-w-0", children: !monthPickerExpanded && /* @__PURE__ */ jsxRuntime.jsx(
|
|
861
|
+
MobileWeekStrip,
|
|
862
|
+
{
|
|
863
|
+
selectedDate: currentDate,
|
|
864
|
+
onDaySelect: onDateSelect,
|
|
865
|
+
onPrevWeek: () => onWeekNavigate("prev"),
|
|
866
|
+
onNextWeek: () => onWeekNavigate("next"),
|
|
867
|
+
weekStartsOn,
|
|
868
|
+
locale
|
|
869
|
+
}
|
|
870
|
+
) })
|
|
871
|
+
}
|
|
872
|
+
),
|
|
873
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
874
|
+
"div",
|
|
875
|
+
{
|
|
876
|
+
className: "overflow-hidden transition-[max-height] duration-300 ease-in-out",
|
|
877
|
+
style: { maxHeight: monthPickerExpanded ? 400 : 0 },
|
|
878
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-b-lg bg-muted/30 px-2 pt-1 pb-2 border-t border-border/50", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
879
|
+
MobileMonthPicker,
|
|
880
|
+
{
|
|
881
|
+
selectedDate: currentDate,
|
|
882
|
+
onDaySelect: onDateSelect,
|
|
883
|
+
weekStartsOn,
|
|
884
|
+
locale
|
|
885
|
+
}
|
|
886
|
+
) }) })
|
|
887
|
+
}
|
|
888
|
+
)
|
|
889
|
+
] })
|
|
890
|
+
] });
|
|
891
|
+
}
|
|
892
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between", children: [
|
|
893
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
894
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Calendar, { className: "h-5 w-5 text-primary" }),
|
|
895
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-xl font-semibold text-foreground", children: title })
|
|
896
|
+
] }) }),
|
|
897
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 sm:gap-4", children: [
|
|
898
|
+
showNavigation && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
|
|
899
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
900
|
+
Button,
|
|
901
|
+
{
|
|
902
|
+
variant: "outline",
|
|
903
|
+
size: "icon",
|
|
904
|
+
onClick: () => onNavigate("prev"),
|
|
905
|
+
className: "h-8 w-8",
|
|
906
|
+
children: [
|
|
907
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronLeft, { className: "h-4 w-4" }),
|
|
908
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Previous" })
|
|
909
|
+
]
|
|
910
|
+
}
|
|
911
|
+
),
|
|
912
|
+
showTodayButton && /* @__PURE__ */ jsxRuntime.jsx(
|
|
913
|
+
Button,
|
|
914
|
+
{
|
|
915
|
+
variant: "outline",
|
|
916
|
+
size: "sm",
|
|
917
|
+
onClick: onToday,
|
|
918
|
+
className: "h-8 px-3 text-xs font-medium",
|
|
919
|
+
children: "Today"
|
|
920
|
+
}
|
|
921
|
+
),
|
|
922
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
923
|
+
Button,
|
|
924
|
+
{
|
|
925
|
+
variant: "outline",
|
|
926
|
+
size: "icon",
|
|
927
|
+
onClick: () => onNavigate("next"),
|
|
928
|
+
className: "h-8 w-8",
|
|
929
|
+
children: [
|
|
930
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "h-4 w-4" }),
|
|
931
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Next" })
|
|
932
|
+
]
|
|
933
|
+
}
|
|
934
|
+
)
|
|
935
|
+
] }),
|
|
936
|
+
showViewSwitcher && views.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
937
|
+
ToggleGroup,
|
|
938
|
+
{
|
|
939
|
+
type: "single",
|
|
940
|
+
value: view,
|
|
941
|
+
onValueChange: (value) => value && onViewChange(value),
|
|
942
|
+
className: "border border-border rounded-lg p-0.5",
|
|
943
|
+
children: views.map((v) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
944
|
+
ToggleGroupItem,
|
|
945
|
+
{
|
|
946
|
+
value: v,
|
|
947
|
+
className: "h-7 px-3 text-xs data-[state=on]:bg-primary data-[state=on]:text-primary-foreground",
|
|
948
|
+
children: VIEW_LABELS[v]
|
|
949
|
+
},
|
|
950
|
+
v
|
|
951
|
+
))
|
|
952
|
+
}
|
|
953
|
+
)
|
|
954
|
+
] })
|
|
955
|
+
] });
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
// components/event-calendar/dnd/types.ts
|
|
959
|
+
function createEventId(event) {
|
|
960
|
+
return `event-${event.id}`;
|
|
961
|
+
}
|
|
962
|
+
function createSlotId(data) {
|
|
963
|
+
switch (data.view) {
|
|
964
|
+
case "day":
|
|
965
|
+
return `slot-day-${data.day.getTime()}-${data.hour}`;
|
|
966
|
+
case "week":
|
|
967
|
+
return `slot-week-${data.day.getTime()}-${data.hour}`;
|
|
968
|
+
case "month":
|
|
969
|
+
return `slot-month-${data.day.getTime()}`;
|
|
970
|
+
case "resource":
|
|
971
|
+
return `slot-resource-${data.resourceId}-${data.day.getTime()}-${data.hour}`;
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
function DroppableSlot({
|
|
975
|
+
data,
|
|
976
|
+
children,
|
|
977
|
+
className,
|
|
978
|
+
style
|
|
979
|
+
}) {
|
|
980
|
+
const id = createSlotId(data);
|
|
981
|
+
const { setNodeRef, isOver } = core.useDroppable({
|
|
982
|
+
id,
|
|
983
|
+
data
|
|
984
|
+
});
|
|
985
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
986
|
+
"div",
|
|
987
|
+
{
|
|
988
|
+
ref: setNodeRef,
|
|
989
|
+
className,
|
|
990
|
+
style: __spreadValues(__spreadValues({}, style), isOver ? { backgroundColor: "var(--accent)" } : {}),
|
|
991
|
+
children
|
|
992
|
+
}
|
|
993
|
+
);
|
|
994
|
+
}
|
|
995
|
+
function DraggableCreateSlot({
|
|
996
|
+
data,
|
|
997
|
+
children,
|
|
998
|
+
disabled = false,
|
|
999
|
+
className,
|
|
1000
|
+
style
|
|
1001
|
+
}) {
|
|
1002
|
+
const id = `create-${createSlotId(data)}`;
|
|
1003
|
+
const { attributes, listeners, setNodeRef, isDragging } = core.useDraggable({
|
|
1004
|
+
id,
|
|
1005
|
+
data: { type: "create", slotData: data },
|
|
1006
|
+
disabled
|
|
1007
|
+
});
|
|
1008
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1009
|
+
"div",
|
|
1010
|
+
__spreadProps(__spreadValues(__spreadValues({
|
|
1011
|
+
ref: setNodeRef
|
|
1012
|
+
}, listeners), attributes), {
|
|
1013
|
+
className,
|
|
1014
|
+
style: __spreadProps(__spreadValues({}, style), {
|
|
1015
|
+
opacity: isDragging ? 0.5 : 1,
|
|
1016
|
+
cursor: disabled ? "default" : "crosshair"
|
|
1017
|
+
}),
|
|
1018
|
+
children
|
|
1019
|
+
})
|
|
1020
|
+
);
|
|
1021
|
+
}
|
|
1022
|
+
function DraggableEvent({
|
|
1023
|
+
event,
|
|
1024
|
+
children,
|
|
1025
|
+
disabled = false,
|
|
1026
|
+
className,
|
|
1027
|
+
style
|
|
1028
|
+
}) {
|
|
1029
|
+
const { attributes, listeners, setNodeRef, isDragging } = core.useDraggable({
|
|
1030
|
+
id: createEventId(event),
|
|
1031
|
+
data: { type: "event", event },
|
|
1032
|
+
disabled
|
|
1033
|
+
});
|
|
1034
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1035
|
+
"div",
|
|
1036
|
+
__spreadProps(__spreadValues(__spreadValues({
|
|
1037
|
+
ref: setNodeRef
|
|
1038
|
+
}, listeners), attributes), {
|
|
1039
|
+
className,
|
|
1040
|
+
style: __spreadProps(__spreadValues({}, style), {
|
|
1041
|
+
opacity: isDragging ? 0.5 : 1,
|
|
1042
|
+
cursor: disabled ? "default" : "grab",
|
|
1043
|
+
position: "absolute"
|
|
1044
|
+
}),
|
|
1045
|
+
children
|
|
1046
|
+
})
|
|
1047
|
+
);
|
|
1048
|
+
}
|
|
1049
|
+
function MonthView({ currentDate, events }) {
|
|
1050
|
+
const {
|
|
1051
|
+
config,
|
|
1052
|
+
onEventClick,
|
|
1053
|
+
onEventDoubleClick,
|
|
1054
|
+
onSlotClick,
|
|
1055
|
+
onSlotDoubleClick,
|
|
1056
|
+
onDayClick,
|
|
1057
|
+
renderEvent,
|
|
1058
|
+
enableDragToCreate = false,
|
|
1059
|
+
enableDragToMove = false
|
|
1060
|
+
} = useCalendar();
|
|
1061
|
+
const days = getMonthDays(currentDate, config.weekStartsOn);
|
|
1062
|
+
const weekdays = getWeekdayNames(config.weekStartsOn, true, config.locale);
|
|
1063
|
+
const today = /* @__PURE__ */ new Date();
|
|
1064
|
+
const handleSlotClick = (day) => {
|
|
1065
|
+
if (onDayClick) {
|
|
1066
|
+
onDayClick(day);
|
|
1067
|
+
}
|
|
1068
|
+
if (onSlotClick) {
|
|
1069
|
+
const slotInfo = {
|
|
1070
|
+
start: dateFns.startOfDay(day),
|
|
1071
|
+
end: dateFns.endOfDay(day)
|
|
1072
|
+
};
|
|
1073
|
+
onSlotClick(slotInfo);
|
|
1074
|
+
}
|
|
1075
|
+
};
|
|
1076
|
+
const handleSlotDoubleClick = (day) => {
|
|
1077
|
+
if (onSlotDoubleClick) {
|
|
1078
|
+
const slotInfo = {
|
|
1079
|
+
start: dateFns.startOfDay(day),
|
|
1080
|
+
end: dateFns.endOfDay(day)
|
|
1081
|
+
};
|
|
1082
|
+
onSlotDoubleClick(slotInfo);
|
|
1083
|
+
}
|
|
1084
|
+
};
|
|
1085
|
+
const handleEventClick = (e, event) => {
|
|
1086
|
+
e.stopPropagation();
|
|
1087
|
+
onEventClick == null ? void 0 : onEventClick(event);
|
|
1088
|
+
};
|
|
1089
|
+
const handleEventDoubleClick = (e, event) => {
|
|
1090
|
+
e.stopPropagation();
|
|
1091
|
+
onEventDoubleClick == null ? void 0 : onEventDoubleClick(event);
|
|
1092
|
+
};
|
|
1093
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col h-full", children: [
|
|
1094
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-7 border-b border-border", children: weekdays.map((day) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1095
|
+
"div",
|
|
1096
|
+
{
|
|
1097
|
+
className: "py-3 text-center text-xs font-medium text-muted-foreground uppercase tracking-wider",
|
|
1098
|
+
children: day
|
|
1099
|
+
},
|
|
1100
|
+
day
|
|
1101
|
+
)) }),
|
|
1102
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-7 flex-1 auto-rows-fr", children: days.map((day, index) => {
|
|
1103
|
+
const dayEvents = getEventsForDay(events, day);
|
|
1104
|
+
const isCurrentMonth = dateFns.isSameMonth(day, currentDate);
|
|
1105
|
+
const isToday = dateFns.isSameDay(day, today);
|
|
1106
|
+
const slotData = { view: "month", day };
|
|
1107
|
+
const cellContent = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1108
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-between mb-1", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1109
|
+
"span",
|
|
1110
|
+
{
|
|
1111
|
+
className: cn(
|
|
1112
|
+
"inline-flex items-center justify-center w-7 h-7 text-sm font-medium rounded-full",
|
|
1113
|
+
isToday && "bg-primary text-primary-foreground",
|
|
1114
|
+
!isToday && isCurrentMonth && "text-foreground",
|
|
1115
|
+
!isToday && !isCurrentMonth && "text-muted-foreground"
|
|
1116
|
+
),
|
|
1117
|
+
children: formatDate(day, "d", config.locale)
|
|
1118
|
+
}
|
|
1119
|
+
) }),
|
|
1120
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-0.5 overflow-hidden", children: [
|
|
1121
|
+
dayEvents.slice(0, config.maxEventsPerDay).map((event) => {
|
|
1122
|
+
const eventColor = event.color || config.defaultEventColor;
|
|
1123
|
+
const eventContent = renderEvent ? renderEvent(event, "month") : /* @__PURE__ */ jsxRuntime.jsx("span", { children: event.title });
|
|
1124
|
+
const eventEl = /* @__PURE__ */ jsxRuntime.jsx(
|
|
1125
|
+
"div",
|
|
1126
|
+
{
|
|
1127
|
+
className: cn(
|
|
1128
|
+
"px-1.5 py-0.5 text-xs font-medium rounded truncate transition-opacity hover:opacity-80",
|
|
1129
|
+
!enableDragToMove && "cursor-pointer"
|
|
1130
|
+
),
|
|
1131
|
+
style: {
|
|
1132
|
+
backgroundColor: `${eventColor}20`,
|
|
1133
|
+
color: eventColor,
|
|
1134
|
+
borderLeft: `2px solid ${eventColor}`
|
|
1135
|
+
},
|
|
1136
|
+
title: event.title,
|
|
1137
|
+
onClick: (e) => handleEventClick(e, event),
|
|
1138
|
+
onDoubleClick: (e) => handleEventDoubleClick(e, event),
|
|
1139
|
+
children: eventContent
|
|
1140
|
+
}
|
|
1141
|
+
);
|
|
1142
|
+
return enableDragToMove ? /* @__PURE__ */ jsxRuntime.jsx(DraggableEvent, { event, children: eventEl }, event.id) : /* @__PURE__ */ jsxRuntime.jsx("div", { children: eventEl }, event.id);
|
|
1143
|
+
}),
|
|
1144
|
+
dayEvents.length > config.maxEventsPerDay && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs text-muted-foreground pl-1.5 font-medium", children: [
|
|
1145
|
+
"+",
|
|
1146
|
+
dayEvents.length - config.maxEventsPerDay,
|
|
1147
|
+
" more"
|
|
1148
|
+
] })
|
|
1149
|
+
] })
|
|
1150
|
+
] });
|
|
1151
|
+
const cell = /* @__PURE__ */ jsxRuntime.jsx(
|
|
1152
|
+
"div",
|
|
1153
|
+
{
|
|
1154
|
+
className: cn(
|
|
1155
|
+
"min-h-[100px] border-b border-r border-border p-1.5 transition-colors hover:bg-muted/50 cursor-pointer h-full",
|
|
1156
|
+
!isCurrentMonth && "bg-muted/30",
|
|
1157
|
+
index % 7 === 0 && "border-l-0",
|
|
1158
|
+
index < 7 && "border-t-0"
|
|
1159
|
+
),
|
|
1160
|
+
onClick: () => handleSlotClick(day),
|
|
1161
|
+
onDoubleClick: () => handleSlotDoubleClick(day),
|
|
1162
|
+
children: cellContent
|
|
1163
|
+
}
|
|
1164
|
+
);
|
|
1165
|
+
return enableDragToCreate || enableDragToMove ? /* @__PURE__ */ jsxRuntime.jsx(DroppableSlot, { data: slotData, className: "min-h-[100px]", children: enableDragToCreate ? /* @__PURE__ */ jsxRuntime.jsx(DraggableCreateSlot, { data: slotData, className: "h-full", children: cell }) : cell }, index) : /* @__PURE__ */ jsxRuntime.jsx("div", { children: cell }, index);
|
|
1166
|
+
}) })
|
|
1167
|
+
] });
|
|
1168
|
+
}
|
|
1169
|
+
function WeekView({ currentDate, events, dayCount, isMobile = false }) {
|
|
1170
|
+
var _a;
|
|
1171
|
+
const {
|
|
1172
|
+
config,
|
|
1173
|
+
onEventClick,
|
|
1174
|
+
onEventDoubleClick,
|
|
1175
|
+
onSlotClick,
|
|
1176
|
+
onSlotDoubleClick,
|
|
1177
|
+
renderEvent,
|
|
1178
|
+
enableDragToCreate = false,
|
|
1179
|
+
enableDragToMove = false
|
|
1180
|
+
} = useCalendar();
|
|
1181
|
+
const days = dayCount === 2 ? getTwoDays(currentDate, config.weekStartsOn) : getWeekDays(currentDate, config.weekStartsOn);
|
|
1182
|
+
const hours = getHoursArray(config.startHour, config.endHour);
|
|
1183
|
+
const today = /* @__PURE__ */ new Date();
|
|
1184
|
+
const totalHours = hours.length;
|
|
1185
|
+
const showCurrentTimeLine = (_a = config.showCurrentTimeLine) != null ? _a : true;
|
|
1186
|
+
const includesToday = days.some((d) => dateFns.isSameDay(d, today));
|
|
1187
|
+
const [now, setNow] = React2.useState(() => /* @__PURE__ */ new Date());
|
|
1188
|
+
const columnRefs = React2.useRef(/* @__PURE__ */ new Map());
|
|
1189
|
+
React2.useEffect(() => {
|
|
1190
|
+
if (!showCurrentTimeLine || !includesToday) return;
|
|
1191
|
+
const id = setInterval(() => setNow(/* @__PURE__ */ new Date()), 6e4);
|
|
1192
|
+
return () => clearInterval(id);
|
|
1193
|
+
}, [showCurrentTimeLine, includesToday]);
|
|
1194
|
+
React2.useEffect(() => {
|
|
1195
|
+
const key = currentDate.toISOString().slice(0, 10);
|
|
1196
|
+
const el = columnRefs.current.get(key);
|
|
1197
|
+
if (el) {
|
|
1198
|
+
el.scrollIntoView({ behavior: "smooth", inline: "center", block: "nearest" });
|
|
1199
|
+
}
|
|
1200
|
+
}, [currentDate]);
|
|
1201
|
+
const currentTimeLineTop = showCurrentTimeLine && includesToday ? getCurrentTimeLineTop(now, config.startHour, config.endHour, config.hourHeight, 0) : null;
|
|
1202
|
+
const dayColumnMinWidth = isMobile && dayCount !== 2 ? "min(45vw, 200px)" : "140px";
|
|
1203
|
+
const handleSlotClick = (day, hour) => {
|
|
1204
|
+
if (onSlotClick) {
|
|
1205
|
+
const slotInfo = {
|
|
1206
|
+
start: createSlotDate(day, hour),
|
|
1207
|
+
end: createSlotDate(day, hour + 1)
|
|
1208
|
+
};
|
|
1209
|
+
onSlotClick(slotInfo);
|
|
1210
|
+
}
|
|
1211
|
+
};
|
|
1212
|
+
const handleSlotDoubleClick = (day, hour) => {
|
|
1213
|
+
if (onSlotDoubleClick) {
|
|
1214
|
+
const slotInfo = {
|
|
1215
|
+
start: createSlotDate(day, hour),
|
|
1216
|
+
end: createSlotDate(day, hour + 1)
|
|
1217
|
+
};
|
|
1218
|
+
onSlotDoubleClick(slotInfo);
|
|
1219
|
+
}
|
|
1220
|
+
};
|
|
1221
|
+
const handleEventClick = (e, event) => {
|
|
1222
|
+
e.stopPropagation();
|
|
1223
|
+
onEventClick == null ? void 0 : onEventClick(event);
|
|
1224
|
+
};
|
|
1225
|
+
const handleEventDoubleClick = (e, event) => {
|
|
1226
|
+
e.stopPropagation();
|
|
1227
|
+
onEventDoubleClick == null ? void 0 : onEventDoubleClick(event);
|
|
1228
|
+
};
|
|
1229
|
+
const maxHeightStyle = config.timeSeriesMaxHeight != null ? typeof config.timeSeriesMaxHeight === "number" ? `${config.timeSeriesMaxHeight}px` : config.timeSeriesMaxHeight : void 0;
|
|
1230
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1231
|
+
"div",
|
|
1232
|
+
{
|
|
1233
|
+
className: "h-full overflow-auto",
|
|
1234
|
+
style: { maxHeight: maxHeightStyle },
|
|
1235
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col min-w-max flex-1", children: [
|
|
1236
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex border-b border-border shrink-0 bg-background z-10 sticky top-0 shadow-[0_4px_12px_-2px_rgba(0,0,0,0.08)] dark:shadow-[0_4px_12px_-2px_rgba(0,0,0,0.2)]", children: [
|
|
1237
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-16 shrink-0 border-r border-border sticky left-0 z-10 bg-background shadow-[4px_0_12px_-2px_rgba(0,0,0,0.08),6px_0_16px_-4px_rgba(0,0,0,0.06)] dark:shadow-[4px_0_16px_-2px_rgba(0,0,0,0.25),6px_0_24px_-4px_rgba(0,0,0,0.2)]" }),
|
|
1238
|
+
days.map((day, index) => {
|
|
1239
|
+
const isToday = dateFns.isSameDay(day, today);
|
|
1240
|
+
const dayKey = day.toISOString().slice(0, 10);
|
|
1241
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1242
|
+
"div",
|
|
1243
|
+
{
|
|
1244
|
+
ref: (el) => {
|
|
1245
|
+
if (el) columnRefs.current.set(dayKey, el);
|
|
1246
|
+
},
|
|
1247
|
+
className: cn(
|
|
1248
|
+
"flex-1 py-3 text-center border-r border-border last:border-r-0",
|
|
1249
|
+
isToday && "bg-primary/5"
|
|
1250
|
+
),
|
|
1251
|
+
style: { minWidth: dayColumnMinWidth },
|
|
1252
|
+
children: [
|
|
1253
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs font-medium text-muted-foreground uppercase", children: formatDate(day, "EEE", config.locale) }),
|
|
1254
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1255
|
+
"div",
|
|
1256
|
+
{
|
|
1257
|
+
className: cn(
|
|
1258
|
+
"mt-1 inline-flex items-center justify-center w-8 h-8 text-lg font-semibold rounded-full",
|
|
1259
|
+
isToday && "bg-primary text-primary-foreground",
|
|
1260
|
+
!isToday && "text-foreground"
|
|
1261
|
+
),
|
|
1262
|
+
children: formatDate(day, "d", config.locale)
|
|
1263
|
+
}
|
|
1264
|
+
)
|
|
1265
|
+
]
|
|
1266
|
+
},
|
|
1267
|
+
index
|
|
1268
|
+
);
|
|
1269
|
+
})
|
|
1270
|
+
] }),
|
|
1271
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1272
|
+
"div",
|
|
1273
|
+
{
|
|
1274
|
+
className: "flex flex-1 relative",
|
|
1275
|
+
style: { minHeight: totalHours * config.hourHeight },
|
|
1276
|
+
children: [
|
|
1277
|
+
currentTimeLineTop != null && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1278
|
+
"div",
|
|
1279
|
+
{
|
|
1280
|
+
className: "absolute left-16 right-0 h-0.5 bg-sky-300 z-20 pointer-events-none",
|
|
1281
|
+
style: { top: currentTimeLineTop },
|
|
1282
|
+
"aria-hidden": true,
|
|
1283
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute -left-1 top-1/2 -translate-y-1/2 w-2 h-2 rounded-full bg-sky-300" })
|
|
1284
|
+
}
|
|
1285
|
+
),
|
|
1286
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-16 shrink-0 border-r border-border sticky left-0 z-10 bg-background shadow-[4px_0_12px_-2px_rgba(0,0,0,0.08),6px_0_16px_-4px_rgba(0,0,0,0.06)] dark:shadow-[4px_0_16px_-2px_rgba(0,0,0,0.25),6px_0_24px_-4px_rgba(0,0,0,0.2)]", children: hours.map((hour) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1287
|
+
"div",
|
|
1288
|
+
{
|
|
1289
|
+
className: "pr-2 flex items-start justify-end",
|
|
1290
|
+
style: { height: `${config.hourHeight}px` },
|
|
1291
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground -mt-2", children: formatHour(hour, config.timeFormat, config.locale) })
|
|
1292
|
+
},
|
|
1293
|
+
hour
|
|
1294
|
+
)) }),
|
|
1295
|
+
days.map((day, dayIndex) => {
|
|
1296
|
+
const dayEvents = getEventsForDay(events, day);
|
|
1297
|
+
const isToday = dateFns.isSameDay(day, today);
|
|
1298
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1299
|
+
"div",
|
|
1300
|
+
{
|
|
1301
|
+
className: cn(
|
|
1302
|
+
"flex-1 border-r border-border last:border-r-0 relative",
|
|
1303
|
+
isToday && "bg-primary/5"
|
|
1304
|
+
),
|
|
1305
|
+
style: { minWidth: dayColumnMinWidth },
|
|
1306
|
+
children: [
|
|
1307
|
+
hours.map((hour, index) => {
|
|
1308
|
+
const slotData = { view: "week", day, hour };
|
|
1309
|
+
const slotContent = /* @__PURE__ */ jsxRuntime.jsx(
|
|
1310
|
+
"div",
|
|
1311
|
+
{
|
|
1312
|
+
className: cn(
|
|
1313
|
+
"cursor-pointer hover:bg-muted/30 transition-colors h-full w-full",
|
|
1314
|
+
index < totalHours - 1 && "border-b border-border"
|
|
1315
|
+
),
|
|
1316
|
+
style: { height: `${config.hourHeight}px` },
|
|
1317
|
+
onClick: () => handleSlotClick(day, hour),
|
|
1318
|
+
onDoubleClick: () => handleSlotDoubleClick(day, hour)
|
|
1319
|
+
}
|
|
1320
|
+
);
|
|
1321
|
+
return enableDragToCreate || enableDragToMove ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1322
|
+
DroppableSlot,
|
|
1323
|
+
{
|
|
1324
|
+
data: slotData,
|
|
1325
|
+
style: { height: `${config.hourHeight}px` },
|
|
1326
|
+
className: cn(index < totalHours - 1 && "border-b border-border"),
|
|
1327
|
+
children: enableDragToCreate ? /* @__PURE__ */ jsxRuntime.jsx(DraggableCreateSlot, { data: slotData, className: "h-full w-full", children: slotContent }) : slotContent
|
|
1328
|
+
},
|
|
1329
|
+
hour
|
|
1330
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1331
|
+
"div",
|
|
1332
|
+
{
|
|
1333
|
+
className: cn(
|
|
1334
|
+
"cursor-pointer hover:bg-muted/30 transition-colors",
|
|
1335
|
+
index < totalHours - 1 && "border-b border-border"
|
|
1336
|
+
),
|
|
1337
|
+
style: { height: `${config.hourHeight}px` },
|
|
1338
|
+
onClick: () => handleSlotClick(day, hour),
|
|
1339
|
+
onDoubleClick: () => handleSlotDoubleClick(day, hour)
|
|
1340
|
+
},
|
|
1341
|
+
hour
|
|
1342
|
+
);
|
|
1343
|
+
}),
|
|
1344
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute bottom-0 left-0 right-0 h-px bg-border" }),
|
|
1345
|
+
dayEvents.map((event) => {
|
|
1346
|
+
if (!dateFns.isSameDay(event.start, day)) return null;
|
|
1347
|
+
const { top, height } = getEventPosition(event, config.hourHeight, config.startHour);
|
|
1348
|
+
const eventColor = event.color || config.defaultEventColor;
|
|
1349
|
+
const eventContent = renderEvent ? renderEvent(event, "week") : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1350
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-semibold truncate", children: event.title }),
|
|
1351
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-[10px] opacity-80", children: [
|
|
1352
|
+
formatDate(event.start, "h:mm a", config.locale),
|
|
1353
|
+
" - ",
|
|
1354
|
+
formatDate(event.end, "h:mm a", config.locale)
|
|
1355
|
+
] })
|
|
1356
|
+
] });
|
|
1357
|
+
const eventEl = /* @__PURE__ */ jsxRuntime.jsx(
|
|
1358
|
+
"div",
|
|
1359
|
+
{
|
|
1360
|
+
className: cn(
|
|
1361
|
+
"px-1.5 py-1 rounded text-xs font-medium overflow-hidden transition-opacity hover:opacity-90 h-full w-full",
|
|
1362
|
+
!enableDragToMove && "cursor-pointer"
|
|
1363
|
+
),
|
|
1364
|
+
style: {
|
|
1365
|
+
backgroundColor: `${eventColor}15`,
|
|
1366
|
+
borderLeft: `3px solid ${eventColor}`,
|
|
1367
|
+
color: eventColor
|
|
1368
|
+
},
|
|
1369
|
+
title: event.title,
|
|
1370
|
+
onClick: (e) => handleEventClick(e, event),
|
|
1371
|
+
onDoubleClick: (e) => handleEventDoubleClick(e, event),
|
|
1372
|
+
children: eventContent
|
|
1373
|
+
}
|
|
1374
|
+
);
|
|
1375
|
+
return enableDragToMove ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1376
|
+
DraggableEvent,
|
|
1377
|
+
{
|
|
1378
|
+
event,
|
|
1379
|
+
className: "absolute left-0.5 right-0.5",
|
|
1380
|
+
style: { top: `${top}px`, height: `${height}px` },
|
|
1381
|
+
children: eventEl
|
|
1382
|
+
},
|
|
1383
|
+
event.id
|
|
1384
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1385
|
+
"div",
|
|
1386
|
+
{
|
|
1387
|
+
className: "absolute left-0.5 right-0.5",
|
|
1388
|
+
style: { top: `${top}px`, height: `${height}px` },
|
|
1389
|
+
children: eventEl
|
|
1390
|
+
},
|
|
1391
|
+
event.id
|
|
1392
|
+
);
|
|
1393
|
+
})
|
|
1394
|
+
]
|
|
1395
|
+
},
|
|
1396
|
+
dayIndex
|
|
1397
|
+
);
|
|
1398
|
+
})
|
|
1399
|
+
]
|
|
1400
|
+
}
|
|
1401
|
+
)
|
|
1402
|
+
] })
|
|
1403
|
+
}
|
|
1404
|
+
);
|
|
1405
|
+
}
|
|
1406
|
+
function DayView({ currentDate, events }) {
|
|
1407
|
+
var _a;
|
|
1408
|
+
const {
|
|
1409
|
+
config,
|
|
1410
|
+
onEventClick,
|
|
1411
|
+
onEventDoubleClick,
|
|
1412
|
+
onSlotClick,
|
|
1413
|
+
onSlotDoubleClick,
|
|
1414
|
+
renderEvent,
|
|
1415
|
+
enableDragToCreate = false,
|
|
1416
|
+
enableDragToMove = false
|
|
1417
|
+
} = useCalendar();
|
|
1418
|
+
const dayEvents = getEventsForDay(events, currentDate);
|
|
1419
|
+
const hours = getHoursArray(config.startHour, config.endHour);
|
|
1420
|
+
const today = /* @__PURE__ */ new Date();
|
|
1421
|
+
const isToday = dateFns.isSameDay(currentDate, today);
|
|
1422
|
+
const totalHours = hours.length;
|
|
1423
|
+
const showCurrentTimeLine = (_a = config.showCurrentTimeLine) != null ? _a : true;
|
|
1424
|
+
const [now, setNow] = React2.useState(() => /* @__PURE__ */ new Date());
|
|
1425
|
+
React2.useEffect(() => {
|
|
1426
|
+
if (!showCurrentTimeLine || !isToday) return;
|
|
1427
|
+
const id = setInterval(() => setNow(/* @__PURE__ */ new Date()), 6e4);
|
|
1428
|
+
return () => clearInterval(id);
|
|
1429
|
+
}, [showCurrentTimeLine, isToday]);
|
|
1430
|
+
const currentTimeLineTop = showCurrentTimeLine && isToday ? getCurrentTimeLineTop(now, config.startHour, config.endHour, config.hourHeight, 0) : null;
|
|
1431
|
+
const handleSlotClick = (hour) => {
|
|
1432
|
+
if (onSlotClick) {
|
|
1433
|
+
const slotInfo = {
|
|
1434
|
+
start: createSlotDate(currentDate, hour),
|
|
1435
|
+
end: createSlotDate(currentDate, hour + 1)
|
|
1436
|
+
};
|
|
1437
|
+
onSlotClick(slotInfo);
|
|
1438
|
+
}
|
|
1439
|
+
};
|
|
1440
|
+
const handleSlotDoubleClick = (hour) => {
|
|
1441
|
+
if (onSlotDoubleClick) {
|
|
1442
|
+
const slotInfo = {
|
|
1443
|
+
start: createSlotDate(currentDate, hour),
|
|
1444
|
+
end: createSlotDate(currentDate, hour + 1)
|
|
1445
|
+
};
|
|
1446
|
+
onSlotDoubleClick(slotInfo);
|
|
1447
|
+
}
|
|
1448
|
+
};
|
|
1449
|
+
const handleEventClick = (e, event) => {
|
|
1450
|
+
e.stopPropagation();
|
|
1451
|
+
onEventClick == null ? void 0 : onEventClick(event);
|
|
1452
|
+
};
|
|
1453
|
+
const handleEventDoubleClick = (e, event) => {
|
|
1454
|
+
e.stopPropagation();
|
|
1455
|
+
onEventDoubleClick == null ? void 0 : onEventDoubleClick(event);
|
|
1456
|
+
};
|
|
1457
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col h-full overflow-hidden", children: [
|
|
1458
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex border-b border-border shrink-0 bg-background z-10 shadow-[0_4px_12px_-2px_rgba(0,0,0,0.08)] dark:shadow-[0_4px_12px_-2px_rgba(0,0,0,0.2)]", children: [
|
|
1459
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-20 shrink-0 border-r border-border" }),
|
|
1460
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1461
|
+
"div",
|
|
1462
|
+
{
|
|
1463
|
+
className: cn(
|
|
1464
|
+
"flex-1 py-4 text-center border-r border-border",
|
|
1465
|
+
isToday && "bg-primary/5"
|
|
1466
|
+
),
|
|
1467
|
+
children: [
|
|
1468
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-medium text-muted-foreground uppercase", children: formatDate(currentDate, "EEEE", config.locale) }),
|
|
1469
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1470
|
+
"div",
|
|
1471
|
+
{
|
|
1472
|
+
className: cn(
|
|
1473
|
+
"mt-1 inline-flex items-center justify-center w-10 h-10 text-xl font-semibold rounded-full",
|
|
1474
|
+
isToday && "bg-primary text-primary-foreground",
|
|
1475
|
+
!isToday && "text-foreground"
|
|
1476
|
+
),
|
|
1477
|
+
children: formatDate(currentDate, "d", config.locale)
|
|
1478
|
+
}
|
|
1479
|
+
)
|
|
1480
|
+
]
|
|
1481
|
+
}
|
|
1482
|
+
)
|
|
1483
|
+
] }),
|
|
1484
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1485
|
+
"div",
|
|
1486
|
+
{
|
|
1487
|
+
className: "flex flex-1 overflow-auto min-h-0",
|
|
1488
|
+
style: {
|
|
1489
|
+
maxHeight: config.timeSeriesMaxHeight != null ? typeof config.timeSeriesMaxHeight === "number" ? `${config.timeSeriesMaxHeight}px` : config.timeSeriesMaxHeight : void 0
|
|
1490
|
+
},
|
|
1491
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1492
|
+
"div",
|
|
1493
|
+
{
|
|
1494
|
+
className: "flex min-w-full relative",
|
|
1495
|
+
style: { minHeight: totalHours * config.hourHeight },
|
|
1496
|
+
children: [
|
|
1497
|
+
currentTimeLineTop != null && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1498
|
+
"div",
|
|
1499
|
+
{
|
|
1500
|
+
className: "absolute left-20 right-0 h-0.5 bg-sky-300 z-20 pointer-events-none",
|
|
1501
|
+
style: { top: currentTimeLineTop },
|
|
1502
|
+
"aria-hidden": true,
|
|
1503
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute -left-1 top-1/2 -translate-y-1/2 w-2 h-2 rounded-full bg-sky-300" })
|
|
1504
|
+
}
|
|
1505
|
+
),
|
|
1506
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-20 shrink-0 border-r border-border relative", children: hours.map((hour) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1507
|
+
"div",
|
|
1508
|
+
{
|
|
1509
|
+
className: "pr-3 flex items-start justify-end",
|
|
1510
|
+
style: { height: `${config.hourHeight}px` },
|
|
1511
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground -mt-2", children: formatHour(hour, config.timeFormat, config.locale) })
|
|
1512
|
+
},
|
|
1513
|
+
hour
|
|
1514
|
+
)) }),
|
|
1515
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex-1 relative border-r border-border", isToday && "bg-primary/5"), children: [
|
|
1516
|
+
hours.map((hour, index) => {
|
|
1517
|
+
const slotData = { view: "day", day: currentDate, hour };
|
|
1518
|
+
const slotContent = /* @__PURE__ */ jsxRuntime.jsx(
|
|
1519
|
+
"div",
|
|
1520
|
+
{
|
|
1521
|
+
className: cn(
|
|
1522
|
+
"cursor-pointer hover:bg-muted/30 transition-colors h-full w-full",
|
|
1523
|
+
index < totalHours - 1 && "border-b border-border"
|
|
1524
|
+
),
|
|
1525
|
+
style: { height: `${config.hourHeight}px` },
|
|
1526
|
+
onClick: () => handleSlotClick(hour),
|
|
1527
|
+
onDoubleClick: () => handleSlotDoubleClick(hour)
|
|
1528
|
+
}
|
|
1529
|
+
);
|
|
1530
|
+
return enableDragToCreate || enableDragToMove ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1531
|
+
DroppableSlot,
|
|
1532
|
+
{
|
|
1533
|
+
data: slotData,
|
|
1534
|
+
style: { height: `${config.hourHeight}px` },
|
|
1535
|
+
className: cn(index < totalHours - 1 && "border-b border-border"),
|
|
1536
|
+
children: enableDragToCreate ? /* @__PURE__ */ jsxRuntime.jsx(DraggableCreateSlot, { data: slotData, className: "h-full w-full", children: slotContent }) : slotContent
|
|
1537
|
+
},
|
|
1538
|
+
hour
|
|
1539
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1540
|
+
"div",
|
|
1541
|
+
{
|
|
1542
|
+
className: cn(
|
|
1543
|
+
"cursor-pointer hover:bg-muted/30 transition-colors",
|
|
1544
|
+
index < totalHours - 1 && "border-b border-border"
|
|
1545
|
+
),
|
|
1546
|
+
style: { height: `${config.hourHeight}px` },
|
|
1547
|
+
onClick: () => handleSlotClick(hour),
|
|
1548
|
+
onDoubleClick: () => handleSlotDoubleClick(hour)
|
|
1549
|
+
},
|
|
1550
|
+
hour
|
|
1551
|
+
);
|
|
1552
|
+
}),
|
|
1553
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute bottom-0 left-0 right-0 h-px bg-border" }),
|
|
1554
|
+
dayEvents.map((event) => {
|
|
1555
|
+
if (!dateFns.isSameDay(event.start, currentDate)) return null;
|
|
1556
|
+
const { top, height } = getEventPosition(event, config.hourHeight, config.startHour);
|
|
1557
|
+
const eventColor = event.color || config.defaultEventColor;
|
|
1558
|
+
const eventContent = renderEvent ? renderEvent(event, "day") : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1559
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-semibold text-sm", style: { color: eventColor }, children: event.title }),
|
|
1560
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs text-muted-foreground mt-0.5", children: [
|
|
1561
|
+
formatDate(event.start, "h:mm a", config.locale),
|
|
1562
|
+
" - ",
|
|
1563
|
+
formatDate(event.end, "h:mm a", config.locale)
|
|
1564
|
+
] }),
|
|
1565
|
+
event.description && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-muted-foreground mt-1 line-clamp-2", children: event.description })
|
|
1566
|
+
] });
|
|
1567
|
+
const eventEl = /* @__PURE__ */ jsxRuntime.jsx(
|
|
1568
|
+
"div",
|
|
1569
|
+
{
|
|
1570
|
+
className: cn(
|
|
1571
|
+
"px-3 py-2 rounded-lg overflow-hidden transition-all hover:shadow-md h-full w-full",
|
|
1572
|
+
!enableDragToMove && "cursor-pointer"
|
|
1573
|
+
),
|
|
1574
|
+
style: {
|
|
1575
|
+
backgroundColor: `${eventColor}15`,
|
|
1576
|
+
borderLeft: `4px solid ${eventColor}`
|
|
1577
|
+
},
|
|
1578
|
+
title: event.title,
|
|
1579
|
+
onClick: (e) => handleEventClick(e, event),
|
|
1580
|
+
onDoubleClick: (e) => handleEventDoubleClick(e, event),
|
|
1581
|
+
children: eventContent
|
|
1582
|
+
}
|
|
1583
|
+
);
|
|
1584
|
+
return enableDragToMove ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1585
|
+
DraggableEvent,
|
|
1586
|
+
{
|
|
1587
|
+
event,
|
|
1588
|
+
className: "absolute left-2 right-2",
|
|
1589
|
+
style: { top: `${top}px`, height: `${height}px` },
|
|
1590
|
+
children: eventEl
|
|
1591
|
+
},
|
|
1592
|
+
event.id
|
|
1593
|
+
) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute left-2 right-2", style: { top: `${top}px`, height: `${height}px` }, children: eventEl }, event.id);
|
|
1594
|
+
})
|
|
1595
|
+
] })
|
|
1596
|
+
]
|
|
1597
|
+
}
|
|
1598
|
+
)
|
|
1599
|
+
}
|
|
1600
|
+
)
|
|
1601
|
+
] });
|
|
1602
|
+
}
|
|
1603
|
+
function ResourceView({ currentDate, events, resources }) {
|
|
1604
|
+
const {
|
|
1605
|
+
config,
|
|
1606
|
+
onEventClick,
|
|
1607
|
+
onEventDoubleClick,
|
|
1608
|
+
onSlotClick,
|
|
1609
|
+
onSlotDoubleClick,
|
|
1610
|
+
renderEvent,
|
|
1611
|
+
enableDragToCreate = false,
|
|
1612
|
+
enableDragToMove = false
|
|
1613
|
+
} = useCalendar();
|
|
1614
|
+
const days = getWeekDays(currentDate, config.weekStartsOn);
|
|
1615
|
+
const hours = getHoursArray(config.startHour, config.endHour);
|
|
1616
|
+
const today = /* @__PURE__ */ new Date();
|
|
1617
|
+
const hourHeight = 56;
|
|
1618
|
+
const totalHours = hours.length;
|
|
1619
|
+
const getResourceDayEvents = (resourceId, day) => {
|
|
1620
|
+
return events.filter(
|
|
1621
|
+
(event) => event.resourceId === resourceId && dateFns.isSameDay(event.start, day)
|
|
1622
|
+
);
|
|
1623
|
+
};
|
|
1624
|
+
const handleSlotClick = (day, hour, resourceId) => {
|
|
1625
|
+
if (onSlotClick) {
|
|
1626
|
+
const slotInfo = {
|
|
1627
|
+
start: createSlotDate(day, hour),
|
|
1628
|
+
end: createSlotDate(day, hour + 1),
|
|
1629
|
+
resourceId
|
|
1630
|
+
};
|
|
1631
|
+
onSlotClick(slotInfo);
|
|
1632
|
+
}
|
|
1633
|
+
};
|
|
1634
|
+
const handleSlotDoubleClick = (day, hour, resourceId) => {
|
|
1635
|
+
if (onSlotDoubleClick) {
|
|
1636
|
+
const slotInfo = {
|
|
1637
|
+
start: createSlotDate(day, hour),
|
|
1638
|
+
end: createSlotDate(day, hour + 1),
|
|
1639
|
+
resourceId
|
|
1640
|
+
};
|
|
1641
|
+
onSlotDoubleClick(slotInfo);
|
|
1642
|
+
}
|
|
1643
|
+
};
|
|
1644
|
+
const handleEventClick = (e, event) => {
|
|
1645
|
+
e.stopPropagation();
|
|
1646
|
+
onEventClick == null ? void 0 : onEventClick(event);
|
|
1647
|
+
};
|
|
1648
|
+
const handleEventDoubleClick = (e, event) => {
|
|
1649
|
+
e.stopPropagation();
|
|
1650
|
+
onEventDoubleClick == null ? void 0 : onEventDoubleClick(event);
|
|
1651
|
+
};
|
|
1652
|
+
if (resources.length === 0) {
|
|
1653
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center h-full text-muted-foreground", children: "No resources available. Add resources to use the resource view." });
|
|
1654
|
+
}
|
|
1655
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col h-full overflow-hidden", children: [
|
|
1656
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex border-b border-border shrink-0 bg-background z-10", children: [
|
|
1657
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-16 shrink-0 border-r border-border" }),
|
|
1658
|
+
resources.map((resource) => {
|
|
1659
|
+
const resourceColor = resource.color || config.defaultResourceColor;
|
|
1660
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1661
|
+
"div",
|
|
1662
|
+
{
|
|
1663
|
+
className: "flex-1 py-3 px-2 text-center border-r border-border last:border-r-0",
|
|
1664
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center gap-2", children: [
|
|
1665
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1666
|
+
"div",
|
|
1667
|
+
{
|
|
1668
|
+
className: "w-3 h-3 rounded-full shrink-0",
|
|
1669
|
+
style: { backgroundColor: resourceColor }
|
|
1670
|
+
}
|
|
1671
|
+
),
|
|
1672
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium text-foreground truncate", children: resource.name })
|
|
1673
|
+
] })
|
|
1674
|
+
},
|
|
1675
|
+
resource.id
|
|
1676
|
+
);
|
|
1677
|
+
})
|
|
1678
|
+
] }),
|
|
1679
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex border-b border-border shrink-0 bg-muted/50 z-10", children: [
|
|
1680
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-16 shrink-0 border-r border-border py-2 px-2 text-xs font-medium text-muted-foreground", children: "Week View" }),
|
|
1681
|
+
resources.map((resource) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 flex border-r border-border last:border-r-0", children: days.map((day, dayIndex) => {
|
|
1682
|
+
const isToday = dateFns.isSameDay(day, today);
|
|
1683
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1684
|
+
"div",
|
|
1685
|
+
{
|
|
1686
|
+
className: cn(
|
|
1687
|
+
"flex-1 py-2 text-center border-r border-border/50 last:border-r-0",
|
|
1688
|
+
isToday && "bg-primary/5"
|
|
1689
|
+
),
|
|
1690
|
+
children: [
|
|
1691
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-[10px] text-muted-foreground uppercase", children: formatDate(day, "EEE", config.locale) }),
|
|
1692
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1693
|
+
"div",
|
|
1694
|
+
{
|
|
1695
|
+
className: cn(
|
|
1696
|
+
"text-xs font-medium",
|
|
1697
|
+
isToday && "text-primary",
|
|
1698
|
+
!isToday && "text-foreground"
|
|
1699
|
+
),
|
|
1700
|
+
children: formatDate(day, "d", config.locale)
|
|
1701
|
+
}
|
|
1702
|
+
)
|
|
1703
|
+
]
|
|
1704
|
+
},
|
|
1705
|
+
dayIndex
|
|
1706
|
+
);
|
|
1707
|
+
}) }, resource.id))
|
|
1708
|
+
] }),
|
|
1709
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-1 overflow-y-auto min-h-0", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1710
|
+
"div",
|
|
1711
|
+
{
|
|
1712
|
+
className: "flex min-w-full",
|
|
1713
|
+
style: { minHeight: totalHours * hourHeight },
|
|
1714
|
+
children: [
|
|
1715
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-16 shrink-0 border-r border-border relative", children: [
|
|
1716
|
+
hours.map((hour, index) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1717
|
+
"div",
|
|
1718
|
+
{
|
|
1719
|
+
className: cn(
|
|
1720
|
+
"pr-2 flex items-start justify-end",
|
|
1721
|
+
index < totalHours - 1 && "border-b border-border"
|
|
1722
|
+
),
|
|
1723
|
+
style: { height: `${hourHeight}px` },
|
|
1724
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-muted-foreground -mt-1.5", children: formatHour(hour, config.timeFormat, config.locale) })
|
|
1725
|
+
},
|
|
1726
|
+
hour
|
|
1727
|
+
)),
|
|
1728
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute bottom-0 left-0 right-0 h-px bg-border" })
|
|
1729
|
+
] }),
|
|
1730
|
+
resources.map((resource) => {
|
|
1731
|
+
const resourceColor = resource.color || config.defaultResourceColor;
|
|
1732
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1733
|
+
"div",
|
|
1734
|
+
{
|
|
1735
|
+
className: "flex-1 flex border-r border-border last:border-r-0",
|
|
1736
|
+
children: days.map((day, dayIndex) => {
|
|
1737
|
+
const dayEvents = getResourceDayEvents(resource.id, day);
|
|
1738
|
+
const isToday = dateFns.isSameDay(day, today);
|
|
1739
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1740
|
+
"div",
|
|
1741
|
+
{
|
|
1742
|
+
className: cn(
|
|
1743
|
+
"flex-1 border-r border-border/50 last:border-r-0 relative",
|
|
1744
|
+
isToday && "bg-primary/5"
|
|
1745
|
+
),
|
|
1746
|
+
children: [
|
|
1747
|
+
hours.map((hour, index) => {
|
|
1748
|
+
const slotData = {
|
|
1749
|
+
view: "resource",
|
|
1750
|
+
day,
|
|
1751
|
+
hour,
|
|
1752
|
+
resourceId: resource.id
|
|
1753
|
+
};
|
|
1754
|
+
const slotContent = /* @__PURE__ */ jsxRuntime.jsx(
|
|
1755
|
+
"div",
|
|
1756
|
+
{
|
|
1757
|
+
className: cn(
|
|
1758
|
+
"cursor-pointer hover:bg-muted/30 transition-colors h-full w-full",
|
|
1759
|
+
index < totalHours - 1 && "border-b border-border"
|
|
1760
|
+
),
|
|
1761
|
+
style: { height: `${hourHeight}px` },
|
|
1762
|
+
onClick: () => handleSlotClick(day, hour, resource.id),
|
|
1763
|
+
onDoubleClick: () => handleSlotDoubleClick(day, hour, resource.id)
|
|
1764
|
+
}
|
|
1765
|
+
);
|
|
1766
|
+
return enableDragToCreate || enableDragToMove ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1767
|
+
DroppableSlot,
|
|
1768
|
+
{
|
|
1769
|
+
data: slotData,
|
|
1770
|
+
style: { height: `${hourHeight}px` },
|
|
1771
|
+
className: cn(index < totalHours - 1 && "border-b border-border"),
|
|
1772
|
+
children: enableDragToCreate ? /* @__PURE__ */ jsxRuntime.jsx(DraggableCreateSlot, { data: slotData, className: "h-full w-full", children: slotContent }) : slotContent
|
|
1773
|
+
},
|
|
1774
|
+
hour
|
|
1775
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1776
|
+
"div",
|
|
1777
|
+
{
|
|
1778
|
+
className: cn(
|
|
1779
|
+
"cursor-pointer hover:bg-muted/30 transition-colors",
|
|
1780
|
+
index < totalHours - 1 && "border-b border-border"
|
|
1781
|
+
),
|
|
1782
|
+
style: { height: `${hourHeight}px` },
|
|
1783
|
+
onClick: () => handleSlotClick(day, hour, resource.id),
|
|
1784
|
+
onDoubleClick: () => handleSlotDoubleClick(day, hour, resource.id)
|
|
1785
|
+
},
|
|
1786
|
+
hour
|
|
1787
|
+
);
|
|
1788
|
+
}),
|
|
1789
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute bottom-0 left-0 right-0 h-px bg-border" }),
|
|
1790
|
+
dayEvents.map((event) => {
|
|
1791
|
+
const { top, height } = getEventPosition(event, config.hourHeight, config.startHour);
|
|
1792
|
+
const scaledTop = top / config.hourHeight * hourHeight;
|
|
1793
|
+
const scaledHeight = height / config.hourHeight * hourHeight;
|
|
1794
|
+
const eventColor = event.color || resourceColor;
|
|
1795
|
+
const eventContent = renderEvent ? renderEvent(event, "resource") : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1796
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "truncate font-semibold", children: event.title }),
|
|
1797
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "truncate opacity-80", children: formatDate(event.start, "h:mm", config.locale) })
|
|
1798
|
+
] });
|
|
1799
|
+
const eventEl = /* @__PURE__ */ jsxRuntime.jsx(
|
|
1800
|
+
"div",
|
|
1801
|
+
{
|
|
1802
|
+
className: cn(
|
|
1803
|
+
"px-1 py-0.5 rounded text-[10px] font-medium overflow-hidden transition-opacity hover:opacity-90 h-full w-full",
|
|
1804
|
+
!enableDragToMove && "cursor-pointer"
|
|
1805
|
+
),
|
|
1806
|
+
style: {
|
|
1807
|
+
backgroundColor: `${eventColor}20`,
|
|
1808
|
+
borderLeft: `2px solid ${eventColor}`,
|
|
1809
|
+
color: eventColor
|
|
1810
|
+
},
|
|
1811
|
+
title: `${event.title} - ${resource.name}`,
|
|
1812
|
+
onClick: (e) => handleEventClick(e, event),
|
|
1813
|
+
onDoubleClick: (e) => handleEventDoubleClick(e, event),
|
|
1814
|
+
children: eventContent
|
|
1815
|
+
}
|
|
1816
|
+
);
|
|
1817
|
+
return enableDragToMove ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1818
|
+
DraggableEvent,
|
|
1819
|
+
{
|
|
1820
|
+
event,
|
|
1821
|
+
className: "absolute left-0.5 right-0.5",
|
|
1822
|
+
style: { top: `${scaledTop}px`, height: `${scaledHeight}px` },
|
|
1823
|
+
children: eventEl
|
|
1824
|
+
},
|
|
1825
|
+
event.id
|
|
1826
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1827
|
+
"div",
|
|
1828
|
+
{
|
|
1829
|
+
className: "absolute left-0.5 right-0.5",
|
|
1830
|
+
style: { top: `${scaledTop}px`, height: `${scaledHeight}px` },
|
|
1831
|
+
children: eventEl
|
|
1832
|
+
},
|
|
1833
|
+
event.id
|
|
1834
|
+
);
|
|
1835
|
+
})
|
|
1836
|
+
]
|
|
1837
|
+
},
|
|
1838
|
+
dayIndex
|
|
1839
|
+
);
|
|
1840
|
+
})
|
|
1841
|
+
},
|
|
1842
|
+
resource.id
|
|
1843
|
+
);
|
|
1844
|
+
})
|
|
1845
|
+
]
|
|
1846
|
+
}
|
|
1847
|
+
) })
|
|
1848
|
+
] });
|
|
1849
|
+
}
|
|
1850
|
+
function EventCalendar({
|
|
1851
|
+
events,
|
|
1852
|
+
resources = [],
|
|
1853
|
+
date,
|
|
1854
|
+
defaultDate = /* @__PURE__ */ new Date(),
|
|
1855
|
+
view,
|
|
1856
|
+
defaultView = "month",
|
|
1857
|
+
views = ["month", "week", "day", "resource"],
|
|
1858
|
+
calendarOptions = {},
|
|
1859
|
+
showNavigation = true,
|
|
1860
|
+
showViewSwitcher = true,
|
|
1861
|
+
showTodayButton = true,
|
|
1862
|
+
className,
|
|
1863
|
+
loading = false,
|
|
1864
|
+
theme = "system",
|
|
1865
|
+
themeVars,
|
|
1866
|
+
enableDragToCreate = false,
|
|
1867
|
+
enableDragToMove = false,
|
|
1868
|
+
mobileBreakpoint = "md",
|
|
1869
|
+
showMobileMonthPicker = true,
|
|
1870
|
+
onEventClick,
|
|
1871
|
+
onEventDoubleClick,
|
|
1872
|
+
onSlotClick,
|
|
1873
|
+
onSlotDoubleClick,
|
|
1874
|
+
onDateChange,
|
|
1875
|
+
onViewChange,
|
|
1876
|
+
onNavigate,
|
|
1877
|
+
onRangeChange,
|
|
1878
|
+
onDayClick,
|
|
1879
|
+
onEventCreate,
|
|
1880
|
+
onEventMove,
|
|
1881
|
+
renderEvent,
|
|
1882
|
+
renderDayCell,
|
|
1883
|
+
renderHeader,
|
|
1884
|
+
renderResourceHeader,
|
|
1885
|
+
renderTimeSlot,
|
|
1886
|
+
renderEmpty,
|
|
1887
|
+
renderSelectedEvent,
|
|
1888
|
+
renderSelectedSlot
|
|
1889
|
+
}) {
|
|
1890
|
+
const [internalDate, setInternalDate] = React2.useState(defaultDate);
|
|
1891
|
+
const [selectedEvent, setSelectedEvent] = React2.useState(null);
|
|
1892
|
+
const [selectedSlot, setSelectedSlot] = React2.useState(null);
|
|
1893
|
+
const currentDate = date != null ? date : internalDate;
|
|
1894
|
+
const isMobile = useMediaQuery(mobileBreakpoint);
|
|
1895
|
+
const [internalView, setInternalView] = React2.useState(defaultView);
|
|
1896
|
+
const currentView = view != null ? view : internalView;
|
|
1897
|
+
const config = React2.useMemo(
|
|
1898
|
+
() => {
|
|
1899
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
|
|
1900
|
+
return {
|
|
1901
|
+
weekStartsOn: (_a = calendarOptions.weekStartsOn) != null ? _a : defaultConfig.weekStartsOn,
|
|
1902
|
+
startHour: (_b = calendarOptions.startHour) != null ? _b : defaultConfig.startHour,
|
|
1903
|
+
endHour: (_c = calendarOptions.endHour) != null ? _c : defaultConfig.endHour,
|
|
1904
|
+
hourHeight: (_d = calendarOptions.hourHeight) != null ? _d : defaultConfig.hourHeight,
|
|
1905
|
+
maxEventsPerDay: (_e = calendarOptions.maxEventsPerDay) != null ? _e : defaultConfig.maxEventsPerDay,
|
|
1906
|
+
timeSeriesMaxHeight: (_f = calendarOptions.timeSeriesMaxHeight) != null ? _f : defaultConfig.timeSeriesMaxHeight,
|
|
1907
|
+
showCurrentTimeLine: (_g = calendarOptions.showCurrentTimeLine) != null ? _g : defaultConfig.showCurrentTimeLine,
|
|
1908
|
+
defaultEventColor: (_h = calendarOptions.defaultEventColor) != null ? _h : defaultConfig.defaultEventColor,
|
|
1909
|
+
defaultResourceColor: (_i = calendarOptions.defaultResourceColor) != null ? _i : defaultConfig.defaultResourceColor,
|
|
1910
|
+
locale: (_j = calendarOptions.locale) != null ? _j : defaultConfig.locale,
|
|
1911
|
+
timeFormat: (_k = calendarOptions.timeFormat) != null ? _k : defaultConfig.timeFormat
|
|
1912
|
+
};
|
|
1913
|
+
},
|
|
1914
|
+
[calendarOptions]
|
|
1915
|
+
);
|
|
1916
|
+
const effectiveView = isMobile ? ["week", "day", "2day"].includes(currentView) ? currentView : "week" : currentView;
|
|
1917
|
+
const handleNavigate = React2.useCallback(
|
|
1918
|
+
(direction) => {
|
|
1919
|
+
const newDate = navigateDate(currentDate, effectiveView, direction);
|
|
1920
|
+
if (date === void 0) {
|
|
1921
|
+
setInternalDate(newDate);
|
|
1922
|
+
}
|
|
1923
|
+
onDateChange == null ? void 0 : onDateChange(newDate);
|
|
1924
|
+
onNavigate == null ? void 0 : onNavigate(newDate, direction);
|
|
1925
|
+
},
|
|
1926
|
+
[currentDate, effectiveView, date, onDateChange, onNavigate]
|
|
1927
|
+
);
|
|
1928
|
+
const handleWeekNavigate = React2.useCallback(
|
|
1929
|
+
(direction) => {
|
|
1930
|
+
const newDate = direction === "next" ? dateFns.addWeeks(currentDate, 1) : dateFns.subWeeks(currentDate, 1);
|
|
1931
|
+
if (date === void 0) {
|
|
1932
|
+
setInternalDate(newDate);
|
|
1933
|
+
}
|
|
1934
|
+
onDateChange == null ? void 0 : onDateChange(newDate);
|
|
1935
|
+
},
|
|
1936
|
+
[currentDate, date, onDateChange]
|
|
1937
|
+
);
|
|
1938
|
+
const handleDateSelect = React2.useCallback(
|
|
1939
|
+
(newDate) => {
|
|
1940
|
+
if (date === void 0) {
|
|
1941
|
+
setInternalDate(newDate);
|
|
1942
|
+
}
|
|
1943
|
+
onDateChange == null ? void 0 : onDateChange(newDate);
|
|
1944
|
+
},
|
|
1945
|
+
[date, onDateChange]
|
|
1946
|
+
);
|
|
1947
|
+
const handleToday = React2.useCallback(() => {
|
|
1948
|
+
const today = /* @__PURE__ */ new Date();
|
|
1949
|
+
if (date === void 0) {
|
|
1950
|
+
setInternalDate(today);
|
|
1951
|
+
}
|
|
1952
|
+
onDateChange == null ? void 0 : onDateChange(today);
|
|
1953
|
+
onNavigate == null ? void 0 : onNavigate(today, "today");
|
|
1954
|
+
}, [date, onDateChange, onNavigate]);
|
|
1955
|
+
const handleViewChange = React2.useCallback(
|
|
1956
|
+
(newView) => {
|
|
1957
|
+
if (view === void 0) {
|
|
1958
|
+
setInternalView(newView);
|
|
1959
|
+
}
|
|
1960
|
+
onViewChange == null ? void 0 : onViewChange(newView);
|
|
1961
|
+
},
|
|
1962
|
+
[view, onViewChange]
|
|
1963
|
+
);
|
|
1964
|
+
const handleEventClick = React2.useCallback(
|
|
1965
|
+
(event) => {
|
|
1966
|
+
onEventClick == null ? void 0 : onEventClick(event);
|
|
1967
|
+
if (renderSelectedEvent) {
|
|
1968
|
+
setSelectedEvent(event);
|
|
1969
|
+
setSelectedSlot(null);
|
|
1970
|
+
}
|
|
1971
|
+
},
|
|
1972
|
+
[onEventClick, renderSelectedEvent]
|
|
1973
|
+
);
|
|
1974
|
+
const handleSlotClick = React2.useCallback(
|
|
1975
|
+
(slot) => {
|
|
1976
|
+
onSlotClick == null ? void 0 : onSlotClick(slot);
|
|
1977
|
+
if (renderSelectedSlot) {
|
|
1978
|
+
setSelectedSlot(slot);
|
|
1979
|
+
setSelectedEvent(null);
|
|
1980
|
+
}
|
|
1981
|
+
},
|
|
1982
|
+
[onSlotClick, renderSelectedSlot]
|
|
1983
|
+
);
|
|
1984
|
+
const handleCloseSelected = React2.useCallback(() => {
|
|
1985
|
+
setSelectedEvent(null);
|
|
1986
|
+
setSelectedSlot(null);
|
|
1987
|
+
}, []);
|
|
1988
|
+
const contextValue = React2.useMemo(
|
|
1989
|
+
() => ({
|
|
1990
|
+
currentDate,
|
|
1991
|
+
view: currentView,
|
|
1992
|
+
events,
|
|
1993
|
+
resources,
|
|
1994
|
+
config,
|
|
1995
|
+
onEventClick: renderSelectedEvent ? handleEventClick : onEventClick,
|
|
1996
|
+
onEventDoubleClick,
|
|
1997
|
+
onSlotClick: renderSelectedSlot ? handleSlotClick : onSlotClick,
|
|
1998
|
+
onSlotDoubleClick,
|
|
1999
|
+
onDayClick,
|
|
2000
|
+
renderEvent,
|
|
2001
|
+
enableDragToCreate,
|
|
2002
|
+
enableDragToMove,
|
|
2003
|
+
onEventCreate,
|
|
2004
|
+
onEventMove
|
|
2005
|
+
}),
|
|
2006
|
+
[
|
|
2007
|
+
currentDate,
|
|
2008
|
+
currentView,
|
|
2009
|
+
events,
|
|
2010
|
+
resources,
|
|
2011
|
+
config,
|
|
2012
|
+
renderSelectedEvent,
|
|
2013
|
+
renderSelectedSlot,
|
|
2014
|
+
handleEventClick,
|
|
2015
|
+
handleSlotClick,
|
|
2016
|
+
onEventClick,
|
|
2017
|
+
onEventDoubleClick,
|
|
2018
|
+
onSlotClick,
|
|
2019
|
+
onSlotDoubleClick,
|
|
2020
|
+
onDayClick,
|
|
2021
|
+
renderEvent,
|
|
2022
|
+
enableDragToCreate,
|
|
2023
|
+
enableDragToMove,
|
|
2024
|
+
onEventCreate,
|
|
2025
|
+
onEventMove
|
|
2026
|
+
]
|
|
2027
|
+
);
|
|
2028
|
+
const mobileViews = ["week", "day", "2day"];
|
|
2029
|
+
const title = getViewTitle(currentDate, effectiveView, config.weekStartsOn, config.locale);
|
|
2030
|
+
React2.useEffect(() => {
|
|
2031
|
+
if (onRangeChange) {
|
|
2032
|
+
const range = getViewDateRange(currentDate, effectiveView, config.weekStartsOn);
|
|
2033
|
+
onRangeChange(range);
|
|
2034
|
+
}
|
|
2035
|
+
}, [currentDate, effectiveView, config.weekStartsOn, onRangeChange]);
|
|
2036
|
+
const availableViews = (isMobile ? mobileViews : views).filter((v) => {
|
|
2037
|
+
if (v === "resource" && resources.length === 0) return false;
|
|
2038
|
+
return true;
|
|
2039
|
+
});
|
|
2040
|
+
const calendarContent = /* @__PURE__ */ jsxRuntime.jsx(CalendarProvider, { value: contextValue, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2041
|
+
Card,
|
|
2042
|
+
{
|
|
2043
|
+
className: cn(
|
|
2044
|
+
"flex flex-col h-full overflow-hidden border-border",
|
|
2045
|
+
isMobile && "gap-0 py-0",
|
|
2046
|
+
className
|
|
2047
|
+
),
|
|
2048
|
+
children: [
|
|
2049
|
+
(showNavigation || showViewSwitcher) && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2050
|
+
"div",
|
|
2051
|
+
{
|
|
2052
|
+
className: cn(
|
|
2053
|
+
"bg-card",
|
|
2054
|
+
isMobile ? "px-3 py-2 border-b border-border relative z-10 rounded-t-xl shadow-[0_4px_24px_rgba(0,0,0,0.12),0_8px_40px_rgba(0,0,0,0.1),0_12px_48px_rgba(0,0,0,0.08)] dark:shadow-[0_4px_24px_rgba(0,0,0,0.35),0_8px_40px_rgba(0,0,0,0.3),0_12px_48px_rgba(0,0,0,0.2)]" : "p-4 border-b border-border"
|
|
2055
|
+
),
|
|
2056
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2057
|
+
CalendarHeader,
|
|
2058
|
+
{
|
|
2059
|
+
currentDate,
|
|
2060
|
+
view: effectiveView,
|
|
2061
|
+
views: availableViews,
|
|
2062
|
+
title,
|
|
2063
|
+
showNavigation,
|
|
2064
|
+
showViewSwitcher,
|
|
2065
|
+
showTodayButton,
|
|
2066
|
+
isMobile,
|
|
2067
|
+
showMobileMonthPicker,
|
|
2068
|
+
weekStartsOn: config.weekStartsOn,
|
|
2069
|
+
locale: config.locale,
|
|
2070
|
+
onNavigate: handleNavigate,
|
|
2071
|
+
onViewChange: handleViewChange,
|
|
2072
|
+
onToday: handleToday,
|
|
2073
|
+
onDateSelect: isMobile ? handleDateSelect : void 0,
|
|
2074
|
+
onWeekNavigate: isMobile ? handleWeekNavigate : void 0,
|
|
2075
|
+
renderHeader
|
|
2076
|
+
}
|
|
2077
|
+
)
|
|
2078
|
+
}
|
|
2079
|
+
),
|
|
2080
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2081
|
+
"div",
|
|
2082
|
+
{
|
|
2083
|
+
className: cn(
|
|
2084
|
+
"flex-1 overflow-hidden relative",
|
|
2085
|
+
isMobile && "rounded-b-xl bg-background shadow-[inset_0_8px_12px_-6px_rgba(0,0,0,0.1),0_2px_8px_rgba(0,0,0,0.06)] dark:shadow-[inset_0_8px_12px_-6px_rgba(0,0,0,0.25),0_2px_8px_rgba(0,0,0,0.15)]"
|
|
2086
|
+
),
|
|
2087
|
+
children: [
|
|
2088
|
+
loading && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 bg-background/50 flex items-center justify-center z-20", children: /* @__PURE__ */ jsxRuntime.jsx(Spinner, { className: "h-8 w-8" }) }),
|
|
2089
|
+
events.length === 0 && renderEmpty ? renderEmpty() : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2090
|
+
effectiveView === "month" && /* @__PURE__ */ jsxRuntime.jsx(MonthView, { currentDate, events }),
|
|
2091
|
+
(effectiveView === "week" || effectiveView === "2day") && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2092
|
+
WeekView,
|
|
2093
|
+
{
|
|
2094
|
+
currentDate,
|
|
2095
|
+
events,
|
|
2096
|
+
dayCount: effectiveView === "2day" ? 2 : void 0,
|
|
2097
|
+
isMobile
|
|
2098
|
+
}
|
|
2099
|
+
),
|
|
2100
|
+
effectiveView === "day" && /* @__PURE__ */ jsxRuntime.jsx(DayView, { currentDate, events }),
|
|
2101
|
+
effectiveView === "resource" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2102
|
+
ResourceView,
|
|
2103
|
+
{
|
|
2104
|
+
currentDate,
|
|
2105
|
+
events,
|
|
2106
|
+
resources
|
|
2107
|
+
}
|
|
2108
|
+
)
|
|
2109
|
+
] })
|
|
2110
|
+
]
|
|
2111
|
+
}
|
|
2112
|
+
),
|
|
2113
|
+
renderSelectedEvent && /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: renderSelectedEvent({
|
|
2114
|
+
event: selectedEvent,
|
|
2115
|
+
onClose: handleCloseSelected
|
|
2116
|
+
}) }),
|
|
2117
|
+
renderSelectedSlot && /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: renderSelectedSlot({
|
|
2118
|
+
slot: selectedSlot,
|
|
2119
|
+
onClose: handleCloseSelected
|
|
2120
|
+
}) })
|
|
2121
|
+
]
|
|
2122
|
+
}
|
|
2123
|
+
) });
|
|
2124
|
+
const wrappedContent = enableDragToCreate || enableDragToMove ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2125
|
+
EventCalendarDndProvider,
|
|
2126
|
+
{
|
|
2127
|
+
enableDragToCreate,
|
|
2128
|
+
enableDragToMove,
|
|
2129
|
+
onEventCreate,
|
|
2130
|
+
onEventMove,
|
|
2131
|
+
defaultEventColor: config.defaultEventColor,
|
|
2132
|
+
locale: config.locale,
|
|
2133
|
+
renderEvent,
|
|
2134
|
+
children: calendarContent
|
|
2135
|
+
}
|
|
2136
|
+
) : calendarContent;
|
|
2137
|
+
if (theme || themeVars) {
|
|
2138
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2139
|
+
EventCalendarThemeProvider,
|
|
2140
|
+
{
|
|
2141
|
+
theme: theme != null ? theme : "system",
|
|
2142
|
+
themeVars,
|
|
2143
|
+
children: wrappedContent
|
|
2144
|
+
}
|
|
2145
|
+
);
|
|
2146
|
+
}
|
|
2147
|
+
return wrappedContent;
|
|
2148
|
+
}
|
|
2149
|
+
|
|
2150
|
+
exports.EventCalendar = EventCalendar;
|
|
2151
|
+
exports.EventCalendarThemeProvider = EventCalendarThemeProvider;
|
|
2152
|
+
exports.createSlotDate = createSlotDate;
|
|
2153
|
+
exports.formatDate = formatDate;
|
|
2154
|
+
exports.formatHour = formatHour;
|
|
2155
|
+
exports.getDateFnsLocale = getDateFnsLocale;
|
|
2156
|
+
exports.getEventsForDay = getEventsForDay;
|
|
2157
|
+
exports.getHoursArray = getHoursArray;
|
|
2158
|
+
exports.getMonthDays = getMonthDays;
|
|
2159
|
+
exports.getViewDateRange = getViewDateRange;
|
|
2160
|
+
exports.getViewTitle = getViewTitle;
|
|
2161
|
+
exports.getWeekDays = getWeekDays;
|
|
2162
|
+
exports.navigateDate = navigateDate;
|
|
2163
|
+
exports.useCalendar = useCalendar;
|
|
2164
|
+
//# sourceMappingURL=index.js.map
|
|
2165
|
+
//# sourceMappingURL=index.js.map
|