@page-speed/agent-everywhere 0.7.0 → 0.9.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/index.js CHANGED
@@ -2,11 +2,11 @@
2
2
  import { clsx } from 'clsx';
3
3
  import { twMerge } from 'tailwind-merge';
4
4
  import * as React4 from 'react';
5
- import { createContext, forwardRef, useRef, useImperativeHandle, useCallback, useLayoutEffect, useState, useEffect, useReducer, useMemo, useContext } from 'react';
5
+ import { createContext, forwardRef, useRef, useImperativeHandle, useCallback, useLayoutEffect, useState, useEffect, useReducer, useMemo, useContext, useId, Fragment as Fragment$1 } from 'react';
6
6
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
7
7
  import { AnimatePresence, motion } from 'motion/react';
8
8
  import { Markdown } from '@page-speed/markdown-to-jsx';
9
- import { SendIcon, PaperclipIcon, FileTextIcon, MicIcon, ImageIcon, XIcon, SearchIcon, UploadIcon, FileIcon, UserCircleIcon, CheckIcon, SparklesIcon, BookmarkIcon, InfoIcon, CheckCircle2Icon, AlertTriangleIcon, LightbulbIcon, BrainIcon, ChevronDownIcon, ZapIcon, CopyIcon, ThumbsUpIcon, ThumbsDownIcon, BotIcon, UserIcon, DownloadIcon, MinusIcon, TrendingDownIcon, TrendingUpIcon, ChevronUpIcon, ArrowUpDownIcon, LinkIcon, PlayIcon, ExternalLinkIcon, WandIcon, LayoutGridIcon, Grid3X3Icon, ArrowUpRightIcon, ShuffleIcon, SkipForwardIcon, ChevronLeftIcon, ChevronRightIcon, XCircleIcon, HelpCircleIcon, Minimize2Icon, Maximize2Icon, RotateCcwIcon, MessageSquareIcon, GripVerticalIcon, PanelLeftOpenIcon, PanelLeftCloseIcon, CheckCircleIcon, AlertCircleIcon, MoreHorizontalIcon, ClipboardListIcon, ArrowLeftIcon, MoreVerticalIcon, Loader2, ArrowUp, PanelLeft, PanelRight, Sparkles, RotateCcw, ChevronDown, MessageSquare, Paperclip, Loader2Icon, ArrowRightIcon, AlignLeftIcon, ListIcon, HashIcon, TypeIcon, ClockIcon, CoinsIcon, ActivityIcon, ArrowUpIcon, ArrowDownIcon } from 'lucide-react';
9
+ import { SendIcon, PaperclipIcon, FileTextIcon, MicIcon, ImageIcon, XIcon, SearchIcon, UploadIcon, FileIcon, UserCircleIcon, CheckIcon, SparklesIcon, BookmarkIcon, InfoIcon, CheckCircle2Icon, AlertTriangleIcon, LightbulbIcon, BrainIcon, ChevronDownIcon, ZapIcon, CopyIcon, ThumbsUpIcon, ThumbsDownIcon, BotIcon, UserIcon, DownloadIcon, MinusIcon, TrendingDownIcon, TrendingUpIcon, ChevronUpIcon, ArrowUpDownIcon, LinkIcon, PlayIcon, ExternalLinkIcon, WandIcon, LayoutGridIcon, Grid3X3Icon, ArrowUpRightIcon, ShuffleIcon, SkipForwardIcon, ChevronLeftIcon, ChevronRightIcon, XCircleIcon, HelpCircleIcon, Minimize2Icon, Maximize2Icon, RotateCcwIcon, MessageSquareIcon, GripVerticalIcon, PanelLeftOpenIcon, PanelLeftCloseIcon, CheckCircleIcon, AlertCircleIcon, MoreHorizontalIcon, ClipboardListIcon, ArrowLeftIcon, MoreVerticalIcon, Loader2, ArrowUp, PanelLeft, PanelRight, RotateCcw, ChevronDown, Sparkles, MessageSquare, Paperclip, Loader2Icon, ArrowRightIcon, AlignLeftIcon, ListIcon, HashIcon, TypeIcon, ClockIcon, CoinsIcon, ActivityIcon, ArrowUpIcon, ArrowDownIcon } from 'lucide-react';
10
10
  import { Slot } from '@radix-ui/react-slot';
11
11
  import { cva } from 'class-variance-authority';
12
12
  import * as AvatarPrimitive from '@radix-ui/react-avatar';
@@ -7670,17 +7670,2281 @@ function MessageActions({
7670
7670
  children
7671
7671
  ] }) });
7672
7672
  }
