@jirawatpyk/aura-react 5.72.0 → 5.73.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,12 @@ 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.73 — Chamber-OS addendum 93 follow-up (#192)
190
+
191
+ - **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.
192
+ - **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.
193
+ - **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.
194
+
189
195
  ## 5.72 — Chamber-OS addendum 93 (#192)
190
196
 
191
197
  - **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,75 @@ 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) {
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
+ const root = document.documentElement;
437
+ let shown = null, boxed = null, pinned2 = false, many = 0;
438
+ for (let i = els.length - 1; i >= 0; i--) {
439
+ const el = els[i];
440
+ if (getComputedStyle(el).position !== "fixed") continue;
441
+ pinned2 = true;
442
+ if (onScreen(el)) {
443
+ many++;
444
+ if (!shown) shown = el;
445
+ } else if (!boxed && el.offsetHeight > 0) boxed = el;
446
+ }
447
+ if (many > 1 && onMany) onMany();
448
+ const use = shown || boxed;
449
+ if (use) root.style.setProperty(name, use.offsetHeight + "px");
450
+ else if (pinned2) root.style.setProperty(name, "0px");
451
+ else root.style.removeProperty(name);
452
+ }
453
+ function later() {
454
+ if (!frame) frame = requestAnimationFrame(write);
455
+ }
456
+ function now() {
457
+ write();
458
+ later();
459
+ }
460
+ function listen(on) {
461
+ docEvents.forEach(function(t) {
462
+ const f = t === "focusin" ? now : later;
463
+ if (on) document.addEventListener(t, f, true);
464
+ else document.removeEventListener(t, f, true);
465
+ });
466
+ winEvents.forEach(function(t) {
467
+ if (on) window.addEventListener(t, later);
468
+ else window.removeEventListener(t, later);
469
+ });
470
+ }
471
+ return {
472
+ add: function(el) {
473
+ els.push(el);
474
+ if (els.length === 1) listen(true);
475
+ write();
476
+ },
477
+ remove: function(el) {
478
+ const i = els.indexOf(el);
479
+ if (i >= 0) els.splice(i, 1);
480
+ if (!els.length) {
481
+ listen(false);
482
+ if (frame) cancelAnimationFrame(frame);
483
+ frame = 0;
484
+ }
485
+ write();
486
+ },
487
+ write
488
+ };
489
+ }
421
490
 
422
491
  // src/display.tsx
423
492
  var React4 = __toESM(require_react(), 1);
@@ -8158,8 +8227,12 @@ window.Aura = (() => {
8158
8227
  });
8159
8228
 
8160
8229
  // src/PageHeaderClient.tsx
8161
- var NAME = "--aura-page-actions-height";
8162
- var bars = [];
8230
+ var bars = barStack("--aura-page-actions-height", function() {
8231
+ devWarnOnce(
8232
+ "pageheader-bar-twice",
8233
+ "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)."
8234
+ );
8235
+ });
8163
8236
  var PageHeader3 = React45.forwardRef(function PageHeader4(props, ref) {
8164
8237
  const own = React45.useRef(null);
8165
8238
  const merged = useMergedRef(ref, own);
@@ -8173,35 +8246,24 @@ window.Aura = (() => {
8173
8246
  split ? ":scope > .aura-page-header__actions > .aura-page-header__bar" : ":scope > .aura-page-header__actions"
8174
8247
  );
8175
8248
  if (!el) return;
8176
- const root = document.documentElement;
8177
8249
  let checked = false;
8178
8250
  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);
8251
+ bars.write();
8252
+ if (!checked && getComputedStyle(el).position === "fixed" && (checked = true, fixedTrapped(el)))
8253
+ devWarnOnce(
8254
+ "pageheader-bar-trapped",
8255
+ "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."
8256
+ );
8188
8257
  }
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);
8258
+ bars.add(el);
8195
8259
  const ro = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(sync);
