@pollinations/ui 0.1.0-alpha.0 → 0.1.0-alpha.1

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 (64) hide show
  1. package/README.md +28 -65
  2. package/dist/{Chip-SM52sUbZ.d.cts → Chip-CQCq34kS.d.cts} +1 -1
  3. package/dist/{Chip-C5impfYd.d.ts → Chip-Cj4xG7Te.d.ts} +1 -1
  4. package/dist/{compositions/app-user.cjs → app-user-menu/sdk.cjs} +148 -148
  5. package/dist/app-user-menu/sdk.cjs.map +1 -0
  6. package/dist/{compositions/app-user.js → app-user-menu/sdk.js} +127 -127
  7. package/dist/app-user-menu/sdk.js.map +1 -0
  8. package/dist/app.css +94 -3
  9. package/dist/auth/index.cjs +2 -2
  10. package/dist/auth/index.cjs.map +1 -1
  11. package/dist/auth/index.js +2 -2
  12. package/dist/auth/index.js.map +1 -1
  13. package/dist/{models → gen}/index.cjs +40 -71
  14. package/dist/gen/index.cjs.map +1 -0
  15. package/dist/gen/index.d.cts +35 -0
  16. package/dist/gen/index.d.ts +35 -0
  17. package/dist/{models → gen}/index.js +31 -66
  18. package/dist/gen/index.js.map +1 -0
  19. package/dist/index.cjs +1594 -1142
  20. package/dist/index.cjs.map +1 -1
  21. package/dist/index.d.cts +268 -178
  22. package/dist/index.d.ts +268 -178
  23. package/dist/index.js +1581 -1134
  24. package/dist/index.js.map +1 -1
  25. package/dist/styles.css +1 -1
  26. package/dist/theme-jRPPBmld.d.cts +20 -0
  27. package/dist/theme-jRPPBmld.d.ts +20 -0
  28. package/dist/wallet/index.cjs +4 -4
  29. package/dist/wallet/index.cjs.map +1 -1
  30. package/dist/wallet/index.d.cts +2 -2
  31. package/dist/wallet/index.d.ts +2 -2
  32. package/dist/wallet/index.js +4 -4
  33. package/dist/wallet/index.js.map +1 -1
  34. package/package.json +9 -24
  35. package/dist/Button-BvLF_Km2.d.cts +0 -26
  36. package/dist/Button-DQAZzvyQ.d.ts +0 -26
  37. package/dist/auth/sdk.cjs +0 -221
  38. package/dist/auth/sdk.cjs.map +0 -1
  39. package/dist/auth/sdk.d.cts +0 -53
  40. package/dist/auth/sdk.d.ts +0 -53
  41. package/dist/auth/sdk.js +0 -188
  42. package/dist/auth/sdk.js.map +0 -1
  43. package/dist/compositions/app-user.cjs.map +0 -1
  44. package/dist/compositions/app-user.js.map +0 -1
  45. package/dist/modality/index.cjs +0 -86
  46. package/dist/modality/index.cjs.map +0 -1
  47. package/dist/modality/index.d.cts +0 -26
  48. package/dist/modality/index.d.ts +0 -26
  49. package/dist/modality/index.js +0 -59
  50. package/dist/modality/index.js.map +0 -1
  51. package/dist/models/index.cjs.map +0 -1
  52. package/dist/models/index.d.cts +0 -22
  53. package/dist/models/index.d.ts +0 -22
  54. package/dist/models/index.js.map +0 -1
  55. package/dist/theme-VMRlhqST.d.cts +0 -9
  56. package/dist/theme-VMRlhqST.d.ts +0 -9
  57. package/dist/wallet/sdk.cjs +0 -206
  58. package/dist/wallet/sdk.cjs.map +0 -1
  59. package/dist/wallet/sdk.d.cts +0 -33
  60. package/dist/wallet/sdk.d.ts +0 -33
  61. package/dist/wallet/sdk.js +0 -175
  62. package/dist/wallet/sdk.js.map +0 -1
  63. /package/dist/{compositions/app-user.d.cts → app-user-menu/sdk.d.cts} +0 -0
  64. /package/dist/{compositions/app-user.d.ts → app-user-menu/sdk.d.ts} +0 -0
