@nucleux/menubar 0.2.0
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/LICENSE +21 -0
- package/README.md +26 -0
- package/dist/index.cjs +165 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +27 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.js +138 -0
- package/dist/index.js.map +1 -0
- package/package.json +58 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Nucleux
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# @nucleux/menubar
|
|
2
|
+
|
|
3
|
+
Application menu bar — Nucleux agentic UI for React.
|
|
4
|
+
|
|
5
|
+
Part of **[Nucleux](https://github.com/intelligaia-open-labs/nucleux)** — agentic UI components for React. Install a single component, or the full kit via [`@nucleux/react`](https://www.npmjs.com/package/@nucleux/react).
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pnpm add @nucleux/menubar @nucleux/tokens
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
`react` / `react-dom` are peer dependencies.
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import { Menubar } from "@nucleux/menubar";
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Requires the theme once in your app: `import "@nucleux/tokens/styles.css";`
|
|
22
|
+
and the Tailwind preset from `@nucleux/tokens/preset`.
|
|
23
|
+
|
|
24
|
+
## License
|
|
25
|
+
|
|
26
|
+
MIT © Nucleux
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var React = require('react');
|
|
5
|
+
var utils = require('@nucleux/utils');
|
|
6
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
7
|
+
|
|
8
|
+
function _interopNamespace(e) {
|
|
9
|
+
if (e && e.__esModule) return e;
|
|
10
|
+
var n = Object.create(null);
|
|
11
|
+
if (e) {
|
|
12
|
+
Object.keys(e).forEach(function (k) {
|
|
13
|
+
if (k !== 'default') {
|
|
14
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
15
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
16
|
+
enumerable: true,
|
|
17
|
+
get: function () { return e[k]; }
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
n.default = e;
|
|
23
|
+
return Object.freeze(n);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
27
|
+
|
|
28
|
+
// src/index.tsx
|
|
29
|
+
var MenubarContext = React__namespace.createContext(null);
|
|
30
|
+
var MenuValueContext = React__namespace.createContext(null);
|
|
31
|
+
var Menubar = React__namespace.forwardRef(
|
|
32
|
+
({ className, children, ...props }, ref) => {
|
|
33
|
+
const [openValue, setOpenValue] = React__namespace.useState(null);
|
|
34
|
+
const rootRef = React__namespace.useRef(null);
|
|
35
|
+
const setRefs = (node) => {
|
|
36
|
+
rootRef.current = node;
|
|
37
|
+
if (typeof ref === "function") ref(node);
|
|
38
|
+
else if (ref) ref.current = node;
|
|
39
|
+
};
|
|
40
|
+
React__namespace.useEffect(() => {
|
|
41
|
+
if (openValue === null) return;
|
|
42
|
+
const onDown = (e) => {
|
|
43
|
+
if (!rootRef.current?.contains(e.target)) setOpenValue(null);
|
|
44
|
+
};
|
|
45
|
+
const onKey = (e) => e.key === "Escape" && setOpenValue(null);
|
|
46
|
+
document.addEventListener("mousedown", onDown);
|
|
47
|
+
document.addEventListener("keydown", onKey);
|
|
48
|
+
return () => {
|
|
49
|
+
document.removeEventListener("mousedown", onDown);
|
|
50
|
+
document.removeEventListener("keydown", onKey);
|
|
51
|
+
};
|
|
52
|
+
}, [openValue]);
|
|
53
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
54
|
+
"div",
|
|
55
|
+
{
|
|
56
|
+
ref: setRefs,
|
|
57
|
+
role: "menubar",
|
|
58
|
+
className: utils.cn(
|
|
59
|
+
"flex items-center gap-0.5 rounded-md border border-border bg-background p-1 shadow-sm",
|
|
60
|
+
className
|
|
61
|
+
),
|
|
62
|
+
...props,
|
|
63
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(MenubarContext.Provider, { value: { openValue, setOpenValue }, children })
|
|
64
|
+
}
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
);
|
|
68
|
+
Menubar.displayName = "Menubar";
|
|
69
|
+
function MenubarMenu({ value, children }) {
|
|
70
|
+
const generated = React__namespace.useId();
|
|
71
|
+
const menuValue = value ?? generated;
|
|
72
|
+
return /* @__PURE__ */ jsxRuntime.jsx(MenuValueContext.Provider, { value: menuValue, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative", children }) });
|
|
73
|
+
}
|
|
74
|
+
var MenubarTrigger = React__namespace.forwardRef(
|
|
75
|
+
({ className, children, ...props }, ref) => {
|
|
76
|
+
const bar = React__namespace.useContext(MenubarContext);
|
|
77
|
+
const value = React__namespace.useContext(MenuValueContext);
|
|
78
|
+
if (!bar || value === null) throw new Error("MenubarTrigger must be used within a MenubarMenu");
|
|
79
|
+
const open = bar.openValue === value;
|
|
80
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
81
|
+
"button",
|
|
82
|
+
{
|
|
83
|
+
ref,
|
|
84
|
+
type: "button",
|
|
85
|
+
role: "menuitem",
|
|
86
|
+
"aria-haspopup": "menu",
|
|
87
|
+
"aria-expanded": open,
|
|
88
|
+
onClick: () => bar.setOpenValue(open ? null : value),
|
|
89
|
+
onMouseEnter: () => bar.openValue !== null && bar.setOpenValue(value),
|
|
90
|
+
className: utils.cn(
|
|
91
|
+
"flex items-center rounded-sm px-3 py-1 text-sm font-medium outline-none transition-colors",
|
|
92
|
+
"focus-visible:ring-2 focus-visible:ring-ring",
|
|
93
|
+
open ? "bg-accent text-accent-foreground" : "text-foreground hover:bg-accent",
|
|
94
|
+
className
|
|
95
|
+
),
|
|
96
|
+
...props,
|
|
97
|
+
children
|
|
98
|
+
}
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
);
|
|
102
|
+
MenubarTrigger.displayName = "MenubarTrigger";
|
|
103
|
+
var MenubarContent = React__namespace.forwardRef(
|
|
104
|
+
({ className, children, ...props }, ref) => {
|
|
105
|
+
const bar = React__namespace.useContext(MenubarContext);
|
|
106
|
+
const value = React__namespace.useContext(MenuValueContext);
|
|
107
|
+
if (!bar || value === null) throw new Error("MenubarContent must be used within a MenubarMenu");
|
|
108
|
+
if (bar.openValue !== value) return null;
|
|
109
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
110
|
+
"div",
|
|
111
|
+
{
|
|
112
|
+
ref,
|
|
113
|
+
role: "menu",
|
|
114
|
+
className: utils.cn(
|
|
115
|
+
"absolute left-0 top-full z-50 mt-1 min-w-[12rem] animate-nx-fade-in rounded-lg border border-border bg-background p-1 text-foreground shadow-md",
|
|
116
|
+
className
|
|
117
|
+
),
|
|
118
|
+
...props,
|
|
119
|
+
children
|
|
120
|
+
}
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
);
|
|
124
|
+
MenubarContent.displayName = "MenubarContent";
|
|
125
|
+
var MenubarItem = React__namespace.forwardRef(
|
|
126
|
+
({ className, children, trailing, destructive = false, onClick, ...props }, ref) => {
|
|
127
|
+
const bar = React__namespace.useContext(MenubarContext);
|
|
128
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
129
|
+
"button",
|
|
130
|
+
{
|
|
131
|
+
ref,
|
|
132
|
+
type: "button",
|
|
133
|
+
role: "menuitem",
|
|
134
|
+
onClick: (e) => {
|
|
135
|
+
onClick?.(e);
|
|
136
|
+
if (!e.defaultPrevented) bar?.setOpenValue(null);
|
|
137
|
+
},
|
|
138
|
+
className: utils.cn(
|
|
139
|
+
"flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-left text-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:size-4",
|
|
140
|
+
destructive ? "text-destructive hover:bg-destructive/10" : "text-foreground hover:bg-accent",
|
|
141
|
+
className
|
|
142
|
+
),
|
|
143
|
+
...props,
|
|
144
|
+
children: [
|
|
145
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 truncate", children }),
|
|
146
|
+
trailing && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 text-muted-foreground", children: trailing })
|
|
147
|
+
]
|
|
148
|
+
}
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
);
|
|
152
|
+
MenubarItem.displayName = "MenubarItem";
|
|
153
|
+
var MenubarSeparator = React__namespace.forwardRef(
|
|
154
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("div", { ref, role: "separator", className: utils.cn("-mx-1 my-1 h-px bg-border", className), ...props })
|
|
155
|
+
);
|
|
156
|
+
MenubarSeparator.displayName = "MenubarSeparator";
|
|
157
|
+
|
|
158
|
+
exports.Menubar = Menubar;
|
|
159
|
+
exports.MenubarContent = MenubarContent;
|
|
160
|
+
exports.MenubarItem = MenubarItem;
|
|
161
|
+
exports.MenubarMenu = MenubarMenu;
|
|
162
|
+
exports.MenubarSeparator = MenubarSeparator;
|
|
163
|
+
exports.MenubarTrigger = MenubarTrigger;
|
|
164
|
+
//# sourceMappingURL=index.cjs.map
|
|
165
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.tsx"],"names":["React","jsx","cn","jsxs"],"mappings":"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","file":"index.cjs","sourcesContent":["import * as React from \"react\";\nimport { cn } from \"@nucleux/utils\";\n\ninterface MenubarContextValue {\n openValue: string | null;\n setOpenValue: (v: string | null) => void;\n}\nconst MenubarContext = React.createContext<MenubarContextValue | null>(null);\n\nconst MenuValueContext = React.createContext<string | null>(null);\n\nexport type MenubarProps = React.HTMLAttributes<HTMLDivElement>;\n\n/** A horizontal bar of top-level menus (File / Edit / View …). */\nexport const Menubar = React.forwardRef<HTMLDivElement, MenubarProps>(\n ({ className, children, ...props }, ref) => {\n const [openValue, setOpenValue] = React.useState<string | null>(null);\n const rootRef = React.useRef<HTMLDivElement>(null);\n const setRefs = (node: HTMLDivElement | null) => {\n (rootRef as React.MutableRefObject<HTMLDivElement | null>).current = node;\n if (typeof ref === \"function\") ref(node);\n else if (ref) (ref as React.MutableRefObject<HTMLDivElement | null>).current = node;\n };\n\n React.useEffect(() => {\n if (openValue === null) return;\n const onDown = (e: MouseEvent) => {\n if (!rootRef.current?.contains(e.target as Node)) setOpenValue(null);\n };\n const onKey = (e: KeyboardEvent) => e.key === \"Escape\" && setOpenValue(null);\n document.addEventListener(\"mousedown\", onDown);\n document.addEventListener(\"keydown\", onKey);\n return () => {\n document.removeEventListener(\"mousedown\", onDown);\n document.removeEventListener(\"keydown\", onKey);\n };\n }, [openValue]);\n\n return (\n <div\n ref={setRefs}\n role=\"menubar\"\n className={cn(\n \"flex items-center gap-0.5 rounded-md border border-border bg-background p-1 shadow-sm\",\n className,\n )}\n {...props}\n >\n <MenubarContext.Provider value={{ openValue, setOpenValue }}>\n {children}\n </MenubarContext.Provider>\n </div>\n );\n },\n);\nMenubar.displayName = \"Menubar\";\n\nexport interface MenubarMenuProps {\n /** Unique key for this menu. Auto-generated if omitted. */\n value?: string;\n children: React.ReactNode;\n}\n\n/** Groups a {@link MenubarTrigger} with its {@link MenubarContent}. */\nexport function MenubarMenu({ value, children }: MenubarMenuProps) {\n const generated = React.useId();\n const menuValue = value ?? generated;\n return (\n <MenuValueContext.Provider value={menuValue}>\n <div className=\"relative\">{children}</div>\n </MenuValueContext.Provider>\n );\n}\n\nexport type MenubarTriggerProps = React.ButtonHTMLAttributes<HTMLButtonElement>;\n\n/** The button that opens a menu. */\nexport const MenubarTrigger = React.forwardRef<HTMLButtonElement, MenubarTriggerProps>(\n ({ className, children, ...props }, ref) => {\n const bar = React.useContext(MenubarContext);\n const value = React.useContext(MenuValueContext);\n if (!bar || value === null) throw new Error(\"MenubarTrigger must be used within a MenubarMenu\");\n const open = bar.openValue === value;\n return (\n <button\n ref={ref}\n type=\"button\"\n role=\"menuitem\"\n aria-haspopup=\"menu\"\n aria-expanded={open}\n onClick={() => bar.setOpenValue(open ? null : value)}\n onMouseEnter={() => bar.openValue !== null && bar.setOpenValue(value)}\n className={cn(\n \"flex items-center rounded-sm px-3 py-1 text-sm font-medium outline-none transition-colors\",\n \"focus-visible:ring-2 focus-visible:ring-ring\",\n open ? \"bg-accent text-accent-foreground\" : \"text-foreground hover:bg-accent\",\n className,\n )}\n {...props}\n >\n {children}\n </button>\n );\n },\n);\nMenubarTrigger.displayName = \"MenubarTrigger\";\n\nexport type MenubarContentProps = React.HTMLAttributes<HTMLDivElement>;\n\n/** The dropdown panel revealed when a menu is open. */\nexport const MenubarContent = React.forwardRef<HTMLDivElement, MenubarContentProps>(\n ({ className, children, ...props }, ref) => {\n const bar = React.useContext(MenubarContext);\n const value = React.useContext(MenuValueContext);\n if (!bar || value === null) throw new Error(\"MenubarContent must be used within a MenubarMenu\");\n if (bar.openValue !== value) return null;\n return (\n <div\n ref={ref}\n role=\"menu\"\n className={cn(\n \"absolute left-0 top-full z-50 mt-1 min-w-[12rem] animate-nx-fade-in rounded-lg border border-border bg-background p-1 text-foreground shadow-md\",\n className,\n )}\n {...props}\n >\n {children}\n </div>\n );\n },\n);\nMenubarContent.displayName = \"MenubarContent\";\n\nexport interface MenubarItemProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n trailing?: React.ReactNode;\n destructive?: boolean;\n}\n\n/** A selectable item inside a {@link MenubarContent}. */\nexport const MenubarItem = React.forwardRef<HTMLButtonElement, MenubarItemProps>(\n ({ className, children, trailing, destructive = false, onClick, ...props }, ref) => {\n const bar = React.useContext(MenubarContext);\n return (\n <button\n ref={ref}\n type=\"button\"\n role=\"menuitem\"\n onClick={(e) => {\n onClick?.(e);\n if (!e.defaultPrevented) bar?.setOpenValue(null);\n }}\n className={cn(\n \"flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-left text-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:size-4\",\n destructive ? \"text-destructive hover:bg-destructive/10\" : \"text-foreground hover:bg-accent\",\n className,\n )}\n {...props}\n >\n <span className=\"flex-1 truncate\">{children}</span>\n {trailing && <span className=\"shrink-0 text-muted-foreground\">{trailing}</span>}\n </button>\n );\n },\n);\nMenubarItem.displayName = \"MenubarItem\";\n\nexport const MenubarSeparator = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ className, ...props }, ref) => (\n <div ref={ref} role=\"separator\" className={cn(\"-mx-1 my-1 h-px bg-border\", className)} {...props} />\n ),\n);\nMenubarSeparator.displayName = \"MenubarSeparator\";\n"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
type MenubarProps = React.HTMLAttributes<HTMLDivElement>;
|
|
4
|
+
/** A horizontal bar of top-level menus (File / Edit / View …). */
|
|
5
|
+
declare const Menubar: React.ForwardRefExoticComponent<MenubarProps & React.RefAttributes<HTMLDivElement>>;
|
|
6
|
+
interface MenubarMenuProps {
|
|
7
|
+
/** Unique key for this menu. Auto-generated if omitted. */
|
|
8
|
+
value?: string;
|
|
9
|
+
children: React.ReactNode;
|
|
10
|
+
}
|
|
11
|
+
/** Groups a {@link MenubarTrigger} with its {@link MenubarContent}. */
|
|
12
|
+
declare function MenubarMenu({ value, children }: MenubarMenuProps): React.JSX.Element;
|
|
13
|
+
type MenubarTriggerProps = React.ButtonHTMLAttributes<HTMLButtonElement>;
|
|
14
|
+
/** The button that opens a menu. */
|
|
15
|
+
declare const MenubarTrigger: React.ForwardRefExoticComponent<MenubarTriggerProps & React.RefAttributes<HTMLButtonElement>>;
|
|
16
|
+
type MenubarContentProps = React.HTMLAttributes<HTMLDivElement>;
|
|
17
|
+
/** The dropdown panel revealed when a menu is open. */
|
|
18
|
+
declare const MenubarContent: React.ForwardRefExoticComponent<MenubarContentProps & React.RefAttributes<HTMLDivElement>>;
|
|
19
|
+
interface MenubarItemProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
20
|
+
trailing?: React.ReactNode;
|
|
21
|
+
destructive?: boolean;
|
|
22
|
+
}
|
|
23
|
+
/** A selectable item inside a {@link MenubarContent}. */
|
|
24
|
+
declare const MenubarItem: React.ForwardRefExoticComponent<MenubarItemProps & React.RefAttributes<HTMLButtonElement>>;
|
|
25
|
+
declare const MenubarSeparator: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<HTMLDivElement>>;
|
|
26
|
+
|
|
27
|
+
export { Menubar, MenubarContent, type MenubarContentProps, MenubarItem, type MenubarItemProps, MenubarMenu, type MenubarMenuProps, type MenubarProps, MenubarSeparator, MenubarTrigger, type MenubarTriggerProps };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
type MenubarProps = React.HTMLAttributes<HTMLDivElement>;
|
|
4
|
+
/** A horizontal bar of top-level menus (File / Edit / View …). */
|
|
5
|
+
declare const Menubar: React.ForwardRefExoticComponent<MenubarProps & React.RefAttributes<HTMLDivElement>>;
|
|
6
|
+
interface MenubarMenuProps {
|
|
7
|
+
/** Unique key for this menu. Auto-generated if omitted. */
|
|
8
|
+
value?: string;
|
|
9
|
+
children: React.ReactNode;
|
|
10
|
+
}
|
|
11
|
+
/** Groups a {@link MenubarTrigger} with its {@link MenubarContent}. */
|
|
12
|
+
declare function MenubarMenu({ value, children }: MenubarMenuProps): React.JSX.Element;
|
|
13
|
+
type MenubarTriggerProps = React.ButtonHTMLAttributes<HTMLButtonElement>;
|
|
14
|
+
/** The button that opens a menu. */
|
|
15
|
+
declare const MenubarTrigger: React.ForwardRefExoticComponent<MenubarTriggerProps & React.RefAttributes<HTMLButtonElement>>;
|
|
16
|
+
type MenubarContentProps = React.HTMLAttributes<HTMLDivElement>;
|
|
17
|
+
/** The dropdown panel revealed when a menu is open. */
|
|
18
|
+
declare const MenubarContent: React.ForwardRefExoticComponent<MenubarContentProps & React.RefAttributes<HTMLDivElement>>;
|
|
19
|
+
interface MenubarItemProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
20
|
+
trailing?: React.ReactNode;
|
|
21
|
+
destructive?: boolean;
|
|
22
|
+
}
|
|
23
|
+
/** A selectable item inside a {@link MenubarContent}. */
|
|
24
|
+
declare const MenubarItem: React.ForwardRefExoticComponent<MenubarItemProps & React.RefAttributes<HTMLButtonElement>>;
|
|
25
|
+
declare const MenubarSeparator: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<HTMLDivElement>>;
|
|
26
|
+
|
|
27
|
+
export { Menubar, MenubarContent, type MenubarContentProps, MenubarItem, type MenubarItemProps, MenubarMenu, type MenubarMenuProps, type MenubarProps, MenubarSeparator, MenubarTrigger, type MenubarTriggerProps };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import { cn } from '@nucleux/utils';
|
|
4
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
5
|
+
|
|
6
|
+
// src/index.tsx
|
|
7
|
+
var MenubarContext = React.createContext(null);
|
|
8
|
+
var MenuValueContext = React.createContext(null);
|
|
9
|
+
var Menubar = React.forwardRef(
|
|
10
|
+
({ className, children, ...props }, ref) => {
|
|
11
|
+
const [openValue, setOpenValue] = React.useState(null);
|
|
12
|
+
const rootRef = React.useRef(null);
|
|
13
|
+
const setRefs = (node) => {
|
|
14
|
+
rootRef.current = node;
|
|
15
|
+
if (typeof ref === "function") ref(node);
|
|
16
|
+
else if (ref) ref.current = node;
|
|
17
|
+
};
|
|
18
|
+
React.useEffect(() => {
|
|
19
|
+
if (openValue === null) return;
|
|
20
|
+
const onDown = (e) => {
|
|
21
|
+
if (!rootRef.current?.contains(e.target)) setOpenValue(null);
|
|
22
|
+
};
|
|
23
|
+
const onKey = (e) => e.key === "Escape" && setOpenValue(null);
|
|
24
|
+
document.addEventListener("mousedown", onDown);
|
|
25
|
+
document.addEventListener("keydown", onKey);
|
|
26
|
+
return () => {
|
|
27
|
+
document.removeEventListener("mousedown", onDown);
|
|
28
|
+
document.removeEventListener("keydown", onKey);
|
|
29
|
+
};
|
|
30
|
+
}, [openValue]);
|
|
31
|
+
return /* @__PURE__ */ jsx(
|
|
32
|
+
"div",
|
|
33
|
+
{
|
|
34
|
+
ref: setRefs,
|
|
35
|
+
role: "menubar",
|
|
36
|
+
className: cn(
|
|
37
|
+
"flex items-center gap-0.5 rounded-md border border-border bg-background p-1 shadow-sm",
|
|
38
|
+
className
|
|
39
|
+
),
|
|
40
|
+
...props,
|
|
41
|
+
children: /* @__PURE__ */ jsx(MenubarContext.Provider, { value: { openValue, setOpenValue }, children })
|
|
42
|
+
}
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
);
|
|
46
|
+
Menubar.displayName = "Menubar";
|
|
47
|
+
function MenubarMenu({ value, children }) {
|
|
48
|
+
const generated = React.useId();
|
|
49
|
+
const menuValue = value ?? generated;
|
|
50
|
+
return /* @__PURE__ */ jsx(MenuValueContext.Provider, { value: menuValue, children: /* @__PURE__ */ jsx("div", { className: "relative", children }) });
|
|
51
|
+
}
|
|
52
|
+
var MenubarTrigger = React.forwardRef(
|
|
53
|
+
({ className, children, ...props }, ref) => {
|
|
54
|
+
const bar = React.useContext(MenubarContext);
|
|
55
|
+
const value = React.useContext(MenuValueContext);
|
|
56
|
+
if (!bar || value === null) throw new Error("MenubarTrigger must be used within a MenubarMenu");
|
|
57
|
+
const open = bar.openValue === value;
|
|
58
|
+
return /* @__PURE__ */ jsx(
|
|
59
|
+
"button",
|
|
60
|
+
{
|
|
61
|
+
ref,
|
|
62
|
+
type: "button",
|
|
63
|
+
role: "menuitem",
|
|
64
|
+
"aria-haspopup": "menu",
|
|
65
|
+
"aria-expanded": open,
|
|
66
|
+
onClick: () => bar.setOpenValue(open ? null : value),
|
|
67
|
+
onMouseEnter: () => bar.openValue !== null && bar.setOpenValue(value),
|
|
68
|
+
className: cn(
|
|
69
|
+
"flex items-center rounded-sm px-3 py-1 text-sm font-medium outline-none transition-colors",
|
|
70
|
+
"focus-visible:ring-2 focus-visible:ring-ring",
|
|
71
|
+
open ? "bg-accent text-accent-foreground" : "text-foreground hover:bg-accent",
|
|
72
|
+
className
|
|
73
|
+
),
|
|
74
|
+
...props,
|
|
75
|
+
children
|
|
76
|
+
}
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
);
|
|
80
|
+
MenubarTrigger.displayName = "MenubarTrigger";
|
|
81
|
+
var MenubarContent = React.forwardRef(
|
|
82
|
+
({ className, children, ...props }, ref) => {
|
|
83
|
+
const bar = React.useContext(MenubarContext);
|
|
84
|
+
const value = React.useContext(MenuValueContext);
|
|
85
|
+
if (!bar || value === null) throw new Error("MenubarContent must be used within a MenubarMenu");
|
|
86
|
+
if (bar.openValue !== value) return null;
|
|
87
|
+
return /* @__PURE__ */ jsx(
|
|
88
|
+
"div",
|
|
89
|
+
{
|
|
90
|
+
ref,
|
|
91
|
+
role: "menu",
|
|
92
|
+
className: cn(
|
|
93
|
+
"absolute left-0 top-full z-50 mt-1 min-w-[12rem] animate-nx-fade-in rounded-lg border border-border bg-background p-1 text-foreground shadow-md",
|
|
94
|
+
className
|
|
95
|
+
),
|
|
96
|
+
...props,
|
|
97
|
+
children
|
|
98
|
+
}
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
);
|
|
102
|
+
MenubarContent.displayName = "MenubarContent";
|
|
103
|
+
var MenubarItem = React.forwardRef(
|
|
104
|
+
({ className, children, trailing, destructive = false, onClick, ...props }, ref) => {
|
|
105
|
+
const bar = React.useContext(MenubarContext);
|
|
106
|
+
return /* @__PURE__ */ jsxs(
|
|
107
|
+
"button",
|
|
108
|
+
{
|
|
109
|
+
ref,
|
|
110
|
+
type: "button",
|
|
111
|
+
role: "menuitem",
|
|
112
|
+
onClick: (e) => {
|
|
113
|
+
onClick?.(e);
|
|
114
|
+
if (!e.defaultPrevented) bar?.setOpenValue(null);
|
|
115
|
+
},
|
|
116
|
+
className: cn(
|
|
117
|
+
"flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-left text-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:size-4",
|
|
118
|
+
destructive ? "text-destructive hover:bg-destructive/10" : "text-foreground hover:bg-accent",
|
|
119
|
+
className
|
|
120
|
+
),
|
|
121
|
+
...props,
|
|
122
|
+
children: [
|
|
123
|
+
/* @__PURE__ */ jsx("span", { className: "flex-1 truncate", children }),
|
|
124
|
+
trailing && /* @__PURE__ */ jsx("span", { className: "shrink-0 text-muted-foreground", children: trailing })
|
|
125
|
+
]
|
|
126
|
+
}
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
);
|
|
130
|
+
MenubarItem.displayName = "MenubarItem";
|
|
131
|
+
var MenubarSeparator = React.forwardRef(
|
|
132
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, role: "separator", className: cn("-mx-1 my-1 h-px bg-border", className), ...props })
|
|
133
|
+
);
|
|
134
|
+
MenubarSeparator.displayName = "MenubarSeparator";
|
|
135
|
+
|
|
136
|
+
export { Menubar, MenubarContent, MenubarItem, MenubarMenu, MenubarSeparator, MenubarTrigger };
|
|
137
|
+
//# sourceMappingURL=index.js.map
|
|
138
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.tsx"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import * as React from \"react\";\nimport { cn } from \"@nucleux/utils\";\n\ninterface MenubarContextValue {\n openValue: string | null;\n setOpenValue: (v: string | null) => void;\n}\nconst MenubarContext = React.createContext<MenubarContextValue | null>(null);\n\nconst MenuValueContext = React.createContext<string | null>(null);\n\nexport type MenubarProps = React.HTMLAttributes<HTMLDivElement>;\n\n/** A horizontal bar of top-level menus (File / Edit / View …). */\nexport const Menubar = React.forwardRef<HTMLDivElement, MenubarProps>(\n ({ className, children, ...props }, ref) => {\n const [openValue, setOpenValue] = React.useState<string | null>(null);\n const rootRef = React.useRef<HTMLDivElement>(null);\n const setRefs = (node: HTMLDivElement | null) => {\n (rootRef as React.MutableRefObject<HTMLDivElement | null>).current = node;\n if (typeof ref === \"function\") ref(node);\n else if (ref) (ref as React.MutableRefObject<HTMLDivElement | null>).current = node;\n };\n\n React.useEffect(() => {\n if (openValue === null) return;\n const onDown = (e: MouseEvent) => {\n if (!rootRef.current?.contains(e.target as Node)) setOpenValue(null);\n };\n const onKey = (e: KeyboardEvent) => e.key === \"Escape\" && setOpenValue(null);\n document.addEventListener(\"mousedown\", onDown);\n document.addEventListener(\"keydown\", onKey);\n return () => {\n document.removeEventListener(\"mousedown\", onDown);\n document.removeEventListener(\"keydown\", onKey);\n };\n }, [openValue]);\n\n return (\n <div\n ref={setRefs}\n role=\"menubar\"\n className={cn(\n \"flex items-center gap-0.5 rounded-md border border-border bg-background p-1 shadow-sm\",\n className,\n )}\n {...props}\n >\n <MenubarContext.Provider value={{ openValue, setOpenValue }}>\n {children}\n </MenubarContext.Provider>\n </div>\n );\n },\n);\nMenubar.displayName = \"Menubar\";\n\nexport interface MenubarMenuProps {\n /** Unique key for this menu. Auto-generated if omitted. */\n value?: string;\n children: React.ReactNode;\n}\n\n/** Groups a {@link MenubarTrigger} with its {@link MenubarContent}. */\nexport function MenubarMenu({ value, children }: MenubarMenuProps) {\n const generated = React.useId();\n const menuValue = value ?? generated;\n return (\n <MenuValueContext.Provider value={menuValue}>\n <div className=\"relative\">{children}</div>\n </MenuValueContext.Provider>\n );\n}\n\nexport type MenubarTriggerProps = React.ButtonHTMLAttributes<HTMLButtonElement>;\n\n/** The button that opens a menu. */\nexport const MenubarTrigger = React.forwardRef<HTMLButtonElement, MenubarTriggerProps>(\n ({ className, children, ...props }, ref) => {\n const bar = React.useContext(MenubarContext);\n const value = React.useContext(MenuValueContext);\n if (!bar || value === null) throw new Error(\"MenubarTrigger must be used within a MenubarMenu\");\n const open = bar.openValue === value;\n return (\n <button\n ref={ref}\n type=\"button\"\n role=\"menuitem\"\n aria-haspopup=\"menu\"\n aria-expanded={open}\n onClick={() => bar.setOpenValue(open ? null : value)}\n onMouseEnter={() => bar.openValue !== null && bar.setOpenValue(value)}\n className={cn(\n \"flex items-center rounded-sm px-3 py-1 text-sm font-medium outline-none transition-colors\",\n \"focus-visible:ring-2 focus-visible:ring-ring\",\n open ? \"bg-accent text-accent-foreground\" : \"text-foreground hover:bg-accent\",\n className,\n )}\n {...props}\n >\n {children}\n </button>\n );\n },\n);\nMenubarTrigger.displayName = \"MenubarTrigger\";\n\nexport type MenubarContentProps = React.HTMLAttributes<HTMLDivElement>;\n\n/** The dropdown panel revealed when a menu is open. */\nexport const MenubarContent = React.forwardRef<HTMLDivElement, MenubarContentProps>(\n ({ className, children, ...props }, ref) => {\n const bar = React.useContext(MenubarContext);\n const value = React.useContext(MenuValueContext);\n if (!bar || value === null) throw new Error(\"MenubarContent must be used within a MenubarMenu\");\n if (bar.openValue !== value) return null;\n return (\n <div\n ref={ref}\n role=\"menu\"\n className={cn(\n \"absolute left-0 top-full z-50 mt-1 min-w-[12rem] animate-nx-fade-in rounded-lg border border-border bg-background p-1 text-foreground shadow-md\",\n className,\n )}\n {...props}\n >\n {children}\n </div>\n );\n },\n);\nMenubarContent.displayName = \"MenubarContent\";\n\nexport interface MenubarItemProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n trailing?: React.ReactNode;\n destructive?: boolean;\n}\n\n/** A selectable item inside a {@link MenubarContent}. */\nexport const MenubarItem = React.forwardRef<HTMLButtonElement, MenubarItemProps>(\n ({ className, children, trailing, destructive = false, onClick, ...props }, ref) => {\n const bar = React.useContext(MenubarContext);\n return (\n <button\n ref={ref}\n type=\"button\"\n role=\"menuitem\"\n onClick={(e) => {\n onClick?.(e);\n if (!e.defaultPrevented) bar?.setOpenValue(null);\n }}\n className={cn(\n \"flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-left text-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:size-4\",\n destructive ? \"text-destructive hover:bg-destructive/10\" : \"text-foreground hover:bg-accent\",\n className,\n )}\n {...props}\n >\n <span className=\"flex-1 truncate\">{children}</span>\n {trailing && <span className=\"shrink-0 text-muted-foreground\">{trailing}</span>}\n </button>\n );\n },\n);\nMenubarItem.displayName = \"MenubarItem\";\n\nexport const MenubarSeparator = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ className, ...props }, ref) => (\n <div ref={ref} role=\"separator\" className={cn(\"-mx-1 my-1 h-px bg-border\", className)} {...props} />\n ),\n);\nMenubarSeparator.displayName = \"MenubarSeparator\";\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nucleux/menubar",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"sideEffects": false,
|
|
6
|
+
"description": "Application menu bar — Nucleux agentic UI for React.",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"nucleux",
|
|
9
|
+
"react",
|
|
10
|
+
"ui",
|
|
11
|
+
"components",
|
|
12
|
+
"agentic",
|
|
13
|
+
"ai",
|
|
14
|
+
"tailwind",
|
|
15
|
+
"menubar"
|
|
16
|
+
],
|
|
17
|
+
"main": "./dist/index.cjs",
|
|
18
|
+
"module": "./dist/index.js",
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"import": "./dist/index.js",
|
|
24
|
+
"require": "./dist/index.cjs"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"dist",
|
|
29
|
+
"README.md"
|
|
30
|
+
],
|
|
31
|
+
"peerDependencies": {
|
|
32
|
+
"react": ">=18",
|
|
33
|
+
"react-dom": ">=18"
|
|
34
|
+
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"lucide-react": "^0.469.0",
|
|
37
|
+
"@nucleux/utils": "0.2.0"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"tsup": "^8.3.5",
|
|
41
|
+
"typescript": "^5.7.2",
|
|
42
|
+
"@types/react": "^18.3.18",
|
|
43
|
+
"react": "^18.3.1"
|
|
44
|
+
},
|
|
45
|
+
"publishConfig": {
|
|
46
|
+
"access": "public"
|
|
47
|
+
},
|
|
48
|
+
"license": "MIT",
|
|
49
|
+
"repository": {
|
|
50
|
+
"type": "git",
|
|
51
|
+
"url": "git+https://github.com/intelligaia-open-labs/nucleux.git",
|
|
52
|
+
"directory": "packages/menubar"
|
|
53
|
+
},
|
|
54
|
+
"homepage": "https://github.com/intelligaia-open-labs/nucleux#readme",
|
|
55
|
+
"scripts": {
|
|
56
|
+
"build": "tsup"
|
|
57
|
+
}
|
|
58
|
+
}
|