react-attendance-calendar 2.4.4 → 2.4.6
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 +251 -288
- package/dist/attendance-calendar.d.ts +17 -0
- package/dist/attendance-calendar.d.ts.map +1 -0
- package/dist/calendar/calendar-grid.d.ts +11 -0
- package/dist/calendar/calendar-grid.d.ts.map +1 -0
- package/dist/calendar/calendar-header.d.ts +6 -0
- package/dist/calendar/calendar-header.d.ts.map +1 -0
- package/dist/calendar/calendar-nav.d.ts +5 -0
- package/dist/calendar/calendar-nav.d.ts.map +1 -0
- package/dist/calendar/calendar-root.d.ts +11 -0
- package/dist/calendar/calendar-root.d.ts.map +1 -0
- package/dist/calendar/calendar-title.d.ts +8 -0
- package/dist/calendar/calendar-title.d.ts.map +1 -0
- package/dist/calendar/calendar-weekdays.d.ts +7 -0
- package/dist/calendar/calendar-weekdays.d.ts.map +1 -0
- package/dist/calendar/context.d.ts +23 -0
- package/dist/calendar/context.d.ts.map +1 -0
- package/dist/calendar/index.d.ts +25 -0
- package/dist/calendar/index.d.ts.map +1 -0
- package/dist/calendar/types.d.ts +28 -0
- package/dist/calendar/types.d.ts.map +1 -0
- package/dist/calendar/utils.d.ts +17 -0
- package/dist/calendar/utils.d.ts.map +1 -0
- package/dist/index.css +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +969 -791
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/AttendanceCalendar.d.ts +0 -39
- package/dist/AttendanceCalendar.d.ts.map +0 -1
package/README.md
CHANGED
|
@@ -1,44 +1,33 @@
|
|
|
1
1
|
# React Attendance Calendar
|
|
2
2
|
|
|
3
|
-
A modern, responsive
|
|
3
|
+
A modern, responsive React attendance calendar with a **compound component** architecture. Style it with classes, swap out navigation buttons, render custom cells — or just drop in the pre-composed version and go.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Features
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
- ⚡ **Auto-initialization** - Defaults to current month if no view provided
|
|
16
|
-
- 🎯 **Smart navigation** - Seamless month/year transitions
|
|
17
|
-
- 🗓️ **Today highlight** - Current date is highlighted; style it with `todayCellClassName` (merged last so it wins over present/absent/cell classes)
|
|
18
|
-
- 📐 **Flexible header** - Position month title left, center, or right
|
|
7
|
+
- **Compound components** — compose `Calendar.Root`, `Header`, `Title`, `PrevTrigger`, `NextTrigger`, `WeekDays`, and `Grid` any way you like
|
|
8
|
+
- **Pre-composed default** — `AttendanceCalendar` works out of the box with zero config
|
|
9
|
+
- **`renderCell`** — full control over every cell's markup and style
|
|
10
|
+
- **`useCalendar()` hook** — headless access to all calendar state for completely custom UIs
|
|
11
|
+
- **`classNames` object** — one clean prop for `cell`, `present`, `absent`, `today`, `outside` styles
|
|
12
|
+
- **Responsive** — auto-switches between 7 and 14 columns based on container width
|
|
13
|
+
- **TypeScript** — full type safety and IntelliSense
|
|
14
|
+
- **Multi-month data** — provide attendance for multiple months at once
|
|
19
15
|
|
|
20
|
-
##
|
|
16
|
+
## Installation
|
|
21
17
|
|
|
22
18
|
```bash
|
|
23
19
|
npm install react-attendance-calendar
|
|
24
20
|
```
|
|
25
21
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
**Simply import the CSS in your app:**
|
|
22
|
+
Import the CSS once in your app entry:
|
|
29
23
|
|
|
30
24
|
```tsx
|
|
31
|
-
// In your main app file (e.g., App.tsx, main.tsx, or _app.tsx)
|
|
32
25
|
import "react-attendance-calendar/styles.css";
|
|
33
26
|
```
|
|
34
27
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
> **Note:** No additional setup required. The package includes pre-compiled CSS. If you're using Tailwind CSS v4 in your project, you can customize the component further using the `className` props.
|
|
38
|
-
|
|
39
|
-
## 🚀 Usage
|
|
28
|
+
> The package ships pre-compiled CSS. If you use Tailwind CSS v4, you can further customize via `className` and `classNames` props.
|
|
40
29
|
|
|
41
|
-
|
|
30
|
+
## Quick Start
|
|
42
31
|
|
|
43
32
|
```tsx
|
|
44
33
|
import { useState } from "react";
|
|
@@ -48,351 +37,325 @@ import "react-attendance-calendar/styles.css";
|
|
|
48
37
|
function App() {
|
|
49
38
|
const [view, setView] = useState({ year: 2024, monthIndex: 0 });
|
|
50
39
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
```tsx
|
|
58
|
-
import { AttendanceCalendar } from "react-attendance-calendar";
|
|
59
|
-
import "react-attendance-calendar/styles.css";
|
|
60
|
-
|
|
61
|
-
function App() {
|
|
62
|
-
const [view, setView] = useState();
|
|
40
|
+
const data = {
|
|
41
|
+
year: 2024,
|
|
42
|
+
monthIndex: 0,
|
|
43
|
+
presentDays: new Set([1, 2, 3, 5, 8, 9, 10]),
|
|
44
|
+
absentDays: new Set([4, 11]),
|
|
45
|
+
};
|
|
63
46
|
|
|
64
|
-
return
|
|
47
|
+
return (
|
|
48
|
+
<AttendanceCalendar
|
|
49
|
+
view={view}
|
|
50
|
+
onChangeView={setView}
|
|
51
|
+
attendanceData={data}
|
|
52
|
+
onDateClick={(day, month, year) => console.log(day, month, year)}
|
|
53
|
+
/>
|
|
54
|
+
);
|
|
65
55
|
}
|
|
66
56
|
```
|
|
67
57
|
|
|
68
|
-
|
|
58
|
+
## Usage
|
|
69
59
|
|
|
70
|
-
|
|
71
|
-
import { AttendanceCalendar } from "react-attendance-calendar";
|
|
72
|
-
import "react-attendance-calendar/styles.css";
|
|
60
|
+
### Pre-composed (simple)
|
|
73
61
|
|
|
74
|
-
|
|
75
|
-
year: 2024,
|
|
76
|
-
monthIndex: 0,
|
|
77
|
-
presentDays: new Set([1, 2, 3, 5, 8, 9, 10]),
|
|
78
|
-
absentDays: new Set([4, 11]),
|
|
79
|
-
};
|
|
62
|
+
The `AttendanceCalendar` component is a ready-to-use calendar with sensible defaults. Pass a `classNames` object to customize cell styles without touching the layout.
|
|
80
63
|
|
|
64
|
+
```tsx
|
|
81
65
|
<AttendanceCalendar
|
|
82
66
|
view={view}
|
|
83
67
|
onChangeView={setView}
|
|
84
|
-
attendanceData={
|
|
85
|
-
|
|
86
|
-
|
|
68
|
+
attendanceData={data}
|
|
69
|
+
classNames={{
|
|
70
|
+
cell: "rounded-full",
|
|
71
|
+
present: "bg-teal-500 shadow-md",
|
|
72
|
+
absent: "bg-rose-500",
|
|
73
|
+
today: "ring-2 ring-blue-400",
|
|
74
|
+
outside: "opacity-20",
|
|
75
|
+
}}
|
|
76
|
+
/>
|
|
87
77
|
```
|
|
88
78
|
|
|
89
|
-
###
|
|
79
|
+
### Compound components (full control)
|
|
80
|
+
|
|
81
|
+
Build your own layout with `Calendar.*` components. Place the title, navigation buttons, weekday headers, and grid wherever you want.
|
|
90
82
|
|
|
91
83
|
```tsx
|
|
92
|
-
import {
|
|
84
|
+
import { Calendar } from "react-attendance-calendar";
|
|
93
85
|
import "react-attendance-calendar/styles.css";
|
|
94
86
|
|
|
95
|
-
|
|
96
|
-
const
|
|
97
|
-
// January 2024
|
|
98
|
-
{
|
|
99
|
-
year: 2024,
|
|
100
|
-
monthIndex: 0,
|
|
101
|
-
presentDays: new Set([
|
|
102
|
-
1, 2, 3, 5, 8, 9, 10, 12, 15, 16, 17, 19, 22, 23, 24, 26, 29, 30, 31,
|
|
103
|
-
]),
|
|
104
|
-
absentDays: new Set([4, 11, 18, 25]),
|
|
105
|
-
},
|
|
106
|
-
// February 2025
|
|
107
|
-
{
|
|
108
|
-
year: 2025,
|
|
109
|
-
monthIndex: 1,
|
|
110
|
-
presentDays: new Set([
|
|
111
|
-
1, 2, 5, 6, 7, 8, 9, 12, 13, 14, 15, 16, 19, 20, 21, 22, 23, 26, 27, 28,
|
|
112
|
-
]),
|
|
113
|
-
absentDays: new Set([3, 10, 17, 24]),
|
|
114
|
-
},
|
|
115
|
-
];
|
|
87
|
+
function MyCalendar() {
|
|
88
|
+
const [view, setView] = useState({ year: 2024, monthIndex: 0 });
|
|
116
89
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
90
|
+
return (
|
|
91
|
+
<Calendar.Root
|
|
92
|
+
view={view}
|
|
93
|
+
onChangeView={setView}
|
|
94
|
+
attendanceData={data}
|
|
95
|
+
onDateClick={(day, month, year) => console.log(day, month, year)}
|
|
96
|
+
>
|
|
97
|
+
<Calendar.Header>
|
|
98
|
+
<Calendar.Title className="text-indigo-700" />
|
|
99
|
+
<div className="flex gap-2">
|
|
100
|
+
<Calendar.PrevTrigger className="rounded-full bg-indigo-500 text-white">
|
|
101
|
+
←
|
|
102
|
+
</Calendar.PrevTrigger>
|
|
103
|
+
<Calendar.NextTrigger className="rounded-full bg-indigo-500 text-white">
|
|
104
|
+
→
|
|
105
|
+
</Calendar.NextTrigger>
|
|
106
|
+
</div>
|
|
107
|
+
</Calendar.Header>
|
|
108
|
+
<Calendar.WeekDays dayClassName="text-indigo-400" />
|
|
109
|
+
<Calendar.Grid
|
|
110
|
+
classNames={{
|
|
111
|
+
present: "bg-indigo-500",
|
|
112
|
+
absent: "bg-pink-500",
|
|
113
|
+
}}
|
|
114
|
+
/>
|
|
115
|
+
</Calendar.Root>
|
|
116
|
+
);
|
|
117
|
+
}
|
|
123
118
|
```
|
|
124
119
|
|
|
125
|
-
### Custom
|
|
120
|
+
### Custom title format
|
|
126
121
|
|
|
127
|
-
|
|
128
|
-
// Center (default) — [←] January 2024 [→]
|
|
129
|
-
<AttendanceCalendar view={view} onChangeView={setView} monthTitlePosition="center" />
|
|
122
|
+
Use `format` for full control over the title markup, or keep the default layout and style the month (`className` on the `<h2>`) and year (`yearClassName` on the year span) separately.
|
|
130
123
|
|
|
131
|
-
|
|
132
|
-
<AttendanceCalendar view={view} onChangeView={setView} monthTitlePosition="left" />
|
|
124
|
+
**Default title with separate year styling**
|
|
133
125
|
|
|
134
|
-
|
|
135
|
-
<AttendanceCalendar view={view} onChangeView={setView} monthTitlePosition="right" />
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
### Custom Styling
|
|
126
|
+
`className` applies to the whole heading (`<h2>`). `yearClassName` applies only to the year number and overrides the default `text-slate-500` (merged with `tailwind-merge`, so a new `text-*` class wins).
|
|
139
127
|
|
|
140
128
|
```tsx
|
|
141
|
-
<
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
presentCellClassName="bg-blue-500 text-white"
|
|
145
|
-
absentCellClassName="bg-red-500 text-white"
|
|
146
|
-
cellClassName="rounded-full"
|
|
129
|
+
<Calendar.Title
|
|
130
|
+
className="text-indigo-900"
|
|
131
|
+
yearClassName="text-indigo-600"
|
|
147
132
|
/>
|
|
148
133
|
```
|
|
149
134
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
The current calendar date (“today”) gets default emphasis (dark slate when the day is neither present nor absent; a ring when it is present or absent). Pass **`todayCellClassName`** with Tailwind utilities to fully control that cell. These classes are **merged last** on the cell, so they override `cellClassName`, `presentCellClassName`, and `absentCellClassName` for today only.
|
|
135
|
+
**Fully custom title**
|
|
153
136
|
|
|
154
137
|
```tsx
|
|
155
|
-
<
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
138
|
+
<Calendar.Title
|
|
139
|
+
format={(monthName, year) => (
|
|
140
|
+
<span className="text-lg font-medium">
|
|
141
|
+
{monthName} / {year}
|
|
142
|
+
</span>
|
|
143
|
+
)}
|
|
161
144
|
/>
|
|
162
145
|
```
|
|
163
146
|
|
|
164
|
-
### Custom
|
|
147
|
+
### Custom cell rendering
|
|
165
148
|
|
|
166
|
-
|
|
167
|
-
// Square cells with custom size
|
|
168
|
-
<AttendanceCalendar
|
|
169
|
-
view={view}
|
|
170
|
-
onChangeView={setView}
|
|
171
|
-
cellSize={60} // 60px x 60px cells
|
|
172
|
-
/>
|
|
149
|
+
Use `renderCell` on `Calendar.Grid` (or the pre-composed `AttendanceCalendar`) for complete control over each cell's markup. The callback receives a `CellData` object with all the state you need.
|
|
173
150
|
|
|
174
|
-
|
|
175
|
-
<
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
151
|
+
```tsx
|
|
152
|
+
<Calendar.Grid
|
|
153
|
+
renderCell={(cell) => (
|
|
154
|
+
<div
|
|
155
|
+
className={`w-full aspect-square grid place-items-center rounded-xl text-sm ${
|
|
156
|
+
cell.isPresent
|
|
157
|
+
? "bg-green-100 text-green-700"
|
|
158
|
+
: cell.isAbsent
|
|
159
|
+
? "bg-red-100 text-red-700"
|
|
160
|
+
: cell.isToday
|
|
161
|
+
? "bg-blue-600 text-white"
|
|
162
|
+
: "text-slate-600"
|
|
163
|
+
}`}
|
|
164
|
+
>
|
|
165
|
+
{cell.day}
|
|
166
|
+
{cell.isPresent && <span className="text-[10px]">✓</span>}
|
|
167
|
+
{cell.isAbsent && <span className="text-[10px]">✗</span>}
|
|
168
|
+
</div>
|
|
169
|
+
)}
|
|
188
170
|
/>
|
|
189
171
|
```
|
|
190
172
|
|
|
191
|
-
###
|
|
173
|
+
### Headless with `useCalendar()`
|
|
174
|
+
|
|
175
|
+
For a completely custom UI, use the hook inside a `Calendar.Root`:
|
|
192
176
|
|
|
193
177
|
```tsx
|
|
194
|
-
import {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
178
|
+
import { Calendar, useCalendar } from "react-attendance-calendar";
|
|
179
|
+
|
|
180
|
+
function HeadlessCalendar() {
|
|
181
|
+
const { view, monthName, goPrev, goNext, cells, currentMonthData, today, columns } =
|
|
182
|
+
useCalendar();
|
|
183
|
+
|
|
184
|
+
// Build any UI you want with full access to calendar state
|
|
185
|
+
return <div>{/* your custom markup */}</div>;
|
|
186
|
+
}
|
|
201
187
|
|
|
202
188
|
function App() {
|
|
203
|
-
const [view, setView] = useState
|
|
204
|
-
year: 2024,
|
|
205
|
-
monthIndex: 0, // January
|
|
206
|
-
});
|
|
207
|
-
|
|
208
|
-
// Sample attendance data for multiple months
|
|
209
|
-
const attendanceData: AttendanceData = [
|
|
210
|
-
// January 2024
|
|
211
|
-
{
|
|
212
|
-
year: 2024,
|
|
213
|
-
monthIndex: 0,
|
|
214
|
-
presentDays: new Set([
|
|
215
|
-
1, 2, 3, 5, 8, 9, 10, 12, 15, 16, 17, 19, 22, 23, 24, 26, 29, 30, 31,
|
|
216
|
-
]),
|
|
217
|
-
absentDays: new Set([4, 11, 18, 25]),
|
|
218
|
-
},
|
|
219
|
-
// February 2025
|
|
220
|
-
{
|
|
221
|
-
year: 2025,
|
|
222
|
-
monthIndex: 1,
|
|
223
|
-
presentDays: new Set([
|
|
224
|
-
1, 2, 5, 6, 7, 8, 9, 12, 13, 14, 15, 16, 19, 20, 21, 22, 23, 26, 27, 28,
|
|
225
|
-
]),
|
|
226
|
-
absentDays: new Set([3, 10, 17, 24]),
|
|
227
|
-
},
|
|
228
|
-
];
|
|
229
|
-
|
|
230
|
-
const handleDateClick = (day: number, month: number, year: number) => {
|
|
231
|
-
console.log(`Clicked on ${day}/${month + 1}/${year}`);
|
|
232
|
-
// Your custom logic here
|
|
233
|
-
};
|
|
189
|
+
const [view, setView] = useState({ year: 2024, monthIndex: 0 });
|
|
234
190
|
|
|
235
191
|
return (
|
|
236
|
-
<
|
|
237
|
-
<
|
|
238
|
-
|
|
239
|
-
onChangeView={setView}
|
|
240
|
-
attendanceData={attendanceData}
|
|
241
|
-
onDateClick={handleDateClick}
|
|
242
|
-
showNavigation={true}
|
|
243
|
-
showWeekdayHeaders={true}
|
|
244
|
-
// Custom styling with className props
|
|
245
|
-
cellClassName="rounded-full"
|
|
246
|
-
presentCellClassName="bg-green-500 text-white shadow-lg"
|
|
247
|
-
absentCellClassName="bg-red-500 text-white border-2 border-red-300"
|
|
248
|
-
navigationButtonClassName="bg-blue-500 text-white hover:bg-blue-600"
|
|
249
|
-
monthTitleClassName="text-3xl text-purple-600"
|
|
250
|
-
containerClassName="border border-gray-200 rounded-lg p-4"
|
|
251
|
-
/>
|
|
252
|
-
</div>
|
|
192
|
+
<Calendar.Root view={view} onChangeView={setView} attendanceData={data}>
|
|
193
|
+
<HeadlessCalendar />
|
|
194
|
+
</Calendar.Root>
|
|
253
195
|
);
|
|
254
196
|
}
|
|
255
|
-
|
|
256
|
-
export default App;
|
|
257
197
|
```
|
|
258
198
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
| Prop | Type | Required | Description |
|
|
262
|
-
| --------------------------- | ---------------------------- | -------- | -------------------------------------------------- |
|
|
263
|
-
| `view` | `MonthView` | ❌ | Current month and year (defaults to current month) |
|
|
264
|
-
| `onChangeView` | `(view: MonthView) => void` | ✅ | Month navigation callback |
|
|
265
|
-
| `attendanceData` | `AttendanceData` | ❌ | Present/absent days data (single month or array) |
|
|
266
|
-
| `onDateClick` | `(day, month, year) => void` | ❌ | Date click callback |
|
|
267
|
-
| `monthTitlePosition` | `'left' \| 'center' \| 'right'` | ❌ | Position of the month title (default: `'center'`) |
|
|
268
|
-
| `showNavigation` | `boolean` | ❌ | Show nav arrows (default: `true`) |
|
|
269
|
-
| `showWeekdayHeaders` | `boolean` | ❌ | Show weekday headers (default: `true`) |
|
|
270
|
-
| `cellSize` | `number` | ❌ | Size in pixels for all calendar cells (square) |
|
|
271
|
-
| `cellHeight` | `number` | ❌ | Height in pixels for calendar cells |
|
|
272
|
-
| `cellWidth` | `number` | ❌ | Width in pixels for calendar cells |
|
|
273
|
-
| `className` | `string` | ❌ | Additional classes for root element |
|
|
274
|
-
| `cellClassName` | `string` | ❌ | Custom classes for all cells |
|
|
275
|
-
| `presentCellClassName` | `string` | ❌ | Custom classes for present days |
|
|
276
|
-
| `absentCellClassName` | `string` | ❌ | Custom classes for absent days |
|
|
277
|
-
| `navigationButtonClassName` | `string` | ❌ | Custom classes for nav buttons |
|
|
278
|
-
| `monthTitleClassName` | `string` | ❌ | Custom classes for month title |
|
|
279
|
-
| `weekdayHeaderClassName` | `string` | ❌ | Custom classes for weekday headers |
|
|
280
|
-
| `containerClassName` | `string` | ❌ | Custom classes for main container |
|
|
281
|
-
| `todayCellClassName` | `string` | ❌ | Classes for **today’s** cell only; merged **last** so they override other cell props |
|
|
282
|
-
|
|
283
|
-
### TypeScript
|
|
284
|
-
|
|
285
|
-
```typescript
|
|
286
|
-
type MonthView = {
|
|
287
|
-
year: number; // e.g., 2024
|
|
288
|
-
monthIndex: number; // 0-11 (0 = January)
|
|
289
|
-
};
|
|
199
|
+
### Custom cell sizes
|
|
290
200
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
presentDays: Set<number>; // Day numbers 1-31
|
|
295
|
-
absentDays: Set<number>; // Day numbers 1-31
|
|
296
|
-
};
|
|
201
|
+
```tsx
|
|
202
|
+
// Square cells
|
|
203
|
+
<AttendanceCalendar view={view} onChangeView={setView} cellSize={50} />
|
|
297
204
|
|
|
298
|
-
//
|
|
299
|
-
|
|
205
|
+
// Custom width and height
|
|
206
|
+
<AttendanceCalendar view={view} onChangeView={setView} cellWidth={80} cellHeight={50} />
|
|
300
207
|
|
|
301
|
-
|
|
208
|
+
// Compact
|
|
209
|
+
<AttendanceCalendar
|
|
210
|
+
view={view}
|
|
211
|
+
onChangeView={setView}
|
|
212
|
+
cellSize={32}
|
|
213
|
+
classNames={{ cell: "rounded-full text-xs" }}
|
|
214
|
+
/>
|
|
302
215
|
```
|
|
303
216
|
|
|
304
|
-
|
|
217
|
+
### Multi-month data
|
|
305
218
|
|
|
306
|
-
|
|
219
|
+
Pass an array to `attendanceData` to pre-load multiple months. Navigation between loaded months is instant.
|
|
307
220
|
|
|
308
|
-
|
|
221
|
+
```tsx
|
|
222
|
+
const data: AttendanceData = [
|
|
223
|
+
{
|
|
224
|
+
year: 2024,
|
|
225
|
+
monthIndex: 0,
|
|
226
|
+
presentDays: new Set([1, 2, 3, 5, 8, 9, 10]),
|
|
227
|
+
absentDays: new Set([4, 11]),
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
year: 2024,
|
|
231
|
+
monthIndex: 1,
|
|
232
|
+
presentDays: new Set([1, 2, 5, 6, 7]),
|
|
233
|
+
absentDays: new Set([3, 4, 8]),
|
|
234
|
+
},
|
|
235
|
+
];
|
|
309
236
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
- **Regular days**: Slate gray (`slate-700`) with light border
|
|
313
|
-
- **Today** (not present/absent): Dark slate background (`slate-900`) with white text; use `todayCellClassName` to replace or extend
|
|
314
|
-
- **Today** (present/absent): Same as that status, plus a subtle ring; override with `todayCellClassName`
|
|
315
|
-
- **Navigation**: Rounded buttons with hover effects
|
|
316
|
-
- **Typography**: Clean, readable fonts with proper hierarchy
|
|
237
|
+
<AttendanceCalendar view={view} onChangeView={setView} attendanceData={data} />;
|
|
238
|
+
```
|
|
317
239
|
|
|
318
|
-
|
|
240
|
+
## API Reference
|
|
319
241
|
|
|
320
|
-
|
|
321
|
-
- **Desktop (≥700px container)**: Switches to 14-column layout
|
|
322
|
-
- **Narrow containers / mobile**: 7-column layout with touch-friendly sizing
|
|
323
|
-
- **Fixed size mode**: Use `cellSize`, `cellWidth`, or `cellHeight` for explicit pixel dimensions
|
|
242
|
+
### `AttendanceCalendar` (pre-composed)
|
|
324
243
|
|
|
325
|
-
|
|
244
|
+
| Prop | Type | Default | Description |
|
|
245
|
+
| --- | --- | --- | --- |
|
|
246
|
+
| `view` | `MonthView` | current month | Current month and year |
|
|
247
|
+
| `onChangeView` | `(view: MonthView) => void` | **required** | Month navigation callback |
|
|
248
|
+
| `attendanceData` | `AttendanceData` | — | Present/absent days (single or array) |
|
|
249
|
+
| `onDateClick` | `(day, month, year) => void` | — | Date click callback |
|
|
250
|
+
| `showNavigation` | `boolean` | `true` | Show header with nav buttons |
|
|
251
|
+
| `showWeekDays` | `boolean` | `true` | Show weekday labels |
|
|
252
|
+
| `className` | `string` | — | Root container class |
|
|
253
|
+
| `classNames` | `GridClassNames` | — | Cell style overrides (see below) |
|
|
254
|
+
| `cellSize` | `number` | — | Square cell size in px |
|
|
255
|
+
| `cellWidth` | `number` | — | Cell width in px |
|
|
256
|
+
| `cellHeight` | `number` | — | Cell height in px |
|
|
257
|
+
| `renderCell` | `(state: CellData) => ReactNode` | — | Custom cell renderer |
|
|
326
258
|
|
|
327
|
-
|
|
259
|
+
### `GridClassNames`
|
|
328
260
|
|
|
329
|
-
|
|
261
|
+
```typescript
|
|
262
|
+
type GridClassNames = {
|
|
263
|
+
cell?: string; // Base class for all cells
|
|
264
|
+
present?: string; // Present-day cells
|
|
265
|
+
absent?: string; // Absent-day cells
|
|
266
|
+
today?: string; // Today's cell (merged last, wins over present/absent)
|
|
267
|
+
outside?: string; // Days outside current month
|
|
268
|
+
};
|
|
269
|
+
```
|
|
330
270
|
|
|
331
|
-
|
|
332
|
-
- **`cellWidth`** - Set only the width of cells
|
|
333
|
-
- **`cellHeight`** - Set only the height of cells
|
|
334
|
-
- **Automatic font sizing** - Text size adjusts based on cell dimensions
|
|
271
|
+
### `CellData`
|
|
335
272
|
|
|
336
|
-
|
|
273
|
+
Passed to `renderCell`:
|
|
337
274
|
|
|
338
|
-
|
|
275
|
+
```typescript
|
|
276
|
+
type CellData = {
|
|
277
|
+
day: number;
|
|
278
|
+
date: Date;
|
|
279
|
+
inCurrentMonth: boolean;
|
|
280
|
+
isPresent: boolean;
|
|
281
|
+
isAbsent: boolean;
|
|
282
|
+
isToday: boolean;
|
|
283
|
+
isClickable: boolean;
|
|
284
|
+
};
|
|
285
|
+
```
|
|
339
286
|
|
|
340
|
-
|
|
341
|
-
- Hover effects, transitions, animations
|
|
342
|
-
- Responsive breakpoints and utilities
|
|
343
|
-
- **`todayCellClassName`** — prefer this for today’s look so your utilities reliably override shared props like `presentCellClassName`
|
|
287
|
+
### Compound Components
|
|
344
288
|
|
|
345
|
-
|
|
289
|
+
| Component | Props | Description |
|
|
290
|
+
| --- | --- | --- |
|
|
291
|
+
| `Calendar.Root` | `view`, `onChangeView`, `attendanceData`, `onDateClick`, `className`, `children` | Context provider and container |
|
|
292
|
+
| `Calendar.Header` | `className`, `children` | Flex wrapper for title + nav |
|
|
293
|
+
| `Calendar.Title` | `className`, `yearClassName?`, `format?` | Month/year heading — `yearClassName` styles the year span only (default year color: `text-slate-500`) |
|
|
294
|
+
| `Calendar.PrevTrigger` | all `<button>` props | Previous month button |
|
|
295
|
+
| `Calendar.NextTrigger` | all `<button>` props | Next month button |
|
|
296
|
+
| `Calendar.WeekDays` | `className`, `dayClassName`, `labels?` | Weekday labels row |
|
|
297
|
+
| `Calendar.Grid` | `className`, `classNames`, `cellSize`, `cellHeight`, `cellWidth`, `renderCell` | Date grid |
|
|
346
298
|
|
|
347
|
-
|
|
299
|
+
### `useCalendar()` Hook
|
|
348
300
|
|
|
349
|
-
|
|
301
|
+
Returns all calendar state when used inside `Calendar.Root`:
|
|
350
302
|
|
|
351
303
|
```typescript
|
|
352
|
-
const
|
|
353
|
-
year
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
304
|
+
const {
|
|
305
|
+
view, // MonthView — current month/year
|
|
306
|
+
monthName, // string — e.g. "January"
|
|
307
|
+
today, // { day, month, year }
|
|
308
|
+
currentMonthData,// MonthAttendanceData | undefined
|
|
309
|
+
columns, // number — 7 or 14 (responsive)
|
|
310
|
+
cells, // { day, inCurrentMonth }[]
|
|
311
|
+
weekdayLabels, // string[]
|
|
312
|
+
goPrev, // () => void
|
|
313
|
+
goNext, // () => void
|
|
314
|
+
onDateClick, // ((day, month, year) => void) | undefined
|
|
315
|
+
} = useCalendar();
|
|
358
316
|
```
|
|
359
317
|
|
|
360
|
-
###
|
|
318
|
+
### Types
|
|
361
319
|
|
|
362
320
|
```typescript
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
// ... add more months as needed
|
|
377
|
-
];
|
|
321
|
+
type MonthView = {
|
|
322
|
+
year: number;
|
|
323
|
+
monthIndex: number; // 0-11
|
|
324
|
+
};
|
|
325
|
+
|
|
326
|
+
type MonthAttendanceData = {
|
|
327
|
+
year: number;
|
|
328
|
+
monthIndex: number;
|
|
329
|
+
presentDays: Set<number>;
|
|
330
|
+
absentDays: Set<number>;
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
type AttendanceData = MonthAttendanceData | MonthAttendanceData[];
|
|
378
334
|
```
|
|
379
335
|
|
|
380
|
-
|
|
336
|
+
## Default Theme
|
|
337
|
+
|
|
338
|
+
- **Present** — emerald green (`emerald-500`) with white text
|
|
339
|
+
- **Absent** — amber orange (`amber-500`) with white text
|
|
340
|
+
- **Today** (no data) — dark slate (`slate-900`) with white text
|
|
341
|
+
- **Today** (present/absent) — status color + ring highlight
|
|
342
|
+
- **Outside month** — faded with light border
|
|
343
|
+
- **Navigation** — rounded buttons with hover/active effects
|
|
344
|
+
|
|
345
|
+
## Responsive Behavior
|
|
381
346
|
|
|
382
|
-
-
|
|
383
|
-
-
|
|
384
|
-
-
|
|
385
|
-
-
|
|
386
|
-
- ✅ **Memory efficient** - Store data in memory for instant access
|
|
387
|
-
- ✅ **Offline ready** - Pre-load data for offline calendar browsing
|
|
347
|
+
- Cells use `w-full aspect-square` by default — fluid with no overflow
|
|
348
|
+
- Container >= 700px: switches to 14-column layout
|
|
349
|
+
- Narrow / mobile: 7-column layout with touch-friendly sizing
|
|
350
|
+
- Use `cellSize`, `cellWidth`, or `cellHeight` for fixed pixel dimensions
|
|
388
351
|
|
|
389
|
-
##
|
|
352
|
+
## License
|
|
390
353
|
|
|
391
354
|
MIT © [Alamin](https://github.com/alamincodes)
|
|
392
355
|
|
|
393
356
|
---
|
|
394
357
|
|
|
395
358
|
<div align="center">
|
|
396
|
-
<a href="https://github.com/alamincodes/attendance-calendar">GitHub</a> •
|
|
359
|
+
<a href="https://github.com/alamincodes/attendance-calendar">GitHub</a> •
|
|
397
360
|
<a href="https://www.npmjs.com/package/react-attendance-calendar">npm</a>
|
|
398
361
|
</div>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { AttendanceData, CellData, GridClassNames, MonthView } from "./calendar/types";
|
|
2
|
+
export type AttendanceCalendarProps = {
|
|
3
|
+
view?: MonthView;
|
|
4
|
+
onChangeView: (next: MonthView) => void;
|
|
5
|
+
attendanceData?: AttendanceData;
|
|
6
|
+
onDateClick?: (day: number, month: number, year: number) => void;
|
|
7
|
+
showNavigation?: boolean;
|
|
8
|
+
showWeekDays?: boolean;
|
|
9
|
+
className?: string;
|
|
10
|
+
classNames?: GridClassNames;
|
|
11
|
+
cellSize?: number;
|
|
12
|
+
cellHeight?: number;
|
|
13
|
+
cellWidth?: number;
|
|
14
|
+
renderCell?: (state: CellData) => React.ReactNode;
|
|
15
|
+
};
|
|
16
|
+
export default function AttendanceCalendar({ view, onChangeView, attendanceData, onDateClick, showNavigation, showWeekDays, className, classNames, cellSize, cellHeight, cellWidth, renderCell, }: AttendanceCalendarProps): import("react/jsx-runtime").JSX.Element;
|
|
17
|
+
//# sourceMappingURL=attendance-calendar.d.ts.map
|