import {
  IconButton
} from "./chunk-PYDVANWI.js";
import {
  CAPTURE_EXCLUDE_ATTRIBUTE
} from "./chunk-LXYCT4YO.js";
import {
  BarChart,
  LineChart,
  PieChart
} from "./chunk-YZB6YXKK.js";
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
  useScrollShadow
} from "./chunk-4MZZH3WX.js";
import {
  cn
} from "./chunk-P6GUNIAE.js";

// src/components/artifacts/artifact-base.ts
var artifactTypes = {
  TABLE: "TABLE",
  CHART: "CHART"
};

// src/components/artifacts/chart-artifact/types.ts
var DEFAULT_CHART_ARTIFACT_LABELS = {
  download: "Download",
  downloadCsv: "Download CSV",
  downloadPng: "Download PNG",
  copyAsImage: "Copy Image",
  unavailable: "Chart data is unavailable.",
  loadError: "Couldn't load chart data.",
  loading: "Loading chart\u2026",
  empty: "No data to chart.",
  othersCategoryLabels: ["Others", "Other"]
};

// src/components/artifacts/table-artifact/types.ts
var DEFAULT_TABLE_ARTIFACT_LABELS = {
  download: "Download CSV",
  unavailable: "Table data is unavailable.",
  loadError: "Couldn't load table data.",
  loading: "Loading table\u2026",
  empty: "No rows to display."
};

// node_modules/@tabler/icons-react/dist/esm/createReactComponent.mjs
import { forwardRef, createElement } from "react";

// node_modules/@tabler/icons-react/dist/esm/defaultAttributes.mjs
var defaultAttributes = {
  outline: {
    xmlns: "http://www.w3.org/2000/svg",
    width: 24,
    height: 24,
    viewBox: "0 0 24 24",
    fill: "none",
    stroke: "currentColor",
    strokeWidth: 2,
    strokeLinecap: "round",
    strokeLinejoin: "round"
  },
  filled: {
    xmlns: "http://www.w3.org/2000/svg",
    width: 24,
    height: 24,
    viewBox: "0 0 24 24",
    fill: "currentColor",
    stroke: "none"
  }
};

// node_modules/@tabler/icons-react/dist/esm/createReactComponent.mjs
var createReactComponent = (type, iconName, iconNamePascal, iconNode) => {
  const Component = forwardRef(
    ({ color = "currentColor", size = 24, stroke = 2, title, className, children, ...rest }, ref) => createElement(
      "svg",
      {
        ref,
        ...defaultAttributes[type],
        width: size,
        height: size,
        className: [`tabler-icon`, `tabler-icon-${iconName}`, className].join(" "),
        ...type === "filled" ? {
          fill: color
        } : {
          strokeWidth: stroke,
          stroke: color
        },
        ...rest
      },
      [
        title && createElement("title", { key: "svg-title" }, title),
        ...iconNode.map(([tag, attrs]) => createElement(tag, attrs)),
        ...Array.isArray(children) ? children : [children]
      ]
    )
  );
  Component.displayName = `${iconNamePascal}`;
  return Component;
};

// node_modules/@tabler/icons-react/dist/esm/icons/IconAlertCircle.mjs
var __iconNode = [["path", { "d": "M3 12a9 9 0 1 0 18 0a9 9 0 0 0 -18 0", "key": "svg-0" }], ["path", { "d": "M12 8v4", "key": "svg-1" }], ["path", { "d": "M12 16h.01", "key": "svg-2" }]];
var IconAlertCircle = createReactComponent("outline", "alert-circle", "AlertCircle", __iconNode);

// node_modules/@tabler/icons-react/dist/esm/icons/IconCheck.mjs
var __iconNode2 = [["path", { "d": "M5 12l5 5l10 -10", "key": "svg-0" }]];
var IconCheck = createReactComponent("outline", "check", "Check", __iconNode2);

// node_modules/@tabler/icons-react/dist/esm/icons/IconCopy.mjs
var __iconNode3 = [["path", { "d": "M7 9.667a2.667 2.667 0 0 1 2.667 -2.667h8.666a2.667 2.667 0 0 1 2.667 2.667v8.666a2.667 2.667 0 0 1 -2.667 2.667h-8.666a2.667 2.667 0 0 1 -2.667 -2.667l0 -8.666", "key": "svg-0" }], ["path", { "d": "M4.012 16.737a2.005 2.005 0 0 1 -1.012 -1.737v-10c0 -1.1 .9 -2 2 -2h10c.75 0 1.158 .385 1.5 1", "key": "svg-1" }]];
var IconCopy = createReactComponent("outline", "copy", "Copy", __iconNode3);

// node_modules/@tabler/icons-react/dist/esm/icons/IconDownload.mjs
var __iconNode4 = [["path", { "d": "M4 17v2a2 2 0 0 0 2 2h12a2 2 0 0 0 2 -2v-2", "key": "svg-0" }], ["path", { "d": "M7 11l5 5l5 -5", "key": "svg-1" }], ["path", { "d": "M12 4l0 12", "key": "svg-2" }]];
var IconDownload = createReactComponent("outline", "download", "Download", __iconNode4);

// node_modules/@tabler/icons-react/dist/esm/icons/IconFileSpreadsheet.mjs
var __iconNode5 = [["path", { "d": "M14 3v4a1 1 0 0 0 1 1h4", "key": "svg-0" }], ["path", { "d": "M17 21h-10a2 2 0 0 1 -2 -2v-14a2 2 0 0 1 2 -2h7l5 5v11a2 2 0 0 1 -2 2", "key": "svg-1" }], ["path", { "d": "M8 11h8v7h-8l0 -7", "key": "svg-2" }], ["path", { "d": "M8 15h8", "key": "svg-3" }], ["path", { "d": "M11 11v7", "key": "svg-4" }]];
var IconFileSpreadsheet = createReactComponent("outline", "file-spreadsheet", "FileSpreadsheet", __iconNode5);

