@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.
@@ -958,6 +958,7 @@ var Icon = React2.forwardRef(function Icon2(props, ref) {
958
958
  var iconNames = Object.keys(map);
959
959
 
960
960
  // src/icons.ts
961
+ var IconMinus = /* @__PURE__ */ defineIcon("minus", [["path", { d: "M5 12h14" }]]);
961
962
  var IconCircleAlert = /* @__PURE__ */ defineIcon("circle-alert", [
962
963
  ["circle", { cx: "12", cy: "12", r: "10" }],
963
964
  ["line", { x1: "12", x2: "12", y1: "8", y2: "12" }],
@@ -1000,6 +1001,14 @@ var IconInbox = /* @__PURE__ */ defineIcon("inbox", [
1000
1001
  { d: "M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z" }
1001
1002
  ]
1002
1003
  ]);
1004
+ var IconTrendingUp = /* @__PURE__ */ defineIcon("trending-up", [
1005
+ ["path", { d: "M16 7h6v6" }],
1006
+ ["path", { d: "m22 7-8.5 8.5-5-5L2 17" }]
1007
+ ]);
1008
+ var IconTrendingDown = /* @__PURE__ */ defineIcon("trending-down", [
1009
+ ["path", { d: "M16 17h6v-6" }],
1010
+ ["path", { d: "m22 17-8.5-8.5-5 5L2 7" }]
1011
+ ]);
1003
1012
 
1004
1013
  // src/display.tsx
1005
1014
  var h2 = React3.createElement;
@@ -1090,12 +1099,31 @@ function badgeElement(props, ref) {
1090
1099
  );
1091
1100
  }
1092
1101
  function emptyStateElement(props, ref) {
1093
- const HT = "h" + (props.headingLevel || 3);
1102
+ const HT = props.headingLevel === false ? "p" : "h" + (props.headingLevel || 3);
1103
+ const rest = omit(props, [
1104
+ "title",
1105
+ "description",
1106
+ "icon",
1107
+ "action",
1108
+ "size",
1109
+ "bordered",
1110
+ "headingLevel",
1111
+ "tone",
1112
+ "className",
1113
+ "children"
1114
+ ]);
1094
1115
  return /* @__PURE__ */ React3.createElement(
1095
1116
  "div",
1096
1117
  {
1118
+ ...rest,
1097
1119
  ref,
1098
- className: cx("aura-empty", props.size === "sm" && "is-sm", props.bordered && "is-bordered", props.className)
1120
+ className: cx(
1121
+ "aura-empty",
1122
+ props.size === "sm" && "is-sm",
1123
+ props.bordered && "is-bordered",
1124
+ props.tone === "danger" && "is-danger",
1125
+ props.className
1126
+ )
1099
1127
  },
1100
1128
  /* @__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
1129
  /* @__PURE__ */ React3.createElement(HT, { className: "aura-empty__title" }, props.title),
@@ -1103,6 +1131,66 @@ function emptyStateElement(props, ref) {
1103
1131
  props.action ? /* @__PURE__ */ React3.createElement("div", { className: "aura-empty__action" }, props.action) : null
1104
1132
  );
1105
1133
  }
1134
+ function statElement(props, ref, Link) {
1135
+ const ch = props.change;
1136
+ const dir = ch && (ch.direction || "flat");
1137
+ const tone2 = ch && (ch.tone || (dir === "up" ? "positive" : dir === "down" ? "negative" : "neutral"));
1138
+ const v = props.value;
1139
+ 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, ""));
1140
+ const Tag = props.href ? Link : props.onClick ? "button" : "div";
1141
+ const interactive = !!(props.href || props.onClick);
1142
+ if (props.headingLevel && Tag === "button")
1143
+ devWarnOnce(
1144
+ "stat-heading-button",
1145
+ "Stat `headingLevel` is ignored with `onClick`: a heading can\u2019t sit in a button. Use `href`, or put the heading outside."
1146
+ );
1147
+ const LabelTag = props.headingLevel && Tag !== "button" ? "h" + props.headingLevel : "span";
1148
+ const HeadTag = LabelTag === "span" ? "span" : "div";
1149
+ return /* @__PURE__ */ React3.createElement(
1150
+ Tag,
1151
+ {
1152
+ ref,
1153
+ className: cx("aura-stat", interactive && "is-interactive", props.loading && "is-loading", props.className),
1154
+ href: props.href,
1155
+ onClick: props.onClick,
1156
+ type: Tag === "button" ? "button" : void 0,
1157
+ "aria-busy": props.loading || void 0
1158
+ },
1159
+ /* @__PURE__ */ React3.createElement(HeadTag, { className: "aura-stat__head" }, /* @__PURE__ */ React3.createElement(LabelTag, { className: "aura-stat__label" }, props.label), props.icon ? /* @__PURE__ */ React3.createElement("span", { className: "aura-stat__icon" }, /* @__PURE__ */ React3.createElement(Icon, { name: props.icon })) : null),
1160
+ props.loading ? /* @__PURE__ */ React3.createElement("span", { className: "aura-stat__value" }, /* @__PURE__ */ React3.createElement("span", { className: "aura-skel aura-stat__skel" })) : /* @__PURE__ */ React3.createElement("span", { className: cx("aura-stat__value", numeric && "is-numeric") }, props.value, props.unit ? /* @__PURE__ */ React3.createElement("span", { className: "aura-stat__unit" }, props.unit) : null),
1161
+ ch && !props.loading || props.caption ? /* @__PURE__ */ React3.createElement("span", { className: "aura-stat__foot" }, ch && !props.loading ? /* @__PURE__ */ React3.createElement("span", { className: cx("aura-stat__change", "is-" + tone2) }, /* @__PURE__ */ React3.createElement(
1162
+ Icon,
1163
+ {
1164
+ name: dir === "up" ? /* @__PURE__ */ React3.createElement(IconTrendingUp, null) : dir === "down" ? /* @__PURE__ */ React3.createElement(IconTrendingDown, null) : /* @__PURE__ */ React3.createElement(IconMinus, null),
1165
+ size: 14
1166
+ }
1167
+ ), /* @__PURE__ */ React3.createElement("span", null, ch.value)) : null, ch && ch.label && !props.loading ? /* @__PURE__ */ React3.createElement("span", { className: "aura-stat__caption" }, ch.label) : null, props.caption ? /* @__PURE__ */ React3.createElement("span", { className: "aura-stat__caption" }, props.caption) : null) : null
1168
+ );
1169
+ }
1170
+ var AVATAR_TONES = ["progress", "ready", "neutral", "warning"];
1171
+ function initials(name) {
1172
+ const parts = String(name || "?").trim().split(/\s+/);
1173
+ return ((parts[0] || "?")[0] + (parts.length > 1 ? parts[parts.length - 1][0] : parts[0][1] || "")).toUpperCase();
1174
+ }
1175
+ function avatarElement(props, ref, broken, onError) {
1176
+ const size = props.size || "md";
1177
+ let hash = 0;
1178
+ String(props.name || "").split("").forEach(function(ch) {
1179
+ hash = hash * 31 + ch.charCodeAt(0) >>> 0;
1180
+ });
1181
+ const tone2 = AVATAR_TONES[hash % AVATAR_TONES.length];
1182
+ return /* @__PURE__ */ React3.createElement(
1183
+ "span",
1184
+ {
1185
+ ref,
1186
+ className: cx("aura-avatar", "aura-avatar--" + size, "aura-avatar--" + tone2, props.className),
1187
+ role: "img",
1188
+ "aria-label": props.name + (props.status ? ", " + props.status : "")
1189
+ },
1190
+ props.src && broken !== props.src ? /* @__PURE__ */ React3.createElement("img", { key: props.src, src: props.src, alt: "", onError }) : /* @__PURE__ */ React3.createElement("span", { "aria-hidden": true }, initials(props.name)),
1191
+ props.status === "online" ? /* @__PURE__ */ React3.createElement("span", { className: "aura-avatar__status", "aria-hidden": true }) : null
1192
+ );
1193
+ }
1106
1194
  function buttonClass(opts = {}) {
1107
1195
  return cx(
1108
1196
  "aura-btn",
@@ -1128,13 +1216,21 @@ function ServerBadge(props) {
1128
1216
  function ServerEmptyState(props) {
1129
1217
  return emptyStateElement(props, void 0);
1130
1218
  }
1219
+ function ServerStat(props) {
1220
+ return statElement(omit(props, ["onClick"]), void 0, props.linkComponent || "a");
1221
+ }
1222
+ function ServerAvatar(props) {
1223
+ return avatarElement(props, void 0, null, void 0);
1224
+ }
1131
1225
  export {
1132
1226
  ServerAlert as Alert,
1227
+ ServerAvatar as Avatar,
1133
1228
  ServerBadge as Badge,
1134
1229
  ServerCard as Card,
1135
1230
  ServerEmptyState as EmptyState,
1136
1231
  Icon,
1137
1232
  STRINGS,
1233
+ ServerStat as Stat,
1138
1234
  ServerStatusPill as StatusPill,
1139
1235
  scale as brandScale,
1140
1236
  breakpoints,
package/dist/styles.css CHANGED
@@ -34,6 +34,16 @@ a.aura-btn { text-decoration: none; }
34
34
  padding-block: var(--aura-space-2); line-height: 1.35; text-align: center; overflow-wrap: anywhere;
35
35
  }
36
36
  .aura-btn.is-loading { cursor: progress; }
37
+ /* 5.14: a button gated with aria-disabled looks unavailable but stays focusable (no pointer-events: none, so the
38
+ * not-allowed cursor and a tooltip still work). */
39
+ button.aura-btn[aria-disabled='true']:not(.is-loading) { opacity: var(--aura-disabled-opacity); cursor: not-allowed; }
40
+ button.aura-btn[aria-disabled='true']:active { transform: none; }
41
+ /* …and hovering it changes nothing: each variant keeps its resting look (the hover rules below are overridden). */
42
+ button.aura-btn--primary[aria-disabled='true']:hover { background: var(--aura-button-primary-bg); }
43
+ button.aura-btn--secondary[aria-disabled='true']:hover, button.aura-btn--ghost[aria-disabled='true']:hover,
44
+ button.aura-btn--danger-secondary[aria-disabled='true']:hover { background: transparent; }
45
+ button.aura-btn--danger[aria-disabled='true']:hover { background: var(--aura-button-danger-bg); }
46
+ button.aura-btn--creative[aria-disabled='true']:hover { box-shadow: var(--aura-shadow-creative); transform: none; }
37
47
  .aura-btn.is-loading:active { transform: none; }
38
48
 
39
49
  /* Focus — ADDED: the source defines none. Solid 2px ring, 2px offset, on every interactive element. */
@@ -868,7 +878,11 @@ a.aura-tab { text-decoration: none; }
868
878
  .aura-drawer--nav .aura-drawer__head { position: absolute; top: var(--aura-space-2); right: var(--aura-space-2); padding: 0; z-index: 1; }
869
879
  .aura-drawer__title { flex: 1; margin: 0; font-size: 16px; line-height: 1.5; font-weight: 600; }
870
880
  .aura-drawer__desc { margin: 0; padding: 0 var(--aura-space-6); font-size: 14px; line-height: 1.7; color: var(--aura-fg-secondary); }
871
- .aura-drawer__body { flex: 1; overflow-y: auto; padding: var(--aura-space-4) var(--aura-space-6); font-size: 14px; line-height: 1.7; }
881
+ .aura-drawer__body {
882
+ flex: 1; overflow-y: auto; padding: var(--aura-space-4) var(--aura-space-6); font-size: 14px; line-height: 1.7;
883
+ /* 5.14 (Chamber-OS 91): a field scrolled into view (focus, the phone keyboard) keeps clear of the head and foot. */
884
+ scroll-padding-block: var(--aura-space-4);
885
+ }
872
886
  .aura-drawer--nav .aura-drawer__body { padding: 0; }
873
887
  .aura-drawer--nav .aura-nav { width: 100%; border-right: 0; }
874
888
  .aura-drawer__foot { display: flex; justify-content: flex-end; flex-wrap: wrap; gap: var(--aura-space-3); padding: var(--aura-space-4) var(--aura-space-6); border-top: 1px solid var(--aura-border-default); }
@@ -913,12 +927,18 @@ a.aura-tab { text-decoration: none; }
913
927
  .aura-grid-layout.is-auto { grid-template-columns: unset; }
914
928
 
915
929
  /* ---------- AppShell ---------- */
916
- .aura-shell { display: flex; min-height: 100vh; min-height: 100dvh; background: var(--aura-bg-canvas); color: var(--aura-fg-primary); font-family: var(--font-sans); }
930
+ .aura-shell {
931
+ display: flex; min-height: 100vh; min-height: 100dvh; background: var(--aura-bg-canvas); color: var(--aura-fg-primary); font-family: var(--font-sans);
932
+ --aura-shell-bar-height: 56px; /* 5.14 (Chamber-OS 104): the top bar's height, for sticky offsets under it */
933
+ }
934
+ .aura-shell--no-bar { --aura-shell-bar-height: 0px; }
935
+ @media (min-width: 1024px) { .aura-shell--menu-bar { --aura-shell-bar-height: 0px; } }
917
936
  .aura-shell__nav { position: sticky; top: 0; height: 100vh; height: 100dvh; flex: none; }
918
937
  .aura-shell__main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
919
938
  .aura-shell__bar {
920
939
  position: sticky; top: 0; z-index: 10; display: flex; align-items: center; gap: var(--aura-space-2);
921
- min-height: 56px; padding: 0 var(--aura-space-6); background: var(--aura-bg-surface); border-bottom: 1px solid var(--aura-border-default);
940
+ box-sizing: border-box; min-height: 56px;
941
+ padding: 0 var(--aura-space-6); background: var(--aura-bg-surface); border-bottom: 1px solid var(--aura-border-default);
922
942
  }
923
943
  /* Responsive in CSS (4.16), so the server's HTML is already right on a phone: below lg the sidebar is hidden and the
924
944
  * menu button shows; from lg up the reverse. JavaScript only opens and closes the drawer. */
@@ -935,10 +955,11 @@ a.aura-tab { text-decoration: none; }
935
955
  .aura-shell__content { flex: 1; min-width: 0; padding: var(--aura-space-6) var(--aura-space-4); }
936
956
  /* 5.7: <main> takes focus (tabIndex -1) for skip links and "the row you acted on is gone"; a landmark gets no ring. */
937
957
  .aura-shell__content:focus { outline: none; }
958
+ .aura-shell__content.is-flush { padding: 0; } /* 5.14 (Chamber-OS 97): contentPadding={false} */
938
959
  @media (min-width: 640px) { .aura-shell__content { padding: var(--aura-space-6); } }
939
960
  @media (min-width: 1024px) { .aura-shell__content { padding: var(--aura-space-8); } }
940
961
  /* The shell already pads its content: a Container directly inside only caps the width. */
941
- .aura-shell__content > .aura-container { padding-left: 0; padding-right: 0; }
962
+ .aura-shell__content:not(.is-flush) > .aura-container { padding-left: 0; padding-right: 0; }
942
963
 
943
964
  /* Totals row (4.19): under the body, a strong top edge; sticky at the bottom of a `height` table with stickyFooter. */
944
965
  .aura-table__total { background: var(--aura-bg-canvas); border-top: 1px solid var(--aura-border-strong); font-weight: 600; }
@@ -958,7 +979,7 @@ button.aura-stat { font: inherit; width: 100%; cursor: pointer; }
958
979
  .aura-stat.is-interactive:hover { border-color: var(--aura-border-strong); }
959
980
  .aura-stat.is-interactive:focus-visible { outline: var(--aura-focus-ring-width) solid var(--aura-focus-ring); outline-offset: var(--aura-focus-ring-offset); }
960
981
  .aura-stat__head { display: flex; align-items: center; justify-content: space-between; gap: var(--aura-space-2); }
961
- .aura-stat__label { font-size: 13px; font-weight: 500; color: var(--aura-fg-secondary); }
982
+ .aura-stat__label { margin: 0; font-size: 13px; font-weight: 500; color: var(--aura-fg-secondary); } /* 5.14: may be a heading */
962
983
  .aura-stat__icon { display: inline-flex; color: var(--aura-fg-secondary); }
963
984
  .aura-stat__value { display: flex; align-items: baseline; gap: var(--aura-space-1); font-size: 28px; line-height: 1.2; font-weight: 600; letter-spacing: -0.01em; min-height: 34px; }
964
985
  .aura-stat__value.is-numeric { font-variant-numeric: tabular-nums; }
@@ -1083,6 +1104,10 @@ a.aura-upload__name:focus-visible { outline: var(--aura-focus-ring-width) solid
1083
1104
  .aura-empty__title { margin: 0; font-size: 16px; line-height: 1.5; font-weight: 600; }
1084
1105
  .aura-empty__text { margin: 0; max-width: 44ch; font-size: 14px; line-height: 1.6; color: var(--aura-fg-secondary); }
1085
1106
  .aura-empty__action { margin-top: var(--aura-space-3); display: flex; gap: var(--aura-space-3); flex-wrap: wrap; justify-content: center; }
1107
+ /* 5.13 (Chamber-OS 82): tone="danger" — a load failure. */
1108
+ .aura-empty.is-danger { background: var(--aura-alert-danger-bg); border-radius: var(--aura-radius-lg); }
1109
+ .aura-empty.is-danger.is-bordered { border: 1px solid var(--aura-border-danger); }
1110
+ .aura-empty.is-danger .aura-empty__icon { background: var(--aura-bg-surface); color: var(--aura-fg-danger); }
1086
1111
 
1087
1112
  /* ---------- Pagination ---------- */
1088
1113
  .aura-pagination { display: flex; align-items: center; gap: var(--aura-space-1); font-family: var(--font-sans); font-size: 13px; }
@@ -1548,6 +1573,13 @@ button.aura-stepper__step:hover .aura-stepper__label { text-decoration: underlin
1548
1573
  .aura-tbl .is-numeric { font-variant-numeric: tabular-nums; white-space: nowrap; }
1549
1574
  .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
1575
  .aura-tbl-wrap:focus-visible { outline: var(--aura-focus-ring-width) solid var(--aura-focus-ring); outline-offset: 2px; }
1576
+ /* 5.13 (Chamber-OS 81): align="middle" centres body and footer cells on their row; bordered={false} drops the frame and
1577
+ * the outer cells' side padding, so the table lines up with what's around it (a Card's heading). */
1578
+ .aura-tbl--middle > .aura-tbl__body > .aura-tbl__row > *, .aura-tbl--middle > .aura-tbl__foot > .aura-tbl__row > * { vertical-align: middle; }
1579
+ .aura-tbl-wrap.is-flush { border: 0; border-radius: 0; background: transparent; }
1580
+ .aura-tbl-wrap.is-flush > .aura-tbl > * > .aura-tbl__row > :first-child { padding-inline-start: 0; }
1581
+ .aura-tbl-wrap.is-flush > .aura-tbl > * > .aura-tbl__row > :last-child { padding-inline-end: 0; }
1582
+ .aura-tbl-wrap.is-flush > .aura-tbl > .aura-tbl__caption { padding-inline: 0; }
1551
1583
  /* Stacked rows (5.8, Chamber-OS 67): below `stackBelow` (the table's own box: sm 640px, md 768px) each body row is a
1552
1584
  * card and each cell shows its column label. The column headers stay for screen readers (visually hidden) and the
1553
1585
  * table keeps explicit roles. The box is a size container, so it needs a width of its own. */
@@ -1562,6 +1594,14 @@ button.aura-stepper__step:hover .aura-stepper__label { text-decoration: underlin
1562
1594
  .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
1595
  .aura-tbl--stack-md > * > .aura-tbl__row > * + * { margin-top: var(--aura-space-2); }
1564
1596
  .aura-tbl--stack-md > .aura-tbl__body > .aura-tbl__row > .aura-tbl__th { font-size: 14px; font-weight: 600; }
1597
+ /* 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. */
1598
+ .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); }
1599
+ .aura-tbl--stack-md > .aura-tbl__body > .aura-tbl__row:has(> [data-card])::after { content: ''; order: 3; flex: 0 0 100%; }
1600
+ .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); }
1601
+ .aura-tbl--stack-md > .aura-tbl__body > .aura-tbl__row:has(> [data-card]) > [data-card] { margin-top: 0; }
1602
+ .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; }
1603
+ .aura-tbl--stack-md > .aura-tbl__body > .aura-tbl__row:has(> [data-card]) > [data-card='action'] { order: 2; flex: none; margin-inline-start: auto; }
1604
+ .aura-tbl-wrap.is-flush > .aura-tbl--stack-md > .aura-tbl__caption { padding-inline: var(--aura-space-4); }
1565
1605
  .aura-tbl--stack-md > * > .aura-tbl__row > .aura-tbl__td[data-label]::before {
1566
1606
  content: attr(data-label); content: attr(data-label) / '';
1567
1607
  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 +1617,14 @@ button.aura-stepper__step:hover .aura-stepper__label { text-decoration: underlin
1577
1617
  .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
1618
  .aura-tbl--stack-sm > * > .aura-tbl__row > * + * { margin-top: var(--aura-space-2); }
1579
1619
  .aura-tbl--stack-sm > .aura-tbl__body > .aura-tbl__row > .aura-tbl__th { font-size: 14px; font-weight: 600; }
1620
+ /* 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. */
1621
+ .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); }
1622
+ .aura-tbl--stack-sm > .aura-tbl__body > .aura-tbl__row:has(> [data-card])::after { content: ''; order: 3; flex: 0 0 100%; }
1623
+ .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); }
1624
+ .aura-tbl--stack-sm > .aura-tbl__body > .aura-tbl__row:has(> [data-card]) > [data-card] { margin-top: 0; }
1625
+ .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; }
1626
+ .aura-tbl--stack-sm > .aura-tbl__body > .aura-tbl__row:has(> [data-card]) > [data-card='action'] { order: 2; flex: none; margin-inline-start: auto; }
1627
+ .aura-tbl-wrap.is-flush > .aura-tbl--stack-sm > .aura-tbl__caption { padding-inline: var(--aura-space-4); }
1580
1628
  .aura-tbl--stack-sm > * > .aura-tbl__row > .aura-tbl__td[data-label]::before {
1581
1629
  content: attr(data-label); content: attr(data-label) / '';
1582
1630
  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 +1677,17 @@ button.aura-stepper__step:hover .aura-stepper__label { text-decoration: underlin
1629
1677
  padding: 0; line-height: normal;
1630
1678
  }
1631
1679
  .aura-table__td[data-hide], .aura-table__head > .aura-table__th[data-hide] { display: block; }
1680
+ /* 5.13 (Chamber-OS 80): card: 'hide' leaves a column out of the card; cardOrder orders the fields. */
1681
+ .aura-table__td[data-card='hide'], .aura-table__head > .aura-table__th[data-card='hide'],
1682
+ .aura-table__row--skeleton .aura-table__td[data-card='hide'] { display: none; }
1683
+ .aura-table__td[data-card='field'] { order: var(--aura-card-order, 5); }
1684
+ /* 5.14 (Chamber-OS 108): in a card every field starts under its label; align: 'end' is for the grid (figures stay tabular). */
1685
+ .aura-table__td.is-end { text-align: start; }
1686
+ .aura-table__row--skeleton .aura-table__td.is-end { justify-content: flex-start; }
1687
+ /* hideSelectionInCards: no row boxes, no select-all line. */
1688
+ .aura-table--cards-nosel .aura-table__row > .aura-table__sel { display: none; }
1689
+ .aura-table--cards-nosel .aura-table__head { position: absolute; width: 1px; height: 1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); }
1690
+ .aura-table--cards-nosel .aura-table__head > .aura-table__sel { display: none; }
1632
1691
  /* 5.11: rowHeight="auto" leaves cards as they are. */
