@ctrl-ui/react 0.8.0 → 0.8.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.
Files changed (62) hide show
  1. package/README.md +1 -0
  2. package/dist/blocks/coding-agent.js +3 -1
  3. package/dist/blocks/file-explorer.js +3 -1
  4. package/dist/blocks/settings.js +3 -1
  5. package/dist/control-props.d.ts +2 -1
  6. package/dist/email/email.d.ts +28 -0
  7. package/dist/email/email.js +79 -0
  8. package/dist/email/length.d.ts +4 -0
  9. package/dist/email/length.js +34 -0
  10. package/dist/email/templates.d.ts +51 -0
  11. package/dist/email/templates.js +228 -0
  12. package/dist/email/theme.d.ts +35 -0
  13. package/dist/email/theme.js +113 -0
  14. package/dist/extensions/create-track-highlight.d.ts +0 -2
  15. package/dist/extensions/create-track-highlight.js +49 -8
  16. package/dist/extensions/supports-anchor-transitions.d.ts +4 -0
  17. package/dist/extensions/supports-anchor-transitions.js +31 -0
  18. package/dist/extensions/track-highlight.d.ts +0 -6
  19. package/dist/extensions/track-highlight.js +25 -9
  20. package/dist/knob-contracts/button-knobs.d.ts +1 -1
  21. package/dist/knob-contracts/button-knobs.js +4 -1
  22. package/dist/knob-contracts/progressive-blur-knobs.d.ts +5 -0
  23. package/dist/knob-contracts/progressive-blur-knobs.js +9 -0
  24. package/dist/scripts/contrast-eval.d.ts +46 -0
  25. package/dist/scripts/contrast-eval.js +327 -0
  26. package/dist/skin.config.js +9 -1
  27. package/dist/skin.d.ts +11 -9
  28. package/dist/skin.js +0 -1
  29. package/dist/styles/index.css +3 -1
  30. package/dist/styles/recipes/button-group.css +46 -0
  31. package/dist/styles/recipes/button.css +53 -5
  32. package/dist/styles/recipes/progressive-blur.css +145 -0
  33. package/dist/styles/recipes/scroll-area.css +140 -5
  34. package/dist/styles/recipes/sidebar-menu.css +156 -0
  35. package/dist/styles/recipes/sidebar.css +25 -69
  36. package/dist/styles/recipes/table-of-contents.css +1 -1
  37. package/dist/styles/recipes/track-highlight.css +126 -2
  38. package/dist/styles/recipes/tree.css +4 -0
  39. package/dist/ui/button-group.d.ts +3 -1
  40. package/dist/ui/button-group.js +21 -18
  41. package/dist/ui/button.d.ts +3 -1
  42. package/dist/ui/button.js +13 -4
  43. package/dist/ui/checkbox-group.d.ts +5 -3
  44. package/dist/ui/checkbox-group.js +23 -6
  45. package/dist/ui/combobox.d.ts +2 -0
  46. package/dist/ui/dropdown-menu.d.ts +28 -21
  47. package/dist/ui/dropdown-menu.js +112 -13
  48. package/dist/ui/progressive-blur.d.ts +12 -0
  49. package/dist/ui/progressive-blur.js +47 -0
  50. package/dist/ui/scroll-area.d.ts +4 -1
  51. package/dist/ui/scroll-area.js +27 -4
  52. package/dist/ui/sidebar-menu.d.ts +49 -0
  53. package/dist/ui/sidebar-menu.js +160 -0
  54. package/dist/ui/sidebar-provider.d.ts +28 -0
  55. package/dist/ui/sidebar-provider.js +80 -0
  56. package/dist/ui/sidebar.d.ts +4 -61
  57. package/dist/ui/sidebar.js +23 -202
  58. package/dist/ui/table-of-contents.js +3 -11
  59. package/dist/ui/toggle.d.ts +3 -2
  60. package/dist/ui/toggle.js +22 -10
  61. package/dist/ui/tree.js +13 -19
  62. package/package.json +5 -1
@@ -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 };
@@ -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 { CSSProperties, ComponentProps, ReactNode } from "react";
3
+ import { SidebarGroup, SidebarGroupContent, SidebarGroupContentProps, SidebarGroupLabel, SidebarGroupLabelProps, SidebarMenu, SidebarMenuAction, SidebarMenuActionProps, 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, SidebarGroupContent, type SidebarGroupContentProps, SidebarGroupLabel, type SidebarGroupLabelProps, SidebarHeader, SidebarInset, SidebarInsetProps, SidebarMenu, SidebarMenuAction, type SidebarMenuActionProps, SidebarMenuButton, type SidebarMenuButtonProps, type SidebarMenuButtonSize, type SidebarMenuButtonVariant, SidebarMenuItem, SidebarMenuSub, SidebarProvider, type SidebarProviderProps, SidebarRail, SidebarRailProps, type SidebarSelectionIndicator, type SidebarStyle, SidebarTrigger, sidebarMenuButtonSizes, sidebarMenuButtonVariants, useSidebar };
@@ -1,100 +1,21 @@
1
1
  "use client";
