calendarkit-pro 1.1.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/dist/index.js ADDED
@@ -0,0 +1,2844 @@
1
+ 'use strict';
2
+
3
+ var React15 = require('react');
4
+ var core = require('@dnd-kit/core');
5
+ var modifiers = require('@dnd-kit/modifiers');
6
+ var framerMotion = require('framer-motion');
7
+ var dateFns = require('date-fns');
8
+ var classVarianceAuthority = require('class-variance-authority');
9
+ var clsx = require('clsx');
10
+ var tailwindMerge = require('tailwind-merge');
11
+ var lucideReact = require('lucide-react');
12
+ var dateFnsTz = require('date-fns-tz');
13
+ var utilities = require('@dnd-kit/utilities');
14
+ var rrule = require('rrule');
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 React15__namespace = /*#__PURE__*/_interopNamespace(React15);
35
+
36
+ function cn(...inputs) {
37
+ return tailwindMerge.twMerge(clsx.clsx(inputs));
38
+ }
39
+
40
+ // src/components/ui/button.tsx
41
+ var buttonVariants = classVarianceAuthority.cva(
42
+ "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
43
+ {
44
+ variants: {
45
+ variant: {
46
+ default: "bg-primary text-primary-foreground hover:bg-primary/90",
47
+ destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
48
+ outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
49
+ secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
50
+ ghost: "hover:bg-accent hover:text-accent-foreground",
51
+ link: "text-primary underline-offset-4 hover:underline"
52
+ },
53
+ size: {
54
+ default: "h-10 px-4 py-2",
55
+ sm: "h-9 rounded-md px-3",
56
+ lg: "h-11 rounded-md px-8",
57
+ icon: "h-10 w-10"
58
+ }
59
+ },
60
+ defaultVariants: {
61
+ variant: "default",
62
+ size: "default"
63
+ }
64
+ }
65
+ );
66
+ var Button = React15__namespace.forwardRef(
67
+ ({ className, variant, size, asChild = false, ...props }, ref) => {
68
+ const Comp = "button";
69
+ return /* @__PURE__ */ React15__namespace.createElement(
70
+ Comp,
71
+ {
72
+ className: cn(buttonVariants({ variant, size, className })),
73
+ ref,
74
+ ...props
75
+ }
76
+ );
77
+ }
78
+ );
79
+ Button.displayName = "Button";
80
+ var CalendarHeader = ({
81
+ currentDate,
82
+ onPrev,
83
+ onNext,
84
+ onToday,
85
+ view,
86
+ onViewChange,
87
+ onMenuClick,
88
+ isDarkMode,
89
+ onThemeToggle,
90
+ translations,
91
+ hideViewSwitcher,
92
+ language,
93
+ onLanguageChange,
94
+ locale
95
+ }) => {
96
+ const viewConfig = [
97
+ { key: "month", icon: lucideReact.CalendarDays },
98
+ { key: "week", icon: lucideReact.CalendarRange },
99
+ { key: "day", icon: lucideReact.Calendar },
100
+ { key: "agenda", icon: lucideReact.ListTodo }
101
+ ];
102
+ return /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex flex-col md:flex-row items-center justify-between px-3 md:px-5 py-3 border-b-[0px] border-border/50 bg-gradient-to-r from-background via-background to-muted/20 gap-3 md:gap-0 min-h-[64px]" }, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex items-center gap-2 w-full md:w-auto justify-between md:justify-start" }, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex items-center gap-2 md:gap-3" }, /* @__PURE__ */ React15__namespace.default.createElement(
103
+ Button,
104
+ {
105
+ variant: "ghost",
106
+ size: "icon",
107
+ className: "text-muted-foreground hover:text-foreground hover:bg-accent/80 rounded-xl h-10 w-10 hidden md:inline-flex transition-all duration-200",
108
+ onClick: onMenuClick
109
+ },
110
+ /* @__PURE__ */ React15__namespace.default.createElement(lucideReact.Menu, { className: "h-5 w-5" })
111
+ ), /* @__PURE__ */ React15__namespace.default.createElement(
112
+ Button,
113
+ {
114
+ variant: "outline",
115
+ onClick: onToday,
116
+ className: "h-9 px-5 rounded-xl text-sm font-medium hidden sm:inline-flex border-[0.5px] border-border/60 hover:border-primary/40 hover:bg-primary/5 hover:text-primary transition-all duration-200"
117
+ },
118
+ translations.today
119
+ ), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex items-center bg-muted/40 rounded-xl p-0.5" }, /* @__PURE__ */ React15__namespace.default.createElement(
120
+ Button,
121
+ {
122
+ variant: "ghost",
123
+ size: "icon",
124
+ onClick: onPrev,
125
+ className: "rounded-lg h-8 w-8 hover:bg-background/80 transition-all duration-200"
126
+ },
127
+ /* @__PURE__ */ React15__namespace.default.createElement(lucideReact.ChevronLeft, { className: "h-4 w-4 text-muted-foreground" })
128
+ ), /* @__PURE__ */ React15__namespace.default.createElement(
129
+ Button,
130
+ {
131
+ variant: "ghost",
132
+ size: "icon",
133
+ onClick: onNext,
134
+ className: "rounded-lg h-8 w-8 hover:bg-background/80 transition-all duration-200"
135
+ },
136
+ /* @__PURE__ */ React15__namespace.default.createElement(lucideReact.ChevronRight, { className: "h-4 w-4 text-muted-foreground" })
137
+ )), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "ml-2 md:ml-4" }, /* @__PURE__ */ React15__namespace.default.createElement("h2", { className: "text-lg md:text-xl font-semibold text-foreground whitespace-nowrap capitalize tracking-tight" }, dateFns.format(currentDate, "MMMM yyyy", { locale }))))), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex items-center gap-2 md:gap-3 w-full md:w-auto justify-end" }, onLanguageChange && language && /* @__PURE__ */ React15__namespace.default.createElement(
138
+ Button,
139
+ {
140
+ variant: "ghost",
141
+ size: "sm",
142
+ onClick: () => onLanguageChange(language === "en" ? "fr" : "en"),
143
+ className: "h-9 px-3 rounded-xl text-xs font-semibold text-muted-foreground hover:text-foreground hover:bg-accent/80 transition-all duration-200 uppercase tracking-wider"
144
+ },
145
+ language
146
+ ), onThemeToggle && /* @__PURE__ */ React15__namespace.default.createElement(
147
+ Button,
148
+ {
149
+ variant: "ghost",
150
+ size: "icon",
151
+ className: "rounded-xl h-9 w-9 hover:bg-accent/80 transition-all duration-200",
152
+ onClick: onThemeToggle
153
+ },
154
+ isDarkMode ? /* @__PURE__ */ React15__namespace.default.createElement(lucideReact.Sun, { className: "h-4 w-4 text-amber-500" }) : /* @__PURE__ */ React15__namespace.default.createElement(lucideReact.Moon, { className: "h-4 w-4 text-muted-foreground" })
155
+ ), !hideViewSwitcher && /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex items-center bg-muted/50 backdrop-blur-sm rounded-xl p-1" }, viewConfig.map(({ key, icon: Icon }) => /* @__PURE__ */ React15__namespace.default.createElement(
156
+ Button,
157
+ {
158
+ key,
159
+ variant: "ghost",
160
+ size: "sm",
161
+ onClick: () => onViewChange(key),
162
+ className: cn(
163
+ "h-8 px-3 text-xs rounded-lg transition-all duration-200 gap-1.5",
164
+ view === key ? "bg-background shadow-sm text-foreground font-medium border-[0.5px] border-border/50" : "text-muted-foreground hover:text-foreground hover:bg-background/50"
165
+ )
166
+ },
167
+ /* @__PURE__ */ React15__namespace.default.createElement(Icon, { className: "h-3.5 w-3.5" }),
168
+ /* @__PURE__ */ React15__namespace.default.createElement("span", { className: "hidden sm:inline" }, translations[key])
169
+ )))));
170
+ };
171
+ var getMonthGrid = (date, weekStartOn = 0) => {
172
+ const monthStart = dateFns.startOfMonth(date);
173
+ const monthEnd = dateFns.endOfMonth(monthStart);
174
+ const startDate = dateFns.startOfWeek(monthStart, { weekStartsOn: weekStartOn });
175
+ const endDate = dateFns.endOfWeek(monthEnd, { weekStartsOn: weekStartOn });
176
+ return dateFns.eachDayOfInterval({
177
+ start: startDate,
178
+ end: endDate
179
+ });
180
+ };
181
+ var MiniCalendar = ({
182
+ currentDate,
183
+ onDateChange,
184
+ onViewChange,
185
+ className
186
+ }) => {
187
+ const [viewDate, setViewDate] = React15__namespace.default.useState(currentDate);
188
+ React15__namespace.default.useEffect(() => {
189
+ setViewDate(currentDate);
190
+ }, [currentDate]);
191
+ const days = React15__namespace.default.useMemo(() => getMonthGrid(viewDate), [viewDate]);
192
+ const weekDays = ["S", "M", "T", "W", "T", "F", "S"];
193
+ const handlePrev = () => {
194
+ const newDate = dateFns.subMonths(viewDate, 1);
195
+ setViewDate(newDate);
196
+ onDateChange(newDate);
197
+ if (onViewChange) onViewChange("month");
198
+ };
199
+ const handleNext = () => {
200
+ const newDate = dateFns.addMonths(viewDate, 1);
201
+ setViewDate(newDate);
202
+ onDateChange(newDate);
203
+ if (onViewChange) onViewChange("month");
204
+ };
205
+ const handleDateClick = (day) => {
206
+ onDateChange(day);
207
+ if (onViewChange) onViewChange("day");
208
+ };
209
+ return /* @__PURE__ */ React15__namespace.default.createElement("div", { className: cn("px-4 w-[260px]", className) }, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex items-center justify-between mb-4" }, /* @__PURE__ */ React15__namespace.default.createElement("span", { className: "text-sm font-semibold text-foreground capitalize" }, dateFns.format(viewDate, "MMMM yyyy")), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex items-center bg-muted/40 rounded-lg p-0.5" }, /* @__PURE__ */ React15__namespace.default.createElement(
210
+ Button,
211
+ {
212
+ variant: "ghost",
213
+ size: "icon",
214
+ className: "h-7 w-7 rounded-md hover:bg-background/80 transition-all",
215
+ onClick: handlePrev,
216
+ "aria-label": "Previous month"
217
+ },
218
+ /* @__PURE__ */ React15__namespace.default.createElement(lucideReact.ChevronLeft, { className: "h-4 w-4" })
219
+ ), /* @__PURE__ */ React15__namespace.default.createElement(
220
+ Button,
221
+ {
222
+ variant: "ghost",
223
+ size: "icon",
224
+ className: "h-7 w-7 rounded-md hover:bg-background/80 transition-all",
225
+ onClick: handleNext,
226
+ "aria-label": "Next month"
227
+ },
228
+ /* @__PURE__ */ React15__namespace.default.createElement(lucideReact.ChevronRight, { className: "h-4 w-4" })
229
+ ))), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "grid grid-cols-7 gap-y-2 text-center mb-2" }, weekDays.map((day, i) => /* @__PURE__ */ React15__namespace.default.createElement("div", { key: `${day}-${i}`, className: "text-[10px] text-muted-foreground/70 font-semibold uppercase" }, day))), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "grid grid-cols-7 gap-y-1 text-center" }, days.map((day) => {
230
+ const isSelected = dateFns.isSameDay(day, currentDate);
231
+ const isCurrentMonth = dateFns.isSameMonth(day, viewDate);
232
+ const isTodayDate = dateFns.isToday(day);
233
+ return /* @__PURE__ */ React15__namespace.default.createElement(
234
+ "button",
235
+ {
236
+ key: day.toISOString(),
237
+ onClick: () => handleDateClick(day),
238
+ className: cn(
239
+ "h-8 w-8 mx-auto flex items-center justify-center text-xs rounded-xl transition-all duration-200 font-medium",
240
+ !isCurrentMonth && "text-muted-foreground/30",
241
+ isCurrentMonth && !isSelected && !isTodayDate && "text-foreground hover:bg-accent/80",
242
+ isSelected && "bg-primary text-primary-foreground shadow-md shadow-primary/30 scale-105",
243
+ !isSelected && isTodayDate && "bg-primary/10 text-primary ring-1 ring-primary/30"
244
+ )
245
+ },
246
+ dateFns.format(day, "d")
247
+ );
248
+ })));
249
+ };
250
+ var Sidebar = ({
251
+ currentDate,
252
+ onDateChange,
253
+ onViewChange,
254
+ onEventCreate,
255
+ timezone,
256
+ onTimezoneChange,
257
+ className,
258
+ readOnly,
259
+ calendars,
260
+ onCalendarToggle,
261
+ translations
262
+ }) => {
263
+ const [calendarsOpen, setCalendarsOpen] = React15.useState(true);
264
+ const [timezoneOpen, setTimezoneOpen] = React15.useState(false);
265
+ const [now, setNow] = React15.useState(null);
266
+ const [hasMounted, setHasMounted] = React15.useState(false);
267
+ React15.useEffect(() => {
268
+ setHasMounted(true);
269
+ setNow(/* @__PURE__ */ new Date());
270
+ const timer = setInterval(() => setNow(/* @__PURE__ */ new Date()), 6e4);
271
+ return () => clearInterval(timer);
272
+ }, []);
273
+ const defaultCalendars = [
274
+ { id: "1", label: "My Calendar", color: "#3b82f6", active: true },
275
+ { id: "2", label: "Birthdays", color: "#10b981", active: true },
276
+ { id: "3", label: "Tasks", color: "#6366f1", active: true }
277
+ ];
278
+ const displayCalendars = calendars || defaultCalendars;
279
+ const getAcronym = (tz) => {
280
+ if (!tz || !now) return "LOC";
281
+ try {
282
+ return new Intl.DateTimeFormat("en-US", { timeZone: tz, timeZoneName: "short" }).formatToParts(now).find((part) => part.type === "timeZoneName")?.value || "";
283
+ } catch (e) {
284
+ return "";
285
+ }
286
+ };
287
+ const timezones = [
288
+ { value: "", label: "Local Time", acronym: "LOC" },
289
+ { value: "UTC", label: "UTC", acronym: "UTC" },
290
+ { value: "America/New_York", label: "New York", acronym: "EST" },
291
+ { value: "America/Chicago", label: "Chicago", acronym: "CST" },
292
+ { value: "America/Denver", label: "Denver", acronym: "MST" },
293
+ { value: "America/Los_Angeles", label: "Los Angeles", acronym: "PST" },
294
+ { value: "Europe/London", label: "London", acronym: "GMT" },
295
+ { value: "Europe/Paris", label: "Paris", acronym: "CET" },
296
+ { value: "Europe/Berlin", label: "Berlin", acronym: "CET" },
297
+ { value: "Asia/Dubai", label: "Dubai", acronym: "GST" },
298
+ { value: "Asia/Tokyo", label: "Tokyo", acronym: "JST" },
299
+ { value: "Asia/Singapore", label: "Singapore", acronym: "SGT" },
300
+ { value: "Australia/Sydney", label: "Sydney", acronym: "AEDT" }
301
+ ];
302
+ const formatTzLabel = (tz, showTime = true) => {
303
+ if (!hasMounted || !now || !showTime) {
304
+ return /* @__PURE__ */ React15__namespace.default.createElement("span", null, tz.label);
305
+ }
306
+ let time = "";
307
+ let acronym = tz.acronym;
308
+ try {
309
+ if (!tz.value) {
310
+ time = dateFns.format(now, "HH:mm");
311
+ try {
312
+ acronym = new Intl.DateTimeFormat("en-US", { timeZoneName: "short" }).formatToParts(now).find((part) => part.type === "timeZoneName")?.value || "LOC";
313
+ } catch (e) {
314
+ }
315
+ } else {
316
+ const zDate = dateFnsTz.toZonedTime(now, tz.value);
317
+ time = dateFns.format(zDate, "HH:mm");
318
+ const dynAcronym = getAcronym(tz.value);
319
+ if (dynAcronym && !dynAcronym.includes("GMT") && !dynAcronym.includes("Time")) {
320
+ acronym = dynAcronym;
321
+ }
322
+ }
323
+ } catch (e) {
324
+ return /* @__PURE__ */ React15__namespace.default.createElement("span", null, tz.label);
325
+ }
326
+ return /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex justify-between w-full" }, /* @__PURE__ */ React15__namespace.default.createElement("span", null, tz.label), /* @__PURE__ */ React15__namespace.default.createElement("span", { className: "text-muted-foreground ml-2 tabular-nums" }, time, " ", /* @__PURE__ */ React15__namespace.default.createElement("span", { className: "text-xs opacity-75" }, "(", acronym, ")")));
327
+ };
328
+ const selectedTzObj = timezones.find((t) => t.value === (timezone || ""));
329
+ const selectedTimezoneLabel = selectedTzObj ? formatTzLabel(selectedTzObj) : translations?.localTime || "Local Time";
330
+ return /* @__PURE__ */ React15__namespace.default.createElement("div", { className: cn("flex flex-col w-[260px] overflow-x-hidden h-full bg-gradient-to-b scrollbar-hide from-background via-background to-muted/10 pt-4 pb-4 overflow-y-auto hidden lg:flex", className) }, !readOnly && /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "px-4 mb-6" }, /* @__PURE__ */ React15__namespace.default.createElement(
331
+ Button,
332
+ {
333
+ className: "w-full rounded-2xl shadow-lg bg-primary text-primary-foreground hover:bg-primary/90 h-12 gap-3 justify-center transition-all duration-300 hover:shadow-xl hover:shadow-primary/20 hover:scale-[1.02] active:scale-[0.98] font-semibold",
334
+ onClick: onEventCreate
335
+ },
336
+ /* @__PURE__ */ React15__namespace.default.createElement(lucideReact.Plus, { className: "w-5 h-5" }),
337
+ /* @__PURE__ */ React15__namespace.default.createElement("span", { className: "text-sm" }, translations?.create || "Create")
338
+ )), /* @__PURE__ */ React15__namespace.default.createElement(MiniCalendar, { currentDate, onDateChange, onViewChange }), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex-1 px-4 space-y-5 mt-5" }, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "bg-muted/20 rounded-2xl p-3 border-[0px] border-border/30" }, /* @__PURE__ */ React15__namespace.default.createElement(
339
+ "div",
340
+ {
341
+ className: "flex items-center justify-between cursor-pointer hover:bg-accent/50 p-2 -m-1 rounded-xl mb-2 transition-all duration-200",
342
+ onClick: () => setCalendarsOpen(!calendarsOpen)
343
+ },
344
+ /* @__PURE__ */ React15__namespace.default.createElement("span", { className: "text-sm font-semibold text-foreground" }, translations?.calendars || "Calendars"),
345
+ /* @__PURE__ */ React15__namespace.default.createElement(lucideReact.ChevronDown, { className: cn("w-4 h-4 text-muted-foreground transition-transform duration-200", calendarsOpen && "rotate-180") })
346
+ ), calendarsOpen && /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "space-y-1" }, displayCalendars.map((cal) => /* @__PURE__ */ React15__namespace.default.createElement(
347
+ "div",
348
+ {
349
+ key: cal.id,
350
+ className: "flex items-center gap-3 py-2 px-2 hover:bg-accent/60 rounded-xl cursor-pointer group transition-all duration-200",
351
+ onClick: () => onCalendarToggle?.(cal.id, !(cal.active ?? true))
352
+ },
353
+ /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "relative flex items-center justify-center" }, /* @__PURE__ */ React15__namespace.default.createElement(
354
+ "input",
355
+ {
356
+ type: "checkbox",
357
+ checked: cal.active ?? true,
358
+ onChange: (e) => {
359
+ e.stopPropagation();
360
+ onCalendarToggle?.(cal.id, e.target.checked);
361
+ },
362
+ className: "peer h-5 w-5 rounded-md border-2 border-border/60 cursor-pointer appearance-none checked:border-transparent transition-all duration-200",
363
+ style: { "--primary-color": cal.color },
364
+ "data-cal-id": cal.id
365
+ }
366
+ ), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "absolute inset-0 flex items-center justify-center pointer-events-none opacity-0 peer-checked:opacity-100 transition-opacity" }, /* @__PURE__ */ React15__namespace.default.createElement("svg", { className: "w-3.5 h-3.5 text-white", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 3 }, /* @__PURE__ */ React15__namespace.default.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M5 13l4 4L19 7" }))), /* @__PURE__ */ React15__namespace.default.createElement("style", null, `
367
+ input[type="checkbox"][data-cal-id="${cal.id}"]:checked {
368
+ background-color: ${cal.color} !important;
369
+ border-color: ${cal.color} !important;
370
+ }
371
+ input[type="checkbox"][data-cal-id="${cal.id}"]:focus {
372
+ --tw-ring-color: ${cal.color}40 !important;
373
+ }
374
+ `)),
375
+ /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex items-center gap-2 flex-1 min-w-0" }, /* @__PURE__ */ React15__namespace.default.createElement("span", { className: "text-sm text-foreground/90 truncate font-medium" }, cal.label)),
376
+ /* @__PURE__ */ React15__namespace.default.createElement(
377
+ "div",
378
+ {
379
+ className: "w-2 h-2 rounded-full opacity-60 group-hover:opacity-100 transition-opacity",
380
+ style: { backgroundColor: cal.color }
381
+ }
382
+ )
383
+ ))))), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "mt-auto px-4 pt-5" }, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "bg-muted/20 rounded-2xl p-3" }, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex items-center gap-2 mb-3" }, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "p-1.5 bg-primary/10 rounded-lg" }, /* @__PURE__ */ React15__namespace.default.createElement(lucideReact.Globe, { className: "w-4 h-4 text-primary" })), /* @__PURE__ */ React15__namespace.default.createElement("span", { className: "text-sm font-semibold text-foreground" }, translations?.timezone || "Timezone")), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "relative" }, /* @__PURE__ */ React15__namespace.default.createElement(
384
+ "button",
385
+ {
386
+ onClick: () => setTimezoneOpen(!timezoneOpen),
387
+ className: "w-full flex items-center justify-between bg-blue-200/40 hover:bg-blue-200/80 rounded-xl py-2.5 pl-4 pr-3 text-sm text-foreground focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary/50 transition-all duration-200 text-left"
388
+ },
389
+ /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex-1 truncate mr-2 font-medium" }, selectedTimezoneLabel),
390
+ /* @__PURE__ */ React15__namespace.default.createElement(lucideReact.ChevronDown, { className: cn("w-4 h-4 text-muted-foreground transition-transform duration-200", timezoneOpen && "rotate-180") })
391
+ ), timezoneOpen && /* @__PURE__ */ React15__namespace.default.createElement(React15__namespace.default.Fragment, null, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "fixed inset-0 z-40", onClick: () => setTimezoneOpen(false) }), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "absolute bottom-full left-0 w-full mb-2 bg-background rounded-xl shadow-2xl z-50 max-h-[260px] overflow-y-auto p-1.5 animate-in fade-in zoom-in-95 duration-200 backdrop-blur-none" }, timezones.map((tz) => /* @__PURE__ */ React15__namespace.default.createElement(
392
+ "div",
393
+ {
394
+ key: tz.value,
395
+ className: cn(
396
+ "px-3 py-2.5 text-sm rounded-lg cursor-pointer transition-all duration-200",
397
+ (timezone || "") === tz.value ? "bg-primary text-primary-foreground font-semibold" : "text-foreground hover:bg-accent/80"
398
+ ),
399
+ onClick: () => {
400
+ onTimezoneChange?.(tz.value);
401
+ setTimezoneOpen(false);
402
+ }
403
+ },
404
+ formatTzLabel(tz)
405
+ ))))))));
406
+ };
407
+ var DraggableEvent = ({ event, children, className, style: propStyle, ...props }) => {
408
+ const { attributes, listeners, setNodeRef, transform, isDragging } = core.useDraggable({
409
+ id: event.id,
410
+ data: { event }
411
+ });
412
+ const style = {
413
+ ...propStyle,
414
+ transform: utilities.CSS.Translate.toString(transform),
415
+ zIndex: isDragging ? 100 : propStyle?.zIndex,
416
+ // When dragging, we want the ORIGINAL element to be almost invisible (or fully invisible)
417
+ // so that the DragOverlay (the "ghost") is the only thing the user focuses on.
418
+ // If we set opacity: 0, it disappears. If 0.1, it's a faint placeholder.
419
+ // The user asked for "Make the entire dragged item transparent".
420
+ // Usually this means the original item should be faded out while the drag overlay is moving.
421
+ opacity: isDragging ? 0 : propStyle?.opacity
422
+ // Hiding original element completely
423
+ };
424
+ return /* @__PURE__ */ React15__namespace.default.createElement(
425
+ "div",
426
+ {
427
+ ref: setNodeRef,
428
+ style,
429
+ ...listeners,
430
+ ...attributes,
431
+ ...props,
432
+ className: cn("touch-none", className)
433
+ },
434
+ children
435
+ );
436
+ };
437
+ var DroppableCell = ({ id, date, resourceId, children, className, style, onClick }) => {
438
+ const { isOver, setNodeRef } = core.useDroppable({
439
+ id,
440
+ data: { date, resourceId }
441
+ });
442
+ const minutes = date.getMinutes();
443
+ const quarterClass = minutes === 0 ? "hover:bg-blue-50/50 dark:hover:bg-blue-900/10" : minutes === 15 ? "hover:bg-blue-50/80 dark:hover:bg-blue-900/20" : minutes === 30 ? "hover:bg-blue-100/50 dark:hover:bg-blue-900/30" : "hover:bg-blue-100/80 dark:hover:bg-blue-900/40";
444
+ const activeQuarterClass = minutes === 0 ? "bg-blue-50/50 dark:bg-blue-900/10 ring-2 ring-primary ring-inset" : minutes === 15 ? "bg-blue-50/80 dark:bg-blue-900/20 ring-2 ring-primary ring-inset" : minutes === 30 ? "bg-blue-100/50 dark:bg-blue-900/30 ring-2 ring-primary ring-inset" : "bg-blue-100/80 dark:bg-blue-900/40 ring-2 ring-primary ring-inset";
445
+ return /* @__PURE__ */ React15__namespace.default.createElement(
446
+ "div",
447
+ {
448
+ ref: setNodeRef,
449
+ className: cn(
450
+ className,
451
+ quarterClass,
452
+ isOver && activeQuarterClass
453
+ ),
454
+ style,
455
+ onClick
456
+ },
457
+ children
458
+ );
459
+ };
460
+
461
+ // src/views/MonthView.tsx
462
+ var EventItem = React15__namespace.default.memo(({ event, onEventClick }) => /* @__PURE__ */ React15__namespace.default.createElement(DraggableEvent, { event }, /* @__PURE__ */ React15__namespace.default.createElement(
463
+ "div",
464
+ {
465
+ className: cn(
466
+ "text-xs px-2.5 py-1.5 rounded-lg truncate cursor-pointer shadow-sm transition-all duration-200",
467
+ "hover:shadow-md hover:scale-[1.02] hover:z-10",
468
+ !event.color && "bg-primary/10 text-primary hover:bg-primary/15 border-[0.5px] border-primary/20"
469
+ ),
470
+ style: event.color ? {
471
+ backgroundColor: `${event.color}20`,
472
+ color: event.color,
473
+ borderLeft: `3px solid ${event.color}`
474
+ } : void 0,
475
+ onClick: (e) => {
476
+ e.stopPropagation();
477
+ onEventClick?.(event);
478
+ }
479
+ },
480
+ /* @__PURE__ */ React15__namespace.default.createElement("span", { className: "font-medium" }, event.title)
481
+ )));
482
+ EventItem.displayName = "EventItem";
483
+ var MonthView = ({
484
+ currentDate,
485
+ events,
486
+ onEventClick,
487
+ onDateClick,
488
+ timezone,
489
+ locale
490
+ }) => {
491
+ const days = React15.useMemo(() => getMonthGrid(currentDate), [currentDate]);
492
+ const weekDays = React15.useMemo(() => {
493
+ const start = dateFns.startOfWeek(currentDate, { weekStartsOn: 1 });
494
+ const end = dateFns.endOfWeek(currentDate, { weekStartsOn: 1 });
495
+ return dateFns.eachDayOfInterval({ start, end });
496
+ }, [currentDate]);
497
+ const getZonedDate = React15.useCallback((date) => {
498
+ return timezone ? dateFnsTz.toZonedTime(date, timezone) : date;
499
+ }, [timezone]);
500
+ const eventsByDay = React15.useMemo(() => {
501
+ const map = /* @__PURE__ */ new Map();
502
+ events.forEach((event) => {
503
+ const zonedStart = getZonedDate(event.start);
504
+ const key = dateFns.format(zonedStart, "yyyy-MM-dd");
505
+ if (!map.has(key)) {
506
+ map.set(key, []);
507
+ }
508
+ map.get(key).push(event);
509
+ });
510
+ return map;
511
+ }, [events, getZonedDate]);
512
+ return /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex flex-col h-full bg-background border-[0.5px] scrollbar-hide border-border/50 rounded-2xl overflow-hidden min-w-[800px] md:min-w-0 shadow-sm" }, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "overflow-y-auto flex-1 relative" }, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "grid grid-cols-7 border-b-[0.5px] border-border/50 bg-gradient-to-r from-muted/30 via-muted/40 to-muted/30 sticky top-0 z-20 backdrop-blur-sm" }, weekDays.map((day) => /* @__PURE__ */ React15__namespace.default.createElement(
513
+ "div",
514
+ {
515
+ key: day.toISOString(),
516
+ className: "py-3 text-center text-xs font-semibold text-muted-foreground border-r-[0.5px] border-border/30 last:border-r-0 uppercase tracking-wider"
517
+ },
518
+ dateFns.format(day, "EEE", { locale })
519
+ ))), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "grid grid-cols-7", style: { gridAutoRows: "130px" } }, days.map((day) => {
520
+ const dayKey = dateFns.format(day, "yyyy-MM-dd");
521
+ const dayEvents = eventsByDay.get(dayKey) || [];
522
+ const isCurrentMonth = dateFns.isSameMonth(day, currentDate);
523
+ const cellId = day.toISOString();
524
+ return /* @__PURE__ */ React15__namespace.default.createElement(
525
+ DroppableCell,
526
+ {
527
+ key: cellId,
528
+ id: cellId,
529
+ date: day,
530
+ className: cn(
531
+ "h-[130px] p-2 border-b-[0.5px] border-r-[0.5px] border-border/30 last:border-r-0 relative transition-all duration-200 hover:bg-accent/5 flex flex-col gap-1.5 overflow-hidden group",
532
+ !isCurrentMonth && "bg-muted/5 text-muted-foreground/60",
533
+ dateFns.isToday(day) && "bg-primary/5 ring-1 ring-inset ring-primary/20"
534
+ ),
535
+ onClick: () => onDateClick?.(day)
536
+ },
537
+ /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex justify-between items-start" }, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: cn(
538
+ "text-sm font-semibold w-7 h-7 flex items-center justify-center rounded-full transition-all duration-200",
539
+ dateFns.isToday(day) ? "bg-primary text-primary-foreground shadow-md shadow-primary/30" : "group-hover:bg-accent"
540
+ ) }, dateFns.format(day, "d", { locale })), dayEvents.length > 0 && /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "text-[10px] font-medium text-muted-foreground/60 bg-muted/50 px-1.5 py-0.5 rounded-full" }, dayEvents.length)),
541
+ /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex-1 flex flex-col gap-1 scrollbar-hide overflow-y-auto overflow-x-hidden" }, dayEvents.slice(0, 4).map((event) => /* @__PURE__ */ React15__namespace.default.createElement(EventItem, { key: `${event.id}-${dayKey}`, event, onEventClick })), dayEvents.length > 4 && /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "text-[10px] text-primary font-semibold text-center py-1 px-2 rounded-md bg-primary/5 hover:bg-primary/10 cursor-pointer transition-colors" }, "+", dayEvents.length - 4, " more"))
542
+ );
543
+ }))));
544
+ };
545
+ var ResizableEvent = ({
546
+ event,
547
+ hourHeight,
548
+ minDuration = 15,
549
+ onResize,
550
+ children,
551
+ className,
552
+ style,
553
+ readonly
554
+ }) => {
555
+ const [isResizing, setIsResizing] = React15.useState(false);
556
+ const [resizeHeight, setResizeHeight] = React15.useState(null);
557
+ const containerRef = React15.useRef(null);
558
+ const startYRef = React15.useRef(0);
559
+ const startHeightRef = React15.useRef(0);
560
+ const handleResizeStart = React15.useCallback((e) => {
561
+ e.preventDefault();
562
+ e.stopPropagation();
563
+ const clientY = "touches" in e ? e.touches[0].clientY : e.clientY;
564
+ startYRef.current = clientY;
565
+ startHeightRef.current = containerRef.current?.offsetHeight || 0;
566
+ setIsResizing(true);
567
+ const handleMove = (moveEvent) => {
568
+ const moveClientY = "touches" in moveEvent ? moveEvent.touches[0].clientY : moveEvent.clientY;
569
+ const deltaY = moveClientY - startYRef.current;
570
+ const snapInterval = hourHeight / 4;
571
+ const snappedDelta = Math.round(deltaY / snapInterval) * snapInterval;
572
+ const newHeight = Math.max(
573
+ minDuration / 60 * hourHeight,
574
+ // Minimum height based on minDuration
575
+ startHeightRef.current + snappedDelta
576
+ );
577
+ setResizeHeight(newHeight);
578
+ };
579
+ const handleEnd = () => {
580
+ setIsResizing(false);
581
+ if (resizeHeight !== null && containerRef.current && onResize) {
582
+ const originalHeight = startHeightRef.current;
583
+ const heightDiff = (resizeHeight || originalHeight) - originalHeight;
584
+ const minutesDiff = heightDiff / hourHeight * 60;
585
+ const newEnd = new Date(event.end);
586
+ newEnd.setMinutes(newEnd.getMinutes() + minutesDiff);
587
+ if (newEnd > event.start) {
588
+ onResize(event, newEnd);
589
+ }
590
+ }
591
+ setResizeHeight(null);
592
+ document.removeEventListener("mousemove", handleMove);
593
+ document.removeEventListener("mouseup", handleEnd);
594
+ document.removeEventListener("touchmove", handleMove);
595
+ document.removeEventListener("touchend", handleEnd);
596
+ };
597
+ document.addEventListener("mousemove", handleMove);
598
+ document.addEventListener("mouseup", handleEnd);
599
+ document.addEventListener("touchmove", handleMove, { passive: false });
600
+ document.addEventListener("touchend", handleEnd);
601
+ }, [event, hourHeight, minDuration, onResize, resizeHeight]);
602
+ return /* @__PURE__ */ React15__namespace.default.createElement(
603
+ "div",
604
+ {
605
+ ref: containerRef,
606
+ className: cn("relative group", className),
607
+ style: {
608
+ ...style,
609
+ height: resizeHeight !== null ? `${resizeHeight}px` : style?.height
610
+ }
611
+ },
612
+ children,
613
+ /* @__PURE__ */ React15__namespace.default.createElement(
614
+ "div",
615
+ {
616
+ className: cn(
617
+ readonly ? "cursor-default" : "cursor-ns-resize group-hover:opacity-100",
618
+ "absolute bottom-0 left-0 right-0 h-3 z-20 flex items-center justify-center",
619
+ "opacity-0 transition-opacity",
620
+ isResizing && "opacity-100"
621
+ ),
622
+ onMouseDown: readonly ? void 0 : handleResizeStart,
623
+ onTouchStart: readonly ? void 0 : handleResizeStart
624
+ },
625
+ /* @__PURE__ */ React15__namespace.default.createElement("div", { className: cn(
626
+ "w-8 h-1 rounded-full transition-all",
627
+ isResizing ? "bg-primary" : "bg-muted-foreground/30 group-hover:bg-primary/50"
628
+ ) })
629
+ ),
630
+ isResizing && /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "absolute inset-0 border-2 border-primary border-dashed rounded-md pointer-events-none bg-primary/5" })
631
+ );
632
+ };
633
+
634
+ // src/views/WeekView.tsx
635
+ var WeekView = ({
636
+ currentDate,
637
+ events,
638
+ onEventClick,
639
+ onTimeSlotClick,
640
+ onEventResize,
641
+ timezone,
642
+ locale,
643
+ readonly
644
+ }) => {
645
+ const start = dateFns.startOfWeek(currentDate, { weekStartsOn: 1 });
646
+ const end = dateFns.endOfWeek(currentDate, { weekStartsOn: 1 });
647
+ const weekDays = dateFns.eachDayOfInterval({ start, end });
648
+ const hours = Array.from({ length: 24 }, (_, i) => i);
649
+ const hourHeight = 60;
650
+ const scrollContainerRef = React15__namespace.default.useRef(null);
651
+ const [now, setNow] = React15__namespace.default.useState(/* @__PURE__ */ new Date());
652
+ React15__namespace.default.useEffect(() => {
653
+ const interval = setInterval(() => setNow(/* @__PURE__ */ new Date()), 6e4);
654
+ return () => clearInterval(interval);
655
+ }, []);
656
+ React15__namespace.default.useEffect(() => {
657
+ if (scrollContainerRef.current) {
658
+ const scrollToActualTime = () => {
659
+ const currentHour = now.getHours();
660
+ const offsetHour = 4;
661
+ return (currentHour - offsetHour) * hourHeight;
662
+ };
663
+ scrollContainerRef.current.scrollTop = scrollToActualTime();
664
+ }
665
+ }, []);
666
+ const getZonedDate = (date) => {
667
+ return timezone ? dateFnsTz.toZonedTime(date, timezone) : date;
668
+ };
669
+ const zonedNow = getZonedDate(/* @__PURE__ */ new Date());
670
+ const getTimezoneDisplay = (tz) => {
671
+ const date = now;
672
+ let displayTime = "";
673
+ let acronym = "";
674
+ if (!tz) {
675
+ displayTime = dateFns.format(date, "HH:mm");
676
+ try {
677
+ acronym = new Intl.DateTimeFormat("en-US", { timeZoneName: "short" }).formatToParts(date).find((part) => part.type === "timeZoneName")?.value || "";
678
+ } catch (e) {
679
+ acronym = "LOC";
680
+ }
681
+ } else {
682
+ try {
683
+ const zDate = dateFnsTz.toZonedTime(date, tz);
684
+ displayTime = dateFns.format(zDate, "HH:mm");
685
+ acronym = new Intl.DateTimeFormat("en-US", { timeZone: tz, timeZoneName: "short" }).formatToParts(date).find((part) => part.type === "timeZoneName")?.value || "";
686
+ } catch (e) {
687
+ displayTime = dateFns.format(date, "HH:mm");
688
+ acronym = tz;
689
+ }
690
+ }
691
+ return /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex flex-col items-center justify-center leading-tight" }, /* @__PURE__ */ React15__namespace.default.createElement("span", null, displayTime), /* @__PURE__ */ React15__namespace.default.createElement("span", { className: "text-[10px] opacity-75" }, "(", acronym, ")"));
692
+ };
693
+ const timeFormat = locale?.code === "fr" ? "H:mm" : "h a";
694
+ const eventTimeFormat = locale?.code === "fr" ? "H:mm" : "h:mm a";
695
+ const nowFormat = locale?.code === "fr" ? "H:mm" : "h:mm";
696
+ return /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex flex-col h-full bg-background border-[0.5px] border-border/50 rounded-2xl overflow-hidden min-w-[800px] md:min-w-0 shadow-sm" }, /* @__PURE__ */ React15__namespace.default.createElement(
697
+ "div",
698
+ {
699
+ ref: scrollContainerRef,
700
+ className: "flex-1 overflow-y-auto scrollbar-hide relative bg-background scroll-smooth",
701
+ style: { scrollbarGutter: "stable" }
702
+ },
703
+ /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex border-b-[0.5px] border-border/50 bg-gradient-to-r from-muted/20 via-background to-muted/20 z-20 sticky top-0 backdrop-blur-sm" }, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex-none p-3 text-center text-xs font-semibold text-muted-foreground w-16 flex items-center justify-center border-r-[0.5px] border-border/30 bg-muted/10" }, getTimezoneDisplay(timezone)), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex-1 grid grid-cols-7" }, weekDays.map((day, index) => /* @__PURE__ */ React15__namespace.default.createElement("div", { key: day.toISOString(), className: cn("py-3 px-2 text-center", index > 0 && "border-l-[0.5px] border-border/30") }, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "text-[10px] font-semibold text-muted-foreground uppercase tracking-wider mb-1.5" }, dateFns.format(day, "EEE", { locale })), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: cn(
704
+ "w-9 h-9 flex items-center justify-center rounded-xl mx-auto text-sm font-semibold transition-all duration-200",
705
+ dateFns.isToday(day) ? "bg-primary text-primary-foreground shadow-lg shadow-primary/30 scale-110" : "text-foreground hover:bg-accent/80"
706
+ ) }, dateFns.format(day, "d", { locale })))))),
707
+ /* @__PURE__ */ React15__namespace.default.createElement(
708
+ "div",
709
+ {
710
+ className: "flex min-w-full relative",
711
+ style: { height: hours.length * hourHeight }
712
+ },
713
+ /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex-none w-16 border-r-[0.5px] border-border/30 relative bg-muted/5" }, hours.map((hour) => /* @__PURE__ */ React15__namespace.default.createElement(
714
+ "div",
715
+ {
716
+ key: hour,
717
+ className: "relative w-full text-[11px] text-muted-foreground/80 text-right pr-3 font-medium tabular-nums box-border",
718
+ style: { height: hourHeight }
719
+ },
720
+ /* @__PURE__ */ React15__namespace.default.createElement("span", { className: "block -translate-y-1/2" }, hour !== 0 && dateFns.format((/* @__PURE__ */ new Date()).setHours(hour, 0, 0, 0), timeFormat, { locale }))
721
+ ))),
722
+ /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex-1 grid grid-cols-7 relative" }, weekDays.map((day, dayIndex) => {
723
+ const dayEvents = events.filter((e) => {
724
+ const zonedStart = getZonedDate(e.start);
725
+ return dateFns.isSameDay(zonedStart, day);
726
+ });
727
+ return /* @__PURE__ */ React15__namespace.default.createElement("div", { key: day.toISOString(), className: cn("relative h-full", dayIndex > 0 && "border-l-[0.5px] border-border/30") }, hours.map((hour) => {
728
+ return /* @__PURE__ */ React15__namespace.default.createElement(
729
+ "div",
730
+ {
731
+ key: hour,
732
+ className: "w-full border-b-[0.5px] border-dashed border-border/20 box-border relative hover:bg-accent/5 transition-colors",
733
+ style: { height: hourHeight }
734
+ },
735
+ [0, 15, 30, 45].map((minute) => {
736
+ const cellDate = new Date(day);
737
+ cellDate.setHours(hour, minute, 0, 0);
738
+ const cellId = cellDate.toISOString();
739
+ return /* @__PURE__ */ React15__namespace.default.createElement(
740
+ DroppableCell,
741
+ {
742
+ key: minute,
743
+ id: cellId,
744
+ date: cellDate,
745
+ className: "w-full absolute left-0 right-0 z-0 transition-colors",
746
+ style: {
747
+ height: "25%",
748
+ top: `${minute / 60 * 100}%`
749
+ }
750
+ },
751
+ /* @__PURE__ */ React15__namespace.default.createElement(
752
+ "div",
753
+ {
754
+ className: "w-full h-full bg-transparent cursor-pointer",
755
+ onClick: () => onTimeSlotClick?.(cellDate)
756
+ }
757
+ )
758
+ );
759
+ })
760
+ );
761
+ }), dayEvents.map((event) => {
762
+ const overlappingEvents = dayEvents.filter((e) => {
763
+ if (e.id === event.id) return false;
764
+ const s1 = getZonedDate(event.start).getTime();
765
+ const e1 = getZonedDate(event.end).getTime();
766
+ const s2 = getZonedDate(e.start).getTime();
767
+ const e2 = getZonedDate(e.end).getTime();
768
+ return s1 < e2 && e1 > s2;
769
+ });
770
+ const group = [event, ...overlappingEvents].sort(
771
+ (a, b) => getZonedDate(a.start).getTime() - getZonedDate(b.start).getTime() || (a.id > b.id ? 1 : -1)
772
+ // stable sort
773
+ );
774
+ const index = group.findIndex((e) => e.id === event.id);
775
+ const count = group.length;
776
+ const widthPercent = 100 / count;
777
+ const leftPercent = index * widthPercent;
778
+ const zonedEventStart = getZonedDate(event.start);
779
+ const zonedEventEnd = getZonedDate(event.end);
780
+ const startMinutes = zonedEventStart.getHours() * 60 + zonedEventStart.getMinutes();
781
+ const durationMinutes = dateFns.differenceInMinutes(zonedEventEnd, zonedEventStart);
782
+ const top = startMinutes / 60 * hourHeight;
783
+ const height = durationMinutes / 60 * hourHeight;
784
+ const isShortEvent = durationMinutes < 60;
785
+ return /* @__PURE__ */ React15__namespace.default.createElement(
786
+ DraggableEvent,
787
+ {
788
+ key: `${event.id}-${day.toISOString()}`,
789
+ event,
790
+ className: `absolute z-10 transition-all ${readonly ? "cursor-default" : ""}`,
791
+ style: {
792
+ top: `${top}px`,
793
+ height: `${Math.max(height, 20)}px`,
794
+ left: `${leftPercent}%`,
795
+ width: `${widthPercent}%`,
796
+ // Add minimal spacing between overlapping events
797
+ paddingRight: count > 1 ? "2px" : "0"
798
+ }
799
+ },
800
+ /* @__PURE__ */ React15__namespace.default.createElement(
801
+ ResizableEvent,
802
+ {
803
+ readonly,
804
+ event,
805
+ hourHeight,
806
+ onResize: onEventResize,
807
+ className: "h-full",
808
+ style: { height: "100%" }
809
+ },
810
+ /* @__PURE__ */ React15__namespace.default.createElement(
811
+ "div",
812
+ {
813
+ className: cn(
814
+ "rounded-md border shadow-sm transition-all hover:shadow-md group overflow-hidden relative",
815
+ "glass",
816
+ readonly ? "cursor-default" : "cursor-grab active:cursor-grabbing",
817
+ !event.color && "border-primary/20 bg-primary/10",
818
+ isShortEvent ? "px-1 flex items-center justify-center" : "p-2",
819
+ // Add active border for overlapped events to distinguish them
820
+ count > 1 && "border-l-4 border-l-primary/50"
821
+ ),
822
+ style: {
823
+ height: "100%",
824
+ backgroundColor: event.color ? `${event.color}15` : void 0,
825
+ borderColor: event.color ? `${event.color}40` : void 0,
826
+ borderLeftWidth: "3px",
827
+ borderLeftColor: event.color || "var(--primary)"
828
+ },
829
+ onClick: (e) => {
830
+ e.stopPropagation();
831
+ onEventClick?.(event);
832
+ },
833
+ title: count > 1 ? `${event.title} (${index + 1}/${count})` : void 0
834
+ },
835
+ /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex flex-col h-full overflow-hidden w-full" }, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: cn(
836
+ "font-semibold truncate text-foreground/90 leading-tight",
837
+ isShortEvent ? "text-xs text-center" : "text-xs"
838
+ ) }, event.title), !isShortEvent && /* @__PURE__ */ React15__namespace.default.createElement(React15__namespace.default.Fragment, null, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "text-[10px] text-muted-foreground truncate mt-0.5 font-medium leading-tight" }, dateFns.format(zonedEventStart, eventTimeFormat, { locale }), " - ", dateFns.format(zonedEventEnd, eventTimeFormat, { locale })), event.description && height > 50 && /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "text-[10px] text-muted-foreground/80 truncate mt-1 leading-tight opacity-80" }, event.description)), count > 1 && !isShortEvent && /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "absolute top-1 right-1 bg-background/80 backdrop-blur-sm rounded-full w-4 h-4 flex items-center justify-center text-[9px] font-bold text-muted-foreground border border-border shadow-sm" }, count))
839
+ )
840
+ )
841
+ );
842
+ }), dateFns.isToday(day) && /* @__PURE__ */ React15__namespace.default.createElement(
843
+ "div",
844
+ {
845
+ className: "absolute left-0 right-0 z-20 pointer-events-none flex items-center",
846
+ style: {
847
+ top: `${(zonedNow.getHours() * 60 + zonedNow.getMinutes()) / 60 * hourHeight}px`
848
+ }
849
+ },
850
+ /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "h-[2px] w-full bg-gradient-to-r from-primary via-primary to-primary/50" }),
851
+ /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "absolute -left-1.5 w-3 h-3 bg-primary rounded-full shadow-lg shadow-primary/40 ring-2 ring-background animate-pulse" })
852
+ ));
853
+ }))
854
+ ),
855
+ /* @__PURE__ */ React15__namespace.default.createElement(
856
+ "div",
857
+ {
858
+ className: "absolute left-0 w-16 pointer-events-none z-30 flex justify-end pr-2",
859
+ style: {
860
+ top: `${(zonedNow.getHours() * 60 + zonedNow.getMinutes()) / 60 * hourHeight + 80}px`
861
+ }
862
+ },
863
+ /* @__PURE__ */ React15__namespace.default.createElement("span", { className: "text-[10px] font-bold text-primary-foreground bg-primary px-1.5 py-0.5 rounded-md shadow-md -translate-y-1/2 backdrop-blur-none" }, dateFns.format(zonedNow, nowFormat, { locale }))
864
+ )
865
+ ));
866
+ };
867
+ var DayView = ({
868
+ currentDate,
869
+ events,
870
+ onEventClick,
871
+ onTimeSlotClick,
872
+ onEventResize,
873
+ timezone,
874
+ locale,
875
+ readonly
876
+ }) => {
877
+ const hours = Array.from({ length: 24 }, (_, i) => i);
878
+ const hourHeight = 80;
879
+ const scrollContainerRef = React15__namespace.default.useRef(null);
880
+ const [now, setNow] = React15__namespace.default.useState(/* @__PURE__ */ new Date());
881
+ React15__namespace.default.useEffect(() => {
882
+ const interval = setInterval(() => setNow(/* @__PURE__ */ new Date()), 6e4);
883
+ return () => clearInterval(interval);
884
+ }, []);
885
+ React15__namespace.default.useEffect(() => {
886
+ if (scrollContainerRef.current) {
887
+ const scrollToActualTime = () => {
888
+ const currentHour = now.getHours();
889
+ const offsetHour = 3;
890
+ return (currentHour - offsetHour) * hourHeight;
891
+ };
892
+ scrollContainerRef.current.scrollTop = scrollToActualTime();
893
+ }
894
+ }, []);
895
+ const getZonedDate = (date) => {
896
+ return timezone ? dateFnsTz.toZonedTime(date, timezone) : date;
897
+ };
898
+ const zonedNow = getZonedDate(now);
899
+ const dayEvents = events.filter((e) => {
900
+ const zonedStart = getZonedDate(e.start);
901
+ return dateFns.isSameDay(zonedStart, currentDate);
902
+ });
903
+ const timeFormat = locale?.code === "fr" ? "H:mm" : "h a";
904
+ const eventTimeFormat = locale?.code === "fr" ? "H:mm" : "h:mm a";
905
+ const nowFormat = locale?.code === "fr" ? "H:mm" : "h:mm a";
906
+ return /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex flex-col h-full bg-background border-[0.5px] border-border/50 rounded-2xl overflow-hidden shadow-sm" }, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "px-6 py-4 border-b-[0.5px] border-border/50 bg-gradient-to-r from-muted/20 via-background to-muted/20 text-center shrink-0" }, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex items-center justify-center gap-3" }, /* @__PURE__ */ React15__namespace.default.createElement("h2", { className: "text-xl font-semibold capitalize text-foreground" }, dateFns.format(currentDate, "EEEE, MMMM d, yyyy", { locale })), dateFns.isToday(currentDate) && /* @__PURE__ */ React15__namespace.default.createElement("span", { className: "text-xs font-semibold bg-primary text-primary-foreground px-3 py-1 rounded-full shadow-md shadow-primary/20" }, "Today"))), /* @__PURE__ */ React15__namespace.default.createElement("div", { ref: scrollContainerRef, className: "flex-1 overflow-y-auto relative" }, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex relative", style: { height: hours.length * hourHeight } }, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "w-20 bg-muted/5 border-r-[0.5px] border-border/30 relative" }, hours.map((hour) => /* @__PURE__ */ React15__namespace.default.createElement(
907
+ "div",
908
+ {
909
+ key: hour,
910
+ className: "relative w-full",
911
+ style: { height: hourHeight }
912
+ },
913
+ hour !== 0 && /* @__PURE__ */ React15__namespace.default.createElement("span", { className: "absolute w-full text-center -top-3 left-1/2 -translate-x-1/2 text-[11px] text-muted-foreground/80 font-medium tabular-nums bg-background px-1.5 py-0.5 rounded-md" }, dateFns.format((/* @__PURE__ */ new Date()).setHours(hour, 0, 0, 0), timeFormat, { locale }))
914
+ )), dateFns.isToday(currentDate) && /* @__PURE__ */ React15__namespace.default.createElement(
915
+ "div",
916
+ {
917
+ className: "absolute left-0 w-full pointer-events-none z-30 flex justify-end pr-2",
918
+ style: {
919
+ top: `${(zonedNow.getHours() * 60 + zonedNow.getMinutes()) / 60 * hourHeight}px`
920
+ }
921
+ },
922
+ /* @__PURE__ */ React15__namespace.default.createElement("span", { className: "text-[10px] font-bold text-white bg-primary px-2 py-1 rounded-lg shadow-md shadow-primary/30 -translate-y-1/2" }, dateFns.format(zonedNow, nowFormat, { locale }))
923
+ )), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex-1 relative" }, hours.map((hour) => {
924
+ return /* @__PURE__ */ React15__namespace.default.createElement(
925
+ "div",
926
+ {
927
+ key: hour,
928
+ className: "border-b-[0.5px] border-dashed border-border/20 box-border relative hover:bg-accent/5 transition-colors",
929
+ style: { height: hourHeight }
930
+ },
931
+ [0, 15, 30, 45].map((minute) => {
932
+ const cellDate = new Date(currentDate);
933
+ cellDate.setHours(hour, minute, 0, 0);
934
+ const cellId = cellDate.toISOString();
935
+ return /* @__PURE__ */ React15__namespace.default.createElement(
936
+ DroppableCell,
937
+ {
938
+ key: minute,
939
+ id: cellId,
940
+ date: cellDate,
941
+ className: "w-full absolute left-0 right-0 z-0 transition-colors",
942
+ style: {
943
+ height: "25%",
944
+ top: `${minute / 60 * 100}%`
945
+ }
946
+ },
947
+ /* @__PURE__ */ React15__namespace.default.createElement(
948
+ "div",
949
+ {
950
+ className: "h-full w-full bg-transparent cursor-pointer",
951
+ onClick: () => onTimeSlotClick?.(cellDate)
952
+ }
953
+ )
954
+ );
955
+ })
956
+ );
957
+ }), dayEvents.map((event) => {
958
+ const overlappingEvents = dayEvents.filter((e) => {
959
+ if (e.id === event.id) return false;
960
+ const s1 = getZonedDate(event.start).getTime();
961
+ const e1 = getZonedDate(event.end).getTime();
962
+ const s2 = getZonedDate(e.start).getTime();
963
+ const e2 = getZonedDate(e.end).getTime();
964
+ return s1 < e2 && e1 > s2;
965
+ });
966
+ const group = [event, ...overlappingEvents].sort(
967
+ (a, b) => getZonedDate(a.start).getTime() - getZonedDate(b.start).getTime() || (a.id > b.id ? 1 : -1)
968
+ );
969
+ const index = group.findIndex((e) => e.id === event.id);
970
+ const count = group.length;
971
+ const widthPercent = 100 / count;
972
+ const leftPercent = index * widthPercent;
973
+ const zonedStart = getZonedDate(event.start);
974
+ const zonedEnd = getZonedDate(event.end);
975
+ const startMinutes = zonedStart.getHours() * 60 + zonedStart.getMinutes();
976
+ const durationMinutes = dateFns.differenceInMinutes(zonedEnd, zonedStart);
977
+ const top = startMinutes / 60 * hourHeight;
978
+ const height = durationMinutes / 60 * hourHeight;
979
+ const isShortEvent = durationMinutes < 45;
980
+ return /* @__PURE__ */ React15__namespace.default.createElement(
981
+ DraggableEvent,
982
+ {
983
+ key: `${event.id}-${currentDate.toISOString()}`,
984
+ event,
985
+ className: `absolute z-10 transition-all ${readonly ? "cursor-default" : ""}`,
986
+ style: {
987
+ top: `${top}px`,
988
+ height: `${Math.max(height, 28)}px`,
989
+ left: `calc(${leftPercent}% + 4px)`,
990
+ width: `calc(${widthPercent}% - 8px)`,
991
+ paddingRight: count > 1 ? "2px" : "0"
992
+ }
993
+ },
994
+ /* @__PURE__ */ React15__namespace.default.createElement(
995
+ ResizableEvent,
996
+ {
997
+ readonly,
998
+ event,
999
+ hourHeight,
1000
+ onResize: onEventResize,
1001
+ className: "h-full",
1002
+ style: { height: "100%" }
1003
+ },
1004
+ /* @__PURE__ */ React15__namespace.default.createElement(
1005
+ "div",
1006
+ {
1007
+ className: cn(
1008
+ "h-full rounded-lg border-[0.5px] shadow-sm overflow-hidden transition-all hover:shadow-lg hover:z-20 group",
1009
+ "glass backdrop-blur-sm",
1010
+ readonly ? "cursor-default" : "cursor-grab active:cursor-grabbing",
1011
+ !event.color && "bg-primary/10 border-primary/20",
1012
+ isShortEvent ? "px-2 flex items-center" : "px-3 py-2",
1013
+ count > 1 && "border-l-4"
1014
+ ),
1015
+ style: {
1016
+ backgroundColor: event.color ? `${event.color}15` : void 0,
1017
+ borderColor: event.color ? `${event.color}30` : void 0,
1018
+ borderLeftColor: event.color || "var(--primary)",
1019
+ borderLeftWidth: count > 1 ? "4px" : "3px"
1020
+ },
1021
+ onClick: (e) => {
1022
+ e.stopPropagation();
1023
+ onEventClick?.(event);
1024
+ },
1025
+ title: count > 1 ? `${event.title} (${index + 1}/${count})` : void 0
1026
+ },
1027
+ /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex flex-col h-full overflow-hidden w-full" }, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: cn(
1028
+ "font-semibold truncate leading-tight",
1029
+ isShortEvent ? "text-xs" : "text-sm",
1030
+ event.color ? "text-foreground" : "text-foreground/90"
1031
+ ) }, event.title), !isShortEvent && /* @__PURE__ */ React15__namespace.default.createElement(React15__namespace.default.Fragment, null, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "text-xs text-muted-foreground mt-0.5 font-medium" }, dateFns.format(zonedStart, eventTimeFormat, { locale }), " - ", dateFns.format(zonedEnd, eventTimeFormat, { locale })), event.description && height > 60 && /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "text-xs text-muted-foreground/80 mt-1 line-clamp-2" }, event.description)), count > 1 && !isShortEvent && /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "absolute top-1.5 right-1.5 bg-background/90 backdrop-blur-sm rounded-full w-5 h-5 flex items-center justify-center text-[10px] font-bold text-muted-foreground border border-border shadow-sm" }, count))
1032
+ )
1033
+ )
1034
+ );
1035
+ }), dateFns.isToday(currentDate) && /* @__PURE__ */ React15__namespace.default.createElement(
1036
+ "div",
1037
+ {
1038
+ className: "absolute left-0 right-0 z-20 pointer-events-none flex items-center",
1039
+ style: {
1040
+ top: `${(zonedNow.getHours() * 60 + zonedNow.getMinutes()) / 60 * hourHeight}px`
1041
+ }
1042
+ },
1043
+ /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "h-[2px] w-full bg-gradient-to-r from-primary via-primary to-primary/50" }),
1044
+ /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "absolute -left-1.5 w-3 h-3 bg-primary rounded-full shadow-lg shadow-primary/40 ring-2 ring-background animate-pulse" })
1045
+ )))));
1046
+ };
1047
+ var AgendaEmptyState = ({ onCreateEvent, translations }) => /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex flex-col items-center justify-center h-full min-h-[400px] py-12" }, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "relative mb-8" }, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "p-8 bg-gradient-to-br from-green-50 to-blue-50 dark:from-green-900/10 dark:to-blue-900/10 rounded-3xl border border-border/30" }, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex items-center gap-4" }, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "w-12 h-12 rounded-2xl bg-green-100 dark:bg-green-900/30 flex items-center justify-center" }, /* @__PURE__ */ React15__namespace.default.createElement("svg", { className: "w-6 h-6 text-green-600 dark:text-green-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2 }, /* @__PURE__ */ React15__namespace.default.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M5 13l4 4L19 7" }))), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "text-left" }, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "font-medium text-foreground" }, "All caught up!"), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "text-sm text-muted-foreground" }, "No events scheduled"))))), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "text-center max-w-sm" }, /* @__PURE__ */ React15__namespace.default.createElement("h3", { className: "text-lg font-semibold text-foreground mb-2" }, translations?.noUpcoming || "Your schedule is clear"), /* @__PURE__ */ React15__namespace.default.createElement("p", { className: "text-sm text-muted-foreground mb-6" }, "No upcoming events to show. Create a new event to start planning."), onCreateEvent && /* @__PURE__ */ React15__namespace.default.createElement(
1048
+ "button",
1049
+ {
1050
+ onClick: onCreateEvent,
1051
+ className: "inline-flex items-center gap-2 px-5 py-2.5 bg-primary text-primary-foreground rounded-xl font-medium text-sm shadow-lg shadow-primary/20 hover:shadow-xl hover:shadow-primary/30 hover:scale-105 active:scale-95 transition-all duration-200"
1052
+ },
1053
+ /* @__PURE__ */ React15__namespace.default.createElement(lucideReact.Plus, { className: "w-4 h-4" }),
1054
+ translations?.createEvent || "Create Event"
1055
+ )));
1056
+ var formatDuration = (start, end) => {
1057
+ const minutes = dateFns.differenceInMinutes(end, start);
1058
+ if (minutes < 60) return `${minutes}m`;
1059
+ const hours = Math.floor(minutes / 60);
1060
+ const remainingMinutes = minutes % 60;
1061
+ if (remainingMinutes === 0) return `${hours}h`;
1062
+ return `${hours}h ${remainingMinutes}m`;
1063
+ };
1064
+ var getDateLabel = (date) => {
1065
+ if (dateFns.isToday(date)) return "Today";
1066
+ if (dateFns.isTomorrow(date)) return "Tomorrow";
1067
+ return dateFns.format(date, "EEEE");
1068
+ };
1069
+ var AgendaView = ({
1070
+ currentDate,
1071
+ events,
1072
+ onEventClick,
1073
+ onCreateEvent
1074
+ }) => {
1075
+ const groupedEvents = React15.useMemo(() => {
1076
+ const startDate = dateFns.startOfDay(currentDate);
1077
+ const groups = [];
1078
+ const sortedEvents = [...events].sort((a, b) => a.start.getTime() - b.start.getTime());
1079
+ for (let i = 0; i < 30; i++) {
1080
+ const day = dateFns.addDays(startDate, i);
1081
+ const dayEvents = sortedEvents.filter((event) => dateFns.isSameDay(event.start, day));
1082
+ if (dayEvents.length > 0) {
1083
+ groups.push({ date: day, events: dayEvents });
1084
+ }
1085
+ }
1086
+ return groups;
1087
+ }, [currentDate, events]);
1088
+ const container = {
1089
+ hidden: { opacity: 0 },
1090
+ show: {
1091
+ opacity: 1,
1092
+ transition: {
1093
+ staggerChildren: 0.05
1094
+ }
1095
+ }
1096
+ };
1097
+ const item = {
1098
+ hidden: { opacity: 0, x: -20 },
1099
+ show: { opacity: 1, x: 0 }
1100
+ };
1101
+ return /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex flex-col h-full bg-background overflow-y-auto" }, groupedEvents.length === 0 ? /* @__PURE__ */ React15__namespace.default.createElement(AgendaEmptyState, { onCreateEvent }) : /* @__PURE__ */ React15__namespace.default.createElement(
1102
+ framerMotion.motion.div,
1103
+ {
1104
+ className: "max-w-3xl mx-auto w-full pb-10 px-4 md:px-6",
1105
+ variants: container,
1106
+ initial: "hidden",
1107
+ animate: "show"
1108
+ },
1109
+ groupedEvents.map((group, groupIndex) => /* @__PURE__ */ React15__namespace.default.createElement(
1110
+ framerMotion.motion.div,
1111
+ {
1112
+ key: group.date.toISOString(),
1113
+ className: "relative",
1114
+ variants: item
1115
+ },
1116
+ /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "sticky top-0 bg-background/95 backdrop-blur-md py-4 z-10 border-b border-border/50" }, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex items-center gap-4" }, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: cn(
1117
+ "flex flex-col items-center justify-center w-16 h-16 rounded-2xl transition-all",
1118
+ dateFns.isToday(group.date) ? "bg-primary text-primary-foreground shadow-lg shadow-primary/30" : "bg-muted/50 text-foreground"
1119
+ ) }, /* @__PURE__ */ React15__namespace.default.createElement("span", { className: "text-2xl font-bold leading-none" }, dateFns.format(group.date, "d")), /* @__PURE__ */ React15__namespace.default.createElement("span", { className: "text-xs font-medium uppercase tracking-wide opacity-80" }, dateFns.format(group.date, "MMM"))), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex flex-col" }, /* @__PURE__ */ React15__namespace.default.createElement("span", { className: cn(
1120
+ "text-lg font-semibold",
1121
+ dateFns.isToday(group.date) && "text-primary"
1122
+ ) }, getDateLabel(group.date)), /* @__PURE__ */ React15__namespace.default.createElement("span", { className: "text-sm text-muted-foreground" }, group.events.length, " event", group.events.length !== 1 ? "s" : "")))),
1123
+ /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "py-4 space-y-3" }, group.events.map((event, eventIndex) => /* @__PURE__ */ React15__namespace.default.createElement(
1124
+ framerMotion.motion.div,
1125
+ {
1126
+ key: event.id,
1127
+ onClick: () => onEventClick?.(event),
1128
+ className: cn(
1129
+ "group relative flex gap-4 p-4 rounded-2xl border border-border/40",
1130
+ "hover:border-primary/40 hover:shadow-lg hover:shadow-primary/5",
1131
+ "transition-all duration-200 cursor-pointer",
1132
+ "bg-gradient-to-br from-card via-card to-card/80"
1133
+ ),
1134
+ whileHover: { scale: 1.01, y: -2 },
1135
+ transition: { duration: 0.2 }
1136
+ },
1137
+ /* @__PURE__ */ React15__namespace.default.createElement(
1138
+ "div",
1139
+ {
1140
+ className: "absolute left-0 top-3 bottom-3 w-1 rounded-full",
1141
+ style: { backgroundColor: event.color || "var(--primary)" }
1142
+ }
1143
+ ),
1144
+ /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex flex-col items-center min-w-[70px] pl-2" }, event.allDay ? /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex flex-col items-center" }, /* @__PURE__ */ React15__namespace.default.createElement("span", { className: "text-xs font-semibold text-muted-foreground bg-muted/80 px-2.5 py-1 rounded-full" }, "All Day")) : /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex flex-col items-center" }, /* @__PURE__ */ React15__namespace.default.createElement("span", { className: "text-base font-semibold text-foreground" }, dateFns.format(event.start, "h:mm")), /* @__PURE__ */ React15__namespace.default.createElement("span", { className: "text-xs text-muted-foreground uppercase" }, dateFns.format(event.start, "a")), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "w-px h-3 bg-border my-1" }), /* @__PURE__ */ React15__namespace.default.createElement("span", { className: "text-xs text-muted-foreground/70 font-medium" }, formatDuration(event.start, event.end)))),
1145
+ /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex-1 min-w-0 space-y-2" }, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex items-start justify-between gap-2" }, /* @__PURE__ */ React15__namespace.default.createElement("h4", { className: "text-base font-semibold text-foreground group-hover:text-primary transition-colors line-clamp-1" }, event.title), /* @__PURE__ */ React15__namespace.default.createElement(
1146
+ "div",
1147
+ {
1148
+ className: "w-3 h-3 rounded-full shrink-0 mt-1.5",
1149
+ style: { backgroundColor: event.color || "var(--primary)" }
1150
+ }
1151
+ )), event.description && /* @__PURE__ */ React15__namespace.default.createElement("p", { className: "text-sm text-muted-foreground line-clamp-2 leading-relaxed" }, event.description), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex flex-wrap items-center gap-3 pt-1" }, !event.allDay && /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex items-center gap-1.5 text-xs text-muted-foreground" }, /* @__PURE__ */ React15__namespace.default.createElement(lucideReact.Clock, { className: "w-3.5 h-3.5" }), /* @__PURE__ */ React15__namespace.default.createElement("span", null, dateFns.format(event.start, "h:mm a"), " - ", dateFns.format(event.end, "h:mm a"))), event.guests && event.guests.length > 0 && /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex items-center gap-1.5 text-xs text-muted-foreground" }, /* @__PURE__ */ React15__namespace.default.createElement(lucideReact.Users, { className: "w-3.5 h-3.5" }), /* @__PURE__ */ React15__namespace.default.createElement("span", null, event.guests.length, " guest", event.guests.length !== 1 ? "s" : "")), event.attachments && event.attachments.length > 0 && /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex items-center gap-1.5 text-xs text-muted-foreground" }, /* @__PURE__ */ React15__namespace.default.createElement(lucideReact.Paperclip, { className: "w-3.5 h-3.5" }), /* @__PURE__ */ React15__namespace.default.createElement("span", null, event.attachments.length)), event.reminders && event.reminders.length > 0 && /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex items-center gap-1.5 text-xs text-muted-foreground" }, /* @__PURE__ */ React15__namespace.default.createElement(lucideReact.Bell, { className: "w-3.5 h-3.5" }), /* @__PURE__ */ React15__namespace.default.createElement("span", null, event.reminders.length)))),
1152
+ /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "absolute right-4 top-1/2 -translate-y-1/2 opacity-0 group-hover:opacity-100 transition-opacity" }, /* @__PURE__ */ React15__namespace.default.createElement("svg", { className: "w-5 h-5 text-muted-foreground", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2" }, /* @__PURE__ */ React15__namespace.default.createElement("path", { d: "M9 18l6-6-6-6" })))
1153
+ )))
1154
+ ))
1155
+ ));
1156
+ };
1157
+ var ResourceView = ({
1158
+ currentDate,
1159
+ events,
1160
+ resources,
1161
+ onEventClick,
1162
+ onTimeSlotClick,
1163
+ locale
1164
+ }) => {
1165
+ const containerRef = React15.useRef(null);
1166
+ const hours = Array.from({ length: 24 }, (_, i) => i);
1167
+ const hourWidth = 100;
1168
+ const timeFormat = locale?.code === "fr" ? "H:mm" : "h a";
1169
+ const getEventStyle = (event) => {
1170
+ const start = new Date(event.start);
1171
+ const end = new Date(event.end);
1172
+ const dayStart = dateFns.startOfDay(currentDate);
1173
+ const startMinutes = dateFns.differenceInMinutes(start, dayStart);
1174
+ const durationMinutes = dateFns.differenceInMinutes(end, start);
1175
+ const left = startMinutes / 60 * hourWidth;
1176
+ const width = durationMinutes / 60 * hourWidth;
1177
+ return {
1178
+ left: `${left}px`,
1179
+ width: `${Math.max(width, 4)}px`
1180
+ // Min width for visibility
1181
+ };
1182
+ };
1183
+ return /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex flex-col h-full bg-background overflow-hidden" }, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex border-b border-border bg-muted/20" }, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "w-48 shrink-0 border-r border-border p-4 font-semibold text-sm bg-background sticky left-0 z-20" }, "Resources"), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex overflow-hidden" }, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex relative", style: { width: hours.length * hourWidth } }, hours.map((hour) => /* @__PURE__ */ React15__namespace.default.createElement(
1184
+ "div",
1185
+ {
1186
+ key: hour,
1187
+ className: "border-r border-border/50 text-xs text-muted-foreground p-2 font-medium shrink-0",
1188
+ style: { width: hourWidth }
1189
+ },
1190
+ dateFns.format((/* @__PURE__ */ new Date()).setHours(hour, 0, 0, 0), timeFormat, { locale })
1191
+ ))))), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex-1 overflow-auto relative", ref: containerRef }, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "min-w-fit" }, resources.map((resource) => {
1192
+ const resourceEvents = events.filter(
1193
+ (e) => e.resourceId === resource.id && dateFns.isSameDay(new Date(e.start), currentDate)
1194
+ );
1195
+ return /* @__PURE__ */ React15__namespace.default.createElement("div", { key: resource.id, className: "flex border-b border-border min-h-[100px]" }, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "w-48 shrink-0 border-r border-border p-4 bg-background sticky left-0 z-10 flex items-center gap-3" }, resource.avatar ? /* @__PURE__ */ React15__namespace.default.createElement("img", { src: resource.avatar, alt: resource.label, className: "w-8 h-8 rounded-full object-cover" }) : /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "w-8 h-8 rounded-full bg-primary/10 flex items-center justify-center text-xs font-bold text-primary" }, resource.label.substring(0, 2).toUpperCase()), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex flex-col" }, /* @__PURE__ */ React15__namespace.default.createElement("span", { className: "text-sm font-medium" }, resource.label), /* @__PURE__ */ React15__namespace.default.createElement("span", { className: "text-xs text-muted-foreground" }, "ID: ", resource.id))), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "relative flex", style: { width: hours.length * hourWidth } }, hours.map((hour) => /* @__PURE__ */ React15__namespace.default.createElement(
1196
+ "div",
1197
+ {
1198
+ key: hour,
1199
+ className: "flex h-full shrink-0",
1200
+ style: { width: hourWidth }
1201
+ },
1202
+ [0, 15, 30, 45].map((minute) => {
1203
+ const slotDate = new Date(currentDate);
1204
+ slotDate.setHours(hour, minute, 0, 0);
1205
+ const slotId = `${resource.id}-${slotDate.toISOString()}`;
1206
+ return /* @__PURE__ */ React15__namespace.default.createElement(
1207
+ DroppableCell,
1208
+ {
1209
+ key: minute,
1210
+ id: slotId,
1211
+ date: slotDate,
1212
+ resourceId: resource.id,
1213
+ className: "h-full flex-1 border-r border-border/10 last:border-border/30 hover:bg-accent/10 transition-colors",
1214
+ onClick: () => {
1215
+ onTimeSlotClick?.(slotDate, resource.id);
1216
+ }
1217
+ }
1218
+ );
1219
+ })
1220
+ )), resourceEvents.map((event) => /* @__PURE__ */ React15__namespace.default.createElement(
1221
+ DraggableEvent,
1222
+ {
1223
+ key: event.id,
1224
+ event,
1225
+ onClick: (e) => {
1226
+ e.stopPropagation();
1227
+ onEventClick?.(event);
1228
+ },
1229
+ className: "absolute top-2 bottom-2 rounded-md px-2 py-1 text-xs font-medium border shadow-sm cursor-pointer overflow-hidden hover:brightness-95 transition-all z-10",
1230
+ style: {
1231
+ ...getEventStyle(event),
1232
+ backgroundColor: event.color || resource.color || "var(--primary)",
1233
+ borderColor: "rgba(0,0,0,0.1)",
1234
+ color: "#fff"
1235
+ }
1236
+ },
1237
+ /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "truncate" }, event.title)
1238
+ ))));
1239
+ }))));
1240
+ };
1241
+ var Modal = ({
1242
+ isOpen,
1243
+ onClose,
1244
+ title,
1245
+ children,
1246
+ className,
1247
+ hideHeader = false
1248
+ }) => {
1249
+ const overlayRef = React15.useRef(null);
1250
+ React15.useEffect(() => {
1251
+ const handleEscape = (e) => {
1252
+ if (e.key === "Escape") {
1253
+ onClose();
1254
+ }
1255
+ };
1256
+ if (isOpen) {
1257
+ document.addEventListener("keydown", handleEscape);
1258
+ }
1259
+ return () => {
1260
+ document.removeEventListener("keydown", handleEscape);
1261
+ };
1262
+ }, [isOpen, onClose]);
1263
+ if (!isOpen) return null;
1264
+ return /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "absolute inset-0 z-50 flex items-center justify-center p-4 bg-black/40 backdrop-blur-md animate-in fade-in duration-300" }, /* @__PURE__ */ React15__namespace.default.createElement(
1265
+ "div",
1266
+ {
1267
+ ref: overlayRef,
1268
+ className: "absolute inset-0",
1269
+ onClick: onClose
1270
+ }
1271
+ ), /* @__PURE__ */ React15__namespace.default.createElement(
1272
+ "div",
1273
+ {
1274
+ className: cn(
1275
+ "relative bg-background rounded-2xl shadow-2xl w-full max-w-md flex flex-col max-h-[70vh] sm:max-h-[80vh] animate-in zoom-in-95 slide-in-from-bottom-4 duration-300 border border-border/50",
1276
+ className
1277
+ )
1278
+ },
1279
+ !hideHeader && /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex items-center justify-between px-6 py-4 border-b border-border/50 shrink-0 bg-gradient-to-r from-muted/20 to-background" }, /* @__PURE__ */ React15__namespace.default.createElement("h3", { className: "text-lg font-semibold text-foreground" }, title), /* @__PURE__ */ React15__namespace.default.createElement(
1280
+ Button,
1281
+ {
1282
+ variant: "ghost",
1283
+ size: "sm",
1284
+ onClick: onClose,
1285
+ className: "h-9 w-9 p-0 rounded-xl hover:bg-accent/80 transition-all duration-200"
1286
+ },
1287
+ /* @__PURE__ */ React15__namespace.default.createElement(lucideReact.X, { className: "h-4 w-4" }),
1288
+ /* @__PURE__ */ React15__namespace.default.createElement("span", { className: "sr-only" }, "Close")
1289
+ )),
1290
+ /* @__PURE__ */ React15__namespace.default.createElement("div", { className: cn("overflow-y-auto flex-1", !hideHeader && "p-6") }, children)
1291
+ ));
1292
+ };
1293
+ var REMINDER_OPTIONS = [
1294
+ { value: 0, label: "At time of event" },
1295
+ { value: 5, label: "5 minutes before" },
1296
+ { value: 10, label: "10 minutes before" },
1297
+ { value: 15, label: "15 minutes before" },
1298
+ { value: 30, label: "30 minutes before" },
1299
+ { value: 60, label: "1 hour before" },
1300
+ { value: 120, label: "2 hours before" },
1301
+ { value: 1440, label: "1 day before" },
1302
+ { value: 2880, label: "2 days before" },
1303
+ { value: 10080, label: "1 week before" }
1304
+ ];
1305
+ var COLOR_PALETTE = [
1306
+ "#3b82f6",
1307
+ // Blue
1308
+ "#ef4444",
1309
+ // Red
1310
+ "#10b981",
1311
+ // Emerald
1312
+ "#f59e0b",
1313
+ // Amber
1314
+ "#8b5cf6",
1315
+ // Violet
1316
+ "#ec4899",
1317
+ // Pink
1318
+ "#06b6d4",
1319
+ // Cyan
1320
+ "#84cc16",
1321
+ // Lime
1322
+ "#f97316",
1323
+ // Orange
1324
+ "#6366f1"
1325
+ // Indigo
1326
+ ];
1327
+ var EventModal = ({
1328
+ isOpen,
1329
+ onClose,
1330
+ event,
1331
+ initialDate,
1332
+ onSave,
1333
+ onDelete,
1334
+ calendars,
1335
+ eventTypes,
1336
+ translations
1337
+ }) => {
1338
+ const [mode, setMode] = React15.useState("create");
1339
+ const [activeTab, setActiveTab] = React15.useState("details");
1340
+ const [formData, setFormData] = React15.useState({
1341
+ title: "",
1342
+ description: "",
1343
+ location: "",
1344
+ start: /* @__PURE__ */ new Date(),
1345
+ end: /* @__PURE__ */ new Date(),
1346
+ allDay: false,
1347
+ color: "#3b82f6",
1348
+ calendarId: calendars?.[0]?.id,
1349
+ type: void 0,
1350
+ recurrence: void 0,
1351
+ attachments: [],
1352
+ reminders: [{ id: "1", type: "notification", time: 30, label: "30 minutes before" }]
1353
+ });
1354
+ const [isCalendarDropdownOpen, setIsCalendarDropdownOpen] = React15.useState(false);
1355
+ const [isColorPickerOpen, setIsColorPickerOpen] = React15.useState(false);
1356
+ const [isReminderDropdownOpen, setIsReminderDropdownOpen] = React15.useState(false);
1357
+ const [isGuestsDropdownOpen, setIsGuestsDropdownOpen] = React15.useState(false);
1358
+ const fakeGuests = [
1359
+ "alice@example.com",
1360
+ "bob@example.com",
1361
+ "charlie@example.com",
1362
+ "diana@example.com",
1363
+ "evan@example.com"
1364
+ ];
1365
+ React15.useRef(null);
1366
+ const [selectedGuests, setSelectedGuests] = React15.useState([]);
1367
+ React15.useEffect(() => {
1368
+ if (isOpen) {
1369
+ if (event) {
1370
+ setMode("view");
1371
+ setFormData({
1372
+ ...event,
1373
+ start: new Date(event.start),
1374
+ end: new Date(event.end),
1375
+ attachments: event.attachments || [],
1376
+ reminders: event.reminders || [{ id: "1", type: "notification", time: 30, label: "30 minutes before" }]
1377
+ });
1378
+ setSelectedGuests(event.guests || []);
1379
+ } else {
1380
+ setMode("create");
1381
+ const start = initialDate || /* @__PURE__ */ new Date();
1382
+ const end = new Date(start);
1383
+ end.setHours(start.getHours() + 1);
1384
+ setFormData({
1385
+ title: "",
1386
+ description: "",
1387
+ location: "",
1388
+ start,
1389
+ end,
1390
+ allDay: false,
1391
+ color: "#3b82f6",
1392
+ calendarId: calendars?.[0]?.id,
1393
+ attachments: [],
1394
+ reminders: [{ id: "1", type: "notification", time: 30, label: "30 minutes before" }]
1395
+ });
1396
+ setSelectedGuests([]);
1397
+ setActiveTab("details");
1398
+ }
1399
+ }
1400
+ }, [isOpen, event, initialDate, calendars]);
1401
+ const toggleGuest = (email) => {
1402
+ setSelectedGuests((prev) => {
1403
+ const newGuests = prev.includes(email) ? prev.filter((e) => e !== email) : [...prev, email];
1404
+ setFormData((curr) => ({ ...curr, guests: newGuests }));
1405
+ return newGuests;
1406
+ });
1407
+ };
1408
+ const handleSubmit = (e) => {
1409
+ e.preventDefault();
1410
+ let eventColor = formData.color;
1411
+ if (formData.calendarId && calendars) {
1412
+ const selectedCal = calendars.find((c) => c.id === formData.calendarId);
1413
+ if (selectedCal?.color) {
1414
+ eventColor = selectedCal.color;
1415
+ }
1416
+ }
1417
+ onSave({
1418
+ ...formData,
1419
+ color: eventColor,
1420
+ id: event?.id
1421
+ });
1422
+ onClose();
1423
+ };
1424
+ const handleDelete = () => {
1425
+ if (event?.id && onDelete) {
1426
+ onDelete(event.id);
1427
+ onClose();
1428
+ }
1429
+ };
1430
+ const formatDateForInput = (date) => {
1431
+ if (!date) return "";
1432
+ return dateFns.format(date, "yyyy-MM-dd'T'HH:mm");
1433
+ };
1434
+ const handleDateChange = (field, value) => {
1435
+ const date = new Date(value);
1436
+ if (isNaN(date.getTime())) return;
1437
+ if (field === "start") {
1438
+ const duration = formData.end.getTime() - formData.start.getTime();
1439
+ setFormData((prev) => ({
1440
+ ...prev,
1441
+ start: date,
1442
+ end: new Date(date.getTime() + duration)
1443
+ }));
1444
+ } else {
1445
+ if (date < formData.start) {
1446
+ setFormData((prev) => ({ ...prev, start: date, end: date }));
1447
+ } else {
1448
+ setFormData((prev) => ({ ...prev, end: date }));
1449
+ }
1450
+ }
1451
+ };
1452
+ const addReminder = (minutes, label) => {
1453
+ const newReminder = {
1454
+ id: Math.random().toString(36).substr(2, 9),
1455
+ type: "notification",
1456
+ time: minutes,
1457
+ label
1458
+ };
1459
+ setFormData((prev) => ({
1460
+ ...prev,
1461
+ reminders: [...prev.reminders || [], newReminder]
1462
+ }));
1463
+ setIsReminderDropdownOpen(false);
1464
+ };
1465
+ const removeReminder = (id) => {
1466
+ setFormData((prev) => ({
1467
+ ...prev,
1468
+ reminders: prev.reminders?.filter((r) => r.id !== id)
1469
+ }));
1470
+ };
1471
+ const handleDownload = (attachment) => {
1472
+ const element = document.createElement("a");
1473
+ const file = new Blob(["Dummy content for " + attachment.name], { type: "text/plain" });
1474
+ element.href = URL.createObjectURL(file);
1475
+ element.download = attachment.name;
1476
+ document.body.appendChild(element);
1477
+ element.click();
1478
+ document.body.removeChild(element);
1479
+ };
1480
+ const getDurationText = () => {
1481
+ if (!formData.start || !formData.end) return "";
1482
+ const mins = dateFns.differenceInMinutes(formData.end, formData.start);
1483
+ if (mins < 60) return `${mins} min`;
1484
+ const hours = Math.floor(mins / 60);
1485
+ const remainingMins = mins % 60;
1486
+ if (remainingMins === 0) return `${hours} hr`;
1487
+ return `${hours} hr ${remainingMins} min`;
1488
+ };
1489
+ const renderViewMode = () => /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex flex-col bg-background overflow-hidden w-full max-h-[90vh]" }, /* @__PURE__ */ React15__namespace.default.createElement(
1490
+ "div",
1491
+ {
1492
+ className: "relative px-6 pt-6 pb-8",
1493
+ style: {
1494
+ background: `linear-gradient(135deg, ${event?.color || "#3b82f6"}15 0%, transparent 100%)`
1495
+ }
1496
+ },
1497
+ /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex items-center justify-between mb-6" }, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React15__namespace.default.createElement(
1498
+ "div",
1499
+ {
1500
+ className: "w-3 h-3 rounded-full",
1501
+ style: { backgroundColor: event?.color || "#3b82f6" }
1502
+ }
1503
+ ), /* @__PURE__ */ React15__namespace.default.createElement("span", { className: "text-xs font-medium text-muted-foreground uppercase tracking-wider" }, calendars?.find((c) => c.id === event?.calendarId)?.label || "Event")), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex items-center gap-1" }, /* @__PURE__ */ React15__namespace.default.createElement(
1504
+ "button",
1505
+ {
1506
+ onClick: () => setMode("edit"),
1507
+ className: "p-2 hover:bg-background/80 rounded-lg transition-all text-muted-foreground hover:text-foreground",
1508
+ title: "Edit"
1509
+ },
1510
+ /* @__PURE__ */ React15__namespace.default.createElement(lucideReact.Edit2, { className: "w-4 h-4" })
1511
+ ), /* @__PURE__ */ React15__namespace.default.createElement(
1512
+ "button",
1513
+ {
1514
+ onClick: handleDelete,
1515
+ className: "p-2 hover:bg-destructive/10 rounded-lg transition-all text-muted-foreground hover:text-destructive",
1516
+ title: "Delete"
1517
+ },
1518
+ /* @__PURE__ */ React15__namespace.default.createElement(lucideReact.Trash2, { className: "w-4 h-4" })
1519
+ ), /* @__PURE__ */ React15__namespace.default.createElement(
1520
+ "button",
1521
+ {
1522
+ onClick: onClose,
1523
+ className: "p-2 hover:bg-background/80 rounded-lg transition-all text-muted-foreground hover:text-foreground",
1524
+ title: "Close"
1525
+ },
1526
+ /* @__PURE__ */ React15__namespace.default.createElement(lucideReact.X, { className: "w-4 h-4" })
1527
+ ))),
1528
+ /* @__PURE__ */ React15__namespace.default.createElement("h1", { className: "text-2xl font-bold text-foreground mb-3 leading-tight" }, event?.title || "(No title)"),
1529
+ /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex items-center gap-3 text-sm" }, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex items-center gap-2 px-3 py-1.5 bg-background/60 backdrop-blur-sm rounded-lg border border-border/30" }, /* @__PURE__ */ React15__namespace.default.createElement(lucideReact.Calendar, { className: "w-4 h-4 text-muted-foreground" }), /* @__PURE__ */ React15__namespace.default.createElement("span", { className: "font-medium" }, event?.start && dateFns.format(new Date(event.start), "EEE, MMM d"))), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex items-center gap-2 px-3 py-1.5 bg-background/60 backdrop-blur-sm rounded-lg border border-border/30" }, /* @__PURE__ */ React15__namespace.default.createElement(lucideReact.Clock, { className: "w-4 h-4 text-muted-foreground" }), /* @__PURE__ */ React15__namespace.default.createElement("span", { className: "font-medium" }, event?.start && dateFns.format(new Date(event.start), "h:mm a"), " \u2013 ", event?.end && dateFns.format(new Date(event.end), "h:mm a"))))
1530
+ ), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "px-6 pb-6 space-y-4 overflow-y-auto flex-1" }, event?.location && /* @__PURE__ */ React15__namespace.default.createElement(
1531
+ framerMotion.motion.div,
1532
+ {
1533
+ initial: { opacity: 0, y: 10 },
1534
+ animate: { opacity: 1, y: 0 },
1535
+ className: "flex items-start gap-3 p-4 rounded-2xl bg-muted/30 border border-border/30 group hover:bg-muted/50 transition-all cursor-pointer"
1536
+ },
1537
+ /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "p-2 bg-primary/10 rounded-xl" }, /* @__PURE__ */ React15__namespace.default.createElement(lucideReact.MapPin, { className: "w-5 h-5 text-primary" })),
1538
+ /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex-1" }, /* @__PURE__ */ React15__namespace.default.createElement("p", { className: "text-sm font-medium text-foreground" }, event.location), /* @__PURE__ */ React15__namespace.default.createElement("p", { className: "text-xs text-muted-foreground mt-0.5" }, "Click to open in maps")),
1539
+ /* @__PURE__ */ React15__namespace.default.createElement(lucideReact.ExternalLink, { className: "w-4 h-4 text-muted-foreground opacity-0 group-hover:opacity-100 transition-opacity" })
1540
+ ), event?.guests && event.guests.length > 0 && /* @__PURE__ */ React15__namespace.default.createElement(
1541
+ framerMotion.motion.div,
1542
+ {
1543
+ initial: { opacity: 0, y: 10 },
1544
+ animate: { opacity: 1, y: 0 },
1545
+ transition: { delay: 0.05 },
1546
+ className: "space-y-3"
1547
+ },
1548
+ /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex items-center justify-between" }, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React15__namespace.default.createElement(lucideReact.Users, { className: "w-4 h-4 text-muted-foreground" }), /* @__PURE__ */ React15__namespace.default.createElement("span", { className: "text-sm font-medium text-foreground" }, event.guests.length, " ", event.guests.length > 1 ? "Guests" : "Guest"))),
1549
+ /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex flex-wrap gap-2" }, event.guests.map((email, index) => /* @__PURE__ */ React15__namespace.default.createElement(
1550
+ "div",
1551
+ {
1552
+ key: index,
1553
+ className: "flex items-center gap-2 px-3 py-2 rounded-xl bg-muted/30 border border-border/30 hover:bg-muted/50 transition-all cursor-pointer group"
1554
+ },
1555
+ /* @__PURE__ */ React15__namespace.default.createElement(
1556
+ "div",
1557
+ {
1558
+ className: "w-8 h-8 rounded-full flex items-center justify-center text-sm font-semibold text-white",
1559
+ style: { backgroundColor: `hsl(${index * 60}, 70%, 50%)` }
1560
+ },
1561
+ email[0].toUpperCase()
1562
+ ),
1563
+ /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex-1 min-w-0" }, /* @__PURE__ */ React15__namespace.default.createElement("p", { className: "text-sm font-medium text-foreground" }, email.split("@")[0]), /* @__PURE__ */ React15__namespace.default.createElement("p", { className: "text-xs text-muted-foreground truncate" }, email))
1564
+ )))
1565
+ ), event?.reminders && event.reminders.length > 0 && /* @__PURE__ */ React15__namespace.default.createElement(
1566
+ framerMotion.motion.div,
1567
+ {
1568
+ initial: { opacity: 0, y: 10 },
1569
+ animate: { opacity: 1, y: 0 },
1570
+ transition: { delay: 0.1 },
1571
+ className: "flex items-center gap-3"
1572
+ },
1573
+ /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "p-2 bg-amber-500/10 rounded-xl" }, /* @__PURE__ */ React15__namespace.default.createElement(lucideReact.Bell, { className: "w-4 h-4 text-amber-500" })),
1574
+ /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex flex-wrap gap-2" }, event.reminders.map((reminder) => /* @__PURE__ */ React15__namespace.default.createElement(
1575
+ "span",
1576
+ {
1577
+ key: reminder.id,
1578
+ className: "text-xs font-medium px-2.5 py-1 rounded-full bg-amber-500/10 text-amber-600 dark:text-amber-400"
1579
+ },
1580
+ reminder.label || `${reminder.time} min before`
1581
+ )))
1582
+ ), event?.description && /* @__PURE__ */ React15__namespace.default.createElement(
1583
+ framerMotion.motion.div,
1584
+ {
1585
+ initial: { opacity: 0, y: 10 },
1586
+ animate: { opacity: 1, y: 0 },
1587
+ transition: { delay: 0.15 },
1588
+ className: "space-y-2"
1589
+ },
1590
+ /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React15__namespace.default.createElement(lucideReact.AlignLeft, { className: "w-4 h-4 text-muted-foreground" }), /* @__PURE__ */ React15__namespace.default.createElement("span", { className: "text-sm font-medium text-foreground" }, "Notes")),
1591
+ /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "text-sm text-foreground/80 whitespace-pre-wrap leading-relaxed pl-6 p-3 rounded-xl bg-muted/20 border border-border/30" }, event.description)
1592
+ ), event?.attachments && event.attachments.length > 0 && /* @__PURE__ */ React15__namespace.default.createElement(
1593
+ framerMotion.motion.div,
1594
+ {
1595
+ initial: { opacity: 0, y: 10 },
1596
+ animate: { opacity: 1, y: 0 },
1597
+ transition: { delay: 0.2 },
1598
+ className: "space-y-2"
1599
+ },
1600
+ /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React15__namespace.default.createElement(lucideReact.Paperclip, { className: "w-4 h-4 text-muted-foreground" }), /* @__PURE__ */ React15__namespace.default.createElement("span", { className: "text-sm font-medium text-foreground" }, "Attachments")),
1601
+ /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "grid gap-2" }, event.attachments.map((att) => /* @__PURE__ */ React15__namespace.default.createElement(
1602
+ "div",
1603
+ {
1604
+ key: att.id,
1605
+ onClick: () => handleDownload(att),
1606
+ className: "flex items-center gap-3 p-3 rounded-xl border border-border/30 bg-muted/20 hover:bg-muted/40 transition-all cursor-pointer group"
1607
+ },
1608
+ /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "p-2 bg-primary/10 rounded-lg" }, /* @__PURE__ */ React15__namespace.default.createElement(lucideReact.File, { className: "w-4 h-4 text-primary" })),
1609
+ /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex-1 min-w-0" }, /* @__PURE__ */ React15__namespace.default.createElement("p", { className: "text-sm font-medium text-foreground truncate" }, att.name), /* @__PURE__ */ React15__namespace.default.createElement("p", { className: "text-xs text-muted-foreground" }, att.size)),
1610
+ /* @__PURE__ */ React15__namespace.default.createElement(lucideReact.Download, { className: "w-4 h-4 text-muted-foreground opacity-0 group-hover:opacity-100 transition-opacity" })
1611
+ )))
1612
+ )));
1613
+ const renderEditMode = () => /* @__PURE__ */ React15__namespace.default.createElement("form", { onSubmit: handleSubmit, className: "flex flex-col bg-background overflow-hidden w-full max-h-[85vh]" }, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex items-center justify-between px-5 py-4 border-b border-border/50 shrink-0" }, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex items-center gap-3" }, /* @__PURE__ */ React15__namespace.default.createElement(
1614
+ "button",
1615
+ {
1616
+ type: "button",
1617
+ onClick: () => setIsColorPickerOpen(!isColorPickerOpen),
1618
+ className: "relative p-1"
1619
+ },
1620
+ /* @__PURE__ */ React15__namespace.default.createElement(
1621
+ "div",
1622
+ {
1623
+ className: "w-5 h-5 rounded-full cursor-pointer hover:scale-110 transition-transform",
1624
+ style: {
1625
+ backgroundColor: formData.color,
1626
+ boxShadow: `0 0 0 2px var(--background), 0 0 0 4px ${formData.color}60`
1627
+ }
1628
+ }
1629
+ ),
1630
+ isColorPickerOpen && /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "absolute top-full left-0 mt-2 p-2 bg-background border border-border rounded-xl shadow-xl z-50 flex flex-wrap gap-1.5 w-[180px]" }, COLOR_PALETTE.map((color) => /* @__PURE__ */ React15__namespace.default.createElement(
1631
+ "button",
1632
+ {
1633
+ key: color,
1634
+ type: "button",
1635
+ onClick: () => {
1636
+ setFormData((prev) => ({ ...prev, color }));
1637
+ setIsColorPickerOpen(false);
1638
+ },
1639
+ className: cn(
1640
+ "w-7 h-7 rounded-full transition-all hover:scale-110",
1641
+ formData.color === color && "ring-2 ring-offset-2 ring-offset-background ring-current"
1642
+ ),
1643
+ style: { backgroundColor: color, color }
1644
+ }
1645
+ )))
1646
+ ), /* @__PURE__ */ React15__namespace.default.createElement("h2", { className: "text-lg font-semibold text-foreground" }, mode === "edit" ? "Edit Event" : "New Event")), /* @__PURE__ */ React15__namespace.default.createElement(
1647
+ "button",
1648
+ {
1649
+ type: "button",
1650
+ onClick: onClose,
1651
+ className: "p-2 hover:bg-accent rounded-xl transition-all text-muted-foreground hover:text-foreground"
1652
+ },
1653
+ /* @__PURE__ */ React15__namespace.default.createElement(lucideReact.X, { className: "w-4 h-4" })
1654
+ )), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex-1 overflow-y-auto" }, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "px-5 py-4 space-y-5" }, /* @__PURE__ */ React15__namespace.default.createElement("div", null, /* @__PURE__ */ React15__namespace.default.createElement(
1655
+ "input",
1656
+ {
1657
+ type: "text",
1658
+ required: true,
1659
+ autoFocus: true,
1660
+ className: "w-full text-xl font-semibold border-0 border-b-2 border-transparent focus:border-primary bg-transparent px-0 py-2 placeholder-muted-foreground/50 transition-all text-foreground focus:outline-none",
1661
+ value: formData.title,
1662
+ onChange: (e) => setFormData({ ...formData, title: e.target.value }),
1663
+ placeholder: "Add title"
1664
+ }
1665
+ )), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex items-center gap-3 p-4 rounded-2xl bg-muted/20 border border-border/30" }, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "p-2 bg-primary/10 rounded-xl shrink-0" }, /* @__PURE__ */ React15__namespace.default.createElement(lucideReact.Clock, { className: "w-5 h-5 text-primary" })), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex-1 grid grid-cols-2 gap-3" }, /* @__PURE__ */ React15__namespace.default.createElement("div", null, /* @__PURE__ */ React15__namespace.default.createElement("label", { className: "text-[10px] font-semibold text-muted-foreground uppercase tracking-wider mb-1 block" }, "Start"), /* @__PURE__ */ React15__namespace.default.createElement(
1666
+ "input",
1667
+ {
1668
+ type: "datetime-local",
1669
+ className: "w-full bg-background border border-border/50 rounded-xl px-3 py-2 text-sm font-medium text-foreground focus:border-primary focus:ring-2 focus:ring-primary/20 transition-all",
1670
+ value: formatDateForInput(formData.start),
1671
+ onChange: (e) => handleDateChange("start", e.target.value)
1672
+ }
1673
+ )), /* @__PURE__ */ React15__namespace.default.createElement("div", null, /* @__PURE__ */ React15__namespace.default.createElement("label", { className: "text-[10px] font-semibold text-muted-foreground uppercase tracking-wider mb-1 block" }, "End"), /* @__PURE__ */ React15__namespace.default.createElement(
1674
+ "input",
1675
+ {
1676
+ type: "datetime-local",
1677
+ className: "w-full bg-background border border-border/50 rounded-xl px-3 py-2 text-sm font-medium text-foreground focus:border-primary focus:ring-2 focus:ring-primary/20 transition-all",
1678
+ value: formatDateForInput(formData.end),
1679
+ onChange: (e) => handleDateChange("end", e.target.value)
1680
+ }
1681
+ )))), getDurationText() && /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex justify-center" }, /* @__PURE__ */ React15__namespace.default.createElement("span", { className: "text-xs font-medium px-3 py-1 rounded-full bg-primary/10 text-primary" }, getDurationText())), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex items-center justify-between" }, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React15__namespace.default.createElement(lucideReact.Bell, { className: "w-4 h-4 text-muted-foreground" }), /* @__PURE__ */ React15__namespace.default.createElement("span", { className: "text-sm font-medium text-foreground" }, "Reminders")), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "relative" }, /* @__PURE__ */ React15__namespace.default.createElement(
1682
+ "button",
1683
+ {
1684
+ type: "button",
1685
+ onClick: () => setIsReminderDropdownOpen(!isReminderDropdownOpen),
1686
+ className: "flex items-center gap-1 text-xs font-medium text-primary hover:text-primary/80 transition-colors"
1687
+ },
1688
+ /* @__PURE__ */ React15__namespace.default.createElement(lucideReact.Plus, { className: "w-3.5 h-3.5" }),
1689
+ "Add"
1690
+ ), isReminderDropdownOpen && /* @__PURE__ */ React15__namespace.default.createElement(React15__namespace.default.Fragment, null, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "fixed inset-0 z-40", onClick: () => setIsReminderDropdownOpen(false) }), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "absolute right-0 top-full mt-1 w-48 bg-background border border-border rounded-xl shadow-xl z-50 py-1 max-h-60 overflow-y-auto" }, REMINDER_OPTIONS.map((option) => /* @__PURE__ */ React15__namespace.default.createElement(
1691
+ "button",
1692
+ {
1693
+ key: option.value,
1694
+ type: "button",
1695
+ onClick: () => addReminder(option.value, option.label),
1696
+ className: "w-full px-3 py-2 text-left text-sm hover:bg-accent transition-colors"
1697
+ },
1698
+ option.label
1699
+ )))))), formData.reminders && formData.reminders.length > 0 && /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex flex-wrap gap-2" }, formData.reminders.map((reminder) => /* @__PURE__ */ React15__namespace.default.createElement(
1700
+ "div",
1701
+ {
1702
+ key: reminder.id,
1703
+ className: "flex items-center gap-2 px-3 py-1.5 rounded-full bg-amber-500/10 border border-amber-500/20"
1704
+ },
1705
+ /* @__PURE__ */ React15__namespace.default.createElement(lucideReact.BellRing, { className: "w-3.5 h-3.5 text-amber-500" }),
1706
+ /* @__PURE__ */ React15__namespace.default.createElement("span", { className: "text-xs font-medium text-amber-600 dark:text-amber-400" }, reminder.label),
1707
+ /* @__PURE__ */ React15__namespace.default.createElement(
1708
+ "button",
1709
+ {
1710
+ type: "button",
1711
+ onClick: () => removeReminder(reminder.id),
1712
+ className: "p-0.5 hover:bg-amber-500/20 rounded-full transition-colors"
1713
+ },
1714
+ /* @__PURE__ */ React15__namespace.default.createElement(lucideReact.X, { className: "w-3 h-3 text-amber-500" })
1715
+ )
1716
+ )))), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React15__namespace.default.createElement(lucideReact.Users, { className: "w-4 h-4 text-muted-foreground" }), /* @__PURE__ */ React15__namespace.default.createElement("span", { className: "text-sm font-medium text-foreground" }, "Guests")), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "relative" }, /* @__PURE__ */ React15__namespace.default.createElement(
1717
+ "button",
1718
+ {
1719
+ type: "button",
1720
+ onClick: () => setIsGuestsDropdownOpen(!isGuestsDropdownOpen),
1721
+ className: "w-full flex items-center justify-between px-4 py-3 bg-muted/20 border border-border/30 rounded-xl text-sm text-left hover:bg-muted/30 transition-all"
1722
+ },
1723
+ /* @__PURE__ */ React15__namespace.default.createElement("span", { className: selectedGuests.length > 0 ? "text-foreground font-medium" : "text-muted-foreground" }, selectedGuests.length > 0 ? `${selectedGuests.length} guest${selectedGuests.length > 1 ? "s" : ""} added` : "Add guests"),
1724
+ /* @__PURE__ */ React15__namespace.default.createElement(lucideReact.ChevronDown, { className: cn("w-4 h-4 text-muted-foreground transition-transform", isGuestsDropdownOpen && "rotate-180") })
1725
+ ), isGuestsDropdownOpen && /* @__PURE__ */ React15__namespace.default.createElement(React15__namespace.default.Fragment, null, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "fixed inset-0 z-40", onClick: () => setIsGuestsDropdownOpen(false) }), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "absolute z-50 w-full mt-2 bg-background border border-border rounded-xl shadow-xl max-h-48 overflow-y-auto" }, fakeGuests.map((email) => /* @__PURE__ */ React15__namespace.default.createElement(
1726
+ "div",
1727
+ {
1728
+ key: email,
1729
+ className: "px-4 py-3 hover:bg-accent cursor-pointer flex items-center gap-3 transition-colors",
1730
+ onClick: () => toggleGuest(email)
1731
+ },
1732
+ /* @__PURE__ */ React15__namespace.default.createElement("div", { className: cn(
1733
+ "w-5 h-5 rounded-md border-2 flex items-center justify-center transition-all",
1734
+ selectedGuests.includes(email) ? "bg-primary border-primary" : "border-border"
1735
+ ) }, selectedGuests.includes(email) && /* @__PURE__ */ React15__namespace.default.createElement(lucideReact.Check, { className: "w-3 h-3 text-primary-foreground" })),
1736
+ /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React15__namespace.default.createElement(
1737
+ "div",
1738
+ {
1739
+ className: "w-7 h-7 rounded-full flex items-center justify-center text-xs font-semibold text-white",
1740
+ style: { backgroundColor: `hsl(${fakeGuests.indexOf(email) * 60}, 70%, 50%)` }
1741
+ },
1742
+ email[0].toUpperCase()
1743
+ ), /* @__PURE__ */ React15__namespace.default.createElement("span", { className: "text-sm" }, email))
1744
+ ))))), selectedGuests.length > 0 && /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex flex-wrap gap-2 mt-2" }, selectedGuests.map((email) => /* @__PURE__ */ React15__namespace.default.createElement(
1745
+ "div",
1746
+ {
1747
+ key: email,
1748
+ className: "flex items-center gap-2 pl-1 pr-2 py-1 bg-muted/30 border border-border/30 rounded-full"
1749
+ },
1750
+ /* @__PURE__ */ React15__namespace.default.createElement(
1751
+ "div",
1752
+ {
1753
+ className: "w-6 h-6 rounded-full flex items-center justify-center text-xs font-semibold text-white",
1754
+ style: { backgroundColor: `hsl(${fakeGuests.indexOf(email) * 60}, 70%, 50%)` }
1755
+ },
1756
+ email[0].toUpperCase()
1757
+ ),
1758
+ /* @__PURE__ */ React15__namespace.default.createElement("span", { className: "text-xs font-medium text-foreground" }, email.split("@")[0]),
1759
+ /* @__PURE__ */ React15__namespace.default.createElement(
1760
+ "button",
1761
+ {
1762
+ type: "button",
1763
+ onClick: () => toggleGuest(email),
1764
+ className: "p-0.5 hover:bg-destructive/10 rounded-full transition-colors"
1765
+ },
1766
+ /* @__PURE__ */ React15__namespace.default.createElement(lucideReact.X, { className: "w-3 h-3 text-muted-foreground" })
1767
+ )
1768
+ )))), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex items-center gap-3 p-3 rounded-xl bg-muted/20 border border-border/30" }, /* @__PURE__ */ React15__namespace.default.createElement(lucideReact.MapPin, { className: "w-5 h-5 text-muted-foreground shrink-0" }), /* @__PURE__ */ React15__namespace.default.createElement(
1769
+ "input",
1770
+ {
1771
+ type: "text",
1772
+ className: "flex-1 bg-transparent text-sm text-foreground placeholder-muted-foreground focus:outline-none",
1773
+ placeholder: "Add location",
1774
+ value: formData.location || "",
1775
+ onChange: (e) => setFormData({ ...formData, location: e.target.value })
1776
+ }
1777
+ )), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React15__namespace.default.createElement(lucideReact.AlignLeft, { className: "w-4 h-4 text-muted-foreground" }), /* @__PURE__ */ React15__namespace.default.createElement("span", { className: "text-sm font-medium text-foreground" }, "Notes")), /* @__PURE__ */ React15__namespace.default.createElement(
1778
+ "textarea",
1779
+ {
1780
+ className: "w-full bg-muted/20 border border-border/30 rounded-xl px-4 py-3 text-sm min-h-[100px] resize-none text-foreground placeholder-muted-foreground focus:border-primary focus:ring-2 focus:ring-primary/20 transition-all",
1781
+ placeholder: "Add description or notes...",
1782
+ value: formData.description || "",
1783
+ onChange: (e) => setFormData({ ...formData, description: e.target.value })
1784
+ }
1785
+ )), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex items-center gap-3 p-3 rounded-xl bg-muted/20 border border-border/30" }, /* @__PURE__ */ React15__namespace.default.createElement(lucideReact.Repeat, { className: "w-5 h-5 text-muted-foreground shrink-0" }), /* @__PURE__ */ React15__namespace.default.createElement(
1786
+ "select",
1787
+ {
1788
+ className: "flex-1 bg-transparent text-sm text-foreground focus:outline-none cursor-pointer",
1789
+ value: formData.recurrence?.freq || "",
1790
+ onChange: (e) => {
1791
+ if (e.target.value === "") {
1792
+ setFormData({ ...formData, recurrence: void 0 });
1793
+ } else {
1794
+ setFormData({
1795
+ ...formData,
1796
+ recurrence: {
1797
+ freq: e.target.value,
1798
+ interval: 1
1799
+ }
1800
+ });
1801
+ }
1802
+ }
1803
+ },
1804
+ /* @__PURE__ */ React15__namespace.default.createElement("option", { value: "" }, "Does not repeat"),
1805
+ /* @__PURE__ */ React15__namespace.default.createElement("option", { value: "DAILY" }, "Daily"),
1806
+ /* @__PURE__ */ React15__namespace.default.createElement("option", { value: "WEEKLY" }, "Weekly"),
1807
+ /* @__PURE__ */ React15__namespace.default.createElement("option", { value: "MONTHLY" }, "Monthly"),
1808
+ /* @__PURE__ */ React15__namespace.default.createElement("option", { value: "YEARLY" }, "Yearly")
1809
+ )), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex items-center justify-between p-3 rounded-xl bg-muted/20 border border-border/30" }, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React15__namespace.default.createElement(lucideReact.Tag, { className: "w-5 h-5 text-muted-foreground" }), /* @__PURE__ */ React15__namespace.default.createElement("span", { className: "text-sm text-foreground" }, "Calendar")), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "relative" }, /* @__PURE__ */ React15__namespace.default.createElement(
1810
+ "button",
1811
+ {
1812
+ type: "button",
1813
+ onClick: () => setIsCalendarDropdownOpen(!isCalendarDropdownOpen),
1814
+ className: "flex items-center gap-2 px-3 py-1.5 bg-background border border-border/50 rounded-lg text-sm hover:bg-accent/50 transition-all"
1815
+ },
1816
+ /* @__PURE__ */ React15__namespace.default.createElement(
1817
+ "div",
1818
+ {
1819
+ className: "w-3 h-3 rounded-full",
1820
+ style: { backgroundColor: calendars?.find((c) => c.id === formData.calendarId)?.color || "#3b82f6" }
1821
+ }
1822
+ ),
1823
+ /* @__PURE__ */ React15__namespace.default.createElement("span", { className: "font-medium" }, calendars?.find((c) => c.id === formData.calendarId)?.label || "Select"),
1824
+ /* @__PURE__ */ React15__namespace.default.createElement(lucideReact.ChevronDown, { className: "w-3.5 h-3.5 text-muted-foreground" })
1825
+ ), isCalendarDropdownOpen && /* @__PURE__ */ React15__namespace.default.createElement(React15__namespace.default.Fragment, null, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "fixed inset-0 z-40", onClick: () => setIsCalendarDropdownOpen(false) }), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "absolute right-0 bottom-full mb-2 w-48 bg-background border border-border rounded-xl shadow-xl z-50 py-1" }, calendars?.map((cal) => /* @__PURE__ */ React15__namespace.default.createElement(
1826
+ "button",
1827
+ {
1828
+ key: cal.id,
1829
+ type: "button",
1830
+ className: "w-full flex items-center gap-3 px-3 py-2 hover:bg-accent transition-colors text-left",
1831
+ onClick: () => {
1832
+ setFormData({
1833
+ ...formData,
1834
+ calendarId: cal.id,
1835
+ color: cal.color || formData.color
1836
+ });
1837
+ setIsCalendarDropdownOpen(false);
1838
+ }
1839
+ },
1840
+ /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "w-3 h-3 rounded-full", style: { backgroundColor: cal.color } }),
1841
+ /* @__PURE__ */ React15__namespace.default.createElement("span", { className: "flex-1 text-sm" }, cal.label),
1842
+ formData.calendarId === cal.id && /* @__PURE__ */ React15__namespace.default.createElement(lucideReact.Check, { className: "w-4 h-4 text-primary" })
1843
+ )))))))), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "px-5 py-4 border-t border-border/50 flex items-center justify-between bg-muted/10 shrink-0" }, mode === "edit" && /* @__PURE__ */ React15__namespace.default.createElement(
1844
+ "button",
1845
+ {
1846
+ type: "button",
1847
+ onClick: handleDelete,
1848
+ className: "flex items-center gap-2 px-4 py-2 text-destructive hover:bg-destructive/10 rounded-xl transition-all text-sm font-medium"
1849
+ },
1850
+ /* @__PURE__ */ React15__namespace.default.createElement(lucideReact.Trash2, { className: "w-4 h-4" }),
1851
+ "Delete"
1852
+ ), mode === "create" && /* @__PURE__ */ React15__namespace.default.createElement("div", null), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React15__namespace.default.createElement(
1853
+ "button",
1854
+ {
1855
+ type: "button",
1856
+ onClick: onClose,
1857
+ className: "px-4 py-2.5 text-muted-foreground hover:text-foreground font-medium text-sm rounded-xl transition-all hover:bg-accent"
1858
+ },
1859
+ "Cancel"
1860
+ ), /* @__PURE__ */ React15__namespace.default.createElement(
1861
+ "button",
1862
+ {
1863
+ type: "submit",
1864
+ className: "px-6 py-2.5 bg-primary hover:bg-primary/90 text-primary-foreground font-semibold text-sm rounded-xl shadow-md transition-all hover:shadow-lg hover:shadow-primary/20 active:scale-95"
1865
+ },
1866
+ mode === "edit" ? "Save Changes" : "Create Event"
1867
+ ))));
1868
+ return /* @__PURE__ */ React15__namespace.default.createElement(Modal, { isOpen, onClose, hideHeader: true, className: "p-0 overflow-hidden max-w-lg rounded-2xl shadow-2xl" }, /* @__PURE__ */ React15__namespace.default.createElement(framerMotion.AnimatePresence, { mode: "wait" }, mode === "view" && event ? /* @__PURE__ */ React15__namespace.default.createElement(
1869
+ framerMotion.motion.div,
1870
+ {
1871
+ key: "view",
1872
+ initial: { opacity: 0 },
1873
+ animate: { opacity: 1 },
1874
+ exit: { opacity: 0 },
1875
+ transition: { duration: 0.15 }
1876
+ },
1877
+ renderViewMode()
1878
+ ) : /* @__PURE__ */ React15__namespace.default.createElement(
1879
+ framerMotion.motion.div,
1880
+ {
1881
+ key: "edit",
1882
+ initial: { opacity: 0 },
1883
+ animate: { opacity: 1 },
1884
+ exit: { opacity: 0 },
1885
+ transition: { duration: 0.15 }
1886
+ },
1887
+ renderEditMode()
1888
+ )));
1889
+ };
1890
+ var Skeleton = ({ className, style }) => /* @__PURE__ */ React15__namespace.default.createElement("div", { className: cn("animate-pulse bg-muted/40 rounded", className), style });
1891
+ var MonthViewSkeleton = () => /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "h-full bg-background border border-border/50 rounded-2xl overflow-hidden" }, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "grid grid-cols-7 border-b border-border/50 bg-muted/10" }, Array.from({ length: 7 }).map((_, i) => /* @__PURE__ */ React15__namespace.default.createElement("div", { key: i, className: "py-3 px-2 text-center border-r border-border/30 last:border-r-0" }, /* @__PURE__ */ React15__namespace.default.createElement(Skeleton, { className: "h-4 w-8 mx-auto" })))), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "grid grid-cols-7 flex-1" }, Array.from({ length: 35 }).map((_, i) => /* @__PURE__ */ React15__namespace.default.createElement("div", { key: i, className: "min-h-[120px] border-r border-b border-border/30 p-2" }, /* @__PURE__ */ React15__namespace.default.createElement(Skeleton, { className: "h-4 w-6 mb-2" }), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "space-y-1" }, Math.random() > 0.5 && /* @__PURE__ */ React15__namespace.default.createElement(Skeleton, { className: "h-5 w-full rounded-md" }), Math.random() > 0.7 && /* @__PURE__ */ React15__namespace.default.createElement(Skeleton, { className: "h-5 w-3/4 rounded-md" }))))));
1892
+ var WeekViewSkeleton = () => /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "h-full bg-background border border-border/50 rounded-2xl overflow-hidden" }, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex border-b border-border/50 bg-muted/10" }, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "w-16 p-3 border-r border-border/30" }, /* @__PURE__ */ React15__namespace.default.createElement(Skeleton, { className: "h-8 w-10 mx-auto" })), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex-1 grid grid-cols-7" }, Array.from({ length: 7 }).map((_, i) => /* @__PURE__ */ React15__namespace.default.createElement("div", { key: i, className: "py-3 px-2 text-center border-r border-border/30 last:border-r-0" }, /* @__PURE__ */ React15__namespace.default.createElement(Skeleton, { className: "h-3 w-8 mx-auto mb-1" }), /* @__PURE__ */ React15__namespace.default.createElement(Skeleton, { className: "h-8 w-8 mx-auto rounded-xl" }))))), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex flex-1", style: { height: "600px" } }, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "w-16 border-r border-border/30" }, Array.from({ length: 10 }).map((_, i) => /* @__PURE__ */ React15__namespace.default.createElement("div", { key: i, className: "h-[60px] relative" }, /* @__PURE__ */ React15__namespace.default.createElement(Skeleton, { className: "h-4 w-10 absolute right-2 -translate-y-1/2" })))), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex-1 grid grid-cols-7 relative" }, Array.from({ length: 7 }).map((_, colIdx) => /* @__PURE__ */ React15__namespace.default.createElement("div", { key: colIdx, className: "relative border-r border-border/30 last:border-r-0" }, Array.from({ length: 10 }).map((_2, rowIdx) => /* @__PURE__ */ React15__namespace.default.createElement("div", { key: rowIdx, className: "h-[60px] border-b border-dashed border-border/20" })), Math.random() > 0.3 && /* @__PURE__ */ React15__namespace.default.createElement(
1893
+ Skeleton,
1894
+ {
1895
+ className: "absolute rounded-md",
1896
+ style: {
1897
+ top: `${Math.floor(Math.random() * 400)}px`,
1898
+ left: "4px",
1899
+ right: "4px",
1900
+ height: `${60 + Math.floor(Math.random() * 120)}px`
1901
+ }
1902
+ }
1903
+ ))))));
1904
+ var DayViewSkeleton = () => /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "h-full bg-background border border-border/50 rounded-2xl overflow-hidden" }, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "px-6 py-4 border-b border-border/50 bg-muted/10 text-center" }, /* @__PURE__ */ React15__namespace.default.createElement(Skeleton, { className: "h-7 w-64 mx-auto" })), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex flex-1", style: { height: "600px" } }, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "w-20 border-r border-border/30 bg-muted/5" }, Array.from({ length: 10 }).map((_, i) => /* @__PURE__ */ React15__namespace.default.createElement("div", { key: i, className: "h-[80px] relative" }, /* @__PURE__ */ React15__namespace.default.createElement(Skeleton, { className: "h-4 w-12 absolute left-1/2 -translate-x-1/2 -translate-y-1/2" })))), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex-1 relative" }, Array.from({ length: 10 }).map((_, i) => /* @__PURE__ */ React15__namespace.default.createElement("div", { key: i, className: "h-[80px] border-b border-dashed border-border/20" })), /* @__PURE__ */ React15__namespace.default.createElement(
1905
+ Skeleton,
1906
+ {
1907
+ className: "absolute rounded-lg left-4 right-4",
1908
+ style: { top: "160px", height: "120px" }
1909
+ }
1910
+ ), /* @__PURE__ */ React15__namespace.default.createElement(
1911
+ Skeleton,
1912
+ {
1913
+ className: "absolute rounded-lg left-4 right-4",
1914
+ style: { top: "400px", height: "80px" }
1915
+ }
1916
+ ))));
1917
+ var AgendaViewSkeleton = () => /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "h-full bg-background border border-border/50 rounded-2xl overflow-hidden p-6" }, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "space-y-6" }, Array.from({ length: 4 }).map((_, dayIdx) => /* @__PURE__ */ React15__namespace.default.createElement("div", { key: dayIdx }, /* @__PURE__ */ React15__namespace.default.createElement(Skeleton, { className: "h-5 w-40 mb-4" }), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "space-y-3" }, Array.from({ length: 2 + Math.floor(Math.random() * 3) }).map((_2, eventIdx) => /* @__PURE__ */ React15__namespace.default.createElement("div", { key: eventIdx, className: "flex items-center gap-4 p-3 rounded-xl bg-muted/10" }, /* @__PURE__ */ React15__namespace.default.createElement(Skeleton, { className: "h-10 w-10 rounded-lg" }), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex-1 space-y-2" }, /* @__PURE__ */ React15__namespace.default.createElement(Skeleton, { className: "h-4 w-3/4" }), /* @__PURE__ */ React15__namespace.default.createElement(Skeleton, { className: "h-3 w-1/2" })))))))));
1918
+ var EventContextMenu = ({
1919
+ event,
1920
+ position,
1921
+ onClose,
1922
+ onEdit,
1923
+ onDelete,
1924
+ onDuplicate,
1925
+ customActions = [],
1926
+ translations
1927
+ }) => {
1928
+ const menuRef = React15.useRef(null);
1929
+ React15.useEffect(() => {
1930
+ const handleKeyDown = (e) => {
1931
+ if (e.key === "Escape") {
1932
+ onClose();
1933
+ }
1934
+ };
1935
+ if (position) {
1936
+ document.addEventListener("keydown", handleKeyDown);
1937
+ return () => document.removeEventListener("keydown", handleKeyDown);
1938
+ }
1939
+ }, [position, onClose]);
1940
+ React15.useEffect(() => {
1941
+ const handleClickOutside = (e) => {
1942
+ if (menuRef.current && !menuRef.current.contains(e.target)) {
1943
+ onClose();
1944
+ }
1945
+ };
1946
+ if (position) {
1947
+ setTimeout(() => {
1948
+ document.addEventListener("mousedown", handleClickOutside);
1949
+ }, 0);
1950
+ return () => document.removeEventListener("mousedown", handleClickOutside);
1951
+ }
1952
+ }, [position, onClose]);
1953
+ if (!event || !position) return null;
1954
+ const actions = [
1955
+ ...onEdit ? [{
1956
+ id: "edit",
1957
+ label: translations?.edit || "Edit",
1958
+ icon: /* @__PURE__ */ React15__namespace.default.createElement(lucideReact.Edit3, { className: "w-4 h-4" }),
1959
+ onClick: () => {
1960
+ onEdit(event);
1961
+ onClose();
1962
+ }
1963
+ }] : [],
1964
+ ...onDuplicate ? [{
1965
+ id: "duplicate",
1966
+ label: translations?.duplicate || "Duplicate",
1967
+ icon: /* @__PURE__ */ React15__namespace.default.createElement(lucideReact.Copy, { className: "w-4 h-4" }),
1968
+ onClick: () => {
1969
+ onDuplicate(event);
1970
+ onClose();
1971
+ }
1972
+ }] : [],
1973
+ ...customActions,
1974
+ ...onDelete ? [{
1975
+ id: "delete",
1976
+ label: translations?.delete || "Delete",
1977
+ icon: /* @__PURE__ */ React15__namespace.default.createElement(lucideReact.Trash2, { className: "w-4 h-4" }),
1978
+ onClick: () => {
1979
+ onDelete(event.id);
1980
+ onClose();
1981
+ },
1982
+ variant: "danger"
1983
+ }] : []
1984
+ ];
1985
+ const adjustedPosition = {
1986
+ x: Math.min(position.x, window.innerWidth - 200),
1987
+ y: Math.min(position.y, window.innerHeight - (actions.length * 44 + 80))
1988
+ };
1989
+ return /* @__PURE__ */ React15__namespace.default.createElement(framerMotion.AnimatePresence, null, /* @__PURE__ */ React15__namespace.default.createElement(
1990
+ framerMotion.motion.div,
1991
+ {
1992
+ ref: menuRef,
1993
+ initial: { opacity: 0, scale: 0.95, y: -5 },
1994
+ animate: { opacity: 1, scale: 1, y: 0 },
1995
+ exit: { opacity: 0, scale: 0.95, y: -5 },
1996
+ transition: { duration: 0.15, ease: "easeOut" },
1997
+ className: "fixed z-[100] min-w-[180px] bg-background border-[0.5px] border-border rounded-xl shadow-xl overflow-hidden",
1998
+ style: {
1999
+ left: adjustedPosition.x,
2000
+ top: adjustedPosition.y
2001
+ }
2002
+ },
2003
+ /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "px-3 py-2 border-b-[0.5px] border-border bg-muted/30" }, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React15__namespace.default.createElement(
2004
+ "div",
2005
+ {
2006
+ className: "w-2.5 h-2.5 rounded-full shrink-0",
2007
+ style: { backgroundColor: event.color || "var(--primary)" }
2008
+ }
2009
+ ), /* @__PURE__ */ React15__namespace.default.createElement("span", { className: "text-sm font-medium truncate text-foreground" }, event.title))),
2010
+ /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "py-1" }, actions.map((action, index) => /* @__PURE__ */ React15__namespace.default.createElement(React15__namespace.default.Fragment, { key: action.id }, index > 0 && action.variant === "danger" && /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "h-px bg-border my-1" }), /* @__PURE__ */ React15__namespace.default.createElement(
2011
+ "button",
2012
+ {
2013
+ onClick: action.onClick,
2014
+ disabled: action.disabled,
2015
+ className: cn(
2016
+ "w-full flex items-center gap-3 px-3 py-2 text-sm transition-colors",
2017
+ action.disabled && "opacity-50 cursor-not-allowed",
2018
+ action.variant === "danger" ? "text-red-600 hover:bg-red-50 dark:text-red-400 dark:hover:bg-red-900/20" : "text-foreground hover:bg-accent"
2019
+ )
2020
+ },
2021
+ action.icon,
2022
+ /* @__PURE__ */ React15__namespace.default.createElement("span", null, action.label)
2023
+ ))))
2024
+ ));
2025
+ };
2026
+ var useEventContextMenu = () => {
2027
+ const [contextMenu, setContextMenu] = React15.useState({ event: null, position: null });
2028
+ const openContextMenu = React15.useCallback((event, e) => {
2029
+ e.preventDefault();
2030
+ e.stopPropagation();
2031
+ setContextMenu({
2032
+ event,
2033
+ position: { x: e.clientX, y: e.clientY }
2034
+ });
2035
+ }, []);
2036
+ const closeContextMenu = React15.useCallback(() => {
2037
+ setContextMenu({ event: null, position: null });
2038
+ }, []);
2039
+ return {
2040
+ contextMenuEvent: contextMenu.event,
2041
+ contextMenuPosition: contextMenu.position,
2042
+ openContextMenu,
2043
+ closeContextMenu
2044
+ };
2045
+ };
2046
+
2047
+ // src/lib/theme.ts
2048
+ function colorToHsl(color) {
2049
+ let r = 0, g = 0, b = 0;
2050
+ if (color.startsWith("#") || /^[0-9a-fA-F]{3,6}$/.test(color)) {
2051
+ let c = color.replace(/^#/, "");
2052
+ if (c.length === 3) {
2053
+ c = c.split("").map((char) => char + char).join("");
2054
+ }
2055
+ if (c.length !== 6) return null;
2056
+ r = parseInt(c.substring(0, 2), 16) / 255;
2057
+ g = parseInt(c.substring(2, 4), 16) / 255;
2058
+ b = parseInt(c.substring(4, 6), 16) / 255;
2059
+ } else if (color.startsWith("rgb")) {
2060
+ const match = color.match(/\d+/g);
2061
+ if (!match || match.length < 3) return null;
2062
+ r = parseInt(match[0]) / 255;
2063
+ g = parseInt(match[1]) / 255;
2064
+ b = parseInt(match[2]) / 255;
2065
+ } else {
2066
+ return null;
2067
+ }
2068
+ const max = Math.max(r, g, b);
2069
+ const min = Math.min(r, g, b);
2070
+ let h = 0;
2071
+ let s = 0;
2072
+ let l = (max + min) / 2;
2073
+ if (max !== min) {
2074
+ const d = max - min;
2075
+ s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
2076
+ switch (max) {
2077
+ case r:
2078
+ h = (g - b) / d + (g < b ? 6 : 0);
2079
+ break;
2080
+ case g:
2081
+ h = (b - r) / d + 2;
2082
+ break;
2083
+ case b:
2084
+ h = (r - g) / d + 4;
2085
+ break;
2086
+ }
2087
+ h /= 6;
2088
+ }
2089
+ const hDeg = Math.round(h * 360);
2090
+ const sPct = Math.round(s * 100);
2091
+ const lPct = Math.round(l * 100);
2092
+ return `${hDeg} ${sPct}% ${lPct}%`;
2093
+ }
2094
+ function getThemeStyles(theme) {
2095
+ if (!theme) return {};
2096
+ const styles = {};
2097
+ if (theme.colors) {
2098
+ const mappings = {
2099
+ "--background": "background",
2100
+ "--foreground": "foreground",
2101
+ "--primary": "primary",
2102
+ "--secondary": "secondary",
2103
+ "--muted": "muted",
2104
+ "--accent": "accent",
2105
+ "--border": "border"
2106
+ };
2107
+ Object.entries(mappings).forEach(([cssVar, themeKey]) => {
2108
+ const colorValue = theme.colors?.[themeKey];
2109
+ if (colorValue) {
2110
+ const hsl = colorToHsl(colorValue);
2111
+ if (hsl) {
2112
+ styles[cssVar] = hsl;
2113
+ }
2114
+ }
2115
+ });
2116
+ }
2117
+ if (theme.borderRadius) {
2118
+ styles["--radius"] = theme.borderRadius;
2119
+ }
2120
+ if (theme.fontFamily) {
2121
+ styles["fontFamily"] = theme.fontFamily;
2122
+ }
2123
+ return styles;
2124
+ }
2125
+ var useCalendarLogic = ({
2126
+ events,
2127
+ view: controlledView,
2128
+ onViewChange: controlledOnViewChange,
2129
+ date: controlledDate,
2130
+ onDateChange: controlledOnDateChange,
2131
+ onEventClick,
2132
+ onEventUpdate,
2133
+ onEventCreate,
2134
+ onEventDelete,
2135
+ readOnly,
2136
+ timezone
2137
+ }) => {
2138
+ const [internalView, setInternalView] = React15.useState("week");
2139
+ const [internalDate, setInternalDate] = React15.useState(/* @__PURE__ */ new Date());
2140
+ const [isSidebarOpen, setIsSidebarOpen] = React15.useState(true);
2141
+ const [isModalOpen, setIsModalOpen] = React15.useState(false);
2142
+ const [selectedEvent, setSelectedEvent] = React15.useState(null);
2143
+ const [modalInitialDate, setModalInitialDate] = React15.useState(void 0);
2144
+ const view = controlledView ?? internalView;
2145
+ const currentDate = controlledDate ?? internalDate;
2146
+ const expandedEvents = React15.useMemo(() => {
2147
+ const allEvents = [];
2148
+ const rangeStart = dateFns.subDays(currentDate, 365);
2149
+ const rangeEnd = dateFns.addDays(currentDate, 365);
2150
+ events.forEach((event) => {
2151
+ if (event.recurrence) {
2152
+ try {
2153
+ const rule = new rrule.RRule({
2154
+ freq: rrule.RRule[event.recurrence.freq],
2155
+ interval: event.recurrence.interval || 1,
2156
+ dtstart: new Date(event.start),
2157
+ until: event.recurrence.until ? new Date(event.recurrence.until) : void 0,
2158
+ count: event.recurrence.count
2159
+ });
2160
+ const dates = rule.between(rangeStart, rangeEnd);
2161
+ dates.forEach((date) => {
2162
+ const duration = dateFns.differenceInMilliseconds(new Date(event.end), new Date(event.start));
2163
+ allEvents.push({
2164
+ ...event,
2165
+ id: `${event.id}-${date.getTime()}`,
2166
+ // Unique ID for each instance
2167
+ originalEventId: event.id,
2168
+ // Reference to original
2169
+ start: date,
2170
+ end: new Date(date.getTime() + duration)
2171
+ });
2172
+ });
2173
+ } catch (e) {
2174
+ console.error("Error parsing recurrence rule", e);
2175
+ allEvents.push(event);
2176
+ }
2177
+ } else {
2178
+ allEvents.push(event);
2179
+ }
2180
+ });
2181
+ return allEvents;
2182
+ }, [events, currentDate]);
2183
+ const handleViewChange = (newView) => {
2184
+ if (controlledOnViewChange) {
2185
+ controlledOnViewChange(newView);
2186
+ } else {
2187
+ setInternalView(newView);
2188
+ }
2189
+ };
2190
+ const handleDateChange = (newDate) => {
2191
+ if (controlledOnDateChange) {
2192
+ controlledOnDateChange(newDate);
2193
+ } else {
2194
+ setInternalDate(newDate);
2195
+ }
2196
+ };
2197
+ const handlePrev = () => {
2198
+ switch (view) {
2199
+ case "month":
2200
+ handleDateChange(dateFns.subMonths(currentDate, 1));
2201
+ break;
2202
+ case "week":
2203
+ handleDateChange(dateFns.subWeeks(currentDate, 1));
2204
+ break;
2205
+ case "day":
2206
+ case "resource":
2207
+ handleDateChange(dateFns.subDays(currentDate, 1));
2208
+ break;
2209
+ case "agenda":
2210
+ handleDateChange(dateFns.subDays(currentDate, 7));
2211
+ break;
2212
+ }
2213
+ };
2214
+ const handleNext = () => {
2215
+ switch (view) {
2216
+ case "month":
2217
+ handleDateChange(dateFns.addMonths(currentDate, 1));
2218
+ break;
2219
+ case "week":
2220
+ handleDateChange(dateFns.addWeeks(currentDate, 1));
2221
+ break;
2222
+ case "day":
2223
+ case "resource":
2224
+ handleDateChange(dateFns.addDays(currentDate, 1));
2225
+ break;
2226
+ case "agenda":
2227
+ handleDateChange(dateFns.addDays(currentDate, 7));
2228
+ break;
2229
+ }
2230
+ };
2231
+ const handleToday = () => {
2232
+ handleDateChange(/* @__PURE__ */ new Date());
2233
+ };
2234
+ const handleDateClick = (date) => {
2235
+ handleDateChange(date);
2236
+ handleViewChange("day");
2237
+ };
2238
+ const handleTimeSlotClick = (date) => {
2239
+ if (readOnly) return;
2240
+ setSelectedEvent(null);
2241
+ setModalInitialDate(date);
2242
+ setIsModalOpen(true);
2243
+ };
2244
+ const handleEventClickInternal = (event) => {
2245
+ if (onEventClick) {
2246
+ onEventClick(event);
2247
+ }
2248
+ if (!readOnly) {
2249
+ setSelectedEvent(event);
2250
+ setModalInitialDate(void 0);
2251
+ setIsModalOpen(true);
2252
+ }
2253
+ };
2254
+ const handleCreateEvent = () => {
2255
+ if (readOnly) return;
2256
+ setSelectedEvent(null);
2257
+ setModalInitialDate(/* @__PURE__ */ new Date());
2258
+ setIsModalOpen(true);
2259
+ };
2260
+ const handleModalSave = (eventData) => {
2261
+ let effectiveEventId = selectedEvent?.id;
2262
+ if (selectedEvent?.originalEventId) {
2263
+ effectiveEventId = selectedEvent.originalEventId;
2264
+ }
2265
+ if (effectiveEventId) {
2266
+ if (onEventUpdate) {
2267
+ onEventUpdate({
2268
+ ...eventData,
2269
+ id: effectiveEventId
2270
+ });
2271
+ }
2272
+ } else {
2273
+ if (onEventCreate) {
2274
+ onEventCreate(eventData);
2275
+ }
2276
+ }
2277
+ };
2278
+ const handleModalDelete = (eventId) => {
2279
+ let effectiveEventId = eventId;
2280
+ if (selectedEvent?.originalEventId && selectedEvent.id === eventId) {
2281
+ effectiveEventId = selectedEvent.originalEventId;
2282
+ }
2283
+ if (onEventDelete) {
2284
+ onEventDelete(effectiveEventId);
2285
+ }
2286
+ };
2287
+ const handleDragEnd = (event) => {
2288
+ const { active, over } = event;
2289
+ if (!over) return;
2290
+ const activeEvent = active.data.current?.event;
2291
+ const overDate = over.data.current?.date;
2292
+ if (!activeEvent || !overDate) return;
2293
+ const originalStart = new Date(activeEvent.start);
2294
+ const originalEnd = new Date(activeEvent.end);
2295
+ const duration = dateFns.differenceInMilliseconds(originalEnd, originalStart);
2296
+ let newStart;
2297
+ if (view === "month") {
2298
+ if (timezone) {
2299
+ const zonedOriginal = dateFnsTz.toZonedTime(originalStart, timezone);
2300
+ const zonedNew = new Date(overDate);
2301
+ zonedNew.setHours(zonedOriginal.getHours());
2302
+ zonedNew.setMinutes(zonedOriginal.getMinutes());
2303
+ zonedNew.setSeconds(zonedOriginal.getSeconds());
2304
+ zonedNew.setMilliseconds(zonedOriginal.getMilliseconds());
2305
+ newStart = dateFnsTz.fromZonedTime(zonedNew, timezone);
2306
+ } else {
2307
+ newStart = new Date(overDate);
2308
+ newStart.setHours(originalStart.getHours());
2309
+ newStart.setMinutes(originalStart.getMinutes());
2310
+ newStart.setSeconds(originalStart.getSeconds());
2311
+ newStart.setMilliseconds(originalStart.getMilliseconds());
2312
+ }
2313
+ } else {
2314
+ if (timezone) {
2315
+ newStart = dateFnsTz.fromZonedTime(overDate, timezone);
2316
+ } else {
2317
+ newStart = new Date(overDate);
2318
+ }
2319
+ newStart.setSeconds(0);
2320
+ newStart.setMilliseconds(0);
2321
+ }
2322
+ const newEnd = new Date(newStart.getTime() + duration);
2323
+ let newResourceId = activeEvent.resourceId;
2324
+ const overResourceId = over.data.current?.resourceId;
2325
+ if (overResourceId) {
2326
+ newResourceId = overResourceId;
2327
+ }
2328
+ if (newStart.getTime() === originalStart.getTime() && newEnd.getTime() === originalEnd.getTime() && newResourceId === activeEvent.resourceId) {
2329
+ return;
2330
+ }
2331
+ if (onEventUpdate) {
2332
+ onEventUpdate({
2333
+ ...activeEvent,
2334
+ start: newStart,
2335
+ end: newEnd,
2336
+ resourceId: newResourceId
2337
+ });
2338
+ }
2339
+ };
2340
+ return {
2341
+ view,
2342
+ currentDate,
2343
+ isSidebarOpen,
2344
+ setIsSidebarOpen,
2345
+ isModalOpen,
2346
+ setIsModalOpen,
2347
+ selectedEvent,
2348
+ modalInitialDate,
2349
+ expandedEvents,
2350
+ handleViewChange,
2351
+ handleDateChange,
2352
+ handlePrev,
2353
+ handleNext,
2354
+ handleToday,
2355
+ handleDateClick,
2356
+ handleTimeSlotClick,
2357
+ handleEventClickInternal,
2358
+ handleCreateEvent,
2359
+ handleModalSave,
2360
+ handleModalDelete,
2361
+ handleDragEnd
2362
+ };
2363
+ };
2364
+ var useSwipeGesture = (options) => {
2365
+ const {
2366
+ onSwipeLeft,
2367
+ onSwipeRight,
2368
+ onSwipeUp,
2369
+ onSwipeDown,
2370
+ threshold = 100,
2371
+ restraint = 100,
2372
+ allowedTime = 500,
2373
+ enabled = true
2374
+ } = options;
2375
+ const touchInfoRef = React15.useRef(null);
2376
+ const elementRef = React15.useRef(null);
2377
+ const handleTouchStart = React15.useCallback((e) => {
2378
+ if (!enabled) return;
2379
+ const touch = e.touches[0];
2380
+ touchInfoRef.current = {
2381
+ startX: touch.clientX,
2382
+ startY: touch.clientY,
2383
+ startTime: Date.now()
2384
+ };
2385
+ }, [enabled]);
2386
+ const handleTouchEnd = React15.useCallback((e) => {
2387
+ if (!enabled || !touchInfoRef.current) return;
2388
+ const touch = e.changedTouches[0];
2389
+ const { startX, startY, startTime } = touchInfoRef.current;
2390
+ const distX = touch.clientX - startX;
2391
+ const distY = touch.clientY - startY;
2392
+ const elapsedTime = Date.now() - startTime;
2393
+ if (elapsedTime <= allowedTime) {
2394
+ if (Math.abs(distX) >= threshold && Math.abs(distY) <= restraint) {
2395
+ if (distX > 0) {
2396
+ onSwipeRight?.();
2397
+ } else {
2398
+ onSwipeLeft?.();
2399
+ }
2400
+ } else if (Math.abs(distY) >= threshold && Math.abs(distX) <= restraint) {
2401
+ if (distY > 0) {
2402
+ onSwipeDown?.();
2403
+ } else {
2404
+ onSwipeUp?.();
2405
+ }
2406
+ }
2407
+ }
2408
+ touchInfoRef.current = null;
2409
+ }, [enabled, threshold, restraint, allowedTime, onSwipeLeft, onSwipeRight, onSwipeUp, onSwipeDown]);
2410
+ React15.useEffect(() => {
2411
+ const element = elementRef.current;
2412
+ if (!element) return;
2413
+ element.addEventListener("touchstart", handleTouchStart, { passive: true });
2414
+ element.addEventListener("touchend", handleTouchEnd, { passive: true });
2415
+ return () => {
2416
+ element.removeEventListener("touchstart", handleTouchStart);
2417
+ element.removeEventListener("touchend", handleTouchEnd);
2418
+ };
2419
+ }, [handleTouchStart, handleTouchEnd]);
2420
+ return elementRef;
2421
+ };
2422
+ var useViewSwipe = (onPrev, onNext, enabled = true) => {
2423
+ return useSwipeGesture({
2424
+ onSwipeLeft: onNext,
2425
+ onSwipeRight: onPrev,
2426
+ threshold: 50,
2427
+ restraint: 100,
2428
+ allowedTime: 300,
2429
+ enabled
2430
+ });
2431
+ };
2432
+
2433
+ // src/index.tsx
2434
+ var Scheduler = ({
2435
+ events = [],
2436
+ view: controlledView,
2437
+ onViewChange: controlledOnViewChange,
2438
+ date: controlledDate,
2439
+ onDateChange: controlledOnDateChange,
2440
+ onEventClick,
2441
+ onEventCreate,
2442
+ onEventUpdate,
2443
+ onEventDelete,
2444
+ onEventResize,
2445
+ timezone,
2446
+ onTimezoneChange,
2447
+ className,
2448
+ theme,
2449
+ renderEventForm,
2450
+ readOnly,
2451
+ calendars,
2452
+ resources,
2453
+ eventTypes,
2454
+ onCalendarToggle,
2455
+ isLoading,
2456
+ isDarkMode,
2457
+ onThemeToggle,
2458
+ translations,
2459
+ // New Prop
2460
+ hideViewSwitcher,
2461
+ language,
2462
+ onLanguageChange,
2463
+ locale
2464
+ // Date-fns locale
2465
+ }) => {
2466
+ const [activeDragEvent, setActiveDragEvent] = React15.useState(null);
2467
+ const {
2468
+ contextMenuEvent,
2469
+ contextMenuPosition,
2470
+ closeContextMenu
2471
+ } = useEventContextMenu();
2472
+ const {
2473
+ view,
2474
+ currentDate,
2475
+ isSidebarOpen,
2476
+ setIsSidebarOpen,
2477
+ isModalOpen,
2478
+ setIsModalOpen,
2479
+ selectedEvent,
2480
+ modalInitialDate,
2481
+ handleViewChange,
2482
+ handleDateChange,
2483
+ handlePrev,
2484
+ handleNext,
2485
+ handleToday,
2486
+ handleDateClick,
2487
+ handleTimeSlotClick,
2488
+ handleEventClickInternal,
2489
+ handleCreateEvent,
2490
+ handleModalSave,
2491
+ handleModalDelete,
2492
+ handleDragEnd,
2493
+ expandedEvents
2494
+ // New export
2495
+ } = useCalendarLogic({
2496
+ events,
2497
+ view: controlledView,
2498
+ onViewChange: controlledOnViewChange,
2499
+ date: controlledDate,
2500
+ onDateChange: controlledOnDateChange,
2501
+ onEventClick,
2502
+ onEventUpdate,
2503
+ onEventCreate,
2504
+ onEventDelete,
2505
+ readOnly,
2506
+ timezone
2507
+ });
2508
+ const sensors = core.useSensors(
2509
+ core.useSensor(core.PointerSensor, {
2510
+ activationConstraint: {
2511
+ distance: 8
2512
+ }
2513
+ })
2514
+ );
2515
+ const gridSize = 15;
2516
+ const snapToGrid = modifiers.createSnapModifier(gridSize);
2517
+ const modifiers$1 = [snapToGrid, modifiers.restrictToWindowEdges];
2518
+ const dndSensors = readOnly ? [] : sensors;
2519
+ const handleEventResize = (event, newEnd) => {
2520
+ if (readOnly) return;
2521
+ if (onEventResize) {
2522
+ onEventResize(event, event.start, newEnd);
2523
+ }
2524
+ if (onEventUpdate) {
2525
+ onEventUpdate({
2526
+ ...event,
2527
+ end: newEnd
2528
+ });
2529
+ }
2530
+ };
2531
+ const id = React15.useId();
2532
+ const swipeRef = useViewSwipe(handlePrev, handleNext, true);
2533
+ const t = {
2534
+ today: "Today",
2535
+ month: "Month",
2536
+ week: "Week",
2537
+ day: "Day",
2538
+ agenda: "Agenda",
2539
+ resource: "Resource",
2540
+ createEvent: "Create Event",
2541
+ editEvent: "Edit Event",
2542
+ delete: "Delete",
2543
+ save: "Save",
2544
+ cancel: "Cancel",
2545
+ title: "Title",
2546
+ start: "Start",
2547
+ end: "End",
2548
+ allDay: "All Day",
2549
+ description: "Description",
2550
+ repeat: "Repeat",
2551
+ noRepeat: "Does not repeat",
2552
+ selectCalendar: "Select Calendar",
2553
+ selectType: "Select Type",
2554
+ daily: "Daily",
2555
+ weekly: "Weekly",
2556
+ monthly: "Monthly",
2557
+ yearly: "Yearly",
2558
+ ...translations
2559
+ };
2560
+ const handleDragStart = (event) => {
2561
+ const { active } = event;
2562
+ const draggedEvent = expandedEvents.find((e) => e.id === active.id);
2563
+ if (draggedEvent) {
2564
+ setActiveDragEvent(draggedEvent);
2565
+ }
2566
+ };
2567
+ const onDragEndWrapper = (event) => {
2568
+ setActiveDragEvent(null);
2569
+ handleDragEnd(event);
2570
+ };
2571
+ const getDragHeight = () => {
2572
+ if (!activeDragEvent) return void 0;
2573
+ if (view === "resource") {
2574
+ return 80;
2575
+ }
2576
+ if (view !== "week" && view !== "day") return void 0;
2577
+ const duration = dateFns.differenceInMinutes(activeDragEvent.end, activeDragEvent.start);
2578
+ const hourHeight = view === "day" ? 80 : 60;
2579
+ return duration / 60 * hourHeight;
2580
+ };
2581
+ const getDragWidth = () => {
2582
+ if (view === "month") return "100%";
2583
+ if (view === "resource" && activeDragEvent) {
2584
+ const duration = dateFns.differenceInMinutes(activeDragEvent.end, activeDragEvent.start);
2585
+ const width = duration / 60 * 100;
2586
+ return `${Math.max(width, 4)}px`;
2587
+ }
2588
+ return "150px";
2589
+ };
2590
+ const filteredEvents = React15.useMemo(() => {
2591
+ if (!calendars) return expandedEvents;
2592
+ const activeCalendarIds = calendars.filter((c) => c.active !== false).map((c) => c.id);
2593
+ return expandedEvents.filter((e) => {
2594
+ if (!e.calendarId) return true;
2595
+ return activeCalendarIds.includes(e.calendarId);
2596
+ });
2597
+ }, [expandedEvents, calendars]);
2598
+ return /* @__PURE__ */ React15__namespace.default.createElement(
2599
+ core.DndContext,
2600
+ {
2601
+ id,
2602
+ sensors: dndSensors,
2603
+ onDragStart: handleDragStart,
2604
+ onDragEnd: onDragEndWrapper,
2605
+ modifiers: modifiers$1
2606
+ },
2607
+ /* @__PURE__ */ React15__namespace.default.createElement(
2608
+ "div",
2609
+ {
2610
+ className: cn("flex flex-col h-full bg-background text-foreground relative", className),
2611
+ style: getThemeStyles(theme)
2612
+ },
2613
+ /* @__PURE__ */ React15__namespace.default.createElement(
2614
+ CalendarHeader,
2615
+ {
2616
+ currentDate,
2617
+ onPrev: handlePrev,
2618
+ onNext: handleNext,
2619
+ onToday: handleToday,
2620
+ view,
2621
+ onViewChange: handleViewChange,
2622
+ onMenuClick: () => setIsSidebarOpen(!isSidebarOpen),
2623
+ isDarkMode,
2624
+ onThemeToggle,
2625
+ translations: t,
2626
+ hideViewSwitcher,
2627
+ language,
2628
+ onLanguageChange,
2629
+ locale
2630
+ }
2631
+ ),
2632
+ /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex flex-1 overflow-hidden" }, /* @__PURE__ */ React15__namespace.default.createElement(
2633
+ framerMotion.motion.div,
2634
+ {
2635
+ className: cn(
2636
+ "hidden md:block overflow-hidden"
2637
+ ),
2638
+ initial: false,
2639
+ animate: {
2640
+ width: isSidebarOpen ? 256 : 0,
2641
+ opacity: isSidebarOpen ? 1 : 0
2642
+ },
2643
+ transition: {
2644
+ duration: 0.3,
2645
+ ease: [0.4, 0, 0.2, 1]
2646
+ }
2647
+ },
2648
+ /* @__PURE__ */ React15__namespace.default.createElement(
2649
+ Sidebar,
2650
+ {
2651
+ currentDate,
2652
+ onDateChange: handleDateChange,
2653
+ onViewChange: handleViewChange,
2654
+ onEventCreate: handleCreateEvent,
2655
+ timezone,
2656
+ onTimezoneChange,
2657
+ className: "w-full h-full",
2658
+ readOnly,
2659
+ calendars,
2660
+ onCalendarToggle,
2661
+ translations: t
2662
+ }
2663
+ )
2664
+ ), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex-1 flex flex-col overflow-hidden relative" }, isLoading ? /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "flex-1 overflow-auto p-0 md:p-4" }, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "h-full min-w-full" }, view === "month" && /* @__PURE__ */ React15__namespace.default.createElement(MonthViewSkeleton, null), view === "week" && /* @__PURE__ */ React15__namespace.default.createElement(WeekViewSkeleton, null), view === "day" && /* @__PURE__ */ React15__namespace.default.createElement(DayViewSkeleton, null), view === "agenda" && /* @__PURE__ */ React15__namespace.default.createElement(AgendaViewSkeleton, null), view === "resource" && /* @__PURE__ */ React15__namespace.default.createElement(WeekViewSkeleton, null))) : /* @__PURE__ */ React15__namespace.default.createElement("div", { ref: swipeRef, className: "flex-1 overflow-auto p-0 md:p-4 touch-pan-y" }, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "h-full min-w-full" }, /* @__PURE__ */ React15__namespace.default.createElement(framerMotion.AnimatePresence, { mode: "wait", initial: false }, /* @__PURE__ */ React15__namespace.default.createElement(
2665
+ framerMotion.motion.div,
2666
+ {
2667
+ key: `${view}-${currentDate.toISOString()}-${timezone || "local"}`,
2668
+ initial: { opacity: 0, scale: 0.98, y: 15 },
2669
+ animate: {
2670
+ opacity: 1,
2671
+ scale: 1,
2672
+ y: 0,
2673
+ transition: {
2674
+ duration: 0.25,
2675
+ ease: [0.25, 0.1, 0.25, 1]
2676
+ }
2677
+ },
2678
+ exit: {
2679
+ opacity: 0,
2680
+ scale: 0.98,
2681
+ y: -10,
2682
+ transition: {
2683
+ duration: 0.15,
2684
+ ease: [0.25, 0.1, 0.25, 1]
2685
+ }
2686
+ },
2687
+ className: "h-full"
2688
+ },
2689
+ view === "month" && /* @__PURE__ */ React15__namespace.default.createElement(
2690
+ MonthView,
2691
+ {
2692
+ currentDate,
2693
+ events: filteredEvents,
2694
+ onEventClick: handleEventClickInternal,
2695
+ onDateClick: handleDateClick,
2696
+ timezone,
2697
+ locale
2698
+ }
2699
+ ),
2700
+ view === "week" && /* @__PURE__ */ React15__namespace.default.createElement(
2701
+ WeekView,
2702
+ {
2703
+ currentDate,
2704
+ events: filteredEvents,
2705
+ onEventClick: handleEventClickInternal,
2706
+ onTimeSlotClick: handleTimeSlotClick,
2707
+ onEventResize: handleEventResize,
2708
+ timezone,
2709
+ locale,
2710
+ readonly: readOnly
2711
+ }
2712
+ ),
2713
+ view === "day" && /* @__PURE__ */ React15__namespace.default.createElement(
2714
+ DayView,
2715
+ {
2716
+ currentDate,
2717
+ events: filteredEvents,
2718
+ onEventClick: handleEventClickInternal,
2719
+ onTimeSlotClick: handleTimeSlotClick,
2720
+ onEventResize: handleEventResize,
2721
+ timezone,
2722
+ locale,
2723
+ readonly: readOnly
2724
+ }
2725
+ ),
2726
+ view === "agenda" && /* @__PURE__ */ React15__namespace.default.createElement(
2727
+ AgendaView,
2728
+ {
2729
+ currentDate,
2730
+ events: filteredEvents,
2731
+ onEventClick: handleEventClickInternal,
2732
+ onCreateEvent: handleCreateEvent
2733
+ }
2734
+ ),
2735
+ view === "resource" && resources && /* @__PURE__ */ React15__namespace.default.createElement(
2736
+ ResourceView,
2737
+ {
2738
+ currentDate,
2739
+ events: filteredEvents,
2740
+ resources,
2741
+ onEventClick: handleEventClickInternal,
2742
+ onTimeSlotClick: (date, resourceId) => {
2743
+ if (readOnly) return;
2744
+ handleTimeSlotClick(date);
2745
+ },
2746
+ locale
2747
+ }
2748
+ )
2749
+ )))), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "md:hidden absolute bottom-6 right-6 z-50" }, /* @__PURE__ */ React15__namespace.default.createElement(
2750
+ "button",
2751
+ {
2752
+ onClick: handleCreateEvent,
2753
+ className: "w-14 h-14 bg-blue-600 rounded-full shadow-lg flex items-center justify-center text-white active:scale-90 transition-transform"
2754
+ },
2755
+ /* @__PURE__ */ React15__namespace.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React15__namespace.default.createElement("path", { d: "M5 12h14" }), /* @__PURE__ */ React15__namespace.default.createElement("path", { d: "M12 5v14" }))
2756
+ )))),
2757
+ renderEventForm ? renderEventForm({
2758
+ isOpen: isModalOpen,
2759
+ onClose: () => setIsModalOpen(false),
2760
+ event: selectedEvent,
2761
+ initialDate: modalInitialDate,
2762
+ onSave: handleModalSave,
2763
+ onDelete: handleModalDelete
2764
+ }) : /* @__PURE__ */ React15__namespace.default.createElement(
2765
+ EventModal,
2766
+ {
2767
+ isOpen: isModalOpen,
2768
+ onClose: () => setIsModalOpen(false),
2769
+ event: selectedEvent,
2770
+ initialDate: modalInitialDate,
2771
+ onSave: handleModalSave,
2772
+ onDelete: handleModalDelete,
2773
+ calendars,
2774
+ eventTypes,
2775
+ translations: t
2776
+ }
2777
+ ),
2778
+ /* @__PURE__ */ React15__namespace.default.createElement(
2779
+ EventContextMenu,
2780
+ {
2781
+ event: contextMenuEvent,
2782
+ position: contextMenuPosition,
2783
+ onClose: closeContextMenu,
2784
+ onEdit: (event) => {
2785
+ handleEventClickInternal(event);
2786
+ closeContextMenu();
2787
+ },
2788
+ onDelete: (eventId) => {
2789
+ onEventDelete?.(eventId);
2790
+ closeContextMenu();
2791
+ },
2792
+ onDuplicate: (event) => {
2793
+ const duplicatedEvent = {
2794
+ ...event,
2795
+ id: `${event.id}-copy-${Date.now()}`,
2796
+ title: `${event.title} (Copy)`,
2797
+ start: new Date(event.start.getTime() + 24 * 60 * 60 * 1e3),
2798
+ // +1 day
2799
+ end: new Date(event.end.getTime() + 24 * 60 * 60 * 1e3)
2800
+ };
2801
+ onEventCreate?.(duplicatedEvent);
2802
+ closeContextMenu();
2803
+ },
2804
+ translations: {
2805
+ edit: t.editEvent || "Edit",
2806
+ delete: t.delete || "Delete",
2807
+ duplicate: "Duplicate"
2808
+ }
2809
+ }
2810
+ ),
2811
+ /* @__PURE__ */ React15__namespace.default.createElement(core.DragOverlay, { dropAnimation: null }, activeDragEvent ? /* @__PURE__ */ React15__namespace.default.createElement(
2812
+ "div",
2813
+ {
2814
+ className: cn(
2815
+ "rounded-lg shadow-2xl border-2 overflow-hidden cursor-grabbing transition-transform",
2816
+ "backdrop-blur-sm",
2817
+ !activeDragEvent.color && "bg-primary/90 border-primary/60 text-primary-foreground"
2818
+ ),
2819
+ style: {
2820
+ backgroundColor: activeDragEvent.color ? `${activeDragEvent.color}e0` : void 0,
2821
+ borderColor: activeDragEvent.color ? `${activeDragEvent.color}80` : void 0,
2822
+ color: activeDragEvent.color ? "#fff" : void 0,
2823
+ width: getDragWidth(),
2824
+ height: getDragHeight() ? `${getDragHeight()}px` : void 0,
2825
+ boxShadow: `0 20px 40px -15px ${activeDragEvent.color || "var(--primary)"}40, 0 10px 20px -10px rgba(0,0,0,0.2)`,
2826
+ transform: "rotate(-2deg) scale(1.02)"
2827
+ }
2828
+ },
2829
+ /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "p-2.5 h-full flex flex-col" }, /* @__PURE__ */ React15__namespace.default.createElement(
2830
+ "div",
2831
+ {
2832
+ className: "absolute left-0 top-0 bottom-0 w-1 rounded-l-lg",
2833
+ style: { backgroundColor: activeDragEvent.color || "var(--primary)" }
2834
+ }
2835
+ ), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "pl-2" }, /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "font-semibold truncate text-sm" }, activeDragEvent.title), (view === "week" || view === "day") && getDragHeight() && getDragHeight() > 40 && /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "text-xs opacity-80 mt-0.5 flex items-center gap-1" }, /* @__PURE__ */ React15__namespace.default.createElement("svg", { className: "w-3 h-3", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2" }, /* @__PURE__ */ React15__namespace.default.createElement("circle", { cx: "12", cy: "12", r: "10" }), /* @__PURE__ */ React15__namespace.default.createElement("path", { d: "M12 6v6l4 2" })), dateFns.format(activeDragEvent.start, "h:mm a"), " - ", dateFns.format(activeDragEvent.end, "h:mm a"))), /* @__PURE__ */ React15__namespace.default.createElement("div", { className: "absolute bottom-1.5 right-1.5 opacity-60" }, /* @__PURE__ */ React15__namespace.default.createElement("svg", { className: "w-4 h-4", viewBox: "0 0 24 24", fill: "currentColor" }, /* @__PURE__ */ React15__namespace.default.createElement("circle", { cx: "9", cy: "5", r: "1.5" }), /* @__PURE__ */ React15__namespace.default.createElement("circle", { cx: "15", cy: "5", r: "1.5" }), /* @__PURE__ */ React15__namespace.default.createElement("circle", { cx: "9", cy: "12", r: "1.5" }), /* @__PURE__ */ React15__namespace.default.createElement("circle", { cx: "15", cy: "12", r: "1.5" }), /* @__PURE__ */ React15__namespace.default.createElement("circle", { cx: "9", cy: "19", r: "1.5" }), /* @__PURE__ */ React15__namespace.default.createElement("circle", { cx: "15", cy: "19", r: "1.5" }))))
2836
+ ) : null)
2837
+ )
2838
+ );
2839
+ };
2840
+
2841
+ exports.Scheduler = Scheduler;
2842
+ exports.cn = cn;
2843
+ //# sourceMappingURL=index.js.map
2844
+ //# sourceMappingURL=index.js.map