@@ -60,7 +60,7 @@ var Dialog = ({
60
60
  ArkDialog.Backdrop,
61
61
  {
62
62
  className: cn(
63
- "polli:fixed polli:inset-0 polli:z-[100] polli:bg-gray-950/50",
63
+ "polli:fixed polli:inset-0 polli:z-[100] polli:bg-ink-950/50",
64
64
  backdropClassName
65
65
  )
66
66
  }
@@ -81,7 +81,7 @@ var Dialog = ({
81
81
  "aria-label": ariaLabel,
82
82
  "aria-labelledby": labelledBy,
83
83
  className: cn(
84
- "polli:my-auto polli:w-full polli:overflow-hidden polli:rounded-lg polli:border-2 polli:border-theme-border polli:bg-white polli:shadow-lg polli:outline-none polli:focus:outline-none polli:focus-visible:outline-none",
84
+ "polli:my-auto polli:w-full polli:overflow-hidden polli:rounded-lg polli:border-2 polli:border-theme-border polli:bg-surface-opaque polli:shadow-lg polli:outline-none polli:focus:outline-none polli:focus-visible:outline-none",
85
85
  sizeClasses[size],
86
86
  contentClassName
87
87
  ),
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/primitives/Dialog.tsx","../../src/lib/cn.ts","../../src/modules/auth/AuthModal.tsx"],"sourcesContent":["import { Dialog as ArkDialog } from \"@ark-ui/react/dialog\";\nimport { Portal } from \"@ark-ui/react/portal\";\nimport type { FC, ReactNode } from \"react\";\nimport { useRef } from \"react\";\nimport { cn } from \"../lib/cn.ts\";\nimport type { ThemeName } from \"../theme.ts\";\n\nconst sizeClasses = {\n sm: \"polli:max-w-md\",\n md: \"polli:max-w-xl\",\n lg: \"polli:max-w-2xl\",\n} as const;\n\nexport type DialogProps = {\n open: boolean;\n onOpenChange?: (open: boolean) => void;\n trigger?: ReactNode;\n triggerAsChild?: boolean;\n triggerClassName?: string;\n title?: ReactNode;\n titleClassName?: string;\n ariaLabel?: string;\n labelledBy?: string;\n theme?: ThemeName;\n size?: keyof typeof sizeClasses;\n showBackdrop?: boolean;\n backdropClassName?: string;\n positionerClassName?: string;\n contentClassName?: string;\n children: ReactNode;\n};\n\nexport const Dialog: FC<DialogProps> = ({\n open,\n onOpenChange,\n trigger,\n triggerAsChild = false,\n triggerClassName,\n title,\n titleClassName,\n ariaLabel,\n labelledBy,\n theme = \"blue\",\n size = \"md\",\n showBackdrop = true,\n backdropClassName,\n positionerClassName,\n contentClassName,\n children,\n}) => {\n const contentRef = useRef<HTMLDivElement>(null);\n\n return (\n <ArkDialog.Root\n open={open}\n initialFocusEl={() => contentRef.current}\n onOpenChange={(details) => onOpenChange?.(details.open)}\n >\n {trigger && (\n <ArkDialog.Trigger\n asChild={triggerAsChild}\n className={triggerClassName}\n >\n {trigger}\n </ArkDialog.Trigger>\n )}\n <Portal>\n {showBackdrop && (\n <ArkDialog.Backdrop\n className={cn(\n \"polli:fixed polli:inset-0 polli:z-[100] polli:bg-gray-950/50\",\n backdropClassName,\n )}\n />\n )}\n <ArkDialog.Positioner\n data-theme={theme}\n className={cn(\n \"polli:fixed polli:inset-0 polli:z-[110] polli:flex polli:h-dvh polli:items-start polli:justify-center polli:overflow-hidden polli:p-4\",\n positionerClassName,\n )}\n >\n <ArkDialog.Content\n ref={contentRef}\n data-theme={theme}\n aria-label={ariaLabel}\n aria-labelledby={labelledBy}\n className={cn(\n \"polli:my-auto polli:w-full polli:overflow-hidden polli:rounded-lg polli:border-2 polli:border-theme-border polli:bg-white polli:shadow-lg polli:outline-none polli:focus:outline-none polli:focus-visible:outline-none\",\n sizeClasses[size],\n contentClassName,\n )}\n >\n {title && (\n <DialogTitle\n className={cn(\n \"polli:px-6 polli:pt-6 polli:font-subheading polli:text-xl polli:text-theme-text-strong\",\n titleClassName,\n )}\n >\n {title}\n </DialogTitle>\n )}\n {children}\n </ArkDialog.Content>\n </ArkDialog.Positioner>\n </Portal>\n </ArkDialog.Root>\n );\n};\n\nexport const DialogTitle = ArkDialog.Title;\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 { CSSProperties, ReactNode } from \"react\";\nimport logoUrl from \"../../assets/logo.svg\";\nimport { Dialog } from \"../../primitives/Dialog.tsx\";\n\nconst authLogoMaskUrl = `url('${logoUrl}')`;\n\nconst authLogoMask: CSSProperties = {\n WebkitMaskImage: authLogoMaskUrl,\n WebkitMaskPosition: \"center\",\n WebkitMaskRepeat: \"no-repeat\",\n WebkitMaskSize: \"contain\",\n maskImage: authLogoMaskUrl,\n maskPosition: \"center\",\n maskRepeat: \"no-repeat\",\n maskSize: \"contain\",\n};\n\nexport type AuthModalProps = {\n children: ReactNode;\n dialog?: {\n label?: string;\n labelledBy?: string;\n };\n tone?: \"default\" | \"error\";\n};\n\nexport function AuthModal({\n children,\n dialog,\n tone = \"default\",\n}: AuthModalProps) {\n const borderClass =\n tone === \"error\"\n ? \"polli:border-intent-danger-border\"\n : \"polli:border-theme-border\";\n return (\n <Dialog\n open\n theme=\"amber\"\n showBackdrop={false}\n ariaLabel={dialog?.label}\n labelledBy={dialog?.labelledBy}\n positionerClassName=\"polli:items-start polli:overflow-y-auto polli:bg-theme-bg-pale\"\n contentClassName={`polli:bg-surface-white polli:border-2 ${borderClass} polli:rounded-lg polli:shadow-lg polli:max-w-xl polli:w-full polli:my-auto`}\n >\n {children}\n </Dialog>\n );\n}\n\nexport type AuthModalHeaderProps = {\n children?: ReactNode;\n};\n\nexport function AuthModalHeader({ children }: AuthModalHeaderProps) {\n const logo = (\n <a\n href=\"https://pollinations.ai\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n tabIndex={-1}\n className=\"polli:block polli:shrink-0 polli:text-theme-text-strong polli:focus:outline-none\"\n aria-label=\"pollinations.ai\"\n >\n <span className=\"polli:sr-only\">pollinations.ai</span>\n <span\n aria-hidden=\"true\"\n className=\"polli:block polli:h-8 polli:w-8 polli:bg-current\"\n style={authLogoMask}\n />\n </a>\n );\n if (!children) {\n return (\n <div className=\"polli:flex polli:justify-start polli:px-6 polli:pt-6\">\n {logo}\n </div>\n );\n }\n return (\n <div className=\"polli:px-6 polli:pt-6 polli:pb-2\">\n <div className=\"polli:flex polli:items-center polli:justify-between polli:gap-3\">\n {logo}\n {children}\n </div>\n </div>\n );\n}\n\nexport function AuthModalLoading() {\n return (\n <AuthModal>\n <AuthModalHeader />\n <div className=\"polli:px-8 polli:pt-2 polli:pb-8 polli:text-center\">\n <p className=\"polli:text-theme-text-strong\">Loading...</p>\n </div>\n </AuthModal>\n );\n}\n\nexport function ErrorBanner({ children }: { children: ReactNode }) {\n return (\n <div className=\"polli:rounded-lg polli:border-2 polli:border-intent-danger-border polli:bg-intent-danger-bg-light polli:p-4\">\n <p className=\"polli:text-sm polli:text-intent-danger-text\">\n {children}\n </p>\n </div>\n );\n}\n\nexport type AuthInfoCardProps = {\n title?: string;\n children: ReactNode;\n};\n\nexport function AuthInfoCard({\n title = \"Authorize\",\n children,\n}: AuthInfoCardProps) {\n return (\n <div className=\"polli:rounded-lg polli:border-2 polli:border-theme-border polli:bg-theme-bg-pale polli:p-4\">\n <p className=\"polli:mb-2 polli:font-body polli:text-xs polli:font-semibold polli:tracking-wide polli:text-theme-text-soft\">\n {title}\n </p>\n {children}\n </div>\n );\n}\n"],"mappings":"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","names":["jsx","jsxs"]}
1
+ {"version":3,"sources":["../../src/primitives/Dialog.tsx","../../src/lib/cn.ts","../../src/modules/auth/AuthModal.tsx"],"sourcesContent":["import { Dialog as ArkDialog } from \"@ark-ui/react/dialog\";\nimport { Portal } from \"@ark-ui/react/portal\";\nimport type { FC, ReactNode } from \"react\";\nimport { useRef } from \"react\";\nimport { cn } from \"../lib/cn.ts\";\nimport type { ThemeName } from \"../theme.ts\";\n\nconst sizeClasses = {\n sm: \"polli:max-w-md\",\n md: \"polli:max-w-xl\",\n lg: \"polli:max-w-2xl\",\n} as const;\n\nexport type DialogProps = {\n open: boolean;\n onOpenChange?: (open: boolean) => void;\n trigger?: ReactNode;\n triggerAsChild?: boolean;\n triggerClassName?: string;\n title?: ReactNode;\n titleClassName?: string;\n ariaLabel?: string;\n labelledBy?: string;\n theme?: ThemeName;\n size?: keyof typeof sizeClasses;\n showBackdrop?: boolean;\n backdropClassName?: string;\n positionerClassName?: string;\n contentClassName?: string;\n children: ReactNode;\n};\n\nexport const Dialog: FC<DialogProps> = ({\n open,\n onOpenChange,\n trigger,\n triggerAsChild = false,\n triggerClassName,\n title,\n titleClassName,\n ariaLabel,\n labelledBy,\n theme = \"blue\",\n size = \"md\",\n showBackdrop = true,\n backdropClassName,\n positionerClassName,\n contentClassName,\n children,\n}) => {\n const contentRef = useRef<HTMLDivElement>(null);\n\n return (\n <ArkDialog.Root\n open={open}\n initialFocusEl={() => contentRef.current}\n onOpenChange={(details) => onOpenChange?.(details.open)}\n >\n {trigger && (\n <ArkDialog.Trigger\n asChild={triggerAsChild}\n className={triggerClassName}\n >\n {trigger}\n </ArkDialog.Trigger>\n )}\n <Portal>\n {showBackdrop && (\n <ArkDialog.Backdrop\n className={cn(\n \"polli:fixed polli:inset-0 polli:z-[100] polli:bg-ink-950/50\",\n backdropClassName,\n )}\n />\n )}\n <ArkDialog.Positioner\n data-theme={theme}\n className={cn(\n \"polli:fixed polli:inset-0 polli:z-[110] polli:flex polli:h-dvh polli:items-start polli:justify-center polli:overflow-hidden polli:p-4\",\n positionerClassName,\n )}\n >\n <ArkDialog.Content\n ref={contentRef}\n data-theme={theme}\n aria-label={ariaLabel}\n aria-labelledby={labelledBy}\n className={cn(\n \"polli:my-auto polli:w-full polli:overflow-hidden polli:rounded-lg polli:border-2 polli:border-theme-border polli:bg-surface-opaque polli:shadow-lg polli:outline-none polli:focus:outline-none polli:focus-visible:outline-none\",\n sizeClasses[size],\n contentClassName,\n )}\n >\n {title && (\n <DialogTitle\n className={cn(\n \"polli:px-6 polli:pt-6 polli:font-subheading polli:text-xl polli:text-theme-text-strong\",\n titleClassName,\n )}\n >\n {title}\n </DialogTitle>\n )}\n {children}\n </ArkDialog.Content>\n </ArkDialog.Positioner>\n </Portal>\n </ArkDialog.Root>\n );\n};\n\nexport const DialogTitle = ArkDialog.Title;\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 { CSSProperties, ReactNode } from \"react\";\nimport logoUrl from \"../../assets/logo.svg\";\nimport { Dialog } from \"../../primitives/Dialog.tsx\";\n\nconst authLogoMaskUrl = `url('${logoUrl}')`;\n\nconst authLogoMask: CSSProperties = {\n WebkitMaskImage: authLogoMaskUrl,\n WebkitMaskPosition: \"center\",\n WebkitMaskRepeat: \"no-repeat\",\n WebkitMaskSize: \"contain\",\n maskImage: authLogoMaskUrl,\n maskPosition: \"center\",\n maskRepeat: \"no-repeat\",\n maskSize: \"contain\",\n};\n\nexport type AuthModalProps = {\n children: ReactNode;\n dialog?: {\n label?: string;\n labelledBy?: string;\n };\n tone?: \"default\" | \"error\";\n};\n\nexport function AuthModal({\n children,\n dialog,\n tone = \"default\",\n}: AuthModalProps) {\n const borderClass =\n tone === \"error\"\n ? \"polli:border-intent-danger-border\"\n : \"polli:border-theme-border\";\n return (\n <Dialog\n open\n theme=\"amber\"\n showBackdrop={false}\n ariaLabel={dialog?.label}\n labelledBy={dialog?.labelledBy}\n positionerClassName=\"polli:items-start polli:overflow-y-auto polli:bg-theme-bg-pale\"\n contentClassName={`polli:bg-surface-white polli:border-2 ${borderClass} polli:rounded-lg polli:shadow-lg polli:max-w-xl polli:w-full polli:my-auto`}\n >\n {children}\n </Dialog>\n );\n}\n\nexport type AuthModalHeaderProps = {\n children?: ReactNode;\n};\n\nexport function AuthModalHeader({ children }: AuthModalHeaderProps) {\n const logo = (\n <a\n href=\"https://pollinations.ai\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n tabIndex={-1}\n className=\"polli:block polli:shrink-0 polli:text-theme-text-strong polli:focus:outline-none\"\n aria-label=\"pollinations.ai\"\n >\n <span className=\"polli:sr-only\">pollinations.ai</span>\n <span\n aria-hidden=\"true\"\n className=\"polli:block polli:h-8 polli:w-8 polli:bg-current\"\n style={authLogoMask}\n />\n </a>\n );\n if (!children) {\n return (\n <div className=\"polli:flex polli:justify-start polli:px-6 polli:pt-6\">\n {logo}\n </div>\n );\n }\n return (\n <div className=\"polli:px-6 polli:pt-6 polli:pb-2\">\n <div className=\"polli:flex polli:items-center polli:justify-between polli:gap-3\">\n {logo}\n {children}\n </div>\n </div>\n );\n}\n\nexport function AuthModalLoading() {\n return (\n <AuthModal>\n <AuthModalHeader />\n <div className=\"polli:px-8 polli:pt-2 polli:pb-8 polli:text-center\">\n <p className=\"polli:text-theme-text-strong\">Loading...</p>\n </div>\n </AuthModal>\n );\n}\n\nexport function ErrorBanner({ children }: { children: ReactNode }) {\n return (\n <div className=\"polli:rounded-lg polli:border-2 polli:border-intent-danger-border polli:bg-intent-danger-bg-light polli:p-4\">\n <p className=\"polli:text-sm polli:text-intent-danger-text\">\n {children}\n </p>\n </div>\n );\n}\n\nexport type AuthInfoCardProps = {\n title?: string;\n children: ReactNode;\n};\n\nexport function AuthInfoCard({\n title = \"Authorize\",\n children,\n}: AuthInfoCardProps) {\n return (\n <div className=\"polli:rounded-lg polli:border-2 polli:border-theme-border polli:bg-theme-bg-pale polli:p-4\">\n <p className=\"polli:mb-2 polli:font-body polli:text-xs polli:font-semibold polli:tracking-wide polli:text-theme-text-soft\">\n {title}\n </p>\n {children}\n </div>\n );\n}\n"],"mappings":"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","names":["jsx","jsxs"]}
@@ -17,12 +17,16 @@ var __copyProps = (to, from, except, desc) => {
17
17
  };
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
 
20
- // src/modules/models/index.ts
21
- var models_exports = {};
22
- __export(models_exports, {
23
- ModelSelector: () => ModelSelector
20
+ // src/modules/gen/index.ts
21
+ var gen_exports = {};
22
+ __export(gen_exports, {
23
+ CATEGORY_LABELS: () => CATEGORY_LABELS,
24
+ ModelSelector: () => ModelSelector,
25
+ categoryLabel: () => categoryLabel,
26
+ getModalityTheme: () => getModalityTheme,
27
+ modalityTheme: () => modalityTheme
24
28
  });
25
- module.exports = __toCommonJS(models_exports);
29
+ module.exports = __toCommonJS(gen_exports);
26
30
 
27
31
  // src/lib/cn.ts
28
32
  var import_clsx = require("clsx");
@@ -127,10 +131,10 @@ var chipSizes = {
127
131
  var intentClasses2 = {
128
132
  news: "polli:bg-intent-news-bg-light polli:text-intent-news-text",
129
133
  alpha: "polli:bg-intent-alpha-bg-light polli:text-intent-alpha-text",
130
- neutral: "polli:border polli:border-gray-400/70 polli:bg-gray-100/80 polli:text-gray-900",
131
- success: "polli:border polli:border-intent-success-border polli:bg-intent-success-bg-light polli:text-intent-success-text",
132
- warning: "polli:border polli:border-intent-warning-border polli:bg-intent-warning-bg-light polli:text-intent-warning-text",
133
- danger: "polli:border polli:border-intent-danger-border polli:bg-intent-danger-bg-light polli:text-intent-danger-text"
134
+ neutral: "polli:bg-ink-100/80 polli:text-ink-900",
135
+ success: "polli:bg-intent-success-bg-light polli:text-intent-success-text",
136
+ warning: "polli:bg-intent-warning-bg-light polli:text-intent-warning-text",
137
+ danger: "polli:bg-intent-danger-bg-light polli:text-intent-danger-text"
134
138
  };
135
139
  var Chip = ({
136
140
  theme,
@@ -348,86 +352,49 @@ var TabButton = ({
348
352
  );
349
353
  };
350
354
 
351
- // src/modules/modality/colors.ts
352
- var filled = "polli:bg-theme-bg-active polli:text-theme-text-strong";
353
- var hover = "polli:hover:bg-theme-bg-subtle polli:hover:text-theme-text-strong";
354
- var text = "polli:text-theme-text-strong";
355
- var MODALITY_COLORS = {
356
- text: {
357
- theme: "blue",
358
- filled,
359
- hover,
360
- text
361
- },
362
- image: {
363
- theme: "pink",
364
- filled,
365
- hover,
366
- text
367
- },
368
- video: {
369
- theme: "teal",
370
- filled,
371
- hover,
372
- text
373
- },
374
- audio: {
375
- theme: "violet",
376
- filled,
377
- hover,
378
- text
379
- },
380
- realtime: {
381
- theme: "green",
382
- filled,
383
- hover,
384
- text
385
- },
386
- embedding: {
387
- theme: "amber",
388
- filled,
389
- hover,
390
- text
391
- }
355
+ // src/modules/gen/themes.ts
356
+ var MODALITY_THEMES = {
357
+ text: "blue",
358
+ image: "pink",
359
+ video: "teal",
360
+ audio: "amber",
361
+ realtime: "coral",
362
+ embedding: "violet"
392
363
  };
364
+ function modalityTheme(category) {
365
+ return MODALITY_THEMES[category];
366
+ }
393
367
  function normalize(category) {
394
368
  const lower = category.toLowerCase();
395
369
  if (lower === "images") return "image";
396
370
  if (lower === "embeddings") return "embedding";
397
- if (lower === "text" || lower === "image" || lower === "video" || lower === "audio" || lower === "realtime" || lower === "embedding") {
398
- return lower;
399
- }
400
- return null;
371
+ return lower in MODALITY_THEMES ? lower : null;
401
372
  }
402
- function getModalityColors(category) {
373
+ function getModalityTheme(category) {
403
374
  const key = normalize(category);
404
- return key ? MODALITY_COLORS[key] : null;
375
+ return key ? MODALITY_THEMES[key] : null;
405
376
  }
406
377
 
407
- // src/modules/models/ModelSelector.tsx
378
+ // src/modules/gen/ModelSelector.tsx
408
379
  var import_jsx_runtime7 = require("react/jsx-runtime");
409
380
  var CATEGORY_LABELS = {
410
381
  image: "Image",
411
382
  video: "Video",
412
383
  text: "Text",
413
- audio: "Audio"
384
+ audio: "Audio",
385
+ embedding: "Embeddings",
386
+ realtime: "Realtime"
414
387
  };
415
- function displayModelName(model) {
416
- return model.description?.split(" - ")[0] || model.name || model.id;
388
+ function categoryLabel(category) {
389
+ return CATEGORY_LABELS[category];
417
390
  }
418
- function modalityTheme(category) {
419
- const colors = getModalityColors(category) ?? getModalityColors("text");
420
- if (!colors) {
421
- throw new Error(`Missing modality colors for ${category}`);
422
- }
423
- return colors.theme;
391
+ function displayModelName(model) {
392
+ return model.title;
424
393
  }
425
394
  function ModelSelector({
426
395
  models,
427
396
  category,
428
397
  value,
429
- allowedModelIds,
430
- isLoggedIn = false,
431
398
  isLoading = false,
432
399
  onChange
433
400
  }) {
@@ -463,7 +430,6 @@ function ModelSelector({
463
430
  theme,
464
431
  className: "polli:max-h-64 polli:pr-2",
465
432
  children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "polli:flex polli:flex-col polli:gap-1", children: filteredModels.map((model) => {
466
- const isAllowed = !isLoggedIn || !allowedModelIds || allowedModelIds.has(model.id);
467
433
  const isActive = value === model.id;
468
434
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
469
435
  TabButton,
@@ -472,7 +438,6 @@ function ModelSelector({
472
438
  theme: modalityTheme(model.category),
473
439
  size: "sm",
474
440
  variant: "ghost",
475
- disabled: !isAllowed,
476
441
  className: "polli:w-full polli:justify-between polli:text-left",
477
442
  onClick: () => {
478
443
  onChange(model.id);
@@ -503,6 +468,10 @@ function ModelSelector({
503
468
  }
504
469
  // Annotate the CommonJS export names for ESM import in node:
505
470
  0 && (module.exports = {
506
- ModelSelector
471
+ CATEGORY_LABELS,
472
+ ModelSelector,
473
+ categoryLabel,
474
+ getModalityTheme,
475
+ modalityTheme
507
476
  });
508
477
  //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/modules/gen/index.ts","../../src/lib/cn.ts","../../src/primitives/Button.tsx","../../src/primitives/ChevronIcon.tsx","../../src/primitives/Chip.tsx","../../src/primitives/Dropdown.tsx","../../src/primitives/ScrollArea.tsx","../../src/primitives/TabButton.tsx","../../src/modules/gen/themes.ts","../../src/modules/gen/ModelSelector.tsx"],"sourcesContent":["export {\n CATEGORY_LABELS,\n categoryLabel,\n ModelSelector,\n type ModelSelectorCategory,\n type ModelSelectorItem,\n type ModelSelectorProps,\n} from \"./ModelSelector.tsx\";\nexport {\n getModalityTheme,\n type Modality,\n modalityTheme,\n} from \"./themes.ts\";\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 type { FC } from \"react\";\nimport { cn } from \"../lib/cn.ts\";\n\ntype ChevronIconProps = {\n /** Rotate 180° when expanded/open. */\n expanded?: boolean;\n className?: string;\n};\n\n/**\n * Canonical chevron used for collapsibles, dropdown triggers, and select pills\n * across the app. One icon everywhere.\n */\nexport const ChevronIcon: FC<ChevronIconProps> = ({ expanded, className }) => (\n <svg\n aria-hidden=\"true\"\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 12 12\"\n className={cn(\n \"polli:shrink-0 polli:transition-transform polli:duration-200 polli:ease-out\",\n expanded && \"polli:rotate-180\",\n className,\n )}\n >\n <path\n d=\"M3 4.5 6 7.5l3-3\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth=\"1.5\"\n />\n </svg>\n);\n","import type { ComponentPropsWithoutRef, FC } from \"react\";\nimport { cn } from \"../lib/cn.ts\";\nimport type { ThemeName } from \"../theme.ts\";\n\n/** Semantic chip labels for status and metadata badges. */\ntype ChipIntent =\n | \"news\"\n | \"alpha\"\n | \"neutral\"\n | \"success\"\n | \"warning\"\n | \"danger\";\n\nconst chipSizes = {\n sm: \"polli:px-2 polli:py-0.5 polli:text-xs\",\n md: \"polli:px-2.5 polli:py-0.5 polli:text-sm\",\n lg: \"polli:px-3 polli:py-1 polli:text-sm\",\n} as const;\n\nconst intentClasses: Record<ChipIntent, string> = {\n news: \"polli:bg-intent-news-bg-light polli:text-intent-news-text\",\n alpha: \"polli:bg-intent-alpha-bg-light polli:text-intent-alpha-text\",\n neutral: \"polli:bg-ink-100/80 polli:text-ink-900\",\n success: \"polli:bg-intent-success-bg-light polli:text-intent-success-text\",\n warning: \"polli:bg-intent-warning-bg-light polli:text-intent-warning-text\",\n danger: \"polli:bg-intent-danger-bg-light polli:text-intent-danger-text\",\n};\n\nexport type ChipProps = ComponentPropsWithoutRef<\"span\"> & {\n /** Override the cascade theme for this chip's subtree. */\n theme?: ThemeName;\n /** Semantic intent. Wins over `theme` when set. */\n intent?: ChipIntent;\n size?: keyof typeof chipSizes;\n};\n\n// Static, rectangular colored container. Round shapes are reserved for buttons.\n// Reads `bg-theme-bg-active` / `text-theme-text-strong` from the cascade unless\n// `intent` is set (semantic, theme-independent).\nexport const Chip: FC<ChipProps> = ({\n theme,\n intent,\n size = \"md\",\n className,\n children,\n ...rest\n}) => {\n const intentClass = intent\n ? intentClasses[intent]\n : \"polli:bg-theme-bg-active polli:text-theme-text-strong\";\n return (\n <span\n {...rest}\n data-theme={theme}\n className={cn(\n \"polli:inline-flex polli:shrink-0 polli:items-center polli:gap-1 polli:rounded-lg polli:font-medium polli:leading-normal\",\n chipSizes[size],\n intentClass,\n className,\n )}\n >\n {children}\n </span>\n );\n};\n","import { Popover } from \"@ark-ui/react/popover\";\nimport { Portal } from \"@ark-ui/react/portal\";\nimport type { FC, ReactNode } from \"react\";\nimport { useState } from \"react\";\nimport { cn } from \"../lib/cn.ts\";\nimport type { ThemeName } from \"../theme.ts\";\n\nconst DEFAULT_PANEL =\n \"polli:rounded-lg polli:border polli:border-theme-border polli:bg-theme-bg-pale polli:shadow-lg\";\n\nexport type DropdownProps = {\n theme: ThemeName;\n /** Trigger element; receives the current open state (e.g. to rotate a chevron). */\n trigger: (open: boolean) => ReactNode;\n /** Panel content. As a function, receives `close` to dismiss after a selection. */\n children: ReactNode | ((close: () => void) => ReactNode);\n /** Panel placement relative to the trigger. */\n align?: \"start\" | \"end\";\n /** Controlled open state. Omit to let the Dropdown manage its own. */\n open?: boolean;\n onOpenChange?: (open: boolean) => void;\n /** Appended after the surface (widths, padding, max-height…). */\n className?: string;\n};\n\nexport const Dropdown: FC<DropdownProps> = ({\n theme,\n trigger,\n children,\n align = \"start\",\n open: openProp,\n onOpenChange,\n className,\n}) => {\n const [internalOpen, setInternalOpen] = useState(false);\n const isControlled = openProp !== undefined;\n const open = isControlled ? openProp : internalOpen;\n\n const setOpen = (next: boolean) => {\n if (!isControlled) setInternalOpen(next);\n onOpenChange?.(next);\n };\n\n return (\n <Popover.Root\n open={open}\n onOpenChange={(details) => setOpen(details.open)}\n positioning={{\n placement: align === \"end\" ? \"bottom-end\" : \"bottom-start\",\n }}\n >\n <Popover.Trigger asChild>{trigger(open)}</Popover.Trigger>\n <Portal>\n <Popover.Positioner>\n <Popover.Content\n data-theme={theme}\n className={cn(\n \"polli:z-50 polli:overflow-hidden polli:focus:outline-none\",\n DEFAULT_PANEL,\n className,\n )}\n >\n {typeof children === \"function\"\n ? children(() => setOpen(false))\n : children}\n </Popover.Content>\n </Popover.Positioner>\n </Portal>\n </Popover.Root>\n );\n};\n","import {\n type ComponentPropsWithoutRef,\n forwardRef,\n type MutableRefObject,\n type PropsWithChildren,\n type Ref,\n useCallback,\n useEffect,\n useRef,\n} from \"react\";\nimport { cn } from \"../lib/cn.ts\";\nimport type { ThemeName } from \"../theme.ts\";\n\ntype ScrollAxis = \"y\" | \"x\";\n\nconst axisClasses: Record<ScrollAxis, string> = {\n y: \"polli:overflow-y-auto polli:overflow-x-hidden\",\n x: \"polli:overflow-x-auto polli:overflow-y-hidden\",\n};\n\ntype ScrollAreaOwnProps = {\n /** Override the ambient cascade theme for this scroller's thumb. */\n theme?: ThemeName;\n /** Scroll direction. Default `y`. */\n axis?: ScrollAxis;\n className?: string;\n};\n\nexport type ScrollAreaProps = PropsWithChildren<\n ScrollAreaOwnProps &\n Omit<ComponentPropsWithoutRef<\"div\">, keyof ScrollAreaOwnProps>\n>;\n\nfunction assignRef<T>(ref: Ref<T> | undefined, value: T | null) {\n if (typeof ref === \"function\") ref(value);\n else if (ref) (ref as MutableRefObject<T | null>).current = value;\n}\n\n/**\n * Themed auto-hide scroll container. Thumb color follows the nearest\n * `[data-theme=\"...\"]` ancestor; pass `theme` to override locally.\n */\nexport const ScrollArea = forwardRef<HTMLDivElement, ScrollAreaProps>(\n ({ theme, axis = \"y\", className, children, ...rest }, externalRef) => {\n const innerRef = useRef<HTMLDivElement | null>(null);\n\n const setRef = useCallback(\n (node: HTMLDivElement | null) => {\n innerRef.current = node;\n assignRef(externalRef, node);\n },\n [externalRef],\n );\n\n useEffect(() => {\n const element = innerRef.current;\n if (!element) return;\n\n let hideTimer: number | null = null;\n\n const clearHideTimer = () => {\n if (hideTimer !== null) {\n window.clearTimeout(hideTimer);\n hideTimer = null;\n }\n };\n\n const show = () => {\n element.dataset.scrollbarActive = \"true\";\n clearHideTimer();\n };\n\n const hide = () => {\n element.dataset.scrollbarActive = \"false\";\n clearHideTimer();\n };\n\n const scheduleHide = () => {\n clearHideTimer();\n hideTimer = window.setTimeout(hide, 2000);\n };\n\n const handleInteraction = () => {\n show();\n scheduleHide();\n };\n\n hide();\n\n element.addEventListener(\"scroll\", handleInteraction, {\n passive: true,\n });\n element.addEventListener(\"wheel\", handleInteraction, {\n passive: true,\n });\n element.addEventListener(\"touchstart\", handleInteraction, {\n passive: true,\n });\n element.addEventListener(\"pointerdown\", handleInteraction);\n element.addEventListener(\"keydown\", handleInteraction);\n element.addEventListener(\"focusin\", handleInteraction);\n element.addEventListener(\"focusout\", scheduleHide);\n\n return () => {\n clearHideTimer();\n element.removeEventListener(\"scroll\", handleInteraction);\n element.removeEventListener(\"wheel\", handleInteraction);\n element.removeEventListener(\"touchstart\", handleInteraction);\n element.removeEventListener(\"pointerdown\", handleInteraction);\n element.removeEventListener(\"keydown\", handleInteraction);\n element.removeEventListener(\"focusin\", handleInteraction);\n element.removeEventListener(\"focusout\", scheduleHide);\n };\n }, []);\n\n return (\n <div\n {...rest}\n ref={setRef}\n data-theme={theme}\n className={cn(\n \"polli-scrollbar-subtle polli:min-w-0 polli:max-w-full\",\n axisClasses[axis],\n className,\n )}\n >\n {children}\n </div>\n );\n },\n);\n\nScrollArea.displayName = \"ScrollArea\";\n","import type { FC, ReactNode } from \"react\";\nimport { cn } from \"../lib/cn.ts\";\nimport type { ThemeName } from \"../theme.ts\";\n\nexport type TabButtonProps = {\n active: boolean;\n onClick: () => void;\n children: ReactNode;\n /** Optional cascade override; defaults to inherited [data-theme]. */\n theme?: ThemeName;\n size?: \"md\" | \"sm\";\n variant?: \"default\" | \"ghost\";\n ariaLabel?: string;\n disabled?: boolean;\n className?: string;\n};\n\nconst sizeClasses = {\n md: \"polli:px-4 polli:py-1.5 polli:text-base\",\n sm: \"polli:px-3 polli:py-1.5 polli:text-sm\",\n} as const;\n\nconst variantClasses = {\n default: {\n base: \"polli:border\",\n active: \"polli:bg-theme-bg-active polli:text-theme-text-strong polli:border-theme-border\",\n inactive:\n \"polli:bg-theme-bg-subtle polli:text-theme-text-base polli:border-theme-border polli:hover:bg-theme-bg-active\",\n },\n ghost: {\n base: \"polli:border polli:border-transparent\",\n active: \"polli:bg-theme-bg-active polli:text-theme-text-strong\",\n inactive:\n \"polli:bg-transparent polli:text-theme-text-base polli:hover:bg-theme-bg-subtle polli:hover:text-theme-text-strong\",\n },\n} as const;\n\nexport const TabButton: FC<TabButtonProps> = ({\n theme,\n active,\n onClick,\n children,\n size = \"md\",\n variant = \"default\",\n ariaLabel,\n disabled = false,\n className,\n}) => {\n const classes = variantClasses[variant];\n return (\n <button\n type=\"button\"\n data-theme={theme}\n onClick={onClick}\n aria-label={ariaLabel}\n aria-pressed={active}\n disabled={disabled}\n className={cn(\n \"polli-control polli:inline-flex polli:items-center polli:justify-center polli:rounded-full polli:font-medium polli:leading-normal polli:transition-all polli:duration-200\",\n classes.base,\n active ? classes.active : classes.inactive,\n disabled && \"polli:cursor-not-allowed polli:opacity-50\",\n sizeClasses[size],\n className,\n )}\n >\n {children}\n </button>\n );\n};\n","/** Pollinations model modality to package theme mapping. */\nimport type { ModelCategory } from \"@pollinations/sdk\";\nimport type { ThemeName } from \"../../theme.ts\";\n\n/** A model modality is just a model category. Single source of truth: the SDK. */\nexport type Modality = ModelCategory;\n\nexport const MODALITY_THEMES: Record<ModelCategory, ThemeName> = {\n text: \"blue\",\n image: \"pink\",\n video: \"teal\",\n audio: \"amber\",\n realtime: \"coral\",\n embedding: \"violet\",\n};\n\n/** Theme for a known model category. Total — every category has a theme. */\nexport function modalityTheme(category: ModelCategory): ThemeName {\n return MODALITY_THEMES[category];\n}\n\n/** Map a human-typed category string to the canonical `ModelCategory` key. */\nfunction normalize(category: string): ModelCategory | null {\n const lower = category.toLowerCase();\n if (lower === \"images\") return \"image\";\n if (lower === \"embeddings\") return \"embedding\";\n return lower in MODALITY_THEMES ? (lower as ModelCategory) : null;\n}\n\n/** Theme for an untrusted category string (e.g. user input); null if unknown. */\nexport function getModalityTheme(category: string): ThemeName | null {\n const key = normalize(category);\n return key ? MODALITY_THEMES[key] : null;\n}\n","import type { ModelCategory } from \"@pollinations/sdk\";\nimport { cn } from \"../../lib/cn.ts\";\nimport { Button } from \"../../primitives/Button.tsx\";\nimport { ChevronIcon } from \"../../primitives/ChevronIcon.tsx\";\nimport { Chip } from \"../../primitives/Chip.tsx\";\nimport { Dropdown } from \"../../primitives/Dropdown.tsx\";\nimport { ScrollArea } from \"../../primitives/ScrollArea.tsx\";\nimport { TabButton } from \"../../primitives/TabButton.tsx\";\nimport { modalityTheme } from \"./themes.ts\";\n\nexport type ModelSelectorCategory = ModelCategory;\n\nexport type ModelSelectorItem = {\n id: string;\n name: string;\n title: string;\n description?: string;\n category: ModelSelectorCategory;\n paidOnly?: boolean;\n};\n\nexport type ModelSelectorProps = {\n models: readonly ModelSelectorItem[];\n category: ModelSelectorCategory;\n value: string;\n isLoading?: boolean;\n onChange: (modelId: string) => void;\n};\n\nexport const CATEGORY_LABELS: Record<ModelSelectorCategory, string> = {\n image: \"Image\",\n video: \"Video\",\n text: \"Text\",\n audio: \"Audio\",\n embedding: \"Embeddings\",\n realtime: \"Realtime\",\n};\n\n/** Human-readable label for a model category, e.g. \"embedding\" -> \"Embeddings\". */\nexport function categoryLabel(category: ModelSelectorCategory): string {\n return CATEGORY_LABELS[category];\n}\n\nfunction displayModelName(model: ModelSelectorItem): string {\n return model.title;\n}\n\nexport function ModelSelector({\n models,\n category,\n value,\n isLoading = false,\n onChange,\n}: ModelSelectorProps) {\n const filteredModels = models.filter(\n (model) => model.category === category,\n );\n const currentModel = models.find((model) => model.id === value);\n const theme = modalityTheme(category);\n const modelLabel = currentModel ? displayModelName(currentModel) : \"Select\";\n const accessibleLabel = currentModel\n ? `${CATEGORY_LABELS[category]} model: ${modelLabel}`\n : `Select ${CATEGORY_LABELS[category].toLowerCase()} model`;\n\n return (\n <Dropdown\n theme={theme}\n align=\"end\"\n className=\"polli:w-[min(24rem,calc(100vw-2rem))] polli:p-2\"\n trigger={(open) => (\n <Button\n type=\"button\"\n theme={theme}\n aria-label={accessibleLabel}\n className=\"polli:min-w-64 polli:max-w-full polli:self-start polli:justify-between polli:gap-2\"\n >\n <span className=\"polli:truncate\">{modelLabel}</span>\n <ChevronIcon expanded={open} />\n </Button>\n )}\n >\n {(close) =>\n isLoading ? (\n <p className=\"polli:m-0 polli:px-2 polli:py-2 polli:text-sm polli:text-theme-text-soft\">\n Loading models...\n </p>\n ) : (\n <ScrollArea\n theme={theme}\n className=\"polli:max-h-64 polli:pr-2\"\n >\n <div className=\"polli:flex polli:flex-col polli:gap-1\">\n {filteredModels.map((model) => {\n const isActive = value === model.id;\n return (\n <TabButton\n key={model.id}\n active={isActive}\n theme={modalityTheme(model.category)}\n size=\"sm\"\n variant=\"ghost\"\n className=\"polli:w-full polli:justify-between polli:text-left\"\n onClick={() => {\n onChange(model.id);\n close();\n }}\n >\n <span className=\"polli:truncate\">\n {displayModelName(model)}\n </span>\n {model.paidOnly && (\n <Chip\n size=\"sm\"\n className={cn(\n \"polli:shrink-0\",\n isActive &&\n \"polli:bg-surface-white\",\n )}\n >\n paid\n </Chip>\n )}\n </TabButton>\n );\n })}\n </div>\n </ScrollArea>\n )\n }\n </Dropdown>\n );\n}\n"],"mappings":"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","names":["import_jsx_runtime","import_jsx_runtime","intentClasses","import_jsx_runtime","import_react","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime"]}
@@ -0,0 +1,35 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ModelCategory } from '@pollinations/sdk';
3
+ import { T as ThemeName } from '../theme-jRPPBmld.cjs';
4
+
5
+ type ModelSelectorCategory = ModelCategory;
6
+ type ModelSelectorItem = {
7
+ id: string;
8
+ name: string;
9
+ title: string;
10
+ description?: string;
11
+ category: ModelSelectorCategory;
12
+ paidOnly?: boolean;
13
+ };
14
+ type ModelSelectorProps = {
15
+ models: readonly ModelSelectorItem[];
16
+ category: ModelSelectorCategory;
17
+ value: string;
18
+ isLoading?: boolean;
19
+ onChange: (modelId: string) => void;
20
+ };
21
+ declare const CATEGORY_LABELS: Record<ModelSelectorCategory, string>;
22
+ /** Human-readable label for a model category, e.g. "embedding" -> "Embeddings". */
23
+ declare function categoryLabel(category: ModelSelectorCategory): string;
24
+ declare function ModelSelector({ models, category, value, isLoading, onChange, }: ModelSelectorProps): react_jsx_runtime.JSX.Element;
25
+
26
+ /** Pollinations model modality to package theme mapping. */
27
+
28
+ /** A model modality is just a model category. Single source of truth: the SDK. */
29
+ type Modality = ModelCategory;
30
+ /** Theme for a known model category. Total — every category has a theme. */
31
+ declare function modalityTheme(category: ModelCategory): ThemeName;
32
+ /** Theme for an untrusted category string (e.g. user input); null if unknown. */
33
+ declare function getModalityTheme(category: string): ThemeName | null;
34
+
35
+ export { CATEGORY_LABELS, type Modality, ModelSelector, type ModelSelectorCategory, type ModelSelectorItem, type ModelSelectorProps, categoryLabel, getModalityTheme, modalityTheme };
@@ -0,0 +1,35 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ModelCategory } from '@pollinations/sdk';
3
+ import { T as ThemeName } from '../theme-jRPPBmld.js';
4
+
5
+ type ModelSelectorCategory = ModelCategory;
6
+ type ModelSelectorItem = {
7
+ id: string;
8
+ name: string;
9
+ title: string;
10
+ description?: string;
11
+ category: ModelSelectorCategory;
12
+ paidOnly?: boolean;
13
+ };
14
+ type ModelSelectorProps = {
15
+ models: readonly ModelSelectorItem[];
16
+ category: ModelSelectorCategory;
17
+ value: string;
18
+ isLoading?: boolean;
19
+ onChange: (modelId: string) => void;
20
+ };
21
+ declare const CATEGORY_LABELS: Record<ModelSelectorCategory, string>;
22
+ /** Human-readable label for a model category, e.g. "embedding" -> "Embeddings". */
23
+ declare function categoryLabel(category: ModelSelectorCategory): string;
24
+ declare function ModelSelector({ models, category, value, isLoading, onChange, }: ModelSelectorProps): react_jsx_runtime.JSX.Element;
25
+
26
+ /** Pollinations model modality to package theme mapping. */
27
+
28
+ /** A model modality is just a model category. Single source of truth: the SDK. */
29
+ type Modality = ModelCategory;
30
+ /** Theme for a known model category. Total — every category has a theme. */
31
+ declare function modalityTheme(category: ModelCategory): ThemeName;
32
+ /** Theme for an untrusted category string (e.g. user input); null if unknown. */
33
+ declare function getModalityTheme(category: string): ThemeName | null;
34
+
35
+ export { CATEGORY_LABELS, type Modality, ModelSelector, type ModelSelectorCategory, type ModelSelectorItem, type ModelSelectorProps, categoryLabel, getModalityTheme, modalityTheme };
@@ -101,10 +101,10 @@ var chipSizes = {
101
101
  var intentClasses2 = {
102
102
  news: "polli:bg-intent-news-bg-light polli:text-intent-news-text",
103
103
  alpha: "polli:bg-intent-alpha-bg-light polli:text-intent-alpha-text",
104
- neutral: "polli:border polli:border-gray-400/70 polli:bg-gray-100/80 polli:text-gray-900",
105
- success: "polli:border polli:border-intent-success-border polli:bg-intent-success-bg-light polli:text-intent-success-text",
106
- warning: "polli:border polli:border-intent-warning-border polli:bg-intent-warning-bg-light polli:text-intent-warning-text",
107
- danger: "polli:border polli:border-intent-danger-border polli:bg-intent-danger-bg-light polli:text-intent-danger-text"
104
+ neutral: "polli:bg-ink-100/80 polli:text-ink-900",
105
+ success: "polli:bg-intent-success-bg-light polli:text-intent-success-text",
106
+ warning: "polli:bg-intent-warning-bg-light polli:text-intent-warning-text",
107
+ danger: "polli:bg-intent-danger-bg-light polli:text-intent-danger-text"
108
108
  };
109
109
  var Chip = ({
110
110
  theme,
@@ -327,86 +327,49 @@ var TabButton = ({
327
327
  );
328
328
  };
329
329
 
330
- // src/modules/modality/colors.ts
331
- var filled = "polli:bg-theme-bg-active polli:text-theme-text-strong";
332
- var hover = "polli:hover:bg-theme-bg-subtle polli:hover:text-theme-text-strong";
333
- var text = "polli:text-theme-text-strong";
334
- var MODALITY_COLORS = {
335
- text: {
336
- theme: "blue",
337
- filled,
338
- hover,
339
- text
340
- },
341
- image: {
342
- theme: "pink",
343
- filled,
344
- hover,
345
- text
346
- },
347
- video: {
348
- theme: "teal",
349
- filled,
350
- hover,
351
- text
352
- },
353
- audio: {
354
- theme: "violet",
355
- filled,
356
- hover,
357
- text
358
- },
359
- realtime: {
360
- theme: "green",
361
- filled,
362
- hover,
363
- text
364
- },
365
- embedding: {
366
- theme: "amber",
367
- filled,
368
- hover,
369
- text
370
- }
330
+ // src/modules/gen/themes.ts
331
+ var MODALITY_THEMES = {
332
+ text: "blue",
333
+ image: "pink",
334
+ video: "teal",
335
+ audio: "amber",
336
+ realtime: "coral",
337
+ embedding: "violet"
371
338
  };
339
+ function modalityTheme(category) {
340
+ return MODALITY_THEMES[category];
341
+ }
372
342
  function normalize(category) {
373
343
  const lower = category.toLowerCase();
374
344
  if (lower === "images") return "image";
375
345
  if (lower === "embeddings") return "embedding";
376
- if (lower === "text" || lower === "image" || lower === "video" || lower === "audio" || lower === "realtime" || lower === "embedding") {
377
- return lower;
378
- }
379
- return null;
346
+ return lower in MODALITY_THEMES ? lower : null;
380
347
  }
381
- function getModalityColors(category) {
348
+ function getModalityTheme(category) {
382
349
  const key = normalize(category);
383
- return key ? MODALITY_COLORS[key] : null;
350
+ return key ? MODALITY_THEMES[key] : null;
384
351
  }
385
352
 
386
- // src/modules/models/ModelSelector.tsx
353
+ // src/modules/gen/ModelSelector.tsx
387
354
  import { jsx as jsx7, jsxs as jsxs2 } from "react/jsx-runtime";
388
355
  var CATEGORY_LABELS = {
389
356
  image: "Image",
390
357
  video: "Video",
391
358
  text: "Text",
392
- audio: "Audio"
359
+ audio: "Audio",
360
+ embedding: "Embeddings",
361
+ realtime: "Realtime"
393
362
  };
394
- function displayModelName(model) {
395
- return model.description?.split(" - ")[0] || model.name || model.id;
363
+ function categoryLabel(category) {
364
+ return CATEGORY_LABELS[category];
396
365
  }
397
- function modalityTheme(category) {
398
- const colors = getModalityColors(category) ?? getModalityColors("text");
399
- if (!colors) {
400
- throw new Error(`Missing modality colors for ${category}`);
401
- }
402
- return colors.theme;
366
+ function displayModelName(model) {
367
+ return model.title;
403
368
  }
404
369
  function ModelSelector({
405
370
  models,
406
371
  category,
407
372
  value,
408
- allowedModelIds,
409
- isLoggedIn = false,
410
373
  isLoading = false,
411
374
  onChange
412
375
  }) {
@@ -442,7 +405,6 @@ function ModelSelector({
442
405
  theme,
443
406
  className: "polli:max-h-64 polli:pr-2",
444
407
  children: /* @__PURE__ */ jsx7("div", { className: "polli:flex polli:flex-col polli:gap-1", children: filteredModels.map((model) => {
445
- const isAllowed = !isLoggedIn || !allowedModelIds || allowedModelIds.has(model.id);
446
408
  const isActive = value === model.id;
447
409
  return /* @__PURE__ */ jsxs2(
448
410
  TabButton,
@@ -451,7 +413,6 @@ function ModelSelector({
451
413
  theme: modalityTheme(model.category),
452
414
  size: "sm",
453
415
  variant: "ghost",
454
- disabled: !isAllowed,
455
416
  className: "polli:w-full polli:justify-between polli:text-left",
456
417
  onClick: () => {
457
418
  onChange(model.id);
@@ -481,6 +442,10 @@ function ModelSelector({
481
442
  );
482
443
  }
483
444
  export {
484
- ModelSelector
445
+ CATEGORY_LABELS,
446
+ ModelSelector,
447
+ categoryLabel,
448
+ getModalityTheme,
449
+ modalityTheme
485
450
  };
486
451
  //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/lib/cn.ts","../../src/primitives/Button.tsx","../../src/primitives/ChevronIcon.tsx","../../src/primitives/Chip.tsx","../../src/primitives/Dropdown.tsx","../../src/primitives/ScrollArea.tsx","../../src/primitives/TabButton.tsx","../../src/modules/gen/themes.ts","../../src/modules/gen/ModelSelector.tsx"],"sourcesContent":["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 type { FC } from \"react\";\nimport { cn } from \"../lib/cn.ts\";\n\ntype ChevronIconProps = {\n /** Rotate 180° when expanded/open. */\n expanded?: boolean;\n className?: string;\n};\n\n/**\n * Canonical chevron used for collapsibles, dropdown triggers, and select pills\n * across the app. One icon everywhere.\n */\nexport const ChevronIcon: FC<ChevronIconProps> = ({ expanded, className }) => (\n <svg\n aria-hidden=\"true\"\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 12 12\"\n className={cn(\n \"polli:shrink-0 polli:transition-transform polli:duration-200 polli:ease-out\",\n expanded && \"polli:rotate-180\",\n className,\n )}\n >\n <path\n d=\"M3 4.5 6 7.5l3-3\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth=\"1.5\"\n />\n </svg>\n);\n","import type { ComponentPropsWithoutRef, FC } from \"react\";\nimport { cn } from \"../lib/cn.ts\";\nimport type { ThemeName } from \"../theme.ts\";\n\n/** Semantic chip labels for status and metadata badges. */\ntype ChipIntent =\n | \"news\"\n | \"alpha\"\n | \"neutral\"\n | \"success\"\n | \"warning\"\n | \"danger\";\n\nconst chipSizes = {\n sm: \"polli:px-2 polli:py-0.5 polli:text-xs\",\n md: \"polli:px-2.5 polli:py-0.5 polli:text-sm\",\n lg: \"polli:px-3 polli:py-1 polli:text-sm\",\n} as const;\n\nconst intentClasses: Record<ChipIntent, string> = {\n news: \"polli:bg-intent-news-bg-light polli:text-intent-news-text\",\n alpha: \"polli:bg-intent-alpha-bg-light polli:text-intent-alpha-text\",\n neutral: \"polli:bg-ink-100/80 polli:text-ink-900\",\n success: \"polli:bg-intent-success-bg-light polli:text-intent-success-text\",\n warning: \"polli:bg-intent-warning-bg-light polli:text-intent-warning-text\",\n danger: \"polli:bg-intent-danger-bg-light polli:text-intent-danger-text\",\n};\n\nexport type ChipProps = ComponentPropsWithoutRef<\"span\"> & {\n /** Override the cascade theme for this chip's subtree. */\n theme?: ThemeName;\n /** Semantic intent. Wins over `theme` when set. */\n intent?: ChipIntent;\n size?: keyof typeof chipSizes;\n};\n\n// Static, rectangular colored container. Round shapes are reserved for buttons.\n// Reads `bg-theme-bg-active` / `text-theme-text-strong` from the cascade unless\n// `intent` is set (semantic, theme-independent).\nexport const Chip: FC<ChipProps> = ({\n theme,\n intent,\n size = \"md\",\n className,\n children,\n ...rest\n}) => {\n const intentClass = intent\n ? intentClasses[intent]\n : \"polli:bg-theme-bg-active polli:text-theme-text-strong\";\n return (\n <span\n {...rest}\n data-theme={theme}\n className={cn(\n \"polli:inline-flex polli:shrink-0 polli:items-center polli:gap-1 polli:rounded-lg polli:font-medium polli:leading-normal\",\n chipSizes[size],\n intentClass,\n className,\n )}\n >\n {children}\n </span>\n );\n};\n","import { Popover } from \"@ark-ui/react/popover\";\nimport { Portal } from \"@ark-ui/react/portal\";\nimport type { FC, ReactNode } from \"react\";\nimport { useState } from \"react\";\nimport { cn } from \"../lib/cn.ts\";\nimport type { ThemeName } from \"../theme.ts\";\n\nconst DEFAULT_PANEL =\n \"polli:rounded-lg polli:border polli:border-theme-border polli:bg-theme-bg-pale polli:shadow-lg\";\n\nexport type DropdownProps = {\n theme: ThemeName;\n /** Trigger element; receives the current open state (e.g. to rotate a chevron). */\n trigger: (open: boolean) => ReactNode;\n /** Panel content. As a function, receives `close` to dismiss after a selection. */\n children: ReactNode | ((close: () => void) => ReactNode);\n /** Panel placement relative to the trigger. */\n align?: \"start\" | \"end\";\n /** Controlled open state. Omit to let the Dropdown manage its own. */\n open?: boolean;\n onOpenChange?: (open: boolean) => void;\n /** Appended after the surface (widths, padding, max-height…). */\n className?: string;\n};\n\nexport const Dropdown: FC<DropdownProps> = ({\n theme,\n trigger,\n children,\n align = \"start\",\n open: openProp,\n onOpenChange,\n className,\n}) => {\n const [internalOpen, setInternalOpen] = useState(false);\n const isControlled = openProp !== undefined;\n const open = isControlled ? openProp : internalOpen;\n\n const setOpen = (next: boolean) => {\n if (!isControlled) setInternalOpen(next);\n onOpenChange?.(next);\n };\n\n return (\n <Popover.Root\n open={open}\n onOpenChange={(details) => setOpen(details.open)}\n positioning={{\n placement: align === \"end\" ? \"bottom-end\" : \"bottom-start\",\n }}\n >\n <Popover.Trigger asChild>{trigger(open)}</Popover.Trigger>\n <Portal>\n <Popover.Positioner>\n <Popover.Content\n data-theme={theme}\n className={cn(\n \"polli:z-50 polli:overflow-hidden polli:focus:outline-none\",\n DEFAULT_PANEL,\n className,\n )}\n >\n {typeof children === \"function\"\n ? children(() => setOpen(false))\n : children}\n </Popover.Content>\n </Popover.Positioner>\n </Portal>\n </Popover.Root>\n );\n};\n","import {\n type ComponentPropsWithoutRef,\n forwardRef,\n type MutableRefObject,\n type PropsWithChildren,\n type Ref,\n useCallback,\n useEffect,\n useRef,\n} from \"react\";\nimport { cn } from \"../lib/cn.ts\";\nimport type { ThemeName } from \"../theme.ts\";\n\ntype ScrollAxis = \"y\" | \"x\";\n\nconst axisClasses: Record<ScrollAxis, string> = {\n y: \"polli:overflow-y-auto polli:overflow-x-hidden\",\n x: \"polli:overflow-x-auto polli:overflow-y-hidden\",\n};\n\ntype ScrollAreaOwnProps = {\n /** Override the ambient cascade theme for this scroller's thumb. */\n theme?: ThemeName;\n /** Scroll direction. Default `y`. */\n axis?: ScrollAxis;\n className?: string;\n};\n\nexport type ScrollAreaProps = PropsWithChildren<\n ScrollAreaOwnProps &\n Omit<ComponentPropsWithoutRef<\"div\">, keyof ScrollAreaOwnProps>\n>;\n\nfunction assignRef<T>(ref: Ref<T> | undefined, value: T | null) {\n if (typeof ref === \"function\") ref(value);\n else if (ref) (ref as MutableRefObject<T | null>).current = value;\n}\n\n/**\n * Themed auto-hide scroll container. Thumb color follows the nearest\n * `[data-theme=\"...\"]` ancestor; pass `theme` to override locally.\n */\nexport const ScrollArea = forwardRef<HTMLDivElement, ScrollAreaProps>(\n ({ theme, axis = \"y\", className, children, ...rest }, externalRef) => {\n const innerRef = useRef<HTMLDivElement | null>(null);\n\n const setRef = useCallback(\n (node: HTMLDivElement | null) => {\n innerRef.current = node;\n assignRef(externalRef, node);\n },\n [externalRef],\n );\n\n useEffect(() => {\n const element = innerRef.current;\n if (!element) return;\n\n let hideTimer: number | null = null;\n\n const clearHideTimer = () => {\n if (hideTimer !== null) {\n window.clearTimeout(hideTimer);\n hideTimer = null;\n }\n };\n\n const show = () => {\n element.dataset.scrollbarActive = \"true\";\n clearHideTimer();\n };\n\n const hide = () => {\n element.dataset.scrollbarActive = \"false\";\n clearHideTimer();\n };\n\n const scheduleHide = () => {\n clearHideTimer();\n hideTimer = window.setTimeout(hide, 2000);\n };\n\n const handleInteraction = () => {\n show();\n scheduleHide();\n };\n\n hide();\n\n element.addEventListener(\"scroll\", handleInteraction, {\n passive: true,\n });\n element.addEventListener(\"wheel\", handleInteraction, {\n passive: true,\n });\n element.addEventListener(\"touchstart\", handleInteraction, {\n passive: true,\n });\n element.addEventListener(\"pointerdown\", handleInteraction);\n element.addEventListener(\"keydown\", handleInteraction);\n element.addEventListener(\"focusin\", handleInteraction);\n element.addEventListener(\"focusout\", scheduleHide);\n\n return () => {\n clearHideTimer();\n element.removeEventListener(\"scroll\", handleInteraction);\n element.removeEventListener(\"wheel\", handleInteraction);\n element.removeEventListener(\"touchstart\", handleInteraction);\n element.removeEventListener(\"pointerdown\", handleInteraction);\n element.removeEventListener(\"keydown\", handleInteraction);\n element.removeEventListener(\"focusin\", handleInteraction);\n element.removeEventListener(\"focusout\", scheduleHide);\n };\n }, []);\n\n return (\n <div\n {...rest}\n ref={setRef}\n data-theme={theme}\n className={cn(\n \"polli-scrollbar-subtle polli:min-w-0 polli:max-w-full\",\n axisClasses[axis],\n className,\n )}\n >\n {children}\n </div>\n );\n },\n);\n\nScrollArea.displayName = \"ScrollArea\";\n","import type { FC, ReactNode } from \"react\";\nimport { cn } from \"../lib/cn.ts\";\nimport type { ThemeName } from \"../theme.ts\";\n\nexport type TabButtonProps = {\n active: boolean;\n onClick: () => void;\n children: ReactNode;\n /** Optional cascade override; defaults to inherited [data-theme]. */\n theme?: ThemeName;\n size?: \"md\" | \"sm\";\n variant?: \"default\" | \"ghost\";\n ariaLabel?: string;\n disabled?: boolean;\n className?: string;\n};\n\nconst sizeClasses = {\n md: \"polli:px-4 polli:py-1.5 polli:text-base\",\n sm: \"polli:px-3 polli:py-1.5 polli:text-sm\",\n} as const;\n\nconst variantClasses = {\n default: {\n base: \"polli:border\",\n active: \"polli:bg-theme-bg-active polli:text-theme-text-strong polli:border-theme-border\",\n inactive:\n \"polli:bg-theme-bg-subtle polli:text-theme-text-base polli:border-theme-border polli:hover:bg-theme-bg-active\",\n },\n ghost: {\n base: \"polli:border polli:border-transparent\",\n active: \"polli:bg-theme-bg-active polli:text-theme-text-strong\",\n inactive:\n \"polli:bg-transparent polli:text-theme-text-base polli:hover:bg-theme-bg-subtle polli:hover:text-theme-text-strong\",\n },\n} as const;\n\nexport const TabButton: FC<TabButtonProps> = ({\n theme,\n active,\n onClick,\n children,\n size = \"md\",\n variant = \"default\",\n ariaLabel,\n disabled = false,\n className,\n}) => {\n const classes = variantClasses[variant];\n return (\n <button\n type=\"button\"\n data-theme={theme}\n onClick={onClick}\n aria-label={ariaLabel}\n aria-pressed={active}\n disabled={disabled}\n className={cn(\n \"polli-control polli:inline-flex polli:items-center polli:justify-center polli:rounded-full polli:font-medium polli:leading-normal polli:transition-all polli:duration-200\",\n classes.base,\n active ? classes.active : classes.inactive,\n disabled && \"polli:cursor-not-allowed polli:opacity-50\",\n sizeClasses[size],\n className,\n )}\n >\n {children}\n </button>\n );\n};\n","/** Pollinations model modality to package theme mapping. */\nimport type { ModelCategory } from \"@pollinations/sdk\";\nimport type { ThemeName } from \"../../theme.ts\";\n\n/** A model modality is just a model category. Single source of truth: the SDK. */\nexport type Modality = ModelCategory;\n\nexport const MODALITY_THEMES: Record<ModelCategory, ThemeName> = {\n text: \"blue\",\n image: \"pink\",\n video: \"teal\",\n audio: \"amber\",\n realtime: \"coral\",\n embedding: \"violet\",\n};\n\n/** Theme for a known model category. Total — every category has a theme. */\nexport function modalityTheme(category: ModelCategory): ThemeName {\n return MODALITY_THEMES[category];\n}\n\n/** Map a human-typed category string to the canonical `ModelCategory` key. */\nfunction normalize(category: string): ModelCategory | null {\n const lower = category.toLowerCase();\n if (lower === \"images\") return \"image\";\n if (lower === \"embeddings\") return \"embedding\";\n return lower in MODALITY_THEMES ? (lower as ModelCategory) : null;\n}\n\n/** Theme for an untrusted category string (e.g. user input); null if unknown. */\nexport function getModalityTheme(category: string): ThemeName | null {\n const key = normalize(category);\n return key ? MODALITY_THEMES[key] : null;\n}\n","import type { ModelCategory } from \"@pollinations/sdk\";\nimport { cn } from \"../../lib/cn.ts\";\nimport { Button } from \"../../primitives/Button.tsx\";\nimport { ChevronIcon } from \"../../primitives/ChevronIcon.tsx\";\nimport { Chip } from \"../../primitives/Chip.tsx\";\nimport { Dropdown } from \"../../primitives/Dropdown.tsx\";\nimport { ScrollArea } from \"../../primitives/ScrollArea.tsx\";\nimport { TabButton } from \"../../primitives/TabButton.tsx\";\nimport { modalityTheme } from \"./themes.ts\";\n\nexport type ModelSelectorCategory = ModelCategory;\n\nexport type ModelSelectorItem = {\n id: string;\n name: string;\n title: string;\n description?: string;\n category: ModelSelectorCategory;\n paidOnly?: boolean;\n};\n\nexport type ModelSelectorProps = {\n models: readonly ModelSelectorItem[];\n category: ModelSelectorCategory;\n value: string;\n isLoading?: boolean;\n onChange: (modelId: string) => void;\n};\n\nexport const CATEGORY_LABELS: Record<ModelSelectorCategory, string> = {\n image: \"Image\",\n video: \"Video\",\n text: \"Text\",\n audio: \"Audio\",\n embedding: \"Embeddings\",\n realtime: \"Realtime\",\n};\n\n/** Human-readable label for a model category, e.g. \"embedding\" -> \"Embeddings\". */\nexport function categoryLabel(category: ModelSelectorCategory): string {\n return CATEGORY_LABELS[category];\n}\n\nfunction displayModelName(model: ModelSelectorItem): string {\n return model.title;\n}\n\nexport function ModelSelector({\n models,\n category,\n value,\n isLoading = false,\n onChange,\n}: ModelSelectorProps) {\n const filteredModels = models.filter(\n (model) => model.category === category,\n );\n const currentModel = models.find((model) => model.id === value);\n const theme = modalityTheme(category);\n const modelLabel = currentModel ? displayModelName(currentModel) : \"Select\";\n const accessibleLabel = currentModel\n ? `${CATEGORY_LABELS[category]} model: ${modelLabel}`\n : `Select ${CATEGORY_LABELS[category].toLowerCase()} model`;\n\n return (\n <Dropdown\n theme={theme}\n align=\"end\"\n className=\"polli:w-[min(24rem,calc(100vw-2rem))] polli:p-2\"\n trigger={(open) => (\n <Button\n type=\"button\"\n theme={theme}\n aria-label={accessibleLabel}\n className=\"polli:min-w-64 polli:max-w-full polli:self-start polli:justify-between polli:gap-2\"\n >\n <span className=\"polli:truncate\">{modelLabel}</span>\n <ChevronIcon expanded={open} />\n </Button>\n )}\n >\n {(close) =>\n isLoading ? (\n <p className=\"polli:m-0 polli:px-2 polli:py-2 polli:text-sm polli:text-theme-text-soft\">\n Loading models...\n </p>\n ) : (\n <ScrollArea\n theme={theme}\n className=\"polli:max-h-64 polli:pr-2\"\n >\n <div className=\"polli:flex polli:flex-col polli:gap-1\">\n {filteredModels.map((model) => {\n const isActive = value === model.id;\n return (\n <TabButton\n key={model.id}\n active={isActive}\n theme={modalityTheme(model.category)}\n size=\"sm\"\n variant=\"ghost\"\n className=\"polli:w-full polli:justify-between polli:text-left\"\n onClick={() => {\n onChange(model.id);\n close();\n }}\n >\n <span className=\"polli:truncate\">\n {displayModelName(model)}\n </span>\n {model.paidOnly && (\n <Chip\n size=\"sm\"\n className={cn(\n \"polli:shrink-0\",\n isActive &&\n \"polli:bg-surface-white\",\n )}\n >\n paid\n </Chip>\n )}\n </TabButton>\n );\n })}\n </div>\n </ScrollArea>\n )\n }\n </Dropdown>\n );\n}\n"],"mappings":";AAAA,SAAS,YAAY;AACrB,SAAS,2BAA2B;AAEpC,IAAM,UAAU,oBAAoB,EAAE,QAAQ,QAAQ,CAAC;AAGhD,SAAS,MAAM,QAA+C;AACjE,SAAO,QAAQ,KAAK,GAAG,MAAM,CAAC;AAClC;;;ACiEQ;AAlER,IAAM,QAAQ;AAAA,EACV,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACR;AAGA,IAAM,eACF;AAKJ,IAAM,gBAA8C;AAAA,EAChD,QACI;AAER;AAYA,IAAM,gBAAgB,CAAC;AAAA,EACnB,OAAO;AAAA,EACP;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACJ,MAAgD;AAC5C,QAAM,eAAe,SAAS,cAAc,MAAM,IAAI;AACtD,SAAO;AAAA,IACH;AAAA,IACA,WACM,8CACA;AAAA,IACN;AAAA,IACA,MAAM,QAAQ,IAAI;AAAA,IAClB;AAAA,EACJ;AACJ;AAOO,SAAS,OAA+C;AAAA,EAC3D;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACP,GAAmB;AACf,QAAM,YAA+B,MAAM;AAE3C,SACI;AAAA,IAAC;AAAA;AAAA,MAEG,cAAY,SAAS,SAAY;AAAA,MACjC,eAAa;AAAA,MACb,WAAW,cAAc;AAAA,QACrB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACJ,CAAC;AAAA,MACD;AAAA,MACC,GAAG;AAAA,MAEH;AAAA;AAAA,EACL;AAER;;;ACjEQ,gBAAAA,YAAA;AAZD,IAAM,cAAoC,CAAC,EAAE,UAAU,UAAU,MACpE,gBAAAA;AAAA,EAAC;AAAA;AAAA,IACG,eAAY;AAAA,IACZ,OAAM;AAAA,IACN,QAAO;AAAA,IACP,SAAQ;AAAA,IACR,WAAW;AAAA,MACP;AAAA,MACA,YAAY;AAAA,MACZ;AAAA,IACJ;AAAA,IAEA,0BAAAA;AAAA,MAAC;AAAA;AAAA,QACG,GAAE;AAAA,QACF,MAAK;AAAA,QACL,QAAO;AAAA,QACP,eAAc;AAAA,QACd,gBAAe;AAAA,QACf,aAAY;AAAA;AAAA,IAChB;AAAA;AACJ;;;ACkBI,gBAAAC,YAAA;AAtCR,IAAM,YAAY;AAAA,EACd,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACR;AAEA,IAAMC,iBAA4C;AAAA,EAC9C,MAAM;AAAA,EACN,OAAO;AAAA,EACP,SAAS;AAAA,EACT,SAAS;AAAA,EACT,SAAS;AAAA,EACT,QAAQ;AACZ;AAaO,IAAM,OAAsB,CAAC;AAAA,EAChC;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP;AAAA,EACA;AAAA,EACA,GAAG;AACP,MAAM;AACF,QAAM,cAAc,SACdA,eAAc,MAAM,IACpB;AACN,SACI,gBAAAD;AAAA,IAAC;AAAA;AAAA,MACI,GAAG;AAAA,MACJ,cAAY;AAAA,MACZ,WAAW;AAAA,QACP;AAAA,QACA,UAAU,IAAI;AAAA,QACd;AAAA,QACA;AAAA,MACJ;AAAA,MAEC;AAAA;AAAA,EACL;AAER;;;AChEA,SAAS,eAAe;AACxB,SAAS,cAAc;AAEvB,SAAS,gBAAgB;AAyCjB,SAOI,OAAAE,MAPJ;AArCR,IAAM,gBACF;AAiBG,IAAM,WAA8B,CAAC;AAAA,EACxC;AAAA,EACA;AAAA,EACA;AAAA,EACA,QAAQ;AAAA,EACR,MAAM;AAAA,EACN;AAAA,EACA;AACJ,MAAM;AACF,QAAM,CAAC,cAAc,eAAe,IAAI,SAAS,KAAK;AACtD,QAAM,eAAe,aAAa;AAClC,QAAM,OAAO,eAAe,WAAW;AAEvC,QAAM,UAAU,CAAC,SAAkB;AAC/B,QAAI,CAAC,aAAc,iBAAgB,IAAI;AACvC,mBAAe,IAAI;AAAA,EACvB;AAEA,SACI;AAAA,IAAC,QAAQ;AAAA,IAAR;AAAA,MACG;AAAA,MACA,cAAc,CAAC,YAAY,QAAQ,QAAQ,IAAI;AAAA,MAC/C,aAAa;AAAA,QACT,WAAW,UAAU,QAAQ,eAAe;AAAA,MAChD;AAAA,MAEA;AAAA,wBAAAA,KAAC,QAAQ,SAAR,EAAgB,SAAO,MAAE,kBAAQ,IAAI,GAAE;AAAA,QACxC,gBAAAA,KAAC,UACG,0BAAAA,KAAC,QAAQ,YAAR,EACG,0BAAAA;AAAA,UAAC,QAAQ;AAAA,UAAR;AAAA,YACG,cAAY;AAAA,YACZ,WAAW;AAAA,cACP;AAAA,cACA;AAAA,cACA;AAAA,YACJ;AAAA,YAEC,iBAAO,aAAa,aACf,SAAS,MAAM,QAAQ,KAAK,CAAC,IAC7B;AAAA;AAAA,QACV,GACJ,GACJ;AAAA;AAAA;AAAA,EACJ;AAER;;;ACtEA;AAAA,EAEI;AAAA,EAIA;AAAA,EACA;AAAA,EACA;AAAA,OACG;AA2GK,gBAAAC,YAAA;AArGZ,IAAM,cAA0C;AAAA,EAC5C,GAAG;AAAA,EACH,GAAG;AACP;AAeA,SAAS,UAAa,KAAyB,OAAiB;AAC5D,MAAI,OAAO,QAAQ,WAAY,KAAI,KAAK;AAAA,WAC/B,IAAK,CAAC,IAAmC,UAAU;AAChE;AAMO,IAAM,aAAa;AAAA,EACtB,CAAC,EAAE,OAAO,OAAO,KAAK,WAAW,UAAU,GAAG,KAAK,GAAG,gBAAgB;AAClE,UAAM,WAAW,OAA8B,IAAI;AAEnD,UAAM,SAAS;AAAA,MACX,CAAC,SAAgC;AAC7B,iBAAS,UAAU;AACnB,kBAAU,aAAa,IAAI;AAAA,MAC/B;AAAA,MACA,CAAC,WAAW;AAAA,IAChB;AAEA,cAAU,MAAM;AACZ,YAAM,UAAU,SAAS;AACzB,UAAI,CAAC,QAAS;AAEd,UAAI,YAA2B;AAE/B,YAAM,iBAAiB,MAAM;AACzB,YAAI,cAAc,MAAM;AACpB,iBAAO,aAAa,SAAS;AAC7B,sBAAY;AAAA,QAChB;AAAA,MACJ;AAEA,YAAM,OAAO,MAAM;AACf,gBAAQ,QAAQ,kBAAkB;AAClC,uBAAe;AAAA,MACnB;AAEA,YAAM,OAAO,MAAM;AACf,gBAAQ,QAAQ,kBAAkB;AAClC,uBAAe;AAAA,MACnB;AAEA,YAAM,eAAe,MAAM;AACvB,uBAAe;AACf,oBAAY,OAAO,WAAW,MAAM,GAAI;AAAA,MAC5C;AAEA,YAAM,oBAAoB,MAAM;AAC5B,aAAK;AACL,qBAAa;AAAA,MACjB;AAEA,WAAK;AAEL,cAAQ,iBAAiB,UAAU,mBAAmB;AAAA,QAClD,SAAS;AAAA,MACb,CAAC;AACD,cAAQ,iBAAiB,SAAS,mBAAmB;AAAA,QACjD,SAAS;AAAA,MACb,CAAC;AACD,cAAQ,iBAAiB,cAAc,mBAAmB;AAAA,QACtD,SAAS;AAAA,MACb,CAAC;AACD,cAAQ,iBAAiB,eAAe,iBAAiB;AACzD,cAAQ,iBAAiB,WAAW,iBAAiB;AACrD,cAAQ,iBAAiB,WAAW,iBAAiB;AACrD,cAAQ,iBAAiB,YAAY,YAAY;AAEjD,aAAO,MAAM;AACT,uBAAe;AACf,gBAAQ,oBAAoB,UAAU,iBAAiB;AACvD,gBAAQ,oBAAoB,SAAS,iBAAiB;AACtD,gBAAQ,oBAAoB,cAAc,iBAAiB;AAC3D,gBAAQ,oBAAoB,eAAe,iBAAiB;AAC5D,gBAAQ,oBAAoB,WAAW,iBAAiB;AACxD,gBAAQ,oBAAoB,WAAW,iBAAiB;AACxD,gBAAQ,oBAAoB,YAAY,YAAY;AAAA,MACxD;AAAA,IACJ,GAAG,CAAC,CAAC;AAEL,WACI,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACI,GAAG;AAAA,QACJ,KAAK;AAAA,QACL,cAAY;AAAA,QACZ,WAAW;AAAA,UACP;AAAA,UACA,YAAY,IAAI;AAAA,UAChB;AAAA,QACJ;AAAA,QAEC;AAAA;AAAA,IACL;AAAA,EAER;AACJ;AAEA,WAAW,cAAc;;;AClFjB,gBAAAC,YAAA;AAjCR,IAAM,cAAc;AAAA,EAChB,IAAI;AAAA,EACJ,IAAI;AACR;AAEA,IAAM,iBAAiB;AAAA,EACnB,SAAS;AAAA,IACL,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,UACI;AAAA,EACR;AAAA,EACA,OAAO;AAAA,IACH,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,UACI;AAAA,EACR;AACJ;AAEO,IAAM,YAAgC,CAAC;AAAA,EAC1C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP,UAAU;AAAA,EACV;AAAA,EACA,WAAW;AAAA,EACX;AACJ,MAAM;AACF,QAAM,UAAU,eAAe,OAAO;AACtC,SACI,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACG,MAAK;AAAA,MACL,cAAY;AAAA,MACZ;AAAA,MACA,cAAY;AAAA,MACZ,gBAAc;AAAA,MACd;AAAA,MACA,WAAW;AAAA,QACP;AAAA,QACA,QAAQ;AAAA,QACR,SAAS,QAAQ,SAAS,QAAQ;AAAA,QAClC,YAAY;AAAA,QACZ,YAAY,IAAI;AAAA,QAChB;AAAA,MACJ;AAAA,MAEC;AAAA;AAAA,EACL;AAER;;;AC9DO,IAAM,kBAAoD;AAAA,EAC7D,MAAM;AAAA,EACN,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AAAA,EACP,UAAU;AAAA,EACV,WAAW;AACf;AAGO,SAAS,cAAc,UAAoC;AAC9D,SAAO,gBAAgB,QAAQ;AACnC;AAGA,SAAS,UAAU,UAAwC;AACvD,QAAM,QAAQ,SAAS,YAAY;AACnC,MAAI,UAAU,SAAU,QAAO;AAC/B,MAAI,UAAU,aAAc,QAAO;AACnC,SAAO,SAAS,kBAAmB,QAA0B;AACjE;AAGO,SAAS,iBAAiB,UAAoC;AACjE,QAAM,MAAM,UAAU,QAAQ;AAC9B,SAAO,MAAM,gBAAgB,GAAG,IAAI;AACxC;;;ACqCgB,SAMI,OAAAC,MANJ,QAAAC,aAAA;AAzCT,IAAM,kBAAyD;AAAA,EAClE,OAAO;AAAA,EACP,OAAO;AAAA,EACP,MAAM;AAAA,EACN,OAAO;AAAA,EACP,WAAW;AAAA,EACX,UAAU;AACd;AAGO,SAAS,cAAc,UAAyC;AACnE,SAAO,gBAAgB,QAAQ;AACnC;AAEA,SAAS,iBAAiB,OAAkC;AACxD,SAAO,MAAM;AACjB;AAEO,SAAS,cAAc;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ;AACJ,GAAuB;AACnB,QAAM,iBAAiB,OAAO;AAAA,IAC1B,CAAC,UAAU,MAAM,aAAa;AAAA,EAClC;AACA,QAAM,eAAe,OAAO,KAAK,CAAC,UAAU,MAAM,OAAO,KAAK;AAC9D,QAAM,QAAQ,cAAc,QAAQ;AACpC,QAAM,aAAa,eAAe,iBAAiB,YAAY,IAAI;AACnE,QAAM,kBAAkB,eAClB,GAAG,gBAAgB,QAAQ,CAAC,WAAW,UAAU,KACjD,UAAU,gBAAgB,QAAQ,EAAE,YAAY,CAAC;AAEvD,SACI,gBAAAD;AAAA,IAAC;AAAA;AAAA,MACG;AAAA,MACA,OAAM;AAAA,MACN,WAAU;AAAA,MACV,SAAS,CAAC,SACN,gBAAAC;AAAA,QAAC;AAAA;AAAA,UACG,MAAK;AAAA,UACL;AAAA,UACA,cAAY;AAAA,UACZ,WAAU;AAAA,UAEV;AAAA,4BAAAD,KAAC,UAAK,WAAU,kBAAkB,sBAAW;AAAA,YAC7C,gBAAAA,KAAC,eAAY,UAAU,MAAM;AAAA;AAAA;AAAA,MACjC;AAAA,MAGH,WAAC,UACE,YACI,gBAAAA,KAAC,OAAE,WAAU,4EAA2E,+BAExF,IAEA,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACG;AAAA,UACA,WAAU;AAAA,UAEV,0BAAAA,KAAC,SAAI,WAAU,yCACV,yBAAe,IAAI,CAAC,UAAU;AAC3B,kBAAM,WAAW,UAAU,MAAM;AACjC,mBACI,gBAAAC;AAAA,cAAC;AAAA;AAAA,gBAEG,QAAQ;AAAA,gBACR,OAAO,cAAc,MAAM,QAAQ;AAAA,gBACnC,MAAK;AAAA,gBACL,SAAQ;AAAA,gBACR,WAAU;AAAA,gBACV,SAAS,MAAM;AACX,2BAAS,MAAM,EAAE;AACjB,wBAAM;AAAA,gBACV;AAAA,gBAEA;AAAA,kCAAAD,KAAC,UAAK,WAAU,kBACX,2BAAiB,KAAK,GAC3B;AAAA,kBACC,MAAM,YACH,gBAAAA;AAAA,oBAAC;AAAA;AAAA,sBACG,MAAK;AAAA,sBACL,WAAW;AAAA,wBACP;AAAA,wBACA,YACI;AAAA,sBACR;AAAA,sBACH;AAAA;AAAA,kBAED;AAAA;AAAA;AAAA,cAxBC,MAAM;AAAA,YA0Bf;AAAA,UAER,CAAC,GACL;AAAA;AAAA,MACJ;AAAA;AAAA,EAGZ;AAER;","names":["jsx","jsx","intentClasses","jsx","jsx","jsx","jsx","jsxs"]}