@invana/ui 0.0.24 → 0.0.25

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
@@ -3984,6 +3984,56 @@ var CitationRow = React23__namespace.forwardRef(
3984
3984
  )
3985
3985
  );
3986
3986
  CitationRow.displayName = "CitationRow";
3987
+ var ClampedText = React23__namespace.forwardRef(
3988
+ ({
3989
+ lines = 3,
3990
+ moreLabel = "Show more",
3991
+ lessLabel = "Show less",
3992
+ className,
3993
+ children,
3994
+ ...props
3995
+ }, ref) => {
3996
+ const [expanded, setExpanded] = React23__namespace.useState(false);
3997
+ const [clipped, setClipped] = React23__namespace.useState(false);
3998
+ const bodyRef = React23__namespace.useRef(null);
3999
+ React23__namespace.useLayoutEffect(() => {
4000
+ const el = bodyRef.current;
4001
+ if (!el || expanded) return;
4002
+ const measure = () => setClipped(el.scrollHeight - el.clientHeight > 1);
4003
+ measure();
4004
+ const observer = new ResizeObserver(measure);
4005
+ observer.observe(el);
4006
+ return () => observer.disconnect();
4007
+ }, [expanded, children, lines]);
4008
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, className: cn("min-w-0", className), ...props, children: [
4009
+ /* @__PURE__ */ jsxRuntime.jsx(
4010
+ "p",
4011
+ {
4012
+ ref: bodyRef,
4013
+ className: cn(
4014
+ "whitespace-pre-line",
4015
+ !expanded && "overflow-hidden [-webkit-box-orient:vertical] [-webkit-line-clamp:var(--clamped-lines)] [display:-webkit-box]"
4016
+ ),
4017
+ style: { "--clamped-lines": lines },
4018
+ children
4019
+ }
4020
+ ),
4021
+ clipped ? /* @__PURE__ */ jsxRuntime.jsx(
4022
+ Button,
4023
+ {
4024
+ type: "button",
4025
+ variant: "link",
4026
+ size: "sm",
4027
+ className: "h-auto p-0",
4028
+ "aria-expanded": expanded,
4029
+ onClick: () => setExpanded((open) => !open),
4030
+ children: expanded ? lessLabel : moreLabel
4031
+ }
4032
+ ) : null
4033
+ ] });
4034
+ }
4035
+ );
4036
+ ClampedText.displayName = "ClampedText";
3987
4037
  var ClarifyCard = React23__namespace.forwardRef(
3988
4038
  ({
3989
4039
  step,
@@ -5192,6 +5242,27 @@ var SearchInput = ({
5192
5242
  }
5193
5243
  );
5194
5244
  };
5245
+ var Eyebrow = React23__namespace.forwardRef(
5246
+ ({ aside, tone = "muted", className, children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(
5247
+ "div",
5248
+ {
5249
+ ref,
5250
+ className: cn(
5251
+ "flex items-baseline gap-2 text-meta font-semibold uppercase tracking-wide",
5252
+ tone === "muted" && "text-muted-foreground",
5253
+ tone === "foreground" && "text-foreground",
5254
+ tone === "accent" && "text-primary",
5255
+ className
5256
+ ),
5257
+ ...props,
5258
+ children: [
5259
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 truncate", children }),
5260
+ aside != null ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-auto shrink-0 font-normal normal-case tracking-normal text-muted-foreground", children: aside }) : null
5261
+ ]
5262
+ }
5263
+ )
5264
+ );
5265
+ Eyebrow.displayName = "Eyebrow";
5195
5266
  var SectionHeader = React23__namespace.forwardRef(({ icon, title, count, actions, bare, className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(
5196
5267
  "div",
5197
5268
  {
@@ -5365,6 +5436,299 @@ function TabbedPanel({
5365
5436
  footerContent && /* @__PURE__ */ jsxRuntime.jsx(CardFooter, { className: cn("shrink-0", footerClassName), children: footerContent })
5366
5437
  ] }) }) });
5367
5438
  }
5439
+ var BAR = {
5440
+ succeeded: "bg-success",
5441
+ running: "bg-info",
5442
+ failed: "bg-destructive",
5443
+ needs_input: "bg-warning",
5444
+ stopped: "bg-muted-foreground",
5445
+ skipped: "bg-transparent",
5446
+ queued: "bg-transparent"
5447
+ };
5448
+ var DOT = {
5449
+ succeeded: "success",
5450
+ running: "running",
5451
+ failed: "error",
5452
+ needs_input: "warning",
5453
+ stopped: "muted",
5454
+ skipped: "muted",
5455
+ queued: "queued"
5456
+ };
5457
+ var STATUS_LABEL = {
5458
+ succeeded: "succeeded",
5459
+ running: "running",
5460
+ failed: "failed",
5461
+ needs_input: "needs input",
5462
+ stopped: "stopped",
5463
+ skipped: "never ran",
5464
+ queued: "not started"
5465
+ };
5466
+ function renderResult(result) {
5467
+ if (result == null) return null;
5468
+ if (React23__namespace.isValidElement(result)) return result;
5469
+ if (typeof result !== "object") {
5470
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono text-meta", children: String(result) });
5471
+ }
5472
+ const entries = Object.entries(result);
5473
+ const scalars = entries.filter(([, v]) => v == null || typeof v !== "object");
5474
+ const nested = entries.filter(([, v]) => v != null && typeof v === "object");
5475
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
5476
+ scalars.length ? /* @__PURE__ */ jsxRuntime.jsx(PropertyList, { labelWidth: 96, children: scalars.map(([k, v]) => /* @__PURE__ */ jsxRuntime.jsx(PropertyRow, { label: k, mono: true, className: "py-0.5", children: v == null ? "\u2014" : String(v) }, k)) }) : null,
5477
+ nested.map(([k, v]) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-0.5", children: [
5478
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-meta text-muted-foreground", children: k }),
5479
+ /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "max-h-40 overflow-auto border border-border bg-muted/40 p-1.5 font-mono text-meta", children: JSON.stringify(v, null, 2) })
5480
+ ] }, k))
5481
+ ] });
5482
+ }
5483
+ var TaskGanttDetailCard = React23__namespace.forwardRef(({ task, elapsedMs, formatDuration = defaultFormatDuration, className, ...props }, ref) => {
5484
+ const status = task.status ?? "succeeded";
5485
+ const ms = task.durationMs ?? elapsedMs;
5486
+ const duration = task.duration ?? (ms != null ? formatDuration(ms) : "\u2014");
5487
+ const attempts = task.attempts ?? [];
5488
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, className: cn("flex flex-col gap-2", className), ...props, children: [
5489
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-baseline gap-2", children: [
5490
+ /* @__PURE__ */ jsxRuntime.jsx(StatusDot, { tone: DOT[status], size: "md", className: "translate-y-px" }),
5491
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate font-mono text-meta font-medium", children: task.key }),
5492
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 font-mono text-meta text-muted-foreground tabular-nums", children: duration })
5493
+ ] }),
5494
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-meta text-muted-foreground", children: [
5495
+ STATUS_LABEL[status],
5496
+ task.summary != null ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
5497
+ " \xB7 ",
5498
+ task.summary
5499
+ ] }) : null
5500
+ ] }),
5501
+ attempts.length ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-0.5", children: attempts.map((a, i) => /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-meta text-muted-foreground", children: [
5502
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-medium text-warning", children: [
5503
+ "attempt ",
5504
+ i + 1
5505
+ ] }),
5506
+ " ",
5507
+ a.title ?? `${a.status ?? "failed"}${a.durationMs != null ? ` \xB7 ${formatDuration(a.durationMs)}` : ""}`
5508
+ ] }, i)) }) : null,
5509
+ task.error != null ? /* @__PURE__ */ jsxRuntime.jsxs(
5510
+ "div",
5511
+ {
5512
+ style: { borderColor: "var(--color-destructive)" },
5513
+ className: "border-l-2 bg-destructive/10 px-2 py-1.5",
5514
+ children: [
5515
+ task.error.code != null ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-mono text-meta font-medium text-destructive", children: task.error.code }) : null,
5516
+ task.error.message != null ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-meta", children: task.error.message }) : null,
5517
+ task.error.detail != null ? /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "mt-1 max-h-32 overflow-auto whitespace-pre-wrap font-mono text-meta text-muted-foreground", children: task.error.detail }) : null
5518
+ ]
5519
+ }
5520
+ ) : null,
5521
+ task.result != null ? renderResult(task.result) : null,
5522
+ task.log != null ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t border-border pt-1.5 font-mono text-meta text-muted-foreground", children: task.log }) : null
5523
+ ] });
5524
+ });
5525
+ TaskGanttDetailCard.displayName = "TaskGanttDetailCard";
5526
+ var toMs = (t) => t instanceof Date ? t.getTime() : typeof t === "number" ? t : Date.parse(t);
5527
+ var defaultFormatDuration = (ms) => {
5528
+ if (ms < 100) return `${Math.round(ms)}ms`;
5529
+ const s = ms / 1e3;
5530
+ return s < 10 ? `${(Math.round(s * 10) / 10).toFixed(1)}s` : `${Math.round(s)}s`;
5531
+ };
5532
+ var defaultFormatTick = (ms) => {
5533
+ if (ms === 0) return "0s";
5534
+ const s = ms / 1e3;
5535
+ return Number.isInteger(s) ? `${s}s` : `${(Math.round(s * 10) / 10).toFixed(1)}s`;
5536
+ };
5537
+ function place(seg, origin) {
5538
+ let start = seg.startMs;
5539
+ if (start == null && seg.startedAt != null && origin != null) {
5540
+ start = toMs(seg.startedAt) - origin;
5541
+ }
5542
+ if (start == null || Number.isNaN(start)) return null;
5543
+ let duration = seg.durationMs;
5544
+ if (duration == null && seg.startedAt != null && seg.finishedAt != null) {
5545
+ duration = toMs(seg.finishedAt) - toMs(seg.startedAt);
5546
+ }
5547
+ return { start, duration: duration != null && duration > 0 ? duration : 0 };
5548
+ }
5549
+ var TaskGantt = React23__namespace.forwardRef(
5550
+ ({
5551
+ tasks,
5552
+ origin,
5553
+ spanMs,
5554
+ nowMs,
5555
+ openEnded,
5556
+ ticks = 4,
5557
+ formatTick = defaultFormatTick,
5558
+ formatDuration = defaultFormatDuration,
5559
+ labelWidth = 112,
5560
+ density = "comfortable",
5561
+ showDetail = true,
5562
+ renderDetail,
5563
+ detailProps,
5564
+ selectedKey,
5565
+ onSelectTask,
5566
+ className,
5567
+ ...props
5568
+ }, ref) => {
5569
+ const barHeight = density === "compact" ? 11 : 13;
5570
+ const durationWidth = 40;
5571
+ const rows = React23__namespace.useMemo(() => {
5572
+ const stamps = [];
5573
+ for (const t of [...tasks, ...tasks.flatMap((t2) => t2.attempts ?? [])]) {
5574
+ if (t.startedAt != null) stamps.push(toMs(t.startedAt));
5575
+ }
5576
+ const zero = origin != null ? toMs(origin) : stamps.length ? Math.min(...stamps) : void 0;
5577
+ return tasks.map((task) => {
5578
+ const segments = [...task.attempts ?? [], task].map((seg) => {
5579
+ const at = place(seg, zero);
5580
+ return at ? { ...at, status: seg.status ?? task.status ?? "succeeded", title: seg.title } : null;
5581
+ }).filter((s) => s !== null);
5582
+ const last = segments[segments.length - 1];
5583
+ return { task, segments, end: last ? last.start + last.duration : 0 };
5584
+ });
5585
+ }, [tasks, origin]);
5586
+ const span = Math.max(
5587
+ spanMs ?? Math.max(nowMs ?? 0, ...rows.map((r) => r.end)),
5588
+ 1
5589
+ );
5590
+ const pct = (ms) => `${Math.max(0, Math.min(100, ms / span * 100))}%`;
5591
+ const axis = Array.from(
5592
+ { length: ticks + 1 },
5593
+ (_, i) => formatTick(span / ticks * i)
5594
+ );
5595
+ const lastLabel = openEnded ? `${axis[axis.length - 1]}+` : axis[axis.length - 1];
5596
+ const detailFor = (task, elapsedMs) => {
5597
+ if (!showDetail) return null;
5598
+ if (renderDetail) return renderDetail(task);
5599
+ if (task.detail != null) return task.detail;
5600
+ const hasBody = task.result != null || task.error != null || task.log != null || task.summary != null || (task.attempts?.length ?? 0) > 0;
5601
+ if (!hasBody) return null;
5602
+ return /* @__PURE__ */ jsxRuntime.jsx(
5603
+ TaskGanttDetailCard,
5604
+ {
5605
+ task,
5606
+ elapsedMs,
5607
+ formatDuration
5608
+ }
5609
+ );
5610
+ };
5611
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, className: cn("flex flex-col", className), ...props, children: [
5612
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 pt-0.5 pb-1", "aria-hidden": true, children: [
5613
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0", style: { width: labelWidth } }),
5614
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex flex-1", children: axis.slice(0, -1).map((label, i) => /* @__PURE__ */ jsxRuntime.jsx(
5615
+ "span",
5616
+ {
5617
+ className: "flex-1 border-l border-border pl-1 text-meta text-muted-foreground tabular-nums",
5618
+ children: label
5619
+ },
5620
+ i
5621
+ )) }),
5622
+ /* @__PURE__ */ jsxRuntime.jsx(
5623
+ "span",
5624
+ {
5625
+ className: "shrink-0 text-right text-meta text-muted-foreground tabular-nums",
5626
+ style: { width: durationWidth },
5627
+ children: lastLabel
5628
+ }
5629
+ )
5630
+ ] }),
5631
+ rows.map(({ task, segments }) => {
5632
+ const neverRan = segments.length === 0;
5633
+ const selected = selectedKey != null && selectedKey === task.key;
5634
+ const pickable = onSelectTask != null;
5635
+ const elapsed = task.durationMs ?? segments[segments.length - 1]?.duration;
5636
+ const duration = task.duration ?? (neverRan || elapsed == null ? "\u2014" : formatDuration(elapsed));
5637
+ const detail = detailFor(task, elapsed);
5638
+ const row = /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 py-[3px]", children: [
5639
+ /* @__PURE__ */ jsxRuntime.jsx(
5640
+ "span",
5641
+ {
5642
+ className: cn(
5643
+ "shrink-0 truncate font-mono text-meta",
5644
+ neverRan && "text-muted-foreground"
5645
+ ),
5646
+ style: { width: labelWidth },
5647
+ title: task.key,
5648
+ children: task.label ?? task.key
5649
+ }
5650
+ ),
5651
+ /* @__PURE__ */ jsxRuntime.jsxs(
5652
+ "span",
5653
+ {
5654
+ className: "relative min-w-0 flex-1 bg-muted/55",
5655
+ style: { height: barHeight },
5656
+ children: [
5657
+ neverRan ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute inset-0 border border-dashed border-border" }) : segments.map((seg, i) => /* @__PURE__ */ jsxRuntime.jsx(
5658
+ "span",
5659
+ {
5660
+ title: seg.title ?? `${task.key} \xB7 ${seg.status} \xB7 ${formatDuration(seg.duration)}`,
5661
+ className: cn("absolute inset-y-0 rounded-[1px]", BAR[seg.status]),
5662
+ style: {
5663
+ left: pct(seg.start),
5664
+ width: pct(seg.duration),
5665
+ minWidth: 2
5666
+ }
5667
+ },
5668
+ i
5669
+ )),
5670
+ nowMs != null ? /* @__PURE__ */ jsxRuntime.jsx(
5671
+ "span",
5672
+ {
5673
+ className: "absolute -top-0.5 -bottom-0.5 w-px bg-info/70",
5674
+ style: { left: pct(nowMs) },
5675
+ "aria-hidden": true
5676
+ }
5677
+ ) : null
5678
+ ]
5679
+ }
5680
+ ),
5681
+ /* @__PURE__ */ jsxRuntime.jsx(
5682
+ "span",
5683
+ {
5684
+ className: "shrink-0 text-right font-mono text-meta text-muted-foreground tabular-nums",
5685
+ style: { width: durationWidth },
5686
+ children: duration
5687
+ }
5688
+ )
5689
+ ] }) });
5690
+ const trigger = pickable ? /* @__PURE__ */ jsxRuntime.jsx(
5691
+ "button",
5692
+ {
5693
+ type: "button",
5694
+ "aria-pressed": selected,
5695
+ onClick: () => onSelectTask(task.key),
5696
+ className: cn(
5697
+ "w-full cursor-pointer text-left focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50",
5698
+ "hover:bg-accent/60",
5699
+ selected && "bg-accent"
5700
+ ),
5701
+ children: row
5702
+ }
5703
+ ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn(detail != null && "hover:bg-accent/60"), children: row });
5704
+ if (detail == null) return /* @__PURE__ */ jsxRuntime.jsx("div", { children: trigger }, task.key);
5705
+ return /* @__PURE__ */ jsxRuntime.jsxs(
5706
+ HoverCard,
5707
+ {
5708
+ openDelay: detailProps?.openDelay ?? 200,
5709
+ closeDelay: detailProps?.closeDelay ?? 80,
5710
+ children: [
5711
+ /* @__PURE__ */ jsxRuntime.jsx(HoverCardTrigger, { asChild: true, children: trigger }),
5712
+ /* @__PURE__ */ jsxRuntime.jsx(
5713
+ HoverCardContent,
5714
+ {
5715
+ side: detailProps?.side ?? "right",
5716
+ align: detailProps?.align ?? "start",
5717
+ sideOffset: detailProps?.sideOffset ?? 8,
5718
+ style: detailProps?.width != null ? { width: detailProps.width } : void 0,
5719
+ className: cn("w-72 p-3", detailProps?.className),
5720
+ children: detail
5721
+ }
5722
+ )
5723
+ ]
5724
+ },
5725
+ task.key
5726
+ );
5727
+ })
5728
+ ] });
5729
+ }
5730
+ );
5731
+ TaskGantt.displayName = "TaskGantt";
5368
5732
  var TemplatePicker = React23__namespace.forwardRef(({ heading, options, value, onSelect, footnote, className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(
5369
5733
  "div",
5370
5734
  {
@@ -6215,6 +6579,7 @@ exports.ChatSessionTaskRow = ChatSessionTaskRow;
6215
6579
  exports.CitationList = CitationList;
6216
6580
  exports.CitationMarker = CitationMarker;
6217
6581
  exports.CitationRow = CitationRow;
6582
+ exports.ClampedText = ClampedText;
6218
6583
  exports.ClarifyCard = ClarifyCard;
6219
6584
  exports.Command = Command;
6220
6585
  exports.CommandDialog = CommandDialog;
@@ -6261,6 +6626,7 @@ exports.EmissionHeader = EmissionHeader;
6261
6626
  exports.EmptyState = EmptyState;
6262
6627
  exports.EmptyStateLock = EmptyStateLock;
6263
6628
  exports.ErrorBoundary = ErrorBoundary;
6629
+ exports.Eyebrow = Eyebrow;
6264
6630
  exports.FilterBar = FilterBar;
6265
6631
  exports.FilterChip = FilterChip;
6266
6632
  exports.HeatStrip = HeatStrip;
@@ -6393,6 +6759,8 @@ exports.Tabs = Tabs;
6393
6759
  exports.TabsContent = TabsContent;
6394
6760
  exports.TabsList = TabsList;
6395
6761
  exports.TabsTrigger = TabsTrigger;
6762
+ exports.TaskGantt = TaskGantt;
6763
+ exports.TaskGanttDetailCard = TaskGanttDetailCard;
6396
6764
  exports.TemplatePicker = TemplatePicker;
6397
6765
  exports.Terminal = Terminal;
6398
6766
  exports.TerminalLine = TerminalLine;