1633
1692
  .aura-table__td--auto { display: block; white-space: nowrap; }
1634
1693
  .aura-table__td--auto .aura-table__cell > .aura-badge, .aura-table__td--auto .aura-table__cell > .aura-pill { margin: 0; }
@@ -36,6 +36,16 @@ a.aura-btn { text-decoration: none; }
36
36
  padding-block: var(--aura-space-2); line-height: 1.35; text-align: center; overflow-wrap: anywhere;
37
37
  }
38
38
  .aura-btn.is-loading { cursor: progress; }
39
+ /* 5.14: a button gated with aria-disabled looks unavailable but stays focusable (no pointer-events: none, so the
40
+ * not-allowed cursor and a tooltip still work). */
41
+ button.aura-btn[aria-disabled='true']:not(.is-loading) { opacity: var(--aura-disabled-opacity); cursor: not-allowed; }
42
+ button.aura-btn[aria-disabled='true']:active { transform: none; }
43
+ /* …and hovering it changes nothing: each variant keeps its resting look (the hover rules below are overridden). */
44
+ button.aura-btn--primary[aria-disabled='true']:hover { background: var(--aura-button-primary-bg); }
45
+ button.aura-btn--secondary[aria-disabled='true']:hover, button.aura-btn--ghost[aria-disabled='true']:hover,
46
+ button.aura-btn--danger-secondary[aria-disabled='true']:hover { background: transparent; }
47
+ button.aura-btn--danger[aria-disabled='true']:hover { background: var(--aura-button-danger-bg); }
48
+ button.aura-btn--creative[aria-disabled='true']:hover { box-shadow: var(--aura-shadow-creative); transform: none; }
39
49
  .aura-btn.is-loading:active { transform: none; }
