@ctrl-ui/react 0.8.19 → 0.8.21

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 (84) hide show
  1. package/README.md +7 -0
  2. package/dist/action-bar.js +2 -2
  3. package/dist/audio-device-select.js +5 -2
  4. package/dist/blocks/coding-agent.js +22 -12
  5. package/dist/blocks/design-canvas-inspector.js +6 -3
  6. package/dist/blocks/design-canvas.js +17 -11
  7. package/dist/blocks/discussion-markdown-input.d.ts +3 -1
  8. package/dist/blocks/discussion-markdown-input.js +3 -1
  9. package/dist/blocks/discussion.d.ts +3 -1
  10. package/dist/blocks/discussion.js +9 -4
  11. package/dist/blocks/file-explorer.js +47 -25
  12. package/dist/blocks/settings.js +8 -6
  13. package/dist/chat-composer-editor/extensions/mention.d.ts +1 -1
  14. package/dist/chat-message.d.ts +13 -0
  15. package/dist/chat-message.js +198 -3
  16. package/dist/filter-bar/editor.js +5 -2
  17. package/dist/knob-contracts/flow-knobs.d.ts +4 -0
  18. package/dist/knob-contracts/flow-knobs.js +32 -0
  19. package/dist/knob-contracts/item-knobs.d.ts +1 -1
  20. package/dist/knob-contracts/item-knobs.js +4 -1
  21. package/dist/knob-contracts/markdown-editor-knobs.d.ts +1 -1
  22. package/dist/knob-contracts/markdown-editor-knobs.js +1 -0
  23. package/dist/knob-contracts/morphing-panel-knobs.d.ts +1 -1
  24. package/dist/knob-contracts/morphing-panel-knobs.js +2 -1
  25. package/dist/knob-contracts/resize-handle-knobs.d.ts +4 -0
  26. package/dist/knob-contracts/resize-handle-knobs.js +12 -0
  27. package/dist/knob-contracts/sidebar-knobs.d.ts +1 -1
  28. package/dist/knob-contracts/sidebar-knobs.js +10 -0
  29. package/dist/lib/canvas-grid.d.ts +4 -0
  30. package/dist/lib/canvas-grid.js +5 -0
  31. package/dist/markdown-editor/drag-handle.d.ts +6 -0
  32. package/dist/markdown-editor/drag-handle.js +126 -0
  33. package/dist/markdown-editor/suggestions.d.ts +12 -0
  34. package/dist/markdown-editor/suggestions.js +235 -0
  35. package/dist/markdown-editor/toolbar.js +6 -3
  36. package/dist/markdown-editor.js +14 -4
  37. package/dist/styles/index.css +6 -3
  38. package/dist/styles/recipes/chat-message-edit.css +105 -0
  39. package/dist/styles/recipes/flow.css +306 -0
  40. package/dist/styles/recipes/infinite-canvas.css +1 -1
  41. package/dist/styles/recipes/item.css +39 -2
  42. package/dist/styles/recipes/markdown-editor.css +44 -6
  43. package/dist/styles/recipes/morphing-panel.css +53 -12
  44. package/dist/styles/recipes/page-layout.css +11 -1
  45. package/dist/styles/recipes/resize-handle.css +126 -0
  46. package/dist/styles/recipes/sidebar-mobile.css +171 -0
  47. package/dist/styles/recipes/toolbar.css +8 -1
  48. package/dist/styles/theme.css +1 -0
  49. package/dist/ui/app-shell.js +1 -1
  50. package/dist/ui/color-picker.js +1 -1
  51. package/dist/ui/combobox.d.ts +1 -1
  52. package/dist/ui/command.js +1 -1
  53. package/dist/ui/dockable-panel.js +1 -1
  54. package/dist/ui/flow.d.ts +51 -0
  55. package/dist/ui/flow.js +153 -0
  56. package/dist/ui/infinite-canvas.js +3 -3
  57. package/dist/ui/item.d.ts +5 -3
  58. package/dist/ui/item.js +2 -1
  59. package/dist/ui/morphing-panel.d.ts +21 -4
  60. package/dist/ui/morphing-panel.js +152 -36
  61. package/dist/ui/resize-handle.d.ts +11 -0
  62. package/dist/ui/resize-handle.js +26 -0
  63. package/dist/ui/responsive-dialog.js +1 -1
  64. package/dist/ui/sidebar-menu.js +1 -1
  65. package/dist/ui/sidebar-mobile.d.ts +17 -0
  66. package/dist/ui/sidebar-mobile.js +70 -0
  67. package/dist/ui/sidebar-provider.d.ts +1 -0
  68. package/dist/ui/sidebar-provider.js +3 -0
  69. package/dist/ui/sidebar.d.ts +3 -1
  70. package/dist/ui/sidebar.js +100 -48
  71. package/dist/ui/toolbar.d.ts +3 -1
  72. package/dist/ui/toolbar.js +2 -1
  73. package/dist/ui/typography.d.ts +5 -2
  74. package/dist/ui/typography.js +5 -3
  75. package/package.json +5 -1
  76. package/dist/environment-variables.d.ts +0 -125
  77. package/dist/environment-variables.js +0 -512
  78. package/dist/hooks/use-environment-variables.d.ts +0 -50
  79. package/dist/hooks/use-environment-variables.js +0 -188
  80. package/dist/knob-contracts/environment-variables-knobs.d.ts +0 -4
  81. package/dist/knob-contracts/environment-variables-knobs.js +0 -12
  82. package/dist/lib/env-file.d.ts +0 -27
  83. package/dist/lib/env-file.js +0 -218
  84. package/dist/styles/recipes/environment-variables.css +0 -170
