@codrstudio/openclaude-chat 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (171) hide show
  1. package/dist/components/Chat.d.ts +23 -0
  2. package/dist/components/Chat.js +12 -0
  3. package/dist/components/ErrorNote.d.ts +6 -0
  4. package/dist/components/ErrorNote.js +6 -0
  5. package/dist/components/LazyRender.d.ts +8 -0
  6. package/dist/components/LazyRender.js +22 -0
  7. package/dist/components/Markdown.d.ts +5 -0
  8. package/dist/components/Markdown.js +65 -0
  9. package/dist/components/MessageBubble.d.ts +9 -0
  10. package/dist/components/MessageBubble.js +45 -0
  11. package/dist/components/MessageInput.d.ts +19 -0
  12. package/dist/components/MessageInput.js +214 -0
  13. package/dist/components/MessageList.d.ts +13 -0
  14. package/dist/components/MessageList.js +72 -0
  15. package/dist/components/StreamingIndicator.d.ts +1 -0
  16. package/dist/components/StreamingIndicator.js +9 -0
  17. package/dist/display/AlertRenderer.d.ts +2 -0
  18. package/dist/display/AlertRenderer.js +13 -0
  19. package/dist/display/CarouselRenderer.d.ts +2 -0
  20. package/dist/display/CarouselRenderer.js +41 -0
  21. package/dist/display/ChartRenderer.d.ts +2 -0
  22. package/dist/display/ChartRenderer.js +76 -0
  23. package/dist/display/ChoiceButtonsRenderer.d.ts +6 -0
  24. package/dist/display/ChoiceButtonsRenderer.js +23 -0
  25. package/dist/display/CodeBlockRenderer.d.ts +2 -0
  26. package/dist/display/CodeBlockRenderer.js +17 -0
  27. package/dist/display/ComparisonTableRenderer.d.ts +2 -0
  28. package/dist/display/ComparisonTableRenderer.js +26 -0
  29. package/dist/display/DataTableRenderer.d.ts +2 -0
  30. package/dist/display/DataTableRenderer.js +74 -0
  31. package/dist/display/DisplayReactRenderer.d.ts +26 -0
  32. package/dist/display/DisplayReactRenderer.js +192 -0
  33. package/dist/display/FileCardRenderer.d.ts +2 -0
  34. package/dist/display/FileCardRenderer.js +31 -0
  35. package/dist/display/GalleryRenderer.d.ts +2 -0
  36. package/dist/display/GalleryRenderer.js +11 -0
  37. package/dist/display/ImageViewerRenderer.d.ts +2 -0
  38. package/dist/display/ImageViewerRenderer.js +15 -0
  39. package/dist/display/LinkPreviewRenderer.d.ts +2 -0
  40. package/dist/display/LinkPreviewRenderer.js +20 -0
  41. package/dist/display/MapViewRenderer.d.ts +2 -0
  42. package/dist/display/MapViewRenderer.js +20 -0
  43. package/dist/display/MetricCardRenderer.d.ts +2 -0
  44. package/dist/display/MetricCardRenderer.js +12 -0
  45. package/dist/display/PriceHighlightRenderer.d.ts +2 -0
  46. package/dist/display/PriceHighlightRenderer.js +30 -0
  47. package/dist/display/ProductCardRenderer.d.ts +2 -0
  48. package/dist/display/ProductCardRenderer.js +23 -0
  49. package/dist/display/ProgressStepsRenderer.d.ts +2 -0
  50. package/dist/display/ProgressStepsRenderer.js +14 -0
  51. package/dist/display/SourcesListRenderer.d.ts +2 -0
  52. package/dist/display/SourcesListRenderer.js +5 -0
  53. package/dist/display/SpreadsheetRenderer.d.ts +2 -0
  54. package/dist/display/SpreadsheetRenderer.js +32 -0
  55. package/dist/display/StepTimelineRenderer.d.ts +2 -0
  56. package/dist/display/StepTimelineRenderer.js +21 -0
  57. package/dist/display/index.d.ts +21 -0
  58. package/dist/display/index.js +20 -0
  59. package/dist/display/react-sandbox/bootstrap.d.ts +1 -0
  60. package/dist/display/react-sandbox/bootstrap.js +154 -0
  61. package/dist/display/registry.d.ts +5 -0
  62. package/dist/display/registry.js +52 -0
  63. package/dist/display/sdk-types.d.ts +187 -0
  64. package/dist/display/sdk-types.js +4 -0
  65. package/dist/hooks/ChatProvider.d.ts +9 -0
  66. package/dist/hooks/ChatProvider.js +14 -0
  67. package/dist/hooks/useIsMobile.d.ts +1 -0
  68. package/dist/hooks/useIsMobile.js +12 -0
  69. package/dist/hooks/useOpenClaudeChat.d.ts +36 -0
  70. package/dist/hooks/useOpenClaudeChat.js +361 -0
  71. package/dist/index.d.ts +47 -0
  72. package/dist/index.js +42 -0
  73. package/dist/lib/utils.d.ts +2 -0
  74. package/dist/lib/utils.js +5 -0
  75. package/dist/parts/PartErrorBoundary.d.ts +21 -0
  76. package/dist/parts/PartErrorBoundary.js +27 -0
  77. package/dist/parts/PartRenderer.d.ts +8 -0
  78. package/dist/parts/PartRenderer.js +99 -0
  79. package/dist/parts/ReasoningBlock.d.ts +6 -0
  80. package/dist/parts/ReasoningBlock.js +18 -0
  81. package/dist/parts/ToolActivity.d.ts +11 -0
  82. package/dist/parts/ToolActivity.js +52 -0
  83. package/dist/parts/ToolResult.d.ts +7 -0
  84. package/dist/parts/ToolResult.js +38 -0
  85. package/dist/styles.css +2 -0
  86. package/dist/types.d.ts +40 -0
  87. package/dist/types.js +4 -0
  88. package/dist/ui/alert.d.ts +12 -0
  89. package/dist/ui/alert.js +28 -0
  90. package/dist/ui/badge.d.ts +9 -0
  91. package/dist/ui/badge.js +20 -0
  92. package/dist/ui/button.d.ts +11 -0
  93. package/dist/ui/button.js +31 -0
  94. package/dist/ui/card.d.ts +8 -0
  95. package/dist/ui/card.js +21 -0
  96. package/dist/ui/collapsible.d.ts +1 -0
  97. package/dist/ui/collapsible.js +2 -0
  98. package/dist/ui/dialog.d.ts +19 -0
  99. package/dist/ui/dialog.js +23 -0
  100. package/dist/ui/dropdown-menu.d.ts +11 -0
  101. package/dist/ui/dropdown-menu.js +15 -0
  102. package/dist/ui/input.d.ts +3 -0
  103. package/dist/ui/input.js +6 -0
  104. package/dist/ui/progress.d.ts +7 -0
  105. package/dist/ui/progress.js +9 -0
  106. package/dist/ui/scroll-area.d.ts +5 -0
  107. package/dist/ui/scroll-area.js +12 -0
  108. package/dist/ui/separator.d.ts +4 -0
  109. package/dist/ui/separator.js +8 -0
  110. package/dist/ui/skeleton.d.ts +3 -0
  111. package/dist/ui/skeleton.js +6 -0
  112. package/dist/ui/table.d.ts +10 -0
  113. package/dist/ui/table.js +27 -0
  114. package/package.json +61 -0
  115. package/src/components/Chat.tsx +107 -0
  116. package/src/components/ErrorNote.tsx +35 -0
  117. package/src/components/LazyRender.tsx +42 -0
  118. package/src/components/Markdown.tsx +114 -0
  119. package/src/components/MessageBubble.tsx +107 -0
  120. package/src/components/MessageInput.tsx +421 -0
  121. package/src/components/MessageList.tsx +153 -0
  122. package/src/components/StreamingIndicator.tsx +19 -0
  123. package/src/display/AlertRenderer.tsx +23 -0
  124. package/src/display/CarouselRenderer.tsx +141 -0
  125. package/src/display/ChartRenderer.tsx +195 -0
  126. package/src/display/ChoiceButtonsRenderer.tsx +114 -0
  127. package/src/display/CodeBlockRenderer.tsx +49 -0
  128. package/src/display/ComparisonTableRenderer.tsx +132 -0
  129. package/src/display/DataTableRenderer.tsx +144 -0
  130. package/src/display/DisplayReactRenderer.tsx +269 -0
  131. package/src/display/FileCardRenderer.tsx +55 -0
  132. package/src/display/GalleryRenderer.tsx +65 -0
  133. package/src/display/ImageViewerRenderer.tsx +114 -0
  134. package/src/display/LinkPreviewRenderer.tsx +74 -0
  135. package/src/display/MapViewRenderer.tsx +75 -0
  136. package/src/display/MetricCardRenderer.tsx +29 -0
  137. package/src/display/PriceHighlightRenderer.tsx +62 -0
  138. package/src/display/ProductCardRenderer.tsx +112 -0
  139. package/src/display/ProgressStepsRenderer.tsx +59 -0
  140. package/src/display/SourcesListRenderer.tsx +47 -0
  141. package/src/display/SpreadsheetRenderer.tsx +86 -0
  142. package/src/display/StepTimelineRenderer.tsx +75 -0
  143. package/src/display/index.ts +21 -0
  144. package/src/display/react-sandbox/bootstrap.ts +155 -0
  145. package/src/display/registry.ts +84 -0
  146. package/src/display/sdk-types.ts +217 -0
  147. package/src/hooks/ChatProvider.tsx +21 -0
  148. package/src/hooks/useIsMobile.ts +15 -0
  149. package/src/hooks/useOpenClaudeChat.ts +476 -0
  150. package/src/index.ts +76 -0
  151. package/src/lib/utils.ts +6 -0
  152. package/src/parts/PartErrorBoundary.tsx +51 -0
  153. package/src/parts/PartRenderer.tsx +145 -0
  154. package/src/parts/ReasoningBlock.tsx +41 -0
  155. package/src/parts/ToolActivity.tsx +78 -0
  156. package/src/parts/ToolResult.tsx +79 -0
  157. package/src/styles.css +2 -0
  158. package/src/types.ts +41 -0
  159. package/src/ui/alert.tsx +77 -0
  160. package/src/ui/badge.tsx +36 -0
  161. package/src/ui/button.tsx +54 -0
  162. package/src/ui/card.tsx +68 -0
  163. package/src/ui/collapsible.tsx +7 -0
  164. package/src/ui/dialog.tsx +122 -0
  165. package/src/ui/dropdown-menu.tsx +76 -0
  166. package/src/ui/input.tsx +24 -0
  167. package/src/ui/progress.tsx +36 -0
  168. package/src/ui/scroll-area.tsx +48 -0
  169. package/src/ui/separator.tsx +31 -0
  170. package/src/ui/skeleton.tsx +9 -0
  171. package/src/ui/table.tsx +114 -0
