@ilamy/calendar 1.8.1 → 2.0.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.
- package/README.md +59 -12
- package/dist/index.d.ts +400 -132
- package/dist/index.js +3 -7
- package/dist/plugins/agenda.d.ts +349 -0
- package/dist/plugins/agenda.js +1 -0
- package/dist/plugins/drag-to-create.d.ts +364 -0
- package/dist/plugins/drag-to-create.js +1 -0
- package/dist/plugins/recurrence.d.ts +383 -0
- package/dist/plugins/recurrence.js +2 -0
- package/dist/shared/chunk-328e2ygt.js +2 -0
- package/dist/shared/chunk-a9j9sahk.js +2 -0
- package/dist/shared/chunk-jfadfww5.js +2 -0
- package/dist/testing/index.d.ts +579 -0
- package/dist/testing/index.js +1 -0
- package/package.json +28 -43
- package/LICENSE +0 -21
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
import { ComponentType, ReactNode as ReactNode2 } from "react";
|
|
2
|
+
import { Dayjs as Dayjs2, ManipulateType as ManipulateType2 } from "dayjs";
|
|
3
|
+
/**
|
|
4
|
+
* Core calendar event interface representing a single calendar event.
|
|
5
|
+
* This is the primary data structure for calendar events.
|
|
6
|
+
*/
|
|
7
|
+
interface CalendarEvent {
|
|
8
|
+
/** Unique identifier for the event */
|
|
9
|
+
id: string | number;
|
|
10
|
+
/** Display title of the event */
|
|
11
|
+
title: string;
|
|
12
|
+
/** Start date and time of the event */
|
|
13
|
+
start: Dayjs2;
|
|
14
|
+
/** End date and time of the event */
|
|
15
|
+
end: Dayjs2;
|
|
16
|
+
/**
|
|
17
|
+
* Color for the event (supports CSS color values, hex, rgb, hsl, or CSS class names)
|
|
18
|
+
* @example "#3b82f6", "blue-500", "rgb(59, 130, 246)"
|
|
19
|
+
*/
|
|
20
|
+
color?: string;
|
|
21
|
+
/**
|
|
22
|
+
* Background color for the event (supports CSS color values, hex, rgb, hsl, or CSS class names)
|
|
23
|
+
* @example "#dbeafe", "blue-100", "rgba(59, 130, 246, 0.1)"
|
|
24
|
+
*/
|
|
25
|
+
backgroundColor?: string;
|
|
26
|
+
/** Optional description or notes for the event */
|
|
27
|
+
description?: string;
|
|
28
|
+
/** Optional location where the event takes place */
|
|
29
|
+
location?: string;
|
|
30
|
+
/**
|
|
31
|
+
* Whether this is an all-day event
|
|
32
|
+
* @default false
|
|
33
|
+
*/
|
|
34
|
+
allDay?: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* UID for iCalendar compatibility
|
|
37
|
+
* Unique identifier across calendar systems
|
|
38
|
+
*/
|
|
39
|
+
uid?: string;
|
|
40
|
+
/** Single resource assignment */
|
|
41
|
+
resourceId?: string | number;
|
|
42
|
+
/** Multiple resource assignment (cross-resource events) */
|
|
43
|
+
resourceIds?: (string | number)[];
|
|
44
|
+
/**
|
|
45
|
+
* Custom data associated with the event
|
|
46
|
+
* Use this to store additional metadata specific to your application
|
|
47
|
+
* @example { meetingType: 'standup', attendees: ['john', 'jane'] }
|
|
48
|
+
*/
|
|
49
|
+
data?: Record<string, unknown>;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Supported days of the week for calendar configuration.
|
|
53
|
+
* Used for setting the first day of the week and other week-related settings.
|
|
54
|
+
*/
|
|
55
|
+
type WeekDays = "sunday" | "monday" | "tuesday" | "wednesday" | "thursday" | "friday" | "saturday";
|
|
56
|
+
/**
|
|
57
|
+
* Configuration for business hours.
|
|
58
|
+
* Defines the working hours to be highlighted on the calendar.
|
|
59
|
+
*/
|
|
60
|
+
interface BusinessHours {
|
|
61
|
+
/**
|
|
62
|
+
* Days of the week to apply business hours to.
|
|
63
|
+
* @default ['monday', 'tuesday', 'wednesday', 'thursday', 'friday']
|
|
64
|
+
*/
|
|
65
|
+
daysOfWeek?: WeekDays[];
|
|
66
|
+
/**
|
|
67
|
+
* Start time for business hours in 24-hour format (0-24).
|
|
68
|
+
* @default 9
|
|
69
|
+
*/
|
|
70
|
+
startTime?: number;
|
|
71
|
+
/**
|
|
72
|
+
* End time for business hours in 24-hour format (0-24).
|
|
73
|
+
* @default 17
|
|
74
|
+
*/
|
|
75
|
+
endTime?: number;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Resource interface representing a calendar resource (person, room, equipment, etc.)
|
|
79
|
+
*/
|
|
80
|
+
interface Resource {
|
|
81
|
+
/** Unique identifier for the resource */
|
|
82
|
+
id: string | number;
|
|
83
|
+
/** Display title of the resource */
|
|
84
|
+
title: string;
|
|
85
|
+
/**
|
|
86
|
+
* Color for the resource (supports CSS color values, hex, rgb, hsl, or CSS class names)
|
|
87
|
+
* @example "#3b82f6", "blue-500", "rgb(59, 130, 246)"
|
|
88
|
+
*/
|
|
89
|
+
color?: string;
|
|
90
|
+
/**
|
|
91
|
+
* Background color for the resource (supports CSS color values, hex, rgb, hsl, or CSS class names)
|
|
92
|
+
* @example "#dbeafe", "blue-100", "rgba(59, 130, 246, 0.1)"
|
|
93
|
+
*/
|
|
94
|
+
backgroundColor?: string;
|
|
95
|
+
/**
|
|
96
|
+
* Configuration for resource-specific business hours.
|
|
97
|
+
* If provided, these will be used instead of the global business hours for this resource.
|
|
98
|
+
*/
|
|
99
|
+
businessHours?: BusinessHours | BusinessHours[];
|
|
100
|
+
/**
|
|
101
|
+
* Custom data associated with the resource
|
|
102
|
+
* Use this to store additional metadata specific to your application
|
|
103
|
+
* @example { avatar: 'https://example.com/avatar.png', role: 'admin' }
|
|
104
|
+
*/
|
|
105
|
+
data?: Record<string, unknown>;
|
|
106
|
+
}
|
|
107
|
+
interface PluginDateRange {
|
|
108
|
+
start: Dayjs2;
|
|
109
|
+
end: Dayjs2;
|
|
110
|
+
}
|
|
111
|
+
interface PluginMutationArgs {
|
|
112
|
+
event: CalendarEvent;
|
|
113
|
+
updates?: Partial<CalendarEvent>;
|
|
114
|
+
currentEvents: CalendarEvent[];
|
|
115
|
+
scope: unknown;
|
|
116
|
+
}
|
|
117
|
+
/** Structured result from `applyEdit` when a mutation updates multiple stored rows. */
|
|
118
|
+
interface PluginMutationResult {
|
|
119
|
+
events: CalendarEvent[];
|
|
120
|
+
/** Existing rows to persist via `onEventUpdate`. */
|
|
121
|
+
updated: CalendarEvent[];
|
|
122
|
+
/** New rows to persist via `onEventAdd`. */
|
|
123
|
+
added: CalendarEvent[];
|
|
124
|
+
/** Existing rows to persist via `onEventDelete`. */
|
|
125
|
+
deleted: CalendarEvent[];
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Calendar configuration handed to a view's `columns()`/`renderHeader()`.
|
|
129
|
+
* Carries the resource axis (`resources`, `orientation`) so a resource-capable
|
|
130
|
+
* view can compose both arrangements. `range()` receives only the
|
|
131
|
+
* `firstDayOfWeek` slice (see its own signature).
|
|
132
|
+
*/
|
|
133
|
+
interface ViewConfig {
|
|
134
|
+
firstDayOfWeek: number;
|
|
135
|
+
hiddenDays?: Set<number>;
|
|
136
|
+
businessHours?: BusinessHours | BusinessHours[];
|
|
137
|
+
hideNonBusinessHours?: boolean;
|
|
138
|
+
/** The resource axis. Set only when the calendar renders resources. */
|
|
139
|
+
resources?: Resource[];
|
|
140
|
+
/**
|
|
141
|
+
* The calendar-level resource arrangement (the user's choice): where the
|
|
142
|
+
* resource axis goes. Only meaningful when `resources` is set.
|
|
143
|
+
*/
|
|
144
|
+
orientation?: "vertical" | "horizontal";
|
|
145
|
+
/**
|
|
146
|
+
* Week-view granularity when `resources` is set: 'hourly' (default) nests
|
|
147
|
+
* hour slots under each day; 'daily' shows one cell per day.
|
|
148
|
+
*/
|
|
149
|
+
weekViewGranularity?: "hourly" | "daily";
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* One column of a 'vertical' view (time flows down the column).
|
|
153
|
+
* Formalizes the calendar's existing VerticalGrid column input.
|
|
154
|
+
*/
|
|
155
|
+
interface VerticalColumnSpec {
|
|
156
|
+
/** Stable column id; drives testids and React keys. */
|
|
157
|
+
id: string;
|
|
158
|
+
/** The date this column represents; gutter/label columns leave it unset. */
|
|
159
|
+
day?: Dayjs2;
|
|
160
|
+
/** The cells of the column: hour slots (gridType 'hour') or dates ('day'). */
|
|
161
|
+
days: Dayjs2[];
|
|
162
|
+
gridType?: "day" | "hour";
|
|
163
|
+
className?: string;
|
|
164
|
+
/** Label-only column (e.g. the time gutter): renders no events. */
|
|
165
|
+
noEvents?: boolean;
|
|
166
|
+
renderCell?: (date: Dayjs2) => ReactNode2;
|
|
167
|
+
/**
|
|
168
|
+
* Resource-axis identity when the column belongs to one resource. The
|
|
169
|
+
* single carrier: consumers derive the id from `resource.id`.
|
|
170
|
+
*/
|
|
171
|
+
resource?: Resource;
|
|
172
|
+
}
|
|
173
|
+
/** One cell of a 'horizontal' row. */
|
|
174
|
+
interface HorizontalCellSpec {
|
|
175
|
+
id: string;
|
|
176
|
+
day?: Dayjs2;
|
|
177
|
+
/** A grouped cell spanning several dates (nested-axis arrangements). */
|
|
178
|
+
days?: Dayjs2[];
|
|
179
|
+
gridType: "day" | "hour";
|
|
180
|
+
className?: string;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* One row of a 'horizontal' view (date cells flow across the row).
|
|
184
|
+
* Formalizes the calendar's existing HorizontalGrid row input.
|
|
185
|
+
*/
|
|
186
|
+
interface HorizontalRowSpec {
|
|
187
|
+
/** Stable row id; drives testids and React keys (matches VerticalColumnSpec.id). */
|
|
188
|
+
id: string;
|
|
189
|
+
columns?: HorizontalCellSpec[];
|
|
190
|
+
className?: string;
|
|
191
|
+
showDayNumber?: boolean;
|
|
192
|
+
/** Resource-axis identity when the row belongs to one resource. */
|
|
193
|
+
resource?: Resource;
|
|
194
|
+
}
|
|
195
|
+
/** Context passed to a view's `renderHeader`. */
|
|
196
|
+
interface ViewHeaderContext {
|
|
197
|
+
date: Dayjs2;
|
|
198
|
+
config: ViewConfig;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Describes a view type — contributed by a plugin or built into the calendar
|
|
202
|
+
* core (the four built-ins are themselves `PluginView` entries). A view either
|
|
203
|
+
* declares `columns` + `layout` and renders through the shared grid engines,
|
|
204
|
+
* or renders entirely through `component` (the escape hatch).
|
|
205
|
+
*/
|
|
206
|
+
interface PluginView {
|
|
207
|
+
/** Unique view id, e.g. 'resource-week'. */
|
|
208
|
+
name: string;
|
|
209
|
+
/** View-switcher label (or a translation key; unknown keys render as-is). */
|
|
210
|
+
label?: string;
|
|
211
|
+
/**
|
|
212
|
+
* View-switcher icon (a component taking `className`, e.g. a lucide icon).
|
|
213
|
+
* Always shown in the switcher; the label appears beside it only when the
|
|
214
|
+
* view is selected, and as a hover tooltip otherwise.
|
|
215
|
+
*/
|
|
216
|
+
icon: ComponentType<{
|
|
217
|
+
className?: string;
|
|
218
|
+
}>;
|
|
219
|
+
/**
|
|
220
|
+
* The escape hatch: renders the whole view when `columns`/`layout` are
|
|
221
|
+
* absent. Spec-driven views omit it. A view with neither renders nothing
|
|
222
|
+
* (dev builds log a warning).
|
|
223
|
+
*/
|
|
224
|
+
component?: ComponentType;
|
|
225
|
+
/** How far prev/next steps when `navigationStep` is absent ('week', 'month', …). */
|
|
226
|
+
navigationUnit?: ManipulateType2;
|
|
227
|
+
/**
|
|
228
|
+
* How far prev/next jumps; defaults to one `navigationUnit`. Custom-duration
|
|
229
|
+
* views (a 40-day grid, a 4-day vertical view) set `{ amount: 40, unit: 'day' }`
|
|
230
|
+
* so navigation moves a full window.
|
|
231
|
+
*
|
|
232
|
+
* This also selects the header title/date-picker form (the core derives it
|
|
233
|
+
* generically, never by view name): a single `day`/`week`/`month`/`year` step
|
|
234
|
+
* borrows that grid's picker and title; any other step (amount > 1, or a custom
|
|
235
|
+
* unit) shows the day picker over the view's `range`. A third-party view gets
|
|
236
|
+
* the right picker for free just by declaring how it navigates.
|
|
237
|
+
*/
|
|
238
|
+
navigationStep?: {
|
|
239
|
+
amount: number;
|
|
240
|
+
unit: ManipulateType2;
|
|
241
|
+
};
|
|
242
|
+
/**
|
|
243
|
+
* Visible range for navigation callbacks and the event pipeline. Views
|
|
244
|
+
* without `range` fall back to the month 6x7 grid range. Receives only the
|
|
245
|
+
* `firstDayOfWeek` slice of the config; the full axis config reaches
|
|
246
|
+
* `columns()`/`renderHeader()`.
|
|
247
|
+
*/
|
|
248
|
+
range?: (date: Dayjs2, config: Pick<ViewConfig, "firstDayOfWeek">) => {
|
|
249
|
+
start: Dayjs2;
|
|
250
|
+
end: Dayjs2;
|
|
251
|
+
};
|
|
252
|
+
/**
|
|
253
|
+
* Column/row specs for the shared renderer. Return `VerticalColumnSpec[]`
|
|
254
|
+
* when `layout` is 'vertical', `HorizontalRowSpec[]` when 'horizontal'.
|
|
255
|
+
* Omit (together with `layout`) to render `component` instead.
|
|
256
|
+
*/
|
|
257
|
+
columns?: (date: Dayjs2, config: ViewConfig) => VerticalColumnSpec[] | HorizontalRowSpec[];
|
|
258
|
+
/**
|
|
259
|
+
* The view's intrinsic shape (the author's choice): which engine renders it
|
|
260
|
+
* when the calendar has NO resources. 'vertical' = time flows down;
|
|
261
|
+
* 'horizontal' = date cells flow across in stacked rows. With resources on
|
|
262
|
+
* a resource-capable view, the calendar-level `orientation` wins instead:
|
|
263
|
+
* `engine = resources && supportsResources ? orientation : layout`.
|
|
264
|
+
*/
|
|
265
|
+
layout?: "vertical" | "horizontal";
|
|
266
|
+
/** Header row content rendered above the grid by the shared renderer. */
|
|
267
|
+
renderHeader?: (ctx: ViewHeaderContext) => ReactNode2;
|
|
268
|
+
/**
|
|
269
|
+
* Whether `columns()` composes the resource axis when `config.resources`
|
|
270
|
+
* is set. Defaults to false; the view switcher hides resource-incapable
|
|
271
|
+
* views on a resource calendar.
|
|
272
|
+
*/
|
|
273
|
+
supportsResources?: boolean;
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* A calendar plugin contributes optional behavior and UI through generic hooks
|
|
277
|
+
* named after pipeline moments and mount points, never after a feature. The
|
|
278
|
+
* core stays agnostic of any specific plugin (e.g. recurrence).
|
|
279
|
+
*
|
|
280
|
+
* Hooks follow the Rollup/Vite execution kinds:
|
|
281
|
+
* - `transformEvents` is sequential: each plugin receives the previous
|
|
282
|
+
* plugin's output, forming a transform chain.
|
|
283
|
+
* - `managesEvent` is first-match: the first plugin whose managesEvent returns
|
|
284
|
+
* true owns its scoped mutations.
|
|
285
|
+
* - `renderSlot` is additive: every plugin may contribute to a mount point.
|
|
286
|
+
*
|
|
287
|
+
* `slotName` is an opaque string identifier and `context` is opaque to the
|
|
288
|
+
* core. The built-in slot names and their context shapes live in the calendar
|
|
289
|
+
* core, which this contract does NOT depend on, so adding a slot never changes
|
|
290
|
+
* this interface. A plugin narrows `context` by `slotName` at its boundary.
|
|
291
|
+
*
|
|
292
|
+
* `scope` is opaque to the core: the owner produces it (via the mutation-scope
|
|
293
|
+
* slot) and consumes it in `applyEdit` / `applyDelete`. A plugin that provides
|
|
294
|
+
* `applyEdit` / `applyDelete` should also render the mutation-scope slot so the
|
|
295
|
+
* core can gather that scope before mutating.
|
|
296
|
+
*/
|
|
297
|
+
interface IlamyPlugin {
|
|
298
|
+
name: string;
|
|
299
|
+
transformEvents?: (events: CalendarEvent[], range: PluginDateRange) => CalendarEvent[];
|
|
300
|
+
managesEvent?: (event: CalendarEvent) => boolean;
|
|
301
|
+
applyEdit?: (args: PluginMutationArgs) => CalendarEvent[] | PluginMutationResult;
|
|
302
|
+
applyDelete?: (args: PluginMutationArgs) => CalendarEvent[] | PluginMutationResult;
|
|
303
|
+
renderSlot?: (slotName: string, context: unknown) => ReactNode2;
|
|
304
|
+
/**
|
|
305
|
+
* Contributes arbitrary data to a named point. Additive: all plugins may
|
|
306
|
+
* contribute to the same point; the runtime aggregates all results via
|
|
307
|
+
* `collect`. Parallel to `renderSlot` but for data rather than UI nodes.
|
|
308
|
+
*/
|
|
309
|
+
contribute?: (point: string, context: unknown) => unknown[];
|
|
310
|
+
/**
|
|
311
|
+
* Registers new view types that the calendar can switch to. Each entry in
|
|
312
|
+
* the array describes one view (id, component, navigation unit, …).
|
|
313
|
+
*/
|
|
314
|
+
views?: PluginView[];
|
|
315
|
+
/**
|
|
316
|
+
* Wraps the calendar subtree so the plugin's own React context is available
|
|
317
|
+
* to its views, slots, and components. Rendered as the outermost wrapper
|
|
318
|
+
* among all plugin providers.
|
|
319
|
+
*/
|
|
320
|
+
provider?: ComponentType<{
|
|
321
|
+
children: ReactNode2;
|
|
322
|
+
}>;
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* The date window the agenda lists (and that prev/next steps over).
|
|
326
|
+
*
|
|
327
|
+
* A named period is the calendar period *containing* the reference date, so it
|
|
328
|
+
* can extend backward to the period's start (e.g. 'month' on the 14th lists from
|
|
329
|
+
* the 1st) and stays aligned with the matching grid view and header label. A
|
|
330
|
+
* number is a rolling window of that many days starting *at* the reference date
|
|
331
|
+
* and counting forward (e.g. 8 on the 14th lists the 14th–21st) — there is no
|
|
332
|
+
* calendar boundary to anchor it to, so it does not look backward.
|
|
333
|
+
*/
|
|
334
|
+
type AgendaWindow = "day" | "week" | "month" | number;
|
|
335
|
+
interface AgendaViewOptions {
|
|
336
|
+
/**
|
|
337
|
+
* The date window the agenda lists and that prev/next steps over. Default 'month'.
|
|
338
|
+
* A named period ('day' | 'week' | 'month') is the calendar period *containing*
|
|
339
|
+
* the current date, so it can include earlier days of that period (and aligns
|
|
340
|
+
* with the matching grid view + header label). A number is a rolling window of
|
|
341
|
+
* that many days starting *at* the current date and counting forward.
|
|
342
|
+
*/
|
|
343
|
+
window?: AgendaWindow;
|
|
344
|
+
}
|
|
345
|
+
/** Builds the agenda `PluginView` for the given window. */
|
|
346
|
+
declare const createAgendaView: ({ window }?: AgendaViewOptions) => PluginView;
|
|
347
|
+
/** Opt-in agenda plugin: registers the `agenda` view. Pass to `IlamyCalendar`'s `plugins`. */
|
|
348
|
+
declare const agendaPlugin: (options?: AgendaViewOptions) => IlamyPlugin;
|
|
349
|
+
export { createAgendaView, agendaPlugin, AgendaWindow, AgendaViewOptions };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{I as s,K as J}from"../shared/chunk-a9j9sahk.js";import{L as $}from"../shared/chunk-jfadfww5.js";import{List as w}from"lucide-react";import{createElement as y}from"react";import{useIlamyCalendarContext as d}from"@ilamy/calendar";import*as b from"@radix-ui/react-scroll-area";import{jsx as z,jsxs as S}from"react/jsx-runtime";function V({className:l,children:r,viewPortProps:c,...f}){return S(b.Root,{className:s("relative",l),"data-slot":"scroll-area",...f,children:[z(b.Viewport,{...c,className:s("focus-visible:ring-ring/50 size-full rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:outline-1",c?.className),"data-slot":"scroll-area-viewport",children:r}),z(k,{}),z(b.Corner,{})]})}function k({className:l,orientation:r="vertical",...c}){return z(b.ScrollAreaScrollbar,{className:s("flex touch-none p-px transition-colors select-none",r==="vertical"&&"h-full w-2.5 border-l border-l-transparent",r==="horizontal"&&"h-2.5 flex-col border-t border-t-transparent",l),"data-slot":"scroll-area-scrollbar",orientation:r,...c,children:z(b.ScrollAreaThumb,{className:"bg-border relative flex-1 rounded-full","data-slot":"scroll-area-thumb"})})}var R={day:(l)=>({start:l.startOf("day"),end:l.endOf("day")}),week:(l,r)=>{let c=(l.day()-r+7)%7,f=l.subtract(c,"day").startOf("day");return{start:f,end:f.add(6,"day").endOf("day")}},month:(l)=>({start:l.startOf("month"),end:l.endOf("month")})},u={day:{amount:1,unit:"day"},week:{amount:1,unit:"week"},month:{amount:1,unit:"month"}},q=(l,r,c=0)=>{if(typeof r==="number")return{start:l.startOf("day"),end:l.add(r-1,"day").endOf("day")};return R[r](l,c)},Y=(l)=>{if(typeof l==="number")return{amount:l,unit:"day"};return u[l]};var I=(l,r,c)=>{if(l.allDay)return l.start.isSameOrBefore(c)&&l.end.isSameOrAfter(r);return l.start.isSameOrAfter(r)&&l.start.isSameOrBefore(c)},E=(l,r)=>{let c=l.allDay?0:1,f=r.allDay?0:1;if(c!==f)return c-f;return l.start.valueOf()-r.start.valueOf()},Z=(l,r)=>{let c=[],f=r.end.startOf("day"),m=r.start.startOf("day");while(m.isSameOrBefore(f)){let i=m.startOf("day"),h=m.endOf("day"),N=l.filter((x)=>I(x,i,h)).sort(E);if(N.length>0)c.push({key:m.format("YYYY-MM-DD"),date:i,events:N});m=m.add(1,"day")}return c};import{useIlamyCalendarContext as g}from"@ilamy/calendar";import{memo as C}from"react";import{jsx as P,jsxs as _,Fragment as j}from"react/jsx-runtime";var D=({rangeStart:l,rangeEnd:r,now:c,axis:f="vertical",render:m,withDot:i=!0})=>{let h=c??$(),N=h.valueOf();if(!(N>=l.valueOf()&&N<r.valueOf()))return null;let x=r.diff(l,"minute"),o=h.diff(l,"minute")/x*100;if(m)return P(j,{children:m({currentTime:h,rangeStart:l,rangeEnd:r,progress:o,axis:f})});if(f==="horizontal")return _("div",{className:"absolute top-0 bottom-0 z-50 flex -translate-x-1/2 flex-col items-center pointer-events-none","data-testid":"current-time-indicator",style:{left:`${o}%`},children:[i&&P("div",{className:"size-2 shrink-0 rounded-full bg-red-500"}),P("div",{className:"w-0.5 flex-1 bg-red-500"})]});return _("div",{className:"absolute right-0 left-0 z-50 flex -translate-y-1/2 items-center pointer-events-none","data-testid":"current-time-indicator",style:{top:`${o}%`},children:[i&&P("div",{className:"size-2 shrink-0 rounded-full bg-red-500"}),P("div",{className:"h-0.5 flex-1 bg-red-500"})]})},F=C(D);import{jsx as G,jsxs as p}from"react/jsx-runtime";var O=({today:l,dayNumber:r,weekday:c,className:f,"data-testid":m})=>{return p("div",{className:s("flex flex-col items-center",f),"data-testid":m,"data-today":l?"true":void 0,children:[c!=null&&G("div",{className:s("w-full truncate text-center text-xs text-muted-foreground",l&&"text-primary"),children:c}),G("div",{className:s("flex h-5 w-5 shrink-0 items-center justify-center rounded-full text-xs font-medium",l&&"bg-primary text-primary-foreground"),children:r})]})};import{useIlamyCalendarContext as v}from"@ilamy/calendar";import{jsx as H,jsxs as a}from"react/jsx-runtime";var t=(l)=>l==="24-hour"?"HH:mm":"h:mm A",L=({event:l,day:r})=>{let{t:c,timeFormat:f,onEventClick:m}=v(),i=l.start.format(t(f)),h=l.allDay?c("allDay"):i,N=l.start.startOf("day"),x=l.end.startOf("day").diff(N,"day")+1,o=r.startOf("day").diff(N,"day")+1,W=Boolean(l.allDay)&&x>1,A=`(${c("day")} ${o}/${x})`,U=W?A:null;return a("button",{className:"hover:bg-accent flex w-full cursor-pointer items-center gap-2 rounded px-2 py-1 text-left text-sm",onClick:()=>m(l),type:"button",children:[H("span",{className:"text-muted-foreground w-20 shrink-0",children:h}),H("span",{className:s("size-3 shrink-0 rounded-full border",l.backgroundColor||"bg-blue-500",l.color),style:{backgroundColor:l.backgroundColor}}),H("span",{className:"truncate",children:l.title}),U&&H("span",{className:"text-muted-foreground shrink-0 text-xs",children:U})]})};import{jsx as Q,jsxs as M}from"react/jsx-runtime";var B=({group:l})=>{let{view:r,renderCurrentTimeIndicator:c}=g(),f=l.date.isSame($(),"day"),m;if(c)m=(i)=>c({...i,view:r});return M("div",{className:"flex gap-4 border-b px-2 py-3","data-testid":J("agenda-day",l.key),children:[Q("div",{className:"text-muted-foreground flex w-16 shrink-0 flex-col items-center text-center",children:Q(O,{className:"flex-col-reverse",dayNumber:l.date.format("D"),today:f,weekday:l.date.format("ddd")})}),M("div",{className:"relative flex flex-1 flex-col gap-1",children:[f&&Q(F,{rangeEnd:l.date.endOf("day"),rangeStart:l.date.startOf("day"),render:m}),l.events.map((i)=>Q(L,{day:l.date,event:i},J(l.key,i.id)))]})]})};import{jsx as X}from"react/jsx-runtime";var T=({window:l})=>{let{currentDate:r,getEventsForDateRange:c,t:f,firstDayOfWeek:m}=d(),i=q(r,l,m),h=c(i.start,i.end),N=Z(h,i);if(N.length===0)return X("div",{className:"text-muted-foreground flex h-full items-center justify-center p-4 text-sm","data-testid":"agenda-empty",children:f("agendaNoEvents")});return X(V,{className:"h-full","data-testid":"agenda-view",children:X("div",{className:"flex flex-col",children:N.map((x)=>X(B,{group:x},x.key))})})};var K=({window:l="month"}={})=>({name:"agenda",label:"agenda",icon:w,navigationStep:Y(l),range:(r,c)=>q(r,l,c.firstDayOfWeek),supportsResources:!1,component:()=>y(T,{window:l})});var n=(l={})=>({name:"agenda",views:[K(l)]});export{K as createAgendaView,n as agendaPlugin};
|