@jsenv/navi 0.29.149 → 0.29.151

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.
@@ -5596,8 +5596,19 @@ const CLICK_SELECTOR = selfInteractionSelector("click");
5596
5596
  * The closest element CLAIMING THE PRESS wins, not the closest one claiming
5597
5597
  * anything: an affordance that took only the drag is transparent here, exactly
5598
5598
  * as it is to the drag readers when it took only the click.
5599
+ *
5600
+ * @param {Event} event The gesture being arbitrated.
5601
+ * @param {Element} controlHost The control asking whether the press is its own.
5602
+ * @param {Element} [requester] Who asked this control to act, when someone did
5603
+ * — the source of a command, typically. The claim answers "was this press
5604
+ * yours or the affordance's"; it says nothing about a request that affordance
5605
+ * is making, and the answer there is always yes.
5599
5606
  */
5600
- const isAimedAtSelfInteractionsBelow = (event, controlHost) => {
5607
+ const isAimedAtSelfInteractionsBelow = (
5608
+ event,
5609
+ controlHost,
5610
+ requester,
5611
+ ) => {
5601
5612
  const target = event?.target;
5602
5613
  if (!target || typeof target.closest !== "function") {
5603
5614
  return false;
@@ -5611,6 +5622,13 @@ const isAimedAtSelfInteractionsBelow = (event, controlHost) => {
5611
5622
  if (claimer === controlHost || claimer.contains(controlHost)) {
5612
5623
  return false;
5613
5624
  }
5625
+ // The claimer is the one asking. Its claim took the press so IT would decide
5626
+ // what the press means, and this is that decision arriving — a clear cross
5627
+ // sending "--navi-clear" to the field it sits in. Stepping back here would be
5628
+ // the control refusing the very request the claim exists to let through.
5629
+ if (requester && (claimer === requester || claimer.contains(requester))) {
5630
+ return false;
5631
+ }
5614
5632
  // From the root rather than the host: a layered control (a picker holding an
5615
5633
  // input) has its gate on the input, and what the application drew sits beside
5616
5634
  // it, not in it.
@@ -9802,12 +9820,21 @@ const createControlInteraction = (
9802
9820
 
9803
9821
  const dispatchRequestInteraction = (
9804
9822
  element,
9805
- { event, name = "", prevented, allowed, always, ...detailRest } = {},
9823
+ {
9824
+ event,
9825
+ name = "",
9826
+ requester,
9827
+ prevented,
9828
+ allowed,
9829
+ always,
9830
+ ...detailRest
9831
+ } = {},
9806
9832
  ) => {
9807
9833
  const controlHost = findControlHost(element) || element;
9808
9834
  return dispatchInternalCustomEvent(controlHost, "navi_request_interaction", {
9809
9835
  event,
9810
9836
  name,
9837
+ requester,
9811
9838
  prevented,
9812
9839
  allowed,
9813
9840
  always,
@@ -9829,6 +9856,9 @@ const onRequestInteraction = (
9829
9856
  // through (see READONLY_CONSTRAINT).
9830
9857
  intent = "write",
9831
9858
  bypassInteractivity = false,
9859
+ // Who asked, when the control is not answering the gesture on its own —
9860
+ // the source of a command (see the self-interactions step-back below).
9861
+ requester,
9832
9862
  prevented,
9833
9863
  allowed,
9834
9864
  always,
@@ -9862,7 +9892,9 @@ const onRequestInteraction = (
9862
9892
  // reaction never happened, so its `prevented`/`always` (an
9863
9893
  // `e.preventDefault()`, for most of them) have nothing to undo and would take
9864
9894
  // the press from the affordance itself.
9865
- if (isAimedAtSelfInteractionsBelow(event, controlHost)) {
9895
+ // Unless that element is the one asking: what it took the press to decide is
9896
+ // arriving here, and it is this control's to answer.
9897
+ if (isAimedAtSelfInteractionsBelow(event, controlHost, requester)) {
9866
9898
  debugInteraction(
9867
9899
  event,
9868
9900
  `"${name}" is for a self-interactions element below`,
@@ -9947,6 +9979,11 @@ const dispatchRequestAction = (
9947
9979
  return dispatchRequestInteraction(element, {
9948
9980
  event,
9949
9981
  name,
9982
+ // The gate needs it as much as the action does: the requester may be an
9983
+ // affordance that claimed the press to ask for this very action, and the
9984
+ // control must not read that claim as "this press was not for me" — see
9985
+ // isAimedAtSelfInteractionsBelow.
9986
+ requester: actionOptions.requester,
9950
9987
  prevented,
9951
9988
  allowed: () => {
9952
9989
  allowed?.();
@@ -30404,6 +30441,9 @@ registerNaviCommand("--navi-update", (source, event, { argument }) => {
30404
30441
  dispatchRequestInteraction(target, {
30405
30442
  event,
30406
30443
  name: "--navi-update",
30444
+ // The source may have claimed the press to send this very command — see
30445
+ // the requester in onRequestInteraction.
30446
+ requester: source,
30407
30447
  prevented: () => event.preventDefault(),
30408
30448
  allowed: () => {
30409
30449
  const commandValue = resolveCommandValue(source, event);
@@ -30442,6 +30482,9 @@ registerNaviCommand("--navi-clear", (source, event) => {
30442
30482
  dispatchRequestInteraction(target, {
30443
30483
  event: clearEvent,
30444
30484
  name: "--navi-clear",
30485
+ // The source may have claimed the press to send this very command — see
30486
+ // the requester in onRequestInteraction.
30487
+ requester: source,
30445
30488
  prevented: () => clearEvent.preventDefault(),
30446
30489
  allowed: () => {
30447
30490
  // What the control holds, before it holds nothing: the clear is
@@ -30529,6 +30572,9 @@ registerNaviCommand("--navi-reset", (source, event) => {
30529
30572
  dispatchRequestInteraction(target, {
30530
30573
  event,
30531
30574
  name: "--navi-reset",
30575
+ // The source may have claimed the press to send this very command — see
30576
+ // the requester in onRequestInteraction.
30577
+ requester: source,
30532
30578
  prevented: () => event.preventDefault(),
30533
30579
  allowed: () => dispatchRequestResetUIState(target, event),
30534
30580
  });
@@ -42834,6 +42880,34 @@ const DetailsFieldContent = ({
42834
42880
  });
42835
42881
  };
42836
42882
 
42883
+ /**
42884
+ * Runs `fn` and commits whatever it re-renders before returning, instead of
42885
+ * letting Preact batch it into the next microtask. Layout effects of what gets
42886
+ * mounted run inside the call too, exactly as they would on any other commit.
42887
+ *
42888
+ * For the caller that has to read the DOM it just asked for — measuring an
42889
+ * element whose content it mounts in the same breath — and cannot wait a tick
42890
+ * to do it, because what comes after is a browser event still in flight
42891
+ * (preventDefault, focus placement) that no longer accepts being answered late.
42892
+ *
42893
+ * `options.debounceRendering` is Preact's own hook for deciding *when* the
42894
+ * render queue drains; swapping it for "right now" for the duration of the call
42895
+ * is exactly how preact/compat implements React's flushSync. Reserve it for the
42896
+ * case above: rendering synchronously in the middle of an event gives up the
42897
+ * batching that makes several state changes one commit.
42898
+ */
42899
+ const flushSyncRendering = (fn) => {
42900
+ const debounceRenderingPrevious = options.debounceRendering;
42901
+ options.debounceRendering = (drainRenderQueue) => {
42902
+ drainRenderQueue();
42903
+ };
42904
+ try {
42905
+ fn();
42906
+ } finally {
42907
+ options.debounceRendering = debounceRenderingPrevious;
42908
+ }
42909
+ };
42910
+
42837
42911
  /**
42838
42912
  * Small, renderer-agnostic helpers shared by Popover and Dialog's own custom
42839
42913
  * (non-top-layer) renderers — operate on a plain DOM element, no knowledge
@@ -43047,6 +43121,96 @@ const resolveAutoAnimationKind = (anchor, parsedPositionArea) => {
43047
43121
  return anchor || (yIsOverlapping && xIsOverlapping) ? "scaling" : "sliding";
43048
43122
  };
43049
43123
 
43124
+ /**
43125
+ * When a popup builds what it holds, and when it throws it away.
43126
+ *
43127
+ * A closed popup shows nothing, focuses nothing, and answers nothing: what it
43128
+ * holds is out of reach until it opens. Building that content at mount time
43129
+ * means a page carrying a handful of closed popups pays, on the very render
43130
+ * that decides how fast it appears, for content nobody has asked for — and
43131
+ * pays again on every subsequent measurement, since each of those nodes makes
43132
+ * the document the rest of the page queries bigger.
43133
+ *
43134
+ * So the content is built when the popup first opens, and stays built from
43135
+ * then on: closing is not throwing away, and a reopened popup finds its scroll
43136
+ * position, its half-typed form and its list state where it left them.
43137
+ *
43138
+ * It is built synchronously, from inside `openController.open()` and before
43139
+ * `openEffect` runs (see open_controller.js), so the popup still measures real
43140
+ * content when it positions and animates itself, and so anything inside it
43141
+ * still observes the opening the way it always did — mounted while the popup
43142
+ * reads as closed, told it opened right after (see
43143
+ * use_displayed_layout_effect.js).
43144
+ *
43145
+ * The `mount` prop moves that line. "closed" is two states, not one — never
43146
+ * opened yet, and closed again after an opening — and the three values answer
43147
+ * both at once:
43148
+ *
43149
+ * | mount | before the first open | after a close |
43150
+ * | ----------------- | --------------------- | ------------- |
43151
+ * | "always" | mounted | mounted |
43152
+ * | "from-first-open" | not mounted | mounted |
43153
+ * | "while-opened" | not mounted | not mounted |
43154
+ *
43155
+ * "always" is for content something else depends on before any opening: a
43156
+ * value the popup's owner reads off its own children, fields a form around it
43157
+ * collects on submit, a size measured from outside.
43158
+ *
43159
+ * "while-opened" is the opposite end: content that must be rebuilt from
43160
+ * scratch every time, because what it shows is read once at build time and can
43161
+ * change while the popup is closed — an uncontrolled field seeded from a
43162
+ * `defaultValue`, a form whose fresh state is its initial state.
43163
+ */
43164
+
43165
+
43166
+ const MOUNT_DEFAULT = "from-first-open";
43167
+
43168
+ const usePopupContentMount = (
43169
+ openController,
43170
+ ref,
43171
+ { children, mount = MOUNT_DEFAULT },
43172
+ ) => {
43173
+ const mountedAlways = mount === "always";
43174
+ const [contentMounted, setContentMounted] = useState(
43175
+ () => mountedAlways || openController.opened,
43176
+ );
43177
+ openController.mountContent = contentMounted
43178
+ ? null
43179
+ : () => {
43180
+ flushSyncRendering(() => {
43181
+ setContentMounted(true);
43182
+ });
43183
+ };
43184
+ openController.unmountContent =
43185
+ mount === "while-opened"
43186
+ ? () => {
43187
+ const element = ref?.current;
43188
+ if (!element) {
43189
+ setContentMounted(false);
43190
+ return;
43191
+ }
43192
+ // The popup is still on screen while it plays its exit transition;
43193
+ // emptying it right away would show that transition running on a
43194
+ // blank surface.
43195
+ whenTransitionSettles(element, () => {
43196
+ if (openController.opened) {
43197
+ // reopened while it was leaving — the content it holds is the
43198
+ // one that open just asked for
43199
+ return;
43200
+ }
43201
+ setContentMounted(false);
43202
+ });
43203
+ }
43204
+ : null;
43205
+ useLayoutEffect(() => {
43206
+ if (mountedAlways) {
43207
+ setContentMounted(true);
43208
+ }
43209
+ }, [mountedAlways]);
43210
+
43211
+ return contentMounted ? children : null;
43212
+ };
43213
+
43050
43214
  installImportMetaCssBuild(import.meta);/**
43051
43215
  * Expandable: an in-flow disclosure — a UI part that reveals a content part.
43052
43216
  * It covers the same ground as <Details> with structural differences:
@@ -43087,10 +43251,9 @@ installImportMetaCssBuild(import.meta);/**
43087
43251
  * events.
43088
43252
  *
43089
43253
  * Content is not built until the first expansion and stays built afterwards —
43090
- * same policy, same prop names as popups (see popup_content_mount.js):
43091
- * `mountWhenClosed` builds it right away, `unmountWhenClosed` throws it away
43092
- * once the collapse settles (so a closing animation still plays on real
43093
- * content).
43254
+ * same policy, same `mount` prop as popups (see popup_content_mount.js):
43255
+ * `"always"` builds it right away, `"while-opened"` throws it away once the
43256
+ * collapse settles (so a closing animation still plays on real content).
43094
43257
  *
43095
43258
  * The animation is a REVEAL, not a resize: the expandable's own footprint
43096
43259
  * grows/shrinks progressively (the content's grid track interpolates
@@ -43252,8 +43415,7 @@ const useExpandableContext = partName => {
43252
43415
  * layout?: "row" | "column",
43253
43416
  * autoFocus?: boolean,
43254
43417
  * maxContentHeight?: string | number,
43255
- * mountWhenClosed?: boolean,
43256
- * unmountWhenClosed?: boolean,
43418
+ * mount?: "always" | "from-first-open" | "while-opened",
43257
43419
  * arrowKeyShortcuts?: boolean,
43258
43420
  * openKeyShortcut?: string,
43259
43421
  * closeKeyShortcut?: string,
@@ -43290,13 +43452,15 @@ const useExpandableContext = partName => {
43290
43452
  * the UI part (it would otherwise be lost to the closed, inert content).
43291
43453
  * @param maxContentHeight - Caps the content height; taller content scrolls
43292
43454
  * inside the expandable instead of growing it.
43293
- * @param mountWhenClosed - Builds the content right away instead of on first
43294
- * expansion. In layout="column" it also gives the closed expandable its
43295
- * content's height (the content is kept laid out at its open width), so
43296
- * opening only reveals the width instead of changing the height too.
43297
- * @param unmountWhenClosed - Throws the content away once the collapse
43298
- * settles — after the closing animation, so it still plays on real content —
43299
- * and rebuilds it from scratch on every expansion.
43455
+ * @param mount - When the content is built and thrown away, same three values
43456
+ * as a popup's (see popup_content_mount.js). `"from-first-open"` (the
43457
+ * default) builds it on the first expansion and keeps it afterwards.
43458
+ * `"always"` builds it right away; in layout="column" it also gives the
43459
+ * closed expandable its content's height (the content is kept laid out at
43460
+ * its open width), so opening only reveals the width instead of changing the
43461
+ * height too. `"while-opened"` throws the content away once the collapse
43462
+ * settles — after the closing animation, so it still plays on real
43463
+ * content — and rebuilds it from scratch on every expansion.
43300
43464
  */
43301
43465
  const Expandable = props => {
43302
43466
  import.meta.css = [css$Q, "@jsenv/navi/src/control/expandable/expandable.jsx"];
@@ -43312,8 +43476,7 @@ const Expandable = props => {
43312
43476
  layout,
43313
43477
  autoFocus,
43314
43478
  maxContentHeight,
43315
- mountWhenClosed,
43316
- unmountWhenClosed,
43479
+ mount = MOUNT_DEFAULT,
43317
43480
  arrowKeyShortcuts = true,
43318
43481
  openKeyShortcut = "ArrowRight",
43319
43482
  closeKeyShortcut = "ArrowLeft",
@@ -43326,7 +43489,9 @@ const Expandable = props => {
43326
43489
  const contentContainerRef = useRef();
43327
43490
  const contentId = useId();
43328
43491
  const isColumn = layout === "column";
43329
- const closedContentSized = Boolean(isColumn && mountWhenClosed);
43492
+ const mountedAlways = mount === "always";
43493
+ const mountedWhileOpened = mount === "while-opened";
43494
+ const closedContentSized = isColumn && mountedAlways;
43330
43495
  // Reading .value during render is what subscribes the expandable to it.
43331
43496
  const openRequested = signal ? signal.value : open;
43332
43497
  const [opened, setOpened] = useState(() => Boolean(openRequested === undefined ? defaultOpen : openRequested));
@@ -43337,13 +43502,10 @@ const Expandable = props => {
43337
43502
  const {
43338
43503
  loading: actionLoading
43339
43504
  } = useActionStatus(effectiveAction);
43340
- const [contentMounted, setContentMounted] = useState(() => Boolean(mountWhenClosed) || opened);
43341
- // Same exclusion as popup_content_mount.js: content that must exist while
43342
- // closed cannot also be thrown away on close.
43343
- const effectiveUnmountWhenClosed = unmountWhenClosed && !mountWhenClosed;
43505
+ const [contentMounted, setContentMounted] = useState(() => mountedAlways || opened);
43344
43506
 
43345
43507
  // Fully open and no longer moving — what allows overflow to become visible
43346
- // (see the CSS) and what unmountWhenClosed waits for before emptying.
43508
+ // (see the CSS) and what mount="while-opened" waits for before emptying.
43347
43509
  const [settled, setSettled] = useState(true);
43348
43510
 
43349
43511
  // Read before the close touches the DOM: flipping the content to inert can
@@ -43410,7 +43572,7 @@ const Expandable = props => {
43410
43572
  focusedAtPointerDownRef.current = null;
43411
43573
  setOpened(nextOpen);
43412
43574
  // Flipped here, before the closing/opening commit, so effects of that very
43413
- // commit already see the movement as started — unmountWhenClosed must not
43575
+ // commit already see the movement as started — mount="while-opened" must not
43414
43576
  // read a stale "settled" and empty the content under a closing animation.
43415
43577
  setSettled(!animation);
43416
43578
  if (signal) {
@@ -43532,17 +43694,17 @@ const Expandable = props => {
43532
43694
  return cancel;
43533
43695
  }, [opened]);
43534
43696
  useLayoutEffect(() => {
43535
- if (settled && !opened && effectiveUnmountWhenClosed) {
43697
+ if (settled && !opened && mountedWhileOpened) {
43536
43698
  setContentMounted(false);
43537
43699
  }
43538
- }, [settled, opened, effectiveUnmountWhenClosed]);
43700
+ }, [settled, opened, mountedWhileOpened]);
43539
43701
  useLayoutEffect(() => {
43540
- if (mountWhenClosed) {
43702
+ if (mountedAlways) {
43541
43703
  setContentMounted(true);
43542
43704
  }
43543
- }, [mountWhenClosed]);
43705
+ }, [mountedAlways]);
43544
43706
 
43545
- // closedContentSized (column + mountWhenClosed): the closed content sizes
43707
+ // closedContentSized (column + mount="always"): the closed content sizes
43546
43708
  // the height (see the CSS), which is only right if it lies at its OPEN
43547
43709
  // width — at its natural closed width (a 0-wide track) it would wrap
43548
43710
  // against nothing and stack word by word. So while closed, its width is
@@ -44090,7 +44252,7 @@ installImportMetaCssBuild(import.meta);const css$P = /* css */`@layer navi {
44090
44252
  --button-color: currentColor;
44091
44253
  --button-cursor: pointer;
44092
44254
  --button-font-size: var(--navi-control-font-size);
44093
- --button-font-family: var(--navi-control-font-family);
44255
+ --button-font-family: var(--navi-control-font-family, inherit);
44094
44256
  --button-border-color-hover: color-mix(in srgb,
44095
44257
  var(--button-border-color) 70%,
44096
44258
  black);
@@ -44337,37 +44499,30 @@ a.navi_button {
44337
44499
  }
44338
44500
 
44339
44501
  &[data-cta] {
44340
- --x-button-background-color: var(--button-cta-background-color);
44341
- --x-button-border-color: var(--button-cta-background-color);
44342
- --x-button-color: white;
44343
-
44344
- &[data-hover] {
44345
- --x-button-background-color: color-mix(in srgb,
44346
- var(--button-cta-background-color) 85%,
44347
- white);
44348
- --x-button-border-color: color-mix(in srgb,
44349
- var(--button-cta-background-color) 85%,
44350
- white);
44351
- }
44352
-
44353
- &[data-readonly] {
44354
- --x-button-background-color: color-mix(in srgb,
44355
- var(--button-cta-background-color) 50%,
44356
- white);
44357
- --x-button-border-color: color-mix(in srgb,
44358
- var(--button-cta-background-color) 50%,
44359
- white);
44360
- }
44361
-
44362
- &[data-disabled] {
44363
- --x-button-background-color: color-mix(in srgb,
44364
- var(--button-cta-background-color) 40%,
44365
- white);
44366
- --x-button-border-color: color-mix(in srgb,
44367
- var(--button-cta-background-color) 40%,
44368
- white);
44369
- --x-button-color: #fff9;
44370
- }
44502
+ --button-background-color: var(--button-background, var(--button-cta-background-color));
44503
+ --button-border-color: var(--button-cta-background-color);
44504
+ --button-color: white;
44505
+ --button-background-color-hover: color-mix(in srgb,
44506
+ var(--button-background-color) 85%,
44507
+ white);
44508
+ --button-border-color-hover: color-mix(in srgb,
44509
+ var(--button-border-color) 85%,
44510
+ white);
44511
+ --button-background-color-readonly: color-mix(in srgb,
44512
+ var(--button-background-color) 50%,
44513
+ white);
44514
+ --button-border-color-readonly: color-mix(in srgb,
44515
+ var(--button-border-color) 50%,
44516
+ white);
44517
+ --button-background-color-disabled: color-mix(in srgb,
44518
+ var(--button-background-color) 40%,
44519
+ white);
44520
+ --button-border-color-disabled: color-mix(in srgb,
44521
+ var(--button-border-color) 40%,
44522
+ white);
44523
+ --button-color-disabled: color-mix(in srgb,
44524
+ var(--button-color) 60%,
44525
+ transparent);
44371
44526
  }
44372
44527
  }
44373
44528
  `;
@@ -45310,7 +45465,7 @@ installImportMetaCssBuild(import.meta);const css$M = /* css */`@layer navi {
45310
45465
  --outline-color: var(--navi-focus-outline-color);
45311
45466
  --margin: 3px 3px 3px 4px;
45312
45467
  --font-size: var(--navi-control-font-size);
45313
- --font-family: var(--navi-control-font-family);
45468
+ --font-family: var(--navi-control-font-family, inherit);
45314
45469
  --width: round(1em, 1px);
45315
45470
  --height: round(1em, 1px);
45316
45471
  --loader-color: var(--navi-loader-color);
@@ -46016,7 +46171,7 @@ installImportMetaCssBuild(import.meta);const css$K = /* css */`@layer navi {
46016
46171
  --border-color-checked: var(--accent-color);
46017
46172
  --cursor: pointer;
46018
46173
  --font-size: var(--navi-control-font-size);
46019
- --font-family: var(--navi-control-font-family);
46174
+ --font-family: var(--navi-control-font-family, inherit);
46020
46175
  --border-color-hover: color-mix(in srgb, var(--border-color) 60%, black);
46021
46176
  --border-color-hover-checked: color-mix(in srgb,
46022
46177
  var(--border-color-checked) 80%,
@@ -46463,7 +46618,7 @@ installImportMetaCssBuild(import.meta);const css$J = /* css */`@layer navi {
46463
46618
  --thumb-border-radius: 100%;
46464
46619
  --thumb-cursor: pointer;
46465
46620
  --font-size: var(--navi-control-font-size);
46466
- --font-family: var(--navi-control-font-family);
46621
+ --font-family: var(--navi-control-font-family, inherit);
46467
46622
  --loader-color: var(--navi-loader-color);
46468
46623
  --accent-color: var(--navi-control-accent-color);
46469
46624
  --color-mix-light: black;
@@ -46811,7 +46966,7 @@ const inputCss = /* css */`@layer navi {
46811
46966
  --outline-offset: calc(-.5 * var(--outline-width));
46812
46967
  --outline-color: var(--navi-focus-outline-color);
46813
46968
  --font-size: var(--navi-control-font-size);
46814
- --font-family: var(--navi-control-font-family);
46969
+ --font-family: var(--navi-control-font-family, inherit);
46815
46970
  --loader-color: var(--navi-loader-color);
46816
46971
  --border-color: var(--navi-control-border-color);
46817
46972
  --background-color: var(--navi-surface-color);
@@ -47026,13 +47181,24 @@ const inputCss = /* css */`@layer navi {
47026
47181
  }
47027
47182
 
47028
47183
  &[data-variant="text"] {
47029
- --x-background-color: transparent;
47030
- --x-border-color: transparent;
47184
+ --background-color: transparent;
47185
+ --background-color-hover: var(--background-color);
47186
+ --background-color-focus: var(--background-color);
47187
+ --background-color-readonly: var(--background-color);
47188
+ --background-color-disabled: var(--background-color);
47189
+ --border-color: transparent;
47190
+ --border-color-hover: var(--border-color);
47191
+ --border-color-readonly: var(--border-color);
47192
+ --border-color-disabled: var(--border-color);
47031
47193
  cursor: inherit;
47032
47194
  }
47033
47195
 
47034
47196
  &[data-variant="underline"] {
47035
- --x-background-color: transparent;
47197
+ --background-color: transparent;
47198
+ --background-color-hover: var(--background-color);
47199
+ --background-color-focus: var(--background-color);
47200
+ --background-color-readonly: var(--background-color);
47201
+ --background-color-disabled: var(--background-color);
47036
47202
  border: none;
47037
47203
  border-radius: 0;
47038
47204
  padding-left: 0;
@@ -47054,12 +47220,7 @@ const inputCss = /* css */`@layer navi {
47054
47220
  position: absolute;
47055
47221
  }
47056
47222
 
47057
- &[data-hover] {
47058
- --x-background-color: transparent;
47059
- }
47060
-
47061
47223
  &[data-focus-visible] {
47062
- --x-background-color: transparent;
47063
47224
  outline-style: none;
47064
47225
 
47065
47226
  & .navi_input_underline {
@@ -47067,10 +47228,6 @@ const inputCss = /* css */`@layer navi {
47067
47228
  height: 2px;
47068
47229
  }
47069
47230
  }
47070
-
47071
- &[data-readonly], &[data-disabled] {
47072
- --x-background-color: transparent;
47073
- }
47074
47231
  }
47075
47232
  }
47076
47233
  `;
@@ -53902,7 +54059,7 @@ const createOpenController = (
53902
54059
  // previous subject first.
53903
54060
  onOpen: null,
53904
54061
  // The counterpart, set only when the popup was told to throw its content
53905
- // away on close (`unmountWhenClosed`). Called from performClose above.
54062
+ // away on close (`mount="while-opened"`). Called from performClose above.
53906
54063
  unmountContent: null,
53907
54064
  // Told whenever `opened` actually changes, whatever asked for it — an
53908
54065
  // interaction, a command, a prop — with the event that asked. What lets a
@@ -54374,111 +54531,6 @@ const getAvailableWidth = (layer, element) => {
54374
54531
  return visualViewportWidthSignal.peek();
54375
54532
  };
54376
54533
 
54377
- /**
54378
- * Runs `fn` and commits whatever it re-renders before returning, instead of
54379
- * letting Preact batch it into the next microtask. Layout effects of what gets
54380
- * mounted run inside the call too, exactly as they would on any other commit.
54381
- *
54382
- * For the caller that has to read the DOM it just asked for — measuring an
54383
- * element whose content it mounts in the same breath — and cannot wait a tick
54384
- * to do it, because what comes after is a browser event still in flight
54385
- * (preventDefault, focus placement) that no longer accepts being answered late.
54386
- *
54387
- * `options.debounceRendering` is Preact's own hook for deciding *when* the
54388
- * render queue drains; swapping it for "right now" for the duration of the call
54389
- * is exactly how preact/compat implements React's flushSync. Reserve it for the
54390
- * case above: rendering synchronously in the middle of an event gives up the
54391
- * batching that makes several state changes one commit.
54392
- */
54393
- const flushSyncRendering = (fn) => {
54394
- const debounceRenderingPrevious = options.debounceRendering;
54395
- options.debounceRendering = (drainRenderQueue) => {
54396
- drainRenderQueue();
54397
- };
54398
- try {
54399
- fn();
54400
- } finally {
54401
- options.debounceRendering = debounceRenderingPrevious;
54402
- }
54403
- };
54404
-
54405
- /**
54406
- * When a popup builds what it holds, and when it throws it away.
54407
- *
54408
- * A closed popup shows nothing, focuses nothing, and answers nothing: what it
54409
- * holds is out of reach until it opens. Building that content at mount time
54410
- * means a page carrying a handful of closed popups pays, on the very render
54411
- * that decides how fast it appears, for content nobody has asked for — and
54412
- * pays again on every subsequent measurement, since each of those nodes makes
54413
- * the document the rest of the page queries bigger.
54414
- *
54415
- * So the content is built when the popup first opens, and stays built from
54416
- * then on: closing is not throwing away, and a reopened popup finds its scroll
54417
- * position, its half-typed form and its list state where it left them.
54418
- *
54419
- * It is built synchronously, from inside `openController.open()` and before
54420
- * `openEffect` runs (see open_controller.js), so the popup still measures real
54421
- * content when it positions and animates itself, and so anything inside it
54422
- * still observes the opening the way it always did — mounted while the popup
54423
- * reads as closed, told it opened right after (see
54424
- * use_displayed_layout_effect.js).
54425
- *
54426
- * `mountWhenClosed` is for content something else depends on before any of
54427
- * this: a value the popup's owner reads off its own children, fields a form
54428
- * around it collects on submit, a size measured from outside.
54429
- *
54430
- * `unmountWhenClosed` is the opposite end: content that must be rebuilt from
54431
- * scratch every time, because what it shows is read once at build time and can
54432
- * change while the popup is closed — an uncontrolled field seeded from a
54433
- * `defaultValue`, a form whose fresh state is its initial state.
54434
- */
54435
-
54436
-
54437
- const usePopupContentMount = (
54438
- openController,
54439
- ref,
54440
- { children, mountWhenClosed, unmountWhenClosed },
54441
- ) => {
54442
- const [contentMounted, setContentMounted] = useState(
54443
- () => Boolean(mountWhenClosed) || openController.opened,
54444
- );
54445
- openController.mountContent = contentMounted
54446
- ? null
54447
- : () => {
54448
- flushSyncRendering(() => {
54449
- setContentMounted(true);
54450
- });
54451
- };
54452
- openController.unmountContent =
54453
- unmountWhenClosed && !mountWhenClosed
54454
- ? () => {
54455
- const element = ref?.current;
54456
- if (!element) {
54457
- setContentMounted(false);
54458
- return;
54459
- }
54460
- // The popup is still on screen while it plays its exit transition;
54461
- // emptying it right away would show that transition running on a
54462
- // blank surface.
54463
- whenTransitionSettles(element, () => {
54464
- if (openController.opened) {
54465
- // reopened while it was leaving — the content it holds is the
54466
- // one that open just asked for
54467
- return;
54468
- }
54469
- setContentMounted(false);
54470
- });
54471
- }
54472
- : null;
54473
- useLayoutEffect(() => {
54474
- if (mountWhenClosed) {
54475
- setContentMounted(true);
54476
- }
54477
- }, [mountWhenClosed]);
54478
-
54479
- return contentMounted ? children : null;
54480
- };
54481
-
54482
54534
  /**
54483
54535
  * Entry/exit animation CSS shared by Popover and Dialog.
54484
54536
  *
@@ -55669,16 +55721,15 @@ const css$E = /* css */`
55669
55721
  * open controller (see `open_controller.js`) for a caller that wants to
55670
55722
  * drive open/close itself instead of `open`/`defaultOpen`/`onClose` (used
55671
55723
  * by `picker_custom.jsx`).
55672
- * @param {boolean} [props.mountWhenClosed] - Builds `children` right away
55673
- * instead of waiting for the first open (see popup_content_mount.js). For
55674
- * content something depends on while the popup is still closed: a value read
55675
- * off it, fields a surrounding form collects on submit, a size measured from
55676
- * outside.
55677
- * @param {boolean} [props.unmountWhenClosed] - Throws `children` away once the
55678
- * popup has finished closing (see popup_content_mount.js). For content whose
55679
- * fresh state is its initial state: an uncontrolled field seeded from a
55680
- * `defaultValue` that changed while the popup was closed. Ignored when
55681
- * `mountWhenClosed` is set.
55724
+ * @param {"always"|"from-first-open"|"while-opened"} [props.mount] - When
55725
+ * `children` are built and thrown away (see popup_content_mount.js).
55726
+ * `"from-first-open"` (the default) builds them on the first open and keeps
55727
+ * them afterwards. `"always"` builds them right away, for content something
55728
+ * depends on while the popup is still closed: a value read off it, fields a
55729
+ * surrounding form collects on submit, a size measured from outside.
55730
+ * `"while-opened"` throws them away once the popup has finished closing, for
55731
+ * content whose fresh state is its initial state: an uncontrolled field
55732
+ * seeded from a `defaultValue` that changed while the popup was closed.
55682
55733
  * @param {import("ignore:preact").ComponentChildren} props.children
55683
55734
  */
55684
55735
  const Dialog = props => {
@@ -55915,8 +55966,7 @@ const useDialogProps = props => {
55915
55966
  // openController.onOpen below).
55916
55967
  onOpen,
55917
55968
  children: childrenProp,
55918
- mountWhenClosed,
55919
- unmountWhenClosed,
55969
+ mount,
55920
55970
  ...rest
55921
55971
  } = props;
55922
55972
  // Assigned on every render, like openEffect below, so it always closes over
@@ -55925,8 +55975,7 @@ const useDialogProps = props => {
55925
55975
  openController.onOpen = onOpen || null;
55926
55976
  const children = usePopupContentMount(openController, props.ref, {
55927
55977
  children: childrenProp,
55928
- mountWhenClosed,
55929
- unmountWhenClosed
55978
+ mount
55930
55979
  });
55931
55980
  const isModal = layer === "top";
55932
55981
  const ref = props.ref;
@@ -57139,16 +57188,15 @@ const css$D = /* css */`
57139
57188
  * open controller (see `open_controller.js`) for a caller that wants to
57140
57189
  * drive open/close itself instead of `open`/`defaultOpen`/`onClose` (used
57141
57190
  * by `picker_custom.jsx`/`side_panel.jsx`).
57142
- * @param {boolean} [props.mountWhenClosed] - Builds `children` right away
57143
- * instead of waiting for the first open (see popup_content_mount.js). For
57144
- * content something depends on while the popup is still closed: a value read
57145
- * off it, fields a surrounding form collects on submit, a size measured from
57146
- * outside.
57147
- * @param {boolean} [props.unmountWhenClosed] - Throws `children` away once the
57148
- * popup has finished closing (see popup_content_mount.js). For content whose
57149
- * fresh state is its initial state: an uncontrolled field seeded from a
57150
- * `defaultValue` that changed while the popup was closed. Ignored when
57151
- * `mountWhenClosed` is set.
57191
+ * @param {"always"|"from-first-open"|"while-opened"} [props.mount] - When
57192
+ * `children` are built and thrown away (see popup_content_mount.js).
57193
+ * `"from-first-open"` (the default) builds them on the first open and keeps
57194
+ * them afterwards. `"always"` builds them right away, for content something
57195
+ * depends on while the popup is still closed: a value read off it, fields a
57196
+ * surrounding form collects on submit, a size measured from outside.
57197
+ * `"while-opened"` throws them away once the popup has finished closing, for
57198
+ * content whose fresh state is its initial state: an uncontrolled field
57199
+ * seeded from a `defaultValue` that changed while the popup was closed.
57152
57200
  * @param {import("ignore:preact").ComponentChildren} props.children
57153
57201
  */
57154
57202
  const Popover = props => {
@@ -57363,8 +57411,7 @@ const usePopoverProps = props => {
57363
57411
  // openController.onOpen below).
57364
57412
  onOpen,
57365
57413
  children: childrenProp,
57366
- mountWhenClosed,
57367
- unmountWhenClosed,
57414
+ mount,
57368
57415
  ...rest
57369
57416
  } = props;
57370
57417
  // Assigned on every render, like openEffect below, so it always closes over
@@ -57373,8 +57420,7 @@ const usePopoverProps = props => {
57373
57420
  openController.onOpen = onOpen || null;
57374
57421
  const children = usePopupContentMount(openController, props.ref, {
57375
57422
  children: childrenProp,
57376
- mountWhenClosed,
57377
- unmountWhenClosed
57423
+ mount
57378
57424
  });
57379
57425
  const isTopLayer = layer === "top";
57380
57426
  const ref = props.ref;
@@ -58313,16 +58359,15 @@ const css$C = /* css */`@layer navi {
58313
58359
  * @param {string} [props.className] - Merged with the shared
58314
58360
  * `"navi_popup"` class (see this file's own CSS) rather than replacing
58315
58361
  * it.
58316
- * @param {boolean} [props.mountWhenClosed] - Builds `children` right away
58317
- * instead of waiting for the first open (see popup_content_mount.js). For
58318
- * content something depends on while the popup is still closed: a value read
58319
- * off it, fields a surrounding form collects on submit, a size measured from
58320
- * outside.
58321
- * @param {boolean} [props.unmountWhenClosed] - Throws `children` away once the
58322
- * popup has finished closing (see popup_content_mount.js). For content whose
58323
- * fresh state is its initial state: an uncontrolled field seeded from a
58324
- * `defaultValue` that changed while the popup was closed. Ignored when
58325
- * `mountWhenClosed` is set.
58362
+ * @param {"always"|"from-first-open"|"while-opened"} [props.mount] - When
58363
+ * `children` are built and thrown away (see popup_content_mount.js).
58364
+ * `"from-first-open"` (the default) builds them on the first open and keeps
58365
+ * them afterwards. `"always"` builds them right away, for content something
58366
+ * depends on while the popup is still closed: a value read off it, fields a
58367
+ * surrounding form collects on submit, a size measured from outside.
58368
+ * `"while-opened"` throws them away once the popup has finished closing, for
58369
+ * content whose fresh state is its initial state: an uncontrolled field
58370
+ * seeded from a `defaultValue` that changed while the popup was closed.
58326
58371
  * @param {import("ignore:preact").ComponentChildren} props.children
58327
58372
  */
58328
58373
  const Popup = props => {
@@ -58852,8 +58897,7 @@ const PickerCustom = props => {
58852
58897
  // and pushes it down instead, leaving the popup free to build its
58853
58898
  // content only when it is first opened (see popup_content_mount.js).
58854
58899
  // A caller who knows better says so with the popup's own props.
58855
- mountWhenClosed: props.mountWhenClosed ?? !isControlValueGivenByProps(props),
58856
- unmountWhenClosed: props.unmountWhenClosed,
58900
+ mount: props.mount ?? (isControlValueGivenByProps(props) ? MOUNT_DEFAULT : "always"),
58857
58901
  // Not on pickerProps (the trigger): commands.js's own
58858
58902
  // resolveClosestExpandable() does `el.closest("[aria-expanded]")` to
58859
58903
  // find where to dispatch navi_request_open/navi_request_close — and
@@ -59139,8 +59183,7 @@ const PickerContentInsidePopup = props => {
59139
59183
  ...rest,
59140
59184
  // On popupProps already (see the picker's popup assembly); they mean
59141
59185
  // nothing to the picker element.
59142
- mountWhenClosed: undefined,
59143
- unmountWhenClosed: undefined,
59186
+ mount: undefined,
59144
59187
  onFocusOut: e => {
59145
59188
  if (!isPopover || !closeOnFocusOut) {
59146
59189
  return;
@@ -59222,7 +59265,7 @@ const PICKER_CALLOUT_CONTENT_TOKEN = createOpenToken();
59222
59265
  * The content is rendered through a portal into an element this component
59223
59266
  * owns, handed to the callout as its message (a Node, appended as-is). It is
59224
59267
  * rendered whether the callout is open or not, so what the content holds
59225
- * survives a close, the way a popup's `mountWhenClosed` keeps it. The element
59268
+ * survives a close, the way a popup's `mount="always"` keeps it. The element
59226
59269
  * carries data-picker-content: the callout is appended inside the picker root,
59227
59270
  * and a press in there must read as inside the popup, not on the trigger.
59228
59271
  */
@@ -59393,7 +59436,12 @@ const PickerConfirmResolver = props => {
59393
59436
  return jsx(Next, {
59394
59437
  ...props,
59395
59438
  type: "navi_js",
59396
- allowNameless: true,
59439
+ allowNameless: true
59440
+ // No chevron, no clear cross, whatever variant the trigger is drawn in:
59441
+ // both announce a value, and a question holds none.
59442
+ ,
59443
+
59444
+ picksNothing: true,
59397
59445
  variant: variant,
59398
59446
  mode: mode,
59399
59447
  focusCapture: focusCapture,
@@ -59401,10 +59449,10 @@ const PickerConfirmResolver = props => {
59401
59449
  onConfirm: onConfirm
59402
59450
  // A question holds no value to read before it is asked: the popup is
59403
59451
  // built on the first open, like that of a picker told its value (see
59404
- // mountWhenClosed in picker_custom.jsx).
59452
+ // the `mount` resolution in picker_custom.jsx).
59405
59453
  ,
59406
59454
 
59407
- mountWhenClosed: false,
59455
+ mount: MOUNT_DEFAULT,
59408
59456
  message: undefined,
59409
59457
  confirmLabel: undefined,
59410
59458
  cancelLabel: undefined,
@@ -60262,7 +60310,7 @@ installImportMetaCssBuild(import.meta);const css$y = /* css */`@layer navi {
60262
60310
  --x-list-item-cursor: default;
60263
60311
  --x-list-item-border-color: var(--list-item-border-color);
60264
60312
  font-size: var(--navi-control-font-size);
60265
- font-family: var(--navi-control-font-family);
60313
+ font-family: var(--navi-control-font-family, inherit);
60266
60314
  line-height: var(--navi-control-line-height);
60267
60315
  position: relative;
60268
60316
  }
@@ -66705,7 +66753,7 @@ installImportMetaCssBuild(import.meta);const css$t = /* css */`@layer navi {
66705
66753
  --picker-padding-x-default: var(--navi-picker-padding-x-default);
66706
66754
  --picker-padding-y-default: var(--navi-picker-padding-y-default);
66707
66755
  --picker-font-size: var(--navi-control-font-size);
66708
- --picker-font-family: var(--navi-control-font-family);
66756
+ --picker-font-family: var(--navi-control-font-family, inherit);
66709
66757
  --picker-loader-color: var(--navi-loader-color);
66710
66758
  --picker-border-color: var(--navi-control-border-color);
66711
66759
  --picker-background-color: white;
@@ -66805,6 +66853,7 @@ installImportMetaCssBuild(import.meta);const css$t = /* css */`@layer navi {
66805
66853
  padding-bottom: var(--x-picker-padding-bottom);
66806
66854
  padding-left: var(--x-picker-padding-left);
66807
66855
  justify-content: inherit;
66856
+ text-align: var(--picker-align-x, var(--picker-text-align-default));
66808
66857
  pointer-events: none;
66809
66858
  user-select: none;
66810
66859
  flex-grow: 1;
@@ -66963,7 +67012,7 @@ installImportMetaCssBuild(import.meta);const css$t = /* css */`@layer navi {
66963
67012
  --picker-background-color-hover: var(--picker-background-color);
66964
67013
  --picker-background-color-readonly: var(--picker-background-color);
66965
67014
  --picker-background-color-disabled: var(--picker-background-color);
66966
- --x-picker-icon-color: currentColor;
67015
+ --picker-icon-color: currentColor;
66967
67016
 
66968
67017
  & .navi_picker_value {
66969
67018
  flex-grow: 0;
@@ -66996,7 +67045,7 @@ installImportMetaCssBuild(import.meta);const css$t = /* css */`@layer navi {
66996
67045
  --picker-background-color-hover: var(--picker-background-color);
66997
67046
  --picker-background-color-readonly: var(--picker-background-color);
66998
67047
  --picker-background-color-disabled: var(--picker-background-color);
66999
- --x-picker-icon-color: currentColor;
67048
+ --picker-icon-color: currentColor;
67000
67049
 
67001
67050
  & .navi_picker_box {
67002
67051
  z-index: -1;
@@ -67018,7 +67067,7 @@ installImportMetaCssBuild(import.meta);const css$t = /* css */`@layer navi {
67018
67067
  --picker-background-color-hover: var(--picker-background-color);
67019
67068
  --picker-background-color-readonly: var(--picker-background-color);
67020
67069
  --picker-background-color-disabled: var(--picker-background-color);
67021
- --x-picker-icon-color: currentColor;
67070
+ --picker-icon-color: currentColor;
67022
67071
  font-size: inherit;
67023
67072
  font-family: inherit;
67024
67073
  line-height: inherit;
@@ -67043,7 +67092,7 @@ installImportMetaCssBuild(import.meta);const css$t = /* css */`@layer navi {
67043
67092
  --picker-border-color-disabled: var(--picker-border-color-readonly);
67044
67093
  --picker-background-color-disabled: var(--picker-background-color-readonly);
67045
67094
  --picker-color-disabled: var(--picker-color-readonly);
67046
- text-align: center;
67095
+ --picker-text-align-default: center;
67047
67096
  }
67048
67097
 
67049
67098
  &[data-variant="text"] {
@@ -67109,6 +67158,11 @@ const PickerButton = props => {
67109
67158
  // not come back. The cross is then a confirm picker (see
67110
67159
  // picker_confirm.jsx), and the clear only goes out on yes.
67111
67160
  clearConfirm,
67161
+ // Nothing is picked here: the popup asks a question rather than holding an
67162
+ // answer, so the trigger draws a label and never a value. Set by the
67163
+ // confirm resolver (see picker_confirm.jsx), which is the picker that is
67164
+ // one — a caller whose popup is a menu of actions says it for themselves.
67165
+ picksNothing,
67112
67166
  readOnly,
67113
67167
  error
67114
67168
  } = props;
@@ -67122,17 +67176,19 @@ const PickerButton = props => {
67122
67176
  const isSingleLine = maxLines === 1;
67123
67177
  // Same rule as the root: phrasing content inside a sentence.
67124
67178
  const ContentTag = variant === "text" ? "span" : "div";
67125
- // Which variants get the right slot — the chevron saying "this opens", and
67126
- // the cross replacing it once there is something to clear.
67127
- // Not the ones that draw no value beside it: an icon picker IS its icon, a
67128
- // headless one draws nothing, a button says what it opens with its label, a
67179
+ // Who gets the right slot — the chevron saying "this opens", and the cross
67180
+ // replacing it once there is something to clear. Both are about a value, so
67181
+ // the slot follows the value and not the drawing: `picksNothing` has none to
67182
+ // announce and none to take back, whatever variant it is drawn in.
67183
+ // Then the variants that draw no value beside it: an icon picker IS its icon,
67184
+ // a headless one draws nothing, a button says what it opens with its label, a
67129
67185
  // word in a sentence has no room for furniture. Nor a picker rendering the
67130
67186
  // browser's own control ("default").
67131
67187
  // Nor a bare one: the picker is that drawing's box to the pixel, so anything
67132
67188
  // navi adds beside it either grows the box or covers what the caller drew.
67133
67189
  // The pieces are the caller's to place there instead — a <Picker.Clear /> in
67134
67190
  // their own layout (see warnOnClearableWithoutSlot).
67135
- const hasRightSlot = variant !== "icon" && variant !== "headless" && variant !== "button" && variant !== "text" && variant !== "bare" && ui !== "default";
67191
+ const hasRightSlot = !picksNothing && variant !== "icon" && variant !== "headless" && variant !== "button" && variant !== "text" && variant !== "bare" && ui !== "default";
67136
67192
  const inputRef = useRef(null);
67137
67193
  const [pickerRemainingProps, inputProps, facadeChildrenProps] = useControlFacadeProps({
67138
67194
  ...props,
@@ -67211,6 +67267,7 @@ const PickerButton = props => {
67211
67267
  rightSlotIconSize: undefined,
67212
67268
  rightSlot: undefined,
67213
67269
  clearConfirm: undefined,
67270
+ picksNothing: undefined,
67214
67271
  openWhileReadOnly: undefined,
67215
67272
  ui: undefined,
67216
67273
  maxLines: undefined,
@@ -67763,7 +67820,7 @@ const css$s = /* css */`@layer navi {
67763
67820
  --x-picker-spin-padding-bottom: var(--picker-spin-padding-bottom, var(--picker-spin-padding-y, var(--picker-spin-padding, var(--picker-spin-padding-y-default))));
67764
67821
  --x-picker-spin-padding-left: var(--picker-spin-padding-left, var(--picker-spin-padding-x, var(--picker-spin-padding, var(--picker-spin-padding-x-default))));
67765
67822
  font-size: var(--navi-control-font-size);
67766
- font-family: var(--navi-control-font-family);
67823
+ font-family: var(--navi-control-font-family, inherit);
67767
67824
  border: var(--navi-control-border-width) solid
67768
67825
  var(--navi-control-border-color);
67769
67826
  border-top-left-radius: var(--x-corner-top-left-radius, var(--navi-control-border-radius));
@@ -67913,7 +67970,7 @@ const css$s = /* css */`@layer navi {
67913
67970
 
67914
67971
  .navi_spin_group {
67915
67972
  font-size: var(--navi-control-font-size);
67916
- font-family: var(--navi-control-font-family);
67973
+ font-family: var(--navi-control-font-family, inherit);
67917
67974
  border: var(--navi-control-border-width) solid
67918
67975
  var(--navi-control-border-color);
67919
67976
  border-top-left-radius: var(--x-corner-top-left-radius, var(--navi-control-border-radius));
@@ -70811,7 +70868,7 @@ const css$m = /* css */`.navi_wheel_container {
70811
70868
  transparent);
70812
70869
  color: var(--wheel-color);
70813
70870
  font-size: var(--navi-control-font-size);
70814
- font-family: var(--navi-control-font-family);
70871
+ font-family: var(--navi-control-font-family, inherit);
70815
70872
  border: var(--navi-control-border-width) solid
70816
70873
  var(--navi-control-border-color);
70817
70874
  border-radius: var(--navi-control-border-radius);
@@ -71101,7 +71158,7 @@ const css$m = /* css */`.navi_wheel_container {
71101
71158
  color: var(--wheel-color, light-dark(#111, #eee));
71102
71159
  font-weight: 600;
71103
71160
  font-size: var(--navi-control-font-size);
71104
- font-family: var(--navi-control-font-family);
71161
+ font-family: var(--navi-control-font-family, inherit);
71105
71162
  white-space: nowrap;
71106
71163
  user-select: none;
71107
71164
  justify-content: center;
@@ -75862,7 +75919,6 @@ const css$g = /* css */`.navi_table_root {
75862
75919
 
75863
75920
  .navi_table {
75864
75921
  --editing-border-color: #a8c7fa;
75865
- font-family: Arial;
75866
75922
  font-size: 16px;
75867
75923
  }
75868
75924