npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

calyx-rn

v0.5.0

Published

Premium headless calendar library for React Native with Timeline and Agenda views

Readme

Calyx RN

Premium Calendar Library for React Native

npm version License: MIT TypeScript Platform

InstallationQuick StartExamplesAPI ReferenceCustomization


🎥 See It In Action

Five powerful view modes: Month, Week, Day, Timeline, and Agenda


✨ Features


📦 Installation

npm install calyx-rn date-fns

or with yarn:

yarn add calyx-rn date-fns

Peer Dependencies

  • react >=18.0.0
  • react-native >=0.70.0
  • date-fns ^4.0.0

🚀 Quick Start

Basic Calendar

import React, { useState } from 'react';
import { Calendar } from 'calyx-rn';

function MyCalendar() {
  const [selected, setSelected] = useState(new Date());

  return (
    <Calendar
      mode="month"
      selected={selected}
      onSelect={setSelected}
      theme="dark"
    />
  );
}

Calendar with Events

import { Calendar } from 'calyx-rn';
import type { CalendarEvent } from 'calyx-rn';

function EventCalendar() {
  const [events, setEvents] = useState<CalendarEvent[]>([
    {
      id: '1',
      title: 'Team Meeting',
      startDate: new Date(2026, 4, 15, 10, 0),
      endDate: new Date(2026, 4, 15, 11, 0),
      color: '#007AFF',
      category: 'Work',
    },
  ]);

  return (
    <Calendar
      mode="month"
      events={events}
      onEventPress={(event) => console.log('Pressed:', event.title)}
    />
  );
}

📘 Examples

Month View

Classic grid calendar with date selection and event indicators.

<Calendar
  mode="month"
  selected={date}
  onSelect={setDate}
  weekStartsOn={1} // Monday
  showWeekNumbers
  theme="ocean"
  events={events}
/>

Props:

  • selected - Currently selected date
  • onSelect - Callback when date is selected
  • weekStartsOn - First day of week (0 = Sunday, 1 = Monday)
  • showWeekNumbers - Display ISO week numbers
  • theme - Theme name or custom theme object
  • events - Array of calendar events
  • minDate / maxDate - Date range constraints
  • disabledDates - Array of disabled dates

Week View

7-day week view with daily event display.

<Calendar
  mode="week"
  selected={date}
  onSelect={setDate}
  showWeekNumber
  theme="forest"
  events={events}
/>

Compound Component:

<Calendar.Week
  selected={date}
  onSelect={setDate}
  showWeekNumber
/>

Day View

Single day view with detailed event listing.

<Calendar
  mode="day"
  value={date}
  onChange={setDate}
  theme="sunset"
  events={events}
/>

Compound Component:

<Calendar.Day
  value={date}
  onChange={setDate}
/>

Timeline View ⏰

Hourly grid with time slots, conflict detection, and side-by-side event layout.

<Calendar
  mode="timeline"
  value={date}
  onChange={setDate}
  events={events}
  timelineConfig={{
    startHour: 8,        // Start at 8 AM
    endHour: 20,         // End at 8 PM
    slotDuration: 30,    // 30-minute slots
    showCurrentTime: true,
    businessHours: { start: 9, end: 17 },
    scrollToNow: true,   // Auto-scroll to current time
  }}
  onEventPress={(event) => console.log(event)}
  onEventLongPress={(event) => console.log('Long press:', event)}
/>

Compound Component:

<Calendar.Timeline
  value={date}
  events={events}
  timelineConfig={config}
/>

Features:

  • Conflict Detection - Automatically detects overlapping events
  • Side-by-Side Layout - Conflicting events displayed in columns
  • Current Time Indicator - Red line showing current time
  • Business Hours - Highlighted background for work hours
  • Auto-Scroll - Scrolls to current time on mount
  • Custom Time Range - Define your own start/end hours

TimelineConfig Props:

