@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.
Files changed (69) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +149 -62
  3. package/dist/api-pagination-CJ0vR_w6.d.mts +34 -0
  4. package/dist/api-pagination-DBTE0yk4.mjs +190 -0
  5. package/dist/chunk-DQk6qfdC.mjs +18 -0
  6. package/dist/client/calendar.d.mts +105 -0
  7. package/dist/client/calendar.mjs +202 -0
  8. package/dist/client/core.d.mts +1614 -0
  9. package/dist/client/core.mjs +2779 -0
  10. package/dist/client/error.d.mts +125 -0
  11. package/dist/client/error.mjs +166 -0
  12. package/dist/client/hooks.d.mts +162 -0
  13. package/dist/client/hooks.mjs +447 -0
  14. package/dist/client/table.d.mts +84 -0
  15. package/dist/client/table.mjs +373 -0
  16. package/dist/client/theme.d.mts +6 -0
  17. package/dist/client/theme.mjs +65 -0
  18. package/dist/command.d.mts +134 -0
  19. package/dist/command.mjs +132 -0
  20. package/dist/compact.d.mts +359 -0
  21. package/dist/compact.mjs +892 -0
  22. package/dist/dashboard.d.mts +778 -0
  23. package/dist/dashboard.mjs +1617 -0
  24. package/dist/filter-utils-DqMmy_v-.mjs +72 -0
  25. package/dist/filter-utils-IZ0GtuPo.d.mts +40 -0
  26. package/dist/forms.d.mts +1549 -0
  27. package/dist/forms.mjs +3740 -0
  28. package/dist/index.d.mts +296 -0
  29. package/dist/index.mjs +432 -0
  30. package/dist/layouts.d.mts +215 -0
  31. package/dist/layouts.mjs +460 -0
  32. package/dist/search-context-DR7DBs7S.mjs +19 -0
  33. package/dist/search.d.mts +254 -0
  34. package/dist/search.mjs +523 -0
  35. package/dist/sheet-wrapper-CWNCvYMD.mjs +211 -0
  36. package/dist/use-base-search-BGgWnWaF.d.mts +35 -0
  37. package/dist/use-debounce-xmZucz5e.mjs +53 -0
  38. package/dist/use-keyboard-shortcut-Bl6YM5Q7.mjs +82 -0
  39. package/dist/use-keyboard-shortcut-_mRCh3QO.d.mts +24 -0
  40. package/dist/use-media-query-BnVNIKT4.mjs +17 -0
  41. package/dist/use-mobile-BX3SQVo2.mjs +20 -0
  42. package/dist/use-scroll-detection-CsgsQYvy.mjs +43 -0
  43. package/dist/utils-CDue7cEt.d.mts +6 -0
  44. package/dist/utils-DQ5SCVoW.mjs +10 -0
  45. package/package.json +85 -45
  46. package/styles.css +2 -2
  47. package/dist/chunk-GUHK2DTW.js +0 -15
  48. package/dist/chunk-GUHK2DTW.js.map +0 -1
  49. package/dist/chunk-H3NFL3GJ.js +0 -57
  50. package/dist/chunk-H3NFL3GJ.js.map +0 -1
  51. package/dist/chunk-J2YRTQE4.js +0 -293
  52. package/dist/chunk-J2YRTQE4.js.map +0 -1
  53. package/dist/compact.d.ts +0 -217
  54. package/dist/compact.js +0 -986
  55. package/dist/compact.js.map +0 -1
  56. package/dist/dashboard.d.ts +0 -386
  57. package/dist/dashboard.js +0 -1032
  58. package/dist/dashboard.js.map +0 -1
  59. package/dist/index.d.ts +0 -2141
  60. package/dist/index.js +0 -6460
  61. package/dist/index.js.map +0 -1
  62. package/dist/layout.d.ts +0 -25
  63. package/dist/layout.js +0 -4
  64. package/dist/layout.js.map +0 -1
  65. package/dist/search.d.ts +0 -172
  66. package/dist/search.js +0 -341
  67. package/dist/search.js.map +0 -1
  68. package/dist/use-base-search-AS5Z3SAy.d.ts +0 -64
  69. package/dist/utils-Cbsgs0XP.d.ts +0 -5
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Classytic
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # @classytic/fluid
2
2
 
3
- Reusable UI components built on shadcn/ui and Base UI for Next.js projects.
3
+ Reusable UI component library built on shadcn/ui and Base UI for Next.js projects.
4
+ Wraps your project's shadcn components (`@/components/ui/*`) with higher-level patterns.
4
5
 
5
6
  ## Install
6
7
 