// node_modules/@tabler/icons-react/dist/esm/icons/IconLoader2.mjs
var __iconNode6 = [["path", { "d": "M12 3a9 9 0 1 0 9 9", "key": "svg-0" }]];
var IconLoader2 = createReactComponent("outline", "loader-2", "Loader2", __iconNode6);

// node_modules/@tabler/icons-react/dist/esm/icons/IconPhoto.mjs
var __iconNode7 = [["path", { "d": "M15 8h.01", "key": "svg-0" }], ["path", { "d": "M3 6a3 3 0 0 1 3 -3h12a3 3 0 0 1 3 3v12a3 3 0 0 1 -3 3h-12a3 3 0 0 1 -3 -3v-12", "key": "svg-1" }], ["path", { "d": "M3 16l5 -5c.928 -.893 2.072 -.893 3 0l5 5", "key": "svg-2" }], ["path", { "d": "M14 14l1 -1c.928 -.893 2.072 -.893 3 0l3 3", "key": "svg-3" }]];
var IconPhoto = createReactComponent("outline", "photo", "Photo", __iconNode7);

// node_modules/@tabler/icons-react/dist/esm/icons/IconThumbDown.mjs
var __iconNode8 = [["path", { "d": "M7 13v-8a1 1 0 0 0 -1 -1h-2a1 1 0 0 0 -1 1v7a1 1 0 0 0 1 1h3a4 4 0 0 1 4 4v1a2 2 0 0 0 4 0v-5h3a2 2 0 0 0 2 -2l-1 -5a2 3 0 0 0 -2 -2h-7a3 3 0 0 0 -3 3", "key": "svg-0" }]];
var IconThumbDown = createReactComponent("outline", "thumb-down", "ThumbDown", __iconNode8);

// node_modules/@tabler/icons-react/dist/esm/icons/IconThumbUp.mjs
var __iconNode9 = [["path", { "d": "M7 11v8a1 1 0 0 1 -1 1h-2a1 1 0 0 1 -1 -1v-7a1 1 0 0 1 1 -1h3a4 4 0 0 0 4 -4v-1a2 2 0 0 1 4 0v5h3a2 2 0 0 1 2 2l-1 5a2 3 0 0 1 -2 2h-7a3 3 0 0 1 -3 -3", "key": "svg-0" }]];
var IconThumbUp = createReactComponent("outline", "thumb-up", "ThumbUp", __iconNode9);

// src/components/artifacts/artifact-copy-as-image-button/artifact-copy-as-image-button.tsx
import { useCallback as useCallback2 } from "react";

// src/components/ui/tooltip.tsx
import * as React from "react";
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
import { jsx } from "react/jsx-runtime";
var TooltipProvider = TooltipPrimitive.Provider;
var Tooltip = TooltipPrimitive.Root;
var TooltipTrigger = TooltipPrimitive.Trigger;
var TooltipContent = React.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx(
  TooltipPrimitive.Content,
  {
    ref,
    sideOffset,
    className: cn(
      "z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-tooltip-content-transform-origin]",
      className
    ),
    ...props
  }
));
TooltipContent.displayName = TooltipPrimitive.Content.displayName;

// src/components/artifacts/artifact-copy-as-image-button/use-copy-as-image.ts
import { useCallback, useEffect, useRef, useState } from "react";
var DEFAULT_RESET_AFTER_MS = 1500;
function useCopyAsImage(targetRef, options = {}) {
  const [status, setStatus] = useState("idle");
  const [error, setError] = useState(null);
  const resetTimerRef = useRef(null);
  useEffect(() => {
    return () => {
      if (resetTimerRef.current !== null) clearTimeout(resetTimerRef.current);
    };
  }, []);
  const copy = useCallback(async () => {
    if (resetTimerRef.current !== null) {
      clearTimeout(resetTimerRef.current);
      resetTimerRef.current = null;
    }
    const { resetAfterMs = DEFAULT_RESET_AFTER_MS, ...nodeOptions } = options;
    const scheduleReset = () => {
      if (resetAfterMs <= 0) return;
      resetTimerRef.current = setTimeout(() => {
        resetTimerRef.current = null;
        setStatus("idle");
        setError(null);
      }, resetAfterMs);
    };
    const node = targetRef.current;
    if (!node) {
      const err = new Error("ArtifactCopyAsImageButton: target ref is not attached to a DOM node.");
      setError(err);
      setStatus("error");
      scheduleReset();
      throw err;
    }
    setError(null);
    setStatus("working");
    try {
      const { copyNodeAsPng } = await import("./dom-to-image-NATF3446.js");
      await copyNodeAsPng(node, nodeOptions);
      setStatus("success");
      scheduleReset();
    } catch (err) {
      const wrapped = err instanceof Error ? err : new Error(String(err));
      setError(wrapped);
      setStatus("error");
      scheduleReset();
      throw wrapped;
    }
  }, [targetRef, options]);
  return { status, error, copy };
}

