@actioneer/ads 1.0.0 → 1.0.1

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.
@@ -81,7 +81,7 @@ export declare const TableBody: React.ForwardRefExoticComponent<React.HTMLAttrib
81
81
  export interface TableRowProps extends React.HTMLAttributes<HTMLTableRowElement> {
82
82
  /** Stable key for selection (required on body rows to be selectable). */
83
83
  rowKey?: string;
84
- /** Explicitly marks a row as opening or expanding something. */
84
+ /** @deprecated Existing visual-only marker. New rows should pass an action via onClick. */
85
85
  isInteractive?: boolean;
86
86
  }
87
87
  export declare const TableRow: React.ForwardRefExoticComponent<TableRowProps & React.RefAttributes<HTMLTableRowElement>>;
@@ -1,62 +1,62 @@
1
1
  "use client";
2
- import { jsx as d, jsxs as T } from "react/jsx-runtime";
2
+ import { jsx as u, jsxs as W } from "react/jsx-runtime";
3
3
  import * as n from "react";
4
- import { cn as m } from "../lib/cn.js";
4
+ import { cn as f } from "../lib/cn.js";
5
5
  import { Checkbox as ne } from "./checkbox.js";
6
6
  import { ChevronUp as ve, ChevronDown as ye, SortIcon as we } from "../lib/icons.js";
