@validationcloud/fractal-ui 1.81.0 → 1.82.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.
@@ -8,6 +8,7 @@ type DropdownMenuProps = {
8
8
  baseColor?: 'bg-neutral-60' | 'bg-neutral-80';
9
9
  className?: string;
10
10
  contentClassName?: string;
11
+ contentStyle?: React.CSSProperties;
11
12
  disabled?: boolean;
12
13
  } & React.ComponentProps<typeof DropdownMenuPrimitive.Root>;
13
14
  /**
@@ -17,5 +18,5 @@ type DropdownMenuProps = {
17
18
  *
18
19
  * @see {@link https://www.radix-ui.com/primitives/docs/components/dropdown-menu}
19
20
  */
20
- export declare function DropdownMenu({ trigger, baseColor, children, className, contentClassName, disabled, ...props }: DropdownMenuProps): import("react/jsx-runtime").JSX.Element;
21
+ export declare function DropdownMenu({ trigger, baseColor, children, className, contentClassName, contentStyle, disabled, ...props }: DropdownMenuProps): import("react/jsx-runtime").JSX.Element;
21
22
  export {};
@@ -1,13 +1,13 @@
1
1
  "use client";
2
- import { jsx as e, jsxs as u } from "react/jsx-runtime";
2
+ import { jsx as e, jsxs as s } from "react/jsx-runtime";
3
3
  import { DropdownMenu as t, ScrollArea as n } from "radix-ui";
