@jsenv/navi 0.29.452 → 0.29.454

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.
@@ -40077,27 +40077,34 @@ const TARGET_WAIT_MS = 1000;
40077
40077
  // covers is a render, not a fetch. Past it the popup's picture plays out on
40078
40078
  // its own.
40079
40079
  const LANDING_WAIT_MS = 300;
40080
- // The popup's own animation duration, published on the root because the
40081
- // ::view-transition tree hangs off it and inherits from nowhere else.
40080
+ // What the pictures are told — the popup's pace, the lifted card's paint, the
40081
+ // corners — is written on ::view-transition (transition_values.js), the root of
40082
+ // the pseudo-element tree they inherit from. Never on the document's root: a
40083
+ // custom property there is inherited by every element, and writing or removing
40084
+ // it restyles the whole document — at the press, again when the app reads
40085
+ // style before the first picture, and once more as the movement ends.
40086
+ //
40087
+ // The popup's own animation duration, for the pictures; the wall reads it off
40088
+ // the popup itself (dialog.jsx).
40082
40089
  const DURATION_PROPERTY = "--navi-popup-lift-duration";
40083
40090
  // The fixed bars (fixed_bar.jsx): the popup is placed in the room between
40084
40091
  // them, and the moving picture is clipped to that room on the way.
40085
40092
  const FIXED_BAR_SELECTOR = ".navi_fixed_bar";
40086
- // The paint of the lifted node, published the same way: the box wears the
40087
- // card's own background, so where it has grown past the picture it carries it
40088
- // is the card that has grown, not a picture fading into a bigger one. Read off
40089
- // the lifted node rather than the anchor: the anchor is often a bare trigger
40090
- // around the card, painting nothing of its own, while the lifted node IS the
40091
- // card — and a card does not change colour on the way.
40093
+ // The paint of the lifted node: the box wears the card's own background, so
40094
+ // where it has grown past the picture it carries it is the card that has
40095
+ // grown, not a picture fading into a bigger one. Read off the lifted node
40096
+ // rather than the anchor: the anchor is often a bare trigger around the card,
40097
+ // painting nothing of its own, while the lifted node IS the card — and a card
40098
+ // does not change colour on the way.
40092
40099
  const BACKGROUND_COLOR_PROPERTY = "--navi-popup-lift-background-color";
40093
40100
  const BACKGROUND_IMAGE_PROPERTY = "--navi-popup-lift-background-image";
40094
- // The corners of the box the movement starts from, published the same way —
40095
- // and, unlike the paint, not kept for the length of the movement: a corner is
40096
- // written per box, on purpose, the same card at two sizes not wanting the same
40097
- // round (a 6px corner stops showing on a big card). The moving box leaves with
40098
- // the corners of the box it leaves and arrives with those of the box it
40099
- // arrives on, the two authored values interpolated on the group's own clock
40100
- // (see animateMovingBox).
40101
+ // The corners of the box the movement starts from — and, unlike the paint, not
40102
+ // kept for the length of the movement: a corner is written per box, on
40103
+ // purpose, the same card at two sizes not wanting the same round (a 6px corner
40104
+ // stops showing on a big card). The moving box leaves with the corners of the
40105
+ // box it leaves and arrives with those of the box it arrives on, the two
40106
+ // authored values interpolated on the group's own clock (see
40107
+ // animateMovingBox).
40101
40108
  const BORDER_RADIUS_PROPERTY = "--navi-popup-lift-border-radius";
40102
40109
 
40103
40110
  let releaseLiftInProgress = null;