type TimelineConfig = {
  startHour?: number;        // Default: 0
  endHour?: number;          // Default: 24
  slotDuration?: number;     // Default: 30 (minutes)
  showCurrentTime?: boolean; // Default: true
  businessHours?: { start: number; end: number }; // Default: 9-17
  scrollToNow?: boolean;     // Default: true
};

Agenda View 📅

Chronological list with day/week/month grouping and infinite scroll.

<Calendar
  mode="agenda"
  value={date}
  onChange={setDate}
  events={events}
  agendaConfig={{
    groupBy: 'day',        // 'day' | 'week' | 'month'
    showEmptyDays: false,  // Hide days with no events
    futureMonths: 3,       // Load 3 months ahead
    dateFormat: 'MMMM d, yyyy',
  }}
  onEventPress={(event) => console.log(event)}
/>

Compound Component:

<Calendar.Agenda
  value={date}
  events={events}
  agendaConfig={config}
/>

Features:

  • Grouping - Group events by day, week, or month
  • Section Headers - Auto-generated with event counts
  • Infinite Scroll - Loads more months as you scroll
  • Smart Formatting - "TODAY", "TOMORROW", or formatted dates
  • All-Day Events - Special handling for all-day events
  • Category Badges - Colored category labels
  • Performance - FlatList virtualization for large lists

AgendaConfig Props:

type AgendaConfig = {
  groupBy?: 'day' | 'week' | 'month'; // Default: 'day'
  showEmptyDays?: boolean;             // Default: false
  futureMonths?: number;               // Default: 3
  dateFormat?: string;                 // Default: 'MMMM d, yyyy'
};

🎨 Theming

Built-in Themes

Six beautiful themes ready to use:

<Calendar theme="light" />   // Clean white background
<Calendar theme="dark" />    // Dark mode
<Calendar theme="ocean" />   // Blue ocean vibes
<Calendar theme="forest" />  // Green forest tones
<Calendar theme="sunset" />  // Warm sunset colors
<Calendar theme="minimal" /> // Minimalist design

Theme Provider

Apply theme to entire component tree:

import { ThemeProvider } from 'calyx-rn';

function App() {
  return (
    <ThemeProvider theme="dark">
      <Calendar mode="month" />
      <Calendar mode="week" />
      {/* All calendars use dark theme */}
    </ThemeProvider>
  );
}

Custom Theme

Create your own theme with full type safety:

import type { CalendarTheme } from 'calyx-rn';

const customTheme: CalendarTheme = {
  colors: {
    background: '#1a1a1a',
    foreground: '#ffffff',
    primary: '#ff6b6b',
    primaryForeground: '#ffffff',
    muted: '#404040',
    mutedForeground: '#999999',
    accent: '#4ecdc4',
    border: '#333333',
  },
  spacing: {
    cellSize: 48,
    cellGap: 2,
    padding: 16,
    headerSpacing: 12,
  },
  borderRadius: {
    cell: 24,
    container: 12,
  },
  fontSize: {
    day: 16,
    weekday: 12,
    header: 20,
  },
  fontWeight: {
    regular: '400',
    bold: '600',
  },
};

<Calendar theme={customTheme} />

🔧 API Reference

Calendar Component

Main router component with mode switching:

type CalendarProps = {
  // Mode
  mode?: 'month' | 'week' | 'day' | 'timeline' | 'agenda';
  
  // Date Selection (controlled)
  selected?: Date;
  onSelect?: (date: Date) => void;
  
  // Date Value (controlled - for day/timeline/agenda)
  value?: Date;
  onChange?: (date: Date) => void;
  
  // Events
  events?: CalendarEvent[];
  onEventPress?: (event: CalendarEvent) => void;
  onEventLongPress?: (event: CalendarEvent) => void;
  
  // Configuration
  weekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6;
  showWeekNumbers?: boolean;
  timelineConfig?: TimelineConfig;
  agendaConfig?: AgendaConfig;
  
  // Constraints
  minDate?: Date;
  maxDate?: Date;
  disabledDates?: Date[];
  disabled?: boolean;
  
  // Theming
  theme?: CalendarTheme | ThemeName;
  
  // Customization
  renderDay?: (day: CalendarDay) => React.ReactNode;
  
  // Styling
  style?: ViewStyle;
};