// src/components/artifacts/artifact-copy-as-image-button/artifact-copy-as-image-button.tsx
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
var MAX_ERROR_MESSAGE_CHARS = 120;
function truncateErrorMessage(message, max = MAX_ERROR_MESSAGE_CHARS) {
  return message.length <= max ? message : `${message.slice(0, max - 1)}\u2026`;
}
var DEFAULT_LABEL = "Copy Image";
var ICON_BY_STATUS = {
  // `IconCopy` reads as the clipboard-copy affordance (action-shaped), distinct from the
  // download menu's format-shaped icons. The button only ever puts bytes on the clipboard, so
  // the visual signal stays consistent across copy-aware artifact types.
  idle: IconCopy,
  working: IconLoader2,
  success: IconCheck,
  error: IconAlertCircle
};
var TRANSIENT_TOOLTIP_BY_STATUS = {
  working: "Copying\u2026",
  success: "Copied",
  error: "Copy failed"
};
function ArtifactCopyAsImageButton({
  targetRef,
  label = DEFAULT_LABEL,
  disabled = false,
  onClick
}) {
  const { status, error, copy } = useCopyAsImage(targetRef);
  const handleClick = useCallback2(() => {
    onClick?.();
    copy().catch((err) => {
      console.warn("[clay] ArtifactCopyAsImageButton: copy failed", err);
    });
  }, [copy, onClick]);
  const statusLabel = status === "idle" ? label : status === "error" && error ? `Copy failed: ${truncateErrorMessage(error.message)}` : TRANSIENT_TOOLTIP_BY_STATUS[status] ?? label;
  return /* @__PURE__ */ jsx2(TooltipProvider, { children: /* @__PURE__ */ jsxs(Tooltip, { children: [
    /* @__PURE__ */ jsx2(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx2(
      IconButton,
      {
        icon: ICON_BY_STATUS[status],
        size: "small",
        onClick: handleClick,
        disabled: disabled || status === "working",
        "aria-label": statusLabel
      }
    ) }),
    /* @__PURE__ */ jsx2(TooltipContent, { children: statusLabel })
  ] }) });
}

// src/components/artifacts/artifact-download-button/artifact-download-button.tsx
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
var DEFAULT_LABEL2 = "Download CSV";
function ArtifactDownloadButton({
  href,
  label = DEFAULT_LABEL2,
  onClick
}) {
  if (!isSafeDownloadUrl(href)) return null;
  return /* @__PURE__ */ jsx3(TooltipProvider, { children: /* @__PURE__ */ jsxs2(Tooltip, { children: [
    /* @__PURE__ */ jsx3(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx3(
      IconButton,
      {
        as: "a",
        href,
        download: true,
        rel: "noopener noreferrer",
        onClick,
        icon: IconDownload,
        size: "small",
        "aria-label": label
      }
    ) }),
    /* @__PURE__ */ jsx3(TooltipContent, { children: label })
  ] }) });
}
function isSafeDownloadUrl(url) {
  try {
    const parsed = new URL(url);
    return parsed.protocol === "https:" || parsed.protocol === "http:";
  } catch {
    return false;
  }
}

// src/components/artifacts/artifact-download-menu/artifact-download-menu.tsx
import { useCallback as useCallback3 } from "react";

// src/components/ui/dropdown-menu.tsx
import * as React2 from "react";
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
import { jsx as jsx4 } from "react/jsx-runtime";
var DropdownMenu = DropdownMenuPrimitive.Root;
var DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
var DropdownMenuContent = React2.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx4(DropdownMenuPrimitive.Portal, { children: /* @__PURE__ */ jsx4(
  DropdownMenuPrimitive.Content,
  {
    ref,
    sideOffset,
    className: cn(
      // Stacking is consumer-configurable via the `--z-popover` CSS variable (default `99999`,
      // declared in clay's generated `_theme-tokens.css` :root block). Consumers whose chat or
      // modal layer sits even higher override on their own root once:
      //   :root { --z-popover: 9999999; }
      // and every clay floating surface picks the new value up via cascade. The fallback in
      // `var(...,99999)` only kicks in if the consumer also strips the clay stylesheet — which
      // they shouldn't, but the safety net costs nothing.
      "z-[var(--z-popover,99999)] min-w-[10rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md",
      "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
      "data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
      className
    ),
    ...props
  }
) }));
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
var DropdownMenuItem = React2.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ jsx4(
  DropdownMenuPrimitive.Item,
  {
    ref,
    className: cn(
      "relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors",
      "focus:bg-accent focus:text-accent-foreground",
      "data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
      "[&_svg]:size-4 [&_svg]:shrink-0",
      inset && "pl-8",
      className
    ),
    ...props
  }
));
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
var DropdownMenuSeparator = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx4(DropdownMenuPrimitive.Separator, { ref, className: cn("-mx-1 my-1 h-px bg-muted", className), ...props }));
DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
var DropdownMenuLabel = React2.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ jsx4(
  DropdownMenuPrimitive.Label,
  {
    ref,
    className: cn("px-2 py-1.5 text-sm font-semibold", inset && "pl-8", className),
    ...props
  }
));
DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;

// src/components/artifacts/artifact-download-menu/artifact-download-menu.tsx
import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
var DEFAULT_TRIGGER_LABEL = "Download";
var DEFAULT_CSV_LABEL = "Download CSV";
var DEFAULT_PNG_LABEL = "Download PNG";
var DEFAULT_PNG_BASENAME = "artifact";
function ArtifactDownloadMenu({
  actions,
  triggerLabel = DEFAULT_TRIGGER_LABEL
}) {
  const { csv, png } = actions;
  const showCsv = csv !== void 0 && isSafeDownloadUrl(csv.href);
  const showPng = png !== void 0;
  const handlePngSelect = useCallback3(async () => {
    if (!png) return;
    png.onSelect?.();
    const node = png.targetRef.current;
    if (!node) return;
    const filename = `${png.filename ?? DEFAULT_PNG_BASENAME}.png`;
    try {
      const { downloadNodeAsPng } = await import("./dom-to-image-NATF3446.js");
      await downloadNodeAsPng(node, filename);
    } catch (err) {
      console.warn("[clay] ArtifactDownloadMenu: PNG download failed", err);
    }
  }, [png]);
  return /* @__PURE__ */ jsxs3(DropdownMenu, { children: [
    /* @__PURE__ */ jsx5(TooltipProvider, { children: /* @__PURE__ */ jsxs3(Tooltip, { children: [
      /* @__PURE__ */ jsx5(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx5(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx5(IconButton, { icon: IconDownload, size: "small", "aria-label": triggerLabel }) }) }),
      /* @__PURE__ */ jsx5(TooltipContent, { children: triggerLabel })
    ] }) }),
    /* @__PURE__ */ jsxs3(DropdownMenuContent, { align: "end", children: [
      showCsv ? (
        // `asChild` lets Radix render the item as our anchor — the browser handles the
        // download natively and respects `Content-Disposition`. The analytics callback rides
        // on the anchor's own `onClick` (rather than Radix's `onSelect`) so the same handler
        // fires whether the user mouse-clicks the item, hits Enter on it, or activates it via
        // touch — `onSelect` is reliable only for keyboard activation when `asChild` is in use.
        /* @__PURE__ */ jsx5(DropdownMenuItem, { asChild: true, children: /* @__PURE__ */ jsxs3("a", { href: csv.href, download: true, rel: "noopener noreferrer", onClick: csv.onSelect, children: [
          /* @__PURE__ */ jsx5(IconFileSpreadsheet, {}),
          csv.label ?? DEFAULT_CSV_LABEL
        ] }) })
      ) : null,
      showPng ? /* @__PURE__ */ jsxs3(DropdownMenuItem, { onSelect: handlePngSelect, disabled: png.disabled ?? false, children: [
        /* @__PURE__ */ jsx5(IconPhoto, {}),
        png.label ?? DEFAULT_PNG_LABEL
      ] }) : null
    ] })
  ] });
}