40
50
 
41
51
  /* Focus — ADDED: the source defines none. Solid 2px ring, 2px offset, on every interactive element. */
@@ -870,7 +880,11 @@ a.aura-tab { text-decoration: none; }
870
880
  .aura-drawer--nav .aura-drawer__head { position: absolute; top: var(--aura-space-2); right: var(--aura-space-2); padding: 0; z-index: 1; }
871
881
  .aura-drawer__title { flex: 1; margin: 0; font-size: 16px; line-height: 1.5; font-weight: 600; }
872
882
  .aura-drawer__desc { margin: 0; padding: 0 var(--aura-space-6); font-size: 14px; line-height: 1.7; color: var(--aura-fg-secondary); }
873
- .aura-drawer__body { flex: 1; overflow-y: auto; padding: var(--aura-space-4) var(--aura-space-6); font-size: 14px; line-height: 1.7; }
883
+ .aura-drawer__body {
884
+ flex: 1; overflow-y: auto; padding: var(--aura-space-4) var(--aura-space-6); font-size: 14px; line-height: 1.7;
885
+ /* 5.14 (Chamber-OS 91): a field scrolled into view (focus, the phone keyboard) keeps clear of the head and foot. */
886
+ scroll-padding-block: var(--aura-space-4);
887
+ }
874
888
  .aura-drawer--nav .aura-drawer__body { padding: 0; }