7673
- function DataPayloadView({ payload, className }) {
7674
- if (payload.type === "chart" && payload.chart) {
7675
- return /* @__PURE__ */ jsx(ChartContainer, { data: payload.chart, className });
7673
+ function CardShell({ className, children }) {
7674
+ return /* @__PURE__ */ jsx("div", { className: cn("rounded-2xl border bg-card text-card-foreground shadow-sm", className), children });
7675
+ }
7676
+ var DELTA_GLYPH = {
7677
+ up: "\u25B2",
7678
+ down: "\u25BC",
7679
+ flat: "\u2014"
7680
+ };
7681
+ var DELTA_DIRECTION_CLASSES = {
7682
+ up: "bg-emerald-50 text-emerald-600",
7683
+ down: "bg-red-50 text-red-600",
7684
+ flat: "bg-slate-100 text-slate-500"
7685
+ };
7686
+ var DELTA_TONE_CLASSES = {
7687
+ positive: "bg-emerald-50 text-emerald-600",
7688
+ negative: "bg-red-50 text-red-600",
7689
+ warning: "bg-amber-50 text-amber-600",
7690
+ info: "bg-blue-50 text-blue-600",
7691
+ neutral: "bg-slate-100 text-slate-500",
7692
+ muted: "bg-slate-100 text-slate-400",
7693
+ default: "bg-slate-100 text-slate-500"
7694
+ };
7695
+ function DeltaPill({
7696
+ value,
7697
+ text,
7698
+ direction,
7699
+ tone,
7700
+ hideArrow,
7701
+ className
7702
+ }) {
7703
+ const label = value ?? text ?? "";
7704
+ const colorClass = (tone && DELTA_TONE_CLASSES[tone]) ?? DELTA_DIRECTION_CLASSES[direction];
7705
+ return /* @__PURE__ */ jsxs(
7706
+ "span",
7707
+ {
7708
+ className: cn(
7709
+ "inline-flex items-center gap-1 rounded-full px-2 py-0.5 font-medium text-xs tabular-nums",
7710
+ colorClass,
7711
+ className
7712
+ ),
7713
+ children: [
7714
+ !hideArrow && /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "text-[0.625rem] leading-none", children: DELTA_GLYPH[direction] }),
7715
+ label
7716
+ ]
7717
+ }
7718
+ );
7719
+ }
7720
+ var STATUS_DOT_COLORS = {
7721
+ healthy: "#10B981",
7722
+ warning: "#F59E0B",
7723
+ critical: "#EF4444"
7724
+ };
7725
+ function StatusDot({
7726
+ status = "healthy",
7727
+ color,
7728
+ label,
7729
+ size = 12,
7730
+ className
7731
+ }) {
7732
+ const fill = color ?? STATUS_DOT_COLORS[status];
7733
+ return /* @__PURE__ */ jsx(
7734
+ "span",
7735
+ {
7736
+ "data-status-dot": "",
7737
+ role: label ? "img" : void 0,
7738
+ "aria-label": label,
7739
+ title: label,
7740
+ className: cn("inline-block shrink-0 rounded-full", className),
7741
+ style: { width: size, height: size, backgroundColor: fill }
7742
+ }
7743
+ );
7744
+ }
7745
+ var TONE_TEXT_CLASSES = {
7746
+ default: "text-slate-800",
7747
+ positive: "text-emerald-600",
7748
+ negative: "text-red-600",
7749
+ neutral: "text-slate-500",
7750
+ warning: "text-amber-600",
7751
+ info: "text-blue-600",
7752
+ muted: "text-slate-400"
7753
+ };
7754
+ function toneTextColor(tone) {
7755
+ if (!tone) return TONE_TEXT_CLASSES.default;
7756
+ return TONE_TEXT_CLASSES[tone] ?? TONE_TEXT_CLASSES.default;
7757
+ }
7758
+ function toAlpha(n, upper) {
7759
+ let out = "";
7760
+ let value = n;
7761
+ while (value > 0) {
7762
+ const rem = (value - 1) % 26;
7763
+ out = String.fromCharCode(97 + rem) + out;
7764
+ value = Math.floor((value - 1) / 26);
7765
+ }
7766
+ return upper ? out.toUpperCase() : out;
7767
+ }
7768
+ var ROMAN_NUMERALS = [
7769
+ [1e3, "m"],
7770
+ [900, "cm"],
7771
+ [500, "d"],
7772
+ [400, "cd"],
7773
+ [100, "c"],
7774
+ [90, "xc"],
7775
+ [50, "l"],
7776
+ [40, "xl"],
7777
+ [10, "x"],
7778
+ [9, "ix"],
7779
+ [5, "v"],
7780
+ [4, "iv"],
7781
+ [1, "i"]
7782
+ ];
7783
+ function toRoman(n) {
7784
+ if (n <= 0) return String(n);
7785
+ let value = n;
7786
+ let out = "";
7787
+ for (const [num, sym] of ROMAN_NUMERALS) {
7788
+ while (value >= num) {
7789
+ out += sym;
7790
+ value -= num;
7791
+ }
7792
+ }
7793
+ return out;
7794
+ }
7795
+ function formatMarker(index, style, start = 1) {
7796
+ const n = index + start;
7797
+ switch (style) {
7798
+ case "lower-alpha":
7799
+ return toAlpha(n, false);
7800
+ case "upper-alpha":
7801
+ return toAlpha(n, true);
7802
+ case "lower-roman":
7803
+ return toRoman(n);
7804
+ default:
7805
+ return String(n);
7806
+ }
7807
+ }
7808
+ var DEFAULT_COLOR = "#10B981";
7809
+ var DEFAULT_WIDTH = 100;
7810
+ var DEFAULT_HEIGHT = 32;
7811
+ function normalizeSeries(data, w, h, pad = 2) {
7812
+ const n = data.length;
7813
+ if (n === 0) return [];
7814
+ const min = Math.min(...data);
7815
+ const max = Math.max(...data);
7816
+ const flat = max === min;
7817
+ const span = flat ? 1 : max - min;
7818
+ const inner = h - pad * 2;
7819
+ return data.map((v, i) => {
7820
+ const x = n === 1 ? w / 2 : i / (n - 1) * w;
7821
+ const y = flat ? h / 2 : h - pad - (v - min) / span * inner;
7822
+ return { x, y };
7823
+ });
7824
+ }
7825
+ function buildLinePath(pts, smooth = false) {
7826
+ if (pts.length < 2) return "";
7827
+ if (!smooth) {
7828
+ const [first, ...rest] = pts;
7829
+ return `M ${fmt(first.x)} ${fmt(first.y)}` + rest.map((p) => ` L ${fmt(p.x)} ${fmt(p.y)}`).join("");
7830
+ }
7831
+ let d = `M ${fmt(pts[0].x)} ${fmt(pts[0].y)}`;
7832
+ for (let i = 0; i < pts.length - 1; i++) {
7833
+ const p0 = pts[i - 1] ?? pts[i];
7834
+ const p1 = pts[i];
7835
+ const p2 = pts[i + 1];
7836
+ const p3 = pts[i + 2] ?? p2;
7837
+ const c1x = p1.x + (p2.x - p0.x) / 6;
7838
+ const c1y = p1.y + (p2.y - p0.y) / 6;
7839
+ const c2x = p2.x - (p3.x - p1.x) / 6;
7840
+ const c2y = p2.y - (p3.y - p1.y) / 6;
7841
+ d += ` C ${fmt(c1x)} ${fmt(c1y)}, ${fmt(c2x)} ${fmt(c2y)}, ${fmt(p2.x)} ${fmt(p2.y)}`;
7842
+ }
7843
+ return d;
7844
+ }
7845
+ function buildAreaPath(pts, h, smooth = false) {
7846
+ if (pts.length < 2) return "";
7847
+ const line = buildLinePath(pts, smooth);
7848
+ if (!line) return "";
7849
+ const last = pts[pts.length - 1];
7850
+ const first = pts[0];
7851
+ return `${line} L ${fmt(last.x)} ${fmt(h)} L ${fmt(first.x)} ${fmt(h)} Z`;
7852
+ }
7853
+ function fmt(n) {
7854
+ return Number.isInteger(n) ? String(n) : String(Math.round(n * 1e3) / 1e3);
7855
+ }
7856
+ function Sparkline({
7857
+ data,
7858
+ color = DEFAULT_COLOR,
7859
+ showArea = false,
7860
+ smooth = false,
7861
+ width = DEFAULT_WIDTH,
7862
+ height = DEFAULT_HEIGHT,
7863
+ pad = 2,
7864
+ strokeWidth = 2,
7865
+ className
7866
+ }) {
7867
+ const gradientId = useId();
7868
+ if (data.length < 2) return null;
7869
+ const points = normalizeSeries(data, width, height, pad);
7870
+ const linePath = buildLinePath(points, smooth);
7871
+ const areaPath = showArea ? buildAreaPath(points, height, smooth) : "";
7872
+ return /* @__PURE__ */ jsxs(
7873
+ "svg",
7874
+ {
7875
+ className: cn("block", className),
7876
+ viewBox: `0 0 ${width} ${height}`,
7877
+ preserveAspectRatio: "none",
7878
+ "aria-hidden": "true",
7879
+ focusable: "false",
7880
+ children: [
7881
+ showArea && areaPath && /* @__PURE__ */ jsxs(Fragment, { children: [
7882
+ /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsxs("linearGradient", { id: gradientId, x1: "0", y1: "0", x2: "0", y2: "1", children: [
7883
+ /* @__PURE__ */ jsx("stop", { offset: "0%", stopColor: color, stopOpacity: 0.18 }),
7884
+ /* @__PURE__ */ jsx("stop", { offset: "100%", stopColor: color, stopOpacity: 0 })
7885
+ ] }) }),
7886
+ /* @__PURE__ */ jsx("path", { d: areaPath, fill: `url(#${gradientId})`, stroke: "none" })
7887
+ ] }),
7888
+ /* @__PURE__ */ jsx(
7889
+ "path",
7890
+ {
7891
+ d: linePath,
7892
+ fill: "none",
7893
+ stroke: color,
7894
+ strokeWidth,
7895
+ strokeLinecap: "round",
7896
+ strokeLinejoin: "round",
7897
+ style: { vectorEffect: "non-scaling-stroke" }
7898
+ }
7899
+ )
7900
+ ]
7901
+ }
7902
+ );
7903
+ }
7904
+ var DEFAULT_SERIES_COLOR = "#3B82F6";
7905
+ var DEFAULT_PILL_COLOR = "#3B6FE0";
7906
+ var BASELINE_COLOR = "#EEF1F5";
7907
+ var CHART_WIDTH = 900;
7908
+ var CHART_HEIGHT = 240;
7909
+ function hexToRgba(hex, alpha) {
7910
+ const match = /^#?([\da-f]{6})$/i.exec(hex.trim());
7911
+ if (!match) return hex;
7912
+ const int = parseInt(match[1], 16);
7913
+ const r = int >> 16 & 255;
7914
+ const g = int >> 8 & 255;
7915
+ const b = int & 255;
7916
+ return `rgba(${r}, ${g}, ${b}, ${alpha})`;
7917
+ }
7918
+ function splitTickLabel(label) {
7919
+ const match = /^(.*?)[\s\u00a0]+(\S+)$/.exec(label.trim());
7920
+ if (!match) return [label];
7921
+ return [match[1], match[2]];
7922
+ }
7923
+ function KpiCardWithChart({
7924
+ title,
7925
+ rangeLabel,
7926
+ data,
7927
+ xAxisLabels,
7928
+ value,
7929
+ delta,
7930
+ seriesColor = DEFAULT_SERIES_COLOR,
7931
+ pillColor = DEFAULT_PILL_COLOR,
7932
+ showBaseline = true,
7933
+ valuePrefix,
7934
+ valueSuffix,
7935
+ className
7936
+ }) {
7937
+ const series = data?.map((point) => point.value) ?? [];
7938
+ const hasChart = series.length >= 2;
7939
+ const hasData = series.length > 0;
7940
+ const formattedValue = value === void 0 || value === null ? null : `${valuePrefix ?? ""}${value}${valueSuffix ?? ""}`;
7941
+ const sparklineProps = {
7942
+ data: series,
7943
+ color: seriesColor,
7944
+ showArea: true,
7945
+ smooth: true,
7946
+ width: CHART_WIDTH,
7947
+ height: CHART_HEIGHT,
7948
+ pad: 12,
7949
+ strokeWidth: 2.5
7950
+ };
7951
+ return /* @__PURE__ */ jsxs(CardShell, { className: cn("w-full overflow-hidden bg-white p-7 sm:p-8", className), children: [
7952
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-4", children: [
7953
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
7954
+ /* @__PURE__ */ jsx("h3", { className: "truncate font-bold text-[1.4rem] text-slate-900 leading-tight tracking-tight", children: title }),
7955
+ formattedValue !== null && /* @__PURE__ */ jsxs("div", { className: "mt-1 flex items-center gap-2", children: [
7956
+ /* @__PURE__ */ jsx("span", { className: "font-bold text-2xl text-slate-900 tabular-nums", children: formattedValue }),
7957
+ delta && /* @__PURE__ */ jsx(DeltaPill, { value: delta.value, direction: delta.direction })
7958
+ ] })
7959
+ ] }),
7960
+ rangeLabel && /* @__PURE__ */ jsx(
7961
+ "span",
7962
+ {
7963
+ className: "shrink-0 rounded-full px-4 py-1.5 font-semibold text-sm",
7964
+ style: {
7965
+ color: pillColor,
7966
+ backgroundColor: hexToRgba(pillColor, 0.12)
7967
+ },
7968
+ children: rangeLabel
7969
+ }
7970
+ )
7971
+ ] }),
7972
+ /* @__PURE__ */ jsx("div", { className: "mt-6", children: hasChart ? /* @__PURE__ */ jsxs("div", { className: "relative h-[180px] w-full", children: [
7973
+ showBaseline && /* @__PURE__ */ jsx(
7974
+ "div",
7975
+ {
7976
+ "aria-hidden": "true",
7977
+ className: "absolute inset-x-0 top-1/2 h-px",
7978
+ style: { backgroundColor: BASELINE_COLOR }
7979
+ }
7980
+ ),
7981
+ /* @__PURE__ */ jsx(Sparkline, { ...sparklineProps, className: "h-full w-full" })
7982
+ ] }) : /* @__PURE__ */ jsx("div", { className: "flex h-[180px] w-full items-center justify-center", children: /* @__PURE__ */ jsx("span", { className: "font-medium text-slate-400 text-sm", children: hasData ? "Not enough data" : "No data" }) }) }),
7983
+ hasChart && xAxisLabels && xAxisLabels.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-4 flex items-start justify-between", children: xAxisLabels.map((label, index) => {
7984
+ const [lead, trailing] = splitTickLabel(label);
7985
+ return /* @__PURE__ */ jsxs(
7986
+ "span",
7987
+ {
7988
+ className: "flex flex-col text-slate-400 text-sm leading-tight",
7989
+ children: [
7990
+ /* @__PURE__ */ jsx("span", { children: lead }),
7991
+ trailing !== void 0 && /* @__PURE__ */ jsx("span", { children: trailing })
7992
+ ]
7993
+ },
7994
+ `${label}-${index}`
7995
+ );
7996
+ }) })
7997
+ ] });
7998
+ }
7999
+
8000
+ // src/components/data-display/primitives/arc.tsx
8001
+ function clamp(n, min, max) {
8002
+ return Math.min(Math.max(n, min), max);
8003
+ }
8004
+ function arcLength(r) {
8005
+ return Math.PI * r;
8006
+ }
8007
+ function halfCircleArcPath(cx, cy, r) {
8008
+ const startX = cx - r;
8009
+ const endX = cx + r;
8010
+ return `M ${startX} ${cy} A ${r} ${r} 0 0 1 ${endX} ${cy}`;
8011
+ }
8012
+ function dashOffsetForFraction(arcLen, fraction) {
8013
+ return arcLen * (1 - clamp(fraction, 0, 1));
8014
+ }
8015
+ function segmentDashArray(value, total, circumference, gap = 0) {
8016
+ const safeTotal = total > 0 ? total : 0;
8017
+ const fraction = safeTotal > 0 ? value / safeTotal : 0;
8018
+ const rawLength = fraction * circumference;
8019
+ const visible = Math.max(0, rawLength - gap);
8020
+ const remainder = Math.max(0, circumference - visible);
8021
+ return {
8022
+ dasharray: `${visible} ${remainder}`,
8023
+ dashoffset: 0
8024
+ };
8025
+ }
8026
+ var DEFAULT_PALETTE = [
8027
+ "#1f2d4d",
8028
+ // navy
8029
+ "#3b82f6",
8030
+ // blue
8031
+ "#f59e0b",
8032
+ // amber
8033
+ "#10b981",
8034
+ // emerald
8035
+ "#8b5cf6",
8036
+ // violet
8037
+ "#ec4899",
8038
+ // pink
8039
+ "#14b8a6",
8040
+ // teal
8041
+ "#f97316"
8042
+ // orange
8043
+ ];
8044
+ var EMPTY_RING_COLOR = "#e5e7eb";
8045
+ var VIEWBOX = 100;
8046
+ var CENTER = VIEWBOX / 2;
8047
+ var RADIUS = 38;
8048
+ var STROKE_WIDTH = 18;
8049
+ var CIRCUMFERENCE = 2 * Math.PI * RADIUS;
8050
+ var SEGMENT_GAP = 1.5;
8051
+ function segmentColor(segment, index) {
8052
+ return segment.color ?? DEFAULT_PALETTE[index % DEFAULT_PALETTE.length];
8053
+ }
8054
+ function legendValue(segment, total, valueFormat) {
8055
+ if (segment.displayValue != null) return segment.displayValue;
8056
+ if (valueFormat === "none") return null;
8057
+ if (valueFormat === "value") return String(segment.value);
8058
+ if (total <= 0) return "0%";
8059
+ const pct = segment.value / total * 100;
8060
+ const rounded = Math.round(pct * 10) / 10;
8061
+ return `${Number.isInteger(rounded) ? rounded : rounded.toFixed(1)}%`;
8062
+ }
8063
+ function PieChartArtifact({
8064
+ title,
8065
+ centerLabel,
8066
+ centerSublabel,
8067
+ segments,
8068
+ valueFormat = "percent",
8069
+ className
8070
+ }) {
8071
+ const safeSegments = segments ?? [];
8072
+ const total = safeSegments.reduce((sum, s) => sum + (s.value > 0 ? s.value : 0), 0);
8073
+ const isEmpty = safeSegments.length === 0 || total <= 0;
8074
+ let runningOffset = 0;
8075
+ return /* @__PURE__ */ jsxs(CardShell, { className: cn("w-full p-6", className), children: [
8076
+ title ? /* @__PURE__ */ jsx("h3", { className: "font-bold text-base text-slate-900 leading-tight", children: title }) : null,
8077
+ /* @__PURE__ */ jsxs(
8078
+ "div",
8079
+ {
8080
+ className: cn(
8081
+ "flex flex-col items-center gap-6 sm:flex-row sm:items-center sm:gap-8",
8082
+ title && "mt-5"
8083
+ ),
8084
+ children: [
8085
+ /* @__PURE__ */ jsxs("div", { className: "relative shrink-0", style: { width: 150, height: 150 }, children: [
8086
+ /* @__PURE__ */ jsx(
8087
+ "svg",
8088
+ {
8089
+ viewBox: `0 0 ${VIEWBOX} ${VIEWBOX}`,
8090
+ width: "100%",
8091
+ height: "100%",
8092
+ role: "img",
8093
+ "aria-label": title ?? "Donut chart",
8094
+ children: /* @__PURE__ */ jsx("g", { transform: `rotate(-90 ${CENTER} ${CENTER})`, fill: "none", children: isEmpty ? /* @__PURE__ */ jsx(
8095
+ "circle",
8096
+ {
8097
+ cx: CENTER,
8098
+ cy: CENTER,
8099
+ r: RADIUS,
8100
+ stroke: EMPTY_RING_COLOR,
8101
+ strokeWidth: STROKE_WIDTH
8102
+ }
8103
+ ) : safeSegments.map((segment, index) => {
8104
+ const value = segment.value > 0 ? segment.value : 0;
8105
+ const { dasharray } = segmentDashArray(
8106
+ value,
8107
+ total,
8108
+ CIRCUMFERENCE,
8109
+ SEGMENT_GAP
8110
+ );
8111
+ const dashoffset = -runningOffset;
8112
+ runningOffset += value / total * CIRCUMFERENCE;
8113
+ if (value <= 0) return null;
8114
+ return /* @__PURE__ */ jsx(
8115
+ "circle",
8116
+ {
8117
+ cx: CENTER,
8118
+ cy: CENTER,
8119
+ r: RADIUS,
8120
+ stroke: segmentColor(segment, index),
8121
+ strokeWidth: STROKE_WIDTH,
8122
+ strokeDasharray: dasharray,
8123
+ strokeDashoffset: dashoffset
8124
+ },
8125
+ segment.label + index
8126
+ );
8127
+ }) })
8128
+ }
8129
+ ),
8130
+ /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute inset-0 flex flex-col items-center justify-center text-center", children: isEmpty ? /* @__PURE__ */ jsx("span", { className: "font-medium text-slate-400 text-sm", children: "No data" }) : /* @__PURE__ */ jsxs(Fragment, { children: [
8131
+ centerLabel ? /* @__PURE__ */ jsx("span", { className: "font-bold text-base text-slate-900 leading-none", children: centerLabel }) : null,
8132
+ centerSublabel ? /* @__PURE__ */ jsx("span", { className: "mt-1 text-slate-500 text-xs leading-none", children: centerSublabel }) : null
8133
+ ] }) })
8134
+ ] }),
8135
+ !isEmpty ? /* @__PURE__ */ jsx("ul", { className: "flex w-full min-w-0 flex-col gap-3.5", children: safeSegments.map((segment, index) => {
8136
+ const value = legendValue(segment, total, valueFormat);
8137
+ return /* @__PURE__ */ jsxs(
8138
+ "li",
8139
+ {
8140
+ className: "flex items-center justify-between gap-4",
8141
+ children: [
8142
+ /* @__PURE__ */ jsxs("span", { className: "flex min-w-0 items-center gap-2.5", children: [
8143
+ /* @__PURE__ */ jsx(
8144
+ "span",
8145
+ {
8146
+ "aria-hidden": "true",
8147
+ className: "inline-block size-3 shrink-0 rounded-sm",
8148
+ style: { backgroundColor: segmentColor(segment, index) }
8149
+ }
8150
+ ),
8151
+ /* @__PURE__ */ jsx("span", { className: "truncate text-slate-600 text-sm", children: segment.label })
8152
+ ] }),
8153
+ value != null ? /* @__PURE__ */ jsx("span", { className: "shrink-0 font-bold text-slate-900 text-sm tabular-nums", children: value }) : null
8154
+ ]
8155
+ },
8156
+ segment.label + index
8157
+ );
8158
+ }) }) : null
8159
+ ]
8160
+ }
8161
+ )
8162
+ ] });
8163
+ }
8164
+ var TREND_COLORS = {
8165
+ up: "#22C55E",
8166
+ down: "#3B82F6",
8167
+ flat: "#9CA3AF"
8168
+ };
8169
+ var PALETTE = ["#22C55E", "#3B82F6", "#F59E0B", "#8B5CF6", "#EF4444"];
8170
+ function resolveColor(row, index) {
8171
+ if (row.color) return row.color;
8172
+ if (row.trend) return TREND_COLORS[row.trend];
8173
+ return PALETTE[index % PALETTE.length];
8174
+ }
8175
+ function StackedSparklines({ rows, className }) {
8176
+ const safeRows = Array.isArray(rows) ? rows : [];
8177
+ return /* @__PURE__ */ jsx(CardShell, { className: cn("overflow-hidden", className), children: /* @__PURE__ */ jsx("div", { className: "px-6", children: safeRows.map((row, index) => {
8178
+ const color = resolveColor(row, index);
8179
+ const hasData = Array.isArray(row.data) && row.data.length >= 2;
8180
+ return /* @__PURE__ */ jsxs(
8181
+ "div",
8182
+ {
8183
+ className: cn(
8184
+ "flex items-center justify-between gap-6 py-5",
8185
+ // Hairline divider on every row except the first.
8186
+ index > 0 && "border-slate-200 border-t"
8187
+ ),
8188
+ children: [
8189
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-1", children: [
8190
+ /* @__PURE__ */ jsx("span", { className: "truncate text-[15px] text-slate-500 leading-tight", children: row.label }),
8191
+ /* @__PURE__ */ jsx("span", { className: "font-bold text-3xl text-slate-900 leading-tight tracking-tight tabular-nums", children: row.value })
8192
+ ] }),
8193
+ /* @__PURE__ */ jsx("div", { className: "h-9 w-[28%] min-w-[88px] shrink-0", children: hasData ? /* @__PURE__ */ jsx(
8194
+ Sparkline,
8195
+ {
8196
+ data: row.data,
8197
+ color,
8198
+ width: 110,
8199
+ height: 36,
8200
+ pad: 4,
8201
+ strokeWidth: 2.5,
8202
+ className: "h-full w-full"
8203
+ }
8204
+ ) : (
8205
+ // Empty/edge state: data length < 2 → blank area, no crash.
8206
+ /* @__PURE__ */ jsx("div", { "aria-hidden": "true", className: "h-full w-full" })
8207
+ ) })
8208
+ ]
8209
+ },
8210
+ `${row.label}-${index}`
8211
+ );
8212
+ }) }) });
8213
+ }
8214
+ var DEFAULT_MIN = 0;
8215
+ var DEFAULT_MAX = 100;
8216
+ var DEFAULT_FILL_COLOR = "#22c55e";
8217
+ var DEFAULT_TRACK_COLOR = "#eef0f2";
8218
+ var DEFAULT_VALUE_COLOR = "#0f172a";
8219
+ var DEFAULT_MIN_LABEL_COLOR = "#94a3b8";
8220
+ var DEFAULT_TITLE_COLOR = "#0f172a";
8221
+ var VIEW_W = 240;
8222
+ var VIEW_H = 130;
8223
+ var CX = 120;
8224
+ var CY = 110;
8225
+ var RADIUS2 = 100;
8226
+ var STROKE_WIDTH2 = 18;
8227
+ function clamp01(n) {
8228
+ if (Number.isNaN(n)) return 0;
8229
+ return Math.min(Math.max(n, 0), 1);
8230
+ }
8231
+ function StatCardHalfCircle({
8232
+ title,
8233
+ value,
8234
+ displayValue,
8235
+ min = DEFAULT_MIN,
8236
+ max = DEFAULT_MAX,
8237
+ minLabel,
8238
+ maxLabel,
8239
+ fillColor = DEFAULT_FILL_COLOR,
8240
+ trackColor = DEFAULT_TRACK_COLOR,
8241
+ valueColor = DEFAULT_VALUE_COLOR,
8242
+ minLabelColor = DEFAULT_MIN_LABEL_COLOR,
8243
+ // maxLabel color defaults to the fill color so a positive reading reads as one accent.
8244
+ maxLabelColor,
8245
+ titleColor = DEFAULT_TITLE_COLOR,
8246
+ className
8247
+ }) {
8248
+ const span = max - min;
8249
+ const fraction = span > 0 ? clamp01((value - min) / span) : 0;
8250
+ const arcPath = halfCircleArcPath(CX, CY, RADIUS2);
8251
+ const len = arcLength(RADIUS2);
8252
+ const fillDashOffset = dashOffsetForFraction(len, fraction);
8253
+ const readout = displayValue ?? String(value);
8254
+ const resolvedMaxLabelColor = maxLabelColor ?? fillColor;
8255
+ return /* @__PURE__ */ jsxs(CardShell, { className: cn("w-full max-w-[440px] p-5 sm:p-6", className), children: [
8256
+ /* @__PURE__ */ jsx(
8257
+ "h3",
8258
+ {
8259
+ className: "font-semibold text-lg leading-tight",
8260
+ style: { color: titleColor },
8261
+ children: title
8262
+ }
8263
+ ),
8264
+ /* @__PURE__ */ jsxs("div", { className: "relative mx-auto mt-4 w-full max-w-[280px]", children: [
8265
+ /* @__PURE__ */ jsxs(
8266
+ "svg",
8267
+ {
8268
+ viewBox: `0 0 ${VIEW_W} ${VIEW_H}`,
8269
+ className: "block w-full",
8270
+ role: "img",
8271
+ "aria-label": `${title}: ${readout}`,
8272
+ preserveAspectRatio: "xMidYMid meet",
8273
+ children: [
8274
+ /* @__PURE__ */ jsx(
8275
+ "path",
8276
+ {
8277
+ d: arcPath,
8278
+ fill: "none",
8279
+ stroke: trackColor,
8280
+ strokeWidth: STROKE_WIDTH2,
8281
+ strokeLinecap: "round"
8282
+ }
8283
+ ),
8284
+ /* @__PURE__ */ jsx(
8285
+ "path",
8286
+ {
8287
+ d: arcPath,
8288
+ fill: "none",
8289
+ stroke: fillColor,
8290
+ strokeWidth: STROKE_WIDTH2,
8291
+ strokeLinecap: "round",
8292
+ strokeDasharray: len,
8293
+ strokeDashoffset: fillDashOffset
8294
+ }
8295
+ )
8296
+ ]
8297
+ }
8298
+ ),
8299
+ /* @__PURE__ */ jsx(
8300
+ "div",
8301
+ {
8302
+ className: "pointer-events-none absolute inset-x-0 bottom-0 flex items-end justify-center pb-1",
8303
+ "aria-hidden": "true",
8304
+ children: /* @__PURE__ */ jsx(
8305
+ "span",
8306
+ {
8307
+ className: "font-bold text-5xl leading-none tabular-nums",
8308
+ style: { color: valueColor },
8309
+ children: readout
8310
+ }
8311
+ )
8312
+ }
8313
+ )
8314
+ ] }),
8315
+ (minLabel || maxLabel) && /* @__PURE__ */ jsxs("div", { className: "mx-auto mt-3 flex w-full max-w-[280px] items-baseline justify-between", children: [
8316
+ /* @__PURE__ */ jsx("span", { className: "font-medium text-sm", style: { color: minLabelColor }, children: minLabel }),
8317
+ /* @__PURE__ */ jsx(
8318
+ "span",
8319
+ {
8320
+ className: "font-semibold text-sm",
8321
+ style: { color: resolvedMaxLabelColor },
8322
+ children: maxLabel
8323
+ }
8324
+ )
8325
+ ] })
8326
+ ] });
8327
+ }
8328
+ var TONE_TEXT_COLOR = {
8329
+ default: "",
8330
+ neutral: "",
8331
+ positive: "text-emerald-600",
8332
+ negative: "text-rose-600",
8333
+ warning: "text-amber-600",
8334
+ info: "text-blue-600",
8335
+ muted: "text-slate-400"
8336
+ };
8337
+ function toneTextColor2(tone, toneMap = {}) {
8338
+ if (!tone) return "";
8339
+ const override = toneMap[tone];
8340
+ if (override !== void 0) return override;
8341
+ return TONE_TEXT_COLOR[tone] ?? "";
8342
+ }
8343
+ function parseBoldString(s) {
8344
+ const segments = [];
8345
+ if (!s) return segments;
8346
+ const regex = /\*\*([\s\S]+?)\*\*/g;
8347
+ let lastIndex = 0;
8348
+ let match;
8349
+ while ((match = regex.exec(s)) !== null) {
8350
+ if (match.index > lastIndex) {
8351
+ segments.push({ text: s.slice(lastIndex, match.index) });
8352
+ }
8353
+ segments.push({ text: match[1], bold: true });
8354
+ lastIndex = regex.lastIndex;
8355
+ }
8356
+ if (lastIndex < s.length) {
8357
+ segments.push({ text: s.slice(lastIndex) });
8358
+ }
8359
+ return segments;
8360
+ }
8361
+ function normalizeRich(content) {
8362
+ return typeof content === "string" ? parseBoldString(content) : content;
8363
+ }
8364
+ function renderRich(content, toneMap = {}) {
8365
+ const segments = normalizeRich(content);
8366
+ return segments.map((segment, index) => {
8367
+ const colorClass = toneTextColor2(segment.tone, toneMap);
8368
+ if (segment.code) {
8369
+ return /* @__PURE__ */ jsx(
8370
+ "code",
8371
+ {
8372
+ className: cn(
8373
+ "rounded bg-slate-100 px-1 py-0.5 font-mono text-[0.85em] text-slate-700",
8374
+ colorClass
8375
+ ),
8376
+ children: segment.text
8377
+ },
8378
+ index
8379
+ );
8380
+ }
8381
+ if (segment.bold) {
8382
+ return /* @__PURE__ */ jsx("strong", { className: cn("font-bold", colorClass), children: segment.text }, index);
8383
+ }
8384
+ if (colorClass) {
8385
+ return /* @__PURE__ */ jsx("span", { className: colorClass, children: segment.text }, index);
8386
+ }
8387
+ return /* @__PURE__ */ jsx(Fragment$1, { children: segment.text }, index);
8388
+ });
8389
+ }
8390
+ var VIEW_W2 = 800;
8391
+ var VIEW_H2 = 300;
8392
+ var PAD_LEFT = 8;
8393
+ var PAD_RIGHT = 8;
8394
+ var PAD_TOP = 16;
8395
+ var PAD_BOTTOM = 16;
8396
+ var PLOT_W = VIEW_W2 - PAD_LEFT - PAD_RIGHT;
8397
+ var PLOT_H = VIEW_H2 - PAD_TOP - PAD_BOTTOM;
8398
+ var GRID_COLOR = "#e2e8f0";
8399
+ var AXIS_LABEL_COLOR = "#94a3b8";
8400
+ var BAND_FILL = "#94a3b8";
8401
+ var TABLE_HEADER_BG = "#f8fafc";
8402
+ var TABLE_HEADER_TEXT = "#64748b";
8403
+ var TABLE_ROW_BORDER = "#f1f5f9";
8404
+ var FIRST_COL_TEXT = "#0f172a";
8405
+ var SUMMARY_TEXT_COLOR = "#475569";
8406
+ function niceMax(value) {
8407
+ if (value <= 0) return 1;
8408
+ const magnitude = Math.pow(10, Math.floor(Math.log10(value)));
8409
+ const normalized = value / magnitude;
8410
+ let nice;
8411
+ if (normalized <= 1) nice = 1;
8412
+ else if (normalized <= 2) nice = 2;
8413
+ else if (normalized <= 5) nice = 5;
8414
+ else nice = 10;
8415
+ return nice * magnitude;
8416
+ }
8417
+ function yFor(value, yMax) {
8418
+ const span = yMax || 1;
8419
+ return PAD_TOP + PLOT_H - value / span * PLOT_H;
8420
+ }
8421
+ function xFor(i, n) {
8422
+ if (n <= 1) return PAD_LEFT + PLOT_W / 2;
8423
+ return PAD_LEFT + i / (n - 1) * PLOT_W;
8424
+ }
8425
+ var ALIGN_CLASS = {
8426
+ left: "text-left",
8427
+ right: "text-right",
8428
+ center: "text-center"
8429
+ };
8430
+ function deltaDirection(d) {
8431
+ return d ?? "flat";
8432
+ }
8433
+ function TableListArtifact({
8434
+ chartTitle,
8435
+ series,
8436
+ xAxisLabels,
8437
+ yAxisTicks,
8438
+ chartType = "area",
8439
+ tableColumns,
8440
+ tableRows,
8441
+ summaryText,
8442
+ className
8443
+ }) {
8444
+ const gradientId = useId();
8445
+ const hasSeries = Array.isArray(series) && series.length > 0 && series.some((s) => Array.isArray(s.data) && s.data.length > 0);
8446
+ const dataMax = hasSeries ? Math.max(
8447
+ 0,
8448
+ ...series.flatMap((s) => Array.isArray(s.data) ? s.data : [])
8449
+ ) : 0;
8450
+ const ticks = yAxisTicks && yAxisTicks.length > 0 ? [...yAxisTicks].sort((a, b) => b.value - a.value) : null;
8451
+ const yMax = ticks ? Math.max(...ticks.map((t) => t.value), dataMax) : niceMax(dataMax);
8452
+ const seriesPoints = hasSeries ? series.map((s) => {
8453
+ const data = Array.isArray(s.data) ? s.data : [];
8454
+ const n = data.length;
8455
+ const pts = data.map((v, i) => ({ x: xFor(i, n), y: yFor(v, yMax) }));
8456
+ return { color: s.color, pts };
8457
+ }) : [];
8458
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-4", className), children: [
8459
+ /* @__PURE__ */ jsxs(CardShell, { className: "border-[#e5e7eb] p-6", children: [
8460
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-4", children: [
8461
+ /* @__PURE__ */ jsx("h3", { className: "font-bold text-[1.125rem] text-slate-800 leading-snug", children: chartTitle }),
8462
+ hasSeries && /* @__PURE__ */ jsx("ul", { className: "flex flex-wrap items-center gap-x-4 gap-y-1", children: series.map((s) => /* @__PURE__ */ jsxs(
8463
+ "li",
8464
+ {
8465
+ className: "flex items-center gap-2 text-slate-600 text-sm",
8466
+ children: [
8467
+ /* @__PURE__ */ jsx(
8468
+ "span",
8469
+ {
8470
+ "aria-hidden": "true",
8471
+ className: "inline-block size-2 shrink-0 rounded-full",
8472
+ style: { backgroundColor: s.color }
8473
+ }
8474
+ ),
8475
+ s.name
8476
+ ]
8477
+ },
8478
+ s.name
8479
+ )) })
8480
+ ] }),
8481
+ /* @__PURE__ */ jsxs("div", { className: "mt-5", children: [
8482
+ hasSeries ? /* @__PURE__ */ jsxs(
8483
+ "svg",
8484
+ {
8485
+ className: "block h-[300px] w-full",
8486
+ viewBox: `0 0 ${VIEW_W2} ${VIEW_H2}`,
8487
+ preserveAspectRatio: "none",
8488
+ role: "img",
8489
+ "aria-label": chartTitle,
8490
+ children: [
8491
+ ticks?.map((tick) => {
8492
+ const y = yFor(tick.value, yMax);
8493
+ return /* @__PURE__ */ jsxs("g", { children: [
8494
+ /* @__PURE__ */ jsx(
8495
+ "line",
8496
+ {
8497
+ x1: PAD_LEFT,
8498
+ y1: y,
8499
+ x2: VIEW_W2 - PAD_RIGHT,
8500
+ y2: y,
8501
+ stroke: GRID_COLOR,
8502
+ strokeWidth: 1,
8503
+ style: { vectorEffect: "non-scaling-stroke" }
8504
+ }
8505
+ ),
8506
+ /* @__PURE__ */ jsx(
8507
+ "text",
8508
+ {
8509
+ x: PAD_LEFT,
8510
+ y: y - 6,
8511
+ fill: AXIS_LABEL_COLOR,
8512
+ fontSize: 13,
8513
+ textAnchor: "start",
8514
+ children: tick.label
8515
+ }
8516
+ )
8517
+ ] }, tick.label);
8518
+ }),
8519
+ chartType === "area" && seriesPoints.length >= 2 && seriesPoints[0].pts.length > 1 && seriesPoints[1].pts.length > 1 && /* @__PURE__ */ jsx(
8520
+ "path",
8521
+ {
8522
+ d: bandPath(seriesPoints[0].pts, seriesPoints[1].pts),
8523
+ fill: BAND_FILL,
8524
+ fillOpacity: 0.12,
8525
+ stroke: "none"
8526
+ }
8527
+ ),
8528
+ chartType === "area" && seriesPoints.length > 0 && (() => {
8529
+ const bottom = seriesPoints[seriesPoints.length - 1];
8530
+ const area = buildAreaPath(bottom.pts, VIEW_H2 - PAD_BOTTOM);
8531
+ if (!area) return null;
8532
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
8533
+ /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsxs(
8534
+ "linearGradient",
8535
+ {
8536
+ id: gradientId,
8537
+ x1: "0",
8538
+ y1: "0",
8539
+ x2: "0",
8540
+ y2: "1",
8541
+ children: [
8542
+ /* @__PURE__ */ jsx(
8543
+ "stop",
8544
+ {
8545
+ offset: "0%",
8546
+ stopColor: bottom.color,
8547
+ stopOpacity: 0.14
8548
+ }
8549
+ ),
8550
+ /* @__PURE__ */ jsx(
8551
+ "stop",
8552
+ {
8553
+ offset: "100%",
8554
+ stopColor: bottom.color,
8555
+ stopOpacity: 0
8556
+ }
8557
+ )
8558
+ ]
8559
+ }
8560
+ ) }),
8561
+ /* @__PURE__ */ jsx(
8562
+ "path",
8563
+ {
8564
+ d: area,
8565
+ fill: `url(#${gradientId})`,
8566
+ stroke: "none"
8567
+ }
8568
+ )
8569
+ ] });
8570
+ })(),
8571
+ seriesPoints.map((sp, idx) => {
8572
+ const d = buildLinePath(sp.pts, true);
8573
+ if (!d) return null;
8574
+ return /* @__PURE__ */ jsx(
8575
+ "path",
8576
+ {
8577
+ d,
8578
+ fill: "none",
8579
+ stroke: sp.color,
8580
+ strokeWidth: 3,
8581
+ strokeLinecap: "round",
8582
+ strokeLinejoin: "round",
8583
+ style: { vectorEffect: "non-scaling-stroke" }
8584
+ },
8585
+ series[idx].name
8586
+ );
8587
+ })
8588
+ ]
8589
+ }
8590
+ ) : /* @__PURE__ */ jsx("div", { className: "flex h-[160px] items-center justify-center text-slate-400 text-sm", children: "No data" }),
8591
+ hasSeries && xAxisLabels && xAxisLabels.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-2 flex justify-between px-1", children: xAxisLabels.map((label, i) => /* @__PURE__ */ jsx(
8592
+ "span",
8593
+ {
8594
+ className: "text-slate-400 text-sm",
8595
+ style: { color: AXIS_LABEL_COLOR },
8596
+ children: label
8597
+ },
8598
+ `${label}-${i}`
8599
+ )) })
8600
+ ] })
8601
+ ] }),
8602
+ /* @__PURE__ */ jsx(CardShell, { className: "overflow-hidden border-[#e5e7eb] p-0", children: /* @__PURE__ */ jsxs("table", { className: "w-full border-collapse", children: [
8603
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsx("tr", { style: { backgroundColor: TABLE_HEADER_BG }, children: tableColumns.map((col) => /* @__PURE__ */ jsx(
8604
+ "th",
8605
+ {
8606
+ scope: "col",
8607
+ className: cn(
8608
+ "px-6 py-4 font-semibold text-[0.75rem] uppercase tracking-wider",
8609
+ ALIGN_CLASS[col.align ?? "left"]
8610
+ ),
8611
+ style: { color: TABLE_HEADER_TEXT },
8612
+ children: col.label
8613
+ },
8614
+ col.key
8615
+ )) }) }),
8616
+ /* @__PURE__ */ jsx("tbody", { children: tableRows.map((row, rowIndex) => /* @__PURE__ */ jsx(
8617
+ "tr",
8618
+ {
8619
+ style: {
8620
+ borderTop: rowIndex === 0 ? void 0 : `1px solid ${TABLE_ROW_BORDER}`
8621
+ },
8622
+ children: tableColumns.map((col, colIndex) => {
8623
+ const align = col.align ?? (colIndex === 0 ? "left" : "right");
8624
+ if (colIndex === 0) {
8625
+ return /* @__PURE__ */ jsx(
8626
+ "td",
8627
+ {
8628
+ className: cn(
8629
+ "px-6 py-5 font-bold text-[1.0625rem]",
8630
+ ALIGN_CLASS[align]
8631
+ ),
8632
+ style: { color: FIRST_COL_TEXT },
8633
+ children: row.label
8634
+ },
8635
+ col.key
8636
+ );
8637
+ }
8638
+ if (colIndex === 1) {
8639
+ return /* @__PURE__ */ jsx(
8640
+ "td",
8641
+ {
8642
+ className: cn(
8643
+ "px-6 py-5 text-[1.0625rem] text-slate-700 tabular-nums",
8644
+ ALIGN_CLASS[align]
8645
+ ),
8646
+ children: row.value
8647
+ },
8648
+ col.key
8649
+ );
8650
+ }
8651
+ return /* @__PURE__ */ jsx(
8652
+ "td",
8653
+ {
8654
+ className: cn("px-6 py-5", ALIGN_CLASS[align]),
8655
+ children: row.delta ? /* @__PURE__ */ jsx(
8656
+ DeltaPill,
8657
+ {
8658
+ value: row.delta.text,
8659
+ direction: deltaDirection(row.delta.direction),
8660
+ hideArrow: true,
8661
+ className: "bg-transparent px-0 py-0 font-semibold text-sm"
8662
+ }
8663
+ ) : null
8664
+ },
8665
+ col.key
8666
+ );
8667
+ })
8668
+ },
8669
+ `${row.label}-${rowIndex}`
8670
+ )) })
8671
+ ] }) }),
8672
+ summaryText && /* @__PURE__ */ jsx(
8673
+ "p",
8674
+ {
8675
+ className: "text-[1rem] leading-relaxed",
8676
+ style: { color: SUMMARY_TEXT_COLOR },
8677
+ children: renderRich(summaryText)
8678
+ }
8679
+ )
8680
+ ] });
8681
+ }
8682
+ function bandPath(top, bottom) {
8683
+ if (top.length === 0 || bottom.length === 0) return "";
8684
+ const fmt2 = (n) => Number.isInteger(n) ? String(n) : String(Math.round(n * 1e3) / 1e3);
8685
+ const forward = top.map((p, i) => `${i === 0 ? "M" : "L"} ${fmt2(p.x)} ${fmt2(p.y)}`).join(" ");
8686
+ const back = [...bottom].reverse().map((p) => `L ${fmt2(p.x)} ${fmt2(p.y)}`).join(" ");
8687
+ return `${forward} ${back} Z`;
8688
+ }
8689
+ var DEFAULT_ICON_CHIP_BG = "#F1F5F9";
8690
+ var DEFAULT_ICON_CHIP_FG = "#334155";
8691
+ var DEFAULT_VALUE_COLOR2 = "#0F172A";
8692
+ var DEFAULT_SPARKLINE_COLOR = "#10B981";
8693
+ function KpiCardWithSparklines({
8694
+ label,
8695
+ value,
8696
+ delta,
8697
+ caption,
8698
+ icon,
8699
+ iconChipBg,
8700
+ iconChipFg,
8701
+ sparkline,
8702
+ accentColor,
8703
+ valueColor,
8704
+ className,
8705
+ onClick
8706
+ }) {
8707
+ const sparklineColor = sparkline?.color ?? accentColor ?? DEFAULT_SPARKLINE_COLOR;
8708
+ const sparkData = sparkline?.data ?? [];
8709
+ const hasSparkline = sparkData.length >= 2;
8710
+ const interactive = typeof onClick === "function";
8711
+ const body = /* @__PURE__ */ jsxs("div", { className: "p-6", children: [
8712
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3", children: [
8713
+ /* @__PURE__ */ jsx("p", { className: "font-medium text-base text-slate-500 leading-snug", children: label }),
8714
+ icon != null && icon !== "" && /* @__PURE__ */ jsx(
8715
+ "span",
8716
+ {
8717
+ "aria-hidden": "true",
8718
+ className: "flex h-10 w-10 shrink-0 items-center justify-center rounded-lg font-semibold text-lg",
8719
+ style: {
8720
+ backgroundColor: iconChipBg ?? DEFAULT_ICON_CHIP_BG,
8721
+ color: iconChipFg ?? DEFAULT_ICON_CHIP_FG
8722
+ },
8723
+ children: icon
8724
+ }
8725
+ )
8726
+ ] }),
8727
+ /* @__PURE__ */ jsxs("div", { className: "mt-4 flex flex-wrap items-end gap-x-3 gap-y-1", children: [
8728
+ /* @__PURE__ */ jsx(
8729
+ "span",
8730
+ {
8731
+ className: "font-extrabold text-5xl leading-none tracking-tight tabular-nums",
8732
+ style: { color: valueColor ?? DEFAULT_VALUE_COLOR2 },
8733
+ children: value
8734
+ }
8735
+ ),
8736
+ delta && /* @__PURE__ */ jsx(
8737
+ DeltaPill,
8738
+ {
8739
+ value: delta.value,
8740
+ direction: delta.direction,
8741
+ tone: delta.tone,
8742
+ className: "mb-1 px-2.5 py-1 text-sm"
8743
+ }
8744
+ )
8745
+ ] }),
8746
+ caption && /* @__PURE__ */ jsx("p", { className: "mt-1 text-slate-400 text-xs", children: caption }),
8747
+ hasSparkline && /* @__PURE__ */ jsx("div", { className: "-mx-6 -mb-6 mt-5", children: /* @__PURE__ */ jsx(
8748
+ Sparkline,
8749
+ {
8750
+ data: sparkData,
8751
+ color: sparklineColor,
8752
+ showArea: sparkline?.showArea ?? true,
8753
+ smooth: sparkline?.smooth ?? false,
8754
+ className: "h-24 w-full"
8755
+ }
8756
+ ) })
8757
+ ] });
8758
+ return /* @__PURE__ */ jsx(
8759
+ CardShell,
8760
+ {
8761
+ className: cn(
8762
+ "overflow-hidden",
8763
+ interactive && "cursor-pointer transition-shadow hover:shadow-md",
8764
+ className
8765
+ ),
8766
+ children: interactive ? /* @__PURE__ */ jsx(
8767
+ "div",
8768
+ {
8769
+ role: "button",
8770
+ tabIndex: 0,
8771
+ onClick,
8772
+ onKeyDown: (event) => {
8773
+ if (event.key === "Enter" || event.key === " ") {
8774
+ event.preventDefault();
8775
+ onClick?.();
8776
+ }
8777
+ },
8778
+ className: "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
8779
+ children: body
8780
+ }
8781
+ ) : body
8782
+ }
8783
+ );
8784
+ }
8785
+ var DEFAULT_LOCATION_LABEL = "Location";
8786
+ var DEFAULT_REVENUE_LABEL = "Rev";
8787
+ var DEFAULT_STATUS_LABEL = "Status";
8788
+ var GRID_TEMPLATE = "grid grid-cols-[1fr_auto_3rem] items-center gap-x-4 px-6";
8789
+ function LocationTableRow({ row }) {
8790
+ return /* @__PURE__ */ jsxs("div", { className: cn(GRID_TEMPLATE, "py-5"), role: "row", children: [
8791
+ /* @__PURE__ */ jsx(
8792
+ "span",
8793
+ {
8794
+ role: "cell",
8795
+ className: "truncate font-semibold text-[1.0625rem] text-slate-800",
8796
+ children: row.name
8797
+ }
8798
+ ),
8799
+ /* @__PURE__ */ jsx(
8800
+ "span",
8801
+ {
8802
+ role: "cell",
8803
+ className: "text-right text-[1.0625rem] text-slate-700 tabular-nums",
8804
+ children: row.revenue
8805
+ }
8806
+ ),
8807
+ /* @__PURE__ */ jsx("span", { role: "cell", className: "flex justify-end", children: /* @__PURE__ */ jsx(
8808
+ StatusDot,
8809
+ {
8810
+ status: row.status,
8811
+ color: row.statusColor,
8812
+ label: row.statusLabel,
8813
+ size: 13
8814
+ }
8815
+ ) })
8816
+ ] });
8817
+ }
8818
+ function LocationsRevenueCard({
8819
+ locationColumnLabel = DEFAULT_LOCATION_LABEL,
8820
+ revenueColumnLabel = DEFAULT_REVENUE_LABEL,
8821
+ statusColumnLabel = DEFAULT_STATUS_LABEL,
8822
+ rows,
8823
+ className
8824
+ }) {
8825
+ const hasRows = Array.isArray(rows) && rows.length > 0;
8826
+ return /* @__PURE__ */ jsx(CardShell, { className: cn("overflow-hidden", className), children: /* @__PURE__ */ jsxs("div", { role: "table", "aria-label": locationColumnLabel, children: [
8827
+ /* @__PURE__ */ jsxs(
8828
+ "div",
8829
+ {
8830
+ role: "row",
8831
+ className: cn(
8832
+ GRID_TEMPLATE,
8833
+ "border-b bg-slate-50 py-4 font-semibold text-[0.75rem] text-slate-400 uppercase tracking-wider"
8834
+ ),
8835
+ children: [
8836
+ /* @__PURE__ */ jsx("span", { role: "columnheader", className: "text-left", children: locationColumnLabel }),
8837
+ /* @__PURE__ */ jsx("span", { role: "columnheader", className: "text-right", children: revenueColumnLabel }),
8838
+ /* @__PURE__ */ jsx("span", { role: "columnheader", className: "text-right", children: statusColumnLabel })
8839
+ ]
8840
+ }
8841
+ ),
8842
+ hasRows ? /* @__PURE__ */ jsx("div", { className: "divide-y", children: rows.map((row, index) => /* @__PURE__ */ jsx(LocationTableRow, { row }, row.id ?? `${row.name}-${index}`)) }) : /* @__PURE__ */ jsx("div", { className: "px-6 py-8 text-center text-slate-400 text-sm", children: "No locations" })
8843
+ ] }) });
8844
+ }
8845
+ var DENSITY_CELL_PADDING = {
8846
+ comfortable: "px-6 py-4",
8847
+ compact: "px-6 py-3"
8848
+ };
8849
+ function RowBasedDataList({
8850
+ rows,
8851
+ title,
8852
+ labelColumnWidth = "30%",
8853
+ density = "comfortable",
8854
+ className
8855
+ }) {
8856
+ const cellPadding = DENSITY_CELL_PADDING[density] ?? DENSITY_CELL_PADDING.comfortable;
8857
+ const hasRows = Array.isArray(rows) && rows.length > 0;
8858
+ return /* @__PURE__ */ jsxs("div", { className: cn("w-full", className), children: [
8859
+ title && /* @__PURE__ */ jsx("p", { className: "mb-2 font-medium text-slate-700 text-sm", children: title }),
8860
+ /* @__PURE__ */ jsx(CardShell, { className: "overflow-hidden rounded-xl border-slate-200 shadow-none", children: hasRows ? /* @__PURE__ */ jsx(
8861
+ "dl",
8862
+ {
8863
+ className: "grid",
8864
+ style: { gridTemplateColumns: `${labelColumnWidth} 1fr` },
8865
+ children: rows.map((row, index) => {
8866
+ const isLast = index === rows.length - 1;
8867
+ return /* @__PURE__ */ jsx(
8868
+ RowPair,
8869
+ {
8870
+ row,
8871
+ isLast,
8872
+ cellPadding
8873
+ },
8874
+ `${row.label}-${index}`
8875
+ );
8876
+ })
8877
+ }
8878
+ ) : /* @__PURE__ */ jsx("p", { className: "px-6 py-5 text-slate-400 text-sm", children: "No details available" }) })
8879
+ ] });
8880
+ }
8881
+ function RowPair({ row, isLast, cellPadding }) {
8882
+ const valueColorClass = toneTextColor(row.valueColor);
8883
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
8884
+ /* @__PURE__ */ jsx(
8885
+ "dt",
8886
+ {
8887
+ className: cn(
8888
+ "min-w-0 break-words bg-slate-50/70 font-normal text-slate-500 text-[0.9375rem] leading-snug",
8889
+ cellPadding,
8890
+ !isLast && "border-slate-100 border-b"
8891
+ ),
8892
+ children: row.label
8893
+ }
8894
+ ),
8895
+ /* @__PURE__ */ jsx(
8896
+ "dd",
8897
+ {
8898
+ className: cn(
8899
+ "min-w-0 break-words border-slate-100 border-l font-medium text-[0.9375rem] leading-snug",
8900
+ valueColorClass,
8901
+ cellPadding,
8902
+ !isLast && "border-b"
8903
+ ),
8904
+ children: row.href ? /* @__PURE__ */ jsx(
8905
+ "a",
8906
+ {
8907
+ href: row.href,
8908
+ target: "_blank",
8909
+ rel: "noreferrer noopener",
8910
+ className: "underline decoration-slate-300 underline-offset-2 hover:decoration-current",
8911
+ children: row.value
8912
+ }
8913
+ ) : row.value
8914
+ }
8915
+ )
8916
+ ] });
8917
+ }
8918
+ var TONE_STYLES = {
8919
+ green: { bg: "#E7F6EC", text: "#16A34A" },
8920
+ blue: { bg: "#E8EDFB", text: "#3B5BDB" },
8921
+ amber: { bg: "#FBEFD3", text: "#B45309" },
8922
+ red: { bg: "#FCE4E7", text: "#DC2626" },
8923
+ gray: { bg: "#F4F5F7", text: "#374151" },
8924
+ neutral: { bg: "#F4F5F7", text: "#374151" }
8925
+ };
8926
+ var TAG_BG = "#F4F5F7";
8927
+ var TAG_BORDER = "#E5E7EB";
8928
+ var TAG_TEXT = "#374151";
8929
+ var DEFAULT_TONE = "neutral";
8930
+ function tintFromColor(color) {
8931
+ const hex = /^#([0-9a-fA-F]{6})$/.exec(color);
8932
+ if (!hex) return color;
8933
+ return `#${hex[1]}24`;
8934
+ }
8935
+ function resolveSolidStyle(badge) {
8936
+ if (badge.color) {
8937
+ return { bg: tintFromColor(badge.color), text: badge.color };
8938
+ }
8939
+ const tone = badge.tone ?? DEFAULT_TONE;
8940
+ return TONE_STYLES[tone] ?? TONE_STYLES[DEFAULT_TONE];
8941
+ }
8942
+ function resolveDotColor(badge) {
8943
+ if (badge.dotColor) return badge.dotColor;
8944
+ if (badge.color) return badge.color;
8945
+ const tone = badge.tone ?? DEFAULT_TONE;
8946
+ return TONE_STYLES[tone]?.text ?? TONE_STYLES[DEFAULT_TONE].text;
8947
+ }
8948
+ function BadgePill({ badge, groupStyle }) {
8949
+ const style = badge.style ?? groupStyle;
8950
+ const baseClass = "inline-flex items-center rounded-full px-4 py-1.5 font-medium text-sm whitespace-nowrap";
8951
+ if (style === "outline") {
8952
+ return /* @__PURE__ */ jsxs(
8953
+ "span",
8954
+ {
8955
+ className: cn(baseClass, "border"),
8956
+ style: {
8957
+ backgroundColor: TAG_BG,
8958
+ borderColor: TAG_BORDER,
8959
+ color: TAG_TEXT
8960
+ },
8961
+ children: [
8962
+ badge.dot && /* @__PURE__ */ jsx(
8963
+ "span",
8964
+ {
8965
+ "aria-hidden": "true",
8966
+ className: "mr-2 inline-block size-2 shrink-0 rounded-full",
8967
+ style: { backgroundColor: resolveDotColor(badge) }
8968
+ }
8969
+ ),
8970
+ badge.label
8971
+ ]
8972
+ }
8973
+ );
8974
+ }
8975
+ const solid = resolveSolidStyle(badge);
8976
+ return /* @__PURE__ */ jsxs(
8977
+ "span",
8978
+ {
8979
+ className: baseClass,
8980
+ style: { backgroundColor: solid.bg, color: solid.text },
8981
+ children: [
8982
+ badge.dot && /* @__PURE__ */ jsx(
8983
+ "span",
8984
+ {
8985
+ "aria-hidden": "true",
8986
+ className: "mr-2 inline-block size-2 shrink-0 rounded-full",
8987
+ style: { backgroundColor: resolveDotColor(badge) }
8988
+ }
8989
+ ),
8990
+ badge.label
8991
+ ]
8992
+ }
8993
+ );
8994
+ }
8995
+ function BadgeGroupBlock({ group }) {
8996
+ const badges = group.badges ?? [];
8997
+ if (badges.length === 0) return null;
8998
+ const groupStyle = group.variant === "tag" ? "outline" : "solid";
8999
+ return /* @__PURE__ */ jsxs("div", { children: [
9000
+ group.label && /* @__PURE__ */ jsx("span", { className: "mb-2 block font-medium text-[11px] text-gray-400 uppercase tracking-wider", children: group.label }),
9001
+ /* @__PURE__ */ jsx("div", { className: "flex flex-wrap items-center gap-3", children: badges.map((badge, i) => {
9002
+ if (!badge?.label) return null;
9003
+ return /* @__PURE__ */ jsx(
9004
+ BadgePill,
9005
+ {
9006
+ badge,
9007
+ groupStyle
9008
+ },
9009
+ `${badge.label}-${i}`
9010
+ );
9011
+ }) })
9012
+ ] });
9013
+ }
9014
+ function BadgesArtifact({ groups, className }) {
9015
+ const safeGroups = groups ?? [];
9016
+ if (safeGroups.length === 0) return null;
9017
+ return /* @__PURE__ */ jsx("div", { className: cn("flex flex-col gap-6", className), children: safeGroups.map((group, i) => /* @__PURE__ */ jsx(BadgeGroupBlock, { group }, group.label ?? `group-${i}`)) });
9018
+ }
9019
+ var BADGE_TONE_CLASSES = {
9020
+ default: "bg-slate-100 text-slate-600",
9021
+ positive: "bg-emerald-50 text-emerald-700",
9022
+ negative: "bg-rose-50 text-rose-700",
9023
+ muted: "bg-slate-50 text-slate-400",
9024
+ info: "bg-blue-50 text-blue-700"
9025
+ };
9026
+ function badgeToneClass(tone) {
9027
+ if (!tone) return BADGE_TONE_CLASSES.default;
9028
+ return BADGE_TONE_CLASSES[tone] ?? BADGE_TONE_CLASSES.default;
9029
+ }
9030
+ function OrderedListArtifact({
9031
+ title,
9032
+ intro,
9033
+ items,
9034
+ startIndex = 1,
9035
+ markerStyle = "number",
9036
+ className
9037
+ }) {
9038
+ const safeItems = Array.isArray(items) ? items : [];
9039
+ return /* @__PURE__ */ jsxs("section", { className: cn("text-left", className), children: [
9040
+ title ? /* @__PURE__ */ jsx("h3", { className: "font-bold text-slate-900 text-xl leading-snug", children: title }) : null,
9041
+ intro ? /* @__PURE__ */ jsx(
9042
+ "p",
9043
+ {
9044
+ className: cn(
9045
+ "text-slate-500 text-[16px] leading-relaxed",
9046
+ title && "mt-4"
9047
+ ),
9048
+ children: renderRich(intro)
9049
+ }
9050
+ ) : null,
9051
+ safeItems.length > 0 ? /* @__PURE__ */ jsx(
9052
+ "ol",
9053
+ {
9054
+ className: cn(
9055
+ "flex list-none flex-col gap-3.5",
9056
+ (title || intro) && "mt-5"
9057
+ ),
9058
+ children: safeItems.map((item, index) => {
9059
+ const marker = item.marker ?? formatMarker(index, markerStyle, startIndex);
9060
+ return /* @__PURE__ */ jsxs(
9061
+ "li",
9062
+ {
9063
+ className: "flex items-start gap-3.5",
9064
+ children: [
9065
+ /* @__PURE__ */ jsx(
9066
+ "span",
9067
+ {
9068
+ className: cn(
9069
+ "flex h-7 w-7 shrink-0 items-center justify-center rounded-md font-medium text-sm tabular-nums",
9070
+ badgeToneClass(item.tone)
9071
+ ),
9072
+ children: marker
9073
+ }
9074
+ ),
9075
+ /* @__PURE__ */ jsx("div", { className: "flex-1 pt-0.5 text-slate-900 text-[16px] leading-relaxed", children: renderRich(item.content) })
9076
+ ]
9077
+ },
9078
+ index
9079
+ );
9080
+ })
9081
+ }
9082
+ ) : null
9083
+ ] });
9084
+ }
9085
+ var COMPLETE_BG = "#E6F4EC";
9086
+ var COMPLETE_ACCENT = "#16A34A";
9087
+ var ACTIVE_COLOR = "#F59E0B";
9088
+ var PENDING_STROKE = "#CBD5E1";
9089
+ var ERROR_BG = "#FEE2E2";
9090
+ var ERROR_COLOR = "#DC2626";
9091
+ var SPIN_CLASS = "ae-spin";
9092
+ var SPIN_STYLE_ID = "ae-spin-keyframes";
9093
+ function ensureSpinKeyframes() {
9094
+ if (typeof document === "undefined") return;
9095
+ if (document.getElementById(SPIN_STYLE_ID)) return;
9096
+ const style = document.createElement("style");
9097
+ style.id = SPIN_STYLE_ID;
9098
+ style.textContent = `@keyframes ${SPIN_CLASS}{to{transform:rotate(360deg)}}@media (prefers-reduced-motion: no-preference){.${SPIN_CLASS}{animation:${SPIN_CLASS} 0.8s linear infinite;transform-origin:center}}`;
9099
+ document.head.appendChild(style);
9100
+ }
9101
+ function resolveSize(size) {
9102
+ if (typeof size === "number") return size;
9103
+ switch (size) {
9104
+ case "sm":
9105
+ return 24;
9106
+ case "lg":
9107
+ return 48;
9108
+ case "md":
9109
+ default:
9110
+ return 34;
9111
+ }
9112
+ }
9113
+ function normalizeStatus(status) {
9114
+ switch (status) {
9115
+ case "completed":
9116
+ return "complete";
9117
+ case "in_progress":
9118
+ return "active";
9119
+ case "active":
9120
+ case "pending":
9121
+ case "error":
9122
+ case "complete":
9123
+ return status;
9124
+ default:
9125
+ return "complete";
9126
+ }
9127
+ }
9128
+ function CheckIcon8({
9129
+ color = COMPLETE_ACCENT,
9130
+ className,
9131
+ style,
9132
+ strokeWidth = 2.25
9133
+ }) {
9134
+ return /* @__PURE__ */ jsx(
9135
+ "svg",
9136
+ {
9137
+ viewBox: "0 0 24 24",
9138
+ fill: "none",
9139
+ stroke: color,
9140
+ strokeWidth,
9141
+ strokeLinecap: "round",
9142
+ strokeLinejoin: "round",
9143
+ "aria-hidden": "true",
9144
+ className,
9145
+ style,
9146
+ children: /* @__PURE__ */ jsx("path", { d: "M5 12l4 4 8-9" })
9147
+ }
9148
+ );
9149
+ }
9150
+ function ClockIcon2({
9151
+ color = "#64748B",
9152
+ className,
9153
+ strokeWidth = 1.75
9154
+ }) {
9155
+ return /* @__PURE__ */ jsxs(
9156
+ "svg",
9157
+ {
9158
+ viewBox: "0 0 24 24",
9159
+ fill: "none",
9160
+ stroke: color,
9161
+ strokeWidth,
9162
+ strokeLinecap: "round",
9163
+ strokeLinejoin: "round",
9164
+ "aria-hidden": "true",
9165
+ className,
9166
+ children: [
9167
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "9" }),
9168
+ /* @__PURE__ */ jsx("path", { d: "M12 7v5l3 2" })
9169
+ ]
9170
+ }
9171
+ );
9172
+ }
9173
+ function XIcon7({
9174
+ color = ERROR_COLOR,
9175
+ className,
9176
+ style
9177
+ }) {
9178
+ return /* @__PURE__ */ jsx(
9179
+ "svg",
9180
+ {
9181
+ viewBox: "0 0 24 24",
9182
+ fill: "none",
9183
+ stroke: color,
9184
+ strokeWidth: 2.25,
9185
+ strokeLinecap: "round",
9186
+ strokeLinejoin: "round",
9187
+ "aria-hidden": "true",
9188
+ className,
9189
+ style,
9190
+ children: /* @__PURE__ */ jsx("path", { d: "M7 7l10 10M17 7L7 17" })
9191
+ }
9192
+ );
9193
+ }
9194
+ function StatusNode({ status, size, accentColor, className }) {
9195
+ const resolved = normalizeStatus(status);
9196
+ const px = resolveSize(size);
9197
+ const accent = accentColor ?? COMPLETE_ACCENT;
9198
+ if (resolved === "active") ensureSpinKeyframes();
9199
+ const base = cn(
9200
+ "inline-flex shrink-0 items-center justify-center rounded-full",
9201
+ className
9202
+ );
9203
+ const dimensions = { width: px, height: px };
9204
+ const glyphPx = Math.round(px * 0.5);
9205
+ if (resolved === "complete") {
9206
+ return /* @__PURE__ */ jsx(
9207
+ "span",
9208
+ {
9209
+ className: base,
9210
+ style: { ...dimensions, backgroundColor: COMPLETE_BG },
9211
+ "data-status": "complete",
9212
+ children: /* @__PURE__ */ jsx(CheckIcon8, { color: accent, className: "block", style: { width: glyphPx, height: glyphPx } })
9213
+ }
9214
+ );
9215
+ }
9216
+ if (resolved === "error") {
9217
+ return /* @__PURE__ */ jsx(
9218
+ "span",
9219
+ {
9220
+ className: base,
9221
+ style: { ...dimensions, backgroundColor: ERROR_BG },
9222
+ "data-status": "error",
9223
+ children: /* @__PURE__ */ jsx(XIcon7, { color: ERROR_COLOR, className: "block", style: { width: glyphPx, height: glyphPx } })
9224
+ }
9225
+ );
9226
+ }
9227
+ if (resolved === "active") {
9228
+ const ringColor = accentColor ?? ACTIVE_COLOR;
9229
+ return /* @__PURE__ */ jsx(
9230
+ "span",
9231
+ {
9232
+ className: base,
9233
+ style: dimensions,
9234
+ "data-status": "active",
9235
+ role: "status",
9236
+ "aria-label": "In progress",
9237
+ "aria-live": "polite",
9238
+ children: /* @__PURE__ */ jsx("span", { className: cn(SPIN_CLASS, "block"), style: { width: px, height: px }, children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", className: "block size-full", children: /* @__PURE__ */ jsx(
9239
+ "circle",
9240
+ {
9241
+ cx: "12",
9242
+ cy: "12",
9243
+ r: "10",
9244
+ fill: "none",
9245
+ stroke: ringColor,
9246
+ strokeWidth: "2.5",
9247
+ strokeLinecap: "round",
9248
+ strokeDasharray: "47 16"
9249
+ }
9250
+ ) }) })
9251
+ }
9252
+ );
9253
+ }
9254
+ return /* @__PURE__ */ jsx("span", { className: base, style: dimensions, "data-status": "pending", children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", className: "block size-full", children: /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10", fill: "none", stroke: PENDING_STROKE, strokeWidth: "1.75" }) }) });
9255
+ }
9256
+ var DEFAULT_TASK_LABEL = "RESEARCH TASK";
9257
+ var DEFAULT_FINDINGS_LABEL = "EMERGING FINDINGS";
9258
+ function stepLabelClass(status) {
9259
+ switch (status) {
9260
+ case "completed":
9261
+ return "font-normal text-slate-700";
9262
+ case "in_progress":
9263
+ return "font-bold text-slate-900";
9264
+ case "pending":
9265
+ default:
9266
+ return "font-normal text-slate-400";
9267
+ }
9268
+ }
9269
+ function hasRichContent(findings) {
9270
+ if (findings == null) return false;
9271
+ if (typeof findings === "string") return findings.trim().length > 0;
9272
+ return findings.some((segment) => segment.text.trim().length > 0);
9273
+ }
9274
+ function DeepResearchProgress({
9275
+ taskLabel = DEFAULT_TASK_LABEL,
9276
+ taskDescription,
9277
+ steps,
9278
+ findingsLabel = DEFAULT_FINDINGS_LABEL,
9279
+ findings,
9280
+ showFindings,
9281
+ className
9282
+ }) {
9283
+ const safeSteps = Array.isArray(steps) ? steps : [];
9284
+ const findingsHasContent = hasRichContent(findings);
9285
+ const findingsVisible = findingsHasContent && showFindings !== false;
9286
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex w-full flex-col gap-6 text-left", className), children: [
9287
+ /* @__PURE__ */ jsxs(CardShell, { className: "rounded-xl border-slate-200/80 bg-slate-50/70 px-5 py-4 shadow-none", children: [
9288
+ taskLabel ? /* @__PURE__ */ jsx("p", { className: "font-medium text-[11px] text-slate-400 uppercase tracking-wider", children: taskLabel }) : null,
9289
+ /* @__PURE__ */ jsx("p", { className: "mt-2 text-[16px] text-slate-700 leading-relaxed", children: taskDescription })
9290
+ ] }),
9291
+ safeSteps.length > 0 ? /* @__PURE__ */ jsx("ol", { className: "flex list-none flex-col gap-5", children: safeSteps.map((step, index) => /* @__PURE__ */ jsxs(
9292
+ "li",
9293
+ {
9294
+ className: "flex items-center gap-4",
9295
+ "data-status": step.status,
9296
+ children: [
9297
+ /* @__PURE__ */ jsx(StatusNode, { status: step.status, size: "md" }),
9298
+ /* @__PURE__ */ jsx(
9299
+ "span",
9300
+ {
9301
+ className: cn(
9302
+ "text-[17px] leading-snug",
9303
+ stepLabelClass(step.status)
9304
+ ),
9305
+ children: step.label
9306
+ }
9307
+ )
9308
+ ]
9309
+ },
9310
+ step.id ?? index
9311
+ )) }) : null,
9312
+ findingsVisible ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
9313
+ /* @__PURE__ */ jsx("hr", { className: "border-slate-200 border-t" }),
9314
+ /* @__PURE__ */ jsxs("div", { children: [
9315
+ findingsLabel ? /* @__PURE__ */ jsx("p", { className: "font-medium text-[11px] text-slate-400 uppercase tracking-wider", children: findingsLabel }) : null,
9316
+ /* @__PURE__ */ jsx("p", { className: "mt-3 text-[16px] text-slate-700 leading-relaxed [&_strong]:text-slate-900", children: renderRich(findings) })
9317
+ ] })
9318
+ ] }) : null
9319
+ ] });
9320
+ }
9321
+ var NODE_SIZE = 48;
9322
+ var NODE_COLUMN_WIDTH = NODE_SIZE;
9323
+ var DEFAULT_ACCENT = "#16A34A";
9324
+ var FOOTER_SEPARATOR = " \xB7 ";
9325
+ function resolveFooterItems(footer) {
9326
+ if (!footer) return [];
9327
+ if (Array.isArray(footer.items) && footer.items.length > 0) {
9328
+ return footer.items.filter((item) => item != null && item !== "");
7676
9329
  }
7677
- if (payload.type === "metrics" && payload.metrics) {
7678
- return /* @__PURE__ */ jsx(MetricsGrid, { metrics: payload.metrics, className });
9330
+ const parts = [];
9331
+ if (footer.thinkingLabel) parts.push(footer.thinkingLabel);
9332
+ if (footer.sourcesLabel) parts.push(footer.sourcesLabel);
9333
+ return parts;
9334
+ }
9335
+ function TimelineStep({
9336
+ step,
9337
+ isLast,
9338
+ accentColor
9339
+ }) {
9340
+ return /* @__PURE__ */ jsxs("li", { className: "relative flex gap-4", "data-status": step.status ?? "complete", children: [
9341
+ /* @__PURE__ */ jsxs(
9342
+ "div",
9343
+ {
9344
+ className: "relative flex shrink-0 justify-center",
9345
+ style: { width: NODE_COLUMN_WIDTH },
9346
+ children: [
9347
+ !isLast && /* @__PURE__ */ jsx(
9348
+ "span",
9349
+ {
9350
+ "aria-hidden": "true",
9351
+ className: "absolute top-1/2 bottom-0 w-0.5 bg-slate-200",
9352
+ style: { top: NODE_SIZE / 2, height: `calc(100% - ${NODE_SIZE / 2}px)` }
9353
+ }
9354
+ ),
9355
+ /* @__PURE__ */ jsx(
9356
+ StatusNode,
9357
+ {
9358
+ status: step.status ?? "complete",
9359
+ size: NODE_SIZE,
9360
+ accentColor,
9361
+ className: "relative z-10"
9362
+ }
9363
+ )
9364
+ ]
9365
+ }
9366
+ ),
9367
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-1.5 pt-1.5 pb-8", children: [
9368
+ /* @__PURE__ */ jsx("p", { className: "font-semibold text-[1.0625rem] text-slate-900 leading-snug", children: step.title }),
9369
+ step.description ? /* @__PURE__ */ jsx("p", { className: "text-[0.9375rem] text-slate-500 leading-snug", children: step.description }) : null
9370
+ ] })
9371
+ ] });
9372
+ }
9373
+ function Tracker({
9374
+ steps,
9375
+ footer,
9376
+ showFooterIcon = true,
9377
+ accentColor = DEFAULT_ACCENT,
9378
+ className
9379
+ }) {
9380
+ const hasSteps = Array.isArray(steps) && steps.length > 0;
9381
+ const footerItems = resolveFooterItems(footer);
9382
+ const hasFooter = footerItems.length > 0;
9383
+ return /* @__PURE__ */ jsxs("div", { className: cn("w-full bg-card pl-2", className), children: [
9384
+ hasSteps ? /* @__PURE__ */ jsx("ol", { className: "flex flex-col", children: steps.map((step, index) => /* @__PURE__ */ jsx(
9385
+ TimelineStep,
9386
+ {
9387
+ step,
9388
+ isLast: index === steps.length - 1,
9389
+ accentColor
9390
+ },
9391
+ step.id ?? `${step.title}-${index}`
9392
+ )) }) : /* @__PURE__ */ jsx("p", { className: "py-6 text-slate-400 text-sm", children: "No steps" }),
9393
+ hasFooter ? /* @__PURE__ */ jsx("div", { className: "mt-2 border-slate-200 border-t pt-5", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-[0.9375rem] text-slate-500", children: [
9394
+ showFooterIcon ? /* @__PURE__ */ jsx(ClockIcon2, { className: "size-4 shrink-0" }) : null,
9395
+ /* @__PURE__ */ jsx("span", { children: footerItems.join(FOOTER_SEPARATOR) })
9396
+ ] }) }) : null
9397
+ ] });
9398
+ }
9399
+ var DEFAULTS = {
9400
+ /** Selected row background — emerald-50. */
9401
+ selectedBg: "#ECFDF5",
9402
+ /** Selected row border — emerald-200. */
9403
+ selectedBorder: "#A7F3D0",
9404
+ /** Selected radio circle fill — emerald-500. */
9405
+ selectedCircle: "#10B981",
9406
+ /** Selected label text — slate-900. */
9407
+ selectedLabel: "#0F172A",
9408
+ /** Unselected row border — slate-200. */
9409
+ unselectedBorder: "#E2E8F0",
9410
+ /** Unselected radio ring — slate-300. */
9411
+ unselectedRing: "#CBD5E1",
9412
+ /** Unselected label text — slate-500. */
9413
+ unselectedLabel: "#64748B",
9414
+ /** Progress pill background — indigo-50. */
9415
+ pillBg: "#EEF2FF",
9416
+ /** Progress pill text — indigo-600. */
9417
+ pillText: "#4F46E5",
9418
+ /** Category label text — slate-400. */
9419
+ categoryText: "#94A3B8",
9420
+ /** Question title text — slate-900. */
9421
+ titleColor: "#0F172A"
9422
+ };
9423
+ function resolveProgressLabel(progressLabel, questionIndex, questionTotal) {
9424
+ if (progressLabel) return progressLabel;
9425
+ if (typeof questionIndex === "number" && typeof questionTotal === "number" && questionTotal > 0) {
9426
+ return `Question ${questionIndex} of ${questionTotal}`;
7679
9427
  }
7680
- if (payload.type === "table" && payload.table) {
7681
- return /* @__PURE__ */ jsx(DataTable, { data: payload.table, className });
9428
+ return void 0;
9429
+ }
9430
+ function CheckIcon9() {
9431
+ return /* @__PURE__ */ jsx(
9432
+ "svg",
9433
+ {
9434
+ "aria-hidden": "true",
9435
+ viewBox: "0 0 24 24",
9436
+ width: "14",
9437
+ height: "14",
9438
+ fill: "none",
9439
+ stroke: "#FFFFFF",
9440
+ strokeWidth: "3",
9441
+ strokeLinecap: "round",
9442
+ strokeLinejoin: "round",
9443
+ children: /* @__PURE__ */ jsx("path", { d: "M5 13l4 4L19 7" })
9444
+ }
9445
+ );
9446
+ }
9447
+ function OptionRow({
9448
+ option,
9449
+ selected,
9450
+ submitted,
9451
+ isTabStop,
9452
+ colors,
9453
+ customAnswer,
9454
+ customAnswerPlaceholder,
9455
+ onSelect,
9456
+ onMove,
9457
+ onCustomChange,
9458
+ onCustomCommit
9459
+ }) {
9460
+ const isOtherExpanded = !!option.isOther && selected;
9461
+ const handleKeyDown = (e) => {
9462
+ if (submitted) return;
9463
+ switch (e.key) {
9464
+ case " ":
9465
+ case "Enter":
9466
+ e.preventDefault();
9467
+ onSelect();
9468
+ break;
9469
+ // WAI-ARIA radiogroup pattern: arrow keys move focus to the adjacent
9470
+ // radio and check it. Down/Right advance, Up/Left retreat.
9471
+ case "ArrowDown":
9472
+ case "ArrowRight":
9473
+ e.preventDefault();
9474
+ onMove(1);
9475
+ break;
9476
+ case "ArrowUp":
9477
+ case "ArrowLeft":
9478
+ e.preventDefault();
9479
+ onMove(-1);
9480
+ break;
9481
+ }
9482
+ };
9483
+ return /* @__PURE__ */ jsxs(
9484
+ "div",
9485
+ {
9486
+ role: "radio",
9487
+ "aria-checked": selected,
9488
+ tabIndex: submitted ? -1 : isTabStop ? 0 : -1,
9489
+ "data-option-id": option.id,
9490
+ onClick: submitted ? void 0 : onSelect,
9491
+ onKeyDown: handleKeyDown,
9492
+ className: cn(
9493
+ "flex items-start gap-3 rounded-xl border px-4 py-4 text-left transition-colors",
9494
+ !submitted && "cursor-pointer focus:outline-none focus-visible:ring-2 focus-visible:ring-emerald-400/60",
9495
+ selected ? "font-medium" : "font-normal"
9496
+ ),
9497
+ style: {
9498
+ backgroundColor: selected ? colors.selectedBg : "transparent",
9499
+ borderColor: selected ? colors.selectedBorder : colors.unselectedBorder
9500
+ },
9501
+ children: [
9502
+ /* @__PURE__ */ jsx(
9503
+ "span",
9504
+ {
9505
+ "aria-hidden": "true",
9506
+ className: "mt-0.5 flex size-7 shrink-0 items-center justify-center rounded-full",
9507
+ style: selected ? { backgroundColor: colors.selectedCircle } : {
9508
+ backgroundColor: "transparent",
9509
+ border: `2px solid ${colors.unselectedRing}`
9510
+ },
9511
+ children: selected && /* @__PURE__ */ jsx(CheckIcon9, {})
9512
+ }
9513
+ ),
9514
+ isOtherExpanded ? /* @__PURE__ */ jsx(
9515
+ "input",
9516
+ {
9517
+ type: "text",
9518
+ value: customAnswer,
9519
+ placeholder: customAnswerPlaceholder,
9520
+ disabled: submitted,
9521
+ autoComplete: "off",
9522
+ onClick: (e) => e.stopPropagation(),
9523
+ onChange: (e) => onCustomChange(e.target.value),
9524
+ onBlur: onCustomCommit,
9525
+ onKeyDown: (e) => {
9526
+ e.stopPropagation();
9527
+ if (e.key === "Enter") {
9528
+ e.preventDefault();
9529
+ onCustomCommit();
9530
+ }
9531
+ },
9532
+ className: "flex-1 border-0 bg-transparent p-0 text-base leading-snug outline-none placeholder:text-slate-400",
9533
+ style: { color: colors.selectedLabel }
9534
+ }
9535
+ ) : /* @__PURE__ */ jsx(
9536
+ "span",
9537
+ {
9538
+ className: "flex-1 text-base leading-snug",
9539
+ style: { color: selected ? colors.selectedLabel : colors.unselectedLabel },
9540
+ children: option.label
9541
+ }
9542
+ )
9543
+ ]
9544
+ }
9545
+ );
9546
+ }
9547
+ function BuiltInQuestions(props) {
9548
+ const {
9549
+ question,
9550
+ options,
9551
+ selectedOptionId,
9552
+ customAnswer,
9553
+ customAnswerPlaceholder,
9554
+ progressLabel,
9555
+ categoryLabel,
9556
+ questionIndex,
9557
+ questionTotal,
9558
+ submitted = false,
9559
+ onSelect,
9560
+ onCustomAnswerChange,
9561
+ onAnswer,
9562
+ colors: colorOverrides,
9563
+ className
9564
+ } = props;
9565
+ const colors = {
9566
+ ...DEFAULTS,
9567
+ ...colorOverrides
9568
+ };
9569
+ const safeOptions = (options ?? []).filter(
9570
+ (option) => !!option?.id
9571
+ );
9572
+ const radioGroupRef = useRef(null);
9573
+ const isControlled = typeof onSelect === "function";
9574
+ const [internalSelected, setInternalSelected] = useState(
9575
+ selectedOptionId ?? null
9576
+ );
9577
+ const [internalCustom, setInternalCustom] = useState(customAnswer ?? "");
9578
+ const activeSelected = isControlled ? selectedOptionId ?? null : internalSelected;
9579
+ const activeCustom = isControlled ? customAnswer ?? "" : internalCustom;
9580
+ const resolvedProgress = resolveProgressLabel(
9581
+ progressLabel,
9582
+ questionIndex,
9583
+ questionTotal
9584
+ );
9585
+ const hasHeader = !!resolvedProgress || !!categoryLabel;
9586
+ const handleSelect = (option) => {
9587
+ if (submitted) return;
9588
+ if (isControlled) {
9589
+ onSelect?.(option.id);
9590
+ } else {
9591
+ setInternalSelected(option.id);
9592
+ }
9593
+ if (!option.isOther) {
9594
+ onAnswer?.({ optionId: option.id });
9595
+ }
9596
+ };
9597
+ const handleMove = (fromIndex, delta) => {
9598
+ if (submitted) return;
9599
+ const count = safeOptions.length;
9600
+ if (count === 0) return;
9601
+ const nextIndex = (fromIndex + delta + count) % count;
9602
+ const nextOption = safeOptions[nextIndex];
9603
+ if (!nextOption) return;
9604
+ handleSelect(nextOption);
9605
+ const group = radioGroupRef.current;
9606
+ if (group) {
9607
+ const target = group.querySelector(
9608
+ `[data-option-id="${CSS.escape(nextOption.id)}"]`
9609
+ );
9610
+ target?.focus();
9611
+ }
9612
+ };
9613
+ const handleCustomChange = (value) => {
9614
+ if (isControlled) {
9615
+ onCustomAnswerChange?.(value);
9616
+ } else {
9617
+ setInternalCustom(value);
9618
+ }
9619
+ };
9620
+ const handleCustomCommit = (optionId) => {
9621
+ onAnswer?.({ optionId, customAnswer: activeCustom });
9622
+ };
9623
+ return /* @__PURE__ */ jsxs(CardShell, { className: cn("p-6 sm:p-7", className), children: [
9624
+ hasHeader && /* @__PURE__ */ jsxs("div", { className: "mb-5 flex items-center justify-between gap-3", children: [
9625
+ resolvedProgress ? /* @__PURE__ */ jsx(
9626
+ "span",
9627
+ {
9628
+ className: "inline-flex items-center rounded-lg px-3 py-1 font-semibold text-[13px]",
9629
+ style: { backgroundColor: colors.pillBg, color: colors.pillText },
9630
+ children: resolvedProgress
9631
+ }
9632
+ ) : /* @__PURE__ */ jsx("span", { "aria-hidden": "true" }),
9633
+ categoryLabel && /* @__PURE__ */ jsx("span", { className: "text-sm", style: { color: colors.categoryText }, children: categoryLabel })
9634
+ ] }),
9635
+ /* @__PURE__ */ jsx(
9636
+ "h3",
9637
+ {
9638
+ className: "font-bold text-2xl leading-snug",
9639
+ style: { color: colors.titleColor },
9640
+ children: question
9641
+ }
9642
+ ),
9643
+ safeOptions.length > 0 && /* @__PURE__ */ jsx(
9644
+ "div",
9645
+ {
9646
+ ref: radioGroupRef,
9647
+ role: "radiogroup",
9648
+ "aria-label": question,
9649
+ className: "mt-7 flex flex-col gap-3",
9650
+ children: (() => {
9651
+ const selectedIndex = safeOptions.findIndex(
9652
+ (option) => option.id === activeSelected
9653
+ );
9654
+ const tabStopIndex = selectedIndex === -1 ? 0 : selectedIndex;
9655
+ return safeOptions.map((option, i) => {
9656
+ const selected = activeSelected === option.id;
9657
+ return /* @__PURE__ */ jsx(
9658
+ OptionRow,
9659
+ {
9660
+ option,
9661
+ selected,
9662
+ submitted,
9663
+ isTabStop: i === tabStopIndex,
9664
+ colors,
9665
+ customAnswer: activeCustom,
9666
+ customAnswerPlaceholder,
9667
+ onSelect: () => handleSelect(option),
9668
+ onMove: (delta) => handleMove(i, delta),
9669
+ onCustomChange: handleCustomChange,
9670
+ onCustomCommit: () => handleCustomCommit(option.id)
9671
+ },
9672
+ option.id
9673
+ );
9674
+ });
9675
+ })()
9676
+ }
9677
+ )
9678
+ ] });
9679
+ }
9680
+ var DEFAULT_ACCENT_COLOR = "#1e2a44";
9681
+ var DEFAULT_INACTIVE_COLOR = "#dfe3ea";
9682
+ var DEFAULT_ACTIVE_CHAPTER_BG = "#f4f6fa";
9683
+ var DEFAULT_MUTED_TEXT_COLOR = "#94a3b8";
9684
+ var DEFAULT_WAVEFORM = [
9685
+ 0.4,
9686
+ 0.45,
9687
+ 0.95,
9688
+ 0.6,
9689
+ 1,
9690
+ 0.85,
9691
+ 0.4,
9692
+ 0.55,
9693
+ 0.7,
9694
+ 0.45,
9695
+ 0.6,
9696
+ 0.45,
9697
+ 0.4,
9698
+ 0.7,
9699
+ 0.5,
9700
+ 0.45,
9701
+ 0.55,
9702
+ 0.4
9703
+ ];
9704
+ function formatTime2(totalSeconds) {
9705
+ const safe = Number.isFinite(totalSeconds) && totalSeconds > 0 ? totalSeconds : 0;
9706
+ const whole = Math.floor(safe);
9707
+ const minutes = Math.floor(whole / 60);
9708
+ const seconds = whole % 60;
9709
+ return `${minutes}:${String(seconds).padStart(2, "0")}`;
9710
+ }
9711
+ function AudioPlayer({
9712
+ title,
9713
+ src,
9714
+ durationSeconds = 0,
9715
+ currentTimeSeconds = 0,
9716
+ isPlaying = false,
9717
+ waveform,
9718
+ chapters,
9719
+ accentColor,
9720
+ inactiveColor,
9721
+ activeChapterBg,
9722
+ mutedTextColor,
9723
+ className,
9724
+ onTogglePlay,
9725
+ onSeek
9726
+ }) {
9727
+ const accent = accentColor ?? DEFAULT_ACCENT_COLOR;
9728
+ const inactive = inactiveColor ?? DEFAULT_INACTIVE_COLOR;
9729
+ const activeBg = activeChapterBg ?? DEFAULT_ACTIVE_CHAPTER_BG;
9730
+ const mutedText = mutedTextColor ?? DEFAULT_MUTED_TEXT_COLOR;
9731
+ const bars = waveform && waveform.length > 0 ? waveform : DEFAULT_WAVEFORM;
9732
+ const chapterList = chapters ?? [];
9733
+ const hasSrc = typeof src === "string" && src.length > 0;
9734
+ const audioRef = useRef(null);
9735
+ const [currentTime, setCurrentTime] = useState(currentTimeSeconds);
9736
+ const [duration, setDuration] = useState(durationSeconds);
9737
+ const [playing, setPlaying] = useState(isPlaying);
9738
+ useEffect(() => {
9739
+ setCurrentTime(currentTimeSeconds);
9740
+ }, [currentTimeSeconds]);
9741
+ useEffect(() => {
9742
+ setDuration(durationSeconds);
9743
+ }, [durationSeconds]);
9744
+ useEffect(() => {
9745
+ setPlaying(isPlaying);
9746
+ }, [isPlaying]);
9747
+ const lastChapterStart = chapterList.reduce(
9748
+ (max, c) => c.startSeconds > max ? c.startSeconds : max,
9749
+ 0
9750
+ );
9751
+ const effectiveDuration = duration > 0 ? duration : durationSeconds > 0 ? durationSeconds : lastChapterStart;
9752
+ const progress = effectiveDuration > 0 ? Math.min(Math.max(currentTime / effectiveDuration, 0), 1) : 0;
9753
+ const handleLoadedMetadata = useCallback(() => {
9754
+ const el = audioRef.current;
9755
+ if (el && Number.isFinite(el.duration)) setDuration(el.duration);
9756
+ }, []);
9757
+ const handleTimeUpdate = useCallback(() => {
9758
+ const el = audioRef.current;
9759
+ if (el) setCurrentTime(el.currentTime);
9760
+ }, []);
9761
+ const handleEnded = useCallback(() => {
9762
+ setPlaying(false);
9763
+ onTogglePlay?.(false);
9764
+ }, [onTogglePlay]);
9765
+ const seekTo = useCallback(
9766
+ (seconds) => {
9767
+ const clamped = effectiveDuration > 0 ? Math.min(Math.max(seconds, 0), effectiveDuration) : Math.max(seconds, 0);
9768
+ setCurrentTime(clamped);
9769
+ const el = audioRef.current;
9770
+ if (el) {
9771
+ try {
9772
+ el.currentTime = clamped;
9773
+ } catch {
9774
+ }
9775
+ }
9776
+ onSeek?.(clamped);
9777
+ },
9778
+ [effectiveDuration, onSeek]
9779
+ );
9780
+ const togglePlay = useCallback(() => {
9781
+ const next = !playing;
9782
+ setPlaying(next);
9783
+ const el = audioRef.current;
9784
+ if (el) {
9785
+ try {
9786
+ if (next) {
9787
+ const maybePromise = el.play();
9788
+ if (maybePromise && typeof maybePromise.catch === "function") {
9789
+ maybePromise.catch(() => {
9790
+ });
9791
+ }
9792
+ } else {
9793
+ el.pause();
9794
+ }
9795
+ } catch {
9796
+ }
9797
+ }
9798
+ onTogglePlay?.(next);
9799
+ }, [playing, onTogglePlay]);
9800
+ const handleWaveformSeek = useCallback(
9801
+ (event) => {
9802
+ const rect = event.currentTarget.getBoundingClientRect();
9803
+ const ratio = rect.width > 0 ? (event.clientX - rect.left) / rect.width : 0;
9804
+ const clampedRatio = Math.min(Math.max(ratio, 0), 1);
9805
+ seekTo(clampedRatio * effectiveDuration);
9806
+ },
9807
+ [effectiveDuration, seekTo]
9808
+ );
9809
+ let activeChapterIndex = -1;
9810
+ for (let i = 0; i < chapterList.length; i += 1) {
9811
+ if (chapterList[i].startSeconds <= currentTime) activeChapterIndex = i;
7682
9812
  }
7683
- return null;
9813
+ return /* @__PURE__ */ jsxs("div", { className: cn("w-full", className), children: [
9814
+ hasSrc && /* @__PURE__ */ jsx(
9815
+ "audio",
9816
+ {
9817
+ ref: audioRef,
9818
+ src,
9819
+ preload: "metadata",
9820
+ className: "hidden",
9821
+ "aria-label": title,
9822
+ onLoadedMetadata: handleLoadedMetadata,
9823
+ onTimeUpdate: handleTimeUpdate,
9824
+ onEnded: handleEnded,
9825
+ children: /* @__PURE__ */ jsx("track", { kind: "captions" })
9826
+ }
9827
+ ),
9828
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-5", children: [
9829
+ /* @__PURE__ */ jsx(
9830
+ "button",
9831
+ {
9832
+ type: "button",
9833
+ onClick: togglePlay,
9834
+ "aria-label": playing ? "Pause" : "Play",
9835
+ "aria-pressed": playing,
9836
+ className: "flex h-24 w-24 shrink-0 items-center justify-center rounded-full text-white transition-opacity hover:opacity-90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
9837
+ style: { backgroundColor: accent },
9838
+ children: playing ? (
9839
+ // Pause glyph: two rounded bars.
9840
+ /* @__PURE__ */ jsxs("svg", { width: "34", height: "34", viewBox: "0 0 24 24", "aria-hidden": "true", children: [
9841
+ /* @__PURE__ */ jsx("rect", { x: "6", y: "4", width: "4", height: "16", rx: "1.5", fill: "currentColor" }),
9842
+ /* @__PURE__ */ jsx("rect", { x: "14", y: "4", width: "4", height: "16", rx: "1.5", fill: "currentColor" })
9843
+ ] })
9844
+ ) : (
9845
+ // Play glyph: a single triangle nudged right for optical centering.
9846
+ /* @__PURE__ */ jsx("svg", { width: "34", height: "34", viewBox: "0 0 24 24", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { d: "M8 5.5l11 6.5-11 6.5z", fill: "currentColor" }) })
9847
+ )
9848
+ }
9849
+ ),
9850
+ /* @__PURE__ */ jsx(
9851
+ "button",
9852
+ {
9853
+ type: "button",
9854
+ onClick: handleWaveformSeek,
9855
+ "aria-label": "Seek",
9856
+ className: "flex h-[88px] flex-1 cursor-pointer items-center gap-[6px] rounded-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
9857
+ children: bars.map((rawHeight, index) => {
9858
+ const height = Math.min(Math.max(rawHeight, 0), 1);
9859
+ const barRatio = bars.length > 1 ? index / (bars.length - 1) : 0;
9860
+ const played = barRatio <= progress;
9861
+ return /* @__PURE__ */ jsx(
9862
+ "span",
9863
+ {
9864
+ "aria-hidden": "true",
9865
+ className: "flex-1 rounded-[3px]",
9866
+ style: {
9867
+ height: `${Math.max(height * 100, 8)}%`,
9868
+ backgroundColor: played ? accent : inactive
9869
+ }
9870
+ },
9871
+ index
9872
+ );
9873
+ })
9874
+ }
9875
+ ),
9876
+ /* @__PURE__ */ jsxs(
9877
+ "span",
9878
+ {
9879
+ className: "shrink-0 font-mono text-lg tabular-nums",
9880
+ style: { color: mutedText },
9881
+ children: [
9882
+ formatTime2(currentTime),
9883
+ " / ",
9884
+ formatTime2(effectiveDuration)
9885
+ ]
9886
+ }
9887
+ )
9888
+ ] }),
9889
+ chapterList.length > 0 && /* @__PURE__ */ jsx("ul", { className: "mt-6 flex flex-col gap-1", children: chapterList.map((chapter, index) => {
9890
+ const isActive = index === activeChapterIndex;
9891
+ return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(
9892
+ "button",
9893
+ {
9894
+ type: "button",
9895
+ onClick: () => seekTo(chapter.startSeconds),
9896
+ "aria-current": isActive ? "true" : void 0,
9897
+ className: cn(
9898
+ "flex w-full items-center gap-5 rounded-xl px-3 py-2.5 text-left transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
9899
+ ),
9900
+ style: isActive ? { backgroundColor: activeBg } : void 0,
9901
+ children: [
9902
+ /* @__PURE__ */ jsx(
9903
+ "span",
9904
+ {
9905
+ className: "shrink-0 font-mono text-sm tabular-nums",
9906
+ style: { color: mutedText },
9907
+ children: formatTime2(chapter.startSeconds)
9908
+ }
9909
+ ),
9910
+ /* @__PURE__ */ jsx(
9911
+ "span",
9912
+ {
9913
+ className: cn(
9914
+ "text-base",
9915
+ isActive ? "font-semibold text-slate-900" : "font-normal text-slate-500"
9916
+ ),
9917
+ children: chapter.label
9918
+ }
9919
+ )
9920
+ ]
9921
+ }
9922
+ ) }, chapter.startSeconds + "-" + chapter.label);
9923
+ }) })
9924
+ ] });
9925
+ }
9926
+ var ARTIFACT_REGISTRY = {
9927
+ chart: ({ payload, className }) => payload.chart ? /* @__PURE__ */ jsx(ChartContainer, { data: payload.chart, className }) : null,
9928
+ metrics: ({ payload, className }) => payload.metrics ? /* @__PURE__ */ jsx(MetricsGrid, { metrics: payload.metrics, className }) : null,
9929
+ table: ({ payload, className }) => payload.table ? /* @__PURE__ */ jsx(DataTable, { data: payload.table, className }) : null,
9930
+ "kpi-card-with-chart": ({ payload, className }) => payload.kpiCardWithChart ? /* @__PURE__ */ jsx(KpiCardWithChart, { ...payload.kpiCardWithChart, className }) : null,
9931
+ "pie-chart": ({ payload, className }) => payload.pieChart ? /* @__PURE__ */ jsx(PieChartArtifact, { ...payload.pieChart, className }) : null,
9932
+ "stacked-sparklines": ({ payload, className }) => payload.stackedSparklines ? /* @__PURE__ */ jsx(StackedSparklines, { ...payload.stackedSparklines, className }) : null,
9933
+ "stat-card-half-circle": ({ payload, className }) => payload.statCardHalfCircle ? /* @__PURE__ */ jsx(StatCardHalfCircle, { ...payload.statCardHalfCircle, className }) : null,
9934
+ "table-list": ({ payload, className }) => payload.tableList ? /* @__PURE__ */ jsx(TableListArtifact, { ...payload.tableList, className }) : null,
9935
+ "kpi-card-with-sparklines": ({ payload, className }) => payload.kpiCardWithSparklines ? /* @__PURE__ */ jsx(KpiCardWithSparklines, { ...payload.kpiCardWithSparklines, className }) : null,
9936
+ "locations-revenue-card": ({ payload, className }) => payload.locationsRevenue ? /* @__PURE__ */ jsx(LocationsRevenueCard, { ...payload.locationsRevenue, className }) : null,
9937
+ "row-based-data-list": ({ payload, className }) => payload.rowBasedDataList ? /* @__PURE__ */ jsx(RowBasedDataList, { ...payload.rowBasedDataList, className }) : null,
9938
+ badges: ({ payload, className }) => payload.badges ? /* @__PURE__ */ jsx(BadgesArtifact, { ...payload.badges, className }) : null,
9939
+ "ordered-list": ({ payload, className }) => payload.orderedList ? /* @__PURE__ */ jsx(OrderedListArtifact, { ...payload.orderedList, className }) : null,
9940
+ "deep-research-progress": ({ payload, className }) => payload.deepResearchProgress ? /* @__PURE__ */ jsx(DeepResearchProgress, { ...payload.deepResearchProgress, className }) : null,
9941
+ tracker: ({ payload, className }) => payload.tracker ? /* @__PURE__ */ jsx(Tracker, { ...payload.tracker, className }) : null,
9942
+ "built-in-questions": ({ payload, className }) => payload.builtInQuestions ? /* @__PURE__ */ jsx(BuiltInQuestions, { ...payload.builtInQuestions, className }) : null,
9943
+ "audio-player": ({ payload, className }) => payload.audioPlayer ? /* @__PURE__ */ jsx(AudioPlayer, { ...payload.audioPlayer, className }) : null
9944
+ };
9945
+ function DataPayloadView({ payload, className }) {
9946
+ const render = ARTIFACT_REGISTRY[payload.type];
9947
+ return render ? /* @__PURE__ */ jsx(Fragment, { children: render({ payload, className }) }) : null;
7684
9948
  }
