@jirawatpyk/aura-react 5.68.0 → 5.69.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.69 — Chamber-OS addendum 86 (#185)
190
+
191
+ - **ActionBar's edge look:** a `position="viewport"` bar takes `look="edge"` (every width) or `edgeBelow="sm"` / `"md"` (the strip below 640px / 768px, the card at and above it — as PageHeader's `actionsBarBelow`) and draws PageHeader's edge strip: the screen's full width, on the bottom edge or directly on a BottomNav, a top border only (no radius, shadow or top margin), the home-indicator inset as padding inside it. `look="floating"` (default) is the inset card, unchanged; a `container` bar ignores both props.
192
+ - **Its promises hold:** the strip is `position: fixed`, so it stays on screen for the whole page, not only while its form is. As PageHeader's bar, `<html>` gets its measured height as `--aura-actionbar-height` (60px before hydration; the home-indicator padding counts), the page's end is padded by it (AppShell's content, else the `body`) and `scroll-padding-bottom` keeps a focused field clear — so the last field, and anything after the form, scroll clear. The ActionBar root is the strip, so `getBoundingClientRect()` on it measures the strip. On a screen 30rem tall or less it is static, in the flow, as every bar. An idle bulk bar (`selected={0}`) stays folded away and adds no room. Drop your own clearance (a hook adding the bar's height to `scroll-padding-bottom` or page padding) when you adopt `look` / `edgeBelow`, or it is counted twice. Buttons stay 44px on a phone; `start`, `status`, `children`, the region and its label are unchanged.
193
+ - **Mind:** a transform, filter, `will-change` or paint containment on an ancestor places a fixed strip against that ancestor instead of the screen (a dev warning says so), and `look="edge"` at desktop widths spans the screen under a side nav — use `edgeBelow` for a phone-only strip. Passing both `look="edge"` and `edgeBelow` warns in development (`look` wins). Replace a hand-built `position: fixed` pay band with `<ActionBar edgeBelow="sm">`.
194
+
189
195
  ## 5.68 — Chamber-OS addendum 85 (#184)
190
196
 
191
197
  - **A disabled group dims its legend:** `RadioGroup` and `CheckboxGroup` with `disabled` add `is-disabled` to the fieldset, so the legend takes the disabled colour (`fg-secondary`) a disabled `Field`'s label has — a form that disables its fields while submitting no longer shows group legends at full contrast over dimmed controls.
