@jirawatpyk/aura-react 5.80.0 → 5.81.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
@@ -248,6 +248,10 @@ DataTable with sort and page in the URL (4.17): `onStateChange={({ sort, page })
248
248
  - **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`.
249
249
  - **Toasts** queue past three instead of dropping: six in a row all show, in order, three at a time.
250
250
 
251
+ ## 5.81 — DxT Monitor 24 (the tab bar hides after a tap)
252
+
253
+ - **BottomNav `hideOnScroll` and AppShell `headerHideOnScroll` after a tap**: with client-side navigation the bar stays mounted, and on Chrome / Android a tap leaves focus on the tapped tab — the bar then never hid on the next page. Focus in the bar now holds it only when it came from the keyboard: focus that enters right after a pointer press doesn't count, and focus moved with the keyboard does (Tab into or within the bar brings it back and keeps it; keys that only scroll the page, such as Space or PageDown, don't). A text field in the bar holds it however it was focused. No new prop; drop any wrapper that blurs the tab on click.
254
+
251
255
  ## 5.79 — visual audit, set 3 (component by component)
252
256
 
253
257
  - **One disabled look for every Button variant:** a faint fill (`--aura-button-disabled-bg`: zinc-100 light, none in dark), a faint edge (`--aura-button-disabled-border` — the variant's own border, or 1px inside for primary and danger) and the tertiary label, at full opacity — primary, secondary, danger, creative and `aria-disabled` alike; a ghost button has neither fill nor edge. (5.30 gave filled buttons a grey fill that read as a To Do pill and faded outline ones.)
@@ -560,7 +564,7 @@ What Chamber-OS's own page header did that PageHeader didn't, so it can be rebui
560
564
 
561
565
  - **Breadcrumb touch targets** (request 11): on a touch screen (`pointer: coarse`) every crumb link or button (and "…") gets a hit area 44px tall and as wide as its text plus 24px; the text doesn't move. It reaches 12px into the gutter on each side, so short neighbours never share a spot, and only 4px below the text, so it stops short of a PageHeader title right underneath — the rest of the height is above, so keep about 20px clear above a breadcrumb (AppShell's content padding already is). When the crumbs wrap, the rows sit 24px apart on touch screens so one row never covers the next. The current page (not a link) gets none; a link component must render its `<a>` directly in the crumb's `li`. Apps that added their own `.aura-crumbs a::after` rule should drop it.
562
566
  - **StatusTile `status="unknown"`** (request 12): for a thing with no data yet (a site before its first check) — a dashed circle (circle-dot-dashed) in `aura-fg-tertiary` on the plain surface and border, status word "No data" (th: ยังไม่มีข้อมูล, sv: Ingen data), value in the text colour. An unrecognised `status` now shows as unknown rather than OK, with a dev warning.
563
- - **AppShell `headerHideOnScroll`** (request 13): below 1024px the top bar slides up out of view while the page scrolls down (after it has moved past the bar's height and kept going 8px) and comes back after 8px up, near the top, and whenever focus enters it. `--aura-shell-bar-height` is 0 while it is away, so a sticky table header pinned under the bar moves up with it. No slide with reduced motion. The page must scroll the window (AppShell's does).
567
+ - **AppShell `headerHideOnScroll`** (request 13): below 1024px the top bar slides up out of view while the page scrolls down (after it has moved past the bar's height and kept going 8px) and comes back after 8px up, near the top, and whenever focus enters it (5.81: a tap's focus doesn't keep it there; keyboard focus does). `--aura-shell-bar-height` is 0 while it is away, so a sticky table header pinned under the bar moves up with it. No slide with reduced motion. The page must scroll the window (AppShell's does).
564
568
  - **BottomNav `hideOnScroll`** (request 14): the same for the tab bar, sliding down. Its spacer stays (nothing shifts) and `--aura-bottomnav-offset` drops while it is away, so viewport ActionBars and toasts follow it down. **ActionBar `hidesBottomNav`**: while that bar is on the page the BottomNav and its spacer are gone and the bar sits on the bottom edge — for a page whose own actions (Acknowledge, Visit site) replace the tabs. Any element can do the same with `data-aura-hide-bottomnav`.
565
569
 
566
570
  ## 5.34 — StatusTile, TileGrid, Sparkline (DxT Monitor Overview S06)
