@forwardreach/saas-ui 0.4.0 → 0.5.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/CHANGELOG.md +21 -0
- package/dist/components/dropdown-menu.d.ts +9 -1
- package/dist/components/dropdown-menu.js +8 -5
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.js +1 -0
- package/dist/components/overflow-menu.d.ts +40 -0
- package/dist/components/overflow-menu.js +15 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.5.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 523e143: Add `OverflowMenu` — a "⋯" icon-button that opens a dropdown of low-frequency,
|
|
8
|
+
whole-object actions, composed from the existing Radix `DropdownMenu` primitives.
|
|
9
|
+
Panel contents are composed with the exported `OverflowMenuItem` and
|
|
10
|
+
`OverflowMenuSeparator` aliases.
|
|
11
|
+
|
|
12
|
+
Menu-item highlight (hover/keyboard) now uses the translucent
|
|
13
|
+
`--ssui-overlay-hover` token instead of `--ssui-surface-muted`, and also styles
|
|
14
|
+
Radix's `data-highlighted` state. Solid `surface-muted` was invisible on themes
|
|
15
|
+
where it matches `surface-elevated` (the panel background); a translucent
|
|
16
|
+
overlay reads on any surface.
|
|
17
|
+
|
|
18
|
+
`DropdownMenuContent` (and `OverflowMenu`) also accept a new `portal` prop.
|
|
19
|
+
It defaults to `true`, preserving today's portal-to-`document.body` behavior;
|
|
20
|
+
pass `false` to render the panel inline next to the trigger, which keeps it
|
|
21
|
+
inside the trigger's DOM subtree — needed when the menu lives in a surface that
|
|
22
|
+
tracks focus, such as a click-to-edit editor that persists on blur.
|
|
23
|
+
|
|
3
24
|
## 0.4.0
|
|
4
25
|
|
|
5
26
|
### Minor Changes
|
|
@@ -10,7 +10,15 @@ export declare const DropdownMenuSubTrigger: React.ForwardRefExoticComponent<Omi
|
|
|
10
10
|
inset?: boolean;
|
|
11
11
|
} & React.RefAttributes<HTMLDivElement>>;
|
|
12
12
|
export declare const DropdownMenuSubContent: React.ForwardRefExoticComponent<Omit<DropdownMenuPrimitive.DropdownMenuSubContentProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
13
|
-
export declare const DropdownMenuContent: React.ForwardRefExoticComponent<Omit<DropdownMenuPrimitive.DropdownMenuContentProps & React.RefAttributes<HTMLDivElement>, "ref"> &
|
|
13
|
+
export declare const DropdownMenuContent: React.ForwardRefExoticComponent<Omit<DropdownMenuPrimitive.DropdownMenuContentProps & React.RefAttributes<HTMLDivElement>, "ref"> & {
|
|
14
|
+
/**
|
|
15
|
+
* Render the panel through a portal to `document.body` (the default). Pass
|
|
16
|
+
* `false` to render it inline, next to the trigger — useful when the menu
|
|
17
|
+
* lives inside a subtree that tracks focus (e.g. a click-to-edit editor that
|
|
18
|
+
* persists on blur) and must keep the open panel within its own DOM.
|
|
19
|
+
*/
|
|
20
|
+
portal?: boolean;
|
|
21
|
+
} & React.RefAttributes<HTMLDivElement>>;
|
|
14
22
|
export declare const DropdownMenuItem: React.ForwardRefExoticComponent<Omit<DropdownMenuPrimitive.DropdownMenuItemProps & React.RefAttributes<HTMLDivElement>, "ref"> & {
|
|
15
23
|
inset?: boolean;
|
|
16
24
|
} & React.RefAttributes<HTMLDivElement>>;
|
|
@@ -9,17 +9,20 @@ export const DropdownMenuGroup = DropdownMenuPrimitive.Group;
|
|
|
9
9
|
export const DropdownMenuPortal = DropdownMenuPrimitive.Portal;
|
|
10
10
|
export const DropdownMenuSub = DropdownMenuPrimitive.Sub;
|
|
11
11
|
export const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
|
|
12
|
-
export const DropdownMenuSubTrigger = React.forwardRef(({ children, className, inset, ...props }, ref) => (_jsxs(DropdownMenuPrimitive.SubTrigger, { ref: ref, className: cn("flex cursor-default select-none items-center rounded-[var(--ssui-radius-sm)] px-2 py-1.5 text-sm text-[color:var(--ssui-text)] outline-none focus:bg-[color:var(--ssui-
|
|
12
|
+
export const DropdownMenuSubTrigger = React.forwardRef(({ children, className, inset, ...props }, ref) => (_jsxs(DropdownMenuPrimitive.SubTrigger, { ref: ref, className: cn("flex cursor-default select-none items-center rounded-[var(--ssui-radius-sm)] px-2 py-1.5 text-sm text-[color:var(--ssui-text)] outline-none focus:bg-[color:var(--ssui-overlay-hover)] data-[highlighted]:bg-[color:var(--ssui-overlay-hover)] data-[state=open]:bg-[color:var(--ssui-overlay-hover)]", inset && "pl-8", className), ...props, children: [children, _jsx(ChevronRight, { className: "ml-auto size-4" })] })));
|
|
13
13
|
DropdownMenuSubTrigger.displayName = DropdownMenuPrimitive.SubTrigger.displayName;
|
|
14
14
|
export const DropdownMenuSubContent = React.forwardRef(({ className, ...props }, ref) => (_jsx(DropdownMenuPrimitive.SubContent, { ref: ref, className: cn("z-50 min-w-40 overflow-hidden rounded-[var(--ssui-radius)] border border-[color:var(--ssui-border)] bg-[color:var(--ssui-surface-elevated)] p-1 text-[color:var(--ssui-text)] shadow-[var(--ssui-shadow-md)]", className), ...props })));
|
|
15
15
|
DropdownMenuSubContent.displayName = DropdownMenuPrimitive.SubContent.displayName;
|
|
16
|
-
export const DropdownMenuContent = React.forwardRef(({ className, sideOffset = 6, ...props }, ref) =>
|
|
16
|
+
export const DropdownMenuContent = React.forwardRef(({ className, portal = true, sideOffset = 6, ...props }, ref) => {
|
|
17
|
+
const content = (_jsx(DropdownMenuPrimitive.Content, { ref: ref, sideOffset: sideOffset, className: cn("z-50 min-w-44 overflow-hidden rounded-[var(--ssui-radius)] border border-[color:var(--ssui-border)] bg-[color:var(--ssui-surface-elevated)] p-1 text-[color:var(--ssui-text)] shadow-[var(--ssui-shadow-md)]", className), ...props }));
|
|
18
|
+
return portal ? _jsx(DropdownMenuPrimitive.Portal, { children: content }) : content;
|
|
19
|
+
});
|
|
17
20
|
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
|
|
18
|
-
export const DropdownMenuItem = React.forwardRef(({ className, inset, ...props }, ref) => (_jsx(DropdownMenuPrimitive.Item, { ref: ref, className: cn("relative flex cursor-default select-none items-center gap-2 rounded-[var(--ssui-radius-sm)] px-2 py-1.5 text-sm outline-none transition-colors focus:bg-[color:var(--ssui-
|
|
21
|
+
export const DropdownMenuItem = React.forwardRef(({ className, inset, ...props }, ref) => (_jsx(DropdownMenuPrimitive.Item, { ref: ref, className: cn("relative flex cursor-default select-none items-center gap-2 rounded-[var(--ssui-radius-sm)] px-2 py-1.5 text-sm outline-none transition-colors focus:bg-[color:var(--ssui-overlay-hover)] data-[highlighted]:bg-[color:var(--ssui-overlay-hover)] data-[disabled]:pointer-events-none data-[disabled]:opacity-50", inset && "pl-8", className), ...props })));
|
|
19
22
|
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
|
|
20
|
-
export const DropdownMenuCheckboxItem = React.forwardRef(({ children, className, checked, ...props }, ref) => (_jsxs(DropdownMenuPrimitive.CheckboxItem, { ref: ref, checked: checked, className: cn("relative flex cursor-default select-none items-center rounded-[var(--ssui-radius-sm)] py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-[color:var(--ssui-
|
|
23
|
+
export const DropdownMenuCheckboxItem = React.forwardRef(({ children, className, checked, ...props }, ref) => (_jsxs(DropdownMenuPrimitive.CheckboxItem, { ref: ref, checked: checked, className: cn("relative flex cursor-default select-none items-center rounded-[var(--ssui-radius-sm)] py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-[color:var(--ssui-overlay-hover)] data-[highlighted]:bg-[color:var(--ssui-overlay-hover)] data-[disabled]:pointer-events-none data-[disabled]:opacity-50", className), ...props, children: [_jsx("span", { className: "absolute left-2 flex size-3.5 items-center justify-center", children: _jsx(DropdownMenuPrimitive.ItemIndicator, { children: _jsx(Check, { className: "size-4" }) }) }), children] })));
|
|
21
24
|
DropdownMenuCheckboxItem.displayName = DropdownMenuPrimitive.CheckboxItem.displayName;
|
|
22
|
-
export const DropdownMenuRadioItem = React.forwardRef(({ children, className, ...props }, ref) => (_jsxs(DropdownMenuPrimitive.RadioItem, { ref: ref, className: cn("relative flex cursor-default select-none items-center rounded-[var(--ssui-radius-sm)] py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-[color:var(--ssui-
|
|
25
|
+
export const DropdownMenuRadioItem = React.forwardRef(({ children, className, ...props }, ref) => (_jsxs(DropdownMenuPrimitive.RadioItem, { ref: ref, className: cn("relative flex cursor-default select-none items-center rounded-[var(--ssui-radius-sm)] py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-[color:var(--ssui-overlay-hover)] data-[highlighted]:bg-[color:var(--ssui-overlay-hover)] data-[disabled]:pointer-events-none data-[disabled]:opacity-50", className), ...props, children: [_jsx("span", { className: "absolute left-2 flex size-3.5 items-center justify-center", children: _jsx(DropdownMenuPrimitive.ItemIndicator, { children: _jsx(Circle, { className: "size-2 fill-current" }) }) }), children] })));
|
|
23
26
|
DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
|
|
24
27
|
export const DropdownMenuLabel = React.forwardRef(({ className, inset, ...props }, ref) => (_jsx(DropdownMenuPrimitive.Label, { ref: ref, className: cn("px-2 py-1.5 text-xs font-medium text-[color:var(--ssui-text-muted)]", inset && "pl-8", className), ...props })));
|
|
25
28
|
DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
|
|
@@ -15,6 +15,7 @@ export * from "./inline-rename-input.js";
|
|
|
15
15
|
export * from "./input.js";
|
|
16
16
|
export * from "./list-shell.js";
|
|
17
17
|
export * from "./login.js";
|
|
18
|
+
export * from "./overflow-menu.js";
|
|
18
19
|
export * from "./page-header.js";
|
|
19
20
|
export * from "./request-access.js";
|
|
20
21
|
export * from "./scroll-area.js";
|
package/dist/components/index.js
CHANGED
|
@@ -15,6 +15,7 @@ export * from "./inline-rename-input.js";
|
|
|
15
15
|
export * from "./input.js";
|
|
16
16
|
export * from "./list-shell.js";
|
|
17
17
|
export * from "./login.js";
|
|
18
|
+
export * from "./overflow-menu.js";
|
|
18
19
|
export * from "./page-header.js";
|
|
19
20
|
export * from "./request-access.js";
|
|
20
21
|
export * from "./scroll-area.js";
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { type IconButtonProps } from "./button.js";
|
|
3
|
+
export interface OverflowMenuProps {
|
|
4
|
+
/** Accessible label and tooltip for the trigger button. Defaults to "More actions". */
|
|
5
|
+
label?: string;
|
|
6
|
+
/** Which edge of the trigger the panel aligns to. Defaults to "end". */
|
|
7
|
+
align?: "start" | "center" | "end";
|
|
8
|
+
/** Trigger icon-button size. Defaults to "icon-sm". */
|
|
9
|
+
size?: IconButtonProps["size"];
|
|
10
|
+
/** Trigger icon-button visual variant. Defaults to "ghost". */
|
|
11
|
+
variant?: IconButtonProps["variant"];
|
|
12
|
+
/** Disable the trigger. */
|
|
13
|
+
disabled?: boolean;
|
|
14
|
+
/** Open the panel by default (uncontrolled). Mainly useful in tests. */
|
|
15
|
+
defaultOpen?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Trap focus and lock scroll while open (Radix's default). Pass `false` for a
|
|
18
|
+
* lightweight menu that doesn't take the page modal — appropriate for inline
|
|
19
|
+
* affordances embedded in a larger surface.
|
|
20
|
+
*/
|
|
21
|
+
modal?: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Portal the panel to `document.body` (the default). Pass `false` to render it
|
|
24
|
+
* inline next to the trigger, keeping it inside the trigger's DOM subtree.
|
|
25
|
+
*/
|
|
26
|
+
portal?: boolean;
|
|
27
|
+
/** Extra classes for the trigger button. */
|
|
28
|
+
triggerClassName?: string;
|
|
29
|
+
/** Extra classes for the panel. */
|
|
30
|
+
contentClassName?: string;
|
|
31
|
+
/** Menu contents — typically `OverflowMenuItem`s separated by `OverflowMenuSeparator`. */
|
|
32
|
+
children: React.ReactNode;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* A "⋯" icon-button that opens a dropdown of low-frequency, whole-object actions.
|
|
36
|
+
* Built on the Radix `DropdownMenu` primitives; compose the panel with
|
|
37
|
+
* `OverflowMenuItem` (and `OverflowMenuSeparator`) as children.
|
|
38
|
+
*/
|
|
39
|
+
export declare function OverflowMenu({ label, align, size, variant, disabled, defaultOpen, modal, portal, triggerClassName, contentClassName, children, }: OverflowMenuProps): import("react/jsx-runtime").JSX.Element;
|
|
40
|
+
export { DropdownMenuItem as OverflowMenuItem, DropdownMenuSeparator as OverflowMenuSeparator, } from "./dropdown-menu.js";
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { MoreHorizontal } from "lucide-react";
|
|
4
|
+
import * as React from "react";
|
|
5
|
+
import { IconButton } from "./button.js";
|
|
6
|
+
import { DropdownMenu, DropdownMenuContent, DropdownMenuTrigger, } from "./dropdown-menu.js";
|
|
7
|
+
/**
|
|
8
|
+
* A "⋯" icon-button that opens a dropdown of low-frequency, whole-object actions.
|
|
9
|
+
* Built on the Radix `DropdownMenu` primitives; compose the panel with
|
|
10
|
+
* `OverflowMenuItem` (and `OverflowMenuSeparator`) as children.
|
|
11
|
+
*/
|
|
12
|
+
export function OverflowMenu({ label = "More actions", align = "end", size = "icon-sm", variant = "ghost", disabled, defaultOpen, modal, portal, triggerClassName, contentClassName, children, }) {
|
|
13
|
+
return (_jsxs(DropdownMenu, { defaultOpen: defaultOpen, modal: modal, children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(IconButton, { className: triggerClassName, disabled: disabled, label: label, size: size, variant: variant, children: _jsx(MoreHorizontal, {}) }) }), _jsx(DropdownMenuContent, { align: align, className: contentClassName, portal: portal, children: children })] }));
|
|
14
|
+
}
|
|
15
|
+
export { DropdownMenuItem as OverflowMenuItem, DropdownMenuSeparator as OverflowMenuSeparator, } from "./dropdown-menu.js";
|
package/package.json
CHANGED