@ctrl-ui/react 0.8.0 → 0.8.1
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 +1 -0
- package/dist/blocks/coding-agent.js +3 -1
- package/dist/blocks/file-explorer.js +3 -1
- package/dist/blocks/settings.js +3 -1
- package/dist/control-props.d.ts +2 -1
- package/dist/email/email.d.ts +28 -0
- package/dist/email/email.js +70 -0
- package/dist/email/templates.d.ts +51 -0
- package/dist/email/templates.js +228 -0
- package/dist/email/theme.d.ts +23 -0
- package/dist/email/theme.js +98 -0
- package/dist/extensions/create-track-highlight.d.ts +0 -2
- package/dist/extensions/create-track-highlight.js +49 -8
- package/dist/extensions/supports-anchor-transitions.d.ts +4 -0
- package/dist/extensions/supports-anchor-transitions.js +31 -0
- package/dist/extensions/track-highlight.d.ts +0 -6
- package/dist/extensions/track-highlight.js +25 -9
- package/dist/knob-contracts/button-knobs.d.ts +1 -1
- package/dist/knob-contracts/button-knobs.js +4 -1
- package/dist/knob-contracts/progressive-blur-knobs.d.ts +5 -0
- package/dist/knob-contracts/progressive-blur-knobs.js +9 -0
- package/dist/scripts/contrast-eval.d.ts +46 -0
- package/dist/scripts/contrast-eval.js +327 -0
- package/dist/skin.config.js +9 -1
- package/dist/skin.d.ts +11 -9
- package/dist/skin.js +0 -1
- package/dist/styles/index.css +2 -1
- package/dist/styles/recipes/button-group.css +46 -0
- package/dist/styles/recipes/button.css +53 -5
- package/dist/styles/recipes/progressive-blur.css +145 -0
- package/dist/styles/recipes/scroll-area.css +140 -5
- package/dist/styles/recipes/sidebar.css +49 -0
- package/dist/styles/recipes/table-of-contents.css +1 -1
- package/dist/styles/recipes/track-highlight.css +126 -2
- package/dist/styles/recipes/tree.css +4 -0
- package/dist/ui/button-group.d.ts +3 -1
- package/dist/ui/button-group.js +21 -18
- package/dist/ui/button.d.ts +3 -1
- package/dist/ui/button.js +13 -4
- package/dist/ui/checkbox-group.d.ts +5 -3
- package/dist/ui/checkbox-group.js +23 -6
- package/dist/ui/color-picker.js +1 -1
- package/dist/ui/dropdown-menu.d.ts +2 -3
- package/dist/ui/dropdown-menu.js +1 -7
- package/dist/ui/progressive-blur.d.ts +12 -0
- package/dist/ui/progressive-blur.js +47 -0
- package/dist/ui/scroll-area.d.ts +4 -1
- package/dist/ui/scroll-area.js +27 -4
- package/dist/ui/sidebar-menu.d.ts +39 -0
- package/dist/ui/sidebar-menu.js +135 -0
- package/dist/ui/sidebar-provider.d.ts +28 -0
- package/dist/ui/sidebar-provider.js +80 -0
- package/dist/ui/sidebar.d.ts +4 -61
- package/dist/ui/sidebar.js +23 -202
- package/dist/ui/table-of-contents.js +3 -11
- package/dist/ui/toggle.d.ts +3 -2
- package/dist/ui/toggle.js +22 -10
- package/dist/ui/tree.js +13 -19
- package/package.json +5 -1
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "../lib/cn.js";
|
|
3
|
+
import { skinIndicator } from "../skin.js";
|
|
4
|
+
import { Tooltip, TooltipContent, TooltipTrigger } from "./tooltip.js";
|
|
5
|
+
import { useSidebar } from "./sidebar-provider.js";
|
|
6
|
+
import { TrackHighlight } from "../extensions/track-highlight.js";
|
|
7
|
+
import { createContext, useContext } from "react";
|
|
8
|
+
import { useRender } from "@base-ui/react/use-render";
|
|
9
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
10
|
+
import { cva } from "class-variance-authority";
|
|
11
|
+
//#region src/ui/sidebar-menu.tsx
|
|
12
|
+
const sidebarMenuButtonVariants = ["default", "outline"];
|
|
13
|
+
const sidebarMenuButtonSizes = [
|
|
14
|
+
"default",
|
|
15
|
+
"sm",
|
|
16
|
+
"lg"
|
|
17
|
+
];
|
|
18
|
+
function SidebarGroup({ className, ...props }) {
|
|
19
|
+
return /* @__PURE__ */ jsx("div", {
|
|
20
|
+
"data-control-ui": "sidebar",
|
|
21
|
+
"data-control-family": "sidebar",
|
|
22
|
+
"data-slot": "group",
|
|
23
|
+
className: cn("relative flex w-full min-w-0 flex-col", className),
|
|
24
|
+
...props
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
function SidebarGroupLabel({ className, render, children, ...props }) {
|
|
28
|
+
return useRender({
|
|
29
|
+
defaultTagName: "div",
|
|
30
|
+
render,
|
|
31
|
+
props: {
|
|
32
|
+
...props,
|
|
33
|
+
"data-control-ui": "sidebar",
|
|
34
|
+
"data-control-family": "sidebar",
|
|
35
|
+
"data-slot": "group-label",
|
|
36
|
+
className: cn("flex h-[var(--control-h-sm)] shrink-0 items-center [&>svg]:size-4 [&>svg]:shrink-0", "group-data-[collapsible=icon]:invisible group-data-[collapsible=icon]:-mt-[var(--control-h-sm)] group-data-[collapsible=icon]:opacity-0", className),
|
|
37
|
+
children
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
const SidebarMenuContext = createContext("none");
|
|
42
|
+
function SidebarMenu({ className, indicator, style, children, ...props }) {
|
|
43
|
+
const resolvedIndicator = indicator ?? skinIndicator("sidebar") ?? "none";
|
|
44
|
+
const hasHighlight = resolvedIndicator !== "none";
|
|
45
|
+
const list = /* @__PURE__ */ jsx("ul", {
|
|
46
|
+
"data-control-ui": "sidebar",
|
|
47
|
+
"data-control-family": "sidebar",
|
|
48
|
+
"data-slot": "menu",
|
|
49
|
+
"data-indicator": resolvedIndicator,
|
|
50
|
+
className: cn("flex min-w-0 flex-col", hasHighlight ? void 0 : className),
|
|
51
|
+
style: hasHighlight ? void 0 : style,
|
|
52
|
+
...props,
|
|
53
|
+
children: /* @__PURE__ */ jsx(SidebarMenuContext.Provider, {
|
|
54
|
+
value: resolvedIndicator,
|
|
55
|
+
children
|
|
56
|
+
})
|
|
57
|
+
});
|
|
58
|
+
if (!hasHighlight) return list;
|
|
59
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
60
|
+
"data-control-ui": "sidebar",
|
|
61
|
+
"data-control-family": "sidebar",
|
|
62
|
+
"data-slot": "menu-track",
|
|
63
|
+
"data-indicator": resolvedIndicator,
|
|
64
|
+
"data-track": resolvedIndicator,
|
|
65
|
+
className: cn("relative isolate", className),
|
|
66
|
+
style,
|
|
67
|
+
children: [list, /* @__PURE__ */ jsx(TrackHighlight, {})]
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
function SidebarMenuItem({ className, ...props }) {
|
|
71
|
+
return /* @__PURE__ */ jsx("li", {
|
|
72
|
+
"data-control-ui": "sidebar",
|
|
73
|
+
"data-control-family": "sidebar",
|
|
74
|
+
"data-slot": "menu-item",
|
|
75
|
+
className: cn("group/menu-item relative", className),
|
|
76
|
+
...props
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
const sidebarMenuButtonClasses = cva("peer/menu-button flex w-full items-center overflow-hidden text-start group-data-[collapsible=icon]:px-0! disabled:pointer-events-none aria-disabled:pointer-events-none [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0", {
|
|
80
|
+
variants: {
|
|
81
|
+
variant: {
|
|
82
|
+
default: null,
|
|
83
|
+
outline: null
|
|
84
|
+
},
|
|
85
|
+
size: {
|
|
86
|
+
default: "group-data-[collapsible=icon]:size-[var(--control-h-md)]!",
|
|
87
|
+
sm: "group-data-[collapsible=icon]:size-[var(--control-h-sm)]!",
|
|
88
|
+
lg: "group-data-[collapsible=icon]:size-[var(--control-h-lg)]!"
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
defaultVariants: {
|
|
92
|
+
variant: "default",
|
|
93
|
+
size: "default"
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
function SidebarMenuButton({ render, isActive = false, variant = "default", size = "default", tooltip, className, children, ...props }) {
|
|
97
|
+
const { isMobile, state } = useSidebar();
|
|
98
|
+
const indicator = useContext(SidebarMenuContext);
|
|
99
|
+
const button = useRender({
|
|
100
|
+
defaultTagName: "button",
|
|
101
|
+
render,
|
|
102
|
+
props: {
|
|
103
|
+
type: "button",
|
|
104
|
+
...props,
|
|
105
|
+
"data-control-ui": "sidebar",
|
|
106
|
+
"data-control-family": "sidebar",
|
|
107
|
+
"data-slot": "menu-button",
|
|
108
|
+
"data-size": size,
|
|
109
|
+
"data-variant": variant,
|
|
110
|
+
"data-active": isActive || void 0,
|
|
111
|
+
"data-track-item": indicator !== "none" ? "" : void 0,
|
|
112
|
+
className: cn(sidebarMenuButtonClasses({
|
|
113
|
+
variant,
|
|
114
|
+
size
|
|
115
|
+
}), className),
|
|
116
|
+
children
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
if (!tooltip) return button;
|
|
120
|
+
return /* @__PURE__ */ jsxs(Tooltip, { children: [/* @__PURE__ */ jsx(TooltipTrigger, { render: button }), /* @__PURE__ */ jsx(TooltipContent, {
|
|
121
|
+
side: "right",
|
|
122
|
+
align: "center",
|
|
123
|
+
hidden: state !== "collapsed" || isMobile,
|
|
124
|
+
children: tooltip
|
|
125
|
+
})] });
|
|
126
|
+
}
|
|
127
|
+
function SidebarMenuSub({ className, ...props }) {
|
|
128
|
+
return /* @__PURE__ */ jsx(SidebarMenu, {
|
|
129
|
+
"data-submenu": "",
|
|
130
|
+
className: cn("group-data-[collapsible=icon]:hidden", className),
|
|
131
|
+
...props
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
//#endregion
|
|
135
|
+
export { SidebarGroup, SidebarGroupLabel, SidebarMenu, SidebarMenuButton, SidebarMenuItem, SidebarMenuSub, sidebarMenuButtonSizes, sidebarMenuButtonVariants };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { SidebarKnobStyle } from "../knob-contracts/sidebar-knobs.js";
|
|
2
|
+
import { CSSProperties, ComponentProps } from "react";
|
|
3
|
+
//#region src/ui/sidebar-provider.d.ts
|
|
4
|
+
type SidebarStyle = CSSProperties & SidebarKnobStyle & {
|
|
5
|
+
"--sidebar-width"?: string;
|
|
6
|
+
"--sidebar-width-icon"?: string;
|
|
7
|
+
};
|
|
8
|
+
type SidebarContextProps = {
|
|
9
|
+
state: "expanded" | "collapsed";
|
|
10
|
+
open: boolean;
|
|
11
|
+
setOpen: (open: boolean) => void;
|
|
12
|
+
openMobile: boolean;
|
|
13
|
+
setOpenMobile: (open: boolean) => void;
|
|
14
|
+
isMobile: boolean;
|
|
15
|
+
toggleSidebar: () => void;
|
|
16
|
+
};
|
|
17
|
+
declare function useSidebar(): SidebarContextProps;
|
|
18
|
+
type SidebarProviderProps = Omit<ComponentProps<"div">, "style"> & {
|
|
19
|
+
defaultOpen?: boolean;
|
|
20
|
+
open?: boolean;
|
|
21
|
+
onOpenChange?: (open: boolean) => void;
|
|
22
|
+
persistOpen?: boolean;
|
|
23
|
+
keyboardShortcut?: string | null;
|
|
24
|
+
style?: SidebarStyle;
|
|
25
|
+
};
|
|
26
|
+
declare function SidebarProvider({ defaultOpen, open: openProp, onOpenChange, persistOpen, keyboardShortcut, ref, className, style, children, ...props }: SidebarProviderProps): import("react").JSX.Element;
|
|
27
|
+
//#endregion
|
|
28
|
+
export { SidebarProvider, SidebarProviderProps, SidebarStyle, useSidebar };
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "../lib/cn.js";
|
|
3
|
+
import { skinSidebarWidth } from "../skin.js";
|
|
4
|
+
import { TooltipProvider } from "./tooltip.js";
|
|
5
|
+
import { SIDEBAR_COOKIE_NAME } from "../control-props.js";
|
|
6
|
+
import { useIsMobile } from "../hooks/use-mobile.js";
|
|
7
|
+
import { createContext, useContext, useEffect, useRef, useState } from "react";
|
|
8
|
+
import { jsx } from "react/jsx-runtime";
|
|
9
|
+
//#region src/ui/sidebar-provider.tsx
|
|
10
|
+
const SIDEBAR_COOKIE_MAX_AGE = 604800;
|
|
11
|
+
const SIDEBAR_WIDTH = "16rem";
|
|
12
|
+
const SIDEBAR_WIDTH_ICON = "3rem";
|
|
13
|
+
const SIDEBAR_KEYBOARD_SHORTCUT = "b";
|
|
14
|
+
const SIDEBAR_MOBILE_BREAKPOINT = 1024;
|
|
15
|
+
const SidebarContext = createContext(null);
|
|
16
|
+
function useSidebar() {
|
|
17
|
+
const context = useContext(SidebarContext);
|
|
18
|
+
if (!context) throw new Error("useSidebar must be used within a SidebarProvider.");
|
|
19
|
+
return context;
|
|
20
|
+
}
|
|
21
|
+
function SidebarProvider({ defaultOpen = true, open: openProp, onOpenChange, persistOpen = true, keyboardShortcut = SIDEBAR_KEYBOARD_SHORTCUT, ref, className, style, children, ...props }) {
|
|
22
|
+
const isMobile = useIsMobile(SIDEBAR_MOBILE_BREAKPOINT);
|
|
23
|
+
const [openMobile, setOpenMobile] = useState(false);
|
|
24
|
+
const [internalOpen, setInternalOpen] = useState(defaultOpen);
|
|
25
|
+
const open = openProp ?? internalOpen;
|
|
26
|
+
const setOpen = (value) => {
|
|
27
|
+
const openState = typeof value === "function" ? value(open) : value;
|
|
28
|
+
if (onOpenChange) onOpenChange(openState);
|
|
29
|
+
else setInternalOpen(openState);
|
|
30
|
+
if (persistOpen) document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`;
|
|
31
|
+
};
|
|
32
|
+
const toggleSidebar = () => isMobile ? setOpenMobile((prev) => !prev) : setOpen(!open);
|
|
33
|
+
const toggleRef = useRef(toggleSidebar);
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
toggleRef.current = toggleSidebar;
|
|
36
|
+
});
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
if (keyboardShortcut === null) return;
|
|
39
|
+
const handleKeyDown = (event) => {
|
|
40
|
+
if (event.key === keyboardShortcut && (event.metaKey || event.ctrlKey)) {
|
|
41
|
+
event.preventDefault();
|
|
42
|
+
toggleRef.current();
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
46
|
+
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
47
|
+
}, [keyboardShortcut]);
|
|
48
|
+
const contextValue = {
|
|
49
|
+
state: open ? "expanded" : "collapsed",
|
|
50
|
+
open,
|
|
51
|
+
setOpen,
|
|
52
|
+
isMobile,
|
|
53
|
+
openMobile,
|
|
54
|
+
setOpenMobile,
|
|
55
|
+
toggleSidebar
|
|
56
|
+
};
|
|
57
|
+
const wrapperStyle = {
|
|
58
|
+
"--sidebar-width": skinSidebarWidth() ?? SIDEBAR_WIDTH,
|
|
59
|
+
"--sidebar-width-icon": SIDEBAR_WIDTH_ICON,
|
|
60
|
+
...style
|
|
61
|
+
};
|
|
62
|
+
return /* @__PURE__ */ jsx(SidebarContext.Provider, {
|
|
63
|
+
value: contextValue,
|
|
64
|
+
children: /* @__PURE__ */ jsx(TooltipProvider, {
|
|
65
|
+
delay: 0,
|
|
66
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
67
|
+
ref,
|
|
68
|
+
"data-control-ui": "sidebar",
|
|
69
|
+
"data-control-family": "sidebar",
|
|
70
|
+
"data-slot": "wrapper",
|
|
71
|
+
style: wrapperStyle,
|
|
72
|
+
className: cn("group/sidebar-wrapper flex min-h-svh w-full", className),
|
|
73
|
+
...props,
|
|
74
|
+
children
|
|
75
|
+
})
|
|
76
|
+
})
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
//#endregion
|
|
80
|
+
export { SidebarProvider, useSidebar };
|
package/dist/ui/sidebar.d.ts
CHANGED
|
@@ -1,55 +1,16 @@
|
|
|
1
|
-
import { RenderProp, SelectionIndicator } from "../control-props.js";
|
|
2
1
|
import { Button } from "./button.js";
|
|
3
2
|
import { SidebarKnobStyle } from "../knob-contracts/sidebar-knobs.js";
|
|
4
|
-
import {
|
|
3
|
+
import { SidebarGroup, SidebarGroupLabel, SidebarGroupLabelProps, SidebarMenu, SidebarMenuButton, SidebarMenuButtonProps, SidebarMenuButtonSize, SidebarMenuButtonVariant, SidebarMenuItem, SidebarMenuSub, SidebarSelectionIndicator, sidebarMenuButtonSizes, sidebarMenuButtonVariants } from "./sidebar-menu.js";
|
|
4
|
+
import { SidebarProvider, SidebarProviderProps, SidebarStyle, useSidebar } from "./sidebar-provider.js";
|
|
5
|
+
import { CSSProperties, ComponentProps } from "react";
|
|
5
6
|
//#region src/ui/sidebar.d.ts
|
|
6
|
-
declare const sidebarMenuButtonVariants: readonly ["default", "outline"];
|
|
7
|
-
type SidebarMenuButtonVariant = (typeof sidebarMenuButtonVariants)[number];
|
|
8
|
-
declare const sidebarMenuButtonSizes: readonly ["default", "sm", "lg"];
|
|
9
|
-
type SidebarMenuButtonSize = (typeof sidebarMenuButtonSizes)[number];
|
|
10
7
|
type SidebarRailProps = Omit<ComponentProps<"button">, "style"> & {
|
|
11
8
|
style?: CSSProperties & SidebarKnobStyle;
|
|
12
9
|
};
|
|
13
10
|
type SidebarInsetProps = Omit<ComponentProps<"main">, "style"> & {
|
|
14
11
|
style?: CSSProperties & SidebarKnobStyle;
|
|
15
12
|
};
|
|
16
|
-
type SidebarGroupLabelProps = Omit<ComponentProps<"div">, "style"> & {
|
|
17
|
-
style?: CSSProperties & SidebarKnobStyle;
|
|
18
|
-
} & {
|
|
19
|
-
render?: RenderProp<ComponentProps<"div">>;
|
|
20
|
-
};
|
|
21
|
-
type SidebarMenuButtonProps = Omit<ComponentProps<"button">, "style"> & {
|
|
22
|
-
style?: CSSProperties & SidebarKnobStyle;
|
|
23
|
-
} & {
|
|
24
|
-
render?: RenderProp<ComponentProps<"button">>;
|
|
25
|
-
isActive?: boolean;
|
|
26
|
-
tooltip?: ReactNode;
|
|
27
|
-
variant?: SidebarMenuButtonVariant;
|
|
28
|
-
size?: SidebarMenuButtonSize;
|
|
29
|
-
};
|
|
30
|
-
/** Exported so blocks can set width through `style` and stay type-checked. */
|
|
31
|
-
type SidebarStyle = CSSProperties & SidebarKnobStyle & {
|
|
32
|
-
"--sidebar-width"?: string;
|
|
33
|
-
"--sidebar-width-icon"?: string;
|
|
34
|
-
};
|
|
35
13
|
type SidebarSurfaceStyle = CSSProperties & SidebarKnobStyle;
|
|
36
|
-
type SidebarContextProps = {
|
|
37
|
-
state: "expanded" | "collapsed";
|
|
38
|
-
open: boolean;
|
|
39
|
-
setOpen: (open: boolean) => void;
|
|
40
|
-
openMobile: boolean;
|
|
41
|
-
setOpenMobile: (open: boolean) => void;
|
|
42
|
-
isMobile: boolean;
|
|
43
|
-
toggleSidebar: () => void;
|
|
44
|
-
};
|
|
45
|
-
declare function useSidebar(): SidebarContextProps;
|
|
46
|
-
type SidebarProviderProps = Omit<ComponentProps<"div">, "style"> & {
|
|
47
|
-
defaultOpen?: boolean;
|
|
48
|
-
open?: boolean;
|
|
49
|
-
onOpenChange?: (open: boolean) => void;
|
|
50
|
-
style?: SidebarStyle;
|
|
51
|
-
};
|
|
52
|
-
declare function SidebarProvider({ defaultOpen, open: openProp, onOpenChange: setOpenProp, ref, className, style, children, ...props }: SidebarProviderProps): import("react").JSX.Element;
|
|
53
14
|
declare function Sidebar({ side, variant, collapsible, ref, className, children, style, ...props }: Omit<ComponentProps<"div">, "style"> & {
|
|
54
15
|
side?: "left" | "right";
|
|
55
16
|
variant?: "sidebar" | "floating" | "inset";
|
|
@@ -66,23 +27,5 @@ declare function SidebarFooter({ className, ...props }: ComponentProps<"div"> &
|
|
|
66
27
|
style?: CSSProperties & SidebarKnobStyle;
|
|
67
28
|
}): import("react").JSX.Element;
|
|
68
29
|
declare function SidebarContent({ className, children, ...props }: ComponentProps<"div">): import("react").JSX.Element;
|
|
69
|
-
declare function SidebarGroup({ className, ...props }: ComponentProps<"div"> & {
|
|
70
|
-
style?: CSSProperties & SidebarKnobStyle;
|
|
71
|
-
}): import("react").JSX.Element;
|
|
72
|
-
declare function SidebarGroupLabel({ className, render, children, ...props }: SidebarGroupLabelProps): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
|
|
73
|
-
type SidebarSelectionIndicator = SelectionIndicator;
|
|
74
|
-
declare function SidebarMenu({ className, indicator, children, ...props }: ComponentProps<"ul"> & {
|
|
75
|
-
/**
|
|
76
|
-
* `slide` replaces per-row backgrounds with one pill that glides to hovered or active item.
|
|
77
|
-
* Defaults to ControlUiSkin.indicators.sidebar, else `none`.
|
|
78
|
-
*/
|
|
79
|
-
indicator?: SidebarSelectionIndicator;
|
|
80
|
-
} & {
|
|
81
|
-
style?: CSSProperties & SidebarKnobStyle;
|
|
82
|
-
}): import("react").JSX.Element;
|
|
83
|
-
declare function SidebarMenuItem({ className, ...props }: ComponentProps<"li"> & {
|
|
84
|
-
style?: CSSProperties & SidebarKnobStyle;
|
|
85
|
-
}): import("react").JSX.Element;
|
|
86
|
-
declare function SidebarMenuButton({ render, isActive, variant, size, tooltip, className, children, ...props }: SidebarMenuButtonProps): import("react").JSX.Element;
|
|
87
30
|
//#endregion
|
|
88
|
-
export { Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupLabel, SidebarGroupLabelProps, SidebarHeader, SidebarInset, SidebarInsetProps, SidebarMenu, SidebarMenuButton, SidebarMenuButtonProps, SidebarMenuButtonSize, SidebarMenuButtonVariant, SidebarMenuItem, SidebarProvider, SidebarProviderProps, SidebarRail, SidebarRailProps, SidebarSelectionIndicator, SidebarStyle, SidebarTrigger, sidebarMenuButtonSizes, sidebarMenuButtonVariants, useSidebar };
|
|
31
|
+
export { Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupLabel, type SidebarGroupLabelProps, SidebarHeader, SidebarInset, SidebarInsetProps, SidebarMenu, SidebarMenuButton, type SidebarMenuButtonProps, type SidebarMenuButtonSize, type SidebarMenuButtonVariant, SidebarMenuItem, SidebarMenuSub, SidebarProvider, type SidebarProviderProps, SidebarRail, SidebarRailProps, type SidebarSelectionIndicator, type SidebarStyle, SidebarTrigger, sidebarMenuButtonSizes, sidebarMenuButtonVariants, useSidebar };
|
package/dist/ui/sidebar.js
CHANGED
|
@@ -1,100 +1,21 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { cn } from "../lib/cn.js";
|
|
3
|
-
import {
|
|
3
|
+
import { skinSidebarLayout } from "../skin.js";
|
|
4
4
|
import { Button } from "./button.js";
|
|
5
5
|
import { ScrollArea } from "./scroll-area.js";
|
|
6
|
-
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "./tooltip.js";
|
|
7
|
-
import { SIDEBAR_COOKIE_NAME } from "../control-props.js";
|
|
8
|
-
import { useIsMobile } from "../hooks/use-mobile.js";
|
|
9
6
|
import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle } from "./sheet.js";
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
7
|
+
import { SidebarProvider, useSidebar } from "./sidebar-provider.js";
|
|
8
|
+
import { SidebarGroup, SidebarGroupLabel, SidebarMenu, SidebarMenuButton, SidebarMenuItem, SidebarMenuSub, sidebarMenuButtonSizes, sidebarMenuButtonVariants } from "./sidebar-menu.js";
|
|
12
9
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
13
10
|
import { PanelLeftIcon } from "lucide-react";
|
|
14
|
-
import { cva } from "class-variance-authority";
|
|
15
11
|
//#region src/ui/sidebar.tsx
|
|
16
|
-
const sidebarMenuButtonVariants = ["default", "outline"];
|
|
17
|
-
const sidebarMenuButtonSizes = [
|
|
18
|
-
"default",
|
|
19
|
-
"sm",
|
|
20
|
-
"lg"
|
|
21
|
-
];
|
|
22
|
-
const TrackHighlight = lazy(() => import("../extensions/track-highlight.js").then((module) => ({ default: module.TrackHighlight })));
|
|
23
|
-
const SIDEBAR_COOKIE_MAX_AGE = 604800;
|
|
24
|
-
const SIDEBAR_WIDTH = "16rem";
|
|
25
12
|
const SIDEBAR_WIDTH_MOBILE = "18rem";
|
|
26
|
-
const SIDEBAR_WIDTH_ICON = "3rem";
|
|
27
|
-
const SIDEBAR_KEYBOARD_SHORTCUT = "b";
|
|
28
|
-
const SIDEBAR_MOBILE_BREAKPOINT = 1024;
|
|
29
13
|
const sidebarTriggerWidth = {
|
|
30
14
|
xs: "w-[var(--control-h-xs)]",
|
|
31
15
|
sm: "w-[var(--control-h-sm)]",
|
|
32
16
|
md: "w-[var(--control-h-md)]",
|
|
33
17
|
lg: "w-[var(--control-h-lg)]"
|
|
34
18
|
};
|
|
35
|
-
const SidebarContext = createContext(null);
|
|
36
|
-
function useSidebar() {
|
|
37
|
-
const context = useContext(SidebarContext);
|
|
38
|
-
if (!context) throw new Error("useSidebar must be used within a SidebarProvider.");
|
|
39
|
-
return context;
|
|
40
|
-
}
|
|
41
|
-
function SidebarProvider({ defaultOpen = true, open: openProp, onOpenChange: setOpenProp, ref, className, style, children, ...props }) {
|
|
42
|
-
const isMobile = useIsMobile(SIDEBAR_MOBILE_BREAKPOINT);
|
|
43
|
-
const [openMobile, setOpenMobile] = useState(false);
|
|
44
|
-
const [_open, _setOpen] = useState(defaultOpen);
|
|
45
|
-
const open = openProp ?? _open;
|
|
46
|
-
const setOpen = (value) => {
|
|
47
|
-
const openState = typeof value === "function" ? value(open) : value;
|
|
48
|
-
if (setOpenProp) setOpenProp(openState);
|
|
49
|
-
else _setOpen(openState);
|
|
50
|
-
document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`;
|
|
51
|
-
};
|
|
52
|
-
const toggleSidebar = () => isMobile ? setOpenMobile((prev) => !prev) : setOpen(!open);
|
|
53
|
-
const toggleRef = useRef(toggleSidebar);
|
|
54
|
-
useEffect(() => {
|
|
55
|
-
toggleRef.current = toggleSidebar;
|
|
56
|
-
});
|
|
57
|
-
useEffect(() => {
|
|
58
|
-
const handleKeyDown = (event) => {
|
|
59
|
-
if (event.key === SIDEBAR_KEYBOARD_SHORTCUT && (event.metaKey || event.ctrlKey)) {
|
|
60
|
-
event.preventDefault();
|
|
61
|
-
toggleRef.current();
|
|
62
|
-
}
|
|
63
|
-
};
|
|
64
|
-
window.addEventListener("keydown", handleKeyDown);
|
|
65
|
-
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
66
|
-
}, []);
|
|
67
|
-
const contextValue = {
|
|
68
|
-
state: open ? "expanded" : "collapsed",
|
|
69
|
-
open,
|
|
70
|
-
setOpen,
|
|
71
|
-
isMobile,
|
|
72
|
-
openMobile,
|
|
73
|
-
setOpenMobile,
|
|
74
|
-
toggleSidebar
|
|
75
|
-
};
|
|
76
|
-
const wrapperStyle = {
|
|
77
|
-
"--sidebar-width": skinSidebarWidth() ?? SIDEBAR_WIDTH,
|
|
78
|
-
"--sidebar-width-icon": SIDEBAR_WIDTH_ICON,
|
|
79
|
-
...style
|
|
80
|
-
};
|
|
81
|
-
return /* @__PURE__ */ jsx(SidebarContext.Provider, {
|
|
82
|
-
value: contextValue,
|
|
83
|
-
children: /* @__PURE__ */ jsx(TooltipProvider, {
|
|
84
|
-
delay: 0,
|
|
85
|
-
children: /* @__PURE__ */ jsx("div", {
|
|
86
|
-
ref,
|
|
87
|
-
"data-control-ui": "sidebar",
|
|
88
|
-
"data-control-family": "sidebar",
|
|
89
|
-
"data-slot": "wrapper",
|
|
90
|
-
style: wrapperStyle,
|
|
91
|
-
className: cn("group/sidebar-wrapper flex min-h-svh w-full", className),
|
|
92
|
-
...props,
|
|
93
|
-
children
|
|
94
|
-
})
|
|
95
|
-
})
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
19
|
function Sidebar({ side = "left", variant, collapsible = "offcanvas", ref, className, children, style, ...props }) {
|
|
99
20
|
const { isMobile, state, openMobile, setOpenMobile } = useSidebar();
|
|
100
21
|
const resolvedVariant = variant ?? skinSidebarLayout() ?? "sidebar";
|
|
@@ -118,11 +39,6 @@ function Sidebar({ side = "left", variant, collapsible = "offcanvas", ref, class
|
|
|
118
39
|
open: openMobile,
|
|
119
40
|
onOpenChange: setOpenMobile,
|
|
120
41
|
children: /* @__PURE__ */ jsxs(SheetContent, {
|
|
121
|
-
ref,
|
|
122
|
-
"data-control-ui": "sidebar",
|
|
123
|
-
"data-control-family": "sidebar",
|
|
124
|
-
"data-slot": "root",
|
|
125
|
-
"data-surface": "panel",
|
|
126
42
|
side,
|
|
127
43
|
className: "w-(--sidebar-width) gap-0 p-0",
|
|
128
44
|
style: mobileSheetStyle,
|
|
@@ -130,11 +46,23 @@ function Sidebar({ side = "left", variant, collapsible = "offcanvas", ref, class
|
|
|
130
46
|
className: "sr-only",
|
|
131
47
|
children: [/* @__PURE__ */ jsx(SheetTitle, { children: "Sidebar" }), /* @__PURE__ */ jsx(SheetDescription, { children: "Displays the mobile sidebar." })]
|
|
132
48
|
}), /* @__PURE__ */ jsx("div", {
|
|
49
|
+
ref,
|
|
133
50
|
"data-control-ui": "sidebar",
|
|
134
51
|
"data-control-family": "sidebar",
|
|
135
|
-
"data-slot": "
|
|
136
|
-
|
|
137
|
-
|
|
52
|
+
"data-slot": "root",
|
|
53
|
+
"data-surface": "panel",
|
|
54
|
+
"data-mobile": "",
|
|
55
|
+
"data-side": side,
|
|
56
|
+
className: cn("flex min-h-0 flex-1 flex-col", className),
|
|
57
|
+
style,
|
|
58
|
+
...props,
|
|
59
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
60
|
+
"data-control-ui": "sidebar",
|
|
61
|
+
"data-control-family": "sidebar",
|
|
62
|
+
"data-slot": "inner",
|
|
63
|
+
className: "flex min-h-0 flex-1 flex-col",
|
|
64
|
+
children
|
|
65
|
+
})
|
|
138
66
|
})]
|
|
139
67
|
})
|
|
140
68
|
});
|
|
@@ -173,11 +101,13 @@ function Sidebar({ side = "left", variant, collapsible = "offcanvas", ref, class
|
|
|
173
101
|
});
|
|
174
102
|
}
|
|
175
103
|
function SidebarTrigger({ className, onClick, size = "sm", ...props }) {
|
|
176
|
-
const { toggleSidebar } = useSidebar();
|
|
104
|
+
const { toggleSidebar, isMobile, openMobile, open } = useSidebar();
|
|
177
105
|
return /* @__PURE__ */ jsxs(Button, {
|
|
178
106
|
"data-control-ui": "sidebar",
|
|
179
107
|
"data-slot": "trigger",
|
|
108
|
+
"data-sidebar-trigger": "",
|
|
180
109
|
variant: "ghost",
|
|
110
|
+
"aria-expanded": isMobile ? openMobile : open,
|
|
181
111
|
size,
|
|
182
112
|
className: cn(sidebarTriggerWidth[size], "px-0", className),
|
|
183
113
|
onClick: (event) => {
|
|
@@ -211,7 +141,7 @@ function SidebarInset({ className, ...props }) {
|
|
|
211
141
|
"data-control-ui": "sidebar",
|
|
212
142
|
"data-control-family": "sidebar",
|
|
213
143
|
"data-slot": "inset",
|
|
214
|
-
className: cn("relative flex w-full flex-1 flex-col", className),
|
|
144
|
+
className: cn("relative flex min-w-0 w-full flex-1 flex-col", className),
|
|
215
145
|
...props
|
|
216
146
|
});
|
|
217
147
|
}
|
|
@@ -249,114 +179,5 @@ function SidebarContent({ className, children, ...props }) {
|
|
|
249
179
|
})
|
|
250
180
|
});
|
|
251
181
|
}
|
|
252
|
-
function SidebarGroup({ className, ...props }) {
|
|
253
|
-
return /* @__PURE__ */ jsx("div", {
|
|
254
|
-
"data-control-ui": "sidebar",
|
|
255
|
-
"data-control-family": "sidebar",
|
|
256
|
-
"data-slot": "group",
|
|
257
|
-
className: cn("relative flex w-full min-w-0 flex-col", className),
|
|
258
|
-
...props
|
|
259
|
-
});
|
|
260
|
-
}
|
|
261
|
-
function SidebarGroupLabel({ className, render, children, ...props }) {
|
|
262
|
-
return useRender({
|
|
263
|
-
defaultTagName: "div",
|
|
264
|
-
render,
|
|
265
|
-
props: {
|
|
266
|
-
...props,
|
|
267
|
-
"data-control-ui": "sidebar",
|
|
268
|
-
"data-control-family": "sidebar",
|
|
269
|
-
"data-slot": "group-label",
|
|
270
|
-
className: cn("flex h-[var(--control-h-sm)] shrink-0 items-center [&>svg]:size-4 [&>svg]:shrink-0", "group-data-[collapsible=icon]:-mt-[var(--control-h-sm)] group-data-[collapsible=icon]:opacity-0", className),
|
|
271
|
-
children
|
|
272
|
-
}
|
|
273
|
-
});
|
|
274
|
-
}
|
|
275
|
-
const SidebarMenuContext = createContext("none");
|
|
276
|
-
function SidebarMenu({ className, indicator, children, ...props }) {
|
|
277
|
-
const resolvedIndicator = indicator ?? skinIndicator("sidebar") ?? "none";
|
|
278
|
-
const sliding = resolvedIndicator === "slide";
|
|
279
|
-
const list = /* @__PURE__ */ jsx("ul", {
|
|
280
|
-
"data-control-ui": "sidebar",
|
|
281
|
-
"data-control-family": "sidebar",
|
|
282
|
-
"data-slot": "menu",
|
|
283
|
-
"data-indicator": resolvedIndicator,
|
|
284
|
-
className: cn("flex w-full min-w-0 flex-col", sliding ? void 0 : className),
|
|
285
|
-
...props,
|
|
286
|
-
children: /* @__PURE__ */ jsx(SidebarMenuContext.Provider, {
|
|
287
|
-
value: resolvedIndicator,
|
|
288
|
-
children
|
|
289
|
-
})
|
|
290
|
-
});
|
|
291
|
-
if (!sliding) return list;
|
|
292
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
293
|
-
"data-control-ui": "sidebar",
|
|
294
|
-
"data-control-family": "sidebar",
|
|
295
|
-
"data-slot": "menu-track",
|
|
296
|
-
"data-indicator": resolvedIndicator,
|
|
297
|
-
className: cn("relative isolate", className),
|
|
298
|
-
children: [/* @__PURE__ */ jsx(Suspense, {
|
|
299
|
-
fallback: null,
|
|
300
|
-
children: /* @__PURE__ */ jsx(TrackHighlight, {
|
|
301
|
-
itemSelector: "[data-control-ui=\"sidebar\"][data-slot=\"menu-button\"]",
|
|
302
|
-
activeSelector: "[data-control-ui=\"sidebar\"][data-slot=\"menu-button\"][data-active]"
|
|
303
|
-
})
|
|
304
|
-
}), list]
|
|
305
|
-
});
|
|
306
|
-
}
|
|
307
|
-
function SidebarMenuItem({ className, ...props }) {
|
|
308
|
-
return /* @__PURE__ */ jsx("li", {
|
|
309
|
-
"data-control-ui": "sidebar",
|
|
310
|
-
"data-control-family": "sidebar",
|
|
311
|
-
"data-slot": "menu-item",
|
|
312
|
-
className: cn("group/menu-item relative", className),
|
|
313
|
-
...props
|
|
314
|
-
});
|
|
315
|
-
}
|
|
316
|
-
const sidebarMenuButtonClasses = cva("peer/menu-button flex w-full items-center overflow-hidden group-data-[collapsible=icon]:px-0! disabled:pointer-events-none aria-disabled:pointer-events-none [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0", {
|
|
317
|
-
variants: {
|
|
318
|
-
variant: {
|
|
319
|
-
default: null,
|
|
320
|
-
outline: null
|
|
321
|
-
},
|
|
322
|
-
size: {
|
|
323
|
-
default: "group-data-[collapsible=icon]:size-[var(--control-h-md)]!",
|
|
324
|
-
sm: "group-data-[collapsible=icon]:size-[var(--control-h-sm)]!",
|
|
325
|
-
lg: "group-data-[collapsible=icon]:size-[var(--control-h-lg)]!"
|
|
326
|
-
}
|
|
327
|
-
},
|
|
328
|
-
defaultVariants: {
|
|
329
|
-
variant: "default",
|
|
330
|
-
size: "default"
|
|
331
|
-
}
|
|
332
|
-
});
|
|
333
|
-
function SidebarMenuButton({ render, isActive = false, variant = "default", size = "default", tooltip, className, children, ...props }) {
|
|
334
|
-
const { isMobile, state } = useSidebar();
|
|
335
|
-
const button = useRender({
|
|
336
|
-
defaultTagName: "button",
|
|
337
|
-
render,
|
|
338
|
-
props: {
|
|
339
|
-
...props,
|
|
340
|
-
"data-control-ui": "sidebar",
|
|
341
|
-
"data-control-family": "sidebar",
|
|
342
|
-
"data-slot": "menu-button",
|
|
343
|
-
"data-size": size,
|
|
344
|
-
"data-variant": variant,
|
|
345
|
-
"data-active": isActive || void 0,
|
|
346
|
-
className: cn(sidebarMenuButtonClasses({
|
|
347
|
-
variant,
|
|
348
|
-
size
|
|
349
|
-
}), className),
|
|
350
|
-
children
|
|
351
|
-
}
|
|
352
|
-
});
|
|
353
|
-
if (!tooltip) return button;
|
|
354
|
-
return /* @__PURE__ */ jsxs(Tooltip, { children: [/* @__PURE__ */ jsx(TooltipTrigger, { render: button }), /* @__PURE__ */ jsx(TooltipContent, {
|
|
355
|
-
side: "right",
|
|
356
|
-
align: "center",
|
|
357
|
-
hidden: state !== "collapsed" || isMobile,
|
|
358
|
-
children: tooltip
|
|
359
|
-
})] });
|
|
360
|
-
}
|
|
361
182
|
//#endregion
|
|
362
|
-
export { Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupLabel, SidebarHeader, SidebarInset, SidebarMenu, SidebarMenuButton, SidebarMenuItem, SidebarProvider, SidebarRail, SidebarTrigger, sidebarMenuButtonSizes, sidebarMenuButtonVariants, useSidebar };
|
|
183
|
+
export { Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupLabel, SidebarHeader, SidebarInset, SidebarMenu, SidebarMenuButton, SidebarMenuItem, SidebarMenuSub, SidebarProvider, SidebarRail, SidebarTrigger, sidebarMenuButtonSizes, sidebarMenuButtonVariants, useSidebar };
|
|
@@ -12,9 +12,6 @@ const tableOfContentsVariants = [
|
|
|
12
12
|
const DETECTION_MARGIN = "-80px 0px -20% 0px";
|
|
13
13
|
const TOC_ITEM_SELECTOR = "[data-control-ui=\"table-of-contents\"][data-slot=\"item\"]";
|
|
14
14
|
const TOC_ACTIVE_SELECTOR = "[data-control-ui=\"table-of-contents\"][data-slot=\"item\"][data-active]";
|
|
15
|
-
const tableOfContentsItemClass = "block";
|
|
16
|
-
const tableOfContentsHighlightClass = "";
|
|
17
|
-
const tableOfContentsTrailClass = "absolute inset-y-0 left-0 w-0.5";
|
|
18
15
|
function getScrollContainer(el) {
|
|
19
16
|
let node = el.parentElement;
|
|
20
17
|
while (node) {
|
|
@@ -91,8 +88,6 @@ function TableOfContents({ items, label = "On this page", variant = "both", clas
|
|
|
91
88
|
const normalizedItems = normalizeItems(items, Math.min(...collectLevels(items), 2));
|
|
92
89
|
const targetIds = flattenItems(normalizedItems).map((item) => item.href.replace(/^#/, ""));
|
|
93
90
|
const activeSet = activeIdsInRange(useVisibleSections(targetIds), targetIds);
|
|
94
|
-
const railStyle = style;
|
|
95
|
-
const highlightStyle = style;
|
|
96
91
|
if (items.length === 0) return null;
|
|
97
92
|
return /* @__PURE__ */ jsxs("nav", {
|
|
98
93
|
"data-control-ui": "table-of-contents",
|
|
@@ -119,8 +114,7 @@ function TableOfContents({ items, label = "On this page", variant = "both", clas
|
|
|
119
114
|
"data-control-ui": "table-of-contents",
|
|
120
115
|
"data-control-family": "table-of-contents",
|
|
121
116
|
"data-slot": "rail",
|
|
122
|
-
className: "pointer-events-none absolute inset-y-0 left-0 -z-20 w-px"
|
|
123
|
-
style: railStyle
|
|
117
|
+
className: "pointer-events-none absolute inset-y-0 left-0 -z-20 w-px"
|
|
124
118
|
}),
|
|
125
119
|
/* @__PURE__ */ jsx(TrackHighlight, {
|
|
126
120
|
"data-variant": variant,
|
|
@@ -128,14 +122,12 @@ function TableOfContents({ items, label = "On this page", variant = "both", clas
|
|
|
128
122
|
activeSelector: TOC_ACTIVE_SELECTOR,
|
|
129
123
|
range: true,
|
|
130
124
|
followHover: false,
|
|
131
|
-
style: highlightStyle,
|
|
132
|
-
className: tableOfContentsHighlightClass,
|
|
133
125
|
children: variant !== "background" && /* @__PURE__ */ jsx("div", {
|
|
134
126
|
"aria-hidden": true,
|
|
135
127
|
"data-control-ui": "table-of-contents",
|
|
136
128
|
"data-control-family": "table-of-contents",
|
|
137
129
|
"data-slot": "trail",
|
|
138
|
-
className:
|
|
130
|
+
className: "absolute inset-y-0 left-0 w-0.5"
|
|
139
131
|
})
|
|
140
132
|
}),
|
|
141
133
|
/* @__PURE__ */ jsx(TocList, {
|
|
@@ -167,7 +159,7 @@ function TocList({ items, activeSet, variant, root = false }) {
|
|
|
167
159
|
"data-depth": item.depth,
|
|
168
160
|
"aria-current": isActive ? "location" : void 0,
|
|
169
161
|
href: item.href,
|
|
170
|
-
className:
|
|
162
|
+
className: "block",
|
|
171
163
|
children: item.label
|
|
172
164
|
}), item.children && /* @__PURE__ */ jsx(TocList, {
|
|
173
165
|
items: item.children,
|