@validationcloud/fractal-ui 1.81.0 → 1.83.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,64 @@
1
- import { default as React } from 'react';
2
1
  import { DropdownMenu } from '../dropdown-menu/dropdown-menu';
3
- type UserWithNameAndPicture = {
2
+ import { IconID } from '../icon/icon';
3
+ export type UserDropdownUser = {
4
4
  email: string;
5
- picture?: string;
6
5
  };
7
- type UserDropdownProps = {
8
- user: UserWithNameAndPicture | undefined;
6
+ type UserDropdownRootProps = {
7
+ user: UserDropdownUser;
8
+ /** Display name shown on the trigger. Falls back to the email prefix when omitted. */
9
+ displayName?: string;
10
+ trigger: React.ReactNode;
11
+ /** When true, the dropdown content width matches the trigger width. */
12
+ matchTriggerWidth?: boolean;
13
+ className?: string;
14
+ children: React.ReactNode;
15
+ } & Omit<React.ComponentProps<typeof DropdownMenu>, 'trigger' | 'contentClassName' | 'contentStyle'>;
16
+ declare function UserDropdownRoot({ user, displayName, trigger, matchTriggerWidth, className, children, ...props }: UserDropdownRootProps): import("react/jsx-runtime").JSX.Element;
17
+ type UserDropdownTriggerProps = {
18
+ /** Plan tier label (e.g. "Free", "PRO \u00b7 Monthly") shown below the name. */
19
+ planLabel?: string;
20
+ /** Render a card-like background (use in sidebar context). */
21
+ card?: boolean;
22
+ /** Custom trailing content. Defaults to a chevron icon. */
23
+ trailing?: React.ReactNode;
24
+ } & React.ComponentPropsWithoutRef<'button'>;
25
+ declare function UserDropdownTrigger({ planLabel, card, trailing, className, ...props }: UserDropdownTriggerProps): import("react/jsx-runtime").JSX.Element;
26
+ type UserDropdownAvatarTriggerProps = React.ComponentPropsWithoutRef<'button'>;
27
+ declare function UserDropdownAvatarTrigger({ className, ...props }: UserDropdownAvatarTriggerProps): import("react/jsx-runtime").JSX.Element;
28
+ declare function UserDropdownUpgradeBadge(): import("react/jsx-runtime").JSX.Element;
29
+ declare function UserDropdownEmail(): import("react/jsx-runtime").JSX.Element;
30
+ type UserDropdownItemProps = {
31
+ href: string;
32
+ icon: IconID;
33
+ children: React.ReactNode;
34
+ };
35
+ declare function UserDropdownItem({ href, icon, children }: UserDropdownItemProps): import("react/jsx-runtime").JSX.Element;
36
+ declare function UserDropdownUpgrade({ href }: {
37
+ href: string;
38
+ }): import("react/jsx-runtime").JSX.Element;
39
+ declare function UserDropdownAccount({ href }: {
40
+ href: string;
41
+ }): import("react/jsx-runtime").JSX.Element;
42
+ declare function UserDropdownLogout({ href }: {
43
+ href: string;
44
+ }): import("react/jsx-runtime").JSX.Element;
45
+ type UserDropdownLoggedOutProps = {
9
46
  loginUrl: string;
10
47
  signupUrl: string;
11
- logoutUrl: string;
12
- accountUrl?: string;
13
- contactItem?: React.ReactNode;
14
- } & Omit<React.ComponentProps<typeof DropdownMenu>, 'trigger'>;
15
- /**
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
-
24
- * @example
25
- * // Example usage of UserDropdown
26
- * <UserDropdown
27
- * user={{ email: 'john.doe@example.com', picture: 'picture-url' }}
28
- * loginUrl="/auth/login"
29
- * signupUrl="/auth/login?screen_hint=signup"
30
- * logoutUrl="/auth/logout"
31
- * accountUrl="/account"
32
- * contactItem={<IntercomButton><Icon icon="help-center"/><p className="tg-body">Contact Support</p></IntercomButton>}
33
- * />
34
- */
35
- export declare function UserDropdown({ user, loginUrl, signupUrl, logoutUrl, accountUrl, contactItem, className, ...props }: UserDropdownProps): import("react/jsx-runtime").JSX.Element;
48
+ className?: string;
49
+ /** Extra menu items rendered inside the mobile dropdown. */
50
+ children?: React.ReactNode;
51
+ };
52
+ declare function UserDropdownLoggedOut({ loginUrl, signupUrl, className, children }: UserDropdownLoggedOutProps): import("react/jsx-runtime").JSX.Element;
53
+ export declare const UserDropdown: typeof UserDropdownRoot & {
54
+ Trigger: typeof UserDropdownTrigger;
55
+ AvatarTrigger: typeof UserDropdownAvatarTrigger;
56
+ UpgradeBadge: typeof UserDropdownUpgradeBadge;
57
+ Email: typeof UserDropdownEmail;
58
+ Item: typeof UserDropdownItem;
59
+ Upgrade: typeof UserDropdownUpgrade;
60
+ Account: typeof UserDropdownAccount;
61
+ Logout: typeof UserDropdownLogout;
62
+ LoggedOut: typeof UserDropdownLoggedOut;
63
+ };
36
64
  export {};
@@ -1,74 +1,152 @@
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,
12
- signupUrl: d,
13
- logoutUrl: g,
14
- accountUrl: c,
15
- contactItem: n,
16
- className: s,
17
- ...m
2
+ import { jsx as e, jsxs as a, Fragment as w } from "react/jsx-runtime";
3
+ import { createContext as v, use as N } from "react";
4
+ import U from "../../assets/default-avatar.svg.js";
5
+ import { Button as g } from "../button/button.js";
6
+ import { DropdownMenu as h, DropdownMenuItem as u } from "../dropdown-menu/dropdown-menu.js";
7
+ import { Icon as p } from "../icon/icon.js";
8
+ import { InitialsAvatar as f } from "./initials-avatar.js";
9
+ import { twMerge as s } from "../../lib/tailwind-merge.js";
10
+ const x = v(null);
11
+ function m() {
12
+ const r = N(x);
13
+ if (!r)
14
+ throw new Error("UserDropdown compound components must be rendered inside <UserDropdown>.");
15
+ return r;
16
+ }
17
+ function D({
18
+ user: r,
19
+ displayName: n,
20
+ trigger: t,
21
+ matchTriggerWidth: o,
22
+ className: c,
23
+ children: d,
24
+ ...i
18
25
  }) {
19
- return l ? /* @__PURE__ */ r(
20
- f,
26
+ const b = n ?? r.email.split("@")[0] ?? r.email;
27
+ return /* @__PURE__ */ e(x, { value: { user: r, displayName: b }, children: /* @__PURE__ */ e(
28
+ h,
21
29
  {
22
- trigger: /* @__PURE__ */ e(
23
- "button",
24
- {
25
- 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" })
28
- }
29
- ),
30
- className: a("tg-caption-bold -mx-2 rounded-xl px-2 py-1", s),
30
+ trigger: t,
31
+ className: c,
31
32
  contentClassName: "bg-neutral-60",
32
- ...m,
33
+ contentStyle: o ? { width: "var(--radix-dropdown-menu-trigger-width)" } : void 0,
34
+ ...i,
35
+ children: d
36
+ }
37
+ ) });
38
+ }
39
+ function y({ planLabel: r, card: n, trailing: t, className: o, ...c }) {
40
+ const { user: d, displayName: i } = m();
41
+ return /* @__PURE__ */ a(
42
+ "button",
43
+ {
44
+ type: "button",
45
+ className: s(
46
+ "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",
47
+ n && "bg-neutral-65 hover:bg-neutral-60 shadow-[0_-6px_12px_-4px_rgba(0,0,0,0.25)]",
48
+ o
49
+ ),
50
+ ...c,
33
51
  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 })
52
+ /* @__PURE__ */ e(f, { email: d.email, displayName: i, className: "shrink-0" }),
53
+ /* @__PURE__ */ a("div", { className: "flex min-w-0 flex-1 flex-col gap-0.5", children: [
54
+ /* @__PURE__ */ e("span", { className: "tg-body-bold text-neutral-10 truncate text-left", children: i }),
55
+ r && /* @__PURE__ */ e("span", { className: "tg-caption text-neutral-40 group-data-[state=open]:text-neutral-10 truncate text-left", children: r })
37
56
  ] }),
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" }),
40
- /* @__PURE__ */ e("p", { className: "tg-body", children: "Account" })
41
- ] }) }),
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" }),
45
- /* @__PURE__ */ e("p", { className: "tg-body", children: "Log out" })
46
- ] }) })
57
+ t ?? /* @__PURE__ */ e(
58
+ p,
59
+ {
60
+ icon: "chevron-vertical",
61
+ className: "text-neutral-40 group-data-[state=open]:text-neutral-10 size-3.5 shrink-0"
62
+ }
63
+ )
47
64
  ]