2
2
  import { cn } from "../lib/cn.js";
3
- import { skinIndicator, skinSidebarLayout, skinSidebarWidth } from "../skin.js";
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 { Suspense, createContext, lazy, useContext, useEffect, useRef, useState } from "react";
11
- import { useRender } from "@base-ui/react/use-render";
7
+ import { SidebarProvider, useSidebar } from "./sidebar-provider.js";
8
+ import { SidebarGroup, SidebarGroupContent, SidebarGroupLabel, SidebarMenu, SidebarMenuAction, 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": "inner",
136
- className: "flex h-full w-full flex-col",
137
- children
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, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInset, SidebarMenu, SidebarMenuAction, 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: tableOfContentsTrailClass
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: tableOfContentsItemClass,
162
+ className: "block",
171
163
  children: item.label
172
164
  }), item.children && /* @__PURE__ */ jsx(TocList, {
173
165
  items: item.children,
@@ -1,4 +1,4 @@
1
- import { ControlledMultiChoice } from "../control-props.js";
1
+ import { ControlledMultiChoice, HoverIndicator } from "../control-props.js";
2
2
  import { ButtonProps } from "./button.js";
3
3
  import { ComponentProps } from "react";
4
4
  //#region src/ui/toggle.d.ts
@@ -13,8 +13,9 @@ type ToggleGroupProps<TValue extends string = string> = Omit<ComponentProps<"div
13
13
  multiple?: boolean;
14
14
  disabled?: boolean;
15
15
  orientation?: "horizontal" | "vertical";
16
+ indicator?: HoverIndicator;
16
17
  };
17
18
  declare function Toggle({ variant, size, tone, active, showCheck, className, pressed, defaultPressed, onPressedChange, value, disabled, children, ...props }: ToggleProps): import("react").JSX.Element;
18
- declare function ToggleGroup<TValue extends string = string>({ className, orientation, ...props }: ToggleGroupProps<TValue>): import("react").JSX.Element;
19
+ declare function ToggleGroup<TValue extends string = string>({ className, orientation, indicator, children, ...props }: ToggleGroupProps<TValue>): import("react").JSX.Element;
19
20
  //#endregion
20
21
  export { Toggle, ToggleGroup, ToggleGroupProps, ToggleProps };
package/dist/ui/toggle.js CHANGED
@@ -1,12 +1,17 @@
1
1
  "use client";
2
2
  import { cn } from "../lib/cn.js";
3
- import { buttonContentClasses, buttonStructureClasses } from "./button.js";
3
+ import { skinIndicator } from "../skin.js";
4
+ import { ButtonTrackContext, buttonContentClasses, buttonStructureClasses, buttonTrackStructureClasses } from "./button.js";
5
+ import { TrackHighlight } from "../extensions/track-highlight.js";
6
+ import { useContext } from "react";
4
7
  import { jsx, jsxs } from "react/jsx-runtime";
5
8
  import { Toggle as Toggle$1 } from "@base-ui/react/toggle";
6
9
  import { ToggleGroup as ToggleGroup$1 } from "@base-ui/react/toggle-group";
7
10
  //#region src/ui/toggle.tsx
8
11
  function Toggle({ variant = "surface", size = "sm", tone = "neutral", active, showCheck = false, className, pressed, defaultPressed, onPressedChange, value, disabled, children, ...props }) {
12
+ const tracksHover = useContext(ButtonTrackContext);
9
13
  return /* @__PURE__ */ jsx(Toggle$1, {
14
+ "data-track-item": tracksHover ? "" : void 0,
10
15
  pressed,
11
16
  defaultPressed,
12
17
  onPressedChange,
@@ -56,15 +61,22 @@ function Toggle({ variant = "surface", size = "sm", tone = "neutral", active, sh
56
61
  children
57
62
  });
58
63
  }
59
- function ToggleGroup({ className, orientation = "horizontal", ...props }) {
60
- return /* @__PURE__ */ jsx(ToggleGroup$1, {
61
- "data-control-ui": "toggle",
62
- "data-control-family": "button",
63
- "data-slot": "group",
64
- "data-orientation": orientation,
65
- orientation,
66
- className: cn("inline-flex items-center", orientation === "vertical" && "flex-col", className),
67
- ...props
64
+ function ToggleGroup({ className, orientation = "horizontal", indicator, children, ...props }) {
65
+ const resolvedIndicator = indicator ?? skinIndicator("toggle-group") ?? "none";
66
+ const tracksHover = resolvedIndicator === "hover";
67
+ return /* @__PURE__ */ jsx(ButtonTrackContext, {
68
+ value: tracksHover,
69
+ children: /* @__PURE__ */ jsxs(ToggleGroup$1, {
70
+ "data-control-ui": "toggle",
71
+ "data-control-family": "button",
72
+ "data-slot": "group",
73
+ "data-orientation": orientation,
74
+ "data-track": resolvedIndicator,
75
+ orientation,
76
+ className: cn(buttonTrackStructureClasses, "inline-flex items-center data-[track=hover]:gap-0", orientation === "vertical" && "flex-col", className),
77
+ ...props,
78
+ children: [children, tracksHover ? /* @__PURE__ */ jsx(TrackHighlight, { className: "z-0" }) : null]
79
+ })
68
80
  });
69
81
  }
70
82
  //#endregion
package/dist/ui/tree.js CHANGED
@@ -1,13 +1,13 @@
1
1
  "use client";
2
2
  import { cn } from "../lib/cn.js";
3
3
  import { skinIndicator } from "../skin.js";
4
- import { Children, Suspense, createContext, isValidElement, lazy, useContext, useRef, useState } from "react";
4
+ import { TrackHighlight } from "../extensions/track-highlight.js";
5
+ import { Children, createContext, isValidElement, useContext, useRef, useState } from "react";
5
6
  import { useRender } from "@base-ui/react/use-render";
6
7
  import { jsx, jsxs } from "react/jsx-runtime";
7
8
  import { ChevronRightIcon } from "lucide-react";
8
9
  import { Collapsible } from "@base-ui/react/collapsible";
9
10
  //#region src/ui/tree.tsx
10
- const TrackHighlight = lazy(() => import("../extensions/track-highlight.js").then((module) => ({ default: module.TrackHighlight })));
11
11
  const TYPEAHEAD_TIMEOUT = 500;
12
12
  const TreeContext = createContext(null);
13
13
  function useTree() {
@@ -211,17 +211,14 @@ function Tree({ selectionMode = "single", indicator, value, defaultValue, onValu
211
211
  toggleExpanded,
212
212
  setFocusedValue
213
213
  };
214
- const rootStyle = style;
215
214
  const sliding = resolvedIndicator === "slide";
216
215
  const list = /* @__PURE__ */ jsx("ul", {
217
216
  "data-control-ui": "tree",
218
217
  "data-control-family": "tree",
219
- "data-indicator": resolvedIndicator,
220
- "data-slot": "root",
218
+ "data-slot": "list",
221
219
  role: "tree",
222
220
  "aria-multiselectable": selectionMode === "multiple" || void 0,
223
- className: cn("flex flex-col", sliding ? void 0 : className),
224
- style: sliding ? void 0 : rootStyle,
221
+ className: "flex flex-col",
225
222
  onKeyDown: (event) => {
226
223
  onKeyDown?.(event);
227
224
  handleTreeKeyDown(event, contextValue, typeahead);
@@ -238,21 +235,18 @@ function Tree({ selectionMode = "single", indicator, value, defaultValue, onValu
238
235
  });
239
236
  return /* @__PURE__ */ jsx(TreeContext.Provider, {
240
237
  value: contextValue,
241
- children: sliding ? /* @__PURE__ */ jsxs("div", {
238
+ children: /* @__PURE__ */ jsxs("div", {
242
239
  "data-control-ui": "tree",
243
240
  "data-control-family": "tree",
244
- "data-slot": "track",
241
+ "data-slot": "root",
245
242
  "data-indicator": resolvedIndicator,
246
- className: cn("relative isolate", className),
247
- style: rootStyle,
248
- children: [/* @__PURE__ */ jsx(Suspense, {
249
- fallback: null,
250
- children: /* @__PURE__ */ jsx(TrackHighlight, {
251
- itemSelector: "[data-control-ui=tree][data-slot=item-trigger]",
252
- activeSelector: "[data-control-ui=tree][data-slot=item-trigger][data-selected]"
253
- })
254
- }), list]
255
- }) : list
243
+ className: cn(sliding && "relative isolate", className),
244
+ style,
245
+ children: [sliding ? /* @__PURE__ */ jsx(TrackHighlight, {
246
+ itemSelector: "[data-control-ui=tree][data-slot=item-trigger]",
247
+ activeSelector: "[data-control-ui=tree][data-slot=item-trigger][data-selected]"
248
+ }) : null, list]
249
+ })
256
250
  });
257
251
  }
258
252
  function TreeItem({ value, disabled = false, label, className, style, children, ref, ...props }) {