// src/components/artifacts/chart-artifact/chart-artifact.tsx
import { useEffect as useEffect3, useMemo as useMemo2, useRef as useRef2 } from "react";

// src/components/ai-elements/artifact.tsx
import { forwardRef as forwardRef4 } from "react";
import { jsx as jsx6 } from "react/jsx-runtime";
var Artifact = forwardRef4(({ className, ...props }, ref) => /* @__PURE__ */ jsx6(
  "div",
  {
    ref,
    className: cn("flex flex-col overflow-hidden rounded-lg border bg-background shadow-sm", className),
    ...props
  }
));
Artifact.displayName = "Artifact";
var ArtifactHeader = ({ className, ...props }) => /* @__PURE__ */ jsx6("div", { className: cn("flex items-center justify-between border-b bg-muted/50 px-4 py-3", className), ...props });
var ArtifactTitle = ({ className, ...props }) => /* @__PURE__ */ jsx6("p", { className: cn("font-medium text-foreground text-sm", className), ...props });
var ArtifactActions = ({ className, ...props }) => /* @__PURE__ */ jsx6("div", { className: cn("flex items-center gap-1", className), ...props });
var ArtifactContent = ({ className, ...props }) => /* @__PURE__ */ jsx6("div", { className: cn("flex-1 overflow-auto p-4", className), ...props });

// src/components/artifacts/status-message.tsx
import { createElement as createElement2 } from "react";
function StatusMessage({ $tone, children }) {
  return createElement2(
    "div",
    {
      className: `py-6 px-2 text-center text-sm font-medium leading-5 ${$tone === "error" ? "text-red-600" : "text-brown-70"}`
    },
    children
  );
}

// src/components/artifacts/chart-artifact/chart-variant-services/constants.ts
var VARIANT_CHART_HEIGHT = "100%";

// src/components/artifacts/chart-artifact/chart-variant-services/bar-chart-variant-component.tsx
import { jsx as jsx7 } from "react/jsx-runtime";
function BarChartVariantComponent({ config, rows }) {
  return /* @__PURE__ */ jsx7(
    BarChart,
    {
      data: rows,
      xKey: config.xKey,
      series: config.series,
      stacked: config.stacked,
      height: VARIANT_CHART_HEIGHT
    }
  );
}

// src/components/artifacts/chart-artifact/chart-variant-services/shared-column-keys.ts
function seriesBasedColumnKeys(config) {
  return [config.xKey, ...config.series.map((s) => s.key)];
}
function pieColumnKeys(config) {
  return [config.categoryKey, config.valueKey];
}

// src/components/artifacts/chart-artifact/chart-variant-services/shared-validators.ts
function isValidChartSeries(series) {
  if (!series || typeof series !== "object") return false;
  const candidate = series;
  if (typeof candidate.key !== "string" || candidate.key.length === 0) return false;
  if (typeof candidate.label !== "string") return false;
  return true;
}

// src/components/artifacts/chart-artifact/chart-variant-services/bar-chart-variant-service.tsx
function isValidBarChartConfig(config) {
  if (!config || typeof config !== "object") return false;
  const candidate = config;
  if (candidate.variant !== "BAR") return false;
  if (typeof candidate.xKey !== "string" || candidate.xKey.length === 0) return false;
  if (!Array.isArray(candidate.series) || candidate.series.length === 0) return false;
  if (!candidate.series.every(isValidChartSeries)) return false;
  return true;
}
var BarChartVariantService = {
  variant: "BAR",
  isValidConfig: isValidBarChartConfig,
  columnKeys: seriesBasedColumnKeys,
  Component: BarChartVariantComponent
};

// src/components/artifacts/chart-artifact/chart-variant-services/line-chart-variant-component.tsx
import { jsx as jsx8 } from "react/jsx-runtime";
function LineChartVariantComponent({ config, rows }) {
  return /* @__PURE__ */ jsx8(LineChart, { data: rows, xKey: config.xKey, series: config.series, height: VARIANT_CHART_HEIGHT });
}

// src/components/artifacts/chart-artifact/chart-variant-services/line-chart-variant-service.tsx
function isValidLineChartConfig(config) {
  if (!config || typeof config !== "object") return false;
  const candidate = config;
  if (candidate.variant !== "LINE") return false;
  if (typeof candidate.xKey !== "string" || candidate.xKey.length === 0) return false;
  if (!Array.isArray(candidate.series) || candidate.series.length === 0) return false;
  if (!candidate.series.every(isValidChartSeries)) return false;
  return true;
}
var LineChartVariantService = {
  variant: "LINE",
  isValidConfig: isValidLineChartConfig,
  columnKeys: seriesBasedColumnKeys,
  Component: LineChartVariantComponent
};

