@actioneer/ads 1.0.8 → 1.0.10

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.
Files changed (64) hide show
  1. package/DESIGN.md +125 -50
  2. package/README.md +31 -7
  3. package/components/answer.js +1 -1
  4. package/components/assistant-ui/composer-harness.js +14 -10
  5. package/components/body-page-header.d.ts +9 -4
  6. package/components/body-page-header.js +10 -10
  7. package/components/breadcrumbs.js +15 -15
  8. package/components/button.d.ts +16 -1
  9. package/components/button.js +7 -4
  10. package/components/card.js +18 -18
  11. package/components/chart.d.ts +40 -4
  12. package/components/chart.js +824 -628
  13. package/components/chip.d.ts +2 -1
  14. package/components/chip.js +49 -46
  15. package/components/collection-header.js +4 -4
  16. package/components/connector-card.js +30 -30
  17. package/components/date-range-picker.js +1 -1
  18. package/components/detail-list.d.ts +28 -0
  19. package/components/detail-list.js +52 -0
  20. package/components/drawer.d.ts +38 -15
  21. package/components/drawer.js +150 -86
  22. package/components/empty-state.d.ts +3 -2
  23. package/components/empty-state.js +22 -22
  24. package/components/field.d.ts +16 -0
  25. package/components/field.js +63 -42
  26. package/components/file-dropzone.d.ts +15 -4
  27. package/components/file-dropzone.js +100 -64
  28. package/components/filter-bar.d.ts +44 -0
  29. package/components/filter-bar.js +89 -0
  30. package/components/filters.d.ts +37 -0
  31. package/components/filters.js +129 -0
  32. package/components/index.d.ts +4 -0
  33. package/components/index.js +526 -510
  34. package/components/input-field.d.ts +1 -1
  35. package/components/input-field.js +24 -22
  36. package/components/modal.d.ts +2 -1
  37. package/components/modal.js +120 -106
  38. package/components/panel.js +26 -27
  39. package/components/popover.d.ts +6 -1
  40. package/components/popover.js +74 -64
  41. package/components/sidebar.d.ts +15 -0
  42. package/components/sidebar.js +166 -129
  43. package/components/sparkline.d.ts +30 -0
  44. package/components/sparkline.js +69 -0
  45. package/components/table.d.ts +8 -0
  46. package/components/table.js +357 -350
  47. package/components/tabs.d.ts +6 -1
  48. package/components/tabs.js +28 -31
  49. package/demo/components/add-to-artifact.js +6 -2
  50. package/examples/README.md +5 -2
  51. package/examples/call-logs-screen.tsx +381 -0
  52. package/examples/campaign-analysis-screen.tsx +180 -0
  53. package/examples/campaigns-screen.tsx +497 -0
  54. package/examples/guardrails-settings-screen.tsx +123 -0
  55. package/fonts/geist-variable.woff2 +0 -0
  56. package/fonts.css +12 -17
  57. package/lib/icons.js +3 -3
  58. package/llms.txt +162 -30
  59. package/manifest.json +11604 -7878
  60. package/package.json +1 -1
  61. package/styles.css +102 -59
  62. package/theme.css +81 -37
  63. package/fonts/aribau-grotesk-medium.woff2 +0 -0
  64. package/fonts/aribau-grotesk-regular.woff2 +0 -0
@@ -1,9 +1,11 @@
1
1
  "use client";
