@classytic/fluid 0.1.2 → 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/README.md +63 -18
- package/animations.css +74 -0
- package/dist/chunk-GUHK2DTW.js +15 -0
- package/dist/chunk-GUHK2DTW.js.map +1 -0
- package/dist/chunk-H3NFL3GJ.js +57 -0
- package/dist/chunk-H3NFL3GJ.js.map +1 -0
- package/dist/chunk-J2YRTQE4.js +293 -0
- package/dist/chunk-J2YRTQE4.js.map +1 -0
- package/dist/compact.d.ts +217 -0
- package/dist/compact.js +986 -0
- package/dist/compact.js.map +1 -0
- package/dist/dashboard.d.ts +38 -1
- package/dist/dashboard.js +65 -25
- package/dist/dashboard.js.map +1 -1
- package/dist/index.d.ts +586 -507
- package/dist/index.js +1656 -2211
- package/dist/index.js.map +1 -1
- package/dist/layout.js +2 -60
- package/dist/layout.js.map +1 -1
- package/dist/search.d.ts +172 -0
- package/dist/search.js +341 -0
- package/dist/search.js.map +1 -0
- package/dist/use-base-search-AS5Z3SAy.d.ts +64 -0
- package/package.json +32 -19
- package/styles.css +3 -0
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @classytic/fluid
|
|
2
2
|
|
|
3
|
-
Reusable UI components built on shadcn/ui for Next.js projects.
|
|
3
|
+
Reusable UI components built on shadcn/ui and Base UI for Next.js projects.
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
@@ -11,47 +11,92 @@ npm install @classytic/fluid
|
|
|
11
11
|
## Usage
|
|
12
12
|
|
|
13
13
|
```tsx
|
|
14
|
-
|
|
15
|
-
import {
|
|
14
|
+
// Main components
|
|
15
|
+
import {
|
|
16
|
+
DialogWrapper,
|
|
17
|
+
FormInput,
|
|
18
|
+
DataTable,
|
|
19
|
+
EmptyState,
|
|
20
|
+
} from "@classytic/fluid";
|
|
21
|
+
|
|
22
|
+
// Dashboard components (sidebar, header, project switcher)
|
|
23
|
+
import {
|
|
24
|
+
PageHeader,
|
|
25
|
+
InsetSidebar,
|
|
26
|
+
SidebarNav,
|
|
27
|
+
} from "@classytic/fluid/dashboard";
|
|
28
|
+
|
|
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";
|
|
34
|
+
|
|
35
|
+
// Composable search system
|
|
36
|
+
import { Search, SearchProvider, useSearch } from "@classytic/fluid/search";
|
|
16
37
|
```
|
|
17
38
|
|
|
18
39
|
## Components
|
|
19
40
|
|
|
20
|
-
| Category
|
|
21
|
-
|
|
22
|
-
| **Dialogs/Sheets** | DialogWrapper, FormDialog, SheetWrapper, FormSheet, ConfirmDialog |
|
|
23
|
-
| **Forms**
|
|
24
|
-
| **
|
|
25
|
-
| **
|
|
26
|
-
| **
|
|
27
|
-
| **
|
|
28
|
-
| **
|
|
29
|
-
| **
|
|
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 |
|
|
54
|
+
|
|
55
|
+
## Hooks
|
|
56
|
+
|
|
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 |
|
|
30
66
|
|
|
31
67
|
## Exports
|
|
32
68
|
|
|
33
69
|
```tsx
|
|
34
|
-
// Main components
|
|
70
|
+
// Main — all components, hooks, and utilities
|
|
35
71
|
import { ... } from "@classytic/fluid";
|
|
36
72
|
|
|
37
|
-
// Dashboard
|
|
73
|
+
// Dashboard — sidebar layouts, headers, navigation
|
|
38
74
|
import { ... } from "@classytic/fluid/dashboard";
|
|
39
75
|
|
|
40
|
-
// Layout
|
|
76
|
+
// Layout — Section, Container
|
|
41
77
|
import { ... } from "@classytic/fluid/layout";
|
|
78
|
+
|
|
79
|
+
// Compact — space-efficient form fields
|
|
80
|
+
import { ... } from "@classytic/fluid/compact";
|
|
81
|
+
|
|
82
|
+
// Search — composable search UI
|
|
83
|
+
import { ... } from "@classytic/fluid/search";
|
|
42
84
|
```
|
|
43
85
|
|
|
44
86
|
## Requirements
|
|
45
87
|
|
|
46
|
-
- Next.js
|
|
88
|
+
- React 18+ (Next.js optional — required for dashboard/routing components)
|
|
47
89
|
- shadcn/ui components at `@/components/ui/*`
|
|
90
|
+
- Tailwind CSS configured in your project
|
|
48
91
|
|
|
49
92
|
## Dev
|
|
50
93
|
|
|
51
94
|
```bash
|
|
52
95
|
npm run build # Build package
|
|
53
96
|
npm run dev # Watch mode
|
|
97
|
+
npm run clean # Remove dist
|
|
54
98
|
```
|
|
99
|
+
|
|
55
100
|
## License
|
|
56
101
|
|
|
57
102
|
**UNLICENSED**
|
|
@@ -59,4 +104,4 @@ npm run dev # Watch mode
|
|
|
59
104
|
Copyright © 2026 Classytic. All rights reserved.
|
|
60
105
|
|
|
61
106
|
This software is the confidential and proprietary information of Classytic.
|
|
62
|
-
Unauthorized copying of this software, via any medium is strictly prohibited.
|
|
107
|
+
Unauthorized copying of this software, via any medium is strictly prohibited.
|
package/animations.css
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @classytic/fluid — Animation System
|
|
3
|
+
*
|
|
4
|
+
* Opt-in file for consumers who want Tailwind animate-* utility classes.
|
|
5
|
+
* If you already import styles.css, you do NOT need this file —
|
|
6
|
+
* styles.css includes both the keyframes and theme tokens.
|
|
7
|
+
*
|
|
8
|
+
* Usage: @import "@classytic/fluid/animations.css";
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
@theme inline {
|
|
12
|
+
--animate-fade-in: fade-in 0.6s ease-out forwards;
|
|
13
|
+
--animate-fade-in-up: fade-in-up 0.6s ease-out forwards;
|
|
14
|
+
--animate-scale-in: scale-in 0.6s ease-out forwards;
|
|
15
|
+
--animate-slide-in-left: slide-in-left 0.6s ease-out forwards;
|
|
16
|
+
--animate-slide-in-right: slide-in-right 0.6s ease-out forwards;
|
|
17
|
+
--animate-slide-in-up: slide-in-up 0.6s ease-out forwards;
|
|
18
|
+
--animate-slide-in-down: slide-in-down 0.6s ease-out forwards;
|
|
19
|
+
--animate-pulse-soft: pulse-soft 3s ease-in-out infinite;
|
|
20
|
+
--animate-float: float 6s ease-in-out infinite;
|
|
21
|
+
|
|
22
|
+
@keyframes fade-in {
|
|
23
|
+
from { opacity: 0; }
|
|
24
|
+
to { opacity: 1; }
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
@keyframes fade-in-up {
|
|
28
|
+
from { opacity: 0; transform: translateY(20px); }
|
|
29
|
+
to { opacity: 1; transform: translateY(0); }
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
@keyframes scale-in {
|
|
33
|
+
from { opacity: 0; transform: scale(0.95); }
|
|
34
|
+
to { opacity: 1; transform: scale(1); }
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
@keyframes slide-in-left {
|
|
38
|
+
from { opacity: 0; transform: translateX(-30px); }
|
|
39
|
+
to { opacity: 1; transform: translateX(0); }
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
@keyframes slide-in-right {
|
|
43
|
+
from { opacity: 0; transform: translateX(30px); }
|
|
44
|
+
to { opacity: 1; transform: translateX(0); }
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
@keyframes slide-in-up {
|
|
48
|
+
from { opacity: 0; transform: translateY(30px); }
|
|
49
|
+
to { opacity: 1; transform: translateY(0); }
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
@keyframes slide-in-down {
|
|
53
|
+
from { opacity: 0; transform: translateY(-30px); }
|
|
54
|
+
to { opacity: 1; transform: translateY(0); }
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
@keyframes pulse-soft {
|
|
58
|
+
0%, 100% { opacity: 1; }
|
|
59
|
+
50% { opacity: 0.8; }
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
@keyframes float {
|
|
63
|
+
0%, 100% { transform: translateY(0); }
|
|
64
|
+
50% { transform: translateY(-10px); }
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
@media (prefers-reduced-motion: reduce) {
|
|
69
|
+
[data-fluid-animate] {
|
|
70
|
+
animation: none !important;
|
|
71
|
+
opacity: 1 !important;
|
|
72
|
+
transform: none !important;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { clsx } from 'clsx';
|
|
2
|
+
import { twMerge } from 'tailwind-merge';
|
|
3
|
+
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
function cn(...inputs) {
|
|
10
|
+
return twMerge(clsx(inputs));
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export { __export, cn };
|
|
14
|
+
//# sourceMappingURL=chunk-GUHK2DTW.js.map
|
|
15
|
+
//# sourceMappingURL=chunk-GUHK2DTW.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils.ts"],"names":[],"mappings":";;;;;;;;AAGO,SAAS,MAAM,MAAA,EAAsB;AAC1C,EAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAC,CAAA;AAC7B","file":"chunk-GUHK2DTW.js","sourcesContent":["import { type ClassValue, clsx } from \"clsx\";\r\nimport { twMerge } from \"tailwind-merge\";\r\n\r\nexport function cn(...inputs: ClassValue[]) {\r\n return twMerge(clsx(inputs));\r\n}\r\n"]}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { cn } from './chunk-GUHK2DTW.js';
|
|
2
|
+
import { jsx } from 'react/jsx-runtime';
|
|
3
|
+
|
|
4
|
+
var backgrounds = {
|
|
5
|
+
default: "bg-background",
|
|
6
|
+
muted: "bg-muted",
|
|
7
|
+
primary: "bg-primary text-primary-foreground",
|
|
8
|
+
transparent: "bg-transparent"
|
|
9
|
+
};
|
|
10
|
+
var paddings = {
|
|
11
|
+
none: "",
|
|
12
|
+
sm: "py-8 md:py-12",
|
|
13
|
+
md: "py-12 md:py-16",
|
|
14
|
+
lg: "py-16 md:py-24",
|
|
15
|
+
xl: "py-24 md:py-32"
|
|
16
|
+
};
|
|
17
|
+
function Section({
|
|
18
|
+
id,
|
|
19
|
+
children,
|
|
20
|
+
className,
|
|
21
|
+
background = "default",
|
|
22
|
+
padding = "sm"
|
|
23
|
+
}) {
|
|
24
|
+
return /* @__PURE__ */ jsx(
|
|
25
|
+
"section",
|
|
26
|
+
{
|
|
27
|
+
id,
|
|
28
|
+
className: cn(backgrounds[background], paddings[padding], className),
|
|
29
|
+
children
|
|
30
|
+
}
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
var maxWidthClasses = {
|
|
34
|
+
sm: "max-w-screen-sm",
|
|
35
|
+
md: "max-w-screen-md",
|
|
36
|
+
lg: "max-w-screen-lg",
|
|
37
|
+
xl: "max-w-screen-xl",
|
|
38
|
+
"2xl": "max-w-screen-2xl",
|
|
39
|
+
"4xl": "max-w-4xl",
|
|
40
|
+
"5xl": "max-w-5xl",
|
|
41
|
+
"6xl": "max-w-6xl",
|
|
42
|
+
"7xl": "max-w-7xl",
|
|
43
|
+
full: "max-w-full"
|
|
44
|
+
};
|
|
45
|
+
function Container({
|
|
46
|
+
children,
|
|
47
|
+
className,
|
|
48
|
+
maxWidth = "7xl"
|
|
49
|
+
}) {
|
|
50
|
+
const isFullWidth = maxWidth === "full";
|
|
51
|
+
const baseClass = isFullWidth ? "w-full px-4 sm:px-6 lg:px-10" : "mx-auto px-4 sm:px-6 lg:px-8";
|
|
52
|
+
return /* @__PURE__ */ jsx("div", { className: cn(baseClass, !isFullWidth && maxWidthClasses[maxWidth], className), children });
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export { Container, Section };
|
|
56
|
+
//# sourceMappingURL=chunk-H3NFL3GJ.js.map
|
|
57
|
+
//# sourceMappingURL=chunk-H3NFL3GJ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/layout/section.tsx","../src/layout/container.tsx"],"names":["jsx"],"mappings":";;;AAcA,IAAM,WAAA,GAA0C;AAAA,EAC9C,OAAA,EAAS,eAAA;AAAA,EACT,KAAA,EAAO,UAAA;AAAA,EACP,OAAA,EAAS,oCAAA;AAAA,EACT,WAAA,EAAa;AACf,CAAA;AAEA,IAAM,QAAA,GAAoC;AAAA,EACxC,IAAA,EAAM,EAAA;AAAA,EACN,EAAA,EAAI,eAAA;AAAA,EACJ,EAAA,EAAI,gBAAA;AAAA,EACJ,EAAA,EAAI,gBAAA;AAAA,EACJ,EAAA,EAAI;AACN,CAAA;AAEO,SAAS,OAAA,CAAQ;AAAA,EACtB,EAAA;AAAA,EACA,QAAA;AAAA,EACA,SAAA;AAAA,EACA,UAAA,GAAa,SAAA;AAAA,EACb,OAAA,GAAU;AACZ,CAAA,EAAiB;AACf,EAAA,uBACE,GAAA;AAAA,IAAC,SAAA;AAAA,IAAA;AAAA,MACC,EAAA;AAAA,MACA,SAAA,EAAW,GAAG,WAAA,CAAY,UAAU,GAAG,QAAA,CAAS,OAAO,GAAG,SAAS,CAAA;AAAA,MAElE;AAAA;AAAA,GACH;AAEJ;ACjCA,IAAM,eAAA,GAA4C;AAAA,EAChD,EAAA,EAAI,iBAAA;AAAA,EACJ,EAAA,EAAI,iBAAA;AAAA,EACJ,EAAA,EAAI,iBAAA;AAAA,EACJ,EAAA,EAAI,iBAAA;AAAA,EACJ,KAAA,EAAO,kBAAA;AAAA,EACP,KAAA,EAAO,WAAA;AAAA,EACP,KAAA,EAAO,WAAA;AAAA,EACP,KAAA,EAAO,WAAA;AAAA,EACP,KAAA,EAAO,WAAA;AAAA,EACP,IAAA,EAAM;AACR,CAAA;AAEO,SAAS,SAAA,CAAU;AAAA,EACxB,QAAA;AAAA,EACA,SAAA;AAAA,EACA,QAAA,GAAW;AACb,CAAA,EAAmB;AACjB,EAAA,MAAM,cAAc,QAAA,KAAa,MAAA;AACjC,EAAA,MAAM,SAAA,GAAY,cACd,8BAAA,GACA,8BAAA;AAEJ,EAAA,uBACEA,GAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,EAAA,CAAG,SAAA,EAAW,CAAC,WAAA,IAAe,eAAA,CAAgB,QAAQ,CAAA,EAAG,SAAS,GAC/E,QAAA,EACH,CAAA;AAEJ","file":"chunk-H3NFL3GJ.js","sourcesContent":["import { cn } from \"../utils\";\r\nimport type { ReactNode } from \"react\";\r\n\r\ntype Background = \"default\" | \"muted\" | \"primary\" | \"transparent\";\r\ntype Padding = \"none\" | \"sm\" | \"md\" | \"lg\" | \"xl\";\r\n\r\nexport interface SectionProps {\r\n id?: string;\r\n children: ReactNode;\r\n className?: string;\r\n background?: Background;\r\n padding?: Padding;\r\n}\r\n\r\nconst backgrounds: Record<Background, string> = {\r\n default: \"bg-background\",\r\n muted: \"bg-muted\",\r\n primary: \"bg-primary text-primary-foreground\",\r\n transparent: \"bg-transparent\",\r\n};\r\n\r\nconst paddings: Record<Padding, string> = {\r\n none: \"\",\r\n sm: \"py-8 md:py-12\",\r\n md: \"py-12 md:py-16\",\r\n lg: \"py-16 md:py-24\",\r\n xl: \"py-24 md:py-32\",\r\n};\r\n\r\nexport function Section({\r\n id,\r\n children,\r\n className,\r\n background = \"default\",\r\n padding = \"sm\",\r\n}: SectionProps) {\r\n return (\r\n <section\r\n id={id}\r\n className={cn(backgrounds[background], paddings[padding], className)}\r\n >\r\n {children}\r\n </section>\r\n );\r\n}\r\n","import { cn } from \"../utils\";\r\nimport type { ReactNode } from \"react\";\r\n\r\ntype MaxWidth = \"sm\" | \"md\" | \"lg\" | \"xl\" | \"2xl\" | \"4xl\" | \"5xl\" | \"6xl\" | \"7xl\" | \"full\";\r\n\r\nexport interface ContainerProps {\r\n children: ReactNode;\r\n className?: string;\r\n maxWidth?: MaxWidth;\r\n}\r\n\r\nconst maxWidthClasses: Record<MaxWidth, string> = {\r\n sm: \"max-w-screen-sm\",\r\n md: \"max-w-screen-md\",\r\n lg: \"max-w-screen-lg\",\r\n xl: \"max-w-screen-xl\",\r\n \"2xl\": \"max-w-screen-2xl\",\r\n \"4xl\": \"max-w-4xl\",\r\n \"5xl\": \"max-w-5xl\",\r\n \"6xl\": \"max-w-6xl\",\r\n \"7xl\": \"max-w-7xl\",\r\n full: \"max-w-full\",\r\n};\r\n\r\nexport function Container({\r\n children,\r\n className,\r\n maxWidth = \"7xl\",\r\n}: ContainerProps) {\r\n const isFullWidth = maxWidth === \"full\";\r\n const baseClass = isFullWidth\r\n ? \"w-full px-4 sm:px-6 lg:px-10\"\r\n : \"mx-auto px-4 sm:px-6 lg:px-8\";\r\n\r\n return (\r\n <div className={cn(baseClass, !isFullWidth && maxWidthClasses[maxWidth], className)}>\r\n {children}\r\n </div>\r\n );\r\n}\r\n"]}
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
import { cn } from './chunk-GUHK2DTW.js';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import { memo, useMemo, useCallback } from 'react';
|
|
4
|
+
import { LoaderIcon } from 'lucide-react';
|
|
5
|
+
import { Button } from '@/components/ui/button';
|
|
6
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
7
|
+
import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetDescription, SheetFooter } from '@/components/ui/sheet';
|
|
8
|
+
|
|
9
|
+
var MOBILE_BREAKPOINT = 768;
|
|
10
|
+
function useIsMobile() {
|
|
11
|
+
const [isMobile, setIsMobile] = React.useState(void 0);
|
|
12
|
+
React.useEffect(() => {
|
|
13
|
+
const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
|
|
14
|
+
const onChange = () => {
|
|
15
|
+
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
|
|
16
|
+
};
|
|
17
|
+
mql.addEventListener("change", onChange);
|
|
18
|
+
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
|
|
19
|
+
return () => mql.removeEventListener("change", onChange);
|
|
20
|
+
}, []);
|
|
21
|
+
return !!isMobile;
|
|
22
|
+
}
|
|
23
|
+
function ClientSubmitButton({
|
|
24
|
+
children,
|
|
25
|
+
disabled,
|
|
26
|
+
loading = false,
|
|
27
|
+
loadingText,
|
|
28
|
+
className,
|
|
29
|
+
variant,
|
|
30
|
+
size,
|
|
31
|
+
form,
|
|
32
|
+
...props
|
|
33
|
+
}) {
|
|
34
|
+
const isDisabled = loading || disabled;
|
|
35
|
+
const content = loading && loadingText ? loadingText : children;
|
|
36
|
+
return /* @__PURE__ */ jsxs(
|
|
37
|
+
Button,
|
|
38
|
+
{
|
|
39
|
+
type: "submit",
|
|
40
|
+
form,
|
|
41
|
+
"aria-disabled": isDisabled,
|
|
42
|
+
"aria-busy": loading,
|
|
43
|
+
className: cn("relative", className),
|
|
44
|
+
disabled: isDisabled,
|
|
45
|
+
variant,
|
|
46
|
+
size,
|
|
47
|
+
...props,
|
|
48
|
+
children: [
|
|
49
|
+
content,
|
|
50
|
+
loading && /* @__PURE__ */ jsx("span", { className: "animate-spin absolute right-4", children: /* @__PURE__ */ jsx(LoaderIcon, {}) }),
|
|
51
|
+
/* @__PURE__ */ jsx("span", { "aria-live": "polite", className: "sr-only", role: "status", children: loading ? "Loading" : "Submit form" })
|
|
52
|
+
]
|
|
53
|
+
}
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
var SIZE_VARIANTS = {
|
|
57
|
+
sm: "sm:!max-w-md",
|
|
58
|
+
default: "w-full sm:!max-w-md md:!max-w-lg",
|
|
59
|
+
lg: "w-full sm:!max-w-lg md:!max-w-2xl lg:!max-w-4xl",
|
|
60
|
+
xl: "w-full sm:!max-w-2xl md:!max-w-4xl lg:!max-w-5xl",
|
|
61
|
+
full: "w-full !max-w-full",
|
|
62
|
+
mobile: "w-[85%] !max-w-sm",
|
|
63
|
+
"mobile-nav": "!w-[300px] sm:!w-[350px]"
|
|
64
|
+
};
|
|
65
|
+
var getPadding = (size, type = "default") => {
|
|
66
|
+
const isFullSize = size === "full";
|
|
67
|
+
if (type === "header" || type === "footer") {
|
|
68
|
+
return isFullSize ? "px-6 lg:px-8" : "px-4";
|
|
69
|
+
}
|
|
70
|
+
return isFullSize ? "p-6 lg:p-8" : "p-4";
|
|
71
|
+
};
|
|
72
|
+
var SheetWrapper = memo(function SheetWrapper2({
|
|
73
|
+
open,
|
|
74
|
+
onOpenChange,
|
|
75
|
+
title,
|
|
76
|
+
description,
|
|
77
|
+
children,
|
|
78
|
+
footer,
|
|
79
|
+
header,
|
|
80
|
+
side = "right",
|
|
81
|
+
size = "default",
|
|
82
|
+
modal = true,
|
|
83
|
+
className,
|
|
84
|
+
headerClassName,
|
|
85
|
+
contentClassName,
|
|
86
|
+
footerClassName,
|
|
87
|
+
innerClassName,
|
|
88
|
+
hideHeader = false,
|
|
89
|
+
hideTitle = false,
|
|
90
|
+
hideDescription = false,
|
|
91
|
+
hideCloseButton = false,
|
|
92
|
+
disableContentPadding = false
|
|
93
|
+
}) {
|
|
94
|
+
const computedClasses = useMemo(
|
|
95
|
+
() => ({
|
|
96
|
+
header: cn(
|
|
97
|
+
"border-b pb-4 pt-6",
|
|
98
|
+
getPadding(size, "header"),
|
|
99
|
+
headerClassName
|
|
100
|
+
),
|
|
101
|
+
inner: cn(
|
|
102
|
+
"flex-1 overflow-y-auto",
|
|
103
|
+
!disableContentPadding && getPadding(size),
|
|
104
|
+
innerClassName
|
|
105
|
+
),
|
|
106
|
+
footer: cn(
|
|
107
|
+
"border-t bg-muted/30 pt-4 pb-6 mt-auto",
|
|
108
|
+
getPadding(size, "footer"),
|
|
109
|
+
footerClassName
|
|
110
|
+
)
|
|
111
|
+
}),
|
|
112
|
+
[
|
|
113
|
+
size,
|
|
114
|
+
headerClassName,
|
|
115
|
+
innerClassName,
|
|
116
|
+
footerClassName,
|
|
117
|
+
disableContentPadding
|
|
118
|
+
]
|
|
119
|
+
);
|
|
120
|
+
const shouldHideTitle = !!header || hideTitle;
|
|
121
|
+
const shouldHideDescription = !!header || hideDescription;
|
|
122
|
+
return /* @__PURE__ */ jsx(Sheet, { open, onOpenChange, modal, children: /* @__PURE__ */ jsxs(
|
|
123
|
+
SheetContent,
|
|
124
|
+
{
|
|
125
|
+
side,
|
|
126
|
+
showCloseButton: !hideCloseButton,
|
|
127
|
+
className: cn(
|
|
128
|
+
SIZE_VARIANTS[size],
|
|
129
|
+
"flex flex-col p-0",
|
|
130
|
+
contentClassName,
|
|
131
|
+
className
|
|
132
|
+
),
|
|
133
|
+
children: [
|
|
134
|
+
!hideHeader && /* @__PURE__ */ jsxs(SheetHeader, { className: computedClasses.header, children: [
|
|
135
|
+
/* @__PURE__ */ jsx(SheetTitle, { className: shouldHideTitle ? "sr-only" : "", children: title || "Sheet" }),
|
|
136
|
+
description && /* @__PURE__ */ jsx(
|
|
137
|
+
SheetDescription,
|
|
138
|
+
{
|
|
139
|
+
className: shouldHideDescription ? "sr-only" : "",
|
|
140
|
+
children: description
|
|
141
|
+
}
|
|
142
|
+
),
|
|
143
|
+
header
|
|
144
|
+
] }),
|
|
145
|
+
/* @__PURE__ */ jsx("div", { className: computedClasses.inner, children }),
|
|
146
|
+
footer && /* @__PURE__ */ jsx(SheetFooter, { className: computedClasses.footer, children: footer })
|
|
147
|
+
]
|
|
148
|
+
}
|
|
149
|
+
) });
|
|
150
|
+
});
|
|
151
|
+
var FormSheet = memo(function FormSheet2({
|
|
152
|
+
open,
|
|
153
|
+
onOpenChange,
|
|
154
|
+
title,
|
|
155
|
+
description,
|
|
156
|
+
children,
|
|
157
|
+
onSubmit,
|
|
158
|
+
onCancel,
|
|
159
|
+
submitLabel = "Submit",
|
|
160
|
+
cancelLabel = "Cancel",
|
|
161
|
+
submitDisabled = false,
|
|
162
|
+
submitLoading = false,
|
|
163
|
+
formId,
|
|
164
|
+
size = "lg",
|
|
165
|
+
...props
|
|
166
|
+
}) {
|
|
167
|
+
const handleCancel = useCallback(() => {
|
|
168
|
+
onCancel?.();
|
|
169
|
+
onOpenChange?.(false);
|
|
170
|
+
}, [onCancel, onOpenChange]);
|
|
171
|
+
const footer = useMemo(
|
|
172
|
+
() => /* @__PURE__ */ jsxs("div", { className: "flex flex-col sm:flex-row gap-2 w-full", children: [
|
|
173
|
+
/* @__PURE__ */ jsx(
|
|
174
|
+
Button,
|
|
175
|
+
{
|
|
176
|
+
type: "button",
|
|
177
|
+
variant: "outline",
|
|
178
|
+
className: "flex-1",
|
|
179
|
+
onClick: handleCancel,
|
|
180
|
+
disabled: submitDisabled || submitLoading,
|
|
181
|
+
children: cancelLabel
|
|
182
|
+
}
|
|
183
|
+
),
|
|
184
|
+
/* @__PURE__ */ jsx(
|
|
185
|
+
ClientSubmitButton,
|
|
186
|
+
{
|
|
187
|
+
form: formId,
|
|
188
|
+
className: "flex-1",
|
|
189
|
+
disabled: submitDisabled,
|
|
190
|
+
loading: submitLoading,
|
|
191
|
+
loadingText: "Saving...",
|
|
192
|
+
children: submitLabel
|
|
193
|
+
}
|
|
194
|
+
)
|
|
195
|
+
] }),
|
|
196
|
+
[
|
|
197
|
+
cancelLabel,
|
|
198
|
+
submitLabel,
|
|
199
|
+
submitDisabled,
|
|
200
|
+
submitLoading,
|
|
201
|
+
formId,
|
|
202
|
+
handleCancel
|
|
203
|
+
]
|
|
204
|
+
);
|
|
205
|
+
return /* @__PURE__ */ jsx(
|
|
206
|
+
SheetWrapper,
|
|
207
|
+
{
|
|
208
|
+
open,
|
|
209
|
+
onOpenChange,
|
|
210
|
+
title,
|
|
211
|
+
description,
|
|
212
|
+
size,
|
|
213
|
+
footer,
|
|
214
|
+
...props,
|
|
215
|
+
children
|
|
216
|
+
}
|
|
217
|
+
);
|
|
218
|
+
});
|
|
219
|
+
var ConfirmSheet = memo(function ConfirmSheet2({
|
|
220
|
+
open,
|
|
221
|
+
onOpenChange,
|
|
222
|
+
title = "Confirm Action",
|
|
223
|
+
description,
|
|
224
|
+
children,
|
|
225
|
+
onConfirm,
|
|
226
|
+
onCancel,
|
|
227
|
+
confirmLabel = "Confirm",
|
|
228
|
+
cancelLabel = "Cancel",
|
|
229
|
+
confirmVariant = "default",
|
|
230
|
+
confirmDisabled = false,
|
|
231
|
+
confirmLoading = false,
|
|
232
|
+
size = "sm",
|
|
233
|
+
...props
|
|
234
|
+
}) {
|
|
235
|
+
const handleConfirm = useCallback(() => {
|
|
236
|
+
onConfirm?.();
|
|
237
|
+
}, [onConfirm]);
|
|
238
|
+
const handleCancel = useCallback(() => {
|
|
239
|
+
onCancel?.();
|
|
240
|
+
onOpenChange?.(false);
|
|
241
|
+
}, [onCancel, onOpenChange]);
|
|
242
|
+
const footer = useMemo(
|
|
243
|
+
() => /* @__PURE__ */ jsxs("div", { className: "flex gap-2 w-full", children: [
|
|
244
|
+
/* @__PURE__ */ jsx(
|
|
245
|
+
Button,
|
|
246
|
+
{
|
|
247
|
+
type: "button",
|
|
248
|
+
variant: "outline",
|
|
249
|
+
className: "flex-1",
|
|
250
|
+
onClick: handleCancel,
|
|
251
|
+
children: cancelLabel
|
|
252
|
+
}
|
|
253
|
+
),
|
|
254
|
+
/* @__PURE__ */ jsx(
|
|
255
|
+
Button,
|
|
256
|
+
{
|
|
257
|
+
type: "button",
|
|
258
|
+
variant: confirmVariant,
|
|
259
|
+
className: "flex-1",
|
|
260
|
+
onClick: handleConfirm,
|
|
261
|
+
disabled: confirmDisabled || confirmLoading,
|
|
262
|
+
children: confirmLoading ? "Loading..." : confirmLabel
|
|
263
|
+
}
|
|
264
|
+
)
|
|
265
|
+
] }),
|
|
266
|
+
[
|
|
267
|
+
cancelLabel,
|
|
268
|
+
confirmLabel,
|
|
269
|
+
confirmVariant,
|
|
270
|
+
confirmDisabled,
|
|
271
|
+
confirmLoading,
|
|
272
|
+
handleConfirm,
|
|
273
|
+
handleCancel
|
|
274
|
+
]
|
|
275
|
+
);
|
|
276
|
+
return /* @__PURE__ */ jsx(
|
|
277
|
+
SheetWrapper,
|
|
278
|
+
{
|
|
279
|
+
open,
|
|
280
|
+
onOpenChange,
|
|
281
|
+
title,
|
|
282
|
+
description,
|
|
283
|
+
size,
|
|
284
|
+
footer,
|
|
285
|
+
...props,
|
|
286
|
+
children
|
|
287
|
+
}
|
|
288
|
+
);
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
export { ClientSubmitButton, ConfirmSheet, FormSheet, SheetWrapper, useIsMobile };
|
|
292
|
+
//# sourceMappingURL=chunk-J2YRTQE4.js.map
|
|
293
|
+
//# sourceMappingURL=chunk-J2YRTQE4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/hooks/use-mobile.ts","../src/components/client-submit-button.tsx","../src/components/sheet-wrapper.tsx"],"names":["SheetWrapper","jsx","jsxs","FormSheet","Button","ConfirmSheet"],"mappings":"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","file":"chunk-J2YRTQE4.js","sourcesContent":["\"use client\";\r\n\r\nimport * as React from \"react\";\r\n\r\nconst MOBILE_BREAKPOINT = 768;\r\n\r\nexport function useIsMobile() {\r\n const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined);\r\n\r\n React.useEffect(() => {\r\n const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);\r\n const onChange = () => {\r\n setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);\r\n };\r\n mql.addEventListener(\"change\", onChange);\r\n setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);\r\n return () => mql.removeEventListener(\"change\", onChange);\r\n }, []);\r\n\r\n return !!isMobile;\r\n}\r\n","\"use client\";\r\n\r\nimport { ReactNode } from \"react\";\r\nimport { LoaderIcon } from \"lucide-react\";\r\nimport { Button } from \"@/components/ui/button\";\r\nimport { cn } from \"../utils\";\r\n\r\nexport interface ClientSubmitButtonProps {\r\n children: ReactNode;\r\n disabled?: boolean;\r\n loading?: boolean;\r\n loadingText?: string;\r\n className?: string;\r\n variant?: \"default\" | \"destructive\" | \"outline\" | \"secondary\" | \"ghost\" | \"link\";\r\n size?: \"default\" | \"sm\" | \"lg\" | \"icon\";\r\n form?: string;\r\n}\r\n\r\nexport function ClientSubmitButton({\r\n children,\r\n disabled,\r\n loading = false,\r\n loadingText,\r\n className,\r\n variant,\r\n size,\r\n form,\r\n ...props\r\n}: ClientSubmitButtonProps) {\r\n const isDisabled = loading || disabled;\r\n const content = loading && loadingText ? loadingText : children;\r\n\r\n return (\r\n <Button\r\n type=\"submit\"\r\n form={form}\r\n aria-disabled={isDisabled}\r\n aria-busy={loading}\r\n className={cn(\"relative\", className)}\r\n disabled={isDisabled}\r\n variant={variant}\r\n size={size}\r\n {...props}\r\n >\r\n {content}\r\n {loading && (\r\n <span className=\"animate-spin absolute right-4\">\r\n <LoaderIcon />\r\n </span>\r\n )}\r\n <span aria-live=\"polite\" className=\"sr-only\" role=\"status\">\r\n {loading ? \"Loading\" : \"Submit form\"}\r\n </span>\r\n </Button>\r\n );\r\n}\r\n","\"use client\";\r\n\r\nimport { memo, useMemo, useCallback, type ReactNode } from \"react\";\r\nimport {\r\n Sheet,\r\n SheetContent,\r\n SheetHeader,\r\n SheetTitle,\r\n SheetDescription,\r\n SheetFooter,\r\n} from \"@/components/ui/sheet\";\r\nimport { Button } from \"@/components/ui/button\";\r\nimport { ClientSubmitButton } from \"./client-submit-button\";\r\nimport { cn } from \"../utils\";\r\n\r\n// Size variants configuration\r\n// !important is required here because the base SheetContent uses data-attribute\r\n// selectors (data-[side=right]:sm:max-w-sm) which add CSS specificity that plain\r\n// utility classes cannot override via tailwind-merge.\r\nconst SIZE_VARIANTS = {\r\n sm: \"sm:!max-w-md\",\r\n default: \"w-full sm:!max-w-md md:!max-w-lg\",\r\n lg: \"w-full sm:!max-w-lg md:!max-w-2xl lg:!max-w-4xl\",\r\n xl: \"w-full sm:!max-w-2xl md:!max-w-4xl lg:!max-w-5xl\",\r\n full: \"w-full !max-w-full\",\r\n mobile: \"w-[85%] !max-w-sm\",\r\n \"mobile-nav\": \"!w-[300px] sm:!w-[350px]\",\r\n} as const;\r\n\r\ntype SizeVariant = keyof typeof SIZE_VARIANTS;\r\n\r\nconst getPadding = (\r\n size: SizeVariant,\r\n type: \"default\" | \"header\" | \"footer\" = \"default\",\r\n) => {\r\n const isFullSize = size === \"full\";\r\n\r\n if (type === \"header\" || type === \"footer\") {\r\n return isFullSize ? \"px-6 lg:px-8\" : \"px-4\";\r\n }\r\n\r\n return isFullSize ? \"p-6 lg:p-8\" : \"p-4\";\r\n};\r\n\r\nexport interface SheetWrapperProps {\r\n open: boolean;\r\n onOpenChange: (open: boolean) => void;\r\n title?: string;\r\n description?: string;\r\n children?: ReactNode;\r\n footer?: ReactNode;\r\n header?: ReactNode;\r\n side?: \"top\" | \"bottom\" | \"left\" | \"right\";\r\n size?: SizeVariant;\r\n modal?: boolean;\r\n className?: string;\r\n headerClassName?: string;\r\n contentClassName?: string;\r\n footerClassName?: string;\r\n innerClassName?: string;\r\n hideHeader?: boolean;\r\n hideTitle?: boolean;\r\n hideDescription?: boolean;\r\n hideCloseButton?: boolean;\r\n disableContentPadding?: boolean;\r\n}\r\n\r\nexport const SheetWrapper = memo(function SheetWrapper({\r\n open,\r\n onOpenChange,\r\n title,\r\n description,\r\n children,\r\n footer,\r\n header,\r\n side = \"right\",\r\n size = \"default\",\r\n modal = true,\r\n className,\r\n headerClassName,\r\n contentClassName,\r\n footerClassName,\r\n innerClassName,\r\n hideHeader = false,\r\n hideTitle = false,\r\n hideDescription = false,\r\n hideCloseButton = false,\r\n disableContentPadding = false,\r\n}: SheetWrapperProps) {\r\n const computedClasses = useMemo(\r\n () => ({\r\n header: cn(\r\n \"border-b pb-4 pt-6\",\r\n getPadding(size, \"header\"),\r\n headerClassName,\r\n ),\r\n inner: cn(\r\n \"flex-1 overflow-y-auto\",\r\n !disableContentPadding && getPadding(size),\r\n innerClassName,\r\n ),\r\n footer: cn(\r\n \"border-t bg-muted/30 pt-4 pb-6 mt-auto\",\r\n getPadding(size, \"footer\"),\r\n footerClassName,\r\n ),\r\n }),\r\n [\r\n size,\r\n headerClassName,\r\n innerClassName,\r\n footerClassName,\r\n disableContentPadding,\r\n ],\r\n );\r\n\r\n const shouldHideTitle = !!header || hideTitle;\r\n const shouldHideDescription = !!header || hideDescription;\r\n\r\n return (\r\n <Sheet open={open} onOpenChange={onOpenChange} modal={modal}>\r\n <SheetContent\r\n side={side}\r\n showCloseButton={!hideCloseButton}\r\n className={cn(\r\n SIZE_VARIANTS[size],\r\n \"flex flex-col p-0\",\r\n contentClassName,\r\n className,\r\n )}\r\n >\r\n {!hideHeader && (\r\n <SheetHeader className={computedClasses.header}>\r\n <SheetTitle className={shouldHideTitle ? \"sr-only\" : \"\"}>\r\n {title || \"Sheet\"}\r\n </SheetTitle>\r\n {description && (\r\n <SheetDescription\r\n className={shouldHideDescription ? \"sr-only\" : \"\"}\r\n >\r\n {description}\r\n </SheetDescription>\r\n )}\r\n {header}\r\n </SheetHeader>\r\n )}\r\n\r\n <div className={computedClasses.inner}>{children}</div>\r\n\r\n {footer && (\r\n <SheetFooter className={computedClasses.footer}>{footer}</SheetFooter>\r\n )}\r\n </SheetContent>\r\n </Sheet>\r\n );\r\n});\r\n\r\nexport interface FormSheetProps extends Omit<SheetWrapperProps, \"footer\"> {\r\n onSubmit?: () => void;\r\n onCancel?: () => void;\r\n submitLabel?: string;\r\n cancelLabel?: string;\r\n submitDisabled?: boolean;\r\n submitLoading?: boolean;\r\n formId?: string;\r\n}\r\n\r\nexport const FormSheet = memo(function FormSheet({\r\n open,\r\n onOpenChange,\r\n title,\r\n description,\r\n children,\r\n onSubmit,\r\n onCancel,\r\n submitLabel = \"Submit\",\r\n cancelLabel = \"Cancel\",\r\n submitDisabled = false,\r\n submitLoading = false,\r\n formId,\r\n size = \"lg\",\r\n ...props\r\n}: FormSheetProps) {\r\n const handleCancel = useCallback(() => {\r\n onCancel?.();\r\n onOpenChange?.(false);\r\n }, [onCancel, onOpenChange]);\r\n\r\n const footer = useMemo(\r\n () => (\r\n <div className=\"flex flex-col sm:flex-row gap-2 w-full\">\r\n <Button\r\n type=\"button\"\r\n variant=\"outline\"\r\n className=\"flex-1\"\r\n onClick={handleCancel}\r\n disabled={submitDisabled || submitLoading}\r\n >\r\n {cancelLabel}\r\n </Button>\r\n <ClientSubmitButton\r\n form={formId}\r\n className=\"flex-1\"\r\n disabled={submitDisabled}\r\n loading={submitLoading}\r\n loadingText=\"Saving...\"\r\n >\r\n {submitLabel}\r\n </ClientSubmitButton>\r\n </div>\r\n ),\r\n [\r\n cancelLabel,\r\n submitLabel,\r\n submitDisabled,\r\n submitLoading,\r\n formId,\r\n handleCancel,\r\n ],\r\n );\r\n\r\n return (\r\n <SheetWrapper\r\n open={open}\r\n onOpenChange={onOpenChange}\r\n title={title}\r\n description={description}\r\n size={size}\r\n footer={footer}\r\n {...props}\r\n >\r\n {children}\r\n </SheetWrapper>\r\n );\r\n});\r\n\r\nexport interface ConfirmSheetProps extends Omit<SheetWrapperProps, \"footer\"> {\r\n onConfirm?: () => void;\r\n onCancel?: () => void;\r\n confirmLabel?: string;\r\n cancelLabel?: string;\r\n confirmVariant?:\r\n | \"default\"\r\n | \"destructive\"\r\n | \"outline\"\r\n | \"secondary\"\r\n | \"ghost\"\r\n | \"link\";\r\n confirmDisabled?: boolean;\r\n confirmLoading?: boolean;\r\n}\r\n\r\nexport const ConfirmSheet = memo(function ConfirmSheet({\r\n open,\r\n onOpenChange,\r\n title = \"Confirm Action\",\r\n description,\r\n children,\r\n onConfirm,\r\n onCancel,\r\n confirmLabel = \"Confirm\",\r\n cancelLabel = \"Cancel\",\r\n confirmVariant = \"default\",\r\n confirmDisabled = false,\r\n confirmLoading = false,\r\n size = \"sm\",\r\n ...props\r\n}: ConfirmSheetProps) {\r\n const handleConfirm = useCallback(() => {\r\n onConfirm?.();\r\n }, [onConfirm]);\r\n\r\n const handleCancel = useCallback(() => {\r\n onCancel?.();\r\n onOpenChange?.(false);\r\n }, [onCancel, onOpenChange]);\r\n\r\n const footer = useMemo(\r\n () => (\r\n <div className=\"flex gap-2 w-full\">\r\n <Button\r\n type=\"button\"\r\n variant=\"outline\"\r\n className=\"flex-1\"\r\n onClick={handleCancel}\r\n >\r\n {cancelLabel}\r\n </Button>\r\n <Button\r\n type=\"button\"\r\n variant={confirmVariant}\r\n className=\"flex-1\"\r\n onClick={handleConfirm}\r\n disabled={confirmDisabled || confirmLoading}\r\n >\r\n {confirmLoading ? \"Loading...\" : confirmLabel}\r\n </Button>\r\n </div>\r\n ),\r\n [\r\n cancelLabel,\r\n confirmLabel,\r\n confirmVariant,\r\n confirmDisabled,\r\n confirmLoading,\r\n handleConfirm,\r\n handleCancel,\r\n ],\r\n );\r\n\r\n return (\r\n <SheetWrapper\r\n open={open}\r\n onOpenChange={onOpenChange}\r\n title={title}\r\n description={description}\r\n size={size}\r\n footer={footer}\r\n {...props}\r\n >\r\n {children}\r\n </SheetWrapper>\r\n );\r\n});\r\n"]}
|