@versini/ui-menu 5.0.2 โ 5.1.1
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 +73 -10
- package/dist/chunks/index.dzHBmDC4.js +61 -0
- package/dist/components/Menu/Menu.js +220 -83
- package/dist/components/Menu/MenuContext.js +3 -1
- package/dist/components/Menu/MenuItem.js +80 -105
- package/dist/index.d.ts +4 -2
- package/dist/index.js +3 -3
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -18,10 +18,11 @@ The Menu package provides dropdown menus and navigation components with full key
|
|
|
18
18
|
## Features
|
|
19
19
|
|
|
20
20
|
- **๐ Composable**: `Menu`, `MenuItem`, `MenuSeparator`, `MenuGroupLabel`
|
|
21
|
+
- **๐ Nested Sub-menus**: Support for multi-level menu hierarchies with automatic positioning
|
|
21
22
|
- **โฟ Accessible**: Built with Floating UI & ARIA roles for robust a11y
|
|
22
23
|
- **โจ๏ธ Keyboard Support**: Arrow navigation, typeahead matching, ESC / click outside close
|
|
23
24
|
- **๐จ Theme & Focus Modes**: Trigger inherits color + separate focus styling
|
|
24
|
-
- **๐งญ Smart Positioning**: Auto flip / shift to remain within viewport
|
|
25
|
+
- **๐งญ Smart Positioning**: Auto flip / shift to remain within viewport, responsive spacing
|
|
25
26
|
- **๐งช Type Safe**: Strongly typed props & label-based typeahead
|
|
26
27
|
|
|
27
28
|
## Installation
|
|
@@ -124,19 +125,81 @@ function AccountMenu() {
|
|
|
124
125
|
</Menu>
|
|
125
126
|
```
|
|
126
127
|
|
|
128
|
+
### Nested Sub-menus
|
|
129
|
+
|
|
130
|
+
Create hierarchical menus by nesting `Menu` components. Simply use a `Menu` with a `label` prop but no `trigger` to create a sub-menu:
|
|
131
|
+
|
|
132
|
+
```tsx
|
|
133
|
+
import { Menu, MenuItem, MenuGroupLabel } from "@versini/ui-menu";
|
|
134
|
+
import { ButtonIcon } from "@versini/ui-button";
|
|
135
|
+
import { IconSettings, IconOpenAI, IconAnthropic } from "@versini/ui-icons";
|
|
136
|
+
|
|
137
|
+
function SettingsMenu() {
|
|
138
|
+
const [engine, setEngine] = useState("openai");
|
|
139
|
+
|
|
140
|
+
return (
|
|
141
|
+
<Menu
|
|
142
|
+
trigger={
|
|
143
|
+
<ButtonIcon label="Settings">
|
|
144
|
+
<IconSettings />
|
|
145
|
+
</ButtonIcon>
|
|
146
|
+
}
|
|
147
|
+
>
|
|
148
|
+
<MenuItem label="Profile" />
|
|
149
|
+
<MenuItem label="Preferences" />
|
|
150
|
+
|
|
151
|
+
{/* Nested sub-menu */}
|
|
152
|
+
<Menu label="AI Settings">
|
|
153
|
+
<MenuGroupLabel>Engines</MenuGroupLabel>
|
|
154
|
+
<MenuItem
|
|
155
|
+
label="OpenAI"
|
|
156
|
+
icon={<IconOpenAI />}
|
|
157
|
+
selected={engine === "openai"}
|
|
158
|
+
onClick={() => setEngine("openai")}
|
|
159
|
+
/>
|
|
160
|
+
<MenuItem
|
|
161
|
+
label="Anthropic"
|
|
162
|
+
icon={<IconAnthropic />}
|
|
163
|
+
selected={engine === "anthropic"}
|
|
164
|
+
onClick={() => setEngine("anthropic")}
|
|
165
|
+
/>
|
|
166
|
+
</Menu>
|
|
167
|
+
|
|
168
|
+
<MenuItem label="About" />
|
|
169
|
+
</Menu>
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
**Features of nested sub-menus:**
|
|
175
|
+
|
|
176
|
+
- Automatically positioned to the right (or left if no space)
|
|
177
|
+
- Visual chevron indicator (`โ`) shows expandable items
|
|
178
|
+
- Hover or click to open sub-menus
|
|
179
|
+
- Smart positioning adjusts for viewport constraints
|
|
180
|
+
- Keyboard navigation works across all levels
|
|
181
|
+
- Sibling sub-menus auto-close when opening another
|
|
182
|
+
|
|
127
183
|
## API
|
|
128
184
|
|
|
129
185
|
### Menu Props
|
|
130
186
|
|
|
131
|
-
| Prop | Type
|
|
132
|
-
| ------------------ |
|
|
133
|
-
| `trigger` | `React.ReactNode`
|
|
134
|
-
| `children` | `React.ReactNode`
|
|
135
|
-
| `
|
|
136
|
-
| `
|
|
137
|
-
| `
|
|
138
|
-
| `
|
|
139
|
-
| `onOpenChange` | `(open: boolean) => void`
|
|
187
|
+
| Prop | Type | Default | Description |
|
|
188
|
+
| ------------------ | ----------------------------------------------- | ---------------- | ---------------------------------------------------------------------------------------------- |
|
|
189
|
+
| `trigger` | `React.ReactNode` | - | Element used to open the menu (Button / ButtonIcon / custom). Optional for nested sub-menus. |
|
|
190
|
+
| `children` | `React.ReactNode` | - | One or more `MenuItem` / `MenuSeparator` / `Menu` (for sub-menus) / custom nodes. |
|
|
191
|
+
| `label` | `string` | `"Open menu"` | Accessible label for the trigger. When used without `trigger`, creates a nested sub-menu item. |
|
|
192
|
+
| `defaultPlacement` | `Placement` (Floating UI) | `"bottom-start"` | Initial preferred placement (only applies to root menu). |
|
|
193
|
+
| `mode` | `"dark" \| "light" \| "system" \| "alt-system"` | `"system"` | Color mode of trigger (when using UI buttons). |
|
|
194
|
+
| `focusMode` | `"dark" \| "light" \| "system" \| "alt-system"` | `"system"` | Focus ring thematic mode (when using UI buttons). |
|
|
195
|
+
| `onOpenChange` | `(open: boolean) => void` | - | Called when menu opens or closes. |
|
|
196
|
+
|
|
197
|
+
**Creating nested sub-menus:**
|
|
198
|
+
|
|
199
|
+
- Use `Menu` with `label` but without `trigger` to create a sub-menu item
|
|
200
|
+
- Sub-menus automatically show a chevron (`โ`) indicator
|
|
201
|
+
- Positioning is automatically handled (right-start, flips to left if needed)
|
|
202
|
+
- Hover or click to open nested menus
|
|
140
203
|
|
|
141
204
|
### MenuItem Props
|
|
142
205
|
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { jsxs as I, jsx as a } from "react/jsx-runtime";
|
|
2
|
+
import m from "clsx";
|
|
3
|
+
const d = ({
|
|
4
|
+
children: o,
|
|
5
|
+
fill: s,
|
|
6
|
+
viewBox: t,
|
|
7
|
+
className: n,
|
|
8
|
+
defaultViewBox: _,
|
|
9
|
+
size: l,
|
|
10
|
+
title: e,
|
|
11
|
+
semantic: i = !1,
|
|
12
|
+
...r
|
|
13
|
+
}) => {
|
|
14
|
+
const c = m(l, n);
|
|
15
|
+
return /* @__PURE__ */ I(
|
|
16
|
+
"svg",
|
|
17
|
+
{
|
|
18
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
19
|
+
className: c,
|
|
20
|
+
viewBox: t || _,
|
|
21
|
+
fill: s || "currentColor",
|
|
22
|
+
role: "img",
|
|
23
|
+
"aria-hidden": !i,
|
|
24
|
+
focusable: !1,
|
|
25
|
+
...r,
|
|
26
|
+
children: [
|
|
27
|
+
e && i && /* @__PURE__ */ a("title", { children: e }),
|
|
28
|
+
o
|
|
29
|
+
]
|
|
30
|
+
}
|
|
31
|
+
);
|
|
32
|
+
};
|
|
33
|
+
/*!
|
|
34
|
+
@versini/ui-svgicon v4.2.2
|
|
35
|
+
ยฉ 2025 gizmette.com
|
|
36
|
+
*/
|
|
37
|
+
try {
|
|
38
|
+
window.__VERSINI_UI_SVGICON__ || (window.__VERSINI_UI_SVGICON__ = {
|
|
39
|
+
version: "4.2.2",
|
|
40
|
+
buildTime: "10/19/2025 01:03 PM EDT",
|
|
41
|
+
homepage: "https://github.com/aversini/ui-components",
|
|
42
|
+
license: "MIT"
|
|
43
|
+
});
|
|
44
|
+
} catch {
|
|
45
|
+
}
|
|
46
|
+
/*!
|
|
47
|
+
@versini/ui-icons v4.13.0
|
|
48
|
+
ยฉ 2025 gizmette.com
|
|
49
|
+
*/
|
|
50
|
+
try {
|
|
51
|
+
window.__VERSINI_UI_ICONS__ || (window.__VERSINI_UI_ICONS__ = {
|
|
52
|
+
version: "4.13.0",
|
|
53
|
+
buildTime: "10/19/2025 01:03 PM EDT",
|
|
54
|
+
homepage: "https://github.com/aversini/ui-components",
|
|
55
|
+
license: "MIT"
|
|
56
|
+
});
|
|
57
|
+
} catch {
|
|
58
|
+
}
|
|
59
|
+
export {
|
|
60
|
+
d as I
|
|
61
|
+
};
|
|
@@ -1,110 +1,247 @@
|
|
|
1
|
-
import { jsxs as
|
|
2
|
-
import { useFloatingTree as
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
|
|
1
|
+
import { jsxs as b, jsx as t } from "react/jsx-runtime";
|
|
2
|
+
import { useFloatingTree as se, useFloatingNodeId as ie, useFloatingParentNodeId as W, useListItem as re, useFloating as ae, autoUpdate as le, offset as de, flip as ue, shift as ce, useHover as fe, safePolygon as me, useClick as pe, useRole as he, useDismiss as ve, useListNavigation as ge, useTypeahead as we, useInteractions as ye, useMergeRefs as be, FloatingNode as D, FloatingList as S, FloatingPortal as _, FloatingFocusManager as K, FloatingTree as xe } from "@floating-ui/react";
|
|
3
|
+
import { I as Ie } from "../../chunks/index.dzHBmDC4.js";
|
|
4
|
+
import Fe from "clsx";
|
|
5
|
+
import Ne, { forwardRef as q, useState as y, useRef as U, useContext as Me, useEffect as P } from "react";
|
|
6
|
+
import { MenuContext as R } from "./MenuContext.js";
|
|
7
|
+
const Ee = ({
|
|
8
|
+
className: e,
|
|
9
|
+
viewBox: n,
|
|
10
|
+
title: d,
|
|
11
|
+
monotone: x,
|
|
12
|
+
...f
|
|
13
|
+
}) => /* @__PURE__ */ b(
|
|
14
|
+
Ie,
|
|
15
|
+
{
|
|
16
|
+
defaultViewBox: "0 0 448 512",
|
|
17
|
+
size: "size-5",
|
|
18
|
+
viewBox: n,
|
|
19
|
+
className: e,
|
|
20
|
+
title: d || "Next",
|
|
21
|
+
...f,
|
|
22
|
+
children: [
|
|
23
|
+
/* @__PURE__ */ t(
|
|
24
|
+
"path",
|
|
25
|
+
{
|
|
26
|
+
d: "M0 256c0 17.7 14.3 32 32 32h306.7l32-32-32-32H32c-17.7 0-32 14.3-32 32",
|
|
27
|
+
opacity: x ? "1" : "0.4"
|
|
28
|
+
}
|
|
29
|
+
),
|
|
30
|
+
/* @__PURE__ */ t("path", { d: "M438.6 233.4c12.5 12.5 12.5 32.8 0 45.3l-160 160c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3L370.7 256 233.4 118.6c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0l160 160z" })
|
|
31
|
+
]
|
|
32
|
+
}
|
|
33
|
+
), V = (e) => {
|
|
6
34
|
if (typeof e == "string")
|
|
7
35
|
return e;
|
|
8
36
|
if (typeof e == "function")
|
|
9
37
|
return e.displayName || e.name || "Component";
|
|
10
38
|
if (typeof e == "object" && e !== null && "type" in e) {
|
|
11
|
-
const
|
|
12
|
-
if (typeof
|
|
13
|
-
return
|
|
39
|
+
const n = e.type;
|
|
40
|
+
if (typeof n == "function" || typeof n == "object")
|
|
41
|
+
return n.displayName || n.name || "Component";
|
|
14
42
|
}
|
|
15
43
|
return "Element";
|
|
16
|
-
},
|
|
44
|
+
}, k = q(
|
|
17
45
|
({
|
|
18
46
|
trigger: e,
|
|
19
|
-
children:
|
|
20
|
-
label:
|
|
21
|
-
defaultPlacement:
|
|
22
|
-
onOpenChange:
|
|
23
|
-
mode:
|
|
24
|
-
focusMode:
|
|
25
|
-
...
|
|
26
|
-
},
|
|
27
|
-
const [
|
|
28
|
-
nodeId:
|
|
29
|
-
open:
|
|
30
|
-
onOpenChange: (
|
|
31
|
-
|
|
47
|
+
children: n,
|
|
48
|
+
label: d = "Open menu",
|
|
49
|
+
defaultPlacement: x = "bottom-start",
|
|
50
|
+
onOpenChange: f,
|
|
51
|
+
mode: G = "system",
|
|
52
|
+
focusMode: J = "system",
|
|
53
|
+
...h
|
|
54
|
+
}, Q) => {
|
|
55
|
+
const [o, I] = y(!1), [C, F] = y(!1), [v, g] = y(null), [m, L] = y(!1), N = U([]), M = U([]), a = Me(R), i = se(), u = ie(), p = W(), A = re({ label: d !== "Open menu" ? d : null }), c = p != null, { floatingStyles: H, refs: E, context: l } = ae({
|
|
56
|
+
nodeId: u,
|
|
57
|
+
open: o,
|
|
58
|
+
onOpenChange: (s) => {
|
|
59
|
+
I(s), f?.(s);
|
|
32
60
|
},
|
|
33
|
-
placement:
|
|
61
|
+
placement: c ? "right-start" : x,
|
|
34
62
|
strategy: "fixed",
|
|
35
|
-
middleware: [
|
|
36
|
-
|
|
37
|
-
|
|
63
|
+
middleware: [
|
|
64
|
+
de(() => c ? {
|
|
65
|
+
mainAxis: window.innerWidth < 640 ? 22 : 14,
|
|
66
|
+
alignmentAxis: -4
|
|
67
|
+
} : {
|
|
68
|
+
mainAxis: 10,
|
|
69
|
+
alignmentAxis: 0
|
|
70
|
+
}),
|
|
71
|
+
ue(),
|
|
72
|
+
ce()
|
|
73
|
+
],
|
|
74
|
+
whileElementsMounted: le
|
|
75
|
+
}), X = fe(l, {
|
|
76
|
+
enabled: c && m,
|
|
77
|
+
delay: { open: 75 },
|
|
78
|
+
handleClose: me({ blockPointerEvents: !0 })
|
|
79
|
+
}), Y = pe(l, {
|
|
38
80
|
event: "mousedown",
|
|
39
|
-
toggle: !
|
|
40
|
-
ignoreMouse:
|
|
41
|
-
}),
|
|
42
|
-
listRef:
|
|
43
|
-
activeIndex:
|
|
44
|
-
nested:
|
|
45
|
-
onNavigate:
|
|
81
|
+
toggle: !c || !m,
|
|
82
|
+
ignoreMouse: c && m
|
|
83
|
+
}), Z = he(l, { role: "menu" }), $ = ve(l, { bubbles: !0 }), ee = ge(l, {
|
|
84
|
+
listRef: N,
|
|
85
|
+
activeIndex: v,
|
|
86
|
+
nested: c,
|
|
87
|
+
onNavigate: g,
|
|
46
88
|
loop: !0
|
|
47
|
-
}),
|
|
48
|
-
listRef:
|
|
49
|
-
onMatch:
|
|
50
|
-
activeIndex:
|
|
51
|
-
}), { getReferenceProps:
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
89
|
+
}), te = we(l, {
|
|
90
|
+
listRef: M,
|
|
91
|
+
onMatch: o ? g : void 0,
|
|
92
|
+
activeIndex: v
|
|
93
|
+
}), { getReferenceProps: B, getFloatingProps: j, getItemProps: z } = ye([X, Y, Z, $, ee, te]), O = be([E.setReference, A.ref, Q]);
|
|
94
|
+
P(() => {
|
|
95
|
+
if (!i)
|
|
96
|
+
return;
|
|
97
|
+
function s() {
|
|
98
|
+
I(!1), f?.(!1);
|
|
99
|
+
}
|
|
100
|
+
function r(w) {
|
|
101
|
+
w.nodeId !== u && w.parentId === p && I(!1);
|
|
102
|
+
}
|
|
103
|
+
return i.events.on("click", s), i.events.on("menuopen", r), () => {
|
|
104
|
+
i.events.off("click", s), i.events.off("menuopen", r);
|
|
105
|
+
};
|
|
106
|
+
}, [i, u, p, f]), P(() => {
|
|
107
|
+
o && i && i.events.emit("menuopen", { parentId: p, nodeId: u });
|
|
108
|
+
}, [i, o, u, p]), P(() => {
|
|
109
|
+
function s({ pointerType: w }) {
|
|
110
|
+
w !== "touch" && L(!0);
|
|
111
|
+
}
|
|
112
|
+
function r() {
|
|
113
|
+
L(!1);
|
|
114
|
+
}
|
|
115
|
+
return window.addEventListener("pointermove", s, {
|
|
116
|
+
once: !0,
|
|
117
|
+
capture: !0
|
|
118
|
+
}), window.addEventListener("keydown", r, !0), () => {
|
|
119
|
+
window.removeEventListener("pointermove", s, {
|
|
120
|
+
capture: !0
|
|
121
|
+
}), window.removeEventListener("keydown", r, !0);
|
|
122
|
+
};
|
|
123
|
+
}, []);
|
|
124
|
+
const T = V(e) === "Button" || V(e) === "ButtonIcon", ne = T ? {
|
|
125
|
+
noInternalClick: T,
|
|
126
|
+
focusMode: J,
|
|
127
|
+
mode: G
|
|
128
|
+
} : {};
|
|
129
|
+
if (c && !e) {
|
|
130
|
+
const s = Fe(
|
|
131
|
+
"flex items-center flex-row justify-between",
|
|
132
|
+
"w-full",
|
|
133
|
+
"m-0 first:mt-0 mt-2 sm:mt-1 px-2 py-1",
|
|
134
|
+
"rounded-md border border-transparent",
|
|
135
|
+
"text-left text-base",
|
|
136
|
+
"outline-hidden focus:border focus:border-border-medium focus:bg-surface-lighter focus:underline",
|
|
137
|
+
"disabled:cursor-not-allowed disabled:text-copy-medium",
|
|
138
|
+
{
|
|
139
|
+
"bg-surface-lighter": o && !C
|
|
140
|
+
}
|
|
141
|
+
);
|
|
142
|
+
return /* @__PURE__ */ b(D, { id: u, children: [
|
|
143
|
+
/* @__PURE__ */ b(
|
|
144
|
+
"button",
|
|
145
|
+
{
|
|
146
|
+
ref: O,
|
|
147
|
+
"data-open": o ? "" : void 0,
|
|
148
|
+
...B(
|
|
149
|
+
a.getItemProps({
|
|
150
|
+
...h,
|
|
151
|
+
className: s,
|
|
152
|
+
onFocus(r) {
|
|
153
|
+
h.onFocus?.(r), F(!1), a.setHasFocusInside(!0);
|
|
154
|
+
},
|
|
155
|
+
onMouseEnter(r) {
|
|
156
|
+
h.onMouseEnter?.(r), a.allowHover && a.isOpen && a.setActiveIndex(A.index);
|
|
157
|
+
}
|
|
158
|
+
})
|
|
159
|
+
),
|
|
160
|
+
children: [
|
|
161
|
+
/* @__PURE__ */ t("span", { children: d }),
|
|
162
|
+
/* @__PURE__ */ t(Ee, { className: "ml-2", size: "size-3", monotone: !0 })
|
|
163
|
+
]
|
|
164
|
+
}
|
|
165
|
+
),
|
|
166
|
+
/* @__PURE__ */ t(
|
|
167
|
+
R.Provider,
|
|
168
|
+
{
|
|
169
|
+
value: {
|
|
170
|
+
activeIndex: v,
|
|
171
|
+
setActiveIndex: g,
|
|
172
|
+
getItemProps: z,
|
|
173
|
+
setHasFocusInside: F,
|
|
174
|
+
isOpen: o,
|
|
175
|
+
allowHover: m,
|
|
176
|
+
parent: a
|
|
177
|
+
},
|
|
178
|
+
children: /* @__PURE__ */ t(S, { elementsRef: N, labelsRef: M, children: o && /* @__PURE__ */ t(_, { children: /* @__PURE__ */ t(
|
|
179
|
+
K,
|
|
180
|
+
{
|
|
181
|
+
context: l,
|
|
182
|
+
modal: !1,
|
|
183
|
+
initialFocus: -1,
|
|
184
|
+
returnFocus: !1,
|
|
185
|
+
children: /* @__PURE__ */ t(
|
|
186
|
+
"div",
|
|
187
|
+
{
|
|
188
|
+
ref: E.setFloating,
|
|
189
|
+
className: "rounded-md bg-surface-light shadow-sm shadow-border-dark outline-hidden p-3 sm:p-2",
|
|
190
|
+
style: H,
|
|
191
|
+
...j(),
|
|
192
|
+
children: n
|
|
193
|
+
}
|
|
194
|
+
)
|
|
195
|
+
}
|
|
196
|
+
) }) })
|
|
197
|
+
}
|
|
198
|
+
)
|
|
199
|
+
] });
|
|
200
|
+
}
|
|
201
|
+
const oe = Ne.cloneElement(
|
|
56
202
|
e,
|
|
57
203
|
{
|
|
58
|
-
...
|
|
59
|
-
"aria-label":
|
|
60
|
-
"data-open":
|
|
61
|
-
"data-focus-inside":
|
|
62
|
-
ref:
|
|
63
|
-
...
|
|
64
|
-
|
|
65
|
-
...
|
|
204
|
+
...ne,
|
|
205
|
+
"aria-label": d,
|
|
206
|
+
"data-open": o ? "" : void 0,
|
|
207
|
+
"data-focus-inside": C ? "" : void 0,
|
|
208
|
+
ref: O,
|
|
209
|
+
...B(
|
|
210
|
+
a.getItemProps({
|
|
211
|
+
...h
|
|
66
212
|
})
|
|
67
213
|
)
|
|
68
214
|
}
|
|
69
215
|
);
|
|
70
|
-
return
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
d(!1), l?.(!1);
|
|
75
|
-
}
|
|
76
|
-
return o.events.on("click", a), () => {
|
|
77
|
-
o.events.off("click", a);
|
|
78
|
-
};
|
|
79
|
-
}, [o, l]), v(() => {
|
|
80
|
-
n && o && o.events.emit("menuopen", { nodeId: r });
|
|
81
|
-
}, [o, n, r]), /* @__PURE__ */ G(ae, { id: r, children: [
|
|
82
|
-
z,
|
|
83
|
-
/* @__PURE__ */ s(
|
|
84
|
-
F.Provider,
|
|
216
|
+
return /* @__PURE__ */ b(D, { id: u, children: [
|
|
217
|
+
oe,
|
|
218
|
+
/* @__PURE__ */ t(
|
|
219
|
+
R.Provider,
|
|
85
220
|
{
|
|
86
221
|
value: {
|
|
87
|
-
activeIndex:
|
|
88
|
-
setActiveIndex:
|
|
89
|
-
getItemProps:
|
|
90
|
-
setHasFocusInside:
|
|
91
|
-
isOpen:
|
|
222
|
+
activeIndex: v,
|
|
223
|
+
setActiveIndex: g,
|
|
224
|
+
getItemProps: z,
|
|
225
|
+
setHasFocusInside: F,
|
|
226
|
+
isOpen: o,
|
|
227
|
+
allowHover: m,
|
|
228
|
+
parent: a
|
|
92
229
|
},
|
|
93
|
-
children: /* @__PURE__ */
|
|
94
|
-
|
|
230
|
+
children: /* @__PURE__ */ t(S, { elementsRef: N, labelsRef: M, children: o && /* @__PURE__ */ t(_, { children: /* @__PURE__ */ t(
|
|
231
|
+
K,
|
|
95
232
|
{
|
|
96
|
-
context:
|
|
233
|
+
context: l,
|
|
97
234
|
modal: !1,
|
|
98
235
|
initialFocus: 0,
|
|
99
236
|
returnFocus: !0,
|
|
100
|
-
children: /* @__PURE__ */
|
|
237
|
+
children: /* @__PURE__ */ t(
|
|
101
238
|
"div",
|
|
102
239
|
{
|
|
103
|
-
ref:
|
|
104
|
-
className: "rounded-md bg-surface-light shadow-sm shadow-border-dark outline-hidden p-
|
|
105
|
-
style:
|
|
106
|
-
...
|
|
107
|
-
children:
|
|
240
|
+
ref: E.setFloating,
|
|
241
|
+
className: "rounded-md bg-surface-light shadow-sm shadow-border-dark outline-hidden p-3 sm:p-2",
|
|
242
|
+
style: H,
|
|
243
|
+
...j(),
|
|
244
|
+
children: n
|
|
108
245
|
}
|
|
109
246
|
)
|
|
110
247
|
}
|
|
@@ -113,9 +250,9 @@ const I = (e) => {
|
|
|
113
250
|
)
|
|
114
251
|
] });
|
|
115
252
|
}
|
|
116
|
-
),
|
|
117
|
-
|
|
118
|
-
|
|
253
|
+
), Pe = q((e, n) => W() === null ? /* @__PURE__ */ t(xe, { children: /* @__PURE__ */ t(k, { ...e, ref: n }) }) : /* @__PURE__ */ t(k, { ...e, ref: n }));
|
|
254
|
+
Pe.displayName = "Menu";
|
|
255
|
+
k.displayName = "MenuComponent";
|
|
119
256
|
export {
|
|
120
|
-
|
|
257
|
+
Pe as Menu
|
|
121
258
|
};
|
|
@@ -1,66 +1,24 @@
|
|
|
1
|
-
import { jsxs as
|
|
2
|
-
import { useListItem as
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
fill: t,
|
|
9
|
-
viewBox: s,
|
|
10
|
-
className: l,
|
|
11
|
-
defaultViewBox: i,
|
|
12
|
-
size: m,
|
|
13
|
-
title: n,
|
|
14
|
-
semantic: r = !1,
|
|
15
|
-
...d
|
|
16
|
-
}) => {
|
|
17
|
-
const a = u(m, l);
|
|
18
|
-
return /* @__PURE__ */ p(
|
|
19
|
-
"svg",
|
|
20
|
-
{
|
|
21
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
22
|
-
className: a,
|
|
23
|
-
viewBox: s || i,
|
|
24
|
-
fill: t || "currentColor",
|
|
25
|
-
role: "img",
|
|
26
|
-
"aria-hidden": !r,
|
|
27
|
-
focusable: !1,
|
|
28
|
-
...d,
|
|
29
|
-
children: [
|
|
30
|
-
n && r && /* @__PURE__ */ o("title", { children: n }),
|
|
31
|
-
e
|
|
32
|
-
]
|
|
33
|
-
}
|
|
34
|
-
);
|
|
35
|
-
};
|
|
36
|
-
/*!
|
|
37
|
-
@versini/ui-svgicon v4.2.2
|
|
38
|
-
ยฉ 2025 gizmette.com
|
|
39
|
-
*/
|
|
40
|
-
try {
|
|
41
|
-
window.__VERSINI_UI_SVGICON__ || (window.__VERSINI_UI_SVGICON__ = {
|
|
42
|
-
version: "4.2.2",
|
|
43
|
-
buildTime: "10/17/2025 12:12 PM EDT",
|
|
44
|
-
homepage: "https://github.com/aversini/ui-components",
|
|
45
|
-
license: "MIT"
|
|
46
|
-
});
|
|
47
|
-
} catch {
|
|
48
|
-
}
|
|
49
|
-
const M = ({
|
|
1
|
+
import { jsxs as x, jsx as o } from "react/jsx-runtime";
|
|
2
|
+
import { useListItem as N, useFloatingTree as w, useMergeRefs as y } from "@floating-ui/react";
|
|
3
|
+
import { I as b } from "../../chunks/index.dzHBmDC4.js";
|
|
4
|
+
import l from "clsx";
|
|
5
|
+
import * as p from "react";
|
|
6
|
+
import { MenuContext as M } from "./MenuContext.js";
|
|
7
|
+
const g = ({
|
|
50
8
|
className: e,
|
|
51
9
|
viewBox: t,
|
|
52
10
|
title: s,
|
|
53
|
-
monotone:
|
|
54
|
-
...
|
|
55
|
-
}) => /* @__PURE__ */
|
|
56
|
-
|
|
11
|
+
monotone: n,
|
|
12
|
+
...r
|
|
13
|
+
}) => /* @__PURE__ */ x(
|
|
14
|
+
b,
|
|
57
15
|
{
|
|
58
16
|
defaultViewBox: "0 0 448 512",
|
|
59
17
|
size: "size-5",
|
|
60
18
|
viewBox: t,
|
|
61
19
|
className: e,
|
|
62
|
-
title: s || "
|
|
63
|
-
...
|
|
20
|
+
title: s || "Checked",
|
|
21
|
+
...r,
|
|
64
22
|
children: [
|
|
65
23
|
/* @__PURE__ */ o(
|
|
66
24
|
"path",
|
|
@@ -72,96 +30,113 @@ const M = ({
|
|
|
72
30
|
/* @__PURE__ */ o("path", { d: "M337 175c9.4 9.4 9.4 24.6 0 33.9L209 337c-9.4 9.4-24.6 9.4-33.9 0l-64-64c-9.4-9.4-9.4-24.6 0-33.9s24.6-9.4 33.9 0l47 47L303 175c9.4-9.4 24.6-9.4 33.9 0z" })
|
|
73
31
|
]
|
|
74
32
|
}
|
|
75
|
-
)
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
33
|
+
), k = ({
|
|
34
|
+
className: e,
|
|
35
|
+
viewBox: t,
|
|
36
|
+
title: s,
|
|
37
|
+
monotone: n,
|
|
38
|
+
...r
|
|
39
|
+
}) => /* @__PURE__ */ o(
|
|
40
|
+
b,
|
|
41
|
+
{
|
|
42
|
+
defaultViewBox: "0 0 448 512",
|
|
43
|
+
size: "size-5",
|
|
44
|
+
viewBox: t,
|
|
45
|
+
className: e,
|
|
46
|
+
title: s || "UnChecked",
|
|
47
|
+
...r,
|
|
48
|
+
children: /* @__PURE__ */ o(
|
|
49
|
+
"path",
|
|
50
|
+
{
|
|
51
|
+
d: "M0 96c0-35.3 28.7-64 64-64h320c35.3 0 64 28.7 64 64v320c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64z",
|
|
52
|
+
opacity: ".4"
|
|
53
|
+
}
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
), I = p.forwardRef(
|
|
90
57
|
({
|
|
91
58
|
label: e,
|
|
92
59
|
disabled: t,
|
|
93
60
|
icon: s,
|
|
94
|
-
raw:
|
|
95
|
-
children:
|
|
96
|
-
ignoreClick:
|
|
97
|
-
selected:
|
|
98
|
-
...
|
|
99
|
-
},
|
|
100
|
-
let
|
|
101
|
-
const
|
|
102
|
-
if (
|
|
61
|
+
raw: n = !1,
|
|
62
|
+
children: r,
|
|
63
|
+
ignoreClick: u = !1,
|
|
64
|
+
selected: i,
|
|
65
|
+
...m
|
|
66
|
+
}, h) => {
|
|
67
|
+
let d = "";
|
|
68
|
+
const a = p.useContext(M), C = N({ label: t ? null : e }), f = w(), v = y([C.ref, h]);
|
|
69
|
+
if (n && r)
|
|
103
70
|
return /* @__PURE__ */ o(
|
|
104
71
|
"div",
|
|
105
72
|
{
|
|
106
73
|
role: "menuitem",
|
|
107
|
-
...
|
|
74
|
+
...a.getItemProps({
|
|
108
75
|
onClick(c) {
|
|
109
|
-
|
|
76
|
+
u || (m.onClick?.(c), f?.events.emit("click"));
|
|
110
77
|
}
|
|
111
78
|
}),
|
|
112
|
-
children:
|
|
79
|
+
children: r
|
|
113
80
|
}
|
|
114
81
|
);
|
|
115
|
-
s && (
|
|
116
|
-
const
|
|
117
|
-
"
|
|
118
|
-
"
|
|
82
|
+
s && (d = "pl-2");
|
|
83
|
+
const z = l(
|
|
84
|
+
"flex flex-row items-center",
|
|
85
|
+
"w-full",
|
|
86
|
+
"m-0 first:mt-0 mt-2 sm:mt-1 px-2 py-1",
|
|
87
|
+
"rounded-md border border-transparent",
|
|
88
|
+
"text-left text-base",
|
|
89
|
+
"outline-hidden focus:border focus:border-border-medium focus:bg-surface-lighter focus:underline",
|
|
90
|
+
"disabled:cursor-not-allowed disabled:text-copy-medium",
|
|
119
91
|
{
|
|
120
|
-
"bg-none": !t && !
|
|
92
|
+
"bg-none": !t && !i
|
|
121
93
|
}
|
|
122
94
|
);
|
|
123
|
-
return /* @__PURE__ */
|
|
95
|
+
return /* @__PURE__ */ x(
|
|
124
96
|
"button",
|
|
125
97
|
{
|
|
126
|
-
...
|
|
127
|
-
ref:
|
|
98
|
+
...m,
|
|
99
|
+
ref: v,
|
|
128
100
|
role: "menuitem",
|
|
129
|
-
className:
|
|
101
|
+
className: z,
|
|
130
102
|
tabIndex: 0,
|
|
131
103
|
disabled: t,
|
|
132
|
-
...
|
|
104
|
+
...a.getItemProps({
|
|
133
105
|
onClick(c) {
|
|
134
|
-
|
|
106
|
+
u || (m.onClick?.(c), f?.events.emit("click"));
|
|
135
107
|
},
|
|
136
108
|
onFocus(c) {
|
|
137
|
-
|
|
109
|
+
m.onFocus?.(c), a.setHasFocusInside(!0);
|
|
138
110
|
}
|
|
139
111
|
}),
|
|
140
112
|
children: [
|
|
141
|
-
|
|
113
|
+
i === !0 && /* @__PURE__ */ o(g, { className: "text-copy-success mr-2", size: "size-4" }),
|
|
114
|
+
i === !1 && /* @__PURE__ */ o(k, { className: "text-copy-medium mr-2", size: "size-4" }),
|
|
142
115
|
s,
|
|
143
|
-
e && /* @__PURE__ */ o("span", { className:
|
|
116
|
+
e && /* @__PURE__ */ o("span", { className: d, children: e })
|
|
144
117
|
]
|
|
145
118
|
}
|
|
146
119
|
);
|
|
147
120
|
}
|
|
148
121
|
);
|
|
149
|
-
|
|
150
|
-
const
|
|
151
|
-
const s =
|
|
122
|
+
I.displayName = "MenuItem";
|
|
123
|
+
const V = ({ className: e, ...t }) => {
|
|
124
|
+
const s = l(e, "my-1 border-t border-border-medium");
|
|
152
125
|
return /* @__PURE__ */ o("div", { className: s, ...t });
|
|
153
|
-
},
|
|
126
|
+
}, j = ({
|
|
154
127
|
className: e,
|
|
155
128
|
...t
|
|
156
129
|
}) => {
|
|
157
|
-
const s =
|
|
130
|
+
const s = l(
|
|
158
131
|
e,
|
|
159
|
-
"pt-1 mb-2
|
|
132
|
+
"pt-1 mb-2",
|
|
133
|
+
"text-sm text-copy-dark font-bold",
|
|
134
|
+
"border-b border-border-medium"
|
|
160
135
|
);
|
|
161
136
|
return /* @__PURE__ */ o("div", { className: s, ...t });
|
|
162
137
|
};
|
|
163
138
|
export {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
139
|
+
j as MenuGroupLabel,
|
|
140
|
+
I as MenuItem,
|
|
141
|
+
V as MenuSeparator
|
|
167
142
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -6,8 +6,9 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
|
6
6
|
type MenuProps = {
|
|
7
7
|
/**
|
|
8
8
|
* The component to use to open the menu, e.g. a ButtonIcon, a Button, etc.
|
|
9
|
+
* Required for root menus, omit for nested sub-menus (use label instead).
|
|
9
10
|
*/
|
|
10
|
-
trigger
|
|
11
|
+
trigger?: React__default.ReactNode;
|
|
11
12
|
/**
|
|
12
13
|
* The children to render.
|
|
13
14
|
*/
|
|
@@ -27,7 +28,8 @@ type MenuProps = {
|
|
|
27
28
|
*/
|
|
28
29
|
mode?: "dark" | "light" | "system" | "alt-system";
|
|
29
30
|
/**
|
|
30
|
-
* The label to use for the menu button.
|
|
31
|
+
* The label to use for the menu button (root menu) or the sub-menu trigger text (nested menu).
|
|
32
|
+
* When used without a trigger, this creates a nested sub-menu.
|
|
31
33
|
*/
|
|
32
34
|
label?: string;
|
|
33
35
|
/**
|
package/dist/index.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { Menu as _ } from "./components/Menu/Menu.js";
|
|
2
2
|
import { MenuGroupLabel as n, MenuItem as t, MenuSeparator as u } from "./components/Menu/MenuItem.js";
|
|
3
3
|
/*!
|
|
4
|
-
@versini/ui-menu v5.
|
|
4
|
+
@versini/ui-menu v5.1.1
|
|
5
5
|
ยฉ 2025 gizmette.com
|
|
6
6
|
*/
|
|
7
7
|
try {
|
|
8
8
|
window.__VERSINI_UI_MENU__ || (window.__VERSINI_UI_MENU__ = {
|
|
9
|
-
version: "5.
|
|
10
|
-
buildTime: "10/
|
|
9
|
+
version: "5.1.1",
|
|
10
|
+
buildTime: "10/20/2025 03:40 PM EDT",
|
|
11
11
|
homepage: "https://github.com/aversini/ui-components",
|
|
12
12
|
license: "MIT"
|
|
13
13
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@versini/ui-menu",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.1.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "Arno Versini",
|
|
6
6
|
"publishConfig": {
|
|
@@ -43,12 +43,12 @@
|
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"@floating-ui/react": "0.27.16",
|
|
45
45
|
"@tailwindcss/typography": "0.5.19",
|
|
46
|
-
"@versini/ui-icons": "4.
|
|
46
|
+
"@versini/ui-icons": "4.13.0",
|
|
47
47
|
"clsx": "2.1.1",
|
|
48
48
|
"tailwindcss": "4.1.14"
|
|
49
49
|
},
|
|
50
50
|
"sideEffects": [
|
|
51
51
|
"**/*.css"
|
|
52
52
|
],
|
|
53
|
-
"gitHead": "
|
|
53
|
+
"gitHead": "b3e3e28ac8c5a3f1b6641dd373cd0bb6f34e3bbe"
|
|
54
54
|
}
|