@object-ui/components 0.3.0 → 0.3.1

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.
Files changed (317) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/ISSUES_FOUND.md +128 -0
  3. package/README.md +19 -1
  4. package/README_SHADCN_SYNC.md +281 -0
  5. package/TESTING.md +335 -0
  6. package/dist/index.css +1 -1
  7. package/dist/index.js +30981 -30027
  8. package/dist/index.umd.cjs +30 -39
  9. package/dist/src/hooks/use-mobile.d.ts +7 -0
  10. package/dist/src/index.d.ts +4 -1
  11. package/dist/src/renderers/basic/button-group.d.ts +8 -0
  12. package/dist/src/renderers/basic/div.d.ts +7 -0
  13. package/dist/src/renderers/basic/html.d.ts +7 -0
  14. package/dist/src/renderers/basic/icon.d.ts +7 -0
  15. package/dist/src/renderers/basic/image.d.ts +7 -0
  16. package/dist/src/renderers/basic/navigation-menu.d.ts +8 -0
  17. package/dist/src/renderers/basic/pagination.d.ts +8 -0
  18. package/dist/src/renderers/basic/separator.d.ts +7 -0
  19. package/dist/src/renderers/basic/span.d.ts +7 -0
  20. package/dist/src/renderers/basic/text.d.ts +7 -0
  21. package/dist/src/renderers/complex/carousel.d.ts +7 -0
  22. package/dist/src/renderers/complex/data-table.d.ts +7 -0
  23. package/dist/src/renderers/complex/filter-builder.d.ts +7 -0
  24. package/dist/src/renderers/complex/resizable.d.ts +7 -0
  25. package/dist/src/renderers/complex/scroll-area.d.ts +7 -0
  26. package/dist/src/renderers/complex/table.d.ts +7 -0
  27. package/dist/src/renderers/data-display/alert.d.ts +7 -0
  28. package/dist/src/renderers/data-display/avatar.d.ts +7 -0
  29. package/dist/src/renderers/data-display/badge.d.ts +7 -0
  30. package/dist/src/renderers/data-display/breadcrumb.d.ts +8 -0
  31. package/dist/src/renderers/data-display/kbd.d.ts +8 -0
  32. package/dist/src/renderers/data-display/list.d.ts +7 -0
  33. package/dist/src/renderers/data-display/statistic.d.ts +7 -0
  34. package/dist/src/renderers/data-display/table.d.ts +8 -0
  35. package/dist/src/renderers/data-display/tree-view.d.ts +7 -0
  36. package/dist/src/renderers/disclosure/accordion.d.ts +7 -0
  37. package/dist/src/renderers/disclosure/collapsible.d.ts +7 -0
  38. package/dist/src/renderers/disclosure/toggle-group.d.ts +8 -0
  39. package/dist/src/renderers/feedback/empty.d.ts +8 -0
  40. package/dist/src/renderers/feedback/loading.d.ts +7 -0
  41. package/dist/src/renderers/feedback/progress.d.ts +7 -0
  42. package/dist/src/renderers/feedback/skeleton.d.ts +7 -0
  43. package/dist/src/renderers/feedback/sonner.d.ts +8 -0
  44. package/dist/src/renderers/feedback/spinner.d.ts +8 -0
  45. package/dist/src/renderers/feedback/toast.d.ts +8 -0
  46. package/dist/src/renderers/feedback/toaster.d.ts +7 -0
  47. package/dist/src/renderers/form/button.d.ts +7 -0
  48. package/dist/src/renderers/form/calendar.d.ts +7 -0
  49. package/dist/src/renderers/form/checkbox.d.ts +7 -0
  50. package/dist/src/renderers/form/combobox.d.ts +8 -0
  51. package/dist/src/renderers/form/command.d.ts +8 -0
  52. package/dist/src/renderers/form/date-picker.d.ts +7 -0
  53. package/dist/src/renderers/form/file-upload.d.ts +7 -0
  54. package/dist/src/renderers/form/form.d.ts +7 -0
  55. package/dist/src/renderers/form/input-otp.d.ts +7 -0
  56. package/dist/src/renderers/form/input.d.ts +7 -0
  57. package/dist/src/renderers/form/label.d.ts +7 -0
  58. package/dist/src/renderers/form/radio-group.d.ts +7 -0
  59. package/dist/src/renderers/form/select.d.ts +7 -0
  60. package/dist/src/renderers/form/slider.d.ts +7 -0
  61. package/dist/src/renderers/form/switch.d.ts +7 -0
  62. package/dist/src/renderers/form/textarea.d.ts +7 -0
  63. package/dist/src/renderers/form/toggle.d.ts +7 -0
  64. package/dist/src/renderers/layout/aspect-ratio.d.ts +8 -0
  65. package/dist/src/renderers/layout/card.d.ts +7 -0
  66. package/dist/src/renderers/layout/container.d.ts +7 -0
  67. package/dist/src/renderers/layout/flex.d.ts +7 -0
  68. package/dist/src/renderers/layout/grid.d.ts +7 -0
  69. package/dist/src/renderers/layout/semantic.d.ts +7 -0
  70. package/dist/src/renderers/layout/stack.d.ts +7 -0
  71. package/dist/src/renderers/layout/tabs.d.ts +7 -0
  72. package/dist/src/renderers/navigation/header-bar.d.ts +7 -0
  73. package/dist/src/renderers/navigation/sidebar.d.ts +7 -0
  74. package/dist/src/renderers/overlay/alert-dialog.d.ts +7 -0
  75. package/dist/src/renderers/overlay/context-menu.d.ts +7 -0
  76. package/dist/src/renderers/overlay/dialog.d.ts +7 -0
  77. package/dist/src/renderers/overlay/drawer.d.ts +7 -0
  78. package/dist/src/renderers/overlay/dropdown-menu.d.ts +7 -0
  79. package/dist/src/renderers/overlay/hover-card.d.ts +7 -0
  80. package/dist/src/renderers/overlay/menubar.d.ts +8 -0
  81. package/dist/src/renderers/overlay/popover.d.ts +7 -0
  82. package/dist/src/renderers/overlay/sheet.d.ts +7 -0
  83. package/dist/src/renderers/overlay/tooltip.d.ts +7 -0
  84. package/dist/src/renderers/placeholders.d.ts +9 -0
  85. package/dist/src/ui/accordion.d.ts +7 -0
  86. package/dist/src/ui/alert-dialog.d.ts +7 -0
  87. package/dist/src/ui/alert.d.ts +7 -0
  88. package/dist/src/ui/aspect-ratio.d.ts +7 -0
  89. package/dist/src/ui/avatar.d.ts +7 -0
  90. package/dist/src/ui/badge.d.ts +7 -0
  91. package/dist/src/ui/breadcrumb.d.ts +7 -0
  92. package/dist/src/ui/button.d.ts +10 -5
  93. package/dist/src/ui/calendar.d.ts +14 -7
  94. package/dist/src/ui/card.d.ts +7 -0
  95. package/dist/src/ui/carousel.d.ts +7 -0
  96. package/dist/src/ui/checkbox.d.ts +7 -0
  97. package/dist/src/ui/collapsible.d.ts +7 -0
  98. package/dist/src/ui/combobox.d.ts +22 -0
  99. package/dist/src/ui/command.d.ts +7 -0
  100. package/dist/src/ui/context-menu.d.ts +7 -0
  101. package/dist/src/ui/date-picker.d.ts +15 -0
  102. package/dist/src/ui/dialog.d.ts +7 -0
  103. package/dist/src/ui/drawer.d.ts +7 -0
  104. package/dist/src/ui/dropdown-menu.d.ts +7 -0
  105. package/dist/src/ui/filter-builder.d.ts +7 -0
  106. package/dist/src/ui/form.d.ts +7 -0
  107. package/dist/src/ui/hover-card.d.ts +7 -0
  108. package/dist/src/ui/index.d.ts +10 -5
  109. package/dist/src/ui/input-otp.d.ts +7 -0
  110. package/dist/src/ui/input.d.ts +7 -0
  111. package/dist/src/ui/item.d.ts +7 -0
  112. package/dist/src/ui/kbd.d.ts +7 -0
  113. package/dist/src/ui/label.d.ts +7 -0
  114. package/dist/src/ui/menubar.d.ts +7 -0
  115. package/dist/src/ui/navigation-menu.d.ts +7 -0
  116. package/dist/src/ui/pagination.d.ts +7 -0
  117. package/dist/src/ui/popover.d.ts +7 -0
  118. package/dist/src/ui/progress.d.ts +7 -0
  119. package/dist/src/ui/radio-group.d.ts +7 -0
  120. package/dist/src/ui/resizable.d.ts +7 -0
  121. package/dist/src/ui/scroll-area.d.ts +7 -0
  122. package/dist/src/ui/select.d.ts +9 -2
  123. package/dist/src/ui/separator.d.ts +7 -0
  124. package/dist/src/ui/sheet.d.ts +7 -0
  125. package/dist/src/ui/sidebar.d.ts +14 -9
  126. package/dist/src/ui/skeleton.d.ts +7 -0
  127. package/dist/src/ui/slider.d.ts +7 -0
  128. package/dist/src/ui/spinner.d.ts +7 -0
  129. package/dist/src/ui/switch.d.ts +7 -0
  130. package/dist/src/ui/table.d.ts +15 -8
  131. package/dist/src/ui/tabs.d.ts +7 -0
  132. package/dist/src/ui/textarea.d.ts +7 -0
  133. package/dist/src/ui/toggle-group.d.ts +8 -3
  134. package/dist/src/ui/toggle.d.ts +7 -0
  135. package/dist/src/ui/tooltip.d.ts +7 -0
  136. package/metadata/ObjectGrid.component.yml +72 -0
  137. package/package.json +23 -11
  138. package/postcss.config.js +9 -1
  139. package/shadcn-components.json +310 -0
  140. package/src/__tests__/README.md +124 -0
  141. package/src/__tests__/basic-renderers.test.tsx +255 -0
  142. package/src/__tests__/complex-disclosure-renderers.test.tsx +301 -0
  143. package/src/__tests__/feedback-overlay-renderers.test.tsx +349 -0
  144. package/src/__tests__/form-renderers.test.tsx +364 -0
  145. package/src/__tests__/layout-data-renderers.test.tsx +340 -0
  146. package/src/__tests__/test-utils.tsx +190 -0
  147. package/src/hooks/use-mobile.tsx +8 -0
  148. package/src/index.css +86 -54
  149. package/src/index.test.ts +8 -0
  150. package/src/index.ts +21 -1
  151. package/src/lib/utils.tsx +8 -0
  152. package/src/new-components.test.ts +8 -9
  153. package/src/renderers/basic/button-group.tsx +78 -0
  154. package/src/renderers/basic/div.tsx +9 -1
  155. package/src/renderers/basic/html.tsx +8 -0
  156. package/src/renderers/basic/icon.tsx +66 -3
  157. package/src/renderers/basic/image.tsx +12 -1
  158. package/src/renderers/basic/index.ts +11 -0
  159. package/src/renderers/basic/navigation-menu.tsx +80 -0
  160. package/src/renderers/basic/pagination.tsx +82 -0
  161. package/src/renderers/basic/separator.tsx +9 -1
  162. package/src/renderers/basic/span.tsx +9 -1
  163. package/src/renderers/basic/text.tsx +8 -0
  164. package/src/renderers/complex/__tests__/data-table.test.ts +8 -0
  165. package/src/renderers/complex/carousel.tsx +11 -3
  166. package/src/renderers/complex/data-table.tsx +19 -4
  167. package/src/renderers/complex/filter-builder.tsx +8 -0
  168. package/src/renderers/complex/index.ts +9 -3
  169. package/src/renderers/complex/resizable.tsx +8 -0
  170. package/src/renderers/complex/scroll-area.tsx +8 -0
  171. package/src/renderers/complex/table.tsx +10 -2
  172. package/src/renderers/data-display/alert.tsx +8 -0
  173. package/src/renderers/data-display/avatar.tsx +8 -0
  174. package/src/renderers/data-display/badge.tsx +8 -0
  175. package/src/renderers/data-display/breadcrumb.tsx +59 -0
  176. package/src/renderers/data-display/index.ts +12 -0
  177. package/src/renderers/data-display/kbd.tsx +49 -0
  178. package/src/renderers/data-display/list.tsx +8 -0
  179. package/src/renderers/data-display/statistic.tsx +24 -43
  180. package/src/renderers/data-display/table.tsx +68 -0
  181. package/src/renderers/data-display/tree-view.tsx +26 -37
  182. package/src/renderers/disclosure/accordion.tsx +8 -0
  183. package/src/renderers/disclosure/collapsible.tsx +8 -0
  184. package/src/renderers/disclosure/index.ts +9 -0
  185. package/src/renderers/disclosure/toggle-group.tsx +77 -0
  186. package/src/renderers/feedback/empty.tsx +48 -0
  187. package/src/renderers/feedback/index.ts +12 -0
  188. package/src/renderers/feedback/loading.tsx +8 -0
  189. package/src/renderers/feedback/progress.tsx +8 -0
  190. package/src/renderers/feedback/skeleton.tsx +8 -0
  191. package/src/renderers/feedback/sonner.tsx +55 -0
  192. package/src/renderers/feedback/spinner.tsx +54 -0
  193. package/src/renderers/feedback/toast.tsx +58 -0
  194. package/src/renderers/feedback/toaster.tsx +13 -17
  195. package/src/renderers/form/button.tsx +8 -0
  196. package/src/renderers/form/calendar.tsx +8 -0
  197. package/src/renderers/form/checkbox.tsx +8 -0
  198. package/src/renderers/form/combobox.tsx +47 -0
  199. package/src/renderers/form/command.tsx +57 -0
  200. package/src/renderers/form/date-picker.tsx +10 -2
  201. package/src/renderers/form/file-upload.tsx +10 -2
  202. package/src/renderers/form/form.tsx +12 -3
  203. package/src/renderers/form/index.ts +10 -0
  204. package/src/renderers/form/input-otp.tsx +34 -15
  205. package/src/renderers/form/input.tsx +89 -50
  206. package/src/renderers/form/label.tsx +8 -0
  207. package/src/renderers/form/radio-group.tsx +8 -0
  208. package/src/renderers/form/select.tsx +8 -0
  209. package/src/renderers/form/slider.tsx +16 -1
  210. package/src/renderers/form/switch.tsx +8 -0
  211. package/src/renderers/form/textarea.tsx +8 -0
  212. package/src/renderers/form/toggle.tsx +8 -0
  213. package/src/renderers/index.ts +8 -0
  214. package/src/renderers/layout/aspect-ratio.tsx +50 -0
  215. package/src/renderers/layout/card.tsx +8 -0
  216. package/src/renderers/layout/container.tsx +20 -12
  217. package/src/renderers/layout/flex.tsx +16 -8
  218. package/src/renderers/layout/grid.tsx +8 -0
  219. package/src/renderers/layout/index.ts +9 -0
  220. package/src/renderers/layout/page.tsx +9 -1
  221. package/src/renderers/layout/semantic.tsx +8 -0
  222. package/src/renderers/layout/stack.tsx +16 -8
  223. package/src/renderers/layout/tabs.tsx +8 -0
  224. package/src/renderers/navigation/header-bar.tsx +9 -1
  225. package/src/renderers/navigation/index.ts +8 -0
  226. package/src/renderers/navigation/sidebar.tsx +8 -0
  227. package/src/renderers/overlay/alert-dialog.tsx +8 -0
  228. package/src/renderers/overlay/context-menu.tsx +9 -1
  229. package/src/renderers/overlay/dialog.tsx +8 -0
  230. package/src/renderers/overlay/drawer.tsx +8 -0
  231. package/src/renderers/overlay/dropdown-menu.tsx +8 -0
  232. package/src/renderers/overlay/hover-card.tsx +8 -0
  233. package/src/renderers/overlay/index.ts +9 -0
  234. package/src/renderers/overlay/menubar.tsx +75 -0
  235. package/src/renderers/overlay/popover.tsx +8 -0
  236. package/src/renderers/overlay/sheet.tsx +8 -0
  237. package/src/renderers/overlay/tooltip.tsx +8 -0
  238. package/src/renderers/placeholders.tsx +107 -0
  239. package/src/ui/accordion.tsx +8 -0
  240. package/src/ui/alert-dialog.tsx +8 -0
  241. package/src/ui/alert.tsx +14 -24
  242. package/src/ui/aspect-ratio.tsx +8 -0
  243. package/src/ui/avatar.tsx +8 -0
  244. package/src/ui/badge.tsx +13 -6
  245. package/src/ui/breadcrumb.tsx +8 -0
  246. package/src/ui/button-group.tsx +8 -0
  247. package/src/ui/button.tsx +38 -36
  248. package/src/ui/calendar.tsx +57 -200
  249. package/src/ui/card.tsx +8 -0
  250. package/src/ui/carousel.tsx +8 -0
  251. package/src/ui/checkbox.tsx +8 -0
  252. package/src/ui/collapsible.tsx +8 -0
  253. package/src/ui/combobox.tsx +104 -0
  254. package/src/ui/command.tsx +8 -0
  255. package/src/ui/context-menu.tsx +8 -0
  256. package/src/ui/date-picker.tsx +61 -0
  257. package/src/ui/dialog.tsx +8 -0
  258. package/src/ui/drawer.tsx +8 -0
  259. package/src/ui/dropdown-menu.tsx +8 -0
  260. package/src/ui/empty.tsx +8 -0
  261. package/src/ui/filter-builder.tsx +8 -0
  262. package/src/ui/form.tsx +8 -0
  263. package/src/ui/hover-card.tsx +8 -0
  264. package/src/ui/index.ts +11 -5
  265. package/src/ui/input-otp.tsx +20 -12
  266. package/src/ui/input.tsx +8 -0
  267. package/src/ui/item.tsx +8 -0
  268. package/src/ui/kbd.tsx +8 -0
  269. package/src/ui/label.tsx +8 -0
  270. package/src/ui/menubar.tsx +8 -0
  271. package/src/ui/navigation-menu.tsx +8 -0
  272. package/src/ui/pagination.tsx +8 -0
  273. package/src/ui/popover.tsx +9 -1
  274. package/src/ui/progress.tsx +11 -15
  275. package/src/ui/radio-group.tsx +8 -0
  276. package/src/ui/resizable.tsx +8 -0
  277. package/src/ui/scroll-area.tsx +9 -1
  278. package/src/ui/select.tsx +17 -9
  279. package/src/ui/separator.tsx +8 -0
  280. package/src/ui/sheet.tsx +8 -0
  281. package/src/ui/sidebar.tsx +34 -15
  282. package/src/ui/skeleton.tsx +8 -0
  283. package/src/ui/slider.tsx +8 -0
  284. package/src/ui/sonner.tsx +12 -20
  285. package/src/ui/spinner.tsx +11 -23
  286. package/src/ui/switch.tsx +8 -0
  287. package/src/ui/table.tsx +102 -97
  288. package/src/ui/tabs.tsx +8 -0
  289. package/src/ui/textarea.tsx +8 -0
  290. package/src/ui/toggle-group.tsx +12 -21
  291. package/src/ui/toggle.tsx +15 -12
  292. package/src/ui/tooltip.tsx +8 -0
  293. package/tsconfig.json +2 -1
  294. package/vite.config.ts +11 -1
  295. package/dist/src/index.test.d.ts +0 -1
  296. package/dist/src/new-components.test.d.ts +0 -1
  297. package/dist/src/renderers/complex/__tests__/data-table.test.d.ts +0 -0
  298. package/dist/src/renderers/complex/calendar-view.d.ts +0 -1
  299. package/dist/src/renderers/complex/chatbot.d.ts +0 -1
  300. package/dist/src/renderers/complex/chatbot.test.d.ts +0 -1
  301. package/dist/src/renderers/complex/timeline.d.ts +0 -1
  302. package/dist/src/ui/calendar-view.d.ts +0 -21
  303. package/dist/src/ui/chatbot.d.ts +0 -36
  304. package/dist/src/ui/field.d.ts +0 -24
  305. package/dist/src/ui/input-group.d.ts +0 -16
  306. package/dist/src/ui/timeline.d.ts +0 -25
  307. package/metadata/ObjectTable.component.yml +0 -41
  308. package/src/renderers/complex/calendar-view.tsx +0 -219
  309. package/src/renderers/complex/chatbot.test.ts +0 -44
  310. package/src/renderers/complex/chatbot.tsx +0 -185
  311. package/src/renderers/complex/timeline.tsx +0 -466
  312. package/src/ui/calendar-view.tsx +0 -503
  313. package/src/ui/chatbot.tsx +0 -240
  314. package/src/ui/field.tsx +0 -246
  315. package/src/ui/input-group.tsx +0 -170
  316. package/src/ui/timeline.tsx +0 -266
  317. package/tailwind.config.js +0 -75