// src/components/artifacts/chart-artifact/chart-variant-services/pie-chart-variant-component.tsx
import { jsx as jsx9 } from "react/jsx-runtime";
function PieChartVariantComponent({
  config,
  rows,
  labels
}) {
  return /* @__PURE__ */ jsx9(
    PieChart,
    {
      data: rows,
      categoryKey: config.categoryKey,
      valueKey: config.valueKey,
      othersCategoryLabels: labels.othersCategoryLabels,
      height: VARIANT_CHART_HEIGHT
    }
  );
}

// src/components/artifacts/chart-artifact/chart-variant-services/pie-chart-variant-service.tsx
function isValidPieChartConfig(config) {
  if (!config || typeof config !== "object") return false;
  const candidate = config;
  if (candidate.variant !== "PIE") return false;
  if (typeof candidate.categoryKey !== "string" || candidate.categoryKey.length === 0) return false;
  if (typeof candidate.valueKey !== "string" || candidate.valueKey.length === 0) return false;
  if (!Array.isArray(candidate.series)) return false;
  return true;
}
var PieChartVariantService = {
  variant: "PIE",
  isValidConfig: isValidPieChartConfig,
  columnKeys: pieColumnKeys,
  Component: PieChartVariantComponent
};

// src/components/artifacts/chart-artifact/chart-variant-services/index.ts
var ChartVariantServices = {
  LINE: LineChartVariantService,
  BAR: BarChartVariantService,
  PIE: PieChartVariantService
};

// src/components/artifacts/chart-artifact/chart-artifact-content.tsx
import { jsx as jsx10 } from "react/jsx-runtime";
function ChartArtifactContent({ config, rows, labels }) {
  const service = ChartVariantServices[config.variant];
  if (!service) {
    return /* @__PURE__ */ jsx10(StatusMessage, { $tone: "info", children: labels.unavailable });
  }
  const Component = service.Component;
  return /* @__PURE__ */ jsx10(Component, { config, rows, labels });
}

// src/components/artifacts/parse-csv.ts
import Papa from "papaparse";
function parseCsv(text, columns) {
  const result = Papa.parse(text, {
    header: true,
    skipEmptyLines: true,
    dynamicTyping: false
  });
  const csvHeaders = new Set(result.meta?.fields ?? []);
  const presentColumns = columns.filter((col) => csvHeaders.has(col.key));
  if (presentColumns.length === 0) return [];
  return result.data.map((rawRow) => {
    const row = {};
    for (const column of presentColumns) {
      const value = rawRow[column.key];
      row[column.key] = value === void 0 || value === "" ? null : value;
    }
    return row;
  });
}

// src/components/artifacts/use-rows-artifact-data.ts
import { useEffect as useEffect2, useMemo, useState as useState2 } from "react";
var LOADING = { status: "loading", rows: null, error: null };
var UNAVAILABLE = { status: "unavailable", rows: null, error: null };
var INITIAL_INTERNAL = { cacheKey: null, data: LOADING };
function columnsFingerprint(columns) {
  return columns.map((c) => c.key).join("|");
}
function scrubUrl(url) {
  const q = url.indexOf("?");
  return q === -1 ? url : `${url.slice(0, q)}?<redacted>`;
}
function useRowsArtifactData(presignedUrl, columns, parse) {
  const colsKey = useMemo(() => columnsFingerprint(columns), [columns]);
  const safeUrl = presignedUrl && isSafeDownloadUrl(presignedUrl) ? presignedUrl : null;
  const cacheKey = safeUrl ? `${safeUrl}::${colsKey}` : null;
  const [state, setState] = useState2(INITIAL_INTERNAL);
  useEffect2(() => {
    if (!safeUrl) return;
    const controller = new AbortController();
    fetch(safeUrl, {
      signal: controller.signal,
      headers: { Accept: "text/csv" },
      // Presigned URLs are cross-origin S3 in production and don't need credentials. Explicit
      // omit so a same-origin URL (compromised payload, local dev) can't accidentally receive
      // session cookies or auth headers.
      credentials: "omit"
    }).then(async (response) => {
      if (!response.ok) throw new Error(`Failed to load artifact data (${response.status})`);
      return response.text();
    }).then((text) => {
      if (controller.signal.aborted) return;
      try {
        const rows = parse(text, columns);
        setState({ cacheKey: `${safeUrl}::${colsKey}`, data: { status: "ready", rows, error: null } });
      } catch (parseError) {
        const err = parseError instanceof Error ? parseError : new Error(String(parseError));
        console.error("[ArtifactData] CSV parse failed:", err.message);
        setState({ cacheKey: `${safeUrl}::${colsKey}`, data: { status: "error", rows: null, error: err } });
      }
    }).catch((error) => {
      if (controller.signal.aborted) return;
      const err = error instanceof Error ? error : new Error(String(error));
      console.error(`[ArtifactData] Fetch failed [${scrubUrl(safeUrl)}]:`, err.message);
      setState({ cacheKey: `${safeUrl}::${colsKey}`, data: { status: "error", rows: null, error: err } });
    });
    return () => {
      controller.abort();
    };
  }, [safeUrl, colsKey]);
  if (!safeUrl) return UNAVAILABLE;
  if (state.cacheKey !== cacheKey) return LOADING;
  return state.data;
}

// src/components/artifacts/chart-artifact/use-chart-artifact-data.ts
function useChartArtifactData(presignedUrl, config) {
  const service = ChartVariantServices[config.variant];
  const keys = service ? service.columnKeys(config) : [];
  const columns = keys.map((key) => ({ key }));
  return useRowsArtifactData(presignedUrl, columns, parseCsv);
}

