@pollinations/ui 0.0.2 → 0.1.0-alpha.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.
Files changed (48) hide show
  1. package/README.md +10 -6
  2. package/dist/{Button-CWUBCiIc.d.cts → Button-BvLF_Km2.d.cts} +3 -3
  3. package/dist/{Button-Bn8pGg6N.d.ts → Button-DQAZzvyQ.d.ts} +3 -3
  4. package/dist/auth/index.cjs +77 -62
  5. package/dist/auth/index.cjs.map +1 -1
  6. package/dist/auth/index.js +77 -62
  7. package/dist/auth/index.js.map +1 -1
  8. package/dist/auth/sdk.cjs +7 -6
  9. package/dist/auth/sdk.cjs.map +1 -1
  10. package/dist/auth/sdk.d.cts +1 -1
  11. package/dist/auth/sdk.d.ts +1 -1
  12. package/dist/auth/sdk.js +7 -6
  13. package/dist/auth/sdk.js.map +1 -1
  14. package/dist/compositions/app-user.cjs +497 -0
  15. package/dist/compositions/app-user.cjs.map +1 -0
  16. package/dist/compositions/app-user.d.cts +18 -0
  17. package/dist/compositions/app-user.d.ts +18 -0
  18. package/dist/compositions/app-user.js +469 -0
  19. package/dist/compositions/app-user.js.map +1 -0
  20. package/dist/index.cjs +932 -270
  21. package/dist/index.cjs.map +1 -1
  22. package/dist/index.d.cts +101 -6
  23. package/dist/index.d.ts +101 -6
  24. package/dist/index.js +891 -247
  25. package/dist/index.js.map +1 -1
  26. package/dist/modality/index.cjs +21 -18
  27. package/dist/modality/index.cjs.map +1 -1
  28. package/dist/modality/index.d.cts +6 -5
  29. package/dist/modality/index.d.ts +6 -5
  30. package/dist/modality/index.js +21 -18
  31. package/dist/modality/index.js.map +1 -1
  32. package/dist/models/index.cjs +508 -0
  33. package/dist/models/index.cjs.map +1 -0
  34. package/dist/models/index.d.cts +22 -0
  35. package/dist/models/index.d.ts +22 -0
  36. package/dist/models/index.js +486 -0
  37. package/dist/models/index.js.map +1 -0
  38. package/dist/styles.css +1 -1
  39. package/dist/wallet/index.cjs +13 -4
  40. package/dist/wallet/index.cjs.map +1 -1
  41. package/dist/wallet/index.js +13 -4
  42. package/dist/wallet/index.js.map +1 -1
  43. package/dist/wallet/sdk.cjs +2 -2
  44. package/dist/wallet/sdk.cjs.map +1 -1
  45. package/dist/wallet/sdk.js +2 -2
  46. package/dist/wallet/sdk.js.map +1 -1
  47. package/package.json +17 -5
  48. package/dist/wallet.css +0 -73
@@ -1,6 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { ReactNode } from 'react';
3
- import { a as ButtonProps } from '../Button-CWUBCiIc.cjs';
3
+ import { a as ButtonProps } from '../Button-BvLF_Km2.cjs';
4
4
  import '../theme-VMRlhqST.cjs';
5
5
 