48
65
  }
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" }) })
66
+ );
67
+ }
68
+ function C({ className: r, ...n }) {
69
+ const { user: t, displayName: o } = m();
70
+ return /* @__PURE__ */ e(
71
+ "button",
72
+ {
73
+ type: "button",
74
+ "aria-label": "User menu",
75
+ className: s(
76
+ "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",
77
+ r
78
+ ),
79
+ ...n,
80
+ children: /* @__PURE__ */ e(
81
+ f,
82
+ {
83
+ email: t.email,
84
+ displayName: o,
85
+ className: "group-hover:brightness-125 group-data-[state=open]:brightness-125"
86
+ }
87
+ )
88
+ }
89
+ );
90
+ }
91
+ function A() {
92
+ return /* @__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" });
93
+ }
94
+ function z() {
95
+ const { user: r } = m();
96
+ return /* @__PURE__ */ a("div", { className: "tg-button-small text-neutral-40 flex items-center gap-3 overflow-hidden px-4 py-2.5 select-text", children: [
97
+ /* @__PURE__ */ e(p, { icon: "user", className: "size-4 flex-none" }),
98
+ /* @__PURE__ */ e("p", { className: "tg-body min-w-0 truncate", children: r.email })
99
+ ] });
100
+ }
101
+ function l({ href: r, icon: n, children: t }) {
102
+ return /* @__PURE__ */ e(u, { asChild: !0, children: /* @__PURE__ */ a("a", { href: r, className: "flex items-center gap-3", children: [
103
+ /* @__PURE__ */ e(p, { icon: n, className: "size-4 flex-none text-white" }),
104
+ /* @__PURE__ */ e("p", { className: "tg-body", children: t })
105
+ ] }) });
106
+ }
107
+ function L({ href: r }) {
108
+ return /* @__PURE__ */ e(l, { href: r, icon: "sparkles", children: "Upgrade plan" });
109
+ }
110
+ function I({ href: r }) {
111
+ return /* @__PURE__ */ e(l, { href: r, icon: "cog", children: "Account" });
112
+ }
113
+ function j({ href: r }) {
114
+ return /* @__PURE__ */ e(l, { href: r, icon: "logout", children: "Log out" });
115
+ }
116
+ function k({ loginUrl: r, signupUrl: n, className: t, children: o }) {
117
+ return /* @__PURE__ */ a(w, { children: [
118
+ /* @__PURE__ */ a("div", { className: s("hidden gap-3 sm:flex", t), children: [
119
+ /* @__PURE__ */ e(g, { variant: "secondary", size: "medium", asChild: !0, children: /* @__PURE__ */ e("a", { href: r, children: "Log in" }) }),
120
+ /* @__PURE__ */ e(g, { variant: "primary", size: "medium", asChild: !0, children: /* @__PURE__ */ e("a", { href: n, children: "Sign up" }) })
53
121
  ] }),
54
- /* @__PURE__ */ r(
55
- f,
122
+ /* @__PURE__ */ a(
123
+ h,
56
124
  {
57
- trigger: /* @__PURE__ */ e("img", { className: "size-7 cursor-pointer sm:hidden", src: h, alt: "User avatar" }),
58
- className: a(
125
+ trigger: /* @__PURE__ */ e("img", { className: "size-7 cursor-pointer sm:hidden", src: U, alt: "User avatar" }),
126
+ className: s(
59
127
  "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
128
+ t
61
129
  ),
62
- ...m,
63
130
  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 })
131
+ /* @__PURE__ */ e(u, { asChild: !0, children: /* @__PURE__ */ e("a", { href: r, className: "tg-body", children: "Log in" }) }),
132
+ /* @__PURE__ */ e(u, { asChild: !0, children: /* @__PURE__ */ e("a", { href: n, className: "tg-body", children: "Sign up" }) }),
133
+ o
67
134
  ]
68
135
  }
69
136
  )
70
137
  ] });
71
138
  }
139
+ const R = Object.assign(D, {
140
+ Trigger: y,
141
+ AvatarTrigger: C,
142
+ UpgradeBadge: A,
143
+ Email: z,
144
+ Item: l,
145
+ Upgrade: L,
146
+ Account: I,
147
+ Logout: j,
148
+ LoggedOut: k
149
+ });
72
150
  export {
73
- C as UserDropdown
151
+ R as UserDropdown
74
152
  };
package/dist/index.d.ts CHANGED
@@ -25,5 +25,5 @@ export { Tooltip } from './components/tooltip/tooltip';
25
25
  export { TooltipProvider } from './components/tooltip-provider/tooltip-provider';
26
26
  export { TouchTarget } from './components/touch-target/touch-target';
27
27
  export { twMerge } from './lib/tailwind-merge';
28
- export { UserDropdown } from './components/user-dropdown/user-dropdown';
28
+ export { UserDropdown, type UserDropdownUser } from './components/user-dropdown/user-dropdown';
29
29
  export { useScrollToBottom } from './hooks/use-scroll-to-bottom';
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.83.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
- };