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

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 (117) hide show
  1. package/README.md +162 -87
  2. package/dist/Button-BGqClaBr.d.cts +29 -0
  3. package/dist/Button-BGqClaBr.d.ts +29 -0
  4. package/dist/Chip-v-ADv6cz.d.cts +18 -0
  5. package/dist/Chip-v-ADv6cz.d.ts +18 -0
  6. package/dist/Dialog-D3Nqt8cE.d.cts +66 -0
  7. package/dist/Dialog-D3Nqt8cE.d.ts +66 -0
  8. package/dist/app-user-menu/sdk.cjs +938 -0
  9. package/dist/app-user-menu/sdk.cjs.map +1 -0
  10. package/dist/app-user-menu/sdk.d.cts +29 -0
  11. package/dist/app-user-menu/sdk.d.ts +29 -0
  12. package/dist/app-user-menu/sdk.js +917 -0
  13. package/dist/app-user-menu/sdk.js.map +1 -0
  14. package/dist/app.css +20 -32
  15. package/dist/auth/index.cjs +1372 -86
  16. package/dist/auth/index.cjs.map +1 -1
  17. package/dist/auth/index.d.cts +91 -6
  18. package/dist/auth/index.d.ts +91 -6
  19. package/dist/auth/index.js +1369 -85
  20. package/dist/auth/index.js.map +1 -1
  21. package/dist/auth/sdk.cjs +93 -64
  22. package/dist/auth/sdk.cjs.map +1 -1
  23. package/dist/auth/sdk.d.cts +2 -15
  24. package/dist/auth/sdk.d.ts +2 -15
  25. package/dist/auth/sdk.js +92 -61
  26. package/dist/auth/sdk.js.map +1 -1
  27. package/dist/brand/badge-made-with.svg +1 -0
  28. package/dist/brand/lockup-horizontal-black.png +0 -0
  29. package/dist/brand/lockup-horizontal-black.svg +4 -0
  30. package/dist/brand/lockup-horizontal-white.png +0 -0
  31. package/dist/brand/lockup-horizontal-white.svg +4 -0
  32. package/dist/brand/lockup-horizontal.svg +4 -0
  33. package/dist/brand/lockup-stacked-black.png +0 -0
  34. package/dist/brand/lockup-stacked-black.svg +4 -0
  35. package/dist/brand/lockup-stacked-white.png +0 -0
  36. package/dist/brand/lockup-stacked-white.svg +4 -0
  37. package/dist/brand/lockup-stacked.svg +4 -0
  38. package/dist/brand/mark-black.png +0 -0
  39. package/dist/brand/mark-black.svg +1 -0
  40. package/dist/brand/mark-white.png +0 -0
  41. package/dist/brand/mark-white.svg +1 -0
  42. package/dist/brand/mark.svg +1 -0
  43. package/dist/brand/polli/polli-lockup-horizontal-black.png +0 -0
  44. package/dist/brand/polli/polli-lockup-horizontal-white.png +0 -0
  45. package/dist/brand/polli/polli-lockup-stacked-black.png +0 -0
  46. package/dist/brand/polli/polli-lockup-stacked-white.png +0 -0
  47. package/dist/brand/polli/polli.png +0 -0
  48. package/dist/brand/wordmark-black.png +0 -0
  49. package/dist/brand/wordmark-black.svg +1 -0
  50. package/dist/brand/wordmark-white.png +0 -0
  51. package/dist/brand/wordmark-white.svg +1 -0
  52. package/dist/brand/wordmark.svg +1 -0
  53. package/dist/fonts/geist-pixel-square.woff2 +0 -0
  54. package/dist/gen/index.cjs +718 -0
  55. package/dist/gen/index.cjs.map +1 -0
  56. package/dist/gen/index.d.cts +91 -0
  57. package/dist/gen/index.d.ts +91 -0
  58. package/dist/gen/index.js +688 -0
  59. package/dist/gen/index.js.map +1 -0
  60. package/dist/index.browser.min.js +2 -0
  61. package/dist/index.browser.min.js.map +1 -0
  62. package/dist/index.cjs +4250 -1517
  63. package/dist/index.cjs.map +1 -1
  64. package/dist/index.d.cts +794 -221
  65. package/dist/index.d.ts +794 -221
  66. package/dist/index.js +4154 -1493
  67. package/dist/index.js.map +1 -1
  68. package/dist/licenses/Geist-OFL.txt +93 -0
  69. package/dist/markdown.cjs +836 -0
  70. package/dist/markdown.cjs.map +1 -0
  71. package/dist/markdown.d.cts +16 -0
  72. package/dist/markdown.d.ts +16 -0
  73. package/dist/markdown.js +807 -0
  74. package/dist/markdown.js.map +1 -0
  75. package/dist/styles.css +1 -1
  76. package/dist/theme.css +94 -0
  77. package/dist/types-CCy9JNu9.d.cts +6 -0
  78. package/dist/types-CCy9JNu9.d.ts +6 -0
  79. package/dist/wallet/index.cjs +298 -68
  80. package/dist/wallet/index.cjs.map +1 -1
  81. package/dist/wallet/index.d.cts +30 -7
  82. package/dist/wallet/index.d.ts +30 -7
  83. package/dist/wallet/index.js +297 -68
  84. package/dist/wallet/index.js.map +1 -1
  85. package/package.json +104 -102
  86. package/dist/Button-BvLF_Km2.d.cts +0 -26
  87. package/dist/Button-DQAZzvyQ.d.ts +0 -26
  88. package/dist/Chip-C5impfYd.d.ts +0 -20
  89. package/dist/Chip-SM52sUbZ.d.cts +0 -20
  90. package/dist/assets/logo-wordmark.svg +0 -1
  91. package/dist/assets/logo.svg +0 -4
  92. package/dist/compositions/app-user.cjs +0 -497
  93. package/dist/compositions/app-user.cjs.map +0 -1
  94. package/dist/compositions/app-user.d.cts +0 -18
  95. package/dist/compositions/app-user.d.ts +0 -18
  96. package/dist/compositions/app-user.js +0 -469
  97. package/dist/compositions/app-user.js.map +0 -1
  98. package/dist/modality/index.cjs +0 -86
  99. package/dist/modality/index.cjs.map +0 -1
  100. package/dist/modality/index.d.cts +0 -26
  101. package/dist/modality/index.d.ts +0 -26
  102. package/dist/modality/index.js +0 -59
  103. package/dist/modality/index.js.map +0 -1
  104. package/dist/models/index.cjs +0 -508
  105. package/dist/models/index.cjs.map +0 -1
  106. package/dist/models/index.d.cts +0 -22
  107. package/dist/models/index.d.ts +0 -22
  108. package/dist/models/index.js +0 -486
  109. package/dist/models/index.js.map +0 -1
  110. package/dist/theme-VMRlhqST.d.cts +0 -9
  111. package/dist/theme-VMRlhqST.d.ts +0 -9
  112. package/dist/wallet/sdk.cjs +0 -206
  113. package/dist/wallet/sdk.cjs.map +0 -1
  114. package/dist/wallet/sdk.d.cts +0 -33
  115. package/dist/wallet/sdk.d.ts +0 -33
  116. package/dist/wallet/sdk.js +0 -175
  117. package/dist/wallet/sdk.js.map +0 -1