@@ -40158,11 +40165,9 @@ const liftPopupFromAnchor = (
40158
40165
  releaseLiftInProgress?.();
40159
40166
 
40160
40167
  const elementLeaving = opened ? resolveAnchor() : resolveLiftTarget(popupEl);
40161
- // Everything read about the leaving side, before the first write. A read
40162
- // brings the style up to date, and the writes below land on the root — an
40163
- // attribute or an unregistered custom property there invalidates the
40164
- // computed style of every element — so a read placed after any of them is
40165
- // the whole document's style over again. Nothing on the leaving side moves
40168
+ // Everything read about the leaving side, before the first write: a read
40169
+ // brings the style up to date, and one placed after the writes below would
40170
+ // pay for them on the spot, in the press. Nothing on the leaving side moves
40166
40171
  // before the movement, the page being held from here on.
40167
40172
  releaseScrollHold = trapScrollInside(popupEl, { backdrop: true });
40168
40173
  const duration = getComputedStyle(popupEl)
@@ -40180,9 +40185,9 @@ const liftPopupFromAnchor = (
40180
40185
  // Empty would substitute into `animation-duration:` as nothing at all,
40181
40186
  // which computes to 0s — a movement nobody sees rather than one at the
40182
40187
  // browser's own pace.
40183
- root.style.setProperty(DURATION_PROPERTY, duration);
40188
+ setTransitionValue(DURATION_PROPERTY, duration);
40184
40189
  }
40185
- root.style.setProperty(BORDER_RADIUS_PROPERTY, cornersLeaving);
40190
+ setTransitionValue(BORDER_RADIUS_PROPERTY, cornersLeaving);
40186
40191
  if (paintLeaving) {
40187
40192
  publishBoxPaint(paintLeaving);
40188
40193
  }
@@ -40209,10 +40214,10 @@ const liftPopupFromAnchor = (
40209
40214
  root.removeAttribute(ROOT_ATTRIBUTE);
40210
40215
  root.removeAttribute(KIND_ATTRIBUTE);
40211
40216
  root.removeAttribute(FIT_ATTRIBUTE);
40212
- root.style.removeProperty(DURATION_PROPERTY);
40213
- root.style.removeProperty(BORDER_RADIUS_PROPERTY);
40214
- root.style.removeProperty(BACKGROUND_COLOR_PROPERTY);
40215
- root.style.removeProperty(BACKGROUND_IMAGE_PROPERTY);
40217
+ removeTransitionValue(DURATION_PROPERTY);
40218
+ removeTransitionValue(BORDER_RADIUS_PROPERTY);
40219
+ removeTransitionValue(BACKGROUND_COLOR_PROPERTY);
40220
+ removeTransitionValue(BACKGROUND_IMAGE_PROPERTY);
40216
40221
  callLiftOverCallbacks();
40217
40222
  };
40218
40223
  releaseLiftInProgress = release;
@@ -40298,8 +40303,6 @@ const liftPopupFromAnchor = (
40298
40303
  if (lift === "box") {
40299
40304
  warnDrawingLiftedAsBox(target);
40300
40305
  }
40301
- // The last write before the transition: nothing reads between it and the
40302
- // style pass the browser makes on its own to take the first picture.
40303
40306
  publishBoxPaint(readBoxPaint(target));
40304
40307
  startMovement(reveal, () => target);
40305
40308
  };
@@ -40351,9 +40354,8 @@ const readBoxPaint = (liftedElement) => {
40351
40354
  };
40352
40355
 
40353
40356
  const publishBoxPaint = ({ backgroundColor, backgroundImage }) => {
40354
- const root = document.documentElement;
40355
- root.style.setProperty(BACKGROUND_COLOR_PROPERTY, backgroundColor);
40356
- root.style.setProperty(BACKGROUND_IMAGE_PROPERTY, backgroundImage);
40357
+ setTransitionValue(BACKGROUND_COLOR_PROPERTY, backgroundColor);
40358
+ setTransitionValue(BACKGROUND_IMAGE_PROPERTY, backgroundImage);
40357
40359
  };
40358
40360
 
40359
40361
  // The corners of a box: the first round found going down through children
@@ -40606,6 +40608,50 @@ const callLiftOverCallbacks = () => {
40606
40608
  });
40607
40609
  };
40608
40610
 
