@trackany-device/components 1.0.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/package.json +185 -0
- package/src/assets/logo.png +0 -0
- package/src/assets/map/arrows/map-arrow-blue.png +0 -0
- package/src/assets/map/arrows/map-arrow-green.png +0 -0
- package/src/assets/map/arrows/map-arrow-purple.png +0 -0
- package/src/assets/map/arrows/map-arrow-red.png +0 -0
- package/src/assets/map/flags/flag-blue.png +0 -0
- package/src/assets/map/flags/flag-green.png +0 -0
- package/src/assets/map/flags/flag-red.png +0 -0
- package/src/assets/map/flags/flag-yellow.png +0 -0
- package/src/assets/map/pins/map-pin-blue.png +0 -0
- package/src/assets/map/pins/map-pin-green.png +0 -0
- package/src/assets/map/pins/map-pin-purple.png +0 -0
- package/src/assets/map/pins/map-pin-red.png +0 -0
- package/src/components/Card.tsx +9 -0
- package/src/components/alert-error.tsx +24 -0
- package/src/components/app-content.tsx +22 -0
- package/src/components/app-header.tsx +153 -0
- package/src/components/app-logo-icon.tsx +13 -0
- package/src/components/app-logo.tsx +21 -0
- package/src/components/app-shell.tsx +19 -0
- package/src/components/app-sidebar-header.tsx +68 -0
- package/src/components/app-sidebar.tsx +106 -0
- package/src/components/appearance-tabs.tsx +46 -0
- package/src/components/breadcrumbs.tsx +50 -0
- package/src/components/cms/blurred-image.tsx +111 -0
- package/src/components/cms/section-bg.tsx +473 -0
- package/src/components/cms/section-button.tsx +127 -0
- package/src/components/cms/sections/banner-5050-section.tsx +135 -0
- package/src/components/cms/sections/blogs-listing-section.tsx +270 -0
- package/src/components/cms/sections/cards-grid-section.tsx +185 -0
- package/src/components/cms/sections/contact-form-section.tsx +157 -0
- package/src/components/cms/sections/cta-section.tsx +101 -0
- package/src/components/cms/sections/featured-blog-slider-section.tsx +256 -0
- package/src/components/cms/sections/featured-products-grid-section.tsx +173 -0
- package/src/components/cms/sections/featured-solutions-grid-section.tsx +183 -0
- package/src/components/cms/sections/hero-section.tsx +180 -0
- package/src/components/cms/sections/solutions-with-filter-section.tsx +234 -0
- package/src/components/cms/sections/text-section.tsx +77 -0
- package/src/components/cutout-image.tsx +228 -0
- package/src/components/devices/devices-mini-map.tsx +275 -0
- package/src/components/docs/docs-shell.tsx +280 -0
- package/src/components/fleet-hero-animated.tsx +383 -0
- package/src/components/input-error.tsx +17 -0
- package/src/components/keenicons/assets/duotone/Read Me.txt +7 -0
- package/src/components/keenicons/assets/duotone/demo-files/demo.css +160 -0
- package/src/components/keenicons/assets/duotone/demo-files/demo.js +32 -0
- package/src/components/keenicons/assets/duotone/demo.html +12424 -0
- package/src/components/keenicons/assets/duotone/fonts/keenicons-duotone.svg +1109 -0
- package/src/components/keenicons/assets/duotone/fonts/keenicons-duotone.ttf +0 -0
- package/src/components/keenicons/assets/duotone/fonts/keenicons-duotone.woff +0 -0
- package/src/components/keenicons/assets/duotone/selection.json +17313 -0
- package/src/components/keenicons/assets/duotone/style.css +4931 -0
- package/src/components/keenicons/assets/filled/Read Me.txt +7 -0
- package/src/components/keenicons/assets/filled/demo-files/demo.css +160 -0
- package/src/components/keenicons/assets/filled/demo-files/demo.js +32 -0
- package/src/components/keenicons/assets/filled/demo.html +12370 -0
- package/src/components/keenicons/assets/filled/fonts/keenicons-filled.svg +1082 -0
- package/src/components/keenicons/assets/filled/fonts/keenicons-filled.ttf +0 -0
- package/src/components/keenicons/assets/filled/fonts/keenicons-filled.woff +0 -0
- package/src/components/keenicons/assets/filled/selection.json +17096 -0
- package/src/components/keenicons/assets/filled/style.css +4769 -0
- package/src/components/keenicons/assets/outline/Read Me.txt +7 -0
- package/src/components/keenicons/assets/outline/demo-files/demo.css +160 -0
- package/src/components/keenicons/assets/outline/demo-files/demo.js +32 -0
- package/src/components/keenicons/assets/outline/demo.html +11356 -0
- package/src/components/keenicons/assets/outline/fonts/keenicons-outline.svg +575 -0
- package/src/components/keenicons/assets/outline/fonts/keenicons-outline.ttf +0 -0
- package/src/components/keenicons/assets/outline/fonts/keenicons-outline.woff +0 -0
- package/src/components/keenicons/assets/outline/selection.json +13054 -0
- package/src/components/keenicons/assets/outline/style.css +1721 -0
- package/src/components/keenicons/assets/solid/Read Me.txt +7 -0
- package/src/components/keenicons/assets/solid/demo-files/demo.css +160 -0
- package/src/components/keenicons/assets/solid/demo-files/demo.js +32 -0
- package/src/components/keenicons/assets/solid/demo.html +11356 -0
- package/src/components/keenicons/assets/solid/fonts/keenicons-solid.svg +575 -0
- package/src/components/keenicons/assets/solid/fonts/keenicons-solid.ttf +0 -0
- package/src/components/keenicons/assets/solid/fonts/keenicons-solid.woff +0 -0
- package/src/components/keenicons/assets/solid/selection.json +13048 -0
- package/src/components/keenicons/assets/solid/style.css +1721 -0
- package/src/components/keenicons/assets/styles.css +4 -0
- package/src/components/keenicons/index.ts +2 -0
- package/src/components/keenicons/keenicons.tsx +16 -0
- package/src/components/keenicons/types.ts +7 -0
- package/src/components/nav-footer.tsx +49 -0
- package/src/components/nav-main.tsx +53 -0
- package/src/components/nav-user.tsx +59 -0
- package/src/components/notification-bell.tsx +190 -0
- package/src/components/products/product-card.tsx +159 -0
- package/src/components/text-link.tsx +23 -0
- package/src/components/ui/accordion-menu.tsx +322 -0
- package/src/components/ui/accordion.tsx +133 -0
- package/src/components/ui/alert-dialog.tsx +82 -0
- package/src/components/ui/alert.tsx +63 -0
- package/src/components/ui/avatar-group.tsx +129 -0
- package/src/components/ui/avatar.tsx +67 -0
- package/src/components/ui/badge.tsx +230 -0
- package/src/components/ui/breadcrumb.tsx +88 -0
- package/src/components/ui/button.tsx +412 -0
- package/src/components/ui/calendar.tsx +56 -0
- package/src/components/ui/card.tsx +147 -0
- package/src/components/ui/chart.tsx +290 -0
- package/src/components/ui/checkbox.tsx +47 -0
- package/src/components/ui/code.tsx +45 -0
- package/src/components/ui/collapsible.tsx +31 -0
- package/src/components/ui/command-palette.tsx +189 -0
- package/src/components/ui/command.tsx +138 -0
- package/src/components/ui/cookie-banner.tsx +220 -0
- package/src/components/ui/copy-button.tsx +60 -0
- package/src/components/ui/data-grid-column-filter.tsx +124 -0
- package/src/components/ui/data-grid-column-header.tsx +284 -0
- package/src/components/ui/data-grid-column-visibility.tsx +38 -0
- package/src/components/ui/data-grid-pagination.tsx +206 -0
- package/src/components/ui/data-grid-table-dnd-rows.tsx +147 -0
- package/src/components/ui/data-grid-table-dnd.tsx +175 -0
- package/src/components/ui/data-grid-table.tsx +500 -0
- package/src/components/ui/data-grid.tsx +193 -0
- package/src/components/ui/data-list.tsx +76 -0
- package/src/components/ui/datefield.tsx +91 -0
- package/src/components/ui/dialog.tsx +139 -0
- package/src/components/ui/divider.tsx +41 -0
- package/src/components/ui/drawer.tsx +59 -0
- package/src/components/ui/dropdown-menu.tsx +224 -0
- package/src/components/ui/empty-state.tsx +54 -0
- package/src/components/ui/file-upload.tsx +152 -0
- package/src/components/ui/form.tsx +88 -0
- package/src/components/ui/icon.tsx +14 -0
- package/src/components/ui/input-otp.tsx +71 -0
- package/src/components/ui/input.tsx +155 -0
- package/src/components/ui/kbd.tsx +26 -0
- package/src/components/ui/label.tsx +31 -0
- package/src/components/ui/navigation-menu.tsx +168 -0
- package/src/components/ui/pagination.tsx +37 -0
- package/src/components/ui/placeholder-pattern.tsx +21 -0
- package/src/components/ui/popover.tsx +50 -0
- package/src/components/ui/progress.tsx +65 -0
- package/src/components/ui/radio-group.tsx +73 -0
- package/src/components/ui/resizable.tsx +39 -0
- package/src/components/ui/scroll-area.tsx +50 -0
- package/src/components/ui/select.tsx +234 -0
- package/src/components/ui/separator.tsx +24 -0
- package/src/components/ui/sheet.tsx +147 -0
- package/src/components/ui/sidebar.tsx +721 -0
- package/src/components/ui/skeleton.tsx +15 -0
- package/src/components/ui/slider.tsx +35 -0
- package/src/components/ui/sonner.tsx +28 -0
- package/src/components/ui/sortable.tsx +724 -0
- package/src/components/ui/spinner.tsx +17 -0
- package/src/components/ui/stat-card.tsx +82 -0
- package/src/components/ui/stepper.tsx +410 -0
- package/src/components/ui/switch.tsx +68 -0
- package/src/components/ui/table.tsx +42 -0
- package/src/components/ui/tabs.tsx +196 -0
- package/src/components/ui/timeline.tsx +90 -0
- package/src/components/ui/toggle-group.tsx +73 -0
- package/src/components/ui/toggle.tsx +45 -0
- package/src/components/ui/tooltip.tsx +55 -0
- package/src/components/user-info.tsx +33 -0
- package/src/components/user-menu-content.tsx +53 -0
- package/src/components/web/SiteFooter.tsx +154 -0
- package/src/components/web/SiteHeader.tsx +159 -0
- package/src/components/workflows/workflow-canvas.tsx +321 -0
- package/src/controls/Blockquote.tsx +25 -0
- package/src/controls/Button.tsx +101 -0
- package/src/controls/Checkbox.tsx +29 -0
- package/src/controls/DateField.tsx +37 -0
- package/src/controls/FormField.tsx +20 -0
- package/src/controls/Heading.tsx +28 -0
- package/src/controls/Input.tsx +21 -0
- package/src/controls/Label.tsx +18 -0
- package/src/controls/Paragraph.tsx +39 -0
- package/src/controls/PasswordInput.tsx +40 -0
- package/src/controls/RadioGroup.tsx +70 -0
- package/src/controls/Select.tsx +24 -0
- package/src/controls/Slider.tsx +33 -0
- package/src/controls/Switch.tsx +31 -0
- package/src/controls/Textarea.tsx +22 -0
- package/src/elements/ConfirmPasswordForm.tsx +43 -0
- package/src/elements/DeviceStatusBadge.tsx +38 -0
- package/src/elements/DriverCard.tsx +67 -0
- package/src/elements/ForgotPasswordForm.tsx +64 -0
- package/src/elements/IncidentCard.tsx +67 -0
- package/src/elements/LoginForm.tsx +100 -0
- package/src/elements/OtpForm.tsx +71 -0
- package/src/elements/RegisterForm.tsx +150 -0
- package/src/elements/ResetPasswordForm.tsx +72 -0
- package/src/elements/SmsChallengeForm.tsx +104 -0
- package/src/elements/VehicleCard.tsx +73 -0
- package/src/elements/VerifyEmailForm.tsx +39 -0
- package/src/hooks/use-appearance.tsx +117 -0
- package/src/hooks/use-applied-theme.ts +98 -0
- package/src/hooks/use-clipboard.ts +34 -0
- package/src/hooks/use-current-url.ts +83 -0
- package/src/hooks/use-dark-mode.ts +48 -0
- package/src/hooks/use-flash-toast.ts +29 -0
- package/src/hooks/use-initials.tsx +24 -0
- package/src/hooks/use-mobile-navigation.ts +12 -0
- package/src/hooks/use-mobile.tsx +38 -0
- package/src/index.ts +408 -0
- package/src/layouts/AppLayout.tsx +60 -0
- package/src/layouts/AuthLayout.tsx +32 -0
- package/src/layouts/SettingsLayout.tsx +21 -0
- package/src/layouts/app/AIChatLayout.tsx +73 -0
- package/src/layouts/app/AsideSidebarLayout.tsx +3 -0
- package/src/layouts/app/CalendarSidebarLayout.tsx +69 -0
- package/src/layouts/app/CommunitiesNavbarLayout.tsx +3 -0
- package/src/layouts/app/DualNavbarSidebarLayout.tsx +3 -0
- package/src/layouts/app/FocusSidebarLayout.tsx +75 -0
- package/src/layouts/app/MailLayout.tsx +69 -0
- package/src/layouts/app/MegaMenuHeaderLayout.tsx +3 -0
- package/src/layouts/app/MegaMenuLayout.tsx +81 -0
- package/src/layouts/app/MegaMenuNavbarLayout.tsx +88 -0
- package/src/layouts/app/MegaMenuSearchNavbarLayout.tsx +3 -0
- package/src/layouts/app/NavbarCollapsibleLayout.tsx +88 -0
- package/src/layouts/app/NavbarCollapsibleLinksLayout.tsx +3 -0
- package/src/layouts/app/NavbarMinimalLayout.tsx +3 -0
- package/src/layouts/app/NavbarMinimalSidebarLayout.tsx +3 -0
- package/src/layouts/app/NavbarSidebarDashboardLayout.tsx +3 -0
- package/src/layouts/app/NavbarSidebarLayout.tsx +92 -0
- package/src/layouts/app/NavbarSimpleSidebarLayout.tsx +3 -0
- package/src/layouts/app/NavbarTitledSidebarLayout.tsx +3 -0
- package/src/layouts/app/PanelSidebarLayout.tsx +3 -0
- package/src/layouts/app/SearchNavbarSidebarLayout.tsx +3 -0
- package/src/layouts/app/SidebarBreadcrumbLayout.tsx +3 -0
- package/src/layouts/app/SidebarCleanLayout.tsx +3 -0
- package/src/layouts/app/SidebarCommunitiesLayout.tsx +3 -0
- package/src/layouts/app/SidebarContentLayout.tsx +3 -0
- package/src/layouts/app/SidebarDualMenuLayout.tsx +104 -0
- package/src/layouts/app/SidebarFixedLayout.tsx +166 -0
- package/src/layouts/app/SidebarFooterNavbarLayout.tsx +3 -0
- package/src/layouts/app/SidebarHeaderMenuLayout.tsx +3 -0
- package/src/layouts/app/SidebarMegaMenuLayout.tsx +4 -0
- package/src/layouts/app/SidebarMinimalLayout.tsx +70 -0
- package/src/layouts/app/SidebarMobileSearchLayout.tsx +3 -0
- package/src/layouts/app/SidebarMultiPanelLayout.tsx +3 -0
- package/src/layouts/app/SidebarPrimarySecondaryLayout.tsx +3 -0
- package/src/layouts/app/SidebarSearchHeaderLayout.tsx +103 -0
- package/src/layouts/app/SidebarSearchToolbarLayout.tsx +3 -0
- package/src/layouts/app/SidebarTabsDualLayout.tsx +3 -0
- package/src/layouts/app/SidebarTabsLayout.tsx +98 -0
- package/src/layouts/app/SidebarTreeLayout.tsx +3 -0
- package/src/layouts/app/SplitNavbarLayout.tsx +3 -0
- package/src/layouts/app/SplitSidebarDashboardLayout.tsx +3 -0
- package/src/layouts/app/SplitSidebarLayout.tsx +99 -0
- package/src/layouts/app/TopNavLayout.tsx +105 -0
- package/src/layouts/app/TopNavLinksLayout.tsx +3 -0
- package/src/layouts/app/WorkspaceBreadcrumbLayout.tsx +3 -0
- package/src/layouts/app/WorkspaceCommunitiesLayout.tsx +3 -0
- package/src/layouts/app/WorkspaceNavbarLayout.tsx +3 -0
- package/src/layouts/app/WorkspaceSidebarLayout.tsx +98 -0
- package/src/layouts/app/WorkspaceSidebarTitleLayout.tsx +3 -0
- package/src/layouts/app/app-header-layout.tsx +45 -0
- package/src/layouts/app/app-sidebar-layout.tsx +56 -0
- package/src/layouts/app/layout-context.tsx +44 -0
- package/src/layouts/app/layout-types.ts +47 -0
- package/src/layouts/app/partials/Footer.tsx +35 -0
- package/src/layouts/app/partials/HeaderTopbar.tsx +96 -0
- package/src/layouts/app/partials/Navbar.tsx +85 -0
- package/src/layouts/app/partials/Toolbar.tsx +47 -0
- package/src/layouts/app-layout.tsx +29 -0
- package/src/layouts/auth/AuthBrandedLayout.tsx +58 -0
- package/src/layouts/auth/AuthCardLayout.tsx +31 -0
- package/src/layouts/auth/AuthCenteredLayout.tsx +41 -0
- package/src/layouts/auth/AuthClassicLayout.tsx +41 -0
- package/src/layouts/auth/AuthSimpleLayout.tsx +33 -0
- package/src/layouts/auth/AuthSplitLayout.tsx +89 -0
- package/src/layouts/web-app-layout.tsx +162 -0
- package/src/layouts/web-layout.tsx +23 -0
- package/src/lib/datetime.ts +188 -0
- package/src/lib/google-maps-loader.ts +99 -0
- package/src/lib/location.ts +127 -0
- package/src/lib/lucide-icon-map.ts +132 -0
- package/src/lib/map-markers.ts +124 -0
- package/src/lib/map-styles.ts +351 -0
- package/src/lib/utils.ts +11 -0
- package/src/platform/adapters/default.tsx +156 -0
- package/src/platform/adapters/inertia.tsx +88 -0
- package/src/platform/adapters/nextjs.ts +86 -0
- package/src/platform/context.tsx +106 -0
- package/src/platform/index.ts +27 -0
- package/src/platform/types.ts +105 -0
- package/src/styles/layouts/sidebar-fixed.css +161 -0
- package/src/styles/themes.css +583 -0
- package/src/types/assets.d.ts +5 -0
- package/src/types/auth.ts +25 -0
- package/src/types/global.d.ts +13 -0
- package/src/types/index.ts +9 -0
- package/src/types/navigation.ts +15 -0
- package/src/types/ui.ts +32 -0
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { createContext, ReactNode, useContext } from 'react';
|
|
4
|
+
import { cn } from '../../lib/utils';
|
|
5
|
+
import { ColumnFiltersState, RowData, SortingState, Table } from '@tanstack/react-table';
|
|
6
|
+
|
|
7
|
+
declare module '@tanstack/react-table' {
|
|
8
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
9
|
+
interface ColumnMeta<TData extends RowData, TValue> {
|
|
10
|
+
headerTitle?: string;
|
|
11
|
+
headerClassName?: string;
|
|
12
|
+
cellClassName?: string;
|
|
13
|
+
skeleton?: ReactNode;
|
|
14
|
+
expandedContent?: (row: TData) => ReactNode;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export type DataGridApiFetchParams = {
|
|
19
|
+
pageIndex: number;
|
|
20
|
+
pageSize: number;
|
|
21
|
+
sorting?: SortingState;
|
|
22
|
+
filters?: ColumnFiltersState;
|
|
23
|
+
searchQuery?: string;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export type DataGridApiResponse<T> = {
|
|
27
|
+
data: T[];
|
|
28
|
+
empty: boolean;
|
|
29
|
+
pagination: {
|
|
30
|
+
total: number;
|
|
31
|
+
page: number;
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export interface DataGridContextProps<TData extends object> {
|
|
36
|
+
props: DataGridProps<TData>;
|
|
37
|
+
table: Table<TData>;
|
|
38
|
+
recordCount: number;
|
|
39
|
+
isLoading: boolean;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export type DataGridRequestParams = {
|
|
43
|
+
pageIndex: number;
|
|
44
|
+
pageSize: number;
|
|
45
|
+
sorting?: SortingState;
|
|
46
|
+
columnFilters?: ColumnFiltersState;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export interface DataGridProps<TData extends object> {
|
|
50
|
+
className?: string;
|
|
51
|
+
table?: Table<TData>;
|
|
52
|
+
recordCount: number;
|
|
53
|
+
children?: ReactNode;
|
|
54
|
+
onRowClick?: (row: TData) => void;
|
|
55
|
+
isLoading?: boolean;
|
|
56
|
+
loadingMode?: 'skeleton' | 'spinner';
|
|
57
|
+
loadingMessage?: ReactNode | string;
|
|
58
|
+
emptyMessage?: ReactNode | string;
|
|
59
|
+
tableLayout?: {
|
|
60
|
+
dense?: boolean;
|
|
61
|
+
cellBorder?: boolean;
|
|
62
|
+
rowBorder?: boolean;
|
|
63
|
+
rowRounded?: boolean;
|
|
64
|
+
stripped?: boolean;
|
|
65
|
+
headerBackground?: boolean;
|
|
66
|
+
headerBorder?: boolean;
|
|
67
|
+
headerSticky?: boolean;
|
|
68
|
+
width?: 'auto' | 'fixed';
|
|
69
|
+
columnsVisibility?: boolean;
|
|
70
|
+
columnsResizable?: boolean;
|
|
71
|
+
columnsPinnable?: boolean;
|
|
72
|
+
columnsMovable?: boolean;
|
|
73
|
+
columnsDraggable?: boolean;
|
|
74
|
+
rowsDraggable?: boolean;
|
|
75
|
+
};
|
|
76
|
+
tableClassNames?: {
|
|
77
|
+
base?: string;
|
|
78
|
+
header?: string;
|
|
79
|
+
headerRow?: string;
|
|
80
|
+
headerSticky?: string;
|
|
81
|
+
body?: string;
|
|
82
|
+
bodyRow?: string;
|
|
83
|
+
footer?: string;
|
|
84
|
+
edgeCell?: string;
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const DataGridContext = createContext<
|
|
89
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
90
|
+
DataGridContextProps<any> | undefined
|
|
91
|
+
>(undefined);
|
|
92
|
+
|
|
93
|
+
function useDataGrid() {
|
|
94
|
+
const context = useContext(DataGridContext);
|
|
95
|
+
if (!context) {
|
|
96
|
+
throw new Error('useDataGrid must be used within a DataGridProvider');
|
|
97
|
+
}
|
|
98
|
+
return context;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function DataGridProvider<TData extends object>({
|
|
102
|
+
children,
|
|
103
|
+
table,
|
|
104
|
+
...props
|
|
105
|
+
}: DataGridProps<TData> & { table: Table<TData> }) {
|
|
106
|
+
return (
|
|
107
|
+
<DataGridContext.Provider
|
|
108
|
+
value={{
|
|
109
|
+
props,
|
|
110
|
+
table,
|
|
111
|
+
recordCount: props.recordCount,
|
|
112
|
+
isLoading: props.isLoading || false,
|
|
113
|
+
}}
|
|
114
|
+
>
|
|
115
|
+
{children}
|
|
116
|
+
</DataGridContext.Provider>
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function DataGrid<TData extends object>({ children, table, ...props }: DataGridProps<TData>) {
|
|
121
|
+
const defaultProps: Partial<DataGridProps<TData>> = {
|
|
122
|
+
loadingMode: 'skeleton',
|
|
123
|
+
tableLayout: {
|
|
124
|
+
dense: false,
|
|
125
|
+
cellBorder: false,
|
|
126
|
+
rowBorder: true,
|
|
127
|
+
rowRounded: false,
|
|
128
|
+
stripped: false,
|
|
129
|
+
headerSticky: false,
|
|
130
|
+
headerBackground: true,
|
|
131
|
+
headerBorder: true,
|
|
132
|
+
width: 'fixed',
|
|
133
|
+
columnsVisibility: false,
|
|
134
|
+
columnsResizable: false,
|
|
135
|
+
columnsPinnable: false,
|
|
136
|
+
columnsMovable: false,
|
|
137
|
+
columnsDraggable: false,
|
|
138
|
+
rowsDraggable: false,
|
|
139
|
+
},
|
|
140
|
+
tableClassNames: {
|
|
141
|
+
base: '',
|
|
142
|
+
header: '',
|
|
143
|
+
headerRow: '',
|
|
144
|
+
headerSticky: 'sticky top-0 z-10 bg-background/90 backdrop-blur-xs',
|
|
145
|
+
body: '',
|
|
146
|
+
bodyRow: '',
|
|
147
|
+
footer: '',
|
|
148
|
+
edgeCell: '',
|
|
149
|
+
},
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
const mergedProps: DataGridProps<TData> = {
|
|
153
|
+
...defaultProps,
|
|
154
|
+
...props,
|
|
155
|
+
tableLayout: {
|
|
156
|
+
...defaultProps.tableLayout,
|
|
157
|
+
...(props.tableLayout || {}),
|
|
158
|
+
},
|
|
159
|
+
tableClassNames: {
|
|
160
|
+
...defaultProps.tableClassNames,
|
|
161
|
+
...(props.tableClassNames || {}),
|
|
162
|
+
},
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
// Ensure table is provided
|
|
166
|
+
if (!table) {
|
|
167
|
+
throw new Error('DataGrid requires a "table" prop');
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return (
|
|
171
|
+
<DataGridProvider table={table} {...mergedProps}>
|
|
172
|
+
{children}
|
|
173
|
+
</DataGridProvider>
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function DataGridContainer({
|
|
178
|
+
children,
|
|
179
|
+
className,
|
|
180
|
+
border = true,
|
|
181
|
+
}: {
|
|
182
|
+
children: ReactNode;
|
|
183
|
+
className?: string;
|
|
184
|
+
border?: boolean;
|
|
185
|
+
}) {
|
|
186
|
+
return (
|
|
187
|
+
<div data-slot="data-grid" className={cn('grid w-full', border && 'border border-border rounded-lg', className)}>
|
|
188
|
+
{children}
|
|
189
|
+
</div>
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export { useDataGrid, DataGridProvider, DataGrid, DataGridContainer, DataGridContext };
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DataList — key/value display (HTML <dl>).
|
|
3
|
+
*
|
|
4
|
+
* Two flavours:
|
|
5
|
+
* - Pass `items` prop: array of { label, value, mono? }
|
|
6
|
+
* - Or compose with <DataListItem> children for richer cells
|
|
7
|
+
*
|
|
8
|
+
* <DataList items={[
|
|
9
|
+
* { label: 'Serial', value: 'P901-00042', mono: true },
|
|
10
|
+
* { label: 'Status', value: <Badge>Active</Badge> },
|
|
11
|
+
* ]} />
|
|
12
|
+
*/
|
|
13
|
+
import * as React from 'react';
|
|
14
|
+
|
|
15
|
+
import { cn } from '../../lib/utils';
|
|
16
|
+
|
|
17
|
+
type Item = {
|
|
18
|
+
label: string;
|
|
19
|
+
value: React.ReactNode;
|
|
20
|
+
mono?: boolean;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
type Props = {
|
|
24
|
+
items?: Item[];
|
|
25
|
+
children?: React.ReactNode;
|
|
26
|
+
className?: string;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export function DataList({ items, children, className }: Props) {
|
|
30
|
+
return (
|
|
31
|
+
<dl
|
|
32
|
+
className={cn(
|
|
33
|
+
'divide-y divide-border rounded-lg border bg-card',
|
|
34
|
+
className,
|
|
35
|
+
)}
|
|
36
|
+
>
|
|
37
|
+
{items
|
|
38
|
+
? items.map((item) => (
|
|
39
|
+
<DataListItem
|
|
40
|
+
key={item.label}
|
|
41
|
+
label={item.label}
|
|
42
|
+
mono={item.mono}
|
|
43
|
+
>
|
|
44
|
+
{item.value}
|
|
45
|
+
</DataListItem>
|
|
46
|
+
))
|
|
47
|
+
: children}
|
|
48
|
+
</dl>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function DataListItem({
|
|
53
|
+
label,
|
|
54
|
+
mono,
|
|
55
|
+
children,
|
|
56
|
+
}: {
|
|
57
|
+
label: string;
|
|
58
|
+
mono?: boolean;
|
|
59
|
+
children: React.ReactNode;
|
|
60
|
+
}) {
|
|
61
|
+
return (
|
|
62
|
+
<div className="flex flex-col gap-1 px-4 py-3 sm:flex-row sm:items-center sm:gap-4">
|
|
63
|
+
<dt className="text-xs font-medium uppercase tracking-wide text-muted-foreground sm:w-40">
|
|
64
|
+
{label}
|
|
65
|
+
</dt>
|
|
66
|
+
<dd
|
|
67
|
+
className={cn(
|
|
68
|
+
'flex-1 text-sm text-foreground',
|
|
69
|
+
mono && 'font-mono',
|
|
70
|
+
)}
|
|
71
|
+
>
|
|
72
|
+
{children}
|
|
73
|
+
</dd>
|
|
74
|
+
</div>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { cn } from '../../lib/utils';
|
|
4
|
+
import { inputVariants } from './input';
|
|
5
|
+
import type { VariantProps } from 'class-variance-authority';
|
|
6
|
+
import {
|
|
7
|
+
composeRenderProps,
|
|
8
|
+
DateFieldProps,
|
|
9
|
+
DateField as DateFieldRa,
|
|
10
|
+
DateInputProps as DateInputPropsRa,
|
|
11
|
+
DateInput as DateInputRa,
|
|
12
|
+
DateSegmentProps,
|
|
13
|
+
DateSegment as DateSegmentRa,
|
|
14
|
+
DateValue as DateValueRa,
|
|
15
|
+
TimeFieldProps,
|
|
16
|
+
TimeField as TimeFieldRa,
|
|
17
|
+
TimeValue as TimeValueRa,
|
|
18
|
+
} from 'react-aria-components';
|
|
19
|
+
|
|
20
|
+
function DateField<T extends DateValueRa>({ className, children, ...props }: DateFieldProps<T>) {
|
|
21
|
+
return (
|
|
22
|
+
<DateFieldRa
|
|
23
|
+
className={composeRenderProps(className, (className) => cn(className))}
|
|
24
|
+
data-slot="datefield"
|
|
25
|
+
{...props}
|
|
26
|
+
>
|
|
27
|
+
{children}
|
|
28
|
+
</DateFieldRa>
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function TimeField<T extends TimeValueRa>({ className, children, ...props }: TimeFieldProps<T>) {
|
|
33
|
+
return (
|
|
34
|
+
<TimeFieldRa
|
|
35
|
+
className={composeRenderProps(className, (className) => cn(className))}
|
|
36
|
+
data-slot="datefield"
|
|
37
|
+
{...props}
|
|
38
|
+
>
|
|
39
|
+
{children}
|
|
40
|
+
</TimeFieldRa>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function DateSegment({ className, ...props }: DateSegmentProps) {
|
|
45
|
+
return (
|
|
46
|
+
<DateSegmentRa
|
|
47
|
+
className={composeRenderProps(className, (className) =>
|
|
48
|
+
cn(
|
|
49
|
+
`
|
|
50
|
+
text-foreground inline-flex rounded px-0.5 caret-transparent outline-hidden data-[type=literal]:text-muted-foreground/70 data-[type=literal]:px-0
|
|
51
|
+
data-placeholder:text-muted-foreground/70
|
|
52
|
+
data-invalid:data-focused:bg-destructive data-invalid:data-placeholder:text-destructive data-invalid:text-destructive data-invalid:data-focused:data-placeholder:text-destructive-foreground data-invalid:data-focused:text-destructive-foreground
|
|
53
|
+
data-focused:bg-accent data-focused:data-placeholder:text-foreground data-focused:text-foreground
|
|
54
|
+
data-disabled:cursor-not-allowed data-disabled:opacity-50
|
|
55
|
+
`,
|
|
56
|
+
className,
|
|
57
|
+
),
|
|
58
|
+
)}
|
|
59
|
+
{...props}
|
|
60
|
+
data-invalid
|
|
61
|
+
/>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const dateInputStyles = `
|
|
66
|
+
relative inline-flex items-center overflow-hidden whitespace-nowrap
|
|
67
|
+
data-focus-within:ring-ring/30 data-focus-within:border-ring data-focus-within:outline-none data-focus-within:ring-[3px]
|
|
68
|
+
data-focus-within:has-aria-invalid:ring-destructive/20 dark:data-focus-within:has-aria-invalid:ring-destructive/40 data-focus-within:has-aria-invalid:border-destructive
|
|
69
|
+
`;
|
|
70
|
+
|
|
71
|
+
interface DateInputProps extends DateInputPropsRa, VariantProps<typeof inputVariants> {
|
|
72
|
+
className?: string;
|
|
73
|
+
variant?: VariantProps<typeof inputVariants>['variant'];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function DateInput({ className, variant = 'md', ...props }: Omit<DateInputProps, 'children'>) {
|
|
77
|
+
return (
|
|
78
|
+
<DateInputRa
|
|
79
|
+
data-slot="input"
|
|
80
|
+
className={composeRenderProps(className, (className) =>
|
|
81
|
+
cn(inputVariants({ variant }), dateInputStyles, className),
|
|
82
|
+
)}
|
|
83
|
+
{...props}
|
|
84
|
+
>
|
|
85
|
+
{(segment) => <DateSegment segment={segment} />}
|
|
86
|
+
</DateInputRa>
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export { DateField, DateInput, DateSegment, TimeField, dateInputStyles };
|
|
91
|
+
export type { DateInputProps };
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { cn } from '../../lib/utils';
|
|
5
|
+
import { cva, VariantProps } from 'class-variance-authority';
|
|
6
|
+
import { X } from 'lucide-react';
|
|
7
|
+
import * as DialogPrimitive from '@radix-ui/react-dialog';
|
|
8
|
+
|
|
9
|
+
const dialogContentVariants = cva(
|
|
10
|
+
'flex flex-col fixed outline-0 z-50 border border-border bg-background p-6 shadow-lg shadow-black/5 duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 sm:rounded-lg',
|
|
11
|
+
{
|
|
12
|
+
variants: {
|
|
13
|
+
variant: {
|
|
14
|
+
default: 'left-[50%] top-[50%] max-w-lg translate-x-[-50%] translate-y-[-50%] w-full',
|
|
15
|
+
fullscreen: 'inset-5',
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
defaultVariants: {
|
|
19
|
+
variant: 'default',
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
function Dialog({ ...props }: React.ComponentProps<typeof DialogPrimitive.Root>) {
|
|
25
|
+
return <DialogPrimitive.Root data-slot="dialog" {...props} />;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function DialogTrigger({ ...props }: React.ComponentProps<typeof DialogPrimitive.Trigger>) {
|
|
29
|
+
return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function DialogPortal({ ...props }: React.ComponentProps<typeof DialogPrimitive.Portal>) {
|
|
33
|
+
return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function DialogClose({ ...props }: React.ComponentProps<typeof DialogPrimitive.Close>) {
|
|
37
|
+
return <DialogPrimitive.Close data-slot="dialog-close" {...props} />;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function DialogOverlay({ className, ...props }: React.ComponentProps<typeof DialogPrimitive.Overlay>) {
|
|
41
|
+
return (
|
|
42
|
+
<DialogPrimitive.Overlay
|
|
43
|
+
data-slot="dialog-overlay"
|
|
44
|
+
className={cn(
|
|
45
|
+
'fixed inset-0 z-50 bg-black/30 [backdrop-filter:blur(4px)] data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
|
|
46
|
+
className,
|
|
47
|
+
)}
|
|
48
|
+
{...props}
|
|
49
|
+
/>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function DialogContent({
|
|
54
|
+
className,
|
|
55
|
+
children,
|
|
56
|
+
showCloseButton = true,
|
|
57
|
+
overlay = true,
|
|
58
|
+
variant,
|
|
59
|
+
...props
|
|
60
|
+
}: React.ComponentProps<typeof DialogPrimitive.Content> &
|
|
61
|
+
VariantProps<typeof dialogContentVariants> & {
|
|
62
|
+
showCloseButton?: boolean;
|
|
63
|
+
overlay?: boolean;
|
|
64
|
+
}) {
|
|
65
|
+
return (
|
|
66
|
+
<DialogPortal>
|
|
67
|
+
{overlay && <DialogOverlay />}
|
|
68
|
+
<DialogPrimitive.Content
|
|
69
|
+
data-slot="dialog-content"
|
|
70
|
+
className={cn(dialogContentVariants({ variant }), className)}
|
|
71
|
+
{...props}
|
|
72
|
+
>
|
|
73
|
+
{children}
|
|
74
|
+
{showCloseButton && (
|
|
75
|
+
<DialogClose className="cursor-pointer outline-0 absolute end-5 top-5 rounded-sm opacity-60 ring-offset-background transition-opacity hover:opacity-100 focus:outline-hidden disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
|
|
76
|
+
<X className="size-4" />
|
|
77
|
+
<span className="sr-only">Close</span>
|
|
78
|
+
</DialogClose>
|
|
79
|
+
)}
|
|
80
|
+
</DialogPrimitive.Content>
|
|
81
|
+
</DialogPortal>
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export default DialogContent;
|
|
86
|
+
|
|
87
|
+
const DialogHeader = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
|
|
88
|
+
<div
|
|
89
|
+
data-slot="dialog-header"
|
|
90
|
+
className={cn('flex flex-col space-y-1 text-center sm:text-start mb-5', className)}
|
|
91
|
+
{...props}
|
|
92
|
+
/>
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
const DialogFooter = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
|
|
96
|
+
<div
|
|
97
|
+
data-slot="dialog-footer"
|
|
98
|
+
className={cn('flex flex-col-reverse sm:flex-row sm:justify-end pt-5 sm:space-x-2.5', className)}
|
|
99
|
+
{...props}
|
|
100
|
+
/>
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
function DialogTitle({ className, ...props }: React.ComponentProps<typeof DialogPrimitive.Title>) {
|
|
104
|
+
return (
|
|
105
|
+
<DialogPrimitive.Title
|
|
106
|
+
data-slot="dialog-title"
|
|
107
|
+
className={cn('text-lg font-semibold leading-none tracking-tight', className)}
|
|
108
|
+
{...props}
|
|
109
|
+
/>
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const DialogBody = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
|
|
114
|
+
<div data-slot="dialog-body" className={cn('grow', className)} {...props} />
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
function DialogDescription({ className, ...props }: React.ComponentProps<typeof DialogPrimitive.Description>) {
|
|
118
|
+
return (
|
|
119
|
+
<DialogPrimitive.Description
|
|
120
|
+
data-slot="dialog-description"
|
|
121
|
+
className={cn('text-sm text-muted-foreground', className)}
|
|
122
|
+
{...props}
|
|
123
|
+
/>
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export {
|
|
128
|
+
Dialog,
|
|
129
|
+
DialogBody,
|
|
130
|
+
DialogClose,
|
|
131
|
+
DialogContent,
|
|
132
|
+
DialogDescription,
|
|
133
|
+
DialogFooter,
|
|
134
|
+
DialogHeader,
|
|
135
|
+
DialogOverlay,
|
|
136
|
+
DialogPortal,
|
|
137
|
+
DialogTitle,
|
|
138
|
+
DialogTrigger,
|
|
139
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Divider — horizontal rule with optional centred label.
|
|
3
|
+
*
|
|
4
|
+
* <Divider />
|
|
5
|
+
* <Divider>OR</Divider>
|
|
6
|
+
*/
|
|
7
|
+
import * as React from 'react';
|
|
8
|
+
|
|
9
|
+
import { cn } from '../../lib/utils';
|
|
10
|
+
|
|
11
|
+
type Props = {
|
|
12
|
+
children?: React.ReactNode;
|
|
13
|
+
className?: string;
|
|
14
|
+
decorative?: boolean;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export function Divider({ children, className, decorative = true }: Props) {
|
|
18
|
+
if (!children) {
|
|
19
|
+
return (
|
|
20
|
+
<hr
|
|
21
|
+
role={decorative ? 'presentation' : 'separator'}
|
|
22
|
+
aria-hidden={decorative ? 'true' : undefined}
|
|
23
|
+
className={cn('my-4 border-border', className)}
|
|
24
|
+
/>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<div
|
|
30
|
+
role={decorative ? 'presentation' : 'separator'}
|
|
31
|
+
aria-hidden={decorative ? 'true' : undefined}
|
|
32
|
+
className={cn('my-4 flex items-center gap-3', className)}
|
|
33
|
+
>
|
|
34
|
+
<span className="h-px flex-1 bg-border" />
|
|
35
|
+
<span className="text-xs font-medium uppercase tracking-wide text-muted-foreground">
|
|
36
|
+
{children}
|
|
37
|
+
</span>
|
|
38
|
+
<span className="h-px flex-1 bg-border" />
|
|
39
|
+
</div>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { Drawer as DrawerPrimitive } from 'vaul';
|
|
5
|
+
import { cn } from '../../lib/utils';
|
|
6
|
+
|
|
7
|
+
const Drawer = ({ shouldScaleBackground = true, ...props }: React.ComponentProps<typeof DrawerPrimitive.Root>) => (
|
|
8
|
+
<DrawerPrimitive.Root shouldScaleBackground={shouldScaleBackground} {...props} />
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
function DrawerTrigger({ ...props }: React.ComponentProps<typeof DrawerPrimitive.Trigger>) {
|
|
12
|
+
return <DrawerPrimitive.Trigger data-slot="drawer-trigger" {...props} />;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function DrawerPortal({ ...props }: React.ComponentProps<typeof DrawerPrimitive.Portal>) {
|
|
16
|
+
return <DrawerPrimitive.Portal data-slot="drawer-portal" {...props} />;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function DrawerClose({ ...props }: React.ComponentProps<typeof DrawerPrimitive.Close>) {
|
|
20
|
+
return <DrawerPrimitive.Close data-slot="drawer-close" {...props} />;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function DrawerOverlay({ className, ...props }: React.ComponentProps<typeof DrawerPrimitive.Overlay>) {
|
|
24
|
+
return <DrawerPrimitive.Overlay data-slot="drawer-overlay" className={cn('fixed inset-0 z-50 bg-black/80', className)} {...props} />;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function DrawerContent({ className, children, ...props }: React.ComponentProps<typeof DrawerPrimitive.Content>) {
|
|
28
|
+
return (
|
|
29
|
+
<DrawerPortal>
|
|
30
|
+
<DrawerOverlay />
|
|
31
|
+
<DrawerPrimitive.Content
|
|
32
|
+
data-slot="drawer-content"
|
|
33
|
+
className={cn('bg-background fixed inset-x-0 bottom-0 z-50 mt-24 flex h-auto flex-col rounded-t-[10px] border', className)}
|
|
34
|
+
{...props}
|
|
35
|
+
>
|
|
36
|
+
<div className="mx-auto mt-4 h-2 w-[100px] rounded-full bg-muted" />
|
|
37
|
+
{children}
|
|
38
|
+
</DrawerPrimitive.Content>
|
|
39
|
+
</DrawerPortal>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const DrawerHeader = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
|
|
44
|
+
<div data-slot="drawer-header" className={cn('grid gap-1.5 p-4 text-center sm:text-left', className)} {...props} />
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
const DrawerFooter = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
|
|
48
|
+
<div data-slot="drawer-footer" className={cn('mt-auto flex flex-col gap-2 p-4', className)} {...props} />
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
function DrawerTitle({ className, ...props }: React.ComponentProps<typeof DrawerPrimitive.Title>) {
|
|
52
|
+
return <DrawerPrimitive.Title data-slot="drawer-title" className={cn('text-lg font-semibold leading-none tracking-tight', className)} {...props} />;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function DrawerDescription({ className, ...props }: React.ComponentProps<typeof DrawerPrimitive.Description>) {
|
|
56
|
+
return <DrawerPrimitive.Description data-slot="drawer-description" className={cn('text-sm text-muted-foreground', className)} {...props} />;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export { Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger };
|