@chronux/core
v0.1.1
Published
Core utilities for the Chronux platform
Maintainers
Readme
@chronux/core
Core utilities for the Chronux platform - a modern, platform-agnostic TypeScript package featuring a powerful headless calendar library.
Features
- 🚀 Modern TypeScript - Built with TypeScript 5.x and ES2022
- 📦 Multiple Formats - ESM and CommonJS support
- 🧪 Comprehensive Testing - Vitest with coverage reporting
- 🔧 Development Tools - ESLint, Prettier, and TypeScript strict mode
- 🌍 Platform Agnostic - Works in Node.js, browsers, and other environments
- 📚 Full TypeScript Support - Complete type definitions included
- 📅 Headless Calendar - Flexible, extensible calendar state machine with zero UI opinions
- 🔍 Advanced Subscriptions - Deep state monitoring with path and selector-based subscriptions
Installation
npm install @chronux/coreCalendar Library
The core package includes a powerful headless calendar library that provides:
- Flexible State Management - Built-in state machine with subscription support
- Multiple Views - Month, week, and day views with custom view support
- Event Management - Add, update, remove, and query events
- Selection Features - Single and multi-date selection
- Drag & Drop - Built-in drag and drop support
- Plugin System - Extensible architecture with plugins and features
- Type Safety - Full TypeScript support with generic event types
- Advanced Subscriptions - Subscribe to specific state paths or computed values
Quick Start
import { Calendar, createCalendar, selectionFeature } from '@chronux/core';
// Create a calendar with events
const calendar = new Calendar({
events: [
{
id: '1',
start: new Date('2024-01-15'),
end: new Date('2024-01-15'),
data: { title: 'Meeting' },
},
],
defaultView: 'month',
_features: {
selection: selectionFeature({ multiple: true }),
},
});
// Subscribe to state changes
const unsubscribe = calendar.subscribe(state => {
console.log('Calendar state changed:', state);
});
// Navigate
calendar.next();
calendar.previous();
calendar.goToDate(new Date('2024-03-01'));
// Get data
const cells = calendar.getCells();
const events = calendar.getEvents();
const selectedDates = calendar.getState().selection;Advanced Subscriptions
The calendar provides three types of subscriptions for efficient state monitoring:
1. Full State Subscription
Subscribe to all state changes:
const unsubscribe = calendar.subscribe(state => {
console.log('Full state changed:', state);
});2. Selector-based Subscription
Subscribe to computed values using selectors:
// Subscribe to event count changes
const unsubscribeEventCount = calendar.subscribeToSelector<number>(
state => state.events.length,
(value, prevValue) => {
console.log('Event count changed from', prevValue, 'to', value);
}
);
// Subscribe to complex computed values
const unsubscribeTodayEvents = calendar.subscribeToSelector<number>(
state => {
const today = new Date();
return state.events.filter(
event => event.start.toDateString() === today.toDateString()
).length;
},
(value, prevValue) => {
console.log('Today events changed from', prevValue, 'to', value);
}
);
// Subscribe to selection state
const unsubscribeSelectionState = calendar.subscribeToSelector<boolean>(
state => state.selection.length > 0,
(value, prevValue) => {
console.log('Has selection changed:', value);
}
);Subscription Management
// Multiple subscriptions
const unsubscribe1 = calendar.subscribeToSelector<number>(
state => state.events.length,
() => {}
);
// Unsubscribe individually
unsubscribe1();
// Or let them be cleaned up automatically on destroy
calendar.destroy();Performance Benefits
- Selective Updates: Only receive notifications when relevant parts of state change
- Deep Comparison: Automatic deep equality checking prevents unnecessary updates
- Memory Efficient: Automatic cleanup prevents memory leaks
- Type Safe: Full TypeScript support with proper type inference
Basic Usage
import { Calendar, createCalendar } from '@chronux/core';
// Simple calendar
const calendar = createCalendar({
events: [],
defaultView: 'month',
});
// With custom event types
interface MyEvent {
id: string;
start: Date;
end: Date;
title: string;
description?: string;
}
const typedCalendar = new Calendar<MyEvent>({
events: [
{
id: '1',
start: new Date(),
end: new Date(),
title: 'My Event',
},
],
getEventId: event => event.id,
getEventStart: event => event.start,
getEventEnd: event => event.end,
});Views
The calendar supports multiple built-in views:
// Month view (default)
calendar.setView('month');
// Week view
calendar.setView('week');
// Day view
calendar.setView('day');Event Management
// Add event
calendar.addEvent({
id: 'new-event',
start: new Date(),
end: new Date(),
data: { title: 'New Event' },
});
// Update event
calendar.updateEvent('event-id', {
data: { title: 'Updated Event' },
});
// Remove event
calendar.removeEvent('event-id');
// Get events for specific date
const eventsForDate = calendar.getEventsForDate(new Date());
// Get events in visible range
const visibleEvents = calendar.getEvents();Selection
// Single selection
calendar.selectDate(new Date());
// Multiple selection
calendar.selectDate(new Date(), true);
// Clear selection
calendar.clearSelection();
// With selection feature
const calendarWithSelection = new Calendar({
data: [],
_features: {
selection: selectionFeature({
multiple: true,
range: true,
}),
},
});
// Use selection API
calendarWithSelection.selection.toggle(new Date());
calendarWithSelection.selection.selectRange(startDate, endDate);Custom Views
import type { ViewDefinition } from '@chronux/core';
const customView: ViewDefinition = {
id: 'custom',
getDateRange: date => ({
start: new Date(date.getFullYear(), date.getMonth(), 1),
end: new Date(date.getFullYear(), date.getMonth() + 1, 0),
}),
getGrid: () => ({ rows: 5, columns: 7 }),
getCellDate: (row, col, startDate) => {
// Custom cell date calculation
return new Date(
startDate.getTime() + (row * 7 + col) * 24 * 60 * 60 * 1000
);
},
};
const calendar = new Calendar({
data: [],
views: {
custom: customView,
},
defaultView: 'custom',
});Plugins and Features
import { dragDropFeature } from '@chronux/core';
const calendar = new Calendar({
data: [],
_features: {
dragDrop: dragDropFeature({
onDrop: (event, newDate) => {
// Custom drop logic
return true; // Allow drop
},
}),
},
});
// Use drag and drop API
calendar.dragDrop.startDrag(event);
calendar.dragDrop.drop(newDate);API Reference
Calendar Class
Constructor
new Calendar<TEvent, TResource>(options: CalendarOptions<TEvent, TResource>)Methods
State Management
getState(): CalendarState<TEvent>- Get current statesetState(updater): void- Update statesubscribe(listener): () => void- Subscribe to all state changessubscribeToSelector<T>(selector, listener): () => void- Subscribe to computed valuesdestroy(): void- Clean up resources
Navigation
next(): void- Go to next periodprevious(): void- Go to previous periodgoToDate(date): void- Go to specific datetoday(): void- Go to today
Views
setView(viewId): void- Change viewgetHeaderGroups(): Array<{id: string, headers: string[]}>- Get header datagetRowModel(): {rows: Row<TEvent>[]}- Get row modelgetCells(): Cell<TEvent>[][]- Get cell data
Events
addEvent(event): void- Add eventupdateEvent(id, updates): void- Update eventremoveEvent(id): void- Remove eventgetEventsForDate(date): TEvent[]- Get events for dategetEvents(): TEvent[]- Get events in visible range
Selection
selectDate(date, multi?): void- Select dateclearSelection(): void- Clear selection
Types
CalendarEvent
interface CalendarEvent<T = unknown> {
id: string;
start: Date;
end: Date;
data?: T;
}CalendarState
interface CalendarState<
TEvent extends CalendarEvent<unknown> = CalendarEvent<unknown>,
> {
currentDate: Date;
view: ViewConfig;
events: TEvent[];
selection: Date[];
visibleRange: { start: Date; end: Date };
gridDimensions: { rows: number; columns: number };
draggedEvent?: TEvent | null;
dropTarget?: Date | null;
selectionMode?: 'single' | 'multiple';
}Cell
interface Cell<TEvent extends CalendarEvent<unknown> = CalendarEvent<unknown>> {
date: Date;
row: number;
col: number;
events: TEvent[];
isSelected: boolean;
isToday: boolean;
isCurrentMonth: boolean;
meta: Record<string, unknown>;
getCellProps?: () => Record<string, unknown>;
}Features
Selection Feature
selectionFeature(options: {
multiple?: boolean;
range?: boolean;
}): FeatureDrag & Drop Feature
dragDropFeature(options: {
onDrop?: (event: unknown, newDate: Date) => boolean;
}): FeatureUtilities
import {
addDays,
startOfMonth,
endOfMonth,
startOfWeek,
isSameDay,
isToday,
} from '@chronux/core';Legacy API
The package also includes legacy utility functions for backward compatibility:
import {
exampleFunction,
exampleAsyncFunction,
validateConfig,
} from '@chronux/core';Development
This package is part of the Chronux monorepo. See the main README for development setup instructions.
License
MIT License - see LICENSE for details.
