@forthtilliath/shadcn-ui 0.2.0
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 +84 -0
- package/dist/components/accordion.d.ts +12 -0
- package/dist/components/accordion.d.ts.map +1 -0
- package/dist/components/accordion.js +28 -0
- package/dist/components/alert-dialog.d.ts +15 -0
- package/dist/components/alert-dialog.d.ts.map +1 -0
- package/dist/components/alert-dialog.js +39 -0
- package/dist/components/alert.d.ts +10 -0
- package/dist/components/alert.d.ts.map +1 -0
- package/dist/components/alert.js +24 -0
- package/dist/components/aspect-ratio.d.ts +4 -0
- package/dist/components/aspect-ratio.d.ts.map +1 -0
- package/dist/components/aspect-ratio.js +7 -0
- package/dist/components/avatar.d.ts +7 -0
- package/dist/components/avatar.d.ts.map +1 -0
- package/dist/components/avatar.js +14 -0
- package/dist/components/badge.d.ts +10 -0
- package/dist/components/badge.d.ts.map +1 -0
- package/dist/components/badge.js +22 -0
- package/dist/components/blocks/accordion.d.ts +56 -0
- package/dist/components/blocks/accordion.d.ts.map +1 -0
- package/dist/components/blocks/accordion.js +138 -0
- package/dist/components/blocks/animated-tabs.d.ts +17 -0
- package/dist/components/blocks/animated-tabs.d.ts.map +1 -0
- package/dist/components/blocks/animated-tabs.js +135 -0
- package/dist/components/blocks/animated-text.d.ts +43 -0
- package/dist/components/blocks/animated-text.d.ts.map +1 -0
- package/dist/components/blocks/animated-text.js +122 -0
- package/dist/components/blocks/avatar.d.ts +17 -0
- package/dist/components/blocks/avatar.d.ts.map +1 -0
- package/dist/components/blocks/avatar.js +31 -0
- package/dist/components/blocks/calendar-date-picker.d.ts +22 -0
- package/dist/components/blocks/calendar-date-picker.d.ts.map +1 -0
- package/dist/components/blocks/calendar-date-picker.js +377 -0
- package/dist/components/blocks/data-table-ext/pagination.d.ts +12 -0
- package/dist/components/blocks/data-table-ext/pagination.d.ts.map +1 -0
- package/dist/components/blocks/data-table-ext/pagination.js +65 -0
- package/dist/components/blocks/data-table-ext/utils/table-config.d.ts +16 -0
- package/dist/components/blocks/data-table-ext/utils/table-config.d.ts.map +1 -0
- package/dist/components/blocks/data-table-ext/utils/table-config.js +28 -0
- package/dist/components/blocks/data-table.d.ts +10 -0
- package/dist/components/blocks/data-table.d.ts.map +1 -0
- package/dist/components/blocks/data-table.js +59 -0
- package/dist/components/blocks/field.d.ts +10 -0
- package/dist/components/blocks/field.d.ts.map +1 -0
- package/dist/components/blocks/field.js +5 -0
- package/dist/components/blocks/form.d.ts +14 -0
- package/dist/components/blocks/form.d.ts.map +1 -0
- package/dist/components/blocks/form.js +12 -0
- package/dist/components/blocks/navbar-01.d.ts +12 -0
- package/dist/components/blocks/navbar-01.d.ts.map +1 -0
- package/dist/components/blocks/navbar-01.js +10 -0
- package/dist/components/blocks/navbar-02.d.ts +11 -0
- package/dist/components/blocks/navbar-02.d.ts.map +1 -0
- package/dist/components/blocks/navbar-02.js +12 -0
- package/dist/components/blocks/navbar-04.d.ts +12 -0
- package/dist/components/blocks/navbar-04.d.ts.map +1 -0
- package/dist/components/blocks/navbar-04.js +10 -0
- package/dist/components/breadcrumb.d.ts +12 -0
- package/dist/components/breadcrumb.d.ts.map +1 -0
- package/dist/components/breadcrumb.js +27 -0
- package/dist/components/button.d.ts +11 -0
- package/dist/components/button.d.ts.map +1 -0
- package/dist/components/button.js +31 -0
- package/dist/components/calendar.d.ts +10 -0
- package/dist/components/calendar.d.ts.map +1 -0
- package/dist/components/calendar.js +77 -0
- package/dist/components/card.d.ts +10 -0
- package/dist/components/card.d.ts.map +1 -0
- package/dist/components/card.js +24 -0
- package/dist/components/carousel.d.ts +20 -0
- package/dist/components/carousel.d.ts.map +1 -0
- package/dist/components/carousel.js +101 -0
- package/dist/components/chart.d.ts +40 -0
- package/dist/components/chart.d.ts.map +1 -0
- package/dist/components/chart.js +144 -0
- package/dist/components/checkbox.d.ts +5 -0
- package/dist/components/checkbox.d.ts.map +1 -0
- package/dist/components/checkbox.js +9 -0
- package/dist/components/collapsible.d.ts +6 -0
- package/dist/components/collapsible.d.ts.map +1 -0
- package/dist/components/collapsible.js +13 -0
- package/dist/components/command.d.ts +19 -0
- package/dist/components/command.d.ts.map +1 -0
- package/dist/components/command.js +34 -0
- package/dist/components/context-menu.d.ts +26 -0
- package/dist/components/context-menu.d.ts.map +1 -0
- package/dist/components/context-menu.js +51 -0
- package/dist/components/dialog.d.ts +16 -0
- package/dist/components/dialog.d.ts.map +1 -0
- package/dist/components/dialog.js +36 -0
- package/dist/components/drawer.d.ts +14 -0
- package/dist/components/drawer.d.ts.map +1 -0
- package/dist/components/drawer.js +35 -0
- package/dist/components/dropdown-menu.d.ts +26 -0
- package/dist/components/dropdown-menu.d.ts.map +1 -0
- package/dist/components/dropdown-menu.js +51 -0
- package/dist/components/form.d.ts +25 -0
- package/dist/components/form.d.ts.map +1 -0
- package/dist/components/form.js +54 -0
- package/dist/components/hover-card.d.ts +7 -0
- package/dist/components/hover-card.d.ts.map +1 -0
- package/dist/components/hover-card.js +14 -0
- package/dist/components/input-otp.d.ts +12 -0
- package/dist/components/input-otp.d.ts.map +1 -0
- package/dist/components/input-otp.js +21 -0
- package/dist/components/input.d.ts +4 -0
- package/dist/components/input.d.ts.map +1 -0
- package/dist/components/input.js +6 -0
- package/dist/components/label.d.ts +5 -0
- package/dist/components/label.d.ts.map +1 -0
- package/dist/components/label.js +8 -0
- package/dist/components/menubar.d.ts +27 -0
- package/dist/components/menubar.d.ts.map +1 -0
- package/dist/components/menubar.js +54 -0
- package/dist/components/navigation-menu.d.ts +15 -0
- package/dist/components/navigation-menu.d.ts.map +1 -0
- package/dist/components/navigation-menu.js +31 -0
- package/dist/components/pagination.d.ts +14 -0
- package/dist/components/pagination.d.ts.map +1 -0
- package/dist/components/pagination.js +29 -0
- package/dist/components/popover.d.ts +8 -0
- package/dist/components/popover.d.ts.map +1 -0
- package/dist/components/popover.js +17 -0
- package/dist/components/progress.d.ts +5 -0
- package/dist/components/progress.d.ts.map +1 -0
- package/dist/components/progress.js +8 -0
- package/dist/components/radio-group.d.ts +6 -0
- package/dist/components/radio-group.d.ts.map +1 -0
- package/dist/components/radio-group.js +12 -0
- package/dist/components/resizable.d.ts +9 -0
- package/dist/components/resizable.d.ts.map +1 -0
- package/dist/components/resizable.js +15 -0
- package/dist/components/scroll-area.d.ts +6 -0
- package/dist/components/scroll-area.d.ts.map +1 -0
- package/dist/components/scroll-area.js +13 -0
- package/dist/components/select.d.ts +16 -0
- package/dist/components/select.d.ts.map +1 -0
- package/dist/components/select.js +38 -0
- package/dist/components/separator.d.ts +5 -0
- package/dist/components/separator.d.ts.map +1 -0
- package/dist/components/separator.js +8 -0
- package/dist/components/sheet.d.ts +14 -0
- package/dist/components/sheet.d.ts.map +1 -0
- package/dist/components/sheet.js +40 -0
- package/dist/components/sidebar.d.ts +70 -0
- package/dist/components/sidebar.d.ts.map +1 -0
- package/dist/components/sidebar.js +221 -0
- package/dist/components/skeleton.d.ts +3 -0
- package/dist/components/skeleton.d.ts.map +1 -0
- package/dist/components/skeleton.js +6 -0
- package/dist/components/slider.d.ts +5 -0
- package/dist/components/slider.d.ts.map +1 -0
- package/dist/components/slider.js +14 -0
- package/dist/components/sonner.d.ts +4 -0
- package/dist/components/sonner.d.ts.map +1 -0
- package/dist/components/sonner.js +13 -0
- package/dist/components/switch.d.ts +5 -0
- package/dist/components/switch.d.ts.map +1 -0
- package/dist/components/switch.js +8 -0
- package/dist/components/table.d.ts +11 -0
- package/dist/components/table.d.ts.map +1 -0
- package/dist/components/table.js +28 -0
- package/dist/components/tabs.d.ts +8 -0
- package/dist/components/tabs.d.ts.map +1 -0
- package/dist/components/tabs.js +17 -0
- package/dist/components/textarea.d.ts +4 -0
- package/dist/components/textarea.d.ts.map +1 -0
- package/dist/components/textarea.js +6 -0
- package/dist/components/toggle-group.d.ts +8 -0
- package/dist/components/toggle-group.d.ts.map +1 -0
- package/dist/components/toggle-group.js +21 -0
- package/dist/components/toggle.d.ts +10 -0
- package/dist/components/toggle.d.ts.map +1 -0
- package/dist/components/toggle.js +26 -0
- package/dist/components/tooltip.d.ts +8 -0
- package/dist/components/tooltip.d.ts.map +1 -0
- package/dist/components/tooltip.js +17 -0
- package/dist/hooks/use-mobile.d.ts +2 -0
- package/dist/hooks/use-mobile.d.ts.map +1 -0
- package/dist/hooks/use-mobile.js +24 -0
- package/dist/lib/input-otp.d.ts +2 -0
- package/dist/lib/input-otp.d.ts.map +1 -0
- package/dist/lib/input-otp.js +1 -0
- package/dist/lib/react-hook-form.d.ts +3 -0
- package/dist/lib/react-hook-form.d.ts.map +1 -0
- package/dist/lib/react-hook-form.js +2 -0
- package/dist/lib/react-table.d.ts +2 -0
- package/dist/lib/react-table.d.ts.map +1 -0
- package/dist/lib/react-table.js +1 -0
- package/dist/lib/recharts.d.ts +2 -0
- package/dist/lib/recharts.d.ts.map +1 -0
- package/dist/lib/recharts.js +1 -0
- package/dist/lib/sonner.d.ts +2 -0
- package/dist/lib/sonner.d.ts.map +1 -0
- package/dist/lib/sonner.js +1 -0
- package/dist/lib/utils.d.ts +4 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/lib/utils.js +5 -0
- package/dist/lib/zod.d.ts +2 -0
- package/dist/lib/zod.d.ts.map +1 -0
- package/dist/lib/zod.js +1 -0
- package/dist/styles/globals-static.css +71 -0
- package/dist/styles/globals.css +71 -0
- package/dist/styles/themes/blue.css +68 -0
- package/dist/styles/themes/bubblegum.css +113 -0
- package/dist/styles/themes/claymorphism.css +108 -0
- package/dist/styles/themes/default.css +69 -0
- package/dist/styles/themes/green.css +68 -0
- package/dist/styles/themes/orange.css +68 -0
- package/dist/styles/themes/red.css +68 -0
- package/dist/styles/themes/rose.css +68 -0
- package/dist/styles/themes/twitter.css +113 -0
- package/dist/styles/themes/violet.css +68 -0
- package/dist/styles/themes/yellow.css +68 -0
- package/package.json +97 -0
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { cva } from "class-variance-authority";
|
|
5
|
+
import { endOfDay, endOfMonth, endOfWeek, endOfYear, startOfDay, startOfMonth, startOfWeek, startOfYear, subDays, } from "date-fns";
|
|
6
|
+
import { formatInTimeZone, toDate } from "date-fns-tz";
|
|
7
|
+
import { CalendarIcon } from "lucide-react";
|
|
8
|
+
import { Button } from "@forthtilliath/shadcn-ui/components/button";
|
|
9
|
+
import { Calendar } from "@forthtilliath/shadcn-ui/components/calendar";
|
|
10
|
+
import { Popover, PopoverContent, PopoverTrigger, } from "@forthtilliath/shadcn-ui/components/popover";
|
|
11
|
+
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@forthtilliath/shadcn-ui/components/select";
|
|
12
|
+
import { cn } from "@forthtilliath/shadcn-ui/lib/utils";
|
|
13
|
+
const months = [
|
|
14
|
+
"January",
|
|
15
|
+
"February",
|
|
16
|
+
"March",
|
|
17
|
+
"April",
|
|
18
|
+
"May",
|
|
19
|
+
"June",
|
|
20
|
+
"July",
|
|
21
|
+
"August",
|
|
22
|
+
"September",
|
|
23
|
+
"October",
|
|
24
|
+
"November",
|
|
25
|
+
"December",
|
|
26
|
+
];
|
|
27
|
+
const multiSelectVariants = cva("flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium text-foreground ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", {
|
|
28
|
+
variants: {
|
|
29
|
+
variant: {
|
|
30
|
+
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
|
31
|
+
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
|
32
|
+
outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
|
|
33
|
+
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
34
|
+
ghost: "hover:bg-accent hover:text-accent-foreground text-background",
|
|
35
|
+
link: " underline-offset-4 hover:underline text-background",
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
defaultVariants: {
|
|
39
|
+
variant: "default",
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
export function CalendarDatePicker({ id = "calendar-date-picker", className, date, closeOnSelect = false, numberOfMonths = 2, yearsRange = 10, onDateSelect, variant, ref, ...props }) {
|
|
43
|
+
const [isPopoverOpen, setIsPopoverOpen] = React.useState(false);
|
|
44
|
+
const [selectedRange, setSelectedRange] = React.useState(numberOfMonths === 2 ? "This Year" : "Today");
|
|
45
|
+
const [monthFrom, setMonthFrom] = React.useState(date.from);
|
|
46
|
+
const [yearFrom, setYearFrom] = React.useState(date.from?.getFullYear());
|
|
47
|
+
const [monthTo, setMonthTo] = React.useState(numberOfMonths === 2 ? date.to : date.from);
|
|
48
|
+
const [yearTo, setYearTo] = React.useState(numberOfMonths === 2 ? date.to?.getFullYear() : date.from?.getFullYear());
|
|
49
|
+
const [highlightedPart, setHighlightedPart] = React.useState(null);
|
|
50
|
+
const timeZone = React.useMemo(() => Intl.DateTimeFormat().resolvedOptions().timeZone, []);
|
|
51
|
+
// `new Date()` is impure, so it's seeded once via useState's lazy
|
|
52
|
+
// initializer (mount time) rather than recomputed directly during render.
|
|
53
|
+
const [today] = React.useState(() => new Date());
|
|
54
|
+
const years = Array.from({ length: yearsRange + 1 }, (_, i) => today.getFullYear() - yearsRange / 2 + i);
|
|
55
|
+
const handleClose = () => {
|
|
56
|
+
setIsPopoverOpen(false);
|
|
57
|
+
};
|
|
58
|
+
const handleTogglePopover = () => {
|
|
59
|
+
setIsPopoverOpen((prev) => !prev);
|
|
60
|
+
};
|
|
61
|
+
const selectDateRange = (from, to, range) => {
|
|
62
|
+
const startDate = startOfDay(toDate(from, { timeZone }));
|
|
63
|
+
const endDate = numberOfMonths === 2 ? endOfDay(toDate(to, { timeZone })) : startDate;
|
|
64
|
+
onDateSelect({ from: startDate, to: endDate });
|
|
65
|
+
setSelectedRange(range);
|
|
66
|
+
setMonthFrom(from);
|
|
67
|
+
setYearFrom(from.getFullYear());
|
|
68
|
+
setMonthTo(to);
|
|
69
|
+
setYearTo(to.getFullYear());
|
|
70
|
+
if (closeOnSelect)
|
|
71
|
+
setIsPopoverOpen(false);
|
|
72
|
+
};
|
|
73
|
+
const handleDateSelect = (range) => {
|
|
74
|
+
if (range?.from) {
|
|
75
|
+
let from = startOfDay(toDate(range.from, { timeZone }));
|
|
76
|
+
let to = range.to ? endOfDay(toDate(range.to, { timeZone })) : from;
|
|
77
|
+
if (numberOfMonths === 1) {
|
|
78
|
+
if (range.from !== date.from) {
|
|
79
|
+
to = from;
|
|
80
|
+
}
|
|
81
|
+
else if (range.to) {
|
|
82
|
+
from = startOfDay(toDate(range.to, { timeZone }));
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
onDateSelect({ from, to });
|
|
86
|
+
setMonthFrom(from);
|
|
87
|
+
setYearFrom(from.getFullYear());
|
|
88
|
+
setMonthTo(to);
|
|
89
|
+
setYearTo(to.getFullYear());
|
|
90
|
+
}
|
|
91
|
+
setSelectedRange(null);
|
|
92
|
+
};
|
|
93
|
+
const handleMonthChange = React.useCallback((newMonthIndex, part) => {
|
|
94
|
+
setSelectedRange(null);
|
|
95
|
+
if (part === "from") {
|
|
96
|
+
if (yearFrom !== undefined) {
|
|
97
|
+
if (newMonthIndex < 0 || newMonthIndex > yearsRange + 1)
|
|
98
|
+
return;
|
|
99
|
+
const newMonth = new Date(yearFrom, newMonthIndex, 1);
|
|
100
|
+
const from = numberOfMonths === 2
|
|
101
|
+
? startOfMonth(toDate(newMonth, { timeZone }))
|
|
102
|
+
: date.from
|
|
103
|
+
? new Date(date.from.getFullYear(), newMonth.getMonth(), date.from.getDate())
|
|
104
|
+
: newMonth;
|
|
105
|
+
const to = numberOfMonths === 2
|
|
106
|
+
? date.to
|
|
107
|
+
? endOfDay(toDate(date.to, { timeZone }))
|
|
108
|
+
: endOfMonth(toDate(newMonth, { timeZone }))
|
|
109
|
+
: from;
|
|
110
|
+
if (from <= to) {
|
|
111
|
+
onDateSelect({ from, to });
|
|
112
|
+
setMonthFrom(newMonth);
|
|
113
|
+
setMonthTo(date.to);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
if (yearTo !== undefined) {
|
|
119
|
+
if (newMonthIndex < 0 || newMonthIndex > yearsRange + 1)
|
|
120
|
+
return;
|
|
121
|
+
const newMonth = new Date(yearTo, newMonthIndex, 1);
|
|
122
|
+
const from = date.from
|
|
123
|
+
? startOfDay(toDate(date.from, { timeZone }))
|
|
124
|
+
: startOfMonth(toDate(newMonth, { timeZone }));
|
|
125
|
+
const to = numberOfMonths === 2
|
|
126
|
+
? endOfMonth(toDate(newMonth, { timeZone }))
|
|
127
|
+
: from;
|
|
128
|
+
if (from <= to) {
|
|
129
|
+
onDateSelect({ from, to });
|
|
130
|
+
setMonthTo(newMonth);
|
|
131
|
+
setMonthFrom(date.from);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}, [
|
|
136
|
+
date,
|
|
137
|
+
numberOfMonths,
|
|
138
|
+
timeZone,
|
|
139
|
+
yearFrom,
|
|
140
|
+
yearTo,
|
|
141
|
+
yearsRange,
|
|
142
|
+
onDateSelect,
|
|
143
|
+
]);
|
|
144
|
+
const handleYearChange = React.useCallback((newYear, part) => {
|
|
145
|
+
setSelectedRange(null);
|
|
146
|
+
if (part === "from") {
|
|
147
|
+
if (years.includes(newYear)) {
|
|
148
|
+
const newMonth = monthFrom
|
|
149
|
+
? new Date(newYear, monthFrom.getMonth(), 1)
|
|
150
|
+
: new Date(newYear, 0, 1);
|
|
151
|
+
const from = numberOfMonths === 2
|
|
152
|
+
? startOfMonth(toDate(newMonth, { timeZone }))
|
|
153
|
+
: date.from
|
|
154
|
+
? new Date(newYear, newMonth.getMonth(), date.from.getDate())
|
|
155
|
+
: newMonth;
|
|
156
|
+
const to = numberOfMonths === 2
|
|
157
|
+
? date.to
|
|
158
|
+
? endOfDay(toDate(date.to, { timeZone }))
|
|
159
|
+
: endOfMonth(toDate(newMonth, { timeZone }))
|
|
160
|
+
: from;
|
|
161
|
+
if (from <= to) {
|
|
162
|
+
onDateSelect({ from, to });
|
|
163
|
+
setYearFrom(newYear);
|
|
164
|
+
setMonthFrom(newMonth);
|
|
165
|
+
setYearTo(date.to?.getFullYear());
|
|
166
|
+
setMonthTo(date.to);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
if (years.includes(newYear)) {
|
|
172
|
+
const newMonth = monthTo
|
|
173
|
+
? new Date(newYear, monthTo.getMonth(), 1)
|
|
174
|
+
: new Date(newYear, 0, 1);
|
|
175
|
+
const from = date.from
|
|
176
|
+
? startOfDay(toDate(date.from, { timeZone }))
|
|
177
|
+
: startOfMonth(toDate(newMonth, { timeZone }));
|
|
178
|
+
const to = numberOfMonths === 2
|
|
179
|
+
? endOfMonth(toDate(newMonth, { timeZone }))
|
|
180
|
+
: from;
|
|
181
|
+
if (from <= to) {
|
|
182
|
+
onDateSelect({ from, to });
|
|
183
|
+
setYearTo(newYear);
|
|
184
|
+
setMonthTo(newMonth);
|
|
185
|
+
setYearFrom(date.from?.getFullYear());
|
|
186
|
+
setMonthFrom(date.from);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}, [date, numberOfMonths, timeZone, monthFrom, monthTo, years, onDateSelect]);
|
|
191
|
+
const dateRanges = [
|
|
192
|
+
{ label: "Today", start: today, end: today },
|
|
193
|
+
{ label: "Yesterday", start: subDays(today, 1), end: subDays(today, 1) },
|
|
194
|
+
{
|
|
195
|
+
label: "This Week",
|
|
196
|
+
start: startOfWeek(today, { weekStartsOn: 1 }),
|
|
197
|
+
end: endOfWeek(today, { weekStartsOn: 1 }),
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
label: "Last Week",
|
|
201
|
+
start: subDays(startOfWeek(today, { weekStartsOn: 1 }), 7),
|
|
202
|
+
end: subDays(endOfWeek(today, { weekStartsOn: 1 }), 7),
|
|
203
|
+
},
|
|
204
|
+
{ label: "Last 7 Days", start: subDays(today, 6), end: today },
|
|
205
|
+
{
|
|
206
|
+
label: "This Month",
|
|
207
|
+
start: startOfMonth(today),
|
|
208
|
+
end: endOfMonth(today),
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
label: "Last Month",
|
|
212
|
+
start: startOfMonth(subDays(today, today.getDate())),
|
|
213
|
+
end: endOfMonth(subDays(today, today.getDate())),
|
|
214
|
+
},
|
|
215
|
+
{ label: "This Year", start: startOfYear(today), end: endOfYear(today) },
|
|
216
|
+
{
|
|
217
|
+
label: "Last Year",
|
|
218
|
+
start: startOfYear(subDays(today, 365)),
|
|
219
|
+
end: endOfYear(subDays(today, 365)),
|
|
220
|
+
},
|
|
221
|
+
];
|
|
222
|
+
const handleMouseOver = (part) => {
|
|
223
|
+
setHighlightedPart(part);
|
|
224
|
+
};
|
|
225
|
+
const handleMouseLeave = () => {
|
|
226
|
+
setHighlightedPart(null);
|
|
227
|
+
};
|
|
228
|
+
// Wired up via a native `addEventListener` below (not a JSX event prop),
|
|
229
|
+
// which never passes a second argument, so there's no "part" parameter —
|
|
230
|
+
// the branch to act on comes from `highlightedPart` state instead.
|
|
231
|
+
const handleWheel = React.useCallback((event) => {
|
|
232
|
+
if (!date.from || !date.to)
|
|
233
|
+
return;
|
|
234
|
+
const from = date.from;
|
|
235
|
+
const to = date.to;
|
|
236
|
+
event.preventDefault();
|
|
237
|
+
setSelectedRange(null);
|
|
238
|
+
if (highlightedPart === "firstDay") {
|
|
239
|
+
const newDate = new Date(from);
|
|
240
|
+
const increment = event.deltaY > 0 ? -1 : 1;
|
|
241
|
+
newDate.setDate(newDate.getDate() + increment);
|
|
242
|
+
if (newDate <= to) {
|
|
243
|
+
if (numberOfMonths === 2) {
|
|
244
|
+
onDateSelect({ from: newDate, to: new Date(to) });
|
|
245
|
+
}
|
|
246
|
+
else {
|
|
247
|
+
onDateSelect({ from: newDate, to: newDate });
|
|
248
|
+
}
|
|
249
|
+
setMonthFrom(newDate);
|
|
250
|
+
}
|
|
251
|
+
else if (newDate > to && numberOfMonths === 1) {
|
|
252
|
+
onDateSelect({ from: newDate, to: newDate });
|
|
253
|
+
setMonthFrom(newDate);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
else if (highlightedPart === "firstMonth") {
|
|
257
|
+
const currentMonth = monthFrom ? monthFrom.getMonth() : 0;
|
|
258
|
+
const newMonthIndex = currentMonth + (event.deltaY > 0 ? -1 : 1);
|
|
259
|
+
handleMonthChange(newMonthIndex, "from");
|
|
260
|
+
}
|
|
261
|
+
else if (highlightedPart === "firstYear" && yearFrom !== undefined) {
|
|
262
|
+
const newYear = yearFrom + (event.deltaY > 0 ? -1 : 1);
|
|
263
|
+
handleYearChange(newYear, "from");
|
|
264
|
+
}
|
|
265
|
+
else if (highlightedPart === "secondDay") {
|
|
266
|
+
const newDate = new Date(to);
|
|
267
|
+
const increment = event.deltaY > 0 ? -1 : 1;
|
|
268
|
+
newDate.setDate(newDate.getDate() + increment);
|
|
269
|
+
if (newDate >= from) {
|
|
270
|
+
onDateSelect({ from: new Date(from), to: newDate });
|
|
271
|
+
setMonthTo(newDate);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
else if (highlightedPart === "secondMonth") {
|
|
275
|
+
const currentMonth = monthTo ? monthTo.getMonth() : 0;
|
|
276
|
+
const newMonthIndex = currentMonth + (event.deltaY > 0 ? -1 : 1);
|
|
277
|
+
handleMonthChange(newMonthIndex, "to");
|
|
278
|
+
}
|
|
279
|
+
else if (highlightedPart === "secondYear" && yearTo !== undefined) {
|
|
280
|
+
const newYear = yearTo + (event.deltaY > 0 ? -1 : 1);
|
|
281
|
+
handleYearChange(newYear, "to");
|
|
282
|
+
}
|
|
283
|
+
}, [
|
|
284
|
+
date,
|
|
285
|
+
highlightedPart,
|
|
286
|
+
numberOfMonths,
|
|
287
|
+
monthFrom,
|
|
288
|
+
monthTo,
|
|
289
|
+
yearFrom,
|
|
290
|
+
yearTo,
|
|
291
|
+
onDateSelect,
|
|
292
|
+
handleMonthChange,
|
|
293
|
+
handleYearChange,
|
|
294
|
+
]);
|
|
295
|
+
React.useEffect(() => {
|
|
296
|
+
const firstDayElement = document.getElementById(`firstDay-${id}`);
|
|
297
|
+
const firstMonthElement = document.getElementById(`firstMonth-${id}`);
|
|
298
|
+
const firstYearElement = document.getElementById(`firstYear-${id}`);
|
|
299
|
+
const secondDayElement = document.getElementById(`secondDay-${id}`);
|
|
300
|
+
const secondMonthElement = document.getElementById(`secondMonth-${id}`);
|
|
301
|
+
const secondYearElement = document.getElementById(`secondYear-${id}`);
|
|
302
|
+
const elements = [
|
|
303
|
+
firstDayElement,
|
|
304
|
+
firstMonthElement,
|
|
305
|
+
firstYearElement,
|
|
306
|
+
secondDayElement,
|
|
307
|
+
secondMonthElement,
|
|
308
|
+
secondYearElement,
|
|
309
|
+
];
|
|
310
|
+
const addPassiveEventListener = (element) => {
|
|
311
|
+
if (element) {
|
|
312
|
+
element.addEventListener("wheel", handleWheel, {
|
|
313
|
+
passive: false,
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
};
|
|
317
|
+
elements.forEach(addPassiveEventListener);
|
|
318
|
+
return () => {
|
|
319
|
+
elements.forEach((element) => {
|
|
320
|
+
if (element) {
|
|
321
|
+
element.removeEventListener("wheel", handleWheel);
|
|
322
|
+
}
|
|
323
|
+
});
|
|
324
|
+
};
|
|
325
|
+
}, [highlightedPart, date, id, handleWheel]);
|
|
326
|
+
const formatWithTz = (date, fmt) => formatInTimeZone(date, timeZone, fmt);
|
|
327
|
+
return (_jsxs(_Fragment, { children: [_jsx("style", { children: `
|
|
328
|
+
.date-part {
|
|
329
|
+
touch-action: none;
|
|
330
|
+
}
|
|
331
|
+
` }), _jsxs(Popover, { open: isPopoverOpen, onOpenChange: setIsPopoverOpen, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs(Button, { id: "date", ref: ref, ...props, className: cn("w-auto", multiSelectVariants({ variant, className })), size: "default", onClick: handleTogglePopover, suppressHydrationWarning: true, children: [_jsx(CalendarIcon, { className: "mr-2 h-4 w-4" }), _jsx("span", { children: date.from ? (date.to ? (_jsxs(_Fragment, { children: [_jsx("span", { id: `firstDay-${id}`, className: cn("date-part", highlightedPart === "firstDay" && "underline font-bold"), onMouseOver: () => {
|
|
332
|
+
handleMouseOver("firstDay");
|
|
333
|
+
}, onMouseLeave: handleMouseLeave, children: formatWithTz(date.from, "dd") }), " ", _jsx("span", { id: `firstMonth-${id}`, className: cn("date-part", highlightedPart === "firstMonth" &&
|
|
334
|
+
"underline font-bold"), onMouseOver: () => {
|
|
335
|
+
handleMouseOver("firstMonth");
|
|
336
|
+
}, onMouseLeave: handleMouseLeave, children: formatWithTz(date.from, "LLL") }), ",", " ", _jsx("span", { id: `firstYear-${id}`, className: cn("date-part", highlightedPart === "firstYear" &&
|
|
337
|
+
"underline font-bold"), onMouseOver: () => {
|
|
338
|
+
handleMouseOver("firstYear");
|
|
339
|
+
}, onMouseLeave: handleMouseLeave, children: formatWithTz(date.from, "y") }), numberOfMonths === 2 && (_jsxs(_Fragment, { children: [" - ", _jsx("span", { id: `secondDay-${id}`, className: cn("date-part", highlightedPart === "secondDay" &&
|
|
340
|
+
"underline font-bold"), onMouseOver: () => {
|
|
341
|
+
handleMouseOver("secondDay");
|
|
342
|
+
}, onMouseLeave: handleMouseLeave, children: formatWithTz(date.to, "dd") }), " ", _jsx("span", { id: `secondMonth-${id}`, className: cn("date-part", highlightedPart === "secondMonth" &&
|
|
343
|
+
"underline font-bold"), onMouseOver: () => {
|
|
344
|
+
handleMouseOver("secondMonth");
|
|
345
|
+
}, onMouseLeave: handleMouseLeave, children: formatWithTz(date.to, "LLL") }), ",", " ", _jsx("span", { id: `secondYear-${id}`, className: cn("date-part", highlightedPart === "secondYear" &&
|
|
346
|
+
"underline font-bold"), onMouseOver: () => {
|
|
347
|
+
handleMouseOver("secondYear");
|
|
348
|
+
}, onMouseLeave: handleMouseLeave, children: formatWithTz(date.to, "y") })] }))] })) : (_jsxs(_Fragment, { children: [_jsx("span", { id: "day", className: cn("date-part", highlightedPart === "day" && "underline font-bold"), onMouseOver: () => {
|
|
349
|
+
handleMouseOver("day");
|
|
350
|
+
}, onMouseLeave: handleMouseLeave, children: formatWithTz(date.from, "dd") }), " ", _jsx("span", { id: "month", className: cn("date-part", highlightedPart === "month" && "underline font-bold"), onMouseOver: () => {
|
|
351
|
+
handleMouseOver("month");
|
|
352
|
+
}, onMouseLeave: handleMouseLeave, children: formatWithTz(date.from, "LLL") }), ",", " ", _jsx("span", { id: "year", className: cn("date-part", highlightedPart === "year" && "underline font-bold"), onMouseOver: () => {
|
|
353
|
+
handleMouseOver("year");
|
|
354
|
+
}, onMouseLeave: handleMouseLeave, children: formatWithTz(date.from, "y") })] }))) : (_jsx("span", { children: "Select a date" })) })] }) }), isPopoverOpen && (_jsx(PopoverContent, { className: "w-auto", align: "start", avoidCollisions: false, onInteractOutside: handleClose, onEscapeKeyDown: handleClose, style: {
|
|
355
|
+
maxHeight: "var(--radix-popover-content-available-height)",
|
|
356
|
+
overflowY: "auto",
|
|
357
|
+
}, children: _jsxs("div", { className: "flex", children: [numberOfMonths === 2 && (_jsx("div", { className: "flex flex-col gap-1 pr-4 text-left border-r border-foreground/10", children: dateRanges.map(({ label, start, end }) => (_jsx(Button, { variant: "ghost", size: "default", className: cn("justify-start hover:bg-primary/90 hover:text-background", selectedRange === label &&
|
|
358
|
+
"bg-primary text-background hover:bg-primary/90 hover:text-background"), onClick: () => {
|
|
359
|
+
selectDateRange(start, end, label);
|
|
360
|
+
setMonthFrom(start);
|
|
361
|
+
setYearFrom(start.getFullYear());
|
|
362
|
+
setMonthTo(end);
|
|
363
|
+
setYearTo(end.getFullYear());
|
|
364
|
+
}, children: label }, label))) })), _jsxs("div", { className: "flex flex-col", children: [_jsxs("div", { className: "flex items-center gap-4", children: [_jsxs("div", { className: "flex gap-2 ml-3", children: [_jsxs(Select, { onValueChange: (value) => {
|
|
365
|
+
handleMonthChange(months.indexOf(value), "from");
|
|
366
|
+
setSelectedRange(null);
|
|
367
|
+
}, value: monthFrom ? months[monthFrom.getMonth()] : undefined, children: [_jsx(SelectTrigger, { className: "w-[122px] focus:ring-0 focus:ring-offset-0 font-medium hover:bg-accent hover:text-accent-foreground", children: _jsx(SelectValue, { placeholder: "Month" }) }), _jsx(SelectContent, { children: months.map((month, idx) => (_jsx(SelectItem, { value: month, children: month }, idx))) })] }), _jsxs(Select, { onValueChange: (value) => {
|
|
368
|
+
handleYearChange(Number(value), "from");
|
|
369
|
+
setSelectedRange(null);
|
|
370
|
+
}, value: yearFrom ? yearFrom.toString() : undefined, children: [_jsx(SelectTrigger, { className: "w-[122px] focus:ring-0 focus:ring-offset-0 font-medium hover:bg-accent hover:text-accent-foreground", children: _jsx(SelectValue, { placeholder: "Year" }) }), _jsx(SelectContent, { children: years.map((year, idx) => (_jsx(SelectItem, { value: year.toString(), children: year }, idx))) })] })] }), numberOfMonths === 2 && (_jsxs("div", { className: "flex gap-2", children: [_jsxs(Select, { onValueChange: (value) => {
|
|
371
|
+
handleMonthChange(months.indexOf(value), "to");
|
|
372
|
+
setSelectedRange(null);
|
|
373
|
+
}, value: monthTo ? months[monthTo.getMonth()] : undefined, children: [_jsx(SelectTrigger, { className: "w-[122px] focus:ring-0 focus:ring-offset-0 font-medium hover:bg-accent hover:text-accent-foreground", children: _jsx(SelectValue, { placeholder: "Month" }) }), _jsx(SelectContent, { children: months.map((month, idx) => (_jsx(SelectItem, { value: month, children: month }, idx))) })] }), _jsxs(Select, { onValueChange: (value) => {
|
|
374
|
+
handleYearChange(Number(value), "to");
|
|
375
|
+
setSelectedRange(null);
|
|
376
|
+
}, value: yearTo ? yearTo.toString() : undefined, children: [_jsx(SelectTrigger, { className: "w-[122px] focus:ring-0 focus:ring-offset-0 font-medium hover:bg-accent hover:text-accent-foreground", children: _jsx(SelectValue, { placeholder: "Year" }) }), _jsx(SelectContent, { children: years.map((year, idx) => (_jsx(SelectItem, { value: year.toString(), children: year }, idx))) })] })] }))] }), _jsx("div", { className: "flex", children: _jsx(Calendar, { mode: "range", defaultMonth: monthFrom, month: monthFrom, onMonthChange: setMonthFrom, selected: date, onSelect: handleDateSelect, numberOfMonths: numberOfMonths, showOutsideDays: false, className: className }) })] })] }) }))] })] }));
|
|
377
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Table } from "@tanstack/react-table";
|
|
2
|
+
interface DataTablePaginationProps<TData> {
|
|
3
|
+
table: Table<TData>;
|
|
4
|
+
totalItems?: number;
|
|
5
|
+
totalSelectedItems?: number;
|
|
6
|
+
pageSizeOptions?: number[];
|
|
7
|
+
size?: "sm" | "default" | "lg";
|
|
8
|
+
}
|
|
9
|
+
export declare function DataTablePagination<TData>({ table, totalItems, totalSelectedItems, pageSizeOptions, // Default options if none provided
|
|
10
|
+
size, }: DataTablePaginationProps<TData>): import("react").JSX.Element;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=pagination.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pagination.d.ts","sourceRoot":"","sources":["../../../../src/components/blocks/data-table-ext/pagination.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAsBnD,UAAU,wBAAwB,CAAC,KAAK;IACtC,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,IAAI,CAAC,EAAE,IAAI,GAAG,SAAS,GAAG,IAAI,CAAC;CAChC;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,EACzC,KAAK,EACL,UAAc,EACd,kBAAsB,EACtB,eAAsC,EAAE,mCAAmC;AAC3E,IAAgB,GACjB,EAAE,wBAAwB,CAAC,KAAK,CAAC,+BA0HjC"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { ChevronLeftIcon, ChevronRightIcon, DoubleArrowLeftIcon, DoubleArrowRightIcon, } from "@radix-ui/react-icons";
|
|
4
|
+
import { Button } from "@forthtilliath/shadcn-ui/components/button";
|
|
5
|
+
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@forthtilliath/shadcn-ui/components/select";
|
|
6
|
+
const getButtonSizeClass = (size) => {
|
|
7
|
+
switch (size) {
|
|
8
|
+
case "sm":
|
|
9
|
+
return "h-7 w-7 p-0";
|
|
10
|
+
case "lg":
|
|
11
|
+
return "h-11 w-11 p-0";
|
|
12
|
+
default:
|
|
13
|
+
return "h-8 w-8 p-0";
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
export function DataTablePagination({ table, totalItems = 0, totalSelectedItems = 0, pageSizeOptions = [10, 20, 30, 40, 50], // Default options if none provided
|
|
17
|
+
size = "default", }) {
|
|
18
|
+
// Convert 'lg' size to 'default' for SelectTrigger since it only accepts 'sm' | 'default'
|
|
19
|
+
const selectSize = size === "lg" ? "default" : size;
|
|
20
|
+
return (_jsxs("div", { className: "flex w-full flex-col items-center justify-between gap-4 overflow-auto px-2 py-1 sm:flex-row sm:gap-8", children: [_jsxs("div", { className: "flex-1 text-sm text-muted-foreground", children: [totalSelectedItems, " of ", totalItems, " row(s) selected."] }), _jsxs("div", { className: "flex flex-col items-center gap-4 sm:flex-row sm:gap-6 lg:gap-8", children: [_jsxs("div", { className: "flex items-center space-x-2", children: [_jsx("p", { className: "whitespace-nowrap text-sm font-medium", children: "Rows per page" }), _jsxs(Select, { value: table.getState().pagination.pageSize.toString(), onValueChange: (value) => {
|
|
21
|
+
// Validate the input value
|
|
22
|
+
const numericValue = parseInt(value, 10);
|
|
23
|
+
if (isNaN(numericValue) || numericValue <= 0) {
|
|
24
|
+
console.error(`Invalid page size value: ${value}`);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
try {
|
|
28
|
+
// Force URL update via direct window manipulation first
|
|
29
|
+
// This ensures the URL gets updated before the table state changes
|
|
30
|
+
const url = new URL(window.location.href);
|
|
31
|
+
url.searchParams.set("pageSize", value);
|
|
32
|
+
url.searchParams.set("page", "1"); // Always reset to page 1
|
|
33
|
+
window.history.replaceState({}, "", url.toString());
|
|
34
|
+
// Then use the table's pagination change handler to update table state
|
|
35
|
+
// This order ensures the URL is already set when the table state updates
|
|
36
|
+
table.setPagination({
|
|
37
|
+
pageIndex: 0, // Reset to first page
|
|
38
|
+
pageSize: numericValue,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
console.error("Error updating pagination:", error);
|
|
43
|
+
}
|
|
44
|
+
}, children: [_jsx(SelectTrigger, { className: "cursor-pointer", size: selectSize, children: _jsx(SelectValue, { placeholder: table.getState().pagination.pageSize }) }), _jsx(SelectContent, { side: "top", className: "cursor-pointer", children: pageSizeOptions.map((pageSize) => (_jsx(SelectItem, { value: pageSize.toString(), className: "cursor-pointer", children: pageSize }, pageSize))) })] })] }), _jsxs("div", { className: "flex items-center justify-center text-sm font-medium", children: ["Page ", table.getState().pagination.pageIndex + 1, " of", " ", table.getPageCount() || 1] }), _jsxs("div", { className: "flex items-center space-x-2", children: [_jsx(Button, { "aria-label": "Go to first page", variant: "outline", className: `${getButtonSizeClass(size)} hidden lg:flex cursor-pointer`, onClick: () => {
|
|
45
|
+
table.setPagination({
|
|
46
|
+
pageIndex: 0,
|
|
47
|
+
pageSize: table.getState().pagination.pageSize,
|
|
48
|
+
});
|
|
49
|
+
}, disabled: !table.getCanPreviousPage(), children: _jsx(DoubleArrowLeftIcon, { className: "h-4 w-4", "aria-hidden": "true" }) }), _jsx(Button, { "aria-label": "Go to previous page", variant: "outline", className: `${getButtonSizeClass(size)} cursor-pointer`, onClick: () => {
|
|
50
|
+
table.setPagination({
|
|
51
|
+
pageIndex: table.getState().pagination.pageIndex - 1,
|
|
52
|
+
pageSize: table.getState().pagination.pageSize,
|
|
53
|
+
});
|
|
54
|
+
}, disabled: !table.getCanPreviousPage(), children: _jsx(ChevronLeftIcon, { className: "h-4 w-4", "aria-hidden": "true" }) }), _jsx(Button, { "aria-label": "Go to next page", variant: "outline", className: `${getButtonSizeClass(size)} cursor-pointer`, onClick: () => {
|
|
55
|
+
table.setPagination({
|
|
56
|
+
pageIndex: table.getState().pagination.pageIndex + 1,
|
|
57
|
+
pageSize: table.getState().pagination.pageSize,
|
|
58
|
+
});
|
|
59
|
+
}, disabled: !table.getCanNextPage(), children: _jsx(ChevronRightIcon, { className: "h-4 w-4", "aria-hidden": "true" }) }), _jsx(Button, { "aria-label": "Go to last page", variant: "outline", className: `${getButtonSizeClass(size)} hidden lg:flex cursor-pointer`, onClick: () => {
|
|
60
|
+
table.setPagination({
|
|
61
|
+
pageIndex: table.getPageCount() - 1,
|
|
62
|
+
pageSize: table.getState().pagination.pageSize,
|
|
63
|
+
});
|
|
64
|
+
}, disabled: !table.getCanNextPage(), children: _jsx(DoubleArrowRightIcon, { className: "h-4 w-4", "aria-hidden": "true" }) })] })] })] }));
|
|
65
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Table configuration options
|
|
3
|
+
* This file provides centralized configuration for the data table features
|
|
4
|
+
*/
|
|
5
|
+
export interface TableConfig {
|
|
6
|
+
enablePagination: boolean;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Provides table configuration, merging in any overrides.
|
|
10
|
+
*
|
|
11
|
+
* Not a hook (calls no hooks internally) despite the data it computes being
|
|
12
|
+
* hook-shaped — renamed off the `use` prefix so tooling doesn't treat it as
|
|
13
|
+
* one.
|
|
14
|
+
*/
|
|
15
|
+
export declare function getTableConfig(overrideConfig?: Partial<TableConfig>): TableConfig;
|
|
16
|
+
//# sourceMappingURL=table-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"table-config.d.ts","sourceRoot":"","sources":["../../../../../src/components/blocks/data-table-ext/utils/table-config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,WAAW,WAAW;IAW1B,gBAAgB,EAAE,OAAO,CAAC;CAqC3B;AAqBD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,cAAc,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,GACpC,WAAW,CAEb"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// Default configuration
|
|
2
|
+
const defaultConfig = {
|
|
3
|
+
// enableRowSelection: true, // Row selection enabled by default
|
|
4
|
+
// enableKeyboardNavigation: false, // Keyboard navigation disabled by default
|
|
5
|
+
// enableClickRowSelect: false, // Clicking row to select disabled by default
|
|
6
|
+
enablePagination: true, // Pagination enabled by default
|
|
7
|
+
// enableSearch: true, // Search enabled by default
|
|
8
|
+
// enableColumnFilters: true, // Column filters enabled by default
|
|
9
|
+
// enableDateFilter: true, // Date filter enabled by default
|
|
10
|
+
// enableColumnVisibility: true, // Column visibility options enabled by default
|
|
11
|
+
// enableExport: true, // Data export enabled by default
|
|
12
|
+
// enableUrlState: true, // URL state persistence enabled by default
|
|
13
|
+
// enableColumnResizing: true, // Column resizing enabled by default
|
|
14
|
+
// enableToolbar: true, // Toolbar enabled by default
|
|
15
|
+
// size: "default", // Default size for buttons and inputs
|
|
16
|
+
// columnResizingTableId: undefined, // No table ID by default
|
|
17
|
+
// searchPlaceholder: undefined, // No custom search placeholder by default
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Provides table configuration, merging in any overrides.
|
|
21
|
+
*
|
|
22
|
+
* Not a hook (calls no hooks internally) despite the data it computes being
|
|
23
|
+
* hook-shaped — renamed off the `use` prefix so tooling doesn't treat it as
|
|
24
|
+
* one.
|
|
25
|
+
*/
|
|
26
|
+
export function getTableConfig(overrideConfig) {
|
|
27
|
+
return { ...defaultConfig, ...overrideConfig };
|
|
28
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { type ColumnDef } from "@tanstack/react-table";
|
|
3
|
+
import { type TableConfig } from "./data-table-ext/utils/table-config";
|
|
4
|
+
export interface Props<T> {
|
|
5
|
+
columns: ColumnDef<T>[];
|
|
6
|
+
data: T[];
|
|
7
|
+
config?: Partial<TableConfig>;
|
|
8
|
+
}
|
|
9
|
+
export declare function DataTable<T>({ columns, data, config }: Props<T>): React.JSX.Element;
|
|
10
|
+
//# sourceMappingURL=data-table.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data-table.d.ts","sourceRoot":"","sources":["../../../src/components/blocks/data-table.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EACL,KAAK,SAAS,EAUf,MAAM,uBAAuB,CAAC;AAqB/B,OAAO,EAEL,KAAK,WAAW,EACjB,MAAM,qCAAqC,CAAC;AAE7C,MAAM,WAAW,KAAK,CAAC,CAAC;IACtB,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;IACxB,IAAI,EAAE,CAAC,EAAE,CAAC;IACV,MAAM,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;CAC/B;AAED,wBAAgB,SAAS,CAAC,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC,qBAiJ/D"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { flexRender, getCoreRowModel, getFilteredRowModel, getPaginationRowModel, getSortedRowModel, useReactTable, } from "@tanstack/react-table";
|
|
5
|
+
import { ChevronDown } from "lucide-react";
|
|
6
|
+
import { Button } from "@forthtilliath/shadcn-ui/components/button";
|
|
7
|
+
import { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuTrigger, } from "@forthtilliath/shadcn-ui/components/dropdown-menu";
|
|
8
|
+
import { Input } from "@forthtilliath/shadcn-ui/components/input";
|
|
9
|
+
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@forthtilliath/shadcn-ui/components/table";
|
|
10
|
+
import { DataTablePagination } from "./data-table-ext/pagination";
|
|
11
|
+
import { getTableConfig, } from "./data-table-ext/utils/table-config";
|
|
12
|
+
export function DataTable({ columns, data, config }) {
|
|
13
|
+
"use no memo";
|
|
14
|
+
// TanStack Table's useReactTable() returns functions that can't be safely
|
|
15
|
+
// memoized by the React Compiler (an upstream, documented limitation) —
|
|
16
|
+
// opt this component out of compiler memoization rather than let it skip
|
|
17
|
+
// silently.
|
|
18
|
+
const tableConfig = getTableConfig(config);
|
|
19
|
+
const [sorting, setSorting] = React.useState([]);
|
|
20
|
+
const [columnFilters, setColumnFilters] = React.useState([]);
|
|
21
|
+
const [columnVisibility, setColumnVisibility] = React.useState({});
|
|
22
|
+
const [rowSelection, setRowSelection] = React.useState({});
|
|
23
|
+
// TanStack Table's useReactTable() is a documented, upstream React
|
|
24
|
+
// Compiler incompatibility (it returns functions the compiler can't
|
|
25
|
+
// memoize safely) — not something fixable here; the "use no memo"
|
|
26
|
+
// directive above already opts this component out of compiler
|
|
27
|
+
// memoization, so this is expected, not a bug.
|
|
28
|
+
// eslint-disable-next-line react-hooks/incompatible-library
|
|
29
|
+
const table = useReactTable({
|
|
30
|
+
data,
|
|
31
|
+
columns,
|
|
32
|
+
onSortingChange: setSorting,
|
|
33
|
+
onColumnFiltersChange: setColumnFilters,
|
|
34
|
+
getCoreRowModel: getCoreRowModel(),
|
|
35
|
+
getPaginationRowModel: getPaginationRowModel(),
|
|
36
|
+
getSortedRowModel: getSortedRowModel(),
|
|
37
|
+
getFilteredRowModel: getFilteredRowModel(),
|
|
38
|
+
onColumnVisibilityChange: setColumnVisibility,
|
|
39
|
+
onRowSelectionChange: setRowSelection,
|
|
40
|
+
state: {
|
|
41
|
+
sorting,
|
|
42
|
+
columnFilters,
|
|
43
|
+
columnVisibility,
|
|
44
|
+
rowSelection,
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
return (_jsxs("div", { className: "w-full", children: [_jsxs("div", { className: "flex items-center py-4", children: [_jsx(Input, { placeholder: "Filter emails...", value: table.getColumn("email")?.getFilterValue() ?? "", onChange: (event) => table.getColumn("email")?.setFilterValue(event.target.value), className: "max-w-sm" }), _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsxs(Button, { variant: "outline", className: "ml-auto", children: ["Columns ", _jsx(ChevronDown, {})] }) }), _jsx(DropdownMenuContent, { align: "end", children: table
|
|
48
|
+
.getAllColumns()
|
|
49
|
+
.filter((column) => column.getCanHide())
|
|
50
|
+
.map((column) => {
|
|
51
|
+
return (_jsx(DropdownMenuCheckboxItem, { className: "capitalize", checked: column.getIsVisible(), onCheckedChange: (value) => {
|
|
52
|
+
column.toggleVisibility(value);
|
|
53
|
+
}, children: column.id }, column.id));
|
|
54
|
+
}) })] })] }), _jsx("div", { className: "rounded-sm border overflow-hidden", children: _jsxs(Table, { children: [_jsx(TableHeader, { children: table.getHeaderGroups().map((headerGroup) => (_jsx(TableRow, { children: headerGroup.headers.map((header) => {
|
|
55
|
+
return (_jsx(TableHead, { children: header.isPlaceholder
|
|
56
|
+
? null
|
|
57
|
+
: flexRender(header.column.columnDef.header, header.getContext()) }, header.id));
|
|
58
|
+
}) }, headerGroup.id))) }), _jsx(TableBody, { children: table.getRowModel().rows.length ? (table.getRowModel().rows.map((row) => (_jsx(TableRow, { "data-state": row.getIsSelected() && "selected", children: row.getVisibleCells().map((cell) => (_jsx(TableCell, { children: flexRender(cell.column.columnDef.cell, cell.getContext()) }, cell.id))) }, row.id)))) : (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: columns.length, className: "h-24 text-center", children: "No results." }) })) })] }) }), tableConfig.enablePagination && (_jsx(DataTablePagination, { table: table, totalItems: table.getFilteredRowModel().rows.length, totalSelectedItems: table.getFilteredSelectedRowModel().rows.length, pageSizeOptions: [10, 20, 30, 40, 50], size: "sm" }))] }));
|
|
59
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import type { FieldValues, Path, UseFormRegisterReturn } from "react-hook-form";
|
|
3
|
+
type Props<TFieldValues extends FieldValues> = {
|
|
4
|
+
label?: ReactNode | undefined;
|
|
5
|
+
description?: ReactNode | undefined;
|
|
6
|
+
name: Path<TFieldValues>;
|
|
7
|
+
} & UseFormRegisterReturn;
|
|
8
|
+
export declare function Field<TFieldValues extends FieldValues>({ label, description, ...props }: Props<TFieldValues>): import("react").JSX.Element;
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=field.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"field.d.ts","sourceRoot":"","sources":["../../../src/components/blocks/field.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAWhF,KAAK,KAAK,CAAC,YAAY,SAAS,WAAW,IAAI;IAC7C,KAAK,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;IAC9B,WAAW,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;IACpC,IAAI,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;CAC1B,GAAG,qBAAqB,CAAC;AAE1B,wBAAgB,KAAK,CAAC,YAAY,SAAS,WAAW,EAAE,EACtD,KAAK,EACL,WAAW,EACX,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,YAAY,CAAC,+BAoBrB"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, } from "@forthtilliath/shadcn-ui/components/form";
|
|
3
|
+
export function Field({ label, description, ...props }) {
|
|
4
|
+
return (_jsx(FormField, { render: ({ field }) => (_jsxs(FormItem, { children: [_jsx(FormLabel, { children: label }), _jsx(FormControl, { children: _jsx("input", { className: "border-input bg-background w-full rounded-md border px-3 py-2", placeholder: "username", ...field }) }), _jsxs(FormDescription, { children: [description, "."] }), _jsx(FormMessage, {})] })), ...props }));
|
|
5
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type DefaultValues, type FieldValues, type UseFormRegister } from "react-hook-form";
|
|
2
|
+
import type { z } from "zod/v4";
|
|
3
|
+
interface Props<TFieldValues extends FieldValues> {
|
|
4
|
+
schema: z.ZodType<TFieldValues, TFieldValues>;
|
|
5
|
+
defaultValues?: DefaultValues<TFieldValues>;
|
|
6
|
+
onSubmit: (data: TFieldValues) => void;
|
|
7
|
+
className?: string;
|
|
8
|
+
children: ({ register, }: {
|
|
9
|
+
register: UseFormRegister<TFieldValues>;
|
|
10
|
+
}) => React.ReactNode;
|
|
11
|
+
}
|
|
12
|
+
export declare function Form<TFieldValues extends FieldValues>({ children, schema, defaultValues, onSubmit, className, }: Props<TFieldValues>): React.ReactNode;
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=form.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form.d.ts","sourceRoot":"","sources":["../../../src/components/blocks/form.tsx"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,WAAW,EAEhB,KAAK,eAAe,EACrB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,QAAQ,CAAC;AAIhC,UAAU,KAAK,CAAC,YAAY,SAAS,WAAW;IAC9C,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;IAC9C,aAAa,CAAC,EAAE,aAAa,CAAC,YAAY,CAAC,CAAC;IAC5C,QAAQ,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,CAAC,EACT,QAAQ,GACT,EAAE;QACD,QAAQ,EAAE,eAAe,CAAC,YAAY,CAAC,CAAC;KACzC,KAAK,KAAK,CAAC,SAAS,CAAC;CACvB;AAED,wBAAgB,IAAI,CAAC,YAAY,SAAS,WAAW,EAAE,EACrD,QAAQ,EACR,MAAM,EACN,aAAa,EACb,QAAQ,EACR,SAAS,GACV,EAAE,KAAK,CAAC,YAAY,CAAC,GAAG,KAAK,CAAC,SAAS,CAgBvC"}
|