7
- const se = (r) => r === "center" ? "text-center" : r === "right" ? "text-right" : "text-left", ae = (r, t = !1) => r === "left" ? m(
7
+ const se = (r) => r === "center" ? "text-center" : r === "right" ? "text-right" : "text-left", ae = (r, e = !1) => r === "left" ? f(
8
8
  "sticky left-0 z-10",
9
9
  // Scroll-aware: the smudge only appears once content is actually
10
10
  // hidden behind the pinned column (nothing to scroll back to at the
11
11
  // far left → no shadow).
12
12
  "group-data-[scroll-left=true]/table-shell:shadow-table-smudge-left"
13
- ) : r === "right" ? m(
13
+ ) : r === "right" ? f(
14
14
  "sticky right-0 z-10",
15
15
  // Backward-compatible fallback. Action columns should opt into the
16
16
  // Table-level elevation so one shadow spans the complete column.
17
- !t && "group-data-[scroll-right=true]/table-shell:shadow-table-smudge-right"
18
- ) : void 0, ie = n.createContext(!1), le = (r) => m(
17
+ !e && "group-data-[scroll-right=true]/table-shell:shadow-table-smudge-right"
18
+ ) : void 0, ie = n.createContext(!1), le = (r) => f(
19
19
  "bg-card align-middle transition-colors",
20
20
  // Functional row hairline; the table shell carries the outer stroke.
21
21
  "border-b border-table-stroke group-last/row:border-b-0",
22
- r && m(
22
+ r && f(
23
23
  // Use WG3 without introducing a new
24
24
  // rounded silhouette. The wash is pre-composited so scrolled text
25
25
  // cannot show through sticky cells.
26
26
  "group-hover/row:bg-(--table-row-hover) group-focus-within/row:bg-(--table-row-hover)",
27
27
  "group-data-[selected]/row:bg-(--table-row-selected)"
28
28
  )
29
- ), ce = "bg-wg1", ue = m(
29
+ ), ce = "bg-wg1", ue = f(
30
30
  "after:pointer-events-none after:absolute after:right-0 after:top-1/2",
31
31
  "after:h-4 after:w-px after:-translate-y-1/2 after:rounded-sm",
32
32
  "after:bg-border-strong last:after:hidden"
33
- ), G = "__ads_table_column_", Q = 64, xe = new Intl.Collator(void 0, {
33
+ ), Q = "__ads_table_column_", Y = 64, xe = new Intl.Collator(void 0, {
34
34
  numeric: !0,
35
35
  sensitivity: "base"
36
36
  });
37
- function V(r) {
38
- const t = [];
37
+ function _(r) {
38
+ const e = [];
39
39
  return n.Children.forEach(r, (a) => {
40
40
  if (n.isValidElement(a) && a.type === n.Fragment) {
41
- t.push(...V(a.props.children));
41
+ e.push(..._(a.props.children));
42
42
  return;
43
43
  }
44
- t.push(a);
45
- }), t;
44
+ e.push(a);
45
+ }), e;
46
46
  }
47
47
  function X(r) {
48
48
  if (r == null || typeof r == "boolean")
49
49
  return "";
50
50
  if (typeof r == "number" || typeof r == "string") return r;
51
51
  if (Array.isArray(r))
52
- return r.map((o) => String(X(o))).join(" ").trim();
52
+ return r.map((s) => String(X(s))).join(" ").trim();
53
53
  if (!n.isValidElement(r)) return "";
54
- const t = r.props.sortValue;
55
- if (typeof t == "string" || typeof t == "number" || t instanceof Date)
56
- return t;
54
+ const e = r.props.sortValue;
55
+ if (typeof e == "string" || typeof e == "number" || e instanceof Date)
56
+ return e;
57
57
  const a = X(r.props.children);
58
58
  if (String(a).trim()) return a;
59
- for (const o of [
59
+ for (const s of [
60
60
  "value",
61
61
  "label",
62
62
  "status",
@@ -64,8 +64,8 @@ function X(r) {
64
64
  "title",
65
65
  "health"
66
66
  ]) {
67
- const s = r.props[o];
68
- if (typeof s == "string" || typeof s == "number") return s;
67
+ const o = r.props[s];
68
+ if (typeof o == "string" || typeof o == "number") return o;
69
69
  }
70
70
  return "";
71
71
  }
@@ -74,211 +74,211 @@ function oe(r) {
74
74
  return { kind: "number", value: r.getTime() };
75
75
  if (typeof r == "number")
76
76
  return { kind: "number", value: r };
77
- const t = r.trim();
78
- if (!t || t === "—" || t === "-")
77
+ const e = r.trim();
78
+ if (!e || e === "—" || e === "-")
79
79
  return { kind: "empty", value: "" };
80
- const a = t.replace(/[,\s]/g, "").replace(/^[₹$€£]/, "").replace(/%$/, "");
80
+ const a = e.replace(/[,\s]/g, "").replace(/^[₹$€£]/, "").replace(/%$/, "");
81
81
  if (/^[+-]?(?:\d+\.?\d*|\.\d+)$/.test(a))
82
82
  return { kind: "number", value: Number(a) };
83
- const s = /^\d{4}[-/]\d{1,2}[-/]\d{1,2}/.test(t) || /\b(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\b/i.test(t) ? Date.parse(t) : Number.NaN;
84
- return Number.isNaN(s) ? { kind: "text", value: t } : { kind: "number", value: s };
83
+ const o = /^\d{4}[-/]\d{1,2}[-/]\d{1,2}/.test(e) || /\b(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\b/i.test(e) ? Date.parse(e) : Number.NaN;
84
+ return Number.isNaN(o) ? { kind: "text", value: e } : { kind: "number", value: o };
85
85
  }
86
- function Ce(r, t, a) {
87
- const o = oe(r), s = oe(t);
88
- if (o.kind === "empty") return s.kind === "empty" ? 0 : 1;
89
- if (s.kind === "empty") return -1;
90
- const c = o.kind === "number" && s.kind === "number" ? o.value - s.value : xe.compare(String(o.value), String(s.value));
86
+ function Ce(r, e, a) {
87
+ const s = oe(r), o = oe(e);
88
+ if (s.kind === "empty") return o.kind === "empty" ? 0 : 1;
89
+ if (o.kind === "empty") return -1;
90
+ const c = s.kind === "number" && o.kind === "number" ? s.value - o.value : xe.compare(String(s.value), String(o.value));
91
91
  return a === "ascending" ? c : -c;
92
92
  }
93
- const de = n.createContext(null), B = () => n.useContext(de), Y = n.createContext("body");
93
+ const de = n.createContext(null), B = () => n.useContext(de), Z = n.createContext("body");
94
94
  function Ne(r) {
95
- const t = [], o = V(r.props.children).map((s, c) => {
96
- if (!n.isValidElement(s) || s.type !== Z)
97
- return s;
98
- let u = 0;
99
- const p = V(s.props.children).map((e) => {
100
- if (!n.isValidElement(e)) return e;
101
- for (; (t[u] ?? 0) > c; )
102
- u += 1;
103
- const N = Math.max(1, Number(e.props.colSpan ?? 1)), x = Math.max(1, Number(e.props.rowSpan ?? 1)), y = u;
104
- for (let g = 0; g < N; g += 1)
105
- t[y + g] = Math.max(
106
- t[y + g] ?? 0,
95
+ const e = [], s = _(r.props.children).map((o, c) => {
96
+ if (!n.isValidElement(o) || o.type !== K)
97
+ return o;
98
+ let d = 0;
99
+ const k = _(o.props.children).map((t) => {
100
+ if (!n.isValidElement(t)) return t;
101
+ for (; (e[d] ?? 0) > c; )
102
+ d += 1;
103
+ const b = Math.max(1, Number(t.props.colSpan ?? 1)), x = Math.max(1, Number(t.props.rowSpan ?? 1)), y = d;
104
+ for (let g = 0; g < b; g += 1)
105
+ e[y + g] = Math.max(
106
+ e[y + g] ?? 0,
107
107
  c + x
108
108
  );
109
- return u += N, e.type !== be ? e : n.cloneElement(e, { _sortColumnIndex: y });
109
+ return d += b, t.type !== be ? t : n.cloneElement(t, { _sortColumnIndex: y });
110
110
  });
111
- return n.cloneElement(s, void 0, p);
111
+ return n.cloneElement(o, void 0, k);
112
112
  });
113
- return n.cloneElement(r, void 0, o);
113
+ return n.cloneElement(r, void 0, s);
114
114
  }
115
- function ke(r, t, a) {
116
- const o = V(r.props.children).map((s, c) => {
117
- if (!n.isValidElement(s) || s.type !== Z)
118
- return { row: s, index: c, value: "" };
119
- const u = V(s.props.children);
115
+ function ke(r, e, a) {
116
+ const s = _(r.props.children).map((o, c) => {
117
+ if (!n.isValidElement(o) || o.type !== K)
118
+ return { row: o, index: c, value: "" };
119
+ const d = _(o.props.children);
120
120
  return {
121
- row: s,
121
+ row: o,
122
122
  index: c,
123
- value: X(u[t])
123
+ value: X(d[e])
124
124
  };
125
125
  });
126
- return o.sort((s, c) => Ce(s.value, c.value, a) || s.index - c.index), n.cloneElement(
126
+ return s.sort((o, c) => Ce(o.value, c.value, a) || o.index - c.index), n.cloneElement(
127
127
  r,
128
128
  void 0,
129
- o.map(({ row: s }) => s)
129
+ s.map(({ row: o }) => o)
130
130
  );
131
131
  }
132
- function me(r, t) {
133
- const a = t != null && t.column.startsWith(G) ? Number(t.column.slice(G.length)) : Number.NaN;
134
- return n.Children.map(r, (o) => n.isValidElement(o) ? o.type === n.Fragment ? n.cloneElement(
135
- o,
132
+ function me(r, e) {
133
+ const a = e != null && e.column.startsWith(Q) ? Number(e.column.slice(Q.length)) : Number.NaN;
134
+ return n.Children.map(r, (s) => n.isValidElement(s) ? s.type === n.Fragment ? n.cloneElement(
135
+ s,
136
136
  void 0,
137
- me(o.props.children, t)
138
- ) : o.type === fe ? Ne(o) : o.type === pe && t && Number.isInteger(a) && a >= 0 ? ke(o, a, t.direction) : o : o);
137
+ me(s.props.children, e)
138
+ ) : s.type === fe ? Ne(s) : s.type === pe && e && Number.isInteger(a) && a >= 0 ? ke(s, a, e.direction) : s : s);
139
139
  }
140
140
  const ze = n.forwardRef(
141
141
  ({
142
142
  className: r,
143
- wrapperClassName: t,
143
+ wrapperClassName: e,
144
144
  toolbar: a,
145
- footer: o,
146
- children: s,
145
+ footer: s,
146
+ children: o,
147
147
  selectionMode: c = "none",
148
- selectedKeys: u,
149
- onSelectionChange: h,
150
- rowKeys: p,
151
- elevatedActionColumn: e = !1,
152
- actionColumnWidth: N = "3rem",
148
+ selectedKeys: d,
149
+ onSelectionChange: v,
150
+ rowKeys: k,
151
+ elevatedActionColumn: t = !1,
152
+ actionColumnWidth: b = "3rem",
153
153
  sortDescriptor: x,
154
154
  onSortChange: y,
155
155
  allowsSorting: g = !0,
156
- isStatic: A = !1,
157
- resizableColumns: E = !0,
158
- maxBodyHeight: k,
159
- ..._
156
+ isStatic: z = !1,
157
+ resizableColumns: S = !0,
158
+ maxBodyHeight: m,
159
+ ...E
160
160
  }, O) => {
161
- const C = n.useMemo(() => p ?? [], [p]), z = u === "all", v = z ? null : u ?? /* @__PURE__ */ new Set(), D = n.useCallback(
162
- (i) => z || !!(v != null && v.has(i)),
163
- [z, v]
164
- ), R = C.length > 0 && (z || C.every((i) => v == null ? void 0 : v.has(i))), W = !R && (z || C.some((i) => v == null ? void 0 : v.has(i))), $ = n.useCallback(
161
+ const N = n.useMemo(() => k ?? [], [k]), R = d === "all", w = R ? null : d ?? /* @__PURE__ */ new Set(), D = n.useCallback(
162
+ (i) => R || !!(w != null && w.has(i)),
163
+ [R, w]
164
+ ), A = N.length > 0 && (R || N.every((i) => w == null ? void 0 : w.has(i))), I = !A && (R || N.some((i) => w == null ? void 0 : w.has(i))), $ = n.useCallback(
165
165
  (i) => {
166
- if (!h) return;
166
+ if (!v) return;
167
167
  if (c === "single") {
168
- h(D(i) ? /* @__PURE__ */ new Set() : /* @__PURE__ */ new Set([i]));
168
+ v(D(i) ? /* @__PURE__ */ new Set() : /* @__PURE__ */ new Set([i]));
169
169
  return;
170
170
  }
171
- const b = new Set(z ? C : v ?? /* @__PURE__ */ new Set());
172
- b.has(i) ? b.delete(i) : b.add(i), h(b);
171
+ const h = new Set(R ? N : w ?? /* @__PURE__ */ new Set());
172
+ h.has(i) ? h.delete(i) : h.add(i), v(h);
173
173
  },
174
- [h, c, D, z, C, v]
175
- ), I = n.useCallback(() => {
176
- h && h(R ? /* @__PURE__ */ new Set() : new Set(C));
177
- }, [h, R, C]), [H, U] = n.useState(), f = g && !y, l = f ? H ?? x : x, S = n.useCallback(
174
+ [v, c, D, R, N, w]
175
+ ), M = n.useCallback(() => {
176
+ v && v(A ? /* @__PURE__ */ new Set() : new Set(N));
177
+ }, [v, A, N]), [H, U] = n.useState(), p = g && !y, l = p ? H ?? x : x, T = n.useCallback(
178
178
  (i) => {
179
179
  if (!g) return;
180
- const b = (l == null ? void 0 : l.column) === i && l.direction === "ascending" ? "descending" : "ascending", w = { column: i, direction: b };
181
- y ? y(w) : U(w);
180
+ const h = (l == null ? void 0 : l.column) === i && l.direction === "ascending" ? "descending" : "ascending", C = { column: i, direction: h };
181
+ y ? y(C) : U(C);
182
182
  },
183
183
  [l, g, y]
184
184
  ), j = n.useMemo(
185
- () => f ? me(s, l) : s,
186
- [l, f, s]
187
- ), M = n.useRef(null), [F, he] = n.useState({
185
+ () => p ? me(o, l) : o,
186
+ [l, p, o]
187
+ ), P = n.useRef(null), [F, ge] = n.useState({
188
188
  left: !1,
189
189
  right: !1
190
190
  }), q = n.useCallback(() => {
191
- const i = M.current;
191
+ const i = P.current;
192
192
  if (!i) return;
193
- const b = i.scrollWidth - i.clientWidth, w = i.scrollLeft > 1, L = i.scrollLeft < b - 1;
194
- he(
195
- (K) => K.left === w && K.right === L ? K : { left: w, right: L }
193
+ const h = i.scrollWidth - i.clientWidth, C = i.scrollLeft > 1, V = i.scrollLeft < h - 1;
194
+ ge(
195
+ (G) => G.left === C && G.right === V ? G : { left: C, right: V }
196
196
  );
197
197
  }, []);
198
198
  n.useEffect(() => {
199
199
  q();
200
- const i = M.current;
200
+ const i = P.current;
201
201
  if (!i || typeof ResizeObserver > "u") return;
202
- const b = new ResizeObserver(q);
203
- b.observe(i);
204
- const w = i.querySelector("table");
205
- return w && b.observe(w), () => b.disconnect();
202
+ const h = new ResizeObserver(q);
203
+ h.observe(i);
204
+ const C = i.querySelector("table");
205
+ return C && h.observe(C), () => h.disconnect();
206
206
  }, [q]);
207
- const [P, J] = n.useState(
207
+ const [L, J] = n.useState(
208
208
  null
209
209
  ), ee = n.useCallback(
210
210
  (i) => {
211
211
  J(
212
- (b) => b ?? Array.from(
212
+ (h) => h ?? Array.from(
213
213
  i.cells,
214
- (w) => w.getBoundingClientRect().width
214
+ (C) => C.getBoundingClientRect().width
215
215
  )
216
216
  );
217
217
  },
218
218
  []
219
- ), te = n.useCallback((i, b) => {
220
- J((w) => {
221
- if (!w) return w;
222
- const L = [...w];
223
- return L[i] = Math.max(Q, b), L;
219
+ ), te = n.useCallback((i, h) => {
220
+ J((C) => {
221
+ if (!C) return C;
222
+ const V = [...C];
223
+ return V[i] = Math.max(Y, h), V;
224
224
  });
225
225
  }, []), re = n.useCallback(
226
226
  () => J(null),
227
227
  []
228
- ), ge = n.useMemo(
228
+ ), he = n.useMemo(
229
229
  () => ({
230
230
  selectionMode: c,
231
231
  isSelected: D,
232
232
  toggleKey: $,
233
- toggleAll: I,
234
- allSelected: R,
235
- someSelected: W,
236
- isStatic: A,
233
+ toggleAll: M,
234
+ allSelected: A,
235
+ someSelected: I,
236
+ isStatic: z,
237
237
  sortDescriptor: l,
238
- requestSort: g ? S : void 0,
239
- automaticSorting: f,
240
- elevatedActionColumn: e,
241
- resizableColumns: E,
242
- columnWidths: P,
238
+ requestSort: g ? T : void 0,
239
+ automaticSorting: p,
240
+ elevatedActionColumn: t,
241
+ resizableColumns: S,
242
+ columnWidths: L,
243
243
  snapshotColumnWidths: ee,
244
244
  setColumnWidth: te,
245
245
  resetColumnWidths: re,
246
- stickyHeader: k != null
246
+ stickyHeader: m != null
247
247
  }),
248
248
  [
249
249
  c,
250
250
  D,
251
251
  $,
252
- I,
253
- R,
254
- W,
252
+ M,
255
253
  A,
254
+ I,
255
+ z,
256
256
  l,
257
257
  g,
258
- f,
258
+ p,
259
+ T,
260
+ t,
259
261
  S,
260
- e,
261
- E,
262
- P,
262
+ L,
263
263
  ee,
264
264
  te,
265
265
  re,
266
- k
266
+ m
267
267
  ]
268
268
  );
269
- return /* @__PURE__ */ d(de.Provider, { value: ge, children: /* @__PURE__ */ T(
269
+ return /* @__PURE__ */ u(de.Provider, { value: he, children: /* @__PURE__ */ W(
270
270
  "div",
271
271
  {
272
272
  "data-slot": "table-container",
273
273
  "data-scroll-left": F.left ? "true" : "false",
274
274
  "data-scroll-right": F.right ? "true" : "false",
275
- className: m(
275
+ className: f(
276
276
  "group/table-shell overflow-clip rounded-m border border-table-stroke bg-table-shell",
277
277
  "[--table-card-radius:var(--radius-m)]",
278
- t
278
+ e
279
279
  ),
280
280
  children: [
281
- a && /* @__PURE__ */ d(
281
+ a && /* @__PURE__ */ u(
282
282
  "div",
283
283
  {
284
284
  "data-slot": "table-toolbar",
@@ -286,65 +286,65 @@ const ze = n.forwardRef(
286
286
  children: a
287
287
  }
288
288
  ),
289
- /* @__PURE__ */ T(
289
+ /* @__PURE__ */ W(
290
290
  "div",
291
291
  {
292
292
  className: "relative",
293
- style: e ? {
294
- "--table-action-column-width": N
293
+ style: t ? {
294
+ "--table-action-column-width": b
295
295
  } : void 0,
296
296
  children: [
297
- /* @__PURE__ */ d(
297
+ /* @__PURE__ */ u(
298
298
  "div",
299
299
  {
300
- ref: M,
300
+ ref: P,
301
301
  onScroll: q,
302
- className: m(
302
+ className: f(
303
303
  "overflow-x-auto rounded-(--table-card-radius)",
304
- k != null && "overflow-y-auto"
304
+ m != null && "overflow-y-auto"
305
305
  ),
306
- style: k != null ? { maxHeight: k } : void 0,
307
- children: /* @__PURE__ */ T(
306
+ style: m != null ? { maxHeight: m } : void 0,
307
+ children: /* @__PURE__ */ W(
308
308
  "table",
309
309
  {
310
310
  ref: O,
311
311
  "data-slot": "table",
312
- className: m(
312
+ className: f(
313
313
  "w-full border-separate border-spacing-0 text-m font-normal",
314
314
  // Manual widths need fixed layout so the <colgroup> wins;
315
315
  // until the first resize the automatic layout is untouched.
316
- P && "table-fixed",
316
+ L && "table-fixed",
317
317
  r
318
318
  ),
319
- ..._,
319
+ ...E,
320
320
  children: [
321
- P && /* @__PURE__ */ d("colgroup", { children: P.map((i, b) => /* @__PURE__ */ d("col", { style: { width: i } }, b)) }),
321
+ L && /* @__PURE__ */ u("colgroup", { children: L.map((i, h) => /* @__PURE__ */ u("col", { style: { width: i } }, h)) }),
322
322
  j
323
323
  ]
324
324
  }
325
325
  )
326
326
  }
327
327
  ),
328
- /* @__PURE__ */ d(
328
+ /* @__PURE__ */ u(
329
329
  "div",
330
330
  {
331
331
  "aria-hidden": "true",
332
332
  "data-slot": "table-scroll-hint",
333
- className: m(
333
+ className: f(
334
334
  "pointer-events-none absolute inset-y-0 z-20 w-10",
335
335
  "bg-gradient-to-l from-(--table-scroll-hint) to-transparent",
336
336
  "opacity-0 transition-opacity duration-150 ease-out motion-reduce:transition-none",
337
337
  F.right && "opacity-100",
338
- e ? "right-[var(--table-action-column-width)]" : "right-0"
338
+ t ? "right-[var(--table-action-column-width)]" : "right-0"
339
339
  )
340
340
  }
341
341
  ),
342
- e && /* @__PURE__ */ d(
342
+ t && /* @__PURE__ */ u(
343
343
  "div",
344
344
  {
345
345
  "aria-hidden": "true",
346
346
  "data-slot": "table-action-column-elevation",
347
- className: m(
347
+ className: f(
348
348
  "pointer-events-none absolute inset-y-0 right-0 z-20",
349
349
  "w-[var(--table-action-column-width)]"
350
350
  // No shadow of its own: while columns hide behind the pinned
@@ -357,58 +357,74 @@ const ze = n.forwardRef(
357
357
  ]
358
358
  }
359
359
  ),
360
- o && /* @__PURE__ */ d("div", { className: "flex items-center border-t border-table-stroke px-4 py-2.5", children: o })
360
+ s && /* @__PURE__ */ u("div", { className: "flex items-center border-t border-table-stroke px-4 py-2.5", children: s })
361
361
  ]
362
362
  }
363
363
  ) });
364
364
  }
365
365
  );
366
366
  ze.displayName = "Table";
367
- const fe = n.forwardRef(({ className: r, ...t }, a) => {
368
- const o = B();
369
- return /* @__PURE__ */ d(Y.Provider, { value: "header", children: /* @__PURE__ */ d(
367
+ const fe = n.forwardRef(({ className: r, ...e }, a) => {
368
+ const s = B();
369
+ return /* @__PURE__ */ u(Z.Provider, { value: "header", children: /* @__PURE__ */ u(
370
370
  "thead",
371
371
  {
372
372
  ref: a,
373
- className: m(
373
+ className: f(
374
374
  "text-s font-medium text-table-header-foreground",
375
- (o == null ? void 0 : o.elevatedActionColumn) && "relative z-30 bg-wg1",
375
+ (s == null ? void 0 : s.elevatedActionColumn) && "relative z-30 bg-wg1",
376
376
  r
377
377
  ),
378
- ...t
378
+ ...e
379
379
  }
380
380
  ) });
381
381
  });
382
382
  fe.displayName = "TableHeader";
383
- const pe = n.forwardRef(({ className: r, ...t }, a) => /* @__PURE__ */ d(Y.Provider, { value: "body", children: /* @__PURE__ */ d("tbody", { ref: a, className: m(r), ...t }) }));
383
+ const pe = n.forwardRef(({ className: r, ...e }, a) => /* @__PURE__ */ u(Z.Provider, { value: "body", children: /* @__PURE__ */ u("tbody", { ref: a, className: f(r), ...e }) }));
384
384
  pe.displayName = "TableBody";
385
- const Z = n.forwardRef(
385
+ const K = n.forwardRef(
386
386
  ({
387
387
  className: r,
388
- rowKey: t,
388
+ rowKey: e,
389
389
  children: a,
390
- isInteractive: o = !1,
391
- onClick: s,
392
- role: c,
393
- ...u
394
- }, h) => {
395
- const p = B(), e = n.useContext(Y), N = !!p && p.selectionMode !== "none", x = e === "body" && !(p != null && p.isStatic) && (o || N || typeof s == "function" || c === "button" || u["aria-expanded"] !== void 0), y = N && e === "body" && t !== void 0 ? p.isSelected(t) : !1;
396
- return /* @__PURE__ */ d(ie.Provider, { value: x, children: /* @__PURE__ */ T(
390
+ isInteractive: s = !1,
391
+ onClick: o,
392
+ onKeyDown: c,
393
+ role: d,
394
+ tabIndex: v,
395
+ ...k
396
+ }, t) => {
397
+ const b = B(), x = n.useContext(Z), y = !!b && b.selectionMode !== "none", g = x === "body" && (typeof o == "function" || y && e !== void 0), z = x === "body" && !(b != null && b.isStatic) && (g || s), S = y && x === "body" && e !== void 0 ? b.isSelected(e) : !1;
398
+ return /* @__PURE__ */ u(ie.Provider, { value: z, children: /* @__PURE__ */ W(
397
399
  "tr",
398
400
  {
399
- ref: h,
400
- "data-interactive": x || void 0,
401
- "data-selected": y || void 0,
402
- className: m("group/row", e === "body" && "h-16", r),
403
- onClick: s,
404
- role: c,
405
- ...u,
401
+ ref: t,
402
+ "data-interactive": z || void 0,
403
+ "data-selected": S || void 0,
404
+ className: f(
405
+ "group/row",
406
+ x === "body" && "h-16",
407
+ g && "cursor-pointer outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring",
408
+ r
409
+ ),
410
+ onClick: (m) => {
411
+ const E = m.target;
412
+ E instanceof Element && E.closest(
413
+ "a, button, input, select, textarea, [role='button'], [role='link'], [contenteditable='true']"
414
+ ) || (o ? o(m) : y && e !== void 0 && (b == null || b.toggleKey(e)));
415
+ },
416
+ onKeyDown: (m) => {
417
+ c == null || c(m), !m.defaultPrevented && g && m.target === m.currentTarget && (m.key === "Enter" || m.key === " ") && (m.preventDefault(), m.currentTarget.click());
418
+ },
419
+ role: d,
420
+ tabIndex: v ?? (g ? 0 : void 0),
421
+ ...k,
406
422
  children: [
407
- N && (e === "header" ? /* @__PURE__ */ T(
423
+ y && (x === "header" ? /* @__PURE__ */ W(
408
424
  "th",
409
425
  {
410
426
  scope: "col",
411
- className: m(
427
+ className: f(
412
428
  "w-10 border-b border-table-stroke px-4 py-2.5",
413
429
  ue,
414
430
  // Sticky without the baked shadow — an always-on smudge
@@ -419,35 +435,35 @@ const Z = n.forwardRef(
419
435
  ce
420
436
  ),
421
437
  children: [
422
- /* @__PURE__ */ d("span", { className: "sr-only", children: "Row selection" }),
423
- p.selectionMode === "multiple" && /* @__PURE__ */ d(
438
+ /* @__PURE__ */ u("span", { className: "sr-only", children: "Row selection" }),
439
+ b.selectionMode === "multiple" && /* @__PURE__ */ u(
424
440
  ne,
425
441
  {
426
442
  size: "sm",
427
443
  "aria-label": "Select all rows",
428
- checked: p.allSelected,
429
- indeterminate: p.someSelected,
430
- onChange: p.toggleAll
444
+ checked: b.allSelected,
445
+ indeterminate: b.someSelected,
446
+ onChange: b.toggleAll
431
447
  }
432
448
  )
433
449
  ]
434
450
  }
435
- ) : /* @__PURE__ */ d(
451
+ ) : /* @__PURE__ */ u(
436
452
  "td",
437
453
  {
438
- className: m(
454
+ className: f(
439
455
  "h-16 w-10 px-4 py-2",
440
- le(x),
456
+ le(z),
441
457
  "sticky left-0 z-10"
442
458
  ),
443
- onClick: (g) => g.stopPropagation(),
444
- children: t !== void 0 && /* @__PURE__ */ d(
459
+ onClick: (m) => m.stopPropagation(),
460
+ children: e !== void 0 && /* @__PURE__ */ u(
445
461
  ne,
446
462
  {
447
463
  size: "sm",
448
- "aria-label": `Select ${t}`,
449
- checked: y,
450
- onChange: () => p.toggleKey(t)
464
+ "aria-label": `Select ${e}`,
465
+ checked: S,
466
+ onChange: () => b.toggleKey(e)
451
467
  }
452
468
  )
453
469
  }
@@ -458,61 +474,61 @@ const Z = n.forwardRef(
458
474
  ) });
459
475
  }
460
476
  );
461
- Z.displayName = "TableRow";
477
+ K.displayName = "TableRow";
462
478
  const be = n.forwardRef(
463
479
  ({
464
480
  className: r,
465
- align: t,
481
+ align: e,
466
482
  sticky: a,
467
- sortKey: o,
468
- allowsSorting: s = !0,
483
+ sortKey: s,
484
+ allowsSorting: o = !0,
469
485
  _sortColumnIndex: c,
470
- children: u,
471
- ...h
472
- }, p) => {
473
- var I, H, U;
474
- const e = B(), x = (e != null && e.automaticSorting && c !== void 0 ? `${G}${c}` : void 0) ?? o, y = Number(h.colSpan ?? 1) === 1, g = String(X(u)).trim(), A = g.length > 0, E = s && y && a !== "right" && A && !!x && !!(e != null && e.requestSort), k = E && ((I = e == null ? void 0 : e.sortDescriptor) == null ? void 0 : I.column) === x, _ = (H = e == null ? void 0 : e.sortDescriptor) == null ? void 0 : H.direction, O = !!(e != null && e.resizableColumns) && y && a !== "right", C = n.useRef(null), [z, v] = n.useState(!1), D = (f) => {
475
- if (f.button !== 0 || !e) return;
476
- const l = f.currentTarget.parentElement, S = l == null ? void 0 : l.parentElement;
477
- if (!(!l || !S)) {
478
- e.snapshotColumnWidths(S), C.current = {
486
+ children: d,
487
+ ...v
488
+ }, k) => {
489
+ var M, H, U;
490
+ const t = B(), x = (t != null && t.automaticSorting && c !== void 0 ? `${Q}${c}` : void 0) ?? s, y = Number(v.colSpan ?? 1) === 1, g = String(X(d)).trim(), z = g.length > 0, S = o && y && a !== "right" && z && !!x && !!(t != null && t.requestSort), m = S && ((M = t == null ? void 0 : t.sortDescriptor) == null ? void 0 : M.column) === x, E = (H = t == null ? void 0 : t.sortDescriptor) == null ? void 0 : H.direction, O = !!(t != null && t.resizableColumns) && y && a !== "right", N = n.useRef(null), [R, w] = n.useState(!1), D = (p) => {
491
+ if (p.button !== 0 || !t) return;
492
+ const l = p.currentTarget.parentElement, T = l == null ? void 0 : l.parentElement;
493
+ if (!(!l || !T)) {
494
+ t.snapshotColumnWidths(T), N.current = {
479
495
  index: l.cellIndex,
480
- startX: f.clientX,
496
+ startX: p.clientX,
481
497
  startWidth: l.getBoundingClientRect().width
482
- }, v(!0);
498
+ }, w(!0);
483
499
  try {
484
- f.currentTarget.setPointerCapture(f.pointerId);
500
+ p.currentTarget.setPointerCapture(p.pointerId);
485
501
  } catch {
486
502
  }
487
- f.preventDefault();
503
+ p.preventDefault();
488
504
  }
489
- }, R = (f) => {
490
- const l = C.current;
491
- !l || !e || e.setColumnWidth(
505
+ }, A = (p) => {
506
+ const l = N.current;
507
+ !l || !t || t.setColumnWidth(
492
508
  l.index,
493
- l.startWidth + (f.clientX - l.startX)
509
+ l.startWidth + (p.clientX - l.startX)
494
510
  );
495
- }, W = () => {
496
- C.current = null, v(!1);
497
- }, $ = (f) => {
498
- if (f.key !== "ArrowLeft" && f.key !== "ArrowRight" || !e) return;
499
- f.preventDefault();
500
- const l = f.currentTarget.parentElement, S = l == null ? void 0 : l.parentElement;
501
- if (!l || !S) return;
502
- e.snapshotColumnWidths(S);
503
- const j = f.shiftKey ? 32 : 8, M = f.key === "ArrowRight" ? j : -j;
504
- e.setColumnWidth(
511
+ }, I = () => {
512
+ N.current = null, w(!1);
513
+ }, $ = (p) => {
514
+ if (p.key !== "ArrowLeft" && p.key !== "ArrowRight" || !t) return;
515
+ p.preventDefault();
516
+ const l = p.currentTarget.parentElement, T = l == null ? void 0 : l.parentElement;
517
+ if (!l || !T) return;
518
+ t.snapshotColumnWidths(T);
519
+ const j = p.shiftKey ? 32 : 8, P = p.key === "ArrowRight" ? j : -j;
520
+ t.setColumnWidth(
505
521
  l.cellIndex,
506
- l.getBoundingClientRect().width + M
522
+ l.getBoundingClientRect().width + P
507
523
  );
508
524
  };
509
- return /* @__PURE__ */ T(
525
+ return /* @__PURE__ */ W(
510
526
  "th",
511
527
  {
512
- ref: p,
528
+ ref: k,
513
529
  scope: "col",
514
- "aria-sort": k ? _ === "ascending" ? "ascending" : "descending" : E ? "none" : void 0,
515
- className: m(
530
+ "aria-sort": m ? E === "ascending" ? "ascending" : "descending" : S ? "none" : void 0,
531
+ className: f(
516
532
  // whitespace-nowrap: header labels hug their content — the table
517
533
  // scrolls horizontally, so wrapping "Null %" to two lines only
518
534
  // wastes header height without saving any width.
@@ -524,9 +540,9 @@ const be = n.forwardRef(
524
540
  O && "after:hidden [&:last-child>[data-slot=resize-handle]]:hidden",
525
541
  // Capped-height tables scroll under the header: pin it to the
526
542
  // viewport top, painted WG1 so rows pass beneath.
527
- (e == null ? void 0 : e.stickyHeader) && "sticky top-0 z-30",
528
- se(t),
529
- a && (a === "right" && (e != null && e.elevatedActionColumn) ? m(
543
+ (t == null ? void 0 : t.stickyHeader) && "sticky top-0 z-30",
544
+ se(e),
545
+ a && (a === "right" && (t != null && t.elevatedActionColumn) ? f(
530
546
  // Preserve the semantic column width, but do not pin or paint
531
547
  // a blank header cell over the labels behind it. Only body
532
548
  // action cells participate in the sticky elevated surface.
@@ -538,54 +554,54 @@ const be = n.forwardRef(
538
554
  ) : ae(a)),
539
555
  r
540
556
  ),
541
- ...h,
557
+ ...v,
542
558
  children: [
543
- E ? /* @__PURE__ */ T(
559
+ S ? /* @__PURE__ */ W(
544
560
  "button",
545
561
  {
546
562
  type: "button",
547
- onClick: () => e.requestSort(x),
548
- className: m(
563
+ onClick: () => t.requestSort(x),
564
+ className: f(
549
565
  "group/sort -mx-1 inline-flex items-center gap-1 rounded px-1 outline-none transition-colors",
550
566
  "hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring",
551
- t === "right" && "flex-row-reverse",
552
- k && "font-medium"
567
+ e === "right" && "flex-row-reverse",
568
+ m && "font-medium"
553
569
  ),
554
570
  children: [
555
- u,
556
- k ? _ === "ascending" ? /* @__PURE__ */ d(ve, { className: "size-3.5" }) : /* @__PURE__ */ d(ye, { className: "size-3.5" }) : /* @__PURE__ */ d(we, { className: "size-3.5 opacity-0 transition-opacity group-hover/sort:opacity-60" })
571
+ d,
572
+ m ? E === "ascending" ? /* @__PURE__ */ u(ve, { className: "size-3.5" }) : /* @__PURE__ */ u(ye, { className: "size-3.5" }) : /* @__PURE__ */ u(we, { className: "size-3.5 opacity-0 transition-opacity group-hover/sort:opacity-60" })
557
573
  ]
558
574
  }
559
- ) : A ? u : /* @__PURE__ */ d("span", { className: "sr-only", children: h["aria-label"] ?? "Table column" }),
560
- O && /* @__PURE__ */ d(
575
+ ) : z ? d : /* @__PURE__ */ u("span", { className: "sr-only", children: v["aria-label"] ?? "Table column" }),
576
+ O && /* @__PURE__ */ u(
561
577
  "span",
562
578
  {
563
579
  "data-slot": "resize-handle",
564
580
  role: "separator",
565
581
  "aria-orientation": "vertical",
566
582
  "aria-label": `Resize ${g || "this"} column`,
567
- "aria-valuemin": Q,
583
+ "aria-valuemin": Y,
568
584
  "aria-valuemax": 2e3,
569
- "aria-valuenow": ((U = e == null ? void 0 : e.columnWidths) == null ? void 0 : U[c ?? -1]) ?? Q,
585
+ "aria-valuenow": ((U = t == null ? void 0 : t.columnWidths) == null ? void 0 : U[c ?? -1]) ?? Y,
570
586
  tabIndex: 0,
571
- "data-resizing": z ? "true" : void 0,
587
+ "data-resizing": R ? "true" : void 0,
572
588
  onPointerDown: D,
573
- onPointerMove: R,
574
- onPointerUp: W,
575
- onPointerCancel: W,
589
+ onPointerMove: A,
590
+ onPointerUp: I,
591
+ onPointerCancel: I,
576
592
  onKeyDown: $,
577
- onDoubleClick: () => e == null ? void 0 : e.resetColumnWidths(),
578
- className: m(
593
+ onDoubleClick: () => t == null ? void 0 : t.resetColumnWidths(),
594
+ className: f(
579
595
  // 12px hit area straddling the column edge; the 1px tick inside
580
596
  // is the visible affordance (it replaces the decorative one).
581
597
  "group/resize absolute -right-1.5 top-0 z-10 flex h-full w-3 cursor-col-resize touch-none select-none items-center justify-center rounded-sm outline-none",
582
598
  "focus-visible:ring-2 focus-visible:ring-ring"
583
599
  ),
584
- children: /* @__PURE__ */ d(
600
+ children: /* @__PURE__ */ u(
585
601
  "span",
586
602
  {
587
603
  "aria-hidden": "true",
588
- className: m(
604
+ className: f(
589
605
  "h-4 w-px rounded-sm bg-border-strong",
590
606
  "transition-[transform,background-color] duration-150 ease-out motion-reduce:transition-none",
591
607
  "group-hover/resize:scale-y-125 group-hover/resize:bg-foreground/60",
@@ -603,14 +619,14 @@ const be = n.forwardRef(
603
619
  );
604
620
  be.displayName = "TableColumn";
605
621
  const Se = n.forwardRef(
606
- ({ className: r, align: t, sticky: a, sortValue: o, ...s }, c) => {
607
- const u = B(), h = n.useContext(ie), p = a === "right" && (u == null ? void 0 : u.elevatedActionColumn);
608
- return /* @__PURE__ */ d(
622
+ ({ className: r, align: e, sticky: a, sortValue: s, ...o }, c) => {
623
+ const d = B(), v = n.useContext(ie), k = a === "right" && (d == null ? void 0 : d.elevatedActionColumn);
624
+ return /* @__PURE__ */ u(
609
625
  "td",
610
626
  {
611
627
  ref: c,
612
- "data-sort-value": o instanceof Date ? o.toISOString() : o,
613
- className: m(
628
+ "data-sort-value": s instanceof Date ? s.toISOString() : s,
629
+ className: f(
614
630
  // whitespace-nowrap: cell content never wraps — the table's
615
631
  // overflow-x-auto viewport scrolls horizontally instead, matching the
616
632
  // header cells. Opt back into wrapping with `whitespace-normal` for
@@ -618,10 +634,10 @@ const Se = n.forwardRef(
618
634
  // Cell values own the ADS 14px body-text contract instead of relying
619
635
  // on inheritance from <Table>; nested content stays 14px by default.
620
636
  "h-16 whitespace-nowrap px-4 py-2 text-m",
621
- le(h),
622
- se(t),
623
- a && ae(a, u == null ? void 0 : u.elevatedActionColumn),
624
- p && m(
637
+ le(v),
638
+ se(e),
639
+ a && ae(a, d == null ? void 0 : d.elevatedActionColumn),
640
+ k && f(
625
641
  "w-[var(--table-action-column-width)]",
626
642
  "min-w-[var(--table-action-column-width)]",
627
643
  "max-w-[var(--table-action-column-width)]",
@@ -632,7 +648,7 @@ const Se = n.forwardRef(
632
648
  ),
633
649
  r
634
650
  ),
635
- ...s
651
+ ...o
636
652
  }
637
653
  );
638
654
  }
@@ -644,5 +660,5 @@ export {
644
660
  Se as TableCell,
645
661
  be as TableColumn,
646
662
  fe as TableHeader,
647
- Z as TableRow
663
+ K as TableRow
648
664
  };
package/llms.txt CHANGED
@@ -456,7 +456,7 @@ Before using any component below, preserve its built-in motion and apply the mot
456
456
  - [SeriesChart] — component [docs](https://ads.actioneer.dev/#/viz-charts)
457
457
  - [StatusAnswer] — component (variants: tone: default|primary|success|warning|danger|info) [docs](https://ads.actioneer.dev/#/ai/answer)
458
458
  - [Tab] — component (variants: orientation: horizontal|vertical; selected: true|false) [docs](https://ads.actioneer.dev/#/tabs)
459
- - [Table] — Use Table for structured tabular data that may need row selection, column sorting, sticky columns, or a paginated footer — not for simple key-value lists. Every primary body-cell value defaults to text-m (14px / 20px); only clearly secondary metadata inside a cell may opt down to text-s. Interactive rows inherit the shared soft neutral hover/focus sink and keep their normal table geometry; do not add a brand tint or hover-only corner rounding. Primary record links stay text-only in every state: never reveal an arrow, chevron, or other directional icon only on hover. Persistent row actions use a final sticky-right column plus elevatedActionColumn so one body-column shadow lifts the action surface instead of repeating on individual cells. The empty matching header cell remains transparent and non-sticky. [docs](https://ads.actioneer.dev/#/table)
459
+ - [Table] — Use Table for structured tabular data that may need row selection, column sorting, sticky columns, or a paginated footer — not for simple key-value lists. Every primary body-cell value defaults to text-m (14px / 20px); only clearly secondary metadata inside a cell may opt down to text-s. Give a whole-row action an onClick and aria-label: TableRow then adds hover/focus feedback, a pointer cursor, and Enter/Space activation. The consumer decides whether that action navigates or opens a panel; TableRow owns neither destination. Display-only rows stay static; selection rows toggle when clicked. Keep normal row geometry without a brand tint or hover-only corner rounding. Nested controls keep their own actions. Primary record links stay text-only in every state: never reveal an arrow, chevron, or other directional icon only on hover. Persistent row actions use a final sticky-right column plus elevatedActionColumn so one body-column shadow lifts the action surface instead of repeating on individual cells. The empty matching header cell remains transparent and non-sticky. [docs](https://ads.actioneer.dev/#/table)
460
460
  - [TableAnswer] — component (variants: tone: default|primary|success|warning|danger|info) [docs](https://ads.actioneer.dev/#/ai/answer)
461
461
  - [TableBody] — component [docs](https://ads.actioneer.dev/#/table)
462
462
  - [TableCell] — component [docs](https://ads.actioneer.dev/#/table)
package/manifest.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@actioneer/ads",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "importPath": "@actioneer/ads",
5
5
  "styleImport": "@import \"@actioneer/ads/styles.css\";",
6
6
  "families": [
@@ -3613,7 +3613,7 @@
3613
3613
  "kind": "component",
3614
3614
  "importPath": "@actioneer/ads",
3615
3615
  "module": "table",
3616
- "description": "Use Table for structured tabular data that may need row selection, column sorting, sticky columns, or a paginated footer — not for simple key-value lists. Every primary body-cell value defaults to text-m (14px / 20px); only clearly secondary metadata inside a cell may opt down to text-s. Interactive rows inherit the shared soft neutral hover/focus sink and keep their normal table geometry; do not add a brand tint or hover-only corner rounding. Primary record links stay text-only in every state: never reveal an arrow, chevron, or other directional icon only on hover. Persistent row actions use a final sticky-right column plus elevatedActionColumn so one body-column shadow lifts the action surface instead of repeating on individual cells. The empty matching header cell remains transparent and non-sticky.",
3616
+ "description": "Use Table for structured tabular data that may need row selection, column sorting, sticky columns, or a paginated footer — not for simple key-value lists. Every primary body-cell value defaults to text-m (14px / 20px); only clearly secondary metadata inside a cell may opt down to text-s. Give a whole-row action an onClick and aria-label: TableRow then adds hover/focus feedback, a pointer cursor, and Enter/Space activation. The consumer decides whether that action navigates or opens a panel; TableRow owns neither destination. Display-only rows stay static; selection rows toggle when clicked. Keep normal row geometry without a brand tint or hover-only corner rounding. Nested controls keep their own actions. Primary record links stay text-only in every state: never reveal an arrow, chevron, or other directional icon only on hover. Persistent row actions use a final sticky-right column plus elevatedActionColumn so one body-column shadow lifts the action surface instead of repeating on individual cells. The empty matching header cell remains transparent and non-sticky.",
3617
3617
  "showcaseUrl": "https://ads.actioneer.dev/#/table",
3618
3618
  "props": [
3619
3619
  "wrapperClassName",
@@ -8923,6 +8923,7 @@
8923
8923
  "constraints": [
8924
8924
  "TableHeader contains TableRow; never place TableColumn directly under TableHeader.",
8925
8925
  "Keep header and body column counts aligned.",
8926
+ "Only give rows hover feedback when clicking the whole row selects it or opens a detail page or panel; actionable rows need an accessible destination label.",
8926
8927
  "Use a sticky-right actions column plus elevatedActionColumn when every row has persistent actions."
8927
8928
  ],
8928
8929
  "principles": [
@@ -14036,7 +14037,7 @@
14036
14037
  "family": "Data display",
14037
14038
  "module": "table",
14038
14039
  "showcaseUrl": "https://ads.actioneer.dev/#/table",
14039
- "description": "Use Table for structured tabular data that may need row selection, column sorting, sticky columns, or a paginated footer — not for simple key-value lists. Every primary body-cell value defaults to text-m (14px / 20px); only clearly secondary metadata inside a cell may opt down to text-s. Interactive rows inherit the shared soft neutral hover/focus sink and keep their normal table geometry; do not add a brand tint or hover-only corner rounding. Primary record links stay text-only in every state: never reveal an arrow, chevron, or other directional icon only on hover. Persistent row actions use a final sticky-right column plus elevatedActionColumn so one body-column shadow lifts the action surface instead of repeating on individual cells. The empty matching header cell remains transparent and non-sticky."
14040
+ "description": "Use Table for structured tabular data that may need row selection, column sorting, sticky columns, or a paginated footer — not for simple key-value lists. Every primary body-cell value defaults to text-m (14px / 20px); only clearly secondary metadata inside a cell may opt down to text-s. Give a whole-row action an onClick and aria-label: TableRow then adds hover/focus feedback, a pointer cursor, and Enter/Space activation. The consumer decides whether that action navigates or opens a panel; TableRow owns neither destination. Display-only rows stay static; selection rows toggle when clicked. Keep normal row geometry without a brand tint or hover-only corner rounding. Nested controls keep their own actions. Primary record links stay text-only in every state: never reveal an arrow, chevron, or other directional icon only on hover. Persistent row actions use a final sticky-right column plus elevatedActionColumn so one body-column shadow lifts the action surface instead of repeating on individual cells. The empty matching header cell remains transparent and non-sticky."
14040
14041
  },
14041
14042
  {
14042
14043
  "id": "component:TableAnswer",
@@ -18127,6 +18128,7 @@
18127
18128
  "constraints": [
18128
18129
  "TableHeader contains TableRow; never place TableColumn directly under TableHeader.",
18129
18130
  "Keep header and body column counts aligned.",
18131
+ "Only give rows hover feedback when clicking the whole row selects it or opens a detail page or panel; actionable rows need an accessible destination label.",
18130
18132
  "Use a sticky-right actions column plus elevatedActionColumn when every row has persistent actions."
18131
18133
  ]
18132
18134
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@actioneer/ads",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Actioneer Design System 1.0 — React 19 + Tailwind v4 component library.",
5
5
  "type": "module",
6
6
  "sideEffects": [
package/styles.css CHANGED
@@ -513,8 +513,8 @@
513
513
  --brand-hover: var(--color-wg11); /* lighter hover lift */
514
514
  --brand-text: var(--color-wg12); /* action text / links */
515
515
 
516
- /* Interactive row hover/focus uses the WG3 highlight wash. */
517
- --table-row-hover: var(--color-wg3);
516
+ /* Interactive row hover/focus uses the WG2 highlight wash. */
517
+ --table-row-hover: var(--color-wg2);
518
518
  --table-row-selected: var(--color-wg1);
519
519
 
520
520
  /* Quiet component fill. WG3 is the first interactive-background
package/theme.css CHANGED
@@ -482,8 +482,8 @@
482
482
  --brand-hover: var(--color-wg11); /* lighter hover lift */
483
483
  --brand-text: var(--color-wg12); /* action text / links */
484
484
 
485
- /* Interactive row hover/focus uses the WG3 highlight wash. */
486
- --table-row-hover: var(--color-wg3);
485
+ /* Interactive row hover/focus uses the WG2 highlight wash. */
486
+ --table-row-hover: var(--color-wg2);
487
487
  --table-row-selected: var(--color-wg1);
488
488
 
489
489
  /* Quiet component fill. WG3 is the first interactive-background