@actioneer/ads 0.5.8 → 0.5.9

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.
@@ -1,11 +1,11 @@
1
1
  "use client";
2
- import { jsx as n, jsxs as x } from "react/jsx-runtime";
3
- import * as d from "react";
4
- import { MotionConfig as h, motion as v } from "motion/react";
5
- import { cva as l } from "class-variance-authority";
6
- import { cn as c } from "../lib/cn.js";
7
- import { springControl as w } from "../lib/motion.js";
8
- const y = l(
2
+ import { jsx as n, jsxs as h } from "react/jsx-runtime";
3
+ import * as l from "react";
4
+ import { MotionConfig as v, motion as w } from "motion/react";
5
+ import { cva as c } from "class-variance-authority";
6
+ import { cn as o } from "../lib/cn.js";
7
+ import { springControl as y } from "../lib/motion.js";
8
+ const D = c(
9
9
  // Borderless recessed track on ink-200 (bg-surface) — matches the Tabs
10
10
  // primary track (the selected segment provides the definition; a stroke around the
11
11
  // track read as a second, heavier control).
@@ -20,8 +20,8 @@ const y = l(
20
20
  },
21
21
  defaultVariants: { size: "md" }
22
22
  }
23
- ), D = l(
24
- c(
23
+ ), k = c(
24
+ o(
25
25
  // The active segment is a shared motion thumb that SLIDES between options
26
26
  // (layoutId), so the option itself only carries text color.
27
27
  "relative inline-flex items-center justify-center whitespace-nowrap font-normal select-none",
@@ -43,33 +43,33 @@ const y = l(
43
43
  },
44
44
  defaultVariants: { size: "md", selected: !1 }
45
45
  }
46
- ), k = d.forwardRef(({ options: r, value: a, onChange: o, size: s, className: m, ...u }, f) => {
47
- const p = d.useId(), i = (e) => {
48
- const t = r.findIndex((b) => b.value === a), g = ((t < 0 ? 0 : t) + e + r.length) % r.length;
49
- o(r[g].value);
46
+ ), I = l.forwardRef(({ options: r, value: a, onChange: s, size: i, className: u, elevated: m = !0, ...f }, p) => {
47
+ const g = l.useId(), d = (e) => {
48
+ const t = r.findIndex((x) => x.value === a), b = ((t < 0 ? 0 : t) + e + r.length) % r.length;
49
+ s(r[b].value);
50
50
  };
51
51
  return /* @__PURE__ */ n(
52
52
  "div",
53
53
  {
54
- ref: f,
54
+ ref: p,
55
55
  role: "radiogroup",
56
56
  onKeyDown: (e) => {
57
57
  switch (e.key) {
58
58
  case "ArrowRight":
59
59
  case "ArrowDown":
60
- e.preventDefault(), i(1);
60
+ e.preventDefault(), d(1);
61
61
  break;
62
62
  case "ArrowLeft":
63
63
  case "ArrowUp":
64
- e.preventDefault(), i(-1);
64
+ e.preventDefault(), d(-1);
65
65
  break;
66
66
  }
67
67
  },
68
- className: c(y({ size: s }), m),
69
- ...u,
70
- children: /* @__PURE__ */ n(h, { reducedMotion: "user", children: r.map((e) => {
68
+ className: o(D({ size: i }), u),
69
+ ...f,
70
+ children: /* @__PURE__ */ n(v, { reducedMotion: "user", children: r.map((e) => {
71
71
  const t = e.value === a;
72
- return /* @__PURE__ */ x(
72
+ return /* @__PURE__ */ h(
73
73
  "button",
74
74
  {
75
75
  type: "button",
@@ -77,17 +77,20 @@ const y = l(
77
77
  "aria-checked": t,
78
78
  "aria-label": e.ariaLabel,
79
79
  tabIndex: t ? 0 : -1,
80
- onClick: () => o(e.value),
81
- className: D({ size: s, selected: t }),
80
+ onClick: () => s(e.value),
81
+ className: k({ size: i, selected: t }),
82
82
  children: [
83
83
  t && /* @__PURE__ */ n(
84
- v.span,
84
+ w.span,
85
85
  {
86
- layoutId: p,
86
+ layoutId: g,
87
87
  "aria-hidden": !0,
88
88
  layoutDependency: a,
89
- transition: w,
90
- className: "absolute inset-0 rounded-[inherit] bg-elevated shadow-elevation"
89
+ transition: y,
90
+ className: o(
91
+ "absolute inset-0 rounded-[inherit] bg-elevated",
92
+ m && "shadow-elevation"
93
+ )
91
94
  }
92
95
  ),
93
96
  /* @__PURE__ */ n("span", { className: "relative", children: e.label })
@@ -99,7 +102,7 @@ const y = l(
99
102
  }
100
103
  );
101
104
  });
102
- k.displayName = "SegmentedControl";
105
+ I.displayName = "SegmentedControl";
103
106
  export {
104
- k as SegmentedControl
107
+ I as SegmentedControl
105
108
  };
@@ -12,6 +12,9 @@ export interface SelectProps extends VariantProps<typeof selectTriggerVariants>
12
12
  items: SelectItem[];
13
13
  value?: string;
14
14
  onChange?: (value: string) => void;
15
+ multiple?: boolean;
16
+ values?: string[];
17
+ onValuesChange?: (values: string[]) => void;
15
18
  placeholder?: string;
16
19
  disabled?: boolean;
17
20
  isInvalid?: boolean;
@@ -25,6 +28,8 @@ export interface SelectProps extends VariantProps<typeof selectTriggerVariants>
25
28
  * `overflow-clip` shell) so the menu isn't cut off. Defaults to `"bottom"`.
26
29
  */
27
30
  placement?: "top" | "bottom";
31
+ /** Render the listbox at the document root so overflow containers cannot clip it. */
32
+ portal?: boolean;
28
33
  }
29
34
  export declare const Select: React.ForwardRefExoticComponent<SelectProps & React.RefAttributes<HTMLButtonElement>>;
30
35
  export {};
@@ -1,16 +1,17 @@
1
1
  "use client";
2
- import { jsxs as b, jsx as i } from "react/jsx-runtime";
3
- import * as a from "react";
4
- import { cva as V } from "class-variance-authority";
5
- import { MotionConfig as $, AnimatePresence as C, motion as K } from "motion/react";
6
- import { ChevronDown as L, Check as O } from "../lib/icons.js";
7
- import { cn as d } from "../lib/cn.js";
8
- import { inputBaseClass as P } from "./field.js";
9
- import { floatVariants as T } from "../lib/motion.js";
10
- import { Ripple as _ } from "./ripple.js";
11
- const B = V(
12
- d(
13
- P,
2
+ import { jsx as u, jsxs as k } from "react/jsx-runtime";
3
+ import * as s from "react";
4
+ import { createPortal as q } from "react-dom";
5
+ import { cva as C } from "class-variance-authority";
6
+ import { MotionConfig as F, AnimatePresence as G, motion as J } from "motion/react";
7
+ import { Check as Q, ChevronDown as V } from "../lib/icons.js";
8
+ import { cn as f } from "../lib/cn.js";
9
+ import { inputBaseClass as W } from "./field.js";
10
+ import { floatVariants as X } from "../lib/motion.js";
11
+ import { Ripple as Y } from "./ripple.js";
12
+ const Z = C(
13
+ f(
14
+ W,
14
15
  "items-center justify-between gap-2 text-left cursor-pointer",
15
16
  "[&_svg]:pointer-events-none [&_svg]:shrink-0"
16
17
  ),
@@ -24,103 +25,195 @@ const B = V(
24
25
  },
25
26
  defaultVariants: { size: "md" }
26
27
  }
27
- ), U = a.forwardRef(
28
+ ), ee = s.forwardRef(
28
29
  ({
29
30
  items: o,
30
- value: c,
31
- onChange: m,
32
- placeholder: I = "Select…",
33
- size: N,
34
- disabled: w,
35
- isInvalid: E,
36
- className: R,
37
- id: A,
38
- placement: v = "bottom",
39
- "aria-label": S,
40
- "aria-describedby": z
41
- }, j) => {
42
- const [r, l] = a.useState(!1), [s, x] = a.useState(-1), g = a.useRef(null), k = a.useRef(null), u = a.useId(), h = o.find((e) => e.value === c), M = a.useCallback(() => {
43
- const e = o.findIndex((t) => t.value === c);
31
+ value: h,
32
+ onChange: E,
33
+ multiple: d = !1,
34
+ values: l = [],
35
+ onValuesChange: I,
36
+ placeholder: R = "Select…",
37
+ size: M,
38
+ disabled: L,
39
+ isInvalid: B,
40
+ className: H,
41
+ id: O,
42
+ placement: m = "bottom",
43
+ portal: p = !1,
44
+ "aria-label": P,
45
+ "aria-describedby": T
46
+ }, _) => {
47
+ const [r, b] = s.useState(!1), [c, N] = s.useState(-1), z = s.useRef(null), w = s.useRef(null), g = s.useId(), [i, S] = s.useState(null), D = o.find((e) => e.value === h), v = d ? o.filter((e) => l.includes(e.value)) : [], K = s.useCallback(() => {
48
+ const e = d ? o.findIndex((t) => l.includes(t.value)) : o.findIndex((t) => t.value === h);
44
49
  return e >= 0 && !o[e].disabled ? e : o.findIndex((t) => !t.disabled);
45
- }, [o, c]);
46
- a.useEffect(() => {
50
+ }, [o, d, h, l]);
51
+ s.useEffect(() => {
47
52
  if (!r) return;
48
53
  const e = (t) => {
49
- var n;
50
- (n = g.current) != null && n.contains(t.target) || l(!1);
54
+ var a, x;
55
+ const n = t.target;
56
+ (a = z.current) != null && a.contains(n) || (x = w.current) != null && x.contains(n) || b(!1);
51
57
  };
52
58
  return document.addEventListener("mousedown", e), () => document.removeEventListener("mousedown", e);
53
- }, [r]), a.useEffect(() => {
59
+ }, [r]), s.useLayoutEffect(() => {
60
+ if (!r || !p) {
61
+ S(null);
62
+ return;
63
+ }
64
+ const e = () => {
65
+ var a, x;
66
+ const t = (a = z.current) == null ? void 0 : a.getBoundingClientRect();
67
+ if (!t) return;
68
+ const n = ((x = w.current) == null ? void 0 : x.offsetHeight) ?? 0;
69
+ S({
70
+ top: m === "top" ? t.top - n - 6 : t.bottom + 6,
71
+ left: t.left,
72
+ width: t.width
73
+ });
74
+ };
75
+ return e(), window.addEventListener("resize", e), window.addEventListener("scroll", e, !0), () => {
76
+ window.removeEventListener("resize", e), window.removeEventListener("scroll", e, !0);
77
+ };
78
+ }, [r, m, p]), s.useEffect(() => {
54
79
  var t;
55
- if (!r || s < 0) return;
56
- const e = (t = k.current) == null ? void 0 : t.children[s];
80
+ if (!r || c < 0) return;
81
+ const e = (t = w.current) == null ? void 0 : t.children[c];
57
82
  e == null || e.scrollIntoView({ block: "nearest" });
58
- }, [r, s]);
59
- const f = () => {
60
- w || (x(M()), l(!0));
61
- }, y = (e) => {
62
- x((t) => {
83
+ }, [r, c]);
84
+ const y = () => {
85
+ L || (N(K()), b(!0));
86
+ }, A = (e) => {
87
+ N((t) => {
63
88
  let n = t;
64
- for (let p = 0; p < o.length; p++)
89
+ for (let a = 0; a < o.length; a++)
65
90
  if (n = (n + e + o.length) % o.length, !o[n].disabled) return n;
66
91
  return t;
67
92
  });
68
- }, D = (e) => {
93
+ }, $ = (e) => {
69
94
  const t = o[e];
70
- !t || t.disabled || (m == null || m(t.value), l(!1));
71
- };
72
- return /* @__PURE__ */ b("div", { ref: g, className: "relative", children: [
73
- /* @__PURE__ */ b(
95
+ if (!(!t || t.disabled)) {
96
+ if (d) {
97
+ I == null || I(
98
+ l.includes(t.value) ? l.filter((n) => n !== t.value) : [...l, t.value]
99
+ );
100
+ return;
101
+ }
102
+ E == null || E(t.value), b(!1);
103
+ }
104
+ }, U = (e) => {
105
+ switch (e.key) {
106
+ case "ArrowDown":
107
+ e.preventDefault(), r ? A(1) : y();
108
+ break;
109
+ case "ArrowUp":
110
+ e.preventDefault(), r ? A(-1) : y();
111
+ break;
112
+ case "Enter":
113
+ case " ":
114
+ e.preventDefault(), r ? $(c) : y();
115
+ break;
116
+ case "Escape":
117
+ r && (e.preventDefault(), e.stopPropagation(), b(!1));
118
+ break;
119
+ case "Tab":
120
+ b(!1);
121
+ break;
122
+ }
123
+ }, j = /* @__PURE__ */ u(F, { reducedMotion: "user", children: /* @__PURE__ */ u(G, { children: r && /* @__PURE__ */ k(
124
+ J.ul,
125
+ {
126
+ ref: w,
127
+ id: g,
128
+ role: "listbox",
129
+ "aria-multiselectable": d || void 0,
130
+ "aria-activedescendant": c >= 0 ? `${g}-opt-${c}` : void 0,
131
+ variants: X,
132
+ initial: "hidden",
133
+ animate: "visible",
134
+ exit: "hidden",
135
+ style: {
136
+ transformOrigin: m === "top" ? "bottom" : "top",
137
+ ...p ? {
138
+ position: "fixed",
139
+ top: (i == null ? void 0 : i.top) ?? 0,
140
+ left: (i == null ? void 0 : i.left) ?? 0,
141
+ width: (i == null ? void 0 : i.width) ?? 0,
142
+ visibility: i ? "visible" : "hidden",
143
+ zIndex: 60
144
+ } : {}
145
+ },
146
+ className: f(
147
+ "max-h-60 overflow-auto p-1",
148
+ "rounded-md border border-border bg-elevated shadow-elevation",
149
+ p ? "fixed" : f(
150
+ "absolute z-50 w-full",
151
+ m === "top" ? "bottom-full mb-1.5" : "top-full mt-1.5"
152
+ )
153
+ ),
154
+ children: [
155
+ /* @__PURE__ */ u(Y, { origin: m === "top" ? "bottom" : "top" }),
156
+ o.map((e, t) => {
157
+ const n = d ? l.includes(e.value) : e.value === h, a = t === c;
158
+ return /* @__PURE__ */ k(
159
+ "li",
160
+ {
161
+ id: `${g}-opt-${t}`,
162
+ role: "option",
163
+ "aria-selected": n,
164
+ "aria-disabled": e.disabled || void 0,
165
+ onMouseEnter: () => !e.disabled && N(t),
166
+ onClick: () => $(t),
167
+ className: f(
168
+ "flex cursor-pointer items-center justify-between gap-2",
169
+ "rounded-sm px-2 py-1.5 text-xs text-foreground select-none",
170
+ a && !e.disabled && "bg-muted",
171
+ e.disabled && "pointer-events-none opacity-50"
172
+ ),
173
+ children: [
174
+ /* @__PURE__ */ u("span", { className: "truncate", children: e.label }),
175
+ n && /* @__PURE__ */ u(Q, { className: "size-4 shrink-0", "aria-hidden": !0 })
176
+ ]
177
+ },
178
+ e.value
179
+ );
180
+ })
181
+ ]
182
+ }
183
+ ) }) });
184
+ return /* @__PURE__ */ k("div", { ref: z, className: "relative", children: [
185
+ /* @__PURE__ */ k(
74
186
  "button",
75
187
  {
76
- ref: j,
77
- id: A,
188
+ ref: _,
189
+ id: O,
78
190
  type: "button",
79
191
  role: "combobox",
80
192
  "aria-haspopup": "listbox",
81
193
  "aria-expanded": r,
82
- "aria-controls": u,
83
- "aria-invalid": E || void 0,
84
- "aria-label": S,
85
- "aria-describedby": z,
86
- disabled: w,
87
- onClick: () => r ? l(!1) : f(),
88
- onKeyDown: (e) => {
89
- switch (e.key) {
90
- case "ArrowDown":
91
- e.preventDefault(), r ? y(1) : f();
92
- break;
93
- case "ArrowUp":
94
- e.preventDefault(), r ? y(-1) : f();
95
- break;
96
- case "Enter":
97
- case " ":
98
- e.preventDefault(), r ? D(s) : f();
99
- break;
100
- case "Escape":
101
- r && (e.preventDefault(), l(!1));
102
- break;
103
- case "Tab":
104
- l(!1);
105
- break;
106
- }
107
- },
108
- className: d(B({ size: N }), R),
194
+ "aria-controls": g,
195
+ "aria-invalid": B || void 0,
196
+ "aria-label": P,
197
+ "aria-describedby": T,
198
+ disabled: L,
199
+ onClick: () => r ? b(!1) : y(),
200
+ onKeyDown: U,
201
+ className: f(Z({ size: M }), H),
109
202
  children: [
110
- /* @__PURE__ */ i(
203
+ /* @__PURE__ */ u(
111
204
  "span",
112
205
  {
113
- className: d(
206
+ className: f(
114
207
  "truncate",
115
- !h && "text-muted-foreground"
208
+ d ? v.length === 0 && "text-muted-foreground" : !D && "text-muted-foreground"
116
209
  ),
117
- children: h ? h.label : I
210
+ children: d ? v.length === 0 ? R : v.length === 1 ? v[0].label : `${v.length} selected` : D ? D.label : R
118
211
  }
119
212
  ),
120
- /* @__PURE__ */ i(
121
- L,
213
+ /* @__PURE__ */ u(
214
+ V,
122
215
  {
123
- className: d(
216
+ className: f(
124
217
  "size-4 text-muted-foreground transition-transform duration-150 ease-out motion-reduce:transition-none",
125
218
  r && "rotate-180"
126
219
  ),
@@ -130,59 +223,11 @@ const B = V(
130
223
  ]
131
224
  }
132
225
  ),
133
- /* @__PURE__ */ i($, { reducedMotion: "user", children: /* @__PURE__ */ i(C, { children: r && /* @__PURE__ */ b(
134
- K.ul,
135
- {
136
- ref: k,
137
- id: u,
138
- role: "listbox",
139
- "aria-activedescendant": s >= 0 ? `${u}-opt-${s}` : void 0,
140
- variants: T,
141
- initial: "hidden",
142
- animate: "visible",
143
- exit: "hidden",
144
- style: {
145
- transformOrigin: v === "top" ? "bottom" : "top"
146
- },
147
- className: d(
148
- "absolute z-50 max-h-60 w-full overflow-auto p-1",
149
- "rounded-md border border-border bg-elevated shadow-elevation",
150
- v === "top" ? "bottom-full mb-1.5" : "top-full mt-1.5"
151
- ),
152
- children: [
153
- /* @__PURE__ */ i(_, { origin: v === "top" ? "bottom" : "top" }),
154
- o.map((e, t) => {
155
- const n = e.value === c, p = t === s;
156
- return /* @__PURE__ */ b(
157
- "li",
158
- {
159
- id: `${u}-opt-${t}`,
160
- role: "option",
161
- "aria-selected": n,
162
- "aria-disabled": e.disabled || void 0,
163
- onMouseEnter: () => !e.disabled && x(t),
164
- onClick: () => D(t),
165
- className: d(
166
- "flex cursor-pointer items-center justify-between gap-2",
167
- "rounded-sm px-2 py-1.5 text-xs text-foreground select-none",
168
- p && !e.disabled && "bg-muted",
169
- e.disabled && "pointer-events-none opacity-50"
170
- ),
171
- children: [
172
- /* @__PURE__ */ i("span", { className: "truncate", children: e.label }),
173
- n && /* @__PURE__ */ i(O, { className: "size-4 shrink-0", "aria-hidden": !0 })
174
- ]
175
- },
176
- e.value
177
- );
178
- })
179
- ]
180
- }
181
- ) }) })
226
+ p && typeof document < "u" ? q(j, document.body) : j
182
227
  ] });
183
228
  }
184
229
  );
185
- U.displayName = "Select";
230
+ ee.displayName = "Select";
186
231
  export {
187
- U as Select
232
+ ee as Select
188
233
  };
@@ -54,6 +54,13 @@ export interface TableProps extends Omit<React.TableHTMLAttributes<HTMLTableElem
54
54
  * layout must stay fixed (e.g. a compact summary card).
55
55
  */
56
56
  resizableColumns?: boolean;
57
+ /**
58
+ * Caps the table's height: the viewport scrolls vertically inside the
59
+ * shell and the header row pins to its top (painted on the shell gray so
60
+ * body rows pass underneath). For long results read in place — an
61
+ * expanded board table, a log — instead of pagination.
62
+ */
63
+ maxBodyHeight?: React.CSSProperties["maxHeight"];
57
64
  }
58
65
  /**
59
66
  * Styled wrapper around a semantic `<table>` with horizontal overflow.