@versini/ui-dropdown 1.3.6 → 1.4.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/dist/index.d.ts +164 -2
- package/dist/index.js +260 -4
- package/package.json +3 -3
- package/dist/DropdownMenu/DropdownMenu.d.ts +0 -17
- package/dist/DropdownMenu/DropdownMenu.js +0 -196
- package/dist/DropdownMenu/DropdownMenuItem.d.ts +0 -5
- package/dist/DropdownMenu/DropdownMenuItem.js +0 -80
- package/dist/DropdownMenu/DropdownMenuTypes.d.ts +0 -127
- package/dist/DropdownMenu/DropdownMenuTypes.js +0 -9
- package/dist/DropdownMenu/utilities.d.ts +0 -1
- package/dist/DropdownMenu/utilities.js +0 -24
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,164 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { JSX } from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
export declare const DropdownMenu: {
|
|
4
|
+
({ trigger, children, label, defaultPlacement, onOpenChange, mode, focusMode, sideOffset, modal, }: DropdownMenuProps): JSX.Element;
|
|
5
|
+
displayName: string;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export declare const DropdownMenuGroupLabel: {
|
|
9
|
+
({ className, icon, children, ...props }: DropdownMenuGroupLabelProps): JSX.Element;
|
|
10
|
+
displayName: string;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
declare type DropdownMenuGroupLabelProps = {
|
|
14
|
+
/**
|
|
15
|
+
* A React component of type Icon to be placed on the left of the label.
|
|
16
|
+
*/
|
|
17
|
+
icon?: React.ReactNode;
|
|
18
|
+
} & React.HTMLAttributes<HTMLDivElement>;
|
|
19
|
+
|
|
20
|
+
export declare const DropdownMenuItem: {
|
|
21
|
+
({ label, disabled, icon, raw, children, ignoreClick, selected, onSelect, onClick, onFocus, onMouseEnter, ...props }: DropdownMenuItemProps): JSX.Element;
|
|
22
|
+
displayName: string;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
declare type DropdownMenuItemProps = {
|
|
26
|
+
/**
|
|
27
|
+
* The label to use for the menu item.
|
|
28
|
+
*/
|
|
29
|
+
label?: string;
|
|
30
|
+
/**
|
|
31
|
+
* Whether or not the menu item is disabled.
|
|
32
|
+
* @default false
|
|
33
|
+
*/
|
|
34
|
+
disabled?: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* A React component of type Icon to be placed on the left of the label.
|
|
37
|
+
*/
|
|
38
|
+
icon?: React.ReactNode;
|
|
39
|
+
/**
|
|
40
|
+
* Disable internal menu item behavior (click, focus, etc.).
|
|
41
|
+
* @default false
|
|
42
|
+
*/
|
|
43
|
+
raw?: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Children to render when using raw mode.
|
|
46
|
+
*/
|
|
47
|
+
children?: React.ReactNode;
|
|
48
|
+
/**
|
|
49
|
+
* Whether or not the menu should close when the menu item is selected.
|
|
50
|
+
* @default false
|
|
51
|
+
*/
|
|
52
|
+
ignoreClick?: boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Whether or not the menu item is selected.
|
|
55
|
+
* @default undefined
|
|
56
|
+
*/
|
|
57
|
+
selected?: boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Callback fired when the menu item is selected.
|
|
60
|
+
*/
|
|
61
|
+
onSelect?: (event: Event) => void;
|
|
62
|
+
/**
|
|
63
|
+
* Optional click handler.
|
|
64
|
+
*/
|
|
65
|
+
onClick?: (event: React.MouseEvent<HTMLDivElement>) => void;
|
|
66
|
+
/**
|
|
67
|
+
* Optional focus handler.
|
|
68
|
+
*/
|
|
69
|
+
onFocus?: (event: React.FocusEvent<HTMLDivElement>) => void;
|
|
70
|
+
/**
|
|
71
|
+
* Optional mouse enter handler.
|
|
72
|
+
*/
|
|
73
|
+
onMouseEnter?: (event: React.MouseEvent<HTMLDivElement>) => void;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
declare type DropdownMenuProps = {
|
|
77
|
+
/**
|
|
78
|
+
* The component to use to open the dropdown menu, e.g. a ButtonIcon, a Button, etc.
|
|
79
|
+
* Required for root menus, omit for nested sub-menus (use label instead).
|
|
80
|
+
*/
|
|
81
|
+
trigger?: React.ReactNode;
|
|
82
|
+
/**
|
|
83
|
+
* The children to render (DropdownMenuItem, DropdownMenuSeparator, etc.).
|
|
84
|
+
*/
|
|
85
|
+
children?: React.ReactNode;
|
|
86
|
+
/**
|
|
87
|
+
* The default location of the popup.
|
|
88
|
+
* @default "bottom-start"
|
|
89
|
+
*/
|
|
90
|
+
defaultPlacement?: "bottom" | "bottom-start" | "bottom-end" | "top" | "top-start" | "top-end" | "left" | "left-start" | "left-end" | "right" | "right-start" | "right-end";
|
|
91
|
+
/**
|
|
92
|
+
* The type of focus for the Button. This will change the color
|
|
93
|
+
* of the focus ring around the Button.
|
|
94
|
+
*/
|
|
95
|
+
focusMode?: "dark" | "light" | "system" | "alt-system";
|
|
96
|
+
/**
|
|
97
|
+
* The type of Button trigger. This will change the color of the Button.
|
|
98
|
+
*/
|
|
99
|
+
mode?: "dark" | "light" | "system" | "alt-system";
|
|
100
|
+
/**
|
|
101
|
+
* The label to use for the menu button (root menu) or the sub-menu trigger text (nested menu).
|
|
102
|
+
* When used without a trigger, this creates a nested sub-menu.
|
|
103
|
+
*/
|
|
104
|
+
label?: string;
|
|
105
|
+
/**
|
|
106
|
+
* Callback fired when the component is opened or closed.
|
|
107
|
+
* @param open whether or not the menu is open
|
|
108
|
+
*/
|
|
109
|
+
onOpenChange?: (open: boolean) => void;
|
|
110
|
+
/**
|
|
111
|
+
* The offset distance from the trigger element.
|
|
112
|
+
* @default 10
|
|
113
|
+
*/
|
|
114
|
+
sideOffset?: number;
|
|
115
|
+
/**
|
|
116
|
+
* Whether the dropdown menu is modal (locks interaction outside).
|
|
117
|
+
* @default true
|
|
118
|
+
*/
|
|
119
|
+
modal?: boolean;
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
export declare const DropdownMenuSeparator: {
|
|
123
|
+
({ className, ...props }: DropdownMenuSeparatorProps): JSX.Element;
|
|
124
|
+
displayName: string;
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
declare type DropdownMenuSeparatorProps = React.HTMLAttributes<HTMLDivElement>;
|
|
128
|
+
|
|
129
|
+
export declare const DropdownMenuSub: {
|
|
130
|
+
({ label, icon, children, disabled, sideOffset, alignOffset, }: DropdownMenuSubProps): JSX.Element;
|
|
131
|
+
displayName: string;
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
declare type DropdownMenuSubProps = {
|
|
135
|
+
/**
|
|
136
|
+
* The label for the sub-menu trigger.
|
|
137
|
+
*/
|
|
138
|
+
label: string;
|
|
139
|
+
/**
|
|
140
|
+
* A React component of type Icon to be placed on the left of the label.
|
|
141
|
+
*/
|
|
142
|
+
icon?: React.ReactNode;
|
|
143
|
+
/**
|
|
144
|
+
* The children to render inside the sub-menu.
|
|
145
|
+
*/
|
|
146
|
+
children?: React.ReactNode;
|
|
147
|
+
/**
|
|
148
|
+
* Whether the sub-menu trigger is disabled.
|
|
149
|
+
* @default false
|
|
150
|
+
*/
|
|
151
|
+
disabled?: boolean;
|
|
152
|
+
/**
|
|
153
|
+
* The offset distance from the sub-menu trigger.
|
|
154
|
+
* @default 2
|
|
155
|
+
*/
|
|
156
|
+
sideOffset?: number;
|
|
157
|
+
/**
|
|
158
|
+
* The alignment offset for the sub-menu.
|
|
159
|
+
* @default -4
|
|
160
|
+
*/
|
|
161
|
+
alignOffset?: number;
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
export { }
|
package/dist/index.js
CHANGED
|
@@ -1,12 +1,268 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
@versini/ui-dropdown v1.
|
|
2
|
+
@versini/ui-dropdown v1.4.0
|
|
3
3
|
© 2026 gizmette.com
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
import { Content, Item, Label, Portal, Root, Separator, Sub, SubContent, SubTrigger, Trigger } from "@radix-ui/react-dropdown-menu";
|
|
8
|
+
import { IconNext, IconSelected, IconUnSelected } from "@versini/ui-icons";
|
|
9
|
+
import clsx from "clsx";
|
|
10
|
+
import { cloneElement, useRef, useState } from "react";
|
|
8
11
|
|
|
9
|
-
;// CONCATENATED MODULE: ./src/components/index.ts
|
|
10
12
|
|
|
11
13
|
|
|
12
14
|
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
const getDisplayName = (element)=>{
|
|
18
|
+
if (typeof element === "string") {
|
|
19
|
+
return element;
|
|
20
|
+
}
|
|
21
|
+
if (typeof element === "function") {
|
|
22
|
+
return element.displayName || element.name || "Component";
|
|
23
|
+
}
|
|
24
|
+
if (typeof element === "object" && element !== null && "type" in element) {
|
|
25
|
+
const type = element.type;
|
|
26
|
+
if (typeof type === "function" || typeof type === "object") {
|
|
27
|
+
/* v8 ignore start */ return type.displayName || type.name || "Component";
|
|
28
|
+
/* v8 ignore stop */ }
|
|
29
|
+
}
|
|
30
|
+
return "Element";
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
const CONTENT_CLASS = "z-100 rounded-md bg-surface-light shadow-sm shadow-border-dark outline-hidden p-3 sm:p-2 prose prose-dark";
|
|
40
|
+
const SUB_CONTENT_CLASS = "z-[60] rounded-md bg-surface-light shadow-sm shadow-border-dark outline-hidden p-3 sm:p-2 mx-3";
|
|
41
|
+
const SUB_TRIGGER_CLASS = clsx("flex items-center flex-row justify-between", "w-full", "m-0 first:mt-0 mt-2 sm:mt-1 px-2 py-1", "rounded-md border border-transparent", "text-left text-base select-none cursor-pointer", "outline-hidden focus:border focus:border-border-medium focus:bg-surface-lighter focus:underline", "disabled:cursor-not-allowed disabled:text-copy-medium", "data-highlighted:bg-surface-lighter data-highlighted:border-border-medium data-highlighted:underline", "data-[state=open]:bg-surface-lighter");
|
|
42
|
+
/**
|
|
43
|
+
* Convert Radix placement format to our simplified format.
|
|
44
|
+
*/ const getRadixSide = (placement)=>{
|
|
45
|
+
/* v8 ignore start */ if (!placement) {
|
|
46
|
+
return "bottom";
|
|
47
|
+
}
|
|
48
|
+
/* v8 ignore stop */ if (placement.startsWith("top")) {
|
|
49
|
+
return "top";
|
|
50
|
+
}
|
|
51
|
+
if (placement.startsWith("left")) {
|
|
52
|
+
return "left";
|
|
53
|
+
}
|
|
54
|
+
if (placement.startsWith("right")) {
|
|
55
|
+
return "right";
|
|
56
|
+
}
|
|
57
|
+
return "bottom";
|
|
58
|
+
};
|
|
59
|
+
const getRadixAlign = (placement)=>{
|
|
60
|
+
/* v8 ignore start */ if (!placement) {
|
|
61
|
+
return "start";
|
|
62
|
+
}
|
|
63
|
+
/* v8 ignore stop */ if (placement.endsWith("-start")) {
|
|
64
|
+
return "start";
|
|
65
|
+
}
|
|
66
|
+
if (placement.endsWith("-end")) {
|
|
67
|
+
return "end";
|
|
68
|
+
}
|
|
69
|
+
return "center";
|
|
70
|
+
};
|
|
71
|
+
const DropdownMenu = ({ trigger, children, label = "Open menu", defaultPlacement = "bottom-start", onOpenChange, mode = "system", focusMode = "system", sideOffset = 10, modal = true })=>{
|
|
72
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
73
|
+
// Track the portal container - either explicitly passed or auto-detected dialog
|
|
74
|
+
const [portalContainer, setPortalContainer] = useState(undefined);
|
|
75
|
+
const noInternalClick = getDisplayName(trigger) === "Button" || getDisplayName(trigger) === "ButtonIcon";
|
|
76
|
+
const uiButtonsExtraProps = noInternalClick ? {
|
|
77
|
+
noInternalClick,
|
|
78
|
+
focusMode,
|
|
79
|
+
mode
|
|
80
|
+
} : {};
|
|
81
|
+
const triggerRef = useRef(null);
|
|
82
|
+
/* v8 ignore start - trigger is required in practice */ const triggerElement = trigger ? /*#__PURE__*/ cloneElement(trigger, {
|
|
83
|
+
...uiButtonsExtraProps,
|
|
84
|
+
"aria-label": label,
|
|
85
|
+
ref: triggerRef
|
|
86
|
+
}) : null;
|
|
87
|
+
/* v8 ignore stop */ const handleOpenChange = (open)=>{
|
|
88
|
+
setIsOpen(open);
|
|
89
|
+
onOpenChange?.(open);
|
|
90
|
+
/**
|
|
91
|
+
* When the menu opens, check if we're inside a native <dialog> element
|
|
92
|
+
* that's shown modally. If so, we need to portal the dropdown content
|
|
93
|
+
* into the dialog so it appears in the browser's top layer.
|
|
94
|
+
* Without this, the dropdown would render to document.body which is
|
|
95
|
+
* behind the dialog's top layer and therefore invisible.
|
|
96
|
+
*/ if (open && triggerRef.current) {
|
|
97
|
+
// Auto-detect if we're inside a native <dialog> element shown modally
|
|
98
|
+
const closestDialog = triggerRef.current.closest("dialog");
|
|
99
|
+
/* v8 ignore start - dialog detection cannot be fully tested without native showModal */ if (closestDialog?.open) {
|
|
100
|
+
setPortalContainer(closestDialog);
|
|
101
|
+
} else {
|
|
102
|
+
setPortalContainer(undefined);
|
|
103
|
+
}
|
|
104
|
+
/* v8 ignore stop */ /**
|
|
105
|
+
* Dispatch a click event to parent elements.
|
|
106
|
+
* This ensures that parent components like Tooltip can detect the
|
|
107
|
+
* interaction and respond appropriately (e.g., disable tooltip display).
|
|
108
|
+
*/ const clickEvent = new MouseEvent("click", {
|
|
109
|
+
bubbles: true,
|
|
110
|
+
cancelable: true,
|
|
111
|
+
view: window
|
|
112
|
+
});
|
|
113
|
+
triggerRef.current.dispatchEvent(clickEvent);
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
return /*#__PURE__*/ jsxs(Root, {
|
|
117
|
+
onOpenChange: handleOpenChange,
|
|
118
|
+
modal: modal,
|
|
119
|
+
children: [
|
|
120
|
+
/*#__PURE__*/ jsx(Trigger, {
|
|
121
|
+
asChild: true,
|
|
122
|
+
"data-state": isOpen ? "open" : "closed",
|
|
123
|
+
children: triggerElement
|
|
124
|
+
}),
|
|
125
|
+
/*#__PURE__*/ jsx(Portal, {
|
|
126
|
+
container: portalContainer,
|
|
127
|
+
children: /*#__PURE__*/ jsx(Content, {
|
|
128
|
+
className: CONTENT_CLASS,
|
|
129
|
+
sideOffset: sideOffset,
|
|
130
|
+
side: getRadixSide(defaultPlacement),
|
|
131
|
+
align: getRadixAlign(defaultPlacement),
|
|
132
|
+
loop: true,
|
|
133
|
+
children: children
|
|
134
|
+
})
|
|
135
|
+
})
|
|
136
|
+
]
|
|
137
|
+
});
|
|
138
|
+
};
|
|
139
|
+
DropdownMenu.displayName = "DropdownMenu";
|
|
140
|
+
const DropdownMenuSub = ({ label, icon, children, disabled = false, sideOffset = 2, alignOffset = -4 })=>{
|
|
141
|
+
const labelSpanClass = icon ? "pl-2" : "";
|
|
142
|
+
return /*#__PURE__*/ jsxs(Sub, {
|
|
143
|
+
children: [
|
|
144
|
+
/*#__PURE__*/ jsxs(SubTrigger, {
|
|
145
|
+
className: SUB_TRIGGER_CLASS,
|
|
146
|
+
disabled: disabled,
|
|
147
|
+
children: [
|
|
148
|
+
/*#__PURE__*/ jsxs("span", {
|
|
149
|
+
className: "flex items-center",
|
|
150
|
+
children: [
|
|
151
|
+
icon,
|
|
152
|
+
/*#__PURE__*/ jsx("span", {
|
|
153
|
+
className: labelSpanClass,
|
|
154
|
+
children: label
|
|
155
|
+
})
|
|
156
|
+
]
|
|
157
|
+
}),
|
|
158
|
+
/*#__PURE__*/ jsx(IconNext, {
|
|
159
|
+
className: "ml-2",
|
|
160
|
+
size: "size-3",
|
|
161
|
+
monotone: true
|
|
162
|
+
})
|
|
163
|
+
]
|
|
164
|
+
}),
|
|
165
|
+
/*#__PURE__*/ jsx(Portal, {
|
|
166
|
+
children: /*#__PURE__*/ jsx(SubContent, {
|
|
167
|
+
className: SUB_CONTENT_CLASS,
|
|
168
|
+
sideOffset: sideOffset,
|
|
169
|
+
alignOffset: alignOffset,
|
|
170
|
+
loop: true,
|
|
171
|
+
children: children
|
|
172
|
+
})
|
|
173
|
+
})
|
|
174
|
+
]
|
|
175
|
+
});
|
|
176
|
+
};
|
|
177
|
+
DropdownMenuSub.displayName = "DropdownMenuSub";
|
|
178
|
+
const DropdownMenuSeparator = ({ className, ...props })=>{
|
|
179
|
+
const separatorClass = clsx(className, "my-1 border-t border-border-medium");
|
|
180
|
+
return /*#__PURE__*/ jsx(Separator, {
|
|
181
|
+
className: separatorClass,
|
|
182
|
+
...props
|
|
183
|
+
});
|
|
184
|
+
};
|
|
185
|
+
DropdownMenuSeparator.displayName = "DropdownMenuSeparator";
|
|
186
|
+
const DropdownMenuGroupLabel = ({ className, icon, children, ...props })=>{
|
|
187
|
+
const groupLabelClass = clsx(className, "pt-1 pb-2 mb-2", "text-sm text-copy-dark font-bold", "border-b border-border-medium", icon && "flex items-center");
|
|
188
|
+
const labelSpanClass = icon ? "px-2" : "";
|
|
189
|
+
return /*#__PURE__*/ jsxs(Label, {
|
|
190
|
+
className: groupLabelClass,
|
|
191
|
+
...props,
|
|
192
|
+
children: [
|
|
193
|
+
icon,
|
|
194
|
+
/*#__PURE__*/ jsx("span", {
|
|
195
|
+
className: labelSpanClass,
|
|
196
|
+
children: children
|
|
197
|
+
})
|
|
198
|
+
]
|
|
199
|
+
});
|
|
200
|
+
};
|
|
201
|
+
DropdownMenuGroupLabel.displayName = "DropdownMenuGroupLabel";
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
const ITEM_CLASS = clsx("flex flex-row items-center", "w-full", "m-0 first:mt-0 mt-2 sm:mt-1 px-2 py-1", "rounded-md border border-transparent", "text-left text-base select-none cursor-pointer", "outline-hidden focus:border focus:border-border-medium focus:bg-surface-lighter focus:underline", "disabled:cursor-not-allowed disabled:text-copy-medium", "data-highlighted:bg-surface-lighter data-highlighted:border-border-medium data-highlighted:underline", "data-disabled:cursor-not-allowed data-disabled:text-copy-medium");
|
|
208
|
+
const DropdownMenuItem = ({ label, disabled, icon, raw = false, children, ignoreClick = false, selected, onSelect, onClick, onFocus, onMouseEnter, ...props })=>{
|
|
209
|
+
let buttonSpanClass = "";
|
|
210
|
+
if (raw && children) {
|
|
211
|
+
return /*#__PURE__*/ jsx(Item, {
|
|
212
|
+
className: "outline-hidden",
|
|
213
|
+
onSelect: (event)=>{
|
|
214
|
+
if (ignoreClick) {
|
|
215
|
+
event.preventDefault();
|
|
216
|
+
}
|
|
217
|
+
onSelect?.(event);
|
|
218
|
+
/* v8 ignore start - optional onClick may not be provided */ onClick?.(event);
|
|
219
|
+
/* v8 ignore stop */ },
|
|
220
|
+
onMouseEnter: onMouseEnter,
|
|
221
|
+
...props,
|
|
222
|
+
children: children
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
if (icon) {
|
|
226
|
+
buttonSpanClass = "pl-2";
|
|
227
|
+
}
|
|
228
|
+
const itemClass = clsx(ITEM_CLASS, {
|
|
229
|
+
"bg-none": !disabled && !selected
|
|
230
|
+
});
|
|
231
|
+
const handleSelect = (event)=>{
|
|
232
|
+
if (ignoreClick) {
|
|
233
|
+
event.preventDefault();
|
|
234
|
+
}
|
|
235
|
+
onSelect?.(event);
|
|
236
|
+
// Also call onClick for compatibility with common patterns
|
|
237
|
+
/* v8 ignore start - optional onClick may not be provided */ onClick?.(event);
|
|
238
|
+
/* v8 ignore stop */ };
|
|
239
|
+
return /*#__PURE__*/ jsxs(Item, {
|
|
240
|
+
className: itemClass,
|
|
241
|
+
disabled: disabled,
|
|
242
|
+
onSelect: handleSelect,
|
|
243
|
+
onFocus: onFocus,
|
|
244
|
+
onMouseEnter: onMouseEnter,
|
|
245
|
+
...props,
|
|
246
|
+
children: [
|
|
247
|
+
selected === true && /*#__PURE__*/ jsx(IconSelected, {
|
|
248
|
+
className: "text-copy-success mr-2",
|
|
249
|
+
size: "size-4"
|
|
250
|
+
}),
|
|
251
|
+
selected === false && /*#__PURE__*/ jsx(IconUnSelected, {
|
|
252
|
+
className: "text-copy-medium mr-2",
|
|
253
|
+
size: "size-4"
|
|
254
|
+
}),
|
|
255
|
+
icon,
|
|
256
|
+
label && /*#__PURE__*/ jsx("span", {
|
|
257
|
+
className: buttonSpanClass,
|
|
258
|
+
children: label
|
|
259
|
+
})
|
|
260
|
+
]
|
|
261
|
+
});
|
|
262
|
+
};
|
|
263
|
+
DropdownMenuItem.displayName = "DropdownMenuItem";
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
export { DropdownMenu, DropdownMenuGroupLabel, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuSub };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@versini/ui-dropdown",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "Arno Versini",
|
|
6
6
|
"publishConfig": {
|
|
@@ -43,12 +43,12 @@
|
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"@radix-ui/react-dropdown-menu": "2.1.16",
|
|
45
45
|
"@tailwindcss/typography": "0.5.19",
|
|
46
|
-
"@versini/ui-icons": "4.
|
|
46
|
+
"@versini/ui-icons": "4.17.0",
|
|
47
47
|
"clsx": "2.1.1",
|
|
48
48
|
"tailwindcss": "4.1.18"
|
|
49
49
|
},
|
|
50
50
|
"sideEffects": [
|
|
51
51
|
"**/*.css"
|
|
52
52
|
],
|
|
53
|
-
"gitHead": "
|
|
53
|
+
"gitHead": "a453a0e3b6497b46673b9f3b14dfa70562fc8168"
|
|
54
54
|
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import type { DropdownMenuGroupLabelProps, DropdownMenuProps, DropdownMenuSeparatorProps, DropdownMenuSubProps } from "./DropdownMenuTypes";
|
|
2
|
-
export declare const DropdownMenu: {
|
|
3
|
-
({ trigger, children, label, defaultPlacement, onOpenChange, mode, focusMode, sideOffset, modal, }: DropdownMenuProps): import("react/jsx-runtime").JSX.Element;
|
|
4
|
-
displayName: string;
|
|
5
|
-
};
|
|
6
|
-
export declare const DropdownMenuSub: {
|
|
7
|
-
({ label, icon, children, disabled, sideOffset, alignOffset, }: DropdownMenuSubProps): import("react/jsx-runtime").JSX.Element;
|
|
8
|
-
displayName: string;
|
|
9
|
-
};
|
|
10
|
-
export declare const DropdownMenuSeparator: {
|
|
11
|
-
({ className, ...props }: DropdownMenuSeparatorProps): import("react/jsx-runtime").JSX.Element;
|
|
12
|
-
displayName: string;
|
|
13
|
-
};
|
|
14
|
-
export declare const DropdownMenuGroupLabel: {
|
|
15
|
-
({ className, icon, children, ...props }: DropdownMenuGroupLabelProps): import("react/jsx-runtime").JSX.Element;
|
|
16
|
-
displayName: string;
|
|
17
|
-
};
|
|
@@ -1,196 +0,0 @@
|
|
|
1
|
-
/*!
|
|
2
|
-
@versini/ui-dropdown v1.3.6
|
|
3
|
-
© 2026 gizmette.com
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
-
import { Content, Label, Portal, Root, Separator, Sub, SubContent, SubTrigger, Trigger } from "@radix-ui/react-dropdown-menu";
|
|
8
|
-
import { IconNext } from "@versini/ui-icons";
|
|
9
|
-
import clsx from "clsx";
|
|
10
|
-
import { cloneElement, useRef, useState } from "react";
|
|
11
|
-
import { getDisplayName } from "./utilities.js";
|
|
12
|
-
|
|
13
|
-
;// CONCATENATED MODULE: external "react/jsx-runtime"
|
|
14
|
-
|
|
15
|
-
;// CONCATENATED MODULE: external "@radix-ui/react-dropdown-menu"
|
|
16
|
-
|
|
17
|
-
;// CONCATENATED MODULE: external "@versini/ui-icons"
|
|
18
|
-
|
|
19
|
-
;// CONCATENATED MODULE: external "clsx"
|
|
20
|
-
|
|
21
|
-
;// CONCATENATED MODULE: external "react"
|
|
22
|
-
|
|
23
|
-
;// CONCATENATED MODULE: external "./utilities.js"
|
|
24
|
-
|
|
25
|
-
;// CONCATENATED MODULE: ./src/components/DropdownMenu/DropdownMenu.tsx
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const CONTENT_CLASS = "z-100 rounded-md bg-surface-light shadow-sm shadow-border-dark outline-hidden p-3 sm:p-2 prose prose-dark";
|
|
33
|
-
const SUB_CONTENT_CLASS = "z-[60] rounded-md bg-surface-light shadow-sm shadow-border-dark outline-hidden p-3 sm:p-2 mx-3";
|
|
34
|
-
const SUB_TRIGGER_CLASS = clsx("flex items-center flex-row justify-between", "w-full", "m-0 first:mt-0 mt-2 sm:mt-1 px-2 py-1", "rounded-md border border-transparent", "text-left text-base select-none cursor-pointer", "outline-hidden focus:border focus:border-border-medium focus:bg-surface-lighter focus:underline", "disabled:cursor-not-allowed disabled:text-copy-medium", "data-highlighted:bg-surface-lighter data-highlighted:border-border-medium data-highlighted:underline", "data-[state=open]:bg-surface-lighter");
|
|
35
|
-
/**
|
|
36
|
-
* Convert Radix placement format to our simplified format.
|
|
37
|
-
*/ const getRadixSide = (placement)=>{
|
|
38
|
-
/* v8 ignore start */ if (!placement) {
|
|
39
|
-
return "bottom";
|
|
40
|
-
}
|
|
41
|
-
/* v8 ignore stop */ if (placement.startsWith("top")) {
|
|
42
|
-
return "top";
|
|
43
|
-
}
|
|
44
|
-
if (placement.startsWith("left")) {
|
|
45
|
-
return "left";
|
|
46
|
-
}
|
|
47
|
-
if (placement.startsWith("right")) {
|
|
48
|
-
return "right";
|
|
49
|
-
}
|
|
50
|
-
return "bottom";
|
|
51
|
-
};
|
|
52
|
-
const getRadixAlign = (placement)=>{
|
|
53
|
-
/* v8 ignore start */ if (!placement) {
|
|
54
|
-
return "start";
|
|
55
|
-
}
|
|
56
|
-
/* v8 ignore stop */ if (placement.endsWith("-start")) {
|
|
57
|
-
return "start";
|
|
58
|
-
}
|
|
59
|
-
if (placement.endsWith("-end")) {
|
|
60
|
-
return "end";
|
|
61
|
-
}
|
|
62
|
-
return "center";
|
|
63
|
-
};
|
|
64
|
-
const DropdownMenu = ({ trigger, children, label = "Open menu", defaultPlacement = "bottom-start", onOpenChange, mode = "system", focusMode = "system", sideOffset = 10, modal = true })=>{
|
|
65
|
-
const [isOpen, setIsOpen] = useState(false);
|
|
66
|
-
// Track the portal container - either explicitly passed or auto-detected dialog
|
|
67
|
-
const [portalContainer, setPortalContainer] = useState(undefined);
|
|
68
|
-
const noInternalClick = getDisplayName(trigger) === "Button" || getDisplayName(trigger) === "ButtonIcon";
|
|
69
|
-
const uiButtonsExtraProps = noInternalClick ? {
|
|
70
|
-
noInternalClick,
|
|
71
|
-
focusMode,
|
|
72
|
-
mode
|
|
73
|
-
} : {};
|
|
74
|
-
const triggerRef = useRef(null);
|
|
75
|
-
/* v8 ignore start - trigger is required in practice */ const triggerElement = trigger ? /*#__PURE__*/ cloneElement(trigger, {
|
|
76
|
-
...uiButtonsExtraProps,
|
|
77
|
-
"aria-label": label,
|
|
78
|
-
ref: triggerRef
|
|
79
|
-
}) : null;
|
|
80
|
-
/* v8 ignore stop */ const handleOpenChange = (open)=>{
|
|
81
|
-
setIsOpen(open);
|
|
82
|
-
onOpenChange?.(open);
|
|
83
|
-
/**
|
|
84
|
-
* When the menu opens, check if we're inside a native <dialog> element
|
|
85
|
-
* that's shown modally. If so, we need to portal the dropdown content
|
|
86
|
-
* into the dialog so it appears in the browser's top layer.
|
|
87
|
-
* Without this, the dropdown would render to document.body which is
|
|
88
|
-
* behind the dialog's top layer and therefore invisible.
|
|
89
|
-
*/ if (open && triggerRef.current) {
|
|
90
|
-
// Auto-detect if we're inside a native <dialog> element shown modally
|
|
91
|
-
const closestDialog = triggerRef.current.closest("dialog");
|
|
92
|
-
/* v8 ignore start - dialog detection cannot be fully tested without native showModal */ if (closestDialog?.open) {
|
|
93
|
-
setPortalContainer(closestDialog);
|
|
94
|
-
} else {
|
|
95
|
-
setPortalContainer(undefined);
|
|
96
|
-
}
|
|
97
|
-
/* v8 ignore stop */ /**
|
|
98
|
-
* Dispatch a click event to parent elements.
|
|
99
|
-
* This ensures that parent components like Tooltip can detect the
|
|
100
|
-
* interaction and respond appropriately (e.g., disable tooltip display).
|
|
101
|
-
*/ const clickEvent = new MouseEvent("click", {
|
|
102
|
-
bubbles: true,
|
|
103
|
-
cancelable: true,
|
|
104
|
-
view: window
|
|
105
|
-
});
|
|
106
|
-
triggerRef.current.dispatchEvent(clickEvent);
|
|
107
|
-
}
|
|
108
|
-
};
|
|
109
|
-
return /*#__PURE__*/ jsxs(Root, {
|
|
110
|
-
onOpenChange: handleOpenChange,
|
|
111
|
-
modal: modal,
|
|
112
|
-
children: [
|
|
113
|
-
/*#__PURE__*/ jsx(Trigger, {
|
|
114
|
-
asChild: true,
|
|
115
|
-
"data-state": isOpen ? "open" : "closed",
|
|
116
|
-
children: triggerElement
|
|
117
|
-
}),
|
|
118
|
-
/*#__PURE__*/ jsx(Portal, {
|
|
119
|
-
container: portalContainer,
|
|
120
|
-
children: /*#__PURE__*/ jsx(Content, {
|
|
121
|
-
className: CONTENT_CLASS,
|
|
122
|
-
sideOffset: sideOffset,
|
|
123
|
-
side: getRadixSide(defaultPlacement),
|
|
124
|
-
align: getRadixAlign(defaultPlacement),
|
|
125
|
-
loop: true,
|
|
126
|
-
children: children
|
|
127
|
-
})
|
|
128
|
-
})
|
|
129
|
-
]
|
|
130
|
-
});
|
|
131
|
-
};
|
|
132
|
-
DropdownMenu.displayName = "DropdownMenu";
|
|
133
|
-
const DropdownMenuSub = ({ label, icon, children, disabled = false, sideOffset = 2, alignOffset = -4 })=>{
|
|
134
|
-
const labelSpanClass = icon ? "pl-2" : "";
|
|
135
|
-
return /*#__PURE__*/ jsxs(Sub, {
|
|
136
|
-
children: [
|
|
137
|
-
/*#__PURE__*/ jsxs(SubTrigger, {
|
|
138
|
-
className: SUB_TRIGGER_CLASS,
|
|
139
|
-
disabled: disabled,
|
|
140
|
-
children: [
|
|
141
|
-
/*#__PURE__*/ jsxs("span", {
|
|
142
|
-
className: "flex items-center",
|
|
143
|
-
children: [
|
|
144
|
-
icon,
|
|
145
|
-
/*#__PURE__*/ jsx("span", {
|
|
146
|
-
className: labelSpanClass,
|
|
147
|
-
children: label
|
|
148
|
-
})
|
|
149
|
-
]
|
|
150
|
-
}),
|
|
151
|
-
/*#__PURE__*/ jsx(IconNext, {
|
|
152
|
-
className: "ml-2",
|
|
153
|
-
size: "size-3",
|
|
154
|
-
monotone: true
|
|
155
|
-
})
|
|
156
|
-
]
|
|
157
|
-
}),
|
|
158
|
-
/*#__PURE__*/ jsx(Portal, {
|
|
159
|
-
children: /*#__PURE__*/ jsx(SubContent, {
|
|
160
|
-
className: SUB_CONTENT_CLASS,
|
|
161
|
-
sideOffset: sideOffset,
|
|
162
|
-
alignOffset: alignOffset,
|
|
163
|
-
loop: true,
|
|
164
|
-
children: children
|
|
165
|
-
})
|
|
166
|
-
})
|
|
167
|
-
]
|
|
168
|
-
});
|
|
169
|
-
};
|
|
170
|
-
DropdownMenuSub.displayName = "DropdownMenuSub";
|
|
171
|
-
const DropdownMenuSeparator = ({ className, ...props })=>{
|
|
172
|
-
const separatorClass = clsx(className, "my-1 border-t border-border-medium");
|
|
173
|
-
return /*#__PURE__*/ jsx(Separator, {
|
|
174
|
-
className: separatorClass,
|
|
175
|
-
...props
|
|
176
|
-
});
|
|
177
|
-
};
|
|
178
|
-
DropdownMenuSeparator.displayName = "DropdownMenuSeparator";
|
|
179
|
-
const DropdownMenuGroupLabel = ({ className, icon, children, ...props })=>{
|
|
180
|
-
const groupLabelClass = clsx(className, "pt-1 pb-2 mb-2", "text-sm text-copy-dark font-bold", "border-b border-border-medium", icon && "flex items-center");
|
|
181
|
-
const labelSpanClass = icon ? "px-2" : "";
|
|
182
|
-
return /*#__PURE__*/ jsxs(Label, {
|
|
183
|
-
className: groupLabelClass,
|
|
184
|
-
...props,
|
|
185
|
-
children: [
|
|
186
|
-
icon,
|
|
187
|
-
/*#__PURE__*/ jsx("span", {
|
|
188
|
-
className: labelSpanClass,
|
|
189
|
-
children: children
|
|
190
|
-
})
|
|
191
|
-
]
|
|
192
|
-
});
|
|
193
|
-
};
|
|
194
|
-
DropdownMenuGroupLabel.displayName = "DropdownMenuGroupLabel";
|
|
195
|
-
|
|
196
|
-
export { DropdownMenu, DropdownMenuGroupLabel, DropdownMenuSeparator, DropdownMenuSub };
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import type { DropdownMenuItemProps } from "./DropdownMenuTypes";
|
|
2
|
-
export declare const DropdownMenuItem: {
|
|
3
|
-
({ label, disabled, icon, raw, children, ignoreClick, selected, onSelect, onClick, onFocus, ...props }: DropdownMenuItemProps): import("react/jsx-runtime").JSX.Element;
|
|
4
|
-
displayName: string;
|
|
5
|
-
};
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
/*!
|
|
2
|
-
@versini/ui-dropdown v1.3.6
|
|
3
|
-
© 2026 gizmette.com
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
-
import { Item } from "@radix-ui/react-dropdown-menu";
|
|
8
|
-
import { IconSelected, IconUnSelected } from "@versini/ui-icons";
|
|
9
|
-
import clsx from "clsx";
|
|
10
|
-
|
|
11
|
-
;// CONCATENATED MODULE: external "react/jsx-runtime"
|
|
12
|
-
|
|
13
|
-
;// CONCATENATED MODULE: external "@radix-ui/react-dropdown-menu"
|
|
14
|
-
|
|
15
|
-
;// CONCATENATED MODULE: external "@versini/ui-icons"
|
|
16
|
-
|
|
17
|
-
;// CONCATENATED MODULE: external "clsx"
|
|
18
|
-
|
|
19
|
-
;// CONCATENATED MODULE: ./src/components/DropdownMenu/DropdownMenuItem.tsx
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
const ITEM_CLASS = clsx("flex flex-row items-center", "w-full", "m-0 first:mt-0 mt-2 sm:mt-1 px-2 py-1", "rounded-md border border-transparent", "text-left text-base select-none cursor-pointer", "outline-hidden focus:border focus:border-border-medium focus:bg-surface-lighter focus:underline", "disabled:cursor-not-allowed disabled:text-copy-medium", "data-highlighted:bg-surface-lighter data-highlighted:border-border-medium data-highlighted:underline", "data-disabled:cursor-not-allowed data-disabled:text-copy-medium");
|
|
25
|
-
const DropdownMenuItem = ({ label, disabled, icon, raw = false, children, ignoreClick = false, selected, onSelect, onClick, onFocus, ...props })=>{
|
|
26
|
-
let buttonSpanClass = "";
|
|
27
|
-
if (raw && children) {
|
|
28
|
-
return /*#__PURE__*/ jsx(Item, {
|
|
29
|
-
className: "outline-hidden",
|
|
30
|
-
onSelect: (event)=>{
|
|
31
|
-
if (ignoreClick) {
|
|
32
|
-
event.preventDefault();
|
|
33
|
-
}
|
|
34
|
-
onSelect?.(event);
|
|
35
|
-
/* v8 ignore start - optional onClick may not be provided */ onClick?.(event);
|
|
36
|
-
/* v8 ignore stop */ },
|
|
37
|
-
...props,
|
|
38
|
-
children: children
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
if (icon) {
|
|
42
|
-
buttonSpanClass = "pl-2";
|
|
43
|
-
}
|
|
44
|
-
const itemClass = clsx(ITEM_CLASS, {
|
|
45
|
-
"bg-none": !disabled && !selected
|
|
46
|
-
});
|
|
47
|
-
const handleSelect = (event)=>{
|
|
48
|
-
if (ignoreClick) {
|
|
49
|
-
event.preventDefault();
|
|
50
|
-
}
|
|
51
|
-
onSelect?.(event);
|
|
52
|
-
// Also call onClick for compatibility with common patterns
|
|
53
|
-
/* v8 ignore start - optional onClick may not be provided */ onClick?.(event);
|
|
54
|
-
/* v8 ignore stop */ };
|
|
55
|
-
return /*#__PURE__*/ jsxs(Item, {
|
|
56
|
-
className: itemClass,
|
|
57
|
-
disabled: disabled,
|
|
58
|
-
onSelect: handleSelect,
|
|
59
|
-
onFocus: onFocus,
|
|
60
|
-
...props,
|
|
61
|
-
children: [
|
|
62
|
-
selected === true && /*#__PURE__*/ jsx(IconSelected, {
|
|
63
|
-
className: "text-copy-success mr-2",
|
|
64
|
-
size: "size-4"
|
|
65
|
-
}),
|
|
66
|
-
selected === false && /*#__PURE__*/ jsx(IconUnSelected, {
|
|
67
|
-
className: "text-copy-medium mr-2",
|
|
68
|
-
size: "size-4"
|
|
69
|
-
}),
|
|
70
|
-
icon,
|
|
71
|
-
label && /*#__PURE__*/ jsx("span", {
|
|
72
|
-
className: buttonSpanClass,
|
|
73
|
-
children: label
|
|
74
|
-
})
|
|
75
|
-
]
|
|
76
|
-
});
|
|
77
|
-
};
|
|
78
|
-
DropdownMenuItem.displayName = "DropdownMenuItem";
|
|
79
|
-
|
|
80
|
-
export { DropdownMenuItem };
|
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
export type DropdownMenuProps = {
|
|
2
|
-
/**
|
|
3
|
-
* The component to use to open the dropdown menu, e.g. a ButtonIcon, a Button, etc.
|
|
4
|
-
* Required for root menus, omit for nested sub-menus (use label instead).
|
|
5
|
-
*/
|
|
6
|
-
trigger?: React.ReactNode;
|
|
7
|
-
/**
|
|
8
|
-
* The children to render (DropdownMenuItem, DropdownMenuSeparator, etc.).
|
|
9
|
-
*/
|
|
10
|
-
children?: React.ReactNode;
|
|
11
|
-
/**
|
|
12
|
-
* The default location of the popup.
|
|
13
|
-
* @default "bottom-start"
|
|
14
|
-
*/
|
|
15
|
-
defaultPlacement?: "bottom" | "bottom-start" | "bottom-end" | "top" | "top-start" | "top-end" | "left" | "left-start" | "left-end" | "right" | "right-start" | "right-end";
|
|
16
|
-
/**
|
|
17
|
-
* The type of focus for the Button. This will change the color
|
|
18
|
-
* of the focus ring around the Button.
|
|
19
|
-
*/
|
|
20
|
-
focusMode?: "dark" | "light" | "system" | "alt-system";
|
|
21
|
-
/**
|
|
22
|
-
* The type of Button trigger. This will change the color of the Button.
|
|
23
|
-
*/
|
|
24
|
-
mode?: "dark" | "light" | "system" | "alt-system";
|
|
25
|
-
/**
|
|
26
|
-
* The label to use for the menu button (root menu) or the sub-menu trigger text (nested menu).
|
|
27
|
-
* When used without a trigger, this creates a nested sub-menu.
|
|
28
|
-
*/
|
|
29
|
-
label?: string;
|
|
30
|
-
/**
|
|
31
|
-
* Callback fired when the component is opened or closed.
|
|
32
|
-
* @param open whether or not the menu is open
|
|
33
|
-
*/
|
|
34
|
-
onOpenChange?: (open: boolean) => void;
|
|
35
|
-
/**
|
|
36
|
-
* The offset distance from the trigger element.
|
|
37
|
-
* @default 10
|
|
38
|
-
*/
|
|
39
|
-
sideOffset?: number;
|
|
40
|
-
/**
|
|
41
|
-
* Whether the dropdown menu is modal (locks interaction outside).
|
|
42
|
-
* @default true
|
|
43
|
-
*/
|
|
44
|
-
modal?: boolean;
|
|
45
|
-
};
|
|
46
|
-
export type DropdownMenuItemProps = {
|
|
47
|
-
/**
|
|
48
|
-
* The label to use for the menu item.
|
|
49
|
-
*/
|
|
50
|
-
label?: string;
|
|
51
|
-
/**
|
|
52
|
-
* Whether or not the menu item is disabled.
|
|
53
|
-
* @default false
|
|
54
|
-
*/
|
|
55
|
-
disabled?: boolean;
|
|
56
|
-
/**
|
|
57
|
-
* A React component of type Icon to be placed on the left of the label.
|
|
58
|
-
*/
|
|
59
|
-
icon?: React.ReactNode;
|
|
60
|
-
/**
|
|
61
|
-
* Disable internal menu item behavior (click, focus, etc.).
|
|
62
|
-
* @default false
|
|
63
|
-
*/
|
|
64
|
-
raw?: boolean;
|
|
65
|
-
/**
|
|
66
|
-
* Children to render when using raw mode.
|
|
67
|
-
*/
|
|
68
|
-
children?: React.ReactNode;
|
|
69
|
-
/**
|
|
70
|
-
* Whether or not the menu should close when the menu item is selected.
|
|
71
|
-
* @default false
|
|
72
|
-
*/
|
|
73
|
-
ignoreClick?: boolean;
|
|
74
|
-
/**
|
|
75
|
-
* Whether or not the menu item is selected.
|
|
76
|
-
* @default undefined
|
|
77
|
-
*/
|
|
78
|
-
selected?: boolean;
|
|
79
|
-
/**
|
|
80
|
-
* Callback fired when the menu item is selected.
|
|
81
|
-
*/
|
|
82
|
-
onSelect?: (event: Event) => void;
|
|
83
|
-
/**
|
|
84
|
-
* Optional click handler.
|
|
85
|
-
*/
|
|
86
|
-
onClick?: (event: React.MouseEvent<HTMLDivElement>) => void;
|
|
87
|
-
/**
|
|
88
|
-
* Optional focus handler.
|
|
89
|
-
*/
|
|
90
|
-
onFocus?: (event: React.FocusEvent<HTMLDivElement>) => void;
|
|
91
|
-
};
|
|
92
|
-
export type DropdownMenuSeparatorProps = React.HTMLAttributes<HTMLDivElement>;
|
|
93
|
-
export type DropdownMenuGroupLabelProps = {
|
|
94
|
-
/**
|
|
95
|
-
* A React component of type Icon to be placed on the left of the label.
|
|
96
|
-
*/
|
|
97
|
-
icon?: React.ReactNode;
|
|
98
|
-
} & React.HTMLAttributes<HTMLDivElement>;
|
|
99
|
-
export type DropdownMenuSubProps = {
|
|
100
|
-
/**
|
|
101
|
-
* The label for the sub-menu trigger.
|
|
102
|
-
*/
|
|
103
|
-
label: string;
|
|
104
|
-
/**
|
|
105
|
-
* A React component of type Icon to be placed on the left of the label.
|
|
106
|
-
*/
|
|
107
|
-
icon?: React.ReactNode;
|
|
108
|
-
/**
|
|
109
|
-
* The children to render inside the sub-menu.
|
|
110
|
-
*/
|
|
111
|
-
children?: React.ReactNode;
|
|
112
|
-
/**
|
|
113
|
-
* Whether the sub-menu trigger is disabled.
|
|
114
|
-
* @default false
|
|
115
|
-
*/
|
|
116
|
-
disabled?: boolean;
|
|
117
|
-
/**
|
|
118
|
-
* The offset distance from the sub-menu trigger.
|
|
119
|
-
* @default 2
|
|
120
|
-
*/
|
|
121
|
-
sideOffset?: number;
|
|
122
|
-
/**
|
|
123
|
-
* The alignment offset for the sub-menu.
|
|
124
|
-
* @default -4
|
|
125
|
-
*/
|
|
126
|
-
alignOffset?: number;
|
|
127
|
-
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const getDisplayName: (element: unknown) => string;
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
/*!
|
|
2
|
-
@versini/ui-dropdown v1.3.6
|
|
3
|
-
© 2026 gizmette.com
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
;// CONCATENATED MODULE: ./src/components/DropdownMenu/utilities.ts
|
|
8
|
-
const getDisplayName = (element)=>{
|
|
9
|
-
if (typeof element === "string") {
|
|
10
|
-
return element;
|
|
11
|
-
}
|
|
12
|
-
if (typeof element === "function") {
|
|
13
|
-
return element.displayName || element.name || "Component";
|
|
14
|
-
}
|
|
15
|
-
if (typeof element === "object" && element !== null && "type" in element) {
|
|
16
|
-
const type = element.type;
|
|
17
|
-
if (typeof type === "function" || typeof type === "object") {
|
|
18
|
-
/* v8 ignore start */ return type.displayName || type.name || "Component";
|
|
19
|
-
/* v8 ignore stop */ }
|
|
20
|
-
}
|
|
21
|
-
return "Element";
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
export { getDisplayName };
|