@ilamy/calendar 0.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,3525 @@
1
+ "use client";
2
+ // src/features/month-view/components/month-view.tsx
3
+ import { AnimatePresence as AnimatePresence3, motion as motion3 } from "motion/react";
4
+ import React5, { useMemo as useMemo2 } from "react";
5
+
6
+ // src/contexts/calendar-context/context.ts
7
+ import { createContext, useContext } from "react";
8
+ var CalendarContext = createContext(undefined);
9
+ var useCalendarContext = () => {
10
+ const context = useContext(CalendarContext);
11
+ if (context === undefined) {
12
+ throw new Error("useCalendarContext must be used within a CalendarProvider");
13
+ }
14
+ return context;
15
+ };
16
+ var usePublicCalendarContext = () => {
17
+ const context = useContext(CalendarContext);
18
+ if (context === undefined) {
19
+ throw new Error("useCalendarContext must be used within ilamy calendar");
20
+ }
21
+ return {
22
+ currentDate: context.currentDate,
23
+ view: context.view,
24
+ events: context.events,
25
+ isEventFormOpen: context.isEventFormOpen,
26
+ selectedEvent: context.selectedEvent,
27
+ selectedDate: context.selectedDate,
28
+ firstDayOfWeek: context.firstDayOfWeek,
29
+ setCurrentDate: context.setCurrentDate,
30
+ selectDate: context.selectDate,
31
+ setView: context.setView,
32
+ nextPeriod: context.nextPeriod,
33
+ prevPeriod: context.prevPeriod,
34
+ today: context.today,
35
+ addEvent: context.addEvent,
36
+ updateEvent: context.updateEvent,
37
+ deleteEvent: context.deleteEvent,
38
+ openEventForm: context.openEventForm,
39
+ closeEventForm: context.closeEventForm
40
+ };
41
+ };
42
+
43
+ // src/components/ui/accordion.tsx
44
+ import * as AccordionPrimitive from "@radix-ui/react-accordion";
45
+ import { ChevronDownIcon } from "lucide-react";
46
+
47
+ // src/lib/utils.ts
48
+ import { clsx } from "clsx";
49
+ import dayjs from "dayjs";
50
+ import { twMerge } from "tailwind-merge";
51
+ function cn(...inputs) {
52
+ return twMerge(clsx(inputs));
53
+ }
54
+
55
+ // src/components/ui/accordion.tsx
56
+ import { jsxDEV } from "react/jsx-dev-runtime";
57
+ // src/components/ui/alert.tsx
58
+ import { cva } from "class-variance-authority";
59
+ import { jsxDEV as jsxDEV2 } from "react/jsx-dev-runtime";
60
+ var alertVariants = cva("relative w-full rounded-lg border px-4 py-3 text-sm grid has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] grid-cols-[0_1fr] has-[>svg]:gap-x-3 gap-y-0.5 items-start [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current", {
61
+ variants: {
62
+ variant: {
63
+ default: "bg-card text-card-foreground",
64
+ destructive: "text-destructive bg-card [&>svg]:text-current *:data-[slot=alert-description]:text-destructive/90",
65
+ primary: "bg-blue-50 dark:bg-blue-950/20 border-blue-200 dark:border-blue-800 text-blue-900 dark:text-blue-100 [&>svg]:text-blue-600 dark:[&>svg]:text-blue-400 *:data-[slot=alert-description]:text-blue-800 dark:*:data-[slot=alert-description]:text-blue-200",
66
+ secondary: "bg-gray-50 dark:bg-gray-950/20 border-gray-200 dark:border-gray-800 text-gray-900 dark:text-gray-100 [&>svg]:text-gray-600 dark:[&>svg]:text-gray-400 *:data-[slot=alert-description]:text-gray-800 dark:*:data-[slot=alert-description]:text-gray-200",
67
+ success: "bg-green-50 dark:bg-green-950/20 border-green-200 dark:border-green-800 text-green-900 dark:text-green-100 [&>svg]:text-green-600 dark:[&>svg]:text-green-400 *:data-[slot=alert-description]:text-green-800 dark:*:data-[slot=alert-description]:text-green-200",
68
+ warning: "bg-yellow-50 dark:bg-yellow-950/20 border-yellow-200 dark:border-yellow-800 text-yellow-900 dark:text-yellow-100 [&>svg]:text-yellow-600 dark:[&>svg]:text-yellow-400 *:data-[slot=alert-description]:text-yellow-800 dark:*:data-[slot=alert-description]:text-yellow-200"
69
+ }
70
+ },
71
+ defaultVariants: {
72
+ variant: "default"
73
+ }
74
+ });
75
+ // src/components/ui/badge.tsx
76
+ import { Slot } from "@radix-ui/react-slot";
77
+ import { cva as cva2 } from "class-variance-authority";
78
+ import { jsxDEV as jsxDEV3 } from "react/jsx-dev-runtime";
79
+ var badgeVariants = cva2("inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-clip", {
80
+ variants: {
81
+ variant: {
82
+ default: "border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90",
83
+ secondary: "border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90",
84
+ destructive: "border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
85
+ outline: "text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground"
86
+ }
87
+ },
88
+ defaultVariants: {
89
+ variant: "default"
90
+ }
91
+ });
92
+ // src/components/ui/button.tsx
93
+ import { Slot as Slot2 } from "@radix-ui/react-slot";
94
+ import { cva as cva3 } from "class-variance-authority";
95
+ import { jsxDEV as jsxDEV4 } from "react/jsx-dev-runtime";
96
+ var buttonVariants = cva3("inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive", {
97
+ variants: {
98
+ variant: {
99
+ default: "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
100
+ destructive: "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
101
+ outline: "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
102
+ secondary: "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
103
+ ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
104
+ link: "text-primary underline-offset-4 hover:underline"
105
+ },
106
+ size: {
107
+ default: "h-9 px-4 py-2 has-[>svg]:px-3",
108
+ sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
109
+ lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
110
+ icon: "size-9"
111
+ }
112
+ },
113
+ defaultVariants: {
114
+ variant: "default",
115
+ size: "default"
116
+ }
117
+ });
118
+ function Button({
119
+ className,
120
+ variant,
121
+ size,
122
+ asChild = false,
123
+ ...props
124
+ }) {
125
+ const Comp = asChild ? Slot2 : "button";
126
+ return /* @__PURE__ */ jsxDEV4(Comp, {
127
+ "data-slot": "button",
128
+ className: cn(buttonVariants({ variant, size, className })),
129
+ ...props
130
+ }, undefined, false, undefined, this);
131
+ }
132
+ // src/components/ui/calendar.tsx
133
+ import { ChevronLeft, ChevronRight } from "lucide-react";
134
+ import { DayPicker } from "react-day-picker";
135
+ import { jsxDEV as jsxDEV5 } from "react/jsx-dev-runtime";
136
+ function Calendar({
137
+ className,
138
+ classNames,
139
+ showOutsideDays = true,
140
+ ...props
141
+ }) {
142
+ return /* @__PURE__ */ jsxDEV5(DayPicker, {
143
+ showOutsideDays,
144
+ className: cn("p-3", className),
145
+ classNames: {
146
+ months: "flex flex-col sm:flex-row gap-2",
147
+ month: "flex flex-col gap-4",
148
+ caption: "flex justify-center pt-1 relative items-center w-full",
149
+ caption_label: "text-sm font-medium",
150
+ nav: "flex items-center gap-1",
151
+ nav_button: cn(buttonVariants({ variant: "outline" }), "size-7 bg-transparent p-0 opacity-50 hover:opacity-100"),
152
+ nav_button_previous: "absolute left-1",
153
+ nav_button_next: "absolute right-1",
154
+ table: "w-full border-collapse space-x-1",
155
+ head_row: "flex",
156
+ head_cell: "text-muted-foreground rounded-md w-8 font-normal text-[0.8rem]",
157
+ row: "flex w-full mt-2",
158
+ cell: cn("relative p-0 text-center text-sm focus-within:relative focus-within:z-20 [&:has([aria-selected])]:bg-accent [&:has([aria-selected].day-range-end)]:rounded-r-md", props.mode === "range" ? "[&:has(>.day-range-end)]:rounded-r-md [&:has(>.day-range-start)]:rounded-l-md first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md" : "[&:has([aria-selected])]:rounded-md"),
159
+ day: cn(buttonVariants({ variant: "ghost" }), "size-8 p-0 font-normal aria-selected:opacity-100"),
160
+ day_range_start: "day-range-start aria-selected:bg-primary aria-selected:text-primary-foreground",
161
+ day_range_end: "day-range-end aria-selected:bg-primary aria-selected:text-primary-foreground",
162
+ day_selected: "bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground",
163
+ day_today: "bg-accent text-accent-foreground",
164
+ day_outside: "day-outside text-muted-foreground aria-selected:text-muted-foreground",
165
+ day_disabled: "text-muted-foreground opacity-50",
166
+ day_range_middle: "aria-selected:bg-accent aria-selected:text-accent-foreground",
167
+ day_hidden: "invisible",
168
+ ...classNames
169
+ },
170
+ components: {
171
+ IconLeft: ({ className: className2, ...props2 }) => /* @__PURE__ */ jsxDEV5(ChevronLeft, {
172
+ className: cn("size-4", className2),
173
+ ...props2
174
+ }, undefined, false, undefined, this),
175
+ IconRight: ({ className: className2, ...props2 }) => /* @__PURE__ */ jsxDEV5(ChevronRight, {
176
+ className: cn("size-4", className2),
177
+ ...props2
178
+ }, undefined, false, undefined, this)
179
+ },
180
+ ...props
181
+ }, undefined, false, undefined, this);
182
+ }
183
+ // src/components/ui/checkbox.tsx
184
+ import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
185
+ import { CheckIcon } from "lucide-react";
186
+ import { jsxDEV as jsxDEV6 } from "react/jsx-dev-runtime";
187
+ function Checkbox({
188
+ className,
189
+ ...props
190
+ }) {
191
+ return /* @__PURE__ */ jsxDEV6(CheckboxPrimitive.Root, {
192
+ "data-slot": "checkbox",
193
+ className: cn("peer border-input dark:bg-input/30 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:data-[state=checked]:bg-primary data-[state=checked]:border-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive size-4 shrink-0 rounded-[4px] border shadow-xs transition-shadow outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50", className),
194
+ ...props,
195
+ children: /* @__PURE__ */ jsxDEV6(CheckboxPrimitive.Indicator, {
196
+ "data-slot": "checkbox-indicator",
197
+ className: "flex items-center justify-center text-current transition-none",
198
+ children: /* @__PURE__ */ jsxDEV6(CheckIcon, {
199
+ className: "size-3.5"
200
+ }, undefined, false, undefined, this)
201
+ }, undefined, false, undefined, this)
202
+ }, undefined, false, undefined, this);
203
+ }
204
+ // src/components/ui/card.tsx
205
+ import { jsxDEV as jsxDEV7 } from "react/jsx-dev-runtime";
206
+ // src/components/ui/date-picker.tsx
207
+ import dayjs2 from "dayjs";
208
+ import { Calendar as CalendarIcon } from "lucide-react";
209
+
210
+ // src/components/ui/popover.tsx
211
+ import * as PopoverPrimitive from "@radix-ui/react-popover";
212
+ import { jsxDEV as jsxDEV8 } from "react/jsx-dev-runtime";
213
+ function Popover({
214
+ ...props
215
+ }) {
216
+ return /* @__PURE__ */ jsxDEV8(PopoverPrimitive.Root, {
217
+ "data-slot": "popover",
218
+ ...props
219
+ }, undefined, false, undefined, this);
220
+ }
221
+ function PopoverTrigger({
222
+ ...props
223
+ }) {
224
+ return /* @__PURE__ */ jsxDEV8(PopoverPrimitive.Trigger, {
225
+ "data-slot": "popover-trigger",
226
+ ...props
227
+ }, undefined, false, undefined, this);
228
+ }
229
+ function PopoverContent({
230
+ className,
231
+ align = "center",
232
+ sideOffset = 4,
233
+ ...props
234
+ }) {
235
+ return /* @__PURE__ */ jsxDEV8(PopoverPrimitive.Portal, {
236
+ children: /* @__PURE__ */ jsxDEV8(PopoverPrimitive.Content, {
237
+ "data-slot": "popover-content",
238
+ align,
239
+ sideOffset,
240
+ className: cn("bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 origin-(--radix-popover-content-transform-origin) rounded-md border p-4 shadow-md outline-hidden", className),
241
+ ...props
242
+ }, undefined, false, undefined, this)
243
+ }, undefined, false, undefined, this);
244
+ }
245
+
246
+ // src/components/ui/date-picker.tsx
247
+ import { useRef } from "react";
248
+ import { PopoverClose } from "@radix-ui/react-popover";
249
+ import { jsxDEV as jsxDEV9 } from "react/jsx-dev-runtime";
250
+ function DatePicker({
251
+ date,
252
+ closeOnSelect,
253
+ setDate,
254
+ label = "Pick a date",
255
+ className
256
+ }) {
257
+ const popOverRef = useRef(null);
258
+ const onSelect = (date2) => {
259
+ setDate(date2);
260
+ if (closeOnSelect) {
261
+ popOverRef.current?.click();
262
+ }
263
+ };
264
+ return /* @__PURE__ */ jsxDEV9("div", {
265
+ className,
266
+ children: /* @__PURE__ */ jsxDEV9(Popover, {
267
+ children: [
268
+ /* @__PURE__ */ jsxDEV9(PopoverTrigger, {
269
+ asChild: true,
270
+ children: /* @__PURE__ */ jsxDEV9(Button, {
271
+ variant: "outline",
272
+ className: cn("w-full justify-start text-left font-normal", !date && "text-muted-foreground"),
273
+ children: [
274
+ /* @__PURE__ */ jsxDEV9(CalendarIcon, {
275
+ className: "mr-2 h-4 w-4"
276
+ }, undefined, false, undefined, this),
277
+ date ? dayjs2(date).format("MMM D, YYYY") : /* @__PURE__ */ jsxDEV9("span", {
278
+ children: label
279
+ }, undefined, false, undefined, this)
280
+ ]
281
+ }, undefined, true, undefined, this)
282
+ }, undefined, false, undefined, this),
283
+ /* @__PURE__ */ jsxDEV9(PopoverContent, {
284
+ className: "w-auto p-0",
285
+ align: "start",
286
+ children: [
287
+ /* @__PURE__ */ jsxDEV9(PopoverClose, {
288
+ ref: popOverRef
289
+ }, undefined, false, undefined, this),
290
+ /* @__PURE__ */ jsxDEV9(Calendar, {
291
+ mode: "single",
292
+ selected: date,
293
+ onSelect,
294
+ initialFocus: true
295
+ }, undefined, false, undefined, this)
296
+ ]
297
+ }, undefined, true, undefined, this)
298
+ ]
299
+ }, undefined, true, undefined, this)
300
+ }, undefined, false, undefined, this);
301
+ }
302
+ // src/components/ui/dialog.tsx
303
+ import * as DialogPrimitive from "@radix-ui/react-dialog";
304
+ import { XIcon } from "lucide-react";
305
+ import { jsxDEV as jsxDEV10 } from "react/jsx-dev-runtime";
306
+ function Dialog({
307
+ ...props
308
+ }) {
309
+ return /* @__PURE__ */ jsxDEV10(DialogPrimitive.Root, {
310
+ "data-slot": "dialog",
311
+ ...props
312
+ }, undefined, false, undefined, this);
313
+ }
314
+ function DialogPortal({
315
+ ...props
316
+ }) {
317
+ return /* @__PURE__ */ jsxDEV10(DialogPrimitive.Portal, {
318
+ "data-slot": "dialog-portal",
319
+ ...props
320
+ }, undefined, false, undefined, this);
321
+ }
322
+ function DialogOverlay({
323
+ className,
324
+ ...props
325
+ }) {
326
+ return /* @__PURE__ */ jsxDEV10(DialogPrimitive.Overlay, {
327
+ "data-slot": "dialog-overlay",
328
+ className: cn("data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50", className),
329
+ ...props
330
+ }, undefined, false, undefined, this);
331
+ }
332
+ function DialogContent({
333
+ className,
334
+ children,
335
+ ...props
336
+ }) {
337
+ return /* @__PURE__ */ jsxDEV10(DialogPortal, {
338
+ "data-slot": "dialog-portal",
339
+ children: [
340
+ /* @__PURE__ */ jsxDEV10(DialogOverlay, {}, undefined, false, undefined, this),
341
+ /* @__PURE__ */ jsxDEV10(DialogPrimitive.Content, {
342
+ "data-slot": "dialog-content",
343
+ className: cn("bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg", className),
344
+ ...props,
345
+ children: [
346
+ children,
347
+ /* @__PURE__ */ jsxDEV10(DialogPrimitive.Close, {
348
+ className: "ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
349
+ children: [
350
+ /* @__PURE__ */ jsxDEV10(XIcon, {}, undefined, false, undefined, this),
351
+ /* @__PURE__ */ jsxDEV10("span", {
352
+ className: "sr-only",
353
+ children: "Close"
354
+ }, undefined, false, undefined, this)
355
+ ]
356
+ }, undefined, true, undefined, this)
357
+ ]
358
+ }, undefined, true, undefined, this)
359
+ ]
360
+ }, undefined, true, undefined, this);
361
+ }
362
+ function DialogHeader({ className, ...props }) {
363
+ return /* @__PURE__ */ jsxDEV10("div", {
364
+ "data-slot": "dialog-header",
365
+ className: cn("flex flex-col gap-2 text-center sm:text-left", className),
366
+ ...props
367
+ }, undefined, false, undefined, this);
368
+ }
369
+ function DialogFooter({ className, ...props }) {
370
+ return /* @__PURE__ */ jsxDEV10("div", {
371
+ "data-slot": "dialog-footer",
372
+ className: cn("flex flex-col-reverse gap-2 sm:flex-row sm:justify-end", className),
373
+ ...props
374
+ }, undefined, false, undefined, this);
375
+ }
376
+ function DialogTitle({
377
+ className,
378
+ ...props
379
+ }) {
380
+ return /* @__PURE__ */ jsxDEV10(DialogPrimitive.Title, {
381
+ "data-slot": "dialog-title",
382
+ className: cn("text-lg leading-none font-semibold", className),
383
+ ...props
384
+ }, undefined, false, undefined, this);
385
+ }
386
+ function DialogDescription({
387
+ className,
388
+ ...props
389
+ }) {
390
+ return /* @__PURE__ */ jsxDEV10(DialogPrimitive.Description, {
391
+ "data-slot": "dialog-description",
392
+ className: cn("text-muted-foreground text-sm", className),
393
+ ...props
394
+ }, undefined, false, undefined, this);
395
+ }
396
+ // src/components/ui/dropdown-menu.tsx
397
+ import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
398
+ import { CheckIcon as CheckIcon2, ChevronRightIcon, CircleIcon } from "lucide-react";
399
+ import { jsxDEV as jsxDEV11 } from "react/jsx-dev-runtime";
400
+ // src/components/ui/form.tsx
401
+ import * as React from "react";
402
+ import { Slot as Slot3 } from "@radix-ui/react-slot";
403
+ import {
404
+ Controller,
405
+ FormProvider,
406
+ useFormContext,
407
+ useFormState
408
+ } from "react-hook-form";
409
+
410
+ // src/components/ui/label.tsx
411
+ import * as LabelPrimitive from "@radix-ui/react-label";
412
+ import { jsxDEV as jsxDEV12 } from "react/jsx-dev-runtime";
413
+
414
+ function Label2({
415
+ className,
416
+ ...props
417
+ }) {
418
+ return /* @__PURE__ */ jsxDEV12(LabelPrimitive.Root, {
419
+ "data-slot": "label",
420
+ className: cn("flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50", className),
421
+ ...props
422
+ }, undefined, false, undefined, this);
423
+ }
424
+
425
+ // src/components/ui/form.tsx
426
+ import { jsxDEV as jsxDEV13 } from "react/jsx-dev-runtime";
427
+ var FormFieldContext = React.createContext({});
428
+ var FormItemContext = React.createContext({});
429
+ // src/components/ui/input.tsx
430
+ import { jsxDEV as jsxDEV14 } from "react/jsx-dev-runtime";
431
+ function Input({ className, type, ...props }) {
432
+ return /* @__PURE__ */ jsxDEV14("input", {
433
+ type,
434
+ "data-slot": "input",
435
+ className: cn("file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm", "focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]", "aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive", className),
436
+ ...props
437
+ }, undefined, false, undefined, this);
438
+ }
439
+ // src/components/ui/link.tsx
440
+ import { jsxDEV as jsxDEV15 } from "react/jsx-dev-runtime";
441
+ // src/components/ui/scroll-area.tsx
442
+ import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area";
443
+ import { jsxDEV as jsxDEV16 } from "react/jsx-dev-runtime";
444
+ function ScrollArea({
445
+ className,
446
+ children,
447
+ ...props
448
+ }) {
449
+ return /* @__PURE__ */ jsxDEV16(ScrollAreaPrimitive.Root, {
450
+ "data-slot": "scroll-area",
451
+ className: cn("relative", className),
452
+ ...props,
453
+ children: [
454
+ /* @__PURE__ */ jsxDEV16(ScrollAreaPrimitive.Viewport, {
455
+ "data-slot": "scroll-area-viewport",
456
+ className: "focus-visible:ring-ring/50 size-full rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:outline-1",
457
+ children
458
+ }, undefined, false, undefined, this),
459
+ /* @__PURE__ */ jsxDEV16(ScrollBar, {}, undefined, false, undefined, this),
460
+ /* @__PURE__ */ jsxDEV16(ScrollAreaPrimitive.Corner, {}, undefined, false, undefined, this)
461
+ ]
462
+ }, undefined, true, undefined, this);
463
+ }
464
+ function ScrollBar({
465
+ className,
466
+ orientation = "vertical",
467
+ ...props
468
+ }) {
469
+ return /* @__PURE__ */ jsxDEV16(ScrollAreaPrimitive.ScrollAreaScrollbar, {
470
+ "data-slot": "scroll-area-scrollbar",
471
+ orientation,
472
+ className: cn("flex touch-none p-px transition-colors select-none", orientation === "vertical" && "h-full w-2.5 border-l border-l-transparent", orientation === "horizontal" && "h-2.5 flex-col border-t border-t-transparent", className),
473
+ ...props,
474
+ children: /* @__PURE__ */ jsxDEV16(ScrollAreaPrimitive.ScrollAreaThumb, {
475
+ "data-slot": "scroll-area-thumb",
476
+ className: "bg-border relative flex-1 rounded-full"
477
+ }, undefined, false, undefined, this)
478
+ }, undefined, false, undefined, this);
479
+ }
480
+ // src/components/ui/select.tsx
481
+ import * as SelectPrimitive from "@radix-ui/react-select";
482
+ import { CheckIcon as CheckIcon3, ChevronDownIcon as ChevronDownIcon2, ChevronUpIcon } from "lucide-react";
483
+ import { jsxDEV as jsxDEV17 } from "react/jsx-dev-runtime";
484
+ // src/components/ui/separator.tsx
485
+ import * as SeparatorPrimitive from "@radix-ui/react-separator";
486
+ import { jsxDEV as jsxDEV18 } from "react/jsx-dev-runtime";
487
+ // src/components/ui/sheet.tsx
488
+ import * as SheetPrimitive from "@radix-ui/react-dialog";
489
+ import { XIcon as XIcon2 } from "lucide-react";
490
+ import { jsxDEV as jsxDEV19 } from "react/jsx-dev-runtime";
491
+ // src/components/ui/table.tsx
492
+ import { jsxDEV as jsxDEV20 } from "react/jsx-dev-runtime";
493
+ // src/components/ui/tabs.tsx
494
+ import * as TabsPrimitive from "@radix-ui/react-tabs";
495
+ import { jsxDEV as jsxDEV21 } from "react/jsx-dev-runtime";
496
+ // src/components/ui/textarea.tsx
497
+ import { jsxDEV as jsxDEV22 } from "react/jsx-dev-runtime";
498
+ // src/components/ui/tooltip.tsx
499
+ import * as TooltipPrimitive from "@radix-ui/react-tooltip";
500
+ import { jsxDEV as jsxDEV23 } from "react/jsx-dev-runtime";
501
+ function TooltipProvider({
502
+ delayDuration = 0,
503
+ ...props
504
+ }) {
505
+ return /* @__PURE__ */ jsxDEV23(TooltipPrimitive.Provider, {
506
+ "data-slot": "tooltip-provider",
507
+ delayDuration,
508
+ ...props
509
+ }, undefined, false, undefined, this);
510
+ }
511
+ function Tooltip({
512
+ ...props
513
+ }) {
514
+ return /* @__PURE__ */ jsxDEV23(TooltipProvider, {
515
+ children: /* @__PURE__ */ jsxDEV23(TooltipPrimitive.Root, {
516
+ "data-slot": "tooltip",
517
+ ...props
518
+ }, undefined, false, undefined, this)
519
+ }, undefined, false, undefined, this);
520
+ }
521
+ function TooltipTrigger({
522
+ ...props
523
+ }) {
524
+ return /* @__PURE__ */ jsxDEV23(TooltipPrimitive.Trigger, {
525
+ "data-slot": "tooltip-trigger",
526
+ ...props
527
+ }, undefined, false, undefined, this);
528
+ }
529
+ function TooltipContent({
530
+ className,
531
+ sideOffset = 0,
532
+ children,
533
+ ...props
534
+ }) {
535
+ return /* @__PURE__ */ jsxDEV23(TooltipPrimitive.Portal, {
536
+ children: /* @__PURE__ */ jsxDEV23(TooltipPrimitive.Content, {
537
+ "data-slot": "tooltip-content",
538
+ sideOffset,
539
+ className: cn("bg-primary text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-md px-3 py-1.5 text-xs text-balance", className),
540
+ ...props,
541
+ children: [
542
+ children,
543
+ /* @__PURE__ */ jsxDEV23(TooltipPrimitive.Arrow, {
544
+ className: "bg-primary fill-primary z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]"
545
+ }, undefined, false, undefined, this)
546
+ ]
547
+ }, undefined, true, undefined, this)
548
+ }, undefined, false, undefined, this);
549
+ }
550
+ // src/features/month-view/components/all-events-dialog.tsx
551
+ import { useImperativeHandle, useState } from "react";
552
+
553
+ // src/features/draggable-event/draggable-event.tsx
554
+ import { useDraggable } from "@dnd-kit/core";
555
+ import { AnimatePresence, motion } from "motion/react";
556
+ import { memo } from "react";
557
+ import { jsxDEV as jsxDEV24 } from "react/jsx-dev-runtime";
558
+ function DraggableEventUnmemoized({
559
+ elementId,
560
+ event,
561
+ className,
562
+ style,
563
+ disableDrag = false
564
+ }) {
565
+ const { onEventClick, renderEvent, disableEventClick, disableDragAndDrop } = useCalendarContext();
566
+ const { attributes, listeners, setNodeRef, isDragging } = useDraggable({
567
+ id: elementId,
568
+ data: {
569
+ event,
570
+ type: "calendar-event"
571
+ },
572
+ disabled: disableDrag || disableDragAndDrop
573
+ });
574
+ const DefaultEventContent = () => /* @__PURE__ */ jsxDEV24("div", {
575
+ className: cn(event.backgroundColor || "bg-blue-500", event.color || "text-white", "h-full w-full px-1 border-[1.5px] border-card rounded-md text-left overflow-clip"),
576
+ style: { backgroundColor: event.backgroundColor, color: event.color },
577
+ children: /* @__PURE__ */ jsxDEV24("p", {
578
+ className: "text-[10px] font-semibold sm:text-xs mt-0.5",
579
+ children: event.title
580
+ }, undefined, false, undefined, this)
581
+ }, undefined, false, undefined, this);
582
+ return /* @__PURE__ */ jsxDEV24(AnimatePresence, {
583
+ mode: "wait",
584
+ children: /* @__PURE__ */ jsxDEV24(motion.div, {
585
+ ref: setNodeRef,
586
+ ...attributes,
587
+ ...listeners,
588
+ initial: { opacity: 0, y: -50 },
589
+ animate: { opacity: 1, y: 0 },
590
+ exit: { opacity: 0, y: -50 },
591
+ layout: true,
592
+ layoutId: elementId,
593
+ transition: { duration: 0.4, ease: "easeInOut" },
594
+ className: cn("truncate h-full w-full", disableDrag || disableDragAndDrop ? disableEventClick ? "cursor-default" : "cursor-pointer" : "cursor-grab", isDragging && !(disableDrag || disableDragAndDrop) && "cursor-grabbing shadow-lg", className),
595
+ style,
596
+ onClick: (e) => {
597
+ e.stopPropagation();
598
+ onEventClick(event);
599
+ },
600
+ children: renderEvent ? renderEvent(event) : /* @__PURE__ */ jsxDEV24(DefaultEventContent, {}, undefined, false, undefined, this)
601
+ }, elementId, false, undefined, this)
602
+ }, undefined, false, undefined, this);
603
+ }
604
+ var DraggableEvent = memo(DraggableEventUnmemoized, (prevProps, nextProps) => {
605
+ return prevProps.elementId === nextProps.elementId && prevProps.disableDrag === nextProps.disableDrag && prevProps.className === nextProps.className && prevProps.event.id === nextProps.event.id && prevProps.event.height === nextProps.event.height;
606
+ });
607
+
608
+ // src/features/month-view/components/all-events-dialog.tsx
609
+ import { jsxDEV as jsxDEV25 } from "react/jsx-dev-runtime";
610
+ var AllEventDialog = ({ ref }) => {
611
+ const [dialogOpen, setDialogOpen] = useState(false);
612
+ const [selectedDayEvents, setSelectedDayEvents] = useState(null);
613
+ const { currentDate, firstDayOfWeek } = useCalendarContext();
614
+ useImperativeHandle(ref, () => ({
615
+ open: () => setDialogOpen(true),
616
+ close: () => setDialogOpen(false),
617
+ setSelectedDayEvents: (dayEvents) => setSelectedDayEvents(dayEvents)
618
+ }));
619
+ const firstDayOfMonth = currentDate.startOf("month");
620
+ let adjustedFirstDayOfCalendar = firstDayOfMonth.clone();
621
+ while (adjustedFirstDayOfCalendar.day() !== firstDayOfWeek) {
622
+ adjustedFirstDayOfCalendar = adjustedFirstDayOfCalendar.subtract(1, "day");
623
+ }
624
+ return /* @__PURE__ */ jsxDEV25(Dialog, {
625
+ open: dialogOpen,
626
+ onOpenChange: setDialogOpen,
627
+ children: /* @__PURE__ */ jsxDEV25(DialogContent, {
628
+ className: "max-h-[80vh] max-w-md overflow-y-auto",
629
+ children: [
630
+ /* @__PURE__ */ jsxDEV25(DialogHeader, {
631
+ children: /* @__PURE__ */ jsxDEV25(DialogTitle, {
632
+ children: selectedDayEvents && selectedDayEvents.day.format("MMMM D, YYYY")
633
+ }, undefined, false, undefined, this)
634
+ }, undefined, false, undefined, this),
635
+ /* @__PURE__ */ jsxDEV25("div", {
636
+ className: "mt-4 space-y-3",
637
+ children: selectedDayEvents && selectedDayEvents.events.map((event) => {
638
+ return /* @__PURE__ */ jsxDEV25(DraggableEvent, {
639
+ elementId: event.id,
640
+ event,
641
+ className: "relative my-1 h-[30px]"
642
+ }, event.id, false, undefined, this);
643
+ })
644
+ }, undefined, false, undefined, this)
645
+ ]
646
+ }, undefined, true, undefined, this)
647
+ }, undefined, false, undefined, this);
648
+ };
649
+
650
+ // src/lib/dayjs-config.ts
651
+ import dayjs3 from "dayjs";
652
+ import weekday from "dayjs/plugin/weekday";
653
+ import weekOfYear from "dayjs/plugin/weekOfYear";
654
+ import isSameOrAfter from "dayjs/plugin/isSameOrAfter";
655
+ import isSameOrBefore from "dayjs/plugin/isSameOrBefore";
656
+ import isBetween from "dayjs/plugin/isBetween";
657
+ import minMax from "dayjs/plugin/minMax";
658
+ import timezone from "dayjs/plugin/timezone";
659
+ import utc from "dayjs/plugin/utc";
660
+ import localeData from "dayjs/plugin/localeData";
661
+ import"dayjs/locale/af";
662
+ import"dayjs/locale/am";
663
+ import"dayjs/locale/ar-dz";
664
+ import"dayjs/locale/ar-iq";
665
+ import"dayjs/locale/ar-kw";
666
+ import"dayjs/locale/ar-ly";
667
+ import"dayjs/locale/ar-ma";
668
+ import"dayjs/locale/ar-sa";
669
+ import"dayjs/locale/ar-tn";
670
+ import"dayjs/locale/ar";
671
+ import"dayjs/locale/az";
672
+ import"dayjs/locale/be";
673
+ import"dayjs/locale/bg";
674
+ import"dayjs/locale/bi";
675
+ import"dayjs/locale/bm";
676
+ import"dayjs/locale/bn-bd";
677
+ import"dayjs/locale/bn";
678
+ import"dayjs/locale/bo";
679
+ import"dayjs/locale/br";
680
+ import"dayjs/locale/bs";
681
+ import"dayjs/locale/ca";
682
+ import"dayjs/locale/cs";
683
+ import"dayjs/locale/cv";
684
+ import"dayjs/locale/cy";
685
+ import"dayjs/locale/da";
686
+ import"dayjs/locale/de-at";
687
+ import"dayjs/locale/de-ch";
688
+ import"dayjs/locale/de";
689
+ import"dayjs/locale/dv";
690
+ import"dayjs/locale/el";
691
+ import"dayjs/locale/en-au";
692
+ import"dayjs/locale/en-ca";
693
+ import"dayjs/locale/en-gb";
694
+ import"dayjs/locale/en-ie";
695
+ import"dayjs/locale/en-il";
696
+ import"dayjs/locale/en-in";
697
+ import"dayjs/locale/en-nz";
698
+ import"dayjs/locale/en-sg";
699
+ import"dayjs/locale/en-tt";
700
+ import"dayjs/locale/en";
701
+ import"dayjs/locale/eo";
702
+ import"dayjs/locale/es-do";
703
+ import"dayjs/locale/es-mx";
704
+ import"dayjs/locale/es-pr";
705
+ import"dayjs/locale/es-us";
706
+ import"dayjs/locale/es";
707
+ import"dayjs/locale/et";
708
+ import"dayjs/locale/eu";
709
+ import"dayjs/locale/fa";
710
+ import"dayjs/locale/fi";
711
+ import"dayjs/locale/fo";
712
+ import"dayjs/locale/fr-ca";
713
+ import"dayjs/locale/fr-ch";
714
+ import"dayjs/locale/fr";
715
+ import"dayjs/locale/fy";
716
+ import"dayjs/locale/ga";
717
+ import"dayjs/locale/gd";
718
+ import"dayjs/locale/gl";
719
+ import"dayjs/locale/gom-latn";
720
+ import"dayjs/locale/gu";
721
+ import"dayjs/locale/he";
722
+ import"dayjs/locale/hi";
723
+ import"dayjs/locale/hr";
724
+ import"dayjs/locale/ht";
725
+ import"dayjs/locale/hu";
726
+ import"dayjs/locale/hy-am";
727
+ import"dayjs/locale/id";
728
+ import"dayjs/locale/is";
729
+ import"dayjs/locale/it-ch";
730
+ import"dayjs/locale/it";
731
+ import"dayjs/locale/ja";
732
+ import"dayjs/locale/jv";
733
+ import"dayjs/locale/ka";
734
+ import"dayjs/locale/kk";
735
+ import"dayjs/locale/km";
736
+ import"dayjs/locale/kn";
737
+ import"dayjs/locale/ko";
738
+ import"dayjs/locale/ku";
739
+ import"dayjs/locale/ky";
740
+ import"dayjs/locale/lb";
741
+ import"dayjs/locale/lo";
742
+ import"dayjs/locale/lt";
743
+ import"dayjs/locale/lv";
744
+ import"dayjs/locale/me";
745
+ import"dayjs/locale/mi";
746
+ import"dayjs/locale/mk";
747
+ import"dayjs/locale/ml";
748
+ import"dayjs/locale/mn";
749
+ import"dayjs/locale/mr";
750
+ import"dayjs/locale/ms-my";
751
+ import"dayjs/locale/ms";
752
+ import"dayjs/locale/mt";
753
+ import"dayjs/locale/my";
754
+ import"dayjs/locale/nb";
755
+ import"dayjs/locale/ne";
756
+ import"dayjs/locale/nl-be";
757
+ import"dayjs/locale/nl";
758
+ import"dayjs/locale/nn";
759
+ import"dayjs/locale/oc-lnc";
760
+ import"dayjs/locale/pa-in";
761
+ import"dayjs/locale/pl";
762
+ import"dayjs/locale/pt-br";
763
+ import"dayjs/locale/pt";
764
+ import"dayjs/locale/rn";
765
+ import"dayjs/locale/ro";
766
+ import"dayjs/locale/ru";
767
+ import"dayjs/locale/rw";
768
+ import"dayjs/locale/sd";
769
+ import"dayjs/locale/se";
770
+ import"dayjs/locale/si";
771
+ import"dayjs/locale/sk";
772
+ import"dayjs/locale/sl";
773
+ import"dayjs/locale/sq";
774
+ import"dayjs/locale/sr-cyrl";
775
+ import"dayjs/locale/sr";
776
+ import"dayjs/locale/ss";
777
+ import"dayjs/locale/sv-fi";
778
+ import"dayjs/locale/sv";
779
+ import"dayjs/locale/sw";
780
+ import"dayjs/locale/ta";
781
+ import"dayjs/locale/te";
782
+ import"dayjs/locale/tet";
783
+ import"dayjs/locale/tg";
784
+ import"dayjs/locale/th";
785
+ import"dayjs/locale/tk";
786
+ import"dayjs/locale/tl-ph";
787
+ import"dayjs/locale/tlh";
788
+ import"dayjs/locale/tr";
789
+ import"dayjs/locale/tzl";
790
+ import"dayjs/locale/tzm-latn";
791
+ import"dayjs/locale/tzm";
792
+ import"dayjs/locale/ug-cn";
793
+ import"dayjs/locale/uk";
794
+ import"dayjs/locale/ur";
795
+ import"dayjs/locale/uz-latn";
796
+ import"dayjs/locale/uz";
797
+ import"dayjs/locale/vi";
798
+ import"dayjs/locale/x-pseudo";
799
+ import"dayjs/locale/yo";
800
+ import"dayjs/locale/zh-cn";
801
+ import"dayjs/locale/zh-hk";
802
+ import"dayjs/locale/zh-tw";
803
+ import"dayjs/locale/zh";
804
+ dayjs3.extend(weekday);
805
+ dayjs3.extend(weekOfYear);
806
+ dayjs3.extend(isSameOrAfter);
807
+ dayjs3.extend(isSameOrBefore);
808
+ dayjs3.extend(isBetween);
809
+ dayjs3.extend(minMax);
810
+ dayjs3.extend(timezone);
811
+ dayjs3.extend(utc);
812
+ dayjs3.extend(localeData);
813
+ var dayjs_config_default = dayjs3;
814
+
815
+ // src/features/month-view/components/day-cell.tsx
816
+ import React3 from "react";
817
+
818
+ // src/features/droppable-cell/droppable-cell.tsx
819
+ import { useDroppable } from "@dnd-kit/core";
820
+ import { jsxDEV as jsxDEV26 } from "react/jsx-dev-runtime";
821
+ function DroppableCell({
822
+ id,
823
+ type,
824
+ date,
825
+ hour,
826
+ minute,
827
+ children,
828
+ className,
829
+ style,
830
+ "data-testid": dataTestId
831
+ }) {
832
+ const { onCellClick, disableDragAndDrop, disableCellClick } = useCalendarContext();
833
+ const { isOver, setNodeRef } = useDroppable({
834
+ id,
835
+ data: {
836
+ type,
837
+ date,
838
+ hour,
839
+ minute
840
+ },
841
+ disabled: disableDragAndDrop
842
+ });
843
+ const handleCellClick = (e) => {
844
+ e.stopPropagation();
845
+ if (disableCellClick)
846
+ return;
847
+ const startDate = date.hour(hour ?? 0).minute(minute ?? 0);
848
+ let endDate = startDate.clone();
849
+ if (hour !== undefined && minute !== undefined) {
850
+ endDate = endDate.hour(hour).minute(minute + 15);
851
+ } else if (hour !== undefined) {
852
+ endDate = endDate.hour(hour + 1).minute(0);
853
+ } else {
854
+ endDate = endDate.hour(23).minute(59);
855
+ }
856
+ onCellClick(startDate, endDate);
857
+ };
858
+ return /* @__PURE__ */ jsxDEV26("div", {
859
+ ref: setNodeRef,
860
+ "data-testid": dataTestId,
861
+ className: cn(className, isOver && !disableDragAndDrop && "bg-accent", disableCellClick ? "cursor-default" : "cursor-pointer"),
862
+ onClick: handleCellClick,
863
+ style,
864
+ children
865
+ }, undefined, false, undefined, this);
866
+ }
867
+
868
+ // src/features/month-view/components/day-cell.tsx
869
+ import { jsxDEV as jsxDEV27, Fragment } from "react/jsx-dev-runtime";
870
+ var DayCell = ({
871
+ index,
872
+ day,
873
+ className = ""
874
+ }) => {
875
+ const allEventsDialogRef = React3.useRef(null);
876
+ const {
877
+ events,
878
+ currentDate,
879
+ firstDayOfWeek,
880
+ dayMaxEvents = 0
881
+ } = useCalendarContext();
882
+ const todayEvents = events.filter((e) => {
883
+ const startsToday = e.start.isSame(day, "day");
884
+ const endsToday = e.end.isSame(day, "day");
885
+ const spansToday = e.start.isBefore(day, "day") && e.end.isAfter(day, "day");
886
+ return startsToday || endsToday || spansToday;
887
+ });
888
+ const firstDayOfMonth = currentDate.startOf("month");
889
+ let adjustedFirstDayOfCalendar = firstDayOfMonth.clone();
890
+ while (adjustedFirstDayOfCalendar.day() !== firstDayOfWeek) {
891
+ adjustedFirstDayOfCalendar = adjustedFirstDayOfCalendar.subtract(1, "day");
892
+ }
893
+ const showAllEvents = (day2, events2) => {
894
+ allEventsDialogRef.current?.setSelectedDayEvents({
895
+ day: day2,
896
+ events: events2
897
+ });
898
+ allEventsDialogRef.current?.open();
899
+ };
900
+ const isToday = day.isSame(dayjs_config_default(), "day");
901
+ const isCurrentMonth = day.month() === currentDate.month();
902
+ const isLastColumn = index === 6;
903
+ const hiddenEventsCount = todayEvents.length - dayMaxEvents;
904
+ const hasHiddenEvents = hiddenEventsCount > 0;
905
+ return /* @__PURE__ */ jsxDEV27(Fragment, {
906
+ children: [
907
+ /* @__PURE__ */ jsxDEV27(DroppableCell, {
908
+ id: `day-cell-${day.format("YYYY-MM-DD")}`,
909
+ type: "day-cell",
910
+ "data-testid": `day-cell-${day.format("YYYY-MM-DD")}`,
911
+ date: day,
912
+ className: cn("cursor-pointer overflow-clip p-1 hover:bg-accent", !isCurrentMonth && "bg-secondary text-muted-foreground", isLastColumn && "border-r-0", className),
913
+ children: /* @__PURE__ */ jsxDEV27("div", {
914
+ className: "flex flex-col gap-1",
915
+ children: [
916
+ /* @__PURE__ */ jsxDEV27("div", {
917
+ className: cn("flex h-5 w-5 items-center justify-center rounded-full text-xs sm:h-6 sm:w-6 sm:text-sm", isToday && "bg-primary text-primary-foreground font-medium"),
918
+ children: day.date()
919
+ }, undefined, false, undefined, this),
920
+ todayEvents.slice(0, dayMaxEvents).map((event, rowIndex) => /* @__PURE__ */ jsxDEV27("div", {
921
+ className: "h-[20px] w-full",
922
+ "data-testid": event?.title
923
+ }, `empty-${rowIndex}`, false, undefined, this)),
924
+ hasHiddenEvents && /* @__PURE__ */ jsxDEV27("div", {
925
+ className: "text-muted-foreground hover:text-foreground cursor-pointer text-[10px] whitespace-nowrap sm:text-xs mt-1",
926
+ onClick: (e) => {
927
+ e.stopPropagation();
928
+ showAllEvents(day, todayEvents);
929
+ },
930
+ children: [
931
+ "+",
932
+ hiddenEventsCount,
933
+ " more"
934
+ ]
935
+ }, undefined, true, undefined, this)
936
+ ]
937
+ }, undefined, true, undefined, this)
938
+ }, undefined, false, undefined, this),
939
+ /* @__PURE__ */ jsxDEV27(AllEventDialog, {
940
+ ref: allEventsDialogRef
941
+ }, undefined, false, undefined, this)
942
+ ]
943
+ }, undefined, true, undefined, this);
944
+ };
945
+
946
+ // src/features/month-view/components/month-header.tsx
947
+ import { AnimatePresence as AnimatePresence2, motion as motion2 } from "motion/react";
948
+ import { useMemo } from "react";
949
+ import dayjs4 from "dayjs";
950
+ import { jsxDEV as jsxDEV28 } from "react/jsx-dev-runtime";
951
+ var MonthHeader = () => {
952
+ const { firstDayOfWeek, currentLocale, stickyHeader } = useCalendarContext();
953
+ const weekDays = useMemo(() => {
954
+ const days = dayjs4.weekdays().map((day) => day.toLowerCase());
955
+ const shortDays = dayjs4.weekdaysShort().map((day) => day.toLowerCase());
956
+ for (let i = 0;i < firstDayOfWeek; i++) {
957
+ const dayToMove = days.shift();
958
+ const shortDayToMove = shortDays.shift();
959
+ if (dayToMove)
960
+ days.push(dayToMove);
961
+ if (shortDayToMove)
962
+ shortDays.push(shortDayToMove);
963
+ }
964
+ return { days, shortDays };
965
+ }, [firstDayOfWeek, currentLocale]);
966
+ return /* @__PURE__ */ jsxDEV28("div", {
967
+ className: cn("grid grid-cols-7 border-b bg-background", stickyHeader && "sticky top-0 z-100 shadow"),
968
+ "data-testid": "month-header",
969
+ children: weekDays.days.map((weekDay, index) => /* @__PURE__ */ jsxDEV28(AnimatePresence2, {
970
+ mode: "wait",
971
+ children: /* @__PURE__ */ jsxDEV28(motion2.div, {
972
+ initial: { opacity: 0, y: -10 },
973
+ animate: { opacity: 1, y: 0 },
974
+ exit: { opacity: 0, y: -10 },
975
+ transition: {
976
+ duration: 0.25,
977
+ ease: "easeInOut",
978
+ delay: index * 0.05
979
+ },
980
+ className: "py-2 text-center font-medium border-r first:border-l",
981
+ "data-testid": `weekday-header-${weekDay}`,
982
+ children: [
983
+ /* @__PURE__ */ jsxDEV28("span", {
984
+ className: "hidden text-sm sm:inline",
985
+ children: weekDay
986
+ }, undefined, false, undefined, this),
987
+ /* @__PURE__ */ jsxDEV28("span", {
988
+ className: "text-xs sm:hidden",
989
+ children: weekDays.shortDays[index]
990
+ }, undefined, false, undefined, this)
991
+ ]
992
+ }, weekDay, true, undefined, this)
993
+ }, weekDay, false, undefined, this))
994
+ }, undefined, false, undefined, this);
995
+ };
996
+
997
+ // src/lib/constants.ts
998
+ var GAP_BETWEEN_ELEMENTS = 1;
999
+ var DAY_NUMBER_HEIGHT = 24;
1000
+ var EVENT_BAR_HEIGHT = 24;
1001
+
1002
+ // src/features/month-view/components/week-events-layer.tsx
1003
+ import { jsxDEV as jsxDEV29 } from "react/jsx-dev-runtime";
1004
+ var WeekEventsLayer = ({ days }) => {
1005
+ const { events, dayMaxEvents } = useCalendarContext();
1006
+ const weekStart = days[0];
1007
+ const weekEnd = days[6];
1008
+ const weekEvents = events.filter((e) => {
1009
+ const startsInWeek = e.start.isSameOrAfter(weekStart.startOf("day")) && e.start.isSameOrBefore(weekEnd.endOf("day"));
1010
+ const endsInWeek = e.end.isSameOrAfter(weekStart.startOf("day")) && e.end.isSameOrBefore(weekEnd.endOf("day"));
1011
+ const spansWeek = e.start.isBefore(weekStart.startOf("day")) && e.end.isAfter(weekEnd.endOf("day"));
1012
+ return startsInWeek || endsInWeek || spansWeek;
1013
+ });
1014
+ const multiDayEvents = weekEvents.filter((e) => e.end.diff(e.start, "day") > 0);
1015
+ const singleDayEvents = weekEvents.filter((e) => e.end.diff(e.start, "day") === 0);
1016
+ const sortedMultiDay = [...multiDayEvents].sort((a, b) => {
1017
+ const startDiff = a.start.diff(b.start);
1018
+ if (startDiff !== 0)
1019
+ return startDiff;
1020
+ return b.end.diff(b.start) - a.end.diff(a.start);
1021
+ });
1022
+ const sortedSingleDay = [...singleDayEvents].sort((a, b) => a.start.diff(b.start));
1023
+ const grid = [];
1024
+ for (let row = 0;row < dayMaxEvents; row++) {
1025
+ grid[row] = [];
1026
+ for (let col = 0;col < 7; col++) {
1027
+ grid[row][col] = { taken: false, event: null };
1028
+ }
1029
+ }
1030
+ const eventPositions = [];
1031
+ for (const event of sortedMultiDay) {
1032
+ const eventStart = dayjs_config_default.max(event.start.startOf("day"), weekStart);
1033
+ const eventEnd = dayjs_config_default.min(event.end.startOf("day"), weekEnd);
1034
+ const startCol = Math.max(0, eventStart.diff(weekStart, "day"));
1035
+ const endCol = Math.min(6, eventEnd.diff(weekStart, "day"));
1036
+ let placedSuccessfully = false;
1037
+ let assignedRow = -1;
1038
+ for (let row = 0;row < dayMaxEvents; row++) {
1039
+ let canPlace = true;
1040
+ for (let col = startCol;col <= endCol; col++) {
1041
+ if (grid[row][col].taken) {
1042
+ canPlace = false;
1043
+ break;
1044
+ }
1045
+ }
1046
+ if (canPlace) {
1047
+ assignedRow = row;
1048
+ break;
1049
+ }
1050
+ }
1051
+ if (assignedRow !== -1) {
1052
+ for (let col = startCol;col <= endCol; col++) {
1053
+ grid[assignedRow][col] = { taken: true, event };
1054
+ }
1055
+ const spanDays = endCol - startCol + 1;
1056
+ eventPositions.push({
1057
+ left: startCol / 7 * 100,
1058
+ width: spanDays / 7 * 100,
1059
+ top: DAY_NUMBER_HEIGHT + GAP_BETWEEN_ELEMENTS + assignedRow * (EVENT_BAR_HEIGHT + GAP_BETWEEN_ELEMENTS),
1060
+ height: EVENT_BAR_HEIGHT,
1061
+ position: assignedRow,
1062
+ ...event
1063
+ });
1064
+ placedSuccessfully = true;
1065
+ }
1066
+ if (!placedSuccessfully) {
1067
+ for (let tryStartCol = startCol + 1;tryStartCol <= endCol; tryStartCol++) {
1068
+ let truncatedAssignedRow = -1;
1069
+ for (let row = 0;row < dayMaxEvents; row++) {
1070
+ let canPlace = true;
1071
+ for (let col = tryStartCol;col <= endCol; col++) {
1072
+ if (grid[row][col].taken) {
1073
+ canPlace = false;
1074
+ break;
1075
+ }
1076
+ }
1077
+ if (canPlace) {
1078
+ truncatedAssignedRow = row;
1079
+ break;
1080
+ }
1081
+ }
1082
+ if (truncatedAssignedRow !== -1) {
1083
+ for (let col = tryStartCol;col <= endCol; col++) {
1084
+ grid[truncatedAssignedRow][col] = { taken: true, event };
1085
+ }
1086
+ const truncatedSpanDays = endCol - tryStartCol + 1;
1087
+ eventPositions.push({
1088
+ left: tryStartCol / 7 * 100,
1089
+ width: truncatedSpanDays / 7 * 100,
1090
+ top: DAY_NUMBER_HEIGHT + GAP_BETWEEN_ELEMENTS + truncatedAssignedRow * (EVENT_BAR_HEIGHT + GAP_BETWEEN_ELEMENTS),
1091
+ height: EVENT_BAR_HEIGHT,
1092
+ position: truncatedAssignedRow,
1093
+ ...event
1094
+ });
1095
+ placedSuccessfully = true;
1096
+ break;
1097
+ }
1098
+ }
1099
+ }
1100
+ }
1101
+ for (const event of sortedSingleDay) {
1102
+ const eventStart = dayjs_config_default.max(event.start.startOf("day"), weekStart);
1103
+ const col = Math.max(0, eventStart.diff(weekStart, "day"));
1104
+ let assignedRow = -1;
1105
+ for (let row = 0;row < dayMaxEvents; row++) {
1106
+ if (!grid[row][col].taken) {
1107
+ assignedRow = row;
1108
+ break;
1109
+ }
1110
+ }
1111
+ if (assignedRow !== -1) {
1112
+ grid[assignedRow][col] = { taken: true, event };
1113
+ eventPositions.push({
1114
+ left: col / 7 * 100,
1115
+ width: 1 / 7 * 100,
1116
+ top: DAY_NUMBER_HEIGHT + GAP_BETWEEN_ELEMENTS + assignedRow * (EVENT_BAR_HEIGHT + GAP_BETWEEN_ELEMENTS),
1117
+ height: EVENT_BAR_HEIGHT,
1118
+ position: assignedRow,
1119
+ ...event
1120
+ });
1121
+ }
1122
+ }
1123
+ return /* @__PURE__ */ jsxDEV29("div", {
1124
+ className: "relative w-full h-full pointer-events-none z-20 overflow-clip",
1125
+ children: eventPositions.map((event) => {
1126
+ return /* @__PURE__ */ jsxDEV29("div", {
1127
+ className: "absolute z-10 pointer-events-auto overflow-clip",
1128
+ style: {
1129
+ left: `calc(${event.left}% + var(--spacing) * 0.25)`,
1130
+ width: `calc(${event.width}% - var(--spacing) * 1)`,
1131
+ top: `${event.top}px`,
1132
+ height: `${EVENT_BAR_HEIGHT}px`
1133
+ },
1134
+ children: /* @__PURE__ */ jsxDEV29(DraggableEvent, {
1135
+ elementId: `event-${event.id}-${event.position}-${weekStart.format("YYYY-MM-DD")}`,
1136
+ event,
1137
+ className: "h-full w-full shadow"
1138
+ }, undefined, false, undefined, this)
1139
+ }, `event-${event.id}-${event.position}-${weekStart.format("YYYY-MM-DD")}`, false, undefined, this);
1140
+ })
1141
+ }, undefined, false, undefined, this);
1142
+ };
1143
+
1144
+ // src/features/month-view/components/month-view.tsx
1145
+ import { jsxDEV as jsxDEV30 } from "react/jsx-dev-runtime";
1146
+ var MonthView = ({ dayMaxEvents = 3 }) => {
1147
+ const allEventsDialogRef = React5.useRef(null);
1148
+ const { currentDate, firstDayOfWeek } = useCalendarContext();
1149
+ const firstDayOfMonth = currentDate.startOf("month");
1150
+ let adjustedFirstDayOfCalendar = firstDayOfMonth.clone();
1151
+ while (adjustedFirstDayOfCalendar.day() !== firstDayOfWeek) {
1152
+ adjustedFirstDayOfCalendar = adjustedFirstDayOfCalendar.subtract(1, "day");
1153
+ }
1154
+ const calendarDays = useMemo2(() => {
1155
+ const days = [[]];
1156
+ let day = adjustedFirstDayOfCalendar.clone();
1157
+ for (let i = 0;i < 42; i++) {
1158
+ if (days[days.length - 1].length === 7) {
1159
+ days.push([]);
1160
+ }
1161
+ days[days.length - 1].push(day);
1162
+ day = day.add(1, "day");
1163
+ }
1164
+ return days;
1165
+ }, [adjustedFirstDayOfCalendar]);
1166
+ return /* @__PURE__ */ jsxDEV30("div", {
1167
+ className: "flex h-full flex-col",
1168
+ "data-testid": "month-view",
1169
+ children: [
1170
+ /* @__PURE__ */ jsxDEV30(MonthHeader, {}, undefined, false, undefined, this),
1171
+ /* @__PURE__ */ jsxDEV30(ScrollArea, {
1172
+ className: "flex-1 overflow-auto",
1173
+ "data-testid": "month-scroll-area",
1174
+ children: /* @__PURE__ */ jsxDEV30(AnimatePresence3, {
1175
+ mode: "wait",
1176
+ children: /* @__PURE__ */ jsxDEV30(motion3.div, {
1177
+ initial: { opacity: 0 },
1178
+ animate: { opacity: 1 },
1179
+ exit: { opacity: 0 },
1180
+ transition: { duration: 0.25, ease: "easeInOut" },
1181
+ className: "relative grid flex-1 grid-cols-7 grid-rows-6 overflow-auto",
1182
+ "data-testid": "month-calendar-grid",
1183
+ children: calendarDays.map((days, index) => {
1184
+ return /* @__PURE__ */ jsxDEV30("div", {
1185
+ className: "relative col-span-7 grid grid-cols-7",
1186
+ "data-testid": `week-row-${index}`,
1187
+ children: [
1188
+ days.map((day, dayIndex) => {
1189
+ return /* @__PURE__ */ jsxDEV30(DayCell, {
1190
+ index: dayIndex,
1191
+ day,
1192
+ dayMaxEvents,
1193
+ className: "border-r border-b first:border-l"
1194
+ }, day.format("YYYY-MM-DD"), false, undefined, this);
1195
+ }),
1196
+ /* @__PURE__ */ jsxDEV30("div", {
1197
+ className: "absolute inset-0 z-10 pointer-events-none",
1198
+ children: /* @__PURE__ */ jsxDEV30(WeekEventsLayer, {
1199
+ days
1200
+ }, undefined, false, undefined, this)
1201
+ }, undefined, false, undefined, this)
1202
+ ]
1203
+ }, `week-${index}`, true, undefined, this);
1204
+ })
1205
+ }, currentDate.format("YYYY-MM-DD"), false, undefined, this)
1206
+ }, undefined, false, undefined, this)
1207
+ }, undefined, false, undefined, this),
1208
+ /* @__PURE__ */ jsxDEV30(AllEventDialog, {
1209
+ ref: allEventsDialogRef
1210
+ }, undefined, false, undefined, this)
1211
+ ]
1212
+ }, undefined, true, undefined, this);
1213
+ };
1214
+
1215
+ // src/features/week-view/week-view.tsx
1216
+ import dayjs9 from "dayjs";
1217
+ import weekOfYear2 from "dayjs/plugin/weekOfYear";
1218
+
1219
+ // src/features/week-view/week-all-day-row.tsx
1220
+ import { useMemo as useMemo3 } from "react";
1221
+ import { jsxDEV as jsxDEV31 } from "react/jsx-dev-runtime";
1222
+ var WeekAllDayRow = () => {
1223
+ const { currentDate, getEventsForDateRange, firstDayOfWeek } = useCalendarContext();
1224
+ const startOfWeek = currentDate.startOf("week").day(firstDayOfWeek);
1225
+ const adjustedStartOfWeek = currentDate.isBefore(startOfWeek) ? startOfWeek.subtract(1, "week") : startOfWeek;
1226
+ const endOfWeek = adjustedStartOfWeek.add(6, "day");
1227
+ const weekDays = [];
1228
+ for (let i = 0;i < 7; i++) {
1229
+ weekDays.push(adjustedStartOfWeek.add(i, "day"));
1230
+ }
1231
+ const expandedStartDate = adjustedStartOfWeek.subtract(6, "day");
1232
+ const expandedEndDate = endOfWeek.add(6, "day");
1233
+ const allEvents = getEventsForDateRange(expandedStartDate, expandedEndDate);
1234
+ const weekEvents = allEvents.filter((event) => {
1235
+ return event.start.isSameOrAfter(adjustedStartOfWeek) && event.start.isSameOrBefore(endOfWeek) || event.end.isSameOrAfter(adjustedStartOfWeek) && event.end.isSameOrBefore(endOfWeek) || event.start.isBefore(adjustedStartOfWeek) && event.end.isAfter(endOfWeek);
1236
+ });
1237
+ const allDayEvents = weekEvents.filter((event) => event.all_day);
1238
+ const { processedAllDayEvents } = useMemo3(() => {
1239
+ const sortedEvents = [...allDayEvents].sort((a, b) => {
1240
+ const startDiff = a.start.diff(b.start);
1241
+ if (startDiff !== 0)
1242
+ return startDiff;
1243
+ const aDuration = a.end.diff(a.start);
1244
+ const bDuration = b.end.diff(b.start);
1245
+ return bDuration - aDuration;
1246
+ });
1247
+ const rows = [];
1248
+ const processedEvents = [];
1249
+ sortedEvents.forEach((event) => {
1250
+ const eventStart = event.start.isBefore(adjustedStartOfWeek) ? adjustedStartOfWeek : event.start;
1251
+ const eventEnd = event.end.isAfter(endOfWeek) ? endOfWeek : event.end;
1252
+ const startDayIndex = Math.max(0, eventStart.diff(adjustedStartOfWeek, "day"));
1253
+ const endDayIndex = Math.min(6, eventEnd.diff(adjustedStartOfWeek, "day"));
1254
+ const left = startDayIndex / 7 * 100;
1255
+ const width = (endDayIndex - startDayIndex + 1) / 7 * 100;
1256
+ let rowIndex = 0;
1257
+ let placed = false;
1258
+ while (!placed) {
1259
+ if (rowIndex >= rows.length) {
1260
+ rows.push([]);
1261
+ placed = true;
1262
+ } else {
1263
+ const row = rows[rowIndex];
1264
+ const canFit = row.every((item) => {
1265
+ return eventStart.isAfter(item.end) || eventEnd.isBefore(item.event.start);
1266
+ });
1267
+ if (canFit) {
1268
+ placed = true;
1269
+ } else {
1270
+ rowIndex++;
1271
+ }
1272
+ }
1273
+ }
1274
+ rows[rowIndex].push({ end: eventEnd, event });
1275
+ processedEvents.push({
1276
+ ...event,
1277
+ left,
1278
+ width,
1279
+ top: rowIndex * (EVENT_BAR_HEIGHT + GAP_BETWEEN_ELEMENTS),
1280
+ height: EVENT_BAR_HEIGHT,
1281
+ all_day: true
1282
+ });
1283
+ });
1284
+ return {
1285
+ processedAllDayEvents: processedEvents,
1286
+ allDayRowsCount: Math.max(1, rows.length)
1287
+ };
1288
+ }, [allDayEvents, adjustedStartOfWeek, endOfWeek]);
1289
+ return /* @__PURE__ */ jsxDEV31("div", {
1290
+ className: "grid grid-cols-[auto_1fr_1fr_1fr_1fr_1fr_1fr_1fr] grid-rows-1 relative",
1291
+ "data-testid": "week-all-day-row",
1292
+ children: [
1293
+ /* @__PURE__ */ jsxDEV31("div", {
1294
+ className: "w-14 flex shrink-0 items-center justify-end border-x border-b pr-2 min-h-16",
1295
+ children: /* @__PURE__ */ jsxDEV31("span", {
1296
+ className: "text-muted-foreground text-[10px] whitespace-nowrap sm:text-xs",
1297
+ children: "All-day"
1298
+ }, undefined, false, undefined, this)
1299
+ }, undefined, false, undefined, this),
1300
+ weekDays.map((day) => /* @__PURE__ */ jsxDEV31(DroppableCell, {
1301
+ id: `all-day-cell-${day.format("YYYY-MM-DD")}`,
1302
+ type: "day-cell",
1303
+ date: day,
1304
+ className: "hover:bg-accent h-full flex-1 cursor-pointer border-r border-b"
1305
+ }, `all-day-${day.format("YYYY-MM-DD")}`, false, undefined, this)),
1306
+ /* @__PURE__ */ jsxDEV31("div", {
1307
+ className: "absolute inset-0 z-10 p-1 col-span-7 col-start-2",
1308
+ children: processedAllDayEvents.map((event, index) => /* @__PURE__ */ jsxDEV31("div", {
1309
+ className: "absolute",
1310
+ style: {
1311
+ left: `${event.left}%`,
1312
+ width: `calc(${event.width}% - var(--spacing) * 2)`,
1313
+ top: `${event.top}px`,
1314
+ height: `${event.height}px`
1315
+ },
1316
+ children: /* @__PURE__ */ jsxDEV31(DraggableEvent, {
1317
+ elementId: `all-day-${event.id}-${index}`,
1318
+ event,
1319
+ className: "h-full w-full overflow-clip text-xs absolute"
1320
+ }, `all-day-${event.id}-${index}`, false, undefined, this)
1321
+ }, `all-day-container-${event.id}`, false, undefined, this))
1322
+ }, undefined, false, undefined, this)
1323
+ ]
1324
+ }, undefined, true, undefined, this);
1325
+ };
1326
+
1327
+ // src/features/week-view/week-header.tsx
1328
+ import dayjs5 from "dayjs";
1329
+ import { AnimatePresence as AnimatePresence4, motion as motion4 } from "motion/react";
1330
+ import { jsxDEV as jsxDEV32 } from "react/jsx-dev-runtime";
1331
+ var WeekHeader = () => {
1332
+ const {
1333
+ currentDate,
1334
+ selectDate,
1335
+ openEventForm,
1336
+ firstDayOfWeek,
1337
+ stickyHeader
1338
+ } = useCalendarContext();
1339
+ const startOfWeek = currentDate.startOf("week").day(firstDayOfWeek);
1340
+ const adjustedStartOfWeek = currentDate.isBefore(startOfWeek) ? startOfWeek.subtract(1, "week") : startOfWeek;
1341
+ const weekDays = [];
1342
+ for (let i = 0;i < 7; i++) {
1343
+ weekDays.push(adjustedStartOfWeek.add(i, "day"));
1344
+ }
1345
+ return /* @__PURE__ */ jsxDEV32("div", {
1346
+ className: cn("grid grid-cols-[auto_1fr_1fr_1fr_1fr_1fr_1fr_1fr] grid-rows-1 bg-background", stickyHeader && "sticky top-0 z-100 shadow"),
1347
+ "data-testid": "week-header",
1348
+ children: [
1349
+ /* @__PURE__ */ jsxDEV32("div", {
1350
+ className: "col-span-1 w-14 shrink-0 items-center justify-center border-x border-b p-2",
1351
+ children: /* @__PURE__ */ jsxDEV32("div", {
1352
+ className: "flex flex-col items-center justify-center",
1353
+ children: [
1354
+ /* @__PURE__ */ jsxDEV32("span", {
1355
+ className: "text-muted-foreground text-xs",
1356
+ children: "Week"
1357
+ }, undefined, false, undefined, this),
1358
+ /* @__PURE__ */ jsxDEV32("span", {
1359
+ className: "font-medium",
1360
+ children: currentDate.week()
1361
+ }, undefined, false, undefined, this)
1362
+ ]
1363
+ }, undefined, true, undefined, this)
1364
+ }, undefined, false, undefined, this),
1365
+ weekDays.map((day, index) => {
1366
+ const isToday = day.isSame(dayjs5(), "day");
1367
+ return /* @__PURE__ */ jsxDEV32(AnimatePresence4, {
1368
+ mode: "wait",
1369
+ children: /* @__PURE__ */ jsxDEV32(motion4.div, {
1370
+ initial: { opacity: 0, y: -10 },
1371
+ animate: { opacity: 1, y: 0 },
1372
+ exit: { opacity: 0, y: -10 },
1373
+ transition: {
1374
+ duration: 0.25,
1375
+ ease: "easeInOut",
1376
+ delay: index * 0.05
1377
+ },
1378
+ className: cn("hover:bg-accent flex-1 cursor-pointer p-1 text-center sm:p-2 border-r border-b", isToday && "bg-primary/10 font-bold"),
1379
+ onClick: () => {
1380
+ selectDate(day);
1381
+ openEventForm(day);
1382
+ },
1383
+ "data-testid": `week-day-header-${day.format("dddd").toLowerCase()}`,
1384
+ children: [
1385
+ /* @__PURE__ */ jsxDEV32("div", {
1386
+ className: "text-xs sm:text-sm",
1387
+ children: day.format("ddd")
1388
+ }, undefined, false, undefined, this),
1389
+ /* @__PURE__ */ jsxDEV32("div", {
1390
+ className: cn("mx-auto mt-1 flex h-5 w-5 items-center justify-center rounded-full text-xs sm:h-7 sm:w-7 sm:text-sm", isToday && "bg-primary text-primary-foreground"),
1391
+ children: day.date()
1392
+ }, undefined, false, undefined, this)
1393
+ ]
1394
+ }, day.format("YYYY-MM-DD"), true, undefined, this)
1395
+ }, day.format("YYYY-MM-DD"), false, undefined, this);
1396
+ })
1397
+ ]
1398
+ }, undefined, true, undefined, this);
1399
+ };
1400
+
1401
+ // src/features/week-view/week-time-grid.tsx
1402
+ import dayjs8 from "dayjs";
1403
+
1404
+ // src/features/week-view/week-day-col.tsx
1405
+ import dayjs7 from "dayjs";
1406
+
1407
+ // src/hooks/useProcessedDayEvents.ts
1408
+ import dayjs6 from "dayjs";
1409
+ import { useMemo as useMemo4 } from "react";
1410
+ var useProcessedDayEvents = ({ day }) => {
1411
+ const { getEventsForDateRange } = useCalendarContext();
1412
+ const todayEvents = useMemo4(() => {
1413
+ let eventsForDay = getEventsForDateRange(day.startOf("day"), day.endOf("day"));
1414
+ eventsForDay = eventsForDay.filter((e) => !e.all_day).toSorted((a, b) => a.start.diff(b.start));
1415
+ if (eventsForDay.length === 0) {
1416
+ return [];
1417
+ }
1418
+ const clusters = [];
1419
+ let currentCluster = [];
1420
+ let lastEventEnd = null;
1421
+ for (const event of eventsForDay) {
1422
+ if (lastEventEnd && event.start.isSameOrAfter(lastEventEnd)) {
1423
+ if (currentCluster.length > 0) {
1424
+ clusters.push(currentCluster);
1425
+ }
1426
+ currentCluster = [];
1427
+ }
1428
+ currentCluster.push(event);
1429
+ lastEventEnd = lastEventEnd ? dayjs6.max(lastEventEnd, event.end) : event.end;
1430
+ }
1431
+ if (currentCluster.length > 0) {
1432
+ clusters.push(currentCluster);
1433
+ }
1434
+ const processedEvents = [];
1435
+ for (const cluster of clusters) {
1436
+ if (cluster.length === 1) {
1437
+ const event = cluster[0];
1438
+ const startTime = event.start.hour() + event.start.minute() / 60;
1439
+ let endTime = event.end.hour() + event.end.minute() / 60;
1440
+ if (endTime < startTime) {
1441
+ endTime = 24;
1442
+ }
1443
+ const totalDuration = endTime - startTime;
1444
+ const top = startTime / 24 * 100;
1445
+ const height = totalDuration / 24 * 100;
1446
+ processedEvents.push({ ...event, left: 0, width: 100, top, height });
1447
+ continue;
1448
+ }
1449
+ const sortedEvents = [...cluster].sort((a, b) => {
1450
+ const aDuration = a.end.diff(a.start, "minute");
1451
+ const bDuration = b.end.diff(b.start, "minute");
1452
+ if (aDuration !== bDuration) {
1453
+ return bDuration - aDuration;
1454
+ }
1455
+ return a.start.diff(b.start);
1456
+ });
1457
+ const totalEvents = sortedEvents.length;
1458
+ let maxOffset;
1459
+ if (totalEvents === 2) {
1460
+ maxOffset = 25;
1461
+ } else if (totalEvents === 3) {
1462
+ maxOffset = 50;
1463
+ } else if (totalEvents === 4) {
1464
+ maxOffset = 60;
1465
+ } else {
1466
+ maxOffset = 70;
1467
+ }
1468
+ const offsetPerEvent = totalEvents > 1 ? maxOffset / (totalEvents - 1) : 0;
1469
+ for (let i = 0;i < sortedEvents.length; i++) {
1470
+ const event = sortedEvents[i];
1471
+ const startTime = event.start.hour() + event.start.minute() / 60;
1472
+ let endTime = event.end.hour() + event.end.minute() / 60;
1473
+ if (endTime < startTime) {
1474
+ endTime = 24;
1475
+ }
1476
+ const totalDuration = endTime - startTime;
1477
+ const top = startTime / 24 * 100;
1478
+ const height = totalDuration / 24 * 100;
1479
+ let left;
1480
+ let width;
1481
+ let zIndex;
1482
+ if (i === 0) {
1483
+ left = 0;
1484
+ width = 100;
1485
+ zIndex = 1;
1486
+ } else {
1487
+ left = offsetPerEvent * i;
1488
+ width = 100 - left;
1489
+ zIndex = i + 1;
1490
+ }
1491
+ processedEvents.push({
1492
+ ...event,
1493
+ left,
1494
+ width,
1495
+ top,
1496
+ height,
1497
+ zIndex
1498
+ });
1499
+ }
1500
+ }
1501
+ return processedEvents;
1502
+ }, [day, getEventsForDateRange]);
1503
+ return todayEvents;
1504
+ };
1505
+
1506
+ // src/features/day-view/day-events-layer.tsx
1507
+ import { jsxDEV as jsxDEV33 } from "react/jsx-dev-runtime";
1508
+ var DayEventsLayer = ({
1509
+ day,
1510
+ "data-testid": dataTestId
1511
+ }) => {
1512
+ const todayEvents = useProcessedDayEvents({ day });
1513
+ return /* @__PURE__ */ jsxDEV33("div", {
1514
+ "data-testid": dataTestId,
1515
+ className: "pointer-events-none absolute inset-0 z-30",
1516
+ children: todayEvents.map((event, index) => {
1517
+ const veryVeryUniqueKey = `event-${event.id}-${index}-${day.format("YYYY-MM-DD")}`;
1518
+ const isShortEvent = event.end.diff(event.start, "minute") <= 15;
1519
+ return /* @__PURE__ */ jsxDEV33("div", {
1520
+ className: "absolute",
1521
+ style: {
1522
+ left: `${event.left}%`,
1523
+ width: `calc(${event.width}% - var(--spacing) * 2)`,
1524
+ top: `${event.top}%`,
1525
+ height: `${event.height}%`
1526
+ },
1527
+ children: /* @__PURE__ */ jsxDEV33(DraggableEvent, {
1528
+ elementId: `draggable-${veryVeryUniqueKey}`,
1529
+ event,
1530
+ className: cn("pointer-events-auto absolute", {
1531
+ "[&_p]:text-[10px] [&_p]:mt-0": isShortEvent
1532
+ })
1533
+ }, undefined, false, undefined, this)
1534
+ }, `container-${veryVeryUniqueKey}`, false, undefined, this);
1535
+ })
1536
+ }, undefined, false, undefined, this);
1537
+ };
1538
+
1539
+ // src/features/week-view/week-day-col.tsx
1540
+ import { jsxDEV as jsxDEV34 } from "react/jsx-dev-runtime";
1541
+ var hours = Array.from({ length: 24 }, (_, i) => i).map((hour) => dayjs7().hour(hour).minute(0));
1542
+ var WeekDayCol = ({ day }) => {
1543
+ return /* @__PURE__ */ jsxDEV34("div", {
1544
+ "data-testid": `week-day-col-${day.format("YYYY-MM-DD")}`,
1545
+ className: "col-span-1 relative grid grid-rows-24 border-r",
1546
+ children: [
1547
+ hours.map((time) => {
1548
+ const hour = time.hour();
1549
+ const cellDate = day.format("YYYY-MM-DD");
1550
+ return /* @__PURE__ */ jsxDEV34(DroppableCell, {
1551
+ id: `time-cell-${cellDate}-${time.format("HH")}`,
1552
+ type: "time-cell",
1553
+ date: day,
1554
+ hour,
1555
+ "data-testid": `week-time-cell-${cellDate}-${time.format("HH")}`,
1556
+ className: cn("hover:bg-accent relative z-20 h-[60px] cursor-pointer border-b")
1557
+ }, `${cellDate}-${time.format("HH")}`, false, undefined, this);
1558
+ }),
1559
+ /* @__PURE__ */ jsxDEV34(DayEventsLayer, {
1560
+ "data-testid": `week-day-events-${day.format("YYYY-MM-DD")}`,
1561
+ day
1562
+ }, undefined, false, undefined, this)
1563
+ ]
1564
+ }, undefined, true, undefined, this);
1565
+ };
1566
+
1567
+ // src/features/week-view/week-time-grid.tsx
1568
+ import { jsxDEV as jsxDEV35 } from "react/jsx-dev-runtime";
1569
+ var hours2 = Array.from({ length: 24 }, (_, i) => i).map((hour) => dayjs8().hour(hour).minute(0));
1570
+ var WeekTimeGrid = () => {
1571
+ const { currentDate, firstDayOfWeek } = useCalendarContext();
1572
+ const startOfWeek = currentDate.startOf("week").day(firstDayOfWeek);
1573
+ const adjustedStartOfWeek = currentDate.isBefore(startOfWeek) ? startOfWeek.subtract(1, "week") : startOfWeek;
1574
+ const weekDays = [];
1575
+ for (let i = 0;i < 7; i++) {
1576
+ weekDays.push(adjustedStartOfWeek.add(i, "day"));
1577
+ }
1578
+ const todayIndex = weekDays.findIndex((day) => day.isSame(dayjs8(), "day"));
1579
+ const isCurrentWeek = todayIndex !== -1;
1580
+ return /* @__PURE__ */ jsxDEV35("div", {
1581
+ "data-testid": "week-time-grid",
1582
+ className: "relative h-full grid grid-cols-[auto_repeat(7,1fr)] grid-rows-[repeat(24,minmax(60px, 1fr))]",
1583
+ children: [
1584
+ /* @__PURE__ */ jsxDEV35("div", {
1585
+ "data-testid": "week-time-labels",
1586
+ className: "z-10 col-span-1 w-14 grid grid-rows-24 border-x",
1587
+ children: hours2.map((time) => /* @__PURE__ */ jsxDEV35("div", {
1588
+ "data-testid": `week-time-hour-${time.format("HH")}`,
1589
+ className: "h-[60px] border-b text-right",
1590
+ children: /* @__PURE__ */ jsxDEV35("span", {
1591
+ className: "text-muted-foreground pr-2 text-right text-[10px] sm:text-xs",
1592
+ children: time.format("h A")
1593
+ }, undefined, false, undefined, this)
1594
+ }, time.format("HH:mm"), false, undefined, this))
1595
+ }, undefined, false, undefined, this),
1596
+ weekDays.map((day) => /* @__PURE__ */ jsxDEV35(WeekDayCol, {
1597
+ day
1598
+ }, day.format("YYYY-MM-DD"), false, undefined, this)),
1599
+ isCurrentWeek && /* @__PURE__ */ jsxDEV35("div", {
1600
+ "data-testid": "week-current-time-indicator",
1601
+ className: "pointer-events-none absolute z-20",
1602
+ style: {
1603
+ top: `${(dayjs8().hour() + dayjs8().minute() / 60) * 60}px`,
1604
+ left: `${todayIndex * (100 / 7)}%`,
1605
+ width: `${100 / 7}%`
1606
+ },
1607
+ children: /* @__PURE__ */ jsxDEV35("div", {
1608
+ className: "w-full border-t border-red-500",
1609
+ children: /* @__PURE__ */ jsxDEV35("div", {
1610
+ className: "-mt-1 ml-1 h-2 w-2 rounded-full bg-red-500"
1611
+ }, undefined, false, undefined, this)
1612
+ }, undefined, false, undefined, this)
1613
+ }, undefined, false, undefined, this)
1614
+ ]
1615
+ }, undefined, true, undefined, this);
1616
+ };
1617
+
1618
+ // src/features/week-view/week-view.tsx
1619
+ import { jsxDEV as jsxDEV36 } from "react/jsx-dev-runtime";
1620
+ dayjs9.extend(weekOfYear2);
1621
+ var WeekView = () => {
1622
+ return /* @__PURE__ */ jsxDEV36("div", {
1623
+ className: "flex h-full flex-col",
1624
+ "data-testid": "week-view",
1625
+ children: [
1626
+ /* @__PURE__ */ jsxDEV36(WeekHeader, {}, undefined, false, undefined, this),
1627
+ /* @__PURE__ */ jsxDEV36(ScrollArea, {
1628
+ className: "flex flex-1 overflow-auto",
1629
+ "data-testid": "week-scroll-area",
1630
+ children: [
1631
+ /* @__PURE__ */ jsxDEV36(WeekAllDayRow, {}, undefined, false, undefined, this),
1632
+ /* @__PURE__ */ jsxDEV36(WeekTimeGrid, {}, undefined, false, undefined, this)
1633
+ ]
1634
+ }, undefined, true, undefined, this)
1635
+ ]
1636
+ }, undefined, true, undefined, this);
1637
+ };
1638
+ var week_view_default = WeekView;
1639
+
1640
+ // src/features/day-view/day-view.tsx
1641
+ import dayjs12 from "dayjs";
1642
+ import { Fragment as Fragment2 } from "react";
1643
+
1644
+ // src/features/day-view/day-all-day-row.tsx
1645
+ import { useMemo as useMemo5 } from "react";
1646
+ import { jsxDEV as jsxDEV37 } from "react/jsx-dev-runtime";
1647
+ var DayAllDayRow = () => {
1648
+ const { currentDate, getEventsForDate } = useCalendarContext();
1649
+ const dayEvents = getEventsForDate(currentDate);
1650
+ const { allDayEvents } = useMemo5(() => {
1651
+ const allDayEvts = dayEvents.filter((event) => event.all_day);
1652
+ const regularEvts = dayEvents.filter((event) => !event.all_day);
1653
+ return { allDayEvents: allDayEvts, regularEvents: regularEvts };
1654
+ }, [dayEvents]);
1655
+ const { processedAllDayEvents } = useMemo5(() => {
1656
+ const sortedEvents = [...allDayEvents].sort((a, b) => {
1657
+ return a.start.diff(b.start);
1658
+ });
1659
+ const rows = [];
1660
+ const processedEvents = [];
1661
+ sortedEvents.forEach((event, rowIndex) => {
1662
+ let placed = false;
1663
+ while (!placed) {
1664
+ if (rowIndex >= rows.length) {
1665
+ rows.push([]);
1666
+ placed = true;
1667
+ } else {
1668
+ placed = true;
1669
+ }
1670
+ }
1671
+ rows[rowIndex].push({ event });
1672
+ processedEvents.push({
1673
+ ...event,
1674
+ left: 0,
1675
+ width: 100,
1676
+ top: rowIndex * EVENT_BAR_HEIGHT,
1677
+ height: EVENT_BAR_HEIGHT,
1678
+ all_day: true
1679
+ });
1680
+ });
1681
+ return {
1682
+ processedAllDayEvents: processedEvents,
1683
+ allDayRowsCount: Math.max(1, rows.length)
1684
+ };
1685
+ }, [allDayEvents]);
1686
+ return /* @__PURE__ */ jsxDEV37("div", {
1687
+ "data-testid": "day-all-day-row",
1688
+ className: "grid grid-cols-8 border-b border-x",
1689
+ children: [
1690
+ /* @__PURE__ */ jsxDEV37("div", {
1691
+ className: "col-span-2 flex shrink-0 items-center justify-end border-r pr-2 md:col-span-1",
1692
+ children: /* @__PURE__ */ jsxDEV37("span", {
1693
+ className: "text-muted-foreground text-[10px] whitespace-nowrap sm:text-xs",
1694
+ children: "All-day"
1695
+ }, undefined, false, undefined, this)
1696
+ }, undefined, false, undefined, this),
1697
+ /* @__PURE__ */ jsxDEV37("div", {
1698
+ className: "relative col-span-6 md:col-span-7 ",
1699
+ children: /* @__PURE__ */ jsxDEV37(DroppableCell, {
1700
+ id: `all-day-${currentDate.format("YYYY-MM-DD")}`,
1701
+ type: "day-cell",
1702
+ date: currentDate,
1703
+ className: "hover:bg-accent w-full cursor-pointer min-h-10 flex flex-col",
1704
+ children: processedAllDayEvents.map((event, index) => {
1705
+ return /* @__PURE__ */ jsxDEV37("div", {
1706
+ style: { height: EVENT_BAR_HEIGHT + "px" },
1707
+ children: /* @__PURE__ */ jsxDEV37(DraggableEvent, {
1708
+ elementId: `all-day-${event.id}-${index}`,
1709
+ event,
1710
+ className: "overflow-clip text-xs",
1711
+ style: { width: `calc(100% - var(--spacing) * 2)` }
1712
+ }, undefined, false, undefined, this)
1713
+ }, `all-day-${event.id}-${index}`, false, undefined, this);
1714
+ })
1715
+ }, undefined, false, undefined, this)
1716
+ }, undefined, false, undefined, this)
1717
+ ]
1718
+ }, undefined, true, undefined, this);
1719
+ };
1720
+
1721
+ // src/features/day-view/day-header.tsx
1722
+ import { AnimatePresence as AnimatePresence5, motion as motion5 } from "motion/react";
1723
+ import dayjs10 from "dayjs";
1724
+ import { jsxDEV as jsxDEV38 } from "react/jsx-dev-runtime";
1725
+ var DayHeader = () => {
1726
+ const { currentDate, stickyHeader } = useCalendarContext();
1727
+ const isToday = currentDate.isSame(dayjs10(), "day");
1728
+ return /* @__PURE__ */ jsxDEV38("div", {
1729
+ "data-testid": "day-header",
1730
+ className: cn("flex items-center justify-center border-b p-2 border-x bg-background", stickyHeader && "sticky top-0 z-100 shadow"),
1731
+ children: /* @__PURE__ */ jsxDEV38(AnimatePresence5, {
1732
+ mode: "wait",
1733
+ children: /* @__PURE__ */ jsxDEV38(motion5.div, {
1734
+ initial: { opacity: 0, y: -10 },
1735
+ animate: { opacity: 1, y: 0 },
1736
+ exit: { opacity: 0, y: -10 },
1737
+ transition: { duration: 0.25, ease: "easeInOut" },
1738
+ className: cn("flex items-center text-center text-base font-semibold sm:text-xl", isToday && "text-primary"),
1739
+ children: [
1740
+ /* @__PURE__ */ jsxDEV38("span", {
1741
+ className: "xs:inline hidden",
1742
+ children: currentDate.format("dddd, ")
1743
+ }, undefined, false, undefined, this),
1744
+ currentDate.format("MMMM D, YYYY"),
1745
+ isToday && /* @__PURE__ */ jsxDEV38("span", {
1746
+ className: "bg-primary text-primary-foreground ml-2 rounded-full px-1 py-0.5 text-xs sm:px-2 sm:text-sm",
1747
+ children: "Today"
1748
+ }, undefined, false, undefined, this)
1749
+ ]
1750
+ }, currentDate.format("YYYY-MM-DD"), true, undefined, this)
1751
+ }, undefined, false, undefined, this)
1752
+ }, undefined, false, undefined, this);
1753
+ };
1754
+
1755
+ // src/features/day-view/day-time-col.tsx
1756
+ import dayjs11 from "dayjs";
1757
+ import { jsxDEV as jsxDEV39 } from "react/jsx-dev-runtime";
1758
+ var hours3 = Array.from({ length: 24 }, (_, i) => i).map((hour) => {
1759
+ return dayjs11().hour(hour).minute(0);
1760
+ });
1761
+ var DayTimeCol = ({ className }) => {
1762
+ return /* @__PURE__ */ jsxDEV39("div", {
1763
+ "data-testid": "day-time-col",
1764
+ className: `col-span-2 h-full md:col-span-1 ${className}`,
1765
+ children: hours3.map((time) => /* @__PURE__ */ jsxDEV39("div", {
1766
+ "data-testid": `day-time-hour-${time.format("HH")}`,
1767
+ className: "h-[60px] border-b text-right",
1768
+ children: /* @__PURE__ */ jsxDEV39("span", {
1769
+ className: "text-muted-foreground pr-2 text-right text-[10px] sm:text-xs",
1770
+ children: time.format("h A")
1771
+ }, undefined, false, undefined, this)
1772
+ }, time.format("HH:mm"), false, undefined, this))
1773
+ }, undefined, false, undefined, this);
1774
+ };
1775
+
1776
+ // src/features/day-view/day-view.tsx
1777
+ import { jsxDEV as jsxDEV40 } from "react/jsx-dev-runtime";
1778
+ var DayView = () => {
1779
+ const { currentDate } = useCalendarContext();
1780
+ const hours4 = Array.from({ length: 24 }, (_, i) => i).map((hour) => {
1781
+ return dayjs12().hour(hour).minute(0);
1782
+ });
1783
+ const timeSegments = [0, 15, 30, 45];
1784
+ const isToday = currentDate.isSame(dayjs12(), "day");
1785
+ const cellDate = currentDate.format("YYYY-MM-DD");
1786
+ return /* @__PURE__ */ jsxDEV40("div", {
1787
+ "data-testid": "day-view",
1788
+ className: "flex h-full flex-col",
1789
+ children: [
1790
+ /* @__PURE__ */ jsxDEV40(DayHeader, {}, undefined, false, undefined, this),
1791
+ /* @__PURE__ */ jsxDEV40(ScrollArea, {
1792
+ "data-testid": "day-scroll-area",
1793
+ className: "relative flex-1 overflow-y-auto",
1794
+ children: [
1795
+ /* @__PURE__ */ jsxDEV40(DayAllDayRow, {}, undefined, false, undefined, this),
1796
+ /* @__PURE__ */ jsxDEV40("div", {
1797
+ "data-testid": "day-time-grid",
1798
+ className: "grid grid-cols-8 divide-x border-x",
1799
+ style: { height: `${hours4.length * 60}px` },
1800
+ children: [
1801
+ /* @__PURE__ */ jsxDEV40(DayTimeCol, {
1802
+ className: "col-span-2 h-full md:col-span-1"
1803
+ }, undefined, false, undefined, this),
1804
+ /* @__PURE__ */ jsxDEV40("div", {
1805
+ "data-testid": "day-events-column",
1806
+ className: "relative col-span-6 h-full md:col-span-7",
1807
+ children: [
1808
+ /* @__PURE__ */ jsxDEV40("div", {
1809
+ "data-testid": "day-background-grid",
1810
+ className: "absolute inset-0 z-0",
1811
+ children: hours4.map((hour, index) => /* @__PURE__ */ jsxDEV40("div", {
1812
+ className: "h-[60px] border-b",
1813
+ children: timeSegments.slice(1).map((minutes) => /* @__PURE__ */ jsxDEV40("div", {
1814
+ className: "border-border absolute w-full border-t border-dashed",
1815
+ style: { top: `${index * 60 + minutes}px` }
1816
+ }, `bg-${hour.format("HH")}-${minutes}`, false, undefined, this))
1817
+ }, `bg-${currentDate.format("YYYY-MM-DD")}-${hour.format("HH")}`, false, undefined, this))
1818
+ }, undefined, false, undefined, this),
1819
+ /* @__PURE__ */ jsxDEV40("div", {
1820
+ "data-testid": "day-interactive-layer",
1821
+ className: "pointer-events-auto absolute inset-0 z-20",
1822
+ children: hours4.map((time) => {
1823
+ const hour = time.hour();
1824
+ return /* @__PURE__ */ jsxDEV40(Fragment2, {
1825
+ children: [
1826
+ /* @__PURE__ */ jsxDEV40(DroppableCell, {
1827
+ id: `time-cell-${cellDate}-${time.format("HH")}-00`,
1828
+ type: "time-cell",
1829
+ date: currentDate,
1830
+ hour,
1831
+ minute: 0,
1832
+ className: cn("hover:bg-accent h-[15px] cursor-pointer")
1833
+ }, undefined, false, undefined, this),
1834
+ /* @__PURE__ */ jsxDEV40(DroppableCell, {
1835
+ id: `time-cell-${cellDate}-${time.format("HH")}-15`,
1836
+ type: "time-cell",
1837
+ date: currentDate,
1838
+ hour,
1839
+ minute: 15,
1840
+ className: "hover:bg-accent h-[15px] cursor-pointer"
1841
+ }, undefined, false, undefined, this),
1842
+ /* @__PURE__ */ jsxDEV40(DroppableCell, {
1843
+ id: `time-cell-${cellDate}-${time.format("HH")}-30`,
1844
+ type: "time-cell",
1845
+ date: currentDate,
1846
+ hour,
1847
+ minute: 30,
1848
+ className: "hover:bg-accent h-[15px] cursor-pointer"
1849
+ }, undefined, false, undefined, this),
1850
+ /* @__PURE__ */ jsxDEV40(DroppableCell, {
1851
+ id: `time-cell-${cellDate}-${time.format("HH")}-45`,
1852
+ type: "time-cell",
1853
+ date: currentDate,
1854
+ hour,
1855
+ minute: 45,
1856
+ className: "hover:bg-accent h-[15px] cursor-pointer"
1857
+ }, undefined, false, undefined, this)
1858
+ ]
1859
+ }, `${cellDate}-${time.format("HH")}`, true, undefined, this);
1860
+ })
1861
+ }, undefined, false, undefined, this),
1862
+ /* @__PURE__ */ jsxDEV40(DayEventsLayer, {
1863
+ day: currentDate
1864
+ }, undefined, false, undefined, this),
1865
+ isToday && /* @__PURE__ */ jsxDEV40("div", {
1866
+ "data-testid": "day-current-time-indicator",
1867
+ className: "absolute right-0 left-0 z-40 border-t border-red-500",
1868
+ style: {
1869
+ top: `${(dayjs12().hour() + dayjs12().minute() / 60) * 60}px`
1870
+ },
1871
+ children: /* @__PURE__ */ jsxDEV40("div", {
1872
+ className: "-mt-1 -ml-1 h-2 w-2 rounded-full bg-red-500"
1873
+ }, undefined, false, undefined, this)
1874
+ }, undefined, false, undefined, this)
1875
+ ]
1876
+ }, undefined, true, undefined, this)
1877
+ ]
1878
+ }, undefined, true, undefined, this)
1879
+ ]
1880
+ }, undefined, true, undefined, this)
1881
+ ]
1882
+ }, undefined, true, undefined, this);
1883
+ };
1884
+ var day_view_default = DayView;
1885
+
1886
+ // src/components/event-form/event-form.tsx
1887
+ import dayjs13 from "dayjs";
1888
+ import { useEffect, useState as useState2 } from "react";
1889
+ import { jsxDEV as jsxDEV41 } from "react/jsx-dev-runtime";
1890
+ var colorOptions = [
1891
+ { value: "bg-blue-100 text-blue-800", label: "Blue" },
1892
+ { value: "bg-green-100 text-green-800", label: "Green" },
1893
+ { value: "bg-purple-100 text-purple-800", label: "Purple" },
1894
+ { value: "bg-red-100 text-red-800", label: "Red" },
1895
+ { value: "bg-yellow-100 text-yellow-800", label: "Yellow" },
1896
+ { value: "bg-pink-100 text-pink-800", label: "Pink" },
1897
+ { value: "bg-indigo-100 text-indigo-800", label: "Indigo" },
1898
+ { value: "bg-amber-100 text-amber-800", label: "Amber" },
1899
+ { value: "bg-emerald-100 text-emerald-800", label: "Emerald" },
1900
+ { value: "bg-sky-100 text-sky-800", label: "Sky" },
1901
+ { value: "bg-violet-100 text-violet-800", label: "Violet" },
1902
+ { value: "bg-rose-100 text-rose-800", label: "Rose" },
1903
+ { value: "bg-teal-100 text-teal-800", label: "Teal" },
1904
+ { value: "bg-orange-100 text-orange-800", label: "Orange" }
1905
+ ];
1906
+ var EventForm = ({
1907
+ selectedEvent,
1908
+ selectedDate,
1909
+ onClose,
1910
+ onUpdate,
1911
+ onDelete,
1912
+ onAdd
1913
+ }) => {
1914
+ const start = selectedEvent?.originalStart ?? selectedEvent?.start;
1915
+ const end = selectedEvent?.originalEnd ?? selectedEvent?.end;
1916
+ const defaultStartDate = selectedDate?.toDate() || new Date;
1917
+ const defaultEndDate = selectedDate?.add(1, "hour").toDate() || dayjs13().add(1, "hour").toDate();
1918
+ const [startDate, setStartDate] = useState2(start?.toDate() || defaultStartDate);
1919
+ const [endDate, setEndDate] = useState2(end?.toDate() || defaultEndDate);
1920
+ const [isAllDay, setIsAllDay] = useState2(selectedEvent?.all_day || false);
1921
+ const [selectedColor, setSelectedColor] = useState2(selectedEvent?.color || colorOptions[0].value);
1922
+ const [startTime, setStartTime] = useState2(selectedEvent ? selectedEvent.start.format("HH:mm") : dayjs13(defaultStartDate).format("HH:mm"));
1923
+ const [endTime, setEndTime] = useState2(selectedEvent ? selectedEvent.end.format("HH:mm") : dayjs13(defaultEndDate).format("HH:mm"));
1924
+ const [formValues, setFormValues] = useState2({
1925
+ title: selectedEvent?.title || "",
1926
+ description: selectedEvent?.description || "",
1927
+ location: selectedEvent?.location || ""
1928
+ });
1929
+ const handleStartDateChange = (date) => {
1930
+ if (date)
1931
+ setStartDate(date);
1932
+ };
1933
+ const handleEndDateChange = (date) => {
1934
+ if (date)
1935
+ setEndDate(date);
1936
+ };
1937
+ const handleInputChange = (e) => {
1938
+ const { name, value } = e.target;
1939
+ setFormValues((prev) => ({ ...prev, [name]: value }));
1940
+ };
1941
+ const handleTimeChange = (e, isStart) => {
1942
+ const timeValue = e.target.value;
1943
+ if (isStart) {
1944
+ setStartTime(timeValue);
1945
+ } else {
1946
+ setEndTime(timeValue);
1947
+ }
1948
+ };
1949
+ useEffect(() => {
1950
+ if (isAllDay) {
1951
+ setEndTime("23:59");
1952
+ }
1953
+ }, [isAllDay]);
1954
+ const handleSubmit = (e) => {
1955
+ e.preventDefault();
1956
+ const [startHours, startMinutes] = startTime.split(":").map(Number);
1957
+ const [endHours, endMinutes] = endTime.split(":").map(Number);
1958
+ let startDateTime = dayjs13(startDate).hour(startHours).minute(startMinutes);
1959
+ let endDateTime = dayjs13(endDate).hour(endHours).minute(endMinutes);
1960
+ if (isAllDay) {
1961
+ startDateTime = startDateTime.hour(0).minute(0);
1962
+ endDateTime = endDateTime.hour(23).minute(59);
1963
+ }
1964
+ const eventData = {
1965
+ id: selectedEvent?.id || dayjs13().format("YYYYMMDDHHmmss"),
1966
+ title: formValues.title,
1967
+ start: startDateTime,
1968
+ end: endDateTime,
1969
+ description: formValues.description,
1970
+ location: formValues.location,
1971
+ all_day: isAllDay,
1972
+ color: selectedColor
1973
+ };
1974
+ if (selectedEvent.id) {
1975
+ onUpdate?.(eventData);
1976
+ } else {
1977
+ onAdd?.(eventData);
1978
+ }
1979
+ onClose();
1980
+ };
1981
+ const handleDelete = () => {
1982
+ if (selectedEvent.id) {
1983
+ onDelete?.(selectedEvent);
1984
+ onClose();
1985
+ }
1986
+ };
1987
+ useEffect(() => {
1988
+ if (dayjs13(startDate).isAfter(dayjs13(endDate))) {
1989
+ setEndDate(startDate);
1990
+ }
1991
+ }, [startDate, endDate]);
1992
+ return /* @__PURE__ */ jsxDEV41(Dialog, {
1993
+ open: true,
1994
+ onOpenChange: onClose,
1995
+ children: /* @__PURE__ */ jsxDEV41(DialogContent, {
1996
+ className: "w-[90vw] max-w-[500px] p-4 sm:p-6",
1997
+ children: /* @__PURE__ */ jsxDEV41("form", {
1998
+ onSubmit: handleSubmit,
1999
+ children: [
2000
+ /* @__PURE__ */ jsxDEV41(DialogHeader, {
2001
+ className: "mb-2 sm:mb-4",
2002
+ children: [
2003
+ /* @__PURE__ */ jsxDEV41(DialogTitle, {
2004
+ className: "text-base sm:text-lg",
2005
+ children: selectedEvent.id ? "Edit Event" : "Create Event"
2006
+ }, undefined, false, undefined, this),
2007
+ /* @__PURE__ */ jsxDEV41(DialogDescription, {
2008
+ className: "text-xs sm:text-sm",
2009
+ children: selectedEvent.id ? "Edit your event details" : "Add a new event to your calendar"
2010
+ }, undefined, false, undefined, this)
2011
+ ]
2012
+ }, undefined, true, undefined, this),
2013
+ /* @__PURE__ */ jsxDEV41("div", {
2014
+ className: "grid gap-3 py-2 sm:gap-4 sm:py-4",
2015
+ children: [
2016
+ /* @__PURE__ */ jsxDEV41("div", {
2017
+ className: "grid gap-2",
2018
+ children: [
2019
+ /* @__PURE__ */ jsxDEV41(Label2, {
2020
+ htmlFor: "title",
2021
+ className: "text-xs sm:text-sm",
2022
+ children: "Title"
2023
+ }, undefined, false, undefined, this),
2024
+ /* @__PURE__ */ jsxDEV41(Input, {
2025
+ id: "title",
2026
+ name: "title",
2027
+ value: formValues.title,
2028
+ onChange: handleInputChange,
2029
+ placeholder: "Event title",
2030
+ required: true,
2031
+ autoFocus: true,
2032
+ className: "h-8 text-sm sm:h-9"
2033
+ }, undefined, false, undefined, this)
2034
+ ]
2035
+ }, undefined, true, undefined, this),
2036
+ /* @__PURE__ */ jsxDEV41("div", {
2037
+ className: "flex items-center space-x-2",
2038
+ children: [
2039
+ /* @__PURE__ */ jsxDEV41(Checkbox, {
2040
+ id: "all_day",
2041
+ checked: isAllDay,
2042
+ onCheckedChange: (checked) => setIsAllDay(checked === true)
2043
+ }, undefined, false, undefined, this),
2044
+ /* @__PURE__ */ jsxDEV41(Label2, {
2045
+ htmlFor: "all_day",
2046
+ className: "text-xs sm:text-sm",
2047
+ children: "All day"
2048
+ }, undefined, false, undefined, this)
2049
+ ]
2050
+ }, undefined, true, undefined, this),
2051
+ /* @__PURE__ */ jsxDEV41("div", {
2052
+ className: "grid grid-cols-2 gap-2 sm:gap-4",
2053
+ children: [
2054
+ /* @__PURE__ */ jsxDEV41("div", {
2055
+ children: [
2056
+ /* @__PURE__ */ jsxDEV41(Label2, {
2057
+ className: "text-xs sm:text-sm",
2058
+ children: "Start Date"
2059
+ }, undefined, false, undefined, this),
2060
+ /* @__PURE__ */ jsxDEV41(DatePicker, {
2061
+ date: startDate,
2062
+ setDate: handleStartDateChange,
2063
+ className: "mt-1",
2064
+ closeOnSelect: true
2065
+ }, undefined, false, undefined, this)
2066
+ ]
2067
+ }, undefined, true, undefined, this),
2068
+ /* @__PURE__ */ jsxDEV41("div", {
2069
+ children: [
2070
+ /* @__PURE__ */ jsxDEV41(Label2, {
2071
+ className: "text-xs sm:text-sm",
2072
+ children: "End Date"
2073
+ }, undefined, false, undefined, this),
2074
+ /* @__PURE__ */ jsxDEV41(DatePicker, {
2075
+ date: endDate,
2076
+ setDate: handleEndDateChange,
2077
+ className: "mt-1",
2078
+ closeOnSelect: true
2079
+ }, undefined, false, undefined, this)
2080
+ ]
2081
+ }, undefined, true, undefined, this)
2082
+ ]
2083
+ }, undefined, true, undefined, this),
2084
+ !isAllDay && /* @__PURE__ */ jsxDEV41("div", {
2085
+ className: "grid grid-cols-2 gap-2 sm:gap-4",
2086
+ children: [
2087
+ /* @__PURE__ */ jsxDEV41("div", {
2088
+ children: [
2089
+ /* @__PURE__ */ jsxDEV41(Label2, {
2090
+ htmlFor: "start-time",
2091
+ className: "text-xs sm:text-sm",
2092
+ children: "Start Time"
2093
+ }, undefined, false, undefined, this),
2094
+ /* @__PURE__ */ jsxDEV41(Input, {
2095
+ id: "start-time",
2096
+ type: "time",
2097
+ value: startTime,
2098
+ onChange: (e) => handleTimeChange(e, true),
2099
+ className: "mt-1 h-8 text-sm sm:h-9"
2100
+ }, undefined, false, undefined, this)
2101
+ ]
2102
+ }, undefined, true, undefined, this),
2103
+ /* @__PURE__ */ jsxDEV41("div", {
2104
+ children: [
2105
+ /* @__PURE__ */ jsxDEV41(Label2, {
2106
+ htmlFor: "end-time",
2107
+ className: "text-xs sm:text-sm",
2108
+ children: "End Time"
2109
+ }, undefined, false, undefined, this),
2110
+ /* @__PURE__ */ jsxDEV41(Input, {
2111
+ id: "end-time",
2112
+ type: "time",
2113
+ value: endTime,
2114
+ onChange: (e) => handleTimeChange(e, false),
2115
+ className: "mt-1 h-8 text-sm sm:h-9"
2116
+ }, undefined, false, undefined, this)
2117
+ ]
2118
+ }, undefined, true, undefined, this)
2119
+ ]
2120
+ }, undefined, true, undefined, this),
2121
+ /* @__PURE__ */ jsxDEV41("div", {
2122
+ className: "grid gap-1 sm:gap-2",
2123
+ children: [
2124
+ /* @__PURE__ */ jsxDEV41(Label2, {
2125
+ className: "text-xs sm:text-sm",
2126
+ children: "Color"
2127
+ }, undefined, false, undefined, this),
2128
+ /* @__PURE__ */ jsxDEV41("div", {
2129
+ className: "flex flex-wrap gap-2",
2130
+ children: /* @__PURE__ */ jsxDEV41(TooltipProvider, {
2131
+ children: colorOptions.map((color) => /* @__PURE__ */ jsxDEV41(Tooltip, {
2132
+ children: [
2133
+ /* @__PURE__ */ jsxDEV41(TooltipTrigger, {
2134
+ asChild: true,
2135
+ children: /* @__PURE__ */ jsxDEV41(Button, {
2136
+ variant: "ghost",
2137
+ type: "button",
2138
+ className: cn(`${color.value} h-6 w-6 rounded-full sm:h-8 sm:w-8`, selectedColor === color.value && "ring-2 ring-black ring-offset-1 sm:ring-offset-2"),
2139
+ onClick: () => setSelectedColor(color.value),
2140
+ "aria-label": color.label
2141
+ }, color.value, false, undefined, this)
2142
+ }, undefined, false, undefined, this),
2143
+ /* @__PURE__ */ jsxDEV41(TooltipContent, {
2144
+ children: /* @__PURE__ */ jsxDEV41("p", {
2145
+ className: "text-xs sm:text-sm",
2146
+ children: color.label
2147
+ }, undefined, false, undefined, this)
2148
+ }, undefined, false, undefined, this)
2149
+ ]
2150
+ }, color.value, true, undefined, this))
2151
+ }, undefined, false, undefined, this)
2152
+ }, undefined, false, undefined, this)
2153
+ ]
2154
+ }, undefined, true, undefined, this),
2155
+ /* @__PURE__ */ jsxDEV41("div", {
2156
+ className: "grid gap-1 sm:gap-2",
2157
+ children: [
2158
+ /* @__PURE__ */ jsxDEV41(Label2, {
2159
+ htmlFor: "location",
2160
+ className: "text-xs sm:text-sm",
2161
+ children: "Location"
2162
+ }, undefined, false, undefined, this),
2163
+ /* @__PURE__ */ jsxDEV41(Input, {
2164
+ id: "location",
2165
+ name: "location",
2166
+ value: formValues.location,
2167
+ onChange: handleInputChange,
2168
+ placeholder: "Event location (optional)",
2169
+ className: "h-8 text-sm sm:h-9"
2170
+ }, undefined, false, undefined, this)
2171
+ ]
2172
+ }, undefined, true, undefined, this),
2173
+ /* @__PURE__ */ jsxDEV41("div", {
2174
+ className: "grid gap-1 sm:gap-2",
2175
+ children: [
2176
+ /* @__PURE__ */ jsxDEV41(Label2, {
2177
+ htmlFor: "description",
2178
+ className: "text-xs sm:text-sm",
2179
+ children: "Description"
2180
+ }, undefined, false, undefined, this),
2181
+ /* @__PURE__ */ jsxDEV41(Input, {
2182
+ id: "description",
2183
+ name: "description",
2184
+ value: formValues.description,
2185
+ onChange: handleInputChange,
2186
+ placeholder: "Event description (optional)",
2187
+ className: "h-8 text-sm sm:h-9"
2188
+ }, undefined, false, undefined, this)
2189
+ ]
2190
+ }, undefined, true, undefined, this)
2191
+ ]
2192
+ }, undefined, true, undefined, this),
2193
+ /* @__PURE__ */ jsxDEV41(DialogFooter, {
2194
+ className: "mt-2 flex flex-col-reverse gap-2 sm:mt-4 sm:flex-row sm:gap-0",
2195
+ children: [
2196
+ selectedEvent.id && /* @__PURE__ */ jsxDEV41(Button, {
2197
+ type: "button",
2198
+ variant: "destructive",
2199
+ onClick: handleDelete,
2200
+ className: "w-full sm:mr-auto sm:w-auto",
2201
+ size: "sm",
2202
+ children: "Delete"
2203
+ }, undefined, false, undefined, this),
2204
+ /* @__PURE__ */ jsxDEV41("div", {
2205
+ className: "flex w-full gap-2 sm:w-auto",
2206
+ children: [
2207
+ /* @__PURE__ */ jsxDEV41(Button, {
2208
+ type: "button",
2209
+ variant: "outline",
2210
+ onClick: onClose,
2211
+ className: "flex-1 sm:flex-none",
2212
+ size: "sm",
2213
+ children: "Cancel"
2214
+ }, undefined, false, undefined, this),
2215
+ /* @__PURE__ */ jsxDEV41(Button, {
2216
+ type: "submit",
2217
+ className: "flex-1 sm:flex-none",
2218
+ size: "sm",
2219
+ children: selectedEvent.id ? "Update" : "Create"
2220
+ }, undefined, false, undefined, this)
2221
+ ]
2222
+ }, undefined, true, undefined, this)
2223
+ ]
2224
+ }, undefined, true, undefined, this)
2225
+ ]
2226
+ }, undefined, true, undefined, this)
2227
+ }, undefined, false, undefined, this)
2228
+ }, undefined, false, undefined, this);
2229
+ };
2230
+
2231
+ // src/components/header/base-header.tsx
2232
+ import { Calendar as CalendarIcon2, Menu, Plus } from "lucide-react";
2233
+ import { useCallback, useState as useState4 } from "react";
2234
+
2235
+ // src/components/header/title-content.tsx
2236
+ import dayjs14 from "dayjs";
2237
+ import { AnimatePresence as AnimatePresence6, motion as motion6 } from "motion/react";
2238
+ import { ChevronDown } from "lucide-react";
2239
+ import { useState as useState3 } from "react";
2240
+ import { jsxDEV as jsxDEV42, Fragment as Fragment3 } from "react/jsx-dev-runtime";
2241
+ var months = [
2242
+ "January",
2243
+ "February",
2244
+ "March",
2245
+ "April",
2246
+ "May",
2247
+ "June",
2248
+ "July",
2249
+ "August",
2250
+ "September",
2251
+ "October",
2252
+ "November",
2253
+ "December"
2254
+ ];
2255
+ var animationVariants = {
2256
+ initial: { opacity: 0, y: 10 },
2257
+ animate: { opacity: 1, y: 0 },
2258
+ exit: { opacity: 0, y: -10 }
2259
+ };
2260
+ var TitleContent = () => {
2261
+ const { currentDate, view, setCurrentDate } = useCalendarContext();
2262
+ const [monthPopoverOpen, setMonthPopoverOpen] = useState3(false);
2263
+ const [yearPopoverOpen, setYearPopoverOpen] = useState3(false);
2264
+ const [weekPopoverOpen, setWeekPopoverOpen] = useState3(false);
2265
+ const [dayPopoverOpen, setDayPopoverOpen] = useState3(false);
2266
+ const currentYear = currentDate.year();
2267
+ const years = Array.from({ length: 11 }, (_, i) => currentYear - 5 + i);
2268
+ const handleMonthChange = (month) => {
2269
+ const newDate = currentDate.month(month);
2270
+ setCurrentDate(newDate);
2271
+ setMonthPopoverOpen(false);
2272
+ };
2273
+ const handleYearChange = (year) => {
2274
+ const newDate = currentDate.year(year);
2275
+ setCurrentDate(newDate);
2276
+ setYearPopoverOpen(false);
2277
+ };
2278
+ return /* @__PURE__ */ jsxDEV42(Fragment3, {
2279
+ children: [
2280
+ view !== "year" && /* @__PURE__ */ jsxDEV42(Popover, {
2281
+ open: monthPopoverOpen,
2282
+ onOpenChange: setMonthPopoverOpen,
2283
+ children: [
2284
+ /* @__PURE__ */ jsxDEV42(PopoverTrigger, {
2285
+ asChild: true,
2286
+ children: /* @__PURE__ */ jsxDEV42(Button, {
2287
+ variant: "ghost",
2288
+ className: "flex items-center gap-1 px-2 font-semibold",
2289
+ children: [
2290
+ /* @__PURE__ */ jsxDEV42(AnimatePresence6, {
2291
+ mode: "wait",
2292
+ children: /* @__PURE__ */ jsxDEV42(motion6.span, {
2293
+ initial: "initial",
2294
+ animate: "animate",
2295
+ exit: "exit",
2296
+ variants: animationVariants,
2297
+ transition: { duration: 0.25, ease: "easeInOut" },
2298
+ children: currentDate.format("MMMM")
2299
+ }, `month-${currentDate.month()}`, false, undefined, this)
2300
+ }, undefined, false, undefined, this),
2301
+ /* @__PURE__ */ jsxDEV42(ChevronDown, {
2302
+ className: "h-4 w-4"
2303
+ }, undefined, false, undefined, this)
2304
+ ]
2305
+ }, undefined, true, undefined, this)
2306
+ }, undefined, false, undefined, this),
2307
+ /* @__PURE__ */ jsxDEV42(PopoverContent, {
2308
+ className: "w-40 p-0",
2309
+ children: /* @__PURE__ */ jsxDEV42("div", {
2310
+ className: "flex max-h-60 flex-col overflow-auto",
2311
+ children: months.map((month, index) => /* @__PURE__ */ jsxDEV42(Button, {
2312
+ variant: "ghost",
2313
+ className: cn("justify-start font-normal", currentDate.month() === index && "bg-primary/10"),
2314
+ onClick: () => handleMonthChange(index),
2315
+ children: month
2316
+ }, month, false, undefined, this))
2317
+ }, undefined, false, undefined, this)
2318
+ }, undefined, false, undefined, this)
2319
+ ]
2320
+ }, undefined, true, undefined, this),
2321
+ /* @__PURE__ */ jsxDEV42(Popover, {
2322
+ open: yearPopoverOpen,
2323
+ onOpenChange: setYearPopoverOpen,
2324
+ children: [
2325
+ /* @__PURE__ */ jsxDEV42(PopoverTrigger, {
2326
+ asChild: true,
2327
+ children: /* @__PURE__ */ jsxDEV42(Button, {
2328
+ variant: "ghost",
2329
+ className: "flex items-center gap-1 px-2 font-semibold",
2330
+ children: [
2331
+ /* @__PURE__ */ jsxDEV42(AnimatePresence6, {
2332
+ mode: "wait",
2333
+ children: /* @__PURE__ */ jsxDEV42(motion6.span, {
2334
+ initial: "initial",
2335
+ animate: "animate",
2336
+ exit: "exit",
2337
+ variants: animationVariants,
2338
+ transition: { duration: 0.25, ease: "easeInOut" },
2339
+ children: currentDate.format("YYYY")
2340
+ }, `year-${currentDate.year()}`, false, undefined, this)
2341
+ }, undefined, false, undefined, this),
2342
+ /* @__PURE__ */ jsxDEV42(ChevronDown, {
2343
+ className: "h-4 w-4"
2344
+ }, undefined, false, undefined, this)
2345
+ ]
2346
+ }, undefined, true, undefined, this)
2347
+ }, undefined, false, undefined, this),
2348
+ /* @__PURE__ */ jsxDEV42(PopoverContent, {
2349
+ className: "w-24 p-0",
2350
+ children: /* @__PURE__ */ jsxDEV42("div", {
2351
+ className: "flex max-h-60 flex-col overflow-auto",
2352
+ children: years.map((year) => /* @__PURE__ */ jsxDEV42(Button, {
2353
+ variant: "ghost",
2354
+ className: cn("justify-start font-normal", currentDate.year() === year && "bg-primary/10"),
2355
+ onClick: () => handleYearChange(year),
2356
+ children: year
2357
+ }, year, false, undefined, this))
2358
+ }, undefined, false, undefined, this)
2359
+ }, undefined, false, undefined, this)
2360
+ ]
2361
+ }, undefined, true, undefined, this),
2362
+ view === "week" && /* @__PURE__ */ jsxDEV42(Popover, {
2363
+ open: weekPopoverOpen,
2364
+ onOpenChange: setWeekPopoverOpen,
2365
+ children: [
2366
+ /* @__PURE__ */ jsxDEV42(PopoverTrigger, {
2367
+ asChild: true,
2368
+ children: /* @__PURE__ */ jsxDEV42(Button, {
2369
+ variant: "ghost",
2370
+ className: "flex items-center gap-1 px-2 font-semibold",
2371
+ children: [
2372
+ /* @__PURE__ */ jsxDEV42(AnimatePresence6, {
2373
+ mode: "wait",
2374
+ children: /* @__PURE__ */ jsxDEV42(motion6.span, {
2375
+ initial: "initial",
2376
+ animate: "animate",
2377
+ exit: "exit",
2378
+ variants: animationVariants,
2379
+ transition: { duration: 0.25, ease: "easeInOut" },
2380
+ children: `${currentDate.startOf("week").format("MMM D")} - ${currentDate.endOf("week").format("MMM D")}`
2381
+ }, `week-range-${currentDate.format("YYYY-MM-DD")}`, false, undefined, this)
2382
+ }, undefined, false, undefined, this),
2383
+ /* @__PURE__ */ jsxDEV42(ChevronDown, {
2384
+ className: "ml-1 h-3 w-3 opacity-70"
2385
+ }, undefined, false, undefined, this)
2386
+ ]
2387
+ }, undefined, true, undefined, this)
2388
+ }, undefined, false, undefined, this),
2389
+ /* @__PURE__ */ jsxDEV42(PopoverContent, {
2390
+ className: "w-56 p-0",
2391
+ children: /* @__PURE__ */ jsxDEV42("div", {
2392
+ className: "flex max-h-60 flex-col overflow-auto",
2393
+ children: Array.from({ length: 7 }, (_, i) => {
2394
+ const weekDate = currentDate.subtract(3, "week").add(i, "week");
2395
+ const startOfWeek = weekDate.startOf("week");
2396
+ const endOfWeek = weekDate.endOf("week");
2397
+ const isCurrentWeek = weekDate.isSame(currentDate, "week");
2398
+ return /* @__PURE__ */ jsxDEV42(Button, {
2399
+ variant: "ghost",
2400
+ className: cn("justify-start font-normal", isCurrentWeek && "bg-primary/10"),
2401
+ onClick: () => {
2402
+ setCurrentDate(startOfWeek);
2403
+ setWeekPopoverOpen(false);
2404
+ },
2405
+ children: /* @__PURE__ */ jsxDEV42("div", {
2406
+ className: "flex w-full items-center justify-between",
2407
+ children: [
2408
+ /* @__PURE__ */ jsxDEV42("span", {
2409
+ children: `${startOfWeek.format("MMM D")} - ${endOfWeek.format("D")}`
2410
+ }, undefined, false, undefined, this),
2411
+ startOfWeek.month() !== endOfWeek.month() && /* @__PURE__ */ jsxDEV42("span", {
2412
+ className: "text-xs opacity-70",
2413
+ children: `${startOfWeek.format("MMM")}-${endOfWeek.format("MMM")}`
2414
+ }, undefined, false, undefined, this)
2415
+ ]
2416
+ }, undefined, true, undefined, this)
2417
+ }, startOfWeek.format("YYYY-MM-DD"), false, undefined, this);
2418
+ })
2419
+ }, undefined, false, undefined, this)
2420
+ }, undefined, false, undefined, this)
2421
+ ]
2422
+ }, undefined, true, undefined, this),
2423
+ view === "day" && /* @__PURE__ */ jsxDEV42(Popover, {
2424
+ open: dayPopoverOpen,
2425
+ onOpenChange: setDayPopoverOpen,
2426
+ children: [
2427
+ /* @__PURE__ */ jsxDEV42(PopoverTrigger, {
2428
+ asChild: true,
2429
+ children: /* @__PURE__ */ jsxDEV42(Button, {
2430
+ variant: "ghost",
2431
+ className: "flex items-center gap-1 px-2 font-semibold",
2432
+ children: [
2433
+ /* @__PURE__ */ jsxDEV42(AnimatePresence6, {
2434
+ mode: "wait",
2435
+ children: /* @__PURE__ */ jsxDEV42(motion6.span, {
2436
+ initial: "initial",
2437
+ animate: "animate",
2438
+ exit: "exit",
2439
+ variants: animationVariants,
2440
+ transition: { duration: 0.25, ease: "easeInOut" },
2441
+ children: currentDate.format("dddd, D")
2442
+ }, `day-info-${currentDate.format("YYYY-MM-DD")}`, false, undefined, this)
2443
+ }, undefined, false, undefined, this),
2444
+ /* @__PURE__ */ jsxDEV42(ChevronDown, {
2445
+ className: "ml-1 h-3 w-3 opacity-70"
2446
+ }, undefined, false, undefined, this)
2447
+ ]
2448
+ }, undefined, true, undefined, this)
2449
+ }, undefined, false, undefined, this),
2450
+ /* @__PURE__ */ jsxDEV42(PopoverContent, {
2451
+ className: "w-56 p-0",
2452
+ children: /* @__PURE__ */ jsxDEV42("div", {
2453
+ className: "flex max-h-60 flex-col overflow-auto",
2454
+ children: (() => {
2455
+ const firstDayOfMonth = currentDate.startOf("month");
2456
+ const daysInMonth = currentDate.daysInMonth();
2457
+ return Array.from({ length: daysInMonth }, (_, i) => {
2458
+ const dayDate = firstDayOfMonth.date(i + 1);
2459
+ const isCurrentDay = dayDate.isSame(currentDate, "day");
2460
+ const isToday = dayDate.isSame(dayjs14(), "day");
2461
+ return /* @__PURE__ */ jsxDEV42(Button, {
2462
+ variant: "ghost",
2463
+ className: cn("justify-start font-normal", isCurrentDay && "bg-primary/10"),
2464
+ onClick: () => {
2465
+ setCurrentDate(dayDate);
2466
+ setDayPopoverOpen(false);
2467
+ },
2468
+ children: /* @__PURE__ */ jsxDEV42("div", {
2469
+ className: "flex w-full items-center justify-between",
2470
+ children: [
2471
+ /* @__PURE__ */ jsxDEV42("span", {
2472
+ children: dayDate.format("dddd, MMM D")
2473
+ }, undefined, false, undefined, this),
2474
+ isToday && /* @__PURE__ */ jsxDEV42("span", {
2475
+ className: "bg-primary text-primary-foreground rounded-sm px-1 text-xs",
2476
+ children: "Today"
2477
+ }, undefined, false, undefined, this)
2478
+ ]
2479
+ }, undefined, true, undefined, this)
2480
+ }, dayDate.format("YYYY-MM-DD"), false, undefined, this);
2481
+ });
2482
+ })()
2483
+ }, undefined, false, undefined, this)
2484
+ }, undefined, false, undefined, this)
2485
+ ]
2486
+ }, undefined, true, undefined, this)
2487
+ ]
2488
+ }, undefined, true, undefined, this);
2489
+ };
2490
+ var title_content_default = TitleContent;
2491
+
2492
+ // src/components/header/view-controls.tsx
2493
+ import { ChevronLeft as ChevronLeft2, ChevronRight as ChevronRight2 } from "lucide-react";
2494
+ import { jsxDEV as jsxDEV43 } from "react/jsx-dev-runtime";
2495
+ var ViewControls = ({
2496
+ currentView,
2497
+ onChange,
2498
+ variant = "default",
2499
+ size = "sm",
2500
+ className,
2501
+ onToday,
2502
+ onNext,
2503
+ onPrevious
2504
+ }) => {
2505
+ const isGrid = variant === "grid";
2506
+ const getButtonClassName = (viewType) => {
2507
+ return cn(isGrid ? "w-full" : "", viewType === "year" ? isGrid ? "w-full" : "hidden md:inline-flex" : "", currentView === viewType && "bg-primary/80");
2508
+ };
2509
+ const getBtnVariant = (viewType) => {
2510
+ return currentView === viewType ? "default" : "outline";
2511
+ };
2512
+ return /* @__PURE__ */ jsxDEV43("div", {
2513
+ className: cn(isGrid ? "grid grid-cols-2 gap-2" : "flex gap-1", className),
2514
+ children: [
2515
+ /* @__PURE__ */ jsxDEV43(Button, {
2516
+ onClick: onPrevious,
2517
+ variant: "outline",
2518
+ size,
2519
+ children: /* @__PURE__ */ jsxDEV43(ChevronLeft2, {
2520
+ className: "h-4 w-4"
2521
+ }, undefined, false, undefined, this)
2522
+ }, undefined, false, undefined, this),
2523
+ /* @__PURE__ */ jsxDEV43(Button, {
2524
+ onClick: onNext,
2525
+ variant: "outline",
2526
+ size,
2527
+ children: /* @__PURE__ */ jsxDEV43(ChevronRight2, {
2528
+ className: "h-4 w-4"
2529
+ }, undefined, false, undefined, this)
2530
+ }, undefined, false, undefined, this),
2531
+ /* @__PURE__ */ jsxDEV43(Button, {
2532
+ onClick: () => onChange("day"),
2533
+ variant: getBtnVariant("day"),
2534
+ size,
2535
+ className: getButtonClassName("day"),
2536
+ children: "Day"
2537
+ }, undefined, false, undefined, this),
2538
+ /* @__PURE__ */ jsxDEV43(Button, {
2539
+ onClick: () => onChange("week"),
2540
+ variant: getBtnVariant("week"),
2541
+ size,
2542
+ className: getButtonClassName("week"),
2543
+ children: "Week"
2544
+ }, undefined, false, undefined, this),
2545
+ /* @__PURE__ */ jsxDEV43(Button, {
2546
+ onClick: () => onChange("month"),
2547
+ variant: getBtnVariant("month"),
2548
+ size,
2549
+ className: getButtonClassName("month"),
2550
+ children: "Month"
2551
+ }, undefined, false, undefined, this),
2552
+ /* @__PURE__ */ jsxDEV43(Button, {
2553
+ onClick: () => onChange("year"),
2554
+ variant: getBtnVariant("year"),
2555
+ size,
2556
+ className: getButtonClassName("year"),
2557
+ children: "Year"
2558
+ }, undefined, false, undefined, this),
2559
+ /* @__PURE__ */ jsxDEV43(Button, {
2560
+ onClick: onToday,
2561
+ variant: "outline",
2562
+ size,
2563
+ children: "Today"
2564
+ }, undefined, false, undefined, this)
2565
+ ]
2566
+ }, undefined, true, undefined, this);
2567
+ };
2568
+ var view_controls_default = ViewControls;
2569
+
2570
+ // src/components/header/base-header.tsx
2571
+ import { jsxDEV as jsxDEV44, Fragment as Fragment4 } from "react/jsx-dev-runtime";
2572
+ var Header2 = () => {
2573
+ const {
2574
+ currentDate,
2575
+ view,
2576
+ setView,
2577
+ nextPeriod,
2578
+ prevPeriod,
2579
+ today,
2580
+ openEventForm
2581
+ } = useCalendarContext();
2582
+ const [mobilePopoverOpen, setMobilePopoverOpen] = useState4(false);
2583
+ const handleViewChange = (newView, closePopover = false) => {
2584
+ setView(newView);
2585
+ if (closePopover) {
2586
+ setMobilePopoverOpen(false);
2587
+ }
2588
+ };
2589
+ const handleNavigation = {
2590
+ today: () => {
2591
+ today();
2592
+ setMobilePopoverOpen(false);
2593
+ },
2594
+ previous: () => {
2595
+ prevPeriod();
2596
+ setMobilePopoverOpen(false);
2597
+ },
2598
+ next: () => {
2599
+ nextPeriod();
2600
+ setMobilePopoverOpen(false);
2601
+ }
2602
+ };
2603
+ const NewEventButton = useCallback(() => /* @__PURE__ */ jsxDEV44("div", {
2604
+ className: "flex items-center gap-2",
2605
+ children: /* @__PURE__ */ jsxDEV44(Button, {
2606
+ onClick: () => openEventForm(currentDate),
2607
+ variant: "default",
2608
+ size: "sm",
2609
+ className: "flex items-center gap-1",
2610
+ children: [
2611
+ /* @__PURE__ */ jsxDEV44(Plus, {
2612
+ className: "h-4 w-4"
2613
+ }, undefined, false, undefined, this),
2614
+ /* @__PURE__ */ jsxDEV44("span", {
2615
+ className: "hidden md:inline",
2616
+ children: "New Event"
2617
+ }, undefined, false, undefined, this),
2618
+ /* @__PURE__ */ jsxDEV44("span", {
2619
+ className: "md:hidden",
2620
+ children: "New"
2621
+ }, undefined, false, undefined, this)
2622
+ ]
2623
+ }, undefined, true, undefined, this)
2624
+ }, undefined, false, undefined, this), [currentDate, openEventForm]);
2625
+ return /* @__PURE__ */ jsxDEV44(Fragment4, {
2626
+ children: /* @__PURE__ */ jsxDEV44("div", {
2627
+ className: "@container grid grid-cols-12 items-center gap-2 border-b p-2 sm:p-4",
2628
+ children: [
2629
+ /* @__PURE__ */ jsxDEV44("div", {
2630
+ className: "col-span-12 flex flex-wrap items-center justify-center gap-2 @4xl:col-span-5 @4xl:justify-start",
2631
+ children: [
2632
+ /* @__PURE__ */ jsxDEV44(CalendarIcon2, {
2633
+ className: "h-5 w-5"
2634
+ }, undefined, false, undefined, this),
2635
+ /* @__PURE__ */ jsxDEV44(title_content_default, {}, undefined, false, undefined, this)
2636
+ ]
2637
+ }, undefined, true, undefined, this),
2638
+ /* @__PURE__ */ jsxDEV44("div", {
2639
+ className: "col-span-12 flex flex-wrap justify-center gap-1 @4xl:col-span-7 @4xl:justify-end",
2640
+ children: [
2641
+ /* @__PURE__ */ jsxDEV44("div", {
2642
+ className: "hidden items-center justify-end gap-1 sm:flex",
2643
+ children: [
2644
+ /* @__PURE__ */ jsxDEV44(view_controls_default, {
2645
+ currentView: view,
2646
+ onChange: setView,
2647
+ onToday: today,
2648
+ onNext: nextPeriod,
2649
+ onPrevious: prevPeriod,
2650
+ variant: "default",
2651
+ className: "justify-end"
2652
+ }, undefined, false, undefined, this),
2653
+ /* @__PURE__ */ jsxDEV44(NewEventButton, {}, undefined, false, undefined, this)
2654
+ ]
2655
+ }, undefined, true, undefined, this),
2656
+ /* @__PURE__ */ jsxDEV44("div", {
2657
+ className: "flex items-center justify-end gap-1 sm:hidden",
2658
+ children: [
2659
+ /* @__PURE__ */ jsxDEV44(NewEventButton, {}, undefined, false, undefined, this),
2660
+ /* @__PURE__ */ jsxDEV44(Popover, {
2661
+ open: mobilePopoverOpen,
2662
+ onOpenChange: setMobilePopoverOpen,
2663
+ children: [
2664
+ /* @__PURE__ */ jsxDEV44(PopoverTrigger, {
2665
+ asChild: true,
2666
+ children: /* @__PURE__ */ jsxDEV44(Button, {
2667
+ variant: "outline",
2668
+ size: "sm",
2669
+ children: /* @__PURE__ */ jsxDEV44(Menu, {
2670
+ className: "h-4 w-4"
2671
+ }, undefined, false, undefined, this)
2672
+ }, undefined, false, undefined, this)
2673
+ }, undefined, false, undefined, this),
2674
+ /* @__PURE__ */ jsxDEV44(PopoverContent, {
2675
+ align: "end",
2676
+ className: "w-[240px] p-2",
2677
+ children: /* @__PURE__ */ jsxDEV44("div", {
2678
+ className: "space-y-2",
2679
+ children: [
2680
+ /* @__PURE__ */ jsxDEV44("h3", {
2681
+ className: "mb-1 text-sm font-medium",
2682
+ children: "View & Navigation"
2683
+ }, undefined, false, undefined, this),
2684
+ /* @__PURE__ */ jsxDEV44(view_controls_default, {
2685
+ currentView: view,
2686
+ onChange: (newView) => handleViewChange(newView, true),
2687
+ onToday: handleNavigation.today,
2688
+ onNext: handleNavigation.next,
2689
+ onPrevious: handleNavigation.previous,
2690
+ variant: "grid"
2691
+ }, undefined, false, undefined, this)
2692
+ ]
2693
+ }, undefined, true, undefined, this)
2694
+ }, undefined, false, undefined, this)
2695
+ ]
2696
+ }, undefined, true, undefined, this)
2697
+ ]
2698
+ }, undefined, true, undefined, this)
2699
+ ]
2700
+ }, undefined, true, undefined, this)
2701
+ ]
2702
+ }, undefined, true, undefined, this)
2703
+ }, undefined, false, undefined, this);
2704
+ };
2705
+ var base_header_default = Header2;
2706
+ // src/features/year-view/year-view.tsx
2707
+ import dayjs15 from "dayjs";
2708
+ import { AnimatePresence as AnimatePresence7, motion as motion7 } from "motion/react";
2709
+ import { jsxDEV as jsxDEV45 } from "react/jsx-dev-runtime";
2710
+ var YearView = () => {
2711
+ const { currentDate, selectDate, events, setView, getEventsForDate } = useCalendarContext();
2712
+ const year = currentDate.year();
2713
+ const months2 = Array.from({ length: 12 }, (_, i) => {
2714
+ const monthDate = dayjs15().year(year).month(i).startOf("month");
2715
+ return {
2716
+ date: monthDate,
2717
+ name: monthDate.format("MMMM"),
2718
+ daysInMonth: monthDate.daysInMonth(),
2719
+ firstDayOfMonth: monthDate.startOf("month").day()
2720
+ };
2721
+ });
2722
+ const monthsWithEventCount = months2.map((month) => {
2723
+ const eventsInMonth = events.filter((event) => event.start.year() === year && event.start.month() === month.date.month());
2724
+ return {
2725
+ ...month,
2726
+ eventCount: eventsInMonth.length
2727
+ };
2728
+ });
2729
+ const handleMonthClick = (date) => {
2730
+ selectDate(date);
2731
+ setView("month");
2732
+ };
2733
+ const handleDayClick = (date, event) => {
2734
+ event.stopPropagation();
2735
+ selectDate(date);
2736
+ setView("day");
2737
+ };
2738
+ const renderMiniCalendar = (month) => {
2739
+ const firstDayOfCalendar = month.date.startOf("month").startOf("week");
2740
+ const daysArray = Array.from({ length: 42 }, (_, i) => {
2741
+ const day = firstDayOfCalendar.add(i, "day");
2742
+ const isCurrentMonth = day.month() === month.date.month();
2743
+ const isToday = day.isSame(dayjs15(), "day");
2744
+ const isCurrentDate = day.isSame(currentDate, "day");
2745
+ const dayEvents = getEventsForDate(day);
2746
+ const hasEvents = dayEvents.length > 0;
2747
+ return {
2748
+ day,
2749
+ isCurrentMonth,
2750
+ isToday,
2751
+ isCurrentDate,
2752
+ hasEvents,
2753
+ eventCount: dayEvents.length,
2754
+ events: dayEvents
2755
+ };
2756
+ });
2757
+ return /* @__PURE__ */ jsxDEV45("div", {
2758
+ "data-testid": `year-mini-calendar-${month.date.format("MM")}`,
2759
+ className: "grid grid-cols-7 gap-[1px] text-[0.6rem]",
2760
+ children: [
2761
+ ["S", "M", "T", "W", "T", "F", "S"].map((dayName, i) => /* @__PURE__ */ jsxDEV45("div", {
2762
+ className: "text-muted-foreground h-3 text-center",
2763
+ children: dayName
2764
+ }, `header-${i}`, false, undefined, this)),
2765
+ daysArray.map((dayInfo, i) => /* @__PURE__ */ jsxDEV45("div", {
2766
+ "data-testid": `year-day-${dayInfo.day.format("YYYY-MM-DD")}`,
2767
+ onClick: (e) => handleDayClick(dayInfo.day, e),
2768
+ className: cn("relative flex aspect-square w-full cursor-pointer flex-col items-center justify-center", "hover:bg-accent rounded-sm transition-colors duration-200", !dayInfo.isCurrentMonth && "text-muted-foreground opacity-50", dayInfo.isToday && "bg-primary text-primary-foreground rounded-full", dayInfo.isCurrentDate && !dayInfo.isToday && "bg-muted rounded-full font-bold", dayInfo.hasEvents && !dayInfo.isToday && !dayInfo.isCurrentDate && "font-medium"),
2769
+ title: dayInfo.hasEvents ? `${dayInfo.eventCount} event${dayInfo.eventCount > 1 ? "s" : ""}` : "",
2770
+ children: [
2771
+ /* @__PURE__ */ jsxDEV45("span", {
2772
+ className: "text-center leading-none",
2773
+ children: dayInfo.day.date()
2774
+ }, undefined, false, undefined, this),
2775
+ dayInfo.hasEvents && /* @__PURE__ */ jsxDEV45("div", {
2776
+ className: cn("absolute bottom-0 flex w-full justify-center space-x-[1px]", dayInfo.isToday ? "bottom-[1px]" : ""),
2777
+ children: [
2778
+ dayInfo.eventCount > 0 && /* @__PURE__ */ jsxDEV45("span", {
2779
+ className: cn("h-[3px] w-[3px] rounded-full", dayInfo.isToday ? "bg-primary-foreground" : "bg-primary")
2780
+ }, undefined, false, undefined, this),
2781
+ dayInfo.eventCount > 1 && /* @__PURE__ */ jsxDEV45("span", {
2782
+ className: cn("h-[3px] w-[3px] rounded-full", dayInfo.isToday ? "bg-primary-foreground" : "bg-blue-500")
2783
+ }, undefined, false, undefined, this),
2784
+ dayInfo.eventCount > 2 && /* @__PURE__ */ jsxDEV45("span", {
2785
+ className: cn("h-[3px] w-[3px] rounded-full", dayInfo.isToday ? "bg-primary-foreground" : "bg-green-500")
2786
+ }, undefined, false, undefined, this)
2787
+ ]
2788
+ }, undefined, true, undefined, this)
2789
+ ]
2790
+ }, `day-${i}`, true, undefined, this))
2791
+ ]
2792
+ }, undefined, true, undefined, this);
2793
+ };
2794
+ return /* @__PURE__ */ jsxDEV45(ScrollArea, {
2795
+ "data-testid": "year-view",
2796
+ className: "h-full",
2797
+ children: /* @__PURE__ */ jsxDEV45("div", {
2798
+ "data-testid": "year-grid",
2799
+ className: "grid auto-rows-fr grid-cols-1 gap-4 p-4 sm:grid-cols-2 lg:grid-cols-3",
2800
+ children: monthsWithEventCount.map((month, index) => /* @__PURE__ */ jsxDEV45("div", {
2801
+ "data-testid": `year-month-${month.date.format("MM")}`,
2802
+ onClick: () => handleMonthClick(month.date),
2803
+ className: "hover:border-primary flex cursor-pointer flex-col rounded-lg border p-3 transition-all duration-200 hover:scale-[1.01] hover:shadow-md",
2804
+ children: [
2805
+ /* @__PURE__ */ jsxDEV45(AnimatePresence7, {
2806
+ mode: "wait",
2807
+ children: /* @__PURE__ */ jsxDEV45(motion7.div, {
2808
+ initial: { opacity: 0, y: -10 },
2809
+ animate: { opacity: 1, y: 0 },
2810
+ exit: { opacity: 0, y: -10 },
2811
+ transition: {
2812
+ duration: 0.25,
2813
+ ease: "easeInOut",
2814
+ delay: index * 0.05
2815
+ },
2816
+ className: "mb-2 flex items-center justify-between",
2817
+ children: [
2818
+ /* @__PURE__ */ jsxDEV45("h3", {
2819
+ "data-testid": `year-month-title-${month.date.format("MM")}`,
2820
+ className: "text-lg font-medium",
2821
+ children: month.name
2822
+ }, undefined, false, undefined, this),
2823
+ month.eventCount > 0 && /* @__PURE__ */ jsxDEV45("span", {
2824
+ "data-testid": `year-month-event-count-${month.date.format("MM")}`,
2825
+ className: "bg-primary text-primary-foreground rounded-full px-2 py-1 text-xs",
2826
+ children: [
2827
+ month.eventCount,
2828
+ " ",
2829
+ month.eventCount === 1 ? "event" : "events"
2830
+ ]
2831
+ }, undefined, true, undefined, this)
2832
+ ]
2833
+ }, `month-${index}`, true, undefined, this)
2834
+ }, undefined, false, undefined, this),
2835
+ renderMiniCalendar(month)
2836
+ ]
2837
+ }, month.name, true, undefined, this))
2838
+ }, undefined, false, undefined, this)
2839
+ }, undefined, false, undefined, this);
2840
+ };
2841
+ var year_view_default = YearView;
2842
+
2843
+ // src/components/ilamy-calendar/ilamy-calendar.tsx
2844
+ import { AnimatePresence as AnimatePresence8, motion as motion8 } from "motion/react";
2845
+
2846
+ // src/features/drag-and-drop/calendar-dnd-context.tsx
2847
+ import {
2848
+ DndContext,
2849
+ DragOverlay,
2850
+ MouseSensor,
2851
+ pointerWithin,
2852
+ TouchSensor,
2853
+ useSensor,
2854
+ useSensors
2855
+ } from "@dnd-kit/core";
2856
+ import dayjs16 from "dayjs";
2857
+ import React9 from "react";
2858
+ import { snapCenterToCursor } from "@dnd-kit/modifiers";
2859
+ import { jsxDEV as jsxDEV46 } from "react/jsx-dev-runtime";
2860
+ function CalendarDndContext({ children }) {
2861
+ const { updateEvent, view, disableDragAndDrop } = useCalendarContext();
2862
+ const [activeEvent, setActiveEvent] = React9.useState(null);
2863
+ const mouseSensor = useSensor(MouseSensor, {
2864
+ activationConstraint: {
2865
+ distance: 2
2866
+ }
2867
+ });
2868
+ const touchSensor = useSensor(TouchSensor, {
2869
+ activationConstraint: {
2870
+ delay: 100,
2871
+ tolerance: 5
2872
+ }
2873
+ });
2874
+ const sensors = useSensors(mouseSensor, touchSensor);
2875
+ const handleDragStart = (event) => {
2876
+ const { active } = event;
2877
+ if (active.data.current?.type === "calendar-event") {
2878
+ setActiveEvent(active.data.current.event);
2879
+ }
2880
+ };
2881
+ const handleDragEnd = (event) => {
2882
+ const { active, over } = event;
2883
+ if (!active || !over || !activeEvent) {
2884
+ setActiveEvent(null);
2885
+ return;
2886
+ }
2887
+ if (over.data.current?.type === "time-cell") {
2888
+ const { date, hour = 0, minute = 0 } = over.data.current;
2889
+ const originalStart = activeEvent.originalStart ?? activeEvent.start;
2890
+ const originalEnd = activeEvent.originalEnd ?? activeEvent.end;
2891
+ const durationMinutes = originalEnd.diff(originalStart, "minute");
2892
+ const newStart = dayjs16(date).hour(hour).minute(minute || 0);
2893
+ let newEnd = newStart.add(durationMinutes, "minute");
2894
+ if (newEnd.isSame(newEnd.startOf("day"))) {
2895
+ newEnd = newEnd.subtract(1, "day").endOf("day");
2896
+ }
2897
+ updateEvent(activeEvent.id, {
2898
+ start: newStart,
2899
+ end: newEnd
2900
+ });
2901
+ } else if (over.data.current?.type === "day-cell") {
2902
+ const { date } = over.data.current;
2903
+ const newDate = dayjs16(date);
2904
+ const isMultiDayEvent = !activeEvent.start.isSame(activeEvent.end, "day");
2905
+ const originalStart = activeEvent.originalStart ?? activeEvent.start;
2906
+ const originalEnd = activeEvent.originalEnd ?? activeEvent.end;
2907
+ if (isMultiDayEvent) {
2908
+ if (view === "week") {
2909
+ const startHour = originalStart.hour();
2910
+ const startMinute = originalStart.minute();
2911
+ const endHour = originalEnd.hour();
2912
+ const endMinute = originalEnd.minute();
2913
+ const durationDays = originalEnd.diff(originalStart, "day");
2914
+ const newStart = newDate.startOf("day").hour(startHour).minute(startMinute);
2915
+ const newEnd = newStart.add(durationDays, "day").hour(endHour).minute(endMinute);
2916
+ updateEvent(activeEvent.id, {
2917
+ start: newStart,
2918
+ end: newEnd,
2919
+ originalStart: undefined,
2920
+ originalEnd: undefined
2921
+ });
2922
+ } else {
2923
+ const daysDifference = newDate.diff(originalStart.startOf("day"), "day");
2924
+ const newStart = originalStart.add(daysDifference, "day");
2925
+ const newEnd = originalEnd.add(daysDifference, "day");
2926
+ updateEvent(activeEvent.id, {
2927
+ start: newStart,
2928
+ end: newEnd,
2929
+ originalStart: undefined,
2930
+ originalEnd: undefined
2931
+ });
2932
+ }
2933
+ } else {
2934
+ const newStart = newDate.hour(activeEvent.start.hour()).minute(activeEvent.start.minute());
2935
+ const durationMinutes = activeEvent.end.diff(activeEvent.start, "minute");
2936
+ const newEnd = newStart.add(durationMinutes, "minute");
2937
+ updateEvent(activeEvent.id, {
2938
+ start: newStart,
2939
+ end: newEnd,
2940
+ originalStart: undefined,
2941
+ originalEnd: undefined
2942
+ });
2943
+ }
2944
+ }
2945
+ setActiveEvent(null);
2946
+ };
2947
+ const handleDragCancel = (_event) => {
2948
+ setActiveEvent(null);
2949
+ };
2950
+ if (disableDragAndDrop) {
2951
+ return children;
2952
+ }
2953
+ return /* @__PURE__ */ jsxDEV46(DndContext, {
2954
+ sensors,
2955
+ onDragStart: handleDragStart,
2956
+ onDragEnd: handleDragEnd,
2957
+ onDragCancel: handleDragCancel,
2958
+ collisionDetection: pointerWithin,
2959
+ children: [
2960
+ children,
2961
+ /* @__PURE__ */ jsxDEV46(DragOverlay, {
2962
+ modifiers: [snapCenterToCursor],
2963
+ children: activeEvent && /* @__PURE__ */ jsxDEV46("div", {
2964
+ className: cn("cursor-grab truncate rounded bg-amber-200 p-2 text-[10px] shadow-lg sm:text-xs", activeEvent.backgroundColor || "bg-blue-500", activeEvent.color || "text-white"),
2965
+ children: activeEvent?.title
2966
+ }, undefined, false, undefined, this)
2967
+ }, undefined, false, undefined, this)
2968
+ ]
2969
+ }, undefined, true, undefined, this);
2970
+ }
2971
+
2972
+ // src/contexts/calendar-context/provider.tsx
2973
+ import dayjs17 from "dayjs";
2974
+ import {
2975
+ useCallback as useCallback2,
2976
+ useEffect as useEffect2,
2977
+ useMemo as useMemo6,
2978
+ useState as useState5
2979
+ } from "react";
2980
+ import { jsxDEV as jsxDEV47 } from "react/jsx-dev-runtime";
2981
+ var CalendarProvider = ({
2982
+ children,
2983
+ initialEvents = [],
2984
+ firstDayOfWeek = 0,
2985
+ renderEvent,
2986
+ onEventClick,
2987
+ onCellClick,
2988
+ onViewChange,
2989
+ locale,
2990
+ timezone: timezone2,
2991
+ disableCellClick,
2992
+ disableEventClick,
2993
+ disableDragAndDrop,
2994
+ dayMaxEvents,
2995
+ stickyHeader
2996
+ }) => {
2997
+ const [currentDate, setCurrentDate] = useState5(dayjs17());
2998
+ const [view, setView] = useState5("month");
2999
+ const [events, setEvents] = useState5(initialEvents);
3000
+ const [isEventFormOpen, setIsEventFormOpen] = useState5(false);
3001
+ const [selectedEvent, setSelectedEvent] = useState5(null);
3002
+ const [selectedDate, setSelectedDate] = useState5(null);
3003
+ const [currentLocale, setCurrentLocale] = useState5(locale || "en");
3004
+ useEffect2(() => {
3005
+ if (initialEvents) {
3006
+ setEvents(initialEvents);
3007
+ }
3008
+ }, [initialEvents]);
3009
+ useEffect2(() => {
3010
+ if (locale) {
3011
+ setCurrentLocale(locale);
3012
+ dayjs17.locale(locale);
3013
+ }
3014
+ }, [locale]);
3015
+ useEffect2(() => {
3016
+ if (timezone2) {
3017
+ setCurrentDate((prevDate) => prevDate.tz(timezone2));
3018
+ }
3019
+ }, [timezone2]);
3020
+ const selectDate = useCallback2((date) => {
3021
+ setCurrentDate(date);
3022
+ }, []);
3023
+ const nextPeriod = useCallback2(() => {
3024
+ switch (view) {
3025
+ case "month":
3026
+ setCurrentDate((currentDate2) => currentDate2.add(1, "month"));
3027
+ break;
3028
+ case "week":
3029
+ setCurrentDate((currentDate2) => currentDate2.add(1, "week"));
3030
+ break;
3031
+ case "day":
3032
+ setCurrentDate((currentDate2) => currentDate2.add(1, "day"));
3033
+ break;
3034
+ case "year":
3035
+ setCurrentDate((currentDate2) => currentDate2.add(1, "year"));
3036
+ break;
3037
+ }
3038
+ }, [view]);
3039
+ const prevPeriod = useCallback2(() => {
3040
+ switch (view) {
3041
+ case "month":
3042
+ setCurrentDate((currentDate2) => currentDate2.subtract(1, "month"));
3043
+ break;
3044
+ case "week":
3045
+ setCurrentDate((currentDate2) => currentDate2.subtract(1, "week"));
3046
+ break;
3047
+ case "day":
3048
+ setCurrentDate((currentDate2) => currentDate2.subtract(1, "day"));
3049
+ break;
3050
+ case "year":
3051
+ setCurrentDate((currentDate2) => currentDate2.subtract(1, "year"));
3052
+ break;
3053
+ }
3054
+ }, [view]);
3055
+ const today = useCallback2(() => {
3056
+ setCurrentDate(dayjs17());
3057
+ }, []);
3058
+ const addEvent = useCallback2((event) => {
3059
+ setEvents((prevEvents) => [...prevEvents, event]);
3060
+ }, []);
3061
+ const updateEvent = useCallback2((eventId, updatedEvent) => {
3062
+ setEvents((prevEvents) => prevEvents.map((event) => event.id === eventId ? { ...event, ...updatedEvent } : event));
3063
+ }, []);
3064
+ const deleteEvent = useCallback2((eventId) => {
3065
+ setEvents((prevEvents) => prevEvents.filter((event) => event.id !== eventId));
3066
+ }, []);
3067
+ const editEvent = useCallback2((event) => {
3068
+ setSelectedEvent(event);
3069
+ setIsEventFormOpen(true);
3070
+ }, []);
3071
+ const closeEventForm = useCallback2(() => {
3072
+ setSelectedDate(null);
3073
+ setSelectedEvent(null);
3074
+ setIsEventFormOpen(false);
3075
+ }, []);
3076
+ const handleViewChange = useCallback2((newView) => {
3077
+ setView(newView);
3078
+ onViewChange?.(newView);
3079
+ }, [onViewChange]);
3080
+ const handleEventClick = useCallback2((event) => {
3081
+ if (disableCellClick)
3082
+ return;
3083
+ if (onEventClick) {
3084
+ onEventClick(event);
3085
+ } else {
3086
+ editEvent(event);
3087
+ }
3088
+ }, [disableCellClick, onEventClick, editEvent]);
3089
+ const handleDateClick = useCallback2((startDate, endDate) => {
3090
+ if (disableCellClick)
3091
+ return;
3092
+ if (onCellClick) {
3093
+ onCellClick(startDate, endDate);
3094
+ } else {
3095
+ setSelectedDate(startDate);
3096
+ setSelectedEvent({
3097
+ title: `New Event`,
3098
+ start: startDate,
3099
+ end: endDate,
3100
+ description: "",
3101
+ all_day: false,
3102
+ isRecurring: false,
3103
+ recurrence: null,
3104
+ parentEventId: null
3105
+ });
3106
+ setIsEventFormOpen(true);
3107
+ }
3108
+ }, [onCellClick, disableCellClick]);
3109
+ const getNextOccurrence = useCallback2((date, freq, int, days) => {
3110
+ switch (freq) {
3111
+ case "daily":
3112
+ return date.add(int, "day");
3113
+ case "weekly":
3114
+ if (days && days.length > 0) {
3115
+ let nextDate = date.add(1, "day");
3116
+ let loopCount = 0;
3117
+ while (loopCount < 7) {
3118
+ if (days.includes(nextDate.day())) {
3119
+ return nextDate;
3120
+ }
3121
+ nextDate = nextDate.add(1, "day");
3122
+ loopCount++;
3123
+ }
3124
+ return date.add(int, "week");
3125
+ } else {
3126
+ return date.add(int, "week");
3127
+ }
3128
+ case "monthly":
3129
+ return date.add(int, "month");
3130
+ case "yearly":
3131
+ return date.add(int, "year");
3132
+ }
3133
+ }, []);
3134
+ const expandRecurringEvent = useCallback2((baseEvent, startDate, endDate) => {
3135
+ const expandedEvents = [];
3136
+ if (!baseEvent.recurrence)
3137
+ return [baseEvent];
3138
+ const {
3139
+ frequency,
3140
+ interval,
3141
+ endDate: recurrenceEndDate,
3142
+ count,
3143
+ daysOfWeek,
3144
+ exceptions = []
3145
+ } = baseEvent.recurrence;
3146
+ const existingExceptions = events.filter((event) => event.parentEventId === baseEvent.id && event.isException);
3147
+ const duration = baseEvent.end.diff(baseEvent.start, "minute");
3148
+ const maxEndDate = recurrenceEndDate && recurrenceEndDate.isBefore(endDate) ? recurrenceEndDate : endDate;
3149
+ let currentDate2 = baseEvent.start.clone();
3150
+ let occurrences = 0;
3151
+ if (currentDate2.isAfter(maxEndDate)) {
3152
+ return [];
3153
+ }
3154
+ if (currentDate2.isBefore(startDate)) {
3155
+ switch (frequency) {
3156
+ case "daily": {
3157
+ const daysToAdd = Math.floor(startDate.diff(currentDate2, "day") / interval) * interval;
3158
+ if (daysToAdd > 0) {
3159
+ currentDate2 = currentDate2.add(daysToAdd, "day");
3160
+ }
3161
+ break;
3162
+ }
3163
+ case "weekly": {
3164
+ if (!daysOfWeek || daysOfWeek.length === 0) {
3165
+ const weeksToAdd = Math.floor(startDate.diff(currentDate2, "week") / interval) * interval;
3166
+ if (weeksToAdd > 0) {
3167
+ currentDate2 = currentDate2.add(weeksToAdd, "week");
3168
+ }
3169
+ }
3170
+ break;
3171
+ }
3172
+ case "monthly": {
3173
+ const monthsToAdd = Math.floor(startDate.diff(currentDate2, "month") / interval) * interval;
3174
+ if (monthsToAdd > 0) {
3175
+ currentDate2 = currentDate2.add(monthsToAdd, "month");
3176
+ }
3177
+ break;
3178
+ }
3179
+ case "yearly": {
3180
+ const yearsToAdd = Math.floor(startDate.diff(currentDate2, "year") / interval) * interval;
3181
+ if (yearsToAdd > 0) {
3182
+ currentDate2 = currentDate2.add(yearsToAdd, "year");
3183
+ }
3184
+ break;
3185
+ }
3186
+ }
3187
+ }
3188
+ while ((currentDate2.isBefore(maxEndDate) || currentDate2.isSame(maxEndDate, "day")) && (count === undefined || occurrences < count)) {
3189
+ const currentDateStr = currentDate2.format("YYYY-MM-DD");
3190
+ if (exceptions.some((date) => date.format("YYYY-MM-DD") === currentDateStr)) {
3191
+ currentDate2 = getNextOccurrence(currentDate2, frequency, interval, daysOfWeek);
3192
+ continue;
3193
+ }
3194
+ if (frequency === "weekly" && daysOfWeek && daysOfWeek.length > 0 && !daysOfWeek.includes(currentDate2.day())) {
3195
+ currentDate2 = currentDate2.add(1, "day");
3196
+ continue;
3197
+ }
3198
+ const exceptionEvent = existingExceptions.find((event) => event.start.format("YYYY-MM-DD") === currentDateStr);
3199
+ if (exceptionEvent) {
3200
+ expandedEvents.push(exceptionEvent);
3201
+ } else if (currentDate2.isAfter(startDate.subtract(1, "day"))) {
3202
+ const eventInstance = {
3203
+ ...baseEvent,
3204
+ id: `${baseEvent.id}-${currentDate2.format("YYYYMMDD")}`,
3205
+ start: currentDate2.clone(),
3206
+ end: currentDate2.clone().add(duration, "minute"),
3207
+ isRecurring: true,
3208
+ parentEventId: baseEvent.id
3209
+ };
3210
+ expandedEvents.push(eventInstance);
3211
+ }
3212
+ occurrences++;
3213
+ currentDate2 = getNextOccurrence(currentDate2, frequency, interval, daysOfWeek);
3214
+ }
3215
+ return expandedEvents;
3216
+ }, [events, getNextOccurrence]);
3217
+ const getEventsForDateRange = useCallback2((start, end) => {
3218
+ const startDate = start.startOf("day");
3219
+ const endDate = end.endOf("day");
3220
+ const regularEvents = events.filter((event) => {
3221
+ return (event.start.isAfter(startDate) || event.start.isSame(startDate)) && (event.start.isBefore(endDate) || event.start.isSame(endDate)) || (event.end.isAfter(startDate) || event.end.isSame(startDate)) && (event.end.isBefore(endDate) || event.end.isSame(endDate)) || event.start.isBefore(startDate) && event.end.isAfter(endDate);
3222
+ });
3223
+ const recurringParentEvents = events.filter((event) => event.recurrence && !event.parentEventId);
3224
+ let recurringEvents = [];
3225
+ recurringParentEvents.forEach((parentEvent) => {
3226
+ const expanded = expandRecurringEvent(parentEvent, startDate, endDate);
3227
+ recurringEvents = [...recurringEvents, ...expanded];
3228
+ });
3229
+ return [...regularEvents, ...recurringEvents].filter((event, index, self) => index === self.findIndex((e) => e.id === event.id));
3230
+ }, [events, expandRecurringEvent]);
3231
+ const getEventsForDate = useCallback2((date) => {
3232
+ const day = date.startOf("day");
3233
+ const nextDay = day.add(1, "day");
3234
+ return getEventsForDateRange(day, nextDay);
3235
+ }, [getEventsForDateRange]);
3236
+ const addRecurringEvent = useCallback2((event) => {
3237
+ setEvents((prevEvents) => [...prevEvents, event]);
3238
+ }, []);
3239
+ const deleteRecurringEvent = useCallback2((eventId, deleteAll) => {
3240
+ setEvents((prevEvents) => {
3241
+ const event = prevEvents.find((e) => e.id === eventId);
3242
+ if (!event)
3243
+ return prevEvents;
3244
+ if (event.parentEventId && !deleteAll) {
3245
+ const parentEvent = prevEvents.find((e) => e.id === event.parentEventId);
3246
+ if (!parentEvent || !parentEvent.recurrence)
3247
+ return prevEvents;
3248
+ return prevEvents.map((e) => {
3249
+ if (e.id === event.parentEventId) {
3250
+ return {
3251
+ ...e,
3252
+ recurrence: {
3253
+ ...e.recurrence,
3254
+ exceptions: [
3255
+ ...e.recurrence.exceptions || [],
3256
+ event.start.startOf("day")
3257
+ ]
3258
+ }
3259
+ };
3260
+ }
3261
+ return e;
3262
+ });
3263
+ } else if (event.parentEventId && deleteAll) {
3264
+ return prevEvents.filter((e) => e.id !== event.parentEventId && e.parentEventId !== event.parentEventId);
3265
+ } else if (event.recurrence) {
3266
+ return prevEvents.filter((e) => e.id !== event.id && e.parentEventId !== event.id);
3267
+ } else {
3268
+ return prevEvents.filter((e) => e.id !== event.id);
3269
+ }
3270
+ });
3271
+ }, []);
3272
+ const updateRecurringEvent = useCallback2((eventId, updatedEvent, updateAll) => {
3273
+ setEvents((prevEvents) => {
3274
+ const event = prevEvents.find((e) => e.id === eventId);
3275
+ if (!event)
3276
+ return prevEvents;
3277
+ if (event.parentEventId && !updateAll) {
3278
+ const exceptionEvent = {
3279
+ ...event,
3280
+ ...updatedEvent,
3281
+ isException: true
3282
+ };
3283
+ const updatedEvents = prevEvents.map((e) => {
3284
+ if (e.id === event.parentEventId) {
3285
+ return {
3286
+ ...e,
3287
+ recurrence: {
3288
+ ...e.recurrence,
3289
+ exceptions: [
3290
+ ...e.recurrence.exceptions || [],
3291
+ event.start.startOf("day")
3292
+ ]
3293
+ }
3294
+ };
3295
+ }
3296
+ return e;
3297
+ });
3298
+ return [...updatedEvents, exceptionEvent];
3299
+ } else if (event.parentEventId && updateAll) {
3300
+ return prevEvents.map((e) => {
3301
+ if (e.id === event.parentEventId) {
3302
+ return { ...e, ...updatedEvent };
3303
+ }
3304
+ return e;
3305
+ });
3306
+ } else if (event.recurrence) {
3307
+ return prevEvents.map((e) => {
3308
+ if (e.id === event.id) {
3309
+ return { ...e, ...updatedEvent };
3310
+ }
3311
+ return e;
3312
+ });
3313
+ } else {
3314
+ return prevEvents.map((e) => {
3315
+ if (e.id === event.id) {
3316
+ return { ...e, ...updatedEvent };
3317
+ }
3318
+ return e;
3319
+ });
3320
+ }
3321
+ });
3322
+ }, []);
3323
+ const createExceptionForRecurringEvent = useCallback2((eventId, date) => {
3324
+ setEvents((prevEvents) => {
3325
+ const event = prevEvents.find((e) => e.id === eventId);
3326
+ if (!event || !event.recurrence)
3327
+ return prevEvents;
3328
+ return prevEvents.map((e) => {
3329
+ if (e.id === eventId) {
3330
+ return {
3331
+ ...e,
3332
+ recurrence: {
3333
+ ...e.recurrence,
3334
+ exceptions: [
3335
+ ...e.recurrence.exceptions || [],
3336
+ date.startOf("day")
3337
+ ]
3338
+ }
3339
+ };
3340
+ }
3341
+ return e;
3342
+ });
3343
+ });
3344
+ }, []);
3345
+ const contextValue = useMemo6(() => ({
3346
+ currentDate,
3347
+ view,
3348
+ events,
3349
+ currentLocale,
3350
+ isEventFormOpen,
3351
+ selectedEvent,
3352
+ selectedDate,
3353
+ firstDayOfWeek,
3354
+ setCurrentDate,
3355
+ selectDate,
3356
+ setView: handleViewChange,
3357
+ nextPeriod,
3358
+ prevPeriod,
3359
+ today,
3360
+ addEvent,
3361
+ updateEvent,
3362
+ deleteEvent,
3363
+ openEventForm: () => setIsEventFormOpen(true),
3364
+ closeEventForm,
3365
+ getEventsForDate,
3366
+ getEventsForDateRange,
3367
+ expandRecurringEvent,
3368
+ addRecurringEvent,
3369
+ deleteRecurringEvent,
3370
+ updateRecurringEvent,
3371
+ createExceptionForRecurringEvent,
3372
+ renderEvent,
3373
+ onEventClick: handleEventClick,
3374
+ onCellClick: handleDateClick,
3375
+ locale,
3376
+ timezone: timezone2,
3377
+ disableCellClick,
3378
+ disableEventClick,
3379
+ disableDragAndDrop,
3380
+ dayMaxEvents,
3381
+ stickyHeader
3382
+ }), [
3383
+ currentDate,
3384
+ view,
3385
+ events,
3386
+ currentLocale,
3387
+ isEventFormOpen,
3388
+ selectedEvent,
3389
+ selectedDate,
3390
+ firstDayOfWeek,
3391
+ selectDate,
3392
+ handleViewChange,
3393
+ nextPeriod,
3394
+ prevPeriod,
3395
+ today,
3396
+ addEvent,
3397
+ updateEvent,
3398
+ deleteEvent,
3399
+ closeEventForm,
3400
+ getEventsForDate,
3401
+ getEventsForDateRange,
3402
+ expandRecurringEvent,
3403
+ addRecurringEvent,
3404
+ deleteRecurringEvent,
3405
+ updateRecurringEvent,
3406
+ createExceptionForRecurringEvent,
3407
+ renderEvent,
3408
+ handleEventClick,
3409
+ handleDateClick,
3410
+ locale,
3411
+ timezone2,
3412
+ disableCellClick,
3413
+ disableEventClick,
3414
+ disableDragAndDrop,
3415
+ dayMaxEvents,
3416
+ stickyHeader
3417
+ ]);
3418
+ return /* @__PURE__ */ jsxDEV47(CalendarContext.Provider, {
3419
+ value: contextValue,
3420
+ children
3421
+ }, undefined, false, undefined, this);
3422
+ };
3423
+
3424
+ // src/components/ilamy-calendar/ilamy-calendar.tsx
3425
+ import { jsxDEV as jsxDEV48 } from "react/jsx-dev-runtime";
3426
+ var CalendarContent = () => {
3427
+ const {
3428
+ view,
3429
+ isEventFormOpen,
3430
+ closeEventForm,
3431
+ selectedEvent,
3432
+ selectedDate,
3433
+ addEvent,
3434
+ updateEvent,
3435
+ deleteEvent,
3436
+ dayMaxEvents
3437
+ } = useCalendarContext();
3438
+ const viewMap = {
3439
+ month: /* @__PURE__ */ jsxDEV48(MonthView, {
3440
+ dayMaxEvents
3441
+ }, "month", false, undefined, this),
3442
+ week: /* @__PURE__ */ jsxDEV48(week_view_default, {}, "week", false, undefined, this),
3443
+ day: /* @__PURE__ */ jsxDEV48(day_view_default, {}, "day", false, undefined, this),
3444
+ year: /* @__PURE__ */ jsxDEV48(year_view_default, {}, "year", false, undefined, this)
3445
+ };
3446
+ const handleOnUpdate = (event) => {
3447
+ updateEvent(event.id, event);
3448
+ };
3449
+ const handleOnDelete = (event) => {
3450
+ deleteEvent(event.id);
3451
+ };
3452
+ return /* @__PURE__ */ jsxDEV48("div", {
3453
+ className: "flex flex-col w-full h-full",
3454
+ children: [
3455
+ /* @__PURE__ */ jsxDEV48(base_header_default, {}, undefined, false, undefined, this),
3456
+ /* @__PURE__ */ jsxDEV48(CalendarDndContext, {
3457
+ children: /* @__PURE__ */ jsxDEV48(AnimatePresence8, {
3458
+ mode: "wait",
3459
+ children: /* @__PURE__ */ jsxDEV48(motion8.div, {
3460
+ initial: { opacity: 0, x: 20 },
3461
+ animate: { opacity: 1, x: 0 },
3462
+ exit: { opacity: 0, x: -20 },
3463
+ transition: { duration: 0.1, ease: "easeInOut" },
3464
+ className: "h-full w-full",
3465
+ children: viewMap[view]
3466
+ }, view, false, undefined, this)
3467
+ }, undefined, false, undefined, this)
3468
+ }, undefined, false, undefined, this),
3469
+ isEventFormOpen && /* @__PURE__ */ jsxDEV48(EventForm, {
3470
+ onClose: closeEventForm,
3471
+ selectedEvent,
3472
+ selectedDate,
3473
+ onAdd: addEvent,
3474
+ onUpdate: handleOnUpdate,
3475
+ onDelete: handleOnDelete
3476
+ }, undefined, false, undefined, this)
3477
+ ]
3478
+ }, undefined, true, undefined, this);
3479
+ };
3480
+ var dayNumberMap = {
3481
+ sunday: 0,
3482
+ monday: 1,
3483
+ tuesday: 2,
3484
+ wednesday: 3,
3485
+ thursday: 4,
3486
+ friday: 5,
3487
+ saturday: 6
3488
+ };
3489
+ var DEFAULT_DAY_MAX_EVENTS = 6;
3490
+ var IlamyCalendar = ({
3491
+ events,
3492
+ firstDayOfWeek = "sunday",
3493
+ renderEvent,
3494
+ onEventClick,
3495
+ onCellClick,
3496
+ onViewChange,
3497
+ locale,
3498
+ timezone: timezone2,
3499
+ disableCellClick,
3500
+ disableEventClick,
3501
+ disableDragAndDrop,
3502
+ dayMaxEvents = DEFAULT_DAY_MAX_EVENTS,
3503
+ stickyHeader = true
3504
+ }) => {
3505
+ return /* @__PURE__ */ jsxDEV48(CalendarProvider, {
3506
+ initialEvents: events,
3507
+ firstDayOfWeek: dayNumberMap[firstDayOfWeek],
3508
+ renderEvent,
3509
+ onEventClick,
3510
+ onCellClick,
3511
+ onViewChange,
3512
+ locale,
3513
+ timezone: timezone2,
3514
+ disableCellClick,
3515
+ disableEventClick,
3516
+ disableDragAndDrop,
3517
+ dayMaxEvents,
3518
+ stickyHeader,
3519
+ children: /* @__PURE__ */ jsxDEV48(CalendarContent, {}, undefined, false, undefined, this)
3520
+ }, undefined, false, undefined, this);
3521
+ };
3522
+ export {
3523
+ usePublicCalendarContext as useIlamyCalendarContext,
3524
+ IlamyCalendar
3525
+ };