@@ -8751,8 +8751,10 @@ window.Aura = (() => {
8751
8751
  // src/scrollHide.ts
8752
8752
  var React48 = __toESM(require_react(), 1);
8753
8753
  var STEP = 8;
8754
+ var TEXT_ENTRY = 'textarea, select, [contenteditable=""], [contenteditable="true"], [contenteditable="plaintext-only"], input:not([type]), input[type="text"], input[type="search"], input[type="email"], input[type="url"], input[type="tel"], input[type="number"], input[type="password"]';
8754
8755
  function useHideOnScroll(enabled, el, media, from) {
8755
8756
  const st = React48.useState(false), hidden = st[0], setHidden = st[1];
8757
+ const tap = React48.useRef({ pressedAt: -1e9, focus: false });
8756
8758
  React48.useEffect(
8757
8759
  function() {
8758
8760
  if (!enabled || typeof window === "undefined") {
@@ -8762,6 +8764,11 @@ window.Aura = (() => {
8762
8764
  const mq = window.matchMedia ? window.matchMedia(media) : null;
8763
8765
  let last = window.scrollY, lastH = window.innerHeight, resizedAt = -1e9, run = 0;
8764
8766
  let restore = null;
8767
+ function holdsBar(node2) {
8768
+ const a = document.activeElement;
8769
+ if (!node2 || !a || !node2.contains(a)) return false;
8770
+ return !tap.current.focus || a.matches(TEXT_ENTRY);
8771
+ }
8765
8772
  function update() {
8766
8773
  if (restore) {
8767
8774
  const r2 = restore;
@@ -8776,7 +8783,7 @@ window.Aura = (() => {
8776
8783
  const y = window.scrollY, dy = y - last;
8777
8784
  last = y;
8778
8785
  const node2 = el.current;
8779
- if (mq && !mq.matches || y <= from || node2 && document.activeElement && node2.contains(document.activeElement)) {
8786
+ if (mq && !mq.matches || y <= from || holdsBar(node2)) {
8780
8787
  run = 0;
8781
8788
  setHidden(false);
8782
8789
  return;
@@ -8796,7 +8803,12 @@ window.Aura = (() => {
8796
8803
  function disarm() {
8797
8804
  restore = null;
8798
8805
  }
8806
+ function onPress(e) {
8807
+ restore = null;
8808
+ tap.current.pressedAt = e.timeStamp;
8809
+ }
8799
8810
  function onKey(e) {
8811
+ tap.current.pressedAt = -1e9;
8800
8812
  if (e.key !== "Tab" && e.code !== "Tab") {
8801
8813
  if (e.key !== "Shift") restore = null;
8802
8814
  return;
@@ -8806,7 +8818,8 @@ window.Aura = (() => {
8806
8818
  tabbing = false;
8807
8819
  });
8808
8820
  }
8809
- function reveal() {
8821
+ function reveal(e) {
8822
+ tap.current.focus = e.timeStamp - tap.current.pressedAt < 1e3;
8810
8823
  const n3 = el.current;
8811
8824
  if (n3 && n3.classList.contains("is-away")) {
8812
8825
  n3.classList.remove("is-away");
@@ -8822,7 +8835,7 @@ window.Aura = (() => {
8822
8835
  document.addEventListener("keydown", onKey, true);
8823
8836
  window.addEventListener("wheel", disarm, { passive: true, capture: true });
8824
8837
  window.addEventListener("touchstart", disarm, { passive: true, capture: true });
8825
- window.addEventListener("pointerdown", disarm, true);
8838
+ window.addEventListener("pointerdown", onPress, true);
8826
8839
  const node = el.current;
8827
8840
  if (node) node.addEventListener("focusin", reveal);
8828
8841
  if (mq && mq.addEventListener) mq.addEventListener("change", update);
@@ -8832,7 +8845,7 @@ window.Aura = (() => {
8832
8845
  document.removeEventListener("keydown", onKey, true);
8833
8846
  window.removeEventListener("wheel", disarm, true);
8834
8847
  window.removeEventListener("touchstart", disarm, true);
8835
- window.removeEventListener("pointerdown", disarm, true);
8848
+ window.removeEventListener("pointerdown", onPress, true);
8836
8849
  if (node) node.removeEventListener("focusin", reveal);
8837
8850
  if (mq && mq.removeEventListener) mq.removeEventListener("change", update);
8838
8851
  };
@@ -8733,8 +8733,10 @@ var React49 = __toESM(require("react"), 1);
8733
8733
  // src/scrollHide.ts
8734
8734
  var React48 = __toESM(require("react"), 1);
8735
8735
  var STEP = 8;
8736
+ var TEXT_ENTRY = 'textarea, select, [contenteditable=""], [contenteditable="true"], [contenteditable="plaintext-only"], input:not([type]), input[type="text"], input[type="search"], input[type="email"], input[type="url"], input[type="tel"], input[type="number"], input[type="password"]';
8736
8737
  function useHideOnScroll(enabled, el, media, from) {
8737
8738
  const st = React48.useState(false), hidden = st[0], setHidden = st[1];
8739
+ const tap = React48.useRef({ pressedAt: -1e9, focus: false });
8738
8740
  React48.useEffect(
8739
8741
  function() {
8740
8742
  if (!enabled || typeof window === "undefined") {
@@ -8744,6 +8746,11 @@ function useHideOnScroll(enabled, el, media, from) {
8744
8746
  const mq = window.matchMedia ? window.matchMedia(media) : null;
8745
8747
  let last = window.scrollY, lastH = window.innerHeight, resizedAt = -1e9, run = 0;
8746
8748
  let restore = null;
8749
+ function holdsBar(node2) {
8750
+ const a = document.activeElement;
8751
+ if (!node2 || !a || !node2.contains(a)) return false;
8752
+ return !tap.current.focus || a.matches(TEXT_ENTRY);
8753
+ }
8747
8754
  function update() {
8748
8755
  if (restore) {
8749
8756
  const r2 = restore;
@@ -8758,7 +8765,7 @@ function useHideOnScroll(enabled, el, media, from) {
8758
8765
  const y = window.scrollY, dy = y - last;
8759
8766
  last = y;
8760
8767
  const node2 = el.current;
8761
- if (mq && !mq.matches || y <= from || node2 && document.activeElement && node2.contains(document.activeElement)) {
8768
+ if (mq && !mq.matches || y <= from || holdsBar(node2)) {
8762
8769
  run = 0;
8763
8770
  setHidden(false);
8764
8771
  return;
@@ -8778,7 +8785,12 @@ function useHideOnScroll(enabled, el, media, from) {
8778
8785
  function disarm() {
8779
8786
  restore = null;
8780
8787
  }
8788
+ function onPress(e) {
8789
+ restore = null;
8790
+ tap.current.pressedAt = e.timeStamp;
8791
+ }
8781
8792
  function onKey(e) {
8793
+ tap.current.pressedAt = -1e9;
8782
8794
  if (e.key !== "Tab" && e.code !== "Tab") {
8783
8795
  if (e.key !== "Shift") restore = null;
8784
8796
  return;
@@ -8788,7 +8800,8 @@ function useHideOnScroll(enabled, el, media, from) {
8788
8800
  tabbing = false;
8789
8801
  });
8790
8802
  }
8791
- function reveal() {
8803
+ function reveal(e) {
8804
+ tap.current.focus = e.timeStamp - tap.current.pressedAt < 1e3;
8792
8805
  const n3 = el.current;
8793
8806
  if (n3 && n3.classList.contains("is-away")) {
8794
8807
  n3.classList.remove("is-away");
@@ -8804,7 +8817,7 @@ function useHideOnScroll(enabled, el, media, from) {
8804
8817
  document.addEventListener("keydown", onKey, true);
8805
8818
  window.addEventListener("wheel", disarm, { passive: true, capture: true });
8806
8819
  window.addEventListener("touchstart", disarm, { passive: true, capture: true });
8807
- window.addEventListener("pointerdown", disarm, true);
8820
+ window.addEventListener("pointerdown", onPress, true);
8808
8821
  const node = el.current;
8809
8822
  if (node) node.addEventListener("focusin", reveal);
8810
8823
  if (mq && mq.addEventListener) mq.addEventListener("change", update);
@@ -8814,7 +8827,7 @@ function useHideOnScroll(enabled, el, media, from) {
8814
8827
  document.removeEventListener("keydown", onKey, true);
8815
8828
  window.removeEventListener("wheel", disarm, true);
8816
8829
  window.removeEventListener("touchstart", disarm, true);
8817
- window.removeEventListener("pointerdown", disarm, true);
8830
+ window.removeEventListener("pointerdown", onPress, true);
8818
8831
  if (node) node.removeEventListener("focusin", reveal);
8819
8832
  if (mq && mq.removeEventListener) mq.removeEventListener("change", update);
8820
8833
  };
@@ -1,8 +1,10 @@
1
1
  'use client';
2
2
  import * as React from "react";
3
3
  const STEP = 8;
4
+ const TEXT_ENTRY = 'textarea, select, [contenteditable=""], [contenteditable="true"], [contenteditable="plaintext-only"], input:not([type]), input[type="text"], input[type="search"], input[type="email"], input[type="url"], input[type="tel"], input[type="number"], input[type="password"]';
4
5
  function useHideOnScroll(enabled, el, media, from) {
5
6
  const st = React.useState(false), hidden = st[0], setHidden = st[1];
7
+ const tap = React.useRef({ pressedAt: -1e9, focus: false });
6
8
  React.useEffect(
7
9
  function() {
8
10
  if (!enabled || typeof window === "undefined") {
@@ -12,6 +14,11 @@ function useHideOnScroll(enabled, el, media, from) {
12
14
  const mq = window.matchMedia ? window.matchMedia(media) : null;
13
15
  let last = window.scrollY, lastH = window.innerHeight, resizedAt = -1e9, run = 0;
14
16
  let restore = null;
17
+ function holdsBar(node2) {
18
+ const a = document.activeElement;
19
+ if (!node2 || !a || !node2.contains(a)) return false;
20
+ return !tap.current.focus || a.matches(TEXT_ENTRY);
21
+ }
15
22
  function update() {
16
23
  if (restore) {
17
24
  const r = restore;
@@ -26,7 +33,7 @@ function useHideOnScroll(enabled, el, media, from) {
26
33
  const y = window.scrollY, dy = y - last;
27
34
  last = y;
28
35
  const node2 = el.current;
29
- if (mq && !mq.matches || y <= from || node2 && document.activeElement && node2.contains(document.activeElement)) {
36
+ if (mq && !mq.matches || y <= from || holdsBar(node2)) {
30
37
  run = 0;
31
38
  setHidden(false);
32
39
  return;
@@ -46,7 +53,12 @@ function useHideOnScroll(enabled, el, media, from) {
46
53
  function disarm() {
47
54
  restore = null;
48
55
  }
56
+ function onPress(e) {
57
+ restore = null;
58
+ tap.current.pressedAt = e.timeStamp;
59
+ }
49
60
  function onKey(e) {
61
+ tap.current.pressedAt = -1e9;
50
62
  if (e.key !== "Tab" && e.code !== "Tab") {
51
63
  if (e.key !== "Shift") restore = null;
52
64
  return;
@@ -56,7 +68,8 @@ function useHideOnScroll(enabled, el, media, from) {
56
68
  tabbing = false;
57
69
  });
58
70
  }
59
- function reveal() {
71
+ function reveal(e) {
72
+ tap.current.focus = e.timeStamp - tap.current.pressedAt < 1e3;
60
73
  const n = el.current;
61
74
  if (n && n.classList.contains("is-away")) {
62
75
  n.classList.remove("is-away");
@@ -72,7 +85,7 @@ function useHideOnScroll(enabled, el, media, from) {
72
85
  document.addEventListener("keydown", onKey, true);
73
86
  window.addEventListener("wheel", disarm, { passive: true, capture: true });
74
87
  window.addEventListener("touchstart", disarm, { passive: true, capture: true });
75
- window.addEventListener("pointerdown", disarm, true);
88
+ window.addEventListener("pointerdown", onPress, true);
76
89
  const node = el.current;
77
90
  if (node) node.addEventListener("focusin", reveal);
78
91
  if (mq && mq.addEventListener) mq.addEventListener("change", update);
@@ -82,7 +95,7 @@ function useHideOnScroll(enabled, el, media, from) {
82
95
  document.removeEventListener("keydown", onKey, true);
83
96
  window.removeEventListener("wheel", disarm, true);
84
97
  window.removeEventListener("touchstart", disarm, true);
85
- window.removeEventListener("pointerdown", disarm, true);
98
+ window.removeEventListener("pointerdown", onPress, true);
86
99
  if (node) node.removeEventListener("focusin", reveal);
87
100
  if (mq && mq.removeEventListener) mq.removeEventListener("change", update);
88
101
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jirawatpyk/aura-react",
3
- "version": "5.80.0",
3
+ "version": "5.81.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",