@ash-cloud/ash-ui 0.0.3 → 0.0.4

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.cjs CHANGED
@@ -636,6 +636,16 @@ function ClipboardListIcon({ className }) {
636
636
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M8 16h.01" })
637
637
  ] });
638
638
  }
639
+ function SpinnerIcon({ className }) {
640
+ return /* @__PURE__ */ jsxRuntime.jsx("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" }) });
641
+ }
642
+ function ErrorIcon({ className }) {
643
+ return /* @__PURE__ */ jsxRuntime.jsxs("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
644
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "10" }),
645
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "15", y1: "9", x2: "9", y2: "15" }),
646
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "9", y1: "9", x2: "15", y2: "15" })
647
+ ] });
648
+ }
639
649
  function StatusIndicator({ status, size = "sm", className }) {
640
650
  const sizeClasses = {
641
651
  sm: "w-2 h-2",
@@ -1534,6 +1544,163 @@ function ToolExecutionGroup({
1534
1544
  }
1535
1545
  );
1536
1546
  }
1547
+ function formatDuration(startMs, endMs) {
1548
+ const duration = endMs - startMs;
1549
+ if (duration < 1e3) return `${duration}ms`;
1550
+ return `${(duration / 1e3).toFixed(1)}s`;
1551
+ }
1552
+ function getToolLabel(toolName, summary) {
1553
+ if (summary && summary.length > 0 && summary.length < 50) {
1554
+ return summary;
1555
+ }
1556
+ const cleaned = toolName.replace(/^mcp__[^_]+__/, "").replace(/Tool$/, "").replace(/_/g, " ").replace(/([a-z])([A-Z])/g, "$1 $2");
1557
+ return cleaned.charAt(0).toUpperCase() + cleaned.slice(1);
1558
+ }
1559
+ function toStepStatus(status) {
1560
+ switch (status) {
1561
+ case "pending":
1562
+ return "running";
1563
+ case "success":
1564
+ return "success";
1565
+ case "failed":
1566
+ return "error";
1567
+ default:
1568
+ return "pending";
1569
+ }
1570
+ }
1571
+ function StepIcon({ status }) {
1572
+ const iconClass = "w-3.5 h-3.5";
1573
+ switch (status) {
1574
+ case "running":
1575
+ return /* @__PURE__ */ jsxRuntime.jsx(SpinnerIcon, { className: cn(iconClass, "animate-spin text-[var(--ash-accent)]") });
1576
+ case "success":
1577
+ return /* @__PURE__ */ jsxRuntime.jsx(CheckIcon, { className: cn(iconClass, "text-[var(--ash-accent)]") });
1578
+ case "error":
1579
+ return /* @__PURE__ */ jsxRuntime.jsx(ErrorIcon, { className: cn(iconClass, "text-red-500") });
1580
+ default:
1581
+ return /* @__PURE__ */ jsxRuntime.jsx(ToolIcon, { className: cn(iconClass, "text-white/40") });
1582
+ }
1583
+ }
1584
+ function StepAccordion({
1585
+ toolCalls,
1586
+ defaultExpanded = false,
1587
+ isExpanded: controlledExpanded,
1588
+ onToggle,
1589
+ className
1590
+ }) {
1591
+ const [internalExpanded, setInternalExpanded] = react.useState(defaultExpanded);
1592
+ const isExpanded = controlledExpanded !== void 0 ? controlledExpanded : internalExpanded;
1593
+ const handleToggle = react.useCallback(() => {
1594
+ if (onToggle) {
1595
+ onToggle();
1596
+ } else {
1597
+ setInternalExpanded((prev) => !prev);
1598
+ }
1599
+ }, [onToggle]);
1600
+ if (toolCalls.length === 0) {
1601
+ return null;
1602
+ }
1603
+ const completedSteps = toolCalls.filter((tc) => tc.status === "success" || tc.status === "failed").length;
1604
+ const runningStep = toolCalls.find((tc) => tc.status === "pending");
1605
+ const hasError = toolCalls.some((tc) => tc.status === "failed");
1606
+ const allComplete = completedSteps === toolCalls.length;
1607
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1608
+ "div",
1609
+ {
1610
+ className: cn(
1611
+ "rounded-xl border overflow-hidden",
1612
+ hasError ? "border-red-500/30" : allComplete ? "border-[var(--ash-accent)]/30" : "border-yellow-500/30",
1613
+ className
1614
+ ),
1615
+ children: [
1616
+ /* @__PURE__ */ jsxRuntime.jsxs(
1617
+ "button",
1618
+ {
1619
+ type: "button",
1620
+ onClick: handleToggle,
1621
+ className: "w-full flex items-center gap-2 px-3 py-2 bg-white/5 hover:bg-white/10 transition-colors text-left cursor-pointer",
1622
+ children: [
1623
+ /* @__PURE__ */ jsxRuntime.jsx(
1624
+ ChevronDownIcon,
1625
+ {
1626
+ className: cn(
1627
+ "w-4 h-4 text-white/40 transition-transform duration-200 flex-shrink-0",
1628
+ !isExpanded && "-rotate-90"
1629
+ )
1630
+ }
1631
+ ),
1632
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-w-0 flex items-center gap-2", children: runningStep ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1633
+ /* @__PURE__ */ jsxRuntime.jsx(SpinnerIcon, { className: "w-3.5 h-3.5 animate-spin text-[var(--ash-accent)] flex-shrink-0" }),
1634
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-white/80 truncate", children: getToolLabel(runningStep.toolName, runningStep.summary) })
1635
+ ] }) : hasError ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1636
+ /* @__PURE__ */ jsxRuntime.jsx(ErrorIcon, { className: "w-3.5 h-3.5 text-red-500 flex-shrink-0" }),
1637
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-red-400 truncate", children: "Completed with errors" })
1638
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1639
+ /* @__PURE__ */ jsxRuntime.jsx(CheckIcon, { className: "w-3.5 h-3.5 text-[var(--ash-accent)] flex-shrink-0" }),
1640
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm text-white/70 truncate", children: [
1641
+ completedSteps,
1642
+ " step",
1643
+ completedSteps !== 1 ? "s" : "",
1644
+ " completed"
1645
+ ] })
1646
+ ] }) }),
1647
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs px-1.5 py-0.5 rounded-full bg-white/10 text-white/50 flex-shrink-0", children: [
1648
+ completedSteps,
1649
+ "/",
1650
+ toolCalls.length
1651
+ ] })
1652
+ ]
1653
+ }
1654
+ ),
1655
+ isExpanded && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t border-white/10 ash-accordion-content", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "divide-y divide-white/5", children: toolCalls.map((toolCall, index) => {
1656
+ const stepStatus = toStepStatus(toolCall.status);
1657
+ const startTime = toolCall.startedAt ? new Date(toolCall.startedAt).getTime() : 0;
1658
+ const endTime = toolCall.completedAt ? new Date(toolCall.completedAt).getTime() : 0;
1659
+ const hasDuration = startTime > 0 && endTime > 0;
1660
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1661
+ "div",
1662
+ {
1663
+ className: cn(
1664
+ "px-3 py-2 flex items-start gap-2",
1665
+ stepStatus === "running" && "bg-[var(--ash-accent)]/5",
1666
+ stepStatus === "error" && "bg-red-500/5"
1667
+ ),
1668
+ children: [
1669
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 flex-shrink-0 pt-0.5", children: [
1670
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-white/40 w-4 text-right", children: [
1671
+ index + 1,
1672
+ "."
1673
+ ] }),
1674
+ /* @__PURE__ */ jsxRuntime.jsx(StepIcon, { status: stepStatus })
1675
+ ] }),
1676
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
1677
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
1678
+ /* @__PURE__ */ jsxRuntime.jsx(
1679
+ "span",
1680
+ {
1681
+ className: cn(
1682
+ "text-sm",
1683
+ stepStatus === "running" && "text-[var(--ash-accent)]",
1684
+ stepStatus === "success" && "text-white/70",
1685
+ stepStatus === "error" && "text-red-400",
1686
+ stepStatus === "pending" && "text-white/40"
1687
+ ),
1688
+ children: getToolLabel(toolCall.toolName, toolCall.summary)
1689
+ }
1690
+ ),
1691
+ hasDuration && (stepStatus === "success" || stepStatus === "error") && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-white/40", children: formatDuration(startTime, endTime) })
1692
+ ] }),
1693
+ toolCall.isError && toolCall.actionType && "result" in toolCall.actionType && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs mt-1 text-red-400/80 truncate", children: String(toolCall.actionType.result?.value || "Error") })
1694
+ ] })
1695
+ ]
1696
+ },
1697
+ toolCall.id
1698
+ );
1699
+ }) }) })
1700
+ ]
1701
+ }
1702
+ );
1703
+ }
1537
1704
 
