@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.
- package/dist/components/Chat.d.ts +23 -0
- package/dist/components/Chat.js +12 -0
- package/dist/components/ErrorNote.d.ts +6 -0
- package/dist/components/ErrorNote.js +6 -0
- package/dist/components/LazyRender.d.ts +8 -0
- package/dist/components/LazyRender.js +22 -0
- package/dist/components/Markdown.d.ts +5 -0
- package/dist/components/Markdown.js +65 -0
- package/dist/components/MessageBubble.d.ts +9 -0
- package/dist/components/MessageBubble.js +45 -0
- package/dist/components/MessageInput.d.ts +19 -0
- package/dist/components/MessageInput.js +214 -0
- package/dist/components/MessageList.d.ts +13 -0
- package/dist/components/MessageList.js +72 -0
- package/dist/components/StreamingIndicator.d.ts +1 -0
- package/dist/components/StreamingIndicator.js +9 -0
- package/dist/display/AlertRenderer.d.ts +2 -0
- package/dist/display/AlertRenderer.js +13 -0
- package/dist/display/CarouselRenderer.d.ts +2 -0
- package/dist/display/CarouselRenderer.js +41 -0
- package/dist/display/ChartRenderer.d.ts +2 -0
- package/dist/display/ChartRenderer.js +76 -0
- package/dist/display/ChoiceButtonsRenderer.d.ts +6 -0
- package/dist/display/ChoiceButtonsRenderer.js +23 -0
- package/dist/display/CodeBlockRenderer.d.ts +2 -0
- package/dist/display/CodeBlockRenderer.js +17 -0
- package/dist/display/ComparisonTableRenderer.d.ts +2 -0
- package/dist/display/ComparisonTableRenderer.js +26 -0
- package/dist/display/DataTableRenderer.d.ts +2 -0
- package/dist/display/DataTableRenderer.js +74 -0
- package/dist/display/DisplayReactRenderer.d.ts +26 -0
- package/dist/display/DisplayReactRenderer.js +192 -0
- package/dist/display/FileCardRenderer.d.ts +2 -0
- package/dist/display/FileCardRenderer.js +31 -0
- package/dist/display/GalleryRenderer.d.ts +2 -0
- package/dist/display/GalleryRenderer.js +11 -0
- package/dist/display/ImageViewerRenderer.d.ts +2 -0
- package/dist/display/ImageViewerRenderer.js +15 -0
- package/dist/display/LinkPreviewRenderer.d.ts +2 -0
- package/dist/display/LinkPreviewRenderer.js +20 -0
- package/dist/display/MapViewRenderer.d.ts +2 -0
- package/dist/display/MapViewRenderer.js +20 -0
- package/dist/display/MetricCardRenderer.d.ts +2 -0
- package/dist/display/MetricCardRenderer.js +12 -0
- package/dist/display/PriceHighlightRenderer.d.ts +2 -0
- package/dist/display/PriceHighlightRenderer.js +30 -0
- package/dist/display/ProductCardRenderer.d.ts +2 -0
- package/dist/display/ProductCardRenderer.js +23 -0
- package/dist/display/ProgressStepsRenderer.d.ts +2 -0
- package/dist/display/ProgressStepsRenderer.js +14 -0
- package/dist/display/SourcesListRenderer.d.ts +2 -0
- package/dist/display/SourcesListRenderer.js +5 -0
- package/dist/display/SpreadsheetRenderer.d.ts +2 -0
- package/dist/display/SpreadsheetRenderer.js +32 -0
- package/dist/display/StepTimelineRenderer.d.ts +2 -0
- package/dist/display/StepTimelineRenderer.js +21 -0
- package/dist/display/index.d.ts +21 -0
- package/dist/display/index.js +20 -0
- package/dist/display/react-sandbox/bootstrap.d.ts +1 -0
- package/dist/display/react-sandbox/bootstrap.js +154 -0
- package/dist/display/registry.d.ts +5 -0
- package/dist/display/registry.js +52 -0
- package/dist/display/sdk-types.d.ts +187 -0
- package/dist/display/sdk-types.js +4 -0
- package/dist/hooks/ChatProvider.d.ts +9 -0
- package/dist/hooks/ChatProvider.js +14 -0
- package/dist/hooks/useIsMobile.d.ts +1 -0
- package/dist/hooks/useIsMobile.js +12 -0
- package/dist/hooks/useOpenClaudeChat.d.ts +36 -0
- package/dist/hooks/useOpenClaudeChat.js +361 -0
- package/dist/index.d.ts +47 -0
- package/dist/index.js +42 -0
- package/dist/lib/utils.d.ts +2 -0
- package/dist/lib/utils.js +5 -0
- package/dist/parts/PartErrorBoundary.d.ts +21 -0
- package/dist/parts/PartErrorBoundary.js +27 -0
- package/dist/parts/PartRenderer.d.ts +8 -0
- package/dist/parts/PartRenderer.js +99 -0
- package/dist/parts/ReasoningBlock.d.ts +6 -0
- package/dist/parts/ReasoningBlock.js +18 -0
- package/dist/parts/ToolActivity.d.ts +11 -0
- package/dist/parts/ToolActivity.js +52 -0
- package/dist/parts/ToolResult.d.ts +7 -0
- package/dist/parts/ToolResult.js +38 -0
- package/dist/styles.css +2 -0
- package/dist/types.d.ts +40 -0
- package/dist/types.js +4 -0
- package/dist/ui/alert.d.ts +12 -0
- package/dist/ui/alert.js +28 -0
- package/dist/ui/badge.d.ts +9 -0
- package/dist/ui/badge.js +20 -0
- package/dist/ui/button.d.ts +11 -0
- package/dist/ui/button.js +31 -0
- package/dist/ui/card.d.ts +8 -0
- package/dist/ui/card.js +21 -0
- package/dist/ui/collapsible.d.ts +1 -0
- package/dist/ui/collapsible.js +2 -0
- package/dist/ui/dialog.d.ts +19 -0
- package/dist/ui/dialog.js +23 -0
- package/dist/ui/dropdown-menu.d.ts +11 -0
- package/dist/ui/dropdown-menu.js +15 -0
- package/dist/ui/input.d.ts +3 -0
- package/dist/ui/input.js +6 -0
- package/dist/ui/progress.d.ts +7 -0
- package/dist/ui/progress.js +9 -0
- package/dist/ui/scroll-area.d.ts +5 -0
- package/dist/ui/scroll-area.js +12 -0
- package/dist/ui/separator.d.ts +4 -0
- package/dist/ui/separator.js +8 -0
- package/dist/ui/skeleton.d.ts +3 -0
- package/dist/ui/skeleton.js +6 -0
- package/dist/ui/table.d.ts +10 -0
- package/dist/ui/table.js +27 -0
- package/package.json +61 -0
- package/src/components/Chat.tsx +107 -0
- package/src/components/ErrorNote.tsx +35 -0
- package/src/components/LazyRender.tsx +42 -0
- package/src/components/Markdown.tsx +114 -0
- package/src/components/MessageBubble.tsx +107 -0
- package/src/components/MessageInput.tsx +421 -0
- package/src/components/MessageList.tsx +153 -0
- package/src/components/StreamingIndicator.tsx +19 -0
- package/src/display/AlertRenderer.tsx +23 -0
- package/src/display/CarouselRenderer.tsx +141 -0
- package/src/display/ChartRenderer.tsx +195 -0
- package/src/display/ChoiceButtonsRenderer.tsx +114 -0
- package/src/display/CodeBlockRenderer.tsx +49 -0
- package/src/display/ComparisonTableRenderer.tsx +132 -0
- package/src/display/DataTableRenderer.tsx +144 -0
- package/src/display/DisplayReactRenderer.tsx +269 -0
- package/src/display/FileCardRenderer.tsx +55 -0
- package/src/display/GalleryRenderer.tsx +65 -0
- package/src/display/ImageViewerRenderer.tsx +114 -0
- package/src/display/LinkPreviewRenderer.tsx +74 -0
- package/src/display/MapViewRenderer.tsx +75 -0
- package/src/display/MetricCardRenderer.tsx +29 -0
- package/src/display/PriceHighlightRenderer.tsx +62 -0
- package/src/display/ProductCardRenderer.tsx +112 -0
- package/src/display/ProgressStepsRenderer.tsx +59 -0
- package/src/display/SourcesListRenderer.tsx +47 -0
- package/src/display/SpreadsheetRenderer.tsx +86 -0
- package/src/display/StepTimelineRenderer.tsx +75 -0
- package/src/display/index.ts +21 -0
- package/src/display/react-sandbox/bootstrap.ts +155 -0
- package/src/display/registry.ts +84 -0
- package/src/display/sdk-types.ts +217 -0
- package/src/hooks/ChatProvider.tsx +21 -0
- package/src/hooks/useIsMobile.ts +15 -0
- package/src/hooks/useOpenClaudeChat.ts +476 -0
- package/src/index.ts +76 -0
- package/src/lib/utils.ts +6 -0
- package/src/parts/PartErrorBoundary.tsx +51 -0
- package/src/parts/PartRenderer.tsx +145 -0
- package/src/parts/ReasoningBlock.tsx +41 -0
- package/src/parts/ToolActivity.tsx +78 -0
- package/src/parts/ToolResult.tsx +79 -0
- package/src/styles.css +2 -0
- package/src/types.ts +41 -0
- package/src/ui/alert.tsx +77 -0
- package/src/ui/badge.tsx +36 -0
- package/src/ui/button.tsx +54 -0
- package/src/ui/card.tsx +68 -0
- package/src/ui/collapsible.tsx +7 -0
- package/src/ui/dialog.tsx +122 -0
- package/src/ui/dropdown-menu.tsx +76 -0
- package/src/ui/input.tsx +24 -0
- package/src/ui/progress.tsx +36 -0
- package/src/ui/scroll-area.tsx +48 -0
- package/src/ui/separator.tsx +31 -0
- package/src/ui/skeleton.tsx +9 -0
- 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,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,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,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,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,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,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
|
+
};
|