40611
+ /**
40612
+ * What a gesture changes in a closed picker is sent at once.
40613
+ *
40614
+ * A picker's `action` waits for its popup to close: what is done in there is
40615
+ * one answer, given when the person is done. A change made while the popup is
40616
+ * closed — a chip's cross, a paste, a cut, a value proposed from beside it
40617
+ * (`--navi-update`) — has no close coming, so nothing would ever send it: the
40618
+ * value moves on screen and the record behind it stays. Each of those gestures
40619
+ * calls this right after setting the value; a failing action puts the value
40620
+ * back (resetOnError), as it does after a close.
40621
+ *
40622
+ * Called by gestures only. A value set without one — a bound signal followed, a
40623
+ * cancel or a failure rolled back — is the picker being told, not asked, which
40624
+ * is why this is not a reaction to every value set on a closed picker.
40625
+ *
40626
+ * The clear cross does the same through `--navi-send` (see --navi-clear in
40627
+ * commands.js), and so does not come through here.
40628
+ */
40629
+
40630
+
40631
+ const sendClosedPickerChange = (element, { event, name, requester }) => {
40632
+ const controlHost = findControlHost(element) || element;
40633
+ const controlRoot = findControlRoot(controlHost);
40634
+ if (!controlRoot || controlRoot.getAttribute("navi-control") !== "picker") {
40635
+ return;
40636
+ }
40637
+ if (controlRoot.getAttribute("aria-expanded") === "true") {
40638
+ return;
40639
+ }
40640
+ const { props } = controlHost.__uiStateController__;
40641
+ if (!props.action) {
40642
+ return;
40643
+ }
40644
+ // A picker that picks nothing (`type="confirm"`, a menu of actions) holds no
40645
+ // value its action would be sending: that action is the yes of its popup,
40646
+ // and a paste landing on the trigger must not say it.
40647
+ if (props.picksNothing) {
40648
+ return;
40649
+ }
40650
+ // `requester`: the source of a command may have claimed the press to send
40651
+ // this very change (see isAimedAtSelfInteractionsBelow).
40652
+ dispatchRequestAction(controlHost, { event, name, requester });
40653
+ };
40654
+
40609
40655
  /**
40610
40656
  * Runs a navi command from JS. It is the LAST RESORT: the attributes say the
40611
40657
  * same thing declaratively and go through this very function, so a press that
@@ -40997,6 +41043,11 @@ registerNaviCommand("--navi-update", (source, event, { argument }) => {
40997
41043
  event,
40998
41044
  behavior: argument,
40999
41045
  });
41046
+ sendClosedPickerChange(target, {
41047
+ event,
41048
+ name: "--navi-update",
41049
+ requester: source,
41050
+ });
41000
41051
  },
41001
41052
  });
41002
41053
  },
@@ -52060,11 +52111,15 @@ const LinkWithRoute = ({
52060
52111
  also: currentAlso
52061
52112
  });
52062
52113
  const innerCurrent = current || linkMatching;
52114
+
52115
+ // What a childless link shows is LinkPlain's call (hrefFallback); a route
52116
+ // only says it the way its pattern writes it, not as the resolved href.
52063
52117
  return jsx(Link, {
52064
52118
  href: url,
52119
+ hrefText: route.buildRelativeUrl(routeParams),
52065
52120
  current: innerCurrent,
52066
52121
  ...rest,
52067
- children: children || route.buildRelativeUrl(routeParams)
52122
+ children: children
52068
52123
  });
52069
52124
  };
52070
52125
  const LinkPlain = props => {
@@ -52090,6 +52145,7 @@ const LinkPlain = props => {
52090
52145
  revealOnInteraction = false,
52091
52146
  stretch,
52092
52147
  hrefFallback = !anchor,
52148
+ hrefText = href,
52093
52149
  routeTransition,
52094
52150
  pressableDuringRouteTransition,
52095
52151
  replace,
@@ -52225,7 +52281,7 @@ const LinkPlain = props => {
52225
52281
  const documentRequest = isDocument ? {
52226
52282
  [LINK_DOCUMENT_ATTRIBUTE]: ""
52227
52283
  } : null;
52228
- const innerChildren = children || (hrefFallback ? href : children);
52284
+ const innerChildren = children || (hrefFallback ? hrefText : children);
52229
52285
  const startIconEl = startIcon;
52230
52286
  const endIconEl = innerEndIcon;
52231
52287
 
@@ -52276,6 +52332,7 @@ const LinkPlain = props => {
52276
52332
  startIcon: undefined,
52277
52333
  endIcon: undefined,
52278
52334
  hrefFallback: undefined,
52335
+ hrefText: undefined,
52279
52336
  routeTransition: undefined,
52280
52337
  pressableDuringRouteTransition: undefined,
52281
52338
  replace: undefined,
@@ -66406,6 +66463,70 @@ const giveUpOnControlsHoldingPopup = (controlsHolding, reason) => {
66406
66463
  */