2
- import { jsxs as v, jsx as l } from "react/jsx-runtime";
3
- import * as a from "react";
4
- import { cn as i } from "../lib/cn.js";
5
- import { interactive as R } from "../lib/interactive.js";
6
- const L = i(
2
+ import { jsxs as d, jsx as t } from "react/jsx-runtime";
3
+ import * as n from "react";
4
+ import { cn as l } from "../lib/cn.js";
5
+ import { interactive as D } from "../lib/interactive.js";
6
+ import { Info as I } from "../lib/icons.js";
7
+ import { Tooltip as B } from "./tooltip.js";
8
+ const P = l(
7
9
  // Border WIDTH only — no border-color utility. ads-interactive owns the
8
10
  // color (rest = --glow-border-rest below); a `border-input` utility here
9
11
  // would out-cascade the shared hover/focus rules.
@@ -19,71 +21,90 @@ const L = i(
19
21
  // hover stays neutral while focus uses the subtle teal edge. The inner
20
22
  // glow is a whisper of inset depth so the writing surface reads recessed —
21
23
  // carried through every interactive state by the --glow-inset hook.
22
- R({ on: "all", color: "brand", intensity: "medium", animate: !0 }),
24
+ D({ on: "all", color: "brand", intensity: "medium", animate: !0 }),
23
25
  "[--glow-border-rest:var(--input)]",
24
26
  "[--glow-border-hover:var(--input)]",
25
27
  "[--glow-border-active:var(--field-focus)]"
26
- ), w = a.forwardRef(({ className: r, children: e, required: o, ...t }, n) => /* @__PURE__ */ v(
28
+ ), u = n.forwardRef(({ className: o, children: e, required: r, ...i }, a) => /* @__PURE__ */ d(
27
29
  "label",
28
30
  {
29
- ref: n,
30
- className: i(
31
+ ref: a,
32
+ className: l(
31
33
  "flex items-center gap-1 text-m font-medium text-secondary select-none",
32
34
  "peer-disabled:cursor-not-allowed peer-disabled:opacity-60",
33
- r
35
+ o
34
36
  ),
35
- ...t,
37
+ ...i,
36
38
  children: [
37
39
  e,
38
- o && /* @__PURE__ */ l("span", { className: "text-danger", children: "*" })
40
+ r && /* @__PURE__ */ t("span", { className: "text-danger", children: "*" })
39
41
  ]
40
42
  }
41
43
  ));
42
- w.displayName = "Label";
43
- const y = a.forwardRef(({ className: r, ...e }, o) => /* @__PURE__ */ l(
44
+ u.displayName = "Label";
45
+ const N = n.forwardRef(({ className: o, ...e }, r) => /* @__PURE__ */ t(
44
46
  "p",
45
47
  {
46
- ref: o,
47
- className: i("text-m font-normal text-muted-foreground", r),
48
+ ref: r,
49
+ className: l("text-m font-normal text-muted-foreground", o),
48
50
  ...e
49
51
  }
50
52
  ));
51
- y.displayName = "FieldDescription";
52
- const h = a.forwardRef(
53
- ({ className: r, children: e, ...o }, t) => e ? /* @__PURE__ */ l(
53
+ N.displayName = "FieldDescription";
54
+ const F = n.forwardRef(
55
+ ({ className: o, children: e, ...r }, i) => e ? /* @__PURE__ */ t(
54
56
  "p",
55
57
  {
56
- ref: t,
57
- className: i("text-m font-normal text-danger", r),
58
- ...o,
58
+ ref: i,
59
+ className: l("text-m font-normal text-danger", o),
60
+ ...r,
59
61
  children: e
60
62
  }
61
63
  ) : null
62
64
  );
63
- h.displayName = "FieldError";
64
- const D = a.forwardRef(
65
- ({ className: r, label: e, description: o, error: t, required: n, htmlFor: g, errorId: s, descriptionId: c, children: d, ...N }, F) => {
66
- const m = a.useId(), p = s ?? `${m}-error`, f = c ?? `${m}-description`, u = t ? p : o ? f : void 0, E = s == null && c == null;
67
- let x = d;
68
- if (E && u && a.isValidElement(d)) {
69
- const b = d.props;
70
- x = a.cloneElement(d, {
71
- "aria-describedby": [b["aria-describedby"], u].filter(Boolean).join(" ") || void 0,
72
- "aria-invalid": b["aria-invalid"] ?? (t ? !0 : void 0)
65
+ F.displayName = "FieldError";
66
+ function $({ children: o, label: e = "More information" }) {
67
+ return /* @__PURE__ */ t(B, { content: o, children: /* @__PURE__ */ t(
68
+ "button",
69
+ {
70
+ type: "button",
71
+ "aria-label": e,
72
+ "data-slot": "field-info",
73
+ className: "inline-flex size-5 shrink-0 cursor-help items-center justify-center rounded-xs text-on-white-tertiary outline-none transition-colors duration-150 ease-out hover:text-action-primary focus-visible:text-action-primary focus-visible:ring-2 focus-visible:ring-ring motion-reduce:transition-none [&_svg]:size-4",
74
+ children: /* @__PURE__ */ t(I, { "aria-hidden": !0 })
75
+ }
76
+ ) });
77
+ }
78
+ const k = n.forwardRef(
79
+ ({ className: o, label: e, description: r, error: i, required: a, htmlFor: f, errorId: p, descriptionId: x, info: c, actions: m, children: s, ...j }, E) => {
80
+ const h = n.useId(), b = p ?? `${h}-error`, v = x ?? `${h}-description`, y = i ? b : r ? v : void 0, R = p == null && x == null;
81
+ let w = s;
82
+ if (R && y && n.isValidElement(s)) {
83
+ const g = s.props;
84
+ w = n.cloneElement(s, {
85
+ "aria-describedby": [g["aria-describedby"], y].filter(Boolean).join(" ") || void 0,
86
+ "aria-invalid": g["aria-invalid"] ?? (i ? !0 : void 0)
73
87
  });
74
88
  }
75
- return /* @__PURE__ */ v("div", { ref: F, className: i("flex flex-col gap-1.5", r), ...N, children: [
76
- e && /* @__PURE__ */ l(w, { htmlFor: g, required: n, children: e }),
77
- x,
78
- t ? /* @__PURE__ */ l(h, { id: p, children: t }) : o ? /* @__PURE__ */ l(y, { id: f, children: o }) : null
89
+ return /* @__PURE__ */ d("div", { ref: E, className: l("flex flex-col gap-1.5", o), ...j, children: [
90
+ e && (c || m) ? /* @__PURE__ */ d("div", { "data-slot": "field-label-row", className: "flex min-h-5 items-center justify-between gap-3", children: [
91
+ /* @__PURE__ */ d("span", { className: "flex min-w-0 items-center gap-1", children: [
92
+ /* @__PURE__ */ t(u, { htmlFor: f, required: a, children: e }),
93
+ c ? /* @__PURE__ */ t($, { label: typeof e == "string" ? `About ${e}` : void 0, children: c }) : null
94
+ ] }),
95
+ m ? /* @__PURE__ */ t("span", { className: "flex shrink-0 items-center gap-2", children: m }) : null
96
+ ] }) : e ? /* @__PURE__ */ t(u, { htmlFor: f, required: a, children: e }) : null,
97
+ w,
98
+ i ? /* @__PURE__ */ t(F, { id: b, children: i }) : r ? /* @__PURE__ */ t(N, { id: v, children: r }) : null
79
99
  ] });
80
100
  }
81
101
  );
82
- D.displayName = "Field";
102
+ k.displayName = "Field";
83
103
  export {
84
- D as Field,
85
- y as FieldDescription,
86
- h as FieldError,
87
- w as Label,
88
- L as inputBaseClass
104
+ k as Field,
105
+ N as FieldDescription,
106
+ F as FieldError,
107
+ $ as FieldInfo,
108
+ u as Label,
109
+ P as inputBaseClass
89
110
  };
@@ -6,13 +6,20 @@ import * as React from "react";
6
6
  *
7
7
  * A dashed edge is the one sanctioned stroke here: it is the affordance
8
8
  * ("something goes in this hole"), not decoration. The empty zone is a White
9
- * surface with a dashed WG5 edge and an outlined icon tile; hover warms it to
10
- * WG1, and a drag-over turns it pale teal with a teal edge, so nothing jumps.
11
- * Once files are chosen it becomes a solid-edged row: file tile, name and
12
- * size, with Replace and Clear on the right.
9
+ * surface with a dashed WG5 edge and a bare icon (icons never sit on a tile or
10
+ * fill — principle `create-modals`); hover warms it to WG1, and a drag-over
11
+ * turns it pale teal with a teal edge, so nothing jumps. Once files are chosen
12
+ * it becomes a solid-edged row: file icon, name and size, with Replace and
13
+ * Clear on the right.
14
+ *
15
+ * `layout="stacked"` (default) is the tall centred target for a page that is
16
+ * about the upload. `layout="inline"` is the 64px strip used inside forms and
17
+ * modals: icon · label + hint · Browse button, so the upload does not push the
18
+ * rest of a fixed-height form out of view.
13
19
  */
14
20
  declare const fileDropzoneVariants: (props?: ({
15
21
  hasFiles?: boolean | null | undefined;
22
+ layout?: "inline" | "stacked" | null | undefined;
16
23
  isDragging?: boolean | null | undefined;
17
24
  isDisabled?: boolean | null | undefined;
18
25
  } & import('class-variance-authority/types').ClassProp) | undefined) => string;
@@ -30,6 +37,10 @@ export interface FileDropzoneProps extends Omit<React.HTMLAttributes<HTMLDivElem
30
37
  label?: React.ReactNode;
31
38
  /** Sub-line, e.g. "CSV up to 10 MB". */
32
39
  hint?: React.ReactNode;
40
+ /** `stacked` tall centred target (default) · `inline` 64px strip for forms and modals. */
41
+ layout?: "stacked" | "inline";
42
+ /** Label of the inline layout's Browse button. */
43
+ browseLabel?: string;
33
44
  }
34
45
  export declare const FileDropzone: React.ForwardRefExoticComponent<FileDropzoneProps & React.RefAttributes<HTMLDivElement>>;
35
46
  export { fileDropzoneVariants };
@@ -1,12 +1,12 @@
1
1
  "use client";
2
- import { jsxs as t, jsx as r, Fragment as m } from "react/jsx-runtime";
3
- import * as s from "react";
4
- import { cva as R } from "class-variance-authority";
5
- import { cn as p } from "../lib/cn.js";
6
- import { Button as v } from "./button.js";
7
- import { FileText as j, Upload as B } from "../lib/icons.js";
8
- const C = R(
9
- p(
2
+ import { jsxs as a, jsx as r, Fragment as m } from "react/jsx-runtime";
3
+ import * as p from "react";
4
+ import { cva as j } from "class-variance-authority";
5
+ import { cn as g } from "../lib/cn.js";
6
+ import { Button as D } from "./button.js";
7
+ import { FileText as T, Upload as z } from "../lib/icons.js";
8
+ const U = j(
9
+ g(
10
10
  "flex w-full cursor-pointer rounded-lg border bg-card outline-none",
11
11
  "transition-[background-color,border-color,transform] duration-150 ease-out",
12
12
  "focus-visible:ring-3 focus-visible:ring-ring motion-reduce:transition-none"
@@ -15,7 +15,11 @@ const C = R(
15
15
  variants: {
16
16
  hasFiles: {
17
17
  true: "flex-row items-center justify-between gap-4 border-solid border-border p-3 text-left",
18
- false: "flex-col items-center justify-center gap-3 border-dashed border-border-strong px-6 py-7 text-center hover:bg-wg1 active:scale-[0.99] motion-reduce:active:scale-100"
18
+ false: "border-dashed border-border-strong hover:bg-wg1 active:scale-[0.99] motion-reduce:active:scale-100"
19
+ },
20
+ layout: {
21
+ stacked: "",
22
+ inline: ""
19
23
  },
20
24
  isDragging: {
21
25
  true: "border-dashed border-field-focus bg-t1 hover:bg-t1",
@@ -26,112 +30,144 @@ const C = R(
26
30
  false: ""
27
31
  }
28
32
  },
29
- defaultVariants: { hasFiles: !1, isDragging: !1, isDisabled: !1 }
33
+ compoundVariants: [
34
+ { hasFiles: !1, layout: "stacked", className: "flex-col items-center justify-center gap-3 px-6 py-7 text-center" },
35
+ { hasFiles: !1, layout: "inline", className: "min-h-16 flex-row items-center gap-3 p-3 text-left" }
36
+ ],
37
+ defaultVariants: { hasFiles: !1, isDragging: !1, isDisabled: !1, layout: "stacked" }
30
38
  }
31
- ), N = "inline-flex size-9 shrink-0 items-center justify-center rounded-md border border-border bg-card text-muted-foreground [&>svg]:size-4.5", F = (a) => a < 1024 ? `${a} B` : a < 1024 * 1024 ? `${Math.round(a / 1024)} KB` : `${(a / (1024 * 1024)).toFixed(1)} MB`, T = s.forwardRef(
39
+ ), N = "inline-flex shrink-0 items-center justify-center text-muted-foreground transition-colors duration-150 ease-out motion-reduce:transition-none [&>svg]:size-5", P = (t) => t < 1024 ? `${t} B` : t < 1024 * 1024 ? `${Math.round(t / 1024)} KB` : `${(t / (1024 * 1024)).toFixed(1)} MB`, V = p.forwardRef(
32
40
  ({
33
- className: a,
34
- accept: y,
35
- multiple: c = !1,
41
+ className: t,
42
+ accept: B,
43
+ multiple: s = !1,
36
44
  disabled: n = !1,
37
- onFiles: l,
38
- files: i,
39
- onClear: g,
40
- label: w,
41
- hint: h,
42
- ...z
43
- }, k) => {
44
- const x = s.useRef(null), [d, f] = s.useState(!1), o = s.useRef(0), b = (e) => {
45
- e != null && e.length && (l == null || l(c ? Array.from(e) : [e[0]]));
46
- }, u = () => {
45
+ onFiles: h,
46
+ files: o,
47
+ onClear: y,
48
+ label: l,
49
+ hint: c,
50
+ layout: x = "stacked",
51
+ browseLabel: C = "Browse",
52
+ ...F
53
+ }, R) => {
54
+ const b = p.useRef(null), [d, v] = p.useState(!1), i = p.useRef(0), k = (e) => {
55
+ e != null && e.length && (h == null || h(s ? Array.from(e) : [e[0]]));
56
+ }, f = () => {
47
57
  var e;
48
- return (e = x.current) == null ? void 0 : e.click();
49
- }, D = !!(i != null && i.length);
50
- return /* @__PURE__ */ t(
58
+ return (e = b.current) == null ? void 0 : e.click();
59
+ }, w = !!(o != null && o.length), u = x !== "inline";
60
+ return /* @__PURE__ */ a(
51
61
  "div",
52
62
  {
53
- ref: k,
63
+ ref: R,
54
64
  "data-slot": "file-dropzone",
55
65
  "data-dragging": d || void 0,
56
- role: "button",
57
- tabIndex: n ? -1 : 0,
66
+ role: u ? "button" : "group",
67
+ "aria-label": u ? void 0 : typeof l == "string" ? l : "Upload",
68
+ tabIndex: u ? n ? -1 : 0 : void 0,
58
69
  "aria-disabled": n || void 0,
59
- onClick: u,
70
+ onClick: f,
60
71
  onKeyDown: (e) => {
61
- (e.key === "Enter" || e.key === " ") && (e.preventDefault(), u());
72
+ u && (e.key === "Enter" || e.key === " ") && (e.preventDefault(), f());
62
73
  },
63
74
  onDragEnter: (e) => {
64
- e.preventDefault(), o.current += 1, f(!0);
75
+ e.preventDefault(), i.current += 1, v(!0);
65
76
  },
66
77
  onDragOver: (e) => e.preventDefault(),
67
78
  onDragLeave: () => {
68
- o.current -= 1, o.current <= 0 && (o.current = 0, f(!1));
79
+ i.current -= 1, i.current <= 0 && (i.current = 0, v(!1));
69
80
  },
70
81
  onDrop: (e) => {
71
- e.preventDefault(), o.current = 0, f(!1), n || b(e.dataTransfer.files);
82
+ e.preventDefault(), i.current = 0, v(!1), n || k(e.dataTransfer.files);
72
83
  },
73
- className: p(
74
- C({ hasFiles: D, isDragging: d, isDisabled: n }),
75
- a
84
+ className: g(
85
+ U({ hasFiles: w, isDragging: d, isDisabled: n, layout: x }),
86
+ t
76
87
  ),
77
- ...z,
88
+ ...F,
78
89
  children: [
79
90
  /* @__PURE__ */ r(
80
91
  "input",
81
92
  {
82
- ref: x,
93
+ ref: b,
83
94
  hidden: !0,
84
95
  type: "file",
85
- accept: y,
86
- multiple: c,
96
+ accept: B,
97
+ multiple: s,
87
98
  disabled: n,
88
99
  onChange: (e) => {
89
- b(e.currentTarget.files), e.currentTarget.value = "";
100
+ k(e.currentTarget.files), e.currentTarget.value = "";
90
101
  }
91
102
  }
92
103
  ),
93
- D ? /* @__PURE__ */ t(m, { children: [
94
- /* @__PURE__ */ r("div", { className: "flex min-w-0 flex-1 flex-col gap-2.5", children: i.map((e) => /* @__PURE__ */ t("span", { className: "flex min-w-0 items-center gap-3", children: [
95
- /* @__PURE__ */ r("span", { "aria-hidden": !0, className: N, children: /* @__PURE__ */ r(j, {}) }),
96
- /* @__PURE__ */ t("span", { className: "flex min-w-0 flex-col", children: [
104
+ w ? /* @__PURE__ */ a(m, { children: [
105
+ /* @__PURE__ */ r("div", { className: "flex min-w-0 flex-1 flex-col gap-2.5", children: o.map((e) => /* @__PURE__ */ a("span", { className: "flex min-w-0 items-center gap-3", children: [
106
+ /* @__PURE__ */ r("span", { "aria-hidden": !0, className: N, children: /* @__PURE__ */ r(T, {}) }),
107
+ /* @__PURE__ */ a("span", { className: "flex min-w-0 flex-col", children: [
97
108
  /* @__PURE__ */ r("span", { className: "truncate text-m font-medium text-foreground", children: e.name }),
98
- /* @__PURE__ */ r("span", { className: "text-s text-tertiary tabular-nums", children: F(e.size) })
109
+ /* @__PURE__ */ r("span", { className: "text-s text-tertiary tabular-nums", children: P(e.size) })
99
110
  ] })
100
111
  ] }, e.name)) }),
101
- /* @__PURE__ */ t("div", { className: "flex shrink-0 items-center gap-1", children: [
102
- /* @__PURE__ */ r(v, { size: "sm", variant: "outline", onClick: (e) => {
103
- e.stopPropagation(), u();
112
+ /* @__PURE__ */ a("div", { className: "flex shrink-0 items-center gap-1", children: [
113
+ /* @__PURE__ */ r(D, { size: "sm", variant: "outline", onClick: (e) => {
114
+ e.stopPropagation(), f();
104
115
  }, children: "Replace" }),
105
- g && /* @__PURE__ */ r(
106
- v,
116
+ y && /* @__PURE__ */ r(
117
+ D,
107
118
  {
108
119
  size: "sm",
109
120
  variant: "ghost",
110
121
  onClick: (e) => {
111
- e.stopPropagation(), g();
122
+ e.stopPropagation(), y();
112
123
  },
113
124
  children: "Clear"
114
125
  }
115
126
  )
116
127
  ] })
117
- ] }) : /* @__PURE__ */ t(m, { children: [
128
+ ] }) : x === "inline" ? /* @__PURE__ */ a(m, { children: [
129
+ /* @__PURE__ */ r(
130
+ "span",
131
+ {
132
+ "aria-hidden": !0,
133
+ className: g(N, d && "text-action-primary"),
134
+ children: /* @__PURE__ */ r(z, {})
135
+ }
136
+ ),
137
+ /* @__PURE__ */ a("span", { className: "flex min-w-0 flex-1 flex-col gap-0.5", children: [
138
+ /* @__PURE__ */ r("span", { className: "truncate text-m font-medium text-foreground", children: l ?? (s ? "Upload files" : "Upload a file") }),
139
+ c && /* @__PURE__ */ r("span", { className: "truncate text-s text-secondary", children: c })
140
+ ] }),
141
+ /* @__PURE__ */ r(
142
+ D,
143
+ {
144
+ variant: "outline",
145
+ className: "shrink-0",
146
+ disabled: n,
147
+ onClick: (e) => {
148
+ e.stopPropagation(), f();
149
+ },
150
+ children: C
151
+ }
152
+ )
153
+ ] }) : /* @__PURE__ */ a(m, { children: [
118
154
  /* @__PURE__ */ r(
119
155
  "span",
120
156
  {
121
157
  "aria-hidden": !0,
122
- className: p(N, d && "text-action-primary"),
123
- children: /* @__PURE__ */ r(B, {})
158
+ className: g(N, d && "text-action-primary"),
159
+ children: /* @__PURE__ */ r(z, {})
124
160
  }
125
161
  ),
126
- /* @__PURE__ */ t("span", { className: "flex flex-col items-center gap-0.5", children: [
127
- /* @__PURE__ */ r("span", { className: "text-m font-medium text-foreground", children: w ?? /* @__PURE__ */ t(m, { children: [
162
+ /* @__PURE__ */ a("span", { className: "flex flex-col items-center gap-0.5", children: [
163
+ /* @__PURE__ */ r("span", { className: "text-m font-medium text-foreground", children: l ?? /* @__PURE__ */ a(m, { children: [
128
164
  "Drop ",
129
- c ? "files" : "a file",
165
+ s ? "files" : "a file",
130
166
  " here, or",
131
167
  " ",
132
168
  /* @__PURE__ */ r("span", { className: "text-action-primary-text", children: "browse" })
133
169
  ] }) }),
134
- h && /* @__PURE__ */ r("span", { className: "text-s text-tertiary", children: h })
170
+ c && /* @__PURE__ */ r("span", { className: "text-s text-tertiary", children: c })
135
171
  ] })
136
172
  ] })
137
173
  ]
@@ -139,8 +175,8 @@ const C = R(
139
175
  );
140
176
  }
141
177
  );
142
- T.displayName = "FileDropzone";
178
+ V.displayName = "FileDropzone";
143
179
  export {
144
- T as FileDropzone,
145
- C as fileDropzoneVariants
180
+ V as FileDropzone,
181
+ U as fileDropzoneVariants
146
182
  };
@@ -0,0 +1,44 @@
1
+ import * as React from "react";
2
+ /**
3
+ * FilterBar — the scope a page is showing, spelled out as joined segments
4
+ * (user-mandated 2026-11-14, the Span filter look).
5
+ *
6
+ * One 32px control with a WG4 `border-input` edge and 6px corners; its
7
+ * segments sit side by side, split by hairlines. Each segment shows its
8
+ * CURRENT value, so the reader sees what the numbers below cover without
9
+ * opening anything:
10
+ *
11
+ * [ This campaign ▾ | 🗓 Oct 19 – Oct 23 ] [ All cohorts ▾ ]
12
+ *
13
+ * - `FilterBarSelect` — a value with a caret that opens a menu of options.
14
+ * - `FilterBarValue` — a read-only value (an optional bare icon + text),
15
+ * such as the dates a preset resolves to; pass `onClick` to make it open
16
+ * something.
17
+ *
18
+ * Use it for the scope row of an analytics/record page. It is not a form
19
+ * field (no label) and not a toggle group (use `SegmentedControl` to switch
20
+ * views).
21
+ */
22
+ export interface FilterBarProps extends React.HTMLAttributes<HTMLDivElement> {
23
+ /** Names the group for assistive tech, e.g. "Report scope". */
24
+ "aria-label": string;
25
+ }
26
+ export declare const FilterBar: React.ForwardRefExoticComponent<FilterBarProps & React.RefAttributes<HTMLDivElement>>;
27
+ export interface FilterBarOption {
28
+ value: string;
29
+ label: string;
30
+ }
31
+ export interface FilterBarSelectProps {
32
+ /** What the segment filters, for assistive tech ("Campaign scope"). */
33
+ label: string;
34
+ value: string;
35
+ options: FilterBarOption[];
36
+ onValueChange: (value: string) => void;
37
+ className?: string;
38
+ }
39
+ export declare function FilterBarSelect({ label, value, options, onValueChange, className }: FilterBarSelectProps): React.JSX.Element;
40
+ export interface FilterBarValueProps extends React.HTMLAttributes<HTMLElement> {
41
+ /** A bare leading glyph, e.g. a calendar for a date range. */
42
+ icon?: React.ReactNode;
43
+ }
44
+ export declare const FilterBarValue: React.ForwardRefExoticComponent<FilterBarValueProps & React.RefAttributes<HTMLElement>>;
@@ -0,0 +1,89 @@
1
+ "use client";
2
+ import { jsx as e, jsxs as c, Fragment as m } from "react/jsx-runtime";
3
+ import * as u from "react";
4
+ import { cn as s } from "../lib/cn.js";
5
+ import { ChevronDown as b, Check as f } from "../lib/icons.js";
6
+ import { Dropdown as h, DropdownTrigger as p, DropdownContent as g, DropdownItem as v } from "./dropdown.js";
7
+ const w = u.forwardRef(
8
+ ({ className: i, ...r }, a) => /* @__PURE__ */ e(
9
+ "div",
10
+ {
11
+ ref: a,
12
+ role: "group",
13
+ "data-slot": "filter-bar",
14
+ className: s(
15
+ "inline-flex h-8 max-w-full shrink-0 items-stretch overflow-hidden rounded-m border border-input bg-card",
16
+ // Hairline between segments; the group's own edge closes the ends.
17
+ "[&>*+*]:border-l [&>*+*]:border-input",
18
+ i
19
+ ),
20
+ ...r
21
+ }
22
+ )
23
+ );
24
+ w.displayName = "FilterBar";
25
+ const d = "inline-flex min-w-0 items-center gap-2 px-3 text-m whitespace-nowrap text-on-white-primary [&_svg]:size-4 [&_svg]:shrink-0";
26
+ function D({ label: i, value: r, options: a, onValueChange: o, className: l }) {
27
+ const n = a.find((t) => t.value === r);
28
+ return /* @__PURE__ */ c(h, { children: [
29
+ /* @__PURE__ */ e(p, { children: /* @__PURE__ */ c(
30
+ "button",
31
+ {
32
+ type: "button",
33
+ "data-slot": "filter-bar-select",
34
+ "aria-label": `${i}: ${(n == null ? void 0 : n.label) ?? r}`,
35
+ className: s(
36
+ d,
37
+ "cursor-pointer outline-none transition-colors duration-150 motion-reduce:transition-none",
38
+ "hover:bg-muted focus-visible:bg-muted focus-visible:ring-3 focus-visible:ring-inset focus-visible:ring-ring",
39
+ l
40
+ ),
41
+ children: [
42
+ /* @__PURE__ */ e("span", { className: "truncate", children: (n == null ? void 0 : n.label) ?? r }),
43
+ /* @__PURE__ */ e(b, { "aria-hidden": !0, className: "text-on-white-secondary" })
44
+ ]
45
+ }
46
+ ) }),
47
+ /* @__PURE__ */ e(g, { "aria-label": i, children: a.map((t) => /* @__PURE__ */ e(
48
+ v,
49
+ {
50
+ "aria-current": t.value === r ? "true" : void 0,
51
+ onSelect: () => o(t.value),
52
+ startContent: /* @__PURE__ */ e(f, { "aria-hidden": !0, className: t.value === r ? "opacity-100" : "opacity-0" }),
53
+ children: t.label
54
+ },
55
+ t.value
56
+ )) })
57
+ ] });
58
+ }
59
+ const x = u.forwardRef(
60
+ ({ className: i, icon: r, children: a, onClick: o, ...l }, n) => {
61
+ const t = /* @__PURE__ */ c(m, { children: [
62
+ r ? /* @__PURE__ */ e("span", { "aria-hidden": !0, className: "inline-flex text-on-white-secondary", children: r }) : null,
63
+ /* @__PURE__ */ e("span", { className: "truncate tabular-nums", children: a })
64
+ ] });
65
+ return o ? /* @__PURE__ */ e(
66
+ "button",
67
+ {
68
+ ref: n,
69
+ type: "button",
70
+ "data-slot": "filter-bar-value",
71
+ onClick: o,
72
+ className: s(
73
+ d,
74
+ "cursor-pointer outline-none transition-colors duration-150 motion-reduce:transition-none",
75
+ "hover:bg-muted focus-visible:ring-3 focus-visible:ring-inset focus-visible:ring-ring",
76
+ i
77
+ ),
78
+ ...l,
79
+ children: t
80
+ }
81
+ ) : /* @__PURE__ */ e("span", { ref: n, "data-slot": "filter-bar-value", className: s(d, i), ...l, children: t });
82
+ }
83
+ );
84
+ x.displayName = "FilterBarValue";
85
+ export {
86
+ w as FilterBar,
87
+ D as FilterBarSelect,
88
+ x as FilterBarValue
89
+ };
@@ -0,0 +1,37 @@
1
+ import * as React from "react";
2
+ export interface FilterOption {
3
+ value: string;
4
+ label: string;
5
+ }
6
+ export interface FilterGroup {
7
+ /** Stable key passed back through `onChange`. */
8
+ id: string;
9
+ /** Accessible name for the group's Select (e.g. "Status"). */
10
+ label: string;
11
+ /** The first option is the group's "All …" default. */
12
+ options: FilterOption[];
13
+ /** The selected option value. */
14
+ value: string;
15
+ }
16
+ export interface FiltersProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "onChange" | "title"> {
17
+ groups: FilterGroup[];
18
+ /** Called with the group id and its newly selected option value. */
19
+ onChange: (id: string, value: string) => void;
20
+ /**
21
+ * Called by "Clear all". When omitted, Clear all resets every applied group
22
+ * to its first option through `onChange`.
23
+ */
24
+ onClearAll?: () => void;
25
+ /** Panel title. Defaults to "Filters". */
26
+ title?: string;
27
+ /** Accessible label for the icon-only trigger. Defaults to `title`. */
28
+ triggerLabel?: string;
29
+ /** Which trigger edge the panel aligns to. Defaults to `"end"`. */
30
+ align?: "start" | "end";
31
+ /** Controlled open state — pair with `onOpenChange`. */
32
+ open?: boolean;
33
+ /** Uncontrolled initial open state. */
34
+ defaultOpen?: boolean;
35
+ onOpenChange?: (open: boolean) => void;
36
+ }
37
+ export declare const Filters: React.ForwardRefExoticComponent<FiltersProps & React.RefAttributes<HTMLDivElement>>;