ilamy Calendar

repository·main·Indexed 43 days ago

https://github.com/kcsujeet/ilamy-calendar

A lightweight, highly pluggable React calendar component library built with TypeScript and Tailwind CSS 4. It supports RFC 5545 recurring events, resource management, and complex interactions. The library includes a recurrence plugin for augmented event data and UI enhancements, and provides integration guides for Next.js (14 and 15), Astro 5+, and Vite.

Tokens
117.3K
Snippets
306
Records
454
Agent score
55%

What's inside ilamy

  1. Introduction to ilamy Calendar

    main

    ilamy Calendar is a modern, open-source React calendar component designed for building robust calendar experiences. It is built for flexibility and ease of use, featuring production-ready functionality, full TypeScript support, and seamless integration with Tailwind CSS v4.

    Key benefits include:

    • Easy to Use: Simple installation and an intuitive API.
    • Fully Customizable: Every aspect of the calendar can be customized to match your design.
    • TypeScript Support: Built with TypeScript for a high-quality developer experience.
    • Lightweight: Minimal bundle size with no unnecessary dependencies.
  2. Overview of ilamy Calendar

    main

    ilamy Calendar is a modern, open-source React calendar component designed for building robust calendar experiences. It follows a lightweight and highly pluggable architecture, featuring a small core (~13 KB gzipped) with opt-in plugins for advanced features like recurring events and agenda views. This allows developers to minimize bundle size by only shipping the capabilities they need.

    Key features include:

    • Lightweight & Pluggable: Small core with opt-in functionality.
    • Fully Customizable: Every aspect of the calendar can be tailored to your design.
    • TypeScript Support: Built with TypeScript for a high-quality developer experience.
    • Tailwind CSS v4 Integration: Seamless support for Tailwind CSS v4 styling.
  3. Understand the Custom Views Parity Plan

    main

    The custom-views-parity-plan is a strategic proposal to bring ilamy-calendar's custom-view system to feature parity with FullCalendar. The goal is to allow end-users (not just plugin authors) to define and override views directly via configuration.

    Key objectives include:

    • Enabling a user-facing views configuration on IlamyCalendarProps.
    • Introducing declarative date-range and navigation controls (e.g., duration, dayCount, dateAlignment).
    • Implementing view families such as dayGrid, timeGrid, list, and multiMonth.
    • Supporting view-specific option overrides with a resolution hierarchy: Specific View → View Family → Global Configuration.
  4. Configure view navigation and range behavior

    main

    When defining a PluginView, you can control how the calendar moves between periods and how it calculates the visible date range:

    • navigationUnit: The unit used for default navigation (e.g., 'day', 'month', 'year').
    • navigationStep: An optional object { amount: number, unit: string } that overrides the default navigation behavior. For example, a 'forty-day' view might use { amount: 40, unit: 'day' }.
    • range: A function (date, config) => { start: Dayjs, end: Dayjs } that defines the temporal boundaries of the view. If not provided, the engine falls back to a default month-based grid range.
    const fortyDayPlugin: IlamyPlugin = {
    	name: 'forty',
    	views: [
    		{
    			name: 'forty-day',
    			component: () => null,
    			navigationStep: { amount: 40, unit: 'day' },
    			range: (date) => ({
    				start: date.startOf('day'),
    				end: date.add(39, 'day').endOf('day'),
    			}),
    		},
    	],
    }
  5. How custom views work in ilamy Calendar

    main

    A custom view is defined as a PluginView entry. The calendar treats built-in views (day, week, month, year) and custom views identically within the same registry.

    To create a view, you must understand the relationship between the view's layout and the user's orientation when resources are present. The rendering engine follows this logic:

    engine = resources && view.supportsResources ? calendar.orientation : view.layout

    • Without resources: The view uses its own layout ('vertical' or 'horizontal').
    • With resources: If supportsResources is true, the view uses the user-selected orientation ('vertical' or 'horizontal') to arrange resources.
  6. Configure the initial date and timezone

    main

    The initialDate property determines the starting date of the calendar view. It follows FullCalendar's timezone logic:

    • A string without an offset is parsed and displayed as if it were in the configured timezone.
    • A string with an offset is appropriately shifted to display in the configured timezone.

    Note: When using anchorInitialDate, you must pass the timezone as an argument. This is because dayjs.tz.setDefault runs in an effect, meaning the module default is empty during the first render. Any component or logic requiring the timezone during the initial render must receive it explicitly.

  7. How Drag-to-Create is implemented via plugins

    main

    In ilamy-calendar, drag-to-create is implemented as a plugin rather than a core feature to keep the core library minimal. The core provides the necessary data via DOM attributes, while the plugin manages all interaction logic.

    Core Responsibility: DroppableCell components expose stable data attributes that allow plugins to reconstruct CellInfo from the DOM without needing internal access to the calendar's state.

    Plugin Responsibility:

    • Pointer Tracking: Attaches pointerdown to the calendar root and uses setPointerCapture to track movement.
    • Hit-testing: Uses document.elementFromPoint(x, y) and .closest('[data-start]') to identify the cells under the pointer during a drag.
    • Visual Feedback: Renders a selectMirror (a visual highlight) as an overlay.
    • Event Triggering: Calls openEventForm({ start, end }) upon pointerup to initiate event creation.
  8. Understand the PluginView contract and view resolution

    main

    The PluginView contract is the unified interface for both built-in and plugin-provided views. The view resolution engine uses a three-way dispatcher based on the layout property to determine how to render a view:

    1. layout: 'vertical': Uses VerticalGrid.
    2. layout: 'horizontal': Uses HorizontalGrid.
    3. Other: Renders the view as a custom component.

    The engine follows a mechanical rule for determining orientation: engine = resources && view.supportsResources ? config.orientation : view.layout.

    Key vocabulary for implementing views:

    • layout: Either 'vertical' or 'horizontal'.
    • supportsResources: A boolean declaring if the view can handle a resource axis.
    • navigationStep: Defines how the view transitions during period navigation.
    • range: Defines the temporal range of the view.
    • columns: Defines the column specification.

    Custom-duration views (e.g., a 40-day grid) are implemented by providing the range, columns, and navigationStep properties.

  9. Configure Week View Granularity and Hidden Days

    main

    The weekViewGranularity option supports 'hourly' or 'daily' modes, but there is a critical constraint when using daily granularity:

    • Daily Mode Constraint: In daily granularity, hiddenDays is not supported. The view will intentionally use all 7 weekDays.
    • Reasoning: Non-contiguous visible days would break the positioning of multi-day events.

    This behavior is documented in the PluginView types and applies to resource-aware views.

  10. Accessing Calendar Data with Type Safety

    main

    In v2, the data fields on CalendarEvent and Resource have been tightened from Record<string, any> to Record<string, unknown>.

    When reading from these fields, you must use type narrowing or a boundary cast to satisfy TypeScript.

    // Example: Type narrowing
    const role = typeof resource.data?.role === 'string' ? resource.data.role : undefined
    
    // Example: Boundary cast
    const meta = resource.data as MyResourceMeta
  11. Constrain view navigation with `validRange`

    main

    You can restrict the dates a user can navigate to within a specific view using the validRange property. This is useful for preventing users from navigating to historical data or far-future dates.

    validRange can be defined as:

    • An object with { start?: Dayjs; end?: Dayjs }.
    • A function: (now: Dayjs) => { start?: Dayjs; end?: Dayjs }.

    When a validRange is set, the calendar engine will clamp navigation, disabling 'prev', 'next', and 'today' buttons when the user reaches the boundaries of the allowed range.