// src/components/artifacts/chart-artifact/validate.ts
function isValidChartConfig(config) {
  if (!config || typeof config !== "object") return false;
  const variant = config.variant;
  if (typeof variant !== "string") return false;
  const service = ChartVariantServices[variant];
  if (!service) return false;
  return service.isValidConfig(config);
}

// src/components/artifacts/chart-artifact/chart-artifact.tsx
import { jsx as jsx11, jsxs as jsxs4 } from "react/jsx-runtime";
var TITLE_CLASSES = "text-sm font-semibold text-foreground";
var CHART_HEIGHT = 320;
function ChartArtifact({ artifact, labels, callbacks }) {
  const validConfig = isValidChartConfig(artifact.config);
  const cardRef = useRef2(null);
  useEffect3(() => {
    if (validConfig) return;
    console.warn("[clay] ChartArtifact: malformed `config` \u2014 skipping render.");
  }, [validConfig]);
  const presignedUrl = artifact.protectedAsset?.presignedUrl ?? null;
  const resolvedLabels = useMemo2(
    () => ({ ...DEFAULT_CHART_ARTIFACT_LABELS, ...labels ?? {} }),
    [labels]
  );
  const data = useChartArtifactData(
    validConfig ? presignedUrl : null,
    validConfig ? artifact.config : { variant: "LINE", series: [], xKey: "x" }
  );
  const { onDownload, onDownloadPng, onCopyAsImage } = callbacks ?? {};
  const handleDownloadCsvSelect = onDownload ? () => onDownload(artifact) : void 0;
  const handleDownloadPngSelect = onDownloadPng ? () => onDownloadPng(artifact) : void 0;
  const handleCopyAsImageClick = onCopyAsImage ? () => onCopyAsImage(artifact) : void 0;
  const canCopyAsImage = data.status === "ready" && data.rows.length > 0;
  const canDownloadPng = data.status === "ready" && data.rows.length > 0;
  const isCsvDownloadAvailable = presignedUrl !== null && isSafeDownloadUrl(presignedUrl);
  const showDownloadMenu = validConfig && canDownloadPng || isCsvDownloadAvailable;
  const showActions = validConfig || showDownloadMenu;
  const pngFilename = (artifact.title ?? "").toLowerCase().split(/[^a-z0-9]+/).filter(Boolean).join("-") || "chart";
  return /* @__PURE__ */ jsxs4(Artifact, { ref: cardRef, className: "shadow-none w-full rounded-2xl bg-background/70", children: [
    /* @__PURE__ */ jsxs4(ArtifactHeader, { className: "bg-background/70", children: [
      artifact.title ? /* @__PURE__ */ jsx11(ArtifactTitle, { className: TITLE_CLASSES, children: artifact.title }) : /* @__PURE__ */ jsx11("span", {}),
      showActions ? /* @__PURE__ */ jsxs4(ArtifactActions, { ...{ [CAPTURE_EXCLUDE_ATTRIBUTE]: "" }, children: [
        validConfig ? /* @__PURE__ */ jsx11(
          ArtifactCopyAsImageButton,
          {
            targetRef: cardRef,
            label: resolvedLabels.copyAsImage,
            disabled: !canCopyAsImage,
            onClick: handleCopyAsImageClick
          }
        ) : null,
        showDownloadMenu ? /* @__PURE__ */ jsx11(
          ArtifactDownloadMenu,
          {
            triggerLabel: resolvedLabels.download,
            actions: {
              csv: isCsvDownloadAvailable ? {
                href: presignedUrl ?? "",
                label: resolvedLabels.downloadCsv,
                onSelect: handleDownloadCsvSelect
              } : void 0,
              png: validConfig ? {
                targetRef: cardRef,
                filename: pngFilename,
                label: resolvedLabels.downloadPng,
                disabled: !canDownloadPng,
                onSelect: handleDownloadPngSelect
              } : void 0
            }
          }
        ) : null
      ] }) : null
    ] }),
    /* @__PURE__ */ jsx11(
      ArtifactContent,
      {
        className: "p-4 overflow-visible flex flex-none items-center justify-center",
        style: { height: CHART_HEIGHT },
        children: renderBody(validConfig, artifact, data, resolvedLabels)
      }
    )
  ] });
}
function renderBody(validConfig, artifact, data, labels) {
  if (!validConfig) {
    return /* @__PURE__ */ jsx11(StatusMessage, { $tone: "info", children: labels.unavailable });
  }
  if (data.status === "error") {
    return /* @__PURE__ */ jsx11(StatusMessage, { $tone: "error", children: labels.loadError });
  }
  if (data.status === "unavailable") {
    return /* @__PURE__ */ jsx11(StatusMessage, { $tone: "info", children: labels.unavailable });
  }
  if (data.status === "loading") {
    return /* @__PURE__ */ jsx11(StatusMessage, { $tone: "info", children: labels.loading });
  }
  if (data.rows.length === 0) {
    return /* @__PURE__ */ jsx11(StatusMessage, { $tone: "info", children: labels.empty });
  }
  return /* @__PURE__ */ jsx11(ChartArtifactContent, { config: artifact.config, rows: data.rows, labels });
}

// src/components/artifacts/table-artifact/table-artifact.tsx
import { useEffect as useEffect4, useMemo as useMemo3 } from "react";

// src/components/artifacts/table-artifact/table-artifact-content.constants.ts
var TABLE_STATUS = {
  LOADING: "loading",
  READY: "ready",
  ERROR: "error",
  UNAVAILABLE: "unavailable"
};

// src/components/artifacts/table-artifact/table-artifact-content.utils.ts
function formatCell(row, column) {
  return row[column.key] ?? "";
}
var HEAD_CLASS = "h-auto py-2 px-4 text-xs font-medium text-foreground whitespace-nowrap text-left";
var CELL_CLASS = "p-4 text-sm font-normal text-foreground align-top min-w-[150px] text-left";
var ROW_CLASSES = "border-b-brown-30 bg-background/70 hover:bg-secondary";
var DATA_ROW_CLASSES = `${ROW_CLASSES} animate-in fade-in duration-300`;
var SCROLL_SHADOW = "0 1px 2px rgb(0 0 0 / 0.01), 0 6px 12px -2px rgb(0 0 0 / 0.03)";

