@neasg/design-system 0.4.8 → 0.4.9
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 +4 -4
- package/dist/alert.d.ts +21 -2
- package/dist/alert.js +10 -3
- package/dist/avatar.d.ts +5 -2
- package/dist/avatar.js +76 -8
- package/dist/back-button.d.ts +2 -0
- package/dist/back-button.js +1 -1
- package/dist/badge.d.ts +3 -2
- package/dist/badge.js +9 -3
- package/dist/breadcrumb.js +2 -1
- package/dist/button.d.ts +1 -1
- package/dist/button.js +12 -9
- package/dist/calendar.js +10 -9
- package/dist/card.d.ts +29 -1
- package/dist/card.js +61 -7
- package/dist/checkbox.d.ts +2 -0
- package/dist/checkbox.js +2 -2
- package/dist/close-button.d.ts +6 -0
- package/dist/close-button.js +8 -0
- package/dist/collapsible.d.ts +7 -1
- package/dist/collapsible.js +2 -2
- package/dist/command-search.d.ts +16 -1
- package/dist/command-search.js +42 -16
- package/dist/command.js +3 -3
- package/dist/copy-button.d.ts +3 -1
- package/dist/copy-button.js +4 -2
- package/dist/count-badge.d.ts +3 -1
- package/dist/count-badge.js +10 -5
- package/dist/date-input.d.ts +18 -3
- package/dist/date-input.js +94 -21
- package/dist/dialog-primitive.js +4 -3
- package/dist/draggable-tabs.d.ts +7 -0
- package/dist/draggable-tabs.js +6 -5
- package/dist/drawer.js +2 -2
- package/dist/dropdown-button.d.ts +18 -0
- package/dist/dropdown-button.js +31 -0
- package/dist/edit-button.d.ts +10 -0
- package/dist/edit-button.js +7 -0
- package/dist/editable-table.d.ts +3 -1
- package/dist/editable-table.js +25 -12
- package/dist/field.d.ts +2 -2
- package/dist/field.js +4 -3
- package/dist/file-upload-status-toast.d.ts +28 -0
- package/dist/file-upload-status-toast.js +136 -0
- package/dist/file-upload.js +8 -7
- package/dist/filter-popover.d.ts +37 -0
- package/dist/filter-popover.js +73 -0
- package/dist/filter-toggle.js +2 -2
- package/dist/index.d.ts +45 -14
- package/dist/index.js +19 -4
- package/dist/input-control.d.ts +3 -2
- package/dist/input-control.js +3 -2
- package/dist/label-value-grid.d.ts +4 -2
- package/dist/label-value-grid.js +7 -6
- package/dist/label-value.js +3 -1
- package/dist/layout-right-panel-edge.d.ts +6 -0
- package/dist/layout-right-panel-edge.js +6 -0
- package/dist/layout.d.ts +77 -5
- package/dist/layout.js +439 -35
- package/dist/lib/date-utils.d.ts +10 -2
- package/dist/lib/date-utils.js +91 -11
- package/dist/lib/utils.js +8 -1
- package/dist/link.js +2 -2
- package/dist/message-item.d.ts +62 -0
- package/dist/message-item.js +148 -0
- package/dist/multi-select.js +31 -5
- package/dist/notification.d.ts +82 -0
- package/dist/notification.js +121 -0
- package/dist/otp-input.js +1 -1
- package/dist/page-header.js +1 -1
- package/dist/page-section.d.ts +2 -1
- package/dist/page-section.js +4 -3
- package/dist/pagination.js +2 -2
- package/dist/popover-menu.d.ts +23 -1
- package/dist/popover-menu.js +75 -5
- package/dist/popover-primitive.js +1 -1
- package/dist/progress.d.ts +5 -2
- package/dist/progress.js +6 -3
- package/dist/radio-group.d.ts +21 -0
- package/dist/radio-group.js +41 -0
- package/dist/rich-text-editor.d.ts +56 -0
- package/dist/rich-text-editor.js +394 -0
- package/dist/routing-timeline.d.ts +22 -0
- package/dist/routing-timeline.js +58 -0
- package/dist/scroll-hint.d.ts +8 -0
- package/dist/scroll-hint.js +7 -0
- package/dist/search-input-shell.js +1 -1
- package/dist/search-input.js +2 -2
- package/dist/section-nav.js +4 -4
- package/dist/select-primitive.js +3 -3
- package/dist/select.js +1 -1
- package/dist/skeleton.js +1 -1
- package/dist/styles.css +235 -57
- package/dist/table-column-visibility.d.ts +21 -0
- package/dist/table-column-visibility.js +74 -0
- package/dist/table-toolbar.js +1 -1
- package/dist/table.d.ts +12 -1
- package/dist/table.js +67 -33
- package/dist/tabs.d.ts +14 -3
- package/dist/tabs.js +60 -6
- package/dist/tailwind-preset.js +46 -0
- package/dist/task-mode-shell.d.ts +24 -0
- package/dist/task-mode-shell.js +110 -0
- package/dist/textarea.js +2 -1
- package/dist/theme-switcher.d.ts +28 -0
- package/dist/theme-switcher.js +27 -0
- package/dist/theme.d.ts +167 -0
- package/dist/theme.js +112 -0
- package/dist/toaster.js +5 -4
- package/dist/tooltip.js +1 -1
- package/dist/typography.d.ts +1 -1
- package/dist/typography.js +5 -5
- package/dist/workspace-header.d.ts +13 -0
- package/dist/workspace-header.js +11 -0
- package/package.json +15 -1
package/dist/layout.js
CHANGED
|
@@ -2,21 +2,87 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import * as CollapsiblePrimitive from "@radix-ui/react-collapsible";
|
|
5
|
+
import { GripVertical } from "lucide-react";
|
|
5
6
|
import { ChevronDownIcon } from "./animated-icons/chevron-down";
|
|
6
7
|
import { ChevronLeftIcon } from "./animated-icons/chevron-left";
|
|
7
8
|
import { ChevronRightIcon } from "./animated-icons/chevron-right";
|
|
8
|
-
import {
|
|
9
|
+
import { AvatarProfile } from "./avatar";
|
|
9
10
|
import { Button } from "./button";
|
|
10
11
|
import { CountBadge } from "./count-badge";
|
|
12
|
+
import { ScrollHint } from "./scroll-hint";
|
|
13
|
+
import { Tabs } from "./tabs";
|
|
11
14
|
import { Tooltip } from "./tooltip";
|
|
15
|
+
import { Typography } from "./typography";
|
|
12
16
|
import { cn } from "./lib/utils";
|
|
17
|
+
import { rightPanelEdgeClassName, rightPanelEdgeClosedClassName, rightPanelEdgeOpenClassName, rightPanelResizeHandleSurfaceClassName, } from "./layout-right-panel-edge";
|
|
13
18
|
const COLLAPSE_BREAKPOINT = 1280;
|
|
19
|
+
const RIGHT_PANEL_AUTO_COLLAPSE_BREAKPOINT = 1600;
|
|
20
|
+
const RIGHT_PANEL_TRANSITION_MS = 300;
|
|
21
|
+
const RIGHT_PANEL_RESIZE_DEFAULT_WIDTH = 432;
|
|
22
|
+
const RIGHT_PANEL_RESIZE_MIN_WIDTH = 320;
|
|
23
|
+
const RIGHT_PANEL_RESIZE_MAX_WIDTH = 640;
|
|
24
|
+
const RIGHT_PANEL_FIXED_WIDTH_RATIO = 0.24;
|
|
25
|
+
const RIGHT_PANEL_SCROLL_HINT_THRESHOLD = 8;
|
|
26
|
+
const collapsedSidebarControlClassName = "h-control min-h-control w-control min-w-control max-w-control shrink-0 rounded-control p-0";
|
|
14
27
|
const TOP_OFFSET_CSS_VAR = "--layout-top-offset";
|
|
15
28
|
const SidebarContext = React.createContext(undefined);
|
|
16
29
|
const useIsomorphicLayoutEffect = typeof window === "undefined" ? React.useEffect : React.useLayoutEffect;
|
|
17
|
-
|
|
18
|
-
const
|
|
19
|
-
const
|
|
30
|
+
function useScrollOverflowHint() {
|
|
31
|
+
const scrollRef = React.useRef(null);
|
|
32
|
+
const [canScrollDown, setCanScrollDown] = React.useState(false);
|
|
33
|
+
const updateScrollHint = React.useCallback(() => {
|
|
34
|
+
const node = scrollRef.current;
|
|
35
|
+
if (!node) {
|
|
36
|
+
setCanScrollDown(false);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const nextCanScrollDown = node.scrollHeight - node.scrollTop - node.clientHeight >
|
|
40
|
+
RIGHT_PANEL_SCROLL_HINT_THRESHOLD;
|
|
41
|
+
setCanScrollDown((current) => current === nextCanScrollDown ? current : nextCanScrollDown);
|
|
42
|
+
}, []);
|
|
43
|
+
useIsomorphicLayoutEffect(() => {
|
|
44
|
+
updateScrollHint();
|
|
45
|
+
});
|
|
46
|
+
useIsomorphicLayoutEffect(() => {
|
|
47
|
+
const node = scrollRef.current;
|
|
48
|
+
if (!node) {
|
|
49
|
+
setCanScrollDown(false);
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
updateScrollHint();
|
|
53
|
+
node.addEventListener("scroll", updateScrollHint, { passive: true });
|
|
54
|
+
window.addEventListener("resize", updateScrollHint);
|
|
55
|
+
const resizeObserver = typeof ResizeObserver === "undefined"
|
|
56
|
+
? undefined
|
|
57
|
+
: new ResizeObserver(() => updateScrollHint());
|
|
58
|
+
const mutationObserver = typeof MutationObserver === "undefined"
|
|
59
|
+
? undefined
|
|
60
|
+
: new MutationObserver(() => updateScrollHint());
|
|
61
|
+
resizeObserver === null || resizeObserver === void 0 ? void 0 : resizeObserver.observe(node);
|
|
62
|
+
Array.from(node.children).forEach((child) => {
|
|
63
|
+
resizeObserver === null || resizeObserver === void 0 ? void 0 : resizeObserver.observe(child);
|
|
64
|
+
});
|
|
65
|
+
mutationObserver === null || mutationObserver === void 0 ? void 0 : mutationObserver.observe(node, {
|
|
66
|
+
childList: true,
|
|
67
|
+
characterData: true,
|
|
68
|
+
subtree: true,
|
|
69
|
+
});
|
|
70
|
+
return () => {
|
|
71
|
+
node.removeEventListener("scroll", updateScrollHint);
|
|
72
|
+
window.removeEventListener("resize", updateScrollHint);
|
|
73
|
+
resizeObserver === null || resizeObserver === void 0 ? void 0 : resizeObserver.disconnect();
|
|
74
|
+
mutationObserver === null || mutationObserver === void 0 ? void 0 : mutationObserver.disconnect();
|
|
75
|
+
};
|
|
76
|
+
}, [updateScrollHint]);
|
|
77
|
+
return { scrollRef, canScrollDown };
|
|
78
|
+
}
|
|
79
|
+
export function SidebarProvider({ children, defaultCollapsed = false, }) {
|
|
80
|
+
const [isCollapsed, setIsCollapsed] = React.useState(defaultCollapsed);
|
|
81
|
+
const manualCollapsedRef = React.useRef(defaultCollapsed);
|
|
82
|
+
const collapse = React.useCallback(() => {
|
|
83
|
+
setIsCollapsed(true);
|
|
84
|
+
manualCollapsedRef.current = true;
|
|
85
|
+
}, []);
|
|
20
86
|
const toggle = () => {
|
|
21
87
|
setIsCollapsed((prev) => {
|
|
22
88
|
const next = !prev;
|
|
@@ -37,7 +103,7 @@ export function SidebarProvider({ children }) {
|
|
|
37
103
|
window.addEventListener("resize", handleResize);
|
|
38
104
|
return () => window.removeEventListener("resize", handleResize);
|
|
39
105
|
}, []);
|
|
40
|
-
return (_jsx(SidebarContext.Provider, { value: { isCollapsed, toggle }, children: children }));
|
|
106
|
+
return (_jsx(SidebarContext.Provider, { value: { isCollapsed, toggle, collapse }, children: children }));
|
|
41
107
|
}
|
|
42
108
|
export function useSidebar() {
|
|
43
109
|
const context = React.useContext(SidebarContext);
|
|
@@ -46,7 +112,7 @@ export function useSidebar() {
|
|
|
46
112
|
}
|
|
47
113
|
return context;
|
|
48
114
|
}
|
|
49
|
-
function DashboardLayout({ className, masthead, prototypeBanner, sidebar, surfaceClassName, contentClassName, children, style, ...props }) {
|
|
115
|
+
function DashboardLayout({ className, masthead, prototypeBanner, sidebar, rightPanel, surfaceClassName, contentClassName, rightPanelClassName, rightPanelFallbackTrigger, rightPanelMode, rightPanelResizable, rightPanelDefaultWidth, rightPanelMinWidth, rightPanelMaxWidth, rightPanelAutoCollapseSidebarBreakpoint, defaultSidebarCollapsed = false, children, style, ...props }) {
|
|
50
116
|
const chromeRef = React.useRef(null);
|
|
51
117
|
const [topOffset, setTopOffset] = React.useState(0);
|
|
52
118
|
const layoutStyle = React.useMemo(() => ({
|
|
@@ -71,18 +137,18 @@ function DashboardLayout({ className, masthead, prototypeBanner, sidebar, surfac
|
|
|
71
137
|
observer.observe(node);
|
|
72
138
|
return () => observer.disconnect();
|
|
73
139
|
}, [masthead, prototypeBanner]);
|
|
74
|
-
return (_jsx(SidebarProvider, { children: _jsxs("div", { className: cn("flex min-h-screen flex-col bg-[hsl(var(--layout-shell-background))]", className), style: layoutStyle, ...props, children: [masthead || prototypeBanner ? (_jsxs("div", { ref: chromeRef, className: "sticky top-0 z-40 shrink-0", children: [masthead, prototypeBanner] })) : null, _jsxs("div", { className: "flex min-h-0 flex-1", children: [sidebar, _jsx(DashboardContent, { className: contentClassName, surfaceClassName: surfaceClassName, children: children })] })] }) }));
|
|
140
|
+
return (_jsx(SidebarProvider, { defaultCollapsed: defaultSidebarCollapsed, children: _jsxs("div", { className: cn("flex min-h-screen flex-col bg-[hsl(var(--layout-shell-background))]", className), style: layoutStyle, ...props, children: [masthead || prototypeBanner ? (_jsxs("div", { ref: chromeRef, className: "sticky top-0 z-40 shrink-0", children: [masthead, prototypeBanner] })) : null, _jsxs("div", { className: "flex min-h-0 flex-1", children: [sidebar, _jsx(DashboardContent, { className: contentClassName, hasSidebar: Boolean(sidebar), rightPanel: rightPanel, rightPanelClassName: rightPanelClassName, rightPanelFallbackTrigger: rightPanelFallbackTrigger, rightPanelMode: rightPanelMode, rightPanelResizable: rightPanelResizable, rightPanelDefaultWidth: rightPanelDefaultWidth, rightPanelMinWidth: rightPanelMinWidth, rightPanelMaxWidth: rightPanelMaxWidth, rightPanelAutoCollapseSidebarBreakpoint: rightPanelAutoCollapseSidebarBreakpoint, surfaceClassName: surfaceClassName, children: children })] })] }) }));
|
|
75
141
|
}
|
|
76
142
|
function SidebarShell({ isCollapsed, className, children, ...props }) {
|
|
77
|
-
return (_jsx("aside", { className: cn("fixed left-0 top-[var(--layout-top-offset)] z-30 flex h-[calc(100dvh-var(--layout-top-offset))] shrink-0 flex-col
|
|
78
|
-
? "w-[var(--layout-sidebar-collapsed-width)]"
|
|
79
|
-
: "w-[var(--layout-sidebar-width)]", className), ...props, children: children }));
|
|
143
|
+
return (_jsx("aside", { className: cn("fixed left-0 top-[var(--layout-top-offset)] z-30 flex h-[calc(100dvh-var(--layout-top-offset))] shrink-0 flex-col bg-[hsl(var(--layout-sidebar-background))] pb-2 pt-[var(--layout-sidebar-padding-top)] transition-all duration-300 ease-in-out", isCollapsed
|
|
144
|
+
? "w-[var(--layout-sidebar-collapsed-width)] overflow-visible px-[var(--layout-sidebar-padding-inline)]"
|
|
145
|
+
: "w-[var(--layout-sidebar-width)] overflow-hidden px-[var(--layout-sidebar-padding-inline)]", className), ...props, children: children }));
|
|
80
146
|
}
|
|
81
147
|
function SidebarHeader({ className, children, }) {
|
|
82
148
|
return _jsx("div", { className: cn("shrink-0", className), children: children });
|
|
83
149
|
}
|
|
84
150
|
function SidebarContent({ className, children, }) {
|
|
85
|
-
return (_jsx("div", { className: cn("flex-1 overflow-y-auto", className), children: children }));
|
|
151
|
+
return (_jsx("div", { className: cn("scrollbar-none flex-1 overflow-y-auto", className), children: children }));
|
|
86
152
|
}
|
|
87
153
|
function SidebarFooter({ className, children, }) {
|
|
88
154
|
return _jsx("div", { className: cn("shrink-0", className), children: children });
|
|
@@ -91,20 +157,22 @@ function SidebarGroup({ className, children, }) {
|
|
|
91
157
|
return _jsx("div", { className: className, children: children });
|
|
92
158
|
}
|
|
93
159
|
function SidebarGroupLabel({ className, children, }) {
|
|
94
|
-
return (_jsx("p", { className: cn("px-
|
|
160
|
+
return (_jsx("p", { className: cn("px-2.5 py-1 text-xs font-normal text-muted-foreground/70", className), children: children }));
|
|
95
161
|
}
|
|
96
162
|
function SidebarMenu({ className, children, }) {
|
|
97
|
-
return _jsx("ul", { className: cn("space-y-
|
|
163
|
+
return _jsx("ul", { className: cn("space-y-0.5", className), children: children });
|
|
98
164
|
}
|
|
99
|
-
function SidebarMenuItem({ className, children, }) {
|
|
100
|
-
return _jsx("li", { className: className, children: children });
|
|
165
|
+
function SidebarMenuItem({ className, children, collapsed = false, }) {
|
|
166
|
+
return (_jsx("li", { className: cn(collapsed && "flex h-control w-full items-center justify-center", className), children: children }));
|
|
101
167
|
}
|
|
102
|
-
const SidebarMenuButton = React.forwardRef(({ active = false, collapsed = false, disabled = false, className, asChild = false, children, ...props }, ref) => {
|
|
103
|
-
return (_jsx(Button, { ref: ref, asChild: asChild, variant: "ghost", disabled: disabled, className: cn("
|
|
168
|
+
const SidebarMenuButton = React.forwardRef(({ active = false, collapsed = false, depth: _depth = 0, disabled = false, className, asChild = false, children, ...props }, ref) => {
|
|
169
|
+
return (_jsx(Button, { ref: ref, asChild: asChild, variant: "ghost", size: collapsed ? "icon" : "default", disabled: disabled, className: cn("relative text-sm font-medium shadow-none transition-[background-color,color,box-shadow] duration-150", collapsed
|
|
170
|
+
? cn(collapsedSidebarControlClassName, "gap-0")
|
|
171
|
+
: "h-control w-full justify-start gap-2.5 px-3", disabled
|
|
104
172
|
? "text-muted-foreground/50 hover:bg-transparent hover:text-muted-foreground/50"
|
|
105
173
|
: active
|
|
106
|
-
? "bg-
|
|
107
|
-
: "text-muted-foreground hover:bg-
|
|
174
|
+
? "border-none bg-card text-card-foreground shadow-sm hover:bg-card hover:text-card-foreground"
|
|
175
|
+
: "text-muted-foreground hover:bg-card hover:text-foreground", className), ...props, children: children }));
|
|
108
176
|
});
|
|
109
177
|
SidebarMenuButton.displayName = "SidebarMenuButton";
|
|
110
178
|
function isDropdownSidebarItem(item) {
|
|
@@ -126,10 +194,13 @@ function renderSidebarSlot(slot, isCollapsed) {
|
|
|
126
194
|
return slot !== null && slot !== void 0 ? slot : null;
|
|
127
195
|
}
|
|
128
196
|
function DashboardSidebarItemButton({ item, isCollapsed, active, expanded, depth = 0, onClick, ariaExpanded, }) {
|
|
197
|
+
var _a;
|
|
129
198
|
const Icon = item.icon;
|
|
130
199
|
const iconRef = React.useRef(null);
|
|
131
|
-
const showWipBadge = item.disabled || item.wip;
|
|
132
200
|
const hasDropdown = isDropdownSidebarItem(item);
|
|
201
|
+
const hasCollapsedBadge = isCollapsed && item.badgeCount !== undefined;
|
|
202
|
+
const shouldRenderIconSlot = Boolean(Icon) || isCollapsed;
|
|
203
|
+
const collapsedBadge = hasCollapsedBadge ? (_jsx(CountBadge, { count: (_a = item.badgeCount) !== null && _a !== void 0 ? _a : 0, max: 9, variant: item.badgeVariant, size: "sm", pulse: item.badgePulse, className: "pointer-events-none absolute -right-1.5 -top-1.5 z-10" })) : null;
|
|
133
204
|
const handleMouseEnter = () => {
|
|
134
205
|
var _a, _b, _c;
|
|
135
206
|
if (!item.disabled) {
|
|
@@ -144,15 +215,24 @@ function DashboardSidebarItemButton({ item, isCollapsed, active, expanded, depth
|
|
|
144
215
|
(_c = item.onHoverEnd) === null || _c === void 0 ? void 0 : _c.call(item);
|
|
145
216
|
}
|
|
146
217
|
};
|
|
147
|
-
const content = (_jsxs(_Fragment, { children: [Icon ? (
|
|
148
|
-
const tooltipLabel =
|
|
149
|
-
const button = (_jsx(SidebarMenuButton, { onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, onFocus: handleMouseEnter, onBlur: handleMouseLeave, onClick: onClick, disabled: item.disabled, active: active, collapsed: isCollapsed, "aria-current": active && !hasDropdown ? "page" : undefined, "aria-expanded": ariaExpanded, "aria-label": isCollapsed ? tooltipLabel : undefined, children: content }));
|
|
150
|
-
const interactive = !hasDropdown && item.href && !item.disabled ? (_jsx(SidebarMenuButton, { asChild: true, onClick: item.onClick, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, onFocus: handleMouseEnter, onBlur: handleMouseLeave, active: active, collapsed: isCollapsed, "aria-current": active ? "page" : undefined, "aria-label": isCollapsed ? tooltipLabel : undefined, children: _jsx("a", { href: item.href, target: item.target, rel: item.rel, children: content }) })) : (button);
|
|
218
|
+
const content = (_jsxs(_Fragment, { children: [Icon ? (_jsx("div", { className: cn("relative flex h-6 w-6 shrink-0 items-center justify-center transition-transform", hasCollapsedBadge && "translate-y-0.5"), children: _jsx(Icon, { ref: iconRef, size: 18 }) })) : shouldRenderIconSlot ? (_jsx("div", { "aria-hidden": "true", className: cn("relative flex h-6 w-6 shrink-0 items-center justify-center transition-transform", hasCollapsedBadge && "translate-y-0.5"), children: _jsx("span", { className: "h-1.5 w-1.5 rounded-full bg-current/35" }) })) : null, !isCollapsed ? (_jsxs(_Fragment, { children: [_jsx("span", { className: "flex-1 truncate text-left", children: item.label }), item.trailing, item.badgeCount !== undefined ? (_jsx(CountBadge, { count: item.badgeCount, variant: item.badgeVariant, size: "md", pulse: item.badgePulse })) : null, hasDropdown ? (_jsx(ChevronDownIcon, { "aria-hidden": "true", className: cn("shrink-0 text-muted-foreground transition-transform duration-200", expanded && "rotate-180 text-foreground"), size: 18 })) : null] })) : null] }));
|
|
219
|
+
const tooltipLabel = item.label;
|
|
220
|
+
const button = (_jsx(SidebarMenuButton, { onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, onFocus: handleMouseEnter, onBlur: handleMouseLeave, onClick: onClick, disabled: item.disabled, active: active, collapsed: isCollapsed, depth: depth, "aria-current": active && !hasDropdown ? "page" : undefined, "aria-expanded": ariaExpanded, "aria-label": isCollapsed ? tooltipLabel : undefined, children: content }));
|
|
221
|
+
const interactive = !hasDropdown && item.href && !item.disabled ? (_jsx(SidebarMenuButton, { asChild: true, onClick: item.onClick, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, onFocus: handleMouseEnter, onBlur: handleMouseLeave, active: active, collapsed: isCollapsed, depth: depth, "aria-current": active ? "page" : undefined, "aria-label": isCollapsed ? tooltipLabel : undefined, children: _jsx("a", { href: item.href, target: item.target, rel: item.rel, children: content }) })) : (button);
|
|
151
222
|
if (isCollapsed) {
|
|
152
|
-
return (_jsx(Tooltip, { side: "right", content: _jsx("p", { children: tooltipLabel }), children:
|
|
223
|
+
return (_jsx(Tooltip, { side: "right", content: _jsx("p", { children: tooltipLabel }), children: _jsxs("span", { className: cn("relative inline-flex h-control w-control shrink-0 items-center justify-center overflow-visible", item.disabled && "cursor-not-allowed"), children: [interactive, collapsedBadge] }) }));
|
|
153
224
|
}
|
|
154
225
|
return interactive;
|
|
155
226
|
}
|
|
227
|
+
function DashboardSidebarProfile({ isCollapsed = false, status = "online", name, role, rolePlacement = "below", size = "sm", ...props }) {
|
|
228
|
+
const statusClassName = {
|
|
229
|
+
online: "bg-primary",
|
|
230
|
+
busy: "bg-[hsl(var(--status-warning-foreground))]",
|
|
231
|
+
offline: "bg-muted-foreground",
|
|
232
|
+
none: "",
|
|
233
|
+
}[status];
|
|
234
|
+
return (_jsx("div", { className: cn(isCollapsed ? "px-0" : "px-2", "pb-4 pt-2"), children: _jsx(AvatarProfile, { ...props, size: size, name: isCollapsed ? undefined : name, role: isCollapsed ? undefined : role, rolePlacement: rolePlacement, className: cn("rounded-control px-2 py-2 text-muted-foreground transition-colors hover:bg-card hover:text-foreground", isCollapsed ? "justify-center px-0" : "min-w-0"), avatarClassName: "h-9 w-9 ring-1 ring-border/60 shadow-sm", fallbackClassName: "bg-background text-foreground", avatarOverlay: status === "none" ? undefined : (_jsx("span", { className: cn("absolute bottom-0 right-0 h-3 w-3 rounded-full border-2 border-[hsl(var(--layout-sidebar-background))] shadow-sm", statusClassName) })) }) }));
|
|
235
|
+
}
|
|
156
236
|
function DashboardSidebarLeafItem({ item, isCollapsed, depth = 0, }) {
|
|
157
237
|
return (_jsx(DashboardSidebarItemButton, { item: item, isCollapsed: isCollapsed, active: sidebarItemIsActive(item), depth: depth, onClick: item.onClick }));
|
|
158
238
|
}
|
|
@@ -192,7 +272,7 @@ function DashboardSidebarDropdownItem({ item, isCollapsed, depth = 0, }) {
|
|
|
192
272
|
}
|
|
193
273
|
handleOpenChange(!expanded);
|
|
194
274
|
}, [expanded, handleOpenChange, isCollapsed, item.disabled, setExpanded, toggle]);
|
|
195
|
-
return (_jsxs(CollapsiblePrimitive.Root, { open: expanded, onOpenChange: handleOpenChange, children: [_jsx(DashboardSidebarItemButton, { item: item, isCollapsed: isCollapsed, active: item.active || hasActiveDescendant, expanded: expanded, depth: depth, onClick: handleClick, ariaExpanded: isCollapsed ? undefined : expanded }), !isCollapsed ? (_jsx(CollapsiblePrimitive.Content, { className: "overflow-hidden", children: _jsx("div", { className: "ml-5 mt-1 border-l border-border
|
|
275
|
+
return (_jsxs(CollapsiblePrimitive.Root, { open: expanded, onOpenChange: handleOpenChange, children: [_jsx(DashboardSidebarItemButton, { item: item, isCollapsed: isCollapsed, active: item.active || hasActiveDescendant, expanded: expanded, depth: depth, onClick: handleClick, ariaExpanded: isCollapsed ? undefined : expanded }), !isCollapsed ? (_jsx(CollapsiblePrimitive.Content, { className: "overflow-hidden", children: _jsx("div", { className: "ml-5 mt-1 border-l border-[hsl(var(--layout-sidebar-border))] pl-2", children: _jsx(SidebarMenu, { className: "space-y-1", children: item.items.map((child) => (_jsx(SidebarMenuItem, { collapsed: isCollapsed, children: _jsx(DashboardSidebarItem, { item: child, isCollapsed: false, depth: depth + 1 }) }, child.id))) }) }) })) : null] }));
|
|
196
276
|
}
|
|
197
277
|
function DashboardSidebarItem({ item, isCollapsed, depth = 0, }) {
|
|
198
278
|
if (isDropdownSidebarItem(item)) {
|
|
@@ -211,20 +291,344 @@ function DashboardSidebar({ className, children, logo, search, navGroups, footer
|
|
|
211
291
|
if (!hasStructuredSidebar) {
|
|
212
292
|
return (_jsx(SidebarShell, { isCollapsed: isCollapsed, className: className, ...props, children: children }));
|
|
213
293
|
}
|
|
214
|
-
return (_jsxs(SidebarShell, { isCollapsed: isCollapsed, className: className, ...props, children: [_jsxs(SidebarHeader, { className: cn("flex h-14 items-center gap-2", isCollapsed ? "justify-center px-
|
|
294
|
+
return (_jsxs(SidebarShell, { isCollapsed: isCollapsed, className: className, ...props, children: [_jsxs(SidebarHeader, { className: cn("flex h-14 items-center gap-2", isCollapsed ? "justify-center px-0" : "justify-between px-3"), children: [renderSidebarSlot(logo, isCollapsed), _jsx(Button, { variant: "ghost", size: "icon", "aria-label": toggleAriaLabel, className: cn("shrink-0 rounded-control", isCollapsed ? collapsedSidebarControlClassName : "h-7 w-7"), onClick: toggle, children: isCollapsed ? (_jsx(ChevronRightIcon, { size: 16 })) : (_jsx(ChevronLeftIcon, { size: 16 })) })] }), search ? (_jsx(SidebarHeader, { className: cn(isCollapsed
|
|
295
|
+
? "flex justify-center px-0 pb-3 pt-2"
|
|
296
|
+
: "px-2 pb-3 pt-2"), children: renderSidebarSlot(search, isCollapsed) })) : null, search || ((_a = navGroups === null || navGroups === void 0 ? void 0 : navGroups.length) !== null && _a !== void 0 ? _a : 0) > 0 ? (_jsx(SidebarHeader, { className: "mx-2 mb-2 border-t border-[hsl(var(--layout-sidebar-border))]" })) : null, (navGroups === null || navGroups === void 0 ? void 0 : navGroups.length) ? (_jsx(SidebarContent, { className: cn(isCollapsed
|
|
297
|
+
? "overflow-visible p-0"
|
|
298
|
+
: "p-[var(--layout-sidebar-content-padding)]"), children: _jsx("nav", { "aria-label": "Sidebar navigation", children: navGroups.map((group, groupIndex) => {
|
|
215
299
|
var _a;
|
|
216
|
-
return (_jsxs(SidebarGroup, { children: [isCollapsed && groupIndex > 0 ? (_jsx("div", { className: "mx-2 my-2 border-t" })) : null, _jsxs("div", { className: cn(!isCollapsed &&
|
|
217
|
-
|
|
300
|
+
return (_jsxs(SidebarGroup, { children: [isCollapsed && groupIndex > 0 ? (_jsx("div", { className: "mx-2 my-2 border-t border-[hsl(var(--layout-sidebar-border))]" })) : null, _jsxs("div", { className: cn(!isCollapsed &&
|
|
301
|
+
groupIndex > 0 &&
|
|
302
|
+
"mt-[var(--layout-sidebar-section-gap)]"), children: [!isCollapsed && group.label ? (_jsx(SidebarGroupLabel, { children: group.label })) : null, _jsx(SidebarMenu, { children: group.items.map((item) => (_jsx(SidebarMenuItem, { collapsed: isCollapsed, children: _jsx(DashboardSidebarItem, { item: item, isCollapsed: isCollapsed }) }, item.id))) })] })] }, `${(_a = group.label) !== null && _a !== void 0 ? _a : "group"}-${groupIndex}`));
|
|
303
|
+
}) }) })) : null, (footerItems === null || footerItems === void 0 ? void 0 : footerItems.length) ? (_jsx(SidebarFooter, { className: cn(isCollapsed ? "px-0 py-1" : "px-1.5 py-1"), children: _jsx(SidebarMenu, { children: footerItems.map((item) => (_jsx(SidebarMenuItem, { collapsed: isCollapsed, children: _jsx(DashboardSidebarItem, { item: item, isCollapsed: isCollapsed }) }, item.id))) }) })) : null, footer ? _jsx(SidebarFooter, { className: "mx-1.5 mt-1.5 border-t border-[hsl(var(--layout-sidebar-border))] pt-1.5" }) : null, footer ? (_jsx(SidebarFooter, { children: renderSidebarSlot(footer, isCollapsed) })) : null] }));
|
|
218
304
|
}
|
|
219
|
-
function
|
|
220
|
-
|
|
305
|
+
function DashboardRightPanelSection({ className, title, description, titleClassName, descriptionClassName, children, ...props }) {
|
|
306
|
+
return (_jsxs("section", { className: cn("space-y-[var(--layout-right-panel-section-gap)]", className), ...props, children: [title || description ? (_jsxs("div", { className: "space-y-[var(--layout-right-panel-heading-gap)]", children: [title ? (_jsx(Typography, { as: "h3", variant: "body", className: cn("font-semibold", titleClassName), children: title })) : null, description ? (_jsx(Typography, { as: "p", variant: "caption", className: descriptionClassName, children: description })) : null] })) : null, children] }));
|
|
307
|
+
}
|
|
308
|
+
function DashboardRightPanelTabs({ className, listWrapperClassName, panelClassName, ...props }) {
|
|
309
|
+
return (_jsx(Tabs, { className: cn("flex min-h-0 flex-1 flex-col space-y-0", className), listWrapperClassName: cn("scrollbar-none w-full min-w-0 max-w-full shrink-0 self-stretch overflow-x-auto overflow-y-hidden px-[var(--layout-right-panel-padding)] pb-[var(--layout-right-panel-tabs-gap)] pt-[var(--layout-right-panel-padding)]", listWrapperClassName), panelClassName: cn("min-h-0 flex-1 flex-col overflow-hidden pt-0 data-[state=active]:flex", panelClassName), ...props }));
|
|
310
|
+
}
|
|
311
|
+
function DashboardRightPanel({ className, ...props }) {
|
|
312
|
+
return (_jsx("div", { className: cn("flex min-h-0 flex-1 flex-col bg-[hsl(var(--layout-right-panel-background))]", className), ...props }));
|
|
313
|
+
}
|
|
314
|
+
function DashboardRightPanelHeader({ className, title, subtitle, badge, action, children, ...props }) {
|
|
315
|
+
return (_jsx("div", { className: cn("shrink-0 p-[var(--layout-right-panel-padding)]", className), ...props, children: _jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx(Typography, { as: "h2", variant: "body", className: "font-semibold", children: title }), badge] }), subtitle ? (_jsx(Typography, { as: "p", variant: "caption", children: subtitle })) : null, children] }), action ? _jsx("div", { className: "shrink-0", children: action }) : null] }) }));
|
|
316
|
+
}
|
|
317
|
+
function DashboardRightPanelBody({ className, contentClassName, footer, footerClassName, children, ...props }) {
|
|
318
|
+
const { scrollRef, canScrollDown } = useScrollOverflowHint();
|
|
319
|
+
if (footer) {
|
|
320
|
+
return (_jsxs("div", { className: cn("flex min-h-0 flex-1 flex-col overflow-hidden p-[var(--layout-right-panel-padding)]", className), ...props, children: [_jsxs("div", { className: "relative min-h-0 flex-1", children: [_jsx("div", { ref: scrollRef, className: cn("scrollbar-none h-full min-h-0 space-y-[var(--layout-right-panel-gap)] overflow-y-auto", contentClassName), children: children }), _jsx(ScrollHint, { visible: canScrollDown })] }), _jsx("div", { className: cn("shrink-0 space-y-[var(--layout-right-panel-footer-gap)] pt-[var(--layout-right-panel-gap)]", footerClassName), children: footer })] }));
|
|
321
|
+
}
|
|
322
|
+
return (_jsxs("div", { className: "relative min-h-0 flex-1", children: [_jsx("div", { ref: scrollRef, className: cn("scrollbar-none h-full min-h-0 space-y-[var(--layout-right-panel-gap)] overflow-y-auto p-[var(--layout-right-panel-padding)]", className), ...props, children: children }), _jsx(ScrollHint, { visible: canScrollDown })] }));
|
|
323
|
+
}
|
|
324
|
+
function DashboardContent({ className, hasSidebar = true, rightPanel, rightPanelClassName, rightPanelFallbackTrigger, rightPanelMode = "responsive", rightPanelResizable = false, rightPanelDefaultWidth = RIGHT_PANEL_RESIZE_DEFAULT_WIDTH, rightPanelMinWidth = RIGHT_PANEL_RESIZE_MIN_WIDTH, rightPanelMaxWidth = RIGHT_PANEL_RESIZE_MAX_WIDTH, rightPanelAutoCollapseSidebarBreakpoint = RIGHT_PANEL_AUTO_COLLAPSE_BREAKPOINT, surfaceClassName, children, ...props }) {
|
|
325
|
+
const { isCollapsed, toggle, collapse } = useSidebar();
|
|
326
|
+
const hasRightPanel = Boolean(rightPanel);
|
|
327
|
+
const persistentRightPanelMinWidth = Math.min(rightPanelMinWidth, rightPanelMaxWidth);
|
|
328
|
+
const persistentRightPanelMaxWidth = Math.max(rightPanelMinWidth, rightPanelMaxWidth);
|
|
329
|
+
const [persistentRightPanelWidth, setPersistentRightPanelWidth] = React.useState(rightPanelDefaultWidth);
|
|
330
|
+
const persistentRightPanelWidthRef = React.useRef(persistentRightPanelWidth);
|
|
331
|
+
const workspaceSurfaceRef = React.useRef(null);
|
|
332
|
+
const persistentRightPanelSlotRef = React.useRef(null);
|
|
333
|
+
const persistentRightPanelSurfaceRef = React.useRef(null);
|
|
334
|
+
const [renderedRightPanel, setRenderedRightPanel] = React.useState(rightPanel);
|
|
335
|
+
const [shouldRenderRightPanel, setShouldRenderRightPanel] = React.useState(hasRightPanel);
|
|
336
|
+
const [rightPanelOpen, setRightPanelOpen] = React.useState(hasRightPanel);
|
|
337
|
+
const [rightPanelOverlayOpen, setRightPanelOverlayOpen] = React.useState(false);
|
|
338
|
+
const [fixedRightPanelWidth, setFixedRightPanelWidth] = React.useState(null);
|
|
339
|
+
const wasRightPanelVisibleRef = React.useRef(hasRightPanel);
|
|
340
|
+
const isCollapsedRef = React.useRef(isCollapsed);
|
|
341
|
+
const hasPersistentRightPanel = rightPanelMode === "persistent" && shouldRenderRightPanel;
|
|
342
|
+
const isPersistentRightPanelResizable = hasPersistentRightPanel && rightPanelResizable;
|
|
343
|
+
const firstChild = React.Children.toArray(children).find((child) => child !== null && child !== undefined);
|
|
344
|
+
const hasLeadingWorkspaceHeader = React.isValidElement(firstChild) &&
|
|
345
|
+
firstChild.type.displayName ===
|
|
346
|
+
"WorkspaceHeader";
|
|
347
|
+
React.useEffect(() => {
|
|
348
|
+
isCollapsedRef.current = isCollapsed;
|
|
349
|
+
}, [isCollapsed]);
|
|
350
|
+
React.useEffect(() => {
|
|
351
|
+
persistentRightPanelWidthRef.current = persistentRightPanelWidth;
|
|
352
|
+
}, [persistentRightPanelWidth]);
|
|
353
|
+
const getPersistentRightPanelGridTemplate = React.useCallback((width) => `minmax(0, 1fr) ${width}px`, []);
|
|
354
|
+
const getFixedPersistentRightPanelGridTemplate = React.useCallback((width, isOpen) => `minmax(0, 1fr) ${isOpen
|
|
355
|
+
? width
|
|
356
|
+
? `${width}px`
|
|
357
|
+
: `${RIGHT_PANEL_FIXED_WIDTH_RATIO * 100}%`
|
|
358
|
+
: "0px"}`, []);
|
|
359
|
+
const measureFixedRightPanelWidth = React.useCallback(() => {
|
|
360
|
+
var _a, _b;
|
|
361
|
+
const surfaceWidth = (_b = (_a = workspaceSurfaceRef.current) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect().width) !== null && _b !== void 0 ? _b : 0;
|
|
362
|
+
if (surfaceWidth <= 0) {
|
|
363
|
+
return null;
|
|
364
|
+
}
|
|
365
|
+
return Math.round(surfaceWidth * RIGHT_PANEL_FIXED_WIDTH_RATIO);
|
|
366
|
+
}, []);
|
|
367
|
+
useIsomorphicLayoutEffect(() => {
|
|
368
|
+
if (!isPersistentRightPanelResizable) {
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
const width = `${persistentRightPanelWidth}px`;
|
|
372
|
+
if (workspaceSurfaceRef.current) {
|
|
373
|
+
workspaceSurfaceRef.current.style.gridTemplateColumns =
|
|
374
|
+
getPersistentRightPanelGridTemplate(rightPanelOpen ? persistentRightPanelWidth : 0);
|
|
375
|
+
}
|
|
376
|
+
if (persistentRightPanelSurfaceRef.current) {
|
|
377
|
+
persistentRightPanelSurfaceRef.current.style.width = width;
|
|
378
|
+
}
|
|
379
|
+
}, [
|
|
380
|
+
getPersistentRightPanelGridTemplate,
|
|
381
|
+
isPersistentRightPanelResizable,
|
|
382
|
+
persistentRightPanelWidth,
|
|
383
|
+
rightPanelOpen,
|
|
384
|
+
]);
|
|
385
|
+
useIsomorphicLayoutEffect(() => {
|
|
386
|
+
if (!hasPersistentRightPanel ||
|
|
387
|
+
isPersistentRightPanelResizable ||
|
|
388
|
+
!rightPanelOpen ||
|
|
389
|
+
!workspaceSurfaceRef.current) {
|
|
390
|
+
return undefined;
|
|
391
|
+
}
|
|
392
|
+
const measureRightPanel = () => {
|
|
393
|
+
const nextWidth = measureFixedRightPanelWidth();
|
|
394
|
+
if (!nextWidth) {
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
setFixedRightPanelWidth((currentWidth) => currentWidth === nextWidth ? currentWidth : nextWidth);
|
|
398
|
+
};
|
|
399
|
+
measureRightPanel();
|
|
400
|
+
const resizeObserver = typeof ResizeObserver === "undefined"
|
|
401
|
+
? undefined
|
|
402
|
+
: new ResizeObserver(measureRightPanel);
|
|
403
|
+
resizeObserver === null || resizeObserver === void 0 ? void 0 : resizeObserver.observe(workspaceSurfaceRef.current);
|
|
404
|
+
window.addEventListener("resize", measureRightPanel);
|
|
405
|
+
return () => {
|
|
406
|
+
resizeObserver === null || resizeObserver === void 0 ? void 0 : resizeObserver.disconnect();
|
|
407
|
+
window.removeEventListener("resize", measureRightPanel);
|
|
408
|
+
};
|
|
409
|
+
}, [
|
|
410
|
+
hasPersistentRightPanel,
|
|
411
|
+
isPersistentRightPanelResizable,
|
|
412
|
+
measureFixedRightPanelWidth,
|
|
413
|
+
rightPanelOpen,
|
|
414
|
+
]);
|
|
415
|
+
React.useEffect(() => {
|
|
416
|
+
if (!rightPanelResizable) {
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
setPersistentRightPanelWidth((width) => Math.min(Math.max(width, persistentRightPanelMinWidth), persistentRightPanelMaxWidth));
|
|
420
|
+
}, [
|
|
421
|
+
persistentRightPanelMaxWidth,
|
|
422
|
+
persistentRightPanelMinWidth,
|
|
423
|
+
rightPanelResizable,
|
|
424
|
+
]);
|
|
425
|
+
useIsomorphicLayoutEffect(() => {
|
|
426
|
+
let frame = 0;
|
|
427
|
+
let nextFrame = 0;
|
|
428
|
+
let timeout = 0;
|
|
429
|
+
if (rightPanelMode === "persistent") {
|
|
430
|
+
setRightPanelOverlayOpen(false);
|
|
431
|
+
}
|
|
432
|
+
if (hasRightPanel) {
|
|
433
|
+
if (rightPanelMode === "persistent" && !rightPanelResizable) {
|
|
434
|
+
const nextFixedRightPanelWidth = measureFixedRightPanelWidth();
|
|
435
|
+
if (nextFixedRightPanelWidth) {
|
|
436
|
+
setFixedRightPanelWidth((currentWidth) => currentWidth === nextFixedRightPanelWidth
|
|
437
|
+
? currentWidth
|
|
438
|
+
: nextFixedRightPanelWidth);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
if (rightPanelAutoCollapseSidebarBreakpoint !== false &&
|
|
442
|
+
!isCollapsedRef.current &&
|
|
443
|
+
window.innerWidth < rightPanelAutoCollapseSidebarBreakpoint) {
|
|
444
|
+
collapse();
|
|
445
|
+
}
|
|
446
|
+
setRenderedRightPanel(rightPanel);
|
|
447
|
+
setShouldRenderRightPanel(true);
|
|
448
|
+
if (wasRightPanelVisibleRef.current) {
|
|
449
|
+
setRightPanelOpen(true);
|
|
450
|
+
}
|
|
451
|
+
else {
|
|
452
|
+
setRightPanelOpen(false);
|
|
453
|
+
frame = window.requestAnimationFrame(() => {
|
|
454
|
+
nextFrame = window.requestAnimationFrame(() => {
|
|
455
|
+
setRightPanelOpen(true);
|
|
456
|
+
});
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
else if (wasRightPanelVisibleRef.current) {
|
|
461
|
+
setRightPanelOpen(false);
|
|
462
|
+
setRightPanelOverlayOpen(false);
|
|
463
|
+
timeout = window.setTimeout(() => {
|
|
464
|
+
setShouldRenderRightPanel(false);
|
|
465
|
+
setRenderedRightPanel(null);
|
|
466
|
+
}, RIGHT_PANEL_TRANSITION_MS);
|
|
467
|
+
}
|
|
468
|
+
else {
|
|
469
|
+
setShouldRenderRightPanel(false);
|
|
470
|
+
setRenderedRightPanel(null);
|
|
471
|
+
setRightPanelOverlayOpen(false);
|
|
472
|
+
}
|
|
473
|
+
wasRightPanelVisibleRef.current = hasRightPanel;
|
|
474
|
+
return () => {
|
|
475
|
+
if (frame) {
|
|
476
|
+
window.cancelAnimationFrame(frame);
|
|
477
|
+
}
|
|
478
|
+
if (nextFrame) {
|
|
479
|
+
window.cancelAnimationFrame(nextFrame);
|
|
480
|
+
}
|
|
481
|
+
if (timeout) {
|
|
482
|
+
window.clearTimeout(timeout);
|
|
483
|
+
}
|
|
484
|
+
};
|
|
485
|
+
}, [
|
|
486
|
+
collapse,
|
|
487
|
+
hasRightPanel,
|
|
488
|
+
rightPanel,
|
|
489
|
+
rightPanelMode,
|
|
490
|
+
rightPanelResizable,
|
|
491
|
+
measureFixedRightPanelWidth,
|
|
492
|
+
rightPanelAutoCollapseSidebarBreakpoint,
|
|
493
|
+
]);
|
|
494
|
+
React.useEffect(() => {
|
|
495
|
+
if (rightPanelMode !== "persistent" ||
|
|
496
|
+
!hasRightPanel ||
|
|
497
|
+
rightPanelAutoCollapseSidebarBreakpoint === false) {
|
|
498
|
+
return undefined;
|
|
499
|
+
}
|
|
500
|
+
const maybeCollapseSidebar = () => {
|
|
501
|
+
if (!isCollapsedRef.current &&
|
|
502
|
+
window.innerWidth < rightPanelAutoCollapseSidebarBreakpoint) {
|
|
503
|
+
collapse();
|
|
504
|
+
}
|
|
505
|
+
};
|
|
506
|
+
maybeCollapseSidebar();
|
|
507
|
+
window.addEventListener("resize", maybeCollapseSidebar);
|
|
508
|
+
return () => window.removeEventListener("resize", maybeCollapseSidebar);
|
|
509
|
+
}, [
|
|
510
|
+
collapse,
|
|
511
|
+
hasRightPanel,
|
|
512
|
+
rightPanelMode,
|
|
513
|
+
rightPanelAutoCollapseSidebarBreakpoint,
|
|
514
|
+
]);
|
|
221
515
|
const handleContentClick = React.useCallback(() => {
|
|
222
516
|
if (!isCollapsed && window.innerWidth < COLLAPSE_BREAKPOINT) {
|
|
223
517
|
toggle();
|
|
224
518
|
}
|
|
225
519
|
}, [isCollapsed, toggle]);
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
520
|
+
const handleRightPanelResizePointerDown = React.useCallback((event) => {
|
|
521
|
+
if (!isPersistentRightPanelResizable) {
|
|
522
|
+
return;
|
|
523
|
+
}
|
|
524
|
+
event.preventDefault();
|
|
525
|
+
const startX = event.clientX;
|
|
526
|
+
const startWidth = persistentRightPanelWidthRef.current;
|
|
527
|
+
const previousCursor = document.body.style.cursor;
|
|
528
|
+
const previousUserSelect = document.body.style.userSelect;
|
|
529
|
+
document.body.style.cursor = "col-resize";
|
|
530
|
+
document.body.style.userSelect = "none";
|
|
531
|
+
let pendingWidth = startWidth;
|
|
532
|
+
let frame = 0;
|
|
533
|
+
const applyPendingWidth = () => {
|
|
534
|
+
frame = 0;
|
|
535
|
+
persistentRightPanelWidthRef.current = pendingWidth;
|
|
536
|
+
if (workspaceSurfaceRef.current) {
|
|
537
|
+
workspaceSurfaceRef.current.style.gridTemplateColumns =
|
|
538
|
+
getPersistentRightPanelGridTemplate(pendingWidth);
|
|
539
|
+
}
|
|
540
|
+
if (persistentRightPanelSurfaceRef.current) {
|
|
541
|
+
persistentRightPanelSurfaceRef.current.style.width = `${pendingWidth}px`;
|
|
542
|
+
}
|
|
543
|
+
};
|
|
544
|
+
const handlePointerMove = (moveEvent) => {
|
|
545
|
+
pendingWidth = Math.min(Math.max(startWidth + startX - moveEvent.clientX, persistentRightPanelMinWidth), persistentRightPanelMaxWidth);
|
|
546
|
+
if (!frame) {
|
|
547
|
+
frame = window.requestAnimationFrame(applyPendingWidth);
|
|
548
|
+
}
|
|
549
|
+
};
|
|
550
|
+
const finishResize = () => {
|
|
551
|
+
if (frame) {
|
|
552
|
+
window.cancelAnimationFrame(frame);
|
|
553
|
+
applyPendingWidth();
|
|
554
|
+
}
|
|
555
|
+
document.body.style.cursor = previousCursor;
|
|
556
|
+
document.body.style.userSelect = previousUserSelect;
|
|
557
|
+
window.removeEventListener("pointermove", handlePointerMove);
|
|
558
|
+
window.removeEventListener("pointerup", finishResize);
|
|
559
|
+
window.removeEventListener("pointercancel", finishResize);
|
|
560
|
+
setPersistentRightPanelWidth(pendingWidth);
|
|
561
|
+
};
|
|
562
|
+
window.addEventListener("pointermove", handlePointerMove);
|
|
563
|
+
window.addEventListener("pointerup", finishResize, { once: true });
|
|
564
|
+
window.addEventListener("pointercancel", finishResize, { once: true });
|
|
565
|
+
}, [
|
|
566
|
+
getPersistentRightPanelGridTemplate,
|
|
567
|
+
isPersistentRightPanelResizable,
|
|
568
|
+
persistentRightPanelMaxWidth,
|
|
569
|
+
persistentRightPanelMinWidth,
|
|
570
|
+
]);
|
|
571
|
+
const workspaceSurfaceStyle = React.useMemo(() => {
|
|
572
|
+
if (!hasPersistentRightPanel) {
|
|
573
|
+
return undefined;
|
|
574
|
+
}
|
|
575
|
+
if (!isPersistentRightPanelResizable) {
|
|
576
|
+
return {
|
|
577
|
+
columnGap: rightPanelOpen ? "var(--space-6)" : 0,
|
|
578
|
+
gridTemplateColumns: getFixedPersistentRightPanelGridTemplate(fixedRightPanelWidth, rightPanelOpen),
|
|
579
|
+
};
|
|
580
|
+
}
|
|
581
|
+
return {
|
|
582
|
+
columnGap: 0,
|
|
583
|
+
gridTemplateColumns: getPersistentRightPanelGridTemplate(rightPanelOpen ? persistentRightPanelWidth : 0),
|
|
584
|
+
};
|
|
585
|
+
}, [
|
|
586
|
+
getFixedPersistentRightPanelGridTemplate,
|
|
587
|
+
getPersistentRightPanelGridTemplate,
|
|
588
|
+
fixedRightPanelWidth,
|
|
589
|
+
hasPersistentRightPanel,
|
|
590
|
+
isPersistentRightPanelResizable,
|
|
591
|
+
persistentRightPanelWidth,
|
|
592
|
+
rightPanelOpen,
|
|
593
|
+
]);
|
|
594
|
+
const persistentRightPanelSurfaceStyle = React.useMemo(() => {
|
|
595
|
+
if (!hasPersistentRightPanel) {
|
|
596
|
+
return undefined;
|
|
597
|
+
}
|
|
598
|
+
if (isPersistentRightPanelResizable) {
|
|
599
|
+
return { width: persistentRightPanelWidth };
|
|
600
|
+
}
|
|
601
|
+
return fixedRightPanelWidth ? { width: fixedRightPanelWidth } : undefined;
|
|
602
|
+
}, [
|
|
603
|
+
fixedRightPanelWidth,
|
|
604
|
+
hasPersistentRightPanel,
|
|
605
|
+
isPersistentRightPanelResizable,
|
|
606
|
+
persistentRightPanelWidth,
|
|
607
|
+
]);
|
|
608
|
+
return (_jsxs("main", { onClick: handleContentClick, className: cn("flex h-[calc(100dvh-var(--layout-top-offset))] min-w-0 flex-1 overflow-hidden bg-[hsl(var(--layout-shell-background))] pb-[var(--layout-content-padding)] pl-[var(--layout-content-gap-start)] pr-[var(--layout-content-padding)] pt-[var(--layout-content-padding)] transition-all duration-300 md:pb-[var(--layout-content-padding-md)] md:pl-[var(--layout-content-gap-start-md)] md:pr-[var(--layout-content-padding-md)] md:pt-[var(--layout-content-padding-md)] lg:pb-[var(--layout-content-padding-lg)] lg:pl-[var(--layout-content-gap-start-lg)] lg:pr-[var(--layout-content-padding-lg)] lg:pt-[var(--layout-content-padding-lg)]", hasSidebar &&
|
|
609
|
+
(isCollapsed
|
|
610
|
+
? "ml-[var(--layout-sidebar-collapsed-width)]"
|
|
611
|
+
: "ml-[var(--layout-sidebar-width)]"), className), ...props, children: [_jsxs("div", { ref: workspaceSurfaceRef, "data-slot": "dashboard-workspace-surface", className: cn("h-full min-h-0 min-w-0 flex-1 overflow-hidden rounded-surface border border-[hsl(var(--layout-surface-border))] bg-[hsl(var(--layout-surface-background))] shadow-[var(--layout-surface-shadow)]", hasPersistentRightPanel
|
|
612
|
+
? "grid transition-[grid-template-columns,column-gap] duration-300 ease-out motion-reduce:transition-none"
|
|
613
|
+
: "flex"), style: workspaceSurfaceStyle, children: [_jsx("div", { className: cn("scrollbar-none flex min-h-0 min-w-0 flex-1 flex-col gap-[var(--layout-surface-gap)] overflow-y-auto overflow-x-clip p-[var(--layout-surface-padding)] md:p-[var(--layout-surface-padding-md)] lg:p-[var(--layout-surface-padding-lg)]", hasPersistentRightPanel && "min-w-0", hasLeadingWorkspaceHeader && "pt-0 md:pt-0 lg:pt-0", surfaceClassName), children: children }), hasPersistentRightPanel ? (_jsx("aside", { ref: persistentRightPanelSlotRef, "aria-hidden": rightPanelOpen ? undefined : true, className: cn("relative min-h-0 transition-[border-color,box-shadow] duration-300 ease-out motion-reduce:transition-none", rightPanelEdgeClassName, rightPanelOpen
|
|
614
|
+
? rightPanelEdgeOpenClassName
|
|
615
|
+
: rightPanelEdgeClosedClassName, !rightPanelOpen && "pointer-events-none", isPersistentRightPanelResizable
|
|
616
|
+
? "min-w-0 overflow-visible"
|
|
617
|
+
: "min-w-0 overflow-hidden"), children: _jsx("div", { "data-slot": "dashboard-right-panel-viewport", className: "relative h-full w-full min-w-0 overflow-hidden", children: _jsxs("div", { ref: persistentRightPanelSurfaceRef, "data-slot": "dashboard-right-panel-surface", className: cn("absolute inset-y-0 right-0 flex h-full w-full min-w-0 bg-[hsl(var(--layout-right-panel-background))] transition-[opacity,transform] duration-300 ease-out motion-reduce:transition-none", rightPanelOpen
|
|
618
|
+
? "translate-x-0 opacity-100"
|
|
619
|
+
: "translate-x-full opacity-0", isPersistentRightPanelResizable
|
|
620
|
+
? "overflow-visible"
|
|
621
|
+
: "overflow-hidden", rightPanelClassName), style: persistentRightPanelSurfaceStyle, children: [isPersistentRightPanelResizable && rightPanelOpen ? (_jsx("button", { type: "button", "aria-label": "Resize right panel", className: "group absolute inset-y-0 -left-3 z-10 flex w-6 cursor-col-resize items-center justify-center rounded-none outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background", onPointerDown: handleRightPanelResizePointerDown, children: _jsx("span", { "aria-hidden": "true", className: cn("flex h-10 w-4 items-center justify-center rounded-full border text-muted-foreground/80 shadow-sm transition-[border-color,color,box-shadow] group-hover:border-ring group-hover:text-foreground group-hover:shadow-md group-focus-visible:border-ring group-focus-visible:text-foreground group-focus-visible:shadow-md", rightPanelResizeHandleSurfaceClassName), children: _jsx(GripVertical, { className: "h-3.5 w-3.5 stroke-[2.25]" }) }) })) : null, _jsx("div", { "data-slot": "dashboard-right-panel-content", className: cn("scrollbar-none flex h-full w-full min-w-0 shrink-0 flex-col overflow-y-auto overflow-x-hidden"), children: renderedRightPanel })] }) }) })) : shouldRenderRightPanel ? (_jsx("aside", { "aria-hidden": rightPanelOpen ? undefined : true, className: cn("hidden min-h-0 shrink-0 overflow-hidden bg-[hsl(var(--layout-right-panel-background))] transition-[width,border-color,box-shadow] duration-300 ease-out will-change-[width] motion-reduce:transition-none xl:flex", rightPanelEdgeClassName, rightPanelOpen
|
|
622
|
+
? [
|
|
623
|
+
"w-[var(--layout-right-panel-width)]",
|
|
624
|
+
rightPanelEdgeOpenClassName,
|
|
625
|
+
]
|
|
626
|
+
: ["pointer-events-none w-0", rightPanelEdgeClosedClassName], rightPanelClassName), children: _jsx("div", { className: cn("scrollbar-none flex h-full w-[var(--layout-right-panel-width)] shrink-0 flex-col overflow-y-auto overflow-x-hidden motion-reduce:animate-none", rightPanelOpen
|
|
627
|
+
? "motion-safe:animate-in motion-safe:fade-in-0 motion-safe:slide-in-from-right-full motion-safe:duration-300"
|
|
628
|
+
: "motion-safe:animate-out motion-safe:fade-out-0 motion-safe:slide-out-to-right-full motion-safe:duration-300"), children: renderedRightPanel }) })) : null] }), rightPanelMode !== "persistent" &&
|
|
629
|
+
shouldRenderRightPanel &&
|
|
630
|
+
rightPanelFallbackTrigger ? (_jsxs(_Fragment, { children: [_jsx(Button, { type: "button", className: cn("fixed bottom-4 right-4 z-50 xl:hidden", rightPanelOverlayOpen && "hidden"), onClick: () => setRightPanelOverlayOpen(true), children: rightPanelFallbackTrigger }), _jsx("aside", { "aria-hidden": rightPanelOverlayOpen ? undefined : true, className: cn("fixed bottom-0 right-0 top-[var(--layout-top-offset)] z-50 flex w-[min(100vw,var(--layout-right-panel-width))] max-w-full overflow-hidden bg-[hsl(var(--layout-right-panel-background))] transition-transform duration-200 ease-out motion-reduce:transition-none xl:hidden", rightPanelEdgeClassName, rightPanelEdgeOpenClassName, rightPanelOverlayOpen
|
|
631
|
+
? "translate-x-0"
|
|
632
|
+
: "pointer-events-none translate-x-full", rightPanelClassName), children: _jsx("div", { className: "scrollbar-none flex h-full w-full flex-col overflow-y-auto overflow-x-hidden", children: renderedRightPanel }) })] })) : null] }));
|
|
229
633
|
}
|
|
230
|
-
export { DashboardLayout, DashboardSidebar, DashboardContent };
|
|
634
|
+
export { DashboardLayout, DashboardSidebar, DashboardSidebarProfile, DashboardContent, DashboardRightPanel, DashboardRightPanelHeader, DashboardRightPanelBody, DashboardRightPanelSection, DashboardRightPanelTabs, };
|
package/dist/lib/date-utils.d.ts
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
|
+
export interface ParseDateTimeOptions {
|
|
2
|
+
/** Base date used for relative strings like "Today" and dates without a year. */
|
|
3
|
+
referenceDate?: Date;
|
|
4
|
+
}
|
|
1
5
|
/**
|
|
2
|
-
* Parse
|
|
6
|
+
* Parse common CLIP date/time strings to a timestamp (ms).
|
|
7
|
+
*
|
|
8
|
+
* Supports numeric dates (`23/03/2025 01:51 AM`), compact meridiem times
|
|
9
|
+
* (`12/05/2026 10:00AM`), month-name dates (`13 Feb 2026, 03:13 PM`), and
|
|
10
|
+
* relative sandbox labels (`Today, 11:12 AM`, `Yesterday, 5:28 PM`).
|
|
3
11
|
*/
|
|
4
|
-
export declare function parseDateTime(dateStr: string): number;
|
|
12
|
+
export declare function parseDateTime(dateStr: string, options?: ParseDateTimeOptions): number;
|
|
5
13
|
/**
|
|
6
14
|
* Format a Date object or ISO string to DD/MM/YYYY HH:MM AM/PM format.
|
|
7
15
|
* Returns `"-"` for null/undefined/invalid input.
|