1538
1705
  // src/types.ts
1539
1706
  function isCommandRunAction(action) {
@@ -1652,7 +1819,13 @@ function MessageList({
1652
1819
  const toolCalls = extractToolCallsFromGroup(groupedEntry.entries);
1653
1820
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-3 ash-animate-fade-in", children: [
1654
1821
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-7 h-7 rounded-full bg-[var(--ash-accent)]/20 flex items-center justify-center shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(BotIcon, { className: "w-4 h-4 text-[var(--ash-accent)]" }) }),
1655
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(
1822
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1", children: config.mode === "accordion" ? /* @__PURE__ */ jsxRuntime.jsx(
1823
+ StepAccordion,
1824
+ {
1825
+ toolCalls,
1826
+ defaultExpanded: config.defaultExpanded
1827
+ }
1828
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
1656
1829
  ToolExecutionGroup,
1657
1830
  {
1658
1831
  toolCalls,
@@ -2072,19 +2245,22 @@ function EnvVarsPanel({
2072
2245
  function DisplayModeToggle({
2073
2246
  className,
2074
2247
  showLabel = true,
2075
- labels = { inline: "Inline", compact: "Compact" }
2248
+ labels = { inline: "Inline", compact: "Compact", accordion: "Steps" },
2249
+ modes = ["inline", "compact", "accordion"]
2076
2250
  }) {
2077
- const { config, toggleMode } = useDisplayMode();
2078
- const isInline = config.mode === "inline";
2079
- return /* @__PURE__ */ jsxRuntime.jsx(
2080
- "button",
2081
- {
2082
- type: "button",
2083
- onClick: toggleMode,
2084
- className: cn("ash-display-mode-toggle", className),
2085
- title: isInline ? "Switch to compact mode" : "Switch to inline mode",
2086
- children: isInline ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2087
- /* @__PURE__ */ jsxRuntime.jsx(
2251
+ const { config, setMode } = useDisplayMode();
2252
+ const currentMode = config.mode;
2253
+ const currentIndex = modes.indexOf(currentMode);
2254
+ const effectiveIndex = currentIndex === -1 ? 0 : currentIndex;
2255
+ const nextIndex = (effectiveIndex + 1) % modes.length;
2256
+ const nextMode = modes[nextIndex];
2257
+ const handleClick = () => {
2258
+ setMode(nextMode);
2259
+ };
2260
+ const getIcon = (mode) => {
2261
+ switch (mode) {
2262
+ case "inline":
2263
+ return /* @__PURE__ */ jsxRuntime.jsx(
2088
2264
  "svg",
2089
2265
  {
2090
2266
  className: "ash-display-mode-icon",
@@ -2101,10 +2277,9 @@ function DisplayModeToggle({
2101
2277
  }
2102
2278
  )
2103
2279
  }
2104
- ),
2105
- showLabel && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ash-display-mode-label", children: labels.inline })
2106
- ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2107
- /* @__PURE__ */ jsxRuntime.jsx(
2280
+ );
2281
+ case "compact":
2282
+ return /* @__PURE__ */ jsxRuntime.jsx(
2108
2283
  "svg",
2109
2284
  {
2110
2285
  className: "ash-display-mode-icon",
@@ -2121,9 +2296,42 @@ function DisplayModeToggle({
2121
2296
  }
2122
2297
  )
2123
2298
  }
2124
- ),
2125
- showLabel && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ash-display-mode-label", children: labels.compact })
2126
- ] })
2299
+ );
2300
+ case "accordion":
2301
+ return /* @__PURE__ */ jsxRuntime.jsx(
2302
+ "svg",
2303
+ {
2304
+ className: "ash-display-mode-icon",
2305
+ viewBox: "0 0 24 24",
2306
+ fill: "none",
2307
+ stroke: "currentColor",
2308
+ strokeWidth: "1.5",
2309
+ children: /* @__PURE__ */ jsxRuntime.jsx(
2310
+ "path",
2311
+ {
2312
+ strokeLinecap: "round",
2313
+ strokeLinejoin: "round",
2314
+ d: "M8.25 6.75h12M8.25 12h12M8.25 17.25h12M3.75 6.75h.007v.008H3.75V6.75zm.375 0a.375.375 0 11-.75 0 .375.375 0 01.75 0zM3.75 12h.007v.008H3.75V12zm.375 0a.375.375 0 11-.75 0 .375.375 0 01.75 0zm-.375 5.25h.007v.008H3.75v-.008zm.375 0a.375.375 0 11-.75 0 .375.375 0 01.75 0z"
2315
+ }
2316
+ )
2317
+ }
2318
+ );
2319
+ }
2320
+ };
2321
+ const getLabel = (mode) => {
2322
+ return labels[mode] || mode.charAt(0).toUpperCase() + mode.slice(1);
2323
+ };
2324
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2325
+ "button",
2326
+ {
2327
+ type: "button",
2328
+ onClick: handleClick,
2329
+ className: cn("ash-display-mode-toggle", className),
2330
+ title: `Switch to ${nextMode} mode`,
2331
+ children: [
2332
+ getIcon(currentMode),
2333
+ showLabel && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ash-display-mode-label", children: getLabel(currentMode) })
2334
+ ]
2127
2335
  }
2128
2336
  );
2129
2337
  }
@@ -2759,6 +2967,7 @@ exports.DisplayModeProvider = DisplayModeProvider;
2759
2967
  exports.DisplayModeToggle = DisplayModeToggle;
2760
2968
  exports.EditIcon = EditIcon;
2761
2969
  exports.EnvVarsPanel = EnvVarsPanel;
2970
+ exports.ErrorIcon = ErrorIcon;
2762
2971
  exports.ErrorMessage = ErrorMessage;
2763
2972
  exports.FileIcon = FileIcon;
2764
2973
  exports.FilePlusIcon = FilePlusIcon;
@@ -2780,7 +2989,9 @@ exports.PlugIcon = PlugIcon;
2780
2989
  exports.SearchIcon = SearchIcon;
2781
2990
  exports.SendIcon = SendIcon;
2782
2991
  exports.SparklesIcon = SparklesIcon;
2992
+ exports.SpinnerIcon = SpinnerIcon;
2783
2993
  exports.StatusIndicator = StatusIndicator;
2994
+ exports.StepAccordion = StepAccordion;
2784
2995
  exports.StopCircleIcon = StopCircleIcon;
2785
2996
  exports.StreamingText = StreamingText;
2786
2997
  exports.SunIcon = SunIcon;