beacon-ui 3.1.8 → 3.1.9
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 +17 -0
- package/dist/components/Menu.d.ts +18 -1
- package/dist/components/Menu.d.ts.map +1 -1
- package/dist/components/Menu.js +29 -5
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,23 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [3.1.9] - 2025-12-29
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- Menu component now supports render props for full customization:
|
|
12
|
+
- `renderSwitch` - Customize or replace the Switch component with your own implementation
|
|
13
|
+
- `renderToggleButton` - Customize or replace the toggle button (menu/close icon) with your own component
|
|
14
|
+
- `renderButton` - Customize or replace the menu action button with your own component
|
|
15
|
+
- Menu component callback props for handling interactions:
|
|
16
|
+
- `onSwitchChange` - Callback when Switch value changes
|
|
17
|
+
- `onToggleButtonClick` - Callback when toggle button is clicked
|
|
18
|
+
- `onButtonClick` - Callback when menu action button is clicked
|
|
19
|
+
- Exported render prop types: `SwitchRenderProps`, `ToggleButtonRenderProps`, `MenuButtonRenderProps`
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
- Menu component now uses internal state management for Switch, allowing better control and customization
|
|
23
|
+
- Render props are optional - if not provided, Menu uses default components (backward compatible)
|
|
24
|
+
|
|
8
25
|
## [3.1.8] - 2025-12-29
|
|
9
26
|
|
|
10
27
|
### Fixed
|
|
@@ -7,6 +7,17 @@ export interface MenuItem {
|
|
|
7
7
|
selected?: boolean;
|
|
8
8
|
onClick?: (item: MenuItem) => void;
|
|
9
9
|
}
|
|
10
|
+
export interface SwitchRenderProps {
|
|
11
|
+
checked: boolean;
|
|
12
|
+
onChange: (checked: boolean) => void;
|
|
13
|
+
}
|
|
14
|
+
export interface ToggleButtonRenderProps {
|
|
15
|
+
isOpen: boolean;
|
|
16
|
+
onClick: () => void;
|
|
17
|
+
}
|
|
18
|
+
export interface MenuButtonRenderProps {
|
|
19
|
+
onClick: () => void;
|
|
20
|
+
}
|
|
10
21
|
export interface MenuProps extends ComponentPropsWithRef<"div"> {
|
|
11
22
|
variant?: MenuVariant;
|
|
12
23
|
showMenu?: boolean;
|
|
@@ -18,7 +29,13 @@ export interface MenuProps extends ComponentPropsWithRef<"div"> {
|
|
|
18
29
|
avatarImageUrl?: string;
|
|
19
30
|
selectedItemId?: string;
|
|
20
31
|
onItemClick?: (item: MenuItem) => void;
|
|
32
|
+
renderSwitch?: (props: SwitchRenderProps) => ReactNode;
|
|
33
|
+
renderToggleButton?: (props: ToggleButtonRenderProps) => ReactNode;
|
|
34
|
+
renderButton?: (props: MenuButtonRenderProps) => ReactNode;
|
|
35
|
+
onSwitchChange?: (checked: boolean) => void;
|
|
36
|
+
onToggleButtonClick?: () => void;
|
|
37
|
+
onButtonClick?: () => void;
|
|
21
38
|
}
|
|
22
|
-
export declare function Menu({ variant, showMenu, showButton, menuItems, headerTitle, headerSubtitle, showChevrons, avatarImageUrl, selectedItemId, onItemClick, className, style, ref, ...rest }: MenuProps): import("react/jsx-runtime").JSX.Element;
|
|
39
|
+
export declare function Menu({ variant, showMenu, showButton, menuItems, headerTitle, headerSubtitle, showChevrons, avatarImageUrl, selectedItemId, onItemClick, renderSwitch, renderToggleButton, renderButton, onSwitchChange, onToggleButtonClick, onButtonClick, className, style, ref, ...rest }: MenuProps): import("react/jsx-runtime").JSX.Element;
|
|
23
40
|
export {};
|
|
24
41
|
//# sourceMappingURL=Menu.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Menu.d.ts","sourceRoot":"","sources":["../../src/components/Menu.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAW,qBAAqB,
|
|
1
|
+
{"version":3,"file":"Menu.d.ts","sourceRoot":"","sources":["../../src/components/Menu.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAW,qBAAqB,EAAoC,SAAS,EAAE,MAAM,OAAO,CAAC;AAMpG,KAAK,WAAW,GAAG,SAAS,GAAG,aAAa,GAAG,eAAe,GAAG,aAAa,GAAG,eAAe,GAAG,YAAY,CAAC;AAEhH,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,KAAK,IAAI,CAAC;CACpC;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CACtC;AAED,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,MAAM,WAAW,SAAU,SAAQ,qBAAqB,CAAC,KAAK,CAAC;IAC7D,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,QAAQ,EAAE,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,KAAK,IAAI,CAAC;IACvC,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,SAAS,CAAC;IACvD,kBAAkB,CAAC,EAAE,CAAC,KAAK,EAAE,uBAAuB,KAAK,SAAS,CAAC;IACnE,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,SAAS,CAAC;IAC3D,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAC5C,mBAAmB,CAAC,EAAE,MAAM,IAAI,CAAC;IACjC,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;CAC5B;AAUD,wBAAgB,IAAI,CAAC,EACnB,OAAmB,EACnB,QAAe,EACf,UAAiB,EACjB,SAA8B,EAC9B,WAAqB,EACrB,cAA2B,EAC3B,YAAmB,EACnB,cAAc,EACd,cAAc,EACd,WAAW,EACX,YAAY,EACZ,kBAAkB,EAClB,YAAY,EACZ,cAAc,EACd,mBAAmB,EACnB,aAAa,EACb,SAAS,EACT,KAAK,EACL,GAAG,EACH,GAAG,IAAI,EACR,EAAE,SAAS,2CAieX"}
|
package/dist/components/Menu.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
-
import { useMemo, useState } from "react";
|
|
3
|
+
import { useMemo, useState, useCallback, useEffect } from "react";
|
|
4
4
|
import { CloseIcon, MenuIcon, DownloadIcon } from "../icons";
|
|
5
5
|
import { Switch } from "./Switch";
|
|
6
6
|
import { useThemeSafe } from "../providers/ThemeProvider";
|
|
@@ -12,10 +12,31 @@ const DEFAULT_MENU_ITEMS = [
|
|
|
12
12
|
{ id: "4", label: "Menu Item #4" },
|
|
13
13
|
{ id: "5", label: "Menu Item #5" },
|
|
14
14
|
];
|
|
15
|
-
export function Menu({ variant = "desktop", showMenu = true, showButton = true, menuItems = DEFAULT_MENU_ITEMS, headerTitle = "Title", headerSubtitle = "Subtitle", showChevrons = true, avatarImageUrl, selectedItemId, onItemClick, className, style, ref, ...rest }) {
|
|
15
|
+
export function Menu({ variant = "desktop", showMenu = true, showButton = true, menuItems = DEFAULT_MENU_ITEMS, headerTitle = "Title", headerSubtitle = "Subtitle", showChevrons = true, avatarImageUrl, selectedItemId, onItemClick, renderSwitch, renderToggleButton, renderButton, onSwitchChange, onToggleButtonClick, onButtonClick, className, style, ref, ...rest }) {
|
|
16
16
|
const themeContext = useThemeSafe();
|
|
17
17
|
const theme = themeContext?.theme ?? "dark";
|
|
18
18
|
const [hoveredItemId, setHoveredItemId] = useState(null);
|
|
19
|
+
const [switchChecked, setSwitchChecked] = useState(theme === "dark");
|
|
20
|
+
// Update switch checked state when theme changes
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
setSwitchChecked(theme === "dark");
|
|
23
|
+
}, [theme]);
|
|
24
|
+
const handleSwitchChange = useCallback((checked) => {
|
|
25
|
+
setSwitchChecked(checked);
|
|
26
|
+
if (onSwitchChange) {
|
|
27
|
+
onSwitchChange(checked);
|
|
28
|
+
}
|
|
29
|
+
}, [onSwitchChange]);
|
|
30
|
+
const handleToggleButtonClick = useCallback(() => {
|
|
31
|
+
if (onToggleButtonClick) {
|
|
32
|
+
onToggleButtonClick();
|
|
33
|
+
}
|
|
34
|
+
}, [onToggleButtonClick]);
|
|
35
|
+
const handleButtonClick = useCallback(() => {
|
|
36
|
+
if (onButtonClick) {
|
|
37
|
+
onButtonClick();
|
|
38
|
+
}
|
|
39
|
+
}, [onButtonClick]);
|
|
19
40
|
const containerStyles = useMemo(() => {
|
|
20
41
|
const baseStyles = {
|
|
21
42
|
display: "flex",
|
|
@@ -178,7 +199,7 @@ export function Menu({ variant = "desktop", showMenu = true, showButton = true,
|
|
|
178
199
|
};
|
|
179
200
|
}, []);
|
|
180
201
|
if (variant === "close-menu") {
|
|
181
|
-
return (_jsx("div", { ref: ref, className: className, style: { ...containerStyles, ...style }, ...rest, children: _jsx("button", { style: iconButtonStyles, children: _jsx("div", { style: { display: "flex", alignItems: "center", justifyContent: "center", width: "32px", height: "32px" }, children: _jsx(CloseIcon, { size: 32 }) }) }) }));
|
|
202
|
+
return (_jsx("div", { ref: ref, className: className, style: { ...containerStyles, ...style }, ...rest, children: renderToggleButton ? (renderToggleButton({ isOpen: true, onClick: handleToggleButtonClick })) : (_jsx("button", { style: iconButtonStyles, onClick: handleToggleButtonClick, children: _jsx("div", { style: { display: "flex", alignItems: "center", justifyContent: "center", width: "32px", height: "32px" }, children: _jsx(CloseIcon, { size: 32 }) }) })) }));
|
|
182
203
|
}
|
|
183
204
|
const isDesktop = variant === "desktop";
|
|
184
205
|
const isTabletOpen = variant === "tablet-open";
|
|
@@ -257,7 +278,10 @@ export function Menu({ variant = "desktop", showMenu = true, showButton = true,
|
|
|
257
278
|
fontWeight: "var(--font-weight-secondary-medium)",
|
|
258
279
|
color: "var(--fg-neutral)",
|
|
259
280
|
margin: 0,
|
|
260
|
-
}, children: headerSubtitle })] }))] }), _jsxs("div", { style: footerStyles, children: [showButton && (_jsxs("div", { style: buttonStyles, children: [_jsx("div", { style: { display: "flex", alignItems: "center", justifyContent: "center", width: "16px", height: "16px" }, children: _jsx(DownloadIcon, { size: 16 }) }), _jsx("span", { children: "Button" })] }))
|
|
281
|
+
}, children: headerSubtitle })] }))] }), _jsxs("div", { style: footerStyles, children: [showButton && (renderButton ? (renderButton({ onClick: handleButtonClick })) : (_jsxs("div", { style: buttonStyles, onClick: handleButtonClick, children: [_jsx("div", { style: { display: "flex", alignItems: "center", justifyContent: "center", width: "16px", height: "16px" }, children: _jsx(DownloadIcon, { size: 16 }) }), _jsx("span", { children: "Button" })] }))), renderSwitch ? (renderSwitch({ checked: switchChecked, onChange: handleSwitchChange })) : (_jsx(Switch, { checked: switchChecked, onChange: handleSwitchChange, showIcons: true })), renderToggleButton ? (renderToggleButton({
|
|
282
|
+
isOpen: isTabletOpen || isMobileOpen,
|
|
283
|
+
onClick: handleToggleButtonClick
|
|
284
|
+
})) : (_jsx("button", { style: iconButtonStyles, onClick: handleToggleButtonClick, children: _jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "center", width: "32px", height: "32px" }, children: [(isTabletOpen || isMobileOpen) && _jsx(CloseIcon, { size: 32 }), (isTabletClosed || isMobileClosed) && _jsx(MenuIcon, { size: 32 })] }) }))] })] })), showMenuItems && (_jsx("div", { style: {
|
|
261
285
|
display: "flex",
|
|
262
286
|
flexDirection: "column",
|
|
263
287
|
gap: "var(--spacing-200)",
|
|
@@ -284,5 +308,5 @@ export function Menu({ variant = "desktop", showMenu = true, showButton = true,
|
|
|
284
308
|
// Determine state for MenuItem component
|
|
285
309
|
const itemState = isSelected ? "Active" : isHovered ? "Hovered" : "Default";
|
|
286
310
|
return (_jsx(MenuItemComponent, { menuTitle: item.label, iconStart: true, iconStart1: item.icon || null, iconEnd: showChevrons, iconEnd1: null, state: itemState, onClick: handleClick, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave }, item.id));
|
|
287
|
-
}) })), isDesktop && (_jsxs(_Fragment, { children: [showButton && (_jsx("div", { style: { display: "flex", flexDirection: "column", gap: "var(--spacing-400)", padding: "var(--spacing-400)", width: "100%" }, children: _jsxs("div", { style: buttonStyles, children: [_jsx("div", { style: { display: "flex", alignItems: "center", justifyContent: "center", width: "16px", height: "16px" }, children: _jsx(DownloadIcon, { size: 16 }) }), _jsx("span", { children: "Button" })] }) })), _jsx("div", { style: footerStyles, children: _jsx(Switch, { checked:
|
|
311
|
+
}) })), isDesktop && (_jsxs(_Fragment, { children: [showButton && (_jsx("div", { style: { display: "flex", flexDirection: "column", gap: "var(--spacing-400)", padding: "var(--spacing-400)", width: "100%" }, children: renderButton ? (renderButton({ onClick: handleButtonClick })) : (_jsxs("div", { style: buttonStyles, onClick: handleButtonClick, children: [_jsx("div", { style: { display: "flex", alignItems: "center", justifyContent: "center", width: "16px", height: "16px" }, children: _jsx(DownloadIcon, { size: 16 }) }), _jsx("span", { children: "Button" })] })) })), _jsx("div", { style: footerStyles, children: renderSwitch ? (renderSwitch({ checked: switchChecked, onChange: handleSwitchChange })) : (_jsx(Switch, { checked: switchChecked, onChange: handleSwitchChange, showIcons: true })) })] }))] }));
|
|
288
312
|
}
|