@jirawatpyk/aura-react 5.12.0 → 5.13.0

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.
@@ -156,6 +156,7 @@ const DataTableImpl = React.forwardRef(function DataTable(props, ref) {
156
156
  [measure, levelShape]
157
157
  );
158
158
  const stacked = !!props.stackBelow && boxWidth[0] != null && below(boxWidth[0], props.stackBelow);
159
+ const noCardSel = !!props.hideSelectionInCards && selectable;
159
160
  useIsoLayoutEffect(
160
161
  function() {
161
162
  if (measure && wrapRef.current) boxWidth[1](wrapRef.current.getBoundingClientRect().width);
@@ -256,9 +257,38 @@ const DataTableImpl = React.forwardRef(function DataTable(props, ref) {
256
257
  const pillKey = (vis.filter(function(c, i) {
257
258
  return i > 0 && c.pill;
258
259
  })[0] || { key: "" }).key;
260
+ const ownTitle = vis.some(function(c) {
261
+ return c.card === "title";
262
+ }), ownPill = vis.some(function(c) {
263
+ return c.card === "pill";
264
+ });
265
+ let autoTitle = -1;
266
+ if (!ownTitle) {
267
+ for (let i = 0; i < vis.length; i++)
268
+ if (!vis[i].card && (i === 0 || !vis[i].actions)) {
269
+ autoTitle = i;
270
+ break;
271
+ }
272
+ }
259
273
  function cardPart(c, i) {
260
- return i === 0 ? "title" : c.key === pillKey ? "pill" : c.actions ? "actions" : "field";
274
+ if (c.card) return c.card;
275
+ if (i === autoTitle) return "title";
276
+ if (c.key === pillKey && !ownPill) return "pill";
277
+ return c.actions ? "actions" : "field";
261
278
  }
279
+ const cardRank = {};
280
+ if (vis.some(function(c) {
281
+ return c.cardOrder != null;
282
+ }))
283
+ vis.map(function(c, i) {
284
+ return { c, i, o: c.cardOrder != null ? c.cardOrder : i };
285
+ }).filter(function(x) {
286
+ return cardPart(x.c, x.i) === "field";
287
+ }).sort(function(a, b) {
288
+ return a.o - b.o || a.i - b.i;
289
+ }).forEach(function(x, n) {
290
+ cardRank[x.c.key] = n;
291
+ });
262
292
  function cardAttrs(c, i) {
263
293
  const part = cardPart(c, i), lv = hideLevel(c);
264
294
  return {
@@ -300,6 +330,7 @@ const DataTableImpl = React.forwardRef(function DataTable(props, ref) {
300
330
  s["--aura-cell-w"] = w + "px";
301
331
  }
302
332
  if (isPinned(c)) s["--aura-cell-left"] = "calc(var(--aura-space-6)" + selW + " + " + pinOffsets[c.key] + ")";
333
+ if (cardRank[c.key] != null) s["--aura-card-order"] = String(5 + cardRank[c.key]);
303
334
  return s;
304
335
  }
305
336
  const sortCol = sort && sort.key ? byKey[sort.key] : void 0;
@@ -440,9 +471,37 @@ const DataTableImpl = React.forwardRef(function DataTable(props, ref) {
440
471
  function colAt(ci) {
441
472
  return selectable ? ci === 0 ? null : vis[ci - 1] : vis[ci];
442
473
  }
474
+ const cardHidden = [];
475
+ for (let ci = 0; ci < nCols; ci++) {
476
+ const col = colAt(ci);
477
+ cardHidden.push(stacked && (col ? cardPart(col, vis.indexOf(col)) === "hide" : noCardSel));
478
+ }
479
+ function nearestShown(c, dir, ok) {
480
+ if (ok(c)) return c;
481
+ for (let d = 1; d < nCols; d++) {
482
+ const a = c + d * dir, b = c - d * dir;
483
+ if (a >= 0 && a < nCols && ok(a)) return a;
484
+ if (b >= 0 && b < nCols && ok(b)) return b;
485
+ }
486
+ return c;
487
+ }
488
+ const acShown = nearestShown(ac, 1, function(cc) {
489
+ return !cardHidden[cc];
490
+ });
491
+ const lastFocus = React.useRef(null);
492
+ React.useEffect(
493
+ function() {
494
+ const was = lastFocus.current, g = gridRef.current;
495
+ if (!stacked || !was || !g || !g.contains(was) || was.getClientRects().length > 0) return;
496
+ if (document.activeElement && document.activeElement !== document.body && document.activeElement !== was) return;
497
+ const el = g.querySelector('[data-rc="' + Math.max(1, ar) + ":" + acShown + '"]');
498
+ if (el && el.getClientRects().length > 0) el.focus();
499
+ },
500
+ [stacked]
501
+ );
443
502
  function tabFor(r, c) {
444
503
  if (!activeRendered) return r === 0 && c === ac ? 0 : -1;
445
- return r === ar && c === ac ? 0 : -1;
504
+ return r === ar && c === acShown ? 0 : -1;
446
505
  }
447
506
  React.useEffect(function() {
448
507
  const p = pending.current;
@@ -466,26 +525,17 @@ const DataTableImpl = React.forwardRef(function DataTable(props, ref) {
466
525
  el.focus();
467
526
  }
468
527
  });
469
- function focusCell(r, c) {
528
+ function focusCell(r, c, dir) {
470
529
  r = Math.max(0, Math.min(r, lastR));
471
530
  c = Math.max(0, Math.min(c, nCols - 1));
472
- if (stacked && r === 0 && nRows > 0 && !(selectable && c === 0)) r = 1;
473
- if (gridRef.current && r === T && hasTotal) {
531
+ if (stacked && r === 0 && nRows > 0 && (!(selectable && c === 0) || noCardSel)) r = 1;
532
+ if (gridRef.current && (r === T && hasTotal || stacked)) {
474
533
  const shown2 = function(cc) {
534
+ if (cardHidden[cc]) return false;
475
535
  const e = gridRef.current.querySelector('[data-rc="' + r + ":" + cc + '"]');
476
536
  return !!e && e.getClientRects().length > 0;
477
537
  };
478
- if (!shown2(c))
479
- for (let d = 1; d < nCols; d++) {
480
- if (c + d < nCols && shown2(c + d)) {
481
- c = c + d;
482
- break;
483
- }
484
- if (c - d >= 0 && shown2(c - d)) {
485
- c = c - d;
486
- break;
487
- }
488
- }
538
+ c = nearestShown(c, dir || 1, shown2);
489
539
  }
490
540
  activeState[1]({ r, c });
491
541
  pending.current = { r, c };
@@ -745,7 +795,7 @@ const DataTableImpl = React.forwardRef(function DataTable(props, ref) {
745
795
  } else if (r === 0 && col && (e.altKey && k === "ArrowDown" || k === "ContextMenu" || e.shiftKey && k === "F10") && controls)
746
796
  openMenu("col", col.key, target, { r: 0, c });
747
797
  else if (k === "ArrowRight") focusCell(r, c + 1);
748
- else if (k === "ArrowLeft") focusCell(r, c - 1);
798
+ else if (k === "ArrowLeft") focusCell(r, c - 1, -1);
749
799
  else if (k === "ArrowDown") {
750
800
  if (r < lastR) focusCell(r + 1, c);
751
801
  else if (pageSize && page < pageCount && goPage(page + 1, { r: 1, c })) activeState[1]({ r: 1, c });
@@ -753,7 +803,7 @@ const DataTableImpl = React.forwardRef(function DataTable(props, ref) {
753
803
  if (r > 1 || r === 1 && !(pageSize && page > 1)) focusCell(r - 1, c);
754
804
  else if (r === 1 && goPage(page - 1, { r: pageSize, c })) activeState[1]({ r: pageSize, c });
755
805
  } else if (k === "Home") focusCell(e.ctrlKey ? 1 : r, 0);
756
- else if (k === "End") focusCell(e.ctrlKey ? lastR : r, nCols - 1);
806
+ else if (k === "End") focusCell(e.ctrlKey ? lastR : r, nCols - 1, -1);
757
807
  else if (k === "PageDown") {
758
808
  if (pageSize) {
759
809
  if (goPage(page + 1, { r: 1, c })) activeState[1]({ r: 1, c });
@@ -773,7 +823,7 @@ const DataTableImpl = React.forwardRef(function DataTable(props, ref) {
773
823
  if (pageKeys.length) toggleAll();
774
824
  } else if (r === 0 && col && col.sortable && canSortAny) sortBy(col.key);
775
825
  else if (r > 0 && k === " " && selectable) {
776
- if (canSelect(row)) toggle(row[rowKey], !selSet[row[rowKey]]);
826
+ if (canSelect(row) && !(stacked && noCardSel)) toggle(row[rowKey], !selSet[row[rowKey]]);
777
827
  } else if (r > 0 && k === "Enter" && rowHref && !target.querySelector("button, a[href]:not(.aura-table__row-link), input, select, textarea"))
778
828
  followRow(target.closest('[role="row"]'), e);
779
829
  else if (r > 0 && k === "Enter" && target.querySelector("button, a[href], input, select, textarea"))
@@ -833,6 +883,7 @@ const DataTableImpl = React.forwardRef(function DataTable(props, ref) {
833
883
  "aria-colindex": ci + 1,
834
884
  style: cellStyle(c, i),
835
885
  "data-hide": hideLevel(c) ? String(hideLevel(c)) : void 0,
886
+ "data-card": cardPart(c, i) === "hide" ? "hide" : void 0,
836
887
  tabIndex: tabFor(0, ci),
837
888
  "data-rc": "0:" + ci,
838
889
  className: cx(
@@ -1198,7 +1249,7 @@ const DataTableImpl = React.forwardRef(function DataTable(props, ref) {
1198
1249
  ),
1199
1250
  style: cellStyle(c, j),
1200
1251
  ...cardAttrs(c, j),
1201
- "data-label": j === 0 ? void 0 : c.label || t.totals
1252
+ "data-label": cardPart(c, j) === "title" ? void 0 : c.label || t.totals
1202
1253
  },
1203
1254
  props.footer[c.key]
1204
1255
  );
@@ -1226,6 +1277,7 @@ const DataTableImpl = React.forwardRef(function DataTable(props, ref) {
1226
1277
  className: cx(
1227
1278
  "aura-table",
1228
1279
  stacked && "aura-table--stacked",
1280
+ noCardSel && "aura-table--cards-nosel",
1229
1281
  scrolledX[0] && "is-scrolled-x",
1230
1282
  refreshing && "is-refreshing",
1231
1283
  !levels.length && props.className
@@ -1243,8 +1295,16 @@ const DataTableImpl = React.forwardRef(function DataTable(props, ref) {
1243
1295
  className: "aura-table__scroll",
1244
1296
  onMouseOver: showFull,
1245
1297
  onMouseLeave: hideFull,
1246
- onFocus: showFull,
1247
- onBlur: hideFull,
1298
+ onFocus: function(e) {
1299
+ lastFocus.current = e.target;
1300
+ showFull(e);
1301
+ },
1302
+ onBlur: function(e) {
1303
+ const to = e.relatedTarget;
1304
+ if ((!to || !e.currentTarget.contains(to)) && e.target.getClientRects().length > 0)
1305
+ lastFocus.current = null;
1306
+ hideFull();
1307
+ },
1248
1308
  style: scrollStyle,
1249
1309
  role: "grid",
1250
1310
  "aria-label": props.label,
package/dist/esm/Table.js CHANGED
@@ -47,7 +47,7 @@ function headerLabels(children) {
47
47
  return out;
48
48
  }
49
49
  const Table = React.forwardRef(function Table2(props, ref) {
50
- const { caption, captionHidden, density, stackBelow, className, children, ...rest } = props;
50
+ const { caption, captionHidden, density, stackBelow, align, bordered, className, children, ...rest } = props;
51
51
  const labels = stackBelow ? headerLabels(children) : null;
52
52
  if (labels && !labels.length)
53
53
  devWarnOnce(
@@ -75,7 +75,7 @@ const Table = React.forwardRef(function Table2(props, ref) {
75
75
  "div",
76
76
  {
77
77
  ref: wrap,
78
- className: cx("aura-tbl-wrap", stackBelow && "is-stackable"),
78
+ className: cx("aura-tbl-wrap", stackBelow && "is-stackable", bordered === false && "is-flush"),
79
79
  "data-density": density,
80
80
  tabIndex: scrolls ? 0 : void 0,
81
81
  role: scrolls && (caption != null || rest["aria-label"]) ? "region" : void 0,
@@ -86,7 +86,12 @@ const Table = React.forwardRef(function Table2(props, ref) {
86
86
  "table",
87
87
  {
88
88
  ref,
89
- className: cx("aura-tbl", stackBelow && "aura-tbl--stack-" + stackBelow, className),
89
+ className: cx(
90
+ "aura-tbl",
91
+ stackBelow && "aura-tbl--stack-" + stackBelow,
92
+ align === "middle" && "aura-tbl--middle",
93
+ className
94
+ ),
90
95
  role: stackBelow ? "table" : void 0,
91
96
  ...rest
92
97
  },
@@ -134,7 +139,7 @@ function cellClass(base, p) {
134
139
  );
135
140
  }
136
141
  const Th = React.forwardRef(function Th2(props, ref) {
137
- const { align, numeric, mono, className, scope, label, ...rest } = props;
142
+ const { align, numeric, mono, className, scope, label, card, ...rest } = props;
138
143
  const stacked = React.useContext(StackLabels) != null;
139
144
  return /* @__PURE__ */ React.createElement(
140
145
  "th",
@@ -143,14 +148,16 @@ const Th = React.forwardRef(function Th2(props, ref) {
143
148
  scope: scope || "col",
144
149
  className: cellClass("aura-tbl__th", props),
145
150
  role: stacked ? scope === "row" ? "rowheader" : "columnheader" : void 0,
151
+ "data-card": stacked && (card === "title" || card === "action") ? card : void 0,
146
152
  ...rest
147
153
  }
148
154
  );
149
155
  });
150
156
  const Td = React.forwardRef(function Td2(props, ref) {
151
- const { align, numeric, mono, className, scope, label, ...rest } = props;
157
+ const { align, numeric, mono, className, scope, label, card, ...rest } = props;
152
158
  const labels = React.useContext(StackLabels), col = React.useContext(ColumnIndex);
153
- const shown = labels ? label != null ? label : col >= 0 ? labels[col] : void 0 : void 0;
159
+ const slot = labels && (card === "title" || card === "action") ? card : void 0;
160
+ const shown = labels && !slot ? label != null ? label : col >= 0 ? labels[col] : void 0 : void 0;
154
161
  return /* @__PURE__ */ React.createElement(
155
162
  "td",
156
163
  {
@@ -158,6 +165,7 @@ const Td = React.forwardRef(function Td2(props, ref) {
158
165
  className: cellClass("aura-tbl__td", props),
159
166
  role: labels ? "cell" : void 0,
160
167
  "data-label": shown || void 0,
168
+ "data-card": slot,
161
169
  ...rest
162
170
  }
163
171
  );
@@ -102,11 +102,30 @@ function badgeElement(props, ref) {
102
102
  }
103
103
  function emptyStateElement(props, ref) {
104
104
  const HT = "h" + (props.headingLevel || 3);
105
+ const rest = omit(props, [
106
+ "title",
107
+ "description",
108
+ "icon",
109
+ "action",
110
+ "size",
111
+ "bordered",
112
+ "headingLevel",
113
+ "tone",
114
+ "className",
115
+ "children"
116
+ ]);
105
117
  return /* @__PURE__ */ React.createElement(
106
118
  "div",
107
119
  {
120
+ ...rest,
108
121
  ref,
109
- className: cx("aura-empty", props.size === "sm" && "is-sm", props.bordered && "is-bordered", props.className)
122
+ className: cx(
123
+ "aura-empty",
124
+ props.size === "sm" && "is-sm",
125
+ props.bordered && "is-bordered",
126
+ props.tone === "danger" && "is-danger",
127
+ props.className
128
+ )
110
129
  },
111
130
  /* @__PURE__ */ React.createElement("span", { className: "aura-empty__icon", "aria-hidden": true }, /* @__PURE__ */ React.createElement(Icon, { name: props.icon || /* @__PURE__ */ React.createElement(IconInbox, null), size: props.size === "sm" ? "md" : "lg" })),
112
131
  /* @__PURE__ */ React.createElement(HT, { className: "aura-empty__title" }, props.title),
package/dist/index.d.cts CHANGED
@@ -89,6 +89,13 @@ export interface DataTableColumn<Row extends Record<string, any> = Record<string
89
89
  hideBelow?: number | "sm" | "md" | "lg" | "xl" | undefined;
90
90
  /** Row actions (a DropdownMenu or IconButton). In stacked cards it sits top-right instead of in the field list. Give it an empty label. */
91
91
  actions?: boolean | undefined;
92
+ /** Its place in a stacked card (5.13): `'hide'` leaves it out of the card (the grid keeps it), `'title'` / `'pill'`
93
+ * make it the card's title or the pill beside it (instead of the first column / first pill column), `'field'` a
94
+ * label/value field. Default: today's rule. */
95
+ card?: "hide" | "field" | "title" | "pill" | undefined;
96
+ /** The order of fields in a stacked card (5.13), lowest first; the grid's column order is unchanged. Fields
97
+ * without one sort by their column index (0-based). Screen readers and arrow keys follow the grid's order. */
98
+ cardOrder?: number | undefined;
92
99
  /** `end` right-aligns header and cells (amounts, counts) and uses tabular figures. Default `start`. */
93
100
  align?: "start" | "end" | undefined;
94
101
  }
@@ -178,6 +185,9 @@ export interface DataTableProps<Row extends Record<string, any> = Record<string,
178
185
  onRowActivate?: RowCallback<void, Row> | undefined;
179
186
  /** Fixed height in px: sticky header, and only the rows in view are rendered. */
180
187
  height?: number | undefined;
188
+ /** Stacked cards (`stackBelow`) without the row checkboxes and the select-all box (5.13). The grid keeps them and
189
+ * the selection is kept; Space doesn't change it while the cards show. */
190
+ hideSelectionInCards?: boolean | undefined;
181
191
  /** `'auto'` (5.11): rows grow to fit content that wraps (two badges, a long name); cells stay vertically centred and
182
192
  * rows keep at least the density's row height. Needs every row in the DOM, so it is ignored with `height`
183
193
  * (virtualized rows are one fixed height). Default: one fixed-height line per row, long text ends in an ellipsis. */
@@ -387,6 +397,7 @@ export interface FilterBarProps {
387
397
  onSearchChange?: ((value: string) => void) | undefined;
388
398
  /** ms to wait after the last keystroke. Default 300. */
389
399
  searchDelay?: number | undefined;
400
+ /** The search field's name. Default "Search". */
390
401
  searchLabel?: string | undefined;
391
402
  searchPlaceholder?: string | undefined;
392
403
  /** Filter controls beside the search: Select, SegmentedControl, a Popover of options… */
@@ -996,7 +1007,7 @@ export interface SeparatorProps {
996
1007
  spacing?: 1 | 2 | 3 | 4 | 5 | 6 | 8 | undefined;
997
1008
  className?: string | undefined;
998
1009
  }
999
- export interface TableProps extends Omit<React$1.TableHTMLAttributes<HTMLTableElement>, "className"> {
1010
+ export interface TableProps extends Omit<React$1.TableHTMLAttributes<HTMLTableElement>, "className" | "align"> {
1000
1011
  /** The table's name (a `<caption>`). Give every table one; `captionHidden` keeps it for screen readers only. */
1001
1012
  caption?: React$1.ReactNode | undefined;
1002
1013
  captionHidden?: boolean | undefined;
@@ -1006,6 +1017,11 @@ export interface TableProps extends Omit<React$1.TableHTMLAttributes<HTMLTableEl
1006
1017
  * cell shows its column's header as a label: a `Td`'s `label`, else the text of the matching `Th` in `THead`.
1007
1018
  * Done in CSS (a container query), so the server's HTML is already right; table semantics are kept. */
1008
1019
  stackBelow?: "sm" | "md" | undefined;
1020
+ /** `middle` centres every body and footer cell on its row (5.13); default `top`, so wrapped text starts level. */
1021
+ align?: "top" | "middle" | undefined;
1022
+ /** `false` (5.13) drops the frame — border, radius, background — and the outer cells' side padding, so the table
1023
+ * lines up with the content around it, e.g. flush inside a Card under its heading. Default `true`. */
1024
+ bordered?: boolean | undefined;
1009
1025
  className?: string | undefined;
1010
1026
  children?: React$1.ReactNode | undefined;
1011
1027
  }
@@ -1026,6 +1042,10 @@ export interface TableCellProps extends Omit<React$1.TdHTMLAttributes<HTMLTableC
1026
1042
  scope?: "col" | "row" | "colgroup" | "rowgroup" | undefined;
1027
1043
  /** The label this cell shows when its table is stacked (`stackBelow`, 5.8). Default: the matching header's text. */
1028
1044
  label?: string | undefined;
1045
+ /** Its place in a stacked row (5.13), on a Td or a row header (`Th scope="row"`). `title` takes the first line,
1046
+ * without a label; `action` sits at the end of that line at its natural size; `field` (default) is a labelled field,
1047
+ * two to a line under them. */
1048
+ card?: "title" | "action" | "field" | undefined;
1029
1049
  className?: string | undefined;
1030
1050
  }
1031
1051
  export interface ActionBarProps {
@@ -1201,7 +1221,7 @@ export interface SkeletonProps {
1201
1221
  size?: number | undefined;
1202
1222
  className?: string | undefined;
1203
1223
  }
1204
- export interface EmptyStateProps {
1224
+ export interface EmptyStateProps extends Omit<React$1.HTMLAttributes<HTMLDivElement>, "title" | "children"> {
1205
1225
  title: React$1.ReactNode;
1206
1226
  description?: React$1.ReactNode | undefined;
1207
1227
  icon?: IconInput | undefined;
@@ -1209,6 +1229,9 @@ export interface EmptyStateProps {
1209
1229
  action?: React$1.ReactNode | undefined;
1210
1230
  size?: "sm" | "md" | undefined;
1211
1231
  bordered?: boolean | undefined;
1232
+ /** `danger` (5.13) for a failure — the data couldn't load: the danger tint, a danger-coloured icon, and a solid
1233
+ * danger frame with `bordered`. It stays quiet; pass `role="alert"` if it must interrupt. Default `neutral`. */
1234
+ tone?: "neutral" | "danger" | undefined;
1212
1235
  headingLevel?: 2 | 3 | 4 | 5 | 6 | undefined;
1213
1236
  className?: string | undefined;
1214
1237
  }
package/dist/index.d.ts CHANGED
@@ -89,6 +89,13 @@ export interface DataTableColumn<Row extends Record<string, any> = Record<string
89
89
  hideBelow?: number | "sm" | "md" | "lg" | "xl" | undefined;
90
90
  /** Row actions (a DropdownMenu or IconButton). In stacked cards it sits top-right instead of in the field list. Give it an empty label. */
91
91
  actions?: boolean | undefined;
92
+ /** Its place in a stacked card (5.13): `'hide'` leaves it out of the card (the grid keeps it), `'title'` / `'pill'`
93
+ * make it the card's title or the pill beside it (instead of the first column / first pill column), `'field'` a
94
+ * label/value field. Default: today's rule. */
95
+ card?: "hide" | "field" | "title" | "pill" | undefined;
96
+ /** The order of fields in a stacked card (5.13), lowest first; the grid's column order is unchanged. Fields
97
+ * without one sort by their column index (0-based). Screen readers and arrow keys follow the grid's order. */
98
+ cardOrder?: number | undefined;
92
99
  /** `end` right-aligns header and cells (amounts, counts) and uses tabular figures. Default `start`. */
93
100
  align?: "start" | "end" | undefined;
94
101
  }
@@ -178,6 +185,9 @@ export interface DataTableProps<Row extends Record<string, any> = Record<string,
178
185
  onRowActivate?: RowCallback<void, Row> | undefined;
179
186
  /** Fixed height in px: sticky header, and only the rows in view are rendered. */
180
187
  height?: number | undefined;
188
+ /** Stacked cards (`stackBelow`) without the row checkboxes and the select-all box (5.13). The grid keeps them and
189
+ * the selection is kept; Space doesn't change it while the cards show. */
190
+ hideSelectionInCards?: boolean | undefined;
181
191
  /** `'auto'` (5.11): rows grow to fit content that wraps (two badges, a long name); cells stay vertically centred and
182
192
  * rows keep at least the density's row height. Needs every row in the DOM, so it is ignored with `height`
183
193
  * (virtualized rows are one fixed height). Default: one fixed-height line per row, long text ends in an ellipsis. */
@@ -387,6 +397,7 @@ export interface FilterBarProps {
387
397
  onSearchChange?: ((value: string) => void) | undefined;
388
398
  /** ms to wait after the last keystroke. Default 300. */
389
399
  searchDelay?: number | undefined;
400
+ /** The search field's name. Default "Search". */
390
401
  searchLabel?: string | undefined;
391
402
  searchPlaceholder?: string | undefined;
392
403
  /** Filter controls beside the search: Select, SegmentedControl, a Popover of options… */
@@ -996,7 +1007,7 @@ export interface SeparatorProps {
996
1007
  spacing?: 1 | 2 | 3 | 4 | 5 | 6 | 8 | undefined;
997
1008
  className?: string | undefined;
998
1009
  }
999
- export interface TableProps extends Omit<React$1.TableHTMLAttributes<HTMLTableElement>, "className"> {
1010
+ export interface TableProps extends Omit<React$1.TableHTMLAttributes<HTMLTableElement>, "className" | "align"> {
1000
1011
  /** The table's name (a `<caption>`). Give every table one; `captionHidden` keeps it for screen readers only. */
1001
1012
  caption?: React$1.ReactNode | undefined;
1002
1013
  captionHidden?: boolean | undefined;
@@ -1006,6 +1017,11 @@ export interface TableProps extends Omit<React$1.TableHTMLAttributes<HTMLTableEl
1006
1017
  * cell shows its column's header as a label: a `Td`'s `label`, else the text of the matching `Th` in `THead`.
1007
1018
  * Done in CSS (a container query), so the server's HTML is already right; table semantics are kept. */
1008
1019
  stackBelow?: "sm" | "md" | undefined;
1020
+ /** `middle` centres every body and footer cell on its row (5.13); default `top`, so wrapped text starts level. */
1021
+ align?: "top" | "middle" | undefined;
1022
+ /** `false` (5.13) drops the frame — border, radius, background — and the outer cells' side padding, so the table
1023
+ * lines up with the content around it, e.g. flush inside a Card under its heading. Default `true`. */
1024
+ bordered?: boolean | undefined;
1009
1025
  className?: string | undefined;
1010
1026
  children?: React$1.ReactNode | undefined;
1011
1027
  }
@@ -1026,6 +1042,10 @@ export interface TableCellProps extends Omit<React$1.TdHTMLAttributes<HTMLTableC
1026
1042
  scope?: "col" | "row" | "colgroup" | "rowgroup" | undefined;
1027
1043
  /** The label this cell shows when its table is stacked (`stackBelow`, 5.8). Default: the matching header's text. */
1028
1044
  label?: string | undefined;
1045
+ /** Its place in a stacked row (5.13), on a Td or a row header (`Th scope="row"`). `title` takes the first line,
1046
+ * without a label; `action` sits at the end of that line at its natural size; `field` (default) is a labelled field,
1047
+ * two to a line under them. */
1048
+ card?: "title" | "action" | "field" | undefined;
1029
1049
  className?: string | undefined;
1030
1050
  }
1031
1051
  export interface ActionBarProps {
@@ -1201,7 +1221,7 @@ export interface SkeletonProps {
1201
1221
  size?: number | undefined;
1202
1222
  className?: string | undefined;
1203
1223
  }
1204
- export interface EmptyStateProps {
1224
+ export interface EmptyStateProps extends Omit<React$1.HTMLAttributes<HTMLDivElement>, "title" | "children"> {
1205
1225
  title: React$1.ReactNode;
1206
1226
  description?: React$1.ReactNode | undefined;
1207
1227
  icon?: IconInput | undefined;
@@ -1209,6 +1229,9 @@ export interface EmptyStateProps {
1209
1229
  action?: React$1.ReactNode | undefined;
1210
1230
  size?: "sm" | "md" | undefined;
1211
1231
  bordered?: boolean | undefined;
1232
+ /** `danger` (5.13) for a failure — the data couldn't load: the danger tint, a danger-coloured icon, and a solid
1233
+ * danger frame with `bordered`. It stays quiet; pass `role="alert"` if it must interrupt. Default `neutral`. */
1234
+ tone?: "neutral" | "danger" | undefined;
1212
1235
  headingLevel?: 2 | 3 | 4 | 5 | 6 | undefined;
1213
1236
  className?: string | undefined;
1214
1237
  }
@@ -1148,11 +1148,30 @@ function badgeElement(props, ref) {
1148
1148
  }
1149
1149
  function emptyStateElement(props, ref) {
1150
1150
  const HT = "h" + (props.headingLevel || 3);
1151
+ const rest = omit(props, [
1152
+ "title",
1153
+ "description",
1154
+ "icon",
1155
+ "action",
1156
+ "size",
1157
+ "bordered",
1158
+ "headingLevel",
1159
+ "tone",
1160
+ "className",
1161
+ "children"
1162
+ ]);
1151
1163
  return /* @__PURE__ */ React3.createElement(
1152
1164
  "div",
1153
1165
  {
1166
+ ...rest,
1154
1167
  ref,
1155
- className: cx("aura-empty", props.size === "sm" && "is-sm", props.bordered && "is-bordered", props.className)
1168
+ className: cx(
1169
+ "aura-empty",
1170
+ props.size === "sm" && "is-sm",
1171
+ props.bordered && "is-bordered",
1172
+ props.tone === "danger" && "is-danger",
1173
+ props.className
1174
+ )
1156
1175
  },
1157
1176
  /* @__PURE__ */ React3.createElement("span", { className: "aura-empty__icon", "aria-hidden": true }, /* @__PURE__ */ React3.createElement(Icon, { name: props.icon || /* @__PURE__ */ React3.createElement(IconInbox, null), size: props.size === "sm" ? "md" : "lg" })),
1158
1177
  /* @__PURE__ */ React3.createElement(HT, { className: "aura-empty__title" }, props.title),
@@ -96,7 +96,7 @@ export interface BadgeProps extends React$1.HTMLAttributes<HTMLSpanElement> {
96
96
  variant?: "soft" | "solid" | "outline" | undefined;
97
97
  icon?: IconInput | undefined;
98
98
  }
99
- export interface EmptyStateProps {
99
+ export interface EmptyStateProps extends Omit<React$1.HTMLAttributes<HTMLDivElement>, "title" | "children"> {
100
100
  title: React$1.ReactNode;
101
101
  description?: React$1.ReactNode | undefined;
102
102
  icon?: IconInput | undefined;
@@ -104,6 +104,9 @@ export interface EmptyStateProps {
104
104
  action?: React$1.ReactNode | undefined;
105
105
  size?: "sm" | "md" | undefined;
106
106
  bordered?: boolean | undefined;
107
+ /** `danger` (5.13) for a failure — the data couldn't load: the danger tint, a danger-coloured icon, and a solid
108
+ * danger frame with `bordered`. It stays quiet; pass `role="alert"` if it must interrupt. Default `neutral`. */
109
+ tone?: "neutral" | "danger" | undefined;
107
110
  headingLevel?: 2 | 3 | 4 | 5 | 6 | undefined;
108
111
  className?: string | undefined;
109
112
  }
@@ -96,7 +96,7 @@ export interface BadgeProps extends React$1.HTMLAttributes<HTMLSpanElement> {
96
96
  variant?: "soft" | "solid" | "outline" | undefined;
97
97
  icon?: IconInput | undefined;
98
98
  }
99
- export interface EmptyStateProps {
99
+ export interface EmptyStateProps extends Omit<React$1.HTMLAttributes<HTMLDivElement>, "title" | "children"> {
100
100
  title: React$1.ReactNode;
101
101
  description?: React$1.ReactNode | undefined;
102
102
  icon?: IconInput | undefined;
@@ -104,6 +104,9 @@ export interface EmptyStateProps {
104
104
  action?: React$1.ReactNode | undefined;
105
105
  size?: "sm" | "md" | undefined;
106
106
  bordered?: boolean | undefined;
107
+ /** `danger` (5.13) for a failure — the data couldn't load: the danger tint, a danger-coloured icon, and a solid
108
+ * danger frame with `bordered`. It stays quiet; pass `role="alert"` if it must interrupt. Default `neutral`. */
109
+ tone?: "neutral" | "danger" | undefined;
107
110
  headingLevel?: 2 | 3 | 4 | 5 | 6 | undefined;
108
111
  className?: string | undefined;
109
112
  }
@@ -1091,11 +1091,30 @@ function badgeElement(props, ref) {
1091
1091
  }
1092
1092
  function emptyStateElement(props, ref) {
1093
1093
  const HT = "h" + (props.headingLevel || 3);
1094
+ const rest = omit(props, [
1095
+ "title",
1096
+ "description",
1097
+ "icon",
1098
+ "action",
1099
+ "size",
1100
+ "bordered",
1101
+ "headingLevel",
1102
+ "tone",
1103
+ "className",
1104
+ "children"
1105
+ ]);
1094
1106
  return /* @__PURE__ */ React3.createElement(
1095
1107
  "div",
1096
1108
  {
1109
+ ...rest,
1097
1110
  ref,
1098
- className: cx("aura-empty", props.size === "sm" && "is-sm", props.bordered && "is-bordered", props.className)
1111
+ className: cx(
1112
+ "aura-empty",
1113
+ props.size === "sm" && "is-sm",
1114
+ props.bordered && "is-bordered",
1115
+ props.tone === "danger" && "is-danger",
1116
+ props.className
1117
+ )
1099
1118
  },
1100
1119
  /* @__PURE__ */ React3.createElement("span", { className: "aura-empty__icon", "aria-hidden": true }, /* @__PURE__ */ React3.createElement(Icon, { name: props.icon || /* @__PURE__ */ React3.createElement(IconInbox, null), size: props.size === "sm" ? "md" : "lg" })),
1101
1120
  /* @__PURE__ */ React3.createElement(HT, { className: "aura-empty__title" }, props.title),
package/dist/styles.css CHANGED
@@ -1083,6 +1083,10 @@ a.aura-upload__name:focus-visible { outline: var(--aura-focus-ring-width) solid
1083
1083
  .aura-empty__title { margin: 0; font-size: 16px; line-height: 1.5; font-weight: 600; }
1084
1084
  .aura-empty__text { margin: 0; max-width: 44ch; font-size: 14px; line-height: 1.6; color: var(--aura-fg-secondary); }
1085
1085
  .aura-empty__action { margin-top: var(--aura-space-3); display: flex; gap: var(--aura-space-3); flex-wrap: wrap; justify-content: center; }
1086
+ /* 5.13 (Chamber-OS 82): tone="danger" — a load failure. */
1087
+ .aura-empty.is-danger { background: var(--aura-alert-danger-bg); border-radius: var(--aura-radius-lg); }
1088
+ .aura-empty.is-danger.is-bordered { border: 1px solid var(--aura-border-danger); }
1089
+ .aura-empty.is-danger .aura-empty__icon { background: var(--aura-bg-surface); color: var(--aura-fg-danger); }
1086
1090
 
1087
1091
  /* ---------- Pagination ---------- */
1088
1092
  .aura-pagination { display: flex; align-items: center; gap: var(--aura-space-1); font-family: var(--font-sans); font-size: 13px; }
@@ -1548,6 +1552,13 @@ button.aura-stepper__step:hover .aura-stepper__label { text-decoration: underlin
1548
1552
  .aura-tbl .is-numeric { font-variant-numeric: tabular-nums; white-space: nowrap; }
1549
1553
  .aura-tbl-wrap[data-density='compact'] .aura-tbl__th, .aura-tbl-wrap[data-density='compact'] .aura-tbl__td { padding-top: var(--aura-space-2); padding-bottom: var(--aura-space-2); }
1550
1554
  .aura-tbl-wrap:focus-visible { outline: var(--aura-focus-ring-width) solid var(--aura-focus-ring); outline-offset: 2px; }
1555
+ /* 5.13 (Chamber-OS 81): align="middle" centres body and footer cells on their row; bordered={false} drops the frame and
1556
+ * the outer cells' side padding, so the table lines up with what's around it (a Card's heading). */
1557
+ .aura-tbl--middle > .aura-tbl__body > .aura-tbl__row > *, .aura-tbl--middle > .aura-tbl__foot > .aura-tbl__row > * { vertical-align: middle; }
1558
+ .aura-tbl-wrap.is-flush { border: 0; border-radius: 0; background: transparent; }
1559
+ .aura-tbl-wrap.is-flush > .aura-tbl > * > .aura-tbl__row > :first-child { padding-inline-start: 0; }
1560
+ .aura-tbl-wrap.is-flush > .aura-tbl > * > .aura-tbl__row > :last-child { padding-inline-end: 0; }
1561
+ .aura-tbl-wrap.is-flush > .aura-tbl > .aura-tbl__caption { padding-inline: 0; }
1551
1562
  /* Stacked rows (5.8, Chamber-OS 67): below `stackBelow` (the table's own box: sm 640px, md 768px) each body row is a
1552
1563
  * card and each cell shows its column label. The column headers stay for screen readers (visually hidden) and the
1553
1564
  * table keeps explicit roles. The box is a size container, so it needs a width of its own. */
@@ -1562,6 +1573,14 @@ button.aura-stepper__step:hover .aura-stepper__label { text-decoration: underlin
1562
1573
  .aura-tbl--stack-md > * > .aura-tbl__row > .aura-tbl__th, .aura-tbl--stack-md > * > .aura-tbl__row > .aura-tbl__td { padding: 0; border-top: 0; background: none; text-align: start; white-space: normal; }
1563
1574
  .aura-tbl--stack-md > * > .aura-tbl__row > * + * { margin-top: var(--aura-space-2); }
1564
1575
  .aura-tbl--stack-md > .aura-tbl__body > .aura-tbl__row > .aura-tbl__th { font-size: 14px; font-weight: 600; }
1576
+ /* 5.13 (Chamber-OS 84): a row with a title or action cell — title and action share the first line, fields two to a line under them. */
1577
+ .aura-tbl--stack-md > .aura-tbl__body > .aura-tbl__row:has(> [data-card]) { display: flex; flex-wrap: wrap; align-items: flex-start; column-gap: var(--aura-space-4); }
1578
+ .aura-tbl--stack-md > .aura-tbl__body > .aura-tbl__row:has(> [data-card])::after { content: ''; order: 3; flex: 0 0 100%; }
1579
+ .aura-tbl--stack-md > .aura-tbl__body > .aura-tbl__row:has(> [data-card]) > * { order: 4; flex: 0 0 calc(50% - var(--aura-space-4) / 2); min-width: 0; margin-top: var(--aura-space-2); }
1580
+ .aura-tbl--stack-md > .aura-tbl__body > .aura-tbl__row:has(> [data-card]) > [data-card] { margin-top: 0; }
1581
+ .aura-tbl--stack-md > .aura-tbl__body > .aura-tbl__row:has(> [data-card]) > [data-card='title'] { order: 1; flex: 1 1 0; font-size: 14px; font-weight: 600; }
1582
+ .aura-tbl--stack-md > .aura-tbl__body > .aura-tbl__row:has(> [data-card]) > [data-card='action'] { order: 2; flex: none; margin-inline-start: auto; }
1583
+ .aura-tbl-wrap.is-flush > .aura-tbl--stack-md > .aura-tbl__caption { padding-inline: var(--aura-space-4); }
1565
1584
  .aura-tbl--stack-md > * > .aura-tbl__row > .aura-tbl__td[data-label]::before {
1566
1585
  content: attr(data-label); content: attr(data-label) / '';
1567
1586
  display: block; margin-bottom: 2px; font-family: var(--font-mono); font-size: 11px; line-height: 16px; font-weight: 400; color: var(--aura-fg-secondary);
@@ -1577,6 +1596,14 @@ button.aura-stepper__step:hover .aura-stepper__label { text-decoration: underlin
1577
1596
  .aura-tbl--stack-sm > * > .aura-tbl__row > .aura-tbl__th, .aura-tbl--stack-sm > * > .aura-tbl__row > .aura-tbl__td { padding: 0; border-top: 0; background: none; text-align: start; white-space: normal; }
1578
1597
  .aura-tbl--stack-sm > * > .aura-tbl__row > * + * { margin-top: var(--aura-space-2); }
1579
1598
  .aura-tbl--stack-sm > .aura-tbl__body > .aura-tbl__row > .aura-tbl__th { font-size: 14px; font-weight: 600; }
1599
+ /* 5.13 (Chamber-OS 84): a row with a title or action cell — title and action share the first line, fields two to a line under them. */
1600
+ .aura-tbl--stack-sm > .aura-tbl__body > .aura-tbl__row:has(> [data-card]) { display: flex; flex-wrap: wrap; align-items: flex-start; column-gap: var(--aura-space-4); }
1601
+ .aura-tbl--stack-sm > .aura-tbl__body > .aura-tbl__row:has(> [data-card])::after { content: ''; order: 3; flex: 0 0 100%; }
1602
+ .aura-tbl--stack-sm > .aura-tbl__body > .aura-tbl__row:has(> [data-card]) > * { order: 4; flex: 0 0 calc(50% - var(--aura-space-4) / 2); min-width: 0; margin-top: var(--aura-space-2); }
1603
+ .aura-tbl--stack-sm > .aura-tbl__body > .aura-tbl__row:has(> [data-card]) > [data-card] { margin-top: 0; }
1604
+ .aura-tbl--stack-sm > .aura-tbl__body > .aura-tbl__row:has(> [data-card]) > [data-card='title'] { order: 1; flex: 1 1 0; font-size: 14px; font-weight: 600; }
1605
+ .aura-tbl--stack-sm > .aura-tbl__body > .aura-tbl__row:has(> [data-card]) > [data-card='action'] { order: 2; flex: none; margin-inline-start: auto; }
1606
+ .aura-tbl-wrap.is-flush > .aura-tbl--stack-sm > .aura-tbl__caption { padding-inline: var(--aura-space-4); }
1580
1607
  .aura-tbl--stack-sm > * > .aura-tbl__row > .aura-tbl__td[data-label]::before {
1581
1608
  content: attr(data-label); content: attr(data-label) / '';
1582
1609
  display: block; margin-bottom: 2px; font-family: var(--font-mono); font-size: 11px; line-height: 16px; font-weight: 400; color: var(--aura-fg-secondary);
@@ -1629,6 +1656,14 @@ button.aura-stepper__step:hover .aura-stepper__label { text-decoration: underlin
1629
1656
  padding: 0; line-height: normal;
1630
1657
  }
1631
1658
  .aura-table__td[data-hide], .aura-table__head > .aura-table__th[data-hide] { display: block; }
1659
+ /* 5.13 (Chamber-OS 80): card: 'hide' leaves a column out of the card; cardOrder orders the fields. */
1660
+ .aura-table__td[data-card='hide'], .aura-table__head > .aura-table__th[data-card='hide'],
1661
+ .aura-table__row--skeleton .aura-table__td[data-card='hide'] { display: none; }
1662
+ .aura-table__td[data-card='field'] { order: var(--aura-card-order, 5); }
1663
+ /* hideSelectionInCards: no row boxes, no select-all line. */
1664
+ .aura-table--cards-nosel .aura-table__row > .aura-table__sel { display: none; }
1665
+ .aura-table--cards-nosel .aura-table__head { position: absolute; width: 1px; height: 1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); }
1666
+ .aura-table--cards-nosel .aura-table__head > .aura-table__sel { display: none; }
1632
1667
  /* 5.11: rowHeight="auto" leaves cards as they are. */
1633
1668
  .aura-table__td--auto { display: block; white-space: nowrap; }
1634
1669
  .aura-table__td--auto .aura-table__cell > .aura-badge, .aura-table__td--auto .aura-table__cell > .aura-pill { margin: 0; }