@hectorbliss/denik-calendar 0.0.3 → 0.0.4
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/README.md +129 -93
- package/dist/index.cjs +283 -54
- package/dist/index.d.cts +116 -3
- package/dist/index.d.ts +116 -3
- package/dist/index.js +283 -56
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -24,7 +24,6 @@ function App() {
|
|
|
24
24
|
<Calendar
|
|
25
25
|
events={events}
|
|
26
26
|
onEventMove={(eventId, newStart) => {
|
|
27
|
-
// Handle event move
|
|
28
27
|
setEvents(prev =>
|
|
29
28
|
prev.map(e => (e.id === eventId ? { ...e, start: newStart } : e))
|
|
30
29
|
);
|
|
@@ -43,74 +42,152 @@ function App() {
|
|
|
43
42
|
}
|
|
44
43
|
```
|
|
45
44
|
|
|
46
|
-
##
|
|
45
|
+
## Resource Mode (Day View)
|
|
47
46
|
|
|
48
|
-
|
|
47
|
+
Display resources (courts, rooms, employees) as columns instead of weekdays:
|
|
49
48
|
|
|
50
49
|
```tsx
|
|
51
|
-
import {
|
|
50
|
+
import { Calendar, useCalendarControls } from "@hectorbliss/denik-calendar";
|
|
51
|
+
|
|
52
|
+
const courts = [
|
|
53
|
+
{ id: "court-1", name: "Cancha 1", icon: <PadelIcon /> },
|
|
54
|
+
{ id: "court-2", name: "Cancha 2", icon: <PadelIcon /> },
|
|
55
|
+
{ id: "court-3", name: "Cancha 3", icon: <TennisIcon /> },
|
|
56
|
+
{ id: "court-4", name: "Cancha 4", icon: <TennisIcon /> },
|
|
57
|
+
];
|
|
58
|
+
|
|
59
|
+
// Events with resourceId
|
|
60
|
+
const events = [
|
|
61
|
+
{ id: "1", start: new Date(), duration: 90, title: "Match", resourceId: "court-1" },
|
|
62
|
+
{ id: "2", start: new Date(), duration: 60, title: "Training", resourceId: "court-2" },
|
|
63
|
+
];
|
|
64
|
+
|
|
65
|
+
function CourtSchedule() {
|
|
66
|
+
return (
|
|
67
|
+
<Calendar
|
|
68
|
+
events={events}
|
|
69
|
+
date={selectedDay}
|
|
70
|
+
resources={courts}
|
|
71
|
+
/>
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Navigation Controls
|
|
52
77
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
78
|
+
Use the headless hook for complete control:
|
|
79
|
+
|
|
80
|
+
```tsx
|
|
81
|
+
import { Calendar, useCalendarControls, CalendarControls } from "@hectorbliss/denik-calendar";
|
|
82
|
+
|
|
83
|
+
function App() {
|
|
84
|
+
const controls = useCalendarControls();
|
|
85
|
+
|
|
86
|
+
return (
|
|
87
|
+
<>
|
|
88
|
+
{/* Pre-built controls */}
|
|
89
|
+
<CalendarControls controls={controls} />
|
|
90
|
+
|
|
91
|
+
{/* Or build your own */}
|
|
92
|
+
<div>
|
|
93
|
+
<button onClick={controls.goToToday}>HOY</button>
|
|
94
|
+
<button onClick={controls.goToPrev}>←</button>
|
|
95
|
+
<button onClick={controls.goToNext}>→</button>
|
|
96
|
+
<span>{controls.label}</span>
|
|
97
|
+
<button onClick={controls.toggleView}>
|
|
98
|
+
{controls.view === "week" ? "DÍA" : "SEMANA"}
|
|
99
|
+
</button>
|
|
100
|
+
</div>
|
|
101
|
+
|
|
102
|
+
<Calendar
|
|
103
|
+
date={controls.date}
|
|
104
|
+
events={events}
|
|
105
|
+
resources={controls.view === "day" ? courts : undefined}
|
|
106
|
+
/>
|
|
107
|
+
</>
|
|
108
|
+
);
|
|
73
109
|
}
|
|
74
110
|
```
|
|
75
111
|
|
|
112
|
+
## Visual Overlaps
|
|
113
|
+
|
|
114
|
+
Events at the same time are displayed side-by-side automatically.
|
|
115
|
+
|
|
116
|
+
## Headless Hooks
|
|
117
|
+
|
|
118
|
+
### useCalendarEvents
|
|
119
|
+
|
|
120
|
+
```tsx
|
|
121
|
+
import { useCalendarEvents } from "@hectorbliss/denik-calendar";
|
|
122
|
+
|
|
123
|
+
const {
|
|
124
|
+
canMove, // Check if event can move to new time
|
|
125
|
+
hasOverlap, // Check if time slot has conflicts
|
|
126
|
+
findConflicts, // Get all conflicting events
|
|
127
|
+
getEventsForDay, // Filter events by day
|
|
128
|
+
getEventsForWeek, // Filter events by week
|
|
129
|
+
findAvailableSlots // Get available time slots
|
|
130
|
+
} = useCalendarEvents(events);
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### useCalendarControls
|
|
134
|
+
|
|
135
|
+
```tsx
|
|
136
|
+
import { useCalendarControls } from "@hectorbliss/denik-calendar";
|
|
137
|
+
|
|
138
|
+
const {
|
|
139
|
+
date, // Current date
|
|
140
|
+
view, // "week" | "day"
|
|
141
|
+
week, // Array of 7 dates (Mon-Sun)
|
|
142
|
+
label, // Formatted date label
|
|
143
|
+
isToday, // Boolean
|
|
144
|
+
goToToday, // Navigate to today
|
|
145
|
+
goToPrev, // Navigate back (7 days or 1 day)
|
|
146
|
+
goToNext, // Navigate forward
|
|
147
|
+
toggleView, // Switch between week/day
|
|
148
|
+
setDate, // Set specific date
|
|
149
|
+
setView, // Set specific view
|
|
150
|
+
} = useCalendarControls({ locale: "es-MX" });
|
|
151
|
+
```
|
|
152
|
+
|
|
76
153
|
## Props
|
|
77
154
|
|
|
78
155
|
### Calendar
|
|
79
156
|
|
|
80
157
|
| Prop | Type | Description |
|
|
81
158
|
|------|------|-------------|
|
|
82
|
-
| `events` | `CalendarEvent[]` | Array of events
|
|
83
|
-
| `date` | `Date` | Current
|
|
84
|
-
| `
|
|
85
|
-
| `
|
|
86
|
-
| `
|
|
87
|
-
| `
|
|
88
|
-
| `
|
|
89
|
-
| `
|
|
90
|
-
|
|
91
|
-
|
|
159
|
+
| `events` | `CalendarEvent[]` | Array of events |
|
|
160
|
+
| `date` | `Date` | Current date (default: today) |
|
|
161
|
+
| `resources` | `Resource[]` | Resources for day view mode |
|
|
162
|
+
| `onEventMove` | `(eventId, newStart) => void` | Drag handler |
|
|
163
|
+
| `onAddBlock` | `(start) => void` | Block creation |
|
|
164
|
+
| `onRemoveBlock` | `(eventId) => void` | Block removal |
|
|
165
|
+
| `onEventClick` | `(event) => void` | Click handler |
|
|
166
|
+
| `onNewEvent` | `(start) => void` | Empty slot click |
|
|
167
|
+
| `config` | `CalendarConfig` | Configuration |
|
|
168
|
+
|
|
169
|
+
### Types
|
|
92
170
|
|
|
93
171
|
```typescript
|
|
94
172
|
interface CalendarEvent {
|
|
95
173
|
id: string;
|
|
96
174
|
start: Date;
|
|
97
|
-
duration: number;
|
|
175
|
+
duration: number; // minutes
|
|
98
176
|
title?: string;
|
|
99
177
|
type?: "BLOCK" | "EVENT";
|
|
178
|
+
resourceId?: string; // For resource mode
|
|
100
179
|
service?: { name: string };
|
|
101
180
|
}
|
|
102
|
-
```
|
|
103
181
|
|
|
104
|
-
|
|
182
|
+
interface Resource {
|
|
183
|
+
id: string;
|
|
184
|
+
name: string;
|
|
185
|
+
icon?: ReactNode;
|
|
186
|
+
}
|
|
105
187
|
|
|
106
|
-
```typescript
|
|
107
188
|
interface CalendarConfig {
|
|
108
|
-
locale?: string;
|
|
109
|
-
icons?: {
|
|
110
|
-
trash?: ReactNode;
|
|
111
|
-
edit?: ReactNode;
|
|
112
|
-
close?: ReactNode;
|
|
113
|
-
};
|
|
189
|
+
locale?: string;
|
|
190
|
+
icons?: { trash?, edit?, close? };
|
|
114
191
|
renderColumnHeader?: (props: ColumnHeaderProps) => ReactNode;
|
|
115
192
|
}
|
|
116
193
|
|
|
@@ -119,62 +196,21 @@ interface ColumnHeaderProps {
|
|
|
119
196
|
index: number;
|
|
120
197
|
isToday: boolean;
|
|
121
198
|
locale: string;
|
|
199
|
+
resource?: Resource;
|
|
122
200
|
}
|
|
123
201
|
```
|
|
124
202
|
|
|
125
|
-
## Custom Column Headers
|
|
126
|
-
|
|
127
|
-
Transform the calendar from weekdays to any resource type:
|
|
128
|
-
|
|
129
|
-
```tsx
|
|
130
|
-
// Padel courts booking
|
|
131
|
-
<Calendar
|
|
132
|
-
events={courtEvents}
|
|
133
|
-
config={{
|
|
134
|
-
renderColumnHeader: ({ index }) => (
|
|
135
|
-
<div className="text-center font-semibold">
|
|
136
|
-
Court {index + 1}
|
|
137
|
-
</div>
|
|
138
|
-
)
|
|
139
|
-
}}
|
|
140
|
-
/>
|
|
141
|
-
|
|
142
|
-
// Meeting rooms
|
|
143
|
-
<Calendar
|
|
144
|
-
events={roomEvents}
|
|
145
|
-
config={{
|
|
146
|
-
renderColumnHeader: ({ index }) => {
|
|
147
|
-
const rooms = ["Sala A", "Sala B", "Sala C", "Sala D", "Sala E", "Sala F", "Sala G"];
|
|
148
|
-
return <span>{rooms[index]}</span>;
|
|
149
|
-
}
|
|
150
|
-
}}
|
|
151
|
-
/>
|
|
152
|
-
|
|
153
|
-
// Employees schedule
|
|
154
|
-
<Calendar
|
|
155
|
-
events={shifts}
|
|
156
|
-
config={{
|
|
157
|
-
renderColumnHeader: ({ index }) => {
|
|
158
|
-
const team = ["Ana", "Carlos", "María", "Pedro", "Laura", "Diego", "Sofia"];
|
|
159
|
-
return (
|
|
160
|
-
<div className="flex flex-col items-center">
|
|
161
|
-
<img src={`/avatars/${index}.jpg`} className="w-8 h-8 rounded-full" />
|
|
162
|
-
<span className="text-sm">{team[index]}</span>
|
|
163
|
-
</div>
|
|
164
|
-
);
|
|
165
|
-
}
|
|
166
|
-
}}
|
|
167
|
-
/>
|
|
168
|
-
```
|
|
169
|
-
|
|
170
203
|
## Features
|
|
171
204
|
|
|
172
|
-
- Drag & drop events
|
|
173
|
-
-
|
|
205
|
+
- Drag & drop events
|
|
206
|
+
- Visual overlap rendering
|
|
207
|
+
- Resource/day view mode
|
|
208
|
+
- Week view mode
|
|
209
|
+
- Navigation controls (hook + component)
|
|
174
210
|
- Block time slots
|
|
175
|
-
- Week navigation
|
|
176
211
|
- Auto-scroll to current hour
|
|
177
|
-
- Custom column headers
|
|
212
|
+
- Custom column headers
|
|
213
|
+
- Horizontal scroll for many resources
|
|
178
214
|
- Customizable icons
|
|
179
215
|
- Locale support
|
|
180
216
|
- TypeScript support
|