875
889
  .aura-drawer--nav .aura-nav { width: 100%; border-right: 0; }
876
890
  .aura-drawer__foot { display: flex; justify-content: flex-end; flex-wrap: wrap; gap: var(--aura-space-3); padding: var(--aura-space-4) var(--aura-space-6); border-top: 1px solid var(--aura-border-default); }
@@ -915,12 +929,18 @@ a.aura-tab { text-decoration: none; }
915
929
  .aura-grid-layout.is-auto { grid-template-columns: unset; }
916
930
 
917
931
  /* ---------- AppShell ---------- */
918
- .aura-shell { display: flex; min-height: 100vh; min-height: 100dvh; background: var(--aura-bg-canvas); color: var(--aura-fg-primary); font-family: var(--font-sans); }
932
+ .aura-shell {
933
+ display: flex; min-height: 100vh; min-height: 100dvh; background: var(--aura-bg-canvas); color: var(--aura-fg-primary); font-family: var(--font-sans);
934
+ --aura-shell-bar-height: 56px; /* 5.14 (Chamber-OS 104): the top bar's height, for sticky offsets under it */
935
+ }
936
+ .aura-shell--no-bar { --aura-shell-bar-height: 0px; }
937
+ @media (min-width: 1024px) { .aura-shell--menu-bar { --aura-shell-bar-height: 0px; } }
919
938
  .aura-shell__nav { position: sticky; top: 0; height: 100vh; height: 100dvh; flex: none; }
