@anymux/ui-kit 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.
Files changed (244) hide show
  1. package/dist/ExplorerLayout-CSIJd7N4.js +105 -0
  2. package/dist/ExplorerLayout-CSIJd7N4.js.map +1 -0
  3. package/dist/FileBrowserContext-B6jixa2j.js +11 -0
  4. package/dist/FileBrowserContext-B6jixa2j.js.map +1 -0
  5. package/dist/calendar-DSlrbHoj.js +761 -0
  6. package/dist/calendar-DSlrbHoj.js.map +1 -0
  7. package/dist/calendar.d.ts +3 -0
  8. package/dist/calendar.js +3 -0
  9. package/dist/contacts-DQXTZzHc.js +539 -0
  10. package/dist/contacts-DQXTZzHc.js.map +1 -0
  11. package/dist/contacts.d.ts +3 -0
  12. package/dist/contacts.js +3 -0
  13. package/dist/file-browser-m5atC3kF.js +6755 -0
  14. package/dist/file-browser-m5atC3kF.js.map +1 -0
  15. package/dist/file-browser.d.ts +11 -0
  16. package/dist/file-browser.js +9 -0
  17. package/dist/git-B55e6LL-.js +561 -0
  18. package/dist/git-B55e6LL-.js.map +1 -0
  19. package/dist/git.d.ts +2 -0
  20. package/dist/git.js +3 -0
  21. package/dist/iconMap-V4B8P-Uh.js +206 -0
  22. package/dist/iconMap-V4B8P-Uh.js.map +1 -0
  23. package/dist/icons-CIsIOZXR.js +0 -0
  24. package/dist/icons.d.ts +2 -0
  25. package/dist/icons.js +4 -0
  26. package/dist/index-BNmNIWBL.d.ts +71 -0
  27. package/dist/index-BNmNIWBL.d.ts.map +1 -0
  28. package/dist/index-Bryv_GCG.d.ts +1481 -0
  29. package/dist/index-Bryv_GCG.d.ts.map +1 -0
  30. package/dist/index-CuQIjSXs.d.ts +134 -0
  31. package/dist/index-CuQIjSXs.d.ts.map +1 -0
  32. package/dist/index-DSu19mq0.d.ts +153 -0
  33. package/dist/index-DSu19mq0.d.ts.map +1 -0
  34. package/dist/index-DmsyeHFr.d.ts +149 -0
  35. package/dist/index-DmsyeHFr.d.ts.map +1 -0
  36. package/dist/index-DxnJ8FYM.d.ts +17 -0
  37. package/dist/index-DxnJ8FYM.d.ts.map +1 -0
  38. package/dist/index-DzfY1Tok.d.ts +32 -0
  39. package/dist/index-DzfY1Tok.d.ts.map +1 -0
  40. package/dist/index-Ml_SgiKa.d.ts +1847 -0
  41. package/dist/index-Ml_SgiKa.d.ts.map +1 -0
  42. package/dist/index-kHr9udZD.d.ts +1025 -0
  43. package/dist/index-kHr9udZD.d.ts.map +1 -0
  44. package/dist/index.d.ts +11 -0
  45. package/dist/index.js +15 -0
  46. package/dist/layout-Ca_4r8ka.js +89 -0
  47. package/dist/layout-Ca_4r8ka.js.map +1 -0
  48. package/dist/layout.d.ts +2 -0
  49. package/dist/layout.js +5 -0
  50. package/dist/list-CxfT6hix.js +6831 -0
  51. package/dist/list-CxfT6hix.js.map +1 -0
  52. package/dist/list.d.ts +2 -0
  53. package/dist/list.js +5 -0
  54. package/dist/media-DZ292aKK.js +557 -0
  55. package/dist/media-DZ292aKK.js.map +1 -0
  56. package/dist/media.d.ts +3 -0
  57. package/dist/media.js +3 -0
  58. package/dist/tree-Dd9Z0Aso.js +3351 -0
  59. package/dist/tree-Dd9Z0Aso.js.map +1 -0
  60. package/dist/tree.d.ts +2 -0
  61. package/dist/tree.js +6 -0
  62. package/dist/types-common-CB3kRek8.d.ts +26 -0
  63. package/dist/types-common-CB3kRek8.d.ts.map +1 -0
  64. package/dist/utils-B4fdKKsy.js +3 -0
  65. package/package.json +109 -0
  66. package/src/calendar/AgendaView.tsx +37 -0
  67. package/src/calendar/CalendarBrowser.tsx +90 -0
  68. package/src/calendar/CalendarModel.ts +142 -0
  69. package/src/calendar/CalendarSidebar.tsx +81 -0
  70. package/src/calendar/DayView.tsx +76 -0
  71. package/src/calendar/EventCard.tsx +51 -0
  72. package/src/calendar/MockCalendarProvider.ts +98 -0
  73. package/src/calendar/MonthView.tsx +77 -0
  74. package/src/calendar/WeekView.tsx +129 -0
  75. package/src/calendar/index.ts +18 -0
  76. package/src/calendar/types.ts +25 -0
  77. package/src/contacts/ContactAvatar.tsx +35 -0
  78. package/src/contacts/ContactBrowser.tsx +56 -0
  79. package/src/contacts/ContactCard.tsx +37 -0
  80. package/src/contacts/ContactDetail.tsx +63 -0
  81. package/src/contacts/ContactGroupSidebar.tsx +40 -0
  82. package/src/contacts/ContactList.tsx +32 -0
  83. package/src/contacts/ContactListModel.ts +120 -0
  84. package/src/contacts/MockContactProvider.ts +77 -0
  85. package/src/contacts/index.ts +17 -0
  86. package/src/contacts/types.ts +26 -0
  87. package/src/demos/CalendarBrowserDemo.tsx +15 -0
  88. package/src/demos/ContactBrowserDemo.tsx +15 -0
  89. package/src/demos/MediaBrowserDemo.tsx +15 -0
  90. package/src/file-browser/adapters/DocumentViewerAdapter.ts +371 -0
  91. package/src/file-browser/adapters/FileSystemBridge.ts +168 -0
  92. package/src/file-browser/adapters/GitBrowserAdapter.ts +546 -0
  93. package/src/file-browser/adapters/README.md +504 -0
  94. package/src/file-browser/adapters/index.ts +27 -0
  95. package/src/file-browser/adapters/types.ts +70 -0
  96. package/src/file-browser/architecture.md +645 -0
  97. package/src/file-browser/components/CreateItemDialog.tsx +71 -0
  98. package/src/file-browser/components/DeleteConfirmDialog.tsx +58 -0
  99. package/src/file-browser/components/FileBrowser.tsx +473 -0
  100. package/src/file-browser/components/FileBrowserContent.tsx +209 -0
  101. package/src/file-browser/components/FileBrowserHeader.tsx +151 -0
  102. package/src/file-browser/components/FileBrowserToolbar.tsx +145 -0
  103. package/src/file-browser/components/LeftPanel/LeftPanel.tsx +103 -0
  104. package/src/file-browser/components/LeftPanel/LeftPanelTabs.tsx +70 -0
  105. package/src/file-browser/components/LeftPanel/TreeNavigationView.tsx +256 -0
  106. package/src/file-browser/components/PreviewPane.tsx +146 -0
  107. package/src/file-browser/components/RightPanel/FilePreview.tsx +219 -0
  108. package/src/file-browser/components/RightPanel/RightPanel.tsx +186 -0
  109. package/src/file-browser/components/RightPanel/RightPanelToolbar.tsx +113 -0
  110. package/src/file-browser/components/UploadProgress.tsx +123 -0
  111. package/src/file-browser/components/ViewerHost.tsx +208 -0
  112. package/src/file-browser/components/mobile/MobileNavigation.tsx +227 -0
  113. package/src/file-browser/components/navigation/NavigationButtons.tsx +171 -0
  114. package/src/file-browser/components/shared/ErrorBoundary.tsx +116 -0
  115. package/src/file-browser/components/shared/FileBrowserItem.tsx +195 -0
  116. package/src/file-browser/components/shared/FileIcon.tsx +169 -0
  117. package/src/file-browser/components/toolbar/ViewModeToggle.tsx +200 -0
  118. package/src/file-browser/components/views/ListView/ListView.tsx +484 -0
  119. package/src/file-browser/components/views/ThumbnailView/ThumbnailView.tsx +323 -0
  120. package/src/file-browser/components/views/TreeView/TreeNode.tsx +186 -0
  121. package/src/file-browser/components/views/TreeView/TreeNodeList.tsx +191 -0
  122. package/src/file-browser/components/views/TreeView/TreeView.tsx +200 -0
  123. package/src/file-browser/components/views/TreemapView/TreemapView.tsx +339 -0
  124. package/src/file-browser/context/FileBrowserContext.tsx +13 -0
  125. package/src/file-browser/examples/BasicUsage.tsx +20 -0
  126. package/src/file-browser/index.ts +98 -0
  127. package/src/file-browser/models/FileBrowserModel.ts +623 -0
  128. package/src/file-browser/models/LeftPanelManagerModel.ts +105 -0
  129. package/src/file-browser/models/NavigationManagerModel.ts +312 -0
  130. package/src/file-browser/models/ResponsiveLayoutManagerModel.ts +437 -0
  131. package/src/file-browser/models/RightPanelManagerModel.ts +190 -0
  132. package/src/file-browser/models/SelectionManagerModel.ts +252 -0
  133. package/src/file-browser/models/ToolbarManagerModel.ts +144 -0
  134. package/src/file-browser/models/UploadModel.ts +147 -0
  135. package/src/file-browser/models/ViewModeManagerModel.ts +185 -0
  136. package/src/file-browser/models/ViewerHostModel.ts +44 -0
  137. package/src/file-browser/models/ui/ListViewUIModel.ts +265 -0
  138. package/src/file-browser/models/ui/PreviewUIModel.ts +297 -0
  139. package/src/file-browser/models/ui/ThumbnailViewUIModel.ts +254 -0
  140. package/src/file-browser/models/ui/TreeViewUIModel.ts +128 -0
  141. package/src/file-browser/models/ui/TreemapViewUIModel.ts +350 -0
  142. package/src/file-browser/providers/FileSystemListProvider.ts +552 -0
  143. package/src/file-browser/providers/FileSystemProvider.ts +401 -0
  144. package/src/file-browser/providers/FileSystemTreeProvider.ts +231 -0
  145. package/src/file-browser/providers/GitProvider.ts +337 -0
  146. package/src/file-browser/providers/GitRepositoryProvider.ts +376 -0
  147. package/src/file-browser/providers/IFileBrowserProvider.ts +56 -0
  148. package/src/file-browser/providers/MemoryProvider.ts +303 -0
  149. package/src/file-browser/providers/index.ts +4 -0
  150. package/src/file-browser/registry/ViewerRegistry.ts +551 -0
  151. package/src/file-browser/registry/types.ts +144 -0
  152. package/src/file-browser/scripts/performanceBenchmark.ts +553 -0
  153. package/src/file-browser/services/ThumbnailCacheService.ts +128 -0
  154. package/src/file-browser/tasks.md +537 -0
  155. package/src/file-browser/types/FileBrowserTypes.ts +126 -0
  156. package/src/file-browser/types/ProviderTypes.ts +155 -0
  157. package/src/file-browser/types/UITypes.ts +235 -0
  158. package/src/file-browser/types/ViewModeTypes.ts +150 -0
  159. package/src/file-browser/utils/gestures.ts +327 -0
  160. package/src/file-browser/utils/performance.ts +563 -0
  161. package/src/file-browser/viewers/ImageViewer.tsx +163 -0
  162. package/src/file-browser/viewers/ImageViewerModel.ts +79 -0
  163. package/src/file-browser/viewers/TextViewer.tsx +95 -0
  164. package/src/file-browser/viewers/UnsupportedFileViewer.tsx +57 -0
  165. package/src/file-browser/viewers/index.ts +61 -0
  166. package/src/git/BranchList.tsx +128 -0
  167. package/src/git/CommitGraph.tsx +239 -0
  168. package/src/git/CommitList.tsx +258 -0
  169. package/src/git/DiffViewer.tsx +219 -0
  170. package/src/git/index.ts +4 -0
  171. package/src/icons/iconMap.ts +146 -0
  172. package/src/icons/index.ts +9 -0
  173. package/src/index.ts +13 -0
  174. package/src/layout/README.md +307 -0
  175. package/src/layout/components/ExplorerLayout/ExplorerLayout.tsx +178 -0
  176. package/src/layout/examples/SimpleExample.tsx +60 -0
  177. package/src/layout/index.ts +6 -0
  178. package/src/lib/utils.ts +1 -0
  179. package/src/list/README.md +303 -0
  180. package/src/list/architecture.md +807 -0
  181. package/src/list/components/CalculatedGridView.tsx +252 -0
  182. package/src/list/components/DragPreview.tsx +102 -0
  183. package/src/list/components/ListContextMenu.tsx +274 -0
  184. package/src/list/components/ListItem.tsx +761 -0
  185. package/src/list/components/ListItems.tsx +919 -0
  186. package/src/list/components/MasonryView.tsx +241 -0
  187. package/src/list/components/SearchFilter.tsx +44 -0
  188. package/src/list/components/TreemapView.tsx +709 -0
  189. package/src/list/components/ViewSizeControls.tsx +205 -0
  190. package/src/list/components/ViewTypeSelector.tsx +312 -0
  191. package/src/list/components/VirtualizedDetailsView.tsx +231 -0
  192. package/src/list/components/VirtualizedGrid.tsx +164 -0
  193. package/src/list/components/VirtualizedList.tsx +154 -0
  194. package/src/list/components/VirtualizedMasonryView.tsx +344 -0
  195. package/src/list/components/shared/EmptyState.tsx +103 -0
  196. package/src/list/components/shared/ErrorBoundary.tsx +123 -0
  197. package/src/list/components/shared/ErrorDisplay.tsx +100 -0
  198. package/src/list/components/shared/ListLoader.tsx +146 -0
  199. package/src/list/components/shared/LoadingIndicator.tsx +80 -0
  200. package/src/list/index.ts +92 -0
  201. package/src/list/models/ListItemsModel.ts +1301 -0
  202. package/src/list/models/TreemapModel.ts +204 -0
  203. package/src/list/providers/ListItemsProvider.ts +313 -0
  204. package/src/list/providers/TestListProvider.ts +604 -0
  205. package/src/list/tasks.md +937 -0
  206. package/src/list/types/ListTypes.ts +178 -0
  207. package/src/list/utils/BenchmarkLogger.ts +243 -0
  208. package/src/list/utils/DragDropManager.ts +320 -0
  209. package/src/list/utils/GridLayoutCalculator.ts +290 -0
  210. package/src/list/utils/ListAccessibility.ts +367 -0
  211. package/src/list/utils/ListKeyboard.ts +414 -0
  212. package/src/list/utils/MasonryLayoutCalculator.ts +302 -0
  213. package/src/list/utils/MasonryLayoutEngine.ts +401 -0
  214. package/src/list/utils/__tests__/MasonryLayoutEngine.test.ts +157 -0
  215. package/src/list/utils/__tests__/VirtualizedMasonryView.test.tsx +251 -0
  216. package/src/media/AlbumSidebar.tsx +48 -0
  217. package/src/media/MediaBrowser.tsx +92 -0
  218. package/src/media/MediaBrowserModel.ts +138 -0
  219. package/src/media/MediaGrid.tsx +50 -0
  220. package/src/media/MediaList.tsx +49 -0
  221. package/src/media/MediaPreview.tsx +63 -0
  222. package/src/media/MediaTimeline.tsx +38 -0
  223. package/src/media/MockMediaProvider.ts +70 -0
  224. package/src/media/index.ts +18 -0
  225. package/src/media/types.ts +21 -0
  226. package/src/styles/variables.css +60 -0
  227. package/src/tree/DEVELOPMENT_SUMMARY.md +170 -0
  228. package/src/tree/__tests__/TreeModel.test.ts +16 -0
  229. package/src/tree/architecture.md +530 -0
  230. package/src/tree/components/Tree.tsx +283 -0
  231. package/src/tree/components/TreeCheckbox.tsx +147 -0
  232. package/src/tree/components/TreeContextMenu.tsx +139 -0
  233. package/src/tree/components/TreeNodeList.tsx +329 -0
  234. package/src/tree/components/TreeTable.tsx +382 -0
  235. package/src/tree/index.ts +58 -0
  236. package/src/tree/models/TreeModel.ts +839 -0
  237. package/src/tree/providers/SimpleTreeProvider.ts +463 -0
  238. package/src/tree/providers/TestTreeProvider.ts +946 -0
  239. package/src/tree/providers/TreeProvider.ts +308 -0
  240. package/src/tree/tasks.md +2046 -0
  241. package/src/tree/types/TreeTypes.ts +279 -0
  242. package/src/tree/utils/SelectionTheme.ts +150 -0
  243. package/src/tree/utils/logger.ts +203 -0
  244. package/src/types-common.ts +21 -0