6
6
  type LoginButtonProps = Omit<ButtonProps<"button">, "as" | "onClick" | "children"> & {
@@ -1,6 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { ReactNode } from 'react';
3
- import { a as ButtonProps } from '../Button-Bn8pGg6N.js';
3
+ import { a as ButtonProps } from '../Button-DQAZzvyQ.js';
4
4
  import '../theme-VMRlhqST.js';
5
5
 
6
6
  type LoginButtonProps = Omit<ButtonProps<"button">, "as" | "onClick" | "children"> & {
package/dist/auth/sdk.js CHANGED
@@ -12,13 +12,13 @@ function cn(...inputs) {
12
12
  // src/primitives/Button.tsx
13
13
  import { jsx } from "react/jsx-runtime";
14
14
  var sizes = {
15
- small: "polli:px-2 polli:pt-0.5 polli:pb-1",
16
- medium: "polli:px-4 polli:pt-1.5 polli:pb-2",
17
- large: "polli:px-6 polli:py-3"
15
+ sm: "polli:px-2 polli:pt-0.5 polli:pb-1",
16
+ md: "polli:px-4 polli:pt-1.5 polli:pb-2",
17
+ lg: "polli:px-6 polli:py-3"
18
18
  };
19
19
  var themeClasses = "polli:bg-theme-bg-active polli:text-theme-text-base polli:hover:bg-theme-bg-hover polli:transition-colors";
20
20
  var intentClasses = {
21
- danger: "polli:bg-intent-danger-bg-light polli:text-intent-danger-text polli:hover:bg-[oklch(0.88_0.075_25)] polli:transition-colors"
21
+ danger: "polli:bg-intent-danger-bg-light polli:text-intent-danger-text polli:hover:bg-intent-danger-bg-hover polli:transition-colors"
22
22
  };
23
23
  var buttonClasses = ({
24
24
  theme: _theme,
@@ -29,10 +29,10 @@ var buttonClasses = ({
29
29
  }) => {
30
30
  const colorClasses = intent ? intentClasses[intent] : themeClasses;
31
31
  return cn(
32
- "polli:inline-flex polli:items-center polli:justify-center polli:rounded-full polli:self-center polli:placeholder-green-950 polli:font-medium polli:leading-normal polli:box-border",
32
+ "polli-control polli:inline-flex polli:items-center polli:justify-center polli:rounded-full polli:self-center polli:font-medium polli:leading-normal polli:box-border",
33
33
  disabled ? "polli:opacity-50 polli:cursor-not-allowed" : "polli:hover:filter polli:hover:brightness-105 polli:cursor-pointer",
34
34
  colorClasses,
35
- sizes[size || "medium"],
35
+ sizes[size || "md"],
36
36
  className
37
37
  );
38
38
  };
@@ -51,6 +51,7 @@ function Button({
51
51
  Component,
52
52
  {
53
53
  "data-theme": intent ? void 0 : theme,
54
+ "data-intent": intent,
54
55
  className: buttonClasses({
55
56
  theme,
56
57
  intent,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/modules/auth/LoginButton.tsx","../../src/lib/cn.ts","../../src/primitives/Button.tsx","../../src/modules/auth/LogoutButton.tsx","../../src/modules/auth/UserAvatar.tsx","../../src/modules/auth/UserEmail.tsx","../../src/modules/auth/UserName.tsx","../../src/modules/auth/WhenLoggedIn.tsx","../../src/modules/auth/WhenLoggedOut.tsx"],"sourcesContent":["import { useAuthActions, useAuthState } from \"@pollinations/sdk/react\";\nimport type { ReactNode } from \"react\";\nimport { Button, type ButtonProps } from \"../../primitives/Button.tsx\";\n\nexport type LoginButtonProps = Omit<\n ButtonProps<\"button\">,\n \"as\" | \"onClick\" | \"children\"\n> & {\n children: ReactNode;\n};\n\n/** Button that kicks off the auth redirect. `null` when already logged in. */\nexport function LoginButton({ children, ...buttonProps }: LoginButtonProps) {\n const { isLoggedIn } = useAuthState();\n const { login } = useAuthActions();\n if (isLoggedIn) return null;\n return (\n <Button {...buttonProps} onClick={() => login()}>\n {children}\n </Button>\n );\n}\n","import { clsx } from \"clsx\";\nimport { extendTailwindMerge } from \"tailwind-merge\";\n\nconst twMerge = extendTailwindMerge({ prefix: \"polli\" });\n\n/** Internal class merge for polli:-prefixed package primitive classes. */\nexport function cn(...inputs: (string | undefined | null | false)[]) {\n return twMerge(clsx(...inputs));\n}\n","import type { PropsWithChildren } from \"react\";\nimport { cn } from \"../lib/cn.ts\";\nimport type { ThemeName } from \"../theme.ts\";\n\n/** Button only supports `danger`. Label/status color recipes live on Chip. */\ntype ButtonIntent = \"danger\";\n\nconst sizes = {\n small: \"polli:px-2 polli:pt-0.5 polli:pb-1\",\n medium: \"polli:px-4 polli:pt-1.5 polli:pb-2\",\n large: \"polli:px-6 polli:py-3\",\n} as const;\n\n// Cascade-driven base — reads [data-theme] vars.\nconst themeClasses =\n \"polli:bg-theme-bg-active polli:text-theme-text-base \" +\n \"polli:hover:bg-theme-bg-hover polli:transition-colors\";\n\n// Single intent: danger. Soft recipe — light tile + deep text, slightly\n// deeper bg on hover. No filled CTAs anywhere.\nconst intentClasses: Record<ButtonIntent, string> = {\n danger:\n \"polli:bg-intent-danger-bg-light polli:text-intent-danger-text \" +\n \"polli:hover:bg-[oklch(0.88_0.075_25)] polli:transition-colors\",\n};\n\ntype BaseButtonProps = {\n /** Override the cascade theme for this button's subtree. Ignored when `intent` is set. */\n theme?: ThemeName;\n /** Only `\"danger\"` for now. */\n intent?: ButtonIntent;\n size?: keyof typeof sizes;\n className?: string;\n disabled?: boolean;\n};\n\nconst buttonClasses = ({\n theme: _theme,\n intent,\n size,\n className,\n disabled,\n}: BaseButtonProps & { disabled?: boolean }) => {\n const colorClasses = intent ? intentClasses[intent] : themeClasses;\n return cn(\n \"polli:inline-flex polli:items-center polli:justify-center polli:rounded-full polli:self-center polli:placeholder-green-950 polli:font-medium polli:leading-normal polli:box-border\",\n disabled\n ? \"polli:opacity-50 polli:cursor-not-allowed\"\n : \"polli:hover:filter polli:hover:brightness-105 polli:cursor-pointer\",\n colorClasses,\n sizes[size || \"medium\"],\n className,\n );\n};\n\nexport type ButtonProps<T extends React.ElementType = \"button\"> =\n PropsWithChildren<BaseButtonProps> & {\n as?: T;\n } & Omit<React.ComponentPropsWithoutRef<T>, keyof BaseButtonProps | \"as\">;\n\nexport function Button<T extends React.ElementType = \"button\">({\n as,\n children,\n theme,\n intent,\n size,\n className,\n disabled,\n ...buttonProps\n}: ButtonProps<T>) {\n const Component: React.ElementType = as || \"button\";\n\n return (\n <Component\n // Cascade override only applies when `intent` is unset.\n data-theme={intent ? undefined : theme}\n className={buttonClasses({\n theme,\n intent,\n size,\n className,\n disabled,\n })}\n disabled={disabled}\n {...buttonProps}\n >\n {children}\n </Component>\n );\n}\n","import { useAuthActions, useAuthState } from \"@pollinations/sdk/react\";\nimport type { ReactNode } from \"react\";\nimport { Button, type ButtonProps } from \"../../primitives/Button.tsx\";\n\nexport type LogoutButtonProps = Omit<\n ButtonProps<\"button\">,\n \"as\" | \"onClick\" | \"children\"\n> & {\n children: ReactNode;\n};\n\n/** Button that clears the session. `null` when logged out. */\nexport function LogoutButton({ children, ...buttonProps }: LogoutButtonProps) {\n const { isLoggedIn } = useAuthState();\n const { logout } = useAuthActions();\n if (!isLoggedIn) return null;\n return (\n <Button {...buttonProps} onClick={() => logout()}>\n {children}\n </Button>\n );\n}\n","import { useAccountProfile, useAuthState } from \"@pollinations/sdk/react\";\nimport { cn } from \"../../lib/cn.ts\";\n\nexport type UserAvatarProps = {\n size?: \"sm\" | \"md\" | \"lg\";\n className?: string;\n};\n\nconst sizeClass = {\n sm: \"polli:w-6 polli:h-6 polli:text-xs\",\n md: \"polli:w-9 polli:h-9 polli:text-sm\",\n lg: \"polli:w-12 polli:h-12 polli:text-base\",\n} as const;\n\nfunction initials(name: string): string | null {\n const parts = name.trim().split(/\\s+/).filter(Boolean);\n if (parts.length === 0) return null;\n if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase() || null;\n const first = parts[0][0] ?? \"\";\n const last = parts[parts.length - 1][0] ?? \"\";\n return (first + last).toUpperCase() || null;\n}\n\n/** Avatar from `profile.image`, or initials from `profile.name`. `null` otherwise. */\nexport function UserAvatar({ size = \"md\", className }: UserAvatarProps) {\n const { isLoggedIn } = useAuthState();\n const { data: profile } = useAccountProfile({ enabled: isLoggedIn });\n if (!isLoggedIn) return null;\n\n const base = cn(\n \"polli:inline-flex polli:items-center polli:justify-center polli:rounded-full polli:overflow-hidden polli:bg-theme-bg-pale polli:text-theme-text-strong polli:font-semibold polli:select-none\",\n sizeClass[size],\n className,\n );\n\n if (profile?.image) {\n return (\n <img\n data-polli=\"user-avatar\"\n src={profile.image}\n alt={profile.name ?? \"\"}\n className={base}\n />\n );\n }\n const label = profile?.name ? initials(profile.name) : null;\n if (!label) return null;\n return (\n <div\n data-polli=\"user-avatar\"\n role=\"img\"\n aria-label={profile?.name ?? undefined}\n className={base}\n >\n {label}\n </div>\n );\n}\n","import { useAccountProfile, useAuthState } from \"@pollinations/sdk/react\";\n\nexport type UserEmailProps = { className?: string };\n\n/** Renders `profile.email`. `null` when logged out or the key lacks `profile` scope. */\nexport function UserEmail({ className }: UserEmailProps) {\n const { isLoggedIn } = useAuthState();\n const { data: profile } = useAccountProfile({ enabled: isLoggedIn });\n if (!isLoggedIn || !profile?.email) return null;\n return (\n <span data-polli=\"user-email\" className={className}>\n {profile.email}\n </span>\n );\n}\n","import { useAccountProfile, useAuthState } from \"@pollinations/sdk/react\";\n\nexport type UserNameProps = { className?: string };\n\n/**\n * Renders the user's display name. Falls back to GitHub username when the\n * `profile` scope was not granted (or `name` is empty). `null` when logged\n * out, or when neither name nor GitHub username is available.\n */\nexport function UserName({ className }: UserNameProps) {\n const { isLoggedIn } = useAuthState();\n const { data: profile } = useAccountProfile({ enabled: isLoggedIn });\n if (!isLoggedIn || !profile) return null;\n const display = profile.name || profile.githubUsername;\n if (!display) return null;\n return (\n <span data-polli=\"user-name\" className={className}>\n {display}\n </span>\n );\n}\n","import { useAuthState } from \"@pollinations/sdk/react\";\nimport { Fragment, type ReactNode } from \"react\";\n\nexport type WhenLoggedInProps = { children: ReactNode };\n\n/** Renders `children` only when a user is signed in. */\nexport function WhenLoggedIn({ children }: WhenLoggedInProps) {\n const { isLoggedIn } = useAuthState();\n if (!isLoggedIn) return null;\n return <Fragment>{children}</Fragment>;\n}\n","import { useAuthState } from \"@pollinations/sdk/react\";\nimport { Fragment, type ReactNode } from \"react\";\n\nexport type WhenLoggedOutProps = { children: ReactNode };\n\n/** Renders `children` only when no user is signed in. */\nexport function WhenLoggedOut({ children }: WhenLoggedOutProps) {\n const { isLoggedIn } = useAuthState();\n if (isLoggedIn) return null;\n return <Fragment>{children}</Fragment>;\n}\n"],"mappings":"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","names":["jsx","useAuthActions","useAuthState","jsx","useAuthState","useAuthActions","useAuthState","jsx","useAuthState","useAccountProfile","useAuthState","jsx","useAccountProfile","useAuthState","jsx","useAuthState","jsx","useAuthState","Fragment","jsx"]}
1
+ {"version":3,"sources":["../../src/modules/auth/LoginButton.tsx","../../src/lib/cn.ts","../../src/primitives/Button.tsx","../../src/modules/auth/LogoutButton.tsx","../../src/modules/auth/UserAvatar.tsx","../../src/modules/auth/UserEmail.tsx","../../src/modules/auth/UserName.tsx","../../src/modules/auth/WhenLoggedIn.tsx","../../src/modules/auth/WhenLoggedOut.tsx"],"sourcesContent":["import { useAuthActions, useAuthState } from \"@pollinations/sdk/react\";\nimport type { ReactNode } from \"react\";\nimport { Button, type ButtonProps } from \"../../primitives/Button.tsx\";\n\nexport type LoginButtonProps = Omit<\n ButtonProps<\"button\">,\n \"as\" | \"onClick\" | \"children\"\n> & {\n children: ReactNode;\n};\n\n/** Button that kicks off the auth redirect. `null` when already logged in. */\nexport function LoginButton({ children, ...buttonProps }: LoginButtonProps) {\n const { isLoggedIn } = useAuthState();\n const { login } = useAuthActions();\n if (isLoggedIn) return null;\n return (\n <Button {...buttonProps} onClick={() => login()}>\n {children}\n </Button>\n );\n}\n","import { clsx } from \"clsx\";\nimport { extendTailwindMerge } from \"tailwind-merge\";\n\nconst twMerge = extendTailwindMerge({ prefix: \"polli\" });\n\n/** Internal class merge for polli:-prefixed package primitive classes. */\nexport function cn(...inputs: (string | undefined | null | false)[]) {\n return twMerge(clsx(...inputs));\n}\n","import type { PropsWithChildren } from \"react\";\nimport { cn } from \"../lib/cn.ts\";\nimport type { ThemeName } from \"../theme.ts\";\n\n/** Button only supports `danger`. Label/status color recipes live on Chip. */\ntype ButtonIntent = \"danger\";\n\nconst sizes = {\n sm: \"polli:px-2 polli:pt-0.5 polli:pb-1\",\n md: \"polli:px-4 polli:pt-1.5 polli:pb-2\",\n lg: \"polli:px-6 polli:py-3\",\n} as const;\n\n// Cascade-driven base — reads [data-theme] vars.\nconst themeClasses =\n \"polli:bg-theme-bg-active polli:text-theme-text-base \" +\n \"polli:hover:bg-theme-bg-hover polli:transition-colors\";\n\n// Single intent: danger. Soft recipe — light tile + deep text, slightly\n// deeper bg on hover. No filled CTAs anywhere.\nconst intentClasses: Record<ButtonIntent, string> = {\n danger:\n \"polli:bg-intent-danger-bg-light polli:text-intent-danger-text \" +\n \"polli:hover:bg-intent-danger-bg-hover polli:transition-colors\",\n};\n\ntype BaseButtonProps = {\n /** Override the cascade theme for this button's subtree. Ignored when `intent` is set. */\n theme?: ThemeName;\n /** Only `\"danger\"` for now. */\n intent?: ButtonIntent;\n size?: keyof typeof sizes;\n className?: string;\n disabled?: boolean;\n};\n\nconst buttonClasses = ({\n theme: _theme,\n intent,\n size,\n className,\n disabled,\n}: BaseButtonProps & { disabled?: boolean }) => {\n const colorClasses = intent ? intentClasses[intent] : themeClasses;\n return cn(\n \"polli-control polli:inline-flex polli:items-center polli:justify-center polli:rounded-full polli:self-center polli:font-medium polli:leading-normal polli:box-border\",\n disabled\n ? \"polli:opacity-50 polli:cursor-not-allowed\"\n : \"polli:hover:filter polli:hover:brightness-105 polli:cursor-pointer\",\n colorClasses,\n sizes[size || \"md\"],\n className,\n );\n};\n\nexport type ButtonProps<T extends React.ElementType = \"button\"> =\n PropsWithChildren<BaseButtonProps> & {\n as?: T;\n } & Omit<React.ComponentPropsWithoutRef<T>, keyof BaseButtonProps | \"as\">;\n\nexport function Button<T extends React.ElementType = \"button\">({\n as,\n children,\n theme,\n intent,\n size,\n className,\n disabled,\n ...buttonProps\n}: ButtonProps<T>) {\n const Component: React.ElementType = as || \"button\";\n\n return (\n <Component\n // Cascade override only applies when `intent` is unset.\n data-theme={intent ? undefined : theme}\n data-intent={intent}\n className={buttonClasses({\n theme,\n intent,\n size,\n className,\n disabled,\n })}\n disabled={disabled}\n {...buttonProps}\n >\n {children}\n </Component>\n );\n}\n","import { useAuthActions, useAuthState } from \"@pollinations/sdk/react\";\nimport type { ReactNode } from \"react\";\nimport { Button, type ButtonProps } from \"../../primitives/Button.tsx\";\n\nexport type LogoutButtonProps = Omit<\n ButtonProps<\"button\">,\n \"as\" | \"onClick\" | \"children\"\n> & {\n children: ReactNode;\n};\n\n/** Button that clears the session. `null` when logged out. */\nexport function LogoutButton({ children, ...buttonProps }: LogoutButtonProps) {\n const { isLoggedIn } = useAuthState();\n const { logout } = useAuthActions();\n if (!isLoggedIn) return null;\n return (\n <Button {...buttonProps} onClick={() => logout()}>\n {children}\n </Button>\n );\n}\n","import { useAccountProfile, useAuthState } from \"@pollinations/sdk/react\";\nimport { cn } from \"../../lib/cn.ts\";\n\nexport type UserAvatarProps = {\n size?: \"sm\" | \"md\" | \"lg\";\n className?: string;\n};\n\nconst sizeClass = {\n sm: \"polli:w-6 polli:h-6 polli:text-xs\",\n md: \"polli:w-9 polli:h-9 polli:text-sm\",\n lg: \"polli:w-12 polli:h-12 polli:text-base\",\n} as const;\n\nfunction initials(name: string): string | null {\n const parts = name.trim().split(/\\s+/).filter(Boolean);\n if (parts.length === 0) return null;\n if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase() || null;\n const first = parts[0][0] ?? \"\";\n const last = parts[parts.length - 1][0] ?? \"\";\n return (first + last).toUpperCase() || null;\n}\n\n/** Avatar from `profile.image`, or initials from `profile.name`. `null` otherwise. */\nexport function UserAvatar({ size = \"md\", className }: UserAvatarProps) {\n const { isLoggedIn } = useAuthState();\n const { data: profile } = useAccountProfile({ enabled: isLoggedIn });\n if (!isLoggedIn) return null;\n\n const base = cn(\n \"polli:inline-flex polli:items-center polli:justify-center polli:rounded-full polli:overflow-hidden polli:bg-theme-bg-pale polli:text-theme-text-strong polli:font-semibold polli:select-none\",\n sizeClass[size],\n className,\n );\n\n if (profile?.image) {\n return (\n <img\n data-polli=\"user-avatar\"\n src={profile.image}\n alt={profile.name ?? \"\"}\n className={base}\n />\n );\n }\n const label = profile?.name ? initials(profile.name) : null;\n if (!label) return null;\n return (\n <div\n data-polli=\"user-avatar\"\n role=\"img\"\n aria-label={profile?.name ?? undefined}\n className={base}\n >\n {label}\n </div>\n );\n}\n","import { useAccountProfile, useAuthState } from \"@pollinations/sdk/react\";\n\nexport type UserEmailProps = { className?: string };\n\n/** Renders `profile.email`. `null` when logged out or the key lacks `profile` scope. */\nexport function UserEmail({ className }: UserEmailProps) {\n const { isLoggedIn } = useAuthState();\n const { data: profile } = useAccountProfile({ enabled: isLoggedIn });\n if (!isLoggedIn || !profile?.email) return null;\n return (\n <span data-polli=\"user-email\" className={className}>\n {profile.email}\n </span>\n );\n}\n","import { useAccountProfile, useAuthState } from \"@pollinations/sdk/react\";\n\nexport type UserNameProps = { className?: string };\n\n/**\n * Renders the user's display name. Falls back to GitHub username when the\n * `profile` scope was not granted (or `name` is empty). `null` when logged\n * out, or when neither name nor GitHub username is available.\n */\nexport function UserName({ className }: UserNameProps) {\n const { isLoggedIn } = useAuthState();\n const { data: profile } = useAccountProfile({ enabled: isLoggedIn });\n if (!isLoggedIn || !profile) return null;\n const display = profile.name || profile.githubUsername;\n if (!display) return null;\n return (\n <span data-polli=\"user-name\" className={className}>\n {display}\n </span>\n );\n}\n","import { useAuthState } from \"@pollinations/sdk/react\";\nimport { Fragment, type ReactNode } from \"react\";\n\nexport type WhenLoggedInProps = { children: ReactNode };\n\n/** Renders `children` only when a user is signed in. */\nexport function WhenLoggedIn({ children }: WhenLoggedInProps) {\n const { isLoggedIn } = useAuthState();\n if (!isLoggedIn) return null;\n return <Fragment>{children}</Fragment>;\n}\n","import { useAuthState } from \"@pollinations/sdk/react\";\nimport { Fragment, type ReactNode } from \"react\";\n\nexport type WhenLoggedOutProps = { children: ReactNode };\n\n/** Renders `children` only when no user is signed in. */\nexport function WhenLoggedOut({ children }: WhenLoggedOutProps) {\n const { isLoggedIn } = useAuthState();\n if (isLoggedIn) return null;\n return <Fragment>{children}</Fragment>;\n}\n"],"mappings":"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","names":["jsx","useAuthActions","useAuthState","jsx","useAuthState","useAuthActions","useAuthState","jsx","useAuthState","useAccountProfile","useAuthState","jsx","useAccountProfile","useAuthState","jsx","useAuthState","jsx","useAuthState","Fragment","jsx"]}
@@ -0,0 +1,497 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/compositions/app-user/index.ts
21
+ var app_user_exports = {};
22
+ __export(app_user_exports, {
23
+ AppUserMenu: () => AppUserMenu,
24
+ isEmbeddedContext: () => isEmbeddedContext
25
+ });
26
+ module.exports = __toCommonJS(app_user_exports);
27
+
28
+ // src/compositions/app-user/AppUserMenu.tsx
29
+ var import_react10 = require("@pollinations/sdk/react");
30
+
31
+ // src/modules/auth/LoginButton.tsx
32
+ var import_react = require("@pollinations/sdk/react");
33
+
34
+ // src/lib/cn.ts
35
+ var import_clsx = require("clsx");
36
+ var import_tailwind_merge = require("tailwind-merge");
37
+ var twMerge = (0, import_tailwind_merge.extendTailwindMerge)({ prefix: "polli" });
38
+ function cn(...inputs) {
39
+ return twMerge((0, import_clsx.clsx)(...inputs));
40
+ }
41
+
42
+ // src/primitives/Button.tsx
43
+ var import_jsx_runtime = require("react/jsx-runtime");
44
+ var sizes = {
45
+ sm: "polli:px-2 polli:pt-0.5 polli:pb-1",
46
+ md: "polli:px-4 polli:pt-1.5 polli:pb-2",
47
+ lg: "polli:px-6 polli:py-3"
48
+ };
49
+ var themeClasses = "polli:bg-theme-bg-active polli:text-theme-text-base polli:hover:bg-theme-bg-hover polli:transition-colors";
50
+ var intentClasses = {
51
+ danger: "polli:bg-intent-danger-bg-light polli:text-intent-danger-text polli:hover:bg-intent-danger-bg-hover polli:transition-colors"
52
+ };
53
+ var buttonClasses = ({
54
+ theme: _theme,
55
+ intent,
56
+ size,
57
+ className,
58
+ disabled
59
+ }) => {
60
+ const colorClasses = intent ? intentClasses[intent] : themeClasses;
61
+ return cn(
62
+ "polli-control polli:inline-flex polli:items-center polli:justify-center polli:rounded-full polli:self-center polli:font-medium polli:leading-normal polli:box-border",
63
+ disabled ? "polli:opacity-50 polli:cursor-not-allowed" : "polli:hover:filter polli:hover:brightness-105 polli:cursor-pointer",
64
+ colorClasses,
65
+ sizes[size || "md"],
66
+ className
67
+ );
68
+ };
69
+ function Button({
70
+ as,
71
+ children,
72
+ theme,
73
+ intent,
74
+ size,
75
+ className,
76
+ disabled,
77
+ ...buttonProps
78
+ }) {
79
+ const Component = as || "button";
80
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
81
+ Component,
82
+ {
83
+ "data-theme": intent ? void 0 : theme,
84
+ "data-intent": intent,
85
+ className: buttonClasses({
86
+ theme,
87
+ intent,
88
+ size,
89
+ className,
90
+ disabled
91
+ }),
92
+ disabled,
93
+ ...buttonProps,
94
+ children
95
+ }
96
+ );
97
+ }
98
+
99
+ // src/modules/auth/LoginButton.tsx
100
+ var import_jsx_runtime2 = require("react/jsx-runtime");
101
+ function LoginButton({ children, ...buttonProps }) {
102
+ const { isLoggedIn } = (0, import_react.useAuthState)();
103
+ const { login } = (0, import_react.useAuthActions)();
104
+ if (isLoggedIn) return null;
105
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Button, { ...buttonProps, onClick: () => login(), children });
106
+ }
107
+
108
+ // src/modules/auth/UserAvatar.tsx
109
+ var import_react2 = require("@pollinations/sdk/react");
110
+ var import_jsx_runtime3 = require("react/jsx-runtime");
111
+ var sizeClass = {
112
+ sm: "polli:w-6 polli:h-6 polli:text-xs",
113
+ md: "polli:w-9 polli:h-9 polli:text-sm",
114
+ lg: "polli:w-12 polli:h-12 polli:text-base"
115
+ };
116
+ function initials(name) {
117
+ const parts = name.trim().split(/\s+/).filter(Boolean);
118
+ if (parts.length === 0) return null;
119
+ if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase() || null;
120
+ const first = parts[0][0] ?? "";
121
+ const last = parts[parts.length - 1][0] ?? "";
122
+ return (first + last).toUpperCase() || null;
123
+ }
124
+ function UserAvatar({ size = "md", className }) {
125
+ const { isLoggedIn } = (0, import_react2.useAuthState)();
126
+ const { data: profile } = (0, import_react2.useAccountProfile)({ enabled: isLoggedIn });
127
+ if (!isLoggedIn) return null;
128
+ const base = cn(
129
+ "polli:inline-flex polli:items-center polli:justify-center polli:rounded-full polli:overflow-hidden polli:bg-theme-bg-pale polli:text-theme-text-strong polli:font-semibold polli:select-none",
130
+ sizeClass[size],
131
+ className
132
+ );
133
+ if (profile?.image) {
134
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
135
+ "img",
136
+ {
137
+ "data-polli": "user-avatar",
138
+ src: profile.image,
139
+ alt: profile.name ?? "",
140
+ className: base
141
+ }
142
+ );
143
+ }
144
+ const label = profile?.name ? initials(profile.name) : null;
145
+ if (!label) return null;
146
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
147
+ "div",
148
+ {
149
+ "data-polli": "user-avatar",
150
+ role: "img",
151
+ "aria-label": profile?.name ?? void 0,
152
+ className: base,
153
+ children: label
154
+ }
155
+ );
156
+ }
157
+
158
+ // src/modules/auth/UserName.tsx
159
+ var import_react3 = require("@pollinations/sdk/react");
160
+ var import_jsx_runtime4 = require("react/jsx-runtime");
161
+ function UserName({ className }) {
162
+ const { isLoggedIn } = (0, import_react3.useAuthState)();
163
+ const { data: profile } = (0, import_react3.useAccountProfile)({ enabled: isLoggedIn });
164
+ if (!isLoggedIn || !profile) return null;
165
+ const display = profile.name || profile.githubUsername;
166
+ if (!display) return null;
167
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { "data-polli": "user-name", className, children: display });
168
+ }
169
+
170
+ // src/modules/auth/WhenLoggedIn.tsx
171
+ var import_react4 = require("@pollinations/sdk/react");
172
+ var import_react5 = require("react");
173
+ var import_jsx_runtime5 = require("react/jsx-runtime");
174
+ function WhenLoggedIn({ children }) {
175
+ const { isLoggedIn } = (0, import_react4.useAuthState)();
176
+ if (!isLoggedIn) return null;
177
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react5.Fragment, { children });
178
+ }
179
+
180
+ // src/modules/auth/WhenLoggedOut.tsx
181
+ var import_react6 = require("@pollinations/sdk/react");
182
+ var import_react7 = require("react");
183
+ var import_jsx_runtime6 = require("react/jsx-runtime");
184
+ function WhenLoggedOut({ children }) {
185
+ const { isLoggedIn } = (0, import_react6.useAuthState)();
186
+ if (isLoggedIn) return null;
187
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react7.Fragment, { children });
188
+ }
189
+
190
+ // src/modules/wallet/Balance.tsx
191
+ var import_react8 = require("@pollinations/sdk/react");
192
+
193
+ // src/primitives/Chip.tsx
194
+ var import_jsx_runtime7 = require("react/jsx-runtime");
195
+ var chipSizes = {
196
+ sm: "polli:px-2 polli:py-0.5 polli:text-xs",
197
+ md: "polli:px-2.5 polli:py-0.5 polli:text-sm",
198
+ lg: "polli:px-3 polli:py-1 polli:text-sm"
199
+ };
200
+ var intentClasses2 = {
201
+ news: "polli:bg-intent-news-bg-light polli:text-intent-news-text",
202
+ alpha: "polli:bg-intent-alpha-bg-light polli:text-intent-alpha-text",
203
+ neutral: "polli:border polli:border-gray-400/70 polli:bg-gray-100/80 polli:text-gray-900",
204
+ success: "polli:border polli:border-intent-success-border polli:bg-intent-success-bg-light polli:text-intent-success-text",
205
+ warning: "polli:border polli:border-intent-warning-border polli:bg-intent-warning-bg-light polli:text-intent-warning-text",
206
+ danger: "polli:border polli:border-intent-danger-border polli:bg-intent-danger-bg-light polli:text-intent-danger-text"
207
+ };
208
+ var Chip = ({
209
+ theme,
210
+ intent,
211
+ size = "md",
212
+ className,
213
+ children,
214
+ ...rest
215
+ }) => {
216
+ const intentClass = intent ? intentClasses2[intent] : "polli:bg-theme-bg-active polli:text-theme-text-strong";
217
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
218
+ "span",
219
+ {
220
+ ...rest,
221
+ "data-theme": theme,
222
+ className: cn(
223
+ "polli:inline-flex polli:shrink-0 polli:items-center polli:gap-1 polli:rounded-lg polli:font-medium polli:leading-normal",
224
+ chipSizes[size],
225
+ intentClass,
226
+ className
227
+ ),
228
+ children
229
+ }
230
+ );
231
+ };
232
+
233
+ // src/modules/wallet/format-pollen.ts
234
+ var BUDGET = 5;
235
+ var MAX_DECIMALS = 4;
236
+ var COMPACT_THRESHOLD = 1e5;
237
+ function floorTo(value, decimals) {
238
+ const factor = 10 ** decimals;
239
+ return Math.floor(value * factor) / factor;
240
+ }
241
+ function formatCompact(value) {
242
+ const abs = Math.abs(value);
243
+ const sign = value < 0 ? "-" : "";
244
+ const [unit, scale] = abs >= 1e9 ? ["B", 1e9] : abs >= 1e6 ? ["M", 1e6] : ["K", 1e3];
245
+ const ratio = abs / scale;
246
+ const intDigits = Math.max(1, Math.floor(Math.log10(ratio)) + 1);
247
+ const decimals = Math.max(0, 3 - intDigits);
248
+ const floored = floorTo(ratio, decimals);
249
+ return `${sign}${Number(floored.toFixed(decimals)).toString()}${unit}`;
250
+ }
251
+ function formatPollen(value) {
252
+ if (!Number.isFinite(value) || value === 0) return "0";
253
+ const abs = Math.abs(value);
254
+ if (abs >= COMPACT_THRESHOLD) return formatCompact(value);
255
+ const intDigits = abs >= 1 ? Math.floor(Math.log10(abs)) + 1 : 1;
256
+ const decimals = Math.min(MAX_DECIMALS, Math.max(0, BUDGET - intDigits));
257
+ const floored = floorTo(value, decimals);
258
+ if (floored === 0) return "0";
259
+ return Number(floored.toFixed(decimals)).toString();
260
+ }
261
+
262
+ // src/modules/wallet/Balance.tsx
263
+ var import_jsx_runtime8 = require("react/jsx-runtime");
264
+ function Balance({ className } = {}) {
265
+ const { isLoggedIn } = (0, import_react8.useAuthState)();
266
+ const { data: balance } = (0, import_react8.useAccountBalance)({ enabled: isLoggedIn });
267
+ if (!isLoggedIn || balance == null) return null;
268
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
269
+ Chip,
270
+ {
271
+ "data-polli": "balance",
272
+ className: cn("polli:tabular-nums", className),
273
+ children: [
274
+ formatPollen(balance.balance),
275
+ " pollen"
276
+ ]
277
+ }
278
+ );
279
+ }
280
+
281
+ // src/primitives/ChevronIcon.tsx
282
+ var import_jsx_runtime9 = require("react/jsx-runtime");
283
+ var ChevronIcon = ({ expanded, className }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
284
+ "svg",
285
+ {
286
+ "aria-hidden": "true",
287
+ width: "12",
288
+ height: "12",
289
+ viewBox: "0 0 12 12",
290
+ className: cn(
291
+ "polli:shrink-0 polli:transition-transform polli:duration-200 polli:ease-out",
292
+ expanded && "polli:rotate-180",
293
+ className
294
+ ),
295
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
296
+ "path",
297
+ {
298
+ d: "M3 4.5 6 7.5l3-3",
299
+ fill: "none",
300
+ stroke: "currentColor",
301
+ strokeLinecap: "round",
302
+ strokeLinejoin: "round",
303
+ strokeWidth: "1.5"
304
+ }
305
+ )
306
+ }
307
+ );
308
+
309
+ // src/primitives/Dropdown.tsx
310
+ var import_popover = require("@ark-ui/react/popover");
311
+ var import_portal = require("@ark-ui/react/portal");
312
+ var import_react9 = require("react");
313
+ var import_jsx_runtime10 = require("react/jsx-runtime");
314
+ var DEFAULT_PANEL = "polli:rounded-lg polli:border polli:border-theme-border polli:bg-theme-bg-pale polli:shadow-lg";
315
+ var Dropdown = ({
316
+ theme,
317
+ trigger,
318
+ children,
319
+ align = "start",
320
+ open: openProp,
321
+ onOpenChange,
322
+ className
323
+ }) => {
324
+ const [internalOpen, setInternalOpen] = (0, import_react9.useState)(false);
325
+ const isControlled = openProp !== void 0;
326
+ const open = isControlled ? openProp : internalOpen;
327
+ const setOpen = (next) => {
328
+ if (!isControlled) setInternalOpen(next);
329
+ onOpenChange?.(next);
330
+ };
331
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
332
+ import_popover.Popover.Root,
333
+ {
334
+ open,
335
+ onOpenChange: (details) => setOpen(details.open),
336
+ positioning: {
337
+ placement: align === "end" ? "bottom-end" : "bottom-start"
338
+ },
339
+ children: [
340
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_popover.Popover.Trigger, { asChild: true, children: trigger(open) }),
341
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_portal.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_popover.Popover.Positioner, { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
342
+ import_popover.Popover.Content,
343
+ {
344
+ "data-theme": theme,
345
+ className: cn(
346
+ "polli:z-50 polli:overflow-hidden polli:focus:outline-none",
347
+ DEFAULT_PANEL,
348
+ className
349
+ ),
350
+ children: typeof children === "function" ? children(() => setOpen(false)) : children
351
+ }
352
+ ) }) })
353
+ ]
354
+ }
355
+ );
356
+ };
357
+
358
+ // src/primitives/DropdownItem.tsx
359
+ var import_jsx_runtime11 = require("react/jsx-runtime");
360
+ function DropdownItem({
361
+ as,
362
+ className,
363
+ children,
364
+ ...rest
365
+ }) {
366
+ const Component = as || "button";
367
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
368
+ Component,
369
+ {
370
+ ...Component === "button" ? { type: "button" } : void 0,
371
+ ...rest,
372
+ className: cn(
373
+ "polli-control polli:flex polli:w-full polli:cursor-pointer polli:items-center polli:gap-2 polli:rounded-lg polli:bg-transparent polli:px-3 polli:py-2 polli:text-left polli:text-sm polli:font-medium polli:text-theme-text-base polli:no-underline polli:transition-colors polli:hover:bg-theme-bg-hover polli:focus-visible:bg-theme-bg-hover",
374
+ className
375
+ ),
376
+ children
377
+ }
378
+ );
379
+ }
380
+
381
+ // src/compositions/app-user/AppUserMenu.tsx
382
+ var import_jsx_runtime12 = require("react/jsx-runtime");
383
+ var defaultLabels = {
384
+ authorize: "Authorize app",
385
+ appUserMenu: "App user menu",
386
+ topUpAccount: "Top up account",
387
+ logout: "Log out from this app"
388
+ };
389
+ function isEmbeddedContext(embedQueryParam = "embed") {
390
+ if (typeof window === "undefined") return false;
391
+ const search = new URLSearchParams(window.location.search);
392
+ if (search.get(embedQueryParam) === "1") return true;
393
+ try {
394
+ return window.self !== window.top;
395
+ } catch {
396
+ return true;
397
+ }
398
+ }
399
+ function AppUserMenu({
400
+ dashboardHref,
401
+ labels: labelOverrides,
402
+ hiddenWhenEmbedded = false,
403
+ embedQueryParam = "embed"
404
+ }) {
405
+ if (hiddenWhenEmbedded && isEmbeddedContext(embedQueryParam)) return null;
406
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
407
+ AppUserMenuContent,
408
+ {
409
+ dashboardHref,
410
+ labels: labelOverrides
411
+ }
412
+ );
413
+ }
414
+ function AppUserMenuContent({
415
+ dashboardHref,
416
+ labels: labelOverrides
417
+ }) {
418
+ const labels = { ...defaultLabels, ...labelOverrides };
419
+ const { logout } = (0, import_react10.useAuthActions)();
420
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { "data-theme": "amber", className: "polli:flex polli:justify-end", children: [
421
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(WhenLoggedOut, { children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(LoginButton, { theme: "amber", children: labels.authorize }) }),
422
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(WhenLoggedIn, { children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
423
+ Dropdown,
424
+ {
425
+ theme: "amber",
426
+ align: "end",
427
+ className: "polli:w-64 polli:p-1",
428
+ trigger: (open) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
429
+ "button",
430
+ {
431
+ type: "button",
432
+ "data-theme": "amber",
433
+ "aria-label": labels.appUserMenu,
434
+ className: "polli-control polli:flex polli:min-w-0 polli:items-center polli:gap-2 polli:rounded-full polli:bg-theme-bg-active polli:py-1 polli:pl-1 polli:pr-3 polli:text-theme-text-base polli:shadow-sm polli:transition-colors polli:hover:bg-theme-bg-hover",
435
+ children: [
436
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
437
+ UserAvatar,
438
+ {
439
+ size: "md",
440
+ className: "polli:h-8 polli:w-8"
441
+ }
442
+ ),
443
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "polli:flex polli:min-w-0 polli:flex-col polli:items-start polli:leading-tight", children: [
444
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(UserName, { className: "polli:max-w-32 polli:truncate polli:text-sm polli:font-semibold" }),
445
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Balance, { className: "polli:bg-transparent polli:px-0 polli:py-0 polli:text-xs polli:text-theme-text-base" })
446
+ ] }),
447
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
448
+ ChevronIcon,
449
+ {
450
+ expanded: open,
451
+ className: "polli:h-4 polli:w-4 polli:text-theme-text-base"
452
+ }
453
+ )
454
+ ]
455
+ }
456
+ ),
457
+ children: (close) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
458
+ "div",
459
+ {
460
+ "data-theme": "amber",
461
+ className: "polli:flex polli:flex-col",
462
+ children: [
463
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
464
+ DropdownItem,
465
+ {
466
+ as: "a",
467
+ href: dashboardHref,
468
+ target: "_blank",
469
+ rel: "noopener noreferrer",
470
+ onClick: close,
471
+ children: labels.topUpAccount
472
+ }
473
+ ),
474
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
475
+ DropdownItem,
476
+ {
477
+ type: "button",
478
+ onClick: () => {
479
+ close();
480
+ logout();
481
+ },
482
+ children: labels.logout
483
+ }
484
+ )
485
+ ]
486
+ }
487
+ )
488
+ }
489
+ ) })
490
+ ] });
491
+ }
492
+ // Annotate the CommonJS export names for ESM import in node:
493
+ 0 && (module.exports = {
494
+ AppUserMenu,
495
+ isEmbeddedContext
496
+ });
497
+ //# sourceMappingURL=app-user.cjs.map