@@ -0,0 +1,688 @@
1
+ // src/lib/cn.ts
2
+ import { clsx } from "clsx";
3
+ import { extendTailwindMerge } from "tailwind-merge";
4
+ var twMerge = extendTailwindMerge({
5
+ prefix: "polli",
6
+ extend: { theme: { text: ["micro"] } }
7
+ });
8
+ function cn(...inputs) {
9
+ return twMerge(clsx(...inputs));
10
+ }
11
+
12
+ // src/primitives/Chip.tsx
13
+ import { jsx } from "react/jsx-runtime";
14
+ var chipSizes = {
15
+ icon: "polli:h-5 polli:w-5 polli:p-0 polli:text-xs",
16
+ sm: "polli:h-5 polli:px-2 polli:text-xs",
17
+ md: "polli:h-6 polli:px-2.5 polli:text-sm",
18
+ lg: "polli:h-7 polli:px-3 polli:text-sm"
19
+ };
20
+ var intentClasses = {
21
+ news: "polli:bg-intent-news-bg-light polli:text-intent-news-text",
22
+ new: "polli:bg-intent-new-bg-light polli:text-intent-new-text",
23
+ free: "polli:bg-intent-free-bg-light polli:text-intent-free-text",
24
+ alpha: "polli:bg-intent-alpha-bg-light polli:text-intent-alpha-text",
25
+ neutral: "polli:bg-ink-100/80 polli:text-ink-900",
26
+ success: "polli:bg-intent-success-bg-bright/15 polli:text-intent-success-text",
27
+ warning: "polli:bg-intent-warning-bg-light polli:text-intent-warning-text",
28
+ info: "polli:bg-intent-info-bg-light polli:text-intent-info-text",
29
+ danger: "polli:bg-intent-danger-bg-light polli:text-intent-danger-text"
30
+ };
31
+ var Chip = ({
32
+ intent,
33
+ size = "md",
34
+ className,
35
+ children,
36
+ ...rest
37
+ }) => {
38
+ const intentClass = intent ? intentClasses[intent] : "polli:bg-theme-bg-active polli:text-theme-text-strong";
39
+ return /* @__PURE__ */ jsx(
40
+ "span",
41
+ {
42
+ ...rest,
43
+ className: cn(
44
+ "polli:inline-flex polli:shrink-0 polli:items-center polli:justify-center polli:gap-1 polli:rounded-lg polli:font-medium polli:leading-none",
45
+ chipSizes[size],
46
+ intentClass,
47
+ className
48
+ ),
49
+ children
50
+ }
51
+ );
52
+ };
53
+
54
+ // src/modules/gen/themes.ts
55
+ var MODALITIES = [
56
+ "text",
57
+ "image",
58
+ "video",
59
+ "audio",
60
+ "realtime",
61
+ "embedding"
62
+ ];
63
+ function getModalityKey(category) {
64
+ const lower = category.toLowerCase();
65
+ if (lower === "images") return "image";
66
+ if (lower === "embeddings") return "embedding";
67
+ return MODALITIES.includes(lower) ? lower : null;
68
+ }
69
+ var modalityColorVar = (key) => `var(--polli-color-modality-${key})`;
70
+ var modalityBgVar = (key) => `var(--polli-color-modality-${key}-bg)`;
71
+ var modalityTextColor = (key) => `color-mix(in oklab, ${modalityColorVar(key)} 60%, var(--polli-color-text-strong))`;
72
+
73
+ // src/modules/gen/ModalityChip.tsx
74
+ import { jsx as jsx2 } from "react/jsx-runtime";
75
+ function ModalityChip({
76
+ modality,
77
+ size = "sm",
78
+ className,
79
+ children
80
+ }) {
81
+ const key = getModalityKey(modality);
82
+ if (!key) {
83
+ return /* @__PURE__ */ jsx2(Chip, { intent: "neutral", size, className, children });
84
+ }
85
+ return /* @__PURE__ */ jsx2(
86
+ Chip,
87
+ {
88
+ size,
89
+ className,
90
+ style: {
91
+ backgroundColor: modalityBgVar(key),
92
+ color: modalityTextColor(key)
93
+ },
94
+ children
95
+ }
96
+ );
97
+ }
98
+
99
+ // src/modules/gen/ModalityDot.tsx
100
+ import { jsx as jsx3 } from "react/jsx-runtime";
101
+ function ModalityDot({
102
+ modality,
103
+ className
104
+ }) {
105
+ const key = getModalityKey(modality);
106
+ if (!key) return null;
107
+ return /* @__PURE__ */ jsx3(
108
+ "span",
109
+ {
110
+ "aria-hidden": "true",
111
+ className: cn(
112
+ "polli:inline-block polli:size-2 polli:shrink-0 polli:rounded-full",
113
+ className
114
+ ),
115
+ style: { backgroundColor: modalityColorVar(key) }
116
+ }
117
+ );
118
+ }
119
+
120
+ // src/primitives/TabButton.tsx
121
+ import { jsx as jsx4, jsxs } from "react/jsx-runtime";
122
+ var tabButtonBaseClass = "polli-control polli:inline-flex polli:items-center polli:justify-center polli:rounded-full polli:font-medium polli:leading-normal polli:transition-colors polli:duration-200";
123
+ var tabButtonSizeClass = {
124
+ xs: "polli:px-2.5 polli:py-1 polli:text-xs",
125
+ lg: "polli:px-5 polli:py-2 polli:text-lg",
126
+ md: "polli:px-4 polli:py-1.5 polli:text-base",
127
+ sm: "polli:px-3 polli:py-1.5 polli:text-sm"
128
+ };
129
+ var variantClasses = {
130
+ // The default tab look: borderless and monochrome. Selected uses `bg-active`
131
+ // — the same light resting fill as the site's normal buttons. Both states
132
+ // deepen to `bg-hover` and use the theme's hover label color. Non-selected
133
+ // uses the quiet `bg-subtle` token until then.
134
+ soft: {
135
+ base: "",
136
+ active: "polli:bg-theme-bg-active polli:text-theme-text-strong polli:hover:bg-theme-bg-hover polli:hover:text-theme-text-hover",
137
+ mixed: "polli:bg-theme-bg-active/45 polli:text-theme-text-strong polli:hover:bg-theme-bg-hover polli:hover:text-theme-text-hover",
138
+ inactive: "polli:bg-theme-bg-subtle polli:text-theme-text-base polli:hover:bg-theme-bg-hover polli:hover:text-theme-text-hover"
139
+ },
140
+ // Transparent until hovered or selected — for multi-select toggles and
141
+ // inline rows where a filled idle pill would read as a hard selection.
142
+ ghost: {
143
+ base: "polli:border polli:border-transparent",
144
+ active: "polli:bg-theme-bg-active polli:text-theme-text-strong polli:hover:bg-theme-bg-hover polli:hover:text-theme-text-hover",
145
+ mixed: "polli:bg-theme-bg-active/45 polli:text-theme-text-strong polli:hover:bg-theme-bg-hover polli:hover:text-theme-text-hover",
146
+ inactive: "polli:bg-transparent polli:text-theme-text-base polli:hover:bg-theme-bg-hover polli:hover:text-theme-text-hover"
147
+ }
148
+ };
149
+ var intentClasses2 = {
150
+ amber: {
151
+ active: "polli:bg-paid-pale polli:text-paid-deep",
152
+ inactive: "polli:bg-transparent polli:text-theme-text-base polli:hover:bg-paid-pale/60"
153
+ },
154
+ green: {
155
+ active: "polli:bg-tier-pale polli:text-tier-deep",
156
+ inactive: "polli:bg-transparent polli:text-tier-deep polli:hover:bg-tier-pale/60"
157
+ },
158
+ // Site navigation: the current page is the one full brand pill; hover
159
+ // only previews it, so "where you are" never doubles up.
160
+ brand: {
161
+ active: "polli:bg-brand-accent polli:font-bold polli:text-brand-dark",
162
+ inactive: "polli:bg-transparent polli:font-bold polli:text-theme-text-strong polli:hover:bg-brand-accent/60 polli:hover:text-brand-dark"
163
+ }
164
+ };
165
+ function TabButton({
166
+ as,
167
+ active,
168
+ onClick,
169
+ children,
170
+ icon,
171
+ size = "md",
172
+ variant = "soft",
173
+ intent,
174
+ detail,
175
+ ariaLabel,
176
+ disabled = false,
177
+ className,
178
+ ...rest
179
+ }) {
180
+ const Component = as || "button";
181
+ const isButton = Component === "button";
182
+ const colors = intent === "neutral" ? variantClasses.soft : intent ? {
183
+ ...intentClasses2[intent],
184
+ mixed: intentClasses2[intent].active
185
+ } : variantClasses[variant];
186
+ const handleClick = disabled ? (event) => {
187
+ event.preventDefault();
188
+ event.stopPropagation();
189
+ } : onClick;
190
+ return /* @__PURE__ */ jsxs(
191
+ Component,
192
+ {
193
+ ...rest,
194
+ ...isButton ? { type: "button", disabled } : {},
195
+ ...!isButton && disabled ? { "aria-disabled": true, tabIndex: -1 } : {},
196
+ ...Component === "a" && disabled ? { href: void 0 } : {},
197
+ onClick: handleClick,
198
+ ...ariaLabel !== void 0 ? { "aria-label": ariaLabel } : {},
199
+ ...isButton ? { "aria-pressed": active } : { "aria-current": active === true ? "page" : void 0 },
200
+ className: cn(
201
+ tabButtonBaseClass,
202
+ variantClasses[variant].base,
203
+ active === "mixed" ? colors.mixed : active ? colors.active : colors.inactive,
204
+ disabled && "polli:pointer-events-none polli:cursor-not-allowed polli:opacity-50",
205
+ tabButtonSizeClass[size],
206
+ className
207
+ ),
208
+ children: [
209
+ icon && /* @__PURE__ */ jsx4(
210
+ "span",
211
+ {
212
+ "aria-hidden": "true",
213
+ className: "polli:mr-1.5 polli:flex polli:size-4 polli:shrink-0 polli:[&>svg]:size-full",
214
+ children: icon
215
+ }
216
+ ),
217
+ children,
218
+ detail != null && /* @__PURE__ */ jsx4("span", { className: "polli:ml-1 polli:font-normal polli:opacity-70", children: detail })
219
+ ]
220
+ }
221
+ );
222
+ }
223
+
224
+ // src/modules/gen/ModalityTab.tsx
225
+ import { jsx as jsx5 } from "react/jsx-runtime";
226
+ function ModalityTab({
227
+ active,
228
+ onClick,
229
+ children,
230
+ size = "md",
231
+ disabled = false,
232
+ className,
233
+ icon: Icon,
234
+ modality,
235
+ ...rest
236
+ }) {
237
+ const tint = modality && !active ? modalityTextColor(modality) : void 0;
238
+ return /* @__PURE__ */ jsx5(
239
+ TabButton,
240
+ {
241
+ ...rest,
242
+ active,
243
+ onClick,
244
+ size,
245
+ disabled,
246
+ className: cn(tint && "polli:group", className),
247
+ icon: Icon && (tint ? /* @__PURE__ */ jsx5(
248
+ Icon,
249
+ {
250
+ className: "polli:text-(--polli-tab-icon) polli:group-hover:text-current",
251
+ style: { "--polli-tab-icon": tint }
252
+ }
253
+ ) : /* @__PURE__ */ jsx5(Icon, {})),
254
+ children
255
+ }
256
+ );
257
+ }
258
+
259
+ // src/primitives/icons/index.tsx
260
+ import { jsx as jsx6, jsxs as jsxs2 } from "react/jsx-runtime";
261
+ var strokeProps = {
262
+ fill: "none",
263
+ stroke: "currentColor",
264
+ strokeWidth: 2,
265
+ strokeLinecap: "round",
266
+ strokeLinejoin: "round"
267
+ };
268
+ function CardIcon(props) {
269
+ return /* @__PURE__ */ jsxs2("svg", { "aria-hidden": "true", viewBox: "0 0 24 24", ...strokeProps, ...props, children: [
270
+ /* @__PURE__ */ jsx6("rect", { x: "2", y: "5", width: "20", height: "14", rx: "2" }),
271
+ /* @__PURE__ */ jsx6("path", { d: "M2 10h20" })
272
+ ] });
273
+ }
274
+ function SproutIcon(props) {
275
+ return /* @__PURE__ */ jsxs2("svg", { "aria-hidden": "true", viewBox: "0 0 24 24", ...strokeProps, ...props, children: [
276
+ /* @__PURE__ */ jsx6("path", { d: "M7 20h10" }),
277
+ /* @__PURE__ */ jsx6("path", { d: "M10 20c5.5-2.5.8-6.4 3-10" }),
278
+ /* @__PURE__ */ jsx6("path", { d: "M9.5 9.4c1.1.8 1.8 2.2 2.3 3.7-2 .4-3.5.4-4.8-.3-1.2-.6-2.3-1.9-3-4.2 2.8-.5 4.4 0 5.5.8z" }),
279
+ /* @__PURE__ */ jsx6("path", { d: "M14.1 6a7 7 0 0 0-1.1 4c1.9-.1 3.3-.6 4.3-1.4 1-1 1.6-2.3 1.7-4.6-2.7.1-4 1-4.9 2z" })
280
+ ] });
281
+ }
282
+
283
+ // src/modules/gen/ModelAccessIcon.tsx
284
+ import { jsx as jsx7 } from "react/jsx-runtime";
285
+ function ModelAccessIcon({
286
+ paidOnly = false,
287
+ className = "polli:h-3.5 polli:w-3.5"
288
+ }) {
289
+ const label = paidOnly ? "Paid Pollen required" : "Works with any Pollen";
290
+ const Icon = paidOnly ? CardIcon : SproutIcon;
291
+ return /* @__PURE__ */ jsx7(
292
+ "span",
293
+ {
294
+ role: "img",
295
+ "aria-label": label,
296
+ title: label,
297
+ className: "polli:inline-flex polli:shrink-0",
298
+ children: /* @__PURE__ */ jsx7(Icon, { className })
299
+ }
300
+ );
301
+ }
302
+
303
+ // src/primitives/Button.tsx
304
+ import { jsx as jsx8, jsxs as jsxs3 } from "react/jsx-runtime";
305
+ var pillSizes = {
306
+ icon: "polli:h-12 polli:w-12 polli:p-0",
307
+ xs: "polli:h-5 polli:px-1.5 polli:py-0 polli:text-[11px] polli:leading-none",
308
+ sm: "polli:min-h-7 polli:px-2 polli:pt-0.5 polli:pb-1",
309
+ md: "polli:min-h-9 polli:px-4 polli:pt-1.5 polli:pb-2",
310
+ lg: "polli:min-h-12 polli:px-6 polli:py-3 polli:text-base"
311
+ };
312
+ var raisedSizes = {
313
+ icon: "polli:h-12 polli:w-12 polli:p-0",
314
+ xs: "polli:px-2 polli:py-1 polli:text-xs",
315
+ sm: "polli:px-4 polli:py-2 polli:text-sm",
316
+ md: "polli:px-7 polli:py-3.5 polli:text-base",
317
+ lg: "polli:px-8 polli:py-4 polli:text-lg"
318
+ };
319
+ var appearanceClasses = {
320
+ pill: "polli:rounded-full",
321
+ raised: "polli:rounded-xl polli:border-r-[3px] polli:border-b-[3px] polli:border-solid polli:border-theme-text-strong/20 polli:hover:border-theme-text-strong/45"
322
+ };
323
+ var themeClasses = "polli:bg-theme-bg-active polli:text-theme-text-strong polli:hover:bg-theme-bg-hover polli:hover:text-theme-text-hover polli:transition-colors";
324
+ var outlined = "polli:border polli:border-theme-text-soft polli:bg-theme-bg-active/30 polli:text-theme-text-strong polli:transition-colors polli:[.dark_&]:bg-transparent";
325
+ var intentClasses3 = {
326
+ brand: `${outlined} polli:hover:bg-theme-bg-active/50 polli:[.dark_&]:hover:bg-theme-text-soft/10`,
327
+ commit: `${outlined} polli:hover:border-theme-bg-active polli:hover:bg-theme-bg-active polli:focus-visible:border-theme-bg-active polli:focus-visible:bg-theme-bg-active polli:[.dark_&]:hover:bg-theme-bg-active polli:[.dark_&]:focus-visible:bg-theme-bg-active`,
328
+ danger: "polli:border polli:border-intent-danger-text polli:bg-intent-danger-bg-light polli:text-intent-danger-text polli:hover:bg-intent-danger-bg-hover polli:focus-visible:bg-intent-danger-bg-hover polli:transition-colors polli:[.dark_&]:bg-transparent polli:[.dark_&]:hover:bg-intent-danger-bg-hover polli:[.dark_&]:focus-visible:bg-intent-danger-bg-hover",
329
+ info: "polli:bg-intent-info-bg-light polli:text-intent-info-text polli:hover:bg-intent-info-bg-hover polli:transition-colors",
330
+ // A quiet white pill on the desk, like the colour toggle; hover previews
331
+ // the accent as the ambient button does.
332
+ surface: "polli:bg-surface-opaque polli:text-theme-text-strong polli:hover:bg-theme-bg-hover polli:hover:text-theme-text-hover polli:transition-colors",
333
+ // Secondary actions never take the accent: one step stronger grey on hover.
334
+ neutral: "polli:bg-theme-bg-subtle polli:text-theme-text-base polli:hover:bg-theme-text-muted/25 polli:hover:text-theme-text-strong polli:transition-colors"
335
+ };
336
+ var buttonClasses = ({
337
+ intent,
338
+ appearance = "pill",
339
+ size,
340
+ className,
341
+ disabled,
342
+ busy
343
+ }) => {
344
+ const colorClasses = intent ? intentClasses3[intent] : themeClasses;
345
+ const sizeClasses = appearance === "raised" ? raisedSizes : pillSizes;
346
+ return cn(
347
+ "polli-control polli:inline-flex polli:items-center polli:justify-center polli:self-center polli:font-body polli:text-sm polli:font-medium polli:leading-normal polli:box-border polli:border polli:border-transparent",
348
+ // A busy button is working, not unavailable: it keeps its strength.
349
+ busy ? "polli:cursor-progress" : disabled ? "polli:opacity-50 polli:cursor-not-allowed" : "polli:hover:filter polli:hover:brightness-105 polli:cursor-pointer",
350
+ colorClasses,
351
+ appearanceClasses[appearance],
352
+ sizeClasses[size || "md"],
353
+ className
354
+ );
355
+ };
356
+ function Button({
357
+ as,
358
+ children,
359
+ icon,
360
+ intent,
361
+ appearance,
362
+ size,
363
+ className,
364
+ disabled,
365
+ ...buttonProps
366
+ }) {
367
+ const Component = as || "button";
368
+ const isButton = Component === "button";
369
+ const isAnchor = Component === "a";
370
+ const buttonType = buttonProps.type;
371
+ const onClick = buttonProps.onClick;
372
+ const ariaBusy = buttonProps["aria-busy"];
373
+ const busy = ariaBusy === true || ariaBusy === "true";
374
+ const handleClick = disabled ? (event) => {
375
+ event.preventDefault();
376
+ event.stopPropagation();
377
+ } : onClick;
378
+ return /* @__PURE__ */ jsxs3(
379
+ Component,
380
+ {
381
+ ...buttonProps,
382
+ "data-intent": intent,
383
+ ...isButton ? { type: buttonType ?? "button", disabled } : {},
384
+ ...!isButton && disabled ? { "aria-disabled": true, tabIndex: -1 } : {},
385
+ ...isAnchor && disabled ? { href: void 0 } : {},
386
+ onClick: handleClick,
387
+ className: buttonClasses({
388
+ intent,
389
+ appearance,
390
+ size,
391
+ className,
392
+ disabled,
393
+ busy
394
+ }),
395
+ children: [
396
+ icon && /* @__PURE__ */ jsx8(
397
+ "span",
398
+ {
399
+ "aria-hidden": "true",
400
+ className: "polli:mr-2 polli:flex polli:size-4 polli:shrink-0 polli:[&>svg]:size-full",
401
+ children: busy ? /* @__PURE__ */ jsx8("span", { className: "polli:block polli:size-full polli:animate-spin polli:rounded-full polli:border-2 polli:border-current polli:border-r-transparent polli:motion-reduce:animate-none" }) : icon
402
+ }
403
+ ),
404
+ children
405
+ ]
406
+ }
407
+ );
408
+ }
409
+
410
+ // src/primitives/ChevronIcon.tsx
411
+ import { jsx as jsx9 } from "react/jsx-runtime";
412
+ var ChevronIcon = ({ expanded, className }) => /* @__PURE__ */ jsx9(
413
+ "svg",
414
+ {
415
+ "aria-hidden": "true",
416
+ width: "12",
417
+ height: "12",
418
+ viewBox: "0 0 12 12",
419
+ className: cn(
420
+ "polli:shrink-0 polli:transition-transform polli:duration-200 polli:ease-out",
421
+ expanded && "polli:rotate-180",
422
+ className
423
+ ),
424
+ children: /* @__PURE__ */ jsx9(
425
+ "path",
426
+ {
427
+ d: "M3 4.5 6 7.5l3-3",
428
+ fill: "none",
429
+ stroke: "currentColor",
430
+ strokeLinecap: "round",
431
+ strokeLinejoin: "round",
432
+ strokeWidth: "1.5"
433
+ }
434
+ )
435
+ }
436
+ );
437
+
438
+ // src/primitives/Dropdown.tsx
439
+ import { Popover } from "@ark-ui/react/popover";
440
+ import { Portal } from "@ark-ui/react/portal";
441
+ import { useId, useState } from "react";
442
+ import { jsx as jsx10, jsxs as jsxs4 } from "react/jsx-runtime";
443
+ var DEFAULT_PANEL = "polli:rounded-lg polli:bg-surface-menu polli:shadow-lg";
444
+ var Dropdown = ({
445
+ trigger,
446
+ children,
447
+ align = "start",
448
+ side = "bottom",
449
+ open: openProp,
450
+ portalled = true,
451
+ onOpenChange,
452
+ className,
453
+ panelStyle
454
+ }) => {
455
+ const triggerId = useId();
456
+ const [internalOpen, setInternalOpen] = useState(false);
457
+ const isControlled = openProp !== void 0;
458
+ const open = isControlled ? openProp : internalOpen;
459
+ const setOpen = (next) => {
460
+ if (!isControlled) setInternalOpen(next);
461
+ onOpenChange?.(next);
462
+ };
463
+ return /* @__PURE__ */ jsxs4(
464
+ Popover.Root,
465
+ {
466
+ ids: { trigger: triggerId },
467
+ open,
468
+ portalled,
469
+ onOpenChange: (details) => setOpen(details.open),
470
+ positioning: {
471
+ placement: `${side}-${align}`,
472
+ strategy: portalled ? "absolute" : "fixed"
473
+ },
474
+ children: [
475
+ /* @__PURE__ */ jsx10(Popover.Trigger, { asChild: true, children: trigger(open) }),
476
+ /* @__PURE__ */ jsx10(Portal, { disabled: !portalled, children: /* @__PURE__ */ jsx10(Popover.Positioner, { children: /* @__PURE__ */ jsx10(
477
+ Popover.Content,
478
+ {
479
+ "aria-labelledby": triggerId,
480
+ style: panelStyle,
481
+ className: cn(
482
+ "polli:z-[120] polli:overflow-hidden polli:focus:outline-none",
483
+ DEFAULT_PANEL,
484
+ className
485
+ ),
486
+ children: typeof children === "function" ? children(() => setOpen(false)) : children
487
+ }
488
+ ) }) })
489
+ ]
490
+ }
491
+ );
492
+ };
493
+
494
+ // src/primitives/ScrollArea.tsx
495
+ import {
496
+ forwardRef,
497
+ useCallback,
498
+ useEffect,
499
+ useRef
500
+ } from "react";
501
+ import { jsx as jsx11 } from "react/jsx-runtime";
502
+ var axisClasses = {
503
+ y: "polli:overflow-y-auto polli:overflow-x-hidden",
504
+ x: "polli:overflow-x-auto polli:overflow-y-hidden",
505
+ both: "polli:overflow-auto"
506
+ };
507
+ function assignRef(ref, value) {
508
+ if (typeof ref === "function") ref(value);
509
+ else if (ref) ref.current = value;
510
+ }
511
+ var ScrollArea = forwardRef(
512
+ ({ axis = "y", scrollbar = "subtle", className, children, ...rest }, externalRef) => {
513
+ const innerRef = useRef(null);
514
+ const setRef = useCallback(
515
+ (node) => {
516
+ innerRef.current = node;
517
+ assignRef(externalRef, node);
518
+ },
519
+ [externalRef]
520
+ );
521
+ useEffect(() => {
522
+ if (scrollbar === "native") return;
523
+ const element = innerRef.current;
524
+ if (!element) return;
525
+ let hideTimer = null;
526
+ const clearHideTimer = () => {
527
+ if (hideTimer !== null) {
528
+ window.clearTimeout(hideTimer);
529
+ hideTimer = null;
530
+ }
531
+ };
532
+ const show = () => {
533
+ element.dataset.scrollbarActive = "true";
534
+ clearHideTimer();
535
+ };
536
+ const hide = () => {
537
+ element.dataset.scrollbarActive = "false";
538
+ clearHideTimer();
539
+ };
540
+ const scheduleHide = () => {
541
+ clearHideTimer();
542
+ hideTimer = window.setTimeout(hide, 2e3);
543
+ };
544
+ const handleInteraction = () => {
545
+ show();
546
+ scheduleHide();
547
+ };
548
+ hide();
549
+ element.addEventListener("scroll", handleInteraction, {
550
+ passive: true
551
+ });
552
+ element.addEventListener("wheel", handleInteraction, {
553
+ passive: true
554
+ });
555
+ element.addEventListener("touchstart", handleInteraction, {
556
+ passive: true
557
+ });
558
+ element.addEventListener("pointerdown", handleInteraction);
559
+ element.addEventListener("keydown", handleInteraction);
560
+ element.addEventListener("focusin", handleInteraction);
561
+ element.addEventListener("focusout", scheduleHide);
562
+ return () => {
563
+ clearHideTimer();
564
+ element.removeEventListener("scroll", handleInteraction);
565
+ element.removeEventListener("wheel", handleInteraction);
566
+ element.removeEventListener("touchstart", handleInteraction);
567
+ element.removeEventListener("pointerdown", handleInteraction);
568
+ element.removeEventListener("keydown", handleInteraction);
569
+ element.removeEventListener("focusin", handleInteraction);
570
+ element.removeEventListener("focusout", scheduleHide);
571
+ };
572
+ }, [scrollbar]);
573
+ return /* @__PURE__ */ jsx11(
574
+ "div",
575
+ {
576
+ ...rest,
577
+ ref: setRef,
578
+ className: cn(
579
+ scrollbar === "subtle" && "polli-scrollbar-subtle",
580
+ "polli:min-w-0 polli:max-w-full",
581
+ axisClasses[axis],
582
+ className
583
+ ),
584
+ children
585
+ }
586
+ );
587
+ }
588
+ );
589
+ ScrollArea.displayName = "ScrollArea";
590
+
591
+ // src/modules/gen/ModelSelector.tsx
592
+ import { jsx as jsx12, jsxs as jsxs5 } from "react/jsx-runtime";
593
+ var CATEGORY_LABELS = {
594
+ image: "Image",
595
+ video: "Video",
596
+ text: "Text",
597
+ audio: "Audio",
598
+ "3d": "3D",
599
+ embedding: "Embeddings",
600
+ realtime: "Realtime"
601
+ };
602
+ function categoryLabel(category) {
603
+ return CATEGORY_LABELS[category];
604
+ }
605
+ function modelId(model) {
606
+ return model.id ?? model.name;
607
+ }
608
+ function ModelSelector({
609
+ models,
610
+ category,
611
+ value,
612
+ isLoading = false,
613
+ onChange
614
+ }) {
615
+ const filteredModels = models.filter((model) => model.category === category).sort((a, b) => modelId(a).localeCompare(modelId(b)));
616
+ const currentModel = models.find((model) => modelId(model) === value);
617
+ const modelLabel = currentModel ? currentModel.title ?? currentModel.name : "Select";
618
+ const accessibleLabel = currentModel ? `${CATEGORY_LABELS[category]} model: ${modelLabel}` : `Select ${CATEGORY_LABELS[category].toLowerCase()} model`;
619
+ return /* @__PURE__ */ jsx12(
620
+ Dropdown,
621
+ {
622
+ align: "start",
623
+ className: "polli:w-[min(24rem,calc(100vw-2rem))] polli:p-2",
624
+ trigger: (open) => /* @__PURE__ */ jsxs5(
625
+ Button,
626
+ {
627
+ type: "button",
628
+ "aria-label": accessibleLabel,
629
+ className: "polli:min-w-64 polli:max-w-full polli:self-start polli:justify-between polli:gap-2",
630
+ children: [
631
+ /* @__PURE__ */ jsxs5("span", { className: "polli:flex polli:min-w-0 polli:items-center polli:gap-2", children: [
632
+ /* @__PURE__ */ jsx12("span", { className: "polli:truncate", children: modelLabel }),
633
+ currentModel && /* @__PURE__ */ jsx12(
634
+ ModelAccessIcon,
635
+ {
636
+ paidOnly: currentModel.paid_only
637
+ }
638
+ )
639
+ ] }),
640
+ /* @__PURE__ */ jsx12(ChevronIcon, { expanded: open })
641
+ ]
642
+ }
643
+ ),
644
+ children: (close) => isLoading ? /* @__PURE__ */ jsx12("p", { className: "polli:m-0 polli:px-2 polli:py-2 polli:text-sm polli:text-theme-text-soft", children: "Loading models..." }) : /* @__PURE__ */ jsx12(ScrollArea, { className: "polli:max-h-80 polli:pr-2", children: /* @__PURE__ */ jsx12("div", { className: "polli:flex polli:flex-col polli:gap-1", children: filteredModels.map((model) => {
645
+ const id = modelId(model);
646
+ const isActive = value === id;
647
+ return /* @__PURE__ */ jsx12(
648
+ TabButton,
649
+ {
650
+ active: isActive,
651
+ size: "sm",
652
+ variant: "ghost",
653
+ className: "polli:w-full polli:justify-start polli:text-left",
654
+ onClick: () => {
655
+ onChange(id);
656
+ close();
657
+ },
658
+ children: /* @__PURE__ */ jsxs5("span", { className: "polli:flex polli:min-w-0 polli:flex-col polli:gap-0.5", children: [
659
+ /* @__PURE__ */ jsxs5("span", { className: "polli:flex polli:min-w-0 polli:items-center polli:gap-2", children: [
660
+ /* @__PURE__ */ jsx12("span", { className: "polli:truncate", children: model.title ?? model.name }),
661
+ /* @__PURE__ */ jsx12(
662
+ ModelAccessIcon,
663
+ {
664
+ paidOnly: model.paid_only
665
+ }
666
+ )
667
+ ] }),
668
+ model.description && /* @__PURE__ */ jsx12("span", { className: "polli:truncate polli:text-xs polli:font-normal polli:text-theme-text-muted", children: model.description })
669
+ ] })
670
+ },
671
+ id
672
+ );
673
+ }) }) })
674
+ }
675
+ );
676
+ }
677
+ export {
678
+ ModalityChip,
679
+ ModalityDot,
680
+ ModalityTab,
681
+ ModelAccessIcon,
682
+ ModelSelector,
683
+ categoryLabel,
684
+ getModalityKey,
685
+ modalityBgVar,
686
+ modalityTextColor
687
+ };
688
+ //# sourceMappingURL=index.js.map