beacon-ui 3.1.7 → 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 CHANGED
@@ -5,6 +5,30 @@ 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
+
25
+ ## [3.1.8] - 2025-12-29
26
+
27
+ ### Fixed
28
+ - Button component now preserves variant colors (success, critical, warning) when in loading state
29
+ - Previously, buttons would revert to default/primary color when loading was enabled
30
+ - Loading state no longer overrides variant-specific colors
31
+
8
32
  ## [3.1.7] - 2025-12-29
9
33
 
10
34
  ### Changed
@@ -4,6 +4,7 @@ export type ButtonSize = "xs" | "sm" | "md" | "lg" | "xl";
4
4
  export type CornerRadiusStep = 0 | 1 | 2 | 3 | 4 | 5;
5
5
  export type JustifyContent = "center" | "space-between";
6
6
  export type ButtonState = "default" | "hovered" | "focused" | "pressed";
7
+ export type ButtonColor = "primary" | "success" | "critical" | "warning";
7
8
  export interface ButtonProps extends Omit<ComponentPropsWithRef<"button">, "type"> {
8
9
  variant?: ButtonVariant;
9
10
  size?: ButtonSize;
@@ -14,8 +15,9 @@ export interface ButtonProps extends Omit<ComponentPropsWithRef<"button">, "type
14
15
  justifyContent?: JustifyContent;
15
16
  loading?: boolean;
16
17
  state?: ButtonState;
18
+ color?: ButtonColor;
17
19
  type?: "button" | "submit" | "reset";
18
20
  children: React.ReactNode;
19
21
  }
20
- export declare function Button({ variant, size, cornerRadius, startIcon, endIcon, fillContainer, justifyContent, loading, disabled, state: stateProp, type, children, className, style, onClick, onMouseEnter, onMouseLeave, onFocus, onBlur, onMouseDown, onMouseUp, ref, ...rest }: ButtonProps): import("react/jsx-runtime").JSX.Element;
22
+ export declare function Button({ variant, size, cornerRadius, startIcon, endIcon, fillContainer, justifyContent, loading, disabled, state: stateProp, color, type, children, className, style, onClick, onMouseEnter, onMouseLeave, onFocus, onBlur, onMouseDown, onMouseUp, ref, ...rest }: ButtonProps): import("react/jsx-runtime").JSX.Element;
21
23
  //# sourceMappingURL=Button.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Button.d.ts","sourceRoot":"","sources":["../../src/components/Button.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAkC,qBAAqB,EAAE,MAAM,OAAO,CAAC;AAI9E,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;AACpE,MAAM,MAAM,UAAU,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAC1D,MAAM,MAAM,gBAAgB,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AACrD,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,eAAe,CAAC;AACxD,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;AAExE,MAAM,WAAW,WAAY,SAAQ,IAAI,CAAC,qBAAqB,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAChF,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,YAAY,CAAC,EAAE,gBAAgB,CAAC;IAChC,SAAS,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC5B,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,IAAI,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,OAAO,CAAC;IACrC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAkED,wBAAgB,MAAM,CAAC,EACrB,OAAkB,EAClB,IAAW,EACX,YAAgB,EAChB,SAAS,EACT,OAAO,EACP,aAAqB,EACrB,cAAyB,EACzB,OAAe,EACf,QAAgB,EAChB,KAAK,EAAE,SAAS,EAChB,IAAe,EACf,QAAQ,EACR,SAAS,EACT,KAAK,EACL,OAAO,EACP,YAAY,EACZ,YAAY,EACZ,OAAO,EACP,MAAM,EACN,WAAW,EACX,SAAS,EACT,GAAG,EACH,GAAG,IAAI,EACR,EAAE,WAAW,2CAoNb"}