66407
66464
 
66408
66465
  const popupCss = /* css */ `
66466
+ /* Not inherited: what the placement writes on a popup (applyNewPosition in
66467
+ @jsenv/dom) and what the popup derives from it are read by the popup
66468
+ alone, for its own size and cut. Inherited, every element of its content
66469
+ carries a copy, and each placement restyles all of them before the first
66470
+ frame. A popup nested in another also stops reading the outer one's values
66471
+ where its own are unset. "*" keeps them untyped: var() substitutes them as
66472
+ it does an unregistered property. */
66473
+ @property --container-position-room-top {
66474
+ syntax: "*";
66475
+ inherits: false;
66476
+ }
66477
+ @property --container-position-room-right {
66478
+ syntax: "*";
66479
+ inherits: false;
66480
+ }
66481
+ @property --container-position-room-bottom {
66482
+ syntax: "*";
66483
+ inherits: false;
66484
+ }
66485
+ @property --container-position-room-left {
66486
+ syntax: "*";
66487
+ inherits: false;
66488
+ }
66489
+ @property --container-position-remaining-height {
66490
+ syntax: "*";
66491
+ inherits: false;
66492
+ }
66493
+ @property --container-position-remaining-width {
66494
+ syntax: "*";
66495
+ inherits: false;
66496
+ }
66497
+ @property --x-popup-cut-top-at-area {
66498
+ syntax: "*";
66499
+ inherits: false;
66500
+ }
66501
+ @property --x-popup-cut-right-at-area {
66502
+ syntax: "*";
66503
+ inherits: false;
66504
+ }
66505
+ @property --x-popup-cut-bottom-at-area {
66506
+ syntax: "*";
66507
+ inherits: false;
66508
+ }
66509
+ @property --x-popup-cut-left-at-area {
66510
+ syntax: "*";
66511
+ inherits: false;
66512
+ }
66513
+ @property --x-popup-cut-top {
66514
+ syntax: "*";
66515
+ inherits: false;
66516
+ }
66517
+ @property --x-popup-cut-right {
66518
+ syntax: "*";
66519
+ inherits: false;
66520
+ }
66521
+ @property --x-popup-cut-bottom {
66522
+ syntax: "*";
66523
+ inherits: false;
66524
+ }
66525
+ @property --x-popup-cut-left {
66526
+ syntax: "*";
66527
+ inherits: false;
66528
+ }
66529
+
66409
66530
  @layer navi {
66410
66531
  .navi_popover,
66411
66532
  .navi_dialog {
@@ -66420,29 +66541,6 @@ const popupCss = /* css */ `
66420
66541
 
66421
66542
  .navi_popover,