8196
- if (ro) ro.observe(el);
8260
+ if (ro) ro.observe(el, { box: "border-box" });
8197
8261
  window.addEventListener("resize", sync);
8198
8262
  sync();
8199
8263
  return function() {
8200
8264
  if (ro) ro.disconnect();
8201
8265
  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);
8266
+ bars.remove(el);
8205
8267
  };
8206
8268
  },
8207
8269
  [bar, hasActions, split]
@@ -8722,17 +8784,7 @@ window.Aura = (() => {
8722
8784
 
8723
8785
  // src/ActionBar.tsx
8724
8786
  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
- }
8787
+ var edges = barStack("--aura-actionbar-height");
8736
8788
  var ActionBar = React50.forwardRef(function ActionBar2(props, ref) {
8737
8789
  const t = useStrings();
8738
8790
  const bulk = props.selected != null;
@@ -8756,14 +8808,14 @@ window.Aura = (() => {
8756
8808
  if (!edge || !el) return;
8757
8809
  let checked = false;
8758
8810
  function sync() {
8759
- writeHeight();
8811
+ edges.write();
8760
8812
  if (!checked && getComputedStyle(el).position === "fixed" && (checked = true, fixedTrapped(el)))
8761
8813
  devWarnOnce(
8762
8814
  "actionbar-edge-trapped",
8763
8815
  `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
8816
  );
8765
8817
  }
8766
- edges.push(el);
8818
+ edges.add(el);
8767
8819
  const ro = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(sync);
8768
8820
  if (ro) ro.observe(el, { box: "border-box" });
8769
8821
  window.addEventListener("resize", sync);
@@ -8771,8 +8823,7 @@ window.Aura = (() => {
8771
8823
  return function() {
8772
8824
  if (ro) ro.disconnect();
8773
8825
  window.removeEventListener("resize", sync);
8774
- edges.splice(edges.indexOf(el), 1);
8775
- writeHeight();
8826
+ edges.remove(el);
8776
8827
  };
8777
8828
  },
8778
8829
  [edge, idle]
@@ -400,6 +400,75 @@ 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) {
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
+ const root = document.documentElement;
419
+ let shown = null, boxed = null, pinned2 = false, many = 0;
420
+ for (let i = els.length - 1; i >= 0; i--) {
421
+ const el = els[i];
422
+ if (getComputedStyle(el).position !== "fixed") continue;
423
+ pinned2 = true;
424
+ if (onScreen(el)) {
425
+ many++;
426
+ if (!shown) shown = el;
427
+ } else if (!boxed && el.offsetHeight > 0) boxed = el;
428
+ }
429
+ if (many > 1 && onMany) onMany();
430
+ const use = shown || boxed;
431
+ if (use) root.style.setProperty(name, use.offsetHeight + "px");
432
+ else if (pinned2) root.style.setProperty(name, "0px");
433
+ else root.style.removeProperty(name);
434
+ }
435
+ function later() {
436
+ if (!frame) frame = requestAnimationFrame(write);
437
+ }
438
+ function now() {
439
+ write();
440
+ later();
441
+ }
442
+ function listen(on) {
443
+ docEvents.forEach(function(t) {
444
+ const f = t === "focusin" ? now : later;
445
+ if (on) document.addEventListener(t, f, true);
446
+ else document.removeEventListener(t, f, true);
447
+ });
448
+ winEvents.forEach(function(t) {
449
+ if (on) window.addEventListener(t, later);
450
+ else window.removeEventListener(t, later);
451
+ });
452
+ }
453
+ return {
454
+ add: function(el) {
455
+ els.push(el);
456
+ if (els.length === 1) listen(true);
457
+ write();
458
+ },
459
+ remove: function(el) {
460
+ const i = els.indexOf(el);
461
+ if (i >= 0) els.splice(i, 1);
462
+ if (!els.length) {
463
+ listen(false);
464
+ if (frame) cancelAnimationFrame(frame);
465
+ frame = 0;
466
+ }
467
+ write();
468
+ },
469
+ write
470
+ };
471
+ }
403
472
 
404
473
  // src/display.tsx
405
474
  var React4 = __toESM(require("react"), 1);
@@ -8140,8 +8209,12 @@ var PageHeader = React44.forwardRef(function PageHeader2(props, ref) {
8140
8209
  });
8141
8210
 
8142
8211
  // src/PageHeaderClient.tsx
8143
- var NAME = "--aura-page-actions-height";
8144
- var bars = [];
8212
+ var bars = barStack("--aura-page-actions-height", function() {
8213
+ devWarnOnce(
8214
+ "pageheader-bar-twice",
8215
+ "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)."
8216
+ );
8217
+ });
8145
8218
  var PageHeader3 = React45.forwardRef(function PageHeader4(props, ref) {
8146
8219
  const own = React45.useRef(null);
8147
8220
  const merged = useMergedRef(ref, own);
@@ -8155,35 +8228,24 @@ var PageHeader3 = React45.forwardRef(function PageHeader4(props, ref) {
8155
8228
  split ? ":scope > .aura-page-header__actions > .aura-page-header__bar" : ":scope > .aura-page-header__actions"
8156
8229
  );
8157
8230
  if (!el) return;
8158
- const root = document.documentElement;
8159
8231
  let checked = false;
8160
8232
  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);
8233
+ bars.write();
8234
+ if (!checked && getComputedStyle(el).position === "fixed" && (checked = true, fixedTrapped(el)))
8235
+ devWarnOnce(
8236
+ "pageheader-bar-trapped",
8237
+ "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."
8238
+ );
8170
8239
  }
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);
8240
+ bars.add(el);
8177
8241
  const ro = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(sync);
8178
- if (ro) ro.observe(el);
8242
+ if (ro) ro.observe(el, { box: "border-box" });
8179
8243
  window.addEventListener("resize", sync);
8180
8244
  sync();
8181
8245
  return function() {
8182
8246
  if (ro) ro.disconnect();
8183
8247
  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);
8248
+ bars.remove(el);
8187
8249
  };
8188
8250
  },
8189
8251
  [bar, hasActions, split]
@@ -8704,17 +8766,7 @@ var AppShell = React49.forwardRef(function AppShell2(props, ref) {
8704
8766
 
8705
8767
  // src/ActionBar.tsx
8706
8768
  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
- }
8769
+ var edges = barStack("--aura-actionbar-height");
8718
8770
  var ActionBar = React50.forwardRef(function ActionBar2(props, ref) {
8719
8771
  const t = useStrings();
8720
8772
  const bulk = props.selected != null;
@@ -8738,14 +8790,14 @@ var ActionBar = React50.forwardRef(function ActionBar2(props, ref) {
8738
8790
  if (!edge || !el) return;
8739
8791
  let checked = false;
8740
8792
  function sync() {
8741
- writeHeight();
8793
+ edges.write();
8742
8794
  if (!checked && getComputedStyle(el).position === "fixed" && (checked = true, fixedTrapped(el)))
8743
8795
  devWarnOnce(
8744
8796
  "actionbar-edge-trapped",
8745
8797
  `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
8798
  );
8747
8799
  }
8748
- edges.push(el);
8800
+ edges.add(el);
8749
8801
  const ro = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(sync);
8750
8802
  if (ro) ro.observe(el, { box: "border-box" });
8751
8803
  window.addEventListener("resize", sync);
@@ -8753,8 +8805,7 @@ var ActionBar = React50.forwardRef(function ActionBar2(props, ref) {
8753
8805
  return function() {
8754
8806
  if (ro) ro.disconnect();
8755
8807
  window.removeEventListener("resize", sync);
8756
- edges.splice(edges.indexOf(el), 1);
8757
- writeHeight();
8808
+ edges.remove(el);
8758
8809
  };
8759
8810
  },
8760
8811
  [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,13 @@
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("--aura-page-actions-height", function() {
6
+ devWarnOnce(
7
+ "pageheader-bar-twice",
8
+ "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)."
9
+ );
10
+ });
7
11
  const PageHeader = React.forwardRef(function PageHeader2(props, ref) {
8
12
  const own = React.useRef(null);
9
13
  const merged = useMergedRef(ref, own);
@@ -17,35 +21,24 @@ const PageHeader = React.forwardRef(function PageHeader2(props, ref) {
17
21
  split ? ":scope > .aura-page-header__actions > .aura-page-header__bar" : ":scope > .aura-page-header__actions"
18
22
  );
19
23
  if (!el) return;
20
- const root = document.documentElement;
21
24
  let checked = false;
22
25
  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);
26
+ bars.write();
27
+ if (!checked && getComputedStyle(el).position === "fixed" && (checked = true, trapped(el)))
28
+ devWarnOnce(
29
+ "pageheader-bar-trapped",
30
+ "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."
31
+ );
32
32
  }
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);
33
+ bars.add(el);
39
34
  const ro = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(sync);
40
- if (ro) ro.observe(el);
35
+ if (ro) ro.observe(el, { box: "border-box" });
41
36
  window.addEventListener("resize", sync);
42
37
  sync();
43
38
  return function() {
44
39
  if (ro) ro.disconnect();
45
40
  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);
41
+ bars.remove(el);
49
42
  };
50
43
  },
51
44
  [bar, hasActions, split]
@@ -117,10 +117,80 @@ 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) {
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
+ const root = document.documentElement;
136
+ let shown = null, boxed = null, pinned = false, many = 0;
137
+ for (let i = els.length - 1; i >= 0; i--) {
138
+ const el = els[i];
139
+ if (getComputedStyle(el).position !== "fixed") continue;
140
+ pinned = true;
141
+ if (onScreen(el)) {
142
+ many++;
143
+ if (!shown) shown = el;
144
+ } else if (!boxed && el.offsetHeight > 0) boxed = el;
145
+ }
146
+ if (many > 1 && onMany) onMany();
147
+ const use = shown || boxed;
148
+ if (use) root.style.setProperty(name, use.offsetHeight + "px");
149
+ else if (pinned) root.style.setProperty(name, "0px");
150
+ else root.style.removeProperty(name);
151
+ }
152
+ function later() {
153
+ if (!frame) frame = requestAnimationFrame(write);
154
+ }
155
+ function now() {
156
+ write();
157
+ later();
158
+ }
159
+ function listen(on) {
160
+ docEvents.forEach(function(t) {
161
+ const f = t === "focusin" ? now : later;
162
+ if (on) document.addEventListener(t, f, true);
163
+ else document.removeEventListener(t, f, true);
164
+ });
165
+ winEvents.forEach(function(t) {
166
+ if (on) window.addEventListener(t, later);
167
+ else window.removeEventListener(t, later);
168
+ });
169
+ }
170
+ return {
171
+ add: function(el) {
172
+ els.push(el);
173
+ if (els.length === 1) listen(true);
174
+ write();
175
+ },
176
+ remove: function(el) {
177
+ const i = els.indexOf(el);
178
+ if (i >= 0) els.splice(i, 1);
179
+ if (!els.length) {
180
+ listen(false);
181
+ if (frame) cancelAnimationFrame(frame);
182
+ frame = 0;
183
+ }
184
+ write();
185
+ },
186
+ write
187
+ };
188
+ }
120
189
  export {
121
190
  FOCUSABLE,
122
191
  FilterSheet,
123
192
  TAB_STOPS,
193
+ barStack,
124
194
  collator,
125
195
  compare,
126
196
  cx,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jirawatpyk/aura-react",
3
- "version": "5.72.0",
3
+ "version": "5.73.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",