@ilamy/calendar
Version:
A full-featured React calendar component library built with Shadcn-Ui, Tailwind CSS, and TypeScript.
631 lines (630 loc) • 20.7 kB
TypeScript
import { Weekday } from "rrule";
import { RRule } from "rrule";
import { Options } from "rrule";
import { Dayjs } from "dayjs";
/**
* Re-rrule.js Options with practical TypeScript interface.
* Makes all properties optional except freq and dtstart (which are required by RFC 5545).
* This allows clean object creation without needing explicit null values.
*
* @see https://tools.ietf.org/html/rfc5545 - RFC 5545 iCalendar specification
* @see https://github.com/jakubroztocil/rrule - rrule.js library documentation
*/
type RRuleOptions = {
/**
* The frequency of the event. Must be one of the following: DAILY, WEEKLY, MONTHLY, etc.
*/
freq: Options["freq"];
/**
* The start date of the recurrence rule. This defines when the recurrence pattern begins.
* Required for proper RRULE functionality according to RFC 5545.
* @important Same as the event start date.
*/
dtstart: Date;
} & Partial<Omit<Options, "freq" | "dtstart">>;
/**
* Core calendar event interface representing a single calendar event.
* This is the primary data structure for calendar events.
*/
interface CalendarEvent {
/** Unique identifier for the event */
id: string | number;
/** Display title of the event */
title: string;
/** Start date and time of the event */
start: Dayjs;
/** End date and time of the event */
end: Dayjs;
/**
* Color for the event (supports CSS color values, hex, rgb, hsl, or CSS class names)
* @example "#3b82f6", "blue-500", "rgb(59, 130, 246)"
*/
color?: string;
/**
* Background color for the event (supports CSS color values, hex, rgb, hsl, or CSS class names)
* @example "#dbeafe", "blue-100", "rgba(59, 130, 246, 0.1)"
*/
backgroundColor?: string;
/** Optional description or notes for the event */
description?: string;
/** Optional location where the event takes place */
location?: string;
/**
* Whether this is an all-day event
* @default false
*/
allDay?: boolean;
/**
* Recurrence rule for recurring events (RFC 5545 standard)
*
* Uses TypeScript interface for better readability, type safety, and IDE support
* compared to RRULE string format. Converted to rrule.js format internally.
*
* @example { freq: 'WEEKLY', interval: 1, byweekday: ['MO', 'WE', 'FR'] }
* @example { freq: 'DAILY', interval: 1, count: 10 }
* @example { freq: 'MONTHLY', interval: 1, until: new Date('2025-12-31') }
*/
rrule?: RRuleOptions;
/**
* Exception dates (EXDATE) - dates to exclude from recurrence
* Uses ISO string format for storage and transmission
* @example ['2025-01-15T09:00:00.000Z', '2025-01-22T09:00:00.000Z']
*/
exdates?: string[];
/**
* Recurrence ID (RECURRENCE-ID) - identifies modified instances
* Points to the original occurrence date this event modifies
* Used for events that are modifications of recurring instances
*/
recurrenceId?: string;
/**
* UID for iCalendar compatibility
* Unique identifier across calendar systems
*/
uid?: string;
/** Single resource assignment */
resourceId?: string | number;
/** Multiple resource assignment (cross-resource events) */
resourceIds?: (string | number)[];
/**
* Custom data associated with the event
* Use this to store additional metadata specific to your application
* @example { meetingType: 'standup', attendees: ['john', 'jane'] }
*/
data?: Record<string, any>;
}
/**
* Supported days of the week for calendar configuration.
* Used for setting the first day of the week and other week-related settings.
*/
type WeekDays = "sunday" | "monday" | "tuesday" | "wednesday" | "thursday" | "friday" | "saturday";
/**
* Configuration for business hours.
* Defines the working hours to be highlighted on the calendar.
*/
interface BusinessHours {
/**
* Days of the week to apply business hours to.
* @default ['monday', 'tuesday', 'wednesday', 'thursday', 'friday']
*/
daysOfWeek?: WeekDays[];
/**
* Start time for business hours in 24-hour format (0-24).
* @default 9
*/
startTime?: number;
/**
* End time for business hours in 24-hour format (0-24).
* @default 17
*/
endTime?: number;
}
interface EventFormProps {
open?: boolean;
selectedEvent?: CalendarEvent | null;
onAdd?: (event: CalendarEvent) => void;
onUpdate?: (event: CalendarEvent) => void;
onDelete?: (event: CalendarEvent) => void;
onClose: () => void;
}
import React4 from "react";
import React3 from "react";
/**
* Public-facing resource calendar event interface with flexible date types.
* Similar to IlamyCalendarPropEvent but with resource assignment fields.
* Dates can be provided as Dayjs, Date, or string and will be normalized internally.
*
* @interface IlamyResourceCalendarPropEvent
* @extends {IlamyCalendarPropEvent}
*/
interface IlamyResourceCalendarPropEvent extends IlamyCalendarPropEvent {
/** Single resource assignment */
resourceId?: string | number;
/** Multiple resource assignment (cross-resource events) */
resourceIds?: (string | number)[];
}
interface IlamyResourceCalendarProps extends Omit<IlamyCalendarProps, "events"> {
/** Array of events to display */
events?: IlamyResourceCalendarPropEvent[];
/** Array of resources */
resources?: Resource[];
/** Custom render function for resources */
renderResource?: (resource: Resource) => React.ReactNode;
/**
* Orientation of the resource view.
* - "horizontal": Resources are rows, time is columns (default)
* - "vertical": Resources are columns, time is rows
*/
orientation?: "horizontal" | "vertical";
/**
* Granularity of time slots in the week view.
* - "hourly": Time slots are 1 hour (default)
* - "daily": Time slots are 1 day
*/
weekViewGranularity?: "hourly" | "daily";
}
/**
* Resource interface representing a calendar resource (person, room, equipment, etc.)
*/
interface Resource {
/** Unique identifier for the resource */
id: string | number;
/** Display title of the resource */
title: string;
/**
* Color for the resource (supports CSS color values, hex, rgb, hsl, or CSS class names)
* @example "#3b82f6", "blue-500", "rgb(59, 130, 246)"
*/
color?: string;
/**
* Background color for the resource (supports CSS color values, hex, rgb, hsl, or CSS class names)
* @example "#dbeafe", "blue-100", "rgba(59, 130, 246, 0.1)"
*/
backgroundColor?: string;
/** Optional position for resource display */
position?: number;
/**
* Configuration for resource-specific business hours.
* If provided, these will be used instead of the global business hours for this resource.
*/
businessHours?: BusinessHours | BusinessHours[];
/**
* Custom data associated with the resource
* Use this to store additional metadata specific to your application
* @example { avatar: 'https://example.com/avatar.png', role: 'admin' }
*/
data?: Record<string, any>;
}
interface Translations {
today: string;
create: string;
new: string;
update: string;
delete: string;
cancel: string;
export: string;
event: string;
events: string;
newEvent: string;
title: string;
description: string;
location: string;
allDay: string;
startDate: string;
endDate: string;
startTime: string;
searchTime: string;
endTime: string;
color: string;
createEvent: string;
editEvent: string;
addNewEvent: string;
editEventDetails: string;
eventTitlePlaceholder: string;
eventDescriptionPlaceholder: string;
eventLocationPlaceholder: string;
repeat: string;
repeats: string;
customRecurrence: string;
daily: string;
weekly: string;
monthly: string;
yearly: string;
interval: string;
repeatOn: string;
never: string;
count: string;
every: string;
ends: string;
after: string;
occurrences: string;
on: string;
editRecurringEvent: string;
deleteRecurringEvent: string;
editRecurringEventQuestion: string;
deleteRecurringEventQuestion: string;
thisEvent: string;
thisEventDescription: string;
thisAndFollowingEvents: string;
thisAndFollowingEventsDescription: string;
allEvents: string;
allEventsDescription: string;
onlyChangeThis: string;
changeThisAndFuture: string;
changeEntireSeries: string;
onlyDeleteThis: string;
deleteThisAndFuture: string;
deleteEntireSeries: string;
month: string;
week: string;
day: string;
year: string;
more: string;
resources: string;
resource: string;
time: string;
date: string;
noResourcesVisible: string;
addResourcesOrShowExisting: string;
sunday: string;
monday: string;
tuesday: string;
wednesday: string;
thursday: string;
friday: string;
saturday: string;
sun: string;
mon: string;
tue: string;
wed: string;
thu: string;
fri: string;
sat: string;
january: string;
february: string;
march: string;
april: string;
may: string;
june: string;
july: string;
august: string;
september: string;
october: string;
november: string;
december: string;
}
type TranslationKey = keyof Translations;
type TranslatorFunction = (key: TranslationKey | string) => string;
/**
* Available calendar view types.
*/
type CalendarView = "month" | "week" | "day" | "year";
/**
* Time format options for displaying times in the calendar.
*/
type TimeFormat = "12-hour" | "24-hour";
/**
* Custom class names for calendar styling.
* Allows users to override default styles for various calendar elements.
*/
interface CalendarClassesOverride {
/**
* Class name for disabled cells (non-business hours).
* Replaces the DISABLED_CELL_CLASSNAME constant.
* @default "bg-secondary text-muted-foreground pointer-events-none"
* @example "bg-gray-100 text-gray-400 cursor-not-allowed"
*/
disabledCell?: string;
}
/**
* This interface extends the base CalendarEvent but allows more flexible date types
* for the start and end properties. The component will automatically convert these
* to dayjs objects internally for consistent date handling.
*
* @interface IlamyCalendarPropEvent
* @extends {Omit<CalendarEvent, 'start' | 'end'>}
*/
interface IlamyCalendarPropEvent extends Omit<CalendarEvent, "start" | "end"> {
start: Dayjs | Date | string;
end: Dayjs | Date | string;
}
/**
* Information passed to the onCellClick callback.
* Uses named properties for extensibility.
*/
interface DateRange {
start: Dayjs;
end: Dayjs;
}
interface CellClickInfo {
/** Start date/time of the clicked cell */
start: Dayjs;
/** End date/time of the clicked cell */
end: Dayjs;
/** Resource ID if clicking on a resource calendar cell (optional) */
resourceId?: string | number;
/** Whether the clicked cell is an all-day cell (optional) */
allDay?: boolean;
}
/**
* Props passed to the custom render function for the current time indicator.
* Allows users to customize how the current time indicator is displayed.
*/
interface RenderCurrentTimeIndicatorProps {
/** The current time as a dayjs object */
currentTime: Dayjs;
/** The start of the visible time range */
rangeStart: Dayjs;
/** The end of the visible time range */
rangeEnd: Dayjs;
/** Progress percentage (0-100) representing position in the range */
progress: number;
/**
* The resource associated with this column (if in a resource-based view).
* Pass this to conditionally render custom indicators for specific resources.
*/
resource?: Resource;
/** The current calendar view (e.g. 'day', 'week') */
view: CalendarView;
}
interface IlamyCalendarProps {
/**
* Array of events to display in the calendar.
*/
events?: IlamyCalendarPropEvent[];
/**
* The first day of the week to display in the calendar.
* Can be 'sunday', 'monday', etc. Defaults to 'sunday'.
*/
firstDayOfWeek?: WeekDays;
/**
* The initial view to display when the calendar loads.
* Defaults to 'month'.
*/
initialView?: CalendarView;
/**
* The initial date to display when the calendar loads.
* If not provided, the calendar will default to today's date.
*/
initialDate?: Dayjs | Date | string;
/**
* Custom render function for calendar events.
* If provided, it will override the default event rendering.
*/
renderEvent?: (event: CalendarEvent) => React3.ReactNode;
/**
* Callback when an event is clicked.
* Provides the clicked event object.
*/
onEventClick?: (event: CalendarEvent) => void;
/**
* Callback when a calendar cell is clicked.
* Provides cell information including start/end dates and optional resourceId.
*/
onCellClick?: (info: CellClickInfo) => void;
/**
* Callback when the calendar view changes (month, week, day, year).
* Useful for syncing with external state or analytics.
*/
onViewChange?: (view: CalendarView) => void;
/**
* Callback when a new event is added to the calendar.
* Provides the newly created event object.
*/
onEventAdd?: (event: CalendarEvent) => void;
/**
* Callback when an existing event is updated.
* Provides the updated event object.
*/
onEventUpdate?: (event: CalendarEvent) => void;
/**
* Callback when an event is deleted from the calendar.
* Provides the deleted event object.
*/
onEventDelete?: (event: CalendarEvent) => void;
/**
* Callback when the current date changes (navigation).
* Provides the new current date and the current visible range.
*/
onDateChange?: (date: Dayjs, range: DateRange) => void;
/**
* Locale to use for formatting dates and times.
* If not provided, the default locale will be used.
*/
locale?: string;
/**
* Translations object for internationalization.
* Provide either this OR translator function, not both.
*/
translations?: Translations;
/**
* Translator function for internationalization.
* Provide either this OR translations object, not both.
*/
translator?: TranslatorFunction;
/**
* Timezone to use for displaying dates and times.
* If not provided, the local timezone will be used.
*/
timezone?: string;
/**
* Whether to disable click events on calendar cells.
* Useful for read-only views or when cell clicks are not needed.
*/
disableCellClick?: boolean;
/**
* Whether to disable click events on calendar events.
* Useful for read-only views or when event clicks are not needed.
*/
disableEventClick?: boolean;
/**
* Whether to disable drag-and-drop functionality for calendar events.
* Useful for read-only views or when drag-and-drop is not needed.
*/
disableDragAndDrop?: boolean;
/**
* Maximum number of events to display per day in month view.
* Additional events will be hidden and can be viewed via a "more" link.
* Defaults to 3 if not specified.
*/
dayMaxEvents?: number;
/**
* Vertical spacing between stacked events in pixels.
* Controls the gap between events when multiple events are displayed in the same view.
* Defaults to 1 pixel if not specified.
* Recommended range: 1-8 pixels for optimal readability.
*/
eventSpacing?: number;
/**
* Height of event bars in horizontal grid views (month view, resource month, resource week horizontal) in pixels.
* Increase this to show more content per event (e.g., title + time on separate lines).
* Does not affect day/week views, which use percentage-based heights that scale with event duration.
* Defaults to 24 pixels if not specified.
*/
eventHeight?: number;
/**
* Whether to stick the view header to the top of the calendar.
* Useful for keeping the header visible while scrolling.
*/
stickyViewHeader?: boolean;
/**
* Custom class name for the view header.
* Useful for applying custom styles or themes.
*/
viewHeaderClassName?: string;
/**
* Custom header component to replace the default calendar header.
* Useful for adding custom branding or additional controls.
*/
headerComponent?: React3.ReactNode;
/**
* Custom class name for the calendar header.
* Useful for applying custom styles to the header.
*/
headerClassName?: string;
/**
* Configuration for business hours.
* Defines the working hours to be highlighted on the calendar.
* Can be a single BusinessHours object (applies to all specified days)
* or an array of BusinessHours objects (for different hours on different days).
*/
businessHours?: BusinessHours | BusinessHours[];
/**
* Custom render function for the event form.
* If provided, it will override the default event form component.
* The function receives EventFormProps and should return a React node.
*/
renderEventForm?: (props: EventFormProps) => React3.ReactNode;
/**
* Time format for displaying times in the calendar.
* - "12-hour": Times displayed as "1:00 PM" (default)
* - "24-hour": Times displayed as "13:00"
*/
timeFormat?: TimeFormat;
/**
* Whether to hide non-business hours in Day and Week views.
* Requires businessHours to be configured.
* @default false
*/
hideNonBusinessHours?: boolean;
/**
* Custom class names for overriding default calendar element styles.
* Allows fine-grained control over the appearance of different calendar elements.
* @example { disabledCell: "bg-gray-100 text-gray-400" }
*/
classesOverride?: CalendarClassesOverride;
/**
* Custom render function for the current time indicator.
* If provided, replaces the default red line indicator.
* Useful for adding custom time labels or styling.
*
* @example
* ```tsx
* renderCurrentTimeIndicator={({ currentTime, progress, resource, view }) => {
* // Only show the time badge for the first resource in Day view (to avoid repetition)
* const isPrimary = !resource || resource.id === 'room-a'
* const showBadge = view === 'day' ? isPrimary : true
*
* return (
* <div style={{ top: `${progress}%` }} className="absolute left-0 right-0">
* <div className="h-0.5 bg-red-500" />
* {showBadge && (
* <span className="absolute left-0 bg-red-500 text-white text-[10px] px-1 rounded-r-sm">
* {currentTime.format('h:mm A')}
* </span>
* )}
* </div>
* )
* }}
* ```
*/
renderCurrentTimeIndicator?: (props: RenderCurrentTimeIndicatorProps) => React3.ReactNode;
/**
* Days of the week to hide from the week view.
* Hidden days won't render as columns, giving remaining days more space.
*
* Applies to:
* - Regular vertical week view (always)
* - Resource vertical week view in hourly granularity
*
* Does NOT apply to:
* - Resource horizontal week view (layout is days-as-rows)
* - Resource vertical week view in daily granularity
* (`weekViewGranularity: 'daily'`) — non-contiguous visible days would
* break multi-day event positioning
* - Month, day, and year views
*
* @default []
* @example ['saturday', 'sunday'] // Hide weekends
*/
hiddenDays?: WeekDays[];
/**
* Custom render function for the hour labels in the gutter/header.
* Receives a Dayjs object for the hour and should return a React node.
*/
renderHour?: (date: Dayjs) => React3.ReactNode;
}
declare const IlamyCalendar: React4.FC<IlamyCalendarProps>;
declare const isRecurringEvent: (event: CalendarEvent) => boolean;
interface GenerateRecurringEventsProps {
event: CalendarEvent;
currentEvents: CalendarEvent[];
startDate: Dayjs;
endDate: Dayjs;
}
declare const generateRecurringEvents: ({ event, currentEvents, startDate, endDate }: GenerateRecurringEventsProps) => CalendarEvent[];
import React5 from "react";
declare const IlamyResourceCalendar: React5.FC<IlamyResourceCalendarProps>;
/**
* Publicly exposed calendar context properties.
*/
interface UseIlamyCalendarContextReturn {
readonly currentDate: Dayjs;
readonly view: CalendarView;
readonly events: CalendarEvent[];
readonly isEventFormOpen: boolean;
readonly selectedEvent: CalendarEvent | null;
readonly selectedDate: Dayjs | null;
readonly firstDayOfWeek: number;
readonly resources: Resource[];
readonly setCurrentDate: (date: Dayjs) => void;
readonly selectDate: (date: Dayjs) => void;
readonly setView: (view: CalendarView) => void;
readonly nextPeriod: () => void;
readonly prevPeriod: () => void;
readonly today: () => void;
readonly addEvent: (event: CalendarEvent) => void;
readonly updateEvent: (eventId: string | number, event: Partial<CalendarEvent>) => void;
readonly deleteEvent: (eventId: string | number) => void;
readonly openEventForm: (eventData?: Partial<CalendarEvent>) => void;
readonly closeEventForm: () => void;
readonly getEventsForResource: (resourceId: string | number) => CalendarEvent[];
readonly businessHours?: BusinessHours | BusinessHours[];
}
/**
* Public hook exported for library users.
* Returns a limited set of commonly used properties and methods.
*/
declare function useIlamyCalendarContext(): UseIlamyCalendarContextReturn;
declare const defaultTranslations: Translations;
export { useIlamyCalendarContext, isRecurringEvent, generateRecurringEvents, defaultTranslations, Weekday, WeekDays, UseIlamyCalendarContextReturn, TranslatorFunction, Translations, TranslationKey, TimeFormat, Resource, RenderCurrentTimeIndicatorProps, RRuleOptions, RRule, IlamyResourceCalendarProps, IlamyResourceCalendar, IlamyCalendarProps, IlamyCalendar, EventFormProps, CellClickInfo, CalendarView, CalendarEvent, BusinessHours };