Calendar
A sophisticated React Native calendar component with infinite scrolling, pinch-to-zoom functionality, and real-time event management. Built with React Native Reanimated for smooth animations and optimized performance.
๐ Features
- Infinite Scrolling: Seamlessly navigate through dates with edge loading
- Pinch-to-Zoom: Adjust time scale from 0.5x to 3x with smooth animations
- Real-time Current Time Indicator: Shows current time with live updates
- Event Management: Display events with custom colors and time ranges
- Month Picker Modal: Quick date selection with month/year navigation
- Responsive Design: Adapts to different screen sizes and orientations
- Performance Optimized: Uses React.memo, useCallback, and efficient re-renders
- TypeScript Support: Full type safety with comprehensive interfaces
๐ Project Structure
booking-planner/
โโโ components/
โ โโโ DayColumn.tsx # Individual day column component
โ โโโ EventBlock.tsx # Event display component
โ โโโ HourGridRow.tsx # Hour grid row component
โ โโโ MonthPicker.tsx # Month picker modal
โ โโโ TimeLabel.tsx # Time label component
โโโ constants/
โ โโโ index.ts # App constants and sample events
โโโ hooks/
โ โโโ useCalendarData.ts # Calendar data management hook
โโโ types/
โ โโโ index.ts # TypeScript interfaces
โโโ utils/
โ โโโ index.ts # Utility functions
โโโ _layout.tsx # Navigation layout
โโโ index.tsx # Main calendar component
โโโ README.md
๐ ๏ธ Setup Instructions
1. Prerequisites
Ensure you have the following dependencies in your package.json
:
{ "dependencies": { "react-native-reanimated": "^3.0.0", "react-native-gesture-handler": "^2.0.0", "@expo/vector-icons": "^13.0.0", "@react-navigation/drawer": "^6.0.0" } }
2. Context Setup
Wrap your app with the CalendarProvider
:
// App.tsx or your root component import { CalendarProvider } from '@/contexts/CalendarContext'; export default function App() { return ( <CalendarProvider> {/* Your app components */} </CalendarProvider> ); }
3. Navigation Integration
Add the calendar to your navigation stack:
// In your navigation configuration import BookingPlanner from '@/app/booking-planner/index'; // Add to your stack navigator <Stack.Screen name="booking-planner" component={BookingPlanner} />
Or navigate to the route directly:
// Navigate to the booking planner navigation.navigate('booking-planner');
4. Gesture Handler Setup
Ensure GestureHandlerRootView
wraps your app:
import { GestureHandlerRootView } from 'react-native-gesture-handler'; export default function App() { return ( <GestureHandlerRootView style={{ flex: 1 }}> <CalendarProvider> {/* Your app */} </CalendarProvider> </GestureHandlerRootView> ); }
๐ฏ Core Components
Main Calendar (index.tsx
)
The main calendar component that orchestrates all functionality:
- Infinite Scrolling: Loads days dynamically as user scrolls
- Pinch Gesture: Handles zoom functionality with
Gesture.Pinch()
- Synchronized Scrolling: Keeps header and body in sync
- Current Time Indicator: Shows live current time position
Event Management
Events are defined with the following interface:
interface EventItem { id: string; title: string; date: string; // YYYY-MM-DD format start: string; // HH:mm format end: string; // HH:mm format color: string; // Hex color code }
Data Hook (useCalendarData.ts
)
Manages calendar state and data loading:
- Day Generation: Creates date ranges for infinite scrolling
- Event Filtering: Filters events by date
- Loading States: Handles future/past day loading
- Date Selection: Manages selected and viewing dates
๐จ Customization
Constants Configuration
Modify constants/index.ts
to customize:
export const DEFAULT_CELL_HEIGHT = 60; // Default hour height export const MIN_SCALE = 0.5; // Minimum zoom level export const MAX_SCALE = 3; // Maximum zoom level export const TIME_COLUMN_WIDTH = 60; // Time column width export const ALL_DAY_HEIGHT = 40; // All-day section height
Event Colors
Update the SAMPLE_EVENTS
array in constants/index.ts
:
export const SAMPLE_EVENTS = [ { id: '1', title: 'Meeting', date: '2025-01-15', start: '09:00', end: '10:00', color: '#FFDAD2', // Custom color }, // ... more events ];
Styling
Customize component styles in their respective files:
EventBlock.tsx
: Event appearance and layoutTimeLabel.tsx
: Time label stylingDayColumn.tsx
: Day column appearanceMonthPicker.tsx
: Month picker modal styling
๐ง Advanced Usage
Custom Event Rendering
Override the default event rendering:
// In your calendar component const renderEvent = useCallback((event: EventItem) => ( <CustomEventBlock event={event} cellHeightSV={cellHeight} /> ), [cellHeight]);
Custom Data Source
Replace the sample events with your data source:
// In useCalendarData.ts const getEventsByDayCallback = useCallback( (d: Date) => getEventsByDay(YOUR_EVENTS_DATA, d), [] );
Calendar Context Integration
Access calendar state from anywhere:
import { useCalendar } from '@/contexts/CalendarContext'; function MyComponent() { const { numberOfDays, setNumberOfDays } = useCalendar(); // Change view (1, 3, 7 days) const changeView = (days: number) => { setNumberOfDays(days); }; }
๐ฎ User Interactions
Navigation
- Horizontal Swipe: Navigate between days
- Pinch Gesture: Zoom in/out of time scale
- Tap Events: Select events (customize in EventBlock)
- Month Picker: Tap header date to open month picker
Gestures
- Pinch: Adjust time scale (0.5x - 3x)
- Scroll: Infinite day navigation
- Tap: Event selection and date picking
๐ฑ Performance Optimizations
React.memo Usage
All components are wrapped with React.memo
for efficient re-renders.
Shared Values
Uses useSharedValue
for smooth animations:
cellHeight
: Controls zoom levelminutesSV
: Tracks current timebaseScale
: Manages pinch gesture
Efficient Rendering
FlatList
withgetItemLayout
for predictable scrollinginitialNumToRender
andmaxToRenderPerBatch
optimizationremoveClippedSubviews
for memory management
๐ Troubleshooting
Common Issues
-
Gesture Handler Not Working
- Ensure
GestureHandlerRootView
wraps your app - Check gesture handler installation
- Ensure
-
Animations Not Smooth
- Verify Reanimated 3.x installation
- Check for conflicting gesture handlers
-
Events Not Displaying
- Verify event date format (YYYY-MM-DD)
- Check time format (HH:mm)
- Ensure events array is properly structured
-
Performance Issues
- Implement virtual scrolling for large datasets
- Use
React.memo
for custom components
Debug Mode
Enable debug logging by adding console logs in key functions:
// In useCalendarData.ts const loadDaysAround = useCallback((anchor: Date) => { console.log('Loading days around:', anchor); // ... existing code }, []);
๐ License
This component is part of the landingcomponents.com library.