@@ -0,0 +1,12 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { ArrowDown, ArrowRight, ArrowUp } from "lucide-react";
3
+ import { Card } from "../ui/card.js";
4
+ const TREND_CONFIG = {
5
+ up: { Icon: ArrowUp, colorClass: "text-primary" },
6
+ down: { Icon: ArrowDown, colorClass: "text-destructive" },
7
+ neutral: { Icon: ArrowRight, colorClass: "text-muted-foreground" },
8
+ };
9
+ export function MetricCardRenderer({ label, value, unit, trend }) {
10
+ const trendConfig = trend ? TREND_CONFIG[trend.direction] : null;
11
+ return (_jsxs(Card, { className: "p-4 w-fit", children: [_jsx("p", { className: "text-sm text-muted-foreground", children: label }), _jsxs("div", { className: "flex items-baseline gap-2 mt-1", children: [_jsx("span", { className: "text-2xl font-bold text-foreground", children: value }), unit && _jsx("span", { className: "text-sm text-muted-foreground", children: unit })] }), trend && trendConfig && (_jsxs("div", { className: `flex items-center gap-1 mt-1 text-sm ${trendConfig.colorClass}`, children: [_jsx(trendConfig.Icon, { size: 14, "aria-hidden": "true" }), _jsx("span", { children: trend.value })] }))] }));
12
+ }
@@ -0,0 +1,2 @@
1
+ import type { DisplayPrice } from "./sdk-types.js";
2
+ export declare function PriceHighlightRenderer({ value, label, context, source, badge }: DisplayPrice): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,30 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { ExternalLink } from "lucide-react";
3
+ import { Badge } from "../ui/badge";
4
+ import { Card } from "../ui/card";
5
+ function formatPrice(value, currency) {
6
+ // Fallbacks defensivos: se o modelo nao enviar currency ou enviar um valor
7
+ // invalido (ex: string vazia), caimos num formato numerico simples em vez de
8
+ // crashar a arvore React com "Currency code is required".
9
+ try {
10
+ return new Intl.NumberFormat("pt-BR", {
11
+ style: "currency",
12
+ currency: currency || "BRL",
13
+ }).format(value);
14
+ }
15
+ catch {
16
+ return new Intl.NumberFormat("pt-BR").format(value);
17
+ }
18
+ }
19
+ export function PriceHighlightRenderer({ value, label, context, source, badge }) {
20
+ // Tambem aceita value como numero flat (modelo pode nao seguir schema exato).
21
+ const amount = typeof value === "number"
22
+ ? value
23
+ : typeof value === "object" && value !== null && "value" in value
24
+ ? value.value
25
+ : 0;
26
+ const currency = typeof value === "object" && value !== null && "currency" in value
27
+ ? value.currency
28
+ : undefined;
29
+ return (_jsxs(Card, { className: "p-4 space-y-1 w-fit", children: [_jsx("p", { className: "text-sm text-muted-foreground", children: label }), _jsxs("div", { className: "flex items-baseline gap-2", children: [_jsx("span", { className: "text-2xl font-bold text-foreground", children: formatPrice(amount, currency) }), badge && (_jsx(Badge, { variant: "destructive", children: badge.label }))] }), context && _jsx("p", { className: "text-sm text-muted-foreground", children: context }), source && (_jsxs("a", { href: source.url, target: "_blank", rel: "noopener noreferrer", className: "flex items-center gap-1.5 text-xs text-primary hover:underline", children: [source.favicon && (_jsx("img", { src: source.favicon, alt: "", width: 14, height: 14, "aria-hidden": "true" })), _jsx("span", { children: source.name }), _jsx(ExternalLink, { size: 12, "aria-hidden": "true" })] }))] }));
30
+ }
@@ -0,0 +1,2 @@
1
+ import type { DisplayProduct } from "./sdk-types.js";
2
+ export declare function ProductCardRenderer({ title, image, price, originalPrice, rating, badges, url, description, }: DisplayProduct): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,23 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState } from "react";
3
+ import { Star } from "lucide-react";
4
+ import { Card, CardContent, CardTitle } from "../ui/card.js";
5
+ import { Badge } from "../ui/badge.js";
6
+ import { Button } from "../ui/button.js";
7
+ import { cn } from "../lib/utils.js";
8
+ function StarRating({ score, count }) {
9
+ const fullStars = Math.floor(score);
10
+ const hasHalf = score - fullStars >= 0.5;
11
+ const emptyStars = 5 - fullStars - (hasHalf ? 1 : 0);
12
+ return (_jsxs("div", { className: "flex items-center gap-0.5 text-primary", "aria-label": `${score} de 5 estrelas (${count} avaliações)`, children: [Array.from({ length: fullStars }).map((_, i) => (_jsx(Star, { size: 14, fill: "currentColor" }, `f${i}`))), hasHalf && _jsx(Star, { size: 14, fill: "none" }), Array.from({ length: emptyStars }).map((_, i) => (_jsx(Star, { size: 14, fill: "none", className: "text-muted-foreground" }, `e${i}`))), _jsxs("span", { className: "text-xs text-muted-foreground ml-1", children: ["(", count, ")"] })] }));
13
+ }
14
+ function formatMoney(value, currency = "BRL") {
15
+ return new Intl.NumberFormat("pt-BR", { style: "currency", currency }).format(value);
16
+ }
17
+ export function ProductCardRenderer({ title, image, price, originalPrice, rating, badges, url, description, }) {
18
+ const [imgError, setImgError] = useState(false);
19
+ const discount = price && originalPrice && originalPrice.value > price.value
20
+ ? Math.round(((originalPrice.value - price.value) / originalPrice.value) * 100)
21
+ : null;
22
+ return (_jsxs(Card, { className: "overflow-hidden w-fit max-w-sm", children: [image && !imgError && (_jsxs("div", { className: "relative", children: [_jsx("img", { src: image, alt: title, className: cn("w-full aspect-video object-cover"), loading: "lazy", decoding: "async", onError: () => setImgError(true) }), discount !== null && (_jsxs(Badge, { variant: "destructive", className: "absolute top-2 right-2", children: ["-", discount, "%"] }))] })), _jsxs(CardContent, { className: "p-4 space-y-2", children: [badges && badges.length > 0 && (_jsx("div", { className: "flex flex-wrap gap-1", children: badges.map((b, i) => (_jsx(Badge, { variant: "secondary", children: b.label }, i))) })), _jsx(CardTitle, { className: "text-sm", children: title }), description && (_jsx("p", { className: "text-xs text-muted-foreground line-clamp-2", children: description })), rating && _jsx(StarRating, { score: rating.score, count: rating.count }), price && (_jsxs("div", { className: "flex items-baseline gap-2", children: [_jsx("span", { className: "text-lg font-bold", children: formatMoney(price.value, price.currency) }), originalPrice && (_jsx("span", { className: "text-sm text-muted-foreground line-through", children: formatMoney(originalPrice.value, originalPrice.currency) }))] })), url && (_jsx(Button, { className: "w-full", size: "sm", asChild: true, children: _jsx("a", { href: url, target: "_blank", rel: "noopener noreferrer", children: "Ver produto" }) }))] })] }));
23
+ }
@@ -0,0 +1,2 @@
1
+ import type { DisplayProgress } from "./sdk-types.js";
2
+ export declare function ProgressStepsRenderer({ title, steps }: DisplayProgress): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,14 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Check, Circle, Clock } from "lucide-react";
3
+ import { Progress } from "../ui/progress.js";
4
+ import { Badge } from "../ui/badge.js";
5
+ import { cn } from "../lib/utils.js";
6
+ export function ProgressStepsRenderer({ title, steps }) {
7
+ const completed = steps.filter((s) => s.status === "completed").length;
8
+ const percentage = steps.length > 0 ? Math.round((completed / steps.length) * 100) : 0;
9
+ return (_jsxs("div", { className: "space-y-3", children: [title && _jsx("p", { className: "font-medium text-foreground", children: title }), _jsxs("div", { className: "flex items-center gap-3", children: [_jsx(Progress, { value: percentage, className: "flex-1" }), _jsxs("span", { className: "text-sm text-muted-foreground tabular-nums", children: [percentage, "%"] })] }), _jsxs("p", { className: "text-sm text-muted-foreground", children: [completed, " de ", steps.length, " conclu\u00EDdos"] }), _jsx("ol", { className: "space-y-2", children: steps.map((step, index) => {
10
+ const isCompleted = step.status === "completed";
11
+ const isPending = step.status === "pending";
12
+ return (_jsxs("li", { className: "flex items-start gap-2", children: [_jsx("span", { "aria-hidden": "true", className: cn("mt-0.5 shrink-0", isCompleted ? "text-primary" : "text-muted-foreground"), children: isCompleted ? (_jsx(Check, { size: 16 })) : isPending ? (_jsx(Circle, { size: 16 })) : (_jsx(Clock, { size: 16 })) }), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("p", { className: cn("text-sm", isCompleted ? "text-foreground" : "text-muted-foreground"), children: step.label }), step.description && (_jsx("p", { className: "text-xs text-muted-foreground mt-0.5", children: step.description }))] }), _jsx(Badge, { variant: "secondary", className: "shrink-0 text-xs", children: index + 1 })] }, index));
13
+ }) })] }));
14
+ }
@@ -0,0 +1,2 @@
1
+ import type { DisplaySources } from "./sdk-types.js";
2
+ export declare function SourcesListRenderer({ label, sources }: DisplaySources): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,5 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { ExternalLink, Globe } from "lucide-react";
3
+ export function SourcesListRenderer({ label, sources }) {
4
+ return (_jsxs("div", { className: "space-y-2", children: [_jsx("p", { className: "text-xs font-medium text-muted-foreground uppercase tracking-wide", children: label }), _jsx("ol", { className: "space-y-1", children: sources.map((source, index) => (_jsx("li", { children: _jsxs("a", { href: source.url, target: "_blank", rel: "noopener noreferrer", className: "flex items-start gap-2 p-2 rounded-md hover:bg-muted text-sm", children: [_jsx("span", { className: "text-xs text-muted-foreground font-mono w-5 shrink-0 pt-0.5", children: index + 1 }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "flex items-center gap-1.5", children: [source.favicon ? (_jsx("img", { src: source.favicon, alt: "", width: 14, height: 14, className: "shrink-0", "aria-hidden": "true" })) : (_jsx(Globe, { size: 14, className: "shrink-0 text-muted-foreground", "aria-hidden": "true" })), _jsx("span", { className: "font-medium text-primary truncate", children: source.title }), _jsx(ExternalLink, { size: 12, className: "shrink-0 text-muted-foreground", "aria-hidden": "true" })] }), source.snippet && (_jsx("p", { className: "text-xs text-muted-foreground line-clamp-2 mt-0.5", children: source.snippet }))] })] }) }, index))) })] }));
5
+ }
@@ -0,0 +1,2 @@
1
+ import type { DisplaySpreadsheet } from "./sdk-types.js";
2
+ export declare function SpreadsheetRenderer({ title, headers, rows, format }: DisplaySpreadsheet): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,32 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { ScrollArea, ScrollBar } from "../ui/scroll-area.js";
3
+ import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "../ui/table.js";
4
+ import { cn } from "../lib/utils.js";
5
+ function formatCell(value, colIndex, moneyColumns = [], percentColumns = []) {
6
+ if (value === null || value === undefined)
7
+ return "";
8
+ if (typeof value === "number") {
9
+ if (moneyColumns.includes(colIndex)) {
10
+ return new Intl.NumberFormat("pt-BR", { style: "currency", currency: "BRL" }).format(value);
11
+ }
12
+ if (percentColumns.includes(colIndex)) {
13
+ return new Intl.NumberFormat("pt-BR", {
14
+ style: "percent",
15
+ minimumFractionDigits: 1,
16
+ maximumFractionDigits: 2,
17
+ }).format(value / 100);
18
+ }
19
+ return new Intl.NumberFormat("pt-BR").format(value);
20
+ }
21
+ return String(value);
22
+ }
23
+ export function SpreadsheetRenderer({ title, headers, rows, format }) {
24
+ const moneyColumns = format?.moneyColumns ?? [];
25
+ const percentColumns = format?.percentColumns ?? [];
26
+ return (_jsxs("div", { className: "space-y-2", children: [title && _jsx("h3", { className: "text-sm font-semibold text-foreground", children: title }), _jsxs(ScrollArea, { className: "w-full", children: [_jsxs(Table, { "aria-readonly": "true", children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { className: "text-muted-foreground font-normal text-center w-10", "aria-label": "Linha" }), headers.map((h, i) => (_jsx(TableHead, { className: "font-semibold", children: h }, i)))] }) }), _jsx(TableBody, { children: rows.map((row, ri) => (_jsxs(TableRow, { children: [_jsx(TableCell, { className: "text-center text-xs text-muted-foreground select-none", children: ri + 1 }), row.map((cell, ci) => {
27
+ const isMoney = moneyColumns.includes(ci);
28
+ const isPercent = percentColumns.includes(ci);
29
+ const isNumber = typeof cell === "number";
30
+ return (_jsx(TableCell, { className: cn((isMoney || isPercent || isNumber) && "text-right font-mono text-sm"), children: formatCell(cell, ci, moneyColumns, percentColumns) }, ci));
31
+ })] }, ri))) })] }), _jsx(ScrollBar, { orientation: "horizontal" })] })] }));
32
+ }
@@ -0,0 +1,2 @@
1
+ import type { DisplaySteps } from "./sdk-types.js";
2
+ export declare function StepTimelineRenderer({ title, steps, orientation }: DisplaySteps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,21 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { cn } from "../lib/utils";
3
+ import { Badge } from "../ui/badge";
4
+ const STATUS_CIRCLE = {
5
+ completed: "bg-primary text-primary-foreground",
6
+ current: "bg-primary/20 border border-primary",
7
+ pending: "bg-muted text-muted-foreground",
8
+ };
9
+ const STATUS_TITLE = {
10
+ completed: "text-foreground",
11
+ current: "text-primary",
12
+ pending: "text-muted-foreground",
13
+ };
14
+ export function StepTimelineRenderer({ title, steps, orientation }) {
15
+ const isVertical = orientation !== "horizontal";
16
+ return (_jsxs("div", { className: cn("flex", isVertical ? "flex-col gap-0" : "flex-row items-start gap-0"), children: [title && (_jsx("p", { className: "text-sm font-medium text-foreground mb-3", children: title })), steps.map((step, index) => {
17
+ const isLast = index === steps.length - 1;
18
+ const { status } = step;
19
+ return (_jsxs("div", { className: cn("flex", isVertical ? "flex-row gap-3" : "flex-col items-center gap-2 flex-1"), children: [_jsxs("div", { className: cn("flex", isVertical ? "flex-col items-center" : "flex-row items-center"), children: [_jsx("div", { className: cn("w-6 h-6 rounded-full flex items-center justify-center shrink-0", STATUS_CIRCLE[status]), children: _jsx(Badge, { variant: "secondary", className: "w-5 h-5 flex items-center justify-center rounded-full p-0 text-[10px] font-semibold border-0 bg-transparent text-inherit", children: index + 1 }) }), !isLast && (_jsx("div", { className: cn(isVertical ? "w-px h-6 bg-border" : "h-px w-full bg-border flex-1") }))] }), _jsxs("div", { className: cn("pb-4 flex-1 min-w-0", isLast && "pb-0", !isVertical && "text-center"), children: [_jsx("p", { className: cn("text-sm font-medium leading-none", STATUS_TITLE[status]), children: step.title }), step.description && (_jsx("p", { className: "text-xs text-muted-foreground mt-1", children: step.description }))] })] }, index));
20
+ })] }));
21
+ }
@@ -0,0 +1,21 @@
1
+ export { AlertRenderer } from "./AlertRenderer.js";
2
+ export { MetricCardRenderer } from "./MetricCardRenderer.js";
3
+ export { PriceHighlightRenderer } from "./PriceHighlightRenderer.js";
4
+ export { FileCardRenderer } from "./FileCardRenderer.js";
5
+ export { CodeBlockRenderer } from "./CodeBlockRenderer.js";
6
+ export { SourcesListRenderer } from "./SourcesListRenderer.js";
7
+ export { StepTimelineRenderer } from "./StepTimelineRenderer.js";
8
+ export { ProgressStepsRenderer } from "./ProgressStepsRenderer.js";
9
+ export { ChartRenderer } from "./ChartRenderer.js";
10
+ export { CarouselRenderer } from "./CarouselRenderer.js";
11
+ export { ProductCardRenderer } from "./ProductCardRenderer.js";
12
+ export { ComparisonTableRenderer } from "./ComparisonTableRenderer.js";
13
+ export { DataTableRenderer } from "./DataTableRenderer.js";
14
+ export { SpreadsheetRenderer } from "./SpreadsheetRenderer.js";
15
+ export { GalleryRenderer } from "./GalleryRenderer.js";
16
+ export { ImageViewerRenderer } from "./ImageViewerRenderer.js";
17
+ export { LinkPreviewRenderer } from "./LinkPreviewRenderer.js";
18
+ export { MapViewRenderer } from "./MapViewRenderer.js";
19
+ export { ChoiceButtonsRenderer } from "./ChoiceButtonsRenderer.js";
20
+ export { defaultDisplayRenderers, resolveDisplayRenderer } from "./registry.js";
21
+ export type { DisplayRendererMap, DisplayActionName } from "./registry.js";
@@ -0,0 +1,20 @@
1
+ export { AlertRenderer } from "./AlertRenderer.js";
2
+ export { MetricCardRenderer } from "./MetricCardRenderer.js";
3
+ export { PriceHighlightRenderer } from "./PriceHighlightRenderer.js";
4
+ export { FileCardRenderer } from "./FileCardRenderer.js";
5
+ export { CodeBlockRenderer } from "./CodeBlockRenderer.js";
6
+ export { SourcesListRenderer } from "./SourcesListRenderer.js";
7
+ export { StepTimelineRenderer } from "./StepTimelineRenderer.js";
8
+ export { ProgressStepsRenderer } from "./ProgressStepsRenderer.js";
9
+ export { ChartRenderer } from "./ChartRenderer.js";
10
+ export { CarouselRenderer } from "./CarouselRenderer.js";
11
+ export { ProductCardRenderer } from "./ProductCardRenderer.js";
12
+ export { ComparisonTableRenderer } from "./ComparisonTableRenderer.js";
13
+ export { DataTableRenderer } from "./DataTableRenderer.js";
14
+ export { SpreadsheetRenderer } from "./SpreadsheetRenderer.js";
15
+ export { GalleryRenderer } from "./GalleryRenderer.js";
16
+ export { ImageViewerRenderer } from "./ImageViewerRenderer.js";
17
+ export { LinkPreviewRenderer } from "./LinkPreviewRenderer.js";
18
+ export { MapViewRenderer } from "./MapViewRenderer.js";
19
+ export { ChoiceButtonsRenderer } from "./ChoiceButtonsRenderer.js";
20
+ export { defaultDisplayRenderers, resolveDisplayRenderer } from "./registry.js";
@@ -0,0 +1 @@
1
+ export declare const SANDBOX_BOOTSTRAP = "\n(function() {\n var WHITELIST = {\n \"react\": \"__React\",\n \"react-dom\": \"__ReactDOM\",\n \"react-dom/client\": \"__ReactDOM\",\n \"framer-motion\": \"__FramerMotion\",\n \"recharts\": \"__Recharts\",\n \"lucide-react\": \"__LucideReact\"\n };\n\n function getGlobal(name) {\n return window[WHITELIST[name]];\n }\n\n function makeRequire() {\n return function require(name) {\n var g = getGlobal(name);\n if (!g) throw new Error(\"sandbox: module not in whitelist: \" + name);\n return g;\n };\n }\n\n function renderError(title, detail) {\n var root = document.getElementById(\"root\");\n if (!root) return;\n root.innerHTML = \"\";\n var box = document.createElement(\"div\");\n box.style.cssText = \"padding:12px 14px;border:1px solid #fca5a5;background:#fef2f2;color:#991b1b;border-radius:8px;font:12px/1.5 system-ui,sans-serif;\";\n var t = document.createElement(\"div\");\n t.style.cssText = \"font-weight:600;margin-bottom:4px;\";\n t.textContent = title;\n box.appendChild(t);\n if (detail) {\n var d = document.createElement(\"pre\");\n d.style.cssText = \"margin:4px 0 0;white-space:pre-wrap;word-break:break-word;font:11px/1.4 ui-monospace,monospace;color:#7f1d1d;\";\n d.textContent = String(detail);\n box.appendChild(d);\n }\n root.appendChild(box);\n }\n\n function applyTheme(theme) {\n var dark = theme === \"dark\" || (theme === \"auto\" && window.matchMedia && window.matchMedia(\"(prefers-color-scheme: dark)\").matches);\n var root = document.documentElement;\n if (dark) {\n root.style.setProperty(\"--bg\", \"#0a0a0a\");\n root.style.setProperty(\"--fg\", \"#fafafa\");\n root.style.setProperty(\"--muted\", \"#a3a3a3\");\n root.style.setProperty(\"--border\", \"#262626\");\n root.style.setProperty(\"--accent\", \"#60a5fa\");\n document.body.style.background = \"#0a0a0a\";\n document.body.style.color = \"#fafafa\";\n } else {\n root.style.setProperty(\"--bg\", \"#ffffff\");\n root.style.setProperty(\"--fg\", \"#0a0a0a\");\n root.style.setProperty(\"--muted\", \"#737373\");\n root.style.setProperty(\"--border\", \"#e5e5e5\");\n root.style.setProperty(\"--accent\", \"#2563eb\");\n document.body.style.background = \"#ffffff\";\n document.body.style.color = \"#0a0a0a\";\n }\n }\n\n function mount(payload, compiledCode) {\n try {\n var React = window.__React;\n var ReactDOM = window.__ReactDOM;\n var FramerMotion = window.__FramerMotion;\n if (!React || !ReactDOM) {\n renderError(\"Sandbox: React runtime missing\", \"__React/__ReactDOM not on window.\");\n return;\n }\n\n applyTheme(payload.theme || \"auto\");\n\n // Evaluate compiled CJS module. sucrase's \"imports\" transform produces code\n // that expects exports/module/require in scope.\n var moduleObj = { exports: {} };\n var exportsObj = moduleObj.exports;\n var requireFn = makeRequire();\n var fn;\n try {\n // eslint-disable-next-line no-new-func\n fn = new Function(\"exports\", \"module\", \"require\", \"React\", compiledCode);\n } catch (e) {\n renderError(\"Sandbox: compile error\", e && e.message);\n return;\n }\n try {\n fn(exportsObj, moduleObj, requireFn, React);\n } catch (e) {\n renderError(\"Sandbox: runtime error\", e && (e.stack || e.message));\n return;\n }\n var Component = moduleObj.exports && (moduleObj.exports.default || moduleObj.exports);\n if (typeof Component !== \"function\") {\n renderError(\"Sandbox: no default export\", \"Expected 'export default function ...' but got: \" + typeof Component);\n return;\n }\n\n // Minimal error boundary\n var ErrorBoundary = (function() {\n function EB(props) { React.Component.call(this, props); this.state = { err: null }; }\n EB.prototype = Object.create(React.Component.prototype);\n EB.prototype.constructor = EB;\n EB.getDerivedStateFromError = function(err) { return { err: err }; };\n EB.prototype.componentDidCatch = function(err) { renderError(\"Sandbox: render crash\", err && (err.stack || err.message)); };\n EB.prototype.render = function() {\n if (this.state.err) return null;\n return this.props.children;\n };\n return EB;\n })();\n\n var root = document.getElementById(\"root\");\n root.innerHTML = \"\";\n var element = React.createElement(ErrorBoundary, null, React.createElement(Component, payload.initialProps || {}));\n if (FramerMotion && FramerMotion.MotionConfig) {\n element = React.createElement(FramerMotion.MotionConfig, { reducedMotion: \"user\" }, element);\n }\n var reactRoot = ReactDOM.createRoot(root);\n reactRoot.render(element);\n\n // ResizeObserver \u2192 notify parent of content height\n if (typeof ResizeObserver !== \"undefined\") {\n var ro = new ResizeObserver(function(entries) {\n for (var i = 0; i < entries.length; i++) {\n var h = Math.ceil(entries[i].contentRect.height);\n window.parent.postMessage({ type: \"sandbox-height\", height: h }, \"*\");\n }\n });\n ro.observe(root);\n }\n\n window.parent.postMessage({ type: \"sandbox-ready\" }, \"*\");\n } catch (e) {\n renderError(\"Sandbox: unexpected error\", e && (e.stack || e.message));\n }\n }\n\n window.addEventListener(\"message\", function(ev) {\n var data = ev.data;\n if (!data || data.type !== \"sandbox-render\") return;\n mount(data.payload, data.compiledCode);\n });\n\n // Signal parent we are alive and waiting for code\n window.parent.postMessage({ type: \"sandbox-boot\" }, \"*\");\n})();\n";
@@ -0,0 +1,154 @@
1
+ // The bootstrap script runs INSIDE the sandboxed iframe.
2
+ // It is serialized to a string and embedded in the srcdoc HTML.
3
+ // Keep it dependency-free — only browser APIs + the 5 globals injected via <script> tags.
4
+ export const SANDBOX_BOOTSTRAP = `
5
+ (function() {
6
+ var WHITELIST = {
7
+ "react": "__React",
8
+ "react-dom": "__ReactDOM",
9
+ "react-dom/client": "__ReactDOM",
10
+ "framer-motion": "__FramerMotion",
11
+ "recharts": "__Recharts",
12
+ "lucide-react": "__LucideReact"
13
+ };
14
+
15
+ function getGlobal(name) {
16
+ return window[WHITELIST[name]];
17
+ }
18
+
19
+ function makeRequire() {
20
+ return function require(name) {
21
+ var g = getGlobal(name);
22
+ if (!g) throw new Error("sandbox: module not in whitelist: " + name);
23
+ return g;
24
+ };
25
+ }
26
+
27
+ function renderError(title, detail) {
28
+ var root = document.getElementById("root");
29
+ if (!root) return;
30
+ root.innerHTML = "";
31
+ var box = document.createElement("div");
32
+ box.style.cssText = "padding:12px 14px;border:1px solid #fca5a5;background:#fef2f2;color:#991b1b;border-radius:8px;font:12px/1.5 system-ui,sans-serif;";
33
+ var t = document.createElement("div");
34
+ t.style.cssText = "font-weight:600;margin-bottom:4px;";
35
+ t.textContent = title;
36
+ box.appendChild(t);
37
+ if (detail) {
38
+ var d = document.createElement("pre");
39
+ d.style.cssText = "margin:4px 0 0;white-space:pre-wrap;word-break:break-word;font:11px/1.4 ui-monospace,monospace;color:#7f1d1d;";
40
+ d.textContent = String(detail);
41
+ box.appendChild(d);
42
+ }
43
+ root.appendChild(box);
44
+ }
45
+
46
+ function applyTheme(theme) {
47
+ var dark = theme === "dark" || (theme === "auto" && window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches);
48
+ var root = document.documentElement;
49
+ if (dark) {
50
+ root.style.setProperty("--bg", "#0a0a0a");
51
+ root.style.setProperty("--fg", "#fafafa");
52
+ root.style.setProperty("--muted", "#a3a3a3");
53
+ root.style.setProperty("--border", "#262626");
54
+ root.style.setProperty("--accent", "#60a5fa");
55
+ document.body.style.background = "#0a0a0a";
56
+ document.body.style.color = "#fafafa";
57
+ } else {
58
+ root.style.setProperty("--bg", "#ffffff");
59
+ root.style.setProperty("--fg", "#0a0a0a");
60
+ root.style.setProperty("--muted", "#737373");
61
+ root.style.setProperty("--border", "#e5e5e5");
62
+ root.style.setProperty("--accent", "#2563eb");
63
+ document.body.style.background = "#ffffff";
64
+ document.body.style.color = "#0a0a0a";
65
+ }
66
+ }
67
+
68
+ function mount(payload, compiledCode) {
69
+ try {
70
+ var React = window.__React;
71
+ var ReactDOM = window.__ReactDOM;
72
+ var FramerMotion = window.__FramerMotion;
73
+ if (!React || !ReactDOM) {
74
+ renderError("Sandbox: React runtime missing", "__React/__ReactDOM not on window.");
75
+ return;
76
+ }
77
+
78
+ applyTheme(payload.theme || "auto");
79
+
80
+ // Evaluate compiled CJS module. sucrase's "imports" transform produces code
81
+ // that expects exports/module/require in scope.
82
+ var moduleObj = { exports: {} };
83
+ var exportsObj = moduleObj.exports;
84
+ var requireFn = makeRequire();
85
+ var fn;
86
+ try {
87
+ // eslint-disable-next-line no-new-func
88
+ fn = new Function("exports", "module", "require", "React", compiledCode);
89
+ } catch (e) {
90
+ renderError("Sandbox: compile error", e && e.message);
91
+ return;
92
+ }
93
+ try {
94
+ fn(exportsObj, moduleObj, requireFn, React);
95
+ } catch (e) {
96
+ renderError("Sandbox: runtime error", e && (e.stack || e.message));
97
+ return;
98
+ }
99
+ var Component = moduleObj.exports && (moduleObj.exports.default || moduleObj.exports);
100
+ if (typeof Component !== "function") {
101
+ renderError("Sandbox: no default export", "Expected 'export default function ...' but got: " + typeof Component);
102
+ return;
103
+ }
104
+
105
+ // Minimal error boundary
106
+ var ErrorBoundary = (function() {
107
+ function EB(props) { React.Component.call(this, props); this.state = { err: null }; }
108
+ EB.prototype = Object.create(React.Component.prototype);
109
+ EB.prototype.constructor = EB;
110
+ EB.getDerivedStateFromError = function(err) { return { err: err }; };
111
+ EB.prototype.componentDidCatch = function(err) { renderError("Sandbox: render crash", err && (err.stack || err.message)); };
112
+ EB.prototype.render = function() {
113
+ if (this.state.err) return null;
114
+ return this.props.children;
115
+ };
116
+ return EB;
117
+ })();
118
+
119
+ var root = document.getElementById("root");
120
+ root.innerHTML = "";
121
+ var element = React.createElement(ErrorBoundary, null, React.createElement(Component, payload.initialProps || {}));
122
+ if (FramerMotion && FramerMotion.MotionConfig) {
123
+ element = React.createElement(FramerMotion.MotionConfig, { reducedMotion: "user" }, element);
124
+ }
125
+ var reactRoot = ReactDOM.createRoot(root);
126
+ reactRoot.render(element);
127
+
128
+ // ResizeObserver → notify parent of content height
129
+ if (typeof ResizeObserver !== "undefined") {
130
+ var ro = new ResizeObserver(function(entries) {
131
+ for (var i = 0; i < entries.length; i++) {
132
+ var h = Math.ceil(entries[i].contentRect.height);
133
+ window.parent.postMessage({ type: "sandbox-height", height: h }, "*");
134
+ }
135
+ });
136
+ ro.observe(root);
137
+ }
138
+
139
+ window.parent.postMessage({ type: "sandbox-ready" }, "*");
140
+ } catch (e) {
141
+ renderError("Sandbox: unexpected error", e && (e.stack || e.message));
142
+ }
143
+ }
144
+
145
+ window.addEventListener("message", function(ev) {
146
+ var data = ev.data;
147
+ if (!data || data.type !== "sandbox-render") return;
148
+ mount(data.payload, data.compiledCode);
149
+ });
150
+
151
+ // Signal parent we are alive and waiting for code
152
+ window.parent.postMessage({ type: "sandbox-boot" }, "*");
153
+ })();
154
+ `;
@@ -0,0 +1,5 @@
1
+ import type { ComponentType } from "react";
2
+ export type DisplayActionName = "metric" | "price" | "alert" | "choices" | "table" | "spreadsheet" | "comparison" | "carousel" | "gallery" | "sources" | "product" | "link" | "file" | "image" | "chart" | "map" | "code" | "progress" | "steps" | "react";
3
+ export type DisplayRendererMap = Partial<Record<string, ComponentType<any>>>;
4
+ export declare const defaultDisplayRenderers: Record<DisplayActionName, ComponentType<any>>;
5
+ export declare function resolveDisplayRenderer(action: string, overrides?: DisplayRendererMap): ComponentType<any> | null;
@@ -0,0 +1,52 @@
1
+ import { AlertRenderer } from "./AlertRenderer.js";
2
+ import { MetricCardRenderer } from "./MetricCardRenderer.js";
3
+ import { PriceHighlightRenderer } from "./PriceHighlightRenderer.js";
4
+ import { FileCardRenderer } from "./FileCardRenderer.js";
5
+ import { CodeBlockRenderer } from "./CodeBlockRenderer.js";
6
+ import { SourcesListRenderer } from "./SourcesListRenderer.js";
7
+ import { StepTimelineRenderer } from "./StepTimelineRenderer.js";
8
+ import { ProgressStepsRenderer } from "./ProgressStepsRenderer.js";
9
+ import { ChartRenderer } from "./ChartRenderer.js";
10
+ import { CarouselRenderer } from "./CarouselRenderer.js";
11
+ import { ProductCardRenderer } from "./ProductCardRenderer.js";
12
+ import { ComparisonTableRenderer } from "./ComparisonTableRenderer.js";
13
+ import { DataTableRenderer } from "./DataTableRenderer.js";
14
+ import { SpreadsheetRenderer } from "./SpreadsheetRenderer.js";
15
+ import { GalleryRenderer } from "./GalleryRenderer.js";
16
+ import { ImageViewerRenderer } from "./ImageViewerRenderer.js";
17
+ import { LinkPreviewRenderer } from "./LinkPreviewRenderer.js";
18
+ import { MapViewRenderer } from "./MapViewRenderer.js";
19
+ import { ChoiceButtonsRenderer } from "./ChoiceButtonsRenderer.js";
20
+ import { DisplayReactRenderer } from "./DisplayReactRenderer.js";
21
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
22
+ export const defaultDisplayRenderers = {
23
+ // highlight
24
+ metric: MetricCardRenderer,
25
+ price: PriceHighlightRenderer,
26
+ alert: AlertRenderer,
27
+ choices: ChoiceButtonsRenderer,
28
+ // collection
29
+ table: DataTableRenderer,
30
+ spreadsheet: SpreadsheetRenderer,
31
+ comparison: ComparisonTableRenderer,
32
+ carousel: CarouselRenderer,
33
+ gallery: GalleryRenderer,
34
+ sources: SourcesListRenderer,
35
+ // card
36
+ product: ProductCardRenderer,
37
+ link: LinkPreviewRenderer,
38
+ file: FileCardRenderer,
39
+ image: ImageViewerRenderer,
40
+ // visual
41
+ chart: ChartRenderer,
42
+ map: MapViewRenderer,
43
+ code: CodeBlockRenderer,
44
+ progress: ProgressStepsRenderer,
45
+ steps: StepTimelineRenderer,
46
+ react: DisplayReactRenderer,
47
+ };
48
+ export function resolveDisplayRenderer(action, overrides) {
49
+ if (overrides?.[action])
50
+ return overrides[action];
51
+ return defaultDisplayRenderers[action] ?? null;
52
+ }
@@ -0,0 +1,187 @@
1
+ export type Money = {
2
+ value: number;
3
+ currency?: string;
4
+ };
5
+ export type SourceRef = {
6
+ name: string;
7
+ url: string;
8
+ favicon?: string;
9
+ };
10
+ export type DisplayBadge = {
11
+ label: string;
12
+ variant?: "default" | "success" | "warning" | "error" | "info";
13
+ };
14
+ export type DisplayMetric = {
15
+ label: string;
16
+ value: string | number;
17
+ unit?: string;
18
+ trend?: {
19
+ direction: "up" | "down" | "neutral";
20
+ value: string;
21
+ };
22
+ icon?: string;
23
+ };
24
+ export type DisplayChart = {
25
+ type: "bar" | "line" | "pie" | "area" | "donut";
26
+ title: string;
27
+ data: Array<{
28
+ label: string;
29
+ value: number;
30
+ color?: string;
31
+ }>;
32
+ format?: {
33
+ prefix?: string;
34
+ suffix?: string;
35
+ locale?: string;
36
+ };
37
+ };
38
+ export type DisplayTable = {
39
+ title?: string;
40
+ columns: Array<{
41
+ key: string;
42
+ label: string;
43
+ type?: "text" | "number" | "money" | "image" | "link" | "badge";
44
+ align?: "left" | "center" | "right";
45
+ }>;
46
+ rows: Array<Record<string, unknown>>;
47
+ sortable?: boolean;
48
+ };
49
+ export type DisplayProgress = {
50
+ title?: string;
51
+ steps: Array<{
52
+ label: string;
53
+ status: "completed" | "current" | "pending";
54
+ description?: string;
55
+ }>;
56
+ };
57
+ export type DisplayProduct = {
58
+ title: string;
59
+ image?: string;
60
+ price?: Money;
61
+ originalPrice?: Money;
62
+ rating?: {
63
+ score: number;
64
+ count: number;
65
+ };
66
+ source?: SourceRef;
67
+ badges?: DisplayBadge[];
68
+ url?: string;
69
+ description?: string;
70
+ };
71
+ export type DisplayComparison = {
72
+ title?: string;
73
+ items: DisplayProduct[];
74
+ attributes?: Array<{
75
+ key: string;
76
+ label: string;
77
+ }>;
78
+ };
79
+ export type DisplayPrice = {
80
+ value: Money;
81
+ label: string;
82
+ context?: string;
83
+ source?: SourceRef;
84
+ badge?: DisplayBadge;
85
+ };
86
+ export type DisplayImage = {
87
+ url: string;
88
+ alt?: string;
89
+ caption?: string;
90
+ width?: number;
91
+ height?: number;
92
+ };
93
+ export type DisplayGallery = {
94
+ title?: string;
95
+ images: Array<{
96
+ url: string;
97
+ alt?: string;
98
+ caption?: string;
99
+ }>;
100
+ layout?: "grid" | "masonry";
101
+ columns?: number;
102
+ };
103
+ export type DisplayCarousel = {
104
+ title?: string;
105
+ items: Array<{
106
+ image?: string;
107
+ title: string;
108
+ subtitle?: string;
109
+ price?: Money;
110
+ url?: string;
111
+ badges?: DisplayBadge[];
112
+ }>;
113
+ };
114
+ export type DisplaySources = {
115
+ label?: string;
116
+ sources: Array<{
117
+ title: string;
118
+ url: string;
119
+ favicon?: string;
120
+ snippet?: string;
121
+ }>;
122
+ };
123
+ export type DisplayLink = {
124
+ url: string;
125
+ title: string;
126
+ description?: string;
127
+ image?: string;
128
+ favicon?: string;
129
+ domain?: string;
130
+ };
131
+ export type DisplayMap = {
132
+ title?: string;
133
+ pins: Array<{
134
+ lat: number;
135
+ lng: number;
136
+ label?: string;
137
+ address?: string;
138
+ }>;
139
+ zoom?: number;
140
+ };
141
+ export type DisplayFile = {
142
+ name: string;
143
+ type: string;
144
+ size?: number;
145
+ url?: string;
146
+ preview?: string;
147
+ };
148
+ export type DisplayCode = {
149
+ language: string;
150
+ code: string;
151
+ title?: string;
152
+ lineNumbers?: boolean;
153
+ };
154
+ export type DisplaySpreadsheet = {
155
+ title?: string;
156
+ headers: string[];
157
+ rows: Array<Array<string | number | null>>;
158
+ format?: {
159
+ moneyColumns?: number[];
160
+ percentColumns?: number[];
161
+ };
162
+ };
163
+ export type DisplaySteps = {
164
+ title?: string;
165
+ steps: Array<{
166
+ title: string;
167
+ description?: string;
168
+ status?: "completed" | "current" | "pending";
169
+ }>;
170
+ orientation?: "vertical" | "horizontal";
171
+ };
172
+ export type DisplayAlert = {
173
+ variant: "info" | "warning" | "error" | "success";
174
+ title?: string;
175
+ message: string;
176
+ icon?: string;
177
+ };
178
+ export type DisplayChoices = {
179
+ question?: string;
180
+ choices: Array<{
181
+ id: string;
182
+ label: string;
183
+ description?: string;
184
+ icon?: string;
185
+ }>;
186
+ layout?: "buttons" | "cards" | "list";
187
+ };
@@ -0,0 +1,4 @@
1
+ // Tipos dos display widgets — espelham os schemas em
2
+ // D:\aw\context\workspaces\openclaude-sdk\repo\src\display\schemas.ts
3
+ // Mantemos local para nao ter dependencia dura em typings da SDK.
4
+ export {};