66422
66543
  .navi_dialog {
66423
- /* The translate property is deliberately absent from this list — it
66424
- carries where the popup stands, and applyNewPosition (visible_rect.js)
66425
- owns it and drives its own transition through the Web Animations API
66426
- instead of CSS, so it stays independent of whatever this list contains
66427
- (no shared transition-property to clobber, no propertyName to filter).
66428
- What moves here is transform, which composes under it. */
66429
- &[navi-animation] {
66430
- /* clip-path takes the translate's own duration, for the one cut that
66431
- still moves (a band of glass beside the app — see this file's top
66432
- comment for why every other cut is a constant). A constant cut, or a
66433
- kind that sets none, has the same value on both sides of the change,
66434
- which costs nothing. */
66435
- transition-property:
66436
- display, overlay, opacity, transform, scale, box-shadow, clip-path;
66437
- transition-duration:
66438
- var(--popup-animation-duration), var(--popup-animation-duration),
66439
- var(--popup-opacity-duration), var(--popup-translate-duration),
66440
- var(--popup-scale-duration), var(--popup-animation-duration),
66441
- var(--popup-translate-duration);
66442
- transition-timing-function: ease;
66443
- transition-behavior: allow-discrete;
66444
- }
66445
-
66446
66544
  /* Where a travel may be cut, per side, in the popup's own coordinates.
66447
66545
  --container-position-room-* is how far past each of its own edges the
66448
66546
  popup may still paint before reaching the edge of the area it was placed
@@ -66474,6 +66572,28 @@ const popupCss = /* css */ `
66474
66572
  -1 * var(--container-position-room-left, 100vmax) - 100vmax +
66475
66573
  min(100vmax, var(--navi-app-inset-left, 0px) * 1000000)
66476
66574
  );
66575
+ /* The translate property is deliberately absent from this list — it
66576
+ carries where the popup stands, and applyNewPosition (visible_rect.js)
66577
+ owns it and drives its own transition through the Web Animations API
66578
+ instead of CSS, so it stays independent of whatever this list contains
66579
+ (no shared transition-property to clobber, no propertyName to filter).
66580
+ What moves here is transform, which composes under it. */
66581
+ &[navi-animation] {
66582
+ /* clip-path takes the translate's own duration, for the one cut that
66583
+ still moves (a band of glass beside the app — see this file's top
66584
+ comment for why every other cut is a constant). A constant cut, or a
66585
+ kind that sets none, has the same value on both sides of the change,
66586
+ which costs nothing. */
66587
+ transition-property:
66588
+ display, overlay, opacity, transform, scale, box-shadow, clip-path;
66589
+ transition-duration:
66590
+ var(--popup-animation-duration), var(--popup-animation-duration),
66591
+ var(--popup-opacity-duration), var(--popup-translate-duration),
66592
+ var(--popup-scale-duration), var(--popup-animation-duration),
66593
+ var(--popup-translate-duration);
66594
+ transition-timing-function: ease;
66595
+ transition-behavior: allow-discrete;
66596
+ }
66477
66597
  /* A local popup is clipped by its clip wrapper (a static ancestor sized to
66478
66598
  the container, overflow: hidden): nothing is left for a cut to hide. */
66479
66599
  &[data-layer="local"] {
@@ -66603,7 +66723,6 @@ const popupCss = /* css */ `
66603
66723
  transform: translate(var(--x-popup-travel-x), var(--x-popup-travel-y));
66604
66724
  }
66605
66725
  }
66606
-
66607
66726
  }
66608
66727
 