// src/components/artifacts/table-artifact/table-artifact-content.tsx
import { jsx as jsx12, jsxs as jsxs5 } from "react/jsx-runtime";
function TableArtifactContent({
  columns,
  data,
  knownRowCount,
  maxShimmerRows,
  maxBodyHeight,
  labels
}) {
  if (data.status === TABLE_STATUS.ERROR) {
    return /* @__PURE__ */ jsx12(StatusMessage, { $tone: "error", children: labels.loadError });
  }
  if (data.status === TABLE_STATUS.UNAVAILABLE) {
    return /* @__PURE__ */ jsx12(StatusMessage, { $tone: "info", children: labels.unavailable });
  }
  if (data.status === TABLE_STATUS.LOADING) {
    if (typeof knownRowCount === "number" && knownRowCount > 0) {
      const shimmerCount = Math.min(knownRowCount, maxShimmerRows);
      return /* @__PURE__ */ jsx12(ArtifactTable, { columns, maxBodyHeight, children: renderShimmerRows(columns, shimmerCount) });
    }
    return /* @__PURE__ */ jsx12(StatusMessage, { $tone: "info", children: labels.loading });
  }
  return /* @__PURE__ */ jsx12(ArtifactTable, { columns, maxBodyHeight, children: data.rows.length === 0 ? renderEmptyRow(columns.length, labels.empty) : renderDataRows(columns, data.rows) });
}
function ArtifactTable({ columns, maxBodyHeight, children }) {
  const { targetRef, isScrolled } = useScrollShadow();
  return /* @__PURE__ */ jsx12("div", { ref: targetRef, className: "overscroll-none", style: { maxHeight: maxBodyHeight, overflowY: "auto" }, children: /* @__PURE__ */ jsxs5(Table, { containerClassName: "overflow-visible", children: [
    /* @__PURE__ */ jsx12(
      TableHeader,
      {
        "data-scrolled": isScrolled ? "true" : void 0,
        className: "sticky top-0 z-10 bg-background/70 backdrop-blur-lg transition-shadow",
        style: isScrolled ? { boxShadow: SCROLL_SHADOW } : void 0,
        children: /* @__PURE__ */ jsx12(TableRow, { className: "hover:bg-transparent", children: columns.map((column) => /* @__PURE__ */ jsx12(TableHead, { scope: "col", className: HEAD_CLASS, children: column.label }, column.key)) })
      }
    ),
    /* @__PURE__ */ jsx12(TableBody, { children })
  ] }) });
}
function renderShimmerRows(columns, count) {
  return Array.from({ length: count }).map((_, index) => /* @__PURE__ */ jsx12(TableRow, { className: ROW_CLASSES, "aria-hidden": "true", children: columns.map((column) => /* @__PURE__ */ jsx12(TableCell, { className: CELL_CLASS, children: /* @__PURE__ */ jsx12("span", { className: "block h-3 w-3/4 animate-pulse rounded bg-muted-foreground/20" }) }, column.key)) }, `shimmer-${index}`));
}
function renderDataRows(columns, rows) {
  return rows.map((row, index) => /* @__PURE__ */ jsx12(TableRow, { className: DATA_ROW_CLASSES, children: columns.map((column) => /* @__PURE__ */ jsx12(TableCell, { className: CELL_CLASS, children: formatCell(row, column) }, column.key)) }, index));
}
function renderEmptyRow(colSpan, emptyMessage) {
  return /* @__PURE__ */ jsx12(TableRow, { className: "hover:bg-transparent", children: /* @__PURE__ */ jsx12(TableCell, { colSpan, className: "py-6 text-center text-sm text-muted-foreground", children: emptyMessage }) });
}

// src/components/artifacts/table-artifact/use-table-artifact-data.ts
function useTableArtifactData(presignedUrl, columns) {
  return useRowsArtifactData(presignedUrl, columns, parseCsv);
}

// src/components/artifacts/table-artifact/validate.ts
function isValidTableConfig(config) {
  if (!config || typeof config !== "object") return false;
  const candidate = config;
  if (!Array.isArray(candidate.columns)) return false;
  if (candidate.columns.length === 0) return false;
  return candidate.columns.every(isValidTableColumn);
}
function isValidTableColumn(column) {
  if (!column || typeof column !== "object") return false;
  const candidate = column;
  if (typeof candidate.key !== "string" || candidate.key.length === 0) return false;
  if (typeof candidate.label !== "string") return false;
  return true;
}