7685
9949
  function ReportView({ report, className }) {
7686
9950
  return /* @__PURE__ */ jsxs("div", { className: cn("space-y-6", className), children: [
@@ -7771,25 +10035,34 @@ function MessageList({
7771
10035
  const hasSteps = message.role === "assistant" && !!message.steps && message.steps.length > 0;
7772
10036
  const hasAttachments = !!message.attachments && message.attachments.length > 0;
7773
10037
  return /* @__PURE__ */ jsxs(MessageContainer, { role: message.role, children: [
7774
- showAvatars && /* @__PURE__ */ jsx(AgentAvatar, { role: message.role, size: "sm" }),
7775
- /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-2", children: [
7776
- hasReasoning && /* @__PURE__ */ jsx(MessageWithReasoning, { steps: message.reasoning }),
7777
- hasSteps && /* @__PURE__ */ jsx(MessageWithSteps, { steps: message.steps }),
7778
- message.content && /* @__PURE__ */ jsx(MessageBubble, { role: message.role, children: /* @__PURE__ */ jsx(MessageContent, { children: message.content }) }),
7779
- hasAttachments && /* @__PURE__ */ jsx(MessageWithAttachments, { attachments: message.attachments }),
7780
- message.data && /* @__PURE__ */ jsx(DataPayloadView, { payload: message.data }),
7781
- message.confirmation && /* @__PURE__ */ jsx(
7782
- ConfirmationPanel,
7783
- {
7784
- title: message.confirmation.title,
7785
- summary: message.confirmation.summary,
7786
- body: message.confirmation.body,
7787
- markdown: message.confirmation.markdown,
7788
- actions: message.confirmation.actions,
7789
- onAction: (actionId) => onConfirmAction?.(message.id, actionId)
7790
- }
7791
- )
7792
- ] })
10038
+ showAvatars && /* @__PURE__ */ jsx(AgentAvatar, { role: message.role, size: "md" }),
10039
+ /* @__PURE__ */ jsxs(
10040
+ "div",
10041
+ {
10042
+ className: cn(
10043
+ "flex min-w-0 flex-col gap-2",
10044
+ message.role === "user" && "items-end"
10045
+ ),
10046
+ children: [
10047
+ hasReasoning && /* @__PURE__ */ jsx(MessageWithReasoning, { steps: message.reasoning }),
10048
+ hasSteps && /* @__PURE__ */ jsx(MessageWithSteps, { steps: message.steps }),
10049
+ message.content && /* @__PURE__ */ jsx(MessageBubble, { role: message.role, children: /* @__PURE__ */ jsx(MessageContent, { children: message.content }) }),
10050
+ hasAttachments && /* @__PURE__ */ jsx(MessageWithAttachments, { attachments: message.attachments }),
10051
+ message.data && /* @__PURE__ */ jsx(DataPayloadView, { payload: message.data }),
10052
+ message.confirmation && /* @__PURE__ */ jsx(
10053
+ ConfirmationPanel,
10054
+ {
10055
+ title: message.confirmation.title,
10056
+ summary: message.confirmation.summary,
10057
+ body: message.confirmation.body,
10058
+ markdown: message.confirmation.markdown,
10059
+ actions: message.confirmation.actions,
10060
+ onAction: (actionId) => onConfirmAction?.(message.id, actionId)
10061
+ }
10062
+ )
10063
+ ]
10064
+ }
10065
+ )
7793
10066
  ] }, message.id);
7794
10067
  }) });
