@jsenv/navi 0.29.94 → 0.29.96

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.
@@ -38,7 +38,7 @@ installImportMetaCssBuild(import.meta);/**
38
38
  * any of these, and a number is the last resort, not the first tool.
39
39
  */
40
40
 
41
- const css$13 = /* css */`
41
+ const css$14 = /* css */`
42
42
  @layer navi {
43
43
  :root {
44
44
  /* A control that overlaps its neighbours (the members of a Group share
@@ -92,7 +92,7 @@ const css$13 = /* css */`
92
92
  }
93
93
  }
94
94
  `;
95
- import.meta.css = [css$13, "@jsenv/navi/src/navi_z_indexes.js"];
95
+ import.meta.css = [css$14, "@jsenv/navi/src/navi_z_indexes.js"];
96
96
 
97
97
  const addIntoArray = (array, ...valuesToAdd) => {
98
98
  if (valuesToAdd.length === 1) {
@@ -361,7 +361,7 @@ installImportMetaCssBuild(import.meta);/**
361
361
  * the very first render and the browser does everything on its own.
362
362
  */
363
363
  const URL_TARGET_ATTRIBUTE = "data-url-target";
364
- const css$12 = /* css */`
364
+ const css$13 = /* css */`
365
365
  @layer navi {
366
366
  [${URL_TARGET_ATTRIBUTE}] {
367
367
  animation: navi_url_target var(--navi-url-target-duration, 2000ms)
@@ -379,7 +379,7 @@ const css$12 = /* css */`
379
379
  }
380
380
  }
381
381
  `;
382
- import.meta.css = [css$12, "@jsenv/navi/src/nav/url_target/url_target.js"];
382
+ import.meta.css = [css$13, "@jsenv/navi/src/nav/url_target/url_target.js"];
383
383
  let urlTargetOptions = {
384
384
  block: "start",
385
385
  behavior: "instant",
@@ -6403,7 +6403,7 @@ installImportMetaCssBuild(import.meta);/**
6403
6403
  * - Arrow automatically shows when pointing at a valid anchor element
6404
6404
  * - Centers in viewport when no anchor element provided or anchor is too big
6405
6405
  */
6406
- const css$11 = /* css */`
6406
+ const css$12 = /* css */`
6407
6407
  @layer navi {
6408
6408
  .navi_callout {
6409
6409
  /* A callout is parented to what it explains, so it inherits from it — and
@@ -6646,7 +6646,7 @@ const openCallout = (message, {
6646
6646
  skipFocus = false,
6647
6647
  debug = () => {}
6648
6648
  } = {}) => {
6649
- import.meta.css = [css$11, "@jsenv/navi/src/control/rules/callout/callout.js"];
6649
+ import.meta.css = [css$12, "@jsenv/navi/src/control/rules/callout/callout.js"];
6650
6650
  if (debug === true) {
6651
6651
  debug = (e, ...args) => console.debug(`"${e.type}" -> `, ...args);
6652
6652
  }
@@ -18873,7 +18873,7 @@ const setupNetworkMonitoring = () => {
18873
18873
  };
18874
18874
  setupNetworkMonitoring();
18875
18875
 
18876
- installImportMetaCssBuild(import.meta);const css$10 = /* css */`
18876
+ installImportMetaCssBuild(import.meta);const css$11 = /* css */`
18877
18877
  .navi_loading_indicator_fluid_container {
18878
18878
  position: relative;
18879
18879
  display: flex;
@@ -18905,7 +18905,7 @@ const LoadingIndicatorFluid = ({
18905
18905
  visuallyHidden,
18906
18906
  ...rest
18907
18907
  }) => {
18908
- import.meta.css = [css$10, "@jsenv/navi/src/graphic/loading/loading_indicator_fluid.jsx"];
18908
+ import.meta.css = [css$11, "@jsenv/navi/src/graphic/loading/loading_indicator_fluid.jsx"];
18909
18909
  const ref = useRef(null);
18910
18910
  // The container dimensions can be deduced from the ref itself as the indicator is absolute inset 0
18911
18911
  const [containerWidth, setContainerWidth] = useState(0);
@@ -19110,7 +19110,7 @@ const LoadingRectangleSvg = ({
19110
19110
  });
19111
19111
  };
19112
19112
 
19113
- installImportMetaCssBuild(import.meta);const css$$ = /* css */`
19113
+ installImportMetaCssBuild(import.meta);const css$10 = /* css */`
19114
19114
  .navi_loading_outline_wrapper {
19115
19115
  position: absolute;
19116
19116
  /* Controls place the outline slightly outside their box, right on top of
@@ -19147,7 +19147,7 @@ installImportMetaCssBuild(import.meta);const css$$ = /* css */`
19147
19147
  }
19148
19148
  `;
19149
19149
  const LoadingOutline = props => {
19150
- import.meta.css = [css$$, "@jsenv/navi/src/graphic/loading/loading_outline.jsx"];
19150
+ import.meta.css = [css$10, "@jsenv/navi/src/graphic/loading/loading_outline.jsx"];
19151
19151
  if (props.containerRef) {
19152
19152
  const container = props.containerRef.current;
19153
19153
  if (!container) {
@@ -19437,7 +19437,7 @@ const selectByTextStrings = (element, range, startText, endText) => {
19437
19437
  };
19438
19438
 
19439
19439
  installImportMetaCssBuild(import.meta);// https://jsfiddle.net/v5xzJ/4/
19440
- const css$_ = /* css */`
19440
+ const css$$ = /* css */`
19441
19441
  @layer navi {
19442
19442
  .navi_text {
19443
19443
  &[data-skeleton] {
@@ -19958,7 +19958,7 @@ const TextShrinkWrap = props => {
19958
19958
  });
19959
19959
  };
19960
19960
  const TextUI = props => {
19961
- import.meta.css = [css$_, "@jsenv/navi/src/text/text.jsx"];
19961
+ import.meta.css = [css$$, "@jsenv/navi/src/text/text.jsx"];
19962
19962
  let {
19963
19963
  ref,
19964
19964
  spacing,
@@ -24761,6 +24761,30 @@ const useUIGroupStateController = (
24761
24761
  }
24762
24762
  };
24763
24763
 
24764
+ // What putting a value on a child comes down to, whichever way the group
24765
+ // worked out that value (one child at a time, or all of them at once).
24766
+ const placeOneChild = (childUIStateController, childNewState, e) => {
24767
+ if (
24768
+ childUIStateController.hasStateProp &&
24769
+ !childUIStateController.props.signal
24770
+ ) {
24771
+ // A child bound to a signal is placed like any other: bound is not
24772
+ // frozen, and the placement writes the signal, so both ends keep
24773
+ // saying the same thing. Only a child controlled by a `value` /
24774
+ // `checked` prop cannot be moved — its owner decides. Worth saying
24775
+ // out loud only when the two disagree: a child already showing what
24776
+ // the group would put there has lost nothing, and both being fed from
24777
+ // the same value is a legitimate way to write a group.
24778
+ if (
24779
+ !compareTwoJsValues(childNewState, childUIStateController.uiState)
24780
+ ) {
24781
+ warnChildAnswersForItself(s.controller);
24782
+ }
24783
+ return;
24784
+ }
24785
+ childUIStateController.setUIState(childNewState, e);
24786
+ };
24787
+
24764
24788
  const applyState = (newUIState, e, { internalBehavior = false } = {}) => {
24765
24789
  const { controller } = s;
24766
24790
  const currentUIState = controller.uiState;
@@ -24806,9 +24830,6 @@ const useUIGroupStateController = (
24806
24830
  ref,
24807
24831
  getPropFromState: (uiState) => uiState,
24808
24832
  distributeChildUIState: resolvedDistributeChildUIState,
24809
- // Where the group puts a value on ONE child: the only place that knows
24810
- // what each child gets, and the only one that sees a child it cannot
24811
- // place — see warnChildAnswersForItself.
24812
24833
  // One pass over every child, which is what a plural distribute needs:
24813
24834
  // it is asked once, sees the whole group, and answers for all of them.
24814
24835
  placeChildrenUIState: (groupUIState, e, { except } = {}) => {
@@ -24842,18 +24863,16 @@ const useUIGroupStateController = (
24842
24863
  // nothing about.
24843
24864
  continue;
24844
24865
  }
24845
- if (
24846
- childUIStateController.hasStateProp &&
24847
- !childUIStateController.props.signal
24848
- ) {
24849
- continue;
24850
- }
24851
- childUIStateController.setUIState(
24866
+ placeOneChild(
24867
+ childUIStateController,
24852
24868
  stateByChild.get(childUIStateController),
24853
24869
  e,
24854
24870
  );
24855
24871
  }
24856
24872
  },
24873
+ // Where the group puts a value on ONE child: the only place that knows
24874
+ // what each child gets, and the only one that sees a child it cannot
24875
+ // place — see warnChildAnswersForItself.
24857
24876
  placeChildUIState: (childUIStateController, groupUIState, e) => {
24858
24877
  if (!shouldPropagateStateToChild(childUIStateController)) {
24859
24878
  return;
@@ -24865,23 +24884,7 @@ const useUIGroupStateController = (
24865
24884
  if (childNewState === CANNOT_DERIVE) {
24866
24885
  return;
24867
24886
  }
24868
- if (
24869
- childUIStateController.hasStateProp &&
24870
- !childUIStateController.props.signal
24871
- ) {
24872
- // A child bound to a signal is placed like any other: bound is not
24873
- // frozen, and the placement writes the signal, so both ends keep
24874
- // saying the same thing. Only a child controlled by a `value` /
24875
- // `checked` prop cannot be moved — its owner decides. Worth saying
24876
- // out loud only when the two disagree: a child already showing what
24877
- // the group would put there has lost nothing, and both being fed
24878
- // from the same value is a legitimate way to write a group.
24879
- if (
24880
- !compareTwoJsValues(childNewState, childUIStateController.uiState)
24881
- ) ;
24882
- return;
24883
- }
24884
- childUIStateController.setUIState(childNewState, e);
24887
+ placeOneChild(childUIStateController, childNewState, e);
24885
24888
  },
24886
24889
  setUIState: (newUIState, e) => {
24887
24890
  if (
@@ -25596,6 +25599,11 @@ const dispatchSyntheticInput = (el, inputEvent, causeEvent) => {
25596
25599
  chainEvent(inputEvent, causeEvent);
25597
25600
  el.dispatchEvent(inputEvent);
25598
25601
  };
25602
+ const warnChildAnswersForItself = (groupController, child) => {
25603
+ {
25604
+ return;
25605
+ }
25606
+ };
25599
25607
 
25600
25608
  /**
25601
25609
  * What a control is worth when it holds nothing — nothing, in the shape of the
@@ -27388,7 +27396,7 @@ const getAssociatedLabels = element => {
27388
27396
  return Array.from(element.labels);
27389
27397
  };
27390
27398
 
27391
- installImportMetaCssBuild(import.meta);const css$Z = /* css */`
27399
+ installImportMetaCssBuild(import.meta);const css$_ = /* css */`
27392
27400
  @layer navi {
27393
27401
  .navi_button {
27394
27402
  --button-border-radius: var(--navi-control-border-radius);
@@ -27819,7 +27827,7 @@ installImportMetaCssBuild(import.meta);const css$Z = /* css */`
27819
27827
  }
27820
27828
  `;
27821
27829
  const ButtonUI = props => {
27822
- import.meta.css = [css$Z, "@jsenv/navi/src/control/input/button_ui.jsx"];
27830
+ import.meta.css = [css$_, "@jsenv/navi/src/control/input/button_ui.jsx"];
27823
27831
  const {
27824
27832
  ref,
27825
27833
  // href/link
@@ -29530,7 +29538,7 @@ installImportMetaCssBuild(import.meta);/**
29530
29538
  * reaches the real container.
29531
29539
  */
29532
29540
  let openLocalDialogCount = 0;
29533
- const css$Y = /* css */`
29541
+ const css$Z = /* css */`
29534
29542
  @layer navi {
29535
29543
  .navi_dialog {
29536
29544
  /* Min gap between the dialog and the edges of its container. Written
@@ -30114,7 +30122,7 @@ const css$Y = /* css */`
30114
30122
  * @param {import("ignore:preact").ComponentChildren} props.children
30115
30123
  */
30116
30124
  const Dialog = props => {
30117
- import.meta.css = [css$Y, "@jsenv/navi/src/layout/dialog.jsx"];
30125
+ import.meta.css = [css$Z, "@jsenv/navi/src/layout/dialog.jsx"];
30118
30126
  if (props.openController) {
30119
30127
  return jsx(ControlledDialog, {
30120
30128
  ...props
@@ -31106,7 +31114,7 @@ installImportMetaCssBuild(import.meta);/**
31106
31114
  * and applied.
31107
31115
  */
31108
31116
  let openLocalPopoverCount = 0;
31109
- const css$X = /* css */`
31117
+ const css$Y = /* css */`
31110
31118
  @layer navi {
31111
31119
  .navi_popover {
31112
31120
  /* soft: user-configurable preferred max-height. Kept as a *default*
@@ -31562,7 +31570,7 @@ const css$X = /* css */`
31562
31570
  * @param {import("ignore:preact").ComponentChildren} props.children
31563
31571
  */
31564
31572
  const Popover = props => {
31565
- import.meta.css = [css$X, "@jsenv/navi/src/layout/popover.jsx"];
31573
+ import.meta.css = [css$Y, "@jsenv/navi/src/layout/popover.jsx"];
31566
31574
  if (props.openController) {
31567
31575
  return jsx(ControlledPopover, {
31568
31576
  ...props
@@ -32590,7 +32598,7 @@ installImportMetaCssBuild(import.meta);/**
32590
32598
  * event, and a caller replacing the body entirely then has one protocol to
32591
32599
  * follow — `--navi-confirm` for yes, anything that closes for no.
32592
32600
  */
32593
- const css$W = /* css */`
32601
+ const css$X = /* css */`
32594
32602
  /* The width lives on the body rather than on the popup, so that custom
32595
32603
  content (which replaces this body entirely) sizes itself instead of
32596
32604
  inheriting a ceiling meant for a sentence-long question. */
@@ -32727,7 +32735,7 @@ const ConfirmPopup = ({
32727
32735
  onAnswer,
32728
32736
  onClosed
32729
32737
  }) => {
32730
- import.meta.css = [css$W, "@jsenv/navi/src/action/confirm_popup.jsx"];
32738
+ import.meta.css = [css$X, "@jsenv/navi/src/action/confirm_popup.jsx"];
32731
32739
  const {
32732
32740
  mode,
32733
32741
  confirmLabel,
@@ -32811,7 +32819,7 @@ const defaultBody = (message, {
32811
32819
  });
32812
32820
  };
32813
32821
 
32814
- installImportMetaCssBuild(import.meta);const css$V = /* css */`
32822
+ installImportMetaCssBuild(import.meta);const css$W = /* css */`
32815
32823
  .action_error {
32816
32824
  margin-top: 0;
32817
32825
  margin-bottom: 20px;
@@ -32836,7 +32844,7 @@ const ActionRenderer = ({
32836
32844
  children,
32837
32845
  disabled
32838
32846
  }) => {
32839
- import.meta.css = [css$V, "@jsenv/navi/src/action/action_renderer.jsx"];
32847
+ import.meta.css = [css$W, "@jsenv/navi/src/action/action_renderer.jsx"];
32840
32848
  if (action === undefined) {
32841
32849
  throw new Error("ActionRenderer requires an action to render, but none was provided.");
32842
32850
  }
@@ -38580,7 +38588,7 @@ const ROUTE_TRAVEL_ATTRIBUTE = "data-navi-route-travel";
38580
38588
  // the root pictures must NOT move (they carry the whole viewport, blank bands
38581
38589
  // included).
38582
38590
 
38583
- const css$U = /* css */`
38591
+ const css$V = /* css */`
38584
38592
  /* The marked region is a picture of its own for the length of a transition of
38585
38593
  OURS, and only then — the name is what makes the pages a picture the
38586
38594
  movement below can carry.
@@ -39009,7 +39017,7 @@ const RouteTransitionArea = ({
39009
39017
  children,
39010
39018
  ...rest
39011
39019
  }) => {
39012
- import.meta.css = [css$U, "@jsenv/navi/src/nav/route_transition.jsx"];
39020
+ import.meta.css = [css$V, "@jsenv/navi/src/nav/route_transition.jsx"];
39013
39021
  const props = {
39014
39022
  ...rest,
39015
39023
  [TRANSITION_AREA_ATTRIBUTE]: ""
@@ -39066,7 +39074,7 @@ const RouteTransitionArea = ({
39066
39074
  * @returns {() => void} remove this relation.
39067
39075
  */
39068
39076
  const defineRouteTransition = (from, to, transition) => {
39069
- import.meta.css = [css$U, "@jsenv/navi/src/nav/route_transition.jsx"];
39077
+ import.meta.css = [css$V, "@jsenv/navi/src/nav/route_transition.jsx"];
39070
39078
  const {
39071
39079
  type,
39072
39080
  duration
@@ -39102,7 +39110,7 @@ const defineRouteTransition = (from, to, transition) => {
39102
39110
  * @returns {() => void} remove this default.
39103
39111
  */
39104
39112
  const defineRouteDefaultTransition = transition => {
39105
- import.meta.css = [css$U, "@jsenv/navi/src/nav/route_transition.jsx"];
39113
+ import.meta.css = [css$V, "@jsenv/navi/src/nav/route_transition.jsx"];
39106
39114
  const value = normalizeTransition(transition);
39107
39115
  defaultTransition = value;
39108
39116
  return () => {
@@ -39703,7 +39711,7 @@ const DRAGGED_ATTRIBUTE = "data-navi-route-travel-dragged";
39703
39711
  const TURNED_ATTRIBUTE = "data-navi-route-travel-turned";
39704
39712
  // The name the box wears while it travels, and only then (see nameForTravel).
39705
39713
  const TRAVEL_NAME = "navi-route-travel";
39706
- const css$T = /* css */`
39714
+ const css$U = /* css */`
39707
39715
  /* The name that makes the page inside this box a picture of its own during a
39708
39716
  transition — rather than part of the one big picture the document takes, so
39709
39717
  the two pages can move past each other while everything else stays where it
@@ -40093,7 +40101,7 @@ const RouteTravel = ({
40093
40101
  children,
40094
40102
  ...rest
40095
40103
  }) => {
40096
- import.meta.css = [css$T, "@jsenv/navi/src/nav/route_travel.jsx"];
40104
+ import.meta.css = [css$U, "@jsenv/navi/src/nav/route_travel.jsx"];
40097
40105
  const elementRef = useRef();
40098
40106
  const gestureRef = useRef(null);
40099
40107
  // The travel in hand: the transition keeping the picture of the page being
@@ -42655,7 +42663,7 @@ const PhoneSvg = () => {
42655
42663
  };
42656
42664
 
42657
42665
  installImportMetaCssBuild(import.meta);// # TextAnchor — how it works
42658
- const css$S = /* css */`
42666
+ const css$T = /* css */`
42659
42667
  .navi_text_anchor {
42660
42668
  vertical-align: baseline;
42661
42669
  user-select: none;
@@ -42690,7 +42698,7 @@ const TextAnchor = ({
42690
42698
  textSize,
42691
42699
  lineLayout
42692
42700
  }) => {
42693
- import.meta.css = [css$S, "@jsenv/navi/src/text/text_anchor.jsx"];
42701
+ import.meta.css = [css$T, "@jsenv/navi/src/text/text_anchor.jsx"];
42694
42702
  const anchorRef = useRef();
42695
42703
 
42696
42704
  // Plain useLayoutEffect would also fire while an ancestor dialog/popover
@@ -42805,7 +42813,7 @@ const computeTopOffset = ({
42805
42813
  };
42806
42814
  const charTopCanvas = document.createElement("canvas");
42807
42815
 
42808
- installImportMetaCssBuild(import.meta);const css$R = /* css */`
42816
+ installImportMetaCssBuild(import.meta);const css$S = /* css */`
42809
42817
  @layer navi {
42810
42818
  /* Ensure data attributes from box.jsx can win to update display */
42811
42819
  .navi_icon {
@@ -42963,7 +42971,7 @@ const Icon = ({
42963
42971
  fillLine,
42964
42972
  ...props
42965
42973
  }) => {
42966
- import.meta.css = [css$R, "@jsenv/navi/src/text/icon.jsx"];
42974
+ import.meta.css = [css$S, "@jsenv/navi/src/text/icon.jsx"];
42967
42975
  const innerChildren = href ? jsx("svg", {
42968
42976
  width: "100%",
42969
42977
  height: "100%",
@@ -43125,7 +43133,7 @@ const useDimColorWhen = (elementRef, shouldDim) => {
43125
43133
  });
43126
43134
  };
43127
43135
 
43128
- installImportMetaCssBuild(import.meta);const css$Q = /* css */`
43136
+ installImportMetaCssBuild(import.meta);const css$R = /* css */`
43129
43137
  @layer navi {
43130
43138
  .navi_link {
43131
43139
  --link-border-radius: unset;
@@ -43587,7 +43595,7 @@ Object.assign(PSEUDO_CLASSES, {
43587
43595
  * @param {boolean} [props.readOnly]
43588
43596
  */
43589
43597
  const Link = props => {
43590
- import.meta.css = [css$Q, "@jsenv/navi/src/nav/link/link.jsx"];
43598
+ import.meta.css = [css$R, "@jsenv/navi/src/nav/link/link.jsx"];
43591
43599
  if (props.route) {
43592
43600
  return jsx(LinkWithRoute, {
43593
43601
  ...props
@@ -43910,7 +43918,7 @@ installImportMetaCssBuild(import.meta);/**
43910
43918
  * https://dribbble.com/search/tabs
43911
43919
  */
43912
43920
  let navCount = 0;
43913
- const css$P = /* css */`
43921
+ const css$Q = /* css */`
43914
43922
  @layer navi {
43915
43923
  .navi_nav {
43916
43924
  --nav-border: none;
@@ -44193,7 +44201,7 @@ const Nav = ({
44193
44201
  slideContainer,
44194
44202
  ...props
44195
44203
  }) => {
44196
- import.meta.css = [css$P, "@jsenv/navi/src/nav/link/nav.jsx"];
44204
+ import.meta.css = [css$Q, "@jsenv/navi/src/nav/link/nav.jsx"];
44197
44205
  const defaultRef = useRef();
44198
44206
  props.ref = props.ref || defaultRef;
44199
44207
  const navRef = props.ref;
@@ -44720,7 +44728,7 @@ installImportMetaCssBuild(import.meta);/**
44720
44728
  * Border width participates in layout (it is added to the tab and page
44721
44729
  * padding): a thick border grows the binder rather than eating into the text.
44722
44730
  */
44723
- const css$O = /* css */`
44731
+ const css$P = /* css */`
44724
44732
  @layer navi {
44725
44733
  .navi_binder {
44726
44734
  --binder-border-width: var(--navi-control-border-width);
@@ -45033,7 +45041,7 @@ const Binder = ({
45033
45041
  pagePadding,
45034
45042
  ...props
45035
45043
  }) => {
45036
- import.meta.css = [css$O, "@jsenv/navi/src/nav/binder/binder.jsx"];
45044
+ import.meta.css = [css$P, "@jsenv/navi/src/nav/binder/binder.jsx"];
45037
45045
  const items = toChildArray(children).map((child, index) => {
45038
45046
  const {
45039
45047
  value: itemValue,
@@ -45520,7 +45528,7 @@ installImportMetaCssBuild(import.meta);/**
45520
45528
  * added to the size asked for exactly like the notch inset is, so the
45521
45529
  * content still gets the size the prop names.
45522
45530
  */
45523
- const css$N = /* css */`
45531
+ const css$O = /* css */`
45524
45532
  @layer navi {
45525
45533
  :root {
45526
45534
  --navi-fixed-bar-width: 56px;
@@ -45668,7 +45676,7 @@ const FixedBar = ({
45668
45676
  border = true,
45669
45677
  ...props
45670
45678
  }) => {
45671
- import.meta.css = [css$N, "@jsenv/navi/src/layout/fixed_bar/fixed_bar.jsx"];
45679
+ import.meta.css = [css$O, "@jsenv/navi/src/layout/fixed_bar/fixed_bar.jsx"];
45672
45680
  const defaultRef = useRef();
45673
45681
  props.ref = props.ref || defaultRef;
45674
45682
  // Said with the width the border rule reads rather than with an attribute of
@@ -45762,7 +45770,7 @@ const FixedBar = ({
45762
45770
  // Subpixel layout rounds rectangles up on boxes that fit exactly.
45763
45771
  const OVERFLOW_TOLERANCE = 1;
45764
45772
 
45765
- const css$M = /* css */ `
45773
+ const css$N = /* css */ `
45766
45774
  [data-navi-overflow-x] {
45767
45775
  outline: 2px dashed #e74c3c;
45768
45776
  outline-offset: -2px;
@@ -45786,7 +45794,7 @@ const detectHorizontalOverflow = ({
45786
45794
  let styleEl = null;
45787
45795
  if (highlight) {
45788
45796
  styleEl = document.createElement("style");
45789
- styleEl.textContent = css$M;
45797
+ styleEl.textContent = css$N;
45790
45798
  document.head.appendChild(styleEl);
45791
45799
  }
45792
45800
 
@@ -45941,7 +45949,7 @@ const useFocusGroup = (
45941
45949
  };
45942
45950
 
45943
45951
  installImportMetaCssBuild(import.meta);const rightArrowPath = "M680-480L360-160l-80-80 240-240-240-240 80-80 320 320z";
45944
- const css$L = /* css */`
45952
+ const css$M = /* css */`
45945
45953
  .navi_summary_marker {
45946
45954
  width: 1em;
45947
45955
  height: 1em;
@@ -46031,7 +46039,7 @@ const SummaryMarker = ({
46031
46039
  loading,
46032
46040
  openDirection = "down"
46033
46041
  }) => {
46034
- import.meta.css = [css$L, "@jsenv/navi/src/control/details/summary_marker.jsx"];
46042
+ import.meta.css = [css$M, "@jsenv/navi/src/control/details/summary_marker.jsx"];
46035
46043
  const showLoading = useDebounceTrue(loading, 300);
46036
46044
  return jsx("span", {
46037
46045
  className: "navi_summary_marker",
@@ -46076,7 +46084,7 @@ const SummaryMarker = ({
46076
46084
  });
46077
46085
  };
46078
46086
 
46079
- installImportMetaCssBuild(import.meta);const css$K = /* css */`
46087
+ installImportMetaCssBuild(import.meta);const css$L = /* css */`
46080
46088
  .navi_details {
46081
46089
  position: relative;
46082
46090
  z-index: 1;
@@ -46122,7 +46130,7 @@ const Details = props => {
46122
46130
  return details;
46123
46131
  };
46124
46132
  const DetailsField = props => {
46125
- import.meta.css = [css$K, "@jsenv/navi/src/control/details/details.jsx"];
46133
+ import.meta.css = [css$L, "@jsenv/navi/src/control/details/details.jsx"];
46126
46134
  const {
46127
46135
  ref,
46128
46136
  persists,
@@ -46342,7 +46350,7 @@ installImportMetaCssBuild(import.meta);/**
46342
46350
  * UI when it comes first). Once settled open the clipping is released, so a
46343
46351
  * popover or focus ring inside is not cut at the edges.
46344
46352
  */
46345
- const css$J = /* css */`
46353
+ const css$K = /* css */`
46346
46354
  .navi_expandable {
46347
46355
  position: relative;
46348
46356
  display: flex;
@@ -46568,7 +46576,7 @@ const useExpandableContext = partName => {
46568
46576
  * and rebuilds it from scratch on every expansion.
46569
46577
  */
46570
46578
  const Expandable = props => {
46571
- import.meta.css = [css$J, "@jsenv/navi/src/control/expandable/expandable.jsx"];
46579
+ import.meta.css = [css$K, "@jsenv/navi/src/control/expandable/expandable.jsx"];
46572
46580
  const {
46573
46581
  ref,
46574
46582
  ui,
@@ -47233,7 +47241,7 @@ const ControlGroup = props => {
47233
47241
  };
47234
47242
  const CONTROL_GROUP_PSEUDO_CLASSES = [":hover", ":focus", ":focus-visible", ":read-only", ":disabled", ":-navi-loading"];
47235
47243
 
47236
- installImportMetaCssBuild(import.meta);const css$I = /* css */`
47244
+ installImportMetaCssBuild(import.meta);const css$J = /* css */`
47237
47245
  @layer navi {
47238
47246
  .navi_checkbox {
47239
47247
  --switch-margin: 0; /* Useful to reserve space for outline */
@@ -47311,7 +47319,7 @@ installImportMetaCssBuild(import.meta);const css$I = /* css */`
47311
47319
  }
47312
47320
  `;
47313
47321
  const SwitchUI = () => {
47314
- import.meta.css = [css$I, "@jsenv/navi/src/control/input/switch_ui.jsx"];
47322
+ import.meta.css = [css$J, "@jsenv/navi/src/control/input/switch_ui.jsx"];
47315
47323
  return jsx(Box, {
47316
47324
  className: "navi_switch",
47317
47325
  as: "svg",
@@ -47353,7 +47361,7 @@ const useCheckableProps = (props, options) => {
47353
47361
  return result;
47354
47362
  };
47355
47363
 
47356
- installImportMetaCssBuild(import.meta);const css$H = /* css */`
47364
+ installImportMetaCssBuild(import.meta);const css$I = /* css */`
47357
47365
  @layer navi {
47358
47366
  .navi_checkbox {
47359
47367
  --border-radius: var(--navi-checkbox-border-radius);
@@ -47680,7 +47688,7 @@ const InputCheckboxHeadless = props => {
47680
47688
  });
47681
47689
  };
47682
47690
  const InputCheckboxFieldInterface = props => {
47683
- import.meta.css = [css$H, "@jsenv/navi/src/control/input/input_checkbox.jsx"];
47691
+ import.meta.css = [css$I, "@jsenv/navi/src/control/input/input_checkbox.jsx"];
47684
47692
  const [checkboxRootProps, checkboxHostProps] = useCheckableProps(props);
47685
47693
  const {
47686
47694
  icon,
@@ -47802,7 +47810,7 @@ const CheckboxButtonStyleCSSVars = {
47802
47810
  const CheckboxPseudoClasses = [":hover", ":active", ":focus", ":focus-visible", ":read-only", ":disabled", ":checked", ":-navi-loading"];
47803
47811
  const CheckboxPseudoElements = ["::-navi-loader", "::-navi-checkmark"];
47804
47812
 
47805
- installImportMetaCssBuild(import.meta);const css$G = /* css */`
47813
+ installImportMetaCssBuild(import.meta);const css$H = /* css */`
47806
47814
  @layer navi {
47807
47815
  .navi_label {
47808
47816
  --label-required-indicator-color: var(--navi-color-danger, #b42318);
@@ -47882,7 +47890,7 @@ installImportMetaCssBuild(import.meta);const css$G = /* css */`
47882
47890
  * </Field>
47883
47891
  */
47884
47892
  const Field = props => {
47885
- import.meta.css = [css$G, "@jsenv/navi/src/control/field.jsx"];
47893
+ import.meta.css = [css$H, "@jsenv/navi/src/control/field.jsx"];
47886
47894
  const refDefault = useRef();
47887
47895
  props.ref = props.ref || refDefault;
47888
47896
  const {
@@ -47917,7 +47925,7 @@ const FieldCSSVars = {
47917
47925
  spacingWithControl: "--spacing-with-control"
47918
47926
  };
47919
47927
  const FieldAsContainer = props => {
47920
- import.meta.css = [css$G, "@jsenv/navi/src/control/field.jsx"];
47928
+ import.meta.css = [css$H, "@jsenv/navi/src/control/field.jsx"];
47921
47929
  const {
47922
47930
  children
47923
47931
  } = props;
@@ -47949,7 +47957,7 @@ const FieldAsContainer = props => {
47949
47957
  };
47950
47958
  const FIELD_PSEUDO_CLASSES = [":hover", ":active", ":focus", ":focus-visible", ":read-only", ":disabled", ":-navi-loading"];
47951
47959
  const Label = props => {
47952
- import.meta.css = [css$G, "@jsenv/navi/src/control/field.jsx"];
47960
+ import.meta.css = [css$H, "@jsenv/navi/src/control/field.jsx"];
47953
47961
  const {
47954
47962
  children,
47955
47963
  // Marks the label when its control is required. Takes what to show, or
@@ -48111,7 +48119,7 @@ const InputSlot = ({
48111
48119
  });
48112
48120
  };
48113
48121
 
48114
- installImportMetaCssBuild(import.meta);const css$F = /* css */`
48122
+ installImportMetaCssBuild(import.meta);const css$G = /* css */`
48115
48123
  @layer navi {
48116
48124
  .navi_radio {
48117
48125
  --margin: 3px 3px 3px 5px;
@@ -48474,7 +48482,7 @@ const InputRadioHeadless = props => {
48474
48482
  };
48475
48483
  const VARIANT_SET = new Set(["icon", "button", "radio"]);
48476
48484
  const InputRadioFieldInterface = props => {
48477
- import.meta.css = [css$F, "@jsenv/navi/src/control/input/input_radio.jsx"];
48485
+ import.meta.css = [css$G, "@jsenv/navi/src/control/input/input_radio.jsx"];
48478
48486
  const [radioRootProps, radioHostProps] = useCheckableProps(props);
48479
48487
  const {
48480
48488
  icon,
@@ -48620,7 +48628,7 @@ const RadioButtonStyleCSSVars = {
48620
48628
  const RadioPseudoClasses = [":hover", ":active", ":focus", ":focus-visible", ":read-only", ":disabled", ":checked", ":-navi-loading"];
48621
48629
  const RadioPseudoElements = ["::-navi-loader", "::-navi-radiomark"];
48622
48630
 
48623
- installImportMetaCssBuild(import.meta);const css$E = /* css */`
48631
+ installImportMetaCssBuild(import.meta);const css$F = /* css */`
48624
48632
  @layer navi {
48625
48633
  .navi_input_range {
48626
48634
  --border-radius: 6px;
@@ -48875,7 +48883,7 @@ const InputRange = props => {
48875
48883
  });
48876
48884
  };
48877
48885
  const InputRangeFieldInterface = props => {
48878
- import.meta.css = [css$E, "@jsenv/navi/src/control/input/input_range.jsx"];
48886
+ import.meta.css = [css$F, "@jsenv/navi/src/control/input/input_range.jsx"];
48879
48887
  const {
48880
48888
  ref
48881
48889
  } = props;
@@ -50983,7 +50991,7 @@ installImportMetaCssBuild(import.meta);/**
50983
50991
  * This means an editable thing MUST have a parent with position relative that wraps the content and the eventual editable input
50984
50992
  *
50985
50993
  */
50986
- const css$D = /* css */`
50994
+ const css$E = /* css */`
50987
50995
  .navi_editable_wrapper {
50988
50996
  --inset-top: 0px;
50989
50997
  --inset-right: 0px;
@@ -51032,7 +51040,7 @@ const useEditionController = () => {
51032
51040
  };
51033
51041
  };
51034
51042
  const Editable = props => {
51035
- import.meta.css = [css$D, "@jsenv/navi/src/control/edition/editable.jsx"];
51043
+ import.meta.css = [css$E, "@jsenv/navi/src/control/edition/editable.jsx"];
51036
51044
  let {
51037
51045
  children,
51038
51046
  action,
@@ -51581,7 +51589,7 @@ installImportMetaCssBuild(import.meta);/**
51581
51589
  * meet are drawn once instead of twice, and only the outer corners stay
51582
51590
  * rounded. See docs/control_group.md.
51583
51591
  */
51584
- const css$C = /* css */`
51592
+ const css$D = /* css */`
51585
51593
  .navi_group {
51586
51594
  --group-border-width: var(--navi-control-border-width);
51587
51595
 
@@ -51697,7 +51705,7 @@ const Group = ({
51697
51705
  vertical = row,
51698
51706
  ...props
51699
51707
  }) => {
51700
- import.meta.css = [css$C, "@jsenv/navi/src/control/group.jsx"];
51708
+ import.meta.css = [css$D, "@jsenv/navi/src/control/group.jsx"];
51701
51709
  return jsx(Box, {
51702
51710
  baseClassName: "navi_group",
51703
51711
  "data-vertical": vertical ? "" : undefined
@@ -51863,7 +51871,7 @@ installImportMetaCssBuild(import.meta);/**
51863
51871
  * So: nothing scrollable between the cap and the slides (a shared [data-body]
51864
51872
  * around them IS a scroller, see box.jsx), and `overflow="auto"` on each Slide.
51865
51873
  */
51866
- const css$B = /* css */`
51874
+ const css$C = /* css */`
51867
51875
  /* Where the picture stands relative to the slide that is current, in boxes
51868
51876
  (see paintTravelProgress). Declared, so that it is a NUMBER the browser can
51869
51877
  interpolate: the trait an indicator draws has to travel with the slides,
@@ -52357,7 +52365,7 @@ const SlideContainer = ({
52357
52365
  children,
52358
52366
  ...rest
52359
52367
  }) => {
52360
- import.meta.css = [css$B, "@jsenv/navi/src/layout/slide_container.jsx"];
52368
+ import.meta.css = [css$C, "@jsenv/navi/src/layout/slide_container.jsx"];
52361
52369
  const debugFocus = useDebugFocus();
52362
52370
  const trackRef = useRef();
52363
52371
  // The box itself: it is what takes the keyboard when what is on screen holds
@@ -55202,7 +55210,7 @@ installImportMetaCssBuild(import.meta);/**
55202
55210
  * and only under its own `sizeFromAnchor`) pass through untouched via
55203
55211
  * `...rest` to whichever of Popover/Dialog actually renders.
55204
55212
  */
55205
- const css$A = /* css */`
55213
+ const css$B = /* css */`
55206
55214
  @layer navi {
55207
55215
  .navi_popup {
55208
55216
  --popup-border-radius: var(--navi-popup-border-radius);
@@ -55319,7 +55327,7 @@ const css$A = /* css */`
55319
55327
  * @param {import("ignore:preact").ComponentChildren} props.children
55320
55328
  */
55321
55329
  const Popup = props => {
55322
- import.meta.css = [css$A, "@jsenv/navi/src/layout/popup.jsx"];
55330
+ import.meta.css = [css$B, "@jsenv/navi/src/layout/popup.jsx"];
55323
55331
  const {
55324
55332
  mode: modeProp,
55325
55333
  maxWidth,
@@ -55380,7 +55388,7 @@ const Popup = props => {
55380
55388
  });
55381
55389
  };
55382
55390
 
55383
- installImportMetaCssBuild(import.meta);const css$z = /* css */`
55391
+ installImportMetaCssBuild(import.meta);const css$A = /* css */`
55384
55392
  .navi_picker {
55385
55393
  /* Sizing ceilings (maxmax), background, box-shadow, outline, padding,
55386
55394
  overflow... are already handled correctly by Popup/Popover/Dialog
@@ -55508,7 +55516,7 @@ installImportMetaCssBuild(import.meta);const css$z = /* css */`
55508
55516
  }
55509
55517
  `;
55510
55518
  const PickerCustomResolver = props => {
55511
- import.meta.css = [css$z, "@jsenv/navi/src/control/picker/picker_custom.jsx"];
55519
+ import.meta.css = [css$A, "@jsenv/navi/src/control/picker/picker_custom.jsx"];
55512
55520
  if (props.children === undefined) {
55513
55521
  return jsx(PickerNative, {
55514
55522
  ...props
@@ -56302,7 +56310,7 @@ const LoadingIndicator = ({
56302
56310
  });
56303
56311
  };
56304
56312
 
56305
- installImportMetaCssBuild(import.meta);const css$y = /* css */`
56313
+ installImportMetaCssBuild(import.meta);const css$z = /* css */`
56306
56314
  @layer navi {
56307
56315
  .navi_separator {
56308
56316
  --size: 1px;
@@ -56380,7 +56388,7 @@ const Separator = ({
56380
56388
  style,
56381
56389
  ...props
56382
56390
  }) => {
56383
- import.meta.css = [css$y, "@jsenv/navi/src/layout/separator.jsx"];
56391
+ import.meta.css = [css$z, "@jsenv/navi/src/layout/separator.jsx"];
56384
56392
  return jsx(Box, {
56385
56393
  as: vertical ? "span" : "hr",
56386
56394
  ...props,
@@ -56873,7 +56881,7 @@ const ListItemFooter = props => {
56873
56881
  });
56874
56882
  };
56875
56883
 
56876
- installImportMetaCssBuild(import.meta);const css$x = /* css */`
56884
+ installImportMetaCssBuild(import.meta);const css$y = /* css */`
56877
56885
  @layer navi {
56878
56886
  .navi_list_container[navi-selectable] {
56879
56887
  /* Focus outline */
@@ -57085,7 +57093,7 @@ const ListSelectableResolver = props => {
57085
57093
  };
57086
57094
  const ListSelectable = props => {
57087
57095
  const Next = useNextResolver();
57088
- import.meta.css = [css$x, "@jsenv/navi/src/control/list/list_selectable.jsx"];
57096
+ import.meta.css = [css$y, "@jsenv/navi/src/control/list/list_selectable.jsx"];
57089
57097
  // we allow ourselves to auto-generate a name
57090
57098
  const defaultName = useId();
57091
57099
  props.name = props.name || `listbox_${defaultName}`;
@@ -57705,7 +57713,7 @@ const ListVirtualContext = createContext(null);
57705
57713
  // that returning a component of one's own — instead of a bare <List.Item> —
57706
57714
  // works the same way.
57707
57715
  const ListRowContext = createContext(null);
57708
- const css$w = /* css */`
57716
+ const css$x = /* css */`
57709
57717
  @layer navi {
57710
57718
  .navi_list_container {
57711
57719
  --list-outline-width: 1px;
@@ -58404,7 +58412,7 @@ const css$w = /* css */`
58404
58412
  }
58405
58413
  `;
58406
58414
  const ListUI = props => {
58407
- import.meta.css = [css$w, "@jsenv/navi/src/control/list/list.jsx"];
58415
+ import.meta.css = [css$x, "@jsenv/navi/src/control/list/list.jsx"];
58408
58416
  const {
58409
58417
  ref,
58410
58418
  renderBudget: renderBudgetProp = RENDER_BUDGET_DEFAULT,
@@ -62073,7 +62081,7 @@ const PickerPresetResolver = props => {
62073
62081
  });
62074
62082
  };
62075
62083
 
62076
- installImportMetaCssBuild(import.meta);const css$v = /* css */`
62084
+ installImportMetaCssBuild(import.meta);const css$w = /* css */`
62077
62085
  @layer navi {
62078
62086
  }
62079
62087
  .navi_badge {
@@ -62185,7 +62193,7 @@ const Badge = ({
62185
62193
  className,
62186
62194
  ...props
62187
62195
  }) => {
62188
- import.meta.css = [css$v, "@jsenv/navi/src/text/badge.jsx"];
62196
+ import.meta.css = [css$w, "@jsenv/navi/src/text/badge.jsx"];
62189
62197
  const defaultRef = useRef();
62190
62198
  props.ref = props.ref || defaultRef;
62191
62199
  const {
@@ -62237,7 +62245,7 @@ const BadgeButton = props => {
62237
62245
  };
62238
62246
  Badge.Button = BadgeButton;
62239
62247
 
62240
- installImportMetaCssBuild(import.meta);const css$u = /* css */`
62248
+ installImportMetaCssBuild(import.meta);const css$v = /* css */`
62241
62249
  @layer navi {
62242
62250
  }
62243
62251
  .navi_badge_list {
@@ -62262,7 +62270,7 @@ const BadgeList = ({
62262
62270
  max,
62263
62271
  ...props
62264
62272
  }) => {
62265
- import.meta.css = [css$u, "@jsenv/navi/src/text/badge_list.jsx"];
62273
+ import.meta.css = [css$v, "@jsenv/navi/src/text/badge_list.jsx"];
62266
62274
  const measureRef = useRef();
62267
62275
  const visibleRef = useRef();
62268
62276
  useLayoutEffect(() => {
@@ -62337,7 +62345,7 @@ const BadgeList = ({
62337
62345
  });
62338
62346
  };
62339
62347
 
62340
- installImportMetaCssBuild(import.meta);const css$t = /* css */`
62348
+ installImportMetaCssBuild(import.meta);const css$u = /* css */`
62341
62349
  .navi_color {
62342
62350
  display: block;
62343
62351
  aspect-ratio: 1/1;
@@ -62368,7 +62376,7 @@ const Color = ({
62368
62376
  children,
62369
62377
  ...rest
62370
62378
  }) => {
62371
- import.meta.css = [css$t, "@jsenv/navi/src/text/color.jsx"];
62379
+ import.meta.css = [css$u, "@jsenv/navi/src/text/color.jsx"];
62372
62380
  const color = children || undefined;
62373
62381
  return jsx(Box, {
62374
62382
  as: "span",
@@ -62825,7 +62833,7 @@ const PickerFileUI = () => {
62825
62833
  return String(value);
62826
62834
  };
62827
62835
 
62828
- installImportMetaCssBuild(import.meta);const css$s = /* css */`
62836
+ installImportMetaCssBuild(import.meta);const css$t = /* css */`
62829
62837
  @layer navi {
62830
62838
  .navi_picker {
62831
62839
  --picker-border-radius: var(--navi-control-border-radius);
@@ -63214,7 +63222,7 @@ installImportMetaCssBuild(import.meta);const css$s = /* css */`
63214
63222
  }
63215
63223
  `;
63216
63224
  const PickerButton = props => {
63217
- import.meta.css = [css$s, "@jsenv/navi/src/control/picker/picker.jsx"];
63225
+ import.meta.css = [css$t, "@jsenv/navi/src/control/picker/picker.jsx"];
63218
63226
  if (typeof props.maxLines === "string") {
63219
63227
  props.maxLines = parseInt(props.maxLines);
63220
63228
  }
@@ -63663,7 +63671,7 @@ installImportMetaCssBuild(import.meta);/**
63663
63671
  * refuse it on purpose, which is what keeps the focus where the travel happens
63664
63672
  * instead of moving it into a slide that is about to leave.
63665
63673
  */
63666
- const css$r = /* css */`
63674
+ const css$s = /* css */`
63667
63675
  @layer navi {
63668
63676
  .navi_picker_spin {
63669
63677
  /* A picker one steps through is still a picker: what themes every picker
@@ -64132,7 +64140,7 @@ const Spin = ({
64132
64140
  nextLabel,
64133
64141
  ...rest
64134
64142
  }) => {
64135
- import.meta.css = [css$r, "@jsenv/navi/src/control/picker/picker_spin.jsx"];
64143
+ import.meta.css = [css$s, "@jsenv/navi/src/control/picker/picker_spin.jsx"];
64136
64144
  const id = useId();
64137
64145
  // What the group around it says, when there is one: how big the whole thing
64138
64146
  // is written is said once, on the group, and every spin in it follows.
@@ -64668,7 +64676,7 @@ const renderValueDefault = value => String(value ?? "");
64668
64676
  * are passed on to the spins sitting in them.
64669
64677
  */
64670
64678
  const SpinGroup = props => {
64671
- import.meta.css = [css$r, "@jsenv/navi/src/control/picker/picker_spin.jsx"];
64679
+ import.meta.css = [css$s, "@jsenv/navi/src/control/picker/picker_spin.jsx"];
64672
64680
  const {
64673
64681
  size
64674
64682
  } = props;
@@ -65181,7 +65189,7 @@ const TimeRangeSpin = ({
65181
65189
  };
65182
65190
 
65183
65191
  installImportMetaCssBuild(import.meta);// TOFIX: select in data then reset, it reset to red/blue instead of red/blue/green
65184
- const css$q = /* css */`
65192
+ const css$r = /* css */`
65185
65193
  .navi_checkbox_group {
65186
65194
  border-style: solid;
65187
65195
 
@@ -65222,7 +65230,7 @@ const CheckboxGroup = props => {
65222
65230
  return checkboxGroup;
65223
65231
  };
65224
65232
  const CheckboxGroupInterface = props => {
65225
- import.meta.css = [css$q, "@jsenv/navi/src/control/input/checkbox_group.jsx"];
65233
+ import.meta.css = [css$r, "@jsenv/navi/src/control/input/checkbox_group.jsx"];
65226
65234
  const {
65227
65235
  ref
65228
65236
  } = props;
@@ -65271,7 +65279,7 @@ installImportMetaCssBuild(import.meta);/**
65271
65279
  * shared sheet is registered here too — a page may render a Textarea without
65272
65280
  * any Input.
65273
65281
  */
65274
- const css$p = /* css */`
65282
+ const css$q = /* css */`
65275
65283
  .navi_input.navi_textarea {
65276
65284
  .navi_control_input {
65277
65285
  min-height: calc(var(--textarea-min-rows, 1.5) * 1lh);
@@ -65358,7 +65366,7 @@ const Textarea = ({
65358
65366
  width = "35ch",
65359
65367
  ...props
65360
65368
  }) => {
65361
- import.meta.css = [inputCss + css$p, "@jsenv/navi/src/control/input/textarea.jsx"];
65369
+ import.meta.css = [inputCss + css$q, "@jsenv/navi/src/control/input/textarea.jsx"];
65362
65370
  const defaultRef = useRef(null);
65363
65371
  props.ref = props.ref || defaultRef;
65364
65372
  usePlaceholderHeight(props.ref, props.placeholder);
@@ -65432,7 +65440,7 @@ const TextareaCharCount = ({
65432
65440
  maxLength,
65433
65441
  ...rest
65434
65442
  }) => {
65435
- import.meta.css = [css$p, "@jsenv/navi/src/control/input/textarea.jsx"];
65443
+ import.meta.css = [css$q, "@jsenv/navi/src/control/input/textarea.jsx"];
65436
65444
  const resolvedValue = signal ? signal.value : value;
65437
65445
  const length = typeof resolvedValue === "string" ? resolvedValue.length : 0;
65438
65446
  return jsx(Box, {
@@ -65617,7 +65625,7 @@ const formatIntlUnit = (unit, {
65617
65625
  }
65618
65626
  };
65619
65627
 
65620
- installImportMetaCssBuild(import.meta);const css$o = /* css */`
65628
+ installImportMetaCssBuild(import.meta);const css$p = /* css */`
65621
65629
  .navi_input_duration {
65622
65630
  --duration-separator-spacing: 4px;
65623
65631
  --loader-color: var(--navi-loader-color);
@@ -65684,7 +65692,7 @@ installImportMetaCssBuild(import.meta);const css$o = /* css */`
65684
65692
  * "auto" aligns each field toward its neighbouring separator (first→right, last→left, middle/solo→center).
65685
65693
  */
65686
65694
  const InputDuration = props => {
65687
- import.meta.css = [css$o, "@jsenv/navi/src/control/input/input_duration.jsx"];
65695
+ import.meta.css = [css$p, "@jsenv/navi/src/control/input/input_duration.jsx"];
65688
65696
  const defaultRef = useRef();
65689
65697
  props.ref = props.ref || defaultRef;
65690
65698
  props.max = props.max || "23h59";
@@ -66186,7 +66194,7 @@ const InputDurationPart = ({
66186
66194
  });
66187
66195
  };
66188
66196
 
66189
- installImportMetaCssBuild(import.meta);const css$n = /* css */`
66197
+ installImportMetaCssBuild(import.meta);const css$o = /* css */`
66190
66198
  .navi_radio_group {
66191
66199
  border-style: solid;
66192
66200
 
@@ -66206,7 +66214,7 @@ const RadioGroup = props => {
66206
66214
  return radioGroup;
66207
66215
  };
66208
66216
  const RadioGroupInterface = props => {
66209
- import.meta.css = [css$n, "@jsenv/navi/src/control/input/radio_group.jsx"];
66217
+ import.meta.css = [css$o, "@jsenv/navi/src/control/input/radio_group.jsx"];
66210
66218
  const {
66211
66219
  ref
66212
66220
  } = props;
@@ -66264,7 +66272,7 @@ installImportMetaCssBuild(import.meta);/**
66264
66272
  * control is drawn — the list it opens stays the platform's own, which is the
66265
66273
  * whole point of using a select.
66266
66274
  */
66267
- const css$m = /* css */`
66275
+ const css$n = /* css */`
66268
66276
  .navi_input.navi_select {
66269
66277
  .navi_control_input {
66270
66278
  /* Room for the chevron, which sits over the padding rather than beside
@@ -66319,7 +66327,7 @@ const Select = ({
66319
66327
  multiple,
66320
66328
  ...props
66321
66329
  }) => {
66322
- import.meta.css = [inputCss + css$m, "@jsenv/navi/src/control/input/select.jsx"];
66330
+ import.meta.css = [inputCss + css$n, "@jsenv/navi/src/control/input/select.jsx"];
66323
66331
  const defaultRef = useRef(null);
66324
66332
  props.ref = props.ref || defaultRef;
66325
66333
  seedDefaultValueFromSignal(props);
@@ -66387,7 +66395,7 @@ installImportMetaCssBuild(import.meta);/**
66387
66395
  * running: one loading outline around both, which is why each half is told
66388
66396
  * `loadingOutline={false}`.
66389
66397
  */
66390
- const css$l = /* css */`
66398
+ const css$m = /* css */`
66391
66399
  /* Around the pair rather than in it: the outline is drawn against this
66392
66400
  element and follows its corners, and a Group counts its own children to
66393
66401
  know which corners to square — an outline among them would be one of the
@@ -66499,7 +66507,7 @@ const css$l = /* css */`
66499
66507
  * Anything else lands on the split button's own box.
66500
66508
  */
66501
66509
  const SplitButton = props => {
66502
- import.meta.css = [css$l, "@jsenv/navi/src/control/input/split_button.jsx"];
66510
+ import.meta.css = [css$m, "@jsenv/navi/src/control/input/split_button.jsx"];
66503
66511
  const {
66504
66512
  options = [],
66505
66513
  value,
@@ -67150,7 +67158,7 @@ installImportMetaCssBuild(import.meta);/*
67150
67158
  * accessors (top/height vs left/width) chosen from `horizontal`, and the CSS has
67151
67159
  * a [data-horizontal] variant.
67152
67160
  */
67153
- const css$k = /* css */`
67161
+ const css$l = /* css */`
67154
67162
  .navi_wheel_container {
67155
67163
  /* Row size and emphasis band are read together: the band is what a value
67156
67164
  must cross to lose its emphasis, and the row is how far it has to travel
@@ -68272,7 +68280,7 @@ const useWheelKeyboard = ({
68272
68280
  }, [isHorizontal, interactive, isLoop]);
68273
68281
  };
68274
68282
  function WheelUI(props) {
68275
- import.meta.css = [css$k, "@jsenv/navi/src/control/wheel/wheel.jsx"];
68283
+ import.meta.css = [css$l, "@jsenv/navi/src/control/wheel/wheel.jsx"];
68276
68284
  const {
68277
68285
  ref,
68278
68286
  visibleCount = 3,
@@ -69181,7 +69189,7 @@ Wheel.Item = WheelItem;
69181
69189
  * @param {boolean} [props.zoom] - Enlarge the centered value of every wheel (see Wheel's zoom prop) with one prop for the whole group.
69182
69190
  */
69183
69191
  const WheelGroup = props => {
69184
- import.meta.css = [css$k, "@jsenv/navi/src/control/wheel/wheel.jsx"];
69192
+ import.meta.css = [css$l, "@jsenv/navi/src/control/wheel/wheel.jsx"];
69185
69193
  // WheelGroup IS a control group: it aggregates its named wheels ("hours",
69186
69194
  // "minutes"…) into one object value, so it can sit directly inside a Form or a
69187
69195
  // Picker with no extra <ControlGroup> wrapper. The wheel-specific presentation
@@ -70046,7 +70054,7 @@ const Z_INDEX_DROP_PREVIEW = Z_INDEX_STICKY_CORNER + 1;
70046
70054
 
70047
70055
  const Z_INDEX_TABLE_UI = Z_INDEX_STICKY_CORNER + 1;
70048
70056
 
70049
- installImportMetaCssBuild(import.meta);const css$j = /* css */`
70057
+ installImportMetaCssBuild(import.meta);const css$k = /* css */`
70050
70058
  .navi_table_drag_clone_container {
70051
70059
  position: absolute;
70052
70060
  top: var(--table-visual-top);
@@ -70201,7 +70209,7 @@ const useTableDragContextValue = ({
70201
70209
  }, [grabTarget, canChangeColumnOrder]);
70202
70210
  };
70203
70211
  const TableDragCloneContainer = forwardRef((props, ref) => {
70204
- import.meta.css = [css$j, "@jsenv/navi/src/control/table/drag/table_drag.jsx"];
70212
+ import.meta.css = [css$k, "@jsenv/navi/src/control/table/drag/table_drag.jsx"];
70205
70213
  const {
70206
70214
  tableId
70207
70215
  } = props;
@@ -70499,7 +70507,7 @@ installImportMetaCssBuild(import.meta);const ROW_MIN_HEIGHT = 30;
70499
70507
  const ROW_MAX_HEIGHT = 100;
70500
70508
  const COLUMN_MIN_WIDTH = 50;
70501
70509
  const COLUMN_MAX_WIDTH = 500;
70502
- const css$i = /* css */`
70510
+ const css$j = /* css */`
70503
70511
  @layer navi {
70504
70512
  .navi_table {
70505
70513
  --table-resizer-handle-color: #063b7c;
@@ -70659,7 +70667,7 @@ const css$i = /* css */`
70659
70667
 
70660
70668
  // Column resize components
70661
70669
  const TableColumnResizer = props => {
70662
- import.meta.css = [css$i, "@jsenv/navi/src/control/table/resize/table_resize.jsx"];
70670
+ import.meta.css = [css$j, "@jsenv/navi/src/control/table/resize/table_resize.jsx"];
70663
70671
  const defaultRef = useRef();
70664
70672
  const ref = props.ref || defaultRef;
70665
70673
  return jsxs("div", {
@@ -71130,7 +71138,7 @@ const findPreviousTableRow = currentRow => {
71130
71138
  return currentIndex > 0 ? allRows[currentIndex - 1] : null;
71131
71139
  };
71132
71140
 
71133
- installImportMetaCssBuild(import.meta);const css$h = /* css */`
71141
+ installImportMetaCssBuild(import.meta);const css$i = /* css */`
71134
71142
  @layer navi {
71135
71143
  .navi_table {
71136
71144
  --selection-border-color: var(--navi-selection-border-color, #0078d4);
@@ -71232,7 +71240,7 @@ const useTableSelectionController = ({
71232
71240
  onSelectionChange,
71233
71241
  selectionColor
71234
71242
  }) => {
71235
- import.meta.css = [css$h, "@jsenv/navi/src/control/table/selection/table_selection.jsx"];
71243
+ import.meta.css = [css$i, "@jsenv/navi/src/control/table/selection/table_selection.jsx"];
71236
71244
  const selectionController = useSelectionController({
71237
71245
  elementRef: tableRef,
71238
71246
  layout: "grid",
@@ -71703,7 +71711,7 @@ const useTableStickyContextValue = ({
71703
71711
  };
71704
71712
 
71705
71713
  installImportMetaCssBuild(import.meta);// TODO: sticky left/top frontier should likely use "followPosition"
71706
- const css$g = /* css */`
71714
+ const css$h = /* css */`
71707
71715
  @layer navi {
71708
71716
  .navi_table {
71709
71717
  --sticky-frontier-color: #c0c0c0;
@@ -71946,7 +71954,7 @@ const css$g = /* css */`
71946
71954
  const TableStickyFrontier = ({
71947
71955
  tableRef
71948
71956
  }) => {
71949
- import.meta.css = [css$g, "@jsenv/navi/src/control/table/sticky/table_sticky.jsx"];
71957
+ import.meta.css = [css$h, "@jsenv/navi/src/control/table/sticky/table_sticky.jsx"];
71950
71958
  const stickyLeftFrontierGhostRef = useRef();
71951
71959
  const stickyLeftFrontierPreviewRef = useRef();
71952
71960
  const stickyTopFrontierGhostRef = useRef();
@@ -72175,7 +72183,7 @@ const initMoveStickyFrontierViaPointer = (pointerdownEvent, {
72175
72183
  * inset 0 -1px 0 0 color; // Bottom border
72176
72184
  */
72177
72185
 
72178
- const css$f = /* css */ `
72186
+ const css$g = /* css */ `
72179
72187
  .navi_table_root {
72180
72188
  position: relative;
72181
72189
  max-width: var(--table-max-width, none);
@@ -72378,7 +72386,7 @@ const css$f = /* css */ `
72378
72386
  }
72379
72387
  `;
72380
72388
 
72381
- installImportMetaCssBuild(import.meta);const css$e = /* css */`
72389
+ installImportMetaCssBuild(import.meta);const css$f = /* css */`
72382
72390
  .navi_table_ui {
72383
72391
  position: fixed;
72384
72392
  inset: 0;
@@ -72389,7 +72397,7 @@ installImportMetaCssBuild(import.meta);const css$e = /* css */`
72389
72397
  }
72390
72398
  `;
72391
72399
  const TableUI = forwardRef((props, ref) => {
72392
- import.meta.css = [css$e, "@jsenv/navi/src/control/table/table_ui.jsx"];
72400
+ import.meta.css = [css$f, "@jsenv/navi/src/control/table/table_ui.jsx"];
72393
72401
  const {
72394
72402
  tableRef,
72395
72403
  tableId,
@@ -72495,7 +72503,7 @@ const RowIndexContext = createContext();
72495
72503
  const TableSectionContext = createContext();
72496
72504
  const useIsInTableHead = () => useContext(TableSectionContext) === "head";
72497
72505
  const Table = props => {
72498
- import.meta.css = [css$f, "@jsenv/navi/src/control/table/table.jsx"];
72506
+ import.meta.css = [css$g, "@jsenv/navi/src/control/table/table.jsx"];
72499
72507
  const tableDefaultRef = useRef();
72500
72508
  const tableDefaultId = `table-${useId()}`;
72501
72509
  const {
@@ -73323,7 +73331,7 @@ const normalizeKey = (key) => {
73323
73331
  return key;
73324
73332
  };
73325
73333
 
73326
- installImportMetaCssBuild(import.meta);const css$d = /* css */`
73334
+ installImportMetaCssBuild(import.meta);const css$e = /* css */`
73327
73335
  .navi_shortcut_container[data-visually-hidden] {
73328
73336
  /* Visually hidden container - doesn't affect layout */
73329
73337
  position: absolute;
@@ -73361,7 +73369,7 @@ installImportMetaCssBuild(import.meta);const css$d = /* css */`
73361
73369
  const ActiveKeyboardShortcuts = ({
73362
73370
  visible
73363
73371
  }) => {
73364
- import.meta.css = [css$d, "@jsenv/navi/src/keyboard/active_keyboard_shortcuts.jsx"];
73372
+ import.meta.css = [css$e, "@jsenv/navi/src/keyboard/active_keyboard_shortcuts.jsx"];
73365
73373
  const activeShortcuts = activeShortcutsSignal.value;
73366
73374
  return jsx("div", {
73367
73375
  className: "navi_shortcut_container",
@@ -73400,7 +73408,7 @@ const KeyboardShortcutAriaElement = ({
73400
73408
  });
73401
73409
  };
73402
73410
 
73403
- installImportMetaCssBuild(import.meta);const css$c = /* css */`
73411
+ installImportMetaCssBuild(import.meta);const css$d = /* css */`
73404
73412
  @layer navi {
73405
73413
  .navi_clipboard_container {
73406
73414
  --height: 1.5em;
@@ -73432,7 +73440,7 @@ const ButtonCopyToClipboard = ({
73432
73440
  children,
73433
73441
  ...props
73434
73442
  }) => {
73435
- import.meta.css = [css$c, "@jsenv/navi/src/control/input/button_copy_to_clipboard.jsx"];
73443
+ import.meta.css = [css$d, "@jsenv/navi/src/control/input/button_copy_to_clipboard.jsx"];
73436
73444
  const [copied, setCopied] = useState(false);
73437
73445
  const renderedRef = useRef();
73438
73446
  useEffect(() => {
@@ -73517,7 +73525,7 @@ const formatNumber = (value, { lang = languagesSignal.value } = {}) => {
73517
73525
  return new Intl.NumberFormat(lang).format(value);
73518
73526
  };
73519
73527
 
73520
- installImportMetaCssBuild(import.meta);const css$b = /* css */`
73528
+ installImportMetaCssBuild(import.meta);const css$c = /* css */`
73521
73529
  @layer navi {
73522
73530
  }
73523
73531
  .navi_text.navi_badge_count {
@@ -73682,7 +73690,7 @@ const BadgeCount = ({
73682
73690
  lineLayout,
73683
73691
  ...props
73684
73692
  }) => {
73685
- import.meta.css = [css$b, "@jsenv/navi/src/text/badge_count.jsx"];
73693
+ import.meta.css = [css$c, "@jsenv/navi/src/text/badge_count.jsx"];
73686
73694
  const defaultRef = useRef();
73687
73695
  props.ref = props.ref || defaultRef;
73688
73696
  const {
@@ -73824,7 +73832,7 @@ const BadgeCountCircle = ({
73824
73832
  });
73825
73833
  };
73826
73834
 
73827
- installImportMetaCssBuild(import.meta);const css$a = /* css */`
73835
+ installImportMetaCssBuild(import.meta);const css$b = /* css */`
73828
73836
  @layer navi {
73829
73837
  .navi_caption {
73830
73838
  --color: #6b7280;
@@ -73845,7 +73853,7 @@ const Caption = ({
73845
73853
  className,
73846
73854
  ...rest
73847
73855
  }) => {
73848
- import.meta.css = [css$a, "@jsenv/navi/src/text/caption.jsx"];
73856
+ import.meta.css = [css$b, "@jsenv/navi/src/text/caption.jsx"];
73849
73857
  return jsx(Text, {
73850
73858
  as: "small",
73851
73859
  size: "0.8em" // We use em to be relative to the parent (we want to be smaller than the surrounding text)
@@ -74258,7 +74266,7 @@ const WarningSvg = () => {
74258
74266
  });
74259
74267
  };
74260
74268
 
74261
- installImportMetaCssBuild(import.meta);const css$9 = /* css */`
74269
+ installImportMetaCssBuild(import.meta);const css$a = /* css */`
74262
74270
  @layer navi {
74263
74271
  .navi_message_box {
74264
74272
  --background-color-info: var(--navi-info-color-light);
@@ -74315,7 +74323,7 @@ const MessageBox = ({
74315
74323
  onClose,
74316
74324
  ...rest
74317
74325
  }) => {
74318
- import.meta.css = [css$9, "@jsenv/navi/src/text/message_box.jsx"];
74326
+ import.meta.css = [css$a, "@jsenv/navi/src/text/message_box.jsx"];
74319
74327
  const [hasTitleChild, setHasTitleChild] = useState(false);
74320
74328
  const innerLeftStripe = leftStripe === undefined ? hasTitleChild : leftStripe;
74321
74329
  if (icon === true) {
@@ -74378,7 +74386,7 @@ const MessageBoxPseudoClasses = [":-navi-status-info", ":-navi-status-success",
74378
74386
  const MessageBoxStatusContext = createContext();
74379
74387
  const MessageBoxReportTitleChildContext = createContext();
74380
74388
 
74381
- installImportMetaCssBuild(import.meta);const css$8 = /* css */`
74389
+ installImportMetaCssBuild(import.meta);const css$9 = /* css */`
74382
74390
  @layer navi {
74383
74391
  }
74384
74392
 
@@ -74469,7 +74477,7 @@ const Quantity = ({
74469
74477
  bold = true,
74470
74478
  ...props
74471
74479
  }) => {
74472
- import.meta.css = [css$8, "@jsenv/navi/src/text/quantity.jsx"];
74480
+ import.meta.css = [css$9, "@jsenv/navi/src/text/quantity.jsx"];
74473
74481
  const value = parseQuantityValue(children);
74474
74482
  const valueRounded = integer && typeof value === "number" ? Math.round(value) : value;
74475
74483
  const valueFormatted = typeof valueRounded === "number" ? formatNumber(valueRounded, {
@@ -74527,7 +74535,7 @@ const parseQuantityValue = children => {
74527
74535
  return Number.isNaN(parsed) ? children : parsed;
74528
74536
  };
74529
74537
 
74530
- installImportMetaCssBuild(import.meta);const css$7 = /* css */`
74538
+ installImportMetaCssBuild(import.meta);const css$8 = /* css */`
74531
74539
  @layer navi {
74532
74540
  .navi_meter {
74533
74541
  --loader-color: var(--navi-loader-color);
@@ -74665,7 +74673,7 @@ const Meter = ({
74665
74673
  style,
74666
74674
  ...rest
74667
74675
  }) => {
74668
- import.meta.css = [css$7, "@jsenv/navi/src/text/meter.jsx"];
74676
+ import.meta.css = [css$8, "@jsenv/navi/src/text/meter.jsx"];
74669
74677
  const defaultRef = useRef();
74670
74678
  const ref = rest.ref || defaultRef;
74671
74679
  value = Number(value);
@@ -74790,7 +74798,7 @@ const Paragraph = props => {
74790
74798
  });
74791
74799
  };
74792
74800
 
74793
- installImportMetaCssBuild(import.meta);const css$6 = /* css */`
74801
+ installImportMetaCssBuild(import.meta);const css$7 = /* css */`
74794
74802
  .navi_text_box {
74795
74803
  min-width: 0;
74796
74804
  align-items: flex-start;
@@ -74832,7 +74840,7 @@ const TextBox = ({
74832
74840
  children,
74833
74841
  ...rest
74834
74842
  }) => {
74835
- import.meta.css = [css$6, "@jsenv/navi/src/text/text_box.jsx"];
74843
+ import.meta.css = [css$7, "@jsenv/navi/src/text/text_box.jsx"];
74836
74844
  const boxRef = useRef(null);
74837
74845
  const contentRef = useRef(null);
74838
74846
  useLayoutEffect(() => {
@@ -74878,7 +74886,7 @@ const adjustWidth = (boxEl, contentEl) => {
74878
74886
  contentEl.style.width = `${Math.ceil(optimalWidth)}px`;
74879
74887
  };
74880
74888
 
74881
- installImportMetaCssBuild(import.meta);const css$5 = /* css */`
74889
+ installImportMetaCssBuild(import.meta);const css$6 = /* css */`
74882
74890
  .navi_message_box {
74883
74891
  .navi_title {
74884
74892
  margin-top: 0;
@@ -74888,7 +74896,7 @@ installImportMetaCssBuild(import.meta);const css$5 = /* css */`
74888
74896
  }
74889
74897
  `;
74890
74898
  const Title = props => {
74891
- import.meta.css = [css$5, "@jsenv/navi/src/text/title.jsx"];
74899
+ import.meta.css = [css$6, "@jsenv/navi/src/text/title.jsx"];
74892
74900
  const messageBoxStatus = useContext(MessageBoxStatusContext);
74893
74901
  const innerAs = props.as || (messageBoxStatus ? "h4" : "h1");
74894
74902
  const titleLevel = parseInt(innerAs.slice(1));
@@ -74912,7 +74920,7 @@ const useTitleLevel = () => {
74912
74920
  };
74913
74921
  const TitlePseudoClasses = [":hover"];
74914
74922
 
74915
- installImportMetaCssBuild(import.meta);const css$4 = /* css */`
74923
+ installImportMetaCssBuild(import.meta);const css$5 = /* css */`
74916
74924
  @keyframes navi_image_shimmer {
74917
74925
  0% {
74918
74926
  background-position: -200% 0;
@@ -74967,7 +74975,7 @@ const Image = ({
74967
74975
  placeholderDark = false,
74968
74976
  ...rest
74969
74977
  }) => {
74970
- import.meta.css = [css$4, "@jsenv/navi/src/graphic/image.jsx"];
74978
+ import.meta.css = [css$5, "@jsenv/navi/src/graphic/image.jsx"];
74971
74979
  const loadedRef = useRef();
74972
74980
  let resolvedPlaceholder = placeholderColor;
74973
74981
  if (resolvedPlaceholder === undefined) {
@@ -75033,7 +75041,7 @@ installImportMetaCssBuild(import.meta);/**
75033
75041
  * @param {ReactNode[]} props.children - SVG elements (first is base, rest are overlays)
75034
75042
  * @returns {ReactElement} A composed SVG with all elements properly masked
75035
75043
  */
75036
- const css$3 = /* css */`
75044
+ const css$4 = /* css */`
75037
75045
  .svg_mask_content * {
75038
75046
  color: black !important;
75039
75047
  opacity: 1 !important;
@@ -75047,7 +75055,7 @@ const SVGMaskOverlay = ({
75047
75055
  viewBox,
75048
75056
  children
75049
75057
  }) => {
75050
- import.meta.css = [css$3, "@jsenv/navi/src/graphic/svg_mask_overlay.jsx"];
75058
+ import.meta.css = [css$4, "@jsenv/navi/src/graphic/svg_mask_overlay.jsx"];
75051
75059
  if (!Array.isArray(children)) {
75052
75060
  return children;
75053
75061
  }
@@ -75111,7 +75119,7 @@ installImportMetaCssBuild(import.meta);/**
75111
75119
  * space the outer box genuinely occupies — so a narrow window shrinks the card
75112
75120
  * and still shows that room, instead of pushing it against the edges.
75113
75121
  */
75114
- const css$2 = /* css */`
75122
+ const css$3 = /* css */`
75115
75123
  @layer navi {
75116
75124
  .navi_card_layout {
75117
75125
  --layout-margin: 30px;
@@ -75217,7 +75225,7 @@ const CardLayout = ({
75217
75225
  alignY = "center",
75218
75226
  ...props
75219
75227
  }) => {
75220
- import.meta.css = [css$2, "@jsenv/navi/src/layout/card_layout.jsx"];
75228
+ import.meta.css = [css$3, "@jsenv/navi/src/layout/card_layout.jsx"];
75221
75229
  return jsx(Box, {
75222
75230
  baseClassName: "navi_card_layout",
75223
75231
  styleCSSVars: CardLayoutStyleCSSVars,
@@ -75233,6 +75241,361 @@ const CardLayout = ({
75233
75241
  });
75234
75242
  };
75235
75243
 
75244
+ installImportMetaCssBuild(import.meta);/**
75245
+ * Where one stands in a walk of steps, drawn as dots on a path.
75246
+ *
75247
+ * Two distinct facts, drawn separately — they usually agree, and everything
75248
+ * this component says comes from the moments they do not:
75249
+ *
75250
+ * - the PATH (`reached`): how far the steps are answered without a gap. A
75251
+ * solid line runs from the first dot to the step it names, and those dots
75252
+ * are filled; past it the line is dashed — the road not walked yet. It
75253
+ * moves when a step is answered, not when one merely looks around.
75254
+ * - the POSITION (`current`): the step being looked at, marked by a halo
75255
+ * around its dot and its label emphasized. It travels freely, so it can be
75256
+ * AHEAD of the path (browsing step 3 while step 1 still misses an answer)
75257
+ * or BEHIND it (back on step 1 to change something already answered).
75258
+ *
75259
+ * Both move smoothly on change (a CSS transition each), so pressing a step
75260
+ * or answering one is seen travelling rather than jumping.
75261
+ *
75262
+ * The dots are drawn in SVG, twice: a muted layer, and a filled layer
75263
+ * clipped at the path's edge — the clip is what makes the path's progress a
75264
+ * single sweep that fills the line and the dots it crosses in one movement.
75265
+ * The line is drawn as segments between the dots (never behind them), so the
75266
+ * dots need no background of their own and the component sits on any
75267
+ * surface. Colors are CSS custom properties (see the css below), overridden
75268
+ * from outside for a dark band or a different accent.
75269
+ *
75270
+ * The steps are the CHILDREN — <StepList.Item value="club">Club</StepList.Item>
75271
+ * — read off the vnodes (toChildArray, so a .map() or a fragment is fine; a
75272
+ * component of your own wrapping an Item is not seen). The Item renders its
75273
+ * label; everything positional is this component's business.
75274
+ */
75275
+ const css$2 = /* css */`
75276
+ .navi_step_list {
75277
+ /* The knobs, in one place: accent is the path, muted is what the path
75278
+ has not reached, on-accent writes on filled dots. --step-list-path-line
75279
+ exists apart from the accent for a dark band where the walked line
75280
+ reads better plain white. */
75281
+ --step-list-accent: #4f8ef7;
75282
+ --step-list-on-accent: white;
75283
+ --step-list-muted: light-dark(#8a93a8, #8b99b8);
75284
+ --step-list-line: light-dark(#c9d0dd, rgba(255, 255, 255, 0.35));
75285
+ --step-list-current-color: light-dark(#1c2433, white);
75286
+ --step-list-path-line: var(--step-list-accent);
75287
+
75288
+ position: relative;
75289
+ display: block;
75290
+ height: 64px;
75291
+ }
75292
+ .navi_step_list_rail {
75293
+ position: absolute;
75294
+ top: 0;
75295
+ left: 0;
75296
+ pointer-events: none;
75297
+ }
75298
+ /* The road not walked yet. */
75299
+ .navi_step_list_rail line {
75300
+ stroke: var(--step-list-line);
75301
+ stroke-width: 2;
75302
+ stroke-dasharray: 4 5;
75303
+ }
75304
+ .navi_step_list_rail circle {
75305
+ fill: none;
75306
+ stroke: var(--step-list-muted);
75307
+ stroke-width: 1.5;
75308
+ }
75309
+ .navi_step_list_rail text {
75310
+ font-weight: 600;
75311
+ font-size: 12px;
75312
+ fill: var(--step-list-muted);
75313
+ }
75314
+ /* The path: same drawing, filled, revealed up to the step it has come to.
75315
+ The clip is set inline (a width in px); transitioning it is what makes
75316
+ an answered step SWEEP the line and the next dot rather than pop. */
75317
+ .navi_step_list_rail_filled {
75318
+ transition: clip-path 300ms ease;
75319
+ }
75320
+ .navi_step_list_rail_filled line {
75321
+ stroke: var(--step-list-path-line);
75322
+ stroke-dasharray: none;
75323
+ }
75324
+ .navi_step_list_rail_filled circle {
75325
+ fill: var(--step-list-accent);
75326
+ stroke: var(--step-list-accent);
75327
+ }
75328
+ .navi_step_list_rail_filled text {
75329
+ fill: var(--step-list-on-accent);
75330
+ }
75331
+ /* The position: a halo around the dot being looked at. It slides from dot
75332
+ to dot (transform, transitioned) — the g moves, the circle inside is
75333
+ drawn at x=0. */
75334
+ .navi_step_list_marker {
75335
+ transition: transform 300ms ease;
75336
+ }
75337
+ .navi_step_list_marker circle {
75338
+ fill: none;
75339
+ stroke: color-mix(in srgb, var(--step-list-accent) 65%, transparent);
75340
+ stroke-width: 1.5;
75341
+ }
75342
+ /* One press target per step, covering the dot AND the label under it. The
75343
+ feedback is NOT the whole surface: a rectangle would say the whole band
75344
+ is a button, when the affordance is the dot — so hover and focus land on
75345
+ a circle drawn over the dot (::before), plus the label brightening.
75346
+ --step-dot-x anchors both on the dot, wherever the dot sits in the slot:
75347
+ the first and last slots are asymmetric (cut at the container's edge,
75348
+ see the geometry in the component). */
75349
+ .navi_step_list_slot {
75350
+ position: absolute;
75351
+ top: 0;
75352
+ box-sizing: border-box;
75353
+ height: 100%;
75354
+ }
75355
+ /* Doubled selector: the discrete variant declares its own hover background
75356
+ var, and navi's stylesheet is injected after this one — specificity is
75357
+ what makes these values the ones read. */
75358
+ .navi_step_list .navi_step_list_step {
75359
+ position: relative;
75360
+ display: block;
75361
+ width: 100%;
75362
+ height: 100%;
75363
+ padding: 0;
75364
+ font-size: 12px;
75365
+ outline: none;
75366
+ --button-color: var(--step-list-muted);
75367
+ --button-color-readonly: var(--step-list-muted);
75368
+ --button-background-color: transparent;
75369
+ --button-background-color-hover: transparent;
75370
+ --button-background-color-readonly: transparent;
75371
+ }
75372
+ /* Centered on the dot: same vertical middle as the rail (top 0, height 34,
75373
+ cy 17). */
75374
+ .navi_step_list_step::before {
75375
+ position: absolute;
75376
+ top: 17px;
75377
+ left: var(--step-dot-x);
75378
+ width: 30px;
75379
+ height: 30px;
75380
+ border-radius: 50%;
75381
+ translate: -50% -50%;
75382
+ content: "";
75383
+ }
75384
+ .navi_step_list_step:hover::before,
75385
+ .navi_step_list_step[data-hover]::before {
75386
+ background: color-mix(in srgb, var(--step-list-accent) 15%, transparent);
75387
+ }
75388
+ .navi_step_list .navi_step_list_step:hover,
75389
+ .navi_step_list .navi_step_list_step[data-hover] {
75390
+ --button-color: var(--step-list-current-color);
75391
+ }
75392
+ .navi_step_list_step:focus-visible::before,
75393
+ .navi_step_list_step[data-focus-visible]::before {
75394
+ outline-width: var(--navi-focus-outline-width);
75395
+ outline-style: solid;
75396
+ outline-color: var(--navi-focus-outline-color);
75397
+ outline-offset: 1px;
75398
+ }
75399
+ .navi_step_list_label {
75400
+ position: absolute;
75401
+ bottom: 6px;
75402
+ left: var(--step-dot-x);
75403
+ white-space: nowrap;
75404
+ translate: -50% 0;
75405
+ }
75406
+ .navi_step_list .navi_step_list_step[data-current] {
75407
+ font-weight: 600;
75408
+ --button-color: var(--step-list-current-color);
75409
+ --button-color-readonly: var(--step-list-current-color);
75410
+ }
75411
+ `;
75412
+ const RAIL_H = 34;
75413
+ const DOT_R = 11;
75414
+ const RING_R = 14.5;
75415
+ // Room for the first and last dot (and their halo) not to touch the edges.
75416
+ const EDGE_INSET = 30;
75417
+ // Between a dot's edge and the line running to the next one: enough for the
75418
+ // halo of a current dot not to sit on the line.
75419
+ const LINE_GAP = 5;
75420
+
75421
+ /**
75422
+ * @type {import("ignore:preact").FunctionComponent<{
75423
+ * current?: string,
75424
+ * reached?: string,
75425
+ * onStepPress?: (value: string, event: Event) => void,
75426
+ * [key: string]: any,
75427
+ * }>}
75428
+ * @param {string} [current] - the step being looked at: its dot gets the
75429
+ * halo, its label the emphasis. Omit for "nowhere" — a confirmation
75430
+ * screen after the walk, say.
75431
+ * @param {string} [reached] - the step the path has come to: the line is
75432
+ * solid and the dots filled up to it, dashed past it. Omit for a path
75433
+ * that has not started.
75434
+ * @param {(value: string, event: Event) => void} [onStepPress] - a step was
75435
+ * pressed. Without it the steps are read-only — shown, not offered.
75436
+ */
75437
+ const StepList = ({
75438
+ current,
75439
+ reached,
75440
+ onStepPress,
75441
+ children,
75442
+ ...rest
75443
+ }) => {
75444
+ import.meta.css = [css$2, "@jsenv/navi/src/layout/step_list.jsx"];
75445
+ const rootRef = useRef();
75446
+ // The dots spread over whatever width the component is given, so the
75447
+ // geometry is measured rather than declared — and measured again when the
75448
+ // room changes.
75449
+ const [width, setWidth] = useState(0);
75450
+ useLayoutEffect(() => {
75451
+ const rootElement = rootRef.current;
75452
+ const measure = () => {
75453
+ setWidth(rootElement.clientWidth);
75454
+ };
75455
+ measure();
75456
+ const observer = new ResizeObserver(measure);
75457
+ observer.observe(rootElement);
75458
+ return () => {
75459
+ observer.disconnect();
75460
+ };
75461
+ }, []);
75462
+
75463
+ // The steps, read off the children: each <StepList.Item> vnode says which
75464
+ // step it is (value) and is rendered as the label under its dot.
75465
+ const stepVNodes = toChildArray(children).filter(child => child && child.props);
75466
+ const stepCount = stepVNodes.length;
75467
+ const valueOf = (vnode, index) => vnode.props.value ?? String(index);
75468
+ const dotXs = [];
75469
+ if (width > 0 && stepCount > 0) {
75470
+ const span = width - EDGE_INSET * 2;
75471
+ let index = 0;
75472
+ while (index < stepCount) {
75473
+ dotXs.push(stepCount === 1 ? width / 2 : EDGE_INSET + span * index / (stepCount - 1));
75474
+ index++;
75475
+ }
75476
+ }
75477
+ const indexOf = value => stepVNodes.findIndex((vnode, index) => valueOf(vnode, index) === value);
75478
+ const currentIndex = current === undefined ? -1 : indexOf(current);
75479
+ const reachedIndex = reached === undefined ? -1 : indexOf(reached);
75480
+ // Covers the reached dot entirely (radius plus stroke), and nothing when
75481
+ // the path has not started.
75482
+ const fillX = reachedIndex === -1 ? 0 : dotXs[reachedIndex] + DOT_R + 3;
75483
+ const cy = RAIL_H / 2;
75484
+ const slotWidth = dotXs.length > 1 ? dotXs[1] - dotXs[0] : width;
75485
+ const renderRail = filled => jsx("svg", {
75486
+ className: filled ? "navi_step_list_rail navi_step_list_rail_filled" : "navi_step_list_rail",
75487
+ style: filled ? {
75488
+ clipPath: `inset(0 ${width - fillX}px 0 0)`
75489
+ } : undefined,
75490
+ width: width,
75491
+ height: RAIL_H,
75492
+ viewBox: `0 0 ${width} ${RAIL_H}`,
75493
+ "aria-hidden": "true",
75494
+ children: dotXs.map((x, index) => jsxs("g", {
75495
+ children: [index > 0 ? jsx("line", {
75496
+ x1: dotXs[index - 1] + DOT_R + LINE_GAP,
75497
+ y1: cy,
75498
+ x2: x - DOT_R - LINE_GAP,
75499
+ y2: cy
75500
+ }) : null, jsx("circle", {
75501
+ cx: x,
75502
+ cy: cy,
75503
+ r: DOT_R
75504
+ }), jsx("text", {
75505
+ x: x,
75506
+ y: cy,
75507
+ dy: "0.36em",
75508
+ "text-anchor": "middle",
75509
+ children: index + 1
75510
+ })]
75511
+ }, valueOf(stepVNodes[index], index)))
75512
+ });
75513
+ return jsx(Box, {
75514
+ ...rest,
75515
+ ref: rootRef,
75516
+ baseClassName: "navi_step_list",
75517
+ "data-step-list": "",
75518
+ children: width > 0 && stepCount > 0 ? jsxs(Fragment$1, {
75519
+ children: [renderRail(false), renderRail(true), currentIndex !== -1 && dotXs[currentIndex] !== undefined ? jsx("svg", {
75520
+ className: "navi_step_list_rail",
75521
+ width: width,
75522
+ height: RAIL_H,
75523
+ viewBox: `0 0 ${width} ${RAIL_H}`,
75524
+ "aria-hidden": "true",
75525
+ children: jsx("g", {
75526
+ className: "navi_step_list_marker",
75527
+ style: {
75528
+ transform: `translateX(${dotXs[currentIndex]}px)`
75529
+ },
75530
+ children: jsx("circle", {
75531
+ cx: "0",
75532
+ cy: cy,
75533
+ r: RING_R
75534
+ })
75535
+ })
75536
+ }) : null, stepVNodes.map((stepVNode, index) => {
75537
+ const value = valueOf(stepVNode, index);
75538
+ // Whatever else the Item was given reaches its button — a
75539
+ // pseudoState held for a demo, an aria attribute.
75540
+ const itemRest = {
75541
+ ...stepVNode.props
75542
+ };
75543
+ delete itemRest.value;
75544
+ delete itemRest.children;
75545
+ // The slots tile the row, cut at the container's edges: the
75546
+ // first and the last cover only the inner half of the room an
75547
+ // interior slot gets, so pressing just outside the box presses
75548
+ // nothing.
75549
+ const first = index === 0;
75550
+ const last = index === stepCount - 1;
75551
+ const slotLeft = first ? dotXs[index] - EDGE_INSET : dotXs[index] - slotWidth / 2;
75552
+ const slotRight = last ? dotXs[index] + EDGE_INSET : dotXs[index] + slotWidth / 2;
75553
+ return jsx("div", {
75554
+ className: "navi_step_list_slot",
75555
+ style: {
75556
+ "left": `${slotLeft}px`,
75557
+ "width": `${slotRight - slotLeft}px`,
75558
+ "--step-dot-x": `${dotXs[index] - slotLeft}px`
75559
+ },
75560
+ children: jsx(Button, {
75561
+ ...itemRest,
75562
+ variant: "discrete",
75563
+ className: "navi_step_list_step",
75564
+ "aria-current": index === currentIndex ? "step" : undefined,
75565
+ "data-current": index === currentIndex ? "" : undefined,
75566
+ readOnly: !onStepPress,
75567
+ onClick: onStepPress ? e => {
75568
+ onStepPress(value, e);
75569
+ } : undefined,
75570
+ children: jsx("span", {
75571
+ className: "navi_step_list_label",
75572
+ children: stepVNode
75573
+ })
75574
+ })
75575
+ }, value);
75576
+ })]
75577
+ }) : null
75578
+ });
75579
+ };
75580
+
75581
+ /**
75582
+ * One step of the walk: `value` names it (what `current`/`reached` say and
75583
+ * what a press reports), the children are its label. Rendered under its dot;
75584
+ * where the dot is, and what state it shows, is the StepList's business.
75585
+ *
75586
+ * It is both StepList.Item and an export of its own, the way Slide is to
75587
+ * SlideContainer.
75588
+ *
75589
+ * @type {import("ignore:preact").FunctionComponent<{
75590
+ * value: string,
75591
+ * [key: string]: any,
75592
+ * }>}
75593
+ */
75594
+ const Step = ({
75595
+ children
75596
+ }) => children;
75597
+ StepList.Item = Step;
75598
+
75236
75599
  installImportMetaCssBuild(import.meta);const css$1 = /* css */`
75237
75600
  @layer navi {
75238
75601
  .navi_viewport_layout {
@@ -75807,5 +76170,5 @@ const UserSvg = () => jsx("svg", {
75807
76170
  })
75808
76171
  });
75809
76172
 
75810
- export { ActionRenderer, ActiveKeyboardShortcuts, Address, Badge, BadgeCount, BadgeList, Binder, Box, Button, ButtonCopyToClipboard, Caption, CardLayout, CheckSvg, CheckboxGroup, CloseSvg, Code, Col, Colgroup, Color, ConstructionSvg, ControlGroup, DaySpin, Details, Dialog, Editable, ErrorBoundary, ErrorBoundaryContext, ExclamationSvg, Expandable, EyeClosedSvg, EyeSvg, Field, FixedBar, Form, Group, Head, HeartSvg, HomeSvg, Icon, Image, Input, InputDuration, Interpolate, Label, Link, LinkAnchorSvg, LinkBlankTargetSvg, LinkCurrentSvg, List, ListItem, ListItemGroup, ListItems, Loading, LoadingDotsSvg, LoadingIndicator, LoadingIndicatorFluid, LoadingOutline, MessageBox, Meter, Nav, NaviDebug, NumberSpin, Paragraph, Picker, Popover, Popup, Quantity, RadioGroup, Route, RouteTransitionArea, RouteTravel, RowNumberCol, RowNumberTableCell, SVGMaskOverlay, SearchSvg, Select, SelectableInput, SelectionContext, Separator, SettingsSvg, SidePanel, Slide, SlideContainer, Spin, SpinGroup, SplitButton, StarSvg, SummaryMarker, Svg, Table, TableCell, Tbody, Text, TextBox, Textarea, TextareaCharCount, Thead, Time, TimeRangeSpin, TimeRangeWheel, TimeSpin, TimeWheel, Title, Tr, UITransition, Unit, UserSvg, ViewportLayout, Wheel, WheelGroup, WheelItem, actionRunEffect, anyMatchingRouteSignal, applySearch, arraySignalMembership, canNavBackSignal, canNavForwardSignal, coarsePointerSignal, compareTwoJsValues, createAction, createAvailableConstraint, createI18n, createRequestCanceller, createSearch, createSelectionKeyboardShortcuts, createSlot, defineInteractionDetector, defineNaviConfirmPopupOptions, defineRouteDefaultTransition, defineRouteTransition, detectHorizontalOverflow, enableDebugActions, enableDebugOnDocumentLoading, ensureDocumentStartViewTransition, errorIsDisplayed, filterTableSelection, formatDatetime, formatDay, formatDayRelative, formatMonth, formatNumber, formatTime, formatTimeRelative, getNowHours, getNowHoursRoundedToStep, interpolateText, isCellSelected, isColumnSelected, isRowSelected, isScrolling, isToday, languagesSignal, localStorageSignal, markErrorAsDisplayedBy, moveArrayItemByIndex, navBack, navForward, navIntegratedVia, navTo, naviI18n, openCallout, rawUrlPart, registerGlobalConstraint, reload, rerunActions, resource, route, routeAction, scrollActivitySignal, setBaseUrl, setPreferredLanguage, setSupportedLanguages, setUrlTargetOptions, setupRoutes, smallTouchScreenSignal, stateSignal, stopLoad, stringifyTableSelectionValue, swapArrayItemByIndex, syncOwnedResourceToSignals, syncResourceToSignals, triggerNaviCommand, updateActions, useActionStatus, useArraySignalMembership, useAsyncData, useCalloutRequestClose, useCanNavBack, useCanNavForward, useCancelPrevious, useCellGridFromRows, useConstraintValidityState, useDependenciesDiff, useDisplayedLayoutEffect, useDocumentResource, useDocumentState, useDocumentUrl, useEditionController, useFocusGroup, useInputGroup, useKeyboardShortcuts, useNavState, useOrderedColumns, usePopupMode, useRouteStatus, useRunOnMount, useSearchText, useSelectableElement, useSelectionController, useSignalSync, useSlideValue, useStateArray, useTitleLevel, useUrlSearchParam, useUrlTargetId, valueInLocalStorage, windowWidthSignal };
76173
+ export { ActionRenderer, ActiveKeyboardShortcuts, Address, Badge, BadgeCount, BadgeList, Binder, Box, Button, ButtonCopyToClipboard, Caption, CardLayout, CheckSvg, CheckboxGroup, CloseSvg, Code, Col, Colgroup, Color, ConstructionSvg, ControlGroup, DaySpin, Details, Dialog, Editable, ErrorBoundary, ErrorBoundaryContext, ExclamationSvg, Expandable, EyeClosedSvg, EyeSvg, Field, FixedBar, Form, Group, Head, HeartSvg, HomeSvg, Icon, Image, Input, InputDuration, Interpolate, Label, Link, LinkAnchorSvg, LinkBlankTargetSvg, LinkCurrentSvg, List, ListItem, ListItemGroup, ListItems, Loading, LoadingDotsSvg, LoadingIndicator, LoadingIndicatorFluid, LoadingOutline, MessageBox, Meter, Nav, NaviDebug, NumberSpin, Paragraph, Picker, Popover, Popup, Quantity, RadioGroup, Route, RouteTransitionArea, RouteTravel, RowNumberCol, RowNumberTableCell, SVGMaskOverlay, SearchSvg, Select, SelectableInput, SelectionContext, Separator, SettingsSvg, SidePanel, Slide, SlideContainer, Spin, SpinGroup, SplitButton, StarSvg, Step, StepList, SummaryMarker, Svg, Table, TableCell, Tbody, Text, TextBox, Textarea, TextareaCharCount, Thead, Time, TimeRangeSpin, TimeRangeWheel, TimeSpin, TimeWheel, Title, Tr, UITransition, Unit, UserSvg, ViewportLayout, Wheel, WheelGroup, WheelItem, actionRunEffect, anyMatchingRouteSignal, applySearch, arraySignalMembership, canNavBackSignal, canNavForwardSignal, coarsePointerSignal, compareTwoJsValues, createAction, createAvailableConstraint, createI18n, createRequestCanceller, createSearch, createSelectionKeyboardShortcuts, createSlot, defineInteractionDetector, defineNaviConfirmPopupOptions, defineRouteDefaultTransition, defineRouteTransition, detectHorizontalOverflow, enableDebugActions, enableDebugOnDocumentLoading, ensureDocumentStartViewTransition, errorIsDisplayed, filterTableSelection, formatDatetime, formatDay, formatDayRelative, formatMonth, formatNumber, formatTime, formatTimeRelative, getNowHours, getNowHoursRoundedToStep, interpolateText, isCellSelected, isColumnSelected, isRowSelected, isScrolling, isToday, languagesSignal, localStorageSignal, markErrorAsDisplayedBy, moveArrayItemByIndex, navBack, navForward, navIntegratedVia, navTo, naviI18n, openCallout, rawUrlPart, registerGlobalConstraint, reload, rerunActions, resource, route, routeAction, scrollActivitySignal, setBaseUrl, setPreferredLanguage, setSupportedLanguages, setUrlTargetOptions, setupRoutes, smallTouchScreenSignal, stateSignal, stopLoad, stringifyTableSelectionValue, swapArrayItemByIndex, syncOwnedResourceToSignals, syncResourceToSignals, triggerNaviCommand, updateActions, useActionStatus, useArraySignalMembership, useAsyncData, useCalloutRequestClose, useCanNavBack, useCanNavForward, useCancelPrevious, useCellGridFromRows, useConstraintValidityState, useDependenciesDiff, useDisplayedLayoutEffect, useDocumentResource, useDocumentState, useDocumentUrl, useEditionController, useFocusGroup, useInputGroup, useKeyboardShortcuts, useNavState, useOrderedColumns, usePopupMode, useRouteStatus, useRunOnMount, useSearchText, useSelectableElement, useSelectionController, useSignalSync, useSlideValue, useStateArray, useTitleLevel, useUrlSearchParam, useUrlTargetId, valueInLocalStorage, windowWidthSignal };
75811
76174
  //# sourceMappingURL=jsenv_navi.js.map