@campxdev/react-blueprint 2.2.3 → 2.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/types/src/components/Navigation/Calendar/Calendar.d.ts +3 -0
- package/dist/cjs/types/src/components/Navigation/Calendar/index.d.ts +3 -0
- package/dist/cjs/types/src/components/Navigation/Calendar/styles.d.ts +9 -0
- package/dist/cjs/types/src/components/Navigation/Calendar/types.d.ts +90 -0
- package/dist/cjs/types/src/components/Navigation/Calendar/utils.d.ts +55 -0
- package/dist/cjs/types/src/components/Navigation/export.d.ts +1 -0
- package/dist/cjs/types/src/stories/Navigation/Calendar.stories.d.ts +10 -0
- package/dist/esm/index.js +2 -2
- package/dist/esm/types/src/components/Navigation/Calendar/Calendar.d.ts +3 -0
- package/dist/esm/types/src/components/Navigation/Calendar/index.d.ts +3 -0
- package/dist/esm/types/src/components/Navigation/Calendar/styles.d.ts +9 -0
- package/dist/esm/types/src/components/Navigation/Calendar/types.d.ts +90 -0
- package/dist/esm/types/src/components/Navigation/Calendar/utils.d.ts +55 -0
- package/dist/esm/types/src/components/Navigation/export.d.ts +1 -0
- package/dist/esm/types/src/stories/Navigation/Calendar.stories.d.ts +10 -0
- package/dist/index.d.ts +151 -4
- package/package.json +6 -1
- package/src/components/Navigation/Calendar/Calendar.tsx +243 -0
- package/src/components/Navigation/Calendar/README.md +308 -0
- package/src/components/Navigation/Calendar/index.ts +3 -0
- package/src/components/Navigation/Calendar/styles.tsx +222 -0
- package/src/components/Navigation/Calendar/types.ts +120 -0
- package/src/components/Navigation/Calendar/utils.ts +265 -0
- package/src/components/Navigation/export.ts +1 -0
- package/src/stories/Navigation/Calendar.stories.tsx +475 -0
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
# Calendar Component
|
|
2
|
+
|
|
3
|
+
A comprehensive calendar component built on FullCalendar with full MUI theme integration. Supports multiple views, event management, and responsive design.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 📅 **Multiple Views**: Month, Week, Day, and List views
|
|
8
|
+
- 🎨 **Theme Integration**: Full MUI theme support with light/dark modes
|
|
9
|
+
- 📱 **Responsive Design**: Mobile-friendly with adaptive layouts
|
|
10
|
+
- ✏️ **Event Management**: Create, edit, delete, and drag-drop events
|
|
11
|
+
- 🎯 **Event Handlers**: Comprehensive callback system for interactions
|
|
12
|
+
- 🔧 **Customizable**: Custom event rendering and styling options
|
|
13
|
+
- ♿ **Accessible**: ARIA compliant and keyboard navigation
|
|
14
|
+
- 🌐 **Internationalization**: Support for multiple locales
|
|
15
|
+
- 📊 **Business Hours**: Constrain events to business hours
|
|
16
|
+
- 🎨 **Custom Styling**: Override default FullCalendar styles
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
The Calendar component comes with the react-blueprint library. Ensure you have the required peer dependencies:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
yarn add @campxdev/react-blueprint
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Basic Usage
|
|
27
|
+
|
|
28
|
+
```tsx
|
|
29
|
+
import { Calendar } from '@campxdev/react-blueprint';
|
|
30
|
+
|
|
31
|
+
const MyCalendar = () => {
|
|
32
|
+
const events = [
|
|
33
|
+
{
|
|
34
|
+
id: '1',
|
|
35
|
+
title: 'Team Meeting',
|
|
36
|
+
start: '2024-01-15T09:00:00',
|
|
37
|
+
end: '2024-01-15T10:00:00',
|
|
38
|
+
},
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
return <Calendar events={events} height="600px" initialView="dayGridMonth" />;
|
|
42
|
+
};
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Props
|
|
46
|
+
|
|
47
|
+
### Event Data
|
|
48
|
+
|
|
49
|
+
- `events?: CalendarEvent[]` - Array of events to display
|
|
50
|
+
|
|
51
|
+
### Event Handlers
|
|
52
|
+
|
|
53
|
+
- `onEventClick?: (eventInfo) => void` - Called when an event is clicked
|
|
54
|
+
- `onEventDrop?: (eventInfo) => void` - Called when an event is dragged and dropped
|
|
55
|
+
- `onEventResize?: (eventInfo) => void` - Called when an event is resized
|
|
56
|
+
- `onDateClick?: (dateInfo) => void` - Called when a date is clicked
|
|
57
|
+
- `onDateSelect?: (selectInfo) => void` - Called when a date range is selected
|
|
58
|
+
- `onEventsSet?: (events) => void` - Called when events are updated
|
|
59
|
+
|
|
60
|
+
### View Configuration
|
|
61
|
+
|
|
62
|
+
- `initialView?: CalendarView` - Initial view to display (`'dayGridMonth'` | `'timeGridWeek'` | `'timeGridDay'` | `'listWeek'`)
|
|
63
|
+
- `views?: CalendarView[]` - Available views in the toolbar
|
|
64
|
+
- `headerToolbar?: CalendarHeaderToolbar | boolean` - Header toolbar configuration
|
|
65
|
+
|
|
66
|
+
### Calendar Behavior
|
|
67
|
+
|
|
68
|
+
- `editable?: boolean` - Allow events to be edited (default: `false`)
|
|
69
|
+
- `selectable?: boolean` - Allow date/time selection (default: `false`)
|
|
70
|
+
- `selectMirror?: boolean` - Show selection preview (default: `true`)
|
|
71
|
+
- `eventResizable?: boolean` - Allow event resizing (default: `false`)
|
|
72
|
+
- `eventDraggable?: boolean` - Allow event dragging (default: `false`)
|
|
73
|
+
- `dayMaxEvents?: boolean | number` - Limit events shown per day (default: `true`)
|
|
74
|
+
|
|
75
|
+
### Styling & Layout
|
|
76
|
+
|
|
77
|
+
- `height?: string | number` - Calendar height (default: `'auto'`)
|
|
78
|
+
- `aspectRatio?: number` - Calendar aspect ratio
|
|
79
|
+
- `containerProps?: StackProps` - Props for the container Stack component
|
|
80
|
+
|
|
81
|
+
### Localization
|
|
82
|
+
|
|
83
|
+
- `locale?: string` - Language locale (default: `'en'`)
|
|
84
|
+
- `timezone?: string` - Timezone (default: `'local'`)
|
|
85
|
+
- `firstDayOfWeek?: 0 | 1 | 2 | 3 | 4 | 5 | 6` - First day of week (default: `0` for Sunday)
|
|
86
|
+
|
|
87
|
+
### Custom Rendering
|
|
88
|
+
|
|
89
|
+
- `eventContent?: (eventInfo) => React.ReactNode` - Custom event content renderer
|
|
90
|
+
- `dayCellContent?: (dayInfo) => React.ReactNode` - Custom day cell content renderer
|
|
91
|
+
|
|
92
|
+
### Navigation
|
|
93
|
+
|
|
94
|
+
- `showNavigationButtons?: boolean` - Show prev/next buttons (default: `true`)
|
|
95
|
+
- `showViewSwitcher?: boolean` - Show view switcher buttons (default: `true`)
|
|
96
|
+
- `showToday?: boolean` - Show today button (default: `true`)
|
|
97
|
+
|
|
98
|
+
### Advanced
|
|
99
|
+
|
|
100
|
+
- `weekends?: boolean` - Show weekend days (default: `true`)
|
|
101
|
+
- `businessHours?: any` - Business hours configuration
|
|
102
|
+
- `eventConstraint?: any` - Constraints for event placement
|
|
103
|
+
- `selectConstraint?: any` - Constraints for date selection
|
|
104
|
+
|
|
105
|
+
## Event Object Structure
|
|
106
|
+
|
|
107
|
+
```tsx
|
|
108
|
+
interface CalendarEvent {
|
|
109
|
+
id: string | number;
|
|
110
|
+
title: string;
|
|
111
|
+
start: Date | string;
|
|
112
|
+
end?: Date | string;
|
|
113
|
+
allDay?: boolean;
|
|
114
|
+
backgroundColor?: string;
|
|
115
|
+
borderColor?: string;
|
|
116
|
+
textColor?: string;
|
|
117
|
+
extendedProps?: {
|
|
118
|
+
[key: string]: any;
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Examples
|
|
124
|
+
|
|
125
|
+
### Interactive Calendar
|
|
126
|
+
|
|
127
|
+
```tsx
|
|
128
|
+
<Calendar
|
|
129
|
+
events={events}
|
|
130
|
+
height="600px"
|
|
131
|
+
editable={true}
|
|
132
|
+
selectable={true}
|
|
133
|
+
eventResizable={true}
|
|
134
|
+
eventDraggable={true}
|
|
135
|
+
onEventClick={(eventInfo) => {
|
|
136
|
+
console.log('Event clicked:', eventInfo.event.title);
|
|
137
|
+
}}
|
|
138
|
+
onDateSelect={(selectInfo) => {
|
|
139
|
+
const title = prompt('Event title:');
|
|
140
|
+
if (title) {
|
|
141
|
+
// Add new event logic
|
|
142
|
+
}
|
|
143
|
+
}}
|
|
144
|
+
/>
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Custom Header Toolbar
|
|
148
|
+
|
|
149
|
+
```tsx
|
|
150
|
+
<Calendar
|
|
151
|
+
events={events}
|
|
152
|
+
headerToolbar={{
|
|
153
|
+
left: 'prev,next today',
|
|
154
|
+
center: 'title',
|
|
155
|
+
right: 'dayGridMonth,timeGridWeek',
|
|
156
|
+
}}
|
|
157
|
+
/>
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Business Hours
|
|
161
|
+
|
|
162
|
+
```tsx
|
|
163
|
+
<Calendar
|
|
164
|
+
events={events}
|
|
165
|
+
initialView="timeGridWeek"
|
|
166
|
+
businessHours={{
|
|
167
|
+
daysOfWeek: [1, 2, 3, 4, 5], // Monday - Friday
|
|
168
|
+
startTime: '09:00',
|
|
169
|
+
endTime: '17:00',
|
|
170
|
+
}}
|
|
171
|
+
selectConstraint="businessHours"
|
|
172
|
+
eventConstraint="businessHours"
|
|
173
|
+
/>
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### Custom Event Rendering
|
|
177
|
+
|
|
178
|
+
```tsx
|
|
179
|
+
<Calendar
|
|
180
|
+
events={events}
|
|
181
|
+
eventContent={(eventInfo) => (
|
|
182
|
+
<div style={{ padding: '2px 4px' }}>
|
|
183
|
+
<div style={{ fontWeight: 'bold' }}>{eventInfo.event.title}</div>
|
|
184
|
+
<div style={{ fontSize: '0.8em' }}>
|
|
185
|
+
📍 {eventInfo.event.extendedProps.location}
|
|
186
|
+
</div>
|
|
187
|
+
</div>
|
|
188
|
+
)}
|
|
189
|
+
/>
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## Utility Functions
|
|
193
|
+
|
|
194
|
+
The Calendar component comes with helpful utility functions:
|
|
195
|
+
|
|
196
|
+
### Generate Recurring Events
|
|
197
|
+
|
|
198
|
+
```tsx
|
|
199
|
+
import { generateRecurringEvents } from '@campxdev/react-blueprint';
|
|
200
|
+
|
|
201
|
+
const recurringEvents = generateRecurringEvents({
|
|
202
|
+
title: 'Daily Standup',
|
|
203
|
+
startTime: '09:00',
|
|
204
|
+
endTime: '09:30',
|
|
205
|
+
startDate: new Date(),
|
|
206
|
+
daysOfWeek: [1, 2, 3, 4, 5], // Weekdays only
|
|
207
|
+
backgroundColor: '#1976d2',
|
|
208
|
+
});
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### Generate Business Events
|
|
212
|
+
|
|
213
|
+
```tsx
|
|
214
|
+
import { generateBusinessEvents } from '@campxdev/react-blueprint';
|
|
215
|
+
|
|
216
|
+
const businessEvents = generateBusinessEvents(new Date());
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### Event Statistics
|
|
220
|
+
|
|
221
|
+
```tsx
|
|
222
|
+
import { calculateEventStats } from '@campxdev/react-blueprint';
|
|
223
|
+
|
|
224
|
+
const stats = calculateEventStats(events);
|
|
225
|
+
console.log(stats.totalEvents, stats.averageEventsPerDay);
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### Export to CSV
|
|
229
|
+
|
|
230
|
+
```tsx
|
|
231
|
+
import { exportEventsToCSV } from '@campxdev/react-blueprint';
|
|
232
|
+
|
|
233
|
+
const csvContent = exportEventsToCSV(events);
|
|
234
|
+
// Download or save the CSV content
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
## Theme Integration
|
|
238
|
+
|
|
239
|
+
The Calendar component fully integrates with your MUI theme:
|
|
240
|
+
|
|
241
|
+
- Uses `theme.palette.surface.*` for backgrounds
|
|
242
|
+
- Uses `theme.palette.text.*` for text colors
|
|
243
|
+
- Uses `theme.palette.primary.*` for accent colors
|
|
244
|
+
- Responds to `theme.breakpoints.*` for responsive design
|
|
245
|
+
- Supports light/dark mode switching
|
|
246
|
+
|
|
247
|
+
## Responsive Behavior
|
|
248
|
+
|
|
249
|
+
The calendar automatically adapts to different screen sizes:
|
|
250
|
+
|
|
251
|
+
- **Desktop**: Full toolbar with all view options
|
|
252
|
+
- **Tablet**: Stacked toolbar on medium screens
|
|
253
|
+
- **Mobile**: Compact toolbar with smaller buttons and text
|
|
254
|
+
|
|
255
|
+
## Accessibility
|
|
256
|
+
|
|
257
|
+
The Calendar component includes:
|
|
258
|
+
|
|
259
|
+
- ARIA labels and roles
|
|
260
|
+
- Keyboard navigation support
|
|
261
|
+
- Focus management
|
|
262
|
+
- Screen reader compatibility
|
|
263
|
+
- High contrast mode support
|
|
264
|
+
|
|
265
|
+
## Browser Support
|
|
266
|
+
|
|
267
|
+
- Chrome 90+
|
|
268
|
+
- Firefox 88+
|
|
269
|
+
- Safari 14+
|
|
270
|
+
- Edge 90+
|
|
271
|
+
|
|
272
|
+
## TypeScript Support
|
|
273
|
+
|
|
274
|
+
The Calendar component is fully typed with TypeScript, including:
|
|
275
|
+
|
|
276
|
+
- Event interfaces
|
|
277
|
+
- Handler function types
|
|
278
|
+
- Configuration options
|
|
279
|
+
- Utility function types
|
|
280
|
+
|
|
281
|
+
## Performance
|
|
282
|
+
|
|
283
|
+
The Calendar component is optimized for performance:
|
|
284
|
+
|
|
285
|
+
- Event memoization
|
|
286
|
+
- Efficient re-rendering
|
|
287
|
+
- Lazy loading of plugins
|
|
288
|
+
- Minimal bundle size impact
|
|
289
|
+
|
|
290
|
+
## Troubleshooting
|
|
291
|
+
|
|
292
|
+
### Events not showing
|
|
293
|
+
|
|
294
|
+
- Ensure events have required `id`, `title`, and `start` properties
|
|
295
|
+
- Check date format (ISO string or Date object)
|
|
296
|
+
- Verify event dates are within the calendar view range
|
|
297
|
+
|
|
298
|
+
### Styling issues
|
|
299
|
+
|
|
300
|
+
- Check theme integration
|
|
301
|
+
- Ensure proper CSS imports
|
|
302
|
+
- Verify responsive breakpoints
|
|
303
|
+
|
|
304
|
+
### Event handlers not firing
|
|
305
|
+
|
|
306
|
+
- Check event prop names match the interface
|
|
307
|
+
- Ensure calendar is in editable mode for interaction events
|
|
308
|
+
- Verify handler functions are properly bound
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { alpha, Box, Stack, styled } from '@mui/material';
|
|
2
|
+
|
|
3
|
+
export const StyledCalendarContainer = styled(Stack, {
|
|
4
|
+
shouldForwardProp: (prop) => prop !== 'height' && prop !== 'aspectRatio',
|
|
5
|
+
})<{
|
|
6
|
+
height?: string | number;
|
|
7
|
+
aspectRatio?: number;
|
|
8
|
+
}>(({ theme, height, aspectRatio }) => ({
|
|
9
|
+
backgroundColor: theme.palette.surface.paperBackground,
|
|
10
|
+
borderRadius: theme.shape?.borderRadius || '8px',
|
|
11
|
+
overflow: 'hidden',
|
|
12
|
+
border: `1px solid ${theme.palette.border.primary}`,
|
|
13
|
+
height: height || 'auto',
|
|
14
|
+
aspectRatio: aspectRatio || 'auto',
|
|
15
|
+
|
|
16
|
+
// FullCalendar specific overrides
|
|
17
|
+
'& .fc': {
|
|
18
|
+
height: '100%',
|
|
19
|
+
fontFamily: theme.typography.fontFamily,
|
|
20
|
+
fontSize: theme.typography.body2.fontSize,
|
|
21
|
+
},
|
|
22
|
+
|
|
23
|
+
// Header styling
|
|
24
|
+
'& .fc-header-toolbar': {
|
|
25
|
+
backgroundColor: theme.palette.surface.defaultBackground,
|
|
26
|
+
padding: theme.spacing(2),
|
|
27
|
+
margin: 0,
|
|
28
|
+
borderBottom: `1px solid ${theme.palette.border.primary}`,
|
|
29
|
+
|
|
30
|
+
'& .fc-button-group': {
|
|
31
|
+
'& .fc-button': {
|
|
32
|
+
backgroundColor: theme.palette.primary.main,
|
|
33
|
+
borderColor: theme.palette.primary.main,
|
|
34
|
+
color: theme.palette.text.primaryContrast,
|
|
35
|
+
fontWeight: theme.typography.button.fontWeight,
|
|
36
|
+
textTransform: 'none',
|
|
37
|
+
borderRadius: theme.shape?.borderRadius || '6px',
|
|
38
|
+
padding: '6px 12px',
|
|
39
|
+
marginRight: '4px',
|
|
40
|
+
|
|
41
|
+
'&:hover': {
|
|
42
|
+
backgroundColor: theme.palette.primary.dark,
|
|
43
|
+
borderColor: theme.palette.primary.dark,
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
'&:focus': {
|
|
47
|
+
boxShadow: `0 0 0 2px ${theme.palette.primary.light}`,
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
'&.fc-button-active': {
|
|
51
|
+
backgroundColor: theme.palette.primary.dark,
|
|
52
|
+
borderColor: theme.palette.primary.dark,
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
'&:disabled': {
|
|
56
|
+
backgroundColor: theme.palette.border.primary,
|
|
57
|
+
borderColor: theme.palette.border.primary,
|
|
58
|
+
color: theme.palette.text.tertiary,
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
'& .fc-toolbar-title': {
|
|
64
|
+
color: theme.palette.text.primary,
|
|
65
|
+
fontSize: theme.typography.h5.fontSize,
|
|
66
|
+
fontWeight: theme.typography.h5.fontWeight,
|
|
67
|
+
margin: 0,
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
// Day header styling
|
|
72
|
+
'& .fc-col-header': {
|
|
73
|
+
backgroundColor: theme.palette.surface.defaultBackground,
|
|
74
|
+
borderBottom: `1px solid ${theme.palette.border.primary}`,
|
|
75
|
+
|
|
76
|
+
'& .fc-col-header-cell': {
|
|
77
|
+
padding: theme.spacing(1),
|
|
78
|
+
|
|
79
|
+
'& .fc-col-header-cell-cushion': {
|
|
80
|
+
color: theme.palette.text.secondary,
|
|
81
|
+
fontWeight: theme.typography.subtitle2.fontWeight,
|
|
82
|
+
textDecoration: 'none',
|
|
83
|
+
fontSize: theme.typography.caption.fontSize,
|
|
84
|
+
textTransform: 'uppercase',
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
|
|
89
|
+
// Day cells styling
|
|
90
|
+
'& .fc-daygrid-day': {
|
|
91
|
+
backgroundColor: theme.palette.surface.paperBackground,
|
|
92
|
+
borderColor: theme.palette.border.primary,
|
|
93
|
+
|
|
94
|
+
'&.fc-day-today': {
|
|
95
|
+
backgroundColor: alpha(theme.palette.primary.light, 0.1),
|
|
96
|
+
},
|
|
97
|
+
|
|
98
|
+
'& .fc-daygrid-day-number': {
|
|
99
|
+
color: theme.palette.text.primary,
|
|
100
|
+
textDecoration: 'none',
|
|
101
|
+
padding: theme.spacing(0.5, 1),
|
|
102
|
+
fontSize: theme.typography.body2.fontSize,
|
|
103
|
+
|
|
104
|
+
'&:hover': {
|
|
105
|
+
backgroundColor: theme.palette.surface.grey,
|
|
106
|
+
borderRadius: '4px',
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
|
|
110
|
+
'& .fc-daygrid-day-top': {
|
|
111
|
+
display: 'flex',
|
|
112
|
+
justifyContent: 'flex-end',
|
|
113
|
+
padding: theme.spacing(0.5),
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
|
|
117
|
+
// Event styling
|
|
118
|
+
'& .fc-event': {
|
|
119
|
+
backgroundColor: theme.palette.primary.main,
|
|
120
|
+
borderColor: theme.palette.primary.main,
|
|
121
|
+
color: theme.palette.text.primaryContrast,
|
|
122
|
+
borderRadius: '4px',
|
|
123
|
+
border: 'none',
|
|
124
|
+
|
|
125
|
+
'&:hover': {
|
|
126
|
+
backgroundColor: theme.palette.primary.dark,
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
|
|
130
|
+
// Time grid styling
|
|
131
|
+
'& .fc-timegrid': {
|
|
132
|
+
'& .fc-timegrid-slot': {
|
|
133
|
+
borderColor: theme.palette.border.primary,
|
|
134
|
+
},
|
|
135
|
+
|
|
136
|
+
'& .fc-timegrid-col.fc-day-today': {
|
|
137
|
+
backgroundColor: alpha(theme.palette.primary.light, 0.08),
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
|
|
141
|
+
// List view styling
|
|
142
|
+
'& .fc-list': {
|
|
143
|
+
'& .fc-list-day': {
|
|
144
|
+
backgroundColor: theme.palette.surface.defaultBackground,
|
|
145
|
+
},
|
|
146
|
+
|
|
147
|
+
'& .fc-list-event': {
|
|
148
|
+
borderColor: theme.palette.border.primary,
|
|
149
|
+
|
|
150
|
+
'&:hover': {
|
|
151
|
+
backgroundColor: theme.palette.surface.grey,
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
|
|
156
|
+
// More link styling
|
|
157
|
+
'& .fc-more-link': {
|
|
158
|
+
color: theme.palette.primary.main,
|
|
159
|
+
|
|
160
|
+
'&:hover': {
|
|
161
|
+
color: theme.palette.primary.dark,
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
|
|
165
|
+
// Popover styling
|
|
166
|
+
'& .fc-popover': {
|
|
167
|
+
backgroundColor: theme.palette.surface.paperBackground,
|
|
168
|
+
border: `1px solid ${theme.palette.border.primary}`,
|
|
169
|
+
borderRadius: theme.shape?.borderRadius || '8px',
|
|
170
|
+
boxShadow: theme.shadows[8],
|
|
171
|
+
|
|
172
|
+
'& .fc-popover-header': {
|
|
173
|
+
backgroundColor: theme.palette.surface.defaultBackground,
|
|
174
|
+
borderBottom: `1px solid ${theme.palette.border.primary}`,
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
|
|
178
|
+
// Responsive design
|
|
179
|
+
[theme.breakpoints.down('md')]: {
|
|
180
|
+
'& .fc-header-toolbar': {
|
|
181
|
+
flexDirection: 'column',
|
|
182
|
+
gap: theme.spacing(1),
|
|
183
|
+
},
|
|
184
|
+
|
|
185
|
+
'& .fc-button-group .fc-button': {
|
|
186
|
+
padding: '4px 8px',
|
|
187
|
+
},
|
|
188
|
+
},
|
|
189
|
+
|
|
190
|
+
[theme.breakpoints.down('sm')]: {
|
|
191
|
+
'& .fc-event': {
|
|
192
|
+
fontSize: '0.7rem',
|
|
193
|
+
},
|
|
194
|
+
},
|
|
195
|
+
}));
|
|
196
|
+
|
|
197
|
+
export const StyledCalendarWrapper = styled(Box)(({ theme }) => ({
|
|
198
|
+
position: 'relative',
|
|
199
|
+
width: '100%',
|
|
200
|
+
|
|
201
|
+
// Custom scrollbar for calendar content
|
|
202
|
+
'& .fc-scroller': {
|
|
203
|
+
'&::-webkit-scrollbar': {
|
|
204
|
+
width: '6px',
|
|
205
|
+
height: '6px',
|
|
206
|
+
},
|
|
207
|
+
|
|
208
|
+
'&::-webkit-scrollbar-track': {
|
|
209
|
+
backgroundColor: theme.palette.surface.defaultBackground,
|
|
210
|
+
borderRadius: '3px',
|
|
211
|
+
},
|
|
212
|
+
|
|
213
|
+
'&::-webkit-scrollbar-thumb': {
|
|
214
|
+
backgroundColor: theme.palette.border.secondary,
|
|
215
|
+
borderRadius: '3px',
|
|
216
|
+
|
|
217
|
+
'&:hover': {
|
|
218
|
+
backgroundColor: theme.palette.surface.grey,
|
|
219
|
+
},
|
|
220
|
+
},
|
|
221
|
+
},
|
|
222
|
+
}));
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { EventApi } from '@fullcalendar/core';
|
|
2
|
+
import { StackProps } from '@mui/material';
|
|
3
|
+
|
|
4
|
+
export interface CalendarEvent {
|
|
5
|
+
id: string | number;
|
|
6
|
+
title: string;
|
|
7
|
+
start: Date | string;
|
|
8
|
+
end?: Date | string;
|
|
9
|
+
allDay?: boolean;
|
|
10
|
+
backgroundColor?: string;
|
|
11
|
+
borderColor?: string;
|
|
12
|
+
textColor?: string;
|
|
13
|
+
extendedProps?: {
|
|
14
|
+
[key: string]: any;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface CalendarEventClickInfo {
|
|
19
|
+
event: EventApi;
|
|
20
|
+
jsEvent: MouseEvent;
|
|
21
|
+
view: any;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface CalendarDateSelectInfo {
|
|
25
|
+
start: Date;
|
|
26
|
+
end: Date;
|
|
27
|
+
allDay: boolean;
|
|
28
|
+
jsEvent: MouseEvent;
|
|
29
|
+
view: any;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface CalendarEventDropInfo {
|
|
33
|
+
event: EventApi;
|
|
34
|
+
delta: any;
|
|
35
|
+
revert: () => void;
|
|
36
|
+
jsEvent: Event;
|
|
37
|
+
view: any;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface CalendarEventResizeInfo {
|
|
41
|
+
event: EventApi;
|
|
42
|
+
startDelta: any;
|
|
43
|
+
endDelta: any;
|
|
44
|
+
revert: () => void;
|
|
45
|
+
jsEvent: Event;
|
|
46
|
+
view: any;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface CalendarDateClickInfo {
|
|
50
|
+
date: Date;
|
|
51
|
+
dateStr: string;
|
|
52
|
+
allDay: boolean;
|
|
53
|
+
dayEl: HTMLElement;
|
|
54
|
+
jsEvent: MouseEvent;
|
|
55
|
+
view: any;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export type CalendarView =
|
|
59
|
+
| 'dayGridMonth'
|
|
60
|
+
| 'timeGridWeek'
|
|
61
|
+
| 'timeGridDay'
|
|
62
|
+
| 'listWeek';
|
|
63
|
+
|
|
64
|
+
export interface CalendarHeaderToolbar {
|
|
65
|
+
left?: string;
|
|
66
|
+
center?: string;
|
|
67
|
+
right?: string;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface CalendarProps {
|
|
71
|
+
// Event data
|
|
72
|
+
events?: CalendarEvent[];
|
|
73
|
+
|
|
74
|
+
// Event handlers
|
|
75
|
+
onEventClick?: (eventInfo: CalendarEventClickInfo) => void;
|
|
76
|
+
onEventDrop?: (eventInfo: CalendarEventDropInfo) => void;
|
|
77
|
+
onEventResize?: (eventInfo: CalendarEventResizeInfo) => void;
|
|
78
|
+
onDateClick?: (dateInfo: CalendarDateClickInfo) => void;
|
|
79
|
+
onDateSelect?: (selectInfo: CalendarDateSelectInfo) => void;
|
|
80
|
+
onEventsSet?: (events: EventApi[]) => void;
|
|
81
|
+
|
|
82
|
+
// View configuration
|
|
83
|
+
initialView?: CalendarView;
|
|
84
|
+
views?: CalendarView[];
|
|
85
|
+
headerToolbar?: CalendarHeaderToolbar | boolean;
|
|
86
|
+
|
|
87
|
+
// Calendar behavior
|
|
88
|
+
editable?: boolean;
|
|
89
|
+
selectable?: boolean;
|
|
90
|
+
selectMirror?: boolean;
|
|
91
|
+
eventResizable?: boolean;
|
|
92
|
+
eventDraggable?: boolean;
|
|
93
|
+
dayMaxEvents?: boolean | number;
|
|
94
|
+
|
|
95
|
+
// Styling & layout
|
|
96
|
+
height?: string | number;
|
|
97
|
+
aspectRatio?: number;
|
|
98
|
+
containerProps?: StackProps;
|
|
99
|
+
|
|
100
|
+
// Localization
|
|
101
|
+
locale?: string;
|
|
102
|
+
timezone?: string;
|
|
103
|
+
firstDayOfWeek?: 0 | 1 | 2 | 3 | 4 | 5 | 6;
|
|
104
|
+
|
|
105
|
+
// Custom rendering
|
|
106
|
+
eventContent?: (eventInfo: any) => React.ReactNode;
|
|
107
|
+
dayCellContent?: (dayInfo: any) => React.ReactNode;
|
|
108
|
+
|
|
109
|
+
// Navigation
|
|
110
|
+
showNavigationButtons?: boolean;
|
|
111
|
+
showViewSwitcher?: boolean;
|
|
112
|
+
showToday?: boolean;
|
|
113
|
+
|
|
114
|
+
// Advanced
|
|
115
|
+
calendarRef?: React.RefObject<any>;
|
|
116
|
+
weekends?: boolean;
|
|
117
|
+
businessHours?: any;
|
|
118
|
+
eventConstraint?: any;
|
|
119
|
+
selectConstraint?: any;
|
|
120
|
+
}
|