{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "calendar-widget",
  "type": "registry:component",
  "title": "Calendar Widget",
  "description": "An animated calendar widget featuring progressive blur effects that enhance depth and focus during interaction.",
  "dependencies": [
    "lucide-react",
    "motion"
  ],
  "files": [
    {
      "path": "components/watermelon/calendar-widget.tsx",
      "type": "registry:component",
      "content": "'use client';\n\nimport { useState, useRef, useEffect, type FC } from 'react';\nimport { motion, AnimatePresence } from 'motion/react';\nimport { CalendarDays } from 'lucide-react';\n\nexport interface CalendarEvent {\n  title: string;\n  time: string;\n}\n\nexport interface EventsData {\n  [key: string]: CalendarEvent[];\n}\n\ninterface DateItem {\n  day: number;\n  fullDate: string;\n  month: number;\n  year: number;\n  dateObj: Date;\n  dayOfWeek: number;\n  dayName: string;\n}\n\nexport interface CalendarWidgetProps {\n  events: EventsData;\n  initialSelectedDate: string;\n  currentMonthYear: string;\n}\n\nconst daysOfWeek: string[] = ['S', 'M', 'T', 'W', 'T', 'F', 'S'];\n\nexport const CalendarWidget: FC<CalendarWidgetProps> = ({\n  events,\n  initialSelectedDate,\n  currentMonthYear,\n}) => {\n  const [selectedDate, setSelectedDate] = useState<string>(initialSelectedDate);\n\n  const scrollRef = useRef<HTMLDivElement | null>(null);\n  const isDragging = useRef<boolean>(false);\n  const startX = useRef<number>(0);\n  const scrollLeftStart = useRef<number>(0);\n\n  useEffect(() => {\n    const el = scrollRef.current;\n    if (!el) return;\n\n    const onMouseDown = (e: MouseEvent) => {\n      isDragging.current = true;\n      startX.current = e.pageX - el.offsetLeft;\n      scrollLeftStart.current = el.scrollLeft;\n      el.style.cursor = 'grabbing';\n    };\n\n    const onMouseLeave = () => {\n      isDragging.current = false;\n      el.style.cursor = 'grab';\n    };\n\n    const onMouseUp = () => {\n      isDragging.current = false;\n      el.style.cursor = 'grab';\n    };\n\n    const onMouseMove = (e: MouseEvent) => {\n      if (!isDragging.current) return;\n      e.preventDefault();\n      const x = e.pageX - el.offsetLeft;\n      const walk = (x - startX.current) * 1;\n      el.scrollLeft = scrollLeftStart.current - walk;\n    };\n\n    el.style.cursor = 'grab';\n    el.addEventListener('mousedown', onMouseDown);\n    el.addEventListener('mouseleave', onMouseLeave);\n    el.addEventListener('mouseup', onMouseUp);\n    el.addEventListener('mousemove', onMouseMove);\n\n    return () => {\n      el.removeEventListener('mousedown', onMouseDown);\n      el.removeEventListener('mouseleave', onMouseLeave);\n      el.removeEventListener('mouseup', onMouseUp);\n      el.removeEventListener('mousemove', onMouseMove);\n    };\n  }, []);\n\n  const dates: DateItem[] = Array.from({ length: 92 }, (_, i) => {\n    const date = new Date(2024, 8, 1 + i);\n    return {\n      day: date.getDate(),\n      fullDate: date.toISOString().split('T')[0],\n      month: date.getMonth(),\n      year: date.getFullYear(),\n      dateObj: date,\n      dayOfWeek: date.getDay(),\n      dayName: daysOfWeek[date.getDay()],\n    };\n  });\n\n  return (\n      <div className=\"flex w-[340px] flex-col rounded-[30px] border border-black/10 bg-[#F6F5FA] shadow-lg transition-colors duration-500 select-none dark:border-white/5 dark:bg-zinc-900\">\n        <div className=\"p-4\">\n          <motion.div\n            key={currentMonthYear}\n            initial={{ opacity: 0, y: -5 }}\n            animate={{ opacity: 1, y: 0 }}\n            className=\"ml-2 text-xl font-semibold dark:text-white\"\n          >\n            {currentMonthYear}\n          </motion.div>\n\n          <div className=\"relative\">\n            <div\n              ref={scrollRef}\n              className=\"scrollbar-hide flex gap-2 overflow-x-auto px-2\"\n              style={{ scrollbarWidth: 'none', msOverflowStyle: 'none' }}\n            >\n              {dates.map((date) => {\n                const isSelected = selectedDate === date.fullDate;\n                const hasEvent = events[date.fullDate]?.length > 0;\n\n                return (\n                  <div\n                    key={date.fullDate}\n                    className=\"relative flex min-w-10 flex-col items-center pt-4\"\n                  >\n                    <div\n                      className={`mb-1 text-base font-medium transition-colors duration-300 ${isSelected\n                          ? 'text-black dark:text-white'\n                          : 'text-gray-500 dark:text-zinc-500'\n                        }`}\n                    >\n                      {date.dayName}\n                    </div>\n\n                    <motion.div\n                      className=\"relative flex cursor-pointer flex-col items-center\"\n                      whileTap={{ scale: 0.9 }}\n                      onClick={() => setSelectedDate(date.fullDate)}\n                    >\n                      <div className=\"relative flex h-10 w-10 items-center justify-center\">\n                        {isSelected && (\n                          <motion.div\n                            layoutId=\"selected-date-bg\"\n                            transition={{\n                              type: 'spring',\n                              stiffness: 180,\n                              damping: 22,\n                            }}\n                            className=\"absolute inset-0 rounded-full bg-white shadow-sm dark:bg-zinc-800\"\n                          />\n                        )}\n                        <span\n                          className={`relative z-10 text-base font-medium ${isSelected\n                              ? 'text-black dark:text-white'\n                              : 'text-black/80 dark:text-zinc-400'\n                            }`}\n                        >\n                          {date.day}\n                        </span>\n                      </div>\n                      <AnimatePresence mode=\"popLayout\" initial={false}>\n                        {hasEvent && !isSelected && (\n                          <motion.span\n                            initial={{\n                              opacity: 0,\n                              scale: 0,\n                              filter: 'blur(4px)',\n                            }}\n                            animate={{\n                              opacity: 1,\n                              scale: 1,\n                              filter: 'blur(0px)',\n                            }}\n                            exit={{ opacity: 0, scale: 0, filter: 'blur(4px)' }}\n                            transition={{\n                              duration: 0.3,\n                            }}\n                            className=\"h-1.5 w-1.5 -translate-y-1/2 rounded-full bg-[#cecdd1] will-change-transform dark:bg-zinc-700\"\n                          />\n                        )}\n                      </AnimatePresence>\n                    </motion.div>\n                  </div>\n                );\n              })}\n            </div>\n          </div>\n        </div>\n\n        <div className=\"relative flex h-52 flex-col overflow-hidden rounded-[28px] border border-black/10 bg-white px-4 pt-2 transition-colors duration-500 dark:border-white/10 dark:bg-zinc-950\">\n          <motion.div className=\"no-scrollbar relative h-full overflow-y-scroll\">\n            <AnimatePresence mode=\"popLayout\" initial={false}>\n              {events[selectedDate]?.length ? (\n                <motion.div key=\"list\" className=\"pb-8\">\n                  {events[selectedDate].map((event) => (\n                    <motion.div\n                      key={event.title}\n                      initial={{ opacity: 0, y: 15, filter: 'blur(4px)' }}\n                      animate={{ opacity: 1, y: 0, filter: 'blur(0px)' }}\n                      exit={{ opacity: 0, y: 15, filter: 'blur(4px)' }}\n                      transition={{\n                        duration: 0.3,\n                        ease: 'easeOut',\n                      }}\n                      className=\"flex flex-col border-b border-gray-200 py-2 last:border-b-0 dark:border-zinc-800\"\n                    >\n                      <span className=\"text-base font-medium text-black/70 dark:text-zinc-300\">\n                        {event.title}\n                      </span>\n                      <span className=\"text-base text-gray-500 dark:text-zinc-500\">\n                        {event.time}\n                      </span>\n                    </motion.div>\n                  ))}\n                </motion.div>\n              ) : (\n                <motion.div\n                  key=\"no-events\"\n                  initial={{ opacity: 0, y: 15, filter: 'blur(4px)' }}\n                  animate={{ opacity: 1, y: 0, filter: 'blur(0px)' }}\n                  exit={{ opacity: 0, y: 15, filter: 'blur(4px)' }}\n                  transition={{\n                    duration: 0.3,\n                    ease: 'easeOut',\n                  }}\n                  className=\"flex h-40 flex-col items-center justify-center gap-3\"\n                >\n                  <div className=\"rounded- bg-zinc-100 p-5 dark:bg-zinc-800\">\n                    <CalendarDays className=\"size-8 text-zinc-500 dark:text-zinc-300\" />\n                  </div>\n                  <p className=\"text-sm text-neutral-500 dark:text-zinc-500\">\n                    No Events\n                  </p>\n                </motion.div>\n              )}\n            </AnimatePresence>\n          </motion.div>\n\n          <div className=\"pointer-events-none absolute right-0 bottom-0 left-0 h-16 rounded-b-[30px] bg-linear-to-t from-white via-white/70 to-transparent dark:from-zinc-950 dark:via-zinc-950/20\" />\n        </div>\n      </div>\n  );\n};\n"
    }
  ]
}
