@carefully-built/cli 0.1.1 → 0.1.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/README.md +101 -80
- package/dist/index.mjs +8 -5
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
- package/registry/ui/avatar/manifest.json +33 -0
- package/registry/ui/avatar/primitives/avatar.tsx +64 -0
- package/registry/ui/avatar/utils/cn.ts +6 -0
- package/registry/ui/button/manifest.json +24 -5
- package/registry/ui/button/utils/cn.ts +6 -0
- package/registry/ui/calendar/manifest.json +35 -0
- package/registry/ui/calendar/primitives/button.tsx +89 -0
- package/registry/ui/calendar/primitives/calendar.tsx +68 -0
- package/registry/ui/calendar/utils/cn.ts +6 -0
- package/registry/ui/card/manifest.json +36 -0
- package/registry/ui/card/primitives/card.tsx +80 -0
- package/registry/ui/card/utils/cn.ts +6 -0
- package/registry/ui/chip/manifest.json +36 -0
- package/registry/ui/chip/primitives/chip-utils.ts +10 -0
- package/registry/ui/chip/primitives/chip.tsx +74 -0
- package/registry/ui/chip/utils/cn.ts +6 -0
- package/registry/ui/chip-utils/manifest.json +33 -0
- package/registry/ui/chip-utils/primitives/chip-utils.ts +10 -0
- package/registry/ui/chip-utils/utils/cn.ts +6 -0
- package/registry/ui/date-display/manifest.json +33 -0
- package/registry/ui/date-display/utils/cn.ts +6 -0
- package/registry/ui/date-display/utils/date-display.ts +61 -0
- package/registry/ui/dialog/manifest.json +43 -0
- package/registry/ui/dialog/primitives/button.tsx +89 -0
- package/registry/ui/dialog/primitives/dialog.tsx +147 -0
- package/registry/ui/dialog/utils/cn.ts +6 -0
- package/registry/ui/display-date/manifest.json +36 -0
- package/registry/ui/display-date/primitives/display-date.tsx +20 -0
- package/registry/ui/display-date/utils/cn.ts +6 -0
- package/registry/ui/display-date/utils/date-display.ts +61 -0
- package/registry/ui/drawer/manifest.json +37 -0
- package/registry/ui/drawer/primitives/drawer.tsx +99 -0
- package/registry/ui/drawer/utils/cn.ts +6 -0
- package/registry/ui/dropdown-menu/manifest.json +37 -0
- package/registry/ui/dropdown-menu/primitives/dropdown-menu.tsx +140 -0
- package/registry/ui/dropdown-menu/utils/cn.ts +6 -0
- package/registry/ui/empty-state/empty-state/collection-empty-state.ts +29 -0
- package/registry/ui/empty-state/empty-state/empty-state-card.tsx +72 -0
- package/registry/ui/empty-state/empty-state/index.ts +8 -0
- package/registry/ui/empty-state/empty-state/initial-empty-state.tsx +36 -0
- package/registry/ui/empty-state/empty-state/no-results-state.tsx +20 -0
- package/registry/ui/empty-state/manifest.json +63 -0
- package/registry/ui/empty-state/primitives/button.tsx +89 -0
- package/registry/ui/empty-state/primitives/card.tsx +80 -0
- package/registry/ui/empty-state/utils/cn.ts +6 -0
- package/registry/ui/error-page/error-page/error-code.tsx +16 -0
- package/registry/ui/error-page/error-page/error-page-content.ts +75 -0
- package/registry/ui/error-page/error-page/index.ts +19 -0
- package/registry/ui/error-page/error-page/posthog-error-capture.ts +83 -0
- package/registry/ui/error-page/error-page/saas-error-page.tsx +146 -0
- package/registry/ui/error-page/manifest.json +64 -0
- package/registry/ui/error-page/primitives/button.tsx +89 -0
- package/registry/ui/error-page/utils/cn.ts +6 -0
- package/registry/ui/field-detail-row/manifest.json +32 -0
- package/registry/ui/field-detail-row/primitives/field-detail-row.tsx +28 -0
- package/registry/ui/field-detail-row/utils/cn.ts +6 -0
- package/registry/ui/file-dropzone/manifest.json +35 -0
- package/registry/ui/file-dropzone/primitives/button.tsx +89 -0
- package/registry/ui/file-dropzone/primitives/file-dropzone.tsx +236 -0
- package/registry/ui/file-dropzone/utils/cn.ts +6 -0
- package/registry/ui/help-info-button/manifest.json +72 -0
- package/registry/ui/help-info-button/overlays/responsive-sheet.footer.tsx +88 -0
- package/registry/ui/help-info-button/overlays/responsive-sheet.layouts.tsx +207 -0
- package/registry/ui/help-info-button/overlays/responsive-sheet.shortcuts.ts +103 -0
- package/registry/ui/help-info-button/overlays/responsive-sheet.tsx +132 -0
- package/registry/ui/help-info-button/primitives/button.tsx +89 -0
- package/registry/ui/help-info-button/primitives/drawer.tsx +99 -0
- package/registry/ui/help-info-button/primitives/help-info-button.tsx +63 -0
- package/registry/ui/help-info-button/primitives/keyboard-shortcut-hint.tsx +40 -0
- package/registry/ui/help-info-button/primitives/sheet.tsx +103 -0
- package/registry/ui/help-info-button/primitives/tooltip.tsx +57 -0
- package/registry/ui/help-info-button/utils/cn.ts +6 -0
- package/registry/ui/help-info-button/utils/use-media-query.ts +28 -0
- package/registry/ui/input/manifest.json +31 -0
- package/registry/ui/input/primitives/input.tsx +19 -0
- package/registry/ui/input/utils/cn.ts +6 -0
- package/registry/ui/keyboard-shortcut-hint/manifest.json +32 -0
- package/registry/ui/keyboard-shortcut-hint/primitives/keyboard-shortcut-hint.tsx +40 -0
- package/registry/ui/keyboard-shortcut-hint/utils/cn.ts +6 -0
- package/registry/ui/label/manifest.json +31 -0
- package/registry/ui/label/primitives/label.tsx +21 -0
- package/registry/ui/label/utils/cn.ts +6 -0
- package/registry/ui/pagination/manifest.json +36 -0
- package/registry/ui/pagination/primitives/button.tsx +89 -0
- package/registry/ui/pagination/primitives/pagination.tsx +143 -0
- package/registry/ui/pagination/utils/cn.ts +6 -0
- package/registry/ui/popover/manifest.json +33 -0
- package/registry/ui/popover/primitives/popover.tsx +46 -0
- package/registry/ui/popover/utils/cn.ts +6 -0
- package/registry/ui/responsive-sheet/manifest.json +66 -0
- package/registry/ui/responsive-sheet/overlays/responsive-sheet.footer.tsx +88 -0
- package/registry/ui/responsive-sheet/overlays/responsive-sheet.layouts.tsx +207 -0
- package/registry/ui/responsive-sheet/overlays/responsive-sheet.shortcuts.ts +103 -0
- package/registry/ui/responsive-sheet/overlays/responsive-sheet.tsx +132 -0
- package/registry/ui/responsive-sheet/primitives/button.tsx +89 -0
- package/registry/ui/responsive-sheet/primitives/drawer.tsx +99 -0
- package/registry/ui/responsive-sheet/primitives/keyboard-shortcut-hint.tsx +40 -0
- package/registry/ui/responsive-sheet/primitives/sheet.tsx +103 -0
- package/registry/ui/responsive-sheet/utils/cn.ts +6 -0
- package/registry/ui/responsive-sheet/utils/use-media-query.ts +28 -0
- package/registry/ui/responsive-sheet.footer/manifest.json +40 -0
- package/registry/ui/responsive-sheet.footer/overlays/responsive-sheet.footer.tsx +88 -0
- package/registry/ui/responsive-sheet.footer/primitives/button.tsx +89 -0
- package/registry/ui/responsive-sheet.footer/primitives/keyboard-shortcut-hint.tsx +40 -0
- package/registry/ui/responsive-sheet.footer/utils/cn.ts +6 -0
- package/registry/ui/responsive-sheet.shortcuts/manifest.json +34 -0
- package/registry/ui/responsive-sheet.shortcuts/overlays/responsive-sheet.shortcuts.ts +103 -0
- package/registry/ui/responsive-sheet.shortcuts/utils/cn.ts +6 -0
- package/registry/ui/scroll-fade-area/manifest.json +31 -0
- package/registry/ui/scroll-fade-area/primitives/scroll-fade-area.tsx +295 -0
- package/registry/ui/scroll-fade-area/utils/cn.ts +6 -0
- package/registry/ui/search/manifest.json +35 -0
- package/registry/ui/search/utils/cn.ts +6 -0
- package/registry/ui/search/utils/search.ts +227 -0
- package/registry/ui/searchable-select/manifest.json +48 -0
- package/registry/ui/searchable-select/primitives/input.tsx +19 -0
- package/registry/ui/searchable-select/search/searchable-select-position.ts +95 -0
- package/registry/ui/searchable-select/search/searchable-select.tsx +431 -0
- package/registry/ui/searchable-select/utils/cn.ts +6 -0
- package/registry/ui/searchable-select/utils/search.ts +227 -0
- package/registry/ui/searchable-select-position/manifest.json +32 -0
- package/registry/ui/searchable-select-position/search/searchable-select-position.ts +95 -0
- package/registry/ui/searchable-select-position/utils/cn.ts +6 -0
- package/registry/ui/segmented-toggle/manifest.json +41 -0
- package/registry/ui/segmented-toggle/primitives/scroll-fade-area.tsx +295 -0
- package/registry/ui/segmented-toggle/primitives/segmented-toggle.tsx +106 -0
- package/registry/ui/segmented-toggle/primitives/tabs.tsx +97 -0
- package/registry/ui/segmented-toggle/utils/cn.ts +6 -0
- package/registry/ui/select/manifest.json +37 -0
- package/registry/ui/select/primitives/select.tsx +142 -0
- package/registry/ui/select/utils/cn.ts +6 -0
- package/registry/ui/sheet/manifest.json +39 -0
- package/registry/ui/sheet/primitives/button.tsx +89 -0
- package/registry/ui/sheet/primitives/sheet.tsx +103 -0
- package/registry/ui/sheet/utils/cn.ts +6 -0
- package/registry/ui/skeleton/manifest.json +31 -0
- package/registry/ui/skeleton/primitives/skeleton.tsx +13 -0
- package/registry/ui/skeleton/utils/cn.ts +6 -0
- package/registry/ui/smart-table/manifest.json +115 -0
- package/registry/ui/smart-table/primitives/button.tsx +89 -0
- package/registry/ui/smart-table/primitives/card.tsx +80 -0
- package/registry/ui/smart-table/primitives/display-date.tsx +20 -0
- package/registry/ui/smart-table/primitives/pagination.tsx +143 -0
- package/registry/ui/smart-table/primitives/skeleton.tsx +13 -0
- package/registry/ui/smart-table/primitives/table.tsx +92 -0
- package/registry/ui/smart-table/primitives/tooltip.tsx +57 -0
- package/registry/ui/smart-table/smart-table/DesktopView.tsx +343 -0
- package/registry/ui/smart-table/smart-table/MobileView.tsx +170 -0
- package/registry/ui/smart-table/smart-table/SmartTable.tsx +85 -0
- package/registry/ui/smart-table/smart-table/SmartTableActions.tsx +71 -0
- package/registry/ui/smart-table/smart-table/TruncatedContent.tsx +147 -0
- package/registry/ui/smart-table/smart-table/index.ts +15 -0
- package/registry/ui/smart-table/smart-table/sorting.ts +148 -0
- package/registry/ui/smart-table/smart-table/truncated-content.utils.ts +22 -0
- package/registry/ui/smart-table/smart-table/types.ts +95 -0
- package/registry/ui/smart-table/smart-table/utils.ts +150 -0
- package/registry/ui/smart-table/utils/cn.ts +6 -0
- package/registry/ui/smart-table/utils/date-display.ts +61 -0
- package/registry/ui/smart-table/utils/use-media-query.ts +28 -0
- package/registry/ui/switch/manifest.json +31 -0
- package/registry/ui/switch/primitives/switch.tsx +31 -0
- package/registry/ui/switch/utils/cn.ts +6 -0
- package/registry/ui/table/manifest.json +38 -0
- package/registry/ui/table/primitives/table.tsx +92 -0
- package/registry/ui/table/utils/cn.ts +6 -0
- package/registry/ui/table-toolbar/manifest.json +93 -0
- package/registry/ui/table-toolbar/overlays/responsive-sheet.footer.tsx +88 -0
- package/registry/ui/table-toolbar/overlays/responsive-sheet.layouts.tsx +207 -0
- package/registry/ui/table-toolbar/overlays/responsive-sheet.shortcuts.ts +103 -0
- package/registry/ui/table-toolbar/overlays/responsive-sheet.tsx +132 -0
- package/registry/ui/table-toolbar/primitives/button.tsx +89 -0
- package/registry/ui/table-toolbar/primitives/drawer.tsx +99 -0
- package/registry/ui/table-toolbar/primitives/input.tsx +19 -0
- package/registry/ui/table-toolbar/primitives/keyboard-shortcut-hint.tsx +40 -0
- package/registry/ui/table-toolbar/primitives/sheet.tsx +103 -0
- package/registry/ui/table-toolbar/search/searchable-select-position.ts +95 -0
- package/registry/ui/table-toolbar/search/searchable-select.tsx +431 -0
- package/registry/ui/table-toolbar/table-toolbar/index.ts +9 -0
- package/registry/ui/table-toolbar/table-toolbar/table-toolbar.tsx +552 -0
- package/registry/ui/table-toolbar/utils/cn.ts +6 -0
- package/registry/ui/table-toolbar/utils/search.ts +227 -0
- package/registry/ui/table-toolbar/utils/use-media-query.ts +28 -0
- package/registry/ui/tabs/manifest.json +40 -0
- package/registry/ui/tabs/primitives/scroll-fade-area.tsx +295 -0
- package/registry/ui/tabs/primitives/tabs.tsx +97 -0
- package/registry/ui/tabs/utils/cn.ts +6 -0
- package/registry/ui/textarea/manifest.json +31 -0
- package/registry/ui/textarea/primitives/textarea.tsx +18 -0
- package/registry/ui/textarea/utils/cn.ts +6 -0
- package/registry/ui/tooltip/manifest.json +34 -0
- package/registry/ui/tooltip/primitives/tooltip.tsx +57 -0
- package/registry/ui/tooltip/utils/cn.ts +6 -0
- package/registry/ui/use-media-query/manifest.json +32 -0
- package/registry/ui/use-media-query/utils/cn.ts +6 -0
- package/registry/ui/use-media-query/utils/use-media-query.ts +28 -0
- package/registry/ui/user-picker/manifest.json +52 -0
- package/registry/ui/user-picker/primitives/avatar.tsx +64 -0
- package/registry/ui/user-picker/primitives/button.tsx +89 -0
- package/registry/ui/user-picker/primitives/input.tsx +19 -0
- package/registry/ui/user-picker/primitives/popover.tsx +46 -0
- package/registry/ui/user-picker/primitives/user-picker-utils.ts +113 -0
- package/registry/ui/user-picker/primitives/user-picker.tsx +226 -0
- package/registry/ui/user-picker/utils/cn.ts +6 -0
- package/registry/ui/user-picker-utils/manifest.json +38 -0
- package/registry/ui/user-picker-utils/primitives/user-picker-utils.ts +113 -0
- package/registry/ui/user-picker-utils/utils/cn.ts +6 -0
- package/assets/hero.png +0 -0
- package/registry/ui/button/cn.ts +0 -6
- /package/registry/ui/button/{button.tsx → primitives/button.tsx} +0 -0
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
|
+
|
|
3
|
+
interface NavigatorWithUserAgentData extends Navigator {
|
|
4
|
+
readonly userAgentData?: {
|
|
5
|
+
readonly platform?: string;
|
|
6
|
+
};
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function getDesktopShortcutModifierLabel(): string {
|
|
10
|
+
if (typeof navigator === "undefined") {
|
|
11
|
+
return "Ctrl";
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const navigatorWithUserAgentData = navigator as NavigatorWithUserAgentData;
|
|
15
|
+
const platform =
|
|
16
|
+
navigatorWithUserAgentData.userAgentData?.platform ?? navigator.userAgent;
|
|
17
|
+
|
|
18
|
+
return /Mac|iPhone|iPad|iPod/i.test(platform) ? "Cmd" : "Ctrl";
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function isAllowedConfirmShortcutEvent(
|
|
22
|
+
event: KeyboardEvent,
|
|
23
|
+
desktopModifierLabel: string,
|
|
24
|
+
): boolean {
|
|
25
|
+
if (event.key !== "Enter" || event.repeat || event.isComposing) {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const expectsMetaKey = desktopModifierLabel === "Cmd";
|
|
30
|
+
const usedExpectedModifier = expectsMetaKey ? event.metaKey : event.ctrlKey;
|
|
31
|
+
const usedOtherModifier = expectsMetaKey ? event.ctrlKey : event.metaKey;
|
|
32
|
+
const usedShiftModifier = event.shiftKey;
|
|
33
|
+
const usedAltModifier = event.altKey;
|
|
34
|
+
|
|
35
|
+
if (
|
|
36
|
+
!usedExpectedModifier ||
|
|
37
|
+
usedOtherModifier ||
|
|
38
|
+
usedShiftModifier ||
|
|
39
|
+
usedAltModifier
|
|
40
|
+
) {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function useDesktopShortcutModifierLabel(
|
|
48
|
+
enabled: boolean,
|
|
49
|
+
): string | null {
|
|
50
|
+
const [desktopModifierLabel, setDesktopModifierLabel] = useState<
|
|
51
|
+
string | null
|
|
52
|
+
>(null);
|
|
53
|
+
|
|
54
|
+
useEffect(() => {
|
|
55
|
+
if (!enabled) {
|
|
56
|
+
setDesktopModifierLabel(null);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
setDesktopModifierLabel(getDesktopShortcutModifierLabel());
|
|
61
|
+
}, [enabled]);
|
|
62
|
+
|
|
63
|
+
return desktopModifierLabel;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
interface UseDesktopConfirmShortcutOptions {
|
|
67
|
+
readonly open: boolean;
|
|
68
|
+
readonly enabled: boolean;
|
|
69
|
+
readonly confirmDisabled: boolean;
|
|
70
|
+
readonly confirmLoading: boolean;
|
|
71
|
+
readonly onConfirm?: () => void;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function useDesktopConfirmShortcut({
|
|
75
|
+
open,
|
|
76
|
+
enabled,
|
|
77
|
+
confirmDisabled,
|
|
78
|
+
confirmLoading,
|
|
79
|
+
onConfirm,
|
|
80
|
+
}: UseDesktopConfirmShortcutOptions): void {
|
|
81
|
+
useEffect(() => {
|
|
82
|
+
if (!open || !enabled || !onConfirm || confirmDisabled || confirmLoading) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const desktopModifierLabel = getDesktopShortcutModifierLabel();
|
|
87
|
+
|
|
88
|
+
const handleKeyDown = (event: KeyboardEvent): void => {
|
|
89
|
+
if (!isAllowedConfirmShortcutEvent(event, desktopModifierLabel)) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
event.preventDefault();
|
|
94
|
+
onConfirm();
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
98
|
+
|
|
99
|
+
return () => {
|
|
100
|
+
window.removeEventListener("keydown", handleKeyDown);
|
|
101
|
+
};
|
|
102
|
+
}, [confirmDisabled, confirmLoading, enabled, onConfirm, open]);
|
|
103
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import type { ReactNode } from 'react';
|
|
4
|
+
|
|
5
|
+
import { SheetActionFooter } from '@/components/ui/responsive-sheet.footer';
|
|
6
|
+
import { DesktopSheetLayout, MobileSheetLayout } from '@/components/ui/responsive-sheet.layouts';
|
|
7
|
+
import {
|
|
8
|
+
useDesktopConfirmShortcut,
|
|
9
|
+
useDesktopShortcutModifierLabel,
|
|
10
|
+
} from '@/components/ui/responsive-sheet.shortcuts';
|
|
11
|
+
import { cn } from '@/lib/utils';
|
|
12
|
+
import { useIsMobile } from '@/components/ui/use-media-query';
|
|
13
|
+
|
|
14
|
+
export interface SheetOutsideInteractionGuard {
|
|
15
|
+
readonly selectors: readonly string[];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface ResponsiveSheetClassNames {
|
|
19
|
+
readonly desktopContent?: string;
|
|
20
|
+
readonly mobileContent?: string;
|
|
21
|
+
readonly header?: string;
|
|
22
|
+
readonly body?: string;
|
|
23
|
+
readonly footer?: string;
|
|
24
|
+
readonly title?: string;
|
|
25
|
+
readonly description?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface ResponsiveSheetProps {
|
|
29
|
+
readonly open: boolean;
|
|
30
|
+
readonly onOpenChange: (open: boolean) => void;
|
|
31
|
+
readonly title: ReactNode;
|
|
32
|
+
readonly description?: ReactNode;
|
|
33
|
+
readonly children: ReactNode;
|
|
34
|
+
readonly footer?: ReactNode;
|
|
35
|
+
readonly onCancel?: () => void;
|
|
36
|
+
readonly cancelLabel?: ReactNode;
|
|
37
|
+
readonly onConfirm?: () => void;
|
|
38
|
+
readonly confirmLabel?: ReactNode;
|
|
39
|
+
readonly confirmDisabled?: boolean;
|
|
40
|
+
readonly confirmLoading?: boolean;
|
|
41
|
+
readonly width?: number;
|
|
42
|
+
readonly modal?: boolean;
|
|
43
|
+
readonly outsideInteractionGuard?: SheetOutsideInteractionGuard;
|
|
44
|
+
readonly enableDesktopConfirmShortcut?: boolean;
|
|
45
|
+
readonly mobileDrawerContentClassName?: string;
|
|
46
|
+
readonly className?: string;
|
|
47
|
+
readonly contentClassName?: string;
|
|
48
|
+
readonly footerClassName?: string;
|
|
49
|
+
readonly classes?: ResponsiveSheetClassNames;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function ResponsiveSheet({
|
|
53
|
+
open,
|
|
54
|
+
onOpenChange,
|
|
55
|
+
title,
|
|
56
|
+
description,
|
|
57
|
+
children,
|
|
58
|
+
footer,
|
|
59
|
+
onCancel,
|
|
60
|
+
cancelLabel = 'Cancel',
|
|
61
|
+
onConfirm,
|
|
62
|
+
confirmLabel = 'Save',
|
|
63
|
+
confirmDisabled = false,
|
|
64
|
+
confirmLoading = false,
|
|
65
|
+
width = 550,
|
|
66
|
+
modal = true,
|
|
67
|
+
outsideInteractionGuard,
|
|
68
|
+
enableDesktopConfirmShortcut = true,
|
|
69
|
+
mobileDrawerContentClassName,
|
|
70
|
+
className,
|
|
71
|
+
contentClassName,
|
|
72
|
+
footerClassName,
|
|
73
|
+
classes,
|
|
74
|
+
}: ResponsiveSheetProps): React.ReactElement {
|
|
75
|
+
const isMobile = useIsMobile();
|
|
76
|
+
const desktopConfirmShortcutEnabled =
|
|
77
|
+
!isMobile && enableDesktopConfirmShortcut && Boolean(onConfirm);
|
|
78
|
+
const desktopModifierLabel = useDesktopShortcutModifierLabel(desktopConfirmShortcutEnabled);
|
|
79
|
+
|
|
80
|
+
useDesktopConfirmShortcut({
|
|
81
|
+
open,
|
|
82
|
+
enabled: desktopConfirmShortcutEnabled,
|
|
83
|
+
confirmDisabled,
|
|
84
|
+
confirmLoading,
|
|
85
|
+
onConfirm: onConfirm
|
|
86
|
+
? () => {
|
|
87
|
+
onConfirm();
|
|
88
|
+
}
|
|
89
|
+
: undefined,
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
const resolvedFooter = (
|
|
93
|
+
<SheetActionFooter
|
|
94
|
+
footer={footer}
|
|
95
|
+
onCancel={onCancel}
|
|
96
|
+
cancelLabel={cancelLabel}
|
|
97
|
+
onConfirm={onConfirm}
|
|
98
|
+
confirmLabel={confirmLabel}
|
|
99
|
+
confirmDisabled={confirmDisabled}
|
|
100
|
+
confirmLoading={confirmLoading}
|
|
101
|
+
desktopConfirmShortcutEnabled={desktopConfirmShortcutEnabled}
|
|
102
|
+
desktopModifierLabel={desktopModifierLabel}
|
|
103
|
+
/>
|
|
104
|
+
);
|
|
105
|
+
const hasFooter = [footer, onCancel, onConfirm].some(
|
|
106
|
+
(value) => value !== null && value !== undefined,
|
|
107
|
+
);
|
|
108
|
+
const sharedLayoutProps = {
|
|
109
|
+
open,
|
|
110
|
+
onOpenChange,
|
|
111
|
+
modal,
|
|
112
|
+
outsideInteractionGuard,
|
|
113
|
+
title,
|
|
114
|
+
description,
|
|
115
|
+
footer: hasFooter ? resolvedFooter : null,
|
|
116
|
+
children,
|
|
117
|
+
contentClassName,
|
|
118
|
+
footerClassName,
|
|
119
|
+
mobileDrawerContentClassName,
|
|
120
|
+
classes: {
|
|
121
|
+
...classes,
|
|
122
|
+
desktopContent: cn(className, classes?.desktopContent),
|
|
123
|
+
mobileContent: cn(className, mobileDrawerContentClassName, classes?.mobileContent),
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
return isMobile ? (
|
|
128
|
+
<MobileSheetLayout {...sharedLayoutProps} />
|
|
129
|
+
) : (
|
|
130
|
+
<DesktopSheetLayout {...sharedLayoutProps} width={width} />
|
|
131
|
+
);
|
|
132
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { cva } from "class-variance-authority";
|
|
3
|
+
import { Slot } from "radix-ui";
|
|
4
|
+
|
|
5
|
+
import { cn } from "@/lib/utils";
|
|
6
|
+
|
|
7
|
+
const buttonVariants = cva(
|
|
8
|
+
"group/button inline-flex shrink-0 cursor-pointer items-center justify-center rounded-lg border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
9
|
+
{
|
|
10
|
+
variants: {
|
|
11
|
+
variant: {
|
|
12
|
+
default:
|
|
13
|
+
"bg-primary text-primary-foreground hover:brightness-90 [a]:hover:bg-primary/80",
|
|
14
|
+
outline:
|
|
15
|
+
"border-border bg-background hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",
|
|
16
|
+
secondary:
|
|
17
|
+
"bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
|
|
18
|
+
ghost:
|
|
19
|
+
"hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50",
|
|
20
|
+
destructive:
|
|
21
|
+
"bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40",
|
|
22
|
+
link: "text-primary underline-offset-4 hover:underline",
|
|
23
|
+
},
|
|
24
|
+
size: {
|
|
25
|
+
default:
|
|
26
|
+
"h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
|
|
27
|
+
xs: "h-6 gap-1 rounded-[min(var(--radius-md),10px)] px-2 text-xs in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3",
|
|
28
|
+
sm: "h-7 gap-1 rounded-[min(var(--radius-md),12px)] px-2.5 text-[0.8rem] in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5",
|
|
29
|
+
lg: "h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
|
|
30
|
+
icon: "size-8",
|
|
31
|
+
"icon-xs":
|
|
32
|
+
"size-6 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-lg [&_svg:not([class*='size-'])]:size-3",
|
|
33
|
+
"icon-sm":
|
|
34
|
+
"size-7 rounded-[min(var(--radius-md),12px)] in-data-[slot=button-group]:rounded-lg",
|
|
35
|
+
"icon-lg": "size-9",
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
defaultVariants: {
|
|
39
|
+
variant: "default",
|
|
40
|
+
size: "default",
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
type ButtonVariant =
|
|
46
|
+
| "default"
|
|
47
|
+
| "outline"
|
|
48
|
+
| "secondary"
|
|
49
|
+
| "ghost"
|
|
50
|
+
| "destructive"
|
|
51
|
+
| "link";
|
|
52
|
+
type ButtonSize =
|
|
53
|
+
| "default"
|
|
54
|
+
| "xs"
|
|
55
|
+
| "sm"
|
|
56
|
+
| "lg"
|
|
57
|
+
| "icon"
|
|
58
|
+
| "icon-xs"
|
|
59
|
+
| "icon-sm"
|
|
60
|
+
| "icon-lg";
|
|
61
|
+
|
|
62
|
+
interface ButtonProps extends React.ComponentProps<"button"> {
|
|
63
|
+
readonly asChild?: boolean;
|
|
64
|
+
readonly size?: ButtonSize;
|
|
65
|
+
readonly variant?: ButtonVariant;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function Button({
|
|
69
|
+
className,
|
|
70
|
+
variant = "default",
|
|
71
|
+
size = "default",
|
|
72
|
+
asChild = false,
|
|
73
|
+
...props
|
|
74
|
+
}: ButtonProps) {
|
|
75
|
+
const Comp = asChild ? Slot.Root : "button";
|
|
76
|
+
|
|
77
|
+
return (
|
|
78
|
+
<Comp
|
|
79
|
+
data-slot="button"
|
|
80
|
+
data-variant={variant}
|
|
81
|
+
data-size={size}
|
|
82
|
+
className={cn(buttonVariants({ variant, size, className }))}
|
|
83
|
+
{...props}
|
|
84
|
+
/>
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export { Button, buttonVariants };
|
|
89
|
+
export type { ButtonProps, ButtonSize, ButtonVariant };
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { Drawer as DrawerPrimitive } from 'vaul';
|
|
5
|
+
|
|
6
|
+
import { cn } from '@/lib/utils';
|
|
7
|
+
|
|
8
|
+
function Drawer({ ...props }: React.ComponentProps<typeof DrawerPrimitive.Root>) {
|
|
9
|
+
return <DrawerPrimitive.Root data-slot="drawer" {...props} />;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function DrawerPortal({ ...props }: React.ComponentProps<typeof DrawerPrimitive.Portal>) {
|
|
13
|
+
return <DrawerPrimitive.Portal data-slot="drawer-portal" {...props} />;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function DrawerOverlay({
|
|
17
|
+
className,
|
|
18
|
+
...props
|
|
19
|
+
}: React.ComponentProps<typeof DrawerPrimitive.Overlay>) {
|
|
20
|
+
return (
|
|
21
|
+
<DrawerPrimitive.Overlay
|
|
22
|
+
data-slot="drawer-overlay"
|
|
23
|
+
className={cn(
|
|
24
|
+
'data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 fixed inset-0 z-50 bg-black/10 backdrop-blur-xs',
|
|
25
|
+
className,
|
|
26
|
+
)}
|
|
27
|
+
{...props}
|
|
28
|
+
/>
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function DrawerContent({
|
|
33
|
+
className,
|
|
34
|
+
children,
|
|
35
|
+
...props
|
|
36
|
+
}: React.ComponentProps<typeof DrawerPrimitive.Content>) {
|
|
37
|
+
return (
|
|
38
|
+
<DrawerPortal data-slot="drawer-portal">
|
|
39
|
+
<DrawerOverlay />
|
|
40
|
+
<DrawerPrimitive.Content
|
|
41
|
+
data-slot="drawer-content"
|
|
42
|
+
className={cn(
|
|
43
|
+
'bg-background group/drawer-content fixed z-50 flex h-auto flex-col overflow-visible text-sm data-[vaul-drawer-direction=bottom]:inset-x-0 data-[vaul-drawer-direction=bottom]:bottom-0 data-[vaul-drawer-direction=bottom]:mt-24 data-[vaul-drawer-direction=bottom]:max-h-[80vh] data-[vaul-drawer-direction=bottom]:rounded-t-xl data-[vaul-drawer-direction=bottom]:border-t data-[vaul-drawer-direction=left]:inset-y-0 data-[vaul-drawer-direction=left]:left-0 data-[vaul-drawer-direction=left]:w-3/4 data-[vaul-drawer-direction=left]:rounded-r-xl data-[vaul-drawer-direction=left]:border-r data-[vaul-drawer-direction=right]:inset-y-0 data-[vaul-drawer-direction=right]:right-0 data-[vaul-drawer-direction=right]:w-3/4 data-[vaul-drawer-direction=right]:rounded-l-xl data-[vaul-drawer-direction=right]:border-l data-[vaul-drawer-direction=top]:inset-x-0 data-[vaul-drawer-direction=top]:top-0 data-[vaul-drawer-direction=top]:mb-24 data-[vaul-drawer-direction=top]:max-h-[80vh] data-[vaul-drawer-direction=top]:rounded-b-xl data-[vaul-drawer-direction=top]:border-b data-[vaul-drawer-direction=left]:sm:max-w-sm data-[vaul-drawer-direction=right]:sm:max-w-sm',
|
|
44
|
+
className,
|
|
45
|
+
)}
|
|
46
|
+
{...props}
|
|
47
|
+
>
|
|
48
|
+
<div className="bg-muted mx-auto mt-4 hidden h-1 w-[100px] shrink-0 rounded-full group-data-[vaul-drawer-direction=bottom]/drawer-content:block" />
|
|
49
|
+
{children}
|
|
50
|
+
</DrawerPrimitive.Content>
|
|
51
|
+
</DrawerPortal>
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function DrawerHeader({ className, ...props }: React.ComponentProps<'div'>) {
|
|
56
|
+
return (
|
|
57
|
+
<div
|
|
58
|
+
data-slot="drawer-header"
|
|
59
|
+
className={cn(
|
|
60
|
+
'flex flex-col gap-0.5 p-4 group-data-[vaul-drawer-direction=bottom]/drawer-content:text-center group-data-[vaul-drawer-direction=top]/drawer-content:text-center md:gap-0.5 md:text-left',
|
|
61
|
+
className,
|
|
62
|
+
)}
|
|
63
|
+
{...props}
|
|
64
|
+
/>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function DrawerTitle({ className, ...props }: React.ComponentProps<typeof DrawerPrimitive.Title>) {
|
|
69
|
+
return (
|
|
70
|
+
<DrawerPrimitive.Title
|
|
71
|
+
data-slot="drawer-title"
|
|
72
|
+
className={cn('text-foreground text-base font-medium', className)}
|
|
73
|
+
{...props}
|
|
74
|
+
/>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function DrawerDescription({
|
|
79
|
+
className,
|
|
80
|
+
...props
|
|
81
|
+
}: React.ComponentProps<typeof DrawerPrimitive.Description>) {
|
|
82
|
+
return (
|
|
83
|
+
<DrawerPrimitive.Description
|
|
84
|
+
data-slot="drawer-description"
|
|
85
|
+
className={cn('text-muted-foreground text-sm', className)}
|
|
86
|
+
{...props}
|
|
87
|
+
/>
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export {
|
|
92
|
+
Drawer,
|
|
93
|
+
DrawerContent,
|
|
94
|
+
DrawerDescription,
|
|
95
|
+
DrawerHeader,
|
|
96
|
+
DrawerOverlay,
|
|
97
|
+
DrawerPortal,
|
|
98
|
+
DrawerTitle,
|
|
99
|
+
};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { CircleHelp } from "lucide-react";
|
|
4
|
+
import { useState, type ReactNode } from "react";
|
|
5
|
+
|
|
6
|
+
import { ResponsiveSheet } from "@/components/ui/responsive-sheet";
|
|
7
|
+
import { Button } from "@/components/ui/button";
|
|
8
|
+
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
|
|
9
|
+
|
|
10
|
+
export interface HelpInfoButtonProps {
|
|
11
|
+
readonly ariaLabel: string;
|
|
12
|
+
readonly tooltip: ReactNode;
|
|
13
|
+
readonly title: ReactNode;
|
|
14
|
+
readonly description?: ReactNode;
|
|
15
|
+
readonly children: ReactNode;
|
|
16
|
+
readonly width?: number;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function HelpInfoButton({
|
|
20
|
+
ariaLabel,
|
|
21
|
+
tooltip,
|
|
22
|
+
title,
|
|
23
|
+
description,
|
|
24
|
+
children,
|
|
25
|
+
width = 620,
|
|
26
|
+
}: HelpInfoButtonProps): React.ReactElement {
|
|
27
|
+
const [open, setOpen] = useState(false);
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<>
|
|
31
|
+
<Tooltip>
|
|
32
|
+
<TooltipTrigger asChild>
|
|
33
|
+
<Button
|
|
34
|
+
type="button"
|
|
35
|
+
variant="ghost"
|
|
36
|
+
size="icon"
|
|
37
|
+
className="size-6 text-muted-foreground hover:text-foreground"
|
|
38
|
+
aria-label={ariaLabel}
|
|
39
|
+
onClick={() => {
|
|
40
|
+
setOpen(true);
|
|
41
|
+
}}
|
|
42
|
+
>
|
|
43
|
+
<CircleHelp className="size-3.5" />
|
|
44
|
+
</Button>
|
|
45
|
+
</TooltipTrigger>
|
|
46
|
+
<TooltipContent>{tooltip}</TooltipContent>
|
|
47
|
+
</Tooltip>
|
|
48
|
+
<ResponsiveSheet
|
|
49
|
+
open={open}
|
|
50
|
+
onOpenChange={setOpen}
|
|
51
|
+
title={title}
|
|
52
|
+
description={description}
|
|
53
|
+
cancelLabel="Close"
|
|
54
|
+
onCancel={() => {
|
|
55
|
+
setOpen(false);
|
|
56
|
+
}}
|
|
57
|
+
width={width}
|
|
58
|
+
>
|
|
59
|
+
{children}
|
|
60
|
+
</ResponsiveSheet>
|
|
61
|
+
</>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { Command } from 'lucide-react';
|
|
4
|
+
|
|
5
|
+
import type { ReactNode } from 'react';
|
|
6
|
+
|
|
7
|
+
import { cn } from '@/lib/utils';
|
|
8
|
+
|
|
9
|
+
export function KeyboardKeycap({
|
|
10
|
+
children,
|
|
11
|
+
className,
|
|
12
|
+
}: {
|
|
13
|
+
readonly children: ReactNode;
|
|
14
|
+
readonly className?: string;
|
|
15
|
+
}): React.ReactElement {
|
|
16
|
+
return (
|
|
17
|
+
<span
|
|
18
|
+
className={cn(
|
|
19
|
+
'inline-flex h-4 min-w-4 items-center justify-center rounded-[4px] border px-1 text-[9px] font-semibold leading-none',
|
|
20
|
+
className,
|
|
21
|
+
)}
|
|
22
|
+
>
|
|
23
|
+
{children}
|
|
24
|
+
</span>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function ShortcutModifierKeycap({
|
|
29
|
+
modifierLabel,
|
|
30
|
+
className,
|
|
31
|
+
}: {
|
|
32
|
+
readonly modifierLabel: string;
|
|
33
|
+
readonly className?: string;
|
|
34
|
+
}): React.ReactElement {
|
|
35
|
+
return (
|
|
36
|
+
<KeyboardKeycap className={className}>
|
|
37
|
+
{modifierLabel === 'Cmd' ? <Command className="size-[10px]" /> : 'Ctrl'}
|
|
38
|
+
</KeyboardKeycap>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { X } from 'lucide-react';
|
|
4
|
+
import * as React from 'react';
|
|
5
|
+
import { Dialog as SheetPrimitive } from 'radix-ui';
|
|
6
|
+
|
|
7
|
+
import { Button } from '@/components/ui/button';
|
|
8
|
+
import { cn } from '@/lib/utils';
|
|
9
|
+
|
|
10
|
+
function Sheet({ ...props }: React.ComponentProps<typeof SheetPrimitive.Root>) {
|
|
11
|
+
return <SheetPrimitive.Root data-slot="sheet" {...props} />;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function SheetPortal({ ...props }: React.ComponentProps<typeof SheetPrimitive.Portal>) {
|
|
15
|
+
return <SheetPrimitive.Portal data-slot="sheet-portal" {...props} />;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function SheetOverlay({
|
|
19
|
+
className,
|
|
20
|
+
...props
|
|
21
|
+
}: React.ComponentProps<typeof SheetPrimitive.Overlay>) {
|
|
22
|
+
return (
|
|
23
|
+
<SheetPrimitive.Overlay
|
|
24
|
+
data-slot="sheet-overlay"
|
|
25
|
+
className={cn(
|
|
26
|
+
'data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 fixed inset-0 z-50 bg-black/10 backdrop-blur-xs duration-100 data-ending-style:opacity-0 data-starting-style:opacity-0',
|
|
27
|
+
className,
|
|
28
|
+
)}
|
|
29
|
+
{...props}
|
|
30
|
+
/>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function SheetContent({
|
|
35
|
+
className,
|
|
36
|
+
children,
|
|
37
|
+
side = 'right',
|
|
38
|
+
showCloseButton = true,
|
|
39
|
+
...props
|
|
40
|
+
}: React.ComponentProps<typeof SheetPrimitive.Content> & {
|
|
41
|
+
side?: 'top' | 'right' | 'bottom' | 'left';
|
|
42
|
+
showCloseButton?: boolean;
|
|
43
|
+
}) {
|
|
44
|
+
return (
|
|
45
|
+
<SheetPortal>
|
|
46
|
+
<SheetOverlay />
|
|
47
|
+
<SheetPrimitive.Content
|
|
48
|
+
data-slot="sheet-content"
|
|
49
|
+
data-side={side}
|
|
50
|
+
className={cn(
|
|
51
|
+
'bg-background data-open:animate-in data-closed:animate-out data-[side=right]:data-closed:slide-out-to-right-10 data-[side=right]:data-open:slide-in-from-right-10 data-[side=left]:data-closed:slide-out-to-left-10 data-[side=left]:data-open:slide-in-from-left-10 data-[side=top]:data-closed:slide-out-to-top-10 data-[side=top]:data-open:slide-in-from-top-10 data-closed:fade-out-0 data-open:fade-in-0 data-[side=bottom]:data-closed:slide-out-to-bottom-10 data-[side=bottom]:data-open:slide-in-from-bottom-10 fixed z-50 flex flex-col gap-4 overflow-visible bg-clip-padding text-sm shadow-lg transition duration-200 ease-in-out data-[side=bottom]:inset-x-0 data-[side=bottom]:bottom-0 data-[side=bottom]:h-auto data-[side=bottom]:border-t data-[side=left]:inset-y-0 data-[side=left]:left-0 data-[side=left]:h-full data-[side=left]:w-3/4 data-[side=left]:rounded-r-xl data-[side=left]:border-r data-[side=right]:inset-y-0 data-[side=right]:right-0 data-[side=right]:h-full data-[side=right]:w-3/4 data-[side=right]:rounded-l-xl data-[side=right]:border-l data-[side=top]:inset-x-0 data-[side=top]:top-0 data-[side=top]:h-auto data-[side=top]:border-b data-[side=left]:sm:max-w-sm data-[side=right]:sm:max-w-sm',
|
|
52
|
+
className,
|
|
53
|
+
)}
|
|
54
|
+
{...props}
|
|
55
|
+
>
|
|
56
|
+
{children}
|
|
57
|
+
{showCloseButton ? (
|
|
58
|
+
<SheetPrimitive.Close data-slot="sheet-close" asChild>
|
|
59
|
+
<Button variant="ghost" className="absolute top-3 right-3" size="icon-sm">
|
|
60
|
+
<X className="size-4" />
|
|
61
|
+
<span className="sr-only">Close</span>
|
|
62
|
+
</Button>
|
|
63
|
+
</SheetPrimitive.Close>
|
|
64
|
+
) : null}
|
|
65
|
+
</SheetPrimitive.Content>
|
|
66
|
+
</SheetPortal>
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function SheetHeader({ className, ...props }: React.ComponentProps<'div'>) {
|
|
71
|
+
return (
|
|
72
|
+
<div
|
|
73
|
+
data-slot="sheet-header"
|
|
74
|
+
className={cn('flex flex-col gap-0.5 p-4', className)}
|
|
75
|
+
{...props}
|
|
76
|
+
/>
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function SheetTitle({ className, ...props }: React.ComponentProps<typeof SheetPrimitive.Title>) {
|
|
81
|
+
return (
|
|
82
|
+
<SheetPrimitive.Title
|
|
83
|
+
data-slot="sheet-title"
|
|
84
|
+
className={cn('text-foreground text-base font-medium', className)}
|
|
85
|
+
{...props}
|
|
86
|
+
/>
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function SheetDescription({
|
|
91
|
+
className,
|
|
92
|
+
...props
|
|
93
|
+
}: React.ComponentProps<typeof SheetPrimitive.Description>) {
|
|
94
|
+
return (
|
|
95
|
+
<SheetPrimitive.Description
|
|
96
|
+
data-slot="sheet-description"
|
|
97
|
+
className={cn('text-muted-foreground text-sm', className)}
|
|
98
|
+
{...props}
|
|
99
|
+
/>
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle };
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import { Tooltip as TooltipPrimitive } from "radix-ui"
|
|
5
|
+
|
|
6
|
+
import { cn } from "@/lib/utils"
|
|
7
|
+
|
|
8
|
+
function TooltipProvider({
|
|
9
|
+
delayDuration = 0,
|
|
10
|
+
...props
|
|
11
|
+
}: React.ComponentProps<typeof TooltipPrimitive.Provider>) {
|
|
12
|
+
return (
|
|
13
|
+
<TooltipPrimitive.Provider
|
|
14
|
+
data-slot="tooltip-provider"
|
|
15
|
+
delayDuration={delayDuration}
|
|
16
|
+
{...props}
|
|
17
|
+
/>
|
|
18
|
+
)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function Tooltip({
|
|
22
|
+
...props
|
|
23
|
+
}: React.ComponentProps<typeof TooltipPrimitive.Root>) {
|
|
24
|
+
return <TooltipPrimitive.Root data-slot="tooltip" {...props} />
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function TooltipTrigger({
|
|
28
|
+
...props
|
|
29
|
+
}: React.ComponentProps<typeof TooltipPrimitive.Trigger>) {
|
|
30
|
+
return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function TooltipContent({
|
|
34
|
+
className,
|
|
35
|
+
sideOffset = 0,
|
|
36
|
+
children,
|
|
37
|
+
...props
|
|
38
|
+
}: React.ComponentProps<typeof TooltipPrimitive.Content>) {
|
|
39
|
+
return (
|
|
40
|
+
<TooltipPrimitive.Portal>
|
|
41
|
+
<TooltipPrimitive.Content
|
|
42
|
+
data-slot="tooltip-content"
|
|
43
|
+
sideOffset={sideOffset}
|
|
44
|
+
className={cn(
|
|
45
|
+
"data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-[state=delayed-open]:animate-in data-[state=delayed-open]:fade-in-0 data-[state=delayed-open]:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 rounded-md bg-foreground px-3 py-1.5 text-xs text-background z-50 w-fit max-w-[min(20rem,calc(100vw-1.5rem))] whitespace-normal break-words origin-(--radix-tooltip-content-transform-origin)",
|
|
46
|
+
className
|
|
47
|
+
)}
|
|
48
|
+
{...props}
|
|
49
|
+
>
|
|
50
|
+
{children}
|
|
51
|
+
<TooltipPrimitive.Arrow className="size-2.5 rotate-45 rounded-[2px] bg-foreground fill-foreground z-50 translate-y-[calc(-50%_-_2px)]" />
|
|
52
|
+
</TooltipPrimitive.Content>
|
|
53
|
+
</TooltipPrimitive.Portal>
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger }
|