返回 presentation-ai
menubar.tsx
根目录 / src / components / ui / menubar.tsx
1 "use client";
2
3 import * as MenubarPrimitive from "@radix-ui/react-menubar";
4 import { Check, ChevronRight, Circle } from "lucide-react";
5 import * as React from "react";
6
7 import { cn } from "@/lib/utils";
8
9 function MenubarMenu({
10 ...props
11 }: React.ComponentProps<typeof MenubarPrimitive.Menu>) {
12 return <MenubarPrimitive.Menu {...props} />;
13 }
14
15 function MenubarGroup({
16 ...props
17 }: React.ComponentProps<typeof MenubarPrimitive.Group>) {
18 return <MenubarPrimitive.Group {...props} />;
19 }
20
21 function MenubarPortal({
22 ...props
23 }: React.ComponentProps<typeof MenubarPrimitive.Portal>) {
24 return <MenubarPrimitive.Portal {...props} />;
25 }
26
27 function MenubarRadioGroup({
28 ...props
29 }: React.ComponentProps<typeof MenubarPrimitive.RadioGroup>) {
30 return <MenubarPrimitive.RadioGroup {...props} />;
31 }
32
33 function MenubarSub({
34 ...props
35 }: React.ComponentProps<typeof MenubarPrimitive.Sub>) {
36 return <MenubarPrimitive.Sub data-slot="menubar-sub" {...props} />;
37 }
38
39 const Menubar = React.forwardRef<
40 React.ElementRef<typeof MenubarPrimitive.Root>,
41 React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Root>
42 >(({ className, ...props }, ref) => (
43 <MenubarPrimitive.Root
44 ref={ref}
45 className={cn(
46 "flex h-10 items-center space-x-1 rounded-md border bg-background p-1",
47 className,
48 )}
49 {...props}
50 />
51 ));
52 Menubar.displayName = MenubarPrimitive.Root.displayName;
53
54 const MenubarTrigger = React.forwardRef<
55 React.ElementRef<typeof MenubarPrimitive.Trigger>,
56 React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Trigger>
57 >(({ className, ...props }, ref) => (
58 <MenubarPrimitive.Trigger
59 ref={ref}
60 className={cn(
61 "flex cursor-default items-center rounded-sm px-3 py-1.5 text-sm font-medium outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground",
62 className,
63 )}
64 {...props}
65 />
66 ));
67 MenubarTrigger.displayName = MenubarPrimitive.Trigger.displayName;
68
69 const MenubarSubTrigger = React.forwardRef<
70 React.ElementRef<typeof MenubarPrimitive.SubTrigger>,
71 React.ComponentPropsWithoutRef<typeof MenubarPrimitive.SubTrigger> & {
72 inset?: boolean;
73 }
74 >(({ className, inset, children, ...props }, ref) => (
75 <MenubarPrimitive.SubTrigger
76 ref={ref}
77 className={cn(
78 "flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground",
79 inset && "pl-8",
80 className,
81 )}
82 {...props}
83 >
84 {children}
85 <ChevronRight className="ml-auto h-4 w-4" />
86 </MenubarPrimitive.SubTrigger>
87 ));
88 MenubarSubTrigger.displayName = MenubarPrimitive.SubTrigger.displayName;
89
90 const MenubarSubContent = React.forwardRef<
91 React.ElementRef<typeof MenubarPrimitive.SubContent>,
92 React.ComponentPropsWithoutRef<typeof MenubarPrimitive.SubContent>
93 >(({ className, ...props }, ref) => (
94 <MenubarPrimitive.SubContent
95 ref={ref}
96 className={cn(
97 "z-50 min-w-32 origin-(--radix-menubar-content-transform-origin) overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
98 className,
99 )}
100 {...props}
101 />
102 ));
103 MenubarSubContent.displayName = MenubarPrimitive.SubContent.displayName;
104
105 const MenubarContent = React.forwardRef<
106 React.ElementRef<typeof MenubarPrimitive.Content>,
107 React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Content>
108 >(
109 (
110 { className, align = "start", alignOffset = -4, sideOffset = 8, ...props },
111 ref,
112 ) => (
113 <MenubarPrimitive.Portal>
114 <MenubarPrimitive.Content
115 ref={ref}
116 align={align}
117 alignOffset={alignOffset}
118 sideOffset={sideOffset}
119 className={cn(
120 "z-50 min-w-48 origin-(--radix-menubar-content-transform-origin) overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
121 className,
122 )}
123 {...props}
124 />
125 </MenubarPrimitive.Portal>
126 ),
127 );
128 MenubarContent.displayName = MenubarPrimitive.Content.displayName;
129
130 const MenubarItem = React.forwardRef<
131 React.ElementRef<typeof MenubarPrimitive.Item>,
132 React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Item> & {
133 inset?: boolean;
134 }
135 >(({ className, inset, ...props }, ref) => (
136 <MenubarPrimitive.Item
137 ref={ref}
138 className={cn(
139 "relative flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50",
140 inset && "pl-8",
141 className,
142 )}
143 {...props}
144 />
145 ));
146 MenubarItem.displayName = MenubarPrimitive.Item.displayName;
147
148 const MenubarCheckboxItem = React.forwardRef<
149 React.ElementRef<typeof MenubarPrimitive.CheckboxItem>,
150 React.ComponentPropsWithoutRef<typeof MenubarPrimitive.CheckboxItem>
151 >(({ className, children, checked, ...props }, ref) => (
152 <MenubarPrimitive.CheckboxItem
153 ref={ref}
154 className={cn(
155 "relative flex cursor-default items-center rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50",
156 className,
157 )}
158 checked={checked}
159 {...props}
160 >
161 <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
162 <MenubarPrimitive.ItemIndicator>
163 <Check className="h-4 w-4" />
164 </MenubarPrimitive.ItemIndicator>
165 </span>
166 {children}
167 </MenubarPrimitive.CheckboxItem>
168 ));
169 MenubarCheckboxItem.displayName = MenubarPrimitive.CheckboxItem.displayName;
170
171 const MenubarRadioItem = React.forwardRef<
172 React.ElementRef<typeof MenubarPrimitive.RadioItem>,
173 React.ComponentPropsWithoutRef<typeof MenubarPrimitive.RadioItem>
174 >(({ className, children, ...props }, ref) => (
175 <MenubarPrimitive.RadioItem
176 ref={ref}
177 className={cn(
178 "relative flex cursor-default items-center rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50",
179 className,
180 )}
181 {...props}
182 >
183 <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
184 <MenubarPrimitive.ItemIndicator>
185 <Circle className="h-2 w-2 fill-current" />
186 </MenubarPrimitive.ItemIndicator>
187 </span>
188 {children}
189 </MenubarPrimitive.RadioItem>
190 ));
191 MenubarRadioItem.displayName = MenubarPrimitive.RadioItem.displayName;
192
193 const MenubarLabel = React.forwardRef<
194 React.ElementRef<typeof MenubarPrimitive.Label>,
195 React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Label> & {
196 inset?: boolean;
197 }
198 >(({ className, inset, ...props }, ref) => (
199 <MenubarPrimitive.Label
200 ref={ref}
201 className={cn(
202 "px-2 py-1.5 text-sm font-semibold",
203 inset && "pl-8",
204 className,
205 )}
206 {...props}
207 />
208 ));
209 MenubarLabel.displayName = MenubarPrimitive.Label.displayName;
210
211 const MenubarSeparator = React.forwardRef<
212 React.ElementRef<typeof MenubarPrimitive.Separator>,
213 React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Separator>
214 >(({ className, ...props }, ref) => (
215 <MenubarPrimitive.Separator
216 ref={ref}
217 className={cn("-mx-1 my-1 h-px bg-muted", className)}
218 {...props}
219 />
220 ));
221 MenubarSeparator.displayName = MenubarPrimitive.Separator.displayName;
222
223 const MenubarShortcut = ({
224 className,
225 ...props
226 }: React.HTMLAttributes<HTMLSpanElement>) => {
227 return (
228 <span
229 className={cn(
230 "ml-auto text-xs tracking-widest text-muted-foreground",
231 className,
232 )}
233 {...props}
234 />
235 );
236 };
237 MenubarShortcut.displayname = "MenubarShortcut";
238
239 export {
240 Menubar,
241 MenubarCheckboxItem,
242 MenubarContent,
243 MenubarGroup,
244 MenubarItem,
245 MenubarLabel,
246 MenubarMenu,
247 MenubarPortal,
248 MenubarRadioGroup,
249 MenubarRadioItem,
250 MenubarSeparator,
251 MenubarShortcut,
252 MenubarSub,
253 MenubarSubContent,
254 MenubarSubTrigger,
255 MenubarTrigger,
256 };
257
257 lines Plain Text