7795
10068
  }
@@ -8715,13 +10988,31 @@ function useOpenState(controlled, defaultOpen, onChange) {
8715
10988
  );
8716
10989
  return [open, setOpen];
8717
10990
  }
10991
+ function useIsDesktop() {
10992
+ const read = () => typeof window !== "undefined" && typeof window.matchMedia === "function" ? window.matchMedia("(min-width: 1024px)").matches : true;
10993
+ const [isDesktop, setIsDesktop] = useState(read);
10994
+ useEffect(() => {
10995
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function")
10996
+ return;
10997
+ const mql = window.matchMedia("(min-width: 1024px)");
10998
+ const update = () => setIsDesktop(mql.matches);
10999
+ update();
11000
+ if (mql.addEventListener) {
11001
+ mql.addEventListener("change", update);
11002
+ return () => mql.removeEventListener("change", update);
11003
+ }
11004
+ mql.addListener(update);
11005
+ return () => mql.removeListener(update);
11006
+ }, []);
11007
+ return isDesktop;
11008
+ }
8718
11009
  function AgentWorkspace({
8719
11010
  children,
8720
11011
  leftPanel,
8721
11012
  rightPanel,
8722
11013
  leftPanelWidth = 320,
8723
11014
  rightPanelWidth = 460,
8724
- defaultLeftPanelOpen = true,
11015
+ defaultLeftPanelOpen,
8725
11016
  defaultRightPanelOpen = true,
8726
11017
  leftPanelOpen: leftPanelOpenProp,
8727
11018
  rightPanelOpen: rightPanelOpenProp,
@@ -8731,6 +11022,7 @@ function AgentWorkspace({
8731
11022
  showHeader,
8732
11023
  showConversationHeader,
8733
11024
  headerActions,
11025
+ headerControlsPlacement = "before",
8734
11026
  headerStatus,
8735
11027
  conversation,
8736
11028
  conversationOpen: conversationOpenProp,
@@ -8750,9 +11042,11 @@ function AgentWorkspace({
8750
11042
  const agent = useNativeAgentOptional();
8751
11043
  const hasLeftPanel = leftPanel !== void 0 && leftPanel !== null;
8752
11044
  const hasRightPanel = rightPanel !== void 0 && rightPanel !== null;
11045
+ const isDesktop = useIsDesktop();
11046
+ const resolvedLeftDefault = defaultLeftPanelOpen ?? (leftPanelOpenProp === void 0 ? isDesktop : true);
8753
11047
  const [leftOpen, setLeftOpen] = useOpenState(
8754
11048
  leftPanelOpenProp,
8755
- defaultLeftPanelOpen,
11049
+ resolvedLeftDefault,
8756
11050
  onLeftPanelOpenChange
8757
11051
  );
8758
11052
  const [rightOpen, setRightOpen] = useOpenState(
@@ -8809,6 +11103,39 @@ function AgentWorkspace({
8809
11103
  ) : composer;
8810
11104
  const headerVisible = showHeader ?? showConversationHeader ?? true;
8811
11105
  const statusLine = headerStatus ?? (agent ? agent.error ?? agent.statusLabel : null);
11106
+ const builtInControls = /* @__PURE__ */ jsxs(Fragment, { children: [
11107
+ agent && /* @__PURE__ */ jsx(
11108
+ "button",
11109
+ {
11110
+ type: "button",
11111
+ onClick: () => agent.reset(),
11112
+ "aria-label": "Start a new conversation",
11113
+ title: "New conversation",
11114
+ className: "flex size-8 items-center justify-center rounded-lg text-muted-foreground transition-colors hover:bg-secondary hover:text-foreground",
11115
+ children: /* @__PURE__ */ jsx(RotateCcw, { className: "size-4" })
11116
+ }
11117
+ ),
11118
+ /* @__PURE__ */ jsx(
11119
+ "button",
11120
+ {
11121
+ type: "button",
11122
+ onClick: () => setConversationOpen(!conversationOpen),
11123
+ "aria-label": conversationOpen ? "Hide conversation" : "Show conversation",
11124
+ title: conversationOpen ? "Hide conversation" : "Show conversation",
11125
+ className: "flex size-8 items-center justify-center rounded-lg text-muted-foreground transition-colors hover:bg-secondary hover:text-foreground",
11126
+ children: /* @__PURE__ */ jsx(
11127
+ ChevronDown,
11128
+ {
11129
+ className: cn(
11130
+ "size-4 transition-transform duration-200",
11131
+ !conversationOpen && "rotate-180"
11132
+ )
11133
+ }
11134
+ )
11135
+ }
11136
+ ),
11137
+ hasRightPanel && /* @__PURE__ */ jsx(AgentWorkspacePanelToggle, { side: "right", className: "hidden md:flex" })
11138
+ ] });
8812
11139
  return /* @__PURE__ */ jsx(AgentWorkspaceContext.Provider, { value, children: /* @__PURE__ */ jsxs(
8813
11140
  "div",
8814
11141
  {
@@ -8824,7 +11151,7 @@ function AgentWorkspace({
8824
11151
  "data-state": leftOpen ? "open" : "collapsed",
8825
11152
  "aria-hidden": !leftOpen || void 0,
8826
11153
  className: cn(
8827
- "relative hidden h-full shrink-0 overflow-hidden border-r border-border transition-[width] duration-300 ease-in-out lg:block",
11154
+ "relative hidden h-full shrink-0 overflow-hidden border-r border-border transition-[width] duration-300 ease-in-out md:block",
8828
11155
  !leftOpen && "border-r-0",
8829
11156
  leftPanelClassName
8830
11157
  ),
@@ -8833,14 +11160,14 @@ function AgentWorkspace({
8833
11160
  }
8834
11161
  ),
8835
11162
  /* @__PURE__ */ jsxs("div", { className: "relative flex h-full min-w-0 grow flex-col", children: [
8836
- showPanelToggles && hasLeftPanel && /* @__PURE__ */ jsx("div", { className: "absolute left-3 top-3 z-30 hidden lg:block", children: /* @__PURE__ */ jsx(
11163
+ showPanelToggles && hasLeftPanel && /* @__PURE__ */ jsx("div", { className: "absolute left-3 top-3 z-30 hidden md:block", children: /* @__PURE__ */ jsx(
8837
11164
  AgentWorkspacePanelToggle,
8838
11165
  {
8839
11166
  side: "left",
8840
11167
  className: "border border-border/60 bg-background/80 shadow-sm backdrop-blur"
8841
11168
  }
8842
11169
  ) }),
8843
- showPanelToggles && hasRightPanel && /* @__PURE__ */ jsx("div", { className: "absolute right-3 top-3 z-30 hidden lg:block", children: /* @__PURE__ */ jsx(
11170
+ showPanelToggles && hasRightPanel && /* @__PURE__ */ jsx("div", { className: "absolute right-3 top-3 z-30 hidden md:block", children: /* @__PURE__ */ jsx(
8844
11171
  AgentWorkspacePanelToggle,
8845
11172
  {
8846
11173
  side: "right",
@@ -8858,7 +11185,7 @@ function AgentWorkspace({
8858
11185
  AgentWorkspacePanelToggle,
8859
11186
  {
8860
11187
  side: "left",
8861
- className: "hidden lg:flex"
11188
+ className: "hidden md:flex"
8862
11189
  }
8863
11190
  ),
8864
11191
  /* @__PURE__ */ jsx("span", { className: "flex size-7 shrink-0 items-center justify-center rounded-md bg-primary text-primary-foreground", children: /* @__PURE__ */ jsx(Sparkles, { className: "size-3.5" }) }),
@@ -8867,46 +11194,13 @@ function AgentWorkspace({
8867
11194
  statusLine && /* @__PURE__ */ jsx("div", { className: "truncate text-xs text-muted-foreground", children: statusLine })
8868
11195
  ] })
8869
11196
  ] }),
8870
- /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center gap-1", children: [
11197
+ /* @__PURE__ */ jsx("div", { className: "flex shrink-0 items-center gap-1", children: headerControlsPlacement === "before" ? /* @__PURE__ */ jsxs(Fragment, { children: [
11198
+ builtInControls,
11199
+ headerActions
11200
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
8871
11201
  headerActions,
8872
- agent && /* @__PURE__ */ jsx(
8873
- "button",
8874
- {
8875
- type: "button",
8876
- onClick: () => agent.reset(),
8877
- "aria-label": "Start a new conversation",
8878
- title: "New conversation",
8879
- className: "flex size-8 items-center justify-center rounded-lg text-muted-foreground transition-colors hover:bg-secondary hover:text-foreground",
8880
- children: /* @__PURE__ */ jsx(RotateCcw, { className: "size-4" })
8881
- }
8882
- ),
8883
- /* @__PURE__ */ jsx(
8884
- "button",
8885
- {
8886
- type: "button",
8887
- onClick: () => setConversationOpen(!conversationOpen),
8888
- "aria-label": conversationOpen ? "Hide conversation" : "Show conversation",
8889
- title: conversationOpen ? "Hide conversation" : "Show conversation",
8890
- className: "flex size-8 items-center justify-center rounded-lg text-muted-foreground transition-colors hover:bg-secondary hover:text-foreground",
8891
- children: /* @__PURE__ */ jsx(
8892
- ChevronDown,
8893
- {
8894
- className: cn(
8895
- "size-4 transition-transform duration-200",
8896
- !conversationOpen && "rotate-180"
8897
- )
8898
- }
8899
- )
8900
- }
8901
- ),
8902
- hasRightPanel && /* @__PURE__ */ jsx(
8903
- AgentWorkspacePanelToggle,
8904
- {
8905
- side: "right",
8906
- className: "hidden lg:flex"
8907
- }
8908
- )
8909
- ] })
11202
+ builtInControls
11203
+ ] }) })
8910
11204
  ]
8911
11205
  }
8912
11206
  ),
@@ -8973,7 +11267,7 @@ function AgentWorkspace({
8973
11267
  "data-state": rightOpen ? "open" : "collapsed",
8974
11268
  "aria-hidden": !rightOpen || void 0,
8975
11269
  className: cn(
8976
- "relative hidden h-full shrink-0 overflow-hidden border-l border-border transition-[width] duration-300 ease-in-out lg:block",
11270
+ "relative hidden h-full shrink-0 overflow-hidden border-l border-border transition-[width] duration-300 ease-in-out md:block",
8977
11271
  !rightOpen && "border-l-0",
8978
11272
  rightPanelClassName
8979
11273
  ),
@@ -8985,7 +11279,97 @@ function AgentWorkspace({
8985
11279
  }
8986
11280
  ) });
8987
11281
  }
11282
+ var Pulse = ({ className }) => /* @__PURE__ */ jsx("div", { className: cn("animate-pulse rounded-md bg-muted", className) });
11283
+ var PanelSkeleton = () => /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-col", children: [
11284
+ /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center justify-between px-4 pb-2 pt-4", children: [
11285
+ /* @__PURE__ */ jsx(Pulse, { className: "h-5 w-28" }),
11286
+ /* @__PURE__ */ jsx(Pulse, { className: "size-8 rounded-lg" })
11287
+ ] }),
11288
+ /* @__PURE__ */ jsx("div", { className: "min-h-0 grow space-y-4 overflow-hidden px-4 py-3", children: [3, 6].map((rows, section) => /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
11289
+ /* @__PURE__ */ jsx(Pulse, { className: "h-3 w-24" }),
11290
+ Array.from({ length: rows }, (_, i) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
11291
+ /* @__PURE__ */ jsx(Pulse, { className: "size-4 shrink-0 rounded-full" }),
11292
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 grow space-y-1.5", children: [
11293
+ /* @__PURE__ */ jsx(Pulse, { className: "h-3.5 w-3/4" }),
11294
+ /* @__PURE__ */ jsx(Pulse, { className: "h-3 w-1/2" })
11295
+ ] })
11296
+ ] }, i))
11297
+ ] }, section)) }),
11298
+ /* @__PURE__ */ jsxs("div", { className: "shrink-0 space-y-2 border-t border-border px-4 py-3", children: [
11299
+ /* @__PURE__ */ jsx(Pulse, { className: "h-3 w-full" }),
11300
+ /* @__PURE__ */ jsx(Pulse, { className: "h-3 w-2/3" })
11301
+ ] })
11302
+ ] });
11303
+ var DefaultContentSkeleton = () => /* @__PURE__ */ jsxs("div", { className: "space-y-4 p-6", children: [
11304
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
11305
+ /* @__PURE__ */ jsx(Pulse, { className: "h-8 w-40" }),
11306
+ /* @__PURE__ */ jsx(Pulse, { className: "h-8 w-28" }),
11307
+ /* @__PURE__ */ jsx(Pulse, { className: "ml-auto h-8 w-20" })
11308
+ ] }),
11309
+ Array.from({ length: 9 }, (_, i) => /* @__PURE__ */ jsx(Pulse, { className: "h-10 w-full" }, i))
11310
+ ] });
11311
+ function AgentWorkspaceSkeleton({
11312
+ leftPanel = true,
11313
+ rightPanel = true,
11314
+ leftPanelWidth = 320,
11315
+ rightPanelWidth = 460,
11316
+ showHeader = true,
11317
+ composer = true,
11318
+ children,
11319
+ className
11320
+ }) {
11321
+ return /* @__PURE__ */ jsxs(
11322
+ "div",
11323
+ {
11324
+ "data-workspace-skeleton": "",
11325
+ className: cn(
11326
+ "flex h-full w-full overflow-hidden bg-background text-foreground",
11327
+ className
11328
+ ),
11329
+ children: [
11330
+ leftPanel && /* @__PURE__ */ jsx(
11331
+ "aside",
11332
+ {
11333
+ "aria-hidden": true,
11334
+ className: "hidden h-full shrink-0 overflow-hidden border-r border-border lg:block",
11335
+ style: { width: leftPanelWidth },
11336
+ children: /* @__PURE__ */ jsx(PanelSkeleton, {})
11337
+ }
11338
+ ),
11339
+ /* @__PURE__ */ jsxs("div", { className: "flex h-full min-w-0 grow flex-col", children: [
11340
+ showHeader && /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center justify-between gap-3 border-b border-border px-3 py-2.5", children: [
11341
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-center gap-2.5", children: [
11342
+ /* @__PURE__ */ jsx(Pulse, { className: "hidden size-8 rounded-lg lg:block" }),
11343
+ /* @__PURE__ */ jsx(Pulse, { className: "size-7 rounded-md" }),
11344
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
11345
+ /* @__PURE__ */ jsx(Pulse, { className: "h-4 w-36" }),
11346
+ /* @__PURE__ */ jsx(Pulse, { className: "h-3 w-20" })
11347
+ ] })
11348
+ ] }),
11349
+ /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center gap-1.5", children: [
11350
+ /* @__PURE__ */ jsx(Pulse, { className: "h-8 w-20 rounded-md" }),
11351
+ /* @__PURE__ */ jsx(Pulse, { className: "size-8 rounded-lg" }),
11352
+ /* @__PURE__ */ jsx(Pulse, { className: "size-8 rounded-lg" }),
11353
+ /* @__PURE__ */ jsx(Pulse, { className: "hidden size-8 rounded-lg lg:block" })
11354
+ ] })
11355
+ ] }),
11356
+ /* @__PURE__ */ jsx("div", { className: "min-h-0 grow overflow-hidden", children: children ?? /* @__PURE__ */ jsx(DefaultContentSkeleton, {}) }),
11357
+ composer && /* @__PURE__ */ jsx("div", { className: "shrink-0 border-t border-border px-4 py-3", children: /* @__PURE__ */ jsx("div", { className: "mx-auto w-full max-w-3xl", children: /* @__PURE__ */ jsx(Pulse, { className: "h-[52px] w-full rounded-2xl" }) }) })
11358
+ ] }),
11359
+ rightPanel && /* @__PURE__ */ jsx(
11360
+ "aside",
11361
+ {
11362
+ "aria-hidden": true,
11363
+ className: "hidden h-full shrink-0 overflow-hidden border-l border-border lg:block",
11364
+ style: { width: rightPanelWidth },
11365
+ children: /* @__PURE__ */ jsx(PanelSkeleton, {})
11366
+ }
11367
+ )
11368
+ ]
11369
+ }
11370
+ );
11371
+ }
8988
11372
 