@@ -1,11 +1,13 @@
1
+ import { ButtonProps } from "./button.js";
1
2
  import { CollapsibleContentProps, CollapsibleProps, CollapsibleTriggerProps } from "./collapsible.js";
2
3
  import { MorphingPanelKnobStyle } from "../knob-contracts/morphing-panel-knobs.js";
3
- import { CSSProperties } from "react";
4
+ import { CSSProperties, ComponentProps } from "react";
4
5
  //#region src/ui/morphing-panel.d.ts
5
6
  export type MorphingPanelDimensions = {
6
7
  width: string;
7
8
  height: string;
8
9
  };
10
+ export type MorphingPanelAnchor = "center" | "top-start" | "top-end" | "bottom-start" | "bottom-end";
9
11
  export type MorphingPanelProps = Omit<CollapsibleProps, "style"> & {
10
12
  collapsedSize: MorphingPanelDimensions;
11
13
  expandedSize: MorphingPanelDimensions;
@@ -14,10 +16,25 @@ export type MorphingPanelProps = Omit<CollapsibleProps, "style"> & {
14
16
  export type MorphingPanelTriggerProps = Omit<CollapsibleTriggerProps, "style"> & {
15
17
  style?: CSSProperties & MorphingPanelKnobStyle;
16
18
  };
17
- export type MorphingPanelContentProps = Omit<CollapsibleContentProps, "style"> & {
19
+ export type MorphingPanelContentProps = Omit<CollapsibleContentProps, "style" | "autoFocus"> & {
20
+ /** Move focus into the surface on opening, for example for an inline confirmation. */
21
+ autoFocus?: boolean;
18
22
  style?: CSSProperties & MorphingPanelKnobStyle;
19
23
  };
20
- export declare function MorphingPanel({ collapsedSize, expandedSize, className, style, ...props }: MorphingPanelProps): import("react").JSX.Element;
24
+ export type MorphingPanelPositionerProps = ComponentProps<"div"> & {
25
+ anchor?: MorphingPanelAnchor;
26
+ };
27
+ export type MorphingPanelPartProps = ComponentProps<"div"> & {
28
+ style?: CSSProperties & MorphingPanelKnobStyle;
29
+ };
30
+ export type MorphingPanelCloseProps = ButtonProps;
31
+ /** Give this container a bounded area; the chosen edge stays fixed throughout resizing. */
32
+ export declare function MorphingPanelPositioner({ anchor, className, ...props }: MorphingPanelPositionerProps): import("react").JSX.Element;
33
+ export declare function MorphingPanel({ collapsedSize, expandedSize, open: openProp, defaultOpen, onOpenChange, onKeyDown, className, style, ...props }: MorphingPanelProps): import("react").JSX.Element;
21
34
  export declare function MorphingPanelTrigger({ render, className, children, ...props }: MorphingPanelTriggerProps): import("react").JSX.Element;
22
- export declare function MorphingPanelContent({ className, ...props }: MorphingPanelContentProps): import("react").JSX.Element;
35
+ export declare function MorphingPanelContent({ autoFocus, ...props }: MorphingPanelContentProps): import("react").JSX.Element;
36
+ export declare function MorphingPanelClose({ onClick, ...props }: MorphingPanelCloseProps): import("react").JSX.Element;
37
+ export declare function MorphingPanelHeader({ className, ...props }: MorphingPanelPartProps): import("react").JSX.Element;
38
+ export declare function MorphingPanelBody({ className, ...props }: MorphingPanelPartProps): import("react").JSX.Element;
39
+ export declare function MorphingPanelFooter({ className, ...props }: MorphingPanelPartProps): import("react").JSX.Element;
23
40
  //#endregion
@@ -1,27 +1,81 @@
1
1
  "use client";
2
2
  import { cn } from "../lib/cn.js";
3
+ import { Button } from "./button.js";
4
+ import { createContext, useContext, useEffect, useLayoutEffect, useRef, useState } from "react";
3
5
  import { useRender } from "@base-ui/react/use-render";
4
6
  import { jsx } from "react/jsx-runtime";
5
7
  import { Collapsible } from "@base-ui/react/collapsible";
6
8
  //#region src/ui/morphing-panel.tsx
9
+ const MorphingPanelContext = createContext(null);
10
+ function useMorphingPanel() {
11
+ const context = useContext(MorphingPanelContext);
12
+ if (!context) throw new Error("MorphingPanel parts must be rendered inside <MorphingPanel>.");
13
+ return context;
14
+ }
15
+ function createCloseDetails(reason, event, trigger) {
16
+ return {
17
+ reason,
18
+ event,
19
+ trigger,
20
+ isCanceled: false,
21
+ isPropagationAllowed: false,
22
+ cancel() {
23
+ this.isCanceled = true;
24
+ },
25
+ allowPropagation() {
26
+ this.isPropagationAllowed = true;
27
+ }
28
+ };
29
+ }
30
+ /** Give this container a bounded area; the chosen edge stays fixed throughout resizing. */
31
+ function MorphingPanelPositioner({ anchor = "center", className, ...props }) {
32
+ return /* @__PURE__ */ jsx("div", {
33
+ ...props,
34
+ "data-control-ui": "morphing-panel",
35
+ "data-control-family": "morphing-panel",
36
+ "data-slot": "positioner",
37
+ "data-anchor": anchor,
38
+ className: cn("grid min-h-0 min-w-0 grid-cols-[minmax(0,1fr)] grid-rows-[minmax(0,1fr)]", className)
39
+ });
40
+ }
7
41
  function MorphingPanelTriggerElement({ triggerProps, open, render, className, children }) {
8
- const panelState = open ? "open" : "closed";
42
+ const { triggerRef } = useMorphingPanel();
9
43
  return useRender({
10
44
  defaultTagName: "button",
11
45
  render,
46
+ ref: triggerRef,
12
47
  state: { open },
13
48
  props: {
14
49
  ...triggerProps,
15
50
  "data-control-ui": "morphing-panel",
16
51
  "data-control-family": "morphing-panel",
17
52
  "data-slot": "trigger",
18
- "data-state": panelState,
53
+ "data-state": open ? "open" : "closed",
19
54
  className: cn(triggerProps.className, className),
20
55
  children
21
56
  }
22
57
  });
23
58
  }
24
- function MorphingPanel({ collapsedSize, expandedSize, className, style, ...props }) {
59
+ function MorphingPanel({ collapsedSize, expandedSize, open: openProp, defaultOpen = false, onOpenChange, onKeyDown, className, style, ...props }) {
60
+ const [uncontrolledOpen, setUncontrolledOpen] = useState(defaultOpen);
61
+ const open = openProp ?? uncontrolledOpen;
62
+ const triggerRef = useRef(null);
63
+ const contentRef = useRef(null);
64
+ const wasOpen = useRef(open);
65
+ useLayoutEffect(() => {
66
+ const content = contentRef.current;
67
+ if (wasOpen.current && !open && content?.contains(content.ownerDocument.activeElement)) triggerRef.current?.focus({ preventScroll: true });
68
+ wasOpen.current = open;
69
+ }, [open]);
70
+ function changeOpen(nextOpen, details) {
71
+ onOpenChange?.(nextOpen, details);
72
+ if (!details.isCanceled && openProp === void 0) setUncontrolledOpen(nextOpen);
73
+ }
74
+ function close(reason, event) {
75
+ const details = createCloseDetails(reason, event, triggerRef.current ?? void 0);
76
+ if (open) changeOpen(false, details);
77
+ return details;
78
+ }
25
79
  const dimensions = {
26
80
  "--_morphing-panel-collapsed-height": collapsedSize.height,
27
81
  "--_morphing-panel-collapsed-width": collapsedSize.width,
@@ -29,29 +83,36 @@ function MorphingPanel({ collapsedSize, expandedSize, className, style, ...props
29
83
  "--_morphing-panel-expanded-width": expandedSize.width,
30
84
  ...style
31
85
  };
32
- return /* @__PURE__ */ jsx(Collapsible.Root, {
33
- className,
34
- style: dimensions,
35
- render: (renderProps, state) => {
36
- const panelState = state.open ? "open" : "closed";
37
- const panelSize = state.open ? "expanded" : "collapsed";
38
- const panelStyle = {
39
- ...renderProps.style,
40
- height: `var(--_morphing-panel-${panelSize}-height)`,
41
- width: `min(var(--_morphing-panel-${panelSize}-width), 100%)`
42
- };
43
- return /* @__PURE__ */ jsx("div", {
86
+ return /* @__PURE__ */ jsx(MorphingPanelContext.Provider, {
87
+ value: {
88
+ open,
89
+ triggerRef,
90
+ contentRef,
91
+ close
92
+ },
93
+ children: /* @__PURE__ */ jsx(Collapsible.Root, {
94
+ ...props,
95
+ open,
96
+ onOpenChange: changeOpen,
97
+ onKeyDown: (event) => {
98
+ onKeyDown?.(event);
99
+ if (event.defaultPrevented || event.key !== "Escape" || !open) return;
100
+ const details = close("escape-key", event.nativeEvent);
101
+ if (!details.isCanceled) event.preventDefault();
102
+ if (!details.isPropagationAllowed) event.stopPropagation();
103
+ },
104
+ className,
105
+ style: dimensions,
106
+ render: (renderProps, state) => /* @__PURE__ */ jsx("div", {
44
107
  ...renderProps,
45
108
  "data-control-ui": "morphing-panel",
46
109
  "data-control-family": "morphing-panel",
47
110
  "data-slot": "root",
48
- "data-state": panelState,
111
+ "data-state": state.open ? "open" : "closed",
49
112
  "data-surface": "panel",
50
- style: panelStyle,
51
- className: cn("relative isolate max-w-full overflow-hidden", renderProps.className)
52
- });
53
- },
54
- ...props
113
+ className: cn("relative isolate min-h-0 min-w-0 max-h-full max-w-full overflow-hidden", renderProps.className)
114
+ })
115
+ })
55
116
  });
56
117
  }
57
118
  function MorphingPanelTrigger({ render, className, children, ...props }) {
@@ -67,22 +128,77 @@ function MorphingPanelTrigger({ render, className, children, ...props }) {
67
128
  })
68
129
  });
69
130
  }
70
- function MorphingPanelContent({ className, ...props }) {
131
+ function MorphingPanelContentElement({ renderProps, open, autoFocus }) {
132
+ const { contentRef } = useMorphingPanel();
133
+ useEffect(() => {
134
+ if (open && autoFocus) contentRef.current?.focus({ preventScroll: true });
135
+ }, [
136
+ open,
137
+ autoFocus,
138
+ contentRef
139
+ ]);
140
+ return useRender({
141
+ defaultTagName: "div",
142
+ ref: contentRef,
143
+ props: {
144
+ ...renderProps,
145
+ tabIndex: renderProps.tabIndex ?? -1,
146
+ inert: !open || renderProps.inert,
147
+ "data-control-ui": "morphing-panel",
148
+ "data-control-family": "morphing-panel",
149
+ "data-slot": "content",
150
+ "data-state": open ? "open" : "closed",
151
+ className: cn("absolute inset-0 flex min-h-0 min-w-0 flex-col overflow-y-auto overscroll-contain", renderProps.className)
152
+ }
153
+ });
154
+ }
155
+ function MorphingPanelContent({ autoFocus = false, ...props }) {
71
156
  return /* @__PURE__ */ jsx(Collapsible.Panel, {
72
- className,
73
- render: (renderProps, state) => {
74
- const panelState = state.open ? "open" : "closed";
75
- return /* @__PURE__ */ jsx("div", {
76
- ...renderProps,
77
- "data-control-ui": "morphing-panel",
78
- "data-control-family": "morphing-panel",
79
- "data-slot": "content",
80
- "data-state": panelState,
81
- className: cn("absolute inset-0 overflow-hidden", renderProps.className)
82
- });
83
- },
84
- ...props
157
+ ...props,
158
+ render: (renderProps, state) => /* @__PURE__ */ jsx(MorphingPanelContentElement, {
159
+ renderProps,
160
+ open: state.open,
161
+ autoFocus
162
+ })
163
+ });
164
+ }
165
+ function MorphingPanelClose({ onClick, ...props }) {
166
+ const { close } = useMorphingPanel();
167
+ return /* @__PURE__ */ jsx(Button, {
168
+ ...props,
169
+ "data-morphing-panel-close": "",
170
+ onClick: (event) => {
171
+ onClick?.(event);
172
+ if (!event.defaultPrevented) close("close-press", event.nativeEvent);
173
+ }
174
+ });
175
+ }
176
+ function MorphingPanelHeader({ className, ...props }) {
177
+ return /* @__PURE__ */ jsx("div", {
178
+ ...props,
179
+ "data-control-ui": "morphing-panel",
180
+ "data-control-family": "morphing-panel",
181
+ "data-slot": "header",
182
+ className: cn("flex shrink-0 items-center", className)
183
+ });
184
+ }
185
+ function MorphingPanelBody({ className, ...props }) {
186
+ return /* @__PURE__ */ jsx("div", {
187
+ ...props,
188
+ "data-control-ui": "morphing-panel",
189
+ "data-control-family": "morphing-panel",
190
+ "data-slot": "body",
191
+ className: cn("min-h-0 min-w-0 flex-1 overflow-y-auto overscroll-contain", className)
192
+ });
193
+ }
194
+ function MorphingPanelFooter({ className, ...props }) {
195
+ return /* @__PURE__ */ jsx("div", {
196
+ ...props,
197
+ "data-control-ui": "morphing-panel",
198
+ "data-control-family": "morphing-panel",
199
+ "data-slot": "footer",
200
+ className: cn("flex shrink-0 flex-wrap items-center justify-end gap-2", className)
85
201
  });
86
202
  }
87
203
  //#endregion
88
- export { MorphingPanel, MorphingPanelContent, MorphingPanelTrigger };
204
+ export { MorphingPanel, MorphingPanelBody, MorphingPanelClose, MorphingPanelContent, MorphingPanelFooter, MorphingPanelHeader, MorphingPanelPositioner, MorphingPanelTrigger };
@@ -0,0 +1,11 @@
1
+ import { ResizeHandleKnobStyle } from "../knob-contracts/resize-handle-knobs.js";
2
+ import { CSSProperties, ComponentProps } from "react";
3
+ //#region src/ui/resize-handle.d.ts
4
+ export declare const resizeHandleDirections: readonly ["n", "ne", "e", "se", "s", "sw", "w", "nw"];
5
+ export type ResizeHandleDirection = (typeof resizeHandleDirections)[number];
6
+ export type ResizeHandleProps = Omit<ComponentProps<"button">, "style"> & {
7
+ direction: ResizeHandleDirection;
8
+ style?: CSSProperties & ResizeHandleKnobStyle;
9
+ };
10
+ export declare function ResizeHandle({ direction, className, ...props }: ResizeHandleProps): import("react").JSX.Element;
11
+ //#endregion
@@ -0,0 +1,26 @@
1
+ import { cn } from "../lib/cn.js";
2
+ import { jsx } from "react/jsx-runtime";
3
+ //#region src/ui/resize-handle.tsx
4
+ const resizeHandleDirections = [
5
+ "n",
6
+ "ne",
7
+ "e",
8
+ "se",
9
+ "s",
10
+ "sw",
11
+ "w",
12
+ "nw"
13
+ ];
14
+ function ResizeHandle({ direction, className, ...props }) {
15
+ return /* @__PURE__ */ jsx("button", {
16
+ type: "button",
17
+ "data-control-ui": "resize-handle",
18
+ "data-control-family": "resize-handle",
19
+ "data-slot": "root",
20
+ "data-direction": direction,
21
+ className: cn("absolute touch-none", className),
22
+ ...props
23
+ });
24
+ }
25
+ //#endregion
26
+ export { ResizeHandle, resizeHandleDirections };
@@ -2,8 +2,8 @@
2
2
  import { cn } from "../lib/cn.js";
3
3
  import { Button } from "./button.js";
4
4
  import { PopupCloseButton } from "../popup-parts.js";
5
- import { Dialog, DialogBody, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from "./dialog.js";
6
5
  import { Drawer, DrawerBody, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerTitle, DrawerTrigger } from "./drawer.js";
6
+ import { Dialog, DialogBody, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from "./dialog.js";
7
7
  import { createContext, useContext, useState, useSyncExternalStore } from "react";
8
8
  import { jsx, jsxs } from "react/jsx-runtime";
9
9
  //#region src/ui/responsive-dialog.tsx
@@ -2,8 +2,8 @@
2
2
  import { cn } from "../lib/cn.js";
3
3
  import { useSkin } from "../skin-provider.js";
4
4
  import { Tooltip, TooltipContent, TooltipTrigger } from "./tooltip.js";
5
- import { TrackHighlight } from "../extensions/track-highlight.js";
6
5
  import { SidebarSurfaceContext, useSidebar } from "./sidebar-provider.js";
6
+ import { TrackHighlight } from "../extensions/track-highlight.js";
7
7
  import { createContext, useContext, useRef, useState } from "react";
8
8
  import { useRender } from "@base-ui/react/use-render";
9
9
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -0,0 +1,17 @@
1
+ import { RenderProp } from "../control-props.js";
2
+ import { SidebarKnobStyle } from "../knob-contracts/sidebar-knobs.js";
3
+ import { SidebarMenuButtonProps } from "./sidebar-menu.js";
4
+ import { CSSProperties, ComponentProps } from "react";
5
+ //#region src/ui/sidebar-mobile.d.ts
6
+ export type SidebarMobileNavProps = Omit<ComponentProps<"nav">, "style"> & {
7
+ variant?: "bar" | "floating";
8
+ style?: CSSProperties & SidebarKnobStyle;
9
+ };
10
+ export declare function SidebarMobileNav({ variant, "aria-label": label, className, style, ...props }: SidebarMobileNavProps): import("react").JSX.Element;
11
+ export declare function SidebarMobileNavItem({ onClick, ...props }: SidebarMenuButtonProps): import("react").JSX.Element;
12
+ export type SidebarMobileTriggerProps = Omit<ComponentProps<"button">, "style"> & {
13
+ render?: RenderProp<ComponentProps<"button">>;
14
+ style?: CSSProperties & SidebarKnobStyle;
15
+ };
16
+ export declare function SidebarMobileTrigger({ render, children, onClick, ref, ...props }: SidebarMobileTriggerProps): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
17
+ //#endregion
@@ -0,0 +1,70 @@
1
+ "use client";
2
+ import { cn } from "../lib/cn.js";
3
+ import { useSidebar, useSidebarElements } from "./sidebar-provider.js";
4
+ import { SidebarMenuButton } from "./sidebar-menu.js";
5
+ import { useRender } from "@base-ui/react/use-render";
6
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
7
+ import { MenuIcon } from "lucide-react";
8
+ //#region src/ui/sidebar-mobile.tsx
9
+ function SidebarMobileNav({ variant = "bar", "aria-label": label = "Mobile navigation", className, style, ...props }) {
10
+ const { layout } = useSidebar();
11
+ return /* @__PURE__ */ jsx("div", {
12
+ "data-control-ui": "sidebar",
13
+ "data-control-family": "sidebar",
14
+ "data-slot": "mobile-nav-container",
15
+ "data-layout": layout,
16
+ "data-variant": variant,
17
+ className: "shrink-0 lg:hidden",
18
+ style,
19
+ children: /* @__PURE__ */ jsx("nav", {
20
+ ...props,
21
+ "aria-label": label,
22
+ "data-control-ui": "sidebar",
23
+ "data-control-family": "sidebar",
24
+ "data-slot": "mobile-nav",
25
+ "data-variant": variant,
26
+ className: cn("flex items-center", className)
27
+ })
28
+ });
29
+ }
30
+ function SidebarMobileNavItem({ onClick, ...props }) {
31
+ const { setOpenMobile } = useSidebar();
32
+ return /* @__PURE__ */ jsx(SidebarMenuButton, {
33
+ ...props,
34
+ "data-mobile-nav-item": "",
35
+ onClick: (event) => {
36
+ onClick?.(event);
37
+ if (!event.defaultPrevented) setOpenMobile(false);
38
+ }
39
+ });
40
+ }
41
+ function SidebarMobileTrigger({ render, children, onClick, ref, ...props }) {
42
+ const { openMobile, setOpenMobile, sidebarId } = useSidebar();
43
+ const { activeTriggerRef } = useSidebarElements();
44
+ return useRender({
45
+ defaultTagName: "button",
46
+ render,
47
+ ref,
48
+ props: {
49
+ type: "button",
50
+ ...props,
51
+ "data-control-ui": "sidebar",
52
+ "data-control-family": "sidebar",
53
+ "data-slot": "mobile-trigger",
54
+ "data-mobile-nav-item": "",
55
+ "data-sidebar-trigger": "",
56
+ "aria-haspopup": "dialog",
57
+ "aria-expanded": openMobile,
58
+ "aria-controls": openMobile ? sidebarId : void 0,
59
+ onClick: (event) => {
60
+ onClick?.(event);
61
+ if (event.defaultPrevented) return;
62
+ activeTriggerRef.current = event.currentTarget;
63
+ setOpenMobile(!openMobile);
64
+ },
65
+ children: children ?? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(MenuIcon, { "aria-hidden": "true" }), /* @__PURE__ */ jsx("span", { children: "Menu" })] })
66
+ }
67
+ });
68
+ }
69
+ //#endregion
70
+ export { SidebarMobileNav, SidebarMobileNavItem, SidebarMobileTrigger };
@@ -28,6 +28,7 @@ type SidebarElements = {
28
28
  offcanvasRef: RefObject<HTMLDivElement | null>;
29
29
  railRef: RefObject<HTMLElement | null>;
30
30
  triggerRef: RefObject<HTMLButtonElement | null>;
31
+ activeTriggerRef: RefObject<HTMLButtonElement | null>;
31
32
  insetRef: RefObject<HTMLElement | null>;
32
33
  };
33
34
  export declare const SidebarSurfaceContext: import("react").Context<{
@@ -42,16 +42,19 @@ function SidebarProvider({ defaultOpen = true, open: openProp, onOpenChange, def
42
42
  const skin = useSkin();
43
43
  const isMobile = useIsMobile(SIDEBAR_MOBILE_BREAKPOINT);
44
44
  const [openMobile, setOpenMobile] = useState(false);
45
+ if (!isMobile && openMobile) setOpenMobile(false);
45
46
  const wrapperRef = useRef(null);
46
47
  const offcanvasRef = useRef(null);
47
48
  const railRef = useRef(null);
48
49
  const triggerRef = useRef(null);
50
+ const activeTriggerRef = useRef(null);
49
51
  const insetRef = useRef(null);
50
52
  const elements = {
51
53
  wrapperRef,
52
54
  offcanvasRef,
53
55
  railRef,
54
56
  triggerRef,
57
+ activeTriggerRef,
55
58
  insetRef
56
59
  };
57
60
  const sidebarId = useId();
@@ -4,6 +4,7 @@ import { SidebarKnobStyle } from "../knob-contracts/sidebar-knobs.js";
4
4
  import { SidebarLayout } from "../skin.js";
5
5
  import { SidebarResizeRailProps } from "./sidebar-resize-rail.js";
6
6
  import { SidebarGroup, SidebarGroupContent, SidebarGroupContentProps, SidebarGroupLabel, SidebarGroupLabelProps, SidebarMenu, SidebarMenuAction, SidebarMenuActionProps, SidebarMenuBadge, SidebarMenuBadgeProps, SidebarMenuButton, SidebarMenuButtonProps, SidebarMenuButtonSize, SidebarMenuButtonVariant, SidebarMenuItem, SidebarMenuSub, SidebarSelectionIndicator, sidebarMenuButtonSizes, sidebarMenuButtonVariants } from "./sidebar-menu.js";
7
+ import { SidebarMobileNav, SidebarMobileNavItem, SidebarMobileNavProps, SidebarMobileTrigger, SidebarMobileTriggerProps } from "./sidebar-mobile.js";
7
8
  import { SidebarLayoutMode, SidebarProvider, SidebarProviderProps, SidebarStyle, useSidebar } from "./sidebar-provider.js";
8
9
  import { CSSProperties, ComponentProps } from "react";
9
10
  //#region src/ui/sidebar.d.ts
@@ -22,6 +23,7 @@ export type SidebarProps = Omit<ComponentProps<"div">, "style"> & {
22
23
  side?: "left" | "right";
23
24
  variant?: SidebarLayout;
24
25
  collapsible?: "offcanvas" | "icon" | "none";
26
+ mobileVariant?: "sheet" | "drawer";
25
27
  label?: string;
26
28
  style?: SidebarSurfaceStyle;
27
29
  };
@@ -39,4 +41,4 @@ export declare function SidebarFooter({ className, ...props }: ComponentProps<"d
39
41
  }): import("react").JSX.Element;
40
42
  export declare function SidebarContent({ className, children, ...props }: ComponentProps<"div">): import("react").JSX.Element;
41
43
  //#endregion
42
- export { SidebarGroup, SidebarGroupContent, type SidebarGroupContentProps, SidebarGroupLabel, type SidebarGroupLabelProps, type SidebarLayoutMode, SidebarMenu, SidebarMenuAction, type SidebarMenuActionProps, SidebarMenuBadge, type SidebarMenuBadgeProps, SidebarMenuButton, type SidebarMenuButtonProps, type SidebarMenuButtonSize, type SidebarMenuButtonVariant, SidebarMenuItem, SidebarMenuSub, SidebarProvider, type SidebarProviderProps, type SidebarSelectionIndicator, type SidebarStyle, sidebarMenuButtonSizes, sidebarMenuButtonVariants, useSidebar };
44
+ export { SidebarGroup, SidebarGroupContent, type SidebarGroupContentProps, SidebarGroupLabel, type SidebarGroupLabelProps, type SidebarLayoutMode, SidebarMenu, SidebarMenuAction, type SidebarMenuActionProps, SidebarMenuBadge, type SidebarMenuBadgeProps, SidebarMenuButton, type SidebarMenuButtonProps, type SidebarMenuButtonSize, type SidebarMenuButtonVariant, SidebarMenuItem, SidebarMenuSub, SidebarMobileNav, SidebarMobileNavItem, type SidebarMobileNavProps, SidebarMobileTrigger, type SidebarMobileTriggerProps, SidebarProvider, type SidebarProviderProps, type SidebarSelectionIndicator, type SidebarStyle, sidebarMenuButtonSizes, sidebarMenuButtonVariants, useSidebar };