// src/components/artifacts/table-artifact/table-artifact.tsx
import { jsx as jsx13, jsxs as jsxs6 } from "react/jsx-runtime";
var TITLE_CLASSES2 = "text-sm font-semibold text-foreground";
var TABLE_MAX_BODY_HEIGHT = 480;
var MAX_SHIMMER_ROWS = 10;
function TableArtifact({ artifact, labels, callbacks }) {
  const validConfig = isValidTableConfig(artifact.config);
  const validColumns = validConfig ? artifact.config.columns : null;
  useEffect4(() => {
    if (validConfig) return;
    console.warn("[clay] TableArtifact: malformed `config` \u2014 skipping render.");
  }, [validConfig]);
  const resolvedLabels = useMemo3(
    () => ({ ...DEFAULT_TABLE_ARTIFACT_LABELS, ...labels ?? {} }),
    [labels]
  );
  const data = useTableArtifactData(
    validConfig ? artifact.protectedAsset?.presignedUrl ?? null : null,
    validColumns ?? []
  );
  const presignedUrl = artifact.protectedAsset?.presignedUrl ?? null;
  const onDownload = callbacks?.onDownload;
  const handleDownloadClick = onDownload ? () => onDownload(artifact) : void 0;
  if (!validConfig || !validColumns) {
    return /* @__PURE__ */ jsxs6(Artifact, { className: "shadow-none w-full rounded-2xl bg-background/70", children: [
      /* @__PURE__ */ jsxs6(ArtifactHeader, { className: "bg-background/70", children: [
        artifact.title ? /* @__PURE__ */ jsx13(ArtifactTitle, { className: TITLE_CLASSES2, children: artifact.title }) : /* @__PURE__ */ jsx13("span", {}),
        presignedUrl ? /* @__PURE__ */ jsx13(ArtifactActions, { children: /* @__PURE__ */ jsx13(
          ArtifactDownloadButton,
          {
            href: presignedUrl,
            label: resolvedLabels.download,
            onClick: handleDownloadClick
          }
        ) }) : null
      ] }),
      /* @__PURE__ */ jsx13(ArtifactContent, { className: "p-0 overflow-auto", style: { maxHeight: TABLE_MAX_BODY_HEIGHT }, children: /* @__PURE__ */ jsx13(StatusMessage, { $tone: "info", children: resolvedLabels.unavailable }) })
    ] });
  }
  return (
    // The table body owns its own scroll container (`ArtifactTable` inside `TableArtifactContent`).
    // Disable the outer overflow container so only one scroll context exists — this prevents
    // double-scroll nesting and lets `useScrollShadow` find the correct scroll ancestor.
    /* @__PURE__ */ jsxs6(Artifact, { className: "shadow-none w-full rounded-2xl bg-background/70", children: [
      /* @__PURE__ */ jsxs6(ArtifactHeader, { className: "bg-background/70", children: [
        artifact.title ? /* @__PURE__ */ jsx13(ArtifactTitle, { className: TITLE_CLASSES2, children: artifact.title }) : /* @__PURE__ */ jsx13("span", {}),
        /* @__PURE__ */ jsx13(ArtifactActions, { children: /* @__PURE__ */ jsx13(
          ArtifactDownloadButton,
          {
            href: presignedUrl ?? "",
            label: resolvedLabels.download,
            onClick: handleDownloadClick
          }
        ) })
      ] }),
      /* @__PURE__ */ jsx13(ArtifactContent, { className: "p-0 overflow-visible", style: { maxHeight: "none" }, children: /* @__PURE__ */ jsx13(
        TableArtifactContent,
        {
          columns: validColumns,
          data,
          knownRowCount: artifact.config.stats?.rowCount,
          maxShimmerRows: MAX_SHIMMER_ROWS,
          maxBodyHeight: TABLE_MAX_BODY_HEIGHT,
          labels: resolvedLabels
        }
      ) })
    ] })
  );
}

// src/components/artifacts/chart-artifact/to-clipboard-text.ts
function chartArtifactToClipboardText(artifact) {
  const trimmedTitle = artifact.title?.trim();
  return trimmedTitle || "Chart";
}

// src/components/artifacts/artifact-services/chart-artifact-service.ts
var ChartArtifactService = {
  type: artifactTypes.CHART,
  Component: ChartArtifact,
  toClipboardText: chartArtifactToClipboardText
};

// src/components/artifacts/table-artifact/to-clipboard-text.ts
function tableArtifactToClipboardText(artifact) {
  const trimmedTitle = artifact.title?.trim();
  return trimmedTitle || "Table";
}

// src/components/artifacts/artifact-services/table-artifact-service.ts
var TableArtifactService = {
  type: artifactTypes.TABLE,
  Component: TableArtifact,
  toClipboardText: tableArtifactToClipboardText
};

// src/components/artifacts/artifact-services/index.ts
var ArtifactServices = {
  [artifactTypes.TABLE]: TableArtifactService,
  [artifactTypes.CHART]: ChartArtifactService
};
function artifactToClipboardText(artifact) {
  const entry = ArtifactServices[artifact.type];
  if (!entry) {
    return `[Artifact: ${artifact.title ?? artifact.type}]`;
  }
  return entry.toClipboardText(artifact);
}

export {
  artifactTypes,
  DEFAULT_CHART_ARTIFACT_LABELS,
  DEFAULT_TABLE_ARTIFACT_LABELS,
  IconCheck,
  IconCopy,
  IconThumbDown,
  IconThumbUp,
  ArtifactCopyAsImageButton,
  ArtifactDownloadButton,
  isSafeDownloadUrl,
  ArtifactDownloadMenu,
  ChartArtifact,
  TableArtifact,
  ArtifactServices,
  artifactToClipboardText
};
/*! Bundled license information:

@tabler/icons-react/dist/esm/defaultAttributes.mjs:
@tabler/icons-react/dist/esm/createReactComponent.mjs:
@tabler/icons-react/dist/esm/icons/IconAlertCircle.mjs:
@tabler/icons-react/dist/esm/icons/IconCheck.mjs:
@tabler/icons-react/dist/esm/icons/IconCopy.mjs:
@tabler/icons-react/dist/esm/icons/IconDownload.mjs:
@tabler/icons-react/dist/esm/icons/IconFileSpreadsheet.mjs:
@tabler/icons-react/dist/esm/icons/IconLoader2.mjs:
@tabler/icons-react/dist/esm/icons/IconPhoto.mjs:
@tabler/icons-react/dist/esm/icons/IconThumbDown.mjs:
@tabler/icons-react/dist/esm/icons/IconThumbUp.mjs:
@tabler/icons-react/dist/esm/tabler-icons-react.mjs:
  (**
   * @license @tabler/icons-react v3.37.1 - MIT
   *
   * This source code is licensed under the MIT license.
   * See the LICENSE file in the root directory of this source tree.
   *)
*/
//# sourceMappingURL=chunk-XFJ6XMJZ.js.map