@pollinations/ui 0.1.0-alpha.1 → 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 (91) hide show
  1. package/README.md +148 -36
  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 +684 -243
  9. package/dist/app-user-menu/sdk.cjs.map +1 -1
  10. package/dist/app-user-menu/sdk.d.cts +18 -7
  11. package/dist/app-user-menu/sdk.d.ts +18 -7
  12. package/dist/app-user-menu/sdk.js +689 -241
  13. package/dist/app-user-menu/sdk.js.map +1 -1
  14. package/dist/app.css +19 -122
  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 +250 -0
  22. package/dist/auth/sdk.cjs.map +1 -0
  23. package/dist/auth/sdk.d.cts +40 -0
  24. package/dist/auth/sdk.d.ts +40 -0
  25. package/dist/auth/sdk.js +219 -0
  26. package/dist/auth/sdk.js.map +1 -0
  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 +459 -218
  55. package/dist/gen/index.cjs.map +1 -1
  56. package/dist/gen/index.d.cts +75 -19
  57. package/dist/gen/index.d.ts +75 -19
  58. package/dist/gen/index.js +453 -216
  59. package/dist/gen/index.js.map +1 -1
  60. package/dist/index.browser.min.js +2 -0
  61. package/dist/index.browser.min.js.map +1 -0
  62. package/dist/index.cjs +3907 -1626
  63. package/dist/index.cjs.map +1 -1
  64. package/dist/index.d.cts +682 -199
  65. package/dist/index.d.ts +682 -199
  66. package/dist/index.js +3671 -1457
  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 +295 -65
  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 +294 -65
  84. package/dist/wallet/index.js.map +1 -1
  85. package/package.json +106 -89
  86. package/dist/Chip-CQCq34kS.d.cts +0 -20
  87. package/dist/Chip-Cj4xG7Te.d.ts +0 -20
  88. package/dist/assets/logo-wordmark.svg +0 -1
  89. package/dist/assets/logo.svg +0 -4
  90. package/dist/theme-jRPPBmld.d.cts +0 -20
  91. package/dist/theme-jRPPBmld.d.ts +0 -20
package/dist/gen/index.js CHANGED
@@ -1,71 +1,415 @@
1
1
  // src/lib/cn.ts
2
2
  import { clsx } from "clsx";
3
3
  import { extendTailwindMerge } from "tailwind-merge";
4
- var twMerge = extendTailwindMerge({ prefix: "polli" });
4
+ var twMerge = extendTailwindMerge({
5
+ prefix: "polli",
6
+ extend: { theme: { text: ["micro"] } }
7
+ });
5
8
  function cn(...inputs) {
6
9
  return twMerge(clsx(...inputs));
7
10
  }
8
11
 
9
- // src/primitives/Button.tsx
12
+ // src/primitives/Chip.tsx
10
13
  import { jsx } from "react/jsx-runtime";
11
- var sizes = {
12
- sm: "polli:px-2 polli:pt-0.5 polli:pb-1",
13
- md: "polli:px-4 polli:pt-1.5 polli:pb-2",
14
- lg: "polli:px-6 polli:py-3"
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"
15
19
  };
16
- var themeClasses = "polli:bg-theme-bg-active polli:text-theme-text-base polli:hover:bg-theme-bg-hover polli:transition-colors";
17
20
  var intentClasses = {
18
- danger: "polli:bg-intent-danger-bg-light polli:text-intent-danger-text polli:hover:bg-intent-danger-bg-hover polli:transition-colors"
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"
19
335
  };
20
336
  var buttonClasses = ({
21
- theme: _theme,
22
337
  intent,
338
+ appearance = "pill",
23
339
  size,
24
340
  className,
25
- disabled
341
+ disabled,
342
+ busy
26
343
  }) => {
27
- const colorClasses = intent ? intentClasses[intent] : themeClasses;
344
+ const colorClasses = intent ? intentClasses3[intent] : themeClasses;
345
+ const sizeClasses = appearance === "raised" ? raisedSizes : pillSizes;
28
346
  return cn(
29
- "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",
30
- disabled ? "polli:opacity-50 polli:cursor-not-allowed" : "polli:hover:filter polli:hover:brightness-105 polli:cursor-pointer",
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",
31
350
  colorClasses,
32
- sizes[size || "md"],
351
+ appearanceClasses[appearance],
352
+ sizeClasses[size || "md"],
33
353
  className
34
354
  );
35
355
  };
