@jirawatpyk/aura-react 5.50.0 → 5.52.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.
@@ -46,6 +46,9 @@ export type StatusTone = "neutral" | "progress" | "ready" | "warning" | "blocked
46
46
  export interface StatusPillProps extends Omit<React$1.HTMLAttributes<HTMLSpanElement>, "children"> {
47
47
  /** The status word shown, e.g. "In Progress". Other attributes (`id`, `data-*`, `aria-*`) go on the pill (5.8). */
48
48
  children: React$1.ReactNode;
49
+ /** 5.51 (Chamber-OS 158): in a box narrower than the words, the text wraps inside the pill (still rounded, the icon
50
+ * on the first line) instead of running out of it. Without it a pill stays on one line. */
51
+ wrap?: boolean | undefined;
49
52
  /** Force a tone. Default: matched from the word (Ready/Done → ready, In Progress/In Review → progress, Warning/Problem/Degraded/At risk → warning (5.1), Blocked/Failed → blocked, anything else → neutral). */
50
53
  tone?: StatusTone | undefined;
51
54
  className?: string | undefined;
@@ -114,6 +117,43 @@ export type DataAttributes = {
114
117
  };
115
118
  export type Breakpoint = "base" | "sm" | "md" | "lg" | "xl";
116
119
  export type Responsive<T> = T | Partial<Record<Breakpoint, T>>;
120
+ /** 5.52 (Chamber-OS 164): what a loading column's placeholder cell looks like. */
121
+ export interface TableSkeletonHint {
122
+ /** Text lines: 2 for a value over its caption. Default 1. */
123
+ lines?: 1 | 2 | undefined;
124
+ /** `text` (default) bars, a status `pill`, or an `action` block as tall as a small Button (44px on a phone card or a
125
+ * touch screen with `touch`). */
126
+ kind?: "text" | "pill" | "action" | undefined;
127
+ /** An `action` block 44px below 640px and on a coarse pointer, as `touchHeight` buttons are. */
128
+ touch?: boolean | undefined;
129
+ }
130
+ /** 5.52 (Chamber-OS 164): one column of a `TableSkeleton` — the same facts a header cell gives a loading Table. */
131
+ export interface TableSkeletonColumn {
132
+ /** Header text (and the stacked card's field label). */
133
+ label?: string | undefined;
134
+ /** Column width: a share such as `'22%'`, or px. Columns without one split what is left evenly. */
135
+ width?: string | number | undefined;
136
+ align?: "start" | "center" | "end" | undefined;
137
+ numeric?: boolean | undefined;
138
+ /** Its place in a stacked row: `title`, `action` or `field` (default), as on a Td. */
139
+ card?: "title" | "action" | "field" | undefined;
140
+ skeleton?: TableSkeletonHint | undefined;
141
+ }
142
+ /** 5.52 (Chamber-OS 164): a loading Table for Server Components. Same frame, density, stacking and cards as Table. */
143
+ export interface TableSkeletonProps {
144
+ columns: TableSkeletonColumn[];
145
+ /** Placeholder rows (default 5). */
146
+ rows?: number | undefined;
147
+ density?: "comfortable" | "compact" | undefined;
148
+ stackBelow?: "sm" | "md" | undefined;
149
+ stackStyle?: "list" | "cards" | undefined;
150
+ bordered?: boolean | undefined;
151
+ bleed?: boolean | undefined;
152
+ bleedEnd?: boolean | undefined;
153
+ rowHeight?: "density" | undefined;
154
+ align?: "top" | "middle" | undefined;
155
+ className?: string | undefined;
156
+ }
117
157
  export interface StatChange {
118
158
  /** Shown as written, e.g. "+12%" or "−3". */
119
159
  value: React$1.ReactNode;
@@ -484,6 +524,9 @@ export interface ContainerProps extends Pick<React$1.HTMLAttributes<HTMLElement>
484
524
  }
485
525
  /** Container — centres content up to aura-container-max (1280px) with responsive side padding. */
486
526
  export declare const Container: React$1.ForwardRefExoticComponent<ContainerProps & React$1.RefAttributes<HTMLElement>>;
527
+ /** A loading Table (5.52, Chamber-OS 164), for Server Components — e.g. a route's loading.tsx. `aria-hidden` and
528
+ * `inert`: announce the load in the page's own status line. */
529
+ export declare function TableSkeleton(props: TableSkeletonProps): React$1.ReactElement;
487
530
  /** PageHeader (5.32, DxT Monitor request 3): the top of a page — an eyebrow, the page's heading, a meta line and the
488
531
  * page's actions. It has no outer padding: inside AppShell, the content padding is the page margin (16px at the sides
489
532
  * and 24px top and bottom on phones, 24px from 640px, 32px from 1024px). Stateless, so it is also exported from
@@ -576,14 +576,14 @@ var STRINGS = {
576
576
 
577
577
  // src/theme.ts
578
578
  function hexToRgb(hex) {
579
- let h6 = String(hex).trim().replace("#", "");
580
- if (h6.length === 3)
581
- h6 = h6.split("").map(function(c) {
579
+ let h7 = String(hex).trim().replace("#", "");
580
+ if (h7.length === 3)
581
+ h7 = h7.split("").map(function(c) {
582
582
  return c + c;
583
583
  }).join("");
584
- if (!/^[0-9a-f]{6}$/i.test(h6)) throw new Error('createTheme: "' + hex + '" is not a #rgb or #rrggbb colour');
584
+ if (!/^[0-9a-f]{6}$/i.test(h7)) throw new Error('createTheme: "' + hex + '" is not a #rgb or #rrggbb colour');
585
585
  return [0, 2, 4].map(function(i) {
586
- return parseInt(h6.slice(i, i + 2), 16) / 255;
586
+ return parseInt(h7.slice(i, i + 2), 16) / 255;
587
587
  });
588
588
  }
589
589
  function rgbToHex(rgb) {
@@ -1176,8 +1176,17 @@ var PILL_ICON = {
1176
1176
  };
1177
1177
  function statusPillElement(props, ref) {
1178
1178
  const tone2 = props.tone || toneFor(props.children);
1179
- const rest = omit(props, ["tone", "className", "children"]);
1180
- return /* @__PURE__ */ React3.createElement("span", { ...rest, ref, className: cx("aura-pill", "aura-pill--" + tone2, props.className) }, /* @__PURE__ */ React3.createElement(Icon, { name: h2(PILL_ICON[tone2] || IconCircle), size: 12 }), props.children);
1179
+ const rest = omit(props, ["tone", "className", "children", "wrap"]);
1180
+ return /* @__PURE__ */ React3.createElement(
1181
+ "span",
1182
+ {
1183
+ ...rest,
1184
+ ref,
1185
+ className: cx("aura-pill", "aura-pill--" + tone2, props.wrap && "is-wrap", props.className)
1186
+ },
1187
+ /* @__PURE__ */ React3.createElement(Icon, { name: h2(PILL_ICON[tone2] || IconCircle), size: 12 }),
1188
+ props.wrap ? /* @__PURE__ */ React3.createElement("span", { className: "aura-pill__text" }, props.children) : props.children
1189
+ );
1181
1190
  }
