@hectorbliss/denik-calendar 0.0.2 → 0.0.3

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 CHANGED
@@ -111,7 +111,60 @@ interface CalendarConfig {
111
111
  edit?: ReactNode;
112
112
  close?: ReactNode;
113
113
  };
114
+ renderColumnHeader?: (props: ColumnHeaderProps) => ReactNode;
114
115
  }
116
+
117
+ interface ColumnHeaderProps {
118
+ date: Date;
119
+ index: number;
120
+ isToday: boolean;
121
+ locale: string;
122
+ }
123
+ ```
124
+
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
+ />
115
168
  ```
116
169
 
117
170
  ## Features
@@ -121,6 +174,7 @@ interface CalendarConfig {
121
174
  - Block time slots
122
175
  - Week navigation
123
176
  - Auto-scroll to current hour
177
+ - Custom column headers (resources, courts, rooms, employees)
124
178
  - Customizable icons
125
179
  - Locale support
126
180
  - TypeScript support
package/dist/index.cjs CHANGED
@@ -217,18 +217,29 @@ var cn = (...classes) => classes.filter(Boolean).join(" ");
217
217
  var DefaultTrashIcon = () => /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", className: "w-4 h-4", fill: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z" }) });
218
218
  var DefaultEditIcon = () => /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", className: "w-4 h-4", fill: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z" }) });
219
219
  var DefaultCloseIcon = () => /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", className: "w-4 h-4", fill: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" }) });
220
- var DayHeader = ({ date, locale }) => /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "grid place-items-center", children: [
221
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "capitalize", children: date.toLocaleDateString(locale, { weekday: "short" }) }),
222
- /* @__PURE__ */ jsxRuntime.jsx(
223
- "span",
224
- {
225
- className: cn(
226
- isToday(date) && "bg-blue-500 rounded-full p-1 text-white"
227
- ),
228
- children: date.getDate()
229
- }
230
- )
231
- ] });
220
+ var DayHeader = ({
221
+ date,
222
+ locale,
223
+ index,
224
+ renderColumnHeader
225
+ }) => {
226
+ const isToday2 = isToday(date);
227
+ if (renderColumnHeader) {
228
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid place-items-center", children: renderColumnHeader({ date, index, isToday: isToday2, locale }) });
229
+ }
230
+ return /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "grid place-items-center", children: [
231
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "capitalize", children: date.toLocaleDateString(locale, { weekday: "short" }) }),
232
+ /* @__PURE__ */ jsxRuntime.jsx(
233
+ "span",
234
+ {
235
+ className: cn(
236
+ isToday2 && "bg-blue-500 rounded-full p-1 text-white"
237
+ ),
238
+ children: date.getDate()
239
+ }
240
+ )
241
+ ] });
242
+ };
232
243
  function Calendar({
233
244
  date = /* @__PURE__ */ new Date(),
234
245
  events = [],
@@ -239,7 +250,7 @@ function Calendar({
239
250
  onRemoveBlock,
240
251
  config = {}
241
252
  }) {
242
- const { locale = "es-MX", icons = {} } = config;
253
+ const { locale = "es-MX", icons = {}, renderColumnHeader } = config;
243
254
  const week = completeWeek(date);
244
255
  const [activeId, setActiveId] = react.useState(null);
245
256
  const { canMove } = useCalendarEvents(events);
@@ -291,7 +302,16 @@ function Calendar({
291
302
  /* @__PURE__ */ jsxRuntime.jsxs("article", { className: "w-full bg-white shadow rounded-xl", children: [
292
303
  /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "grid grid-cols-8 place-items-center py-4", children: [
293
304
  /* @__PURE__ */ jsxRuntime.jsx("p", { children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-gray-500", children: Intl.DateTimeFormat().resolvedOptions().timeZone }) }),
294
- week.map((day) => /* @__PURE__ */ jsxRuntime.jsx(DayHeader, { date: day, locale }, day.toISOString()))
305
+ week.map((day, index) => /* @__PURE__ */ jsxRuntime.jsx(
306
+ DayHeader,
307
+ {
308
+ date: day,
309
+ locale,
310
+ index,
311
+ renderColumnHeader
312
+ },
313
+ day.toISOString()
314
+ ))
295
315
  ] }),
296
316
  /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "grid grid-cols-8 max-h-[80vh] overflow-y-auto", children: [
297
317
  /* @__PURE__ */ jsxRuntime.jsx(TimeColumn, {}),
package/dist/index.d.cts CHANGED
@@ -1,6 +1,20 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { ReactNode, RefObject } from 'react';
3
3
 
4
+ /**
5
+ * Props passed to custom column header renderer
6
+ * Use this to build custom headers for resources (courts, rooms, employees, etc.)
7
+ */
8
+ interface ColumnHeaderProps {
9
+ /** The date for this column */
10
+ date: Date;
11
+ /** Column index (0-6) */
12
+ index: number;
13
+ /** Whether this column represents today */
14
+ isToday: boolean;
15
+ /** The configured locale */
16
+ locale: string;
17
+ }
4
18
  /**
5
19
  * Generic calendar event - decoupled from any ORM
6
20
  */
@@ -30,6 +44,23 @@ interface CalendarConfig {
30
44
  edit?: ReactNode;
31
45
  close?: ReactNode;
32
46
  };
47
+ /**
48
+ * Custom renderer for column headers.
49
+ * Use this to display resources (courts, rooms, employees) instead of weekdays.
50
+ *
51
+ * @example
52
+ * // Padel courts
53
+ * renderColumnHeader: ({ index }) => <span>Court {index + 1}</span>
54
+ *
55
+ * @example
56
+ * // With custom styling
57
+ * renderColumnHeader: ({ date, isToday }) => (
58
+ * <div className={isToday ? "font-bold" : ""}>
59
+ * {date.toLocaleDateString("en", { weekday: "short" })}
60
+ * </div>
61
+ * )
62
+ */
63
+ renderColumnHeader?: (props: ColumnHeaderProps) => ReactNode;
33
64
  }
34
65
  /**
35
66
  * Calendar component props
@@ -128,4 +159,4 @@ declare function useClickOutside<T extends HTMLElement>({ isActive, onOutsideCli
128
159
  */
129
160
  declare function formatDate(date: Date, locale?: string): string;
130
161
 
131
- export { Calendar, type CalendarConfig, type CalendarEvent, type CalendarProps, Calendar as SimpleBigWeekView, addDaysToDate, addMinutesToDate, areSameDates, completeWeek, formatDate, fromDateToTimeString, fromMinsToLocaleTimeString, fromMinsToTimeString, generateHours, getDaysInMonth, getMonday, isToday, useCalendarEvents, useClickOutside, useEventOverlap };
162
+ export { Calendar, type CalendarConfig, type CalendarEvent, type CalendarProps, type ColumnHeaderProps, Calendar as SimpleBigWeekView, addDaysToDate, addMinutesToDate, areSameDates, completeWeek, formatDate, fromDateToTimeString, fromMinsToLocaleTimeString, fromMinsToTimeString, generateHours, getDaysInMonth, getMonday, isToday, useCalendarEvents, useClickOutside, useEventOverlap };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,20 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { ReactNode, RefObject } from 'react';
3
3
 
4
+ /**
5
+ * Props passed to custom column header renderer
6
+ * Use this to build custom headers for resources (courts, rooms, employees, etc.)
7
+ */
8
+ interface ColumnHeaderProps {
9
+ /** The date for this column */
10
+ date: Date;
11
+ /** Column index (0-6) */
12
+ index: number;
13
+ /** Whether this column represents today */
14
+ isToday: boolean;
15
+ /** The configured locale */
16
+ locale: string;
17
+ }
4
18
  /**
5
19
  * Generic calendar event - decoupled from any ORM
6
20
  */
@@ -30,6 +44,23 @@ interface CalendarConfig {
30
44
  edit?: ReactNode;
31
45
  close?: ReactNode;
32
46
  };
47
+ /**
48
+ * Custom renderer for column headers.
49
+ * Use this to display resources (courts, rooms, employees) instead of weekdays.
50
+ *
51
+ * @example
52
+ * // Padel courts
53
+ * renderColumnHeader: ({ index }) => <span>Court {index + 1}</span>
54
+ *
55
+ * @example
56
+ * // With custom styling
57
+ * renderColumnHeader: ({ date, isToday }) => (
58
+ * <div className={isToday ? "font-bold" : ""}>
59
+ * {date.toLocaleDateString("en", { weekday: "short" })}
60
+ * </div>
61
+ * )
62
+ */
63
+ renderColumnHeader?: (props: ColumnHeaderProps) => ReactNode;
33
64
  }
34
65
  /**
35
66
  * Calendar component props
@@ -128,4 +159,4 @@ declare function useClickOutside<T extends HTMLElement>({ isActive, onOutsideCli
128
159
  */
129
160
  declare function formatDate(date: Date, locale?: string): string;
130
161
 
131
- export { Calendar, type CalendarConfig, type CalendarEvent, type CalendarProps, Calendar as SimpleBigWeekView, addDaysToDate, addMinutesToDate, areSameDates, completeWeek, formatDate, fromDateToTimeString, fromMinsToLocaleTimeString, fromMinsToTimeString, generateHours, getDaysInMonth, getMonday, isToday, useCalendarEvents, useClickOutside, useEventOverlap };
162
+ export { Calendar, type CalendarConfig, type CalendarEvent, type CalendarProps, type ColumnHeaderProps, Calendar as SimpleBigWeekView, addDaysToDate, addMinutesToDate, areSameDates, completeWeek, formatDate, fromDateToTimeString, fromMinsToLocaleTimeString, fromMinsToTimeString, generateHours, getDaysInMonth, getMonday, isToday, useCalendarEvents, useClickOutside, useEventOverlap };
package/dist/index.js CHANGED
@@ -215,18 +215,29 @@ var cn = (...classes) => classes.filter(Boolean).join(" ");
215
215
  var DefaultTrashIcon = () => /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", className: "w-4 h-4", fill: "currentColor", children: /* @__PURE__ */ jsx("path", { d: "M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z" }) });
216
216
  var DefaultEditIcon = () => /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", className: "w-4 h-4", fill: "currentColor", children: /* @__PURE__ */ jsx("path", { d: "M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z" }) });
217
217
  var DefaultCloseIcon = () => /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", className: "w-4 h-4", fill: "currentColor", children: /* @__PURE__ */ jsx("path", { d: "M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" }) });
218
- var DayHeader = ({ date, locale }) => /* @__PURE__ */ jsxs("p", { className: "grid place-items-center", children: [
219
- /* @__PURE__ */ jsx("span", { className: "capitalize", children: date.toLocaleDateString(locale, { weekday: "short" }) }),
220
- /* @__PURE__ */ jsx(
221
- "span",
222
- {
223
- className: cn(
224
- isToday(date) && "bg-blue-500 rounded-full p-1 text-white"
225
- ),
226
- children: date.getDate()
227
- }
228
- )
229
- ] });
218
+ var DayHeader = ({
219
+ date,
220
+ locale,
221
+ index,
222
+ renderColumnHeader
223
+ }) => {
224
+ const isToday2 = isToday(date);
225
+ if (renderColumnHeader) {
226
+ return /* @__PURE__ */ jsx("div", { className: "grid place-items-center", children: renderColumnHeader({ date, index, isToday: isToday2, locale }) });
227
+ }
228
+ return /* @__PURE__ */ jsxs("p", { className: "grid place-items-center", children: [
229
+ /* @__PURE__ */ jsx("span", { className: "capitalize", children: date.toLocaleDateString(locale, { weekday: "short" }) }),
230
+ /* @__PURE__ */ jsx(
231
+ "span",
232
+ {
233
+ className: cn(
234
+ isToday2 && "bg-blue-500 rounded-full p-1 text-white"
235
+ ),
236
+ children: date.getDate()
237
+ }
238
+ )
239
+ ] });
240
+ };
230
241
  function Calendar({
231
242
  date = /* @__PURE__ */ new Date(),
232
243
  events = [],
@@ -237,7 +248,7 @@ function Calendar({
237
248
  onRemoveBlock,
238
249
  config = {}
239
250
  }) {
240
- const { locale = "es-MX", icons = {} } = config;
251
+ const { locale = "es-MX", icons = {}, renderColumnHeader } = config;
241
252
  const week = completeWeek(date);
242
253
  const [activeId, setActiveId] = useState(null);
243
254
  const { canMove } = useCalendarEvents(events);
@@ -289,7 +300,16 @@ function Calendar({
289
300
  /* @__PURE__ */ jsxs("article", { className: "w-full bg-white shadow rounded-xl", children: [
290
301
  /* @__PURE__ */ jsxs("section", { className: "grid grid-cols-8 place-items-center py-4", children: [
291
302
  /* @__PURE__ */ jsx("p", { children: /* @__PURE__ */ jsx("span", { className: "text-sm text-gray-500", children: Intl.DateTimeFormat().resolvedOptions().timeZone }) }),
292
- week.map((day) => /* @__PURE__ */ jsx(DayHeader, { date: day, locale }, day.toISOString()))
303
+ week.map((day, index) => /* @__PURE__ */ jsx(
304
+ DayHeader,
305
+ {
306
+ date: day,
307
+ locale,
308
+ index,
309
+ renderColumnHeader
310
+ },
311
+ day.toISOString()
312
+ ))
293
313
  ] }),
294
314
  /* @__PURE__ */ jsxs("section", { className: "grid grid-cols-8 max-h-[80vh] overflow-y-auto", children: [
295
315
  /* @__PURE__ */ jsx(TimeColumn, {}),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hectorbliss/denik-calendar",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "private": false,
5
5
  "description": "A React drag-and-drop week calendar component with overlap detection. Built with @dnd-kit.",
6
6
  "type": "module",