36
356
  function Button({
37
357
  as,
38
358
  children,
39
- theme,
359
+ icon,
40
360
  intent,
361
+ appearance,
41
362
  size,
42
363
  className,
43
364
  disabled,
44
365
  ...buttonProps
45
366
  }) {
46
367
  const Component = as || "button";
47
- return /* @__PURE__ */ jsx(
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(
48
379
  Component,
49
380
  {
50
- "data-theme": intent ? void 0 : theme,
381
+ ...buttonProps,
51
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,
52
387
  className: buttonClasses({
53
- theme,
54
388
  intent,
389
+ appearance,
55
390
  size,
56
391
  className,
57
- disabled
392
+ disabled,
393
+ busy
58
394
  }),
59
- disabled,
60
- ...buttonProps,
61
- children
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
+ ]
62
406
  }
63
407
  );
64
408
  }
65
409
 
66
410
  // src/primitives/ChevronIcon.tsx
67
- import { jsx as jsx2 } from "react/jsx-runtime";
68
- var ChevronIcon = ({ expanded, className }) => /* @__PURE__ */ jsx2(
411
+ import { jsx as jsx9 } from "react/jsx-runtime";
412
+ var ChevronIcon = ({ expanded, className }) => /* @__PURE__ */ jsx9(
69
413
  "svg",
70
414
  {
71
415
  "aria-hidden": "true",
@@ -77,7 +421,7 @@ var ChevronIcon = ({ expanded, className }) => /* @__PURE__ */ jsx2(
77
421
  expanded && "polli:rotate-180",
78
422
  className
79
423
  ),
80
- children: /* @__PURE__ */ jsx2(
424
+ children: /* @__PURE__ */ jsx9(
81
425
  "path",
82
426
  {
83
427
  d: "M3 4.5 6 7.5l3-3",
@@ -91,61 +435,24 @@ var ChevronIcon = ({ expanded, className }) => /* @__PURE__ */ jsx2(
91
435
  }
92
436
  );
93
437
 
94
- // src/primitives/Chip.tsx
95
- import { jsx as jsx3 } from "react/jsx-runtime";
96
- var chipSizes = {
97
- sm: "polli:px-2 polli:py-0.5 polli:text-xs",
98
- md: "polli:px-2.5 polli:py-0.5 polli:text-sm",
99
- lg: "polli:px-3 polli:py-1 polli:text-sm"
100
- };
101
- var intentClasses2 = {
102
- news: "polli:bg-intent-news-bg-light polli:text-intent-news-text",
103
- alpha: "polli:bg-intent-alpha-bg-light polli:text-intent-alpha-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
- };
109
- var Chip = ({
110
- theme,
111
- intent,
112
- size = "md",
113
- className,
114
- children,
115
- ...rest
116
- }) => {
117
- const intentClass = intent ? intentClasses2[intent] : "polli:bg-theme-bg-active polli:text-theme-text-strong";
118
- return /* @__PURE__ */ jsx3(
119
- "span",
120
- {
121
- ...rest,
122
- "data-theme": theme,
123
- className: cn(
124
- "polli:inline-flex polli:shrink-0 polli:items-center polli:gap-1 polli:rounded-lg polli:font-medium polli:leading-normal",
125
- chipSizes[size],
126
- intentClass,
127
- className
128
- ),
129
- children
130
- }
131
- );
132
- };
133
-
134
438
  // src/primitives/Dropdown.tsx
135
439
  import { Popover } from "@ark-ui/react/popover";
136
440
  import { Portal } from "@ark-ui/react/portal";
137
- import { useState } from "react";
138
- import { jsx as jsx4, jsxs } from "react/jsx-runtime";
139
- var DEFAULT_PANEL = "polli:rounded-lg polli:border polli:border-theme-border polli:bg-theme-bg-pale polli:shadow-lg";
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";
140
444
  var Dropdown = ({
141
- theme,
142
445
  trigger,
143
446
  children,
144
447
  align = "start",
448
+ side = "bottom",
145
449
  open: openProp,
450
+ portalled = true,
146
451
  onOpenChange,
147
- className
452
+ className,
453
+ panelStyle
148
454
  }) => {
455
+ const triggerId = useId();
149
456
  const [internalOpen, setInternalOpen] = useState(false);
150
457
  const isControlled = openProp !== void 0;
151
458
  const open = isControlled ? openProp : internalOpen;
@@ -153,22 +460,26 @@ var Dropdown = ({
153
460
  if (!isControlled) setInternalOpen(next);
154
461
  onOpenChange?.(next);
155
462
  };
156
- return /* @__PURE__ */ jsxs(
463
+ return /* @__PURE__ */ jsxs4(
157
464
  Popover.Root,
158
465
  {
466
+ ids: { trigger: triggerId },
159
467
  open,
468
+ portalled,
160
469
  onOpenChange: (details) => setOpen(details.open),
161
470
  positioning: {
162
- placement: align === "end" ? "bottom-end" : "bottom-start"
471
+ placement: `${side}-${align}`,
472
+ strategy: portalled ? "absolute" : "fixed"
163
473
  },
164
474
  children: [
165
- /* @__PURE__ */ jsx4(Popover.Trigger, { asChild: true, children: trigger(open) }),
166
- /* @__PURE__ */ jsx4(Portal, { children: /* @__PURE__ */ jsx4(Popover.Positioner, { children: /* @__PURE__ */ jsx4(
475
+ /* @__PURE__ */ jsx10(Popover.Trigger, { asChild: true, children: trigger(open) }),
476
+ /* @__PURE__ */ jsx10(Portal, { disabled: !portalled, children: /* @__PURE__ */ jsx10(Popover.Positioner, { children: /* @__PURE__ */ jsx10(
167
477
  Popover.Content,
168
478
  {
169
- "data-theme": theme,
479
+ "aria-labelledby": triggerId,
480
+ style: panelStyle,
170
481
  className: cn(
171
- "polli:z-50 polli:overflow-hidden polli:focus:outline-none",
482
+ "polli:z-[120] polli:overflow-hidden polli:focus:outline-none",
172
483
  DEFAULT_PANEL,
173
484
  className
174
485
  ),
@@ -187,17 +498,18 @@ import {
187
498
  useEffect,
188
499
  useRef
189
500
  } from "react";
190
- import { jsx as jsx5 } from "react/jsx-runtime";
501
+ import { jsx as jsx11 } from "react/jsx-runtime";
191
502
  var axisClasses = {
192
503
  y: "polli:overflow-y-auto polli:overflow-x-hidden",
193
- x: "polli:overflow-x-auto polli:overflow-y-hidden"
504
+ x: "polli:overflow-x-auto polli:overflow-y-hidden",
505
+ both: "polli:overflow-auto"
194
506
  };
195
507
  function assignRef(ref, value) {
196
508
  if (typeof ref === "function") ref(value);
197
509
  else if (ref) ref.current = value;
198
510
  }
199
511
  var ScrollArea = forwardRef(
200
- ({ theme, axis = "y", className, children, ...rest }, externalRef) => {
512
+ ({ axis = "y", scrollbar = "subtle", className, children, ...rest }, externalRef) => {
201
513
  const innerRef = useRef(null);
202
514
  const setRef = useCallback(
203
515
  (node) => {
@@ -207,6 +519,7 @@ var ScrollArea = forwardRef(
207
519
  [externalRef]
208
520
  );
209
521
  useEffect(() => {
522
+ if (scrollbar === "native") return;
210
523
  const element = innerRef.current;
211
524
  if (!element) return;
212
525
  let hideTimer = null;
@@ -256,15 +569,15 @@ var ScrollArea = forwardRef(
256
569
  element.removeEventListener("focusin", handleInteraction);
257
570
  element.removeEventListener("focusout", scheduleHide);
258
571
  };
259
- }, []);
260
- return /* @__PURE__ */ jsx5(
572
+ }, [scrollbar]);
573
+ return /* @__PURE__ */ jsx11(
261
574
  "div",
262
575
  {
263
576
  ...rest,
264
577
  ref: setRef,
265
- "data-theme": theme,
266
578
  className: cn(
267
- "polli-scrollbar-subtle polli:min-w-0 polli:max-w-full",
579
+ scrollbar === "subtle" && "polli-scrollbar-subtle",
580
+ "polli:min-w-0 polli:max-w-full",
268
581
  axisClasses[axis],
269
582
  className
270
583
  ),
@@ -275,96 +588,22 @@ var ScrollArea = forwardRef(
275
588
  );
276
589
  ScrollArea.displayName = "ScrollArea";
277
590
 
278
- // src/primitives/TabButton.tsx
279
- import { jsx as jsx6 } from "react/jsx-runtime";
280
- var sizeClasses = {
281
- md: "polli:px-4 polli:py-1.5 polli:text-base",
282
- sm: "polli:px-3 polli:py-1.5 polli:text-sm"
283
- };
284
- var variantClasses = {
285
- default: {
286
- base: "polli:border",
287
- active: "polli:bg-theme-bg-active polli:text-theme-text-strong polli:border-theme-border",
288
- inactive: "polli:bg-theme-bg-subtle polli:text-theme-text-base polli:border-theme-border polli:hover:bg-theme-bg-active"
289
- },
290
- ghost: {
291
- base: "polli:border polli:border-transparent",
292
- active: "polli:bg-theme-bg-active polli:text-theme-text-strong",
293
- inactive: "polli:bg-transparent polli:text-theme-text-base polli:hover:bg-theme-bg-subtle polli:hover:text-theme-text-strong"
294
- }
295
- };
296
- var TabButton = ({
297
- theme,
298
- active,
299
- onClick,
300
- children,
301
- size = "md",
302
- variant = "default",
303
- ariaLabel,
304
- disabled = false,
305
- className
306
- }) => {
307
- const classes = variantClasses[variant];
308
- return /* @__PURE__ */ jsx6(
309
- "button",
310
- {
311
- type: "button",
312
- "data-theme": theme,
313
- onClick,
314
- "aria-label": ariaLabel,
315
- "aria-pressed": active,
316
- disabled,
317
- className: cn(
318
- "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",
319
- classes.base,
320
- active ? classes.active : classes.inactive,
321
- disabled && "polli:cursor-not-allowed polli:opacity-50",
322
- sizeClasses[size],
323
- className
324
- ),
325
- children
326
- }
327
- );
328
- };
329
-
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"
338
- };
339
- function modalityTheme(category) {
340
- return MODALITY_THEMES[category];
341
- }
342
- function normalize(category) {
343
- const lower = category.toLowerCase();
344
- if (lower === "images") return "image";
345
- if (lower === "embeddings") return "embedding";
346
- return lower in MODALITY_THEMES ? lower : null;
347
- }
348
- function getModalityTheme(category) {
349
- const key = normalize(category);
350
- return key ? MODALITY_THEMES[key] : null;
351
- }
352
-
353
591
  // src/modules/gen/ModelSelector.tsx
354
- import { jsx as jsx7, jsxs as jsxs2 } from "react/jsx-runtime";
592
+ import { jsx as jsx12, jsxs as jsxs5 } from "react/jsx-runtime";
355
593
  var CATEGORY_LABELS = {
356
594
  image: "Image",
357
595
  video: "Video",
358
596
  text: "Text",
359
597
  audio: "Audio",
598
+ "3d": "3D",
360
599
  embedding: "Embeddings",
361
600
  realtime: "Realtime"
362
601
  };
363
602
  function categoryLabel(category) {
364
603
  return CATEGORY_LABELS[category];
365
604
  }
366
- function displayModelName(model) {
367
- return model.title;
605
+ function modelId(model) {
606
+ return model.id ?? model.name;
368
607
  }
369
608
  function ModelSelector({
370
609
  models,
@@ -373,79 +612,77 @@ function ModelSelector({
373
612
  isLoading = false,
374
613
  onChange
375
614
  }) {
376
- const filteredModels = models.filter(
377
- (model) => model.category === category
378
- );
379
- const currentModel = models.find((model) => model.id === value);
380
- const theme = modalityTheme(category);
381
- const modelLabel = currentModel ? displayModelName(currentModel) : "Select";
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";
382
618
  const accessibleLabel = currentModel ? `${CATEGORY_LABELS[category]} model: ${modelLabel}` : `Select ${CATEGORY_LABELS[category].toLowerCase()} model`;
383
- return /* @__PURE__ */ jsx7(
619
+ return /* @__PURE__ */ jsx12(
384
620
  Dropdown,
385
621
  {
386
- theme,
387
- align: "end",
622
+ align: "start",
388
623
  className: "polli:w-[min(24rem,calc(100vw-2rem))] polli:p-2",
389
- trigger: (open) => /* @__PURE__ */ jsxs2(
624
+ trigger: (open) => /* @__PURE__ */ jsxs5(
390
625
  Button,
391
626
  {
392
627
  type: "button",
393
- theme,
394
628
  "aria-label": accessibleLabel,
395
629
  className: "polli:min-w-64 polli:max-w-full polli:self-start polli:justify-between polli:gap-2",
396
630
  children: [
397
- /* @__PURE__ */ jsx7("span", { className: "polli:truncate", children: modelLabel }),
398
- /* @__PURE__ */ jsx7(ChevronIcon, { expanded: open })
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 })
399
641
  ]
400
642
  }
401
643
  ),
402
- children: (close) => isLoading ? /* @__PURE__ */ jsx7("p", { className: "polli:m-0 polli:px-2 polli:py-2 polli:text-sm polli:text-theme-text-soft", children: "Loading models..." }) : /* @__PURE__ */ jsx7(
403
- ScrollArea,
404
- {
405
- theme,
406
- className: "polli:max-h-64 polli:pr-2",
407
- children: /* @__PURE__ */ jsx7("div", { className: "polli:flex polli:flex-col polli:gap-1", children: filteredModels.map((model) => {
408
- const isActive = value === model.id;
409
- return /* @__PURE__ */ jsxs2(
410
- TabButton,
411
- {
412
- active: isActive,
413
- theme: modalityTheme(model.category),
414
- size: "sm",
415
- variant: "ghost",
416
- className: "polli:w-full polli:justify-between polli:text-left",
417
- onClick: () => {
418
- onChange(model.id);
419
- close();
420
- },
421
- children: [
422
- /* @__PURE__ */ jsx7("span", { className: "polli:truncate", children: displayModelName(model) }),
423
- model.paidOnly && /* @__PURE__ */ jsx7(
424
- Chip,
425
- {
426
- size: "sm",
427
- className: cn(
428
- "polli:shrink-0",
429
- isActive && "polli:bg-surface-white"
430
- ),
431
- children: "paid"
432
- }
433
- )
434
- ]
435
- },
436
- model.id
437
- );
438
- }) })
439
- }
440
- )
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
+ }) }) })
441
674
  }
442
675
  );
443
676
  }
444
677
  export {
445
- CATEGORY_LABELS,
678
+ ModalityChip,
679
+ ModalityDot,
680
+ ModalityTab,
681
+ ModelAccessIcon,
446
682
  ModelSelector,
447
683
  categoryLabel,
448
- getModalityTheme,
449
- modalityTheme
684
+ getModalityKey,
685
+ modalityBgVar,
686
+ modalityTextColor
450
687
  };
451
688
  //# sourceMappingURL=index.js.map