Skip to content

Commit 555651b

Browse files
committed
feat: add menubar component
1 parent c700f91 commit 555651b

File tree

10 files changed

+476
-145
lines changed

10 files changed

+476
-145
lines changed

apps/docs/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
},
1414
"dependencies": {
1515
"@fontsource/inter": "^5.0.16",
16-
"@kobalte/core": "^0.11.2",
16+
"@kobalte/core": "^0.12.1",
1717
"@modular-forms/solid": "^0.20.0",
1818
"@solid-primitives/keyboard": "^1.2.5",
1919
"@solidjs/meta": "^0.28.6",

apps/docs/public/registry/index.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,13 @@
215215
],
216216
"type": "ui"
217217
},
218+
{
219+
"name": "menubar",
220+
"files": [
221+
"ui/menubar.tsx"
222+
],
223+
"type": "ui"
224+
},
218225
{
219226
"name": "pagination",
220227
"dependencies": [
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"name": "menubar",
3+
"files": [
4+
{
5+
"name": "menubar.tsx",
6+
"content": "import type { Component, ComponentProps } from \"solid-js\"\nimport { splitProps } from \"solid-js\"\n\nimport { Menubar as MenubarPrimitive } from \"@kobalte/core\"\nimport { TbCheck, TbChevronRight, TbCircle } from \"solid-icons/tb\"\n\nimport { cn } from \"~/lib/utils\"\n\nconst MenubarMenu: Component<MenubarPrimitive.MenubarMenuProps> = (props) => {\n return <MenubarPrimitive.Menu gutter={8} {...props} />\n}\n\nconst MenubarGroup = MenubarPrimitive.Group\n\nconst MenubarPortal = MenubarPrimitive.Portal\n\nconst MenubarSub = MenubarPrimitive.Sub\n\nconst MenubarRadioGroup = MenubarPrimitive.RadioGroup\n\nconst Menubar: Component<MenubarPrimitive.MenubarRootProps> = (props) => {\n const [, rest] = splitProps(props, [\"class\"])\n return (\n <MenubarPrimitive.Root\n class={cn(\n \"bg-background flex h-10 items-center space-x-1 rounded-md border p-1\",\n props.class\n )}\n {...rest}\n ></MenubarPrimitive.Root>\n )\n}\n\nconst MenubarTrigger: Component<MenubarPrimitive.MenubarTriggerProps> = (props) => {\n const [, rest] = splitProps(props, [\"class\"])\n return (\n <MenubarPrimitive.Trigger\n class={cn(\n \"focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex cursor-default select-none items-center rounded-sm px-3 py-1.5 text-sm font-medium outline-none\",\n props.class\n )}\n {...rest}\n />\n )\n}\n\nconst MenubarContent: Component<MenubarPrimitive.MenubarContentProps> = (props) => {\n const [, rest] = splitProps(props, [\"class\"])\n return (\n <MenubarPrimitive.Portal>\n <MenubarPrimitive.Content\n class={cn(\n \"bg-popover text-popover-foreground animate-content-hide data-[expanded]:animate-content-show z-50 min-w-[12rem] origin-[var(--kb-menu-content-transform-origin)] overflow-hidden rounded-md border p-1 shadow-md\",\n props.class\n )}\n {...rest}\n />\n </MenubarPrimitive.Portal>\n )\n}\n\nconst MenubarSubTrigger: Component<\n MenubarPrimitive.MenubarSubTriggerProps & { inset?: boolean }\n> = (props) => {\n const [, rest] = splitProps(props, [\"class\", \"children\", \"inset\"])\n return (\n <MenubarPrimitive.SubTrigger\n class={cn(\n \"focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none\",\n props.inset && \"pl-8\",\n props.class\n )}\n {...rest}\n >\n {props.children}\n <TbChevronRight class=\"ml-auto h-4 w-4\" />\n </MenubarPrimitive.SubTrigger>\n )\n}\n\nconst MenubarSubContent: Component<MenubarPrimitive.MenubarSubContentProps> = (props) => {\n const [, rest] = splitProps(props, [\"class\"])\n return (\n <MenubarPrimitive.SubContent\n class={cn(\n \"bg-popover text-popover-foreground animate-in z-50 min-w-[8rem] origin-[var(--kb-menu-content-transform-origin)] overflow-hidden rounded-md border p-1 shadow-md\",\n props.class\n )}\n {...rest}\n />\n )\n}\n\nconst MenubarItem: Component<MenubarPrimitive.MenubarItemProps & { inset?: boolean }> = (props) => {\n const [, rest] = splitProps(props, [\"class\", \"inset\"])\n return (\n <MenubarPrimitive.Item\n class={cn(\n \"focus:bg-accent focus:text-accent-foreground relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n props.inset && \"pl-8\",\n props.class\n )}\n {...rest}\n />\n )\n}\n\nconst MenubarCheckboxItem: Component<MenubarPrimitive.MenubarCheckboxItemProps> = (props) => {\n const [, rest] = splitProps(props, [\"class\", \"children\"])\n return (\n <MenubarPrimitive.CheckboxItem\n class={cn(\n \"focus:bg-accent focus:text-accent-foreground relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n props.class\n )}\n {...rest}\n >\n <span class=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n <MenubarPrimitive.ItemIndicator>\n <TbCheck class=\"h-4 w-4\" />\n </MenubarPrimitive.ItemIndicator>\n </span>\n {props.children}\n </MenubarPrimitive.CheckboxItem>\n )\n}\n\nconst MenubarRadioItem: Component<MenubarPrimitive.MenubarRadioItemProps> = (props) => {\n const [, rest] = splitProps(props, [\"class\", \"children\"])\n return (\n <MenubarPrimitive.RadioItem\n class={cn(\n \"focus:bg-accent focus:text-accent-foreground relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n props.class\n )}\n {...rest}\n >\n <span class=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n <MenubarPrimitive.ItemIndicator>\n <TbCircle class=\"h-2 w-2 fill-current\" />\n </MenubarPrimitive.ItemIndicator>\n </span>\n {props.children}\n </MenubarPrimitive.RadioItem>\n )\n}\n\nconst MenubarItemLabel: Component<MenubarPrimitive.MenubarItemLabelProps & { inset?: boolean }> = (\n props\n) => {\n const [, rest] = splitProps(props, [\"class\", \"inset\"])\n return (\n <MenubarPrimitive.ItemLabel\n class={cn(\"px-2 py-1.5 text-sm font-semibold\", props.inset && \"pl-8\", props.class)}\n {...rest}\n />\n )\n}\n\nconst MenubarGroupLabel: Component<\n MenubarPrimitive.MenubarGroupLabelProps & { inset?: boolean }\n> = (props) => {\n const [, rest] = splitProps(props, [\"class\", \"inset\"])\n return (\n <MenubarPrimitive.GroupLabel\n class={cn(\"px-2 py-1.5 text-sm font-semibold\", props.inset && \"pl-8\", props.class)}\n {...rest}\n />\n )\n}\n\nconst MenubarSeparator: Component<MenubarPrimitive.MenubarSeparatorProps> = (props) => {\n const [, rest] = splitProps(props, [\"class\"])\n return (\n <MenubarPrimitive.Separator class={cn(\"bg-muted -mx-1 my-1 h-px\", props.class)} {...rest} />\n )\n}\n\nconst MenubarShortcut: Component<ComponentProps<\"span\">> = (props) => {\n const [, rest] = splitProps(props, [\"class\"])\n return (\n <span\n class={cn(\"text-muted-foreground ml-auto text-xs tracking-widest\", props.class)}\n {...rest}\n />\n )\n}\n\nexport {\n Menubar,\n MenubarMenu,\n MenubarTrigger,\n MenubarContent,\n MenubarItem,\n MenubarSeparator,\n MenubarItemLabel,\n MenubarGroupLabel,\n MenubarCheckboxItem,\n MenubarRadioGroup,\n MenubarRadioItem,\n MenubarPortal,\n MenubarSubContent,\n MenubarSubTrigger,\n MenubarGroup,\n MenubarSub,\n MenubarShortcut\n}\n"
7+
}
8+
],
9+
"type": "ui"
10+
}

apps/docs/src/__registry__/index.tsx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,13 @@ export const Index: Record<string, any> = {
167167
component: lazy(() => import("~/registry/ui/label")),
168168
files: ["registry/ui/label.tsx"],
169169
},
170+
"menubar": {
171+
name: "menubar",
172+
type: "ui",
173+
registryDependencies: undefined,
174+
component: lazy(() => import("~/registry/ui/menubar")),
175+
files: ["registry/ui/menubar.tsx"],
176+
},
170177
"pagination": {
171178
name: "pagination",
172179
type: "ui",
@@ -461,6 +468,13 @@ export const Index: Record<string, any> = {
461468
component: lazy(() => import("~/registry/example/input-demo")),
462469
files: ["registry/example/input-demo.tsx"],
463470
},
471+
"menubar-demo": {
472+
name: "menubar-demo",
473+
type: "example",
474+
registryDependencies: undefined,
475+
component: lazy(() => import("~/registry/example/menubar-demo")),
476+
files: ["registry/example/menubar-demo.tsx"],
477+
},
464478
"pagination-demo": {
465479
name: "pagination-demo",
466480
type: "example",

apps/docs/src/config/docs.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,10 @@ export const docsConfig: Config = {
160160
title: "Label",
161161
href: "/docs/components/label"
162162
},
163+
{
164+
title: "Menubar",
165+
href: "/docs/components/menubar"
166+
},
163167
{
164168
title: "Pagination",
165169
href: "/docs/components/pagination"
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import {
2+
Menubar,
3+
MenubarCheckboxItem,
4+
MenubarContent,
5+
MenubarItem,
6+
MenubarMenu,
7+
MenubarRadioGroup,
8+
MenubarRadioItem,
9+
MenubarSeparator,
10+
MenubarShortcut,
11+
MenubarSub,
12+
MenubarSubContent,
13+
MenubarSubTrigger,
14+
MenubarTrigger
15+
} from "~/registry/ui/menubar"
16+
17+
export default function MenubarDemo() {
18+
return (
19+
<Menubar>
20+
<MenubarMenu>
21+
<MenubarTrigger>File</MenubarTrigger>
22+
<MenubarContent>
23+
<MenubarItem>
24+
New Tab <MenubarShortcut>⌘T</MenubarShortcut>
25+
</MenubarItem>
26+
<MenubarItem>
27+
New Window <MenubarShortcut>⌘N</MenubarShortcut>
28+
</MenubarItem>
29+
<MenubarItem disabled>New Incognito Window</MenubarItem>
30+
<MenubarSeparator />
31+
<MenubarSub>
32+
<MenubarSubTrigger>Share</MenubarSubTrigger>
33+
<MenubarSubContent>
34+
<MenubarItem>Email link</MenubarItem>
35+
<MenubarItem>Messages</MenubarItem>
36+
<MenubarItem>Notes</MenubarItem>
37+
</MenubarSubContent>
38+
</MenubarSub>
39+
<MenubarSeparator />
40+
<MenubarItem>
41+
Print... <MenubarShortcut>⌘P</MenubarShortcut>
42+
</MenubarItem>
43+
</MenubarContent>
44+
</MenubarMenu>
45+
<MenubarMenu>
46+
<MenubarTrigger>Edit</MenubarTrigger>
47+
<MenubarContent>
48+
<MenubarItem>
49+
Undo <MenubarShortcut>⌘Z</MenubarShortcut>
50+
</MenubarItem>
51+
<MenubarItem>
52+
Redo <MenubarShortcut>⇧⌘Z</MenubarShortcut>
53+
</MenubarItem>
54+
<MenubarSeparator />
55+
<MenubarSub>
56+
<MenubarSubTrigger>Find</MenubarSubTrigger>
57+
<MenubarSubContent>
58+
<MenubarItem>Search the web</MenubarItem>
59+
<MenubarSeparator />
60+
<MenubarItem>Find...</MenubarItem>
61+
<MenubarItem>Find Next</MenubarItem>
62+
<MenubarItem>Find Previous</MenubarItem>
63+
</MenubarSubContent>
64+
</MenubarSub>
65+
<MenubarSeparator />
66+
<MenubarItem>Cut</MenubarItem>
67+
<MenubarItem>Copy</MenubarItem>
68+
<MenubarItem>Paste</MenubarItem>
69+
</MenubarContent>
70+
</MenubarMenu>
71+
<MenubarMenu>
72+
<MenubarTrigger>View</MenubarTrigger>
73+
<MenubarContent>
74+
<MenubarCheckboxItem>Always Show Bookmarks Bar</MenubarCheckboxItem>
75+
<MenubarCheckboxItem checked>Always Show Full URLs</MenubarCheckboxItem>
76+
<MenubarSeparator />
77+
<MenubarItem inset>
78+
Reload <MenubarShortcut>⌘R</MenubarShortcut>
79+
</MenubarItem>
80+
<MenubarItem disabled inset>
81+
Force Reload <MenubarShortcut>⇧⌘R</MenubarShortcut>
82+
</MenubarItem>
83+
<MenubarSeparator />
84+
<MenubarItem inset>Toggle Fullscreen</MenubarItem>
85+
<MenubarSeparator />
86+
<MenubarItem inset>Hide Sidebar</MenubarItem>
87+
</MenubarContent>
88+
</MenubarMenu>
89+
<MenubarMenu>
90+
<MenubarTrigger>Profiles</MenubarTrigger>
91+
<MenubarContent>
92+
<MenubarRadioGroup value="benoit">
93+
<MenubarRadioItem value="andy">Andy</MenubarRadioItem>
94+
<MenubarRadioItem value="benoit">Benoit</MenubarRadioItem>
95+
<MenubarRadioItem value="Luis">Luis</MenubarRadioItem>
96+
</MenubarRadioGroup>
97+
<MenubarSeparator />
98+
<MenubarItem inset>Edit...</MenubarItem>
99+
<MenubarSeparator />
100+
<MenubarItem inset>Add Profile...</MenubarItem>
101+
</MenubarContent>
102+
</MenubarMenu>
103+
</Menubar>
104+
)
105+
}

apps/docs/src/registry/registry.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,11 @@ const ui: Registry = [
132132
type: "ui",
133133
files: ["ui/label.tsx"]
134134
},
135+
{
136+
name: "menubar",
137+
type: "ui",
138+
files: ["ui/menubar.tsx"]
139+
},
135140
{
136141
name: "pagination",
137142
type: "ui",
@@ -368,6 +373,11 @@ const examples: Registry = [
368373
type: "example",
369374
files: ["example/input-demo.tsx"]
370375
},
376+
{
377+
name: "menubar-demo",
378+
type: "example",
379+
files: ["example/menubar-demo.tsx"]
380+
},
371381
{
372382
name: "pagination-demo",
373383
type: "example",

0 commit comments

Comments
 (0)