@@ -8,100 +9,186 @@ Reusable UI components built on shadcn/ui and Base UI for Next.js projects.
8
9
  npm install @classytic/fluid
9
10
  ```
10
11
 
12
+ ## Entry Points
13
+
14
+ | Entry | Purpose | `"use client"` | Requires |
15
+ |-------|---------|:-:|----------|
16
+ | `@classytic/fluid` | RSC-compatible: utils, layout, display, states, skeletons (no `"use client"`) | No | react |
17
+ | `@classytic/fluid/client/hooks` | Hooks + storage utilities | Yes | react, next |
18
+ | `@classytic/fluid/client/core` | Interactive components (dialogs, cards, pills, tabs, animations...) | Yes | react, next |
19
+ | `@classytic/fluid/client/table` | DataTable + DataTableToolbar | Yes | @tanstack/react-table |
20
+ | `@classytic/fluid/client/theme` | ModeToggle | Yes | next-themes |
21
+ | `@classytic/fluid/client/error` | ErrorBoundary, AsyncBoundary | Yes | react-error-boundary |
22
+ | `@classytic/fluid/client/calendar` | EventCalendar | Yes | date-fns |
23
+ | `@classytic/fluid/forms` | Form components with react-hook-form integration | Yes | react-hook-form |
24
+ | `@classytic/fluid/dashboard` | Dashboard layout, sidebar presets, headers, nav utils | Yes | next |
25
+ | `@classytic/fluid/compact` | Compact form variants (floating labels) | Yes | react |
26
+ | `@classytic/fluid/search` | Composable search system | Yes | react, next |
27
+ | `@classytic/fluid/command` | Command palette, keyboard shortcuts | Yes | react |
28
+ | `@classytic/fluid/layouts` | NavigationBar, DrawerWrapper, ContextMenu, HoverCard | Yes | react, next |
29
+
30
+ > **Note:** All entries resolve `@/components/ui/*` from your project's shadcn setup at build time.
31
+ > The root entry omits `"use client"` so it can be imported in Server Components, but it still
32
+ > requires your shadcn components to be available for resolution.
33
+
11
34
  ## Usage
12
35
 
13
36
  ```tsx
14
- // Main components
37
+ // RSC-compatible — layout, display, states
38
+ import { Section, Container, EmptyState, LoadingState, cn } from "@classytic/fluid";
39
+
40
+ // Client sub-entries — import from specific sub-entry for tree-shaking
41
+ import { useIsMobile, useDebounce, useLocalStorage } from "@classytic/fluid/client/hooks";
42
+ import { DialogWrapper, CardWrapper, TabsWrapper } from "@classytic/fluid/client/core";
43
+ import { DataTable } from "@classytic/fluid/client/table"; // needs @tanstack/react-table
44
+ import { ModeToggle } from "@classytic/fluid/client/theme"; // needs next-themes
45
+ import { ErrorBoundary, AsyncBoundary } from "@classytic/fluid/client/error"; // needs react-error-boundary
46
+ import { EventCalendar } from "@classytic/fluid/client/calendar"; // needs date-fns
47
+
48
+ // Form components — react-hook-form integration
15
49
  import {
16
- DialogWrapper,
17
- FormInput,
18
- DataTable,
19
- EmptyState,
20
- } from "@classytic/fluid";
50
+ FormInput, FormTextarea, SelectInput, ComboboxInput,
51
+ DateInput, TagInput, SlugField,
52
+ } from "@classytic/fluid/forms";
21
53
 
22
- // Dashboard components (sidebar, header, project switcher)
54
+ // Dashboard layout, sidebar, headers
23
55
  import {
24
- PageHeader,
25
- InsetSidebar,
26
- SidebarNav,
56
+ DashboardPageLayout, PageHeader, InsetSidebar,
57
+ SidebarNav, ProjectSwitcher,
27
58
  } from "@classytic/fluid/dashboard";
28
59
 
29
- // Layout utilities
30
- import { Section, Container } from "@classytic/fluid/layout";
31
-
32
- // Compact form components (floating labels)
33
- import { CompactInput, CompactSelect, Field } from "@classytic/fluid/compact";
60
+ // Compact form variants (floating labels)
61
+ import { CompactInput, CompactSelect } from "@classytic/fluid/compact";
34
62
 
35
- // Composable search system
63
+ // Search system
36
64
  import { Search, SearchProvider, useSearch } from "@classytic/fluid/search";
65
+
66
+ // Command palette + keyboard shortcuts
67
+ import { CommandSearch, useKeyboardShortcut } from "@classytic/fluid/command";
37
68
  ```
38
69
 
39
70
  ## Components
40
71
 
41
- | Category | Components |
42
- | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
43
- | **Dialogs/Sheets** | DialogWrapper, FormDialog, SheetWrapper, FormSheet, ConfirmDialog, ConfirmSheet, DeleteConfirmDialog |
44
- | **Forms** | FormInput, FormTextarea, SelectInput, CheckboxInput, RadioInput, SwitchInput, DateInput, DateRangeInput, TagInput, TagChoiceInput, ComboboxInput, SlugField, PhoneInput, FormErrorSummary, DateRangeFilter |
45
- | **Compact Forms** | CompactInput, CompactTextarea, CompactSelect, CompactNumberInput, CompactTagChoice, CompactSlugField, Field |
46
- | **Tables** | DataTable, TableWrapper, SimpleTable |
47
- | **Layout** | CardWrapper, DataCard, StatsCard, CollapsibleWrapper, CollapsibleCard, ResponsiveSplitLayout, TabsWrapper, DynamicTabs, Section, Container |
48
- | **Display** | Pill (+ PillAvatar, PillStatus, PillDelta, PillIcon), InfoRow, CopyButton, CopyText, CopyCodeBlock, Thumbnail, DisplayHeading |
49
- | **Feedback** | EmptyState (+ NoResults, NoData, NotFound presets), LoadingState, LoadingOverlay, ErrorState, StatusBanner |
50
- | **Navigation** | ApiPagination, CustomPagination |
51
- | **Search** | Search.Root, Search.Input, Search.TypeInput, Search.Filters, Search.Actions, Search.Container, SearchProvider |
52
- | **Dashboard** | PageHeader, HeaderSection, InsetSidebar, DualSidebar, ProjectSwitcher, SidebarNav, SidebarBrand, SidebarUserMenu |
53
- | **Other** | ModeToggle, TooltipWrapper, ButtonTooltip, IconTooltip, DropdownWrapper, ActionDropdown, SelectDropdown, CheckboxDropdown, RadioDropdown, AccordionSection, FaqAccordion, EventCalendar |
72
+ ### `@classytic/fluid` (RSC-compatible)
54
73
 
55
- ## Hooks
74
+ | Category | Components |
75
+ |----------|-----------|
76
+ | **Layout** | Section, Container |
77
+ | **Display** | DisplayHeading, SocialIcons (Facebook, Google, TwitterX, Instagram, WhatsApp) |
78
+ | **States** | EmptyState, EmptyStateNoResults, EmptyStateNoData, EmptyStateNotFound |
79
+ | **Loading** | LoadingState, LoadingOverlay |
80
+ | **Skeletons** | SkeletonTable, SkeletonList, SkeletonCard, SkeletonGrid |
81
+ | **Utilities** | cn, buildFilterParams, buildSearchParams, getApiParams |
56
82
 
57
- | Hook | Description |
58
- | ---------------------- | ------------------------------------------ |
59
- | `useDebounce` | Debounce a value (e.g., search input) |
60
- | `useDebouncedCallback` | Debounce a function callback |
61
- | `useCopyToClipboard` | Copy text to clipboard with feedback state |
62
- | `useBaseSearch` | Full search state management with filters |
63
- | `useIsMobile` | Responsive breakpoint detection |
64
- | `useMediaQuery` | Generic media query hook |
65
- | `useScrollDetection` | Detect scroll position/direction |
83
+ ### `@classytic/fluid/client/core`
66
84
 
67
- ## Exports
85
+ | Category | Components |
86
+ |----------|-----------|
87
+ | **Dialogs/Sheets** | DialogWrapper, FormDialog, SheetWrapper, FormSheet, ConfirmDialog, ConfirmSheet, DeleteConfirmDialog, InfoAlert |
88
+ | **Tables** | TableWrapper, SimpleTable |
89
+ | **Layout** | CardWrapper, DataCard, LoadingCard, StatsCard, DraggableCard, CollapsibleWrapper, CollapsibleCard, CollapsibleSection, ResponsiveSplitLayout, TabsWrapper, DynamicTabs, AccordionSection, FaqAccordion |
90
+ | **Display** | Pill (+ Avatar, Button, Status, Indicator, Delta, Icon, AvatarGroup), InfoRow, CopyButton, CopyText, CopyCodeBlock, Thumbnail, DetailView, DetailItem |
91
+ | **Feedback** | ErrorState, ErrorStateInline, StatusBanner, Stepper, Timeline |
92
+ | **Navigation** | ApiPagination, CustomPagination, PaginationInfo |
93
+ | **Dropdowns** | DropdownWrapper, ActionDropdown, SelectDropdown, CheckboxDropdown, RadioDropdown |
94
+ | **Animations** | FadeIn, FadeInUp, SlideIn, ScaleIn, StaggerChildren, AnimatedText, AnimatedCounter |
95
+ | **Other** | TooltipWrapper, ButtonTooltip, IconTooltip, InfoTooltip, ActionTooltip, PhoneInput, ClientSubmitButton, FeatureItem, FeatureList |
68
96
 
69
- ```tsx
70
- // Main — all components, hooks, and utilities
71
- import { ... } from "@classytic/fluid";
97
+ ### `@classytic/fluid/client/table`
98
+
99
+ DataTable, DataTableToolbar
100
+
101
+ ### `@classytic/fluid/client/theme`
102
+
103
+ ModeToggle
104
+
105
+ ### `@classytic/fluid/client/error`
106
+
107
+ ErrorBoundary, FeatureErrorBoundary, AsyncBoundary, FullPageErrorFallback, InlineErrorFallback
108
+
109
+ ### `@classytic/fluid/client/calendar`
110
+
111
+ EventCalendar, CalendarWithDetail, CalendarDayDetail
112
+
113
+ ### `@classytic/fluid/forms`
114
+
115
+ | Category | Components |
116
+ |----------|-----------|
117
+ | **Text** | FormInput, FormTextarea, PasswordInput, NumberInput |
118
+ | **Selection** | SelectInput, ComboboxInput, MultiSelect, AsyncCombobox, AsyncMultiSelect |
119
+ | **Toggle** | CheckboxInput, RadioInput, SwitchInput |
120
+ | **Date/Time** | DateInput, DateRangeInput, DateTimeInput, DateRangeFilter |
121
+ | **Tags** | TagInput, TagChoiceInput |
122
+ | **Special** | SlugField, OTPInput, FileUploadInput, PhoneInput (in client/core) |
123
+ | **Layout** | FormSection, FormGrid, FormFieldArray, FormFieldArrayItem |
124
+ | **Feedback** | FormErrorSummary |
72
125
 
73
- // Dashboard — sidebar layouts, headers, navigation
74
- import { ... } from "@classytic/fluid/dashboard";
126
+ ### `@classytic/fluid/layouts`
75
127
 
76
- // Layout Section, Container
77
- import { ... } from "@classytic/fluid/layout";
128
+ DrawerWrapper, FormDrawer, ConfirmDrawer, NavigationBar, ContextMenuWrapper, HoverCardWrapper, UserHoverCard
78
129
 
79
- // Compact — space-efficient form fields
80
- import { ... } from "@classytic/fluid/compact";
130
+ ### `@classytic/fluid/dashboard`
81
131
 
82
- // Search composable search UI
83
- import { ... } from "@classytic/fluid/search";
132
+ DashboardPageLayout, PageHeader, HeaderSection, DashboardContent, DashboardHeader, InsetSidebar, DualSidebar, FloatingSidebar, MiniSidebar, TopbarRail, SidebarBrand, SidebarNav, SidebarUserMenu, ProjectSwitcher
133
+
134
+ ### `@classytic/fluid/compact`
135
+
136
+ CompactInput, CompactTextarea, CompactSelect, CompactNumberInput, CompactTagChoice, CompactSlugField
137
+
138
+ ### `@classytic/fluid/command`
139
+
140
+ CommandSearch (+ Input, List, Group, Item, Empty, Separator), useCommandSearch, useKeyboardShortcut
141
+
142
+ ## Hooks
143
+
144
+ | Hook | Entry | Description |
145
+ |------|-------|-------------|
146
+ | `useIsMobile` | client/hooks | Responsive breakpoint detection |
147
+ | `useMediaQuery` | client/hooks | Generic media query hook |
148
+ | `useDebounce` | client/hooks | Debounce a value |
149
+ | `useDebouncedCallback` | client/hooks | Debounce a function callback |
150
+ | `useCopyToClipboard` | client/hooks | Copy text with feedback state |
151
+ | `useBaseSearch` | client/hooks | Full search state with URL sync |
152
+ | `useScrollDetection` | client/hooks | Detect scroll position/direction |
153
+ | `useLocalStorage` | client/hooks | Typed localStorage hook |
154
+ | `useKeyboardShortcut` | client/hooks | Register keyboard shortcuts |
155
+ | `useInView` | client/core | Intersection observer hook |
156
+ | `useCommandSearch` | command | Programmatic command palette control |
157
+ | `useSearch` | search | Search context consumer |
158
+
159
+ ## Styles
160
+
161
+ Import the stylesheet in your root layout. This includes both the Tailwind `@source` directive (so Tailwind scans fluid's dist for class names) and animation keyframes:
162
+
163
+ ```tsx
164
+ import "@classytic/fluid/styles.css";
84
165
  ```
85
166
 
86
167
  ## Requirements
87
168
 
88
- - React 18+ (Next.js optional — required for dashboard/routing components)
169
+ - React 19+ and Next.js 15+
89
170
  - shadcn/ui components at `@/components/ui/*`
90
171
  - Tailwind CSS configured in your project
91
172
 
173
+ ### Optional peer dependencies
174
+
175
+ | Package | Required by |
176
+ |---------|------------|
177
+ | `next-themes` | ModeToggle component |
178
+ | `react-hook-form` | `@classytic/fluid/forms` entry |
179
+ | `react-error-boundary` | ErrorBoundary, AsyncBoundary |
180
+ | `@tanstack/react-table` | DataTable component |
181
+ | `date-fns` | DateInput, DateRangeInput, EventCalendar |
182
+
92
183
  ## Dev
93
184
 
94
185
  ```bash
95
- npm run build # Build package
96
- npm run dev # Watch mode
97
- npm run clean # Remove dist
186
+ npm run build # Build with tsdown
187
+ npm run dev # Watch mode
188
+ npm run typecheck # Type check
189
+ npm run clean # Remove dist
98
190
  ```
99
191
 
100
192
  ## License
101
193
 
102
- **UNLICENSED**
103
-
104
- Copyright © 2026 Classytic. All rights reserved.
105
-
106
- This software is the confidential and proprietary information of Classytic.
107
- Unauthorized copying of this software, via any medium is strictly prohibited.
194
+ MIT — see [LICENSE](./LICENSE) for details.
@@ -0,0 +1,34 @@
1
+ import * as react_jsx_runtime0 from "react/jsx-runtime";
2
+
3
+ //#region src/components/api-pagination.d.ts
4
+ interface ApiPaginationData {
5
+ total: number;
6
+ pages: number;
7
+ page: number;
8
+ limit: number;
9
+ hasNext: boolean;
10
+ hasPrev: boolean;
11
+ }
12
+ interface ApiPaginationProps extends Partial<ApiPaginationData> {
13
+ onPageChange?: (page: number) => void;
14
+ className?: string;
15
+ showInfo?: boolean;
16
+ infoPosition?: "left" | "right";
17
+ }
18
+ /**
19
+ * ApiPagination - A reusable pagination component for API-driven data
20
+ */
21
+ declare function ApiPagination({
22
+ total,
23
+ limit,
24
+ pages,
25
+ page,
26
+ hasNext,
27
+ hasPrev,
28
+ onPageChange,
29
+ className,
30
+ showInfo,
31
+ infoPosition
32
+ }: ApiPaginationProps): react_jsx_runtime0.JSX.Element;
33
+ //#endregion
34
+ export { ApiPaginationData as n, ApiPaginationProps as r, ApiPagination as t };
@@ -0,0 +1,190 @@
1
+ import { t as cn } from "./utils-DQ5SCVoW.mjs";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useState } from "react";
4
+ import { Pagination, PaginationContent, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious } from "@/components/ui/pagination";
5
+
6
+ //#region src/components/custom-pagination.tsx
7
+ function CustomPagination({ page, onPageChange, pages, hasPrev, hasNext }) {
8
+ const [isMobile, setIsMobile] = useState(false);
9
+ const currentPageNum = Number(page);
10
+ useEffect(() => {
11
+ const checkMobile = () => {
12
+ setIsMobile(window.innerWidth < 640);
13
+ };
14
+ checkMobile();
15
+ window.addEventListener("resize", checkMobile);
16
+ return () => window.removeEventListener("resize", checkMobile);
17
+ }, []);
18
+ if (pages <= 1) return null;
19
+ const getPageNumbers = () => {
20
+ const delta = isMobile ? 1 : 2;
21
+ const range = [];
22
+ const rangeWithDots = [];
23
+ for (let i = Math.max(2, currentPageNum - delta); i <= Math.min(pages - 1, currentPageNum + delta); i++) range.push(i);
24
+ if (currentPageNum - delta > 2) rangeWithDots.push(1, "...");
25
+ else rangeWithDots.push(1);
26
+ rangeWithDots.push(...range);
27
+ if (currentPageNum + delta < pages - 1) rangeWithDots.push("...", pages);
28
+ else if (pages > 1) {
29
+ if (!range.includes(pages)) rangeWithDots.push(pages);
30
+ }
31
+ return [...new Set(rangeWithDots)];
32
+ };
33
+ if (isMobile && pages > 5) return /* @__PURE__ */ jsx(Pagination, {
34
+ className: "mx-0 w-auto",
35
+ children: /* @__PURE__ */ jsxs(PaginationContent, {
36
+ className: "gap-1",
37
+ children: [
38
+ /* @__PURE__ */ jsx(PaginationItem, { children: /* @__PURE__ */ jsx(PaginationPrevious, {
39
+ onClick: () => hasPrev ? onPageChange(currentPageNum - 1) : void 0,
40
+ className: cn("cursor-pointer transition-colors h-8 px-2 text-xs", !hasPrev && "pointer-events-none opacity-50 cursor-not-allowed", hasPrev && "hover:bg-accent hover:text-accent-foreground"),
41
+ "aria-disabled": !hasPrev
42
+ }) }),
43
+ /* @__PURE__ */ jsx(PaginationItem, { children: /* @__PURE__ */ jsxs("div", {
44
+ className: "flex h-8 items-center justify-center px-3 text-xs font-medium bg-primary text-primary-foreground rounded-md",
45
+ children: [
46
+ currentPageNum,
47
+ " / ",
48
+ pages
49
+ ]
50
+ }) }),
51
+ /* @__PURE__ */ jsx(PaginationItem, { children: /* @__PURE__ */ jsx(PaginationNext, {
52
+ onClick: () => hasNext ? onPageChange(currentPageNum + 1) : void 0,
53
+ className: cn("cursor-pointer transition-colors h-8 px-2 text-xs", !hasNext && "pointer-events-none opacity-50 cursor-not-allowed", hasNext && "hover:bg-accent hover:text-accent-foreground"),
54
+ "aria-disabled": !hasNext
55
+ }) })
56
+ ]
57
+ })
58
+ });
59
+ return /* @__PURE__ */ jsx(Pagination, {
60
+ className: "mx-0 w-auto",
61
+ children: /* @__PURE__ */ jsxs(PaginationContent, {
62
+ className: "gap-1 flex-wrap",
63
+ children: [
64
+ /* @__PURE__ */ jsx(PaginationItem, { children: /* @__PURE__ */ jsx(PaginationPrevious, {
65
+ onClick: () => hasPrev ? onPageChange(currentPageNum - 1) : void 0,
66
+ className: cn("cursor-pointer transition-colors", isMobile ? "h-8 px-2 text-xs" : "h-9 px-3 text-sm", !hasPrev && "pointer-events-none opacity-50 cursor-not-allowed", hasPrev && "hover:bg-accent hover:text-accent-foreground"),
67
+ "aria-disabled": !hasPrev
68
+ }) }),
69
+ getPageNumbers().map((pageNum, index) => /* @__PURE__ */ jsx(PaginationItem, { children: pageNum === "..." ? /* @__PURE__ */ jsx("span", {
70
+ className: cn("flex items-center justify-center text-muted-foreground", isMobile ? "h-8 w-8 text-xs" : "h-9 w-9 text-sm"),
71
+ children: "..."
72
+ }) : /* @__PURE__ */ jsx(PaginationLink, {
73
+ className: cn("cursor-pointer transition-colors", isMobile ? "h-8 w-8 text-xs p-0" : "h-9 w-9 text-sm p-0", "hover:bg-accent hover:text-accent-foreground", Number(currentPageNum) === Number(pageNum) && "bg-primary text-primary-foreground hover:bg-primary/90"),
74
+ onClick: () => typeof pageNum === "number" ? onPageChange(pageNum) : void 0,
75
+ isActive: Number(currentPageNum) === Number(pageNum),
76
+ "aria-label": `Go to page ${pageNum}`,
77
+ "aria-current": Number(currentPageNum) === Number(pageNum) ? "page" : void 0,
78
+ children: pageNum
79
+ }) }, `pagination-page-${pageNum}-${index}`)),
80
+ /* @__PURE__ */ jsx(PaginationItem, { children: /* @__PURE__ */ jsx(PaginationNext, {
81
+ onClick: () => hasNext ? onPageChange(currentPageNum + 1) : void 0,
82
+ className: cn("cursor-pointer transition-colors", isMobile ? "h-8 px-2 text-xs" : "h-9 px-3 text-sm", !hasNext && "pointer-events-none opacity-50 cursor-not-allowed", hasNext && "hover:bg-accent hover:text-accent-foreground"),
83
+ "aria-disabled": !hasNext
84
+ }) })
85
+ ]
86
+ })
87
+ });
88
+ }
89
+ function PaginationInfo({ page, total, limit = 10 }) {
90
+ const [isMobile, setIsMobile] = useState(false);
91
+ useEffect(() => {
92
+ const checkMobile = () => {
93
+ setIsMobile(window.innerWidth < 640);
94
+ };
95
+ checkMobile();
96
+ window.addEventListener("resize", checkMobile);
97
+ return () => window.removeEventListener("resize", checkMobile);
98
+ }, []);
99
+ if (total === 0) return /* @__PURE__ */ jsx("div", {
100
+ className: "flex-1 text-sm text-muted-foreground",
101
+ children: /* @__PURE__ */ jsx("p", { children: "No entries found" })
102
+ });
103
+ const startEntry = (page - 1) * limit + 1;
104
+ const endEntry = Math.min(page * limit, total);
105
+ return /* @__PURE__ */ jsx("div", {
106
+ className: "flex-1 text-sm text-muted-foreground",
107
+ children: /* @__PURE__ */ jsx("p", {
108
+ className: cn("whitespace-nowrap", isMobile && "text-xs"),
109
+ children: isMobile ? /* @__PURE__ */ jsxs("span", { children: [
110
+ startEntry.toLocaleString(),
111
+ "-",
112
+ endEntry.toLocaleString(),
113
+ " of",
114
+ " ",
115
+ total.toLocaleString()
116
+ ] }) : /* @__PURE__ */ jsxs("span", { children: [
117
+ "Showing",
118
+ " ",
119
+ /* @__PURE__ */ jsx("span", {
120
+ className: "font-medium text-foreground",
121
+ children: startEntry.toLocaleString()
122
+ }),
123
+ " ",
124
+ "to",
125
+ " ",
126
+ /* @__PURE__ */ jsx("span", {
127
+ className: "font-medium text-foreground",
128
+ children: endEntry.toLocaleString()
129
+ }),
130
+ " ",
131
+ "of",
132
+ " ",
133
+ /* @__PURE__ */ jsx("span", {
134
+ className: "font-medium text-foreground",
135
+ children: total.toLocaleString()
136
+ }),
137
+ " ",
138
+ total === 1 ? "result" : "results"
139
+ ] })
140
+ })
141
+ });
142
+ }
143
+
144
+ //#endregion
145
+ //#region src/components/api-pagination.tsx
146
+ /**
147
+ * ApiPagination - A reusable pagination component for API-driven data
148
+ */
149
+ function ApiPagination({ total = 0, limit = 10, pages = 1, page = 1, hasNext = false, hasPrev = false, onPageChange = () => {}, className, showInfo = true, infoPosition = "left" }) {
150
+ const infoComponent = showInfo && /* @__PURE__ */ jsx("div", {
151
+ className: "shrink-0",
152
+ children: /* @__PURE__ */ jsx(PaginationInfo, {
153
+ total,
154
+ page,
155
+ limit
156
+ })
157
+ });
158
+ const paginationComponent = /* @__PURE__ */ jsx("div", {
159
+ className: "flex justify-center sm:justify-end",
160
+ children: /* @__PURE__ */ jsx(CustomPagination, {
161
+ page,
162
+ pages,
163
+ hasPrev,
164
+ hasNext,
165
+ onPageChange
166
+ })
167
+ });
168
+ return /* @__PURE__ */ jsx("div", {
169
+ className: cn("shrink-0 bg-muted/30 rounded-lg border border-border p-3 mb-2", className),
170
+ children: /* @__PURE__ */ jsx("div", {
171
+ className: "flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between sm:gap-4",
172
+ children: infoPosition === "left" ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("div", {
173
+ className: "order-2 sm:order-1",
174
+ children: infoComponent
175
+ }), /* @__PURE__ */ jsx("div", {
176
+ className: "order-1 sm:order-2",
177
+ children: paginationComponent
178
+ })] }) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("div", {
179
+ className: "order-1 sm:order-1",
180
+ children: paginationComponent
181
+ }), /* @__PURE__ */ jsx("div", {
182
+ className: "order-2 sm:order-2",
183
+ children: infoComponent
184
+ })] })
185
+ })
186
+ });
187
+ }
188
+
189
+ //#endregion
190
+ export { CustomPagination as n, PaginationInfo as r, ApiPagination as t };
@@ -0,0 +1,18 @@
1
+ //#region \0rolldown/runtime.js
2
+ var __defProp = Object.defineProperty;
3
+ var __exportAll = (all, no_symbols) => {
4
+ let target = {};
5
+ for (var name in all) {
6
+ __defProp(target, name, {
7
+ get: all[name],
8
+ enumerable: true
9
+ });
10
+ }
11
+ if (!no_symbols) {
12
+ __defProp(target, Symbol.toStringTag, { value: "Module" });
13
+ }
14
+ return target;
15
+ };
16
+
17
+ //#endregion
18
+ export { __exportAll as t };
@@ -0,0 +1,105 @@
1
+ import * as react_jsx_runtime0 from "react/jsx-runtime";
2
+ import { ReactNode } from "react";
3
+
4
+ //#region src/components/event-calendar.d.ts
5
+ interface CalendarEvent {
6
+ id: string;
7
+ date: Date | string;
8
+ [key: string]: any;
9
+ }
10
+ interface EventCalendarProps<T extends CalendarEvent> {
11
+ /** Events to display on the calendar */
12
+ events?: T[];
13
+ /** Currently selected date */
14
+ selectedDate?: Date | null;
15
+ /** Callback when a date is selected */
16
+ onDateSelect?: (date: Date, events: T[]) => void;
17
+ /** Callback when month changes */
18
+ onMonthChange?: (date: Date) => void;
19
+ /** Initial month to display */
20
+ initialMonth?: Date;
21
+ /** Custom render for day cell content */
22
+ renderDayContent?: (date: Date, events: T[], isSelected: boolean) => ReactNode;
23
+ /** Custom render for event indicators */
24
+ renderEventIndicators?: (events: T[]) => ReactNode;
25
+ /** Get events for a specific date (custom filtering) */
26
+ getEventsForDate?: (date: Date, events: T[]) => T[];
27
+ /** Additional class names */
28
+ className?: string;
29
+ /** Header content (left side) */
30
+ headerLeft?: ReactNode;
31
+ /** Header content (right side, before navigation) */
32
+ headerRight?: ReactNode;
33
+ /** Minimum cell height */
34
+ minCellHeight?: string;
35
+ /** Show week numbers */
36
+ showWeekNumbers?: boolean;
37
+ /** Loading state */
38
+ isLoading?: boolean;
39
+ }
40
+ /**
41
+ * EventCalendar - A reusable calendar component for displaying events
42
+ *
43
+ * Can be used for attendance tracking, scheduling, etc.
44
+ */
45
+ declare function EventCalendar<T extends CalendarEvent>({
46
+ events,
47
+ selectedDate: controlledSelectedDate,
48
+ onDateSelect,
49
+ onMonthChange,
50
+ initialMonth,
51
+ renderDayContent,
52
+ renderEventIndicators,
53
+ getEventsForDate,
54
+ className,
55
+ headerLeft,
56
+ headerRight,
57
+ minCellHeight,
58
+ showWeekNumbers,
59
+ isLoading
60
+ }: EventCalendarProps<T>): react_jsx_runtime0.JSX.Element;
61
+ /**
62
+ * CalendarDayDetail - Side panel component for showing selected day details
63
+ */
64
+ interface CalendarDayDetailProps {
65
+ date: Date | null;
66
+ title?: string;
67
+ emptyMessage?: string;
68
+ children?: ReactNode;
69
+ className?: string;
70
+ }
71
+ declare function CalendarDayDetail({
72
+ date,
73
+ title,
74
+ emptyMessage,
75
+ children,
76
+ className
77
+ }: CalendarDayDetailProps): react_jsx_runtime0.JSX.Element;
78
+ /**
79
+ * CalendarWithDetail - Calendar with integrated detail panel
80
+ */
81
+ interface CalendarWithDetailProps<T extends CalendarEvent> extends Omit<EventCalendarProps<T>, "onDateSelect"> {
82
+ /** Render detail panel content */
83
+ renderDetail?: (date: Date, events: T[]) => ReactNode;
84
+ /** Detail panel title when no date selected */
85
+ detailTitle?: string;
86
+ /** Detail panel empty message */
87
+ detailEmptyMessage?: string;
88
+ /** Layout direction */
89
+ layout?: "horizontal" | "vertical";
90
+ /** Detail panel position */
91
+ detailPosition?: "left" | "right" | "top" | "bottom";
92
+ /** Callback when date is selected */
93
+ onDateSelect?: (date: Date, events: T[]) => void;
94
+ }
95
+ declare function CalendarWithDetail<T extends CalendarEvent>({
96
+ renderDetail,
97
+ detailTitle,
98
+ detailEmptyMessage,
99
+ layout,
100
+ detailPosition,
101
+ onDateSelect,
102
+ ...calendarProps
103
+ }: CalendarWithDetailProps<T>): react_jsx_runtime0.JSX.Element;
104
+ //#endregion
105
+ export { CalendarDayDetail, type CalendarDayDetailProps, type CalendarEvent, CalendarWithDetail, type CalendarWithDetailProps, EventCalendar, type EventCalendarProps };