CalendarEvent Type

type CalendarEvent = {
  id: string;
  title: string;
  description?: string;
  startDate: Date;
  endDate: Date;
  isAllDay?: boolean;
  color?: string;
  category?: string;
  createdAt?: Date;
  updatedAt?: Date;
};

Compound Components

All compound components support the same props as the main Calendar component:

Calendar.Month   // Month grid view
Calendar.Week    // Week view
Calendar.Day     // Day view
Calendar.Timeline // Timeline/hourly view
Calendar.Agenda   // Agenda/list view

🎭 Customization

Custom Day Rendering

Full control over day cell appearance:

<Calendar.Month
  renderDay={(day) => (
    <View style={styles.customDay}>
      <Text style={styles.dayNumber}>{day.calendarDate.day}</Text>
      
      {day.isToday && (
        <View style={styles.todayBadge}>
          <Text>Today</Text>
        </View>
      )}
      
      {day.isOutside && <Text style={styles.muted}>•</Text>}
      
      {hasEvent(day.date) && (
        <View style={styles.eventDot} />
      )}
    </View>
  )}
/>

Day Object:

type CalendarDay = {
  date: Date;
  calendarDate: { day: number; month: number; year: number };
  isToday: boolean;
  isOutside: boolean; // Outside current month
  isWeekend: boolean;
};

Custom Event Rendering (Timeline)

Customize event cards in Timeline view:

<Calendar.Timeline
  renderEvent={(event, layout) => (
    <Pressable
      style={{
        position: 'absolute',
        top: layout.top,
        left: `${layout.left}%`,
        width: `${layout.width}%`,
        height: layout.height,
        backgroundColor: event.color,
        borderRadius: 8,
        padding: 8,
      }}
      onPress={() => console.log(event)}
    >
      <Text style={{ color: 'white', fontWeight: 'bold' }}>
        {event.title}
      </Text>
      <Text style={{ color: 'white', fontSize: 12 }}>
        {formatTime(event.startDate)}
      </Text>
    </Pressable>
  )}
/>

🪝 Headless Hooks

Use the headless hooks for complete control over rendering:

useMonthCalendar

import { useMonthCalendar } from 'calyx-rn';

const calendar = useMonthCalendar({
  initialDate: new Date(),
  weekStartsOn: 0,
});

// Access:
calendar.monthData      // { year, month, weeks: [{ days }] }
calendar.goToNextMonth()
calendar.goToPreviousMonth()
calendar.goToToday()
calendar.goToDate(date)

useWeekCalendar

import { useWeekCalendar } from 'calyx-rn';

const calendar = useWeekCalendar({
  initialDate: new Date(),
  weekStartsOn: 1,
});

// Access:
calendar.weekData       // { weekNumber, days: [] }
calendar.goToNextWeek()
calendar.goToPreviousWeek()

useTimelineLayout

Calculate event positions for Timeline view:

import { useTimelineLayout } from 'calyx-rn';

const layouts = useTimelineLayout(events, currentDate, {
  startHour: 9,
  endHour: 17,
});

// Returns: Array<TimelineEventLayout>
// { event, top, height, left, width, columnIndex, totalColumns }

useAgendaGrouping

Group events by day/week/month:

import { useAgendaGrouping } from 'calyx-rn';

const sections = useAgendaGrouping(events, startDate, {
  groupBy: 'day',
  futureMonths: 3,
});

// Returns: Array<AgendaSection>
// { title, date, events: [] }

📚 Event Management

Fetching from API

import { Calendar } from 'calyx-rn';
import type { CalendarEvent } from 'calyx-rn';