8989
- export { AgentAvatar, AgentComposer, AgentConversation, AgentHandoff, AgentProvider, AgentSurface, AgentWorkspace, AgentWorkspaceComposer, AgentWorkspacePanelToggle, AllocationBreakdown, AnalyticsDashboard, Avatar, AvatarFallback, AvatarImage, Badge, Button, ChartContainer, ChatPanel, Collapsible, CollapsibleContent2 as CollapsibleContent, CollapsibleTrigger2 as CollapsibleTrigger, ConfirmationPanel, ControlGrid, ConversationAnalytics, ConversationArtifact, DataPayloadView, DataTable, DynamicRenderer, EntityCard, FileDropZone, FloatingWidget, FullBleedSurface, FullscreenDashboard, GuidedLessonFlow, ImageGenerator, InlineSuggestionsInput, Input, ListingFeed, MediaEditorCanvas, MediaGallery, MessageActions, MessageBubble, MessageContainer, MessageContent, MessageList, MessageWithAttachments, MessageWithFeedback, MessageWithReasoning, MessageWithSteps, MetricsGrid, MobileShell, MultimodalInput, NativeAgentProvider, NativeSurface, OnboardingWizard, OptionCards, OverlayModal, PerformanceMetrics, PersonaSelector, Progress, ProgressTracker, PromptInput, PromptLibrary, QuickReplies, QuizCard, RecommendationCards, ReportView, ScheduleTimeline, ScrollArea, ScrollBar, SemanticBuilderSocketClient, SentimentDisplay, SettingsPanel, SlotRenderer, SplitView, StatusBadge, SystemMessage, TemplateSelector, Textarea, Timestamp, Tooltip4 as Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, TypingIndicator, WritingAssistant, badgeVariants, buildSocketUrl, buttonVariants, calculatePercentage, cn, componentManifest, componentMap, componentRegistry, copyToClipboard, createMockBackend, debounce, delay, findComponentsByCapability, findComponentsByCategory, findComponentsBySurface, formatBytes, formatCurrency, formatNumber, formatRelativeTime, formatTime, generateId, getInitials, getManifestEntry, getSentimentBgColor, getSentimentColor, isBrowser, isInIframe, normalizeWebsiteId, parseTextWithBold, registerAllComponents, truncate, useAgent, useAgentBackend, useAgentInput, useAgentLayout, useAgentMessages, useAgentWorkspace, useAgentWorkspaceOptional, useNativeAgent, useNativeAgentOptional, useSemanticBuilder };
11373
+ export { AgentAvatar, AgentComposer, AgentConversation, AgentHandoff, AgentProvider, AgentSurface, AgentWorkspace, AgentWorkspaceComposer, AgentWorkspacePanelToggle, AgentWorkspaceSkeleton, AllocationBreakdown, AnalyticsDashboard, AudioPlayer, Avatar, AvatarFallback, AvatarImage, Badge, BadgesArtifact, BuiltInQuestions, Button, ChartContainer, ChatPanel, Collapsible, CollapsibleContent2 as CollapsibleContent, CollapsibleTrigger2 as CollapsibleTrigger, ConfirmationPanel, ControlGrid, ConversationAnalytics, ConversationArtifact, DataPayloadView, DataTable, DeepResearchProgress, DynamicRenderer, EntityCard, FileDropZone, FloatingWidget, FullBleedSurface, FullscreenDashboard, GuidedLessonFlow, ImageGenerator, InlineSuggestionsInput, Input, KpiCardWithChart, KpiCardWithSparklines, ListingFeed, LocationsRevenueCard, MediaEditorCanvas, MediaGallery, MessageActions, MessageBubble, MessageContainer, MessageContent, MessageList, MessageWithAttachments, MessageWithFeedback, MessageWithReasoning, MessageWithSteps, MetricsGrid, MobileShell, MultimodalInput, NativeAgentProvider, NativeSurface, OnboardingWizard, OptionCards, OrderedListArtifact, OverlayModal, PerformanceMetrics, PersonaSelector, PieChartArtifact, Progress, ProgressTracker, PromptInput, PromptLibrary, QuickReplies, QuizCard, RecommendationCards, ReportView, RowBasedDataList, ScheduleTimeline, ScrollArea, ScrollBar, SemanticBuilderSocketClient, SentimentDisplay, SettingsPanel, SlotRenderer, SplitView, StackedSparklines, StatCardHalfCircle, StatusBadge, SystemMessage, TableListArtifact, TemplateSelector, Textarea, Timestamp, Tooltip4 as Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, Tracker, TypingIndicator, WritingAssistant, badgeVariants, buildSocketUrl, buttonVariants, calculatePercentage, cn, componentManifest, componentMap, componentRegistry, copyToClipboard, createMockBackend, debounce, delay, findComponentsByCapability, findComponentsByCategory, findComponentsBySurface, formatBytes, formatCurrency, formatNumber, formatRelativeTime, formatTime, generateId, getInitials, getManifestEntry, getSentimentBgColor, getSentimentColor, isBrowser, isInIframe, normalizeWebsiteId, parseTextWithBold, registerAllComponents, truncate, useAgent, useAgentBackend, useAgentInput, useAgentLayout, useAgentMessages, useAgentWorkspace, useAgentWorkspaceOptional, useNativeAgent, useNativeAgentOptional, useSemanticBuilder };
8990
11374
  //# sourceMappingURL=index.js.map
8991
11375
  //# sourceMappingURL=index.js.map