@@ -1,503 +0,0 @@
1
- "use client"
2
-
3
- import * as React from "react"
4
- import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react"
5
- import { cn } from "../lib/utils"
6
- import { Button } from "./button"
7
- import {
8
- Select,
9
- SelectContent,
10
- SelectItem,
11
- SelectTrigger,
12
- SelectValue,
13
- } from "./select"
14
-
15
- const DEFAULT_EVENT_COLOR = "bg-blue-500 text-white"
16
-
17
- export interface CalendarEvent {
18
- id: string | number
19
- title: string
20
- start: Date
21
- end?: Date
22
- allDay?: boolean
23
- color?: string
24
- data?: any
25
- }
26
-
27
- export interface CalendarViewProps {
28
- events?: CalendarEvent[]
29
- view?: "month" | "week" | "day"
30
- currentDate?: Date
31
- onEventClick?: (event: CalendarEvent) => void
32
- onDateClick?: (date: Date) => void
33
- onViewChange?: (view: "month" | "week" | "day") => void
34
- onNavigate?: (date: Date) => void
35
- className?: string
36
- }
37
-
38
- function CalendarView({
39
- events = [],
40
- view = "month",
41
- currentDate = new Date(),
42
- onEventClick,
43
- onDateClick,
44
- onViewChange,
45
- onNavigate,
46
- className,
47
- }: CalendarViewProps) {
48
- const [selectedView, setSelectedView] = React.useState(view)
49
- const [selectedDate, setSelectedDate] = React.useState(currentDate)
50
-
51
- const handlePrevious = () => {
52
- const newDate = new Date(selectedDate)
53
- if (selectedView === "month") {
54
- newDate.setMonth(newDate.getMonth() - 1)
55
- } else if (selectedView === "week") {
56
- newDate.setDate(newDate.getDate() - 7)
57
- } else {
58
- newDate.setDate(newDate.getDate() - 1)
59
- }
60
- setSelectedDate(newDate)
61
- onNavigate?.(newDate)
62
- }
63
-
64
- const handleNext = () => {
65
- const newDate = new Date(selectedDate)
66
- if (selectedView === "month") {
67
- newDate.setMonth(newDate.getMonth() + 1)
68
- } else if (selectedView === "week") {
69
- newDate.setDate(newDate.getDate() + 7)
70
- } else {
71
- newDate.setDate(newDate.getDate() + 1)
72
- }
73
- setSelectedDate(newDate)
74
- onNavigate?.(newDate)
75
- }
76
-
77
- const handleToday = () => {
78
- const today = new Date()
79
- setSelectedDate(today)
80
- onNavigate?.(today)
81
- }
82
-
83
- const handleViewChange = (newView: "month" | "week" | "day") => {
84
- setSelectedView(newView)
85
- onViewChange?.(newView)
86
- }
87
-
88
- const getDateLabel = () => {
89
- if (selectedView === "month") {
90
- return selectedDate.toLocaleDateString("default", {
91
- month: "long",
92
- year: "numeric",
93
- })
94
- } else if (selectedView === "week") {
95
- const weekStart = getWeekStart(selectedDate)
96
- const weekEnd = new Date(weekStart)
97
- weekEnd.setDate(weekEnd.getDate() + 6)
98
- return `${weekStart.toLocaleDateString("default", {
99
- month: "short",
100
- day: "numeric",
101
- })} - ${weekEnd.toLocaleDateString("default", {
102
- month: "short",
103
- day: "numeric",
104
- year: "numeric",
105
- })}`
106
- } else {
107
- return selectedDate.toLocaleDateString("default", {
108
- weekday: "long",
109
- month: "long",
110
- day: "numeric",
111
- year: "numeric",
112
- })
113
- }
114
- }
115
-
116
- return (
117
- <div className={cn("flex flex-col h-full bg-background", className)}>
118
- {/* Header */}
119
- <div className="flex items-center justify-between p-4 border-b">
120
- <div className="flex items-center gap-2">
121
- <Button variant="outline" size="sm" onClick={handleToday}>
122
- Today
123
- </Button>
124
- <div className="flex items-center">
125
- <Button
126
- variant="ghost"
127
- size="icon"
128
- onClick={handlePrevious}
129
- className="h-8 w-8"
130
- >
131
- <ChevronLeftIcon className="h-4 w-4" />
132
- </Button>
133
- <Button
134
- variant="ghost"
135
- size="icon"
136
- onClick={handleNext}
137
- className="h-8 w-8"
138
- >
139
- <ChevronRightIcon className="h-4 w-4" />
140
- </Button>
141
- </div>
142
- <h2 className="text-lg font-semibold ml-2">{getDateLabel()}</h2>
143
- </div>
144
- <div className="flex items-center gap-2">
145
- <Select value={selectedView} onValueChange={handleViewChange}>
146
- <SelectTrigger className="w-32">
147
- <SelectValue />
148
- </SelectTrigger>
149
- <SelectContent>
150
- <SelectItem value="day">Day</SelectItem>
151
- <SelectItem value="week">Week</SelectItem>
152
- <SelectItem value="month">Month</SelectItem>
153
- </SelectContent>
154
- </Select>
155
- </div>
156
- </div>
157
-
158
- {/* Calendar Grid */}
159
- <div className="flex-1 overflow-auto">
160
- {selectedView === "month" && (
161
- <MonthView
162
- date={selectedDate}
163
- events={events}
164
- onEventClick={onEventClick}
165
- onDateClick={onDateClick}
166
- />
167
- )}
168
- {selectedView === "week" && (
169
- <WeekView
170
- date={selectedDate}
171
- events={events}
172
- onEventClick={onEventClick}
173
- onDateClick={onDateClick}
174
- />
175
- )}
176
- {selectedView === "day" && (
177
- <DayView
178
- date={selectedDate}
179
- events={events}
180
- onEventClick={onEventClick}
181
- />
182
- )}
183
- </div>
184
- </div>
185
- )
186
- }
187
-
188
- function getWeekStart(date: Date): Date {
189
- const d = new Date(date)
190
- const day = d.getDay()
191
- const diff = d.getDate() - day
192
- return new Date(d.setDate(diff))
193
- }
194
-
195
- function getMonthDays(date: Date): Date[] {
196
- const year = date.getFullYear()
197
- const month = date.getMonth()
198
- const firstDay = new Date(year, month, 1)
199
- const lastDay = new Date(year, month + 1, 0)
200
- const startDay = firstDay.getDay()
201
- const days: Date[] = []
202
-
203
- // Add previous month days
204
- for (let i = startDay - 1; i >= 0; i--) {
205
- const prevDate = new Date(firstDay)
206
- prevDate.setDate(prevDate.getDate() - (i + 1))
207
- days.push(prevDate)
208
- }
209
-
210
- // Add current month days
211
- for (let i = 1; i <= lastDay.getDate(); i++) {
212
- days.push(new Date(year, month, i))
213
- }
214
-
215
- // Add next month days
216
- const remainingDays = 42 - days.length
217
- for (let i = 1; i <= remainingDays; i++) {
218
- const nextDate = new Date(lastDay)
219
- nextDate.setDate(nextDate.getDate() + i)
220
- days.push(nextDate)
221
- }
222
-
223
- return days
224
- }
225
-
226
- function isSameDay(date1: Date, date2: Date): boolean {
227
- return (
228
- date1.getFullYear() === date2.getFullYear() &&
229
- date1.getMonth() === date2.getMonth() &&
230
- date1.getDate() === date2.getDate()
231
- )
232
- }
233
-
234
- function getEventsForDate(date: Date, events: CalendarEvent[]): CalendarEvent[] {
235
- return events.filter((event) => {
236
- const eventStart = new Date(event.start)
237
- const eventEnd = event.end ? new Date(event.end) : new Date(eventStart)
238
-
239
- // Create new date objects for comparison to avoid mutation
240
- const dateStart = new Date(date)
241
- dateStart.setHours(0, 0, 0, 0)
242
- const dateEnd = new Date(date)
243
- dateEnd.setHours(23, 59, 59, 999)
244
-
245
- const eventStartTime = new Date(eventStart)
246
- eventStartTime.setHours(0, 0, 0, 0)
247
- const eventEndTime = new Date(eventEnd)
248
- eventEndTime.setHours(23, 59, 59, 999)
249
-
250
- return dateStart <= eventEndTime && dateEnd >= eventStartTime
251
- })
252
- }
253
-
254
- interface MonthViewProps {
255
- date: Date
256
- events: CalendarEvent[]
257
- onEventClick?: (event: CalendarEvent) => void
258
- onDateClick?: (date: Date) => void
259
- }
260
-
261
- function MonthView({ date, events, onEventClick, onDateClick }: MonthViewProps) {
262
- const days = getMonthDays(date)
263
- const today = new Date()
264
- const weekDays = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
265
-
266
- return (
267
- <div className="flex flex-col h-full">
268
- {/* Week day headers */}
269
- <div className="grid grid-cols-7 border-b">
270
- {weekDays.map((day) => (
271
- <div
272
- key={day}
273
- className="p-2 text-center text-sm font-medium text-muted-foreground border-r last:border-r-0"
274
- >
275
- {day}
276
- </div>
277
- ))}
278
- </div>
279
-
280
- {/* Calendar days */}
281
- <div className="grid grid-cols-7 flex-1 auto-rows-fr">
282
- {days.map((day, index) => {
283
- const dayEvents = getEventsForDate(day, events)
284
- const isCurrentMonth = day.getMonth() === date.getMonth()
285
- const isToday = isSameDay(day, today)
286
-
287
- return (
288
- <div
289
- key={index}
290
- className={cn(
291
- "border-b border-r last:border-r-0 p-2 min-h-[100px] cursor-pointer hover:bg-accent/50",
292
- !isCurrentMonth && "bg-muted/30 text-muted-foreground"
293
- )}
294
- onClick={() => onDateClick?.(day)}
295
- >
296
- <div
297
- className={cn(
298
- "text-sm font-medium mb-1",
299
- isToday &&
300
- "inline-flex items-center justify-center rounded-full bg-primary text-primary-foreground h-6 w-6"
301
- )}
302
- >
303
- {day.getDate()}
304
- </div>
305
- <div className="space-y-1">
306
- {dayEvents.slice(0, 3).map((event) => (
307
- <div
308
- key={event.id}
309
- className={cn(
310
- "text-xs px-2 py-1 rounded truncate cursor-pointer hover:opacity-80",
311
- event.color || DEFAULT_EVENT_COLOR
312
- )}
313
- style={
314
- event.color && event.color.startsWith("#")
315
- ? { backgroundColor: event.color }
316
- : undefined
317
- }
318
- onClick={(e) => {
319
- e.stopPropagation()
320
- onEventClick?.(event)
321
- }}
322
- >
323
- {event.title}
324
- </div>
325
- ))}
326
- {dayEvents.length > 3 && (
327
- <div className="text-xs text-muted-foreground px-2">
328
- +{dayEvents.length - 3} more
329
- </div>
330
- )}
331
- </div>
332
- </div>
333
- )
334
- })}
335
- </div>
336
- </div>
337
- )
338
- }
339
-
340
- interface WeekViewProps {
341
- date: Date
342
- events: CalendarEvent[]
343
- onEventClick?: (event: CalendarEvent) => void
344
- onDateClick?: (date: Date) => void
345
- }
346
-
347
- function WeekView({ date, events, onEventClick, onDateClick }: WeekViewProps) {
348
- const weekStart = getWeekStart(date)
349
- const weekDays = Array.from({ length: 7 }, (_, i) => {
350
- const day = new Date(weekStart)
351
- day.setDate(day.getDate() + i)
352
- return day
353
- })
354
- const today = new Date()
355
-
356
- return (
357
- <div className="flex flex-col h-full">
358
- {/* Week day headers */}
359
- <div className="grid grid-cols-7 border-b">
360
- {weekDays.map((day) => {
361
- const isToday = isSameDay(day, today)
362
- return (
363
- <div
364
- key={day.toISOString()}
365
- className="p-3 text-center border-r last:border-r-0"
366
- >
367
- <div className="text-sm font-medium text-muted-foreground">
368
- {day.toLocaleDateString("default", { weekday: "short" })}
369
- </div>
370
- <div
371
- className={cn(
372
- "text-lg font-semibold mt-1",
373
- isToday &&
374
- "inline-flex items-center justify-center rounded-full bg-primary text-primary-foreground h-8 w-8"
375
- )}
376
- >
377
- {day.getDate()}
378
- </div>
379
- </div>
380
- )
381
- })}
382
- </div>
383
-
384
- {/* Week events */}
385
- <div className="grid grid-cols-7 flex-1">
386
- {weekDays.map((day) => {
387
- const dayEvents = getEventsForDate(day, events)
388
- return (
389
- <div
390
- key={day.toISOString()}
391
- className="border-r last:border-r-0 p-2 min-h-[400px] cursor-pointer hover:bg-accent/50"
392
- onClick={() => onDateClick?.(day)}
393
- >
394
- <div className="space-y-2">
395
- {dayEvents.map((event) => (
396
- <div
397
- key={event.id}
398
- className={cn(
399
- "text-sm px-3 py-2 rounded cursor-pointer hover:opacity-80",
400
- event.color || DEFAULT_EVENT_COLOR
401
- )}
402
- style={
403
- event.color && event.color.startsWith("#")
404
- ? { backgroundColor: event.color }
405
- : undefined
406
- }
407
- onClick={(e) => {
408
- e.stopPropagation()
409
- onEventClick?.(event)
410
- }}
411
- >
412
- <div className="font-medium">{event.title}</div>
413
- {!event.allDay && (
414
- <div className="text-xs opacity-90 mt-1">
415
- {event.start.toLocaleTimeString("default", {
416
- hour: "numeric",
417
- minute: "2-digit",
418
- })}
419
- </div>
420
- )}
421
- </div>
422
- ))}
423
- </div>
424
- </div>
425
- )
426
- })}
427
- </div>
428
- </div>
429
- )
430
- }
431
-
432
- interface DayViewProps {
433
- date: Date
434
- events: CalendarEvent[]
435
- onEventClick?: (event: CalendarEvent) => void
436
- }
437
-
438
- function DayView({ date, events, onEventClick }: DayViewProps) {
439
- const dayEvents = getEventsForDate(date, events)
440
- const hours = Array.from({ length: 24 }, (_, i) => i)
441
-
442
- return (
443
- <div className="flex flex-col h-full">
444
- <div className="flex-1 overflow-auto">
445
- {hours.map((hour) => {
446
- const hourEvents = dayEvents.filter((event) => {
447
- if (event.allDay) return hour === 0
448
- const eventHour = event.start.getHours()
449
- return eventHour === hour
450
- })
451
-
452
- return (
453
- <div key={hour} className="flex border-b min-h-[60px]">
454
- <div className="w-20 p-2 text-sm text-muted-foreground border-r">
455
- {hour === 0
456
- ? "12 AM"
457
- : hour < 12
458
- ? `${hour} AM`
459
- : hour === 12
460
- ? "12 PM"
461
- : `${hour - 12} PM`}
462
- </div>
463
- <div className="flex-1 p-2 space-y-2">
464
- {hourEvents.map((event) => (
465
- <div
466
- key={event.id}
467
- className={cn(
468
- "px-3 py-2 rounded cursor-pointer hover:opacity-80",
469
- event.color || DEFAULT_EVENT_COLOR
470
- )}
471
- style={
472
- event.color && event.color.startsWith("#")
473
- ? { backgroundColor: event.color }
474
- : undefined
475
- }
476
- onClick={() => onEventClick?.(event)}
477
- >
478
- <div className="font-medium">{event.title}</div>
479
- {!event.allDay && (
480
- <div className="text-xs opacity-90 mt-1">
481
- {event.start.toLocaleTimeString("default", {
482
- hour: "numeric",
483
- minute: "2-digit",
484
- })}
485
- {event.end &&
486
- ` - ${event.end.toLocaleTimeString("default", {
487
- hour: "numeric",
488
- minute: "2-digit",
489
- })}`}
490
- </div>
491
- )}
492
- </div>
493
- ))}
494
- </div>
495
- </div>
496
- )
497
- })}
498
- </div>
499
- </div>
500
- )
501
- }
502
-
503
- export { CalendarView }