4
- import { forwardRef as g } from "react";
5
- import { twMerge as s } from "../../lib/tailwind-merge.js";
6
- const p = g(
4
+ import { forwardRef as p } from "react";
5
+ import { twMerge as d } from "../../lib/tailwind-merge.js";
6
+ const m = p(
7
7
  ({ className: o, baseColor: r = "bg-neutral-60", textValue: l, ...a }, i) => /* @__PURE__ */ e(
8
8
  t.Item,
9
9
  {
10
- className: s(
10
+ className: d(
11
11
  "tg-button-small data-highlighted:text-neutral-10 flex cursor-pointer items-center truncate rounded-[4px] px-4 py-2.5 transition-colors outline-none select-none",
12
12
  r === "bg-neutral-60" && "text-neutral-20 data-highlighted:bg-neutral-55",
13
13
  r === "bg-neutral-80" && "text-neutral-40 data-highlighted:bg-neutral-60",
@@ -19,41 +19,43 @@ const p = g(
19
19
  }
20
20
  )
21
21
  );
22
- p.displayName = "DropdownMenuItem";
23
- function w({
22
+ m.displayName = "DropdownMenuItem";
23
+ function v({
24
24
  trigger: o,
25
25
  baseColor: r = "bg-neutral-60",
26
26
  children: l,
27
27
  className: a,
28
28
  contentClassName: i,
29
- disabled: d,
30
- ...c
29
+ contentStyle: u,
30
+ disabled: c,
31
+ ...h
31
32
  }) {
32
- return /* @__PURE__ */ u(t.Root, { ...c, children: [
33
- /* @__PURE__ */ e(t.Trigger, { className: s("", a), asChild: !0, disabled: d, children: o }),
33
+ return /* @__PURE__ */ s(t.Root, { ...h, children: [
34
+ /* @__PURE__ */ e(t.Trigger, { className: d("", a), asChild: !0, disabled: c, children: o }),
34
35
  /* @__PURE__ */ e(t.Portal, { children: /* @__PURE__ */ e(
35
36
  n.Root,
36
37
  {
37
38
  type: "hover",
38
39
  style: { "--scrollbar-size": "10px" },
39
40
  asChild: !0,
40
- children: /* @__PURE__ */ u(
41
+ children: /* @__PURE__ */ s(
41
42
  t.Content,
42
43
  {
43
- onCloseAutoFocus: (h) => {
44
- h.preventDefault();
44
+ onCloseAutoFocus: (g) => {
45
+ g.preventDefault();
45
46
  },
46
- className: s(
47
+ className: d(
47
48
  "max-h-(--radix-dropdown-menu-content-available-height) overflow-hidden rounded-lg shadow-[0px_8px_20px_2px_rgba(0,0,0,0.40)]",
48
49
  r === "bg-neutral-60" && "bg-neutral-60",
49
50
  r === "bg-neutral-80" && "bg-neutral-80",
50
51
  i
51
52
  ),
53
+ style: u,
52
54
  align: "end",
53
55
  sideOffset: 8,
54
56
  collisionPadding: 8,
55
57
  children: [
56
- /* @__PURE__ */ e(n.Viewport, { className: "max-h-(--radix-dropdown-menu-content-available-height) p-1", children: l }),
58
+ /* @__PURE__ */ e(n.Viewport, { className: "max-h-(--radix-dropdown-menu-content-available-height) overflow-x-hidden p-1 [&>div]:block!", children: l }),
57
59
  /* @__PURE__ */ e(
58
60
  n.Scrollbar,
59
61
  {
@@ -70,6 +72,6 @@ function w({
70
72
  ] });
71
73
  }
72
74
  export {
73
- w as DropdownMenu,
74
- p as DropdownMenuItem
75
+ v as DropdownMenu,
76
+ m as DropdownMenuItem
75
77
  };
@@ -1,5 +1,5 @@
1
1
  import { default as React } from 'react';
2
- type SidebarItemId = 'home' | 'mavrik' | 'nodeApi' | 'staking' | 'apiKey' | 'docs';
2
+ type SidebarItemId = 'home' | 'mavrik' | 'nodeApi' | 'staking';
3
3
  type SidebarDestination = {
4
4
  href: string;
5
5
  matchPaths?: string | string[];
@@ -16,7 +16,7 @@ type SidebarProps = {
16
16
  *
17
17
  * Provide a key to show that item; omit it to hide it.
18
18
  *
19
- * Possible keys: 'home', 'mavrik', 'nodeApi', 'staking', 'apiKey', 'docs'.
19
+ * Possible keys: 'home', 'mavrik', 'nodeApi', 'staking'.
20
20
  *
21
21
  * Destination shape (per key):
22
22
  * - `href` (required): URL or in-app route string
@@ -30,8 +30,6 @@ type SidebarProps = {
30
30
  * mavrik: { href: '/mavrik', matchPaths: '/ai/[[...rest]]' },
31
31
  * nodeApi: { href: '/node-api', matchPaths: '/node/[[...rest]]' },
32
32
  * staking: { href: '/staking', matchPaths: '/staking/[[...rest]]' },
33
- * apiKey: { href: '/settings/api-keys' },
34
- * docs: { href: 'https://docs.validationcloud.io', external: true, openInNewTab: true },
35
33
  * };
36
34
  * ```
37
35
  */
@@ -61,24 +59,14 @@ type SidebarProps = {
61
59
  * ```
62
60
  */
63
61
  renderLink: (props: RenderLinkProps) => React.ReactElement;
64
- /**
65
- * Bottom item content for the account area (e.g. `UserDropdown`).
66
- *
67
- * Rendered at the bottom of the Sidebar.
68
- */
69
- accountItem: React.ReactNode;
70
- /**
71
- * Optional bottom contact item (e.g. `IntercomButton`).
72
- *
73
- * Rendered above `accountItem` when provided.
74
- */
75
- helpItem?: React.ReactNode;
76
62
  /**
77
63
  * The app's current pathname (e.g. value from`usePathname()` ).
78
64
  *
79
65
  * Used to compute active state for product items via each destination's `matchPaths`.
80
66
  */
81
67
  currentPathname: string;
68
+ /** Content rendered at the bottom of the icon rail (e.g. a collapsed `<UserDropdown>`). */
69
+ footer?: React.ReactNode;
82
70
  } & React.ComponentProps<'nav'>;
83
71
  /**
84
72
  * Vertical navigation sidebar.
@@ -88,5 +76,5 @@ type SidebarProps = {
88
76
  * - Provide `renderLink` to hook into your app router.
89
77
  * - Provide `currentPathname` + per-route `matchPaths` to enable active styling for product items.
90
78
  */
91
- export declare function Sidebar({ routes, renderLink, helpItem, accountItem, currentPathname, className }: SidebarProps): import("react/jsx-runtime").JSX.Element;
79
+ export declare function Sidebar({ routes, renderLink, currentPathname, footer, className }: SidebarProps): import("react/jsx-runtime").JSX.Element;
92
80
  export {};
@@ -1,75 +1,58 @@
1
- import { jsxs as t, jsx as o } from "react/jsx-runtime";
2
- import s from "react";
3
- import N from "../../assets/mavrik-icon-muted.svg.js";
4
- import b from "../../assets/mavrik-icon.svg.js";
5
- import I from "../../assets/node-api-icon-muted.svg.js";
6
- import A from "../../assets/node-api-icon.svg.js";
7
- import k from "../../assets/staking-icon-muted.svg.js";
8
- import x from "../../assets/staking-icon.svg.js";
9
- import P from "../../assets/vc-logo-sm-white.svg.js";
10
- import { Icon as d } from "../icon/icon.js";
11
- import { BottomNavItem as u } from "./bottom-nav-item.js";
12
- import { ProductNavItem as H } from "./product-nav-item.js";
13
- import { twMerge as w } from "../../lib/tailwind-merge.js";
14
- import { matchesPathname as f } from "../../utils/matches-pathname.js";
15
- const y = [
1
+ import { jsxs as f, jsx as o } from "react/jsx-runtime";
2
+ import g from "react";
3
+ import v from "../../assets/mavrik-icon-muted.svg.js";
4
+ import h from "../../assets/mavrik-icon.svg.js";
5
+ import N from "../../assets/node-api-icon-muted.svg.js";
6
+ import k from "../../assets/node-api-icon.svg.js";
7
+ import I from "../../assets/staking-icon-muted.svg.js";
8
+ import A from "../../assets/staking-icon.svg.js";
9
+ import H from "../../assets/vc-logo-sm-white.svg.js";
10
+ import { ProductNavItem as P } from "./product-nav-item.js";
11
+ import { twMerge as b } from "../../lib/tailwind-merge.js";
12
+ import { matchesPathname as n } from "../../utils/matches-pathname.js";
13
+ const w = [
16
14
  {
17
15
  id: "mavrik",
18
16
  label: "Mavrik",
19
- icon: /* @__PURE__ */ o("img", { src: N, alt: "Mavrik", className: "w-5" }),
20
- iconHover: /* @__PURE__ */ o("img", { src: b, alt: "Mavrik", className: "w-5" })
17
+ icon: /* @__PURE__ */ o("img", { src: v, alt: "Mavrik", className: "w-5" }),
18
+ iconHover: /* @__PURE__ */ o("img", { src: h, alt: "Mavrik", className: "w-5" })
21
19
  },
22
20
  {
23
21
  id: "nodeApi",
24
22
  label: "Node API",
25
- icon: /* @__PURE__ */ o("img", { src: I, alt: "Node API", className: "w-4" }),
26
- iconHover: /* @__PURE__ */ o("img", { src: A, alt: "Node API", className: "w-4" })
23
+ icon: /* @__PURE__ */ o("img", { src: N, alt: "Node API", className: "w-4" }),
24
+ iconHover: /* @__PURE__ */ o("img", { src: k, alt: "Node API", className: "w-4" })
27
25
  },
28
26
  {
29
27
  id: "staking",
30
28
  label: "Staking",
31
- icon: /* @__PURE__ */ o("img", { src: k, alt: "Staking", className: "w-4" }),
32
- iconHover: /* @__PURE__ */ o("img", { src: x, alt: "Staking", className: "w-4" })
29
+ icon: /* @__PURE__ */ o("img", { src: I, alt: "Staking", className: "w-4" }),
30
+ iconHover: /* @__PURE__ */ o("img", { src: A, alt: "Staking", className: "w-4" })
33
31
  }
34
- ], M = [
35
- { id: "apiKey", label: "API Key", icon: /* @__PURE__ */ o(d, { icon: "key", className: "size-5 flex-none" }) },
36
- { id: "docs", label: "Docs", icon: /* @__PURE__ */ o(d, { icon: "documents", className: "mb-1 size-4 flex-none" }) }
37
32
  ];
38
- function U({ routes: c, renderLink: r, helpItem: n, accountItem: p, currentPathname: l, className: g }) {
39
- const m = c.home;
40
- return /* @__PURE__ */ t("nav", { className: w("bg-neutral-80 flex h-full w-16 flex-col items-center gap-4 pt-4 pb-9", g), children: [
41
- m && r({
42
- destination: m,
33
+ function F({ routes: e, renderLink: m, currentPathname: t, footer: l, className: s }) {
34
+ const c = e.home;
35
+ return /* @__PURE__ */ f("nav", { className: b("bg-neutral-80 flex h-full w-16 flex-col items-center gap-4 pt-4", s), children: [
36
+ c && m({
37
+ destination: c,
43
38
  "aria-label": "Home",
44
- children: /* @__PURE__ */ o("div", { className: "px-5 py-2", children: /* @__PURE__ */ o("img", { src: P, alt: "Company Logo" }) })
39
+ children: /* @__PURE__ */ o("div", { className: "px-5 py-2", children: /* @__PURE__ */ o("img", { src: H, alt: "Company Logo" }) })
45
40
  }),
46
- y.map((a) => {
47
- const i = c[a.id];
48
- if (!i) return null;
49
- let e = !1;
50
- i.matchPaths && (Array.isArray(i.matchPaths) ? e = i.matchPaths.some((h) => f(l, h)) : e = f(l, i.matchPaths));
51
- const v = r({
52
- destination: i,
53
- children: /* @__PURE__ */ o(H, { icon: a.icon, iconHover: a.iconHover, label: a.label, isActive: e })
41
+ w.map((i) => {
42
+ const a = e[i.id];
43
+ if (!a) return null;
44
+ let r = !1;
45
+ a.matchPaths && (Array.isArray(a.matchPaths) ? r = a.matchPaths.some((d) => n(t, d)) : r = n(t, a.matchPaths));
46
+ const p = m({
47
+ destination: a,
48
+ children: /* @__PURE__ */ o(P, { icon: i.icon, iconHover: i.iconHover, label: i.label, isActive: r })
54
49
  });
55
- return /* @__PURE__ */ o(s.Fragment, { children: v }, a.id);
50
+ return /* @__PURE__ */ o(g.Fragment, { children: p }, i.id);
56
51
  }),
57
52
  /* @__PURE__ */ o("div", { className: "flex-1" }),
58
- /* @__PURE__ */ t("div", { className: "flex flex-col items-center gap-6", children: [
59
- M.map((a) => {
60
- const i = c[a.id];
61
- if (!i) return null;
62
- const e = r({
63
- destination: i,
64
- children: /* @__PURE__ */ o(u, { icon: a.icon, label: a.label })
65
- });
66
- return /* @__PURE__ */ o(s.Fragment, { children: e }, a.id);
67
- }),
68
- n && n,
69
- p
70
- ] })
53
+ l
71
54
  ] });
72
55
  }
73
56
  export {
74
- U as Sidebar
57
+ F as Sidebar
75
58
  };
@@ -0,0 +1,7 @@
1
+ type InitialsAvatarProps = {
2
+ email: string;
3
+ displayName: string | undefined;
4
+ className?: string;
5
+ };
6
+ export declare function InitialsAvatar({ email, displayName, className }: InitialsAvatarProps): import("react/jsx-runtime").JSX.Element;
7
+ export {};
@@ -0,0 +1,42 @@
1
+ import { jsx as a } from "react/jsx-runtime";
2
+ import { twMerge as s } from "../../lib/tailwind-merge.js";
3
+ const n = [
4
+ "var(--color-primary-50)",
5
+ "var(--color-secondary-50)",
6
+ "var(--color-purple)",
7
+ "var(--color-success-50)",
8
+ "var(--color-primary-60)",
9
+ "var(--color-secondary-60)",
10
+ "var(--color-warning-60)",
11
+ "var(--color-secondary-70)"
12
+ ], c = /\s+/;
13
+ function i(o, r) {
14
+ if (o) {
15
+ const t = o.trim().split(c), e = t[0]?.[0] ?? "";
16
+ return t.length >= 2 ? (e + (t.at(-1)?.[0] ?? "")).toUpperCase() : e.toUpperCase();
17
+ }
18
+ return (r[0] ?? "").toUpperCase();
19
+ }
20
+ function l(o) {
21
+ let r = 0;
22
+ for (const t of o)
23
+ r = (r << 5) - r + t.charCodeAt(0) | 0;
24
+ return n[Math.abs(r) % n.length] ?? "var(--color-primary-50)";
25
+ }
26
+ function p({ email: o, displayName: r, className: t }) {
27
+ return /* @__PURE__ */ a(
28
+ "div",
29
+ {
30
+ className: s(
31
+ "flex size-8 items-center justify-center rounded-full text-xs font-semibold text-white outline-1 -outline-offset-1 outline-white/10 select-none",
32
+ t
33
+ ),
34
+ style: { backgroundColor: l(o) },
35
+ "aria-hidden": "true",
36
+ children: i(r, o)
37
+ }
38
+ );
39
+ }
40
+ export {
41
+ p as InitialsAvatar
42
+ };
@@ -1,36 +1,42 @@
1
1
  import { default as React } from 'react';
2
2
  import { DropdownMenu } from '../dropdown-menu/dropdown-menu';
3
- type UserWithNameAndPicture = {
3
+ type UserDropdownUser = {
4
4
  email: string;
5
- picture?: string;
6
5
  };
7
6
  type UserDropdownProps = {
8
- user: UserWithNameAndPicture | undefined;
7
+ user: UserDropdownUser | undefined;
9
8
  loginUrl: string;
10
9
  signupUrl: string;
11
10
  logoutUrl: string;
12
11
  accountUrl?: string;
13
- contactItem?: React.ReactNode;
14
- } & Omit<React.ComponentProps<typeof DropdownMenu>, 'trigger'>;
12
+ /** Extra menu items rendered between account and logout. */
13
+ menuItems?: React.ReactNode;
14
+ /** Display name shown on the trigger card. Falls back to email prefix when omitted. */
15
+ displayName?: string;
16
+ /** Plan tier label (e.g. "Free", "PRO · Monthly") shown below the name on the trigger card. */
17
+ planLabel?: string;
18
+ /** When provided, shows an "Upgrade" badge on the trigger and an upgrade menu item in the dropdown. */
19
+ upgradeUrl?: string;
20
+ /** When true, renders a compact avatar-only trigger (e.g. when the sidebar is collapsed). */
21
+ collapsed?: boolean;
22
+ /** When true, renders the trigger with a card-like background (use in sidebar context). */
23
+ card?: boolean;
24
+ } & Omit<React.ComponentProps<typeof DropdownMenu>, 'trigger' | 'contentClassName'>;
15
25
  /**
16
- * User dropdown menu that displays a user's email, account, and logout options.
17
- * @param user - The user to display in the dropdown
18
- * @param loginUrl - The URL to navigate to the login page
19
- * @param signupUrl - The URL to navigate to the signup page
20
- * @param logoutUrl - The URL to navigate to the logout page
21
- * @param accountUrl - The URL to navigate to the account page
22
- * @param contactItem - The item to display in the contact dropdown
23
-
26
+ * User dropdown menu with a trigger card showing avatar, display name, plan
27
+ * tier, and an optional upgrade pill. Opens a dropdown with email, account,
28
+ * contact, and logout items.
29
+ *
24
30
  * @example
25
- * // Example usage of UserDropdown
26
31
  * <UserDropdown
27
- * user={{ email: 'john.doe@example.com', picture: 'picture-url' }}
32
+ * user={{ email: 'john.doe@example.com' }}
33
+ * displayName="John"
34
+ * planLabel="PRO · Monthly"
28
35
  * loginUrl="/auth/login"
29
36
  * signupUrl="/auth/login?screen_hint=signup"
30
37
  * logoutUrl="/auth/logout"
31
38
  * accountUrl="/account"
32
- * contactItem={<IntercomButton><Icon icon="help-center"/><p className="tg-body">Contact Support</p></IntercomButton>}
33
39
  * />
34
40
  */
35
- export declare function UserDropdown({ user, loginUrl, signupUrl, logoutUrl, accountUrl, contactItem, className, ...props }: UserDropdownProps): import("react/jsx-runtime").JSX.Element;
41
+ export declare function UserDropdown({ user, loginUrl, signupUrl, logoutUrl, accountUrl, menuItems, displayName, planLabel, upgradeUrl, collapsed, card, className, ...props }: UserDropdownProps): import("react/jsx-runtime").JSX.Element;
36
42
  export {};
@@ -1,74 +1,118 @@
1
1
  "use client";
2
- import { jsxs as r, Fragment as p, jsx as e } from "react/jsx-runtime";
3
- import "react";
4
- import h from "../../assets/default-avatar.svg.js";
5
- import { Button as u } from "../button/button.js";
6
- import { DropdownMenu as f, DropdownMenuItem as i } from "../dropdown-menu/dropdown-menu.js";
7
- import { Icon as t } from "../icon/icon.js";
8
- import { twMerge as a } from "../../lib/tailwind-merge.js";
9
- function C({
10
- user: l,
11
- loginUrl: o,
2
+ import { jsxs as t, Fragment as y, jsx as e } from "react/jsx-runtime";
3
+ import z from "../../assets/default-avatar.svg.js";
4
+ import { Button as x } from "../button/button.js";
5
+ import { DropdownMenu as b, DropdownMenuItem as n } from "../dropdown-menu/dropdown-menu.js";
6
+ import { Icon as a } from "../icon/icon.js";
7
+ import { InitialsAvatar as N } from "./initials-avatar.js";
8
+ import { twMerge as o } from "../../lib/tailwind-merge.js";
9
+ function S({
10
+ user: r,
11
+ loginUrl: c,
12
12
  signupUrl: d,
13
- logoutUrl: g,
14
- accountUrl: c,
15
- contactItem: n,
13
+ logoutUrl: v,
14
+ accountUrl: u,
15
+ menuItems: m,
16
+ displayName: i,
17
+ planLabel: h,
18
+ upgradeUrl: l,
19
+ collapsed: g,
20
+ card: p,
16
21
  className: s,
17
- ...m
22
+ ...f
18
23
  }) {
19
- return l ? /* @__PURE__ */ r(
20
- f,
24
+ if (!r)
25
+ return /* @__PURE__ */ t(y, { children: [
26
+ /* @__PURE__ */ t("div", { className: o("hidden gap-3 sm:flex", s), children: [
27
+ /* @__PURE__ */ e(x, { variant: "secondary", size: "medium", asChild: !0, children: /* @__PURE__ */ e("a", { href: c, children: "Log in" }) }),
28
+ /* @__PURE__ */ e(x, { variant: "primary", size: "medium", asChild: !0, children: /* @__PURE__ */ e("a", { href: d, children: "Sign up" }) })
29
+ ] }),
30
+ /* @__PURE__ */ t(
31
+ b,
32
+ {
33
+ trigger: /* @__PURE__ */ e("img", { className: "size-7 cursor-pointer sm:hidden", src: z, alt: "User avatar" }),
34
+ className: o(
35
+ "hover:bg-neutral-60 focus-visible:ring-neutral-60 data-[state=open]:bg-neutral-60 rounded-full outline-none focus-visible:ring-2 sm:hidden",
36
+ s
37
+ ),
38
+ ...f,
39
+ children: [
40
+ /* @__PURE__ */ e(n, { asChild: !0, children: /* @__PURE__ */ e("a", { href: c, className: "tg-body", children: "Log in" }) }),
41
+ /* @__PURE__ */ e(n, { asChild: !0, children: /* @__PURE__ */ e("a", { href: d, className: "tg-body", children: "Sign up" }) }),
42
+ m
43
+ ]
44
+ }
45
+ )
46
+ ] });
47
+ const w = i ?? r.email.split("@")[0] ?? r.email;
48
+ return /* @__PURE__ */ t(
49
+ b,
21
50
  {
22
- trigger: /* @__PURE__ */ e(
51
+ trigger: g ? /* @__PURE__ */ e(
23
52
  "button",
24
53
  {
25
54
  type: "button",
26
- className: "gap-r3 focus-visible:ring-neutral-40 flex h-10 shrink cursor-pointer flex-row items-center overflow-hidden px-3 py-6 focus:outline-none focus-visible:rounded-xl focus-visible:ring-2",
27
- children: /* @__PURE__ */ e("img", { className: "size-7 rounded-full sm:size-9", src: l.picture ?? h, alt: "User avatar" })
55
+ "aria-label": "User menu",
56
+ className: "group focus-visible:ring-neutral-40 flex h-14 w-16 cursor-pointer items-center justify-center rounded-xl focus:outline-none focus-visible:ring-2",
57
+ children: /* @__PURE__ */ e(
58
+ N,
59
+ {
60
+ email: r.email,
61
+ displayName: i,
62
+ className: "group-hover:brightness-125 group-data-[state=open]:brightness-125"
63
+ }
64
+ )
65
+ }
66
+ ) : /* @__PURE__ */ t(
67
+ "button",
68
+ {
69
+ type: "button",
70
+ className: o(
71
+ "group focus-visible:ring-neutral-40 flex h-14 w-full cursor-pointer items-center gap-4 rounded-xl pr-3.5 pl-4 focus:outline-none focus-visible:ring-2",
72
+ p && "bg-neutral-65 hover:bg-neutral-60 shadow-[0_-6px_12px_-4px_rgba(0,0,0,0.25)]"
73
+ ),
74
+ children: [
75
+ /* @__PURE__ */ e(N, { email: r.email, displayName: i, className: "shrink-0" }),
76
+ /* @__PURE__ */ t("div", { className: "flex min-w-0 flex-1 flex-col gap-0.5", children: [
77
+ /* @__PURE__ */ e("span", { className: "tg-body-bold text-neutral-10 truncate text-left", children: w }),
78
+ h && /* @__PURE__ */ e("span", { className: "tg-caption text-neutral-40 group-data-[state=open]:text-neutral-10 truncate text-left", children: h })
79
+ ] }),
80
+ l ? /* @__PURE__ */ e("span", { className: "tg-caption-bold text-neutral-20 shrink-0 rounded-full border border-neutral-50 px-2.5 py-0.5", children: "Upgrade" }) : /* @__PURE__ */ e(
81
+ a,
82
+ {
83
+ icon: "chevron-vertical",
84
+ className: "text-neutral-40 group-data-[state=open]:text-neutral-10 size-3.5 shrink-0"
85
+ }
86
+ )
87
+ ]
28
88
  }
29
89
  ),
30
- className: a("tg-caption-bold -mx-2 rounded-xl px-2 py-1", s),
90
+ className: s,
31
91
  contentClassName: "bg-neutral-60",
32
- ...m,
92
+ contentStyle: p && !g ? { width: "var(--radix-dropdown-menu-trigger-width)" } : void 0,
93
+ ...f,
33
94
  children: [
34
- /* @__PURE__ */ r("div", { className: "tg-button-small text-neutral-40 flex items-center gap-3 px-4 py-2.5 select-text", children: [
35
- /* @__PURE__ */ e(t, { icon: "user", className: "size-4 flex-none" }),
36
- /* @__PURE__ */ e("p", { className: "tg-body", children: l.email })
95
+ l && /* @__PURE__ */ e(n, { asChild: !0, children: /* @__PURE__ */ t("a", { href: l, className: "flex items-center gap-3", children: [
96
+ /* @__PURE__ */ e(a, { icon: "sparkles", className: "size-4 flex-none text-white" }),
97
+ /* @__PURE__ */ e("p", { className: "tg-body", children: "Upgrade plan" })
98
+ ] }) }),
99
+ /* @__PURE__ */ t("div", { className: "tg-button-small text-neutral-40 flex items-center gap-3 overflow-hidden px-4 py-2.5 select-text", children: [
100
+ /* @__PURE__ */ e(a, { icon: "user", className: "size-4 flex-none" }),
101
+ /* @__PURE__ */ e("p", { className: "tg-body min-w-0 truncate", children: r.email })
37
102
  ] }),
38
- c && /* @__PURE__ */ e(i, { asChild: !0, children: /* @__PURE__ */ r("a", { href: c, className: "flex items-center gap-3", children: [
39
- /* @__PURE__ */ e(t, { icon: "cog", className: "size-4 flex-none text-white" }),
103
+ u && /* @__PURE__ */ e(n, { asChild: !0, children: /* @__PURE__ */ t("a", { href: u, className: "flex items-center gap-3", children: [
104
+ /* @__PURE__ */ e(a, { icon: "cog", className: "size-4 flex-none text-white" }),
40
105
  /* @__PURE__ */ e("p", { className: "tg-body", children: "Account" })
41
106
  ] }) }),
42
- n && /* @__PURE__ */ e(i, { asChild: !0, children: n }),
43
- /* @__PURE__ */ e(i, { asChild: !0, children: /* @__PURE__ */ r("a", { href: g, className: "flex items-center gap-3", children: [
44
- /* @__PURE__ */ e(t, { icon: "logout", className: "size-4 flex-none text-white" }),
107
+ m,
108
+ /* @__PURE__ */ e(n, { asChild: !0, children: /* @__PURE__ */ t("a", { href: v, className: "flex items-center gap-3", children: [
109
+ /* @__PURE__ */ e(a, { icon: "logout", className: "size-4 flex-none text-white" }),
45
110
  /* @__PURE__ */ e("p", { className: "tg-body", children: "Log out" })
46
111
  ] }) })
47
112
  ]
48
113
  }
49
- ) : /* @__PURE__ */ r(p, { children: [
50
- /* @__PURE__ */ r("div", { className: a("hidden gap-3 sm:flex", s), children: [
51
- /* @__PURE__ */ e(u, { variant: "secondary", size: "medium", asChild: !0, children: /* @__PURE__ */ e("a", { href: o, children: "Log in" }) }),
52
- /* @__PURE__ */ e(u, { variant: "primary", size: "medium", asChild: !0, children: /* @__PURE__ */ e("a", { href: d, children: "Sign up" }) })
53
- ] }),
54
- /* @__PURE__ */ r(
55
- f,
56
- {
57
- trigger: /* @__PURE__ */ e("img", { className: "size-7 cursor-pointer sm:hidden", src: h, alt: "User avatar" }),
58
- className: a(
59
- "hover:bg-neutral-60 focus-visible:ring-neutral-60 data-[state=open]:bg-neutral-60 rounded-full outline-none focus-visible:ring-2 sm:hidden",
60
- s
61
- ),
62
- ...m,
63
- children: [
64
- /* @__PURE__ */ e(i, { asChild: !0, children: /* @__PURE__ */ e("a", { href: o, className: "tg-body", children: "Log in" }) }),
65
- /* @__PURE__ */ e(i, { asChild: !0, children: /* @__PURE__ */ e("a", { href: d, className: "tg-body", children: "Sign up" }) }),
66
- n && /* @__PURE__ */ e(i, { children: n })
67
- ]
68
- }
69
- )
70
- ] });
114
+ );
71
115
  }
72
116
  export {
73
- C as UserDropdown
117
+ S as UserDropdown
74
118
  };
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@validationcloud/fractal-ui",
3
3
  "description": "Validation Cloud's shared React component library with design tokens, Tailwind CSS utilities, and CLI tools",
4
4
  "private": false,
5
- "version": "1.81.0",
5
+ "version": "1.82.0",
6
6
  "module": "./dist/index.js",
7
7
  "type": "module",
8
8
  "bin": {
@@ -1,7 +0,0 @@
1
- import { default as React } from 'react';
2
- type BottomNavItemProps = {
3
- icon: React.ReactNode;
4
- label: string;
5
- } & React.ComponentPropsWithoutRef<'div'>;
6
- export declare function BottomNavItem({ icon, label, className, ...props }: BottomNavItemProps): import("react/jsx-runtime").JSX.Element;
7
- export {};
@@ -1,19 +0,0 @@
1
- import { jsxs as o, jsx as c } from "react/jsx-runtime";
2
- import "react";
3
- import { twMerge as i } from "../../lib/tailwind-merge.js";
4
- function l({ icon: t, label: e, className: r, ...n }) {
5
- return /* @__PURE__ */ o(
6
- "div",
7
- {
8
- className: i("text-neutral-40 hover:text-neutral-10 flex flex-col items-center justify-center", r),
9
- ...n,
10
- children: [
11
- t,
12
- /* @__PURE__ */ c("span", { className: "tg-caption text-center", children: e })
13
- ]
14
- }
15
- );
16
- }
17
- export {
18
- l as BottomNavItem
19
- };