1182
1191
  function badgeElement(props, ref) {
1183
1192
  const rest = omit(props, ["tone", "variant", "icon", "className", "children"]);
@@ -1366,10 +1375,171 @@ var Container = React4.forwardRef(function Container2(props, ref) {
1366
1375
  );
1367
1376
  });
1368
1377
 
1369
- // src/PageHeader.tsx
1378
+ // src/TableSkeleton.tsx
1370
1379
  import * as React5 from "react";
1371
1380
  var h4 = React5.createElement;
1372
- var PageHeader = React5.forwardRef(function PageHeader2(props, ref) {
1381
+ function inertProps() {
1382
+ return { inert: parseInt(React5.version, 10) >= 19 ? true : "", "aria-hidden": true };
1383
+ }
1384
+ function widthOf(w) {
1385
+ return w == null || w === "" ? void 0 : typeof w === "number" ? w + "px" : w;
1386
+ }
1387
+ function skeletonColgroup(cols) {
1388
+ return h4(
1389
+ "colgroup",
1390
+ null,
1391
+ cols.map(function(c, i) {
1392
+ const w = widthOf(c.width);
1393
+ return h4("col", { key: i, style: w ? { width: w } : void 0 });
1394
+ })
1395
+ );
1396
+ }
1397
+ function placeholder(c) {
1398
+ const s = c.skeleton || {};
1399
+ if (s.kind === "pill") return h4("span", { className: "aura-skel aura-skel--pill" });
1400
+ if (s.kind === "action") return h4("span", { className: cx("aura-skel aura-skel--action", s.touch && "is-touch") });
1401
+ if (s.lines === 2)
1402
+ return h4(
1403
+ "span",
1404
+ { className: "aura-skel-lines" },
1405
+ h4("span", { className: "aura-skel aura-skel--text", style: { width: "100%" } }),
1406
+ h4("span", { className: "aura-skel aura-skel--text", style: { width: "60%" } })
1407
+ );
1408
+ return h4("span", { className: "aura-skel aura-skel--text", style: { width: "80%" } });
1409
+ }
1410
+ function cellCls(base, c) {
1411
+ const align = c.align || (c.numeric ? "end" : void 0);
1412
+ return cx(base, align === "end" && "is-end", align === "center" && "is-center", c.numeric && "is-numeric");
1413
+ }
1414
+ function skeletonBody(cols, n3, stacked) {
1415
+ const rows = [];
1416
+ for (let r2 = 0; r2 < n3; r2++)
1417
+ rows.push(
1418
+ h4(
1419
+ "tr",
1420
+ { key: r2, className: "aura-tbl__row aura-tbl__row--skeleton", role: stacked ? "row" : void 0 },
1421
+ cols.map(function(c, i) {
1422
+ const slot = stacked && (c.card === "title" || c.card === "action") ? c.card : void 0;
1423
+ return h4(
1424
+ "td",
1425
+ {
1426
+ key: i,
1427
+ className: cellCls("aura-tbl__td", c),
1428
+ role: stacked ? "cell" : void 0,
1429
+ "data-label": stacked && !slot && c.label ? c.label : void 0,
1430
+ "data-card": slot
1431
+ },
1432
+ placeholder(c)
1433
+ );
1434
+ })
1435
+ )
1436
+ );
1437
+ return h4(
1438
+ "tbody",
1439
+ { key: "aura-skeleton", className: "aura-tbl__body", role: stacked ? "rowgroup" : void 0 },
1440
+ rows
1441
+ );
1442
+ }
1443
+ function tableWrapClass(p) {
1444
+ return cx(
1445
+ "aura-tbl-wrap",
1446
+ p.stackBelow && "is-stackable",
1447
+ p.bordered === false && "is-flush",
1448
+ p.bleed && "aura-bleed-frame",
1449
+ p.bleed && !p.cards && "aura-bleed",
1450
+ p.bleed && p.bleedEnd && !p.cards && "aura-bleed-end"
1451
+ );
1452
+ }
1453
+ function tableClass(p) {
1454
+ return cx(
1455
+ "aura-tbl",
1456
+ p.stackBelow && "aura-tbl--stack-" + p.stackBelow,
1457
+ (p.align === "middle" || p.rowHeight === "density" && p.align !== "top") && "aura-tbl--middle",
1458
+ p.rowHeight === "density" && "aura-tbl--row-density",
1459
+ p.cards && "aura-tbl--cards",
1460
+ p.className
1461
+ );
1462
+ }
1463
+ function cardsFrame(el, p) {
1464
+ return p.cards ? h4(
1465
+ "div",
1466
+ {
1467
+ className: cx(
1468
+ "aura-tbl-cards aura-tbl-cards--" + p.stackBelow,
1469
+ p.bleed && "aura-bleed",
1470
+ p.bleed && p.bleedEnd && "aura-bleed-end"
1471
+ )
1472
+ },
1473
+ el
1474
+ ) : el;
1475
+ }
1476
+ function TableSkeleton(props) {
1477
+ const cols = props.columns || [];
1478
+ const n3 = props.rows != null ? Math.max(0, props.rows) : 5;
1479
+ const stacked = !!props.stackBelow;
1480
+ const cards = stacked && props.stackStyle === "cards";
1481
+ const head = h4(
1482
+ "thead",
1483
+ { className: "aura-tbl__head", role: stacked ? "rowgroup" : void 0 },
1484
+ h4(
1485
+ "tr",
1486
+ { className: "aura-tbl__row", role: stacked ? "row" : void 0 },
1487
+ cols.map(function(c, i) {
1488
+ return h4(
1489
+ "th",
1490
+ { key: i, scope: "col", className: cellCls("aura-tbl__th", c), role: stacked ? "columnheader" : void 0 },
1491
+ c.label
1492
+ );
1493
+ })
1494
+ )
1495
+ );
1496
+ const table = h4(
1497
+ "div",
1498
+ Object.assign(
1499
+ {
1500
+ className: tableWrapClass({
1501
+ stackBelow: props.stackBelow,
1502
+ bordered: props.bordered,
1503
+ bleed: props.bleed,
1504
+ bleedEnd: props.bleedEnd,
1505
+ cards
1506
+ }),
1507
+ "data-density": props.density || "comfortable"
1508
+ },
1509
+ inertProps()
1510
+ ),
1511
+ h4(
1512
+ "table",
1513
+ {
1514
+ className: cx(
1515
+ tableClass({
1516
+ stackBelow: props.stackBelow,
1517
+ align: props.align,
1518
+ rowHeight: props.rowHeight,
1519
+ cards,
1520
+ className: props.className
1521
+ }),
1522
+ "aura-tbl--skeleton"
1523
+ ),
1524
+ role: stacked ? "table" : void 0
1525
+ },
1526
+ skeletonColgroup(cols),
1527
+ head,
1528
+ skeletonBody(cols, n3, stacked)
1529
+ )
1530
+ );
1531
+ return cardsFrame(table, {
1532
+ stackBelow: props.stackBelow,
1533
+ bleed: props.bleed,
1534
+ bleedEnd: props.bleedEnd,
1535
+ cards
1536
+ });
1537
+ }
1538
+
1539
+ // src/PageHeader.tsx
1540
+ import * as React6 from "react";
1541
+ var h5 = React6.createElement;
1542
+ var PageHeader = React6.forwardRef(function PageHeader2(props, ref) {
1373
1543
  const attrs2 = {};
1374
1544
  Object.keys(props).forEach(function(k) {
1375
1545
  if (k === "id" || k === "lang" || k === "dir" || k === "role" || /^(aria|data)-/.test(k))
@@ -1385,7 +1555,7 @@ var PageHeader = React5.forwardRef(function PageHeader2(props, ref) {
1385
1555
  const size = props.size === "compact" || props.size === "hero" || props.size === "hero-lg" ? props.size : null;
1386
1556
  const eyebrow = props.eyebrow;
1387
1557
  const plainEyebrow = typeof eyebrow === "string" || typeof eyebrow === "number";
1388
- const heading = h4(
1558
+ const heading = h5(
1389
1559
  "h" + level,
1390
1560
  {
1391
1561
  className: "aura-page-header__title",
@@ -1397,7 +1567,7 @@ var PageHeader = React5.forwardRef(function PageHeader2(props, ref) {
1397
1567
  );
1398
1568
  const hasActions = props.actions != null && props.actions !== false;
1399
1569
  const bar = hasActions && (props.actionsBarBelow === "sm" || props.actionsBarBelow === "md") ? props.actionsBarBelow : null;
1400
- return h4(
1570
+ return h5(
1401
1571
  "div",
1402
1572
  Object.assign(attrs2, {
1403
1573
  ref,
@@ -1414,32 +1584,32 @@ var PageHeader = React5.forwardRef(function PageHeader2(props, ref) {
1414
1584
  ),
1415
1585
  style: props.style
1416
1586
  }),
1417
- h4(
1587
+ h5(
1418
1588
  "div",
1419
1589
  { className: "aura-page-header__text" },
1420
- props.breadcrumb != null && props.breadcrumb !== false ? h4("div", { className: "aura-page-header__breadcrumb" }, props.breadcrumb) : null,
1421
- shown(eyebrow) ? plainEyebrow ? h4("p", { className: "aura-page-header__eyebrow" }, eyebrow) : h4("div", { className: "aura-page-header__eyebrow aura-page-header__eyebrow--rich" }, eyebrow) : null,
1422
- shown(props.titleAddon) ? h4(
1590
+ props.breadcrumb != null && props.breadcrumb !== false ? h5("div", { className: "aura-page-header__breadcrumb" }, props.breadcrumb) : null,
1591
+ shown(eyebrow) ? plainEyebrow ? h5("p", { className: "aura-page-header__eyebrow" }, eyebrow) : h5("div", { className: "aura-page-header__eyebrow aura-page-header__eyebrow--rich" }, eyebrow) : null,
1592
+ shown(props.titleAddon) ? h5(
1423
1593
  "div",
1424
1594
  { className: "aura-page-header__title-row" },
1425
1595
  heading,
1426
- h4("div", { className: "aura-page-header__title-addon" }, props.titleAddon)
1596
+ h5("div", { className: "aura-page-header__title-addon" }, props.titleAddon)
1427
1597
  ) : heading,
1428
- shown(props.subtitle) ? h4("div", { className: "aura-page-header__subtitle" }, props.subtitle) : null,
1429
- props.meta != null && props.meta !== false ? h4("div", { className: "aura-page-header__meta" }, props.meta) : null
1598
+ shown(props.subtitle) ? h5("div", { className: "aura-page-header__subtitle" }, props.subtitle) : null,
1599
+ props.meta != null && props.meta !== false ? h5("div", { className: "aura-page-header__meta" }, props.meta) : null
1430
1600
  ),
1431
- props.actions != null && props.actions !== false ? h4(
1601
+ props.actions != null && props.actions !== false ? h5(
1432
1602
  "div",
1433
1603
  { className: "aura-page-header__actions" },
1434
- bar && props.actionsStatus != null && props.actionsStatus !== false ? h4("div", { className: "aura-page-header__status", role: "status" }, props.actionsStatus) : null,
1604
+ bar && props.actionsStatus != null && props.actionsStatus !== false ? h5("div", { className: "aura-page-header__status", role: "status" }, props.actionsStatus) : null,
1435
1605
  props.actions
1436
1606
  ) : null
1437
1607
  );
1438
1608
  });
1439
1609
 
1440
1610
  // src/tiles.tsx
1441
- import * as React6 from "react";
1442
- var h5 = React6.createElement;
1611
+ import * as React7 from "react";
1612
+ var h6 = React7.createElement;
1443
1613
  var STATUS_ICON = {
1444
1614
  down: IconCircleAlert,
1445
1615
  problem: IconTriangleAlert,
@@ -1472,7 +1642,7 @@ function attrs(props) {
1472
1642
  });
1473
1643
  return out;
1474
1644
  }
1475
- var comma = h5("span", { className: "aura-status-tile__sep" }, ",");
1645
+ var comma = h6("span", { className: "aura-status-tile__sep" }, ",");
1476
1646
  function statusTileElement(props, ref, Link, t, titleRef) {
1477
1647
  const status = STATUS_ICON[props.status] ? props.status : "unknown";
1478
1648
  if (status !== props.status)
@@ -1488,43 +1658,43 @@ function statusTileElement(props, ref, Link, t, titleRef) {
1488
1658
  };
1489
1659
  const hasValue = has(props.value), hasMeta = has(props.meta);
1490
1660
  const Tag = props.href ? Link : "div";
1491
- return h5(
1661
+ return h6(
1492
1662
  Tag,
1493
1663
  Object.assign(attrs(props), {
1494
1664
  ref,
1495
1665
  href: props.href,
1496
1666
  className: cx("aura-status-tile", "aura-status-tile--" + status, props.href && "is-interactive", props.className)
1497
1667
  }),
1498
- h5(
1668
+ h6(
1499
1669
  "span",
1500
1670
  { className: "aura-status-tile__head" },
1501
- h5(Icon, { name: h5(STATUS_ICON[status]), size: 16, className: "aura-status-tile__icon" }),
1502
- h5("span", { className: "aura-status-tile__title", ref: titleRef }, props.title, comma),
1503
- h5("span", { className: "aura-sr-only" }, word + (hasValue || hasMeta || markers.length ? "," : "")),
1504
- hasValue ? h5(
1671
+ h6(Icon, { name: h6(STATUS_ICON[status]), size: 16, className: "aura-status-tile__icon" }),
1672
+ h6("span", { className: "aura-status-tile__title", ref: titleRef }, props.title, comma),
1673
+ h6("span", { className: "aura-sr-only" }, word + (hasValue || hasMeta || markers.length ? "," : "")),
1674
+ hasValue ? h6(
1505
1675
  "span",
1506
1676
  { className: cx("aura-status-tile__value", "is-" + valueTone) },
1507
1677
  props.value,
1508
1678
  hasMeta || markers.length ? comma : null
1509
1679
  ) : null
1510
1680
  ),
1511
- hasMeta || markers.length ? h5(
1681
+ hasMeta || markers.length ? h6(
1512
1682
  "span",
1513
1683
  { className: "aura-status-tile__foot" },
1514
- hasMeta ? h5("span", { className: "aura-status-tile__meta" }, props.meta, markers.length ? comma : null) : null,
1515
- markers.length ? h5(
1684
+ hasMeta ? h6("span", { className: "aura-status-tile__meta" }, props.meta, markers.length ? comma : null) : null,
1685
+ markers.length ? h6(
1516
1686
  "span",
1517
1687
  { className: "aura-status-tile__markers" },
1518
1688
  markers.map(function(m, i) {
1519
- return h5(
1689
+ return h6(
1520
1690
  "span",
1521
1691
  {
1522
1692
  key: i,
1523
1693
  className: cx("aura-status-tile__marker", "is-" + (m.tone || "neutral")),
1524
1694
  "data-aura-tip": m.label
1525
1695
  },
1526
- h5(Icon, { name: m.icon, size: 14 }),
1527
- h5("span", { className: "aura-sr-only" }, m.label + (i < markers.length - 1 ? "," : ""))
1696
+ h6(Icon, { name: m.icon, size: 14 }),
1697
+ h6("span", { className: "aura-sr-only" }, m.label + (i < markers.length - 1 ? "," : ""))
1528
1698
  );
1529
1699
  })
1530
1700
  ) : null
@@ -1534,13 +1704,13 @@ function statusTileElement(props, ref, Link, t, titleRef) {
1534
1704
  function ServerStatusTile(props) {
1535
1705
  return statusTileElement(props, void 0, props.linkComponent || "a", STRINGS.en);
1536
1706
  }
1537
- var TileGrid = React6.forwardRef(function TileGrid2(props, ref) {
1707
+ var TileGrid = React7.forwardRef(function TileGrid2(props, ref) {
1538
1708
  const style = Object.assign(
1539
1709
  {},
1540
1710
  respVars("aura-grid-cols", props.columns == null ? { base: 2, md: 3 } : props.columns),
1541
1711
  props.style
1542
1712
  );
1543
- return h5(
1713
+ return h6(
1544
1714
  "ul",
1545
1715
  Object.assign(attrs(props), {
1546
1716
  ref,
@@ -1550,16 +1720,16 @@ var TileGrid = React6.forwardRef(function TileGrid2(props, ref) {
1550
1720
  }),
1551
1721
  /* toArray drops null and booleans and keys each element; a Fragment's children are items too. */
1552
1722
  flat(props.children).map(function(c, i) {
1553
- return h5("li", { key: React6.isValidElement(c) && c.key != null ? c.key : i }, c);
1723
+ return h6("li", { key: React7.isValidElement(c) && c.key != null ? c.key : i }, c);
1554
1724
  })
1555
1725
  );
1556
1726
  });
1557
1727
  function flat(children) {
1558
1728
  const out = [];
1559
- React6.Children.toArray(children).forEach(function(c) {
1560
- if (React6.isValidElement(c) && c.type === React6.Fragment)
1729
+ React7.Children.toArray(children).forEach(function(c) {
1730
+ if (React7.isValidElement(c) && c.type === React7.Fragment)
1561
1731
  flat(c.props.children).forEach(function(x) {
1562
- out.push(React6.isValidElement(x) ? React6.cloneElement(x, { key: String(c.key) + "/" + String(x.key) }) : x);
1732
+ out.push(React7.isValidElement(x) ? React7.cloneElement(x, { key: String(c.key) + "/" + String(x.key) }) : x);
1563
1733
  });
1564
1734
  else if (c !== "") out.push(c);
1565
1735
  });
@@ -1573,7 +1743,7 @@ function r(n3) {
1573
1743
  function num(v) {
1574
1744
  return typeof v === "number" && isFinite(v) ? v : null;
1575
1745
  }
1576
- var Sparkline = React6.forwardRef(function Sparkline2(props, ref) {
1746
+ var Sparkline = React7.forwardRef(function Sparkline2(props, ref) {
1577
1747
  const wh = SIZES2[props.size || "sm"] || SIZES2.sm;
1578
1748
  const W = wh[0], H = wh[1];
1579
1749
  const data = (props.data || []).map(num);
@@ -1603,7 +1773,7 @@ var Sparkline = React6.forwardRef(function Sparkline2(props, ref) {
1603
1773
  data.forEach(function(v, i) {
1604
1774
  if (v == null) return;
1605
1775
  const prev = i > 0 && data[i - 1] != null, next = i < n3 - 1 && data[i + 1] != null;
1606
- if (!prev && !next) dots.push(h5("circle", { key: "d" + i, cx: r(x(i)), cy: r(y(v)), r: 1.5 }));
1776
+ if (!prev && !next) dots.push(h6("circle", { key: "d" + i, cx: r(x(i)), cy: r(y(v)), r: 1.5 }));
1607
1777
  else d += (prev ? "L" : "M") + r(x(i)) + " " + r(y(v));
1608
1778
  });
1609
1779
  const mode = props.failures || "none";
@@ -1613,10 +1783,10 @@ var Sparkline = React6.forwardRef(function Sparkline2(props, ref) {
1613
1783
  if (!props.failed[i]) return;
1614
1784
  if (mode === "band") {
1615
1785
  const w = Math.max(2, step || W), left = Math.max(0, x(i) - w / 2), right = Math.min(W, x(i) + w / 2);
1616
- fails.push(h5("rect", { key: "f" + i, x: r(left), y: 0, width: r(right - left), height: H }));
1786
+ fails.push(h6("rect", { key: "f" + i, x: r(left), y: 0, width: r(right - left), height: H }));
1617
1787
  } else
1618
1788
  fails.push(
1619
- h5("rect", {
1789
+ h6("rect", {
1620
1790
  key: "f" + i,
1621
1791
  x: r(Math.max(0, Math.min(W - 1.5, x(i) - 0.75))),
1622
1792
  y: H - 6,
@@ -1626,7 +1796,7 @@ var Sparkline = React6.forwardRef(function Sparkline2(props, ref) {
1626
1796
  );
1627
1797
  });
1628
1798
  const named = !!props.label;
1629
- return h5(
1799
+ return h6(
1630
1800
  "svg",
1631
1801
  Object.assign(attrs(props), {
1632
1802
  ref,
@@ -1639,10 +1809,10 @@ var Sparkline = React6.forwardRef(function Sparkline2(props, ref) {
1639
1809
  "aria-hidden": named ? void 0 : true,
1640
1810
  focusable: "false"
1641
1811
  }),
1642
- fails.length && mode === "band" ? h5("g", { className: "aura-sparkline__band" }, fails) : null,
1643
- d ? h5("path", { className: "aura-sparkline__line", d }) : null,
1644
- dots.length ? h5("g", { className: "aura-sparkline__dots" }, dots) : null,
1645
- fails.length && mode === "ticks" ? h5("g", { className: "aura-sparkline__ticks" }, fails) : null
1812
+ fails.length && mode === "band" ? h6("g", { className: "aura-sparkline__band" }, fails) : null,
1813
+ d ? h6("path", { className: "aura-sparkline__line", d }) : null,
1814
+ dots.length ? h6("g", { className: "aura-sparkline__dots" }, dots) : null,
1815
+ fails.length && mode === "ticks" ? h6("g", { className: "aura-sparkline__ticks" }, fails) : null
1646
1816
  );
1647
1817
  });
1648
1818
  export {
@@ -1659,6 +1829,7 @@ export {
1659
1829
  ServerStat as Stat,
1660
1830
  ServerStatusPill as StatusPill,
1661
1831
  ServerStatusTile as StatusTile,
1832
+ TableSkeleton,
1662
1833
  TileGrid,
1663
1834
  scale as brandScale,
1664
1835
  breakpoints,
package/dist/styles.css CHANGED
@@ -105,7 +105,10 @@ button.aura-btn--creative[aria-disabled='true']:hover { box-shadow: var(--aura-s
105
105
  background: var(--aura-bg-surface);
106
106
  color: var(--aura-fg-primary);
107
107
  }
108
- .aura-table__scroll { position: relative; overflow: auto; overscroll-behavior: contain; height: var(--aura-table-h, auto); }
108
+ /* 5.51 (Chamber-OS 163): only the sideways axis is contained (a trackpad swipe in a wide grid never goes back a page);
109
+ * a vertical wheel over a grid that scrolls sideways still scrolls the page, and a fixed-height grid scrolls inside
110
+ * first, then chains to the page at its end. */
111
+ .aura-table__scroll { position: relative; overflow: auto; overscroll-behavior-x: contain; overscroll-behavior-y: auto; height: var(--aura-table-h, auto); }
109
112
  /* 5.30: more columns past the end edge — a soft shadow over the grid's end edge (not over its scrollbars, its footer
110
113
  * or the column button), so it reads as scrolling sideways. JavaScript places it (top, height, scrollbar inset). */
111
114
  .aura-table__edge {
@@ -440,6 +443,13 @@ a.aura-icon-btn { text-decoration: none; }
440
443
  background: var(--aura-status-neutral-bg);
441
444
  color: var(--aura-status-neutral-fg);
442
445
  }
446
+ /* 5.51 (Chamber-OS 158, addendum 61): wrap — the words break inside the pill when its box is narrower; the icon stays
447
+ * beside the first line. Corners are aura-radius-lg (16px), not full: on one line (20px tall) that still clamps to fully
448
+ * round ends, and a wrapped pill is a rounded rectangle, not a tall lozenge. */
449
+ .aura-pill.is-wrap { align-items: flex-start; white-space: normal; border-radius: var(--aura-radius-lg); }
450
+ .aura-pill.is-wrap > .aura-icon { margin-top: calc((max(16px, 1rem) - 12px) / 2); }
451
+ .aura-pill.is-wrap:lang(th) > .aura-icon { margin-top: calc((max(18px, 1.125rem) - 12px) / 2); }
452
+ .aura-pill__text { min-width: 0; overflow-wrap: anywhere; }
443
453
  .aura-pill--progress { background: var(--aura-status-progress-bg); color: var(--aura-status-progress-fg); }
444
454
  .aura-pill--ready { background: var(--aura-status-ready-bg); color: var(--aura-status-ready-fg); }
445
455
  .aura-pill--warning { background: var(--aura-status-warning-bg); color: var(--aura-status-warning-fg); }
@@ -529,9 +539,10 @@ a.aura-icon-btn { text-decoration: none; }
529
539
  .aura-input__suffix { padding: 0 var(--aura-space-3) 0 0; color: var(--aura-fg-secondary); font-size: max(13px, .8125rem); white-space: nowrap; }
530
540
  .aura-field.is-invalid .aura-input, .aura-field.is-invalid .aura-textarea { border-color: var(--aura-border-danger); }
531
541
  /* 5.50 (Chamber-OS 156): a control the page marks aria-invalid="true" itself gets the same edge, message or not (a
532
- * disabled field keeps its disabled edge, as with is-invalid). */
533
- .aura-field:not(.is-disabled) .aura-input:has(> .aura-input__control[aria-invalid="true"]),
534
- .aura-field:not(.is-disabled) .aura-textarea[aria-invalid="true"] { border-color: var(--aura-border-danger); }
542
+ * disabled field keeps its disabled edge, as with is-invalid; 5.51: so does a disabled control inside an enabled custom
543
+ * Field). */
544
+ .aura-field:not(.is-disabled) .aura-input:has(> .aura-input__control[aria-invalid="true"]:not(:disabled)),
545
+ .aura-field:not(.is-disabled) .aura-textarea[aria-invalid="true"]:not(:disabled) { border-color: var(--aura-border-danger); }
535
546
  .aura-field.is-disabled .aura-input { background: var(--aura-bg-input-disabled); color: var(--aura-fg-secondary); border-color: var(--aura-border-default); }
536
547
  .aura-field.is-disabled .aura-input__control { cursor: not-allowed; }
537
548
  /* A read-only text field. Only an input: `:read-only` also matches any element that isn't editable — a
@@ -1864,6 +1875,16 @@ button.aura-stepper__step:hover .aura-stepper__label { text-decoration: underlin
1864
1875
  * (So a FilterBar with only chips needs a width from its parent — it is full width in a block.) */
1865
1876
  .aura-filterbar__chips { contain: inline-size; }
1866
1877
  .aura-filterbar__chips > .aura-tag .aura-tag__text { max-width: none; min-width: 0; }
1878
+ /* 5.51 (Chamber-OS 160): a toggle Tag among FilterBar's controls (or in its sheet) is a filter, not a label to cut:
1879
+ * from 640px it shows its whole text, cut only when wider than the bar. Below 640px (outside the sheet) the 24ch cap
1880
+ * and its tip stay. */
1881
+ @media (min-width: 640px) {
1882
+ .aura-filterbar .aura-tag.is-selectable { max-width: 100%; min-width: 0; }
1883
+ .aura-filterbar .aura-tag.is-selectable .aura-tag__text { max-width: none; min-width: 0; }
1884
+ }
1885
+ /* …and in the Filters sheet at any width: it is full width, with every control labelled. */
1886
+ .aura-filterbar--sheet .aura-tag.is-selectable { max-width: 100%; min-width: 0; }
1887
+ .aura-filterbar--sheet .aura-tag.is-selectable .aura-tag__text { max-width: none; min-width: 0; }
1867
1888
  .aura-filterbar__clear {
1868
1889
  border: 0; background: transparent; padding: 4px var(--aura-space-2); border-radius: var(--aura-radius-sm);
1869
1890
  font: inherit; font-size: max(13px, .8125rem); font-weight: 500; color: var(--aura-fg-accent); cursor: pointer; text-decoration: underline; text-underline-offset: 2px;
@@ -2147,6 +2168,12 @@ button.aura-stepper__step:hover .aura-stepper__label { text-decoration: underlin
2147
2168
  var(--aura-tbl-bg, var(--aura-bg-surface));
2148
2169
  }
2149
2170
  .aura-tbl { width: 100%; border-collapse: collapse; border-spacing: 0; font-size: max(13px, .8125rem); line-height: max(20px, 1.25rem); }
2171
+ /* 5.52 (Chamber-OS 164): a loading Table has no content to size its columns from, so they take the head's widths
2172
+ * (or even shares); each placeholder bar sits on the row's 20px line, so a skeleton row is as tall as a text row. */
2173
+ .aura-tbl--skeleton { table-layout: fixed; }
2174
+ .aura-tbl__row--skeleton .aura-skel--text { display: block; margin: 5px 0; margin: calc((1lh - 10px) / 2) 0; }
2175
+ .aura-tbl__row--skeleton .aura-tbl__td.is-end > .aura-skel--text { margin-inline-start: auto; }
2176
+ .aura-tbl__row--skeleton .aura-tbl__td.is-end > .aura-skel-lines { align-items: flex-end; }
2150
2177
  .aura-tbl__caption { caption-side: top; padding: var(--aura-space-4) var(--aura-space-6) var(--aura-space-3); text-align: left; font-size: max(14px, .875rem); font-weight: 600; }
2151
2178
  /* 5.30: from 640px a cell is at least 10ch wide, so the table never squeezes a column to one letter; a longer word (an
2152
2179
  * email, a URL) still breaks to fit instead of widening the table. Phones keep fitting the box: use stackBelow there. */
@@ -107,7 +107,10 @@ button.aura-btn--creative[aria-disabled='true']:hover { box-shadow: var(--aura-s
107
107
  background: var(--aura-bg-surface);
108
108
  color: var(--aura-fg-primary);
109
109
  }
110
- .aura-table__scroll { position: relative; overflow: auto; overscroll-behavior: contain; height: var(--aura-table-h, auto); }
110
+ /* 5.51 (Chamber-OS 163): only the sideways axis is contained (a trackpad swipe in a wide grid never goes back a page);
111
+ * a vertical wheel over a grid that scrolls sideways still scrolls the page, and a fixed-height grid scrolls inside
112
+ * first, then chains to the page at its end. */
113
+ .aura-table__scroll { position: relative; overflow: auto; overscroll-behavior-x: contain; overscroll-behavior-y: auto; height: var(--aura-table-h, auto); }
111
114
  /* 5.30: more columns past the end edge — a soft shadow over the grid's end edge (not over its scrollbars, its footer
112
115
  * or the column button), so it reads as scrolling sideways. JavaScript places it (top, height, scrollbar inset). */
113
116
  .aura-table__edge {
@@ -442,6 +445,13 @@ a.aura-icon-btn { text-decoration: none; }
442
445
  background: var(--aura-status-neutral-bg);
443
446
  color: var(--aura-status-neutral-fg);
444
447
  }
448
+ /* 5.51 (Chamber-OS 158, addendum 61): wrap — the words break inside the pill when its box is narrower; the icon stays
449
+ * beside the first line. Corners are aura-radius-lg (16px), not full: on one line (20px tall) that still clamps to fully
450
+ * round ends, and a wrapped pill is a rounded rectangle, not a tall lozenge. */
451
+ .aura-pill.is-wrap { align-items: flex-start; white-space: normal; border-radius: var(--aura-radius-lg); }
452
+ .aura-pill.is-wrap > .aura-icon { margin-top: calc((max(16px, 1rem) - 12px) / 2); }
453
+ .aura-pill.is-wrap:lang(th) > .aura-icon { margin-top: calc((max(18px, 1.125rem) - 12px) / 2); }
454
+ .aura-pill__text { min-width: 0; overflow-wrap: anywhere; }
445
455
  .aura-pill--progress { background: var(--aura-status-progress-bg); color: var(--aura-status-progress-fg); }
446
456
  .aura-pill--ready { background: var(--aura-status-ready-bg); color: var(--aura-status-ready-fg); }
447
457
  .aura-pill--warning { background: var(--aura-status-warning-bg); color: var(--aura-status-warning-fg); }
@@ -531,9 +541,10 @@ a.aura-icon-btn { text-decoration: none; }
531
541
  .aura-input__suffix { padding: 0 var(--aura-space-3) 0 0; color: var(--aura-fg-secondary); font-size: max(13px, .8125rem); white-space: nowrap; }
532
542
  .aura-field.is-invalid .aura-input, .aura-field.is-invalid .aura-textarea { border-color: var(--aura-border-danger); }
533
543
  /* 5.50 (Chamber-OS 156): a control the page marks aria-invalid="true" itself gets the same edge, message or not (a
534
- * disabled field keeps its disabled edge, as with is-invalid). */
535
- .aura-field:not(.is-disabled) .aura-input:has(> .aura-input__control[aria-invalid="true"]),
536
- .aura-field:not(.is-disabled) .aura-textarea[aria-invalid="true"] { border-color: var(--aura-border-danger); }
544
+ * disabled field keeps its disabled edge, as with is-invalid; 5.51: so does a disabled control inside an enabled custom
545
+ * Field). */
546
+ .aura-field:not(.is-disabled) .aura-input:has(> .aura-input__control[aria-invalid="true"]:not(:disabled)),
547
+ .aura-field:not(.is-disabled) .aura-textarea[aria-invalid="true"]:not(:disabled) { border-color: var(--aura-border-danger); }
537
548
  .aura-field.is-disabled .aura-input { background: var(--aura-bg-input-disabled); color: var(--aura-fg-secondary); border-color: var(--aura-border-default); }
538
549
  .aura-field.is-disabled .aura-input__control { cursor: not-allowed; }
539
550
  /* A read-only text field. Only an input: `:read-only` also matches any element that isn't editable — a
@@ -1866,6 +1877,16 @@ button.aura-stepper__step:hover .aura-stepper__label { text-decoration: underlin
1866
1877
  * (So a FilterBar with only chips needs a width from its parent — it is full width in a block.) */
1867
1878
  .aura-filterbar__chips { contain: inline-size; }
1868
1879
  .aura-filterbar__chips > .aura-tag .aura-tag__text { max-width: none; min-width: 0; }
1880
+ /* 5.51 (Chamber-OS 160): a toggle Tag among FilterBar's controls (or in its sheet) is a filter, not a label to cut:
1881
+ * from 640px it shows its whole text, cut only when wider than the bar. Below 640px (outside the sheet) the 24ch cap
1882
+ * and its tip stay. */
1883
+ @media (min-width: 640px) {
1884
+ .aura-filterbar .aura-tag.is-selectable { max-width: 100%; min-width: 0; }
1885
+ .aura-filterbar .aura-tag.is-selectable .aura-tag__text { max-width: none; min-width: 0; }
1886
+ }
1887
+ /* …and in the Filters sheet at any width: it is full width, with every control labelled. */
1888
+ .aura-filterbar--sheet .aura-tag.is-selectable { max-width: 100%; min-width: 0; }
1889
+ .aura-filterbar--sheet .aura-tag.is-selectable .aura-tag__text { max-width: none; min-width: 0; }
1869
1890
  .aura-filterbar__clear {
1870
1891
  border: 0; background: transparent; padding: 4px var(--aura-space-2); border-radius: var(--aura-radius-sm);
1871
1892
  font: inherit; font-size: max(13px, .8125rem); font-weight: 500; color: var(--aura-fg-accent); cursor: pointer; text-decoration: underline; text-underline-offset: 2px;
@@ -2149,6 +2170,12 @@ button.aura-stepper__step:hover .aura-stepper__label { text-decoration: underlin
2149
2170
  var(--aura-tbl-bg, var(--aura-bg-surface));
2150
2171
  }
2151
2172
  .aura-tbl { width: 100%; border-collapse: collapse; border-spacing: 0; font-size: max(13px, .8125rem); line-height: max(20px, 1.25rem); }
2173
+ /* 5.52 (Chamber-OS 164): a loading Table has no content to size its columns from, so they take the head's widths
2174
+ * (or even shares); each placeholder bar sits on the row's 20px line, so a skeleton row is as tall as a text row. */
2175
+ .aura-tbl--skeleton { table-layout: fixed; }
2176
+ .aura-tbl__row--skeleton .aura-skel--text { display: block; margin: 5px 0; margin: calc((1lh - 10px) / 2) 0; }
2177
+ .aura-tbl__row--skeleton .aura-tbl__td.is-end > .aura-skel--text { margin-inline-start: auto; }
2178
+ .aura-tbl__row--skeleton .aura-tbl__td.is-end > .aura-skel-lines { align-items: flex-end; }
2152
2179
  .aura-tbl__caption { caption-side: top; padding: var(--aura-space-4) var(--aura-space-6) var(--aura-space-3); text-align: left; font-size: max(14px, .875rem); font-weight: 600; }
2153
2180
  /* 5.30: from 640px a cell is at least 10ch wide, so the table never squeezes a column to one letter; a longer word (an
2154
2181
  * email, a URL) still breaks to fit instead of widening the table. Phones keep fitting the box: use stackBelow there. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jirawatpyk/aura-react",
3
- "version": "5.50.0",
3
+ "version": "5.52.0",
4
4
  "description": "AURA Design System — React components (Enterprise Standard, Human Creative). Thai-first: Buddhist-era dates, Thai collation.",
5
5
  "license": "MIT",
6
6
  "type": "module",