@@ -409,6 +409,14 @@ window.Aura = (() => {
409
409
  return !e.defaultPrevented && e.button === 0 && !e.metaKey && !e.ctrlKey && !e.shiftKey && !e.altKey;
410
410
  }
411
411
  var FilterSheet = React3.createContext(false);
412
+ function fixedTrapped(el) {
413
+ for (let p = el.parentElement; p && p !== document.documentElement; p = p.parentElement) {
414
+ const s = getComputedStyle(p);
415
+ if (s.transform !== "none" || s.filter !== "none" || (s.backdropFilter || "none") !== "none" || s.contentVisibility === "auto" || s.perspective !== "none" || /transform|filter|perspective/.test(s.willChange) || /paint|layout|strict|content/.test(s.contain))
416
+ return true;
417
+ }
418
+ return false;
419
+ }
412
420
 
413
421
  // src/display.tsx
414
422
  var React4 = __toESM(require_react(), 1);
@@ -8113,14 +8121,6 @@ window.Aura = (() => {
8113
8121
  // src/PageHeaderClient.tsx
8114
8122
  var NAME = "--aura-page-actions-height";
8115
8123
  var bars = [];
8116
- function trapped(el) {
8117
- for (let p = el.parentElement; p && p !== document.documentElement; p = p.parentElement) {
8118
- const s = getComputedStyle(p);
8119
- if (s.transform !== "none" || s.filter !== "none" || (s.backdropFilter || "none") !== "none" || s.contentVisibility === "auto" || s.perspective !== "none" || /transform|filter|perspective/.test(s.willChange) || /paint|layout|strict|content/.test(s.contain))
8120
- return true;
8121
- }
8122
- return false;
8123
- }
8124
8124
  var PageHeader3 = React45.forwardRef(function PageHeader4(props, ref) {
8125
8125
  const own = React45.useRef(null);
8126
8126
  const merged = useMergedRef(ref, own);
@@ -8137,7 +8137,7 @@ window.Aura = (() => {
8137
8137
  if (bars[bars.length - 1] !== sync) return;
8138
8138
  if (getComputedStyle(el).position === "fixed") {
8139
8139
  root.style.setProperty(NAME, el.offsetHeight + "px");
8140
- if (!checked && (checked = true, trapped(el)))
8140
+ if (!checked && (checked = true, fixedTrapped(el)))
8141
8141
  devWarnOnce(
8142
8142
  "pageheader-bar-trapped",
8143
8143
  "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."
@@ -8680,6 +8680,17 @@ window.Aura = (() => {
8680
8680
 
8681
8681
  // src/ActionBar.tsx
8682
8682
  var React50 = __toESM(require_react(), 1);
8683
+ var HEIGHT = "--aura-actionbar-height";
8684
+ var edges = [];
8685
+ function writeHeight() {
8686
+ const root = document.documentElement;
8687
+ for (let i = edges.length - 1; i >= 0; i--)
8688
+ if (getComputedStyle(edges[i]).position === "fixed") {
8689
+ root.style.setProperty(HEIGHT, edges[i].offsetHeight + "px");
8690
+ return;
8691
+ }
8692
+ root.style.removeProperty(HEIGHT);
8693
+ }
8683
8694
  var ActionBar = React50.forwardRef(function ActionBar2(props, ref) {
8684
8695
  const t = useStrings();
8685
8696
  const bulk = props.selected != null;
@@ -8690,6 +8701,40 @@ window.Aura = (() => {
8690
8701
  });
8691
8702
  const cameFrom = React50.useRef(null);
8692
8703
  const own = React50.useRef(null);
8704
+ const viewport = (props.position || "viewport") === "viewport";
8705
+ const edge = !viewport ? null : props.look === "edge" ? "all" : props.edgeBelow || null;
8706
+ if (props.look === "edge" && props.edgeBelow && viewport)
8707
+ devWarnOnce(
8708
+ "actionbar-edge-both",
8709
+ 'ActionBar: look="edge" draws the edge strip at every width, so edgeBelow does nothing. Pass edgeBelow alone for a strip on a phone and the floating card above it.'
8710
+ );
8711
+ React50.useEffect(
8712
+ function() {
8713
+ const el = own.current;
8714
+ if (!edge || !el) return;
8715
+ let checked = false;
8716
+ function sync() {
8717
+ writeHeight();
8718
+ if (!checked && getComputedStyle(el).position === "fixed" && (checked = true, fixedTrapped(el)))
8719
+ devWarnOnce(
8720
+ "actionbar-edge-trapped",
8721
+ `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.`
8722
+ );
8723
+ }
8724
+ edges.push(el);
8725
+ const ro = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(sync);
8726
+ if (ro) ro.observe(el, { box: "border-box" });
8727
+ window.addEventListener("resize", sync);
8728
+ sync();
8729
+ return function() {
8730
+ if (ro) ro.disconnect();
8731
+ window.removeEventListener("resize", sync);
8732
+ edges.splice(edges.indexOf(el), 1);
8733
+ writeHeight();
8734
+ };
8735
+ },
8736
+ [edge, idle]
8737
+ );
8693
8738
  function clear() {
8694
8739
  props.onClearSelection();
8695
8740
  setTimeout(function() {
@@ -8716,6 +8761,7 @@ window.Aura = (() => {
8716
8761
  className: cx(
8717
8762
  "aura-actionbar",
8718
8763
  "aura-actionbar--" + (props.position || "viewport"),
8764
+ edge && (edge === "all" ? "aura-actionbar--edge" : "aura-actionbar--edge-below-" + edge),
8719
8765
  idle && "is-idle",
8720
8766
  props.className
8721
8767
  )
@@ -391,6 +391,14 @@ function plainClick(e) {
391
391
  return !e.defaultPrevented && e.button === 0 && !e.metaKey && !e.ctrlKey && !e.shiftKey && !e.altKey;
392
392
  }
393
393
  var FilterSheet = React3.createContext(false);
394
+ function fixedTrapped(el) {
395
+ for (let p = el.parentElement; p && p !== document.documentElement; p = p.parentElement) {
396
+ const s = getComputedStyle(p);
397
+ if (s.transform !== "none" || s.filter !== "none" || (s.backdropFilter || "none") !== "none" || s.contentVisibility === "auto" || s.perspective !== "none" || /transform|filter|perspective/.test(s.willChange) || /paint|layout|strict|content/.test(s.contain))
398
+ return true;
399
+ }
400
+ return false;
401
+ }
394
402
 
395
403
  // src/display.tsx
396
404
  var React4 = __toESM(require("react"), 1);
@@ -8095,14 +8103,6 @@ var PageHeader = React44.forwardRef(function PageHeader2(props, ref) {
8095
8103
  // src/PageHeaderClient.tsx
8096
8104
  var NAME = "--aura-page-actions-height";
8097
8105
  var bars = [];
8098
- function trapped(el) {
8099
- for (let p = el.parentElement; p && p !== document.documentElement; p = p.parentElement) {
8100
- const s = getComputedStyle(p);
8101
- if (s.transform !== "none" || s.filter !== "none" || (s.backdropFilter || "none") !== "none" || s.contentVisibility === "auto" || s.perspective !== "none" || /transform|filter|perspective/.test(s.willChange) || /paint|layout|strict|content/.test(s.contain))
8102
- return true;
8103
- }
8104
- return false;
8105
- }
8106
8106
  var PageHeader3 = React45.forwardRef(function PageHeader4(props, ref) {
8107
8107
  const own = React45.useRef(null);
8108
8108
  const merged = useMergedRef(ref, own);
@@ -8119,7 +8119,7 @@ var PageHeader3 = React45.forwardRef(function PageHeader4(props, ref) {
8119
8119
  if (bars[bars.length - 1] !== sync) return;
8120
8120
  if (getComputedStyle(el).position === "fixed") {
8121
8121
  root.style.setProperty(NAME, el.offsetHeight + "px");
8122
- if (!checked && (checked = true, trapped(el)))
8122
+ if (!checked && (checked = true, fixedTrapped(el)))
8123
8123
  devWarnOnce(
8124
8124
  "pageheader-bar-trapped",
8125
8125
  "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."
@@ -8662,6 +8662,17 @@ var AppShell = React49.forwardRef(function AppShell2(props, ref) {
8662
8662
 
8663
8663
  // src/ActionBar.tsx
8664
8664
  var React50 = __toESM(require("react"), 1);
8665
+ var HEIGHT = "--aura-actionbar-height";
8666
+ var edges = [];
8667
+ function writeHeight() {
8668
+ const root = document.documentElement;
8669
+ for (let i = edges.length - 1; i >= 0; i--)
8670
+ if (getComputedStyle(edges[i]).position === "fixed") {
8671
+ root.style.setProperty(HEIGHT, edges[i].offsetHeight + "px");
8672
+ return;
8673
+ }
8674
+ root.style.removeProperty(HEIGHT);
8675
+ }
8665
8676
  var ActionBar = React50.forwardRef(function ActionBar2(props, ref) {
8666
8677
  const t = useStrings();
8667
8678
  const bulk = props.selected != null;
@@ -8672,6 +8683,40 @@ var ActionBar = React50.forwardRef(function ActionBar2(props, ref) {
8672
8683
  });
8673
8684
  const cameFrom = React50.useRef(null);
8674
8685
  const own = React50.useRef(null);
8686
+ const viewport = (props.position || "viewport") === "viewport";
8687
+ const edge = !viewport ? null : props.look === "edge" ? "all" : props.edgeBelow || null;
8688
+ if (props.look === "edge" && props.edgeBelow && viewport)
8689
+ devWarnOnce(
8690
+ "actionbar-edge-both",
8691
+ 'ActionBar: look="edge" draws the edge strip at every width, so edgeBelow does nothing. Pass edgeBelow alone for a strip on a phone and the floating card above it.'
8692
+ );
8693
+ React50.useEffect(
8694
+ function() {
8695
+ const el = own.current;
8696
+ if (!edge || !el) return;
8697
+ let checked = false;
8698
+ function sync() {
8699
+ writeHeight();
8700
+ if (!checked && getComputedStyle(el).position === "fixed" && (checked = true, fixedTrapped(el)))
8701
+ devWarnOnce(
8702
+ "actionbar-edge-trapped",
8703
+ `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.`
8704
+ );
8705
+ }
8706
+ edges.push(el);
8707
+ const ro = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(sync);
8708
+ if (ro) ro.observe(el, { box: "border-box" });
8709
+ window.addEventListener("resize", sync);
8710
+ sync();
8711
+ return function() {
8712
+ if (ro) ro.disconnect();
8713
+ window.removeEventListener("resize", sync);
8714
+ edges.splice(edges.indexOf(el), 1);
8715
+ writeHeight();
8716
+ };
8717
+ },
8718
+ [edge, idle]
8719
+ );
8675
8720
  function clear() {
8676
8721
  props.onClearSelection();
8677
8722
  setTimeout(function() {
@@ -8698,6 +8743,7 @@ var ActionBar = React50.forwardRef(function ActionBar2(props, ref) {
8698
8743
  className: cx(
8699
8744
  "aura-actionbar",
8700
8745
  "aura-actionbar--" + (props.position || "viewport"),
8746
+ edge && (edge === "all" ? "aura-actionbar--edge" : "aura-actionbar--edge-below-" + edge),
8701
8747
  idle && "is-idle",
8702
8748
  props.className
8703
8749
  )
@@ -1,8 +1,19 @@
1
1
  'use client';
2
2
  import * as React from "react";
3
3
  import { Button } from "./Button.js";
4
- import { cx } from "./internal.js";
4
+ import { 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 (getComputedStyle(edges[i]).position === "fixed") {
12
+ root.style.setProperty(HEIGHT, edges[i].offsetHeight + "px");
13
+ return;
14
+ }
15
+ root.style.removeProperty(HEIGHT);
16
+ }
6
17
  const ActionBar = React.forwardRef(function ActionBar2(props, ref) {
7
18
  const t = useStrings();
8
19
  const bulk = props.selected != null;
@@ -13,6 +24,40 @@ const ActionBar = React.forwardRef(function ActionBar2(props, ref) {
13
24
  });
14
25
  const cameFrom = React.useRef(null);
15
26
  const own = React.useRef(null);
27
+ const viewport = (props.position || "viewport") === "viewport";
28
+ const edge = !viewport ? null : props.look === "edge" ? "all" : props.edgeBelow || null;
29
+ if (props.look === "edge" && props.edgeBelow && viewport)
30
+ devWarnOnce(
31
+ "actionbar-edge-both",
32
+ 'ActionBar: look="edge" draws the edge strip at every width, so edgeBelow does nothing. Pass edgeBelow alone for a strip on a phone and the floating card above it.'
33
+ );
34
+ React.useEffect(
35
+ function() {
36
+ const el = own.current;
37
+ if (!edge || !el) return;
38
+ let checked = false;
39
+ function sync() {
40
+ writeHeight();
41
+ if (!checked && getComputedStyle(el).position === "fixed" && (checked = true, fixedTrapped(el)))
42
+ devWarnOnce(
43
+ "actionbar-edge-trapped",
44
+ `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
+ );
46
+ }
47
+ edges.push(el);
48
+ const ro = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(sync);
49
+ if (ro) ro.observe(el, { box: "border-box" });
50
+ window.addEventListener("resize", sync);
51
+ sync();
52
+ return function() {
53
+ if (ro) ro.disconnect();
54
+ window.removeEventListener("resize", sync);
55
+ edges.splice(edges.indexOf(el), 1);
56
+ writeHeight();
57
+ };
58
+ },
59
+ [edge, idle]
60
+ );
16
61
  function clear() {
17
62
  props.onClearSelection();
18
63
  setTimeout(function() {
@@ -39,6 +84,7 @@ const ActionBar = React.forwardRef(function ActionBar2(props, ref) {
39
84
  className: cx(
40
85
  "aura-actionbar",
41
86
  "aura-actionbar--" + (props.position || "viewport"),
87
+ edge && (edge === "all" ? "aura-actionbar--edge" : "aura-actionbar--edge-below-" + edge),
42
88
  idle && "is-idle",
43
89
  props.className
44
90
  )
@@ -1,17 +1,9 @@
1
1
  'use client';
2
2
  import * as React from "react";
3
3
  import { PageHeader as StaticPageHeader } from "./PageHeader.js";
4
- import { devWarnOnce, useMergedRef } from "./internal.js";
4
+ import { devWarnOnce, fixedTrapped as trapped, useMergedRef } from "./internal.js";
5
5
  const NAME = "--aura-page-actions-height";
6
6
  const bars = [];
7
- function trapped(el) {
8
- for (let p = el.parentElement; p && p !== document.documentElement; p = p.parentElement) {
9
- const s = getComputedStyle(p);
10
- if (s.transform !== "none" || s.filter !== "none" || (s.backdropFilter || "none") !== "none" || s.contentVisibility === "auto" || s.perspective !== "none" || /transform|filter|perspective/.test(s.willChange) || /paint|layout|strict|content/.test(s.contain))
11
- return true;
12
- }
13
- return false;
14
- }
15
7
  const PageHeader = React.forwardRef(function PageHeader2(props, ref) {
16
8
  const own = React.useRef(null);
17
9
  const merged = useMergedRef(ref, own);
@@ -109,6 +109,14 @@ function plainClick(e) {
109
109
  return !e.defaultPrevented && e.button === 0 && !e.metaKey && !e.ctrlKey && !e.shiftKey && !e.altKey;
110
110
  }
111
111
  const FilterSheet = React.createContext(false);
112
+ function fixedTrapped(el) {
113
+ for (let p = el.parentElement; p && p !== document.documentElement; p = p.parentElement) {
114
+ const s = getComputedStyle(p);
115
+ if (s.transform !== "none" || s.filter !== "none" || (s.backdropFilter || "none") !== "none" || s.contentVisibility === "auto" || s.perspective !== "none" || /transform|filter|perspective/.test(s.willChange) || /paint|layout|strict|content/.test(s.contain))
116
+ return true;
117
+ }
118
+ return false;
119
+ }
112
120
  export {
113
121
  FOCUSABLE,
114
122
  FilterSheet,
@@ -117,6 +125,7 @@ export {
117
125
  compare,
118
126
  cx,
119
127
  devWarnOnce,
128
+ fixedTrapped,
120
129
  focusFirst,
121
130
  inClosedDetails,
122
131
  isTabStop,
package/dist/index.d.cts CHANGED
@@ -1514,6 +1514,16 @@ export interface ActionBarProps {
1514
1514
  * parent, so they never cover the last field. Make it the last child of the form or card it belongs to: like any
1515
1515
  * `position: sticky` element it sticks only while that parent is on screen. */
1516
1516
  position?: "viewport" | "container" | undefined;
1517
+ /** 5.69 (Chamber-OS 185), `position="viewport"` only. `floating` (default): the inset card, bordered all round,
1518
+ * rounded, with a shadow. `edge`: PageHeader's edge strip at every width — the screen's full width, on the bottom
1519
+ * edge or on a BottomNav, a top border only, the home-indicator inset inside it. The strip is `position: fixed` and
1520
+ * stays on screen for the whole page (not only while its form is), so, as PageHeader's bar, the page gains its height
1521
+ * at the end (`--aura-actionbar-height` on `<html>`) and a focused field scrolls clear; on a screen 30rem tall or
1522
+ * less it is static, in the flow. For a strip on a phone only, use `edgeBelow`. */
1523
+ look?: "floating" | "edge" | undefined;
1524
+ /** 5.69 (Chamber-OS 185), `position="viewport"` only: the edge strip below this width (`sm` 640px, `md` 768px),
1525
+ * the `look` card at and above it — as PageHeader's `actionsBarBelow`. */
1526
+ edgeBelow?: "sm" | "md" | undefined;
1517
1527
  /** 5.35 (DxT Monitor #14): while this bar is on the page, a BottomNav (and its spacer) is hidden and the bar takes the
1518
1528
  * bottom edge — for a page whose own actions (Acknowledge, Visit site) replace the tab bar. Any element can do the
1519
1529
  * same with the `data-aura-hide-bottomnav` attribute. */
@@ -2296,8 +2306,6 @@ export declare const STRINGS: {
2296
2306
  export declare const TileGrid: React$1.ForwardRefExoticComponent<TileGridProps & React$1.RefAttributes<HTMLUListElement>>;
2297
2307
  export declare const Sparkline: React$1.ForwardRefExoticComponent<SparklineProps & React$1.RefAttributes<SVGSVGElement>>;
2298
2308
  export declare const AppShell: React$1.ForwardRefExoticComponent<AppShellProps & React$1.RefAttributes<HTMLDivElement>>;
2299
- /** ActionBar — a bar stuck to the bottom of the screen or of a card: a status line and the form's or selection's
2300
- * actions. It is `position: sticky`, so it stays in the flow at the end of its parent and never covers the last field. */
2301
2309
  export declare const ActionBar: React$1.ForwardRefExoticComponent<ActionBarProps & React$1.RefAttributes<HTMLDivElement>>;
2302
2310
  /** Separator — a 1px `aura-border-default` rule between groups of content (4.20). Decorative by default (hidden from
2303
2311
  * screen readers); `decorative={false}` makes it a `role="separator"` that is announced. */
package/dist/index.d.ts CHANGED
@@ -1514,6 +1514,16 @@ export interface ActionBarProps {
1514
1514
  * parent, so they never cover the last field. Make it the last child of the form or card it belongs to: like any
1515
1515
  * `position: sticky` element it sticks only while that parent is on screen. */
1516
1516
  position?: "viewport" | "container" | undefined;
1517
+ /** 5.69 (Chamber-OS 185), `position="viewport"` only. `floating` (default): the inset card, bordered all round,
1518
+ * rounded, with a shadow. `edge`: PageHeader's edge strip at every width — the screen's full width, on the bottom
1519
+ * edge or on a BottomNav, a top border only, the home-indicator inset inside it. The strip is `position: fixed` and
1520
+ * stays on screen for the whole page (not only while its form is), so, as PageHeader's bar, the page gains its height
1521
+ * at the end (`--aura-actionbar-height` on `<html>`) and a focused field scrolls clear; on a screen 30rem tall or
1522
+ * less it is static, in the flow. For a strip on a phone only, use `edgeBelow`. */
1523
+ look?: "floating" | "edge" | undefined;
1524
+ /** 5.69 (Chamber-OS 185), `position="viewport"` only: the edge strip below this width (`sm` 640px, `md` 768px),
1525
+ * the `look` card at and above it — as PageHeader's `actionsBarBelow`. */
1526
+ edgeBelow?: "sm" | "md" | undefined;
1517
1527
  /** 5.35 (DxT Monitor #14): while this bar is on the page, a BottomNav (and its spacer) is hidden and the bar takes the
1518
1528
  * bottom edge — for a page whose own actions (Acknowledge, Visit site) replace the tab bar. Any element can do the
1519
1529
  * same with the `data-aura-hide-bottomnav` attribute. */
@@ -2296,8 +2306,6 @@ export declare const STRINGS: {
2296
2306
  export declare const TileGrid: React$1.ForwardRefExoticComponent<TileGridProps & React$1.RefAttributes<HTMLUListElement>>;
2297
2307
  export declare const Sparkline: React$1.ForwardRefExoticComponent<SparklineProps & React$1.RefAttributes<SVGSVGElement>>;
2298
2308
  export declare const AppShell: React$1.ForwardRefExoticComponent<AppShellProps & React$1.RefAttributes<HTMLDivElement>>;
2299
- /** ActionBar — a bar stuck to the bottom of the screen or of a card: a status line and the form's or selection's
2300
- * actions. It is `position: sticky`, so it stays in the flow at the end of its parent and never covers the last field. */
2301
2309
  export declare const ActionBar: React$1.ForwardRefExoticComponent<ActionBarProps & React$1.RefAttributes<HTMLDivElement>>;
2302
2310
  /** Separator — a 1px `aura-border-default` rule between groups of content (4.20). Decorative by default (hidden from
2303
2311
  * screen readers); `decorative={false}` makes it a `role="separator"` that is announced. */
package/dist/styles.css CHANGED
@@ -2270,6 +2270,32 @@ button.aura-stepper__step:hover .aura-stepper__label { text-decoration: underlin
2270
2270
  .aura-actionbar__start:empty { display: none; }
2271
2271
  @container aura-actionbar (min-width: 640px) { .aura-actionbar__start { order: -1; } }
2272
2272
  @container aura-actionbar (max-width: 639.98px) { .aura-actionbar__inner.has-start > .aura-actionbar__status:not(:empty) { flex-basis: 100%; } }
2273
+ /* 5.69 (Chamber-OS 185): look="edge" / edgeBelow — PageHeader's edge strip (5.48): the screen's full width, on the
2274
+ * bottom edge or on a BottomNav, a top border only, the home-indicator inset inside it. Fixed, so it spans the screen
2275
+ * and not its parent; as PageHeader's bar, the page gains its height at the end (the shell's content, else the body)
2276
+ * and as scroll-padding — --aura-actionbar-height, measured on the client, 60px until then — so the page's end and a
2277
+ * focused field scroll clear of it. On a screen 30rem tall or less it is static, in the flow, as every bar (5.48/5.49). */
2278
+ .aura-actionbar--edge:not(.is-idle) { border: 0; border-top: 1px solid var(--aura-border-default); border-radius: 0; box-shadow: none; }
2279
+ @media (min-height: 30.00125rem) {
2280
+ .aura-actionbar--edge:not(.is-idle) { position: fixed; left: 0; right: 0; width: auto; bottom: var(--aura-bottomnav-offset, 0px); margin: 0; padding-bottom: max(0px, env(safe-area-inset-bottom, 0px) - var(--aura-bottomnav-offset, 0px)); }
2281
+ :root:has(.aura-actionbar--edge:not(.is-idle)) { --aura-actionbar-space: calc(var(--aura-actionbar-height, 60px) + var(--aura-bottomnav-offset, 0px) + var(--aura-space-3)); scroll-padding-bottom: var(--aura-actionbar-space); }
2282
+ :root:has(.aura-actionbar--edge:not(.is-idle)) .aura-shell__content { padding-bottom: calc(var(--aura-space-6) + var(--aura-actionbar-space)); }
2283
+ :root:has(.aura-actionbar--edge:not(.is-idle)):not(:has(.aura-shell__content)) body { padding-bottom: var(--aura-actionbar-space); }
2284
+ }
2285
+ @media (max-width: 639.98px) { .aura-actionbar--edge-below-sm:not(.is-idle) { border: 0; border-top: 1px solid var(--aura-border-default); border-radius: 0; box-shadow: none; } }
2286
+ @media (max-width: 639.98px) and (min-height: 30.00125rem) {
2287
+ .aura-actionbar--edge-below-sm:not(.is-idle) { position: fixed; left: 0; right: 0; width: auto; bottom: var(--aura-bottomnav-offset, 0px); margin: 0; padding-bottom: max(0px, env(safe-area-inset-bottom, 0px) - var(--aura-bottomnav-offset, 0px)); }
2288
+ :root:has(.aura-actionbar--edge-below-sm:not(.is-idle)) { --aura-actionbar-space: calc(var(--aura-actionbar-height, 60px) + var(--aura-bottomnav-offset, 0px) + var(--aura-space-3)); scroll-padding-bottom: var(--aura-actionbar-space); }
2289
+ :root:has(.aura-actionbar--edge-below-sm:not(.is-idle)) .aura-shell__content { padding-bottom: calc(var(--aura-space-6) + var(--aura-actionbar-space)); }
2290
+ :root:has(.aura-actionbar--edge-below-sm:not(.is-idle)):not(:has(.aura-shell__content)) body { padding-bottom: var(--aura-actionbar-space); }
2291
+ }
2292
+ @media (max-width: 767.98px) { .aura-actionbar--edge-below-md:not(.is-idle) { border: 0; border-top: 1px solid var(--aura-border-default); border-radius: 0; box-shadow: none; } }
2293
+ @media (max-width: 767.98px) and (min-height: 30.00125rem) {
2294
+ .aura-actionbar--edge-below-md:not(.is-idle) { position: fixed; left: 0; right: 0; width: auto; bottom: var(--aura-bottomnav-offset, 0px); margin: 0; padding-bottom: max(0px, env(safe-area-inset-bottom, 0px) - var(--aura-bottomnav-offset, 0px)); }
2295
+ :root:has(.aura-actionbar--edge-below-md:not(.is-idle)) { --aura-actionbar-space: calc(var(--aura-actionbar-height, 60px) + var(--aura-bottomnav-offset, 0px) + var(--aura-space-3)); scroll-padding-bottom: var(--aura-actionbar-space); }
2296
+ :root:has(.aura-actionbar--edge-below-md:not(.is-idle)) .aura-shell__content { padding-bottom: calc(var(--aura-space-6) + var(--aura-actionbar-space)); }
2297
+ :root:has(.aura-actionbar--edge-below-md:not(.is-idle)):not(:has(.aura-shell__content)) body { padding-bottom: var(--aura-actionbar-space); }
2298
+ }
2273
2299
 
2274
2300
  /* ---------- 4.20: Separator ---------- */
2275
2301
  .aura-separator { flex: none; align-self: stretch; height: 1px; margin: var(--aura-separator-space, 0) 0; background: var(--aura-border-default); border: 0; }
@@ -2272,6 +2272,32 @@ button.aura-stepper__step:hover .aura-stepper__label { text-decoration: underlin
2272
2272
  .aura-actionbar__start:empty { display: none; }
2273
2273
  @container aura-actionbar (min-width: 640px) { .aura-actionbar__start { order: -1; } }
2274
2274
  @container aura-actionbar (max-width: 639.98px) { .aura-actionbar__inner.has-start > .aura-actionbar__status:not(:empty) { flex-basis: 100%; } }
2275
+ /* 5.69 (Chamber-OS 185): look="edge" / edgeBelow — PageHeader's edge strip (5.48): the screen's full width, on the
2276
+ * bottom edge or on a BottomNav, a top border only, the home-indicator inset inside it. Fixed, so it spans the screen
2277
+ * and not its parent; as PageHeader's bar, the page gains its height at the end (the shell's content, else the body)
2278
+ * and as scroll-padding — --aura-actionbar-height, measured on the client, 60px until then — so the page's end and a
2279
+ * focused field scroll clear of it. On a screen 30rem tall or less it is static, in the flow, as every bar (5.48/5.49). */
2280
+ .aura-actionbar--edge:not(.is-idle) { border: 0; border-top: 1px solid var(--aura-border-default); border-radius: 0; box-shadow: none; }
2281
+ @media (min-height: 30.00125rem) {
2282
+ .aura-actionbar--edge:not(.is-idle) { position: fixed; left: 0; right: 0; width: auto; bottom: var(--aura-bottomnav-offset, 0px); margin: 0; padding-bottom: max(0px, env(safe-area-inset-bottom, 0px) - var(--aura-bottomnav-offset, 0px)); }
2283
+ :root:has(.aura-actionbar--edge:not(.is-idle)) { --aura-actionbar-space: calc(var(--aura-actionbar-height, 60px) + var(--aura-bottomnav-offset, 0px) + var(--aura-space-3)); scroll-padding-bottom: var(--aura-actionbar-space); }
2284
+ :root:has(.aura-actionbar--edge:not(.is-idle)) .aura-shell__content { padding-bottom: calc(var(--aura-space-6) + var(--aura-actionbar-space)); }
2285
+ :root:has(.aura-actionbar--edge:not(.is-idle)):not(:has(.aura-shell__content)) body { padding-bottom: var(--aura-actionbar-space); }
2286
+ }
2287
+ @media (max-width: 639.98px) { .aura-actionbar--edge-below-sm:not(.is-idle) { border: 0; border-top: 1px solid var(--aura-border-default); border-radius: 0; box-shadow: none; } }
2288
+ @media (max-width: 639.98px) and (min-height: 30.00125rem) {
2289
+ .aura-actionbar--edge-below-sm:not(.is-idle) { position: fixed; left: 0; right: 0; width: auto; bottom: var(--aura-bottomnav-offset, 0px); margin: 0; padding-bottom: max(0px, env(safe-area-inset-bottom, 0px) - var(--aura-bottomnav-offset, 0px)); }
2290
+ :root:has(.aura-actionbar--edge-below-sm:not(.is-idle)) { --aura-actionbar-space: calc(var(--aura-actionbar-height, 60px) + var(--aura-bottomnav-offset, 0px) + var(--aura-space-3)); scroll-padding-bottom: var(--aura-actionbar-space); }
2291
+ :root:has(.aura-actionbar--edge-below-sm:not(.is-idle)) .aura-shell__content { padding-bottom: calc(var(--aura-space-6) + var(--aura-actionbar-space)); }
2292
+ :root:has(.aura-actionbar--edge-below-sm:not(.is-idle)):not(:has(.aura-shell__content)) body { padding-bottom: var(--aura-actionbar-space); }
2293
+ }
2294
+ @media (max-width: 767.98px) { .aura-actionbar--edge-below-md:not(.is-idle) { border: 0; border-top: 1px solid var(--aura-border-default); border-radius: 0; box-shadow: none; } }
2295
+ @media (max-width: 767.98px) and (min-height: 30.00125rem) {
2296
+ .aura-actionbar--edge-below-md:not(.is-idle) { position: fixed; left: 0; right: 0; width: auto; bottom: var(--aura-bottomnav-offset, 0px); margin: 0; padding-bottom: max(0px, env(safe-area-inset-bottom, 0px) - var(--aura-bottomnav-offset, 0px)); }
2297
+ :root:has(.aura-actionbar--edge-below-md:not(.is-idle)) { --aura-actionbar-space: calc(var(--aura-actionbar-height, 60px) + var(--aura-bottomnav-offset, 0px) + var(--aura-space-3)); scroll-padding-bottom: var(--aura-actionbar-space); }
2298
+ :root:has(.aura-actionbar--edge-below-md:not(.is-idle)) .aura-shell__content { padding-bottom: calc(var(--aura-space-6) + var(--aura-actionbar-space)); }
2299
+ :root:has(.aura-actionbar--edge-below-md:not(.is-idle)):not(:has(.aura-shell__content)) body { padding-bottom: var(--aura-actionbar-space); }
2300
+ }
2275
2301
 
2276
2302
  /* ---------- 4.20: Separator ---------- */
2277
2303
  .aura-separator { flex: none; align-self: stretch; height: 1px; margin: var(--aura-separator-space, 0) 0; background: var(--aura-border-default); border: 0; }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jirawatpyk/aura-react",
3
- "version": "5.68.0",
3
+ "version": "5.69.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",