@ctrl-ui/react 0.8.18 → 0.8.20
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 +7 -0
- package/dist/action-bar.js +2 -2
- package/dist/audio-device-select.js +5 -2
- package/dist/blocks/coding-agent.js +22 -12
- package/dist/blocks/design-canvas-inspector.js +6 -3
- package/dist/blocks/design-canvas.js +20 -10
- package/dist/blocks/discussion-markdown-input.d.ts +14 -0
- package/dist/blocks/discussion-markdown-input.js +36 -0
- package/dist/blocks/discussion.d.ts +9 -3
- package/dist/blocks/discussion.js +82 -16
- package/dist/blocks/file-explorer.js +46 -24
- package/dist/blocks/settings.js +10 -6
- package/dist/chat-composer-editor/extensions/mention.d.ts +1 -1
- package/dist/chat-message.d.ts +13 -0
- package/dist/chat-message.js +198 -3
- package/dist/filter-bar/editor.js +5 -2
- package/dist/knob-contracts/flow-knobs.d.ts +4 -0
- package/dist/knob-contracts/flow-knobs.js +32 -0
- package/dist/knob-contracts/item-knobs.d.ts +1 -1
- package/dist/knob-contracts/item-knobs.js +4 -1
- package/dist/knob-contracts/label-knobs.d.ts +4 -0
- package/dist/knob-contracts/label-knobs.js +4 -0
- package/dist/knob-contracts/markdown-editor-knobs.d.ts +4 -0
- package/dist/knob-contracts/markdown-editor-knobs.js +17 -0
- package/dist/knob-contracts/morphing-panel-knobs.d.ts +1 -1
- package/dist/knob-contracts/morphing-panel-knobs.js +2 -1
- package/dist/knob-contracts/resize-handle-knobs.d.ts +4 -0
- package/dist/knob-contracts/resize-handle-knobs.js +12 -0
- package/dist/knob-contracts/sidebar-knobs.d.ts +1 -1
- package/dist/knob-contracts/sidebar-knobs.js +10 -0
- package/dist/knob-contracts/switch-knobs.d.ts +1 -1
- package/dist/knob-contracts/switch-knobs.js +1 -0
- package/dist/lib/canvas-grid.d.ts +4 -0
- package/dist/lib/canvas-grid.js +5 -0
- package/dist/markdown-editor/context.d.ts +22 -0
- package/dist/markdown-editor/context.js +10 -0
- package/dist/markdown-editor/drag-handle.d.ts +6 -0
- package/dist/markdown-editor/drag-handle.js +126 -0
- package/dist/markdown-editor/extensions.d.ts +10 -0
- package/dist/markdown-editor/extensions.js +139 -0
- package/dist/markdown-editor/suggestions.d.ts +12 -0
- package/dist/markdown-editor/suggestions.js +235 -0
- package/dist/markdown-editor/toolbar.d.ts +9 -0
- package/dist/markdown-editor/toolbar.js +339 -0
- package/dist/markdown-editor/uploads.d.ts +23 -0
- package/dist/markdown-editor/uploads.js +32 -0
- package/dist/markdown-editor/use-image-uploads.d.ts +12 -0
- package/dist/markdown-editor/use-image-uploads.js +120 -0
- package/dist/markdown-editor.d.ts +27 -0
- package/dist/markdown-editor.js +202 -0
- package/dist/styles/index.css +9 -4
- package/dist/styles/recipes/chat-message-edit.css +105 -0
- package/dist/styles/recipes/code.css +4 -0
- package/dist/styles/recipes/field.css +1 -1
- package/dist/styles/recipes/flow.css +304 -0
- package/dist/styles/recipes/infinite-canvas.css +1 -1
- package/dist/styles/recipes/item.css +39 -2
- package/dist/styles/recipes/label.css +19 -0
- package/dist/styles/recipes/markdown-editor.css +234 -0
- package/dist/styles/recipes/morphing-panel.css +53 -12
- package/dist/styles/recipes/page-layout.css +11 -1
- package/dist/styles/recipes/resize-handle.css +126 -0
- package/dist/styles/recipes/sidebar-mobile.css +171 -0
- package/dist/styles/recipes/switch.css +17 -5
- package/dist/styles/recipes/toolbar.css +8 -1
- package/dist/styles/theme.css +1 -0
- package/dist/ui/autocomplete.js +1 -1
- package/dist/ui/code.js +1 -0
- package/dist/ui/color-picker.js +1 -1
- package/dist/ui/combobox.d.ts +1 -1
- package/dist/ui/combobox.js +1 -1
- package/dist/ui/dockable-panel.js +1 -1
- package/dist/ui/flow.d.ts +51 -0
- package/dist/ui/flow.js +153 -0
- package/dist/ui/infinite-canvas.js +3 -3
- package/dist/ui/item.d.ts +5 -3
- package/dist/ui/item.js +2 -1
- package/dist/ui/label.d.ts +8 -0
- package/dist/ui/label.js +14 -0
- package/dist/ui/markdown.d.ts +2 -1
- package/dist/ui/markdown.js +3 -3
- package/dist/ui/morphing-panel.d.ts +21 -4
- package/dist/ui/morphing-panel.js +152 -36
- package/dist/ui/resize-handle.d.ts +11 -0
- package/dist/ui/resize-handle.js +26 -0
- package/dist/ui/sidebar-mobile.d.ts +17 -0
- package/dist/ui/sidebar-mobile.js +70 -0
- package/dist/ui/sidebar-provider.d.ts +1 -0
- package/dist/ui/sidebar-provider.js +3 -0
- package/dist/ui/sidebar.d.ts +3 -1
- package/dist/ui/sidebar.js +101 -49
- package/dist/ui/toolbar.d.ts +3 -1
- package/dist/ui/toolbar.js +2 -1
- package/dist/ui/typography.d.ts +47 -0
- package/dist/ui/typography.js +61 -0
- package/dist/ui/use-switch-drag.js +1 -1
- package/package.json +41 -1
- package/dist/environment-variables.d.ts +0 -125
- package/dist/environment-variables.js +0 -512
- package/dist/hooks/use-environment-variables.d.ts +0 -50
- package/dist/hooks/use-environment-variables.js +0 -188
- package/dist/knob-contracts/environment-variables-knobs.d.ts +0 -4
- package/dist/knob-contracts/environment-variables-knobs.js +0 -12
- package/dist/lib/env-file.d.ts +0 -27
- package/dist/lib/env-file.js +0 -218
- 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
|
|
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({
|
|
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
|
|
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":
|
|
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(
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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":
|
|
111
|
+
"data-state": state.open ? "open" : "closed",
|
|
49
112
|
"data-surface": "panel",
|
|
50
|
-
|
|
51
|
-
|
|
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
|
|
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
|
-
|
|
73
|
-
render: (renderProps, state) => {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
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 };
|
|
@@ -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();
|
package/dist/ui/sidebar.d.ts
CHANGED
|
@@ -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 };
|