@jirawatpyk/aura-react 5.72.0 → 5.74.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,16 @@ 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.74 — Chamber-OS addendum 94 (#193)
190
+
191
+ - **A PageHeader bar with nothing left in it goes:** when every direct child of the phone bar but the status line (looking through `display: contents` wrappers) is hidden — the `hidden` attribute, `display: none`, `visibility: hidden` set on it, or visually hidden text (an `aria-describedby` note: `.sr-only`-style classes, or an inline absolutely positioned, clipped box) — and no text sits in it, the strip takes no box and the page loses its bar padding and `scroll-padding` (`--aura-page-actions-height` is `0px`), as if there were no bar. A status alone is not a bar. It applies to `actionsBar`'s strip and to the plain `actionsBarBelow` bar, and follows a child being shown or hidden (its `hidden`, `class` or `style`), added or removed, at most once a frame — for a pay bar that hides, not unmounts, once paying succeeds. A bar under a `visibility: hidden` ancestor (a page-enter gate) is not taken for empty. The client marks the header `data-aura-bar="empty"` or `"shown"`; before it does (server HTML), `actionsBar`'s strip whose element children are all `hidden` or visually hidden already goes, though the page padding waits for the client. From the breakpoint up nothing changes. A `:has(> [hidden])` stand-in can go once your PageHeaders render on the client. The `hidden` attribute is trusted as hidden: don't give a hidden child a class that displays it anyway (Tailwind v3's `flex` beats the browser's `[hidden]`).
192
+
193
+ ## 5.73 — Chamber-OS addendum 93 follow-up (#192)
194
+
195
+ - **Hidden bars, every way a tab panel hides them:** the edge ActionBar and PageHeader's `actionsBarBelow` bar now share one rule. The newest bar that is pinned and on screen sets the page's clearance (`--aura-actionbar-height`, `--aura-page-actions-height`). A bar with no box (`display: none`), `visibility: hidden`, or inside `content-visibility: hidden` (`hidden="until-found"`) is skipped. A visibility switch resizes nothing, so the bars are re-read after any click, key press, focus move, transition, find-in-page reveal (`beforematch`) or history change; a switch made by a timer or a resolved request is caught at the next of those.
196
+ - **When no bar is on screen:** a pinned bar hidden only by `visibility` (a gate that may lift with no event) keeps its room — too much space is cosmetic, too little hides content; with every pinned bar boxless (`display: none` tab panels) the variable is `0px`, so the page keeps no space for a strip that isn't there (5.72 removed it, and the CSS then reserved its 60px / 7rem fallback). With no bar pinned (a wide or short screen) it is removed, as before.
197
+ - **PageHeader in tab panels:** one PageHeader with `actionsBarBelow` per tab panel now works like the ActionBars: the shown one's bar counts, where before the newest one — shown or not — set the height. The development warning now fires only when two bars are on screen at once.
198
+
189
199
  ## 5.72 — Chamber-OS addendum 93 (#192)
190
200
 
191
201
  - **An edge ActionBar in a hidden tab no longer zeroes the page's clearance:** a bar with `look="edge"` / `edgeBelow` inside a `display: none` parent (an inactive tab panel) still computes `position: fixed` but has no box; it is now skipped, so `--aura-actionbar-height` (and with it the page's end padding and `scroll-padding-bottom`) is the visible bar's height. Switching tabs moves it to the bar now shown; with none shown it is removed. Mounting one bar for the active tab is still the simplest shape.
@@ -418,6 +418,76 @@ window.Aura = (() => {
418
418
  }
419
419
  return false;
420
420
  }
421
+ function onScreen(el) {
422
+ if (el.offsetHeight <= 0 || el.getClientRects().length === 0) return false;
423
+ const check = el.checkVisibility;
424
+ if (typeof check === "function") return check.call(el, { visibilityProperty: true });
425
+ const v = getComputedStyle(el).visibility;
426
+ return v !== "hidden" && v !== "collapse";
427
+ }
428
+ function barStack(name, onMany, onRead) {
429
+ const els = [];
430
+ let frame = 0;
431
+ const docEvents = ["click", "keydown", "focusin", "transitionend", "beforematch"];
432
+ const winEvents = ["hashchange", "popstate"];
433
+ function write() {
434
+ if (frame) cancelAnimationFrame(frame);
435
+ frame = 0;
436
+ if (onRead) onRead();
437
+ const root = document.documentElement;
438
+ let shown = null, boxed = null, pinned2 = false, many = 0;
439
+ for (let i = els.length - 1; i >= 0; i--) {
440
+ const el = els[i];
441
+ if (getComputedStyle(el).position !== "fixed") continue;
442
+ pinned2 = true;
443
+ if (onScreen(el)) {
444
+ many++;
445
+ if (!shown) shown = el;
446
+ } else if (!boxed && el.offsetHeight > 0) boxed = el;
447
+ }
448
+ if (many > 1 && onMany) onMany();
449
+ const use = shown || boxed;
450
+ if (use) root.style.setProperty(name, use.offsetHeight + "px");
451
+ else if (pinned2) root.style.setProperty(name, "0px");
452
+ else root.style.removeProperty(name);
453
+ }
454
+ function later() {
455
+ if (!frame) frame = requestAnimationFrame(write);
456
+ }
457
+ function now() {
458
+ write();
459
+ later();
460
+ }
461
+ function listen(on) {
462
+ docEvents.forEach(function(t) {
463
+ const f = t === "focusin" ? now : later;
464
+ if (on) document.addEventListener(t, f, true);
465
+ else document.removeEventListener(t, f, true);
466
+ });
467
+ winEvents.forEach(function(t) {
468
+ if (on) window.addEventListener(t, later);
469
+ else window.removeEventListener(t, later);
470
+ });
471
+ }
472
+ return {
473
+ add: function(el) {
474
+ els.push(el);
475
+ if (els.length === 1) listen(true);
476
+ write();
477
+ },
478
+ remove: function(el) {
479
+ const i = els.indexOf(el);
480
+ if (i >= 0) els.splice(i, 1);
481
+ if (!els.length) {
482
+ listen(false);
483
+ if (frame) cancelAnimationFrame(frame);
484
+ frame = 0;
485
+ }
486
+ write();
487
+ },
488
+ write
489
+ };
490
+ }
421
491
 
422
492
  // src/display.tsx
423
493
  var React4 = __toESM(require_react(), 1);
@@ -8158,8 +8228,41 @@ window.Aura = (() => {
8158
8228
  });
8159
8229
 
8160
8230
  // src/PageHeaderClient.tsx