920
939
  .aura-shell__main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
921
940
  .aura-shell__bar {
922
941
  position: sticky; top: 0; z-index: 10; display: flex; align-items: center; gap: var(--aura-space-2);
923
- min-height: 56px; padding: 0 var(--aura-space-6); background: var(--aura-bg-surface); border-bottom: 1px solid var(--aura-border-default);
942
+ box-sizing: border-box; min-height: 56px;
943
+ padding: 0 var(--aura-space-6); background: var(--aura-bg-surface); border-bottom: 1px solid var(--aura-border-default);
924
944
  }
925
945
  /* Responsive in CSS (4.16), so the server's HTML is already right on a phone: below lg the sidebar is hidden and the
926
946
  * menu button shows; from lg up the reverse. JavaScript only opens and closes the drawer. */
@@ -937,10 +957,11 @@ a.aura-tab { text-decoration: none; }
937
957
  .aura-shell__content { flex: 1; min-width: 0; padding: var(--aura-space-6) var(--aura-space-4); }
938
958
  /* 5.7: <main> takes focus (tabIndex -1) for skip links and "the row you acted on is gone"; a landmark gets no ring. */
939
959
  .aura-shell__content:focus { outline: none; }
960
+ .aura-shell__content.is-flush { padding: 0; } /* 5.14 (Chamber-OS 97): contentPadding={false} */
940
961
  @media (min-width: 640px) { .aura-shell__content { padding: var(--aura-space-6); } }