1
+ {"version":3,"file":"Button.d.ts","sourceRoot":"","sources":["../../src/components/Button.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAkC,qBAAqB,EAAE,MAAM,OAAO,CAAC;AAI9E,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;AACpE,MAAM,MAAM,UAAU,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAC1D,MAAM,MAAM,gBAAgB,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AACrD,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,eAAe,CAAC;AACxD,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;AACxE,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,CAAC;AAEzE,MAAM,WAAW,WAAY,SAAQ,IAAI,CAAC,qBAAqB,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAChF,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,YAAY,CAAC,EAAE,gBAAgB,CAAC;IAChC,SAAS,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC5B,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,IAAI,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,OAAO,CAAC;IACrC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAkED,wBAAgB,MAAM,CAAC,EACrB,OAAkB,EAClB,IAAW,EACX,YAAgB,EAChB,SAAS,EACT,OAAO,EACP,aAAqB,EACrB,cAAyB,EACzB,OAAe,EACf,QAAgB,EAChB,KAAK,EAAE,SAAS,EAChB,KAAiB,EACjB,IAAe,EACf,QAAQ,EACR,SAAS,EACT,KAAK,EACL,OAAO,EACP,YAAY,EACZ,YAAY,EACZ,OAAO,EACP,MAAM,EACN,WAAW,EACX,SAAS,EACT,GAAG,EACH,GAAG,IAAI,EACR,EAAE,WAAW,2CAiPb"}
@@ -55,7 +55,7 @@ const LOADER_ICON_SIZE_MAP = {
55
55
  lg: 32,
56
56
  xl: 40,
57
57
  };
58
- export function Button({ variant = "filled", size = "md", cornerRadius = 2, startIcon, endIcon, fillContainer = false, justifyContent = "center", loading = false, disabled = false, state: stateProp, type = "button", children, className, style, onClick, onMouseEnter, onMouseLeave, onFocus, onBlur, onMouseDown, onMouseUp, ref, ...rest }) {
58
+ export function Button({ variant = "filled", size = "md", cornerRadius = 2, startIcon, endIcon, fillContainer = false, justifyContent = "center", loading = false, disabled = false, state: stateProp, color = "primary", type = "button", children, className, style, onClick, onMouseEnter, onMouseLeave, onFocus, onBlur, onMouseDown, onMouseUp, ref, ...rest }) {
59
59
  const themeContext = useThemeSafe();
60
60
  const sizeConfig = SIZE_CONFIG[size];
61
61
  const borderRadius = CORNER_RADIUS_MAP[cornerRadius];
@@ -97,7 +97,8 @@ export function Button({ variant = "filled", size = "md", cornerRadius = 2, star
97
97
  }
98
98
  onMouseUp?.(e);
99
99
  }, [disabled, loading, stateProp, onMouseUp]);
100
- const isDisabled = disabled || loading;
100
+ const isDisabled = disabled;
101
+ const isLoading = loading;
101
102
  const currentState = isDisabled ? "default" : state;
102
103
  const buttonStyles = useMemo(() => {
103
104
  const baseStyles = {
@@ -113,7 +114,7 @@ export function Button({ variant = "filled", size = "md", cornerRadius = 2, star
113
114
  borderStyle: "solid",
114
115
  borderColor: "transparent",
115
116
  borderRadius,
116
- cursor: isDisabled ? "not-allowed" : "pointer",
117
+ cursor: (isDisabled || isLoading) ? "not-allowed" : "pointer",
117
118
  transition: "background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease",
118
119
  minHeight: sizeConfig.height,
119
120
  paddingLeft: sizeConfig.paddingX,
@@ -123,34 +124,49 @@ export function Button({ variant = "filled", size = "md", cornerRadius = 2, star
123
124
  width: fillContainer ? "100%" : "auto",
124
125
  opacity: isDisabled ? 0.6 : 1,
125
126
  };
127
+ // Get color token prefixes based on color prop
128
+ const colorPrefix = color === "primary" ? "primary" : color;
129
+ const bgToken = `--bg-${colorPrefix}`;
130
+ const bgTonalToken = `--bg-${colorPrefix}-tonal`;
131
+ const bgHoverToken = `--bg-${colorPrefix}-on-hover`;
132
+ const bgPressedToken = color === "primary" ? `--bg-${colorPrefix}-pressed` : `--bg-${colorPrefix}-on-hover`;
133
+ const bgFocusedToken = color === "primary" ? `--bg-${colorPrefix}-on-focused` : `--bg-${colorPrefix}-on-hover`;
134
+ const bgTonalHoverToken = color === "primary" ? `--bg-${colorPrefix}-tonal-on-hover` : `--bg-${colorPrefix}-tonal`;
135
+ const fgToken = `--fg-${colorPrefix}`;
136
+ const fgTonalToken = `--fg-${colorPrefix}-on-tonal`;
137
+ const fgHoverToken = color === "primary" ? `--fg-${colorPrefix}-on-hover` : `--fg-${colorPrefix}`;
138
+ const borderToken = `--border-${colorPrefix}`;
139
+ const borderTonalToken = `--border-${colorPrefix}-tonal`;
140
+ const borderHoverToken = color === "primary" ? `--border-${colorPrefix}-on-hover` : `--border-${colorPrefix}`;
141
+ // For non-primary colors, use the base border token for hover since there's no specific hover border token
126
142
  // Get base variant styles
127
143
  let variantStyles = {};
128
144
  switch (variant) {
129
145
  case "filled":
130
146
  variantStyles = {
131
- backgroundColor: "var(--bg-primary)",
147
+ backgroundColor: `var(${bgToken})`,
132
148
  color: "var(--fg-on-action)",
133
- borderColor: "var(--bg-primary)",
149
+ borderColor: `var(${bgToken})`,
134
150
  };
135
151
  break;
136
152
  case "tonal":
137
153
  variantStyles = {
138
- backgroundColor: "var(--bg-primary-tonal)",
139
- color: "var(--fg-primary-on-tonal)",
140
- borderColor: "var(--border-primary-tonal)",
154
+ backgroundColor: `var(${bgTonalToken})`,
155
+ color: `var(${fgTonalToken})`,
156
+ borderColor: `var(${borderTonalToken})`,
141
157
  };
142
158
  break;
143
159
  case "outline":
144
160
  variantStyles = {
145
161
  backgroundColor: "transparent",
146
- color: "var(--fg-primary)",
147
- borderColor: "var(--border-primary)",
162
+ color: `var(${fgToken})`,
163
+ borderColor: `var(${borderToken})`,
148
164
  };
149
165
  break;
150
166
  case "link":
151
167
  variantStyles = {
152
168
  backgroundColor: "transparent",
153
- color: "var(--fg-primary)",
169
+ color: `var(${fgToken})`,
154
170
  borderWidth: 0,
155
171
  borderStyle: "none",
156
172
  borderColor: "transparent",
@@ -160,6 +176,7 @@ export function Button({ variant = "filled", size = "md", cornerRadius = 2, star
160
176
  break;
161
177
  }
162
178
  // Apply state-specific overrides
179
+ // When loading, preserve variant colors and don't apply state-specific styles
163
180
  const stateStyles = {};
164
181
  if (isDisabled) {
165
182
  if (variant === "filled") {
@@ -180,44 +197,51 @@ export function Button({ variant = "filled", size = "md", cornerRadius = 2, star
180
197
  stateStyles.color = "var(--fg-disabled)";
181
198
  }
182
199
  }
183
- else if (currentState === "hovered") {
200
+ else if (!isLoading && currentState === "hovered") {
184
201
  if (variant === "filled") {
185
- stateStyles.backgroundColor = "var(--bg-primary-on-hover)";
186
- stateStyles.borderColor = "var(--bg-primary-on-hover)";
202
+ stateStyles.backgroundColor = `var(${bgHoverToken})`;
203
+ stateStyles.borderColor = `var(${bgHoverToken})`;
187
204
  }
188
205
  else if (variant === "tonal") {
189
- stateStyles.backgroundColor = "var(--bg-primary-tonal-on-hover)";
206
+ stateStyles.backgroundColor = `var(${bgTonalHoverToken})`;
190
207
  }
191
208
  else if (variant === "outline") {
192
- stateStyles.borderColor = "var(--border-primary-on-hover)";
209
+ stateStyles.borderColor = `var(${borderHoverToken})`;
193
210
  }
194
211
  else if (variant === "link") {
195
- stateStyles.color = "var(--fg-primary-on-hover)";
212
+ stateStyles.color = `var(${fgHoverToken})`;
196
213
  }
197
214
  }
198
- else if (currentState === "pressed") {
215
+ else if (!isLoading && currentState === "pressed") {
199
216
  if (variant === "filled") {
200
- stateStyles.backgroundColor = "var(--bg-primary-pressed)";
201
- stateStyles.borderColor = "var(--bg-primary-pressed)";
217
+ stateStyles.backgroundColor = `var(${bgPressedToken})`;
218
+ stateStyles.borderColor = `var(${bgPressedToken})`;
202
219
  }
203
220
  else if (variant === "tonal") {
204
- stateStyles.backgroundColor = "var(--bg-primary-tonal-on-hover)";
221
+ stateStyles.backgroundColor = `var(${bgTonalHoverToken})`;
205
222
  }
206
223
  }
207
- else if (currentState === "focused") {
224
+ else if (!isLoading && currentState === "focused") {
208
225
  if (variant === "filled") {
209
- stateStyles.backgroundColor = "var(--bg-primary-on-focused)";
210
- stateStyles.borderColor = "var(--bg-primary-on-focused)";
226
+ stateStyles.backgroundColor = `var(${bgFocusedToken})`;
227
+ stateStyles.borderColor = `var(${bgFocusedToken})`;
211
228
  }
212
229
  else if (variant === "outline") {
213
- stateStyles.borderColor = "var(--border-primary)";
230
+ stateStyles.borderColor = `var(${borderToken})`;
214
231
  }
215
- stateStyles.outline = "2px solid var(--border-primary)";
232
+ stateStyles.outline = `2px solid var(${borderToken})`;
216
233
  stateStyles.outlineOffset = "2px";
217
234
  }
218
235
  return { ...baseStyles, ...variantStyles, ...stateStyles, ...style };
219
- }, [variant, sizeConfig, borderRadius, fillContainer, justifyContent, currentState, isDisabled, style]);
236
+ }, [variant, sizeConfig, borderRadius, fillContainer, justifyContent, currentState, isDisabled, isLoading, color, style]);
220
237
  const showStartIcon = !loading && startIcon;
221
238
  const showEndIcon = !loading && endIcon;
222
- return (_jsx("button", { ref: ref, type: type, className: className, style: buttonStyles, disabled: isDisabled, onClick: onClick, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, onFocus: handleFocus, onBlur: handleBlur, onMouseDown: handleMouseDown, onMouseUp: handleMouseUp, ...rest, children: loading ? (_jsx(LoaderIcon, { size: LOADER_ICON_SIZE_MAP[size], className: "ds-button-loading-spinner" })) : (_jsxs(_Fragment, { children: [showStartIcon && _jsx("span", { style: { display: "inline-flex", alignItems: "center" }, children: startIcon }), children, showEndIcon && _jsx("span", { style: { display: "inline-flex", alignItems: "center" }, children: endIcon })] })) }));
239
+ const handleClick = useCallback((e) => {
240
+ if (isDisabled || isLoading) {
241
+ e.preventDefault();
242
+ return;
243
+ }
244
+ onClick?.(e);
245
+ }, [isDisabled, isLoading, onClick]);
246
+ return (_jsx("button", { ref: ref, type: type, className: className, style: buttonStyles, disabled: isDisabled, onClick: handleClick, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, onFocus: handleFocus, onBlur: handleBlur, onMouseDown: handleMouseDown, onMouseUp: handleMouseUp, ...rest, children: loading ? (_jsx(LoaderIcon, { size: LOADER_ICON_SIZE_MAP[size], className: "ds-button-loading-spinner" })) : (_jsxs(_Fragment, { children: [showStartIcon && _jsx("span", { style: { display: "inline-flex", alignItems: "center" }, children: startIcon }), children, showEndIcon && _jsx("span", { style: { display: "inline-flex", alignItems: "center" }, children: endIcon })] })) }));
223
247
  }
@@ -1,8 +1,22 @@
1
- import { ComponentPropsWithRef } from "react";
1
+ import { ComponentPropsWithRef, ReactNode } from "react";
2
2
  type MenuVariant = "desktop" | "tablet-open" | "tablet-closed" | "mobile-open" | "mobile-closed" | "close-menu";
3
- interface MenuItem {
3
+ export interface MenuItem {
4
4
  id: string;
5
5
  label: string;
6
+ icon?: ReactNode;
7
+ selected?: boolean;
8
+ onClick?: (item: MenuItem) => void;
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;
6
20
  }
7
21
  export interface MenuProps extends ComponentPropsWithRef<"div"> {
8
22
  variant?: MenuVariant;
@@ -13,7 +27,15 @@ export interface MenuProps extends ComponentPropsWithRef<"div"> {
13
27
  headerSubtitle?: string;
14
28
  showChevrons?: boolean;
15
29
  avatarImageUrl?: string;
30
+ selectedItemId?: string;
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;
16
38
  }
17
- export declare function Menu({ variant, showMenu, showButton, menuItems, headerTitle, headerSubtitle, showChevrons, avatarImageUrl, 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;
18
40
  export {};
19
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,EAAE,MAAM,OAAO,CAAC;AAKvD,KAAK,WAAW,GAAG,SAAS,GAAG,aAAa,GAAG,eAAe,GAAG,aAAa,GAAG,eAAe,GAAG,YAAY,CAAC;AAEhH,UAAU,QAAQ;IAChB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;CACf;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;CACzB;AAUD,wBAAgB,IAAI,CAAC,EACnB,OAAmB,EACnB,QAAe,EACf,UAAiB,EACjB,SAA8B,EAC9B,WAAqB,EACrB,cAA2B,EAC3B,YAAmB,EACnB,cAAc,EACd,SAAS,EACT,KAAK,EACL,GAAG,EACH,GAAG,IAAI,EACR,EAAE,SAAS,2CAgZX"}
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"}
@@ -1,9 +1,10 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
- import { useMemo } from "react";
4
- import { UserPersonIcon, ChevronRightIcon, CloseIcon, MenuIcon, DownloadIcon } from "../icons";
3
+ import { useMemo, useState, useCallback, useEffect } from "react";
4
+ import { CloseIcon, MenuIcon, DownloadIcon } from "../icons";
5
5
  import { Switch } from "./Switch";
6
6
  import { useThemeSafe } from "../providers/ThemeProvider";
7
+ import { MenuItem as MenuItemComponent } from "./MenuItem";
7
8
  const DEFAULT_MENU_ITEMS = [
8
9
  { id: "1", label: "Menu Item #1" },
9
10
  { id: "2", label: "Menu Item #2" },
@@ -11,9 +12,31 @@ const DEFAULT_MENU_ITEMS = [
11
12
  { id: "4", label: "Menu Item #4" },
12
13
  { id: "5", label: "Menu Item #5" },
13
14
  ];
14
- export function Menu({ variant = "desktop", showMenu = true, showButton = true, menuItems = DEFAULT_MENU_ITEMS, headerTitle = "Title", headerSubtitle = "Subtitle", showChevrons = true, avatarImageUrl, 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 }) {
15
16
  const themeContext = useThemeSafe();
16
17
  const theme = themeContext?.theme ?? "dark";
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]);
17
40
  const containerStyles = useMemo(() => {
18
41
  const baseStyles = {
19
42
  display: "flex",
@@ -111,17 +134,6 @@ export function Menu({ variant = "desktop", showMenu = true, showButton = true,
111
134
  overflow: "hidden",
112
135
  };
113
136
  }, []);
114
- const menuItemStyles = useMemo(() => {
115
- return {
116
- display: "flex",
117
- gap: "var(--spacing-200)",
118
- alignItems: "center",
119
- padding: "var(--spacing-200) var(--spacing-200)",
120
- borderRadius: "var(--corner-radius-200)",
121
- backgroundColor: "var(--bg-page-primary)",
122
- width: "100%",
123
- };
124
- }, []);
125
137
  const buttonStyles = useMemo(() => {
126
138
  return {
127
139
  display: "flex",
@@ -187,7 +199,7 @@ export function Menu({ variant = "desktop", showMenu = true, showButton = true,
187
199
  };
188
200
  }, []);
189
201
  if (variant === "close-menu") {
190
- 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 }) }) })) }));
191
203
  }
192
204
  const isDesktop = variant === "desktop";
193
205
  const isTabletOpen = variant === "tablet-open";
@@ -196,12 +208,27 @@ export function Menu({ variant = "desktop", showMenu = true, showButton = true,
196
208
  const isMobileClosed = variant === "mobile-closed";
197
209
  const showMenuItems = (isDesktop || isTabletOpen || isMobileOpen) && showMenu;
198
210
  const showHeaderContent = isDesktop || isTabletOpen || isTabletClosed;
199
- return (_jsxs("div", { ref: ref, className: className, style: { ...containerStyles, ...style }, ...rest, children: [isDesktop ? (_jsx(_Fragment, { children: _jsxs("div", { style: headerStyles, children: [_jsx("div", { style: avatarStyles, children: avatarImageUrl ? (_jsx("img", { src: avatarImageUrl, alt: "User avatar", style: {
211
+ return (_jsxs("div", { ref: ref, className: className, style: { ...containerStyles, ...style }, ...rest, children: [isDesktop ? (_jsx(_Fragment, { children: _jsxs("div", { style: headerStyles, children: [_jsx("div", { style: avatarStyles, children: _jsx("img", { src: avatarImageUrl || "/images/avatars/avatar-female.png", alt: "User avatar", style: {
200
212
  width: "100%",
201
213
  height: "100%",
202
214
  objectFit: "cover",
203
215
  objectPosition: "center",
204
- } })) : (_jsx(UserPersonIcon, { size: 24 })) }), showHeaderContent && (_jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "var(--spacing-none)", flex: 1 }, children: [_jsx("p", { style: {
216
+ }, onError: (e) => {
217
+ // Fallback to icon if image fails to load
218
+ const target = e.target;
219
+ target.style.display = "none";
220
+ const iconContainer = target.parentElement;
221
+ if (iconContainer && !iconContainer.querySelector("svg")) {
222
+ const iconWrapper = document.createElement("div");
223
+ iconWrapper.style.display = "flex";
224
+ iconWrapper.style.alignItems = "center";
225
+ iconWrapper.style.justifyContent = "center";
226
+ iconWrapper.style.width = "100%";
227
+ iconWrapper.style.height = "100%";
228
+ iconWrapper.innerHTML = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M12 12C14.21 12 16 10.21 16 8C16 5.79 14.21 4 12 4C9.79 4 8 5.79 8 8C8 10.21 9.79 12 12 12ZM12 14C9.33 14 4 15.34 4 18V20H20V18C20 15.34 14.67 14 12 14Z" fill="var(--fg-neutral)"/></svg>`;
229
+ iconContainer.appendChild(iconWrapper);
230
+ }
231
+ } }) }), showHeaderContent && (_jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "var(--spacing-none)", flex: 1 }, children: [_jsx("p", { style: {
205
232
  fontFamily: "var(--font-secondary)",
206
233
  fontSize: "var(--body-small-text-size)",
207
234
  lineHeight: "var(--body-small-line-height)",
@@ -217,12 +244,27 @@ export function Menu({ variant = "desktop", showMenu = true, showButton = true,
217
244
  margin: 0,
218
245
  }, children: headerSubtitle })] }))] }) })) : (
219
246
  /* Tablet/Mobile: Header and Footer in single row */
220
- _jsxs("div", { style: mainRowStyles, children: [_jsxs("div", { style: headerStyles, children: [_jsx("div", { style: avatarStyles, children: avatarImageUrl ? (_jsx("img", { src: avatarImageUrl, alt: "User avatar", style: {
247
+ _jsxs("div", { style: mainRowStyles, children: [_jsxs("div", { style: headerStyles, children: [_jsx("div", { style: avatarStyles, children: _jsx("img", { src: avatarImageUrl || "/images/avatars/avatar-female.png", alt: "User avatar", style: {
221
248
  width: "100%",
222
249
  height: "100%",
223
250
  objectFit: "cover",
224
251
  objectPosition: "center",
225
- } })) : (_jsx(UserPersonIcon, { size: 24 })) }), showHeaderContent && (_jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "var(--spacing-none)", flex: 1 }, children: [_jsx("p", { style: {
252
+ }, onError: (e) => {
253
+ // Fallback to icon if image fails to load
254
+ const target = e.target;
255
+ target.style.display = "none";
256
+ const iconContainer = target.parentElement;
257
+ if (iconContainer && !iconContainer.querySelector("svg")) {
258
+ const iconWrapper = document.createElement("div");
259
+ iconWrapper.style.display = "flex";
260
+ iconWrapper.style.alignItems = "center";
261
+ iconWrapper.style.justifyContent = "center";
262
+ iconWrapper.style.width = "100%";
263
+ iconWrapper.style.height = "100%";
264
+ iconWrapper.innerHTML = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M12 12C14.21 12 16 10.21 16 8C16 5.79 14.21 4 12 4C9.79 4 8 5.79 8 8C8 10.21 9.79 12 12 12ZM12 14C9.33 14 4 15.34 4 18V20H20V18C20 15.34 14.67 14 12 14Z" fill="var(--fg-neutral)"/></svg>`;
265
+ iconContainer.appendChild(iconWrapper);
266
+ }
267
+ } }) }), showHeaderContent && (_jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "var(--spacing-none)", flex: 1 }, children: [_jsx("p", { style: {
226
268
  fontFamily: "var(--font-secondary)",
227
269
  fontSize: "var(--body-small-text-size)",
228
270
  lineHeight: "var(--body-small-line-height)",
@@ -236,20 +278,35 @@ export function Menu({ variant = "desktop", showMenu = true, showButton = true,
236
278
  fontWeight: "var(--font-weight-secondary-medium)",
237
279
  color: "var(--fg-neutral)",
238
280
  margin: 0,
239
- }, 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" })] })), _jsx(Switch, { checked: theme === "dark", showIcons: true }), _jsx("button", { style: iconButtonStyles, 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: {
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: {
240
285
  display: "flex",
241
286
  flexDirection: "column",
242
287
  gap: "var(--spacing-200)",
243
288
  padding: isDesktop ? "var(--spacing-600) 0" : "var(--spacing-400) var(--spacing-200)",
244
289
  width: "100%",
245
290
  flex: isDesktop ? 1 : undefined,
246
- }, children: menuItems.map((item) => (_jsxs("div", { style: menuItemStyles, children: [_jsx("div", { style: { display: "flex", alignItems: "center", justifyContent: "center", width: "20px", height: "20px", flexShrink: 0, color: "var(--fg-neutral)" }, children: _jsx(UserPersonIcon, { size: 20 }) }), _jsx("p", { style: {
247
- fontFamily: "var(--font-secondary)",
248
- fontSize: "var(--body-small-text-size)",
249
- lineHeight: "var(--body-small-line-height)",
250
- fontWeight: "var(--font-weight-secondary-medium)",
251
- color: "var(--fg-neutral-secondary)",
252
- margin: 0,
253
- flex: 1,
254
- }, children: item.label }), showChevrons && (_jsx("div", { style: { display: "flex", alignItems: "center", justifyContent: "center", width: "16px", height: "16px", flexShrink: 0, color: "var(--fg-neutral)" }, children: _jsx(ChevronRightIcon, { size: 16 }) }))] }, item.id))) })), 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: theme === "dark", showIcons: true }) })] }))] }));
291
+ }, children: menuItems.map((item) => {
292
+ const isSelected = selectedItemId === item.id || item.selected === true;
293
+ const isHovered = hoveredItemId === item.id;
294
+ const handleClick = () => {
295
+ if (item.onClick) {
296
+ item.onClick(item);
297
+ }
298
+ if (onItemClick) {
299
+ onItemClick(item);
300
+ }
301
+ };
302
+ const handleMouseEnter = () => {
303
+ setHoveredItemId(item.id);
304
+ };
305
+ const handleMouseLeave = () => {
306
+ setHoveredItemId(null);
307
+ };
308
+ // Determine state for MenuItem component
309
+ const itemState = isSelected ? "Active" : isHovered ? "Hovered" : "Default";
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));
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 })) })] }))] }));
255
312
  }
@@ -0,0 +1,13 @@
1
+ import { ComponentPropsWithRef, ReactNode } from "react";
2
+ export type MenuItemState = "Default" | "Hovered" | "Active" | "Disabled";
3
+ export interface MenuItemProps extends Omit<ComponentPropsWithRef<"button">, "onClick"> {
4
+ menuTitle?: string;
5
+ iconStart?: boolean;
6
+ iconStart1?: ReactNode | null;
7
+ iconEnd?: boolean;
8
+ iconEnd1?: ReactNode | null;
9
+ state?: MenuItemState;
10
+ onClick?: () => void;
11
+ }
12
+ export declare function MenuItem({ menuTitle, iconStart, iconStart1, iconEnd, iconEnd1, state, onClick, className, style, ...rest }: MenuItemProps): import("react/jsx-runtime").JSX.Element;
13
+ //# sourceMappingURL=MenuItem.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MenuItem.d.ts","sourceRoot":"","sources":["../../src/components/MenuItem.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,qBAAqB,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGzD,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,GAAG,UAAU,CAAC;AAE1E,MAAM,WAAW,aAAc,SAAQ,IAAI,CAAC,qBAAqB,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;IAC9B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;IAC5B,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,wBAAgB,QAAQ,CAAC,EACvB,SAAuB,EACvB,SAAgB,EAChB,UAAiB,EACjB,OAAc,EACd,QAAe,EACf,KAAiB,EACjB,OAAO,EACP,SAAS,EACT,KAAK,EACL,GAAG,IAAI,EACR,EAAE,aAAa,2CAiIf"}
@@ -0,0 +1,90 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { UserPersonIcon, ChevronRightIcon } from "../icons";
4
+ export function MenuItem({ menuTitle = "Menu Item", iconStart = true, iconStart1 = null, iconEnd = true, iconEnd1 = null, state = "Default", onClick, className, style, ...rest }) {
5
+ const isActive = state === "Active";
6
+ const isDisabled = state === "Disabled";
7
+ const isHovered = state === "Hovered";
8
+ const isDefault = state === "Default";
9
+ // Background colors based on state
10
+ const backgroundColor = isActive
11
+ ? "var(--bg-primary-tonal)"
12
+ : isHovered
13
+ ? "var(--bg-page-secondary)"
14
+ : isDisabled
15
+ ? "var(--bg-page-primary)"
16
+ : "var(--bg-page-primary)";
17
+ // Text colors based on state
18
+ const textColor = isActive
19
+ ? "var(--fg-primary-on-tonal)"
20
+ : isDisabled
21
+ ? "var(--fg-on-disabled)"
22
+ : isHovered
23
+ ? "var(--fg-neutral)"
24
+ : "var(--fg-neutral-secondary)";
25
+ // Icon colors based on state
26
+ const iconColor = isActive
27
+ ? "var(--fg-primary-on-tonal)"
28
+ : isDisabled
29
+ ? "var(--fg-on-disabled)"
30
+ : isHovered
31
+ ? "var(--fg-neutral)"
32
+ : "var(--fg-neutral-secondary)";
33
+ // Chevron colors based on state
34
+ const chevronColor = isActive
35
+ ? "var(--fg-primary-on-tonal)"
36
+ : isDisabled
37
+ ? "var(--fg-on-disabled)"
38
+ : "var(--fg-neutral)";
39
+ // Border for disabled state
40
+ const borderStyle = isDisabled
41
+ ? "var(--border-width-25) solid var(--border-neutral-tertiary)"
42
+ : "none";
43
+ const containerStyles = {
44
+ display: "flex",
45
+ gap: "var(--spacing-200)",
46
+ alignItems: "center",
47
+ padding: "var(--spacing-200) var(--spacing-200)",
48
+ borderRadius: "var(--corner-radius-200)",
49
+ width: "100%",
50
+ backgroundColor,
51
+ border: borderStyle,
52
+ cursor: isDisabled ? "not-allowed" : onClick ? "pointer" : "default",
53
+ transition: "background-color 0.2s ease, border-color 0.2s ease",
54
+ ...style,
55
+ };
56
+ return (_jsxs("button", { type: "button", className: className, style: containerStyles, onClick: isDisabled ? undefined : onClick, disabled: isDisabled, ...rest, children: [iconStart && (_jsx("div", { style: {
57
+ display: "flex",
58
+ alignItems: "center",
59
+ justifyContent: "center",
60
+ width: "20px",
61
+ height: "20px",
62
+ flexShrink: 0,
63
+ color: iconColor,
64
+ }, children: iconStart1 || _jsx(UserPersonIcon, { size: 20 }) })), _jsx("p", { style: {
65
+ fontFamily: "var(--font-secondary)",
66
+ fontSize: "var(--body-small-text-size)",
67
+ lineHeight: "var(--body-small-line-height)",
68
+ fontWeight: isActive ? "var(--font-weight-secondary-semibold)" : "var(--font-weight-secondary-medium)",
69
+ color: textColor,
70
+ margin: 0,
71
+ flex: 1,
72
+ textAlign: "left",
73
+ }, children: menuTitle }), iconEnd && !isDisabled && (_jsx("div", { style: {
74
+ display: "flex",
75
+ alignItems: "center",
76
+ justifyContent: "center",
77
+ width: "16px",
78
+ height: "16px",
79
+ flexShrink: 0,
80
+ color: chevronColor,
81
+ }, children: iconEnd1 || _jsx(ChevronRightIcon, { size: 16 }) })), iconEnd && isDisabled && (_jsx("div", { style: {
82
+ display: "flex",
83
+ alignItems: "center",
84
+ justifyContent: "center",
85
+ width: "16px",
86
+ height: "16px",
87
+ flexShrink: 0,
88
+ color: chevronColor,
89
+ }, children: iconEnd1 || _jsx(ChevronRightIcon, { size: 16 }) }))] }));
90
+ }
package/dist/index.d.ts CHANGED
@@ -5,9 +5,10 @@ export { Switch } from "./components/Switch";
5
5
  export { Input } from "./components/Input";
6
6
  export { Avatar } from "./components/Avatar";
7
7
  export { Chip } from "./components/Chip";
8
- export { Menu } from "./components/Menu";
8
+ export { Menu, type MenuItem as MenuItemData } from "./components/Menu";
9
+ export { MenuItem, type MenuItemProps, type MenuItemState } from "./components/MenuItem";
9
10
  export { RadioButton } from "./components/RadioButton";
10
- export type { ButtonProps, ButtonVariant, ButtonSize, CornerRadiusStep, JustifyContent, ButtonState } from "./components/Button";
11
+ export type { ButtonProps, ButtonVariant, ButtonSize, CornerRadiusStep, JustifyContent, ButtonState, ButtonColor } from "./components/Button";
11
12
  export type { CardProps, CardType, ProductCardSize, ProductCardStatus, ExperienceCardType, GenericCardStatus } from "./components/Card";
12
13
  export type { CheckboxProps, CheckboxStatus } from "./components/Checkbox";
13
14
  export type { SwitchProps, SwitchStatus } from "./components/Switch";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjD,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAGvD,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,UAAU,EAAE,gBAAgB,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACjI,YAAY,EAAE,SAAS,EAAE,QAAQ,EAAE,eAAe,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACxI,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC3E,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACrE,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAC7E,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAC3G,YAAY,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACxE,YAAY,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACnD,YAAY,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAGpF,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAGlF,YAAY,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACxD,YAAY,EACV,cAAc,EACd,aAAa,EACb,YAAY,EACZ,eAAe,EACf,eAAe,EACf,WAAW,GACZ,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjD,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,KAAK,QAAQ,IAAI,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACxE,OAAO,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,KAAK,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACzF,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAGvD,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,UAAU,EAAE,gBAAgB,EAAE,cAAc,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAC9I,YAAY,EAAE,SAAS,EAAE,QAAQ,EAAE,eAAe,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACxI,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC3E,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACrE,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAC7E,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAC3G,YAAY,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACxE,YAAY,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACnD,YAAY,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAGpF,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAGlF,YAAY,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACxD,YAAY,EACV,cAAc,EACd,aAAa,EACb,YAAY,EACZ,eAAe,EACf,eAAe,EACf,WAAW,GACZ,MAAM,gBAAgB,CAAC"}
package/dist/index.js CHANGED
@@ -7,6 +7,7 @@ export { Input } from "./components/Input";
7
7
  export { Avatar } from "./components/Avatar";
8
8
  export { Chip } from "./components/Chip";
9
9
  export { Menu } from "./components/Menu";
10
+ export { MenuItem } from "./components/MenuItem";
10
11
  export { RadioButton } from "./components/RadioButton";
11
12
  // Providers
12
13
  export { ThemeProvider, useTheme, useThemeSafe } from "./providers/ThemeProvider";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "beacon-ui",
3
- "version": "3.1.7",
3
+ "version": "3.1.9",
4
4
  "description": "Beacon Design System - Components and tokens",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",