@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
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
|
|
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
|
-
//
|
|
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
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
EmptyState,
|
|
20
|
-
} from "@classytic/fluid";
|
|
50
|
+
FormInput, FormTextarea, SelectInput, ComboboxInput,
|
|
51
|
+
DateInput, TagInput, SlugField,
|
|
52
|
+
} from "@classytic/fluid/forms";
|
|
21
53
|
|
|
22
|
-
// Dashboard
|
|
54
|
+
// Dashboard — layout, sidebar, headers
|
|
23
55
|
import {
|
|
24
|
-
PageHeader,
|
|
25
|
-
|
|
26
|
-
SidebarNav,
|
|
56
|
+
DashboardPageLayout, PageHeader, InsetSidebar,
|
|
57
|
+
SidebarNav, ProjectSwitcher,
|
|
27
58
|
} from "@classytic/fluid/dashboard";
|
|
28
59
|
|
|
29
|
-
//
|
|
30
|
-
import {
|
|
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
|
-
//
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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
|
-
|
|
74
|
-
import { ... } from "@classytic/fluid/dashboard";
|
|
126
|
+
### `@classytic/fluid/layouts`
|
|
75
127
|
|
|
76
|
-
|
|
77
|
-
import { ... } from "@classytic/fluid/layout";
|
|
128
|
+
DrawerWrapper, FormDrawer, ConfirmDrawer, NavigationBar, ContextMenuWrapper, HoverCardWrapper, UserHoverCard
|
|
78
129
|
|
|
79
|
-
|
|
80
|
-
import { ... } from "@classytic/fluid/compact";
|
|
130
|
+
### `@classytic/fluid/dashboard`
|
|
81
131
|
|
|
82
|
-
|
|
83
|
-
|
|
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
|
|
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
|
|
96
|
-
npm run dev
|
|
97
|
-
npm run
|
|
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
|
-
|
|
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 };
|