@jirawatpyk/aura-react 5.12.0 → 5.14.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.
@@ -2,7 +2,7 @@
2
2
  import * as React from "react";
3
3
  import { Drawer } from "./Dialog.js";
4
4
  import { IconButton } from "./IconButton.js";
5
- import { cx } from "./internal.js";
5
+ import { cx, useIsoLayoutEffect, useMergedRef } from "./internal.js";
6
6
  import { useStrings } from "./locale.js";
7
7
  import { useBreakpoint } from "./responsive.js";
8
8
  import { IconMenu } from "./icons.js";
@@ -24,6 +24,27 @@ const AppShell = React.forwardRef(function AppShell2(props, ref) {
24
24
  if (shared) navState[1](id);
25
25
  if (navEl && navEl.props.onChange) navEl.props.onChange(id);
26
26
  }
27
+ const rootRef = React.useRef(null);
28
+ const barRef = React.useRef(null);
29
+ const mergedRef = useMergedRef(ref, rootRef);
30
+ const hasBar = !!(props.header || props.nav);
31
+ useIsoLayoutEffect(
32
+ function() {
33
+ const root = rootRef.current, bar = barRef.current;
34
+ if (!root || !bar) return;
35
+ function sync() {
36
+ root.style.setProperty("--aura-shell-bar-height", bar.getBoundingClientRect().height + "px");
37
+ }
38
+ sync();
39
+ const ro = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(sync);
40
+ if (ro) ro.observe(bar);
41
+ return function() {
42
+ if (ro) ro.disconnect();
43
+ root.style.removeProperty("--aura-shell-bar-height");
44
+ };
45
+ },
46
+ [hasBar]
47
+ );
27
48
  const deskNav = navEl && shared ? React.cloneElement(navEl, { value: navState[0], onChange: onNav }) : props.nav;
28
49
  const drawerNav = navEl ? React.cloneElement(navEl, {
29
50
  value: shared ? navState[0] : navEl.props.value,
@@ -35,32 +56,56 @@ const AppShell = React.forwardRef(function AppShell2(props, ref) {
35
56
  collapsed: false,
36
57
  collapsible: false
37
58
  }) : props.nav;
38
- return /* @__PURE__ */ React.createElement("div", { ref, className: cx("aura-shell", props.bottomNav && "aura-shell--bottomnav", props.className) }, props.nav ? /* @__PURE__ */ React.createElement("div", { className: "aura-shell__nav" }, deskNav) : null, props.nav ? /* @__PURE__ */ React.createElement(
39
- Drawer,
59
+ return /* @__PURE__ */ React.createElement(
60
+ "div",
40
61
  {
41
- open,
42
- onClose: function() {
43
- setOpen(false);
44
- },
45
- side: "left",
46
- size: "nav",
47
- "aria-label": props.navLabel || t.navigation,
48
- dismissible: true
62
+ ref: mergedRef,
63
+ className: cx(
64
+ "aura-shell",
65
+ props.bottomNav && "aura-shell--bottomnav",
66
+ /* 5.14: no top bar at all, or one that only holds the menu button (gone from lg up): the bar-height token is 0. */
67
+ !props.header && !props.nav && "aura-shell--no-bar",
68
+ !props.header && props.nav && "aura-shell--menu-bar",
69
+ props.className
70
+ )
49
71
  },
50
- drawerNav
51
- ) : null, /* @__PURE__ */ React.createElement("div", { className: "aura-shell__main" }, props.header || props.nav ? /* @__PURE__ */ React.createElement("header", { className: cx("aura-shell__bar", !props.header && "aura-shell__bar--menu-only") }, props.nav ? /* @__PURE__ */ React.createElement(
52
- IconButton,
53
- {
54
- className: "aura-shell__menu",
55
- icon: /* @__PURE__ */ React.createElement(IconMenu, null),
56
- label: props.menuLabel || t.openNav,
57
- size: "md",
58
- onClick: function() {
59
- setOpen(true);
72
+ props.nav ? /* @__PURE__ */ React.createElement("div", { className: "aura-shell__nav" }, deskNav) : null,
73
+ props.nav ? /* @__PURE__ */ React.createElement(
74
+ Drawer,
75
+ {
76
+ open,
77
+ onClose: function() {
78
+ setOpen(false);
79
+ },
80
+ side: "left",
81
+ size: "nav",
82
+ "aria-label": props.navLabel || t.navigation,
83
+ dismissible: true
84
+ },
85
+ drawerNav
86
+ ) : null,
87
+ /* @__PURE__ */ React.createElement("div", { className: "aura-shell__main" }, props.header || props.nav ? /* @__PURE__ */ React.createElement("header", { ref: barRef, className: cx("aura-shell__bar", !props.header && "aura-shell__bar--menu-only") }, props.nav ? /* @__PURE__ */ React.createElement(
88
+ IconButton,
89
+ {
90
+ className: "aura-shell__menu",
91
+ icon: /* @__PURE__ */ React.createElement(IconMenu, null),
92
+ label: props.menuLabel || t.openNav,
93
+ size: "md",
94
+ onClick: function() {
95
+ setOpen(true);
96
+ },
97
+ "aria-expanded": open
98
+ }
99
+ ) : null, /* @__PURE__ */ React.createElement("div", { className: "aura-shell__bar-content" }, props.header)) : null, /* @__PURE__ */ React.createElement(
100
+ "main",
101
+ {
102
+ className: cx("aura-shell__content", props.contentPadding === false && "is-flush"),
103
+ id: props.mainId || "main",
104
+ tabIndex: -1
60
105
  },
61
- "aria-expanded": open
62
- }
63
- ) : null, /* @__PURE__ */ React.createElement("div", { className: "aura-shell__bar-content" }, props.header)) : null, /* @__PURE__ */ React.createElement("main", { className: "aura-shell__content", id: props.mainId || "main", tabIndex: -1 }, props.children), props.bottomNav || null));
106
+ props.children
107
+ ), props.bottomNav || null)
108
+ );
64
109
  });
65
110
  export {
66
111
  AppShell
@@ -1,39 +1,11 @@
1
1
  'use client';
2
2
  import * as React from "react";
3
- import { cx } from "./internal.js";
4
- const AVATAR_TONES = ["progress", "ready", "neutral", "warning"];
5
- function initials(name) {
6
- const parts = String(name || "?").trim().split(/\s+/);
7
- return ((parts[0] || "?")[0] + (parts.length > 1 ? parts[parts.length - 1][0] : parts[0][1] || "")).toUpperCase();
8
- }
3
+ import { avatarElement } from "./display.js";
9
4
  const Avatar = React.forwardRef(function Avatar2(props, ref) {
10
- const size = props.size || "md", errState = React.useState(null);
11
- let hash = 0;
12
- String(props.name || "").split("").forEach(function(ch) {
13
- hash = hash * 31 + ch.charCodeAt(0) >>> 0;
5
+ const errState = React.useState(null);
6
+ return avatarElement(props, ref, errState[0], function() {
7
+ errState[1](props.src || null);
14
8
  });
15
- const tone = AVATAR_TONES[hash % AVATAR_TONES.length];
16
- return /* @__PURE__ */ React.createElement(
17
- "span",
18
- {
19
- ref,
20
- className: cx("aura-avatar", "aura-avatar--" + size, "aura-avatar--" + tone, props.className),
21
- role: "img",
22
- "aria-label": props.name + (props.status ? ", " + props.status : "")
23
- },
24
- props.src && errState[0] !== props.src ? /* @__PURE__ */ React.createElement(
25
- "img",
26
- {
27
- key: props.src,
28
- src: props.src,
29
- alt: "",
30
- onError: function() {
31
- errState[1](props.src || null);
32
- }
33
- }
34
- ) : /* @__PURE__ */ React.createElement("span", { "aria-hidden": true }, initials(props.name)),
35
- props.status === "online" ? /* @__PURE__ */ React.createElement("span", { className: "aura-avatar__status", "aria-hidden": true }) : null
36
- );
37
9
  });
38
10
  export {
39
11
  Avatar
@@ -52,6 +52,8 @@ const Button = React.forwardRef(
52
52
  const props = all;
53
53
  const variant = props.variant || "primary";
54
54
  const loading = !!props.loading;
55
+ const ad = props["aria-disabled"];
56
+ const blocked = loading || ad === true || ad === "true";
55
57
  const rest = omit(props, [
56
58
  "variant",
57
59
  "className",
@@ -78,8 +80,8 @@ const Button = React.forwardRef(
78
80
  className: props.className
79
81
  }),
80
82
  "aria-busy": loading || void 0,
81
- "aria-disabled": loading || void 0,
82
- onClick: loading ? function(e) {
83
+ "aria-disabled": blocked || void 0,
84
+ onClick: blocked ? function(e) {
83
85
  e.preventDefault();
84
86
  } : props.onClick
85
87
  },
@@ -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/Stat.js CHANGED
@@ -1,38 +1,10 @@
1
1
  'use client';
2
2
  import * as React from "react";
3
- import { cx } from "./internal.js";
4
- import { Icon } from "./Icon.js";
5
3
  import { useLinkComponent } from "./locale.js";
6
- import { IconMinus, IconTrendingDown, IconTrendingUp } from "./icons.js";
4
+ import { statElement } from "./display.js";
7
5
  const Stat = React.forwardRef(function Stat2(props, ref) {
8
- const ch = props.change;
9
- const dir = ch && (ch.direction || "flat");
10
- const tone = ch && (ch.tone || (dir === "up" ? "positive" : dir === "down" ? "negative" : "neutral"));
11
6
  const Link = useLinkComponent(props.linkComponent);
12
- const v = props.value;
13
- const numeric = typeof v === "number" || typeof v === "string" && /\d/.test(v) && /^[\s\d.,:+\-\u2212%()\u0E3F$\u20AC\u00A3\u00A5kKmMbB]+$/.test(v.replace(/\b[A-Z]{3}\b/g, ""));
14
- const Tag = props.href ? Link : props.onClick ? "button" : "div";
15
- const interactive = !!(props.href || props.onClick);
16
- return /* @__PURE__ */ React.createElement(
17
- Tag,
18
- {
19
- ref,
20
- className: cx("aura-stat", interactive && "is-interactive", props.loading && "is-loading", props.className),
21
- href: props.href,
22
- onClick: props.onClick,
23
- type: Tag === "button" ? "button" : void 0,
24
- "aria-busy": props.loading || void 0
25
- },
26
- /* @__PURE__ */ React.createElement("span", { className: "aura-stat__head" }, /* @__PURE__ */ React.createElement("span", { className: "aura-stat__label" }, props.label), props.icon ? /* @__PURE__ */ React.createElement("span", { className: "aura-stat__icon" }, /* @__PURE__ */ React.createElement(Icon, { name: props.icon })) : null),
27
- props.loading ? /* @__PURE__ */ React.createElement("span", { className: "aura-stat__value" }, /* @__PURE__ */ React.createElement("span", { className: "aura-skel aura-stat__skel" })) : /* @__PURE__ */ React.createElement("span", { className: cx("aura-stat__value", numeric && "is-numeric") }, props.value, props.unit ? /* @__PURE__ */ React.createElement("span", { className: "aura-stat__unit" }, props.unit) : null),
28
- ch && !props.loading || props.caption ? /* @__PURE__ */ React.createElement("span", { className: "aura-stat__foot" }, ch && !props.loading ? /* @__PURE__ */ React.createElement("span", { className: cx("aura-stat__change", "is-" + tone) }, /* @__PURE__ */ React.createElement(
29
- Icon,
30
- {
31
- name: dir === "up" ? /* @__PURE__ */ React.createElement(IconTrendingUp, null) : dir === "down" ? /* @__PURE__ */ React.createElement(IconTrendingDown, null) : /* @__PURE__ */ React.createElement(IconMinus, null),
32
- size: 14
33
- }
34
- ), /* @__PURE__ */ React.createElement("span", null, ch.value)) : null, ch && ch.label && !props.loading ? /* @__PURE__ */ React.createElement("span", { className: "aura-stat__caption" }, ch.label) : null, props.caption ? /* @__PURE__ */ React.createElement("span", { className: "aura-stat__caption" }, props.caption) : null) : null
35
- );
7
+ return statElement(props, ref, Link);
36
8
  });
37
9
  export {
38
10
  Stat
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
  );
package/dist/esm/Tabs.js CHANGED
@@ -81,7 +81,7 @@ const Tabs = React.forwardRef(function Tabs2(props, ref) {
81
81
  key: t.id,
82
82
  href: t.href,
83
83
  className: tabCls(on, own.className),
84
- "aria-current": on ? "page" : void 0,
84
+ "aria-current": on ? props.current || "page" : void 0,
85
85
  onClick: function(e) {
86
86
  if (own.onClick) own.onClick(e);
87
87
  if (e.defaultPrevented || e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return;
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
  import * as React from "react";
3
3
  import { Icon } from "./Icon.js";
4
- import { cx, omit, tone as badgeTone } from "./classes.js";
4
+ import { cx, devWarnOnce, omit, tone as badgeTone } from "./classes.js";
5
5
  import { toneFor } from "./status.js";
6
6
  import {
7
7
  IconBan,
@@ -11,6 +11,9 @@ import {
11
11
  IconCircleDotDashed,
12
12
  IconInbox,
13
13
  IconInfo,
14
+ IconMinus,
15
+ IconTrendingDown,
16
+ IconTrendingUp,
14
17
  IconTriangleAlert
15
18
  } from "./icons.js";
16
19
  const h = React.createElement;
@@ -101,12 +104,31 @@ function badgeElement(props, ref) {
101
104
  );
102
105
  }
103
106
  function emptyStateElement(props, ref) {
104
- const HT = "h" + (props.headingLevel || 3);
107
+ const HT = props.headingLevel === false ? "p" : "h" + (props.headingLevel || 3);
108
+ const rest = omit(props, [
109
+ "title",
110
+ "description",
111
+ "icon",
112
+ "action",
113
+ "size",
114
+ "bordered",
115
+ "headingLevel",
116
+ "tone",
117
+ "className",
118
+ "children"
119
+ ]);
105
120
  return /* @__PURE__ */ React.createElement(
106
121
  "div",
107
122
  {
123
+ ...rest,
108
124
  ref,
109
- className: cx("aura-empty", props.size === "sm" && "is-sm", props.bordered && "is-bordered", props.className)
125
+ className: cx(
126
+ "aura-empty",
127
+ props.size === "sm" && "is-sm",
128
+ props.bordered && "is-bordered",
129
+ props.tone === "danger" && "is-danger",
130
+ props.className
131
+ )
110
132
  },
111
133
  /* @__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
134
  /* @__PURE__ */ React.createElement(HT, { className: "aura-empty__title" }, props.title),
@@ -114,6 +136,66 @@ function emptyStateElement(props, ref) {
114
136
  props.action ? /* @__PURE__ */ React.createElement("div", { className: "aura-empty__action" }, props.action) : null
115
137
  );
116
138
  }
139
+ function statElement(props, ref, Link) {
140
+ const ch = props.change;
141
+ const dir = ch && (ch.direction || "flat");
142
+ const tone = ch && (ch.tone || (dir === "up" ? "positive" : dir === "down" ? "negative" : "neutral"));
143
+ const v = props.value;
144
+ const numeric = typeof v === "number" || typeof v === "string" && /\d/.test(v) && /^[\s\d.,:+\-\u2212%()\u0E3F$\u20AC\u00A3\u00A5kKmMbB]+$/.test(v.replace(/\b[A-Z]{3}\b/g, ""));
145
+ const Tag = props.href ? Link : props.onClick ? "button" : "div";
146
+ const interactive = !!(props.href || props.onClick);
147
+ if (props.headingLevel && Tag === "button")
148
+ devWarnOnce(
149
+ "stat-heading-button",
150
+ "Stat `headingLevel` is ignored with `onClick`: a heading can\u2019t sit in a button. Use `href`, or put the heading outside."
151
+ );
152
+ const LabelTag = props.headingLevel && Tag !== "button" ? "h" + props.headingLevel : "span";
153
+ const HeadTag = LabelTag === "span" ? "span" : "div";
154
+ return /* @__PURE__ */ React.createElement(
155
+ Tag,
156
+ {
157
+ ref,
158
+ className: cx("aura-stat", interactive && "is-interactive", props.loading && "is-loading", props.className),
159
+ href: props.href,
160
+ onClick: props.onClick,
161
+ type: Tag === "button" ? "button" : void 0,
162
+ "aria-busy": props.loading || void 0
163
+ },
164
+ /* @__PURE__ */ React.createElement(HeadTag, { className: "aura-stat__head" }, /* @__PURE__ */ React.createElement(LabelTag, { className: "aura-stat__label" }, props.label), props.icon ? /* @__PURE__ */ React.createElement("span", { className: "aura-stat__icon" }, /* @__PURE__ */ React.createElement(Icon, { name: props.icon })) : null),
165
+ props.loading ? /* @__PURE__ */ React.createElement("span", { className: "aura-stat__value" }, /* @__PURE__ */ React.createElement("span", { className: "aura-skel aura-stat__skel" })) : /* @__PURE__ */ React.createElement("span", { className: cx("aura-stat__value", numeric && "is-numeric") }, props.value, props.unit ? /* @__PURE__ */ React.createElement("span", { className: "aura-stat__unit" }, props.unit) : null),
166
+ ch && !props.loading || props.caption ? /* @__PURE__ */ React.createElement("span", { className: "aura-stat__foot" }, ch && !props.loading ? /* @__PURE__ */ React.createElement("span", { className: cx("aura-stat__change", "is-" + tone) }, /* @__PURE__ */ React.createElement(
167
+ Icon,
168
+ {
169
+ name: dir === "up" ? /* @__PURE__ */ React.createElement(IconTrendingUp, null) : dir === "down" ? /* @__PURE__ */ React.createElement(IconTrendingDown, null) : /* @__PURE__ */ React.createElement(IconMinus, null),
170
+ size: 14
171
+ }
172
+ ), /* @__PURE__ */ React.createElement("span", null, ch.value)) : null, ch && ch.label && !props.loading ? /* @__PURE__ */ React.createElement("span", { className: "aura-stat__caption" }, ch.label) : null, props.caption ? /* @__PURE__ */ React.createElement("span", { className: "aura-stat__caption" }, props.caption) : null) : null
173
+ );
174
+ }
175
+ const AVATAR_TONES = ["progress", "ready", "neutral", "warning"];
176
+ function initials(name) {
177
+ const parts = String(name || "?").trim().split(/\s+/);
178
+ return ((parts[0] || "?")[0] + (parts.length > 1 ? parts[parts.length - 1][0] : parts[0][1] || "")).toUpperCase();
179
+ }
180
+ function avatarElement(props, ref, broken, onError) {
181
+ const size = props.size || "md";
182
+ let hash = 0;
183
+ String(props.name || "").split("").forEach(function(ch) {
184
+ hash = hash * 31 + ch.charCodeAt(0) >>> 0;
185
+ });
186
+ const tone = AVATAR_TONES[hash % AVATAR_TONES.length];
187
+ return /* @__PURE__ */ React.createElement(
188
+ "span",
189
+ {
190
+ ref,
191
+ className: cx("aura-avatar", "aura-avatar--" + size, "aura-avatar--" + tone, props.className),
192
+ role: "img",
193
+ "aria-label": props.name + (props.status ? ", " + props.status : "")
194
+ },
195
+ props.src && broken !== props.src ? /* @__PURE__ */ React.createElement("img", { key: props.src, src: props.src, alt: "", onError }) : /* @__PURE__ */ React.createElement("span", { "aria-hidden": true }, initials(props.name)),
196
+ props.status === "online" ? /* @__PURE__ */ React.createElement("span", { className: "aura-avatar__status", "aria-hidden": true }) : null
197
+ );
198
+ }
117
199
  function buttonClass(opts = {}) {
118
200
  return cx(
119
201
  "aura-btn",
@@ -139,17 +221,27 @@ function ServerBadge(props) {
139
221
  function ServerEmptyState(props) {
140
222
  return emptyStateElement(props, void 0);
141
223
  }
224
+ function ServerStat(props) {
225
+ return statElement(omit(props, ["onClick"]), void 0, props.linkComponent || "a");
226
+ }
227
+ function ServerAvatar(props) {
228
+ return avatarElement(props, void 0, null, void 0);
229
+ }
142
230
  export {
143
231
  ALERT_ICON,
144
232
  ServerAlert,
233
+ ServerAvatar,
145
234
  ServerBadge,
146
235
  ServerCard,
147
236
  ServerEmptyState,
237
+ ServerStat,
148
238
  ServerStatusPill,
149
239
  alertElement,
240
+ avatarElement,
150
241
  badgeElement,
151
242
  buttonClass,
152
243
  cardElement,
153
244
  emptyStateElement,
245
+ statElement,
154
246
  statusPillElement
155
247
  };