function MyCalendar() {
  const [events, setEvents] = useState<CalendarEvent[]>([]);

  useEffect(() => {
    fetch('https://api.example.com/events')
      .then(res => res.json())
      .then(data => {
        // Transform API data to CalendarEvent format
        const calendarEvents = data.map(apiEvent => ({
          id: apiEvent.id,
          title: apiEvent.title,
          startDate: new Date(apiEvent.start_time),
          endDate: new Date(apiEvent.end_time),
          color: apiEvent.color,
          category: apiEvent.category,
        }));
        setEvents(calendarEvents);
      });
  }, []);

  return <Calendar mode="month" events={events} />;
}

Using with React Query

import { useQuery } from '@tanstack/react-query';
import { Calendar } from 'calyx-rn';

function MyCalendar() {
  const { data: events = [] } = useQuery({
    queryKey: ['events'],
    queryFn: fetchEvents,
  });

  return <Calendar mode="month" events={events} />;
}

Using with Zustand Store

import { create } from 'zustand';
import { Calendar } from 'calyx-rn';

const useEventStore = create((set) => ({
  events: [],
  addEvent: (event) => set((state) => ({
    events: [...state.events, event]
  })),
}));

function MyCalendar() {
  const events = useEventStore((state) => state.events);
  
  return <Calendar mode="month" events={events} />;
}

🔍 Advanced Usage

Date Range Selection

function DateRangePicker() {
  const [start, setStart] = useState<Date | null>(null);
  const [end, setEnd] = useState<Date | null>(null);

  const handleSelect = (date: Date) => {
    if (!start) {
      setStart(date);
    } else if (!end) {
      setEnd(date);
    } else {
      setStart(date);
      setEnd(null);
    }
  };

  return (
    <Calendar
      mode="month"
      onSelect={handleSelect}
      renderDay={(day) => {
        const isInRange = start && end && 
          day.date >= start && day.date <= end;
        
        return (
          <View style={[
            styles.day,
            isInRange && styles.dayInRange
          ]}>
            <Text>{day.calendarDate.day}</Text>
          </View>
        );
      }}
    />
  );
}

Multi-Select

function MultiSelectCalendar() {
  const [selected, setSelected] = useState<Date[]>([]);

  const handleSelect = (date: Date) => {
    setSelected(prev => {
      const exists = prev.some(d => isSameDay(d, date));
      if (exists) {
        return prev.filter(d => !isSameDay(d, date));
      }
      return [...prev, date];
    });
  };

  return (
    <Calendar
      mode="month"
      onSelect={handleSelect}
      renderDay={(day) => {
        const isSelected = selected.some(d => isSameDay(d, day.date));
        return (
          <View style={[styles.day, isSelected && styles.selected]}>
            <Text>{day.calendarDate.day}</Text>
          </View>
        );
      }}
    />
  );
}

🧪 Testing

import { render, fireEvent } from '@testing-library/react-native';
import { Calendar } from 'calyx-rn';

test('selects date when pressed', () => {
  const onSelect = jest.fn();
  const { getByText } = render(
    <Calendar mode="month" onSelect={onSelect} />
  );
  
  fireEvent.press(getByText('15'));
  expect(onSelect).toHaveBeenCalled();
});

🚀 Performance Tips

  1. Memoize Events - Use useMemo for event arrays:

    const events = useMemo(() => fetchedEvents, [fetchedEvents]);
  2. Virtualize Long Lists - Agenda view automatically uses FlatList virtualization

  3. Optimize Renders - Use React.memo for custom day components

  4. Limit Date Range - Use minDate and maxDate to constrain navigation


🛠️ Development

# Clone repository
git clone https://github.com/lakshya-rohila/-calyx.git
cd -calyx

# Install dependencies
npm install

# Run tests
npm test

# Type check
npm run typecheck

# Build library
npm run build

# Run example app
npm run ios
npm run android

🤝 Contributing

Contributions are welcome! Please see our Contributing Guide for details.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Requirements:

  • All PRs must include tests
  • Follow the existing code style
  • Update documentation for new features

📄 License

MIT © Lakshya Rohila

See LICENSE for details.


💬 Support


🙏 Acknowledgments

Built with ❤️ using: