@classytic/fluid 0.2.1 → 0.3.2
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/LICENSE +21 -0
- package/README.md +149 -62
- package/dist/api-pagination-CJ0vR_w6.d.mts +34 -0
- package/dist/api-pagination-DBTE0yk4.mjs +190 -0
- package/dist/chunk-DQk6qfdC.mjs +18 -0
- package/dist/client/calendar.d.mts +105 -0
- package/dist/client/calendar.mjs +202 -0
- package/dist/client/core.d.mts +1614 -0
- package/dist/client/core.mjs +2779 -0
- package/dist/client/error.d.mts +125 -0
- package/dist/client/error.mjs +166 -0
- package/dist/client/hooks.d.mts +162 -0
- package/dist/client/hooks.mjs +447 -0
- package/dist/client/table.d.mts +84 -0
- package/dist/client/table.mjs +373 -0
- package/dist/client/theme.d.mts +6 -0
- package/dist/client/theme.mjs +65 -0
- package/dist/command.d.mts +134 -0
- package/dist/command.mjs +132 -0
- package/dist/compact.d.mts +359 -0
- package/dist/compact.mjs +892 -0
- package/dist/dashboard.d.mts +778 -0
- package/dist/dashboard.mjs +1617 -0
- package/dist/filter-utils-DqMmy_v-.mjs +72 -0
- package/dist/filter-utils-IZ0GtuPo.d.mts +40 -0
- package/dist/forms.d.mts +1549 -0
- package/dist/forms.mjs +3740 -0
- package/dist/index.d.mts +296 -0
- package/dist/index.mjs +432 -0
- package/dist/layouts.d.mts +215 -0
- package/dist/layouts.mjs +460 -0
- package/dist/search-context-DR7DBs7S.mjs +19 -0
- package/dist/search.d.mts +254 -0
- package/dist/search.mjs +523 -0
- package/dist/sheet-wrapper-CWNCvYMD.mjs +211 -0
- package/dist/use-base-search-BGgWnWaF.d.mts +35 -0
- package/dist/use-debounce-xmZucz5e.mjs +53 -0
- package/dist/use-keyboard-shortcut-Bl6YM5Q7.mjs +82 -0
- package/dist/use-keyboard-shortcut-_mRCh3QO.d.mts +24 -0
- package/dist/use-media-query-BnVNIKT4.mjs +17 -0
- package/dist/use-mobile-BX3SQVo2.mjs +20 -0
- package/dist/use-scroll-detection-CsgsQYvy.mjs +43 -0
- package/dist/utils-CDue7cEt.d.mts +6 -0
- package/dist/utils-DQ5SCVoW.mjs +10 -0
- package/package.json +85 -45
- package/styles.css +2 -2
- package/dist/chunk-GUHK2DTW.js +0 -15
- package/dist/chunk-GUHK2DTW.js.map +0 -1
- package/dist/chunk-H3NFL3GJ.js +0 -57
- package/dist/chunk-H3NFL3GJ.js.map +0 -1
- package/dist/chunk-J2YRTQE4.js +0 -293
- package/dist/chunk-J2YRTQE4.js.map +0 -1
- package/dist/compact.d.ts +0 -217
- package/dist/compact.js +0 -986
- package/dist/compact.js.map +0 -1
- package/dist/dashboard.d.ts +0 -386
- package/dist/dashboard.js +0 -1032
- package/dist/dashboard.js.map +0 -1
- package/dist/index.d.ts +0 -2141
- package/dist/index.js +0 -6460
- package/dist/index.js.map +0 -1
- package/dist/layout.d.ts +0 -25
- package/dist/layout.js +0 -4
- package/dist/layout.js.map +0 -1
- package/dist/search.d.ts +0 -172
- package/dist/search.js +0 -341
- package/dist/search.js.map +0 -1
- package/dist/use-base-search-AS5Z3SAy.d.ts +0 -64
- package/dist/utils-Cbsgs0XP.d.ts +0 -5
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { t as cn } from "../utils-DQ5SCVoW.mjs";
|
|
4
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
import { useCallback, useMemo, useState } from "react";
|
|
6
|
+
import { ChevronLeft, ChevronRight } from "lucide-react";
|
|
7
|
+
import { Button } from "@/components/ui/button";
|
|
8
|
+
import { addMonths, eachDayOfInterval, endOfMonth, format, getDay, isSameDay, isSameMonth, startOfMonth, subMonths } from "date-fns";
|
|
9
|
+
|
|
10
|
+
//#region src/components/event-calendar.tsx
|
|
11
|
+
const WEEKDAYS = [
|
|
12
|
+
"Sun",
|
|
13
|
+
"Mon",
|
|
14
|
+
"Tue",
|
|
15
|
+
"Wed",
|
|
16
|
+
"Thu",
|
|
17
|
+
"Fri",
|
|
18
|
+
"Sat"
|
|
19
|
+
];
|
|
20
|
+
/**
|
|
21
|
+
* EventCalendar - A reusable calendar component for displaying events
|
|
22
|
+
*
|
|
23
|
+
* Can be used for attendance tracking, scheduling, etc.
|
|
24
|
+
*/
|
|
25
|
+
function EventCalendar({ events = [], selectedDate: controlledSelectedDate, onDateSelect, onMonthChange, initialMonth = /* @__PURE__ */ new Date(), renderDayContent, renderEventIndicators, getEventsForDate, className, headerLeft, headerRight, minCellHeight = "5rem", showWeekNumbers = false, isLoading = false }) {
|
|
26
|
+
const [currentMonth, setCurrentMonth] = useState(initialMonth);
|
|
27
|
+
const [internalSelectedDate, setInternalSelectedDate] = useState(null);
|
|
28
|
+
const selectedDate = controlledSelectedDate ?? internalSelectedDate;
|
|
29
|
+
const { days, paddingDaysBefore, paddingDaysAfter } = useMemo(() => {
|
|
30
|
+
const monthStart = startOfMonth(currentMonth);
|
|
31
|
+
const daysInMonth = eachDayOfInterval({
|
|
32
|
+
start: monthStart,
|
|
33
|
+
end: endOfMonth(currentMonth)
|
|
34
|
+
});
|
|
35
|
+
const startDayOfWeek = getDay(monthStart);
|
|
36
|
+
return {
|
|
37
|
+
days: daysInMonth,
|
|
38
|
+
paddingDaysBefore: startDayOfWeek,
|
|
39
|
+
paddingDaysAfter: 42 - (startDayOfWeek + daysInMonth.length)
|
|
40
|
+
};
|
|
41
|
+
}, [currentMonth]);
|
|
42
|
+
const defaultGetEventsForDate = useCallback((date, allEvents) => {
|
|
43
|
+
return allEvents.filter((event) => {
|
|
44
|
+
return isSameDay(typeof event.date === "string" ? new Date(event.date) : event.date, date);
|
|
45
|
+
});
|
|
46
|
+
}, []);
|
|
47
|
+
const getEvents = getEventsForDate || defaultGetEventsForDate;
|
|
48
|
+
const handlePrevMonth = useCallback(() => {
|
|
49
|
+
const newMonth = subMonths(currentMonth, 1);
|
|
50
|
+
setCurrentMonth(newMonth);
|
|
51
|
+
onMonthChange?.(newMonth);
|
|
52
|
+
}, [currentMonth, onMonthChange]);
|
|
53
|
+
const handleNextMonth = useCallback(() => {
|
|
54
|
+
const newMonth = addMonths(currentMonth, 1);
|
|
55
|
+
setCurrentMonth(newMonth);
|
|
56
|
+
onMonthChange?.(newMonth);
|
|
57
|
+
}, [currentMonth, onMonthChange]);
|
|
58
|
+
const handleDateClick = useCallback((date) => {
|
|
59
|
+
const dayEvents = getEvents(date, events);
|
|
60
|
+
setInternalSelectedDate(date);
|
|
61
|
+
onDateSelect?.(date, dayEvents);
|
|
62
|
+
}, [
|
|
63
|
+
events,
|
|
64
|
+
getEvents,
|
|
65
|
+
onDateSelect
|
|
66
|
+
]);
|
|
67
|
+
const defaultRenderEventIndicators = useCallback((dayEvents) => {
|
|
68
|
+
if (dayEvents.length === 0) return null;
|
|
69
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
70
|
+
className: "flex gap-0.5 mt-1",
|
|
71
|
+
children: [dayEvents.slice(0, 3).map((_, idx) => /* @__PURE__ */ jsx("div", { className: "h-1.5 w-1.5 rounded-full bg-primary" }, idx)), dayEvents.length > 3 && /* @__PURE__ */ jsxs("span", {
|
|
72
|
+
className: "text-[10px] text-muted-foreground ml-0.5",
|
|
73
|
+
children: ["+", dayEvents.length - 3]
|
|
74
|
+
})]
|
|
75
|
+
});
|
|
76
|
+
}, []);
|
|
77
|
+
const renderIndicators = renderEventIndicators || defaultRenderEventIndicators;
|
|
78
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
79
|
+
className: cn("space-y-4", className),
|
|
80
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
81
|
+
className: "flex items-center justify-between",
|
|
82
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
83
|
+
className: "flex items-center gap-4",
|
|
84
|
+
children: [headerLeft, /* @__PURE__ */ jsx("h2", {
|
|
85
|
+
className: "text-lg font-semibold",
|
|
86
|
+
children: format(currentMonth, "MMMM yyyy")
|
|
87
|
+
})]
|
|
88
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
89
|
+
className: "flex items-center gap-2",
|
|
90
|
+
children: [headerRight, /* @__PURE__ */ jsxs("div", {
|
|
91
|
+
className: "flex gap-1",
|
|
92
|
+
children: [/* @__PURE__ */ jsx(Button, {
|
|
93
|
+
variant: "outline",
|
|
94
|
+
size: "icon",
|
|
95
|
+
onClick: handlePrevMonth,
|
|
96
|
+
disabled: isLoading,
|
|
97
|
+
children: /* @__PURE__ */ jsx(ChevronLeft, { className: "h-4 w-4" })
|
|
98
|
+
}), /* @__PURE__ */ jsx(Button, {
|
|
99
|
+
variant: "outline",
|
|
100
|
+
size: "icon",
|
|
101
|
+
onClick: handleNextMonth,
|
|
102
|
+
disabled: isLoading,
|
|
103
|
+
children: /* @__PURE__ */ jsx(ChevronRight, { className: "h-4 w-4" })
|
|
104
|
+
})]
|
|
105
|
+
})]
|
|
106
|
+
})]
|
|
107
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
108
|
+
className: "rounded-lg border overflow-hidden",
|
|
109
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
110
|
+
className: cn("grid bg-muted/50", showWeekNumbers ? "grid-cols-8" : "grid-cols-7"),
|
|
111
|
+
children: [showWeekNumbers && /* @__PURE__ */ jsx("div", {
|
|
112
|
+
className: "px-2 py-3 text-center text-xs font-medium text-muted-foreground border-r",
|
|
113
|
+
children: "Wk"
|
|
114
|
+
}), WEEKDAYS.map((day) => /* @__PURE__ */ jsx("div", {
|
|
115
|
+
className: "px-2 py-3 text-center text-xs font-medium text-muted-foreground",
|
|
116
|
+
children: day
|
|
117
|
+
}, day))]
|
|
118
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
119
|
+
className: cn("grid gap-px bg-border", showWeekNumbers ? "grid-cols-8" : "grid-cols-7"),
|
|
120
|
+
children: [
|
|
121
|
+
Array.from({ length: paddingDaysBefore }).map((_, index) => /* @__PURE__ */ jsx("div", {
|
|
122
|
+
className: "bg-card",
|
|
123
|
+
style: { minHeight: minCellHeight }
|
|
124
|
+
}, `padding-start-${index}`)),
|
|
125
|
+
days.map((day) => {
|
|
126
|
+
const dayEvents = getEvents(day, events);
|
|
127
|
+
const isToday = isSameDay(day, /* @__PURE__ */ new Date());
|
|
128
|
+
const isSelected = selectedDate ? isSameDay(day, selectedDate) : false;
|
|
129
|
+
const isCurrentMonth = isSameMonth(day, currentMonth);
|
|
130
|
+
return /* @__PURE__ */ jsx("div", {
|
|
131
|
+
className: cn("bg-card p-2 cursor-pointer transition-colors hover:bg-muted/50", isSelected && "ring-2 ring-primary ring-inset bg-primary/5", !isCurrentMonth && "opacity-50", isLoading && "pointer-events-none opacity-50"),
|
|
132
|
+
style: { minHeight: minCellHeight },
|
|
133
|
+
onClick: () => handleDateClick(day),
|
|
134
|
+
children: renderDayContent ? renderDayContent(day, dayEvents, isSelected) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("div", {
|
|
135
|
+
className: cn("flex h-7 w-7 items-center justify-center rounded-full text-sm", isToday && "bg-primary text-primary-foreground font-semibold"),
|
|
136
|
+
children: format(day, "d")
|
|
137
|
+
}), renderIndicators(dayEvents)] })
|
|
138
|
+
}, day.toISOString());
|
|
139
|
+
}),
|
|
140
|
+
Array.from({ length: paddingDaysAfter }).map((_, index) => /* @__PURE__ */ jsx("div", {
|
|
141
|
+
className: "bg-card",
|
|
142
|
+
style: { minHeight: minCellHeight }
|
|
143
|
+
}, `padding-end-${index}`))
|
|
144
|
+
]
|
|
145
|
+
})]
|
|
146
|
+
})]
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
function CalendarDayDetail({ date, title, emptyMessage = "Click on a day to see details", children, className }) {
|
|
150
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
151
|
+
className: cn("rounded-lg border bg-card", className),
|
|
152
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
153
|
+
className: "p-4 border-b",
|
|
154
|
+
children: /* @__PURE__ */ jsx("h3", {
|
|
155
|
+
className: "font-semibold",
|
|
156
|
+
children: date ? format(date, "EEEE, MMMM d") : title || "Select a day"
|
|
157
|
+
})
|
|
158
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
159
|
+
className: "p-4",
|
|
160
|
+
children: !date ? /* @__PURE__ */ jsx("p", {
|
|
161
|
+
className: "text-sm text-muted-foreground",
|
|
162
|
+
children: emptyMessage
|
|
163
|
+
}) : children
|
|
164
|
+
})]
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
function CalendarWithDetail({ renderDetail, detailTitle, detailEmptyMessage, layout = "horizontal", detailPosition = "right", onDateSelect, ...calendarProps }) {
|
|
168
|
+
const [selectedDate, setSelectedDate] = useState(null);
|
|
169
|
+
const [selectedEvents, setSelectedEvents] = useState([]);
|
|
170
|
+
const handleDateSelect = useCallback((date, events) => {
|
|
171
|
+
setSelectedDate(date);
|
|
172
|
+
setSelectedEvents(events);
|
|
173
|
+
onDateSelect?.(date, events);
|
|
174
|
+
}, [onDateSelect]);
|
|
175
|
+
const isHorizontal = layout === "horizontal";
|
|
176
|
+
const detailFirst = detailPosition === "left" || detailPosition === "top";
|
|
177
|
+
const calendarElement = /* @__PURE__ */ jsx(EventCalendar, {
|
|
178
|
+
...calendarProps,
|
|
179
|
+
selectedDate,
|
|
180
|
+
onDateSelect: handleDateSelect
|
|
181
|
+
});
|
|
182
|
+
const detailElement = /* @__PURE__ */ jsx(CalendarDayDetail, {
|
|
183
|
+
date: selectedDate,
|
|
184
|
+
title: detailTitle,
|
|
185
|
+
emptyMessage: detailEmptyMessage,
|
|
186
|
+
className: isHorizontal ? "min-w-[300px]" : "",
|
|
187
|
+
children: selectedDate && renderDetail?.(selectedDate, selectedEvents)
|
|
188
|
+
});
|
|
189
|
+
return /* @__PURE__ */ jsx("div", {
|
|
190
|
+
className: cn("gap-4", isHorizontal ? "flex" : "flex flex-col", isHorizontal && "items-start"),
|
|
191
|
+
children: detailFirst ? /* @__PURE__ */ jsxs(Fragment, { children: [detailElement, /* @__PURE__ */ jsx("div", {
|
|
192
|
+
className: "flex-1",
|
|
193
|
+
children: calendarElement
|
|
194
|
+
})] }) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("div", {
|
|
195
|
+
className: isHorizontal ? "flex-1" : "",
|
|
196
|
+
children: calendarElement
|
|
197
|
+
}), detailElement] })
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
//#endregion
|
|
202
|
+
export { CalendarDayDetail, CalendarWithDetail, EventCalendar };
|