66609
66728
  .navi_popover {
@@ -66968,6 +67087,62 @@ let openLocalDialogCount = 0;
66968
67087
  const css$E = /* css */`
66969
67088
  /* jsenv-css-opaque: popupCss overlaps these rules, own sheet = cascade
66970
67089
  order depending on which popup renders first. */
67090
+
67091
+ /* Not inherited: each is written on the dialog or derived there — by its
67092
+ placement (see popup_css.js for what inheriting would cost), by its
67093
+ opening (the anchor box under sizeFromAnchor, the stack order) or from the
67094
+ minWidth/maxWidth/minHeight/maxHeight props — and read by the dialog
67095
+ alone. Inherited, a dialog nested in this one would also open at this
67096
+ one's size. */
67097
+ @property --dialog-stack-order {
67098
+ syntax: "*";
67099
+ inherits: false;
67100
+ }
67101
+ @property --anchor-width {
67102
+ syntax: "*";
67103
+ inherits: false;
67104
+ }
67105
+ @property --anchor-height {
67106
+ syntax: "*";
67107
+ inherits: false;
67108
+ }
67109
+ @property --dialog-min-width {
67110
+ syntax: "*";
67111
+ inherits: false;
67112
+ }
67113
+ @property --dialog-max-width {
67114
+ syntax: "*";
67115
+ inherits: false;
67116
+ }
67117
+ @property --dialog-min-height {
67118
+ syntax: "*";
67119
+ inherits: false;
67120
+ }
67121
+ @property --dialog-max-height {
67122
+ syntax: "*";
67123
+ inherits: false;
67124
+ }
67125
+ @property --x-dialog-container-spacing {
67126
+ syntax: "*";
67127
+ inherits: false;
67128
+ }
67129
+ @property --dialog-maxmax-width {
67130
+ syntax: "*";
67131
+ inherits: false;
67132
+ }
67133
+ @property --dialog-maxmax-height {
67134
+ syntax: "*";
67135
+ inherits: false;
67136
+ }
67137
+ @property --x-dialog-max-width {
67138
+ syntax: "*";
67139
+ inherits: false;
67140
+ }
67141
+ @property --x-dialog-max-height {
67142
+ syntax: "*";
67143
+ inherits: false;
67144
+ }
67145
+
66971
67146
  @layer navi {
66972
67147
  .navi_dialog {
66973
67148
  /* Min gap between the dialog and the edges of its container. Written
@@ -67065,18 +67240,6 @@ const css$E = /* css */`
67065
67240
  --x-corner-bottom-right-radius: initial;
67066
67241
  --x-corner-bottom-left-radius: initial;
67067
67242
 
67068
- /* Sizing is per dialog: the anchor box (sizeFromAnchor) and the
67069
- minWidth/maxWidth/minHeight/maxHeight props are written inline on THIS
67070
- element, and an inline declaration wins over these resets. Without
67071
- them, a dialog nested in another dialog would inherit its parent's
67072
- inline values and open at the parent's size. */
67073
- --anchor-width: initial;
67074
- --anchor-height: initial;
67075
- --dialog-min-width: initial;
67076
- --dialog-max-width: initial;
67077
- --dialog-min-height: initial;
67078
- --dialog-max-height: initial;
67079
-
67080
67243
  /* Computed once, reused by both max-width itself and min-width's own
67081
67244
  clamp below (see its comment for why) — avoids repeating the same
67082
67245
  min(..., ...) expression twice. */
@@ -67331,7 +67494,7 @@ const css$E = /* css */`
67331
67494
  &[aria-expanded="true"]:not([navi-transitions-off])::backdrop {
67332
67495
  opacity: 1;
67333
67496
  transition-property: opacity;
67334
- transition-duration: var(--navi-popup-lift-duration, 0.25s);
67497
+ transition-duration: var(--popup-animation-duration, 0.18s);
67335
67498
  transition-timing-function: ease;
67336
67499
 
67337
67500
  @starting-style {
@@ -67514,7 +67677,7 @@ const css$E = /* css */`
67514
67677
  &[aria-expanded="true"] {
67515
67678
  opacity: 1;
67516
67679
  transition-property: opacity;
67517
- transition-duration: var(--navi-popup-lift-duration, 0.25s);
67680
+ transition-duration: var(--popup-animation-duration);
67518
67681
  transition-timing-function: ease;
67519
67682
  }
67520
67683
  }
@@ -67552,8 +67715,9 @@ const css$E = /* css */`
67552
67715
  and unpressable while the movement plays: under a modal wall at the
67553
67716
  opening, and for the popup's --popup-animation-duration at the closing. */
67554
67717
  :root[data-navi-popup-lift] {
67555
- /* The popup's own pace, published on the root by popup_lift.js because the
67556
- ::view-transition tree hangs off it and inherits from nowhere else. */
67718
+ /* The popup's own pace, published on ::view-transition by popup_lift.js:
67719
+ the pictures inherit from nowhere else. The wall reads it off the
67720
+ dialog itself (the [data-lifting] backdrop rules above). */
67557
67721
  &::view-transition-group(navi-popup-lift),
67558
67722
  &::view-transition-old(navi-popup-lift),
67559
67723
  &::view-transition-new(navi-popup-lift),
@@ -69381,6 +69545,58 @@ let openLocalPopoverCount = 0;
69381
69545
  const css$D = /* css */`
69382
69546
  /* jsenv-css-opaque: popupCss overlaps these rules, own sheet = cascade
69383
69547
  order depending on which popup renders first. */
