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

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 (112) hide show
  1. package/README.md +151 -87
  2. package/dist/Button-CO3Dpbkj.d.cts +29 -0
  3. package/dist/Button-CO3Dpbkj.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-yXzIFrDg.d.cts +63 -0
  7. package/dist/Dialog-yXzIFrDg.d.ts +63 -0
  8. package/dist/app-user-menu/sdk.cjs +893 -0
  9. package/dist/app-user-menu/sdk.cjs.map +1 -0
  10. package/dist/{compositions/app-user.d.cts → app-user-menu/sdk.d.cts} +6 -7
  11. package/dist/{compositions/app-user.d.ts → app-user-menu/sdk.d.ts} +6 -7
  12. package/dist/app-user-menu/sdk.js +872 -0
  13. package/dist/app-user-menu/sdk.js.map +1 -0
  14. package/dist/app.css +7 -32
  15. package/dist/auth/index.cjs +1346 -76
  16. package/dist/auth/index.cjs.map +1 -1
  17. package/dist/auth/index.d.cts +88 -6
  18. package/dist/auth/index.d.ts +88 -6
  19. package/dist/auth/index.js +1343 -75
  20. package/dist/auth/index.js.map +1 -1
  21. package/dist/auth/sdk.cjs +78 -60
  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 +77 -57
  26. package/dist/auth/sdk.js.map +1 -1
  27. package/dist/brand/lockup-horizontal-black.png +0 -0
  28. package/dist/brand/lockup-horizontal-black.svg +4 -0
  29. package/dist/brand/lockup-horizontal-white.png +0 -0
  30. package/dist/brand/lockup-horizontal-white.svg +4 -0
  31. package/dist/brand/lockup-horizontal.svg +1 -0
  32. package/dist/brand/lockup-stacked-black.png +0 -0
  33. package/dist/brand/lockup-stacked-black.svg +4 -0
  34. package/dist/brand/lockup-stacked-white.png +0 -0
  35. package/dist/brand/lockup-stacked-white.svg +4 -0
  36. package/dist/brand/lockup-stacked.svg +4 -0
  37. package/dist/brand/mark-black.png +0 -0
  38. package/dist/brand/mark-black.svg +3 -0
  39. package/dist/brand/mark-white.png +0 -0
  40. package/dist/brand/mark-white.svg +3 -0
  41. package/dist/brand/mark.svg +1 -0
  42. package/dist/brand/polli/polli-lockup-horizontal-black.png +0 -0
  43. package/dist/brand/polli/polli-lockup-horizontal-white.png +0 -0
  44. package/dist/brand/polli/polli-lockup-stacked-black.png +0 -0
  45. package/dist/brand/polli/polli-lockup-stacked-white.png +0 -0
  46. package/dist/brand/polli/polli.png +0 -0
  47. package/dist/brand/wordmark-black.png +0 -0
  48. package/dist/brand/wordmark-black.svg +1 -0
  49. package/dist/brand/wordmark-white.png +0 -0
  50. package/dist/brand/wordmark-white.svg +1 -0
  51. package/dist/brand/wordmark.svg +1 -0
  52. package/dist/fonts/geist-pixel-square.woff2 +0 -0
  53. package/dist/gen/index.cjs +658 -0
  54. package/dist/gen/index.cjs.map +1 -0
  55. package/dist/gen/index.d.cts +80 -0
  56. package/dist/gen/index.d.ts +80 -0
  57. package/dist/gen/index.js +630 -0
  58. package/dist/gen/index.js.map +1 -0
  59. package/dist/index.browser.min.js +2 -0
  60. package/dist/index.browser.min.js.map +1 -0
  61. package/dist/index.cjs +3847 -1490
  62. package/dist/index.cjs.map +1 -1
  63. package/dist/index.d.cts +632 -218
  64. package/dist/index.d.ts +632 -218
  65. package/dist/index.js +3744 -1450
  66. package/dist/index.js.map +1 -1
  67. package/dist/licenses/Geist-OFL.txt +93 -0
  68. package/dist/markdown.cjs +821 -0
  69. package/dist/markdown.cjs.map +1 -0
  70. package/dist/markdown.d.cts +16 -0
  71. package/dist/markdown.d.ts +16 -0
  72. package/dist/markdown.js +792 -0
  73. package/dist/markdown.js.map +1 -0
  74. package/dist/styles.css +1 -1
  75. package/dist/theme.css +92 -0
  76. package/dist/wallet/index.cjs +258 -45
  77. package/dist/wallet/index.cjs.map +1 -1
  78. package/dist/wallet/index.d.cts +29 -7
  79. package/dist/wallet/index.d.ts +29 -7
  80. package/dist/wallet/index.js +257 -45
  81. package/dist/wallet/index.js.map +1 -1
  82. package/package.json +104 -102
  83. package/dist/Button-BvLF_Km2.d.cts +0 -26
  84. package/dist/Button-DQAZzvyQ.d.ts +0 -26
  85. package/dist/Chip-C5impfYd.d.ts +0 -20
  86. package/dist/Chip-SM52sUbZ.d.cts +0 -20
  87. package/dist/assets/logo-wordmark.svg +0 -1
  88. package/dist/assets/logo.svg +0 -4
  89. package/dist/compositions/app-user.cjs +0 -497
  90. package/dist/compositions/app-user.cjs.map +0 -1
  91. package/dist/compositions/app-user.js +0 -469
  92. package/dist/compositions/app-user.js.map +0 -1
  93. package/dist/modality/index.cjs +0 -86
  94. package/dist/modality/index.cjs.map +0 -1
  95. package/dist/modality/index.d.cts +0 -26
  96. package/dist/modality/index.d.ts +0 -26
  97. package/dist/modality/index.js +0 -59
  98. package/dist/modality/index.js.map +0 -1
  99. package/dist/models/index.cjs +0 -508
  100. package/dist/models/index.cjs.map +0 -1
  101. package/dist/models/index.d.cts +0 -22
  102. package/dist/models/index.d.ts +0 -22
  103. package/dist/models/index.js +0 -486
  104. package/dist/models/index.js.map +0 -1
  105. package/dist/theme-VMRlhqST.d.cts +0 -9
  106. package/dist/theme-VMRlhqST.d.ts +0 -9
  107. package/dist/wallet/sdk.cjs +0 -206
  108. package/dist/wallet/sdk.cjs.map +0 -1
  109. package/dist/wallet/sdk.d.cts +0 -33
  110. package/dist/wallet/sdk.d.ts +0 -33
  111. package/dist/wallet/sdk.js +0 -175
  112. package/dist/wallet/sdk.js.map +0 -1