941
962
  @media (min-width: 1024px) { .aura-shell__content { padding: var(--aura-space-8); } }
942
963
  /* The shell already pads its content: a Container directly inside only caps the width. */
943
- .aura-shell__content > .aura-container { padding-left: 0; padding-right: 0; }
964
+ .aura-shell__content:not(.is-flush) > .aura-container { padding-left: 0; padding-right: 0; }
944
965
 
945
966
  /* Totals row (4.19): under the body, a strong top edge; sticky at the bottom of a `height` table with stickyFooter. */
946
967
  .aura-table__total { background: var(--aura-bg-canvas); border-top: 1px solid var(--aura-border-strong); font-weight: 600; }
@@ -960,7 +981,7 @@ button.aura-stat { font: inherit; width: 100%; cursor: pointer; }
960
981
  .aura-stat.is-interactive:hover { border-color: var(--aura-border-strong); }
961
982
  .aura-stat.is-interactive:focus-visible { outline: var(--aura-focus-ring-width) solid var(--aura-focus-ring); outline-offset: var(--aura-focus-ring-offset); }
962
983
  .aura-stat__head { display: flex; align-items: center; justify-content: space-between; gap: var(--aura-space-2); }
963
- .aura-stat__label { font-size: 13px; font-weight: 500; color: var(--aura-fg-secondary); }
984
+ .aura-stat__label { margin: 0; font-size: 13px; font-weight: 500; color: var(--aura-fg-secondary); } /* 5.14: may be a heading */
964
985
  .aura-stat__icon { display: inline-flex; color: var(--aura-fg-secondary); }
