Plugins
Day Flow uses a plugin architecture to extend functionality. Plugins provide modular features that can be enabled, disabled, or configured based on your needs.
Plugin System Overview
The plugin system allows you to:
- Enable/disable features - Only load what you need
- Configure behavior - Customize plugin settings
- Extend functionality - Create custom plugins
- Access plugin APIs - Use plugin services in your code
Built-in Plugins
Day Flow comes with two core plugins:
Drag Plugin
Enables drag-and-drop functionality for creating, moving, and resizing events.
Features:
- Drag events to move them
- Resize events to adjust duration
- Double-click to create new events
- Drag in all-day row to create all-day events
- View-specific behavior
Installation:
import {
useCalendarApp,
DayFlowCalendar,
createDragPlugin,
createMonthView,
ViewType,
} from '@dayflow/core';
import '@dayflow/core/dist/styles.css';
function MyCalendar() {
const dragPlugin = createDragPlugin({
enableDrag: true,
enableResize: true,
enableCreate: true,
enableAllDayCreate: true,
supportedViews: [ViewType.DAY, ViewType.WEEK, ViewType.MONTH],
});
const calendar = useCalendarApp({
views: [createMonthView()],
plugins: [dragPlugin],
});
return <DayFlowCalendar calendar={calendar} />;
}Configuration:
interface DragPluginConfig {
enableDrag: boolean; // Enable dragging events (default: true)
enableResize: boolean; // Enable resizing events (default: true)
enableCreate: boolean; // Enable creating events by double-click (default: true)
enableAllDayCreate: boolean; // Enable creating all-day events (default: true)
supportedViews: ViewType[]; // Views that support drag (default: [DAY, WEEK, MONTH])
}Default Configuration:
const dragPlugin = createDragPlugin({
enableDrag: true,
enableResize: true,
enableCreate: true,
enableAllDayCreate: true,
supportedViews: [ViewType.DAY, ViewType.WEEK, ViewType.MONTH],
});Accessing Drag API:
// Get drag service from the calendar app
const dragService = calendar.app.getPlugin<DragService>('drag');
// Get current configuration
const config = dragService?.getConfig();
// Update configuration dynamically
dragService?.updateConfig({
enableResize: false,
});
// Check if view supports drag
const isSupported = dragService?.isViewSupported(ViewType.MONTH);Events Plugin
Provides advanced event management capabilities including validation, filtering, and querying.
Features:
- Event validation
- Date range queries
- Event filtering
- Automatic day recalculation
- Max events per day limit
Installation:
import {
useCalendarApp,
DayFlowCalendar,
createEventsPlugin,
createMonthView,
} from '@dayflow/core';
import '@dayflow/core/dist/styles.css';
function MyCalendar() {
const eventsPlugin = createEventsPlugin({
enableAutoRecalculate: true,
enableValidation: true,
maxEventsPerDay: 50,
});
const calendar = useCalendarApp({
views: [createMonthView()],
plugins: [eventsPlugin],
});
return <DayFlowCalendar calendar={calendar} />;
}Configuration:
interface EventsPluginConfig {
enableAutoRecalculate?: boolean; // Auto-recalculate event days (default: true)
enableValidation?: boolean; // Validate events before add/update (default: true)
defaultEvents?: Event[]; // Initial events (default: [])
maxEventsPerDay?: number; // Maximum events per day (default: 50)
}Accessing Events API:
// Get events service from the calendar app
const eventsService = calendar.app.getPlugin<EventsService>('events');
// Get all events
const allEvents = eventsService?.getAll();
// Get event by ID
const event = eventsService?.getById('event-1');
// Get events by date
const todayEvents = eventsService?.getByDate(new Date());
// Get events by date range
const rangeEvents = eventsService?.getByDateRange(
new Date(2024, 9, 1),
new Date(2024, 9, 31)
);
// Get events for specific day of week
const mondayEvents = eventsService?.getByDay(0, weekStart);
// Get all-day events
const allDayEvents = eventsService?.getAllDayEvents(0, events);
// Validate an event
const errors = eventsService?.validateEvent(event);
if (errors && errors.length > 0) {
console.error('Validation errors:', errors);
}
// Filter events by calendar type
const filteredEvents = eventsService?.filterEvents(
events,
event => event.calendarId === 'work'
);
// Recalculate event days
const recalculatedEvents = eventsService?.recalculateEventDays(
events,
weekStart
);Using Multiple Plugins
You can combine multiple plugins for full functionality:
import {
useCalendarApp,
DayFlowCalendar,
createDragPlugin,
createEventsPlugin,
createMonthView,
createWeekView,
} from '@dayflow/core';
import '@dayflow/core/dist/styles.css';
function MyCalendar() {
const dragPlugin = createDragPlugin({
enableDrag: true,
enableResize: true,
enableCreate: true,
});
const eventsPlugin = createEventsPlugin({
enableValidation: true,
maxEventsPerDay: 50,
});
const calendar = useCalendarApp({
views: [createMonthView(), createWeekView()],
plugins: [dragPlugin, eventsPlugin],
events: initialEvents,
});
return <DayFlowCalendar calendar={calendar} />;
}Using Both Plugins Together
For most use cases, you’ll want to use both plugins together:
import {
useCalendarApp,
DayFlowCalendar,
createDragPlugin,
createEventsPlugin,
createMonthView,
} from '@dayflow/core';
import '@dayflow/core/dist/styles.css';
function MyCalendar() {
const dragPlugin = createDragPlugin({
enableDrag: true,
enableResize: true,
});
const eventsPlugin = createEventsPlugin({
enableValidation: true,
maxEventsPerDay: 100,
});
const calendar = useCalendarApp({
views: [createMonthView()],
plugins: [dragPlugin, eventsPlugin],
});
return <DayFlowCalendar calendar={calendar} />;
}Creating Custom Plugins
You can create your own plugins to extend calendar functionality:
Plugin Interface
interface CalendarPlugin {
name: string; // Unique plugin name
install: (app: CalendarApp) => void; // Installation function
config?: Record<string, unknown>; // Plugin configuration
api?: unknown; // Public API
}Example: Analytics Plugin
import { CalendarPlugin, CalendarApp, Event } from '@dayflow/core';
interface AnalyticsConfig {
trackEventCreate: boolean;
trackEventUpdate: boolean;
trackEventDelete: boolean;
trackViewChange: boolean;
}
interface AnalyticsService {
logEvent: (name: string, data: any) => void;
getStats: () => { eventCreates: number; eventUpdates: number };
}
export function createAnalyticsPlugin(
config: Partial<AnalyticsConfig> = {}
): CalendarPlugin {
const finalConfig: AnalyticsConfig = {
trackEventCreate: true,
trackEventUpdate: true,
trackEventDelete: true,
trackViewChange: true,
...config,
};
let stats = {
eventCreates: 0,
eventUpdates: 0,
eventDeletes: 0,
viewChanges: 0,
};
const analyticsService: AnalyticsService = {
logEvent: (name: string, data: any) => {
console.log(`[Analytics] ${name}:`, data);
// Send to your analytics service
},
getStats: () => ({
eventCreates: stats.eventCreates,
eventUpdates: stats.eventUpdates,
}),
};
return {
name: 'analytics',
config: finalConfig,
install: (app: CalendarApp) => {
console.log('📊 Analytics plugin installed');
// Hook into calendar callbacks
const originalAddEvent = app.addEvent.bind(app);
app.addEvent = (event: Event) => {
if (finalConfig.trackEventCreate) {
stats.eventCreates++;
analyticsService.logEvent('event_created', { id: event.id });
}
originalAddEvent(event);
};
const originalUpdateEvent = app.updateEvent.bind(app);
app.updateEvent = (id: string, updates: Partial<Event>) => {
if (finalConfig.trackEventUpdate) {
stats.eventUpdates++;
analyticsService.logEvent('event_updated', { id });
}
originalUpdateEvent(id, updates);
};
const originalDeleteEvent = app.deleteEvent.bind(app);
app.deleteEvent = (id: string) => {
if (finalConfig.trackEventDelete) {
stats.eventDeletes++;
analyticsService.logEvent('event_deleted', { id });
}
originalDeleteEvent(id);
};
},
api: analyticsService,
};
}Using Custom Plugin
import {
useCalendarApp,
DayFlowCalendar,
createMonthView,
} from '@dayflow/core';
function MyCalendar() {
const analyticsPlugin = createAnalyticsPlugin({
trackEventCreate: true,
trackEventUpdate: true,
});
const calendar = useCalendarApp({
views: [createMonthView()],
plugins: [analyticsPlugin],
});
// Access plugin API
const analytics = calendar.app.getPlugin<AnalyticsService>('analytics');
const stats = analytics?.getStats();
return <DayFlowCalendar calendar={calendar} />;
}Plugin Best Practices
1. Naming Convention
Use descriptive, unique names for your plugins:
// Good
name: 'analytics';
name: 'custom-validation';
name: 'sync';
// Bad
name: 'plugin';
name: 'p1';2. Configuration
Provide sensible defaults and make configuration optional:
const defaultConfig = {
enabled: true,
timeout: 5000,
};
export function createMyPlugin(config: Partial<MyConfig> = {}) {
const finalConfig = { ...defaultConfig, ...config };
// ...
}3. API Design
Expose a clean, typed API for plugin functionality:
interface MyPluginService {
doSomething: () => void;
getSomething: () => SomeData;
}
const service: MyPluginService = {
doSomething: () => {
/* ... */
},
getSomething: () => {
/* ... */
},
};
return {
name: 'my-plugin',
api: service,
};4. Error Handling
Handle errors gracefully and provide meaningful messages:
install: (app: CalendarApp) => {
try {
// Plugin initialization
} catch (error) {
console.error('[MyPlugin] Failed to initialize:', error);
throw new Error('MyPlugin initialization failed');
}
};5. Cleanup
Clean up resources when needed:
let timer: NodeJS.Timeout;
install: (app: CalendarApp) => {
timer = setInterval(() => {
// Do something periodically
}, 1000);
// Note: Add cleanup logic if your plugin needs it
// (Calendar doesn't have a built-in cleanup lifecycle yet)
};Plugin Lifecycle
- Plugin Creation - Call
createMyPlugin()with config - Plugin Registration - Add to
pluginsarray inuseCalendarApp - Installation -
install()function is called with CalendarApp instance - Usage - Access plugin API via
app.getPlugin()
// 1. Create
const plugin = createDragPlugin({ enableDrag: true });
// 2. Register
const calendar = useCalendarApp({
plugins: [plugin], // Installation happens here
});
// 3. Use
const dragService = calendar.app.getPlugin<DragService>('drag');Checking for Plugins
Always check if a plugin is installed before using it:
function MyComponent({ calendar }: { calendar: CalendarApp }) {
// Check if plugin exists
if (calendar.hasPlugin('drag')) {
const dragService = calendar.getPlugin<DragService>('drag');
// Use drag service
}
// Or get and check
const eventsService = calendar.getPlugin<EventsService>('events');
if (eventsService) {
const events = eventsService.getAll();
}
}Plugin TypeScript Types
import type {
CalendarPlugin,
DragService,
DragPluginConfig,
EventsService,
EventsPluginConfig,
} from '@dayflow/core';
// Type-safe plugin usage
const dragService = app.getPlugin<DragService>('drag');
const eventsService = app.getPlugin<EventsService>('events');Related Documentation
- Getting Started - Basic setup
- Events - Working with calendar events
- Views - Understanding calendar views
- API Reference - Complete API documentation