69548
+
69549
+ /* Not inherited: each is written on the popover or derived there — by its
69550
+ placement (the anchor box included; see popup_css.js for what inheriting
69551
+ would cost), by its opening (the stack order, which the backdrop gets a
69552
+ copy of) or from the minWidth/maxWidth/minHeight/maxHeight props — and
69553
+ read by the popover alone. Inherited, a popover nested in another popup
69554
+ would also open at the outer one's size. */
69555
+ @property --popover-stack-order {
69556
+ syntax: "*";
69557
+ inherits: false;
69558
+ }
69559
+ @property --anchor-width {
69560
+ syntax: "*";
69561
+ inherits: false;
69562
+ }
69563
+ @property --anchor-height {
69564
+ syntax: "*";
69565
+ inherits: false;
69566
+ }
69567
+ @property --anchor-inner-width {
69568
+ syntax: "*";
69569
+ inherits: false;
69570
+ }
69571
+ @property --anchor-inner-height {
69572
+ syntax: "*";
69573
+ inherits: false;
69574
+ }
69575
+ @property --popover-min-width {
69576
+ syntax: "*";
69577
+ inherits: false;
69578
+ }
69579
+ @property --popover-max-width {
69580
+ syntax: "*";
69581
+ inherits: false;
69582
+ }
69583
+ @property --popover-min-height {
69584
+ syntax: "*";
69585
+ inherits: false;
69586
+ }
69587
+ @property --popover-max-height {
69588
+ syntax: "*";
69589
+ inherits: false;
69590
+ }
69591
+ @property --x-popover-max-width {
69592
+ syntax: "*";
69593
+ inherits: false;
69594
+ }
69595
+ @property --x-popover-max-height {
69596
+ syntax: "*";
69597
+ inherits: false;
69598
+ }
69599
+
69384
69600
  @layer navi {
69385
69601
  .navi_popover {
69386
69602
  /* soft: user-configurable preferred max-height. Kept as a *default*
@@ -69442,21 +69658,6 @@ const css$D = /* css */`
69442
69658
  --x-corner-bottom-right-radius: initial;
69443
69659
  --x-corner-bottom-left-radius: initial;
69444
69660
 
69445
- /* Sizing is per popover: the anchor box and the
69446
- minWidth/maxWidth/minHeight/maxHeight props are written inline on THIS
69447
- element, and an inline declaration wins over these resets. Without
69448
- them, a popover nested in another popup (or opened without an anchor
69449
- inside one sized from its own) would inherit the outer inline values
69450
- and open at the outer size. */
69451
- --anchor-width: initial;
69452
- --anchor-height: initial;
69453
- --anchor-inner-width: initial;
69454
- --anchor-inner-height: initial;
69455
- --popover-min-width: initial;
69456
- --popover-max-width: initial;
69457
- --popover-min-height: initial;
69458
- --popover-max-height: initial;
69459
-
69460
69661
  --x-popover-max-width: min(
69461
69662
  var(--popover-max-width, var(--popover-maxmax-width)),
69462
69663
  var(--container-position-remaining-width, var(--popover-maxmax-width)),
@@ -69585,10 +69786,8 @@ const css$D = /* css */`
69585
69786
  "position: absolute" above. */
69586
69787
  &[popover] {
69587
69788
  position: fixed;
69588
- /* The native top layer already gives "last shown wins" for free —
69589
- --popover-stack-order is only ever set by the custom renderer's own
69590
- openEffect, but reset here regardless in case a consumer sets the
69591
- var directly on an ancestor. */
69789
+ /* The native top layer already gives "last shown wins" for free: the
69790
+ custom renderer's stack order has no say here. */
69592
69791
  z-index: unset;
69593
69792
  padding: 0;
69594
69793
 
@@ -82616,7 +82815,9 @@ const PickerArrayUI = /*#__PURE__*/asPickerOwnUI(() => {
82616
82815
  /**
82617
82816
  * One value the picker holds, drawn as a chip with a cross that takes it back
82618
82817
  * out. Sits wherever the application draws what was picked — on the picker's
82619
- * façade (`ui`) or inside its popup — and both behave the same.
82818
+ * façade (`ui`) or inside its popup. Inside the open popup the removal waits
82819
+ * for the close like any change made there; pressed while the popup is closed
82820
+ * it is the whole gesture, and the picker's `action` runs at once.
82620
82821
  *
82621
82822
  * The cross asks with `--navi-unselect` rather than writing a new list, and it
82622
82823
  * asks the picker — which holds what was picked, and hands it down to whatever
@@ -83648,15 +83849,25 @@ const PickerButton = props => {
83648
83849
  const displayText = pickerEl.querySelector(".navi_picker_value")?.textContent ?? String(uiState);
83649
83850
  e.clipboardData.setData("text/plain", displayText);
83650
83851
  e.clipboardData.setData("application/x-navi", JSON.stringify(uiState));
83852
+ e.preventDefault();
83853
+ // A picker that asks before its cross clears anything is not
83854
+ // emptied by a keystroke without the question: the cut copies,
83855
+ // and the value stays.
83856
+ if (clearConfirm !== undefined) {
83857
+ return;
83858
+ }
83651
83859
  // the clear ui state part need control to be interactable
83652
83860
  dispatchRequestInteraction(pickerEl, {
83653
83861
  event: e,
83654
83862
  name: "cut",
83655
83863
  allowed: () => {
83656
83864
  dispatchRequestClearUIState(inputRef.current, e);
83865
+ sendClosedPickerChange(inputRef.current, {
83866
+ event: e,
83867
+ name: "cut"
83868
+ });
83657
83869
  }
83658
83870
  });
83659
- e.preventDefault();
83660
83871
  },
83661
83872
  onPaste: e => {
83662
83873
  const pickerEl = ref.current;
@@ -83682,6 +83893,10 @@ const PickerButton = props => {
83682
83893
  dispatchRequestSetUIState(inputRef.current, pasteValue, {
83683
83894
  event: e
83684
83895
  });
83896
+ sendClosedPickerChange(inputRef.current, {
83897
+ event: e,
83898
+ name: "paste"
83899
+ });
83685
83900
  }
83686
83901
  });
83687
83902
  e.preventDefault();
@@ -83927,6 +84142,10 @@ const requestPickerListEntry = (pickerEl, pickerInputEl, e, goal) => {
83927
84142
  dispatchRequestSetUIState(pickerInputEl, uiStateNext, {
83928
84143
  event: e
83929
84144
  });
84145
+ sendClosedPickerChange(pickerInputEl, {
84146
+ event: e,
84147
+ name: goal
84148
+ });
83930
84149
  }
83931
84150
  });
83932
84151
  };
@@ -96074,6 +96293,10 @@ const css$5 = /* css */`@keyframes navi_image_shimmer {
96074
96293
  `;
96075
96294
  const DEFAULT_PLACEHOLDER_LIGHT = "#d4d8dd";
96076
96295
  const DEFAULT_PLACEHOLDER_DARK = "#374151";
96296
+ // On an <img>, width/height describe the image: they stay HTML attributes.
96297
+ // Box would write them as inline styles, which beat every stylesheet rule, so
96298
+ // an image given its file's size (3840×2160) would overflow the box sizing it.
96299
+ const IMAGE_ATTRIBUTE_PROP_SET = new Set(["width", "height"]);
96077
96300
 
96078
96301
  /**
96079
96302
  * The props may come in any order: `src` and `srcset` reach the element after
@@ -96082,6 +96305,12 @@ const DEFAULT_PLACEHOLDER_DARK = "#374151";
96082
96305
  * decides whether to load when `src` is set, and an image whose `src` came
96083
96306
  * first loads, lazy or not.
96084
96307
  *
96308
+ * @param {number} [props.width] - The image's width in pixels, written as the
96309
+ * `<img>` attribute, like `height`. Given both, the browser reserves the
96310
+ * aspect ratio before the bytes arrive. They size the element only while no
96311
+ * stylesheet rule does: a box that holds the image sizes it with CSS (or
96312
+ * `style`) and keeps the ratio.
96313
+ * @param {number} [props.height] - The image's height in pixels, see `width`.
96085
96314
  * @param {string|false} [props.placeholderColor] - Background color shown while the image loads.
96086
96315
  * Defaults to a light gray. Pass `false` to disable.
96087
96316
  * @param {boolean} [props.placeholderDark] - Use a dark default placeholder color,
@@ -96106,6 +96335,7 @@ const Image = ({
96106
96335
  ...rest,
96107
96336
  as: "img",
96108
96337
  baseClassName: "navi_image",
96338
+ childPropSet: IMAGE_ATTRIBUTE_PROP_SET,
96109
96339
  "navi-placeholder": loadedRef.current ? undefined : "",
96110
96340
  style: {
96111
96341
  "--placeholder-color": resolvedPlaceholder || undefined,