965
986
  .aura-stat__value { display: flex; align-items: baseline; gap: var(--aura-space-1); font-size: 28px; line-height: 1.2; font-weight: 600; letter-spacing: -0.01em; min-height: 34px; }
966
987
  .aura-stat__value.is-numeric { font-variant-numeric: tabular-nums; }
@@ -1085,6 +1106,10 @@ a.aura-upload__name:focus-visible { outline: var(--aura-focus-ring-width) solid
1085
1106
  .aura-empty__title { margin: 0; font-size: 16px; line-height: 1.5; font-weight: 600; }
1086
1107
  .aura-empty__text { margin: 0; max-width: 44ch; font-size: 14px; line-height: 1.6; color: var(--aura-fg-secondary); }
1087
1108
  .aura-empty__action { margin-top: var(--aura-space-3); display: flex; gap: var(--aura-space-3); flex-wrap: wrap; justify-content: center; }
1109
+ /* 5.13 (Chamber-OS 82): tone="danger" — a load failure. */
1110
+ .aura-empty.is-danger { background: var(--aura-alert-danger-bg); border-radius: var(--aura-radius-lg); }
1111
+ .aura-empty.is-danger.is-bordered { border: 1px solid var(--aura-border-danger); }
1112
+ .aura-empty.is-danger .aura-empty__icon { background: var(--aura-bg-surface); color: var(--aura-fg-danger); }
1088
1113
 
1089
1114
  /* ---------- Pagination ---------- */
1090
1115
  .aura-pagination { display: flex; align-items: center; gap: var(--aura-space-1); font-family: var(--font-sans); font-size: 13px; }
@@ -1550,6 +1575,13 @@ button.aura-stepper__step:hover .aura-stepper__label { text-decoration: underlin
1550
1575
  .aura-tbl .is-numeric { font-variant-numeric: tabular-nums; white-space: nowrap; }
1551
1576
  .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); }
1552
1577
  .aura-tbl-wrap:focus-visible { outline: var(--aura-focus-ring-width) solid var(--aura-focus-ring); outline-offset: 2px; }
1578
+ /* 5.13 (Chamber-OS 81): align="middle" centres body and footer cells on their row; bordered={false} drops the frame and
1579
+ * the outer cells' side padding, so the table lines up with what's around it (a Card's heading). */
1580
+ .aura-tbl--middle > .aura-tbl__body > .aura-tbl__row > *, .aura-tbl--middle > .aura-tbl__foot > .aura-tbl__row > * { vertical-align: middle; }
1581
+ .aura-tbl-wrap.is-flush { border: 0; border-radius: 0; background: transparent; }
1582
+ .aura-tbl-wrap.is-flush > .aura-tbl > * > .aura-tbl__row > :first-child { padding-inline-start: 0; }
1583
+ .aura-tbl-wrap.is-flush > .aura-tbl > * > .aura-tbl__row > :last-child { padding-inline-end: 0; }
1584
+ .aura-tbl-wrap.is-flush > .aura-tbl > .aura-tbl__caption { padding-inline: 0; }
1553
1585
  /* Stacked rows (5.8, Chamber-OS 67): below `stackBelow` (the table's own box: sm 640px, md 768px) each body row is a
1554
1586
  * card and each cell shows its column label. The column headers stay for screen readers (visually hidden) and the
1555
1587
  * table keeps explicit roles. The box is a size container, so it needs a width of its own. */
