@actioneer/ads 0.5.1 → 0.5.3

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.
@@ -5,7 +5,7 @@ import { cva as u } from "class-variance-authority";
5
5
  import { Info as l, WarningCircle as g, Warning as p, CheckCircle as x, Close as v } from "../lib/icons.js";
6
6
  import { cn as n } from "../lib/cn.js";
7
7
  const h = u(
8
- "flex w-full items-start gap-4 rounded-2xl bg-muted px-4 py-3",
8
+ "flex w-full items-start gap-4 rounded-2xl bg-muted p-4",
9
9
  {
10
10
  variants: {
11
11
  variant: {
@@ -58,7 +58,7 @@ const h = u(
58
58
  }
59
59
  );
60
60
  N.displayName = "Alert";
61
- const y = i.forwardRef(({ className: t, ...r }, a) => /* @__PURE__ */ e(
61
+ const b = i.forwardRef(({ className: t, ...r }, a) => /* @__PURE__ */ e(
62
62
  "p",
63
63
  {
64
64
  ref: a,
@@ -66,8 +66,8 @@ const y = i.forwardRef(({ className: t, ...r }, a) => /* @__PURE__ */ e(
66
66
  ...r
67
67
  }
68
68
  ));
69
- y.displayName = "AlertTitle";
70
- const b = i.forwardRef(({ className: t, ...r }, a) => (
69
+ b.displayName = "AlertTitle";
70
+ const y = i.forwardRef(({ className: t, ...r }, a) => (
71
71
  // leading-normal (150%) — the description is the only part of an alert that
72
72
  // regularly wraps, and the text-xs default (138%) sets multi-line copy too
73
73
  // tight to scan.
@@ -80,9 +80,9 @@ const b = i.forwardRef(({ className: t, ...r }, a) => (
80
80
  }
81
81
  )
82
82
  ));
83
- b.displayName = "AlertDescription";
83
+ y.displayName = "AlertDescription";
84
84
  export {
85
85
  N as Alert,
86
- b as AlertDescription,
87
- y as AlertTitle
86
+ y as AlertDescription,
87
+ b as AlertTitle
88
88
  };
@@ -22,6 +22,8 @@ import "../file-dropzone.js";
22
22
  import "../scroll-area.js";
23
23
  import "../stepper.js";
24
24
  import "../resizable-panel.js";
25
+ import "react";
26
+ import { Bolt as a, ChevronDown as f, CheckList as h, Sparkles as g } from "../../lib/icons.js";
25
27
  import "../input.js";
26
28
  import "../input-field.js";
27
29
  import "../textarea.js";
@@ -34,9 +36,7 @@ import "../autocomplete.js";
34
36
  import "../slider.js";
35
37
  import "../segmented.js";
36
38
  import "../modal.js";
37
- import "react";
38
39
  import "react-dom";
39
- import { Bolt as a, ChevronDown as f, CheckList as h, Sparkles as g } from "../../lib/icons.js";
40
40
  import "../drawer.js";
41
41
  import "../popover.js";
42
42
  import "motion/react";
@@ -0,0 +1,30 @@
1
+ import * as React from "react";
2
+ /**
3
+ * AudioWaveform — the ADS recording player (ported from the voice product's
4
+ * call panel). One waveform with play/seek, hover scrubbing, and a download
5
+ * action; controls are ADS Buttons and the elapsed time lives ON the play
6
+ * control (0:00 at rest — no separate time strip).
7
+ *
8
+ * Speaker-split mode: for two-channel conversation audio (channel 0 = agent,
9
+ * channel 1 = the caller) the agent's energy draws ABOVE the centerline and
10
+ * the caller's BELOW it, so turn-taking reads at a glance — one waveform,
11
+ * never two stacked lanes. Enabled automatically when `channels > 1`;
12
+ * label the halves with `topLabel` / `bottomLabel` (default Agent / User).
13
+ *
14
+ * Colors ride the theme tokens (waveform = muted-foreground, progress =
15
+ * foreground) — never hardcoded.
16
+ */
17
+ export interface AudioWaveformProps {
18
+ /** Audio source URL (same-origin or CORS-served). */
19
+ src: string;
20
+ /** Known duration — lets the waveform render its scale before decode. */
21
+ durationSeconds?: number;
22
+ contentType?: string;
23
+ /** >1 enables speaker-split rendering (ch0 above, ch1 below). */
24
+ channels?: number;
25
+ topLabel?: string;
26
+ bottomLabel?: string;
27
+ downloadName?: string;
28
+ className?: string;
29
+ }
30
+ export declare function AudioWaveform({ src, durationSeconds, contentType, channels, topLabel, bottomLabel, downloadName, className, }: AudioWaveformProps): React.JSX.Element;
@@ -0,0 +1,147 @@
1
+ "use client";
2
+ import { jsxs as l, jsx as r } from "react/jsx-runtime";
3
+ import * as u from "react";
4
+ import { Button as ee, buttonVariants as re } from "./button.js";
5
+ import { Loader as te, Warning as ae, Pause as ne, Play as oe, Download as ie } from "../lib/icons.js";
6
+ import { cn as se } from "../lib/cn.js";
7
+ function A(t) {
8
+ if (!t || !Number.isFinite(t) || t < 0) return "0:00";
9
+ const e = Math.floor(t), a = Math.floor(e / 3600), c = Math.floor(e % 3600 / 60), d = e % 60;
10
+ return a > 0 ? `${a}:${String(c).padStart(2, "0")}:${String(d).padStart(2, "0")}` : `${c}:${String(d).padStart(2, "0")}`;
11
+ }
12
+ function B(t, e, a) {
13
+ return getComputedStyle(t).getPropertyValue(e).trim() || a;
14
+ }
15
+ function le(t, e, a) {
16
+ var m;
17
+ if (a) return a;
18
+ const c = e != null && e.includes("wav") ? "wav" : e != null && e.includes("mpeg") ? "mp3" : "audio", d = ((m = t.split("/").filter(Boolean).at(-1)) == null ? void 0 : m.split("?")[0]) || "recording";
19
+ return `${decodeURIComponent(d)}.${c}`;
20
+ }
21
+ function fe({
22
+ src: t,
23
+ durationSeconds: e,
24
+ contentType: a,
25
+ channels: c,
26
+ topLabel: d = "Agent",
27
+ bottomLabel: m = "User",
28
+ downloadName: U,
29
+ className: V
30
+ }) {
31
+ const F = u.useRef(null), p = u.useRef(null), [G, b] = u.useState(0), [L, D] = u.useState(e ?? 0), [k, C] = u.useState(!1), [E, x] = u.useState(!1), [f, R] = u.useState(null), v = (c ?? 0) > 1, q = le(t, a, U);
32
+ u.useEffect(() => {
33
+ const o = F.current;
34
+ if (!o) return;
35
+ let M = !1;
36
+ return b(0), D(e ?? 0), C(!1), x(!1), R(null), o.replaceChildren(), (async () => {
37
+ try {
38
+ const [{ default: w }, { default: K }] = await Promise.all([
39
+ import("wavesurfer.js"),
40
+ import("wavesurfer.js/dist/plugins/hover.esm.js")
41
+ ]);
42
+ if (M) return;
43
+ const N = B(o, "--foreground", "currentColor"), O = B(o, "--muted-foreground", "currentColor"), Q = B(o, "--background", "Canvas"), X = (s, P) => {
44
+ const Y = s[0] ?? [], Z = s[1] ?? s[0] ?? [], { width: _, height: T } = P.canvas, y = T / 2, S = 4, I = 2, $ = Math.max(1, Math.floor(_ / (S + I))), H = (n, g) => {
45
+ if (!n.length) return 0;
46
+ const h = Math.floor(g / $ * n.length), j = Math.max(h + 1, Math.floor((g + 1) / $ * n.length));
47
+ let W = 0;
48
+ for (let z = h; z < j; z++) W = Math.max(W, Math.abs(Number(n[z]) || 0));
49
+ return W;
50
+ };
51
+ for (let n = 0; n < $; n++) {
52
+ const g = n * (S + I), h = Math.max(1, H(Y, n) * (y - 2)), j = Math.max(1, H(Z, n) * (y - 2));
53
+ P.fillRect(g, y - h, S, h), P.fillRect(g, y + 1, S, j);
54
+ }
55
+ }, i = w.create({
56
+ container: o,
57
+ url: t,
58
+ duration: e,
59
+ height: 92,
60
+ normalize: !0,
61
+ waveColor: O,
62
+ progressColor: N,
63
+ cursorColor: N,
64
+ cursorWidth: 1,
65
+ barWidth: 2,
66
+ barGap: 1,
67
+ barRadius: 2,
68
+ barMinHeight: 1,
69
+ dragToSeek: !0,
70
+ hideScrollbar: !0,
71
+ renderFunction: v ? X : void 0,
72
+ plugins: [
73
+ K.create({
74
+ lineColor: N,
75
+ labelColor: Q,
76
+ labelBackground: N,
77
+ labelSize: 11,
78
+ formatTimeCallback: A
79
+ })
80
+ ]
81
+ });
82
+ p.current = i, i.on("ready", (s) => {
83
+ D(s), C(!0);
84
+ }), i.on("timeupdate", (s) => b(s)), i.on("seeking", (s) => b(s)), i.on("play", () => x(!0)), i.on("pause", () => x(!1)), i.on("finish", () => {
85
+ x(!1), b(i.getDuration());
86
+ }), i.on("error", () => {
87
+ R("Recording could not be loaded."), C(!1);
88
+ });
89
+ } catch {
90
+ M || R("Recording could not be loaded.");
91
+ }
92
+ })(), () => {
93
+ var w;
94
+ M = !0, (w = p.current) == null || w.destroy(), p.current = null;
95
+ };
96
+ }, [t, e, v]);
97
+ const J = () => {
98
+ var o;
99
+ !k || f || (o = p.current) == null || o.playPause();
100
+ };
101
+ return /* @__PURE__ */ l("div", { className: se("space-y-3", V), "data-slot": "audio-waveform", children: [
102
+ /* @__PURE__ */ l("div", { className: "flex items-center justify-between gap-3", children: [
103
+ /* @__PURE__ */ l("div", { className: "min-w-0", children: [
104
+ /* @__PURE__ */ r("p", { className: "text-base font-medium", children: "Recording" }),
105
+ /* @__PURE__ */ r("p", { className: "mt-0.5 truncate text-xs text-muted-foreground", children: v ? `${d} above · ${m.toLowerCase()} below` : a ?? "Audio" })
106
+ ] }),
107
+ /* @__PURE__ */ r("p", { className: "font-mono text-xs tabular-nums text-muted-foreground", children: A(L) })
108
+ ] }),
109
+ /* @__PURE__ */ l("div", { className: "relative overflow-hidden py-2", children: [
110
+ v && /* @__PURE__ */ l("div", { className: "pointer-events-none absolute inset-x-0 top-2 z-10 flex h-[92px] flex-col items-center justify-between text-[10px] font-medium uppercase tracking-wide text-muted-foreground", children: [
111
+ /* @__PURE__ */ r("span", { className: "rounded-sm bg-card/85 px-1.5 py-0.5", children: d }),
112
+ /* @__PURE__ */ r("span", { className: "rounded-sm bg-card/85 px-1.5 py-0.5", children: m })
113
+ ] }),
114
+ /* @__PURE__ */ r("div", { ref: F, className: "min-h-[92px]" }),
115
+ !k && !f && /* @__PURE__ */ r("div", { className: "absolute inset-0 flex items-center justify-center bg-background/70", children: /* @__PURE__ */ l("div", { className: "inline-flex items-center gap-2 rounded-md bg-background px-3 py-1.5 text-xs text-muted-foreground", children: [
116
+ /* @__PURE__ */ r(te, { className: "size-3.5 animate-spin motion-reduce:animate-none", "aria-hidden": "true" }),
117
+ "Loading waveform"
118
+ ] }) }),
119
+ f && /* @__PURE__ */ r("div", { className: "absolute inset-0 flex items-center justify-center bg-background/80", children: /* @__PURE__ */ l("div", { className: "inline-flex items-center gap-2 rounded-md bg-background px-3 py-1.5 text-xs text-muted-foreground", children: [
120
+ /* @__PURE__ */ r(ae, { className: "size-3.5", "aria-hidden": "true" }),
121
+ f
122
+ ] }) })
123
+ ] }),
124
+ /* @__PURE__ */ l("div", { className: "flex items-center justify-between gap-3", children: [
125
+ /* @__PURE__ */ r(
126
+ ee,
127
+ {
128
+ type: "button",
129
+ variant: "secondary",
130
+ onClick: J,
131
+ disabled: !k || !!f,
132
+ "aria-label": E ? "Pause recording" : "Play recording",
133
+ startContent: E ? /* @__PURE__ */ r(ne, { "aria-hidden": "true" }) : /* @__PURE__ */ r(oe, { "aria-hidden": "true" }),
134
+ className: "font-mono tabular-nums",
135
+ children: A(G)
136
+ }
137
+ ),
138
+ /* @__PURE__ */ l("a", { href: t, download: q, className: re({ variant: "ghost" }), children: [
139
+ /* @__PURE__ */ r(ie, { "aria-hidden": "true", className: "size-4" }),
140
+ "Audio"
141
+ ] })
142
+ ] })
143
+ ] });
144
+ }
145
+ export {
146
+ fe as AudioWaveform
147
+ };
@@ -1,50 +1,62 @@
1
1
  "use client";
2
- import { jsx as e, jsxs as p } from "react/jsx-runtime";
3
- import * as t from "react";
2
+ import { jsx as e, jsxs as b } from "react/jsx-runtime";
3
+ import * as r from "react";
4
4
  import { ChevronRight as g } from "../lib/icons.js";
5
- import { cn as a } from "../lib/cn.js";
6
- const u = t.createContext({
5
+ import { cn as n } from "../lib/cn.js";
6
+ const l = r.createContext({
7
7
  count: 0
8
- }), l = t.createContext(0), b = t.forwardRef(
9
- ({ className: i, children: n, ...c }, r) => {
10
- const o = t.Children.toArray(n);
11
- return /* @__PURE__ */ e("nav", { ref: r, "aria-label": "Breadcrumb", className: i, ...c, children: /* @__PURE__ */ e("ol", { className: "flex items-center gap-1.5 text-xs", children: /* @__PURE__ */ e(u.Provider, { value: { count: o.length }, children: o.map((m, s) => /* @__PURE__ */ e(l.Provider, { value: s, children: m }, s)) }) }) });
8
+ }), u = r.createContext(0), p = r.forwardRef(
9
+ ({ className: i, children: o, ...c }, t) => {
10
+ const s = r.Children.toArray(o);
11
+ return /* @__PURE__ */ e(
12
+ "nav",
13
+ {
14
+ ref: t,
15
+ "aria-label": "Breadcrumb",
16
+ className: n(
17
+ "flex min-h-12 w-full items-center border-b border-border",
18
+ i
19
+ ),
20
+ ...c,
21
+ children: /* @__PURE__ */ e("ol", { className: "flex min-w-0 items-center gap-1.5 text-xs", children: /* @__PURE__ */ e(l.Provider, { value: { count: s.length }, children: s.map((m, a) => /* @__PURE__ */ e(u.Provider, { value: a, children: m }, a)) }) })
22
+ }
23
+ );
12
24
  }
13
25
  );
14
- b.displayName = "Breadcrumbs";
15
- const h = t.forwardRef(({ className: i, href: n, isCurrent: c, children: r, ...o }, m) => {
16
- const { count: s } = t.useContext(u), x = t.useContext(l) === s - 1, d = "inline-flex items-center", f = c ? /* @__PURE__ */ e(
26
+ p.displayName = "Breadcrumbs";
27
+ const h = r.forwardRef(({ className: i, href: o, isCurrent: c, children: t, ...s }, m) => {
28
+ const { count: a } = r.useContext(l), x = r.useContext(u) === a - 1, d = "inline-flex items-center", f = c ? /* @__PURE__ */ e(
17
29
  "span",
18
30
  {
19
31
  "aria-current": "page",
20
- className: a(d, "text-muted-foreground"),
21
- children: r
32
+ className: n(d, "font-medium text-foreground"),
33
+ children: t
22
34
  }
23
- ) : n ? /* @__PURE__ */ e(
35
+ ) : o ? /* @__PURE__ */ e(
24
36
  "a",
25
37
  {
26
- href: n,
27
- className: a(
38
+ href: o,
39
+ className: n(
28
40
  d,
29
- "font-medium text-foreground transition-colors hover:underline",
41
+ "font-medium text-muted-foreground transition-colors hover:text-foreground hover:underline",
30
42
  "outline-none focus-visible:ring-3 focus-visible:ring-ring rounded-sm"
31
43
  ),
32
- children: r
44
+ children: t
33
45
  }
34
- ) : /* @__PURE__ */ e("span", { className: a(d, "text-muted-foreground"), children: r });
35
- return /* @__PURE__ */ p(
46
+ ) : /* @__PURE__ */ e("span", { className: n(d, "text-muted-foreground"), children: t });
47
+ return /* @__PURE__ */ b(
36
48
  "li",
37
49
  {
38
50
  ref: m,
39
- className: a("flex items-center gap-1.5", i),
40
- ...o,
51
+ className: n("flex items-center gap-1.5", i),
52
+ ...s,
41
53
  children: [
42
54
  f,
43
55
  !x && /* @__PURE__ */ e(
44
56
  g,
45
57
  {
46
58
  "aria-hidden": !0,
47
- className: "size-3.5 shrink-0 text-muted-foreground"
59
+ className: "size-3.5 shrink-0 text-border-strong"
48
60
  }
49
61
  )
50
62
  ]
@@ -54,5 +66,5 @@ const h = t.forwardRef(({ className: i, href: n, isCurrent: c, children: r, ...o
54
66
  h.displayName = "BreadcrumbItem";
55
67
  export {
56
68
  h as BreadcrumbItem,
57
- b as Breadcrumbs
69
+ p as Breadcrumbs
58
70
  };
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { jsxs as r, jsx as b } from "react/jsx-runtime";
2
+ import { jsxs as r, jsx as u } from "react/jsx-runtime";
3
3
  import * as c from "react";
4
4
  import { cva as v } from "class-variance-authority";
5
5
  import { cn as t } from "../lib/cn.js";
@@ -22,7 +22,7 @@ const p = v(
22
22
  variant: {
23
23
  solid: "bg-brand text-brand-foreground shadow-[var(--inner-glow-cta)] hover:bg-brand-hover",
24
24
  secondary: "bg-fill text-fill-foreground shadow-[var(--inner-glow-fill)] hover:bg-fill/70",
25
- outline: "border-border-strong bg-transparent text-foreground hover:bg-muted",
25
+ outline: "border-border bg-transparent text-foreground hover:border-border-strong hover:bg-muted",
26
26
  ghost: "bg-transparent text-foreground hover:bg-muted",
27
27
  soft: "bg-muted text-foreground shadow-[var(--inner-glow-fill)] hover:bg-fill",
28
28
  link: "bg-transparent text-foreground underline-offset-4 hover:underline active:scale-none",
@@ -43,31 +43,31 @@ const p = v(
43
43
  ), x = c.forwardRef(
44
44
  ({
45
45
  className: n,
46
- variant: s,
47
- size: o,
46
+ variant: o,
47
+ size: s,
48
48
  isLoading: e = !1,
49
49
  startContent: i,
50
50
  endContent: a,
51
51
  fullWidth: d,
52
52
  disabled: l,
53
53
  children: g,
54
- ...f
55
- }, u) => /* @__PURE__ */ r(
54
+ ...b
55
+ }, f) => /* @__PURE__ */ r(
56
56
  "button",
57
57
  {
58
- ref: u,
58
+ ref: f,
59
59
  disabled: l || e,
60
60
  "aria-busy": e || void 0,
61
61
  className: t(
62
- p({ variant: s, size: o }),
62
+ p({ variant: o, size: s }),
63
63
  d && "w-full",
64
64
  // Real disabled fades; loading keeps the brand color
65
65
  e ? "opacity-100" : "disabled:opacity-50",
66
66
  n
67
67
  ),
68
- ...f,
68
+ ...b,
69
69
  children: [
70
- e && /* @__PURE__ */ b(
70
+ e && /* @__PURE__ */ u(
71
71
  m,
72
72
  {
73
73
  size: "sm",
@@ -203,9 +203,11 @@ export interface FunnelChartProps {
203
203
  valueKey: string;
204
204
  height?: number;
205
205
  formatValue?: (value: number) => string;
206
- /** Custom data-bearing stage label, or false to hide labels. */
206
+ /** Custom per-stage metric label (default: % of the first stage, above the
207
+ * bar), or false to hide it. Stage name + value under each column are
208
+ * structural and always render. */
207
209
  label?: FunnelLabelRenderer | false;
208
- /** Space reserved on the right for the label channel. */
210
+ /** @deprecated The stepped funnel has no right-hand label channel; ignored. */
209
211
  labelWidth?: number;
210
212
  tooltip?: ChartTooltipRenderer | false;
211
213
  className?: string;