@@ -0,0 +1,761 @@
1
+ import React, { useEffect } from "react";
2
+ import { observer } from "mobx-react-lite";
3
+ import { ChevronLeft, ChevronRight, Clock, Loader2, MapPin } from "lucide-react";
4
+ import { BrowserError } from "@anymux/ui/components/browser-error";
5
+ import { flow, makeAutoObservable } from "mobx";
6
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
7
+
8
+ //#region src/calendar/CalendarModel.ts
9
+ var CalendarModel = class {
10
+ constructor(provider) {
11
+ this.provider = provider;
12
+ this.events = [];
13
+ this.calendars = [];
14
+ this.currentDate = new Date();
15
+ this.viewMode = "month";
16
+ this.selectedEvent = null;
17
+ this.loading = false;
18
+ this.error = null;
19
+ this.loadEvents = flow(function* () {
20
+ this.loading = true;
21
+ this.error = null;
22
+ try {
23
+ const { start, end } = this.visibleDateRange;
24
+ const [events, calendars] = yield Promise.all([this.provider.getEventsByRange(start, end), this.provider.getCalendars()]);
25
+ this.events = events;
26
+ this.calendars = calendars;
27
+ } catch (err) {
28
+ this.error = err?.message || "Failed to load calendar events";
29
+ } finally {
30
+ this.loading = false;
31
+ }
32
+ });
33
+ this.createEvent = flow(function* (event) {
34
+ const created = yield this.provider.createItem(event);
35
+ this.events.push(created);
36
+ return created;
37
+ });
38
+ this.deleteEvent = flow(function* (id) {
39
+ yield this.provider.deleteItem(id);
40
+ this.events = this.events.filter((e) => e.id !== id);
41
+ if (this.selectedEvent?.id === id) this.selectedEvent = null;
42
+ });
43
+ makeAutoObservable(this);
44
+ }
45
+ get visibleDateRange() {
46
+ const d = this.currentDate;
47
+ switch (this.viewMode) {
48
+ case "month": {
49
+ const start = new Date(d.getFullYear(), d.getMonth(), 1);
50
+ start.setDate(start.getDate() - start.getDay());
51
+ const end = new Date(d.getFullYear(), d.getMonth() + 1, 0);
52
+ end.setDate(end.getDate() + (6 - end.getDay()));
53
+ return {
54
+ start,
55
+ end
56
+ };
57
+ }
58
+ case "week": {
59
+ const start = new Date(d);
60
+ start.setDate(d.getDate() - d.getDay());
61
+ start.setHours(0, 0, 0, 0);
62
+ const end = new Date(start);
63
+ end.setDate(start.getDate() + 6);
64
+ end.setHours(23, 59, 59, 999);
65
+ return {
66
+ start,
67
+ end
68
+ };
69
+ }
70
+ case "day": {
71
+ const start = new Date(d);
72
+ start.setHours(0, 0, 0, 0);
73
+ const end = new Date(d);
74
+ end.setHours(23, 59, 59, 999);
75
+ return {
76
+ start,
77
+ end
78
+ };
79
+ }
80
+ case "agenda": {
81
+ const start = new Date(d);
82
+ start.setHours(0, 0, 0, 0);
83
+ const end = new Date(d);
84
+ end.setDate(end.getDate() + 30);
85
+ return {
86
+ start,
87
+ end
88
+ };
89
+ }
90
+ }
91
+ }
92
+ get eventsForCurrentView() {
93
+ const { start, end } = this.visibleDateRange;
94
+ return this.events.filter((e) => e.endDate >= start && e.startDate <= end);
95
+ }
96
+ get eventsByDay() {
97
+ const map = new Map();
98
+ for (const event of this.eventsForCurrentView) {
99
+ const key = event.startDate.toISOString().slice(0, 10);
100
+ const list = map.get(key) ?? [];
101
+ list.push(event);
102
+ map.set(key, list);
103
+ }
104
+ return map;
105
+ }
106
+ selectEvent(event) {
107
+ this.selectedEvent = event;
108
+ }
109
+ setDate(date) {
110
+ this.currentDate = date;
111
+ this.loadEvents();
112
+ }
113
+ setViewMode(mode) {
114
+ this.viewMode = mode;
115
+ this.loadEvents();
116
+ }
117
+ navigateForward() {
118
+ const d = new Date(this.currentDate);
119
+ switch (this.viewMode) {
120
+ case "month":
121
+ d.setMonth(d.getMonth() + 1);
122
+ break;
123
+ case "week":
124
+ d.setDate(d.getDate() + 7);
125
+ break;
126
+ case "day":
127
+ d.setDate(d.getDate() + 1);
128
+ break;
129
+ case "agenda":
130
+ d.setDate(d.getDate() + 30);
131
+ break;
132
+ }
133
+ this.setDate(d);
134
+ }
135
+ navigateBack() {
136
+ const d = new Date(this.currentDate);
137
+ switch (this.viewMode) {
138
+ case "month":
139
+ d.setMonth(d.getMonth() - 1);
140
+ break;
141
+ case "week":
142
+ d.setDate(d.getDate() - 7);
143
+ break;
144
+ case "day":
145
+ d.setDate(d.getDate() - 1);
146
+ break;
147
+ case "agenda":
148
+ d.setDate(d.getDate() - 30);
149
+ break;
150
+ }
151
+ this.setDate(d);
152
+ }
153
+ today() {
154
+ this.setDate(new Date());
155
+ }
156
+ };
157
+
158
+ //#endregion
159
+ //#region src/calendar/EventCard.tsx
160
+ const formatTime = (d) => d.toLocaleTimeString([], {
161
+ hour: "2-digit",
162
+ minute: "2-digit"
163
+ });
164
+ const EventCard = ({ event, compact = false, onClick, className = "" }) => {
165
+ const color = event.color ?? "#3b82f6";
166
+ if (compact) return /* @__PURE__ */ jsx("button", {
167
+ onClick,
168
+ className: `text-left text-xs px-1.5 py-0.5 rounded truncate w-full hover:opacity-80 transition-opacity ${className}`,
169
+ style: {
170
+ backgroundColor: `${color}20`,
171
+ color,
172
+ borderLeft: `2px solid ${color}`
173
+ },
174
+ title: event.title,
175
+ children: event.title
176
+ });
177
+ return /* @__PURE__ */ jsxs("button", {
178
+ onClick,
179
+ className: `text-left w-full p-3 rounded-lg border border-gray-200 hover:shadow-sm transition-shadow ${className}`,
180
+ style: {
181
+ borderLeftWidth: "3px",
182
+ borderLeftColor: color
183
+ },
184
+ children: [/* @__PURE__ */ jsx("p", {
185
+ className: "text-sm font-medium text-gray-900 truncate",
186
+ title: event.title,
187
+ children: event.title
188
+ }), /* @__PURE__ */ jsxs("div", {
189
+ className: "mt-1 flex items-center gap-3 text-xs text-gray-500",
190
+ children: [/* @__PURE__ */ jsxs("span", {
191
+ className: "flex items-center gap-1",
192
+ children: [/* @__PURE__ */ jsx(Clock, { size: 12 }), event.allDay ? "All day" : `${formatTime(event.startDate)} - ${formatTime(event.endDate)}`]
193
+ }), event.location && /* @__PURE__ */ jsxs("span", {
194
+ className: "flex items-center gap-1",
195
+ children: [/* @__PURE__ */ jsx(MapPin, { size: 12 }), event.location]
196
+ })]
197
+ })]
198
+ });
199
+ };
200
+
201
+ //#endregion
202
+ //#region src/calendar/MonthView.tsx
203
+ const DAYS$1 = [
204
+ "Sunday",
205
+ "Monday",
206
+ "Tuesday",
207
+ "Wednesday",
208
+ "Thursday",
209
+ "Friday",
210
+ "Saturday"
211
+ ];
212
+ const MonthView = observer(({ model, className = "" }) => {
213
+ const d = model.currentDate;
214
+ const year = d.getFullYear();
215
+ const month = d.getMonth();
216
+ const today = new Date();
217
+ const firstDay = new Date(year, month, 1).getDay();
218
+ const daysInMonth = new Date(year, month + 1, 0).getDate();
219
+ const weeks = [];
220
+ let week = [];
221
+ for (let i = 0; i < firstDay; i++) week.push(null);
222
+ for (let day = 1; day <= daysInMonth; day++) {
223
+ week.push(day);
224
+ if (week.length === 7) {
225
+ weeks.push(week);
226
+ week = [];
227
+ }
228
+ }
229
+ if (week.length > 0) {
230
+ while (week.length < 7) week.push(null);
231
+ weeks.push(week);
232
+ }
233
+ const isToday = (day) => day === today.getDate() && month === today.getMonth() && year === today.getFullYear();
234
+ return /* @__PURE__ */ jsxs("div", {
235
+ className: `flex flex-col h-full ${className}`,
236
+ children: [/* @__PURE__ */ jsx("div", {
237
+ className: "grid grid-cols-7 border-b border-gray-200",
238
+ children: DAYS$1.map((day) => /* @__PURE__ */ jsx("div", {
239
+ className: "px-2 py-2 text-xs font-medium text-gray-500 text-center",
240
+ children: day.slice(0, 3)
241
+ }, day))
242
+ }), /* @__PURE__ */ jsx("div", {
243
+ className: "flex-1 grid grid-rows-[repeat(auto-fill,1fr)]",
244
+ children: weeks.map((week$1, wi) => /* @__PURE__ */ jsx("div", {
245
+ className: "grid grid-cols-7 border-b border-gray-100 min-h-[80px]",
246
+ children: week$1.map((day, di) => {
247
+ const dateKey = day ? `${year}-${String(month + 1).padStart(2, "0")}-${String(day).padStart(2, "0")}` : null;
248
+ const events = dateKey ? model.eventsByDay.get(dateKey) ?? [] : [];
249
+ return /* @__PURE__ */ jsx("div", {
250
+ className: `border-r border-gray-100 p-1 ${day === null ? "bg-gray-50" : ""}`,
251
+ children: day !== null && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("div", {
252
+ className: `text-xs mb-0.5 w-6 h-6 flex items-center justify-center rounded-full ${isToday(day) ? "bg-blue-500 text-white font-bold" : "text-gray-700"}`,
253
+ children: day
254
+ }), /* @__PURE__ */ jsxs("div", {
255
+ className: "space-y-0.5",
256
+ children: [events.slice(0, 3).map((ev) => /* @__PURE__ */ jsx(EventCard, {
257
+ event: ev,
258
+ compact: true,
259
+ onClick: () => model.selectEvent(ev)
260
+ }, ev.id)), events.length > 3 && /* @__PURE__ */ jsxs("p", {
261
+ className: "text-[10px] text-gray-400 pl-1",
262
+ children: [
263
+ "+",
264
+ events.length - 3,
265
+ " more"
266
+ ]
267
+ })]
268
+ })] })
269
+ }, di);
270
+ })
271
+ }, wi))
272
+ })]
273
+ });
274
+ });
275
+
276
+ //#endregion
277
+ //#region src/calendar/WeekView.tsx
278
+ const HOURS$1 = Array.from({ length: 24 }, (_, i) => i);
279
+ const WeekView = observer(({ model, className = "" }) => {
280
+ const { start } = model.visibleDateRange;
281
+ const days = Array.from({ length: 7 }, (_, i) => {
282
+ const d = new Date(start);
283
+ d.setDate(start.getDate() + i);
284
+ return d;
285
+ });
286
+ const now = new Date();
287
+ const isToday = (d) => d.toDateString() === now.toDateString();
288
+ const currentHour = now.getHours();
289
+ const currentMinute = now.getMinutes();
290
+ const allDayEventsByDay = days.map((d) => {
291
+ const dateKey = d.toISOString().slice(0, 10);
292
+ return (model.eventsByDay.get(dateKey) ?? []).filter((e) => e.allDay);
293
+ });
294
+ const hasAllDay = allDayEventsByDay.some((events) => events.length > 0);
295
+ return /* @__PURE__ */ jsxs("div", {
296
+ className: `flex flex-col h-full overflow-auto ${className}`,
297
+ children: [/* @__PURE__ */ jsxs("div", {
298
+ className: "sticky top-0 bg-white z-10 border-b border-gray-200",
299
+ children: [/* @__PURE__ */ jsxs("div", {
300
+ className: "grid",
301
+ style: { gridTemplateColumns: "60px repeat(7, 1fr)" },
302
+ children: [/* @__PURE__ */ jsx("div", {}), days.map((d, i) => /* @__PURE__ */ jsxs("div", {
303
+ className: `text-center py-2 border-l border-gray-100 ${isToday(d) ? "bg-blue-50" : ""}`,
304
+ children: [/* @__PURE__ */ jsx("div", {
305
+ className: "text-xs text-gray-500",
306
+ children: d.toLocaleDateString(void 0, { weekday: "short" })
307
+ }), /* @__PURE__ */ jsx("div", {
308
+ className: `text-lg font-medium ${isToday(d) ? "text-blue-600" : "text-gray-900"}`,
309
+ children: d.getDate()
310
+ })]
311
+ }, i))]
312
+ }), hasAllDay && /* @__PURE__ */ jsxs("div", {
313
+ className: "grid border-t border-gray-100",
314
+ style: { gridTemplateColumns: "60px repeat(7, 1fr)" },
315
+ children: [/* @__PURE__ */ jsx("div", {
316
+ className: "text-[10px] text-gray-400 text-right pr-2 py-1",
317
+ children: "all-day"
318
+ }), allDayEventsByDay.map((events, i) => /* @__PURE__ */ jsx("div", {
319
+ className: "border-l border-gray-100 px-0.5 py-0.5 space-y-0.5",
320
+ children: events.map((ev) => /* @__PURE__ */ jsx("button", {
321
+ onClick: () => model.selectEvent(ev),
322
+ className: "w-full text-left text-[10px] px-1 py-0.5 rounded truncate",
323
+ style: {
324
+ backgroundColor: `${ev.color ?? "#3b82f6"}20`,
325
+ color: ev.color ?? "#3b82f6",
326
+ borderLeft: `2px solid ${ev.color ?? "#3b82f6"}`
327
+ },
328
+ title: ev.title,
329
+ children: ev.title
330
+ }, ev.id))
331
+ }, i))]
332
+ })]
333
+ }), /* @__PURE__ */ jsx("div", {
334
+ className: "flex-1 relative",
335
+ children: HOURS$1.map((hour) => /* @__PURE__ */ jsxs("div", {
336
+ className: "grid border-b border-gray-50",
337
+ style: {
338
+ gridTemplateColumns: "60px repeat(7, 1fr)",
339
+ height: "48px"
340
+ },
341
+ children: [/* @__PURE__ */ jsx("div", {
342
+ className: "text-[10px] text-gray-400 text-right pr-2 -mt-2",
343
+ children: hour === 0 ? "" : `${hour % 12 || 12} ${hour < 12 ? "AM" : "PM"}`
344
+ }), days.map((d, i) => {
345
+ const dateKey = d.toISOString().slice(0, 10);
346
+ const events = (model.eventsByDay.get(dateKey) ?? []).filter((e) => !e.allDay && e.startDate.getHours() === hour);
347
+ const showTimeLine = isToday(d) && hour === currentHour;
348
+ return /* @__PURE__ */ jsxs("div", {
349
+ className: "border-l border-gray-100 relative",
350
+ children: [showTimeLine && /* @__PURE__ */ jsxs("div", {
351
+ className: "absolute left-0 right-0 z-10 pointer-events-none",
352
+ style: { top: `${currentMinute / 60 * 48}px` },
353
+ children: [/* @__PURE__ */ jsx("div", { className: "w-2 h-2 bg-red-500 rounded-full absolute -left-1 -top-1" }), /* @__PURE__ */ jsx("div", { className: "h-px bg-red-500 w-full" })]
354
+ }), events.map((ev, ei) => {
355
+ const durationHours = Math.max(.5, (ev.endDate.getTime() - ev.startDate.getTime()) / 36e5);
356
+ const topOffset = ev.startDate.getMinutes() / 60 * 48;
357
+ return /* @__PURE__ */ jsx("button", {
358
+ onClick: () => model.selectEvent(ev),
359
+ className: "absolute text-xs px-1 py-0.5 rounded truncate z-[1]",
360
+ title: ev.title,
361
+ style: {
362
+ backgroundColor: `${ev.color ?? "#3b82f6"}20`,
363
+ color: ev.color ?? "#3b82f6",
364
+ borderLeft: `2px solid ${ev.color ?? "#3b82f6"}`,
365
+ height: `${durationHours * 48}px`,
366
+ top: `${topOffset}px`,
367
+ left: `${ei * 4 + 2}px`,
368
+ right: "2px"
369
+ },
370
+ children: ev.title
371
+ }, ev.id);
372
+ })]
373
+ }, i);
374
+ })]
375
+ }, hour))
376
+ })]
377
+ });
378
+ });
379
+
380
+ //#endregion
381
+ //#region src/calendar/DayView.tsx
382
+ const HOURS = Array.from({ length: 24 }, (_, i) => i);
383
+ const DayView = observer(({ model, className = "" }) => {
384
+ const d = model.currentDate;
385
+ const dateKey = d.toISOString().slice(0, 10);
386
+ const dayEvents = model.eventsByDay.get(dateKey) ?? [];
387
+ const allDayEvents = dayEvents.filter((e) => e.allDay);
388
+ const timedEvents = dayEvents.filter((e) => !e.allDay);
389
+ return /* @__PURE__ */ jsxs("div", {
390
+ className: `flex flex-col h-full overflow-auto ${className}`,
391
+ children: [/* @__PURE__ */ jsxs("div", {
392
+ className: "border-b border-gray-200 px-4 py-2 sticky top-0 bg-white z-10",
393
+ children: [/* @__PURE__ */ jsx("h2", {
394
+ className: "text-lg font-medium text-gray-900",
395
+ children: d.toLocaleDateString(void 0, {
396
+ weekday: "long",
397
+ month: "long",
398
+ day: "numeric"
399
+ })
400
+ }), allDayEvents.length > 0 && /* @__PURE__ */ jsx("div", {
401
+ className: "flex gap-1 mt-1",
402
+ children: allDayEvents.map((ev) => /* @__PURE__ */ jsx("button", {
403
+ onClick: () => model.selectEvent(ev),
404
+ className: "text-xs px-2 py-0.5 rounded",
405
+ style: {
406
+ backgroundColor: `${ev.color ?? "#3b82f6"}20`,
407
+ color: ev.color ?? "#3b82f6"
408
+ },
409
+ children: ev.title
410
+ }, ev.id))
411
+ })]
412
+ }), /* @__PURE__ */ jsx("div", {
413
+ className: "flex-1",
414
+ children: HOURS.map((hour) => {
415
+ const hourEvents = timedEvents.filter((e) => e.startDate.getHours() === hour);
416
+ return /* @__PURE__ */ jsxs("div", {
417
+ className: "grid grid-cols-[60px_1fr] border-b border-gray-50 min-h-[48px]",
418
+ children: [/* @__PURE__ */ jsx("div", {
419
+ className: "text-[10px] text-gray-400 text-right pr-2 -mt-2",
420
+ children: hour === 0 ? "" : `${hour % 12 || 12} ${hour < 12 ? "AM" : "PM"}`
421
+ }), /* @__PURE__ */ jsx("div", {
422
+ className: "border-l border-gray-100 relative pl-1",
423
+ children: hourEvents.map((ev) => /* @__PURE__ */ jsxs("button", {
424
+ onClick: () => model.selectEvent(ev),
425
+ className: "w-full text-left text-xs p-1.5 rounded mb-0.5",
426
+ style: {
427
+ backgroundColor: `${ev.color ?? "#3b82f6"}15`,
428
+ color: ev.color ?? "#3b82f6",
429
+ borderLeft: `2px solid ${ev.color ?? "#3b82f6"}`
430
+ },
431
+ children: [/* @__PURE__ */ jsx("span", {
432
+ className: "font-medium",
433
+ children: ev.title
434
+ }), /* @__PURE__ */ jsx("span", {
435
+ className: "ml-2 opacity-70",
436
+ children: ev.startDate.toLocaleTimeString([], {
437
+ hour: "2-digit",
438
+ minute: "2-digit"
439
+ })
440
+ })]
441
+ }, ev.id))
442
+ })]
443
+ }, hour);
444
+ })
445
+ })]
446
+ });
447
+ });
448
+
449
+ //#endregion
450
+ //#region src/calendar/AgendaView.tsx
451
+ const AgendaView = observer(({ model, className = "" }) => {
452
+ const sortedEntries = Array.from(model.eventsByDay.entries()).sort(([a], [b]) => a.localeCompare(b));
453
+ return /* @__PURE__ */ jsxs("div", {
454
+ className: `overflow-y-auto p-4 space-y-4 ${className}`,
455
+ children: [sortedEntries.length === 0 && /* @__PURE__ */ jsx("div", {
456
+ className: "flex items-center justify-center h-32 text-gray-400 text-sm",
457
+ children: "No upcoming events"
458
+ }), sortedEntries.map(([dateKey, events]) => {
459
+ const date = new Date(dateKey + "T00:00:00");
460
+ return /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("h3", {
461
+ className: "text-sm font-semibold text-gray-700 mb-2 sticky top-0 bg-white/90 backdrop-blur-sm py-1",
462
+ children: date.toLocaleDateString(void 0, {
463
+ weekday: "long",
464
+ month: "long",
465
+ day: "numeric"
466
+ })
467
+ }), /* @__PURE__ */ jsx("div", {
468
+ className: "space-y-1.5",
469
+ children: events.map((ev) => /* @__PURE__ */ jsx(EventCard, {
470
+ event: ev,
471
+ onClick: () => model.selectEvent(ev)
472
+ }, ev.id))
473
+ })] }, dateKey);
474
+ })]
475
+ });
476
+ });
477
+
478
+ //#endregion
479
+ //#region src/calendar/CalendarSidebar.tsx
480
+ const DAYS = [
481
+ "Su",
482
+ "Mo",
483
+ "Tu",
484
+ "We",
485
+ "Th",
486
+ "Fr",
487
+ "Sa"
488
+ ];
489
+ const CalendarSidebar = observer(({ model, className = "" }) => {
490
+ const d = model.currentDate;
491
+ const year = d.getFullYear();
492
+ const month = d.getMonth();
493
+ const firstDay = new Date(year, month, 1).getDay();
494
+ const daysInMonth = new Date(year, month + 1, 0).getDate();
495
+ const today = new Date();
496
+ const cells = [];
497
+ for (let i = 0; i < firstDay; i++) cells.push(null);
498
+ for (let i = 1; i <= daysInMonth; i++) cells.push(i);
499
+ const isToday = (day) => day === today.getDate() && month === today.getMonth() && year === today.getFullYear();
500
+ const isSelected = (day) => day === d.getDate();
501
+ return /* @__PURE__ */ jsxs("div", {
502
+ className: `w-56 border-r border-gray-200 bg-gray-50 p-3 ${className}`,
503
+ children: [/* @__PURE__ */ jsxs("div", {
504
+ className: "mb-4",
505
+ children: [/* @__PURE__ */ jsxs("div", {
506
+ className: "flex items-center justify-between mb-2",
507
+ children: [
508
+ /* @__PURE__ */ jsx("button", {
509
+ onClick: () => model.navigateBack(),
510
+ className: "p-1 hover:bg-gray-200 rounded",
511
+ children: /* @__PURE__ */ jsx(ChevronLeft, { size: 14 })
512
+ }),
513
+ /* @__PURE__ */ jsx("span", {
514
+ className: "text-sm font-medium",
515
+ children: d.toLocaleDateString(void 0, {
516
+ month: "long",
517
+ year: "numeric"
518
+ })
519
+ }),
520
+ /* @__PURE__ */ jsx("button", {
521
+ onClick: () => model.navigateForward(),
522
+ className: "p-1 hover:bg-gray-200 rounded",
523
+ children: /* @__PURE__ */ jsx(ChevronRight, { size: 14 })
524
+ })
525
+ ]
526
+ }), /* @__PURE__ */ jsxs("div", {
527
+ className: "grid grid-cols-7 gap-0.5 text-center",
528
+ children: [DAYS.map((day) => /* @__PURE__ */ jsx("div", {
529
+ className: "text-[10px] text-gray-400 font-medium py-0.5",
530
+ children: day
531
+ }, day)), cells.map((day, i) => /* @__PURE__ */ jsx("button", {
532
+ disabled: day === null,
533
+ onClick: () => day && model.setDate(new Date(year, month, day)),
534
+ className: `text-xs py-0.5 rounded ${day === null ? "" : isSelected(day) ? "bg-blue-500 text-white" : isToday(day) ? "bg-blue-100 text-blue-700 font-bold" : "text-gray-700 hover:bg-gray-200"}`,
535
+ children: day
536
+ }, i))]
537
+ })]
538
+ }), /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("h3", {
539
+ className: "text-xs font-semibold text-gray-500 uppercase tracking-wider mb-2",
540
+ children: "Calendars"
541
+ }), model.calendars.map((cal) => /* @__PURE__ */ jsxs("div", {
542
+ className: "flex items-center gap-2 px-2 py-1.5 text-sm text-gray-700",
543
+ children: [/* @__PURE__ */ jsx("div", {
544
+ className: "w-3 h-3 rounded-full",
545
+ style: { backgroundColor: cal.color }
546
+ }), /* @__PURE__ */ jsx("span", {
547
+ className: "truncate",
548
+ title: cal.name,
549
+ children: cal.name
550
+ })]
551
+ }, cal.id))] })]
552
+ });
553
+ });
554
+
555
+ //#endregion
556
+ //#region src/calendar/CalendarBrowser.tsx
557
+ const VIEW_LABELS = {
558
+ month: "Month",
559
+ week: "Week",
560
+ day: "Day",
561
+ agenda: "Agenda"
562
+ };
563
+ const CalendarBrowser = observer(({ model, className = "", showSidebar = true }) => {
564
+ useEffect(() => {
565
+ model.loadEvents();
566
+ }, [model]);
567
+ return /* @__PURE__ */ jsxs("div", {
568
+ className: `flex h-full bg-white rounded-xl border border-gray-200 overflow-hidden ${className}`,
569
+ children: [showSidebar && /* @__PURE__ */ jsx(CalendarSidebar, { model }), /* @__PURE__ */ jsxs("div", {
570
+ className: "flex-1 flex flex-col min-w-0",
571
+ children: [/* @__PURE__ */ jsxs("div", {
572
+ className: "flex items-center gap-2 px-4 py-2 border-b border-gray-200",
573
+ children: [
574
+ /* @__PURE__ */ jsx("button", {
575
+ onClick: () => model.today(),
576
+ className: "text-sm px-3 py-1.5 border border-gray-200 rounded-lg hover:bg-gray-50",
577
+ children: "Today"
578
+ }),
579
+ /* @__PURE__ */ jsx("button", {
580
+ onClick: () => model.navigateBack(),
581
+ className: "p-1.5 hover:bg-gray-100 rounded-lg",
582
+ children: /* @__PURE__ */ jsx(ChevronLeft, { size: 16 })
583
+ }),
584
+ /* @__PURE__ */ jsx("button", {
585
+ onClick: () => model.navigateForward(),
586
+ className: "p-1.5 hover:bg-gray-100 rounded-lg",
587
+ children: /* @__PURE__ */ jsx(ChevronRight, { size: 16 })
588
+ }),
589
+ /* @__PURE__ */ jsx("h2", {
590
+ className: "text-sm font-medium text-gray-900 ml-2",
591
+ children: model.currentDate.toLocaleDateString(void 0, {
592
+ month: "long",
593
+ year: "numeric",
594
+ ...model.viewMode === "day" ? {
595
+ day: "numeric",
596
+ weekday: "long"
597
+ } : {}
598
+ })
599
+ }),
600
+ /* @__PURE__ */ jsx("div", {
601
+ className: "ml-auto flex items-center border border-gray-200 rounded-lg overflow-hidden",
602
+ children: Object.keys(VIEW_LABELS).map((mode) => /* @__PURE__ */ jsx("button", {
603
+ onClick: () => model.setViewMode(mode),
604
+ className: `px-3 py-1.5 text-xs font-medium ${model.viewMode === mode ? "bg-blue-50 text-blue-600" : "text-gray-500 hover:bg-gray-50"}`,
605
+ children: VIEW_LABELS[mode]
606
+ }, mode))
607
+ })
608
+ ]
609
+ }), /* @__PURE__ */ jsx("div", {
610
+ className: "flex-1 overflow-hidden",
611
+ children: model.loading ? /* @__PURE__ */ jsx("div", {
612
+ className: "flex items-center justify-center h-64",
613
+ children: /* @__PURE__ */ jsx(Loader2, {
614
+ size: 24,
615
+ className: "animate-spin text-gray-400"
616
+ })
617
+ }) : model.error ? /* @__PURE__ */ jsx(BrowserError, {
618
+ error: model.error,
619
+ context: "Calendar",
620
+ onRetry: () => model.loadEvents()
621
+ }) : /* @__PURE__ */ jsxs(Fragment, { children: [
622
+ model.viewMode === "month" && /* @__PURE__ */ jsx(MonthView, { model }),
623
+ model.viewMode === "week" && /* @__PURE__ */ jsx(WeekView, { model }),
624
+ model.viewMode === "day" && /* @__PURE__ */ jsx(DayView, { model }),
625
+ model.viewMode === "agenda" && /* @__PURE__ */ jsx(AgendaView, { model })
626
+ ] })
627
+ })]
628
+ })]
629
+ });
630
+ });
631
+
632
+ //#endregion
633
+ //#region src/calendar/MockCalendarProvider.ts
634
+ const CALENDARS = [
635
+ {
636
+ id: "personal",
637
+ name: "Personal",
638
+ color: "#3b82f6"
639
+ },
640
+ {
641
+ id: "work",
642
+ name: "Work",
643
+ color: "#10b981"
644
+ },
645
+ {
646
+ id: "family",
647
+ name: "Family",
648
+ color: "#f59e0b"
649
+ }
650
+ ];
651
+ const EVENT_TITLES = [
652
+ "Team standup",
653
+ "Lunch with Sarah",
654
+ "Design review",
655
+ "Gym session",
656
+ "Doctor appointment",
657
+ "Code review",
658
+ "Sprint planning",
659
+ "Movie night",
660
+ "Grocery shopping",
661
+ "Piano lesson",
662
+ "Board meeting",
663
+ "Yoga class",
664
+ "Project deadline",
665
+ "Coffee with Alex",
666
+ "Dentist",
667
+ "Book club"
668
+ ];
669
+ const LOCATIONS = [
670
+ "Office",
671
+ "Zoom",
672
+ "Conference Room A",
673
+ "Downtown Cafe",
674
+ "Home",
675
+ void 0
676
+ ];
677
+ function generateEvents() {
678
+ const events = [];
679
+ const now = new Date();
680
+ const baseDate = new Date(now.getFullYear(), now.getMonth(), 1);
681
+ for (let i = 0; i < 40; i++) {
682
+ const day = Math.floor(Math.random() * 35) - 5;
683
+ const hour = 8 + Math.floor(Math.random() * 10);
684
+ const duration = 1 + Math.floor(Math.random() * 3);
685
+ const allDay = i % 8 === 0;
686
+ const calendar = CALENDARS[i % CALENDARS.length];
687
+ const startDate = new Date(baseDate);
688
+ startDate.setDate(startDate.getDate() + day);
689
+ startDate.setHours(hour, 0, 0, 0);
690
+ const endDate = new Date(startDate);
691
+ if (allDay) endDate.setHours(23, 59, 59, 999);
692
+ else endDate.setHours(hour + duration);
693
+ events.push({
694
+ id: `event-${i}`,
695
+ type: "calendar-event",
696
+ title: EVENT_TITLES[i % EVENT_TITLES.length],
697
+ startDate,
698
+ endDate,
699
+ allDay,
700
+ location: LOCATIONS[i % LOCATIONS.length],
701
+ attendees: i % 3 === 0 ? ["alice@example.com", "bob@example.com"] : void 0,
702
+ color: calendar.color,
703
+ calendarId: calendar.id,
704
+ createdAt: now,
705
+ updatedAt: now
706
+ });
707
+ }
708
+ return events;
709
+ }
710
+ var MockCalendarProvider = class {
711
+ constructor() {
712
+ this.events = generateEvents();
713
+ }
714
+ async listItems() {
715
+ return this.events;
716
+ }
717
+ async getItem(id) {
718
+ return this.events.find((e) => e.id === id) ?? null;
719
+ }
720
+ async createItem(item) {
721
+ const now = new Date();
722
+ const created = {
723
+ ...item,
724
+ id: `event-${Date.now()}`,
725
+ createdAt: now,
726
+ updatedAt: now
727
+ };
728
+ this.events.push(created);
729
+ return created;
730
+ }
731
+ async updateItem(id, updates) {
732
+ const idx = this.events.findIndex((e) => e.id === id);
733
+ if (idx === -1) throw new Error("Not found");
734
+ this.events[idx] = {
735
+ ...this.events[idx],
736
+ ...updates,
737
+ updatedAt: new Date()
738
+ };
739
+ return this.events[idx];
740
+ }
741
+ async deleteItem(id) {
742
+ this.events = this.events.filter((e) => e.id !== id);
743
+ }
744
+ async search(query) {
745
+ const q = query.toLowerCase();
746
+ return this.events.filter((e) => e.title.toLowerCase().includes(q));
747
+ }
748
+ async getCalendars() {
749
+ return CALENDARS;
750
+ }
751
+ async getEventsByRange(start, end) {
752
+ return this.events.filter((e) => e.endDate >= start && e.startDate <= end);
753
+ }
754
+ async getEventsByCalendar(calendarId) {
755
+ return this.events.filter((e) => e.calendarId === calendarId);
756
+ }
757
+ };
758
+
759
+ //#endregion
760
+ export { AgendaView, CalendarBrowser, CalendarModel, CalendarSidebar, DayView, EventCard, MockCalendarProvider, MonthView, WeekView };
761
+ //# sourceMappingURL=calendar-DSlrbHoj.js.map