@@ -1564,6 +1596,14 @@ button.aura-stepper__step:hover .aura-stepper__label { text-decoration: underlin
1564
1596
  .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; }
1565
1597
  .aura-tbl--stack-md > * > .aura-tbl__row > * + * { margin-top: var(--aura-space-2); }
1566
1598
  .aura-tbl--stack-md > .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-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); }
1601
+ .aura-tbl--stack-md > .aura-tbl__body > .aura-tbl__row:has(> [data-card])::after { content: ''; order: 3; flex: 0 0 100%; }
1602
+ .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); }
1603
+ .aura-tbl--stack-md > .aura-tbl__body > .aura-tbl__row:has(> [data-card]) > [data-card] { margin-top: 0; }
1604
+ .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; }
1605
+ .aura-tbl--stack-md > .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-md > .aura-tbl__caption { padding-inline: var(--aura-space-4); }
1567
1607
  .aura-tbl--stack-md > * > .aura-tbl__row > .aura-tbl__td[data-label]::before {
1568
1608
  content: attr(data-label); content: attr(data-label) / '';
1569
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);
@@ -1579,6 +1619,14 @@ button.aura-stepper__step:hover .aura-stepper__label { text-decoration: underlin
1579
1619
  .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; }
1580
1620
  .aura-tbl--stack-sm > * > .aura-tbl__row > * + * { margin-top: var(--aura-space-2); }
1581
1621
  .aura-tbl--stack-sm > .aura-tbl__body > .aura-tbl__row > .aura-tbl__th { font-size: 14px; font-weight: 600; }
1622
+ /* 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. */
1623
+ .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); }
1624
+ .aura-tbl--stack-sm > .aura-tbl__body > .aura-tbl__row:has(> [data-card])::after { content: ''; order: 3; flex: 0 0 100%; }
1625
+ .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); }
1626
+ .aura-tbl--stack-sm > .aura-tbl__body > .aura-tbl__row:has(> [data-card]) > [data-card] { margin-top: 0; }
1627
+ .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; }
1628
+ .aura-tbl--stack-sm > .aura-tbl__body > .aura-tbl__row:has(> [data-card]) > [data-card='action'] { order: 2; flex: none; margin-inline-start: auto; }
1629
+ .aura-tbl-wrap.is-flush > .aura-tbl--stack-sm > .aura-tbl__caption { padding-inline: var(--aura-space-4); }
1582
1630
  .aura-tbl--stack-sm > * > .aura-tbl__row > .aura-tbl__td[data-label]::before {
1583
1631
  content: attr(data-label); content: attr(data-label) / '';
1584
1632
  display: block; margin-bottom: 2px; font-family: var(--font-mono); font-size: 11px; line-height: 16px; font-weight: 400; color: var(--aura-fg-secondary);
@@ -1631,6 +1679,17 @@ button.aura-stepper__step:hover .aura-stepper__label { text-decoration: underlin
1631
1679
  padding: 0; line-height: normal;
1632
1680
  }
1633
1681
  .aura-table__td[data-hide], .aura-table__head > .aura-table__th[data-hide] { display: block; }
1682
+ /* 5.13 (Chamber-OS 80): card: 'hide' leaves a column out of the card; cardOrder orders the fields. */
1683
+ .aura-table__td[data-card='hide'], .aura-table__head > .aura-table__th[data-card='hide'],
1684
+ .aura-table__row--skeleton .aura-table__td[data-card='hide'] { display: none; }
1685
+ .aura-table__td[data-card='field'] { order: var(--aura-card-order, 5); }
1686
+ /* 5.14 (Chamber-OS 108): in a card every field starts under its label; align: 'end' is for the grid (figures stay tabular). */
1687
+ .aura-table__td.is-end { text-align: start; }
1688
+ .aura-table__row--skeleton .aura-table__td.is-end { justify-content: flex-start; }
1689
+ /* hideSelectionInCards: no row boxes, no select-all line. */
1690
+ .aura-table--cards-nosel .aura-table__row > .aura-table__sel { display: none; }
1691
+ .aura-table--cards-nosel .aura-table__head { position: absolute; width: 1px; height: 1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); }
1692
+ .aura-table--cards-nosel .aura-table__head > .aura-table__sel { display: none; }
1634
1693
  /* 5.11: rowHeight="auto" leaves cards as they are. */
1635
1694
  .aura-table__td--auto { display: block; white-space: nowrap; }
1636
1695
  .aura-table__td--auto .aura-table__cell > .aura-badge, .aura-table__td--auto .aura-table__cell > .aura-pill { margin: 0; }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jirawatpyk/aura-react",
3
- "version": "5.12.0",
3
+ "version": "5.14.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",