@jirawatpyk/aura-react 5.62.0 → 5.64.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.
package/README.md CHANGED
@@ -186,6 +186,15 @@ DataTable with sort and page in the URL (4.17): `onStateChange={({ sort, page })
186
186
  - **Time zone**: `timeZone` on AuraProvider, DatePicker, DateRangePicker and Calendar decides "today" (the marker, `min`/`max="today"`, the first month shown); or pass `today` as an ISO date. `todayIn('Asia/Bangkok')` is exported from the root and `/server`.
187
187
  - **Toasts** queue past three instead of dropping: six in a row all show, in order, three at a time.
188
188
 
189
+ ## 5.64 — Chamber-OS addendum 80 (#179)
190
+
191
+ - **Progress `legend` — a key for the reserved part:** `legend={{ value: 'Used', secondary: 'Reserved (in review or scheduled)' }}` draws a key under the bar (above the `hint`): a swatch in the bar's tone for each part (`value` is optional), the second striped like the reserved segment, so it follows `tone="danger"`. It shows only while the reserved segment is drawn and wraps on a phone. It is `aria-hidden`, so while it shows the bar reads both counts ("2 of 6 used, 1 reserved") even when you pass a `valueLabel` — pass `valueText` to word it yourself. In forced colours the bar and the swatches use Highlight in every tone (before 5.64 a toned bar kept its colour). Drop a hand-drawn key that copies the stripe.
192
+
193
+ ## 5.63 — Chamber-OS addendum 79 (#178)
194
+
195
+ - **A lazy chip still makes `meta` the chip row:** a Server Component's Badge or StatusPill passed through a `'use client'` wrapper can arrive as a lazy node on Next's dev server. PageHeader now looks through a resolved lazy node (a chip makes the row, text keeps the line, as when it arrives resolved), and an unresolved one is neutral — the other children decide — so the layout no longer depends on the build mode. Anything else unresolved (a promise, an iterator) keeps a line.
196
+ - **`metaLayout`:** `"row"` lays `meta` out as the wrapping chip row whatever it holds, `"line"` as a text line; `"auto"` (default) keeps 5.62's guess (elements only → row). Pass `metaLayout="row"` where chips come from a Server Component, so nothing is guessed (an all-lazy meta that hasn't resolved would otherwise be a line). Also from `/server`. Drop the `flex flex-wrap items-center gap-2` stand-in.
197
+
189
198
  ## 5.62 — Chamber-OS addendum 78 (#177)
190
199
 
191
200
  - **PageHeader `meta` lays chips out as a row:** a `meta` made only of elements (Badges, a StatusPill — through Fragments and arrays) is now a wrapping row, 8px apart and vertically centred, as `eyebrow` — so chips no longer touch when the JSX has no space between them, and they wrap on a phone. Any text in it — a string `meta` ("128 members · updated 3 min ago"), or a sentence with a `<strong>`, `<time>`, a link or `{count}` — keeps it a text line, as before. Also from `/server`. Drop a `flex flex-wrap items-center gap-2` stand-in wrapper.
@@ -7914,6 +7914,7 @@ window.Aura = (() => {
7914
7914
  // src/PageHeader.tsx
7915
7915
  var React43 = __toESM(require_react(), 1);
7916
7916
  var h8 = React43.createElement;
7917
+ var LAZY = Symbol.for("react.lazy");
7917
7918
  function chipsOnly(node) {
7918
7919
  let el = 0;
7919
7920
  const walk = function(n3) {
@@ -7921,6 +7922,16 @@ window.Aura = (() => {
7921
7922
  if (typeof n3 === "string") return n3.trim() === "";
7922
7923
  if (typeof n3 === "number" || typeof n3 === "bigint") return false;
7923
7924
  if (Array.isArray(n3)) return n3.every(walk);
7925
+ if (typeof n3 === "object" && n3.$$typeof === LAZY) {
7926
+ const lazy = n3;
7927
+ let value;
7928
+ try {
7929
+ value = lazy._init(lazy._payload);
7930
+ } catch {
7931
+ return true;
7932
+ }
7933
+ return walk(value);
7934
+ }
7924
7935
  if (React43.isValidElement(n3)) {
7925
7936
  if (n3.type === React43.Fragment) return walk(n3.props.children);
7926
7937
  el++;
@@ -7946,7 +7957,7 @@ window.Aura = (() => {
7946
7957
  const size = props.size === "compact" || props.size === "hero" || props.size === "hero-lg" ? props.size : null;
7947
7958
  const eyebrow = props.eyebrow;
7948
7959
  const plainEyebrow = typeof eyebrow === "string" || typeof eyebrow === "number";
7949
- const richMeta = chipsOnly(props.meta);
7960
+ const richMeta = props.metaLayout === "row" ? true : props.metaLayout === "line" ? false : chipsOnly(props.meta);
7950
7961
  const heading = h8(
7951
7962
  "h" + level,
7952
7963
  {
@@ -10160,7 +10171,8 @@ window.Aura = (() => {
10160
10171
  const pct = det ? Math.max(0, Math.min(100, props.value / max * 100)) : 0;
10161
10172
  const sec = det && props.secondaryValue != null && props.secondaryValue > 0 ? props.secondaryValue : 0;
10162
10173
  const spct = sec ? Math.max(0, Math.min(100 - pct, sec / max * 100)) : 0;
10163
- const valueText = props.valueText != null ? props.valueText : props.valueLabel != null ? String(props.valueLabel) : sec ? t.progressReserved(props.value, sec, max) : void 0;
10174
+ const keyed = !!props.legend && spct > 0;
10175
+ const valueText = props.valueText != null ? props.valueText : keyed ? t.progressReserved(props.value, sec, max) : props.valueLabel != null ? String(props.valueLabel) : sec ? t.progressReserved(props.value, sec, max) : void 0;
10164
10176
  const shown = props.valueLabel != null ? props.valueLabel : det ? Math.round(pct) + "%" : null;
10165
10177
  return /* @__PURE__ */ React61.createElement(
10166
10178
  "div",
@@ -10195,6 +10207,7 @@ window.Aura = (() => {
10195
10207
  }
10196
10208
  ) : null
10197
10209
  ),
10210
+ keyed ? /* @__PURE__ */ React61.createElement("div", { className: "aura-progress__legend", "aria-hidden": "true" }, props.legend.value != null && props.legend.value !== false ? /* @__PURE__ */ React61.createElement("span", { className: "aura-progress__key" }, /* @__PURE__ */ React61.createElement("span", { className: "aura-progress__swatch" }), props.legend.value) : null, /* @__PURE__ */ React61.createElement("span", { className: "aura-progress__key" }, /* @__PURE__ */ React61.createElement("span", { className: "aura-progress__swatch aura-progress__swatch--reserved" }), props.legend.secondary)) : null,
10198
10211
  props.hint ? /* @__PURE__ */ React61.createElement("p", { className: "aura-progress__hint" }, props.hint) : null
10199
10212
  );
10200
10213
  });
@@ -7896,6 +7896,7 @@ var React44 = __toESM(require("react"), 1);
7896
7896
  // src/PageHeader.tsx
7897
7897
  var React43 = __toESM(require("react"), 1);
7898
7898
  var h8 = React43.createElement;
7899
+ var LAZY = Symbol.for("react.lazy");
7899
7900
  function chipsOnly(node) {
7900
7901
  let el = 0;
7901
7902
  const walk = function(n3) {
@@ -7903,6 +7904,16 @@ function chipsOnly(node) {
7903
7904
  if (typeof n3 === "string") return n3.trim() === "";
7904
7905
  if (typeof n3 === "number" || typeof n3 === "bigint") return false;
7905
7906
  if (Array.isArray(n3)) return n3.every(walk);
7907
+ if (typeof n3 === "object" && n3.$$typeof === LAZY) {
7908
+ const lazy = n3;
7909
+ let value;
7910
+ try {
7911
+ value = lazy._init(lazy._payload);
7912
+ } catch {
7913
+ return true;
7914
+ }
7915
+ return walk(value);
7916
+ }
7906
7917
  if (React43.isValidElement(n3)) {
7907
7918
  if (n3.type === React43.Fragment) return walk(n3.props.children);
7908
7919
  el++;
@@ -7928,7 +7939,7 @@ var PageHeader = React43.forwardRef(function PageHeader2(props, ref) {
7928
7939
  const size = props.size === "compact" || props.size === "hero" || props.size === "hero-lg" ? props.size : null;
7929
7940
  const eyebrow = props.eyebrow;
7930
7941
  const plainEyebrow = typeof eyebrow === "string" || typeof eyebrow === "number";
7931
- const richMeta = chipsOnly(props.meta);
7942
+ const richMeta = props.metaLayout === "row" ? true : props.metaLayout === "line" ? false : chipsOnly(props.meta);
7932
7943
  const heading = h8(
7933
7944
  "h" + level,
7934
7945
  {
@@ -10142,7 +10153,8 @@ var Progress = React61.forwardRef(function Progress2(props, ref) {
10142
10153
  const pct = det ? Math.max(0, Math.min(100, props.value / max * 100)) : 0;
10143
10154
  const sec = det && props.secondaryValue != null && props.secondaryValue > 0 ? props.secondaryValue : 0;
10144
10155
  const spct = sec ? Math.max(0, Math.min(100 - pct, sec / max * 100)) : 0;
10145
- const valueText = props.valueText != null ? props.valueText : props.valueLabel != null ? String(props.valueLabel) : sec ? t.progressReserved(props.value, sec, max) : void 0;
10156
+ const keyed = !!props.legend && spct > 0;
10157
+ const valueText = props.valueText != null ? props.valueText : keyed ? t.progressReserved(props.value, sec, max) : props.valueLabel != null ? String(props.valueLabel) : sec ? t.progressReserved(props.value, sec, max) : void 0;
10146
10158
  const shown = props.valueLabel != null ? props.valueLabel : det ? Math.round(pct) + "%" : null;
10147
10159
  return /* @__PURE__ */ React61.createElement(
10148
10160
  "div",
@@ -10177,6 +10189,7 @@ var Progress = React61.forwardRef(function Progress2(props, ref) {
10177
10189
  }
10178
10190
  ) : null
10179
10191
  ),
10192
+ keyed ? /* @__PURE__ */ React61.createElement("div", { className: "aura-progress__legend", "aria-hidden": "true" }, props.legend.value != null && props.legend.value !== false ? /* @__PURE__ */ React61.createElement("span", { className: "aura-progress__key" }, /* @__PURE__ */ React61.createElement("span", { className: "aura-progress__swatch" }), props.legend.value) : null, /* @__PURE__ */ React61.createElement("span", { className: "aura-progress__key" }, /* @__PURE__ */ React61.createElement("span", { className: "aura-progress__swatch aura-progress__swatch--reserved" }), props.legend.secondary)) : null,
10180
10193
  props.hint ? /* @__PURE__ */ React61.createElement("p", { className: "aura-progress__hint" }, props.hint) : null
10181
10194
  );
10182
10195
  });
@@ -2,6 +2,7 @@
2
2
  import * as React from "react";
3
3
  import { cx } from "./classes.js";
4
4
  const h = React.createElement;
5
+ const LAZY = Symbol.for("react.lazy");
5
6
  function chipsOnly(node) {
6
7
  let el = 0;
7
8
  const walk = function(n) {
@@ -9,6 +10,16 @@ function chipsOnly(node) {
9
10
  if (typeof n === "string") return n.trim() === "";
10
11
  if (typeof n === "number" || typeof n === "bigint") return false;
11
12
  if (Array.isArray(n)) return n.every(walk);
13
+ if (typeof n === "object" && n.$$typeof === LAZY) {
14
+ const lazy = n;
15
+ let value;
16
+ try {
17
+ value = lazy._init(lazy._payload);
18
+ } catch {
19
+ return true;
20
+ }
21
+ return walk(value);
22
+ }
12
23
  if (React.isValidElement(n)) {
13
24
  if (n.type === React.Fragment) return walk(n.props.children);
14
25
  el++;
@@ -34,7 +45,7 @@ const PageHeader = React.forwardRef(function PageHeader2(props, ref) {
34
45
  const size = props.size === "compact" || props.size === "hero" || props.size === "hero-lg" ? props.size : null;
35
46
  const eyebrow = props.eyebrow;
36
47
  const plainEyebrow = typeof eyebrow === "string" || typeof eyebrow === "number";
37
- const richMeta = chipsOnly(props.meta);
48
+ const richMeta = props.metaLayout === "row" ? true : props.metaLayout === "line" ? false : chipsOnly(props.meta);
38
49
  const heading = h(
39
50
  "h" + level,
40
51
  {
@@ -9,7 +9,8 @@ const Progress = React.forwardRef(function Progress2(props, ref) {
9
9
  const pct = det ? Math.max(0, Math.min(100, props.value / max * 100)) : 0;
10
10
  const sec = det && props.secondaryValue != null && props.secondaryValue > 0 ? props.secondaryValue : 0;
11
11
  const spct = sec ? Math.max(0, Math.min(100 - pct, sec / max * 100)) : 0;
12
- const valueText = props.valueText != null ? props.valueText : props.valueLabel != null ? String(props.valueLabel) : sec ? t.progressReserved(props.value, sec, max) : void 0;
12
+ const keyed = !!props.legend && spct > 0;
13
+ const valueText = props.valueText != null ? props.valueText : keyed ? t.progressReserved(props.value, sec, max) : props.valueLabel != null ? String(props.valueLabel) : sec ? t.progressReserved(props.value, sec, max) : void 0;
13
14
  const shown = props.valueLabel != null ? props.valueLabel : det ? Math.round(pct) + "%" : null;
14
15
  return /* @__PURE__ */ React.createElement(
15
16
  "div",
@@ -44,6 +45,7 @@ const Progress = React.forwardRef(function Progress2(props, ref) {
44
45
  }
45
46
  ) : null
46
47
  ),
48
+ keyed ? /* @__PURE__ */ React.createElement("div", { className: "aura-progress__legend", "aria-hidden": "true" }, props.legend.value != null && props.legend.value !== false ? /* @__PURE__ */ React.createElement("span", { className: "aura-progress__key" }, /* @__PURE__ */ React.createElement("span", { className: "aura-progress__swatch" }), props.legend.value) : null, /* @__PURE__ */ React.createElement("span", { className: "aura-progress__key" }, /* @__PURE__ */ React.createElement("span", { className: "aura-progress__swatch aura-progress__swatch--reserved" }), props.legend.secondary)) : null,
47
49
  props.hint ? /* @__PURE__ */ React.createElement("p", { className: "aura-progress__hint" }, props.hint) : null
48
50
  );
49
51
  });
package/dist/index.d.cts CHANGED
@@ -1653,6 +1653,14 @@ export interface ProgressProps {
1653
1653
  /** A reserved amount drawn after `value` as a striped segment of the same tone — queued sends on a quota
1654
1654
  * (5.15, Chamber-OS 89). Both counts are read out ("2 of 6 used, 1 reserved") unless `valueLabel` is given. */
1655
1655
  secondaryValue?: number | undefined;
1656
+ /** A key under the bar for its two parts (5.64, Chamber-OS 179): `{ value: 'Used', secondary: 'Reserved' }` — a
1657
+ * swatch in the bar's tone for each (`value` optional), the second striped like the reserved segment. Shown only
1658
+ * while the reserved segment is drawn; hidden from screen readers — so while it shows, the bar reads both counts
1659
+ * ("2 of 6 used, 1 reserved") even with a `valueLabel`, unless you pass `valueText`. */
1660
+ legend?: {
1661
+ value?: React$1.ReactNode;
1662
+ secondary: React$1.ReactNode;
1663
+ } | undefined;
1656
1664
  hint?: React$1.ReactNode | undefined;
1657
1665
  tone?: Tone | undefined;
1658
1666
  size?: "sm" | "md" | undefined;
@@ -2075,6 +2083,10 @@ export interface PageHeaderProps extends Pick<React$1.HTMLAttributes<HTMLElement
2075
2083
  /** A line under the title — counts, last update, owner. 5.62 (Chamber-OS 177): made only of elements (Badges, a
2076
2084
  * StatusPill), it is laid out as a wrapping row, 8px apart; any text in it keeps it a line. */
2077
2085
  meta?: React$1.ReactNode | undefined;
2086
+ /** 5.63 (Chamber-OS 178): `row` lays `meta` out as the wrapping chip row whatever its children are, `line` as a text
2087
+ * line; `auto` (default) guesses from them (elements only → row). Pass `row` when chips come from a Server Component
2088
+ * through a client wrapper, where they may arrive unresolved. */
2089
+ metaLayout?: "auto" | "row" | "line" | undefined;
2078
2090
  /** Buttons for the page, bottom-aligned at the end; they wrap below the text on a narrow screen. */
2079
2091
  actions?: React$1.ReactNode | undefined;
2080
2092
  /** 5.37 (DxT Monitor #17): below this breakpoint (`sm` 640px, `md` 768px, `lg` 1024px) the actions take the whole
package/dist/index.d.ts CHANGED
@@ -1653,6 +1653,14 @@ export interface ProgressProps {
1653
1653
  /** A reserved amount drawn after `value` as a striped segment of the same tone — queued sends on a quota
1654
1654
  * (5.15, Chamber-OS 89). Both counts are read out ("2 of 6 used, 1 reserved") unless `valueLabel` is given. */
1655
1655
  secondaryValue?: number | undefined;
1656
+ /** A key under the bar for its two parts (5.64, Chamber-OS 179): `{ value: 'Used', secondary: 'Reserved' }` — a
1657
+ * swatch in the bar's tone for each (`value` optional), the second striped like the reserved segment. Shown only
1658
+ * while the reserved segment is drawn; hidden from screen readers — so while it shows, the bar reads both counts
1659
+ * ("2 of 6 used, 1 reserved") even with a `valueLabel`, unless you pass `valueText`. */
1660
+ legend?: {
1661
+ value?: React$1.ReactNode;
1662
+ secondary: React$1.ReactNode;
1663
+ } | undefined;
1656
1664
  hint?: React$1.ReactNode | undefined;
1657
1665
  tone?: Tone | undefined;
1658
1666
  size?: "sm" | "md" | undefined;
@@ -2075,6 +2083,10 @@ export interface PageHeaderProps extends Pick<React$1.HTMLAttributes<HTMLElement
2075
2083
  /** A line under the title — counts, last update, owner. 5.62 (Chamber-OS 177): made only of elements (Badges, a
2076
2084
  * StatusPill), it is laid out as a wrapping row, 8px apart; any text in it keeps it a line. */
2077
2085
  meta?: React$1.ReactNode | undefined;
2086
+ /** 5.63 (Chamber-OS 178): `row` lays `meta` out as the wrapping chip row whatever its children are, `line` as a text
2087
+ * line; `auto` (default) guesses from them (elements only → row). Pass `row` when chips come from a Server Component
2088
+ * through a client wrapper, where they may arrive unresolved. */
2089
+ metaLayout?: "auto" | "row" | "line" | undefined;
2078
2090
  /** Buttons for the page, bottom-aligned at the end; they wrap below the text on a narrow screen. */
2079
2091
  actions?: React$1.ReactNode | undefined;
2080
2092
  /** 5.37 (DxT Monitor #17): below this breakpoint (`sm` 640px, `md` 768px, `lg` 1024px) the actions take the whole
@@ -1632,6 +1632,7 @@ function TableSkeleton(props) {
1632
1632
  // src/PageHeader.tsx
1633
1633
  var React6 = __toESM(require("react"), 1);
1634
1634
  var h5 = React6.createElement;
1635
+ var LAZY = Symbol.for("react.lazy");
1635
1636
  function chipsOnly(node) {
1636
1637
  let el = 0;
1637
1638
  const walk = function(n3) {
@@ -1639,6 +1640,16 @@ function chipsOnly(node) {
1639
1640
  if (typeof n3 === "string") return n3.trim() === "";
1640
1641
  if (typeof n3 === "number" || typeof n3 === "bigint") return false;
1641
1642
  if (Array.isArray(n3)) return n3.every(walk);
1643
+ if (typeof n3 === "object" && n3.$$typeof === LAZY) {
1644
+ const lazy = n3;
1645
+ let value;
1646
+ try {
1647
+ value = lazy._init(lazy._payload);
1648
+ } catch {
1649
+ return true;
1650
+ }
1651
+ return walk(value);
1652
+ }
1642
1653
  if (React6.isValidElement(n3)) {
1643
1654
  if (n3.type === React6.Fragment) return walk(n3.props.children);
1644
1655
  el++;
@@ -1664,7 +1675,7 @@ var PageHeader = React6.forwardRef(function PageHeader2(props, ref) {
1664
1675
  const size = props.size === "compact" || props.size === "hero" || props.size === "hero-lg" ? props.size : null;
1665
1676
  const eyebrow = props.eyebrow;
1666
1677
  const plainEyebrow = typeof eyebrow === "string" || typeof eyebrow === "number";
1667
- const richMeta = chipsOnly(props.meta);
1678
+ const richMeta = props.metaLayout === "row" ? true : props.metaLayout === "line" ? false : chipsOnly(props.meta);
1668
1679
  const heading = h5(
1669
1680
  "h" + level,
1670
1681
  {
@@ -585,6 +585,10 @@ export interface PageHeaderProps extends Pick<React$1.HTMLAttributes<HTMLElement
585
585
  /** A line under the title — counts, last update, owner. 5.62 (Chamber-OS 177): made only of elements (Badges, a
586
586
  * StatusPill), it is laid out as a wrapping row, 8px apart; any text in it keeps it a line. */
587
587
  meta?: React$1.ReactNode | undefined;
588
+ /** 5.63 (Chamber-OS 178): `row` lays `meta` out as the wrapping chip row whatever its children are, `line` as a text
589
+ * line; `auto` (default) guesses from them (elements only → row). Pass `row` when chips come from a Server Component
590
+ * through a client wrapper, where they may arrive unresolved. */
591
+ metaLayout?: "auto" | "row" | "line" | undefined;
588
592
  /** Buttons for the page, bottom-aligned at the end; they wrap below the text on a narrow screen. */
589
593
  actions?: React$1.ReactNode | undefined;
590
594
  /** 5.37 (DxT Monitor #17): below this breakpoint (`sm` 640px, `md` 768px, `lg` 1024px) the actions take the whole
@@ -585,6 +585,10 @@ export interface PageHeaderProps extends Pick<React$1.HTMLAttributes<HTMLElement
585
585
  /** A line under the title — counts, last update, owner. 5.62 (Chamber-OS 177): made only of elements (Badges, a
586
586
  * StatusPill), it is laid out as a wrapping row, 8px apart; any text in it keeps it a line. */
587
587
  meta?: React$1.ReactNode | undefined;
588
+ /** 5.63 (Chamber-OS 178): `row` lays `meta` out as the wrapping chip row whatever its children are, `line` as a text
589
+ * line; `auto` (default) guesses from them (elements only → row). Pass `row` when chips come from a Server Component
590
+ * through a client wrapper, where they may arrive unresolved. */
591
+ metaLayout?: "auto" | "row" | "line" | undefined;
588
592
  /** Buttons for the page, bottom-aligned at the end; they wrap below the text on a narrow screen. */
589
593
  actions?: React$1.ReactNode | undefined;
590
594
  /** 5.37 (DxT Monitor #17): below this breakpoint (`sm` 640px, `md` 768px, `lg` 1024px) the actions take the whole
@@ -1566,6 +1566,7 @@ function TableSkeleton(props) {
1566
1566
  // src/PageHeader.tsx
1567
1567
  import * as React6 from "react";
1568
1568
  var h5 = React6.createElement;
1569
+ var LAZY = Symbol.for("react.lazy");
1569
1570
  function chipsOnly(node) {
1570
1571
  let el = 0;
1571
1572
  const walk = function(n3) {
@@ -1573,6 +1574,16 @@ function chipsOnly(node) {
1573
1574
  if (typeof n3 === "string") return n3.trim() === "";
1574
1575
  if (typeof n3 === "number" || typeof n3 === "bigint") return false;
1575
1576
  if (Array.isArray(n3)) return n3.every(walk);
1577
+ if (typeof n3 === "object" && n3.$$typeof === LAZY) {
1578
+ const lazy = n3;
1579
+ let value;
1580
+ try {
1581
+ value = lazy._init(lazy._payload);
1582
+ } catch {
1583
+ return true;
1584
+ }
1585
+ return walk(value);
1586
+ }
1576
1587
  if (React6.isValidElement(n3)) {
1577
1588
  if (n3.type === React6.Fragment) return walk(n3.props.children);
1578
1589
  el++;
@@ -1598,7 +1609,7 @@ var PageHeader = React6.forwardRef(function PageHeader2(props, ref) {
1598
1609
  const size = props.size === "compact" || props.size === "hero" || props.size === "hero-lg" ? props.size : null;
1599
1610
  const eyebrow = props.eyebrow;
1600
1611
  const plainEyebrow = typeof eyebrow === "string" || typeof eyebrow === "number";
1601
- const richMeta = chipsOnly(props.meta);
1612
+ const richMeta = props.metaLayout === "row" ? true : props.metaLayout === "line" ? false : chipsOnly(props.meta);
1602
1613
  const heading = h5(
1603
1614
  "h" + level,
1604
1615
  {
package/dist/styles.css CHANGED
@@ -1578,13 +1578,19 @@ a.aura-upload__name:focus-visible { outline: var(--aura-focus-ring-width) solid
1578
1578
  .aura-progress__track { position: relative; height: 8px; border-radius: var(--aura-radius-full); background: var(--aura-progress-track); box-shadow: inset 0 0 0 1px var(--aura-progress-track-edge); overflow: hidden; }
1579
1579
  .aura-progress.is-sm .aura-progress__track { height: 4px; }
1580
1580
  .aura-progress__bar { position: absolute; inset: 0 auto 0 0; border-radius: inherit; background: var(--aura-fg-accent); transition: width var(--aura-duration-base) var(--aura-ease); }
1581
- .aura-progress--success .aura-progress__bar { background: var(--aura-fg-positive); }
1582
- .aura-progress--warning .aura-progress__bar { background: var(--aura-alert-warning-fg); }
1583
- .aura-progress--danger .aura-progress__bar { background: var(--aura-fg-danger); }
1584
- .aura-progress--neutral .aura-progress__bar { background: var(--aura-fg-secondary); }
1581
+ /* 5.64 (Chamber-OS 179): legend — a swatch per part in the bar's tone, the reserved one striped like its segment. */
1582
+ .aura-progress__legend { display: flex; flex-wrap: wrap; gap: var(--aura-space-1) var(--aura-space-4); font-size: max(12px, .75rem); line-height: 1.5; color: var(--aura-fg-secondary); }
1583
+ .aura-progress__key { display: inline-flex; align-items: center; gap: 6px; min-width: 0; }
1584
+ .aura-progress__swatch { flex: none; width: 12px; height: 8px; border-radius: 2px; background: var(--aura-fg-accent); }
1585
+ .aura-progress--success :is(.aura-progress__bar, .aura-progress__swatch) { background: var(--aura-fg-positive); }
1586
+ .aura-progress--warning :is(.aura-progress__bar, .aura-progress__swatch) { background: var(--aura-alert-warning-fg); }
1587
+ .aura-progress--danger :is(.aura-progress__bar, .aura-progress__swatch) { background: var(--aura-fg-danger); }
1588
+ .aura-progress--neutral :is(.aura-progress__bar, .aura-progress__swatch) { background: var(--aura-fg-secondary); }
1585
1589
  /* 5.15 (Chamber-OS 89): a reserved amount after the value — the same tone, striped, so it reads without colour. */
1586
1590
  .aura-progress__bar--reserved {
1587
1591
  transition: left var(--aura-duration-base) var(--aura-ease), width var(--aura-duration-base) var(--aura-ease);
1592
+ }
1593
+ .aura-progress__bar--reserved, .aura-progress__swatch--reserved {
1588
1594
  -webkit-mask-image: repeating-linear-gradient(135deg, currentColor 0 3px, transparent 3px 6px);
1589
1595
  mask-image: repeating-linear-gradient(135deg, currentColor 0 3px, transparent 3px 6px);
1590
1596
  }
@@ -2545,7 +2551,7 @@ button.aura-stepper__step:hover .aura-stepper__label { text-decoration: underlin
2545
2551
  .aura-switch.is-on:disabled .aura-switch__thumb { background: Canvas; }
2546
2552
  .aura-switch-row.is-disabled .aura-choice__label { color: GrayText; }
2547
2553
  .aura-progress__track, .aura-upload__bar { border: 1px solid CanvasText; }
2548
- .aura-progress__bar, .aura-upload__bar > span { background: Highlight; forced-color-adjust: none; }
2554
+ .aura-progress :is(.aura-progress__bar, .aura-progress__swatch), .aura-upload__bar > span { background: Highlight; forced-color-adjust: none; } /* every tone (5.64) */
2549
2555
  .aura-segmented__option.is-selected { outline: 2px solid Highlight; outline-offset: -2px; }
2550
2556
  .aura-tab { border-bottom-color: Canvas; }
2551
2557
  .aura-tab.is-active { border-bottom-color: Highlight; }
@@ -1580,13 +1580,19 @@ a.aura-upload__name:focus-visible { outline: var(--aura-focus-ring-width) solid
1580
1580
  .aura-progress__track { position: relative; height: 8px; border-radius: var(--aura-radius-full); background: var(--aura-progress-track); box-shadow: inset 0 0 0 1px var(--aura-progress-track-edge); overflow: hidden; }
1581
1581
  .aura-progress.is-sm .aura-progress__track { height: 4px; }
1582
1582
  .aura-progress__bar { position: absolute; inset: 0 auto 0 0; border-radius: inherit; background: var(--aura-fg-accent); transition: width var(--aura-duration-base) var(--aura-ease); }
1583
- .aura-progress--success .aura-progress__bar { background: var(--aura-fg-positive); }
1584
- .aura-progress--warning .aura-progress__bar { background: var(--aura-alert-warning-fg); }
1585
- .aura-progress--danger .aura-progress__bar { background: var(--aura-fg-danger); }
1586
- .aura-progress--neutral .aura-progress__bar { background: var(--aura-fg-secondary); }
1583
+ /* 5.64 (Chamber-OS 179): legend — a swatch per part in the bar's tone, the reserved one striped like its segment. */
1584
+ .aura-progress__legend { display: flex; flex-wrap: wrap; gap: var(--aura-space-1) var(--aura-space-4); font-size: max(12px, .75rem); line-height: 1.5; color: var(--aura-fg-secondary); }
1585
+ .aura-progress__key { display: inline-flex; align-items: center; gap: 6px; min-width: 0; }
1586
+ .aura-progress__swatch { flex: none; width: 12px; height: 8px; border-radius: 2px; background: var(--aura-fg-accent); }
1587
+ .aura-progress--success :is(.aura-progress__bar, .aura-progress__swatch) { background: var(--aura-fg-positive); }
1588
+ .aura-progress--warning :is(.aura-progress__bar, .aura-progress__swatch) { background: var(--aura-alert-warning-fg); }
1589
+ .aura-progress--danger :is(.aura-progress__bar, .aura-progress__swatch) { background: var(--aura-fg-danger); }
1590
+ .aura-progress--neutral :is(.aura-progress__bar, .aura-progress__swatch) { background: var(--aura-fg-secondary); }
1587
1591
  /* 5.15 (Chamber-OS 89): a reserved amount after the value — the same tone, striped, so it reads without colour. */
1588
1592
  .aura-progress__bar--reserved {
1589
1593
  transition: left var(--aura-duration-base) var(--aura-ease), width var(--aura-duration-base) var(--aura-ease);
1594
+ }
1595
+ .aura-progress__bar--reserved, .aura-progress__swatch--reserved {
1590
1596
  -webkit-mask-image: repeating-linear-gradient(135deg, currentColor 0 3px, transparent 3px 6px);
1591
1597
  mask-image: repeating-linear-gradient(135deg, currentColor 0 3px, transparent 3px 6px);
1592
1598
  }
@@ -2547,7 +2553,7 @@ button.aura-stepper__step:hover .aura-stepper__label { text-decoration: underlin
2547
2553
  .aura-switch.is-on:disabled .aura-switch__thumb { background: Canvas; }
2548
2554
  .aura-switch-row.is-disabled .aura-choice__label { color: GrayText; }
2549
2555
  .aura-progress__track, .aura-upload__bar { border: 1px solid CanvasText; }
2550
- .aura-progress__bar, .aura-upload__bar > span { background: Highlight; forced-color-adjust: none; }
2556
+ .aura-progress :is(.aura-progress__bar, .aura-progress__swatch), .aura-upload__bar > span { background: Highlight; forced-color-adjust: none; } /* every tone (5.64) */
2551
2557
  .aura-segmented__option.is-selected { outline: 2px solid Highlight; outline-offset: -2px; }
2552
2558
  .aura-tab { border-bottom-color: Canvas; }
2553
2559
  .aura-tab.is-active { border-bottom-color: Highlight; }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jirawatpyk/aura-react",
3
- "version": "5.62.0",
3
+ "version": "5.64.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",