8161
- var NAME = "--aura-page-actions-height";
8162
- var bars = [];
8231
+ var bars = barStack(
8232
+ "--aura-page-actions-height",
8233
+ function() {
8234
+ devWarnOnce(
8235
+ "pageheader-bar-twice",
8236
+ "PageHeader actionsBarBelow: two bars are on screen at once and overlap at the bottom of the screen. Give it to one PageHeader per page (one per tab panel is fine: only the shown one counts)."
8237
+ );
8238
+ },
8239
+ function() {
8240
+ marks.forEach(function(m) {
8241
+ m();
8242
+ });
8243
+ }
8244
+ );
8245
+ var UNSEEN = ".aura-page-header__status, .sr-only, .aura-sr-only, .visually-hidden, .screen-reader-text";
8246
+ function noneShown(el, barVisible) {
8247
+ for (let n3 = el.firstChild; n3; n3 = n3.nextSibling) {
8248
+ if (n3.nodeType === 3) {
8249
+ if ((n3.textContent || "").trim()) return false;
8250
+ continue;
8251
+ }
8252
+ if (n3.nodeType !== 1) continue;
8253
+ const c = n3;
8254
+ if (c.hidden || c.matches(UNSEEN)) continue;
8255
+ const s = getComputedStyle(c);
8256
+ if (s.display === "none") continue;
8257
+ if (barVisible && (s.visibility === "hidden" || s.visibility === "collapse")) continue;
8258
+ const inline = c.getAttribute("style") || "";
8259
+ if (/position:\s*absolute/.test(inline) && /clip/.test(inline)) continue;
8260
+ if (s.display === "contents" && noneShown(c, barVisible)) continue;
8261
+ return false;
8262
+ }
8263
+ return true;
8264
+ }
8265
+ var marks = /* @__PURE__ */ new Set();
8163
8266
  var PageHeader3 = React45.forwardRef(function PageHeader4(props, ref) {
8164
8267
  const own = React45.useRef(null);
8165
8268
  const merged = useMergedRef(ref, own);
@@ -8173,35 +8276,52 @@ window.Aura = (() => {
8173
8276
  split ? ":scope > .aura-page-header__actions > .aura-page-header__bar" : ":scope > .aura-page-header__actions"
8174
8277
  );
8175
8278
  if (!el) return;
8176
- const root = document.documentElement;
8279
+ const head = own.current;
8177
8280
  let checked = false;
8281
+ function mark() {
8282
+ const empty = noneShown(el, getComputedStyle(el).visibility === "visible");
8283
+ const state = empty ? "empty" : "shown";
8284
+ if (head.getAttribute("data-aura-bar") !== state) head.setAttribute("data-aura-bar", state);
8285
+ }
8178
8286
  function sync() {
8179
- if (bars[bars.length - 1] !== sync) return;
8180
- if (getComputedStyle(el).position === "fixed") {
8181
- root.style.setProperty(NAME, el.offsetHeight + "px");
8182
- if (!checked && (checked = true, fixedTrapped(el)))
8183
- devWarnOnce(
8184
- "pageheader-bar-trapped",
8185
- "PageHeader actionsBarBelow: an ancestor has a transform, filter, will-change or paint containment, so the fixed bar is placed against it instead of the screen. Remove it from the page header's ancestors."
8186
- );
8187
- } else root.style.removeProperty(NAME);
8287
+ mark();
8288
+ bars.write();
8289
+ if (!checked && getComputedStyle(el).position === "fixed" && (checked = true, fixedTrapped(el)))
8290
+ devWarnOnce(
8291
+ "pageheader-bar-trapped",
8292
+ "PageHeader actionsBarBelow: an ancestor has a transform, filter, will-change or paint containment, so the fixed bar is placed against it instead of the screen. Remove it from the page header's ancestors."
8293
+ );
8188
8294
  }
8189
- if (bars.length)
8190
- devWarnOnce(
8191
- "pageheader-bar-twice",
8192
- "PageHeader actionsBarBelow: two bars on one page overlap at the bottom of the screen. Give it to one PageHeader per page."
8193
- );
8194
- bars.push(sync);
8295
+ mark();
8296
+ marks.add(mark);
8297
+ bars.add(el);
8298
+ const mo = typeof MutationObserver === "undefined" ? null : new MutationObserver(function() {
8299
+ if (!frame) frame = requestAnimationFrame(later);
8300
+ });
8301
+ let frame = 0;
8302
+ function later() {
8303
+ frame = 0;
8304
+ sync();
8305
+ }
8306
+ if (mo)
8307
+ mo.observe(el, {
8308
+ childList: true,
8309
+ subtree: true,
8310
+ attributes: true,
8311
+ attributeFilter: ["hidden", "class", "style"]
8312
+ });
8195
8313
  const ro = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(sync);
8196
- if (ro) ro.observe(el);
8314
+ if (ro) ro.observe(el, { box: "border-box" });
8197
8315
  window.addEventListener("resize", sync);
8198
8316
  sync();
8199
8317
  return function() {
8200
8318
  if (ro) ro.disconnect();
8319
+ if (mo) mo.disconnect();
8320
+ if (frame) cancelAnimationFrame(frame);
8321
+ marks.delete(mark);
8201
8322
  window.removeEventListener("resize", sync);
8202
- bars.splice(bars.indexOf(sync), 1);
8203
- if (bars.length) bars[bars.length - 1]();
8204
- else root.style.removeProperty(NAME);
8323
+ head.removeAttribute("data-aura-bar");
8324
+ bars.remove(el);
8205
8325
  };
8206
8326
  },
8207
8327
  [bar, hasActions, split]
@@ -8722,17 +8842,7 @@ window.Aura = (() => {
8722
8842
 
8723
8843
  // src/ActionBar.tsx
8724
8844
  var React50 = __toESM(require_react(), 1);
8725
- var HEIGHT = "--aura-actionbar-height";
8726
- var edges = [];
8727
- function writeHeight() {
8728
- const root = document.documentElement;
8729
- for (let i = edges.length - 1; i >= 0; i--)
8730
- if (edges[i].getClientRects().length > 0 && edges[i].offsetHeight > 0 && getComputedStyle(edges[i]).position === "fixed") {
8731
- root.style.setProperty(HEIGHT, edges[i].offsetHeight + "px");
8732
- return;
8733
- }
8734
- root.style.removeProperty(HEIGHT);
8735
- }
8845
+ var edges = barStack("--aura-actionbar-height");
8736
8846
  var ActionBar = React50.forwardRef(function ActionBar2(props, ref) {
8737
8847
  const t = useStrings();
8738
8848
  const bulk = props.selected != null;
@@ -8756,14 +8866,14 @@ window.Aura = (() => {
8756
8866
  if (!edge || !el) return;
8757
8867
  let checked = false;
8758
8868
  function sync() {
8759
- writeHeight();
8869
+ edges.write();
8760
8870
  if (!checked && getComputedStyle(el).position === "fixed" && (checked = true, fixedTrapped(el)))
8761
8871
  devWarnOnce(
8762
8872
  "actionbar-edge-trapped",
8763
8873
  `ActionBar look="edge": an ancestor has a transform, filter, will-change or paint containment, so the fixed strip is placed against it instead of the screen. Remove it from the bar's ancestors.`
8764
8874
  );
8765
8875
  }
8766
- edges.push(el);
8876
+ edges.add(el);
8767
8877
  const ro = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(sync);
8768
8878
  if (ro) ro.observe(el, { box: "border-box" });
8769
8879
  window.addEventListener("resize", sync);
@@ -8771,8 +8881,7 @@ window.Aura = (() => {
8771
8881
  return function() {
8772
8882
  if (ro) ro.disconnect();
8773
8883
  window.removeEventListener("resize", sync);
8774
- edges.splice(edges.indexOf(el), 1);
8775
- writeHeight();
8884
+ edges.remove(el);
8776
8885
  };
8777
8886
  },
8778
8887
  [edge, idle]
@@ -400,6 +400,76 @@ function fixedTrapped(el) {
400
400
  }
401
401
  return false;
402
402
  }
403
+ function onScreen(el) {
404
+ if (el.offsetHeight <= 0 || el.getClientRects().length === 0) return false;
405
+ const check = el.checkVisibility;
406
+ if (typeof check === "function") return check.call(el, { visibilityProperty: true });
407
+ const v = getComputedStyle(el).visibility;
408
+ return v !== "hidden" && v !== "collapse";
409
+ }
410
+ function barStack(name, onMany, onRead) {
411
+ const els = [];
412
+ let frame = 0;
413
+ const docEvents = ["click", "keydown", "focusin", "transitionend", "beforematch"];
414
+ const winEvents = ["hashchange", "popstate"];
415
+ function write() {
416
+ if (frame) cancelAnimationFrame(frame);
417
+ frame = 0;
418
+ if (onRead) onRead();
419
+ const root = document.documentElement;
420
+ let shown = null, boxed = null, pinned2 = false, many = 0;
421
+ for (let i = els.length - 1; i >= 0; i--) {
422
+ const el = els[i];
423
+ if (getComputedStyle(el).position !== "fixed") continue;
424
+ pinned2 = true;
425
+ if (onScreen(el)) {
426
+ many++;
427
+ if (!shown) shown = el;
428
+ } else if (!boxed && el.offsetHeight > 0) boxed = el;
429
+ }
430
+ if (many > 1 && onMany) onMany();
431
+ const use = shown || boxed;
432
+ if (use) root.style.setProperty(name, use.offsetHeight + "px");
433
+ else if (pinned2) root.style.setProperty(name, "0px");
434
+ else root.style.removeProperty(name);
435
+ }
436
+ function later() {
437
+ if (!frame) frame = requestAnimationFrame(write);
438
+ }
439
+ function now() {
440
+ write();
441
+ later();
442
+ }
443
+ function listen(on) {
444
+ docEvents.forEach(function(t) {
445
+ const f = t === "focusin" ? now : later;
446
+ if (on) document.addEventListener(t, f, true);
447
+ else document.removeEventListener(t, f, true);
448
+ });
449
+ winEvents.forEach(function(t) {
450
+ if (on) window.addEventListener(t, later);
451
+ else window.removeEventListener(t, later);
452
+ });
453
+ }
454
+ return {
455
+ add: function(el) {
456
+ els.push(el);
457
+ if (els.length === 1) listen(true);
458
+ write();
459
+ },
460
+ remove: function(el) {
461
+ const i = els.indexOf(el);
462
+ if (i >= 0) els.splice(i, 1);
463
+ if (!els.length) {
464
+ listen(false);
465
+ if (frame) cancelAnimationFrame(frame);
466
+ frame = 0;
467
+ }
468
+ write();
469
+ },
470
+ write
471
+ };
472
+ }
403
473
 
404
474
  // src/display.tsx
405
475
  var React4 = __toESM(require("react"), 1);
@@ -8140,8 +8210,41 @@ var PageHeader = React44.forwardRef(function PageHeader2(props, ref) {
8140
8210
  });
8141
8211
 
8142
8212
  // src/PageHeaderClient.tsx
8143
- var NAME = "--aura-page-actions-height";
8144
- var bars = [];
8213
+ var bars = barStack(
8214
+ "--aura-page-actions-height",
8215
+ function() {
8216
+ devWarnOnce(
8217
+ "pageheader-bar-twice",
8218
+ "PageHeader actionsBarBelow: two bars are on screen at once and overlap at the bottom of the screen. Give it to one PageHeader per page (one per tab panel is fine: only the shown one counts)."
8219
+ );
8220
+ },
8221
+ function() {
8222
+ marks.forEach(function(m) {
8223
+ m();
8224
+ });
8225
+ }
8226
+ );
8227
+ var UNSEEN = ".aura-page-header__status, .sr-only, .aura-sr-only, .visually-hidden, .screen-reader-text";
8228
+ function noneShown(el, barVisible) {
8229
+ for (let n3 = el.firstChild; n3; n3 = n3.nextSibling) {
8230
+ if (n3.nodeType === 3) {
8231
+ if ((n3.textContent || "").trim()) return false;
8232
+ continue;
8233
+ }
8234
+ if (n3.nodeType !== 1) continue;
8235
+ const c = n3;
8236
+ if (c.hidden || c.matches(UNSEEN)) continue;
8237
+ const s = getComputedStyle(c);
8238
+ if (s.display === "none") continue;
8239
+ if (barVisible && (s.visibility === "hidden" || s.visibility === "collapse")) continue;
8240
+ const inline = c.getAttribute("style") || "";
8241
+ if (/position:\s*absolute/.test(inline) && /clip/.test(inline)) continue;
8242
+ if (s.display === "contents" && noneShown(c, barVisible)) continue;
8243
+ return false;
8244
+ }
8245
+ return true;
8246
+ }
8247
+ var marks = /* @__PURE__ */ new Set();
8145
8248
  var PageHeader3 = React45.forwardRef(function PageHeader4(props, ref) {
8146
8249
  const own = React45.useRef(null);
8147
8250
  const merged = useMergedRef(ref, own);
@@ -8155,35 +8258,52 @@ var PageHeader3 = React45.forwardRef(function PageHeader4(props, ref) {
8155
8258
  split ? ":scope > .aura-page-header__actions > .aura-page-header__bar" : ":scope > .aura-page-header__actions"
8156
8259
  );
8157
8260
  if (!el) return;
8158
- const root = document.documentElement;
8261
+ const head = own.current;
8159
8262
  let checked = false;
8263
+ function mark() {
8264
+ const empty = noneShown(el, getComputedStyle(el).visibility === "visible");
8265
+ const state = empty ? "empty" : "shown";
8266
+ if (head.getAttribute("data-aura-bar") !== state) head.setAttribute("data-aura-bar", state);
8267
+ }
8160
8268
  function sync() {
8161
- if (bars[bars.length - 1] !== sync) return;
8162
- if (getComputedStyle(el).position === "fixed") {
8163
- root.style.setProperty(NAME, el.offsetHeight + "px");
8164
- if (!checked && (checked = true, fixedTrapped(el)))
8165
- devWarnOnce(
8166
- "pageheader-bar-trapped",
8167
- "PageHeader actionsBarBelow: an ancestor has a transform, filter, will-change or paint containment, so the fixed bar is placed against it instead of the screen. Remove it from the page header's ancestors."
8168
- );
8169
- } else root.style.removeProperty(NAME);
8269
+ mark();
8270
+ bars.write();
8271
+ if (!checked && getComputedStyle(el).position === "fixed" && (checked = true, fixedTrapped(el)))
8272
+ devWarnOnce(
8273
+ "pageheader-bar-trapped",
8274
+ "PageHeader actionsBarBelow: an ancestor has a transform, filter, will-change or paint containment, so the fixed bar is placed against it instead of the screen. Remove it from the page header's ancestors."
8275
+ );
8170
8276
  }
8171
- if (bars.length)
8172
- devWarnOnce(
8173
- "pageheader-bar-twice",
8174
- "PageHeader actionsBarBelow: two bars on one page overlap at the bottom of the screen. Give it to one PageHeader per page."
8175
- );
8176
- bars.push(sync);
8277
+ mark();
8278
+ marks.add(mark);
8279
+ bars.add(el);
8280
+ const mo = typeof MutationObserver === "undefined" ? null : new MutationObserver(function() {
8281
+ if (!frame) frame = requestAnimationFrame(later);
8282
+ });
8283
+ let frame = 0;
8284
+ function later() {
8285
+ frame = 0;
8286
+ sync();
8287
+ }
8288
+ if (mo)
8289
+ mo.observe(el, {
8290
+ childList: true,
8291
+ subtree: true,
8292
+ attributes: true,
8293
+ attributeFilter: ["hidden", "class", "style"]
8294
+ });
8177
8295
  const ro = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(sync);
8178
- if (ro) ro.observe(el);
8296
+ if (ro) ro.observe(el, { box: "border-box" });
8179
8297
  window.addEventListener("resize", sync);
8180
8298
  sync();
8181
8299
  return function() {
8182
8300
  if (ro) ro.disconnect();
8301
+ if (mo) mo.disconnect();
8302
+ if (frame) cancelAnimationFrame(frame);
8303
+ marks.delete(mark);
8183
8304
  window.removeEventListener("resize", sync);
8184
- bars.splice(bars.indexOf(sync), 1);
8185
- if (bars.length) bars[bars.length - 1]();
8186
- else root.style.removeProperty(NAME);
8305
+ head.removeAttribute("data-aura-bar");
8306
+ bars.remove(el);
8187
8307
  };
8188
8308
  },
8189
8309
  [bar, hasActions, split]
@@ -8704,17 +8824,7 @@ var AppShell = React49.forwardRef(function AppShell2(props, ref) {
8704
8824
 
8705
8825
  // src/ActionBar.tsx
8706
8826
  var React50 = __toESM(require("react"), 1);
8707
- var HEIGHT = "--aura-actionbar-height";
8708
- var edges = [];
8709
- function writeHeight() {
8710
- const root = document.documentElement;
8711
- for (let i = edges.length - 1; i >= 0; i--)
8712
- if (edges[i].getClientRects().length > 0 && edges[i].offsetHeight > 0 && getComputedStyle(edges[i]).position === "fixed") {
8713
- root.style.setProperty(HEIGHT, edges[i].offsetHeight + "px");
8714
- return;
8715
- }
8716
- root.style.removeProperty(HEIGHT);
8717
- }
8827
+ var edges = barStack("--aura-actionbar-height");
8718
8828
  var ActionBar = React50.forwardRef(function ActionBar2(props, ref) {
8719
8829
  const t = useStrings();
8720
8830
  const bulk = props.selected != null;
@@ -8738,14 +8848,14 @@ var ActionBar = React50.forwardRef(function ActionBar2(props, ref) {
8738
8848
  if (!edge || !el) return;
8739
8849
  let checked = false;
8740
8850
  function sync() {
8741
- writeHeight();
8851
+ edges.write();
8742
8852
  if (!checked && getComputedStyle(el).position === "fixed" && (checked = true, fixedTrapped(el)))
8743
8853
  devWarnOnce(
8744
8854
  "actionbar-edge-trapped",
8745
8855
  `ActionBar look="edge": an ancestor has a transform, filter, will-change or paint containment, so the fixed strip is placed against it instead of the screen. Remove it from the bar's ancestors.`
8746
8856
  );
8747
8857
  }
8748
- edges.push(el);
8858
+ edges.add(el);
8749
8859
  const ro = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(sync);
8750
8860
  if (ro) ro.observe(el, { box: "border-box" });
8751
8861
  window.addEventListener("resize", sync);
@@ -8753,8 +8863,7 @@ var ActionBar = React50.forwardRef(function ActionBar2(props, ref) {
8753
8863
  return function() {
8754
8864
  if (ro) ro.disconnect();
8755
8865
  window.removeEventListener("resize", sync);
8756
- edges.splice(edges.indexOf(el), 1);
8757
- writeHeight();
8866
+ edges.remove(el);
8758
8867
  };
8759
8868
  },
8760
8869
  [edge, idle]
@@ -1,19 +1,9 @@
1
1
  'use client';
2
2
  import * as React from "react";
3
3
  import { Button } from "./Button.js";
4
- import { cx, devWarnOnce, fixedTrapped } from "./internal.js";
4
+ import { barStack, cx, devWarnOnce, fixedTrapped } from "./internal.js";
5
5
  import { useStrings } from "./locale.js";
6
- const HEIGHT = "--aura-actionbar-height";
7
- const edges = [];
8
- function writeHeight() {
9
- const root = document.documentElement;
10
- for (let i = edges.length - 1; i >= 0; i--)
11
- if (edges[i].getClientRects().length > 0 && edges[i].offsetHeight > 0 && getComputedStyle(edges[i]).position === "fixed") {
12
- root.style.setProperty(HEIGHT, edges[i].offsetHeight + "px");
13
- return;
14
- }
15
- root.style.removeProperty(HEIGHT);
16
- }
6
+ const edges = barStack("--aura-actionbar-height");
17
7
  const ActionBar = React.forwardRef(function ActionBar2(props, ref) {
18
8
  const t = useStrings();
19
9
  const bulk = props.selected != null;
@@ -37,14 +27,14 @@ const ActionBar = React.forwardRef(function ActionBar2(props, ref) {
37
27
  if (!edge || !el) return;
38
28
  let checked = false;
39
29
  function sync() {
40
- writeHeight();
30
+ edges.write();
41
31
  if (!checked && getComputedStyle(el).position === "fixed" && (checked = true, fixedTrapped(el)))
42
32
  devWarnOnce(
43
33
  "actionbar-edge-trapped",
44
34
  `ActionBar look="edge": an ancestor has a transform, filter, will-change or paint containment, so the fixed strip is placed against it instead of the screen. Remove it from the bar's ancestors.`
45
35
  );
46
36
  }
47
- edges.push(el);
37
+ edges.add(el);
48
38
  const ro = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(sync);
49
39
  if (ro) ro.observe(el, { box: "border-box" });
50
40
  window.addEventListener("resize", sync);
@@ -52,8 +42,7 @@ const ActionBar = React.forwardRef(function ActionBar2(props, ref) {
52
42
  return function() {
53
43
  if (ro) ro.disconnect();
54
44
  window.removeEventListener("resize", sync);
55
- edges.splice(edges.indexOf(el), 1);
56
- writeHeight();
45
+ edges.remove(el);
57
46
  };
58
47
  },
59
48
  [edge, idle]
@@ -1,9 +1,42 @@
1
1
  'use client';
2
2
  import * as React from "react";
3
3
  import { PageHeader as StaticPageHeader } from "./PageHeader.js";
4
- import { devWarnOnce, fixedTrapped as trapped, useMergedRef } from "./internal.js";
5
- const NAME = "--aura-page-actions-height";
6
- const bars = [];
4
+ import { barStack, devWarnOnce, fixedTrapped as trapped, useMergedRef } from "./internal.js";
5
+ const bars = barStack(
6
+ "--aura-page-actions-height",
7
+ function() {
8
+ devWarnOnce(
9
+ "pageheader-bar-twice",
10
+ "PageHeader actionsBarBelow: two bars are on screen at once and overlap at the bottom of the screen. Give it to one PageHeader per page (one per tab panel is fine: only the shown one counts)."
11
+ );
12
+ },
13
+ function() {
14
+ marks.forEach(function(m) {
15
+ m();
16
+ });
17
+ }
18
+ );
19
+ const UNSEEN = ".aura-page-header__status, .sr-only, .aura-sr-only, .visually-hidden, .screen-reader-text";
20
+ function noneShown(el, barVisible) {
21
+ for (let n = el.firstChild; n; n = n.nextSibling) {
22
+ if (n.nodeType === 3) {
23
+ if ((n.textContent || "").trim()) return false;
24
+ continue;
25
+ }
26
+ if (n.nodeType !== 1) continue;
27
+ const c = n;
28
+ if (c.hidden || c.matches(UNSEEN)) continue;
29
+ const s = getComputedStyle(c);
30
+ if (s.display === "none") continue;
31
+ if (barVisible && (s.visibility === "hidden" || s.visibility === "collapse")) continue;
32
+ const inline = c.getAttribute("style") || "";
33
+ if (/position:\s*absolute/.test(inline) && /clip/.test(inline)) continue;
34
+ if (s.display === "contents" && noneShown(c, barVisible)) continue;
35
+ return false;
36
+ }
37
+ return true;
38
+ }
39
+ const marks = /* @__PURE__ */ new Set();
7
40
  const PageHeader = React.forwardRef(function PageHeader2(props, ref) {
8
41
  const own = React.useRef(null);
9
42
  const merged = useMergedRef(ref, own);
@@ -17,35 +50,52 @@ const PageHeader = React.forwardRef(function PageHeader2(props, ref) {
17
50
  split ? ":scope > .aura-page-header__actions > .aura-page-header__bar" : ":scope > .aura-page-header__actions"
18
51
  );
19
52
  if (!el) return;
20
- const root = document.documentElement;
53
+ const head = own.current;
21
54
  let checked = false;
55
+ function mark() {
56
+ const empty = noneShown(el, getComputedStyle(el).visibility === "visible");
57
+ const state = empty ? "empty" : "shown";
58
+ if (head.getAttribute("data-aura-bar") !== state) head.setAttribute("data-aura-bar", state);
59
+ }
22
60
  function sync() {
23
- if (bars[bars.length - 1] !== sync) return;
24
- if (getComputedStyle(el).position === "fixed") {
25
- root.style.setProperty(NAME, el.offsetHeight + "px");
26
- if (!checked && (checked = true, trapped(el)))
27
- devWarnOnce(
28
- "pageheader-bar-trapped",
29
- "PageHeader actionsBarBelow: an ancestor has a transform, filter, will-change or paint containment, so the fixed bar is placed against it instead of the screen. Remove it from the page header's ancestors."
30
- );
31
- } else root.style.removeProperty(NAME);
61
+ mark();
62
+ bars.write();
63
+ if (!checked && getComputedStyle(el).position === "fixed" && (checked = true, trapped(el)))
64
+ devWarnOnce(
65
+ "pageheader-bar-trapped",
66
+ "PageHeader actionsBarBelow: an ancestor has a transform, filter, will-change or paint containment, so the fixed bar is placed against it instead of the screen. Remove it from the page header's ancestors."
67
+ );
68
+ }
69
+ mark();
70
+ marks.add(mark);
71
+ bars.add(el);
72
+ const mo = typeof MutationObserver === "undefined" ? null : new MutationObserver(function() {
73
+ if (!frame) frame = requestAnimationFrame(later);
74
+ });
75
+ let frame = 0;
76
+ function later() {
77
+ frame = 0;
78
+ sync();
32
79
  }
33
- if (bars.length)
34
- devWarnOnce(
35
- "pageheader-bar-twice",
36
- "PageHeader actionsBarBelow: two bars on one page overlap at the bottom of the screen. Give it to one PageHeader per page."
37
- );
38
- bars.push(sync);
80
+ if (mo)
81
+ mo.observe(el, {
82
+ childList: true,
83
+ subtree: true,
84
+ attributes: true,
85
+ attributeFilter: ["hidden", "class", "style"]
86
+ });
39
87
  const ro = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(sync);
40
- if (ro) ro.observe(el);
88
+ if (ro) ro.observe(el, { box: "border-box" });
41
89
  window.addEventListener("resize", sync);
42
90
  sync();
43
91
  return function() {
44
92
  if (ro) ro.disconnect();
93
+ if (mo) mo.disconnect();
94
+ if (frame) cancelAnimationFrame(frame);
95
+ marks.delete(mark);
45
96
  window.removeEventListener("resize", sync);
46
- bars.splice(bars.indexOf(sync), 1);
47
- if (bars.length) bars[bars.length - 1]();
48
- else root.style.removeProperty(NAME);
97
+ head.removeAttribute("data-aura-bar");
98
+ bars.remove(el);
49
99
  };
50
100
  },
51
101
  [bar, hasActions, split]
@@ -117,10 +117,81 @@ function fixedTrapped(el) {
117
117
  }
118
118
  return false;
119
119
  }
120
+ function onScreen(el) {
121
+ if (el.offsetHeight <= 0 || el.getClientRects().length === 0) return false;
122
+ const check = el.checkVisibility;
123
+ if (typeof check === "function") return check.call(el, { visibilityProperty: true });
124
+ const v = getComputedStyle(el).visibility;
125
+ return v !== "hidden" && v !== "collapse";
126
+ }
127
+ function barStack(name, onMany, onRead) {
128
+ const els = [];
129
+ let frame = 0;
130
+ const docEvents = ["click", "keydown", "focusin", "transitionend", "beforematch"];
131
+ const winEvents = ["hashchange", "popstate"];
132
+ function write() {
133
+ if (frame) cancelAnimationFrame(frame);
134
+ frame = 0;
135
+ if (onRead) onRead();
136
+ const root = document.documentElement;
137
+ let shown = null, boxed = null, pinned = false, many = 0;
138
+ for (let i = els.length - 1; i >= 0; i--) {
139
+ const el = els[i];
140
+ if (getComputedStyle(el).position !== "fixed") continue;
141
+ pinned = true;
142
+ if (onScreen(el)) {
143
+ many++;
144
+ if (!shown) shown = el;
145
+ } else if (!boxed && el.offsetHeight > 0) boxed = el;
146
+ }
147
+ if (many > 1 && onMany) onMany();
148
+ const use = shown || boxed;
149
+ if (use) root.style.setProperty(name, use.offsetHeight + "px");
150
+ else if (pinned) root.style.setProperty(name, "0px");
151
+ else root.style.removeProperty(name);
152
+ }
153
+ function later() {
154
+ if (!frame) frame = requestAnimationFrame(write);
155
+ }
156
+ function now() {
157
+ write();
158
+ later();
159
+ }
160
+ function listen(on) {
161
+ docEvents.forEach(function(t) {
162
+ const f = t === "focusin" ? now : later;
163
+ if (on) document.addEventListener(t, f, true);
164
+ else document.removeEventListener(t, f, true);
165
+ });
166
+ winEvents.forEach(function(t) {
167
+ if (on) window.addEventListener(t, later);
168
+ else window.removeEventListener(t, later);
169
+ });
170
+ }
171
+ return {
172
+ add: function(el) {
173
+ els.push(el);
174
+ if (els.length === 1) listen(true);
175
+ write();
176
+ },
177
+ remove: function(el) {
178
+ const i = els.indexOf(el);
179
+ if (i >= 0) els.splice(i, 1);
180
+ if (!els.length) {
181
+ listen(false);
182
+ if (frame) cancelAnimationFrame(frame);
183
+ frame = 0;
184
+ }
185
+ write();
186
+ },
187
+ write
188
+ };
189
+ }
120
190
  export {
121
191
  FOCUSABLE,
122
192
  FilterSheet,
123
193
  TAB_STOPS,
194
+ barStack,
124
195
  collator,
125
196
  compare,
126
197
  cx,
package/dist/styles.css CHANGED
@@ -1357,6 +1357,10 @@ summary.aura-link::-webkit-details-marker { display: none; }
1357
1357
  .aura-page-header__actions.is-split:not(:has(> :not(.aura-page-header__bar))) { display: contents; }
1358
1358
  @media (max-width: 639.98px) and (min-height: 30.00125rem) {
1359
1359
  .aura-page-header--actions-bar-below-sm > .aura-page-header__actions > .aura-page-header__bar { display: flex; flex: none; min-width: 0; }
1360
+ /* 5.74 (Chamber-OS 193): nothing but the status shown (Pay now hidden after paying): no strip, and no bar padding below. */
1361
+ .aura-page-header--actions-bar-below-sm[data-aura-bar="empty"] > .aura-page-header__actions:not(.is-split), .aura-page-header--actions-bar-below-sm[data-aura-bar="empty"] > .aura-page-header__actions > .aura-page-header__bar { display: none; }
1362
+ /* …and before hydration, from the markup alone (actionsBar's strip whose element children but the status are all `hidden` or visually hidden): it already goes; the page padding follows once the client has looked. */
1363
+ .aura-page-header--actions-bar-below-sm:not([data-aura-bar="shown"]) > .aura-page-header__actions > .aura-page-header__bar:not(:has(> :not(.aura-page-header__status, [hidden], .sr-only, .aura-sr-only, .visually-hidden, .screen-reader-text))):has(> *) { display: none; }
1360
1364
  :is(.aura-page-header--actions-bar-below-sm > .aura-page-header__actions:not(.is-split), .aura-page-header--actions-bar-below-sm > .aura-page-header__actions > .aura-page-header__bar) { position: fixed; z-index: var(--aura-z-bar); left: 0; right: 0; bottom: var(--aura-bottomnav-offset, 0px); box-sizing: border-box; min-height: 60px; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: var(--aura-space-2); margin: 0; padding: var(--aura-space-2) var(--aura-space-3) calc(var(--aura-space-2) + max(0px, env(safe-area-inset-bottom, 0px) - var(--aura-bottomnav-offset, 0px))) var(--aura-space-4); background: var(--aura-bg-surface); color: var(--aura-fg-primary); border: 0; border-top: 1px solid var(--aura-border-default); border-radius: 0; box-shadow: none; transition: bottom var(--aura-duration-base) var(--aura-ease); }
1361
1365
  /* 5.54 (Chamber-OS 166): the bar's buttons are 44px whatever the density, as ActionBar's on a phone. */
1362
1366
  :is(.aura-page-header--actions-bar-below-sm > .aura-page-header__actions:not(.is-split), .aura-page-header--actions-bar-below-sm > .aura-page-header__actions > .aura-page-header__bar) { --aura-button-height: var(--aura-touch-target); --aura-button-height-sm: var(--aura-touch-target); }
@@ -1372,13 +1376,17 @@ summary.aura-link::-webkit-details-marker { display: none; }
1372
1376
  :is(.aura-page-header--actions-bar-below-sm > .aura-page-header__actions:not(.is-split), .aura-page-header--actions-bar-below-sm > .aura-page-header__actions > .aura-page-header__bar):has(> .aura-icon-btn, > * > .aura-icon-btn) > :is(.aura-icon-btn, :has(> .aura-icon-btn)) { align-self: center; }
1373
1377
  :is(.aura-page-header--actions-bar-below-sm > .aura-page-header__actions:not(.is-split), .aura-page-header--actions-bar-below-sm > .aura-page-header__actions > .aura-page-header__bar):has(> .aura-icon-btn, > * > .aura-icon-btn) > :is(.aura-btn, * > .aura-btn):not(.aura-icon-btn) { height: auto; min-height: var(--aura-button-height); white-space: normal; padding: var(--aura-space-2) var(--aura-space-3); line-height: 1.35; text-align: center; overflow-wrap: anywhere; hyphens: auto; border-radius: min(var(--aura-button-radius), 22px); }
1374
1378
  :is(.aura-page-header--actions-bar-below-sm > .aura-page-header__actions:not(.is-split), .aura-page-header--actions-bar-below-sm > .aura-page-header__actions > .aura-page-header__bar):not(:has(> .aura-btn, > * > .aura-btn)) > .aura-page-header__status { flex: 1 1 0; align-self: center; }
1375
- :root:has(.aura-page-header--actions-bar-below-sm) { --aura-page-actions-space: calc(var(--aura-page-actions-height, 7rem) + var(--aura-bottomnav-offset, 0px) + var(--aura-space-3)); scroll-padding-bottom: var(--aura-page-actions-space); }
1376
- :root:has(.aura-page-header--actions-bar-below-sm.aura-page-header--actions-bar-floating) { --aura-page-actions-space: calc(var(--aura-page-actions-height, 7rem) + var(--aura-bottomnav-offset, 0px) + max(var(--aura-space-3), env(safe-area-inset-bottom, 0px)) + var(--aura-space-3)); }
1377
- :root:has(.aura-page-header--actions-bar-below-sm) .aura-shell__content { padding-bottom: calc(var(--aura-space-6) + var(--aura-page-actions-space)); }
1378
- :root:has(.aura-page-header--actions-bar-below-sm):not(:has(.aura-shell__content)) body { padding-bottom: var(--aura-page-actions-space); }
1379
+ :root:has(.aura-page-header--actions-bar-below-sm:not([data-aura-bar="empty"])) { --aura-page-actions-space: calc(var(--aura-page-actions-height, 7rem) + var(--aura-bottomnav-offset, 0px) + var(--aura-space-3)); scroll-padding-bottom: var(--aura-page-actions-space); }
1380
+ :root:has(.aura-page-header--actions-bar-below-sm.aura-page-header--actions-bar-floating:not([data-aura-bar="empty"])) { --aura-page-actions-space: calc(var(--aura-page-actions-height, 7rem) + var(--aura-bottomnav-offset, 0px) + max(var(--aura-space-3), env(safe-area-inset-bottom, 0px)) + var(--aura-space-3)); }
1381
+ :root:has(.aura-page-header--actions-bar-below-sm:not([data-aura-bar="empty"])) .aura-shell__content { padding-bottom: calc(var(--aura-space-6) + var(--aura-page-actions-space)); }
1382
+ :root:has(.aura-page-header--actions-bar-below-sm:not([data-aura-bar="empty"])):not(:has(.aura-shell__content)) body { padding-bottom: var(--aura-page-actions-space); }
1379
1383
  }
1380
1384
  @media (max-width: 767.98px) and (min-height: 30.00125rem) {
1381
1385
  .aura-page-header--actions-bar-below-md > .aura-page-header__actions > .aura-page-header__bar { display: flex; flex: none; min-width: 0; }
1386
+ /* 5.74 (Chamber-OS 193): nothing but the status shown (Pay now hidden after paying): no strip, and no bar padding below. */
1387
+ .aura-page-header--actions-bar-below-md[data-aura-bar="empty"] > .aura-page-header__actions:not(.is-split), .aura-page-header--actions-bar-below-md[data-aura-bar="empty"] > .aura-page-header__actions > .aura-page-header__bar { display: none; }
1388
+ /* …and before hydration, from the markup alone (actionsBar's strip whose element children but the status are all `hidden` or visually hidden): it already goes; the page padding follows once the client has looked. */
1389
+ .aura-page-header--actions-bar-below-md:not([data-aura-bar="shown"]) > .aura-page-header__actions > .aura-page-header__bar:not(:has(> :not(.aura-page-header__status, [hidden], .sr-only, .aura-sr-only, .visually-hidden, .screen-reader-text))):has(> *) { display: none; }
1382
1390
  :is(.aura-page-header--actions-bar-below-md > .aura-page-header__actions:not(.is-split), .aura-page-header--actions-bar-below-md > .aura-page-header__actions > .aura-page-header__bar) { position: fixed; z-index: var(--aura-z-bar); left: 0; right: 0; bottom: var(--aura-bottomnav-offset, 0px); box-sizing: border-box; min-height: 60px; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: var(--aura-space-2); margin: 0; padding: var(--aura-space-2) var(--aura-space-3) calc(var(--aura-space-2) + max(0px, env(safe-area-inset-bottom, 0px) - var(--aura-bottomnav-offset, 0px))) var(--aura-space-4); background: var(--aura-bg-surface); color: var(--aura-fg-primary); border: 0; border-top: 1px solid var(--aura-border-default); border-radius: 0; box-shadow: none; transition: bottom var(--aura-duration-base) var(--aura-ease); }
1383
1391
  /* 5.54 (Chamber-OS 166): the bar's buttons are 44px whatever the density, as ActionBar's on a phone. */
1384
1392
  :is(.aura-page-header--actions-bar-below-md > .aura-page-header__actions:not(.is-split), .aura-page-header--actions-bar-below-md > .aura-page-header__actions > .aura-page-header__bar) { --aura-button-height: var(--aura-touch-target); --aura-button-height-sm: var(--aura-touch-target); }
@@ -1394,10 +1402,10 @@ summary.aura-link::-webkit-details-marker { display: none; }
1394
1402
  :is(.aura-page-header--actions-bar-below-md > .aura-page-header__actions:not(.is-split), .aura-page-header--actions-bar-below-md > .aura-page-header__actions > .aura-page-header__bar):has(> .aura-icon-btn, > * > .aura-icon-btn) > :is(.aura-icon-btn, :has(> .aura-icon-btn)) { align-self: center; }
1395
1403
  :is(.aura-page-header--actions-bar-below-md > .aura-page-header__actions:not(.is-split), .aura-page-header--actions-bar-below-md > .aura-page-header__actions > .aura-page-header__bar):has(> .aura-icon-btn, > * > .aura-icon-btn) > :is(.aura-btn, * > .aura-btn):not(.aura-icon-btn) { height: auto; min-height: var(--aura-button-height); white-space: normal; padding: var(--aura-space-2) var(--aura-space-3); line-height: 1.35; text-align: center; overflow-wrap: anywhere; hyphens: auto; border-radius: min(var(--aura-button-radius), 22px); }
1396
1404
  :is(.aura-page-header--actions-bar-below-md > .aura-page-header__actions:not(.is-split), .aura-page-header--actions-bar-below-md > .aura-page-header__actions > .aura-page-header__bar):not(:has(> .aura-btn, > * > .aura-btn)) > .aura-page-header__status { flex: 1 1 0; align-self: center; }
1397
- :root:has(.aura-page-header--actions-bar-below-md) { --aura-page-actions-space: calc(var(--aura-page-actions-height, 7rem) + var(--aura-bottomnav-offset, 0px) + var(--aura-space-3)); scroll-padding-bottom: var(--aura-page-actions-space); }
1398
- :root:has(.aura-page-header--actions-bar-below-md.aura-page-header--actions-bar-floating) { --aura-page-actions-space: calc(var(--aura-page-actions-height, 7rem) + var(--aura-bottomnav-offset, 0px) + max(var(--aura-space-3), env(safe-area-inset-bottom, 0px)) + var(--aura-space-3)); }
1399
- :root:has(.aura-page-header--actions-bar-below-md) .aura-shell__content { padding-bottom: calc(var(--aura-space-6) + var(--aura-page-actions-space)); }
1400
- :root:has(.aura-page-header--actions-bar-below-md):not(:has(.aura-shell__content)) body { padding-bottom: var(--aura-page-actions-space); }
1405
+ :root:has(.aura-page-header--actions-bar-below-md:not([data-aura-bar="empty"])) { --aura-page-actions-space: calc(var(--aura-page-actions-height, 7rem) + var(--aura-bottomnav-offset, 0px) + var(--aura-space-3)); scroll-padding-bottom: var(--aura-page-actions-space); }
1406
+ :root:has(.aura-page-header--actions-bar-below-md.aura-page-header--actions-bar-floating:not([data-aura-bar="empty"])) { --aura-page-actions-space: calc(var(--aura-page-actions-height, 7rem) + var(--aura-bottomnav-offset, 0px) + max(var(--aura-space-3), env(safe-area-inset-bottom, 0px)) + var(--aura-space-3)); }
1407
+ :root:has(.aura-page-header--actions-bar-below-md:not([data-aura-bar="empty"])) .aura-shell__content { padding-bottom: calc(var(--aura-space-6) + var(--aura-page-actions-space)); }
1408
+ :root:has(.aura-page-header--actions-bar-below-md:not([data-aura-bar="empty"])):not(:has(.aura-shell__content)) body { padding-bottom: var(--aura-page-actions-space); }
1401
1409
  }
1402
1410
  /* 5.71: as specific as the bar rules (and after them), and on actionsBar's box too, so reduced motion stops the slide. */
1403
1411
  @media (prefers-reduced-motion: reduce) { .aura-page-header.aura-page-header > .aura-page-header__actions, .aura-page-header.aura-page-header > .aura-page-header__actions > .aura-page-header__bar { transition: none; } }
@@ -1359,6 +1359,10 @@ summary.aura-link::-webkit-details-marker { display: none; }
1359
1359
  .aura-page-header__actions.is-split:not(:has(> :not(.aura-page-header__bar))) { display: contents; }
1360
1360
  @media (max-width: 639.98px) and (min-height: 30.00125rem) {
1361
1361
  .aura-page-header--actions-bar-below-sm > .aura-page-header__actions > .aura-page-header__bar { display: flex; flex: none; min-width: 0; }
1362
+ /* 5.74 (Chamber-OS 193): nothing but the status shown (Pay now hidden after paying): no strip, and no bar padding below. */
1363
+ .aura-page-header--actions-bar-below-sm[data-aura-bar="empty"] > .aura-page-header__actions:not(.is-split), .aura-page-header--actions-bar-below-sm[data-aura-bar="empty"] > .aura-page-header__actions > .aura-page-header__bar { display: none; }
1364
+ /* …and before hydration, from the markup alone (actionsBar's strip whose element children but the status are all `hidden` or visually hidden): it already goes; the page padding follows once the client has looked. */
1365
+ .aura-page-header--actions-bar-below-sm:not([data-aura-bar="shown"]) > .aura-page-header__actions > .aura-page-header__bar:not(:has(> :not(.aura-page-header__status, [hidden], .sr-only, .aura-sr-only, .visually-hidden, .screen-reader-text))):has(> *) { display: none; }
1362
1366
  :is(.aura-page-header--actions-bar-below-sm > .aura-page-header__actions:not(.is-split), .aura-page-header--actions-bar-below-sm > .aura-page-header__actions > .aura-page-header__bar) { position: fixed; z-index: var(--aura-z-bar); left: 0; right: 0; bottom: var(--aura-bottomnav-offset, 0px); box-sizing: border-box; min-height: 60px; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: var(--aura-space-2); margin: 0; padding: var(--aura-space-2) var(--aura-space-3) calc(var(--aura-space-2) + max(0px, env(safe-area-inset-bottom, 0px) - var(--aura-bottomnav-offset, 0px))) var(--aura-space-4); background: var(--aura-bg-surface); color: var(--aura-fg-primary); border: 0; border-top: 1px solid var(--aura-border-default); border-radius: 0; box-shadow: none; transition: bottom var(--aura-duration-base) var(--aura-ease); }
1363
1367
  /* 5.54 (Chamber-OS 166): the bar's buttons are 44px whatever the density, as ActionBar's on a phone. */
1364
1368
  :is(.aura-page-header--actions-bar-below-sm > .aura-page-header__actions:not(.is-split), .aura-page-header--actions-bar-below-sm > .aura-page-header__actions > .aura-page-header__bar) { --aura-button-height: var(--aura-touch-target); --aura-button-height-sm: var(--aura-touch-target); }
@@ -1374,13 +1378,17 @@ summary.aura-link::-webkit-details-marker { display: none; }
1374
1378
  :is(.aura-page-header--actions-bar-below-sm > .aura-page-header__actions:not(.is-split), .aura-page-header--actions-bar-below-sm > .aura-page-header__actions > .aura-page-header__bar):has(> .aura-icon-btn, > * > .aura-icon-btn) > :is(.aura-icon-btn, :has(> .aura-icon-btn)) { align-self: center; }
1375
1379
  :is(.aura-page-header--actions-bar-below-sm > .aura-page-header__actions:not(.is-split), .aura-page-header--actions-bar-below-sm > .aura-page-header__actions > .aura-page-header__bar):has(> .aura-icon-btn, > * > .aura-icon-btn) > :is(.aura-btn, * > .aura-btn):not(.aura-icon-btn) { height: auto; min-height: var(--aura-button-height); white-space: normal; padding: var(--aura-space-2) var(--aura-space-3); line-height: 1.35; text-align: center; overflow-wrap: anywhere; hyphens: auto; border-radius: min(var(--aura-button-radius), 22px); }
1376
1380
  :is(.aura-page-header--actions-bar-below-sm > .aura-page-header__actions:not(.is-split), .aura-page-header--actions-bar-below-sm > .aura-page-header__actions > .aura-page-header__bar):not(:has(> .aura-btn, > * > .aura-btn)) > .aura-page-header__status { flex: 1 1 0; align-self: center; }
1377
- :root:has(.aura-page-header--actions-bar-below-sm) { --aura-page-actions-space: calc(var(--aura-page-actions-height, 7rem) + var(--aura-bottomnav-offset, 0px) + var(--aura-space-3)); scroll-padding-bottom: var(--aura-page-actions-space); }
1378
- :root:has(.aura-page-header--actions-bar-below-sm.aura-page-header--actions-bar-floating) { --aura-page-actions-space: calc(var(--aura-page-actions-height, 7rem) + var(--aura-bottomnav-offset, 0px) + max(var(--aura-space-3), env(safe-area-inset-bottom, 0px)) + var(--aura-space-3)); }
1379
- :root:has(.aura-page-header--actions-bar-below-sm) .aura-shell__content { padding-bottom: calc(var(--aura-space-6) + var(--aura-page-actions-space)); }
1380
- :root:has(.aura-page-header--actions-bar-below-sm):not(:has(.aura-shell__content)) body { padding-bottom: var(--aura-page-actions-space); }
1381
+ :root:has(.aura-page-header--actions-bar-below-sm:not([data-aura-bar="empty"])) { --aura-page-actions-space: calc(var(--aura-page-actions-height, 7rem) + var(--aura-bottomnav-offset, 0px) + var(--aura-space-3)); scroll-padding-bottom: var(--aura-page-actions-space); }
1382
+ :root:has(.aura-page-header--actions-bar-below-sm.aura-page-header--actions-bar-floating:not([data-aura-bar="empty"])) { --aura-page-actions-space: calc(var(--aura-page-actions-height, 7rem) + var(--aura-bottomnav-offset, 0px) + max(var(--aura-space-3), env(safe-area-inset-bottom, 0px)) + var(--aura-space-3)); }
1383
+ :root:has(.aura-page-header--actions-bar-below-sm:not([data-aura-bar="empty"])) .aura-shell__content { padding-bottom: calc(var(--aura-space-6) + var(--aura-page-actions-space)); }
1384
+ :root:has(.aura-page-header--actions-bar-below-sm:not([data-aura-bar="empty"])):not(:has(.aura-shell__content)) body { padding-bottom: var(--aura-page-actions-space); }
1381
1385
  }
1382
1386
  @media (max-width: 767.98px) and (min-height: 30.00125rem) {
1383
1387
  .aura-page-header--actions-bar-below-md > .aura-page-header__actions > .aura-page-header__bar { display: flex; flex: none; min-width: 0; }
1388
+ /* 5.74 (Chamber-OS 193): nothing but the status shown (Pay now hidden after paying): no strip, and no bar padding below. */
1389
+ .aura-page-header--actions-bar-below-md[data-aura-bar="empty"] > .aura-page-header__actions:not(.is-split), .aura-page-header--actions-bar-below-md[data-aura-bar="empty"] > .aura-page-header__actions > .aura-page-header__bar { display: none; }
1390
+ /* …and before hydration, from the markup alone (actionsBar's strip whose element children but the status are all `hidden` or visually hidden): it already goes; the page padding follows once the client has looked. */
1391
+ .aura-page-header--actions-bar-below-md:not([data-aura-bar="shown"]) > .aura-page-header__actions > .aura-page-header__bar:not(:has(> :not(.aura-page-header__status, [hidden], .sr-only, .aura-sr-only, .visually-hidden, .screen-reader-text))):has(> *) { display: none; }
1384
1392
  :is(.aura-page-header--actions-bar-below-md > .aura-page-header__actions:not(.is-split), .aura-page-header--actions-bar-below-md > .aura-page-header__actions > .aura-page-header__bar) { position: fixed; z-index: var(--aura-z-bar); left: 0; right: 0; bottom: var(--aura-bottomnav-offset, 0px); box-sizing: border-box; min-height: 60px; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: var(--aura-space-2); margin: 0; padding: var(--aura-space-2) var(--aura-space-3) calc(var(--aura-space-2) + max(0px, env(safe-area-inset-bottom, 0px) - var(--aura-bottomnav-offset, 0px))) var(--aura-space-4); background: var(--aura-bg-surface); color: var(--aura-fg-primary); border: 0; border-top: 1px solid var(--aura-border-default); border-radius: 0; box-shadow: none; transition: bottom var(--aura-duration-base) var(--aura-ease); }
1385
1393
  /* 5.54 (Chamber-OS 166): the bar's buttons are 44px whatever the density, as ActionBar's on a phone. */
1386
1394
  :is(.aura-page-header--actions-bar-below-md > .aura-page-header__actions:not(.is-split), .aura-page-header--actions-bar-below-md > .aura-page-header__actions > .aura-page-header__bar) { --aura-button-height: var(--aura-touch-target); --aura-button-height-sm: var(--aura-touch-target); }
@@ -1396,10 +1404,10 @@ summary.aura-link::-webkit-details-marker { display: none; }
1396
1404
  :is(.aura-page-header--actions-bar-below-md > .aura-page-header__actions:not(.is-split), .aura-page-header--actions-bar-below-md > .aura-page-header__actions > .aura-page-header__bar):has(> .aura-icon-btn, > * > .aura-icon-btn) > :is(.aura-icon-btn, :has(> .aura-icon-btn)) { align-self: center; }
1397
1405
  :is(.aura-page-header--actions-bar-below-md > .aura-page-header__actions:not(.is-split), .aura-page-header--actions-bar-below-md > .aura-page-header__actions > .aura-page-header__bar):has(> .aura-icon-btn, > * > .aura-icon-btn) > :is(.aura-btn, * > .aura-btn):not(.aura-icon-btn) { height: auto; min-height: var(--aura-button-height); white-space: normal; padding: var(--aura-space-2) var(--aura-space-3); line-height: 1.35; text-align: center; overflow-wrap: anywhere; hyphens: auto; border-radius: min(var(--aura-button-radius), 22px); }
1398
1406
  :is(.aura-page-header--actions-bar-below-md > .aura-page-header__actions:not(.is-split), .aura-page-header--actions-bar-below-md > .aura-page-header__actions > .aura-page-header__bar):not(:has(> .aura-btn, > * > .aura-btn)) > .aura-page-header__status { flex: 1 1 0; align-self: center; }
1399
- :root:has(.aura-page-header--actions-bar-below-md) { --aura-page-actions-space: calc(var(--aura-page-actions-height, 7rem) + var(--aura-bottomnav-offset, 0px) + var(--aura-space-3)); scroll-padding-bottom: var(--aura-page-actions-space); }
1400
- :root:has(.aura-page-header--actions-bar-below-md.aura-page-header--actions-bar-floating) { --aura-page-actions-space: calc(var(--aura-page-actions-height, 7rem) + var(--aura-bottomnav-offset, 0px) + max(var(--aura-space-3), env(safe-area-inset-bottom, 0px)) + var(--aura-space-3)); }
1401
- :root:has(.aura-page-header--actions-bar-below-md) .aura-shell__content { padding-bottom: calc(var(--aura-space-6) + var(--aura-page-actions-space)); }
1402
- :root:has(.aura-page-header--actions-bar-below-md):not(:has(.aura-shell__content)) body { padding-bottom: var(--aura-page-actions-space); }
1407
+ :root:has(.aura-page-header--actions-bar-below-md:not([data-aura-bar="empty"])) { --aura-page-actions-space: calc(var(--aura-page-actions-height, 7rem) + var(--aura-bottomnav-offset, 0px) + var(--aura-space-3)); scroll-padding-bottom: var(--aura-page-actions-space); }
1408
+ :root:has(.aura-page-header--actions-bar-below-md.aura-page-header--actions-bar-floating:not([data-aura-bar="empty"])) { --aura-page-actions-space: calc(var(--aura-page-actions-height, 7rem) + var(--aura-bottomnav-offset, 0px) + max(var(--aura-space-3), env(safe-area-inset-bottom, 0px)) + var(--aura-space-3)); }
1409
+ :root:has(.aura-page-header--actions-bar-below-md:not([data-aura-bar="empty"])) .aura-shell__content { padding-bottom: calc(var(--aura-space-6) + var(--aura-page-actions-space)); }
1410
+ :root:has(.aura-page-header--actions-bar-below-md:not([data-aura-bar="empty"])):not(:has(.aura-shell__content)) body { padding-bottom: var(--aura-page-actions-space); }
1403
1411
  }
1404
1412
  /* 5.71: as specific as the bar rules (and after them), and on actionsBar's box too, so reduced motion stops the slide. */
1405
1413
  @media (prefers-reduced-motion: reduce) { .aura-page-header.aura-page-header > .aura-page-header__actions, .aura-page-header.aura-page-header > .aura-page-header__actions > .aura-page-header__bar { transition: none; } }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jirawatpyk/aura-react",
3
- "version": "5.72.0",
3
+ "version": "5.74.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",