@@ -0,0 +1,792 @@
1
+ // src/compositions/Markdown.tsx
2
+ import { isValidElement } from "react";
3
+ import ReactMarkdown from "react-markdown";
4
+ import remarkGfm from "remark-gfm";
5
+
6
+ // src/lib/cn.ts
7
+ import { clsx } from "clsx";
8
+ import { extendTailwindMerge } from "tailwind-merge";
9
+ var twMerge = extendTailwindMerge({ prefix: "polli" });
10
+ function cn(...inputs) {
11
+ return twMerge(clsx(...inputs));
12
+ }
13
+
14
+ // src/lib/link.ts
15
+ function isExternalHref(href, origin = globalThis.location?.origin) {
16
+ if (typeof href !== "string" || !/^(https?:)?\/\//i.test(href))
17
+ return false;
18
+ if (!origin) return true;
19
+ try {
20
+ return new URL(href, origin).origin !== origin;
21
+ } catch {
22
+ return false;
23
+ }
24
+ }
25
+
26
+ // src/primitives/icons/index.tsx
27
+ import { jsx, jsxs } from "react/jsx-runtime";
28
+ var strokeProps = {
29
+ fill: "none",
30
+ stroke: "currentColor",
31
+ strokeWidth: 2,
32
+ strokeLinecap: "round",
33
+ strokeLinejoin: "round"
34
+ };
35
+ function CheckIcon(props) {
36
+ return /* @__PURE__ */ jsx(
37
+ "svg",
38
+ {
39
+ "aria-hidden": "true",
40
+ viewBox: "0 0 24 24",
41
+ ...strokeProps,
42
+ strokeWidth: 2.5,
43
+ ...props,
44
+ children: /* @__PURE__ */ jsx("polyline", { points: "20 6 9 17 4 12" })
45
+ }
46
+ );
47
+ }
48
+ function ClipboardIcon(props) {
49
+ return /* @__PURE__ */ jsxs("svg", { "aria-hidden": "true", viewBox: "0 0 24 24", ...strokeProps, ...props, children: [
50
+ /* @__PURE__ */ jsx("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2" }),
51
+ /* @__PURE__ */ jsx("path", { d: "M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" })
52
+ ] });
53
+ }
54
+ function ExternalLinkIcon(props) {
55
+ return /* @__PURE__ */ jsx("svg", { "aria-hidden": "true", viewBox: "0 0 24 24", ...strokeProps, ...props, children: /* @__PURE__ */ jsx("path", { d: "M7 17 17 7M9 7h8v8" }) });
56
+ }
57
+
58
+ // src/primitives/InlineLink.tsx
59
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
60
+ function InlineLink({
61
+ as,
62
+ external,
63
+ showIcon = true,
64
+ size = "inherit",
65
+ tone = "accent",
66
+ className,
67
+ children,
68
+ ...linkProps
69
+ }) {
70
+ const Component = as || "a";
71
+ const isExternal = external ?? isExternalHref(linkProps.href);
72
+ return /* @__PURE__ */ jsxs2(
73
+ Component,
74
+ {
75
+ target: isExternal && as !== "button" ? "_blank" : void 0,
76
+ rel: isExternal && as !== "button" ? "noopener noreferrer" : void 0,
77
+ className: ["polli-link", className].filter(Boolean).join(" "),
78
+ "data-size": size,
79
+ "data-tone": tone,
80
+ ...linkProps,
81
+ children: [
82
+ children,
83
+ showIcon && isExternal && /* @__PURE__ */ jsx2(
84
+ ExternalLinkIcon,
85
+ {
86
+ "aria-hidden": "true",
87
+ className: "polli-link-external-icon"
88
+ }
89
+ )
90
+ ]
91
+ }
92
+ );
93
+ }
94
+
95
+ // src/compositions/CopyButton.tsx
96
+ import {
97
+ useEffect as useEffect2,
98
+ useRef as useRef2,
99
+ useState as useState2
100
+ } from "react";
101
+
102
+ // src/primitives/Button.tsx
103
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
104
+ var pillSizes = {
105
+ icon: "polli:h-12 polli:w-12 polli:p-0",
106
+ xs: "polli:h-5 polli:px-1.5 polli:py-0 polli:text-[11px] polli:leading-none",
107
+ sm: "polli:min-h-7 polli:px-2 polli:pt-0.5 polli:pb-1",
108
+ md: "polli:min-h-9 polli:px-4 polli:pt-1.5 polli:pb-2",
109
+ lg: "polli:min-h-12 polli:px-6 polli:py-3"
110
+ };
111
+ var raisedSizes = {
112
+ icon: "polli:h-12 polli:w-12 polli:p-0",
113
+ xs: "polli:px-2 polli:py-1 polli:text-xs",
114
+ sm: "polli:px-4 polli:py-2 polli:text-sm",
115
+ md: "polli:px-7 polli:py-3.5 polli:text-base",
116
+ lg: "polli:px-8 polli:py-4 polli:text-lg"
117
+ };
118
+ var appearanceClasses = {
119
+ pill: "polli:rounded-full",
120
+ 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"
121
+ };
122
+ 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";
123
+ var outlined = "polli:border polli:border-theme-text-soft polli:bg-surface-white polli:text-theme-text-strong polli:transition-colors polli:[.dark_&]:bg-transparent";
124
+ var intentClasses = {
125
+ brand: `${outlined} polli:hover:bg-theme-text-soft/10`,
126
+ 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`,
127
+ danger: "polli:border polli:border-intent-danger-text polli:bg-transparent polli:text-intent-danger-text polli:hover:bg-intent-danger-bg-hover polli:focus-visible:bg-intent-danger-bg-hover polli:transition-colors",
128
+ info: "polli:bg-intent-info-bg-light polli:text-intent-info-text polli:hover:bg-intent-info-bg-hover polli:transition-colors",
129
+ // Secondary actions never take the accent: one step stronger grey on hover.
130
+ 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"
131
+ };
132
+ var buttonClasses = ({
133
+ intent,
134
+ appearance = "pill",
135
+ size,
136
+ className,
137
+ disabled
138
+ }) => {
139
+ const colorClasses = intent ? intentClasses[intent] : themeClasses;
140
+ const sizeClasses = appearance === "raised" ? raisedSizes : pillSizes;
141
+ return cn(
142
+ "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",
143
+ disabled ? "polli:opacity-50 polli:cursor-not-allowed" : "polli:hover:filter polli:hover:brightness-105 polli:cursor-pointer",
144
+ colorClasses,
145
+ appearanceClasses[appearance],
146
+ sizeClasses[size || "md"],
147
+ className
148
+ );
149
+ };
150
+ function Button({
151
+ as,
152
+ children,
153
+ icon,
154
+ intent,
155
+ appearance,
156
+ size,
157
+ className,
158
+ disabled,
159
+ ...buttonProps
160
+ }) {
161
+ const Component = as || "button";
162
+ const isButton = Component === "button";
163
+ const isAnchor = Component === "a";
164
+ const buttonType = buttonProps.type;
165
+ const onClick = buttonProps.onClick;
166
+ const handleClick = disabled ? (event) => {
167
+ event.preventDefault();
168
+ event.stopPropagation();
169
+ } : onClick;
170
+ return /* @__PURE__ */ jsxs3(
171
+ Component,
172
+ {
173
+ ...buttonProps,
174
+ "data-intent": intent,
175
+ ...isButton ? { type: buttonType ?? "button", disabled } : {},
176
+ ...!isButton && disabled ? { "aria-disabled": true, tabIndex: -1 } : {},
177
+ ...isAnchor && disabled ? { href: void 0 } : {},
178
+ onClick: handleClick,
179
+ className: buttonClasses({
180
+ intent,
181
+ appearance,
182
+ size,
183
+ className,
184
+ disabled
185
+ }),
186
+ children: [
187
+ icon && /* @__PURE__ */ jsx3(
188
+ "span",
189
+ {
190
+ "aria-hidden": "true",
191
+ className: "polli:mr-2 polli:flex polli:size-4 polli:shrink-0 polli:[&>svg]:size-full",
192
+ children: icon
193
+ }
194
+ ),
195
+ children
196
+ ]
197
+ }
198
+ );
199
+ }
200
+
201
+ // src/primitives/Tooltip.tsx
202
+ import {
203
+ useEffect,
204
+ useId,
205
+ useRef,
206
+ useState
207
+ } from "react";
208
+ import { createPortal } from "react-dom";
209
+ import { Fragment, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
210
+ var TOOLTIP_MAX_WIDTH = 288;
211
+ var TOOLTIP_VIEWPORT_MARGIN = 12;
212
+ var Tooltip = ({
213
+ children,
214
+ content,
215
+ align = "start",
216
+ ariaLabel,
217
+ clampToViewport = true,
218
+ className,
219
+ maxWidth = TOOLTIP_MAX_WIDTH,
220
+ onClick,
221
+ stopClickPropagation = true,
222
+ style,
223
+ tapEnabled = false,
224
+ triggerAs = "button",
225
+ displayContents = false
226
+ }) => {
227
+ const [showTooltip, setShowTooltip] = useState(false);
228
+ const [tooltipPosition, setTooltipPosition] = useState({
229
+ top: 0,
230
+ left: 0,
231
+ maxWidth
232
+ });
233
+ const triggerRef = useRef(null);
234
+ const tapPinnedRef = useRef(false);
235
+ const tooltipId = useId();
236
+ const closeTooltip = () => {
237
+ tapPinnedRef.current = false;
238
+ setShowTooltip(false);
239
+ };
240
+ useEffect(() => {
241
+ if (!showTooltip) return;
242
+ const dismissOnOutsideTap = (event) => {
243
+ if (triggerRef.current?.contains(event.target)) return;
244
+ tapPinnedRef.current = false;
245
+ setShowTooltip(false);
246
+ };
247
+ const dismissOnEscape = (event) => {
248
+ if (event.key !== "Escape") return;
249
+ tapPinnedRef.current = false;
250
+ setShowTooltip(false);
251
+ };
252
+ const dismissOnViewportChange = () => {
253
+ tapPinnedRef.current = false;
254
+ setShowTooltip(false);
255
+ };
256
+ document.addEventListener("pointerdown", dismissOnOutsideTap);
257
+ document.addEventListener("keydown", dismissOnEscape);
258
+ window.addEventListener("scroll", dismissOnViewportChange, {
259
+ capture: true,
260
+ passive: true
261
+ });
262
+ window.addEventListener("resize", dismissOnViewportChange);
263
+ return () => {
264
+ document.removeEventListener("pointerdown", dismissOnOutsideTap);
265
+ document.removeEventListener("keydown", dismissOnEscape);
266
+ window.removeEventListener("scroll", dismissOnViewportChange, true);
267
+ window.removeEventListener("resize", dismissOnViewportChange);
268
+ };
269
+ }, [showTooltip]);
270
+ const updateTooltipPosition = () => {
271
+ if (triggerRef.current) {
272
+ const rect = triggerRef.current.getBoundingClientRect();
273
+ const availableMaxWidth = Math.min(
274
+ maxWidth,
275
+ window.innerWidth - TOOLTIP_VIEWPORT_MARGIN * 2
276
+ );
277
+ let left = align === "center" ? rect.left + rect.width / 2 : rect.left;
278
+ let transform = align === "center" ? "translateX(-50%)" : void 0;
279
+ if (clampToViewport) {
280
+ left = Math.min(
281
+ Math.max(rect.left, TOOLTIP_VIEWPORT_MARGIN),
282
+ Math.max(
283
+ TOOLTIP_VIEWPORT_MARGIN,
284
+ window.innerWidth - availableMaxWidth - TOOLTIP_VIEWPORT_MARGIN
285
+ )
286
+ );
287
+ transform = void 0;
288
+ }
289
+ setTooltipPosition({
290
+ top: rect.bottom + 4,
291
+ left,
292
+ maxWidth: availableMaxWidth,
293
+ transform
294
+ });
295
+ }
296
+ };
297
+ const triggerClassName = cn(
298
+ "polli-control polli:relative polli:cursor-help polli:text-left polli:inline-flex polli:items-center",
299
+ className
300
+ );
301
+ const cursorClass = displayContents ? "polli:contents" : "polli:cursor-inherit";
302
+ const popupClasses = "polli:fixed polli:w-max polli:px-2 polli:py-1 polli:bg-surface-menu polli:text-theme-text-base polli:font-normal polli:leading-snug polli:tracking-normal polli:normal-case polli:not-italic polli:text-xs polli:rounded-md polli:shadow-md polli:z-[130] polli:pointer-events-none polli:transition-opacity polli:whitespace-pre-line polli:break-words";
303
+ const popupNode = content ? /* @__PURE__ */ jsx4(
304
+ "span",
305
+ {
306
+ id: tooltipId,
307
+ role: "tooltip",
308
+ "aria-hidden": !showTooltip,
309
+ style: {
310
+ top: tooltipPosition.top,
311
+ left: tooltipPosition.left,
312
+ maxWidth: tooltipPosition.maxWidth,
313
+ transform: tooltipPosition.transform
314
+ },
315
+ className: `${showTooltip ? "polli:visible polli:opacity-100" : "polli:invisible polli:opacity-0"} ${popupClasses}`,
316
+ children: content
317
+ }
318
+ ) : null;
319
+ const tooltipPopup = popupNode && typeof document !== "undefined" ? createPortal(
320
+ popupNode,
321
+ triggerRef.current?.closest('[role="dialog"]') ?? document.body
322
+ ) : popupNode;
323
+ const contentNode = /* @__PURE__ */ jsxs4(Fragment, { children: [
324
+ /* @__PURE__ */ jsx4("span", { className: cursorClass, children }),
325
+ tooltipPopup
326
+ ] });
327
+ const sharedProps = {
328
+ "aria-label": ariaLabel,
329
+ "aria-describedby": content && showTooltip ? tooltipId : void 0,
330
+ className: triggerClassName,
331
+ onMouseEnter: () => {
332
+ updateTooltipPosition();
333
+ setShowTooltip(true);
334
+ },
335
+ onMouseLeave: () => {
336
+ if (!tapPinnedRef.current) setShowTooltip(false);
337
+ },
338
+ onClick: (e) => {
339
+ if (stopClickPropagation) e.stopPropagation();
340
+ if (onClick) {
341
+ onClick();
342
+ }
343
+ if (!tapEnabled || !content) return;
344
+ updateTooltipPosition();
345
+ if (tapPinnedRef.current) {
346
+ closeTooltip();
347
+ return;
348
+ }
349
+ tapPinnedRef.current = true;
350
+ setShowTooltip(true);
351
+ },
352
+ onFocus: () => {
353
+ updateTooltipPosition();
354
+ setShowTooltip(true);
355
+ },
356
+ onBlur: closeTooltip,
357
+ style
358
+ };
359
+ if (triggerAs === "span") {
360
+ const handleKeyDown = (event) => {
361
+ if (!tapEnabled || !content) return;
362
+ if (event.key !== "Enter" && event.key !== " ") return;
363
+ event.preventDefault();
364
+ updateTooltipPosition();
365
+ if (tapPinnedRef.current) {
366
+ closeTooltip();
367
+ return;
368
+ }
369
+ tapPinnedRef.current = true;
370
+ setShowTooltip(true);
371
+ };
372
+ const spanInteractionProps = {
373
+ ...sharedProps,
374
+ role: tapEnabled && content ? "button" : void 0,
375
+ tabIndex: tapEnabled && content ? 0 : void 0,
376
+ onKeyDown: tapEnabled && content ? handleKeyDown : void 0
377
+ };
378
+ return /* @__PURE__ */ jsx4(
379
+ "span",
380
+ {
381
+ ref: (node) => {
382
+ triggerRef.current = node;
383
+ },
384
+ ...spanInteractionProps,
385
+ children: contentNode
386
+ }
387
+ );
388
+ }
389
+ return /* @__PURE__ */ jsx4(
390
+ "button",
391
+ {
392
+ ref: (node) => {
393
+ triggerRef.current = node;
394
+ },
395
+ type: "button",
396
+ "aria-label": ariaLabel,
397
+ "aria-describedby": content && showTooltip ? tooltipId : void 0,
398
+ className: triggerClassName,
399
+ onMouseEnter: sharedProps.onMouseEnter,
400
+ onMouseLeave: sharedProps.onMouseLeave,
401
+ onClick: sharedProps.onClick,
402
+ onFocus: sharedProps.onFocus,
403
+ onBlur: sharedProps.onBlur,
404
+ style,
405
+ children: contentNode
406
+ }
407
+ );
408
+ };
409
+
410
+ // src/compositions/CopyButton.tsx
411
+ import { jsx as jsx5 } from "react/jsx-runtime";
412
+ function CopyButton({
413
+ value,
414
+ children,
415
+ copiedTimeoutMs = 2e3,
416
+ tooltip = "\u{1F4CB} Click to copy",
417
+ tooltipAlign,
418
+ tooltipClampToViewport,
419
+ tooltipMaxWidth,
420
+ copiedTooltip = "\u2705 Copied!",
421
+ tooltipClassName,
422
+ className,
423
+ variant = "plain",
424
+ intent,
425
+ onCopied,
426
+ onCopyError,
427
+ ...buttonProps
428
+ }) {
429
+ const [copied, setCopied] = useState2(false);
430
+ const timeoutRef = useRef2(null);
431
+ useEffect2(
432
+ () => () => {
433
+ if (timeoutRef.current) clearTimeout(timeoutRef.current);
434
+ },
435
+ []
436
+ );
437
+ async function handleCopy(event) {
438
+ event.stopPropagation();
439
+ try {
440
+ const text = typeof value === "function" ? await value() : value;
441
+ await navigator.clipboard.writeText(text);
442
+ setCopied(true);
443
+ onCopied?.();
444
+ if (timeoutRef.current) clearTimeout(timeoutRef.current);
445
+ timeoutRef.current = setTimeout(
446
+ () => setCopied(false),
447
+ copiedTimeoutMs
448
+ );
449
+ } catch (error) {
450
+ onCopyError?.(error);
451
+ }
452
+ }
453
+ const Control = variant === "button" ? Button : "button";
454
+ const button = /* @__PURE__ */ jsx5(
455
+ Control,
456
+ {
457
+ ...buttonProps,
458
+ ...variant === "button" && intent ? { intent } : {},
459
+ type: "button",
460
+ onClick: handleCopy,
461
+ className: cn(
462
+ "polli-control",
463
+ buttonProps.disabled ? "polli:cursor-not-allowed" : "polli:cursor-pointer",
464
+ typeof className === "function" ? className(copied) : className
465
+ ),
466
+ children: typeof children === "function" ? children(copied) : children
467
+ }
468
+ );
469
+ if (tooltip === null) {
470
+ return button;
471
+ }
472
+ return /* @__PURE__ */ jsx5(
473
+ Tooltip,
474
+ {
475
+ triggerAs: "span",
476
+ content: copied ? copiedTooltip : tooltip,
477
+ align: tooltipAlign,
478
+ clampToViewport: tooltipClampToViewport,
479
+ maxWidth: tooltipMaxWidth,
480
+ displayContents: true,
481
+ tapEnabled: false,
482
+ className: cn(
483
+ buttonProps.disabled ? "polli:cursor-not-allowed" : "polli:cursor-pointer",
484
+ tooltipClassName
485
+ ),
486
+ children: button
487
+ }
488
+ );
489
+ }
490
+
491
+ // src/compositions/CodeBlock.tsx
492
+ import { Fragment as Fragment2, jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
493
+ var CodeBlock = ({
494
+ code,
495
+ codeClassName,
496
+ language,
497
+ className,
498
+ ...rest
499
+ }) => {
500
+ const label = language || "Code";
501
+ return /* @__PURE__ */ jsxs5(
502
+ "div",
503
+ {
504
+ ...rest,
505
+ className: cn(
506
+ "polli:min-w-0 polli:max-w-full polli:overflow-hidden polli:rounded-lg polli:border polli:border-theme-border polli:bg-theme-bg-pale",
507
+ className
508
+ ),
509
+ children: [
510
+ /* @__PURE__ */ jsxs5("div", { className: "polli:flex polli:min-h-9 polli:items-center polli:justify-between polli:gap-3 polli:bg-theme-bg-subtle polli:px-3 polli:py-1.5", children: [
511
+ /* @__PURE__ */ jsx6("span", { className: "polli:truncate polli:font-mono polli:text-[11px] polli:font-medium polli:uppercase polli:tracking-wide polli:text-theme-text-muted", children: label }),
512
+ /* @__PURE__ */ jsx6(
513
+ CopyButton,
514
+ {
515
+ value: code,
516
+ tooltip: null,
517
+ "aria-label": "Copy code",
518
+ className: "polli:flex polli:items-center polli:gap-1.5 polli:rounded-md polli:px-2 polli:py-1 polli:text-xs polli:font-medium polli:text-theme-text-base polli:transition-colors polli:hover:bg-theme-bg-hover polli:hover:text-theme-text-hover",
519
+ children: (copied) => /* @__PURE__ */ jsxs5(Fragment2, { children: [
520
+ copied ? /* @__PURE__ */ jsx6(CheckIcon, { className: "polli:size-3.5" }) : /* @__PURE__ */ jsx6(ClipboardIcon, { className: "polli:size-3.5" }),
521
+ /* @__PURE__ */ jsx6("span", { children: copied ? "Copied" : "Copy" })
522
+ ] })
523
+ }
524
+ )
525
+ ] }),
526
+ /* @__PURE__ */ jsx6(
527
+ "pre",
528
+ {
529
+ className: cn(
530
+ "polli:m-0 polli:min-w-0 polli:whitespace-pre-wrap polli:break-words polli:[overflow-wrap:anywhere] polli:[tab-size:4] polli:p-3 polli:font-mono polli:text-xs polli:leading-6 polli:text-theme-text-strong",
531
+ codeClassName
532
+ ),
533
+ children: /* @__PURE__ */ jsx6("code", { children: code })
534
+ }
535
+ )
536
+ ]
537
+ }
538
+ );
539
+ };
540
+
541
+ // src/compositions/Markdown.tsx
542
+ import { jsx as jsx7 } from "react/jsx-runtime";
543
+ function textContent(value) {
544
+ if (typeof value === "string" || typeof value === "number") {
545
+ return String(value);
546
+ }
547
+ if (Array.isArray(value)) return value.map(textContent).join("");
548
+ if (isValidElement(value)) {
549
+ return textContent(value.props.children);
550
+ }
551
+ return "";
552
+ }
553
+ var VIDEO_EXTENSIONS = /* @__PURE__ */ new Set(["m4v", "mov", "mp4", "webm"]);
554
+ var AUDIO_EXTENSIONS = /* @__PURE__ */ new Set([
555
+ "aac",
556
+ "flac",
557
+ "m4a",
558
+ "mp3",
559
+ "ogg",
560
+ "opus",
561
+ "wav"
562
+ ]);
563
+ function urlExtension(src) {
564
+ const path = src.split(/[?#]/, 1)[0];
565
+ return path.split(".").pop()?.toLowerCase() ?? "";
566
+ }
567
+ function inlineMedia(src, label) {
568
+ if (!src) return null;
569
+ const extension = urlExtension(src);
570
+ const video = VIDEO_EXTENSIONS.has(extension) || label === "Generated video";
571
+ const audio = AUDIO_EXTENSIONS.has(extension) || label === "Generated audio";
572
+ if (!video && !audio) return null;
573
+ const Element = video ? "video" : "audio";
574
+ return /* @__PURE__ */ jsx7(
575
+ Element,
576
+ {
577
+ src,
578
+ "aria-label": label,
579
+ controls: true,
580
+ playsInline: video || void 0,
581
+ preload: "metadata",
582
+ className: "polli:max-w-full polli:rounded-lg"
583
+ }
584
+ );
585
+ }
586
+ function MarkdownCodeBlock({ children }) {
587
+ const child = isValidElement(children) ? children : null;
588
+ const language = child?.props.className?.match(/language-([^\s]+)/)?.[1];
589
+ const code = textContent(child?.props.children ?? children).replace(
590
+ /\n$/,
591
+ ""
592
+ );
593
+ return /* @__PURE__ */ jsx7(CodeBlock, { code, language, className: "polli:my-3" });
594
+ }
595
+ var components = {
596
+ ul: ({ node, ...props }) => /* @__PURE__ */ jsx7(
597
+ "ul",
598
+ {
599
+ className: "polli:flex polli:min-w-0 polli:list-disc polli:flex-col polli:gap-1 polli:pl-5 polli:marker:text-theme-text-muted",
600
+ ...props
601
+ }
602
+ ),
603
+ ol: ({ node, ...props }) => /* @__PURE__ */ jsx7(
604
+ "ol",
605
+ {
606
+ className: "polli:flex polli:min-w-0 polli:list-decimal polli:flex-col polli:gap-1 polli:pl-5 polli:marker:text-theme-text-muted",
607
+ ...props
608
+ }
609
+ ),
610
+ p: ({ node, ...props }) => /* @__PURE__ */ jsx7("p", { className: "polli:mb-2 polli:last:mb-0", ...props }),
611
+ strong: ({ node, ...props }) => /* @__PURE__ */ jsx7(
612
+ "strong",
613
+ {
614
+ className: "polli:font-semibold polli:text-theme-text-strong",
615
+ ...props
616
+ }
617
+ ),
618
+ code: ({ node, ...props }) => /* @__PURE__ */ jsx7(
619
+ "code",
620
+ {
621
+ className: "polli:break-words polli:rounded polli:bg-theme-bg-subtle polli:px-1 polli:py-0.5 polli:font-mono polli:text-xs",
622
+ ...props
623
+ }
624
+ ),
625
+ pre: ({ children }) => /* @__PURE__ */ jsx7(MarkdownCodeBlock, { children }),
626
+ img: ({ node, src, alt, ...props }) => {
627
+ const media = inlineMedia(
628
+ typeof src === "string" ? src : void 0,
629
+ alt
630
+ );
631
+ if (media) return media;
632
+ return /* @__PURE__ */ jsx7(
633
+ "img",
634
+ {
635
+ src,
636
+ alt,
637
+ loading: "lazy",
638
+ className: "polli:max-w-full polli:rounded-lg",
639
+ ...props
640
+ }
641
+ );
642
+ },
643
+ a: ({ node, href, ...props }) => {
644
+ const media = inlineMedia(href, textContent(props.children));
645
+ if (media) return media;
646
+ return /* @__PURE__ */ jsx7(InlineLink, { href, ...props });
647
+ }
648
+ };
649
+ function Markdown({ children, className }) {
650
+ return /* @__PURE__ */ jsx7(
651
+ "div",
652
+ {
653
+ className: cn(
654
+ "polli:min-w-0 polli:font-body polli:leading-relaxed",
655
+ className
656
+ ),
657
+ children: /* @__PURE__ */ jsx7(ReactMarkdown, { remarkPlugins: [remarkGfm], components, children })
658
+ }
659
+ );
660
+ }
661
+
662
+ // src/compositions/Prose.tsx
663
+ import Markdown2 from "react-markdown";
664
+ import rehypeSlug from "rehype-slug";
665
+ import remarkGfm2 from "remark-gfm";
666
+
667
+ // src/primitives/Typography.tsx
668
+ import { jsx as jsx8 } from "react/jsx-runtime";
669
+ var headingSizeClasses = {
670
+ display: "polli:font-heading polli:text-5xl polli:leading-none",
671
+ title: "polli:font-heading polli:text-4xl polli:leading-none",
672
+ section: "polli:font-subheading polli:text-2xl polli:leading-tight",
673
+ subsection: "polli:font-subheading polli:text-xl polli:leading-tight",
674
+ card: "polli:font-subheading polli:text-lg polli:leading-tight"
675
+ };
676
+ function headingClassName(size, className) {
677
+ return cn(
678
+ "polli:break-words polli:text-theme-text-strong",
679
+ headingSizeClasses[size],
680
+ className
681
+ );
682
+ }
683
+
684
+ // src/compositions/Prose.tsx
685
+ import { jsx as jsx9 } from "react/jsx-runtime";
686
+ var components2 = {
687
+ h1: ({ node, ...props }) => /* @__PURE__ */ jsx9(
688
+ "h1",
689
+ {
690
+ className: headingClassName("title", "polli:mt-0 polli:mb-5"),
691
+ ...props
692
+ }
693
+ ),
694
+ h2: ({ node, ...props }) => /* @__PURE__ */ jsx9(
695
+ "h2",
696
+ {
697
+ className: headingClassName("section", "polli:mt-8 polli:mb-3"),
698
+ ...props
699
+ }
700
+ ),
701
+ h3: ({ node, ...props }) => /* @__PURE__ */ jsx9(
702
+ "h3",
703
+ {
704
+ className: headingClassName("subsection", "polli:mt-6 polli:mb-2"),
705
+ ...props
706
+ }
707
+ ),
708
+ p: ({ node, ...props }) => /* @__PURE__ */ jsx9("p", { className: "polli:my-4 polli:leading-relaxed", ...props }),
709
+ a: ({ node, ...props }) => /* @__PURE__ */ jsx9(InlineLink, { ...props }),
710
+ ul: ({ node, ...props }) => /* @__PURE__ */ jsx9(
711
+ "ul",
712
+ {
713
+ className: "polli:my-4 polli:list-disc polli:pl-6 polli:leading-relaxed",
714
+ ...props
715
+ }
716
+ ),
717
+ ol: ({ node, ...props }) => /* @__PURE__ */ jsx9(
718
+ "ol",
719
+ {
720
+ className: "polli:my-4 polli:list-decimal polli:pl-6 polli:leading-relaxed",
721
+ ...props
722
+ }
723
+ ),
724
+ blockquote: ({ node, ...props }) => /* @__PURE__ */ jsx9(
725
+ "blockquote",
726
+ {
727
+ className: "polli:my-4 polli:border-l-4 polli:border-theme-border polli:pl-4 polli:text-theme-text-soft",
728
+ ...props
729
+ }
730
+ ),
731
+ code: ({ node, ...props }) => /* @__PURE__ */ jsx9(
732
+ "code",
733
+ {
734
+ className: "polli:rounded polli:bg-theme-bg-active polli:px-1 polli:py-0.5 polli:font-pixel polli:text-sm",
735
+ ...props
736
+ }
737
+ ),
738
+ pre: ({ node, ...props }) => /* @__PURE__ */ jsx9(
739
+ "pre",
740
+ {
741
+ className: "polli:my-4 polli:overflow-x-auto polli:rounded-lg polli:bg-theme-bg-active polli:p-4",
742
+ ...props
743
+ }
744
+ ),
745
+ table: ({ node, ...props }) => /* @__PURE__ */ jsx9(
746
+ "table",
747
+ {
748
+ className: "polli:my-4 polli:w-full polli:border-collapse polli:text-sm",
749
+ ...props
750
+ }
751
+ ),
752
+ th: ({ node, ...props }) => /* @__PURE__ */ jsx9(
753
+ "th",
754
+ {
755
+ className: "polli:border polli:border-theme-border polli:px-3 polli:py-2 polli:text-left polli:font-semibold",
756
+ ...props
757
+ }
758
+ ),
759
+ td: ({ node, ...props }) => /* @__PURE__ */ jsx9(
760
+ "td",
761
+ {
762
+ className: "polli:border polli:border-theme-border polli:px-3 polli:py-2",
763
+ ...props
764
+ }
765
+ ),
766
+ hr: ({ node, ...props }) => /* @__PURE__ */ jsx9("hr", { className: "polli:my-6 polli:border-theme-border", ...props })
767
+ };
768
+ function Prose({ children, className }) {
769
+ return /* @__PURE__ */ jsx9(
770
+ "div",
771
+ {
772
+ className: cn(
773
+ "polli:font-body polli:text-theme-text-base polli:leading-relaxed",
774
+ className
775
+ ),
776
+ children: /* @__PURE__ */ jsx9(
777
+ Markdown2,
778
+ {
779
+ remarkPlugins: [remarkGfm2],
780
+ rehypePlugins: [rehypeSlug],
781
+ components: components2,
782
+ children
783
+ }
784
+ )
785
+ }
786
+ );
787
+ }
788
+ export {
789
+ Markdown,
790
+ Prose
791
+ };
792
+ //# sourceMappingURL=markdown.js.map