@jirawatpyk/aura-react 5.73.0 → 5.75.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,20 @@ 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.75 — visual audit, set 1
190
+
191
+ - **Status pills are soft in every tone.** Blocked is red-800 on red-100 (dark red-300 on a red wash), Warning amber-800 on amber-100 (dark amber-300 on an amber wash), like Ready, In Progress and To Do, and like Alert and Badge — so a table of statuses reads evenly; the word and the icon carry the meaning. For the one status on a screen that must catch the eye (an overdue total, a failed payment) pass `variant="solid"`: the strong fill, in every tone (`--aura-status-{tone}-solid-bg` / `-fg`; Blocked and Warning are the 5.30 fills). Badge `tone="danger" variant="solid"` is unchanged.
192
+ - **Status words:** Down, Offline and Outage read as blocked; Active, Up, Online and Resolved as ready (`statusTone`, StatusPill, DataTable status columns — which also moves them in a DataTable sort by status). Pass `tone` to keep an earlier look.
193
+ - **List options:** in Select, Combobox and TimePicker, the option under the pointer is shaded only, as a Menu item; moving by keys (or opening with them) shows the focus ring on the active option.
194
+ - **Plain links** (`<a>` with no class) in a PageHeader, a Popover, a Drawer, `.aura-prose`, `.aura-text-body` and `.aura-text-caption` take the accent, as in a Card or a table since 5.30, and are always underlined. Zero specificity: your own link rules win.
195
+ - **Dark theme:** `--aura-bg-selected` is a 20% violet wash (#352f48) and the active SideNav item has a 3px violet edge (`--aura-nav-active-edge`; `createTheme` uses the brand's — regenerate a theme made with an earlier `createTheme`, or its dark edge stays AURA's violet); the DataTable and Table header band is #1f1f22, a step above the card instead of below it.
196
+ - **Progress `tone="warning"`** fills amber-700 in light (`--aura-progress-warning-fill`), amber like the dark theme, no longer rust.
197
+ - **Small fixes:** a sortable `Th` label sits on the same line as a plain one; Tag toggles among FilterBar's controls are as tall as the search; Tag's remove × is 16px in a 24px button.
198
+
199
+ ## 5.74 — Chamber-OS addendum 94 (#193)
200
+
201
+ - **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]`).
202
+
189
203
  ## 5.73 — Chamber-OS addendum 93 follow-up (#192)
190
204
 
191
205
  - **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.
@@ -425,7 +425,7 @@ window.Aura = (() => {
425
425
  const v = getComputedStyle(el).visibility;
426
426
  return v !== "hidden" && v !== "collapse";
427
427
  }
428
- function barStack(name, onMany) {
428
+ function barStack(name, onMany, onRead) {
429
429
  const els = [];
430
430
  let frame = 0;
431
431
  const docEvents = ["click", "keydown", "focusin", "transitionend", "beforematch"];
@@ -433,6 +433,7 @@ window.Aura = (() => {
433
433
  function write() {
434
434
  if (frame) cancelAnimationFrame(frame);
435
435
  frame = 0;
436
+ if (onRead) onRead();
436
437
  const root = document.documentElement;
437
438
  let shown = null, boxed = null, pinned2 = false, many = 0;
438
439
  for (let i = els.length - 1; i >= 0; i--) {
@@ -487,16 +488,46 @@ window.Aura = (() => {
487
488
  write
488
489
  };
489
490
  }
491
+ var modalityOn = false;
492
+ function setModality(m) {
493
+ const root = document.documentElement;
494
+ if (m === "pointer") {
495
+ if (root.getAttribute("data-aura-modality") !== "pointer") root.setAttribute("data-aura-modality", "pointer");
496
+ } else if (root.hasAttribute("data-aura-modality")) root.removeAttribute("data-aura-modality");
497
+ }
498
+ function useInputModality() {
499
+ React3.useEffect(function() {
500
+ if (modalityOn) return;
501
+ modalityOn = true;
502
+ document.addEventListener(
503
+ "keydown",
504
+ function() {
505
+ setModality("key");
506
+ },
507
+ true
508
+ );
509
+ document.addEventListener(
510
+ "pointerdown",
511
+ function() {
512
+ setModality("pointer");
513
+ },
514
+ true
515
+ );
516
+ }, []);
517
+ }
518
+ function pointerModality() {
519
+ setModality("pointer");
520
+ }
490
521
 
491
522
  // src/display.tsx
492
523
  var React4 = __toESM(require_react(), 1);
493
524
 
494
525
  // src/status.ts
495
526
  var TONE_WORDS = {
496
- ready: ["ready", "done", "complete", "completed", "approved", "live", "passed"],
527
+ ready: ["ready", "done", "complete", "completed", "approved", "live", "passed", "active", "up", "online", "resolved"],
497
528
  progress: ["in progress", "in review", "review", "syncing", "running", "pending"],
498
529
  warning: ["warning", "problem", "degraded", "at risk"],
499
- blocked: ["blocked", "failed", "error", "rejected", "on hold", "cancelled"]
530
+ blocked: ["blocked", "failed", "error", "rejected", "on hold", "cancelled", "down", "offline", "outage"]
500
531
  };
501
532
  function toneFor(status) {
502
533
  const s = String(status == null ? "" : status).trim().toLowerCase();
@@ -814,13 +845,19 @@ window.Aura = (() => {
814
845
  };
815
846
  function statusPillElement(props, ref) {
816
847
  const tone2 = props.tone || toneFor(props.children);
817
- const rest = omit(props, ["tone", "className", "children", "wrap", "busy"]);
848
+ const rest = omit(props, ["tone", "className", "children", "wrap", "busy", "variant"]);
818
849
  return /* @__PURE__ */ React4.createElement(
819
850
  "span",
820
851
  {
821
852
  ...rest,
822
853
  ref,
823
- className: cx("aura-pill", "aura-pill--" + tone2, props.wrap && "is-wrap", props.className)
854
+ className: cx(
855
+ "aura-pill",
856
+ "aura-pill--" + tone2,
857
+ props.variant === "solid" && "is-solid",
858
+ props.wrap && "is-wrap",
859
+ props.className
860
+ )
824
861
  },
825
862
  props.busy ? /* @__PURE__ */ React4.createElement(Icon, { name: h2(IconLoaderCircle), size: 12, className: "aura-spin" }) : /* @__PURE__ */ React4.createElement(Icon, { name: h2(PILL_ICON[tone2] || IconCircle), size: 12 }),
826
863
  props.wrap ? /* @__PURE__ */ React4.createElement("span", { className: "aura-pill__text" }, props.children) : props.children
@@ -2394,6 +2431,7 @@ window.Aura = (() => {
2394
2431
  const rest = omit(props, FIELD_KEYS.concat(["children", FILTER_KEY, "readOnly"]));
2395
2432
  const ro = !!props.readOnly && !props.disabled;
2396
2433
  const mounted = useMounted();
2434
+ useInputModality();
2397
2435
  const kept = React16.useRef(null);
2398
2436
  const current2 = [].concat(props.value != null ? props.value : props.defaultValue != null ? props.defaultValue : []).map(String);
2399
2437
  const opts = (props.options || []).map(function(o) {
@@ -2806,6 +2844,7 @@ window.Aura = (() => {
2806
2844
  e.preventDefault();
2807
2845
  },
2808
2846
  onPointerMove: function() {
2847
+ pointerModality();
2809
2848
  if (!it.disabled && active !== it.index) activeState[1](it.index);
2810
2849
  },
2811
2850
  onClick: function() {
@@ -4207,6 +4246,7 @@ window.Aura = (() => {
4207
4246
  const posState = React23.useState(null);
4208
4247
  const inputRef = React23.useRef(null), inputMerged = useMergedRef(ref, inputRef), boxRef = React23.useRef(null), listRef = React23.useRef(null);
4209
4248
  const mounted = useMounted();
4249
+ useInputModality();
4210
4250
  const limit = props.limit || 200;
4211
4251
  const filter = props.filter || defaultFilter;
4212
4252
  let shown = props.onSearch || query == null ? options : options.filter(function(o) {
@@ -4390,6 +4430,7 @@ window.Aura = (() => {
4390
4430
  if (!blocked || isSel) choose(o);
4391
4431
  },
4392
4432
  onPointerMove: function() {
4433
+ pointerModality();
4393
4434
  if (activeIdx !== i) setActive(i);
4394
4435
  }
4395
4436
  },
@@ -5526,7 +5567,7 @@ window.Aura = (() => {
5526
5567
  "aria-label": props.removeLabel || t.remove(name),
5527
5568
  onClick: props.onRemove
5528
5569
  },
5529
- /* @__PURE__ */ React31.createElement(Icon, { name: /* @__PURE__ */ React31.createElement(IconX, null), size: 14 })
5570
+ /* @__PURE__ */ React31.createElement(Icon, { name: /* @__PURE__ */ React31.createElement(IconX, null), size: 16 })
5530
5571
  );
5531
5572
  return /* @__PURE__ */ React31.createElement(Tooltip, { content: fullText, open: fullText ? void 0 : false }, btn);
5532
5573
  }() : null);
@@ -8227,12 +8268,41 @@ window.Aura = (() => {
8227
8268
  });
8228
8269
 
8229
8270
  // src/PageHeaderClient.tsx
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
- });
8271
+ var bars = barStack(
8272
+ "--aura-page-actions-height",
8273
+ function() {
8274
+ devWarnOnce(
8275
+ "pageheader-bar-twice",
8276
+ "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)."
8277
+ );
8278
+ },
8279
+ function() {
8280
+ marks.forEach(function(m) {
8281
+ m();
8282
+ });
8283
+ }
8284
+ );
8285
+ var UNSEEN = ".aura-page-header__status, .sr-only, .aura-sr-only, .visually-hidden, .screen-reader-text";
8286
+ function noneShown(el, barVisible) {
8287
+ for (let n3 = el.firstChild; n3; n3 = n3.nextSibling) {
8288
+ if (n3.nodeType === 3) {
8289
+ if ((n3.textContent || "").trim()) return false;
8290
+ continue;
8291
+ }
8292
+ if (n3.nodeType !== 1) continue;
8293
+ const c = n3;
8294
+ if (c.hidden || c.matches(UNSEEN)) continue;
8295
+ const s = getComputedStyle(c);
8296
+ if (s.display === "none") continue;
8297
+ if (barVisible && (s.visibility === "hidden" || s.visibility === "collapse")) continue;
8298
+ const inline = c.getAttribute("style") || "";
8299
+ if (/position:\s*absolute/.test(inline) && /clip/.test(inline)) continue;
8300
+ if (s.display === "contents" && noneShown(c, barVisible)) continue;
8301
+ return false;
8302
+ }
8303
+ return true;
8304
+ }
8305
+ var marks = /* @__PURE__ */ new Set();
8236
8306
  var PageHeader3 = React45.forwardRef(function PageHeader4(props, ref) {
8237
8307
  const own = React45.useRef(null);
8238
8308
  const merged = useMergedRef(ref, own);
@@ -8246,8 +8316,15 @@ window.Aura = (() => {
8246
8316
  split ? ":scope > .aura-page-header__actions > .aura-page-header__bar" : ":scope > .aura-page-header__actions"
8247
8317
  );
8248
8318
  if (!el) return;
8319
+ const head = own.current;
8249
8320
  let checked = false;
8321
+ function mark() {
8322
+ const empty = noneShown(el, getComputedStyle(el).visibility === "visible");
8323
+ const state = empty ? "empty" : "shown";
8324
+ if (head.getAttribute("data-aura-bar") !== state) head.setAttribute("data-aura-bar", state);
8325
+ }
8250
8326
  function sync() {
8327
+ mark();
8251
8328
  bars.write();
8252
8329
  if (!checked && getComputedStyle(el).position === "fixed" && (checked = true, fixedTrapped(el)))
8253
8330
  devWarnOnce(
@@ -8255,14 +8332,35 @@ window.Aura = (() => {
8255
8332
  "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
8333
  );
8257
8334
  }
8335
+ mark();
8336
+ marks.add(mark);
8258
8337
  bars.add(el);
8338
+ const mo = typeof MutationObserver === "undefined" ? null : new MutationObserver(function() {
8339
+ if (!frame) frame = requestAnimationFrame(later);
8340
+ });
8341
+ let frame = 0;
8342
+ function later() {
8343
+ frame = 0;
8344
+ sync();
8345
+ }
8346
+ if (mo)
8347
+ mo.observe(el, {
8348
+ childList: true,
8349
+ subtree: true,
8350
+ attributes: true,
8351
+ attributeFilter: ["hidden", "class", "style"]
8352
+ });
8259
8353
  const ro = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(sync);
8260
8354
  if (ro) ro.observe(el, { box: "border-box" });
8261
8355
  window.addEventListener("resize", sync);
8262
8356
  sync();
8263
8357
  return function() {
8264
8358
  if (ro) ro.disconnect();
8359
+ if (mo) mo.disconnect();
8360
+ if (frame) cancelAnimationFrame(frame);
8361
+ marks.delete(mark);
8265
8362
  window.removeEventListener("resize", sync);
8363
+ head.removeAttribute("data-aura-bar");
8266
8364
  bars.remove(el);
8267
8365
  };
8268
8366
  },
@@ -9523,6 +9621,7 @@ window.Aura = (() => {
9523
9621
  const pos = React57.useState(null);
9524
9622
  const boxRef = React57.useRef(null), inputRef = React57.useRef(null), listRef = React57.useRef(null), inputMerged = useMergedRef(ref, inputRef);
9525
9623
  const mounted = useMounted();
9624
+ useInputModality();
9526
9625
  function nearest(v) {
9527
9626
  const n3 = toMin(v);
9528
9627
  if (n3 == null) return 0;
@@ -9694,6 +9793,7 @@ window.Aura = (() => {
9694
9793
  choose(i);
9695
9794
  },
9696
9795
  onPointerMove: function() {
9796
+ pointerModality();
9697
9797
  if (active !== i) setActive(i);
9698
9798
  }
9699
9799
  },
@@ -10289,7 +10389,7 @@ window.Aura = (() => {
10289
10389
  D["fg-accent"] = fit(b[300], darkGrounds, 4.5, 1);
10290
10390
  D["accent-violet"] = fit(b[400], darkGrounds, 3, 1);
10291
10391
  D["focus-ring"] = fit(b[400], darkGrounds, 3, 1);
10292
- D["bg-selected"] = mix(ZINC[900], b[500], 0.16);
10392
+ D["bg-selected"] = mix(ZINC[900], b[500], 0.2);
10293
10393
  D["alert-info-bg"] = D["bg-selected"];
10294
10394
  D["alert-info-fg"] = fit(b[300], [D["alert-info-bg"]], 4.5, 1);
10295
10395
  D["alert-info-border"] = mix(ZINC[900], b[400], 0.4);
@@ -10310,6 +10410,7 @@ window.Aura = (() => {
10310
10410
  L["control-checked-fg"] = onFill(L["control-checked-bg"]);
10311
10411
  D["control-checked-bg"] = fit(b[300], darkGrounds, 3, 1);
10312
10412
  D["control-checked-fg"] = onFill(D["control-checked-bg"]);
10413
+ D["nav-active-edge"] = D["control-checked-bg"];
10313
10414
  const shadowLight = INK, shadowDark = D["accent-violet"];
10314
10415
  if (o.primary === "brand") {
10315
10416
  L["button-primary-bg"] = fit(b[600], [ZINC[0]], 4.5, -1);
@@ -407,7 +407,7 @@ function onScreen(el) {
407
407
  const v = getComputedStyle(el).visibility;
408
408
  return v !== "hidden" && v !== "collapse";
409
409
  }
410
- function barStack(name, onMany) {
410
+ function barStack(name, onMany, onRead) {
411
411
  const els = [];
412
412
  let frame = 0;
413
413
  const docEvents = ["click", "keydown", "focusin", "transitionend", "beforematch"];
@@ -415,6 +415,7 @@ function barStack(name, onMany) {
415
415
  function write() {
416
416
  if (frame) cancelAnimationFrame(frame);
417
417
  frame = 0;
418
+ if (onRead) onRead();
418
419
  const root = document.documentElement;
419
420
  let shown = null, boxed = null, pinned2 = false, many = 0;
420
421
  for (let i = els.length - 1; i >= 0; i--) {
@@ -469,16 +470,46 @@ function barStack(name, onMany) {
469
470
  write
470
471
  };
471
472
  }
473
+ var modalityOn = false;
474
+ function setModality(m) {
475
+ const root = document.documentElement;
476
+ if (m === "pointer") {
477
+ if (root.getAttribute("data-aura-modality") !== "pointer") root.setAttribute("data-aura-modality", "pointer");
478
+ } else if (root.hasAttribute("data-aura-modality")) root.removeAttribute("data-aura-modality");
479
+ }
480
+ function useInputModality() {
481
+ React3.useEffect(function() {
482
+ if (modalityOn) return;
483
+ modalityOn = true;
484
+ document.addEventListener(
485
+ "keydown",
486
+ function() {
487
+ setModality("key");
488
+ },
489
+ true
490
+ );
491
+ document.addEventListener(
492
+ "pointerdown",
493
+ function() {
494
+ setModality("pointer");
495
+ },
496
+ true
497
+ );
498
+ }, []);
499
+ }
500
+ function pointerModality() {
501
+ setModality("pointer");
502
+ }
472
503
 
473
504
  // src/display.tsx
474
505
  var React4 = __toESM(require("react"), 1);
475
506
 
476
507
  // src/status.ts
477
508
  var TONE_WORDS = {
478
- ready: ["ready", "done", "complete", "completed", "approved", "live", "passed"],
509
+ ready: ["ready", "done", "complete", "completed", "approved", "live", "passed", "active", "up", "online", "resolved"],
479
510
  progress: ["in progress", "in review", "review", "syncing", "running", "pending"],
480
511
  warning: ["warning", "problem", "degraded", "at risk"],
481
- blocked: ["blocked", "failed", "error", "rejected", "on hold", "cancelled"]
512
+ blocked: ["blocked", "failed", "error", "rejected", "on hold", "cancelled", "down", "offline", "outage"]
482
513
  };
483
514
  function toneFor(status) {
484
515
  const s = String(status == null ? "" : status).trim().toLowerCase();
@@ -796,13 +827,19 @@ var PILL_ICON = {
796
827
  };
797
828
  function statusPillElement(props, ref) {
798
829
  const tone2 = props.tone || toneFor(props.children);
799
- const rest = omit(props, ["tone", "className", "children", "wrap", "busy"]);
830
+ const rest = omit(props, ["tone", "className", "children", "wrap", "busy", "variant"]);
800
831
  return /* @__PURE__ */ React4.createElement(
801
832
  "span",
802
833
  {
803
834
  ...rest,
804
835
  ref,
805
- className: cx("aura-pill", "aura-pill--" + tone2, props.wrap && "is-wrap", props.className)
836
+ className: cx(
837
+ "aura-pill",
838
+ "aura-pill--" + tone2,
839
+ props.variant === "solid" && "is-solid",
840
+ props.wrap && "is-wrap",
841
+ props.className
842
+ )
806
843
  },
807
844
  props.busy ? /* @__PURE__ */ React4.createElement(Icon, { name: h2(IconLoaderCircle), size: 12, className: "aura-spin" }) : /* @__PURE__ */ React4.createElement(Icon, { name: h2(PILL_ICON[tone2] || IconCircle), size: 12 }),
808
845
  props.wrap ? /* @__PURE__ */ React4.createElement("span", { className: "aura-pill__text" }, props.children) : props.children
@@ -2376,6 +2413,7 @@ var Select = React16.forwardRef(function Select2(props, ref) {
2376
2413
  const rest = omit(props, FIELD_KEYS.concat(["children", FILTER_KEY, "readOnly"]));
2377
2414
  const ro = !!props.readOnly && !props.disabled;
2378
2415
  const mounted = useMounted();
2416
+ useInputModality();
2379
2417
  const kept = React16.useRef(null);
2380
2418
  const current2 = [].concat(props.value != null ? props.value : props.defaultValue != null ? props.defaultValue : []).map(String);
2381
2419
  const opts = (props.options || []).map(function(o) {
@@ -2788,6 +2826,7 @@ var Select = React16.forwardRef(function Select2(props, ref) {
2788
2826
  e.preventDefault();
2789
2827
  },
2790
2828
  onPointerMove: function() {
2829
+ pointerModality();
2791
2830
  if (!it.disabled && active !== it.index) activeState[1](it.index);
2792
2831
  },
2793
2832
  onClick: function() {
@@ -4189,6 +4228,7 @@ var Combobox = React23.forwardRef(
4189
4228
  const posState = React23.useState(null);
4190
4229
  const inputRef = React23.useRef(null), inputMerged = useMergedRef(ref, inputRef), boxRef = React23.useRef(null), listRef = React23.useRef(null);
4191
4230
  const mounted = useMounted();
4231
+ useInputModality();
4192
4232
  const limit = props.limit || 200;
4193
4233
  const filter = props.filter || defaultFilter;
4194
4234
  let shown = props.onSearch || query == null ? options : options.filter(function(o) {
@@ -4372,6 +4412,7 @@ var Combobox = React23.forwardRef(
4372
4412
  if (!blocked || isSel) choose(o);
4373
4413
  },
4374
4414
  onPointerMove: function() {
4415
+ pointerModality();
4375
4416
  if (activeIdx !== i) setActive(i);
4376
4417
  }
4377
4418
  },
@@ -5508,7 +5549,7 @@ var Tag = React31.forwardRef(function Tag2(props, ref) {
5508
5549
  "aria-label": props.removeLabel || t.remove(name),
5509
5550
  onClick: props.onRemove
5510
5551
  },
5511
- /* @__PURE__ */ React31.createElement(Icon, { name: /* @__PURE__ */ React31.createElement(IconX, null), size: 14 })
5552
+ /* @__PURE__ */ React31.createElement(Icon, { name: /* @__PURE__ */ React31.createElement(IconX, null), size: 16 })
5512
5553
  );
5513
5554
  return /* @__PURE__ */ React31.createElement(Tooltip, { content: fullText, open: fullText ? void 0 : false }, btn);
5514
5555
  }() : null);
@@ -8209,12 +8250,41 @@ var PageHeader = React44.forwardRef(function PageHeader2(props, ref) {
8209
8250
  });
8210
8251
 
8211
8252
  // src/PageHeaderClient.tsx
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
- });
8253
+ var bars = barStack(
8254
+ "--aura-page-actions-height",
8255
+ function() {
8256
+ devWarnOnce(
8257
+ "pageheader-bar-twice",
8258
+ "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)."
8259
+ );
8260
+ },
8261
+ function() {
8262
+ marks.forEach(function(m) {
8263
+ m();
8264
+ });
8265
+ }
8266
+ );
8267
+ var UNSEEN = ".aura-page-header__status, .sr-only, .aura-sr-only, .visually-hidden, .screen-reader-text";
8268
+ function noneShown(el, barVisible) {
8269
+ for (let n3 = el.firstChild; n3; n3 = n3.nextSibling) {
8270
+ if (n3.nodeType === 3) {
8271
+ if ((n3.textContent || "").trim()) return false;
8272
+ continue;
8273
+ }
8274
+ if (n3.nodeType !== 1) continue;
8275
+ const c = n3;
8276
+ if (c.hidden || c.matches(UNSEEN)) continue;
8277
+ const s = getComputedStyle(c);
8278
+ if (s.display === "none") continue;
8279
+ if (barVisible && (s.visibility === "hidden" || s.visibility === "collapse")) continue;
8280
+ const inline = c.getAttribute("style") || "";
8281
+ if (/position:\s*absolute/.test(inline) && /clip/.test(inline)) continue;
8282
+ if (s.display === "contents" && noneShown(c, barVisible)) continue;
8283
+ return false;
8284
+ }
8285
+ return true;
8286
+ }
8287
+ var marks = /* @__PURE__ */ new Set();
8218
8288
  var PageHeader3 = React45.forwardRef(function PageHeader4(props, ref) {
8219
8289
  const own = React45.useRef(null);
8220
8290
  const merged = useMergedRef(ref, own);
@@ -8228,8 +8298,15 @@ var PageHeader3 = React45.forwardRef(function PageHeader4(props, ref) {
8228
8298
  split ? ":scope > .aura-page-header__actions > .aura-page-header__bar" : ":scope > .aura-page-header__actions"
8229
8299
  );
8230
8300
  if (!el) return;
8301
+ const head = own.current;
8231
8302
  let checked = false;
8303
+ function mark() {
8304
+ const empty = noneShown(el, getComputedStyle(el).visibility === "visible");
8305
+ const state = empty ? "empty" : "shown";
8306
+ if (head.getAttribute("data-aura-bar") !== state) head.setAttribute("data-aura-bar", state);
8307
+ }
8232
8308
  function sync() {
8309
+ mark();
8233
8310
  bars.write();
8234
8311
  if (!checked && getComputedStyle(el).position === "fixed" && (checked = true, fixedTrapped(el)))
8235
8312
  devWarnOnce(
@@ -8237,14 +8314,35 @@ var PageHeader3 = React45.forwardRef(function PageHeader4(props, ref) {
8237
8314
  "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
8315
  );
8239
8316
  }
8317
+ mark();
8318
+ marks.add(mark);
8240
8319
  bars.add(el);
8320
+ const mo = typeof MutationObserver === "undefined" ? null : new MutationObserver(function() {
8321
+ if (!frame) frame = requestAnimationFrame(later);
8322
+ });
8323
+ let frame = 0;
8324
+ function later() {
8325
+ frame = 0;
8326
+ sync();
8327
+ }
8328
+ if (mo)
8329
+ mo.observe(el, {
8330
+ childList: true,
8331
+ subtree: true,
8332
+ attributes: true,
8333
+ attributeFilter: ["hidden", "class", "style"]
8334
+ });
8241
8335
  const ro = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(sync);
8242
8336
  if (ro) ro.observe(el, { box: "border-box" });
8243
8337
  window.addEventListener("resize", sync);
8244
8338
  sync();
8245
8339
  return function() {
8246
8340
  if (ro) ro.disconnect();
8341
+ if (mo) mo.disconnect();
8342
+ if (frame) cancelAnimationFrame(frame);
8343
+ marks.delete(mark);
8247
8344
  window.removeEventListener("resize", sync);
8345
+ head.removeAttribute("data-aura-bar");
8248
8346
  bars.remove(el);
8249
8347
  };
8250
8348
  },
@@ -9505,6 +9603,7 @@ var TimePicker = React57.forwardRef(function TimePicker2(props, ref) {
9505
9603
  const pos = React57.useState(null);
9506
9604
  const boxRef = React57.useRef(null), inputRef = React57.useRef(null), listRef = React57.useRef(null), inputMerged = useMergedRef(ref, inputRef);
9507
9605
  const mounted = useMounted();
9606
+ useInputModality();
9508
9607
  function nearest(v) {
9509
9608
  const n3 = toMin(v);
9510
9609
  if (n3 == null) return 0;
@@ -9676,6 +9775,7 @@ var TimePicker = React57.forwardRef(function TimePicker2(props, ref) {
9676
9775
  choose(i);
9677
9776
  },
9678
9777
  onPointerMove: function() {
9778
+ pointerModality();
9679
9779
  if (active !== i) setActive(i);
9680
9780
  }
9681
9781
  },
@@ -10271,7 +10371,7 @@ function createTheme(opts) {
10271
10371
  D["fg-accent"] = fit(b[300], darkGrounds, 4.5, 1);
10272
10372
  D["accent-violet"] = fit(b[400], darkGrounds, 3, 1);
10273
10373
  D["focus-ring"] = fit(b[400], darkGrounds, 3, 1);
10274
- D["bg-selected"] = mix(ZINC[900], b[500], 0.16);
10374
+ D["bg-selected"] = mix(ZINC[900], b[500], 0.2);
10275
10375
  D["alert-info-bg"] = D["bg-selected"];
10276
10376
  D["alert-info-fg"] = fit(b[300], [D["alert-info-bg"]], 4.5, 1);
10277
10377
  D["alert-info-border"] = mix(ZINC[900], b[400], 0.4);
@@ -10292,6 +10392,7 @@ function createTheme(opts) {
10292
10392
  L["control-checked-fg"] = onFill(L["control-checked-bg"]);
10293
10393
  D["control-checked-bg"] = fit(b[300], darkGrounds, 3, 1);
10294
10394
  D["control-checked-fg"] = onFill(D["control-checked-bg"]);
10395
+ D["nav-active-edge"] = D["control-checked-bg"];
10295
10396
  const shadowLight = INK, shadowDark = D["accent-violet"];
10296
10397
  if (o.primary === "brand") {
10297
10398
  L["button-primary-bg"] = fit(b[600], [ZINC[0]], 4.5, -1);
@@ -2,7 +2,17 @@
2
2
  import * as React from "react";
3
3
  import { useStrings, useDensity } from "./locale.js";
4
4
  import { createPortal } from "react-dom";
5
- import { cx, uid, useMaybeControlled, useMounted, useIsoLayoutEffect, useMergedRef, touchClass } from "./internal.js";
5
+ import {
6
+ cx,
7
+ uid,
8
+ useMaybeControlled,
9
+ useMounted,
10
+ useIsoLayoutEffect,
11
+ useMergedRef,
12
+ touchClass,
13
+ useInputModality,
14
+ pointerModality
15
+ } from "./internal.js";
6
16
  import { Icon } from "./Icon.js";
7
17
  import { Field } from "./Field.js";
8
18
  import { IconCheck, IconChevronDown, IconLoaderCircle, IconSearch, IconX } from "./icons.js";
@@ -67,6 +77,7 @@ const Combobox = React.forwardRef(
67
77
  const posState = React.useState(null);
68
78
  const inputRef = React.useRef(null), inputMerged = useMergedRef(ref, inputRef), boxRef = React.useRef(null), listRef = React.useRef(null);
69
79
  const mounted = useMounted();
80
+ useInputModality();
70
81
  const limit = props.limit || 200;
71
82
  const filter = props.filter || defaultFilter;
72
83
  let shown = props.onSearch || query == null ? options : options.filter(function(o) {
@@ -250,6 +261,7 @@ const Combobox = React.forwardRef(
250
261
  if (!blocked || isSel) choose(o);
251
262
  },
252
263
  onPointerMove: function() {
264
+ pointerModality();
253
265
  if (activeIdx !== i) setActive(i);
254
266
  }
255
267
  },
@@ -2,12 +2,41 @@
2
2
  import * as React from "react";
3
3
  import { PageHeader as StaticPageHeader } from "./PageHeader.js";
4
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
- });
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();
11
40
  const PageHeader = React.forwardRef(function PageHeader2(props, ref) {
12
41
  const own = React.useRef(null);
13
42
  const merged = useMergedRef(ref, own);
@@ -21,8 +50,15 @@ const PageHeader = React.forwardRef(function PageHeader2(props, ref) {
21
50
  split ? ":scope > .aura-page-header__actions > .aura-page-header__bar" : ":scope > .aura-page-header__actions"
22
51
  );
23
52
  if (!el) return;
53
+ const head = own.current;
24
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
+ }
25
60
  function sync() {
61
+ mark();
26
62
  bars.write();
27
63
  if (!checked && getComputedStyle(el).position === "fixed" && (checked = true, trapped(el)))
28
64
  devWarnOnce(
@@ -30,14 +66,35 @@ const PageHeader = React.forwardRef(function PageHeader2(props, ref) {
30
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."
31
67
  );
32
68
  }
69
+ mark();
70
+ marks.add(mark);
33
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();
79
+ }
80
+ if (mo)
81
+ mo.observe(el, {
82
+ childList: true,
83
+ subtree: true,
84
+ attributes: true,
85
+ attributeFilter: ["hidden", "class", "style"]
86
+ });
34
87
  const ro = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(sync);
35
88
  if (ro) ro.observe(el, { box: "border-box" });
36
89
  window.addEventListener("resize", sync);
37
90
  sync();
38
91
  return function() {
39
92
  if (ro) ro.disconnect();
93
+ if (mo) mo.disconnect();
94
+ if (frame) cancelAnimationFrame(frame);
95
+ marks.delete(mark);
40
96
  window.removeEventListener("resize", sync);
97
+ head.removeAttribute("data-aura-bar");
41
98
  bars.remove(el);
42
99
  };
43
100
  },