@jsenv/navi 0.29.299 → 0.29.301

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.
@@ -10587,6 +10587,8 @@ defineInteractionDetector({
10587
10587
  }
10588
10588
  let swipe = null;
10589
10589
  let press = null;
10590
+ // Set below, with the hold; a no-op until then so the swipe can call it.
10591
+ let forgetInnerLongPress = () => {};
10590
10592
 
10591
10593
  if (axes) {
10592
10594
  swipe = startSwipe(pointerDownEvent, {
@@ -10606,14 +10608,35 @@ defineInteractionDetector({
10606
10608
  onSwipeStart: () => {
10607
10609
  press?.cancel();
10608
10610
  press = null;
10611
+ forgetInnerLongPress();
10609
10612
  },
10610
10613
  });
10611
10614
  }
10612
10615
  if (hasLongPress) {
10616
+ // A hold declared INSIDE this element, on this same press: the nearer
10617
+ // one answers, the way a click is the innermost target's, and this
10618
+ // wait is given up — two sheets opening from one hold is nobody's
10619
+ // intention. Delays being equal, the inner timer was set first (the
10620
+ // press reached it first) and fires first; the inner hold arrives here
10621
+ // as its own event, bubbling, before this timer runs.
10622
+ const onInnerLongPress = (longPressEvent) => {
10623
+ if (longPressEvent.target === element || !press) {
10624
+ return;
10625
+ }
10626
+ press.cancel();
10627
+ press = null;
10628
+ forgetInnerLongPress();
10629
+ };
10630
+ forgetInnerLongPress = () => {
10631
+ element.removeEventListener("longpress", onInnerLongPress);
10632
+ };
10633
+ element.addEventListener("longpress", onInnerLongPress);
10613
10634
  press = waitForPressHeld(pointerDownEvent, {
10614
10635
  delay: readConfig(LONGPRESS_DELAY_ATTRIBUTE, LONGPRESS_DELAY_DEFAULT),
10615
10636
  slop: readConfig(LONGPRESS_SLOP_ATTRIBUTE, LONGPRESS_SLOP_DEFAULT),
10637
+ onPressCancel: forgetInnerLongPress,
10616
10638
  onPressHeld: (pressEvent, { endPress }) => {
10639
+ forgetInnerLongPress();
10617
10640
  // The hold won the arbitration: the swipe never got the distance it
10618
10641
  // needed, and must not get it from whatever the finger does next.
10619
10642
  swipe?.stop();
@@ -34631,6 +34654,12 @@ const useUIStateController = (
34631
34654
  },
34632
34655
  resetUIState: (e) => {
34633
34656
  controller.setUIState(controller.state, e);
34657
+ // What the control holds moved back, and a bound signal mirrors what
34658
+ // it holds (see PROPAGATE_DOWN_EVENT_SET). Left on the value the
34659
+ // reset just undid — written there by the control itself at the
34660
+ // pick — the signal would hand it straight back on the next render,
34661
+ // and the refused value would win over the rollback.
34662
+ writeBoundSignal(controller.state);
34634
34663
  },
34635
34664
  // Read by the callout manager when it has nowhere else to point.
34636
34665
  getCalloutAnchorElement: (event) =>
@@ -34734,9 +34763,27 @@ const useUIStateController = (
34734
34763
  controller.hasStateProp = true;
34735
34764
  const currentState = controller.state;
34736
34765
  if (!compareTwoJsValues(state, currentState)) {
34737
- controller.state = state;
34738
- if (!optimisticWorkInFlight) {
34739
- controller.setUIState(state, new CustomEvent("state_prop_change"));
34766
+ // A bound signal controls the state the way a `value` prop does —
34767
+ // and, unlike a `value`, it is written by the control itself at
34768
+ // every ui action. Read back here on a control that runs an action,
34769
+ // a signal matching the ui state is that echo (see the signal branch
34770
+ // below for the same rule on an uncontrolled control): `state` is
34771
+ // the rollback target, and taking the echo would make resetOnError
34772
+ // put back the very value the action is about to send, or has just
34773
+ // been refused. The action settles it — success acknowledges,
34774
+ // failure resets to what is kept here.
34775
+ const signalEchoesOwnWrite =
34776
+ Boolean(controlInfo.signal) &&
34777
+ Boolean(props.action) &&
34778
+ compareTwoJsValues(state, controller.uiState);
34779
+ if (!signalEchoesOwnWrite) {
34780
+ controller.state = state;
34781
+ if (!optimisticWorkInFlight) {
34782
+ controller.setUIState(
34783
+ state,
34784
+ new CustomEvent("state_prop_change"),
34785
+ );
34786
+ }
34740
34787
  }
34741
34788
  }
34742
34789
  } else {
@@ -45536,9 +45583,15 @@ const createOpenController = (
45536
45583
  change();
45537
45584
  };
45538
45585
  const runChange = (change, { opened, event }) => {
45586
+ const applyChange = () => {
45587
+ // Recorded with the change itself: what the DOM shows is what a render
45588
+ // landing between the ask and the picture must draw (see `openedInDom`).
45589
+ controller.openedInDom = opened;
45590
+ change();
45591
+ };
45539
45592
  const { transitionChange } = controller;
45540
45593
  if (!transitionChange) {
45541
- change();
45594
+ applyChange();
45542
45595
  return;
45543
45596
  }
45544
45597
  // What the controller answers about itself does not wait for the picture:
@@ -45547,10 +45600,10 @@ const createOpenController = (
45547
45600
  // caller's own signal), and a request arriving before the change lands
45548
45601
  // runs it first rather than reading a DOM that disagrees.
45549
45602
  controller.opened = opened;
45550
- changeAwaitingTransition = change;
45603
+ changeAwaitingTransition = applyChange;
45551
45604
  transitionChange(
45552
45605
  () => {
45553
- if (changeAwaitingTransition === change) {
45606
+ if (changeAwaitingTransition === applyChange) {
45554
45607
  flushChangeAwaitingTransition();
45555
45608
  }
45556
45609
  },
@@ -45668,6 +45721,13 @@ const createOpenController = (
45668
45721
  };
45669
45722
  const controller = {
45670
45723
  opened: false,
45724
+ // What the DOM currently shows, as opposed to what the controller has
45725
+ // decided: the two differ for the frame a change spends waiting for the
45726
+ // browser to photograph the state being left (see runChange). A render
45727
+ // landing in that frame — a picker re-rendering because its action just
45728
+ // started — must draw THIS, or it paints the closed state before the
45729
+ // picture is taken and the movement has nothing to leave from.
45730
+ openedInDom: false,
45671
45731
  // Which press the popup opened during, written at every open (see
45672
45732
  // openedDuringThisPress). Never any press before there has been one.
45673
45733
  pressCountAtOpen: null,
@@ -60290,14 +60350,14 @@ const useDialogProps = props => {
60290
60350
  // and matching what a descendant relying on
60291
60351
  // use_displayed_layout_effect.js's own aria-expanded-presence check
60292
60352
  // needs — see popover.jsx's own identical prop for the full reasoning.
60293
- "aria-expanded": openController.opened ? "true" : "false",
60353
+ "aria-expanded": openController.openedInDom ? "true" : "false",
60294
60354
  // Present from this very first render (recomputed fresh on every one
60295
60355
  // from openController.opened, not a frozen mount-time constant) so
60296
60356
  // there's no gap for the browser to ever paint this plain-div backdrop
60297
60357
  // visible before anything has actually opened it — see popover.jsx's
60298
60358
  // own identical prop for the full reasoning, and this file's own CSS
60299
60359
  // for the rule it drives.
60300
- "navi-hidden": openController.opened ? undefined : "",
60360
+ "navi-hidden": openController.openedInDom ? undefined : "",
60301
60361
  "styleCSSVars": DIALOG_STYLE_CSS_VARS,
60302
60362
  "animationDuration": rest.animationDuration,
60303
60363
  "data-pointer-interaction-outside": pointerInteractionOutsideEffect,
@@ -60309,7 +60369,7 @@ const useDialogProps = props => {
60309
60369
  tabIndex,
60310
60370
  // See backdropProps' own identical prop above for the full reasoning
60311
60371
  // (kept once, not repeated here).
60312
- "aria-expanded": openController.opened ? "true" : "false",
60372
+ "aria-expanded": openController.openedInDom ? "true" : "false",
60313
60373
  // Present from the very first render (recomputed fresh from
60314
60374
  // openController.opened every time, not a frozen mount-time constant —
60315
60375
  // see popover.jsx's own identical prop for the full reasoning) so a
@@ -60317,7 +60377,7 @@ const useDialogProps = props => {
60317
60377
  // can't silently defeat showModal()/close()'s native open/close — see
60318
60378
  // this file's own CSS rule for dialogEl and the open/close steps below
60319
60379
  // for how it's toggled.
60320
- "navi-hidden": openController.opened ? undefined : "",
60380
+ "navi-hidden": openController.openedInDom ? undefined : "",
60321
60381
  // Unlike Popover (which genuinely can't resolve "auto" until it
60322
60382
  // measures against a real anchor), resolvedAnimation is already fully
60323
60383
  // known synchronously here — a dialog never needs to flip anything
@@ -61940,12 +62000,12 @@ const usePopoverProps = props => {
61940
62000
  // commit (a plain prop is, no effect needed) — see
61941
62001
  // use_displayed_layout_effect.js's own comments for why a descendant
61942
62002
  // relying on aria-expanded's mere presence needs that.
61943
- "aria-expanded": openController.opened ? "true" : "false",
62003
+ "aria-expanded": openController.openedInDom ? "true" : "false",
61944
62004
  // Read fresh on every render (not frozen at mount), so it stays
61945
62005
  // correct even across a re-render that happens to occur while open —
61946
62006
  // see contentProps' own identical prop just below for the full
61947
62007
  // reasoning (kept once, not repeated here).
61948
- "navi-hidden": openController.opened ? undefined : "",
62008
+ "navi-hidden": openController.openedInDom ? undefined : "",
61949
62009
  "styleCSSVars": POPUP_STYLE_CSS_VARS,
61950
62010
  "animationDuration": rest.animationDuration,
61951
62011
  "data-pointer-interaction-outside": pointerInteractionOutsideEffect,
@@ -61994,7 +62054,7 @@ const usePopoverProps = props => {
61994
62054
  "navi-animation": isAutoAnimation ? undefined : animation,
61995
62055
  // See backdropProps' own identical prop above for the full reasoning
61996
62056
  // (kept once, not repeated here).
61997
- "aria-expanded": openController.opened ? "true" : "false",
62057
+ "aria-expanded": openController.openedInDom ? "true" : "false",
61998
62058
  // Only load-bearing for the custom renderer (a plain div has no native
61999
62059
  // starting-hidden default) — present from this very first render so
62000
62060
  // there's no gap for the browser to ever paint it visible before
@@ -62004,7 +62064,7 @@ const usePopoverProps = props => {
62004
62064
  // the last render, so as long as this always reflects the *current*
62005
62065
  // truth, it never fights the imperative
62006
62066
  // removeAttribute/setAttribute openEffect/close do directly.
62007
- "navi-hidden": openController.opened ? undefined : "",
62067
+ "navi-hidden": openController.openedInDom ? undefined : "",
62008
62068
  "styleCSSVars": POPUP_STYLE_CSS_VARS,
62009
62069
  ...rest,
62010
62070
  ...autoFocusProps,
@@ -62349,6 +62409,7 @@ const css$B = /* css */`.navi_picker {
62349
62409
  --popover-background-color: var(--picker-popup-background-color, var(--navi-popup-background-color));
62350
62410
  --popover-outline-width: var(--picker-outline-width);
62351
62411
  --popover-outline-color: var(--picker-outline-color);
62412
+ --popover-box-shadow: var(--picker-popup-box-shadow, var(--navi-popup-box-shadow));
62352
62413
  --popover-max-height: var(--picker-popover-max-height);
62353
62414
  min-width: var(--picker-popover-min-width, var(--anchor-width, 0px));
62354
62415
  cursor: default;
@@ -62385,6 +62446,7 @@ const css$B = /* css */`.navi_picker {
62385
62446
  --dialog-background-color: var(--picker-popup-background-color, var(--navi-popup-background-color));
62386
62447
  --dialog-outline-width: var(--picker-outline-width);
62387
62448
  --dialog-outline-color: var(--picker-outline-color);
62449
+ --dialog-box-shadow: var(--picker-popup-box-shadow, var(--navi-popup-box-shadow));
62388
62450
  --dialog-min-width: var(--picker-dialog-min-width);
62389
62451
  --dialog-min-height: var(--picker-dialog-min-height);
62390
62452
  --dialog-max-width: var(--picker-dialog-max-width);
@@ -62406,6 +62468,10 @@ const css$B = /* css */`.navi_picker {
62406
62468
  }
62407
62469
  }
62408
62470
  }
62471
+
62472
+ &[data-dialog-size-from-anchor] .navi_dialog {
62473
+ --dialog-max-width: var(--picker-dialog-max-width, var(--anchor-width));
62474
+ }
62409
62475
  }
62410
62476
 
62411
62477
  &[data-popup-width-fit-content] {
@@ -62569,7 +62635,10 @@ const PickerCustom = props => {
62569
62635
  // hands the popup that controller, and a controlled Dialog/Popover reads
62570
62636
  // no onOpen/onClose of its own.
62571
62637
  onOpen,
62572
- onClose
62638
+ onClose,
62639
+ // What opens the popup — the press, or an interaction navi detects
62640
+ // ("longpress", "contextmenu"…, or a list of them). See the JSDoc.
62641
+ openOn = "press"
62573
62642
  } = props;
62574
62643
  // Resolve the id the same way useControlProps does (own id > Field's id > generated id)
62575
62644
  // before computing popupId below, so two Pickers without an explicit id never collide.
@@ -62605,6 +62674,7 @@ const PickerCustom = props => {
62605
62674
  delete pickerProps.onConfirm;
62606
62675
  delete pickerProps.onOpen;
62607
62676
  delete pickerProps.onClose;
62677
+ delete pickerProps.openOn;
62608
62678
  // Read below for the popup alone; on the trigger it would land on the DOM as
62609
62679
  // an unknown attribute holding a ref object.
62610
62680
  delete pickerProps.anchor;
@@ -63002,7 +63072,29 @@ const PickerCustom = props => {
63002
63072
  // could then never form. So the picker steps back and opens on the click,
63003
63073
  // which the browser only delivers if the press stayed a press (a gesture
63004
63074
  // swallows the click it leaves behind).
63005
- const interactionsDispute = interactionsDisputeThePress(props.interactions);
63075
+ // Opening on something else than the press: the hold, the right click.
63076
+ // Declared on the picker itself, as the caller would declare their own,
63077
+ // so it is read and arbitrated like any other gesture — a swipe on the
63078
+ // same card takes the press a hold would have taken — and gated like one:
63079
+ // a read-only picker refuses it where the finger is. The press is then
63080
+ // nobody's: a tap on the card opens nothing (see the two reactions
63081
+ // below), and the keyboard keeps its own ways in (the shortcuts above).
63082
+ const openOnList = Array.isArray(openOn) ? openOn : [openOn];
63083
+ const opensOnPress = openOnList.includes("press");
63084
+ let interactions = props.interactions;
63085
+ if (!opensOnPress) {
63086
+ interactions = {
63087
+ ...interactions
63088
+ };
63089
+ for (const type of openOnList) {
63090
+ interactions[type] = e => {
63091
+ requestOpen(e);
63092
+ };
63093
+ }
63094
+ pickerProps.interactions = interactions;
63095
+ pickerProps["data-open-on"] = openOnList.join(" ");
63096
+ }
63097
+ const interactionsDispute = interactionsDisputeThePress(interactions);
63006
63098
  Object.assign(pickerProps, {
63007
63099
  eventReactionDefinitions: {
63008
63100
  mouseDown: e => {
@@ -63028,7 +63120,7 @@ const PickerCustom = props => {
63028
63120
  // because that is where such a box says what it travels by — and
63029
63121
  // asked at every press, since what the picker sits in is not the
63030
63122
  // picker's to know at mount.
63031
- if (interactionsDispute || isPressDisputedByDrag(e.target)) {
63123
+ if (!opensOnPress || interactionsDispute || isPressDisputedByDrag(e.target) || isPressDisputedByHold(ref.current)) {
63032
63124
  return null;
63033
63125
  }
63034
63126
  return {
@@ -63045,6 +63137,11 @@ const PickerCustom = props => {
63045
63137
  if (isWithinPickerContent(e.target)) {
63046
63138
  return null;
63047
63139
  }
63140
+ if (!opensOnPress) {
63141
+ // Neither the tap, nor the click a hold leaves behind: the press
63142
+ // is not what opens this picker.
63143
+ return null;
63144
+ }
63048
63145
  // When a label is clicked it transfers focus to the select
63049
63146
  // in that case we want to open it (otherwise we have already opened on mousedown interaction)
63050
63147
  // And when a gesture disputes the press (see the two disputes
@@ -63073,6 +63170,13 @@ const PickerCustom = props => {
63073
63170
  mode: mode
63074
63171
  });
63075
63172
  };
63173
+
63174
+ // A hold declared on something AROUND the picker (a card opened by
63175
+ // `openOn="longpress"`, holding this one in its drawing): the finger going
63176
+ // down may be the start of that hold, so this picker opens on the click — which
63177
+ // the hold, if it completes, swallows — rather than on the press. The picker's
63178
+ // own hold (its `openOn`) is not "around" it, and has already stepped back.
63179
+ const isPressDisputedByHold = pickerEl => Boolean(pickerEl?.parentElement?.closest(`[${LONGPRESS_ATTRIBUTE}]`));
63076
63180
  const getPickerInput = pickerEl => {
63077
63181
  return pickerEl.querySelector(".navi_picker_input");
63078
63182
  };
@@ -63125,7 +63229,12 @@ const PickerContentInsidePopup = props => {
63125
63229
  // itself, and this one does not. Popover ignores it, same as Dialog ignores
63126
63230
  // marginWithAnchor.
63127
63231
  dockedOnSmallTouchScreen,
63232
+ // Same again: the dialog takes the trigger's box as a floor (and, with
63233
+ // dialogMaxWidth="var(--anchor-width)", as a ceiling) — what keeps a card
63234
+ // its own width once lifted. Dialog's own `sizeFromAnchor`.
63235
+ dialogSizeFromAnchor,
63128
63236
  animation,
63237
+ animationDuration,
63129
63238
  // mode="callout": what the callout says about what it holds, and paints
63130
63239
  // in its border and icon — "none" for a plain tooltip (see the callout
63131
63240
  // defaults in PickerCustomResolver). And whether it wears a cross: without
@@ -63141,6 +63250,7 @@ const PickerContentInsidePopup = props => {
63141
63250
  return jsx(Next, {
63142
63251
  "aria-haspopup": isPopover ? "listbox" : "dialog",
63143
63252
  "navi-popover-mode": isPopover ? popoverMode : undefined,
63253
+ "data-dialog-size-from-anchor": !isPopover && dialogSizeFromAnchor ? "" : undefined,
63144
63254
  ...rest,
63145
63255
  // On popupProps already (see the picker's popup assembly); they mean
63146
63256
  // nothing to the picker element.
@@ -63186,6 +63296,7 @@ const PickerContentInsidePopup = props => {
63186
63296
  mode: mode,
63187
63297
  layer: popupLayer,
63188
63298
  animation: animation,
63299
+ animationDuration: animationDuration,
63189
63300
  positionArea: isPopover ? positionArea ?? (popoverMode === "nearby" ? "bottom-start" : "inset(top-left)") : positionArea,
63190
63301
  marginWithAnchor: isPopover ? popoverSpacing : undefined,
63191
63302
  marginWithContainer: marginWithContainer === undefined && isPopover ? popoverSpacing : marginWithContainer,
@@ -63200,6 +63311,7 @@ const PickerContentInsidePopup = props => {
63200
63311
  expandX: isPopover ? undefined : dialogExpandX,
63201
63312
  expandY: isPopover ? undefined : dialogExpandY,
63202
63313
  dockedOnSmallTouchScreen: isPopover ? undefined : dockedOnSmallTouchScreen,
63314
+ sizeFromAnchor: isPopover ? undefined : dialogSizeFromAnchor,
63203
63315
  children: jsx(PopupModeContext.Provider, {
63204
63316
  value: mode,
63205
63317
  children: children
@@ -63480,6 +63592,34 @@ const pickerUIIsNaviOwn = ui => {
63480
63592
  return Boolean(ui) && typeof ui === "object" && Boolean(ui.type?.isPickerOwnUI);
63481
63593
  };
63482
63594
 
63595
+ /**
63596
+ * What the picker holds, read from inside its `ui` — for a drawing given as
63597
+ * an element (`ui={<MyCard game={game} />}`), which the picker cannot hand
63598
+ * props to. `value` is the state the picker holds right now: the answer the
63599
+ * popup just closed on, before the server has said anything, and put back if
63600
+ * the action fails. `loading` is the run in flight; `interactive` is false
63601
+ * while the picker is disabled, read-only or busy.
63602
+ *
63603
+ * @returns {{ value: any, loading: boolean, interactive: boolean } | null}
63604
+ * null outside a picker.
63605
+ */
63606
+ const usePickerState = () => {
63607
+ const context = useContext(PickerContext);
63608
+ if (!context) {
63609
+ return null;
63610
+ }
63611
+ const {
63612
+ value,
63613
+ loading,
63614
+ interactive
63615
+ } = context;
63616
+ return {
63617
+ value,
63618
+ loading,
63619
+ interactive
63620
+ };
63621
+ };
63622
+
63483
63623
  const PickerNaviMinute = props => {
63484
63624
  const Next = useNextResolver();
63485
63625
  const {
@@ -71217,6 +71357,21 @@ const css$t = /* css */`@layer navi {
71217
71357
  }
71218
71358
  }
71219
71359
 
71360
+ &[data-open-on~="longpress"] {
71361
+ -webkit-touch-callout: none;
71362
+ user-select: none;
71363
+ }
71364
+
71365
+ &[data-open-on] {
71366
+ & > .navi_picker_box > .navi_picker_input {
71367
+ pointer-events: none;
71368
+ }
71369
+
71370
+ & > .navi_picker_box > .navi_picker_value {
71371
+ pointer-events: auto;
71372
+ }
71373
+ }
71374
+
71220
71375
  &[navi-ui-custom] {
71221
71376
  & .navi_picker_input {
71222
71377
  top: calc(-1 * (var(--picker-border-width) + var(--x-picker-press-padding-top)));
@@ -71545,12 +71700,15 @@ const PickerButton = props => {
71545
71700
  // What the picker knows about itself, for the pieces it does not place: the
71546
71701
  // drawings of its value (Picker.UI.*), and the affordances a caller may put
71547
71702
  // in their own `ui` (Picker.Clear) as much as the ones it puts in its slot.
71703
+ // `ui={MyCard}`: a component the picker renders itself, told what it holds.
71704
+ const UIComponent = typeof ui === "function" ? ui : null;
71548
71705
  const pickerContext = {
71549
71706
  value,
71550
71707
  placeholder,
71551
71708
  maxLines,
71552
71709
  id: inputProps.id,
71553
71710
  interactive,
71711
+ loading,
71554
71712
  clearConfirm
71555
71713
  };
71556
71714
  return (
@@ -71741,7 +71899,17 @@ const PickerButton = props => {
71741
71899
  size: rightSlotIconSize,
71742
71900
  lineOverflow: "allow",
71743
71901
  children: rightSlotIcon === undefined ? jsx(ChevronDownSvg$1, {}) : rightSlotIcon
71744
- }) : jsx(PickerDefaultUI, {}) : ui
71902
+ }) : jsx(PickerDefaultUI, {}) : UIComponent ?
71903
+ // Told what the picker HOLDS — the value it just closed
71904
+ // on, before the server has said anything — so a façade
71905
+ // shows the answer at once, and the wait with it. The
71906
+ // same state usePickerState() hands an element (see the
71907
+ // `ui` doc).
71908
+ jsx(UIComponent, {
71909
+ value: value,
71910
+ loading: loading,
71911
+ interactive: interactive
71912
+ }) : ui
71745
71913
  })
71746
71914
  })
71747
71915
  }), hasRightSlot ? jsx("span", {
@@ -72045,6 +72213,7 @@ const PickerStyleCSSVars = {
72045
72213
  "dialogMaxHeight": ["--picker-dialog-max-height", "maxHeight"],
72046
72214
  "popupBackgroundColor": "--picker-popup-background-color",
72047
72215
  "popupBorderRadius": ["--picker-popup-border-radius", "borderRadius"],
72216
+ "popupBoxShadow": ["--picker-popup-box-shadow", "boxShadow"],
72048
72217
  "dialogBorderWidth": ["--picker-dialog-border-width", "borderWidth"],
72049
72218
  "slotSpacing": ["--picker-slot-spacing", "margin"],
72050
72219
  "pressPadding": ["--picker-press-padding", "padding"],
@@ -72129,7 +72298,7 @@ const PickerFirstResolver = props => {
72129
72298
  * defaultValue?: any,
72130
72299
  * name?: string,
72131
72300
  * placeholder?: import("ignore:preact").ComponentChildren,
72132
- * ui?: import("ignore:preact").ComponentChildren | "default",
72301
+ * ui?: import("ignore:preact").ComponentChildren | "default" | import("ignore:preact").ComponentType<{ value: any, loading: boolean, interactive: boolean }>,
72133
72302
  * required?: boolean,
72134
72303
  * min?: Date | string | number,
72135
72304
  * max?: Date | string | number,
@@ -72142,6 +72311,9 @@ const PickerFirstResolver = props => {
72142
72311
  * action?: (value: any, event: Event) => void,
72143
72312
  * children?: import("ignore:preact").ComponentChildren,
72144
72313
  * mode?: "popover" | "dialog" | "callout",
72314
+ * openOn?: "press" | "longpress" | "contextmenu" | string | string[],
72315
+ * animation?: boolean | "auto" | "fading" | "scaling" | "sliding" | "growing" | `slide-from-${string}`,
72316
+ * animationDuration?: string,
72145
72317
  * calloutStatus?: "info" | "warning" | "error" | "success" | "none",
72146
72318
  * calloutIcon?: boolean,
72147
72319
  * calloutCloseButton?: boolean,
@@ -72172,6 +72344,7 @@ const PickerFirstResolver = props => {
72172
72344
  * dialogMaxHeight?: number | string,
72173
72345
  * popupBackgroundColor?: string,
72174
72346
  * popupBorderRadius?: number | string,
72347
+ * popupBoxShadow?: string,
72175
72348
  * dialogBorderWidth?: number | string,
72176
72349
  * clearable?: boolean,
72177
72350
  * picksNothing?: boolean,
@@ -72184,6 +72357,7 @@ const PickerFirstResolver = props => {
72184
72357
  * dialogExpand?: boolean,
72185
72358
  * dialogExpandX?: boolean,
72186
72359
  * dialogExpandY?: boolean,
72360
+ * dialogSizeFromAnchor?: boolean,
72187
72361
  * marginWithContainer?: number | string,
72188
72362
  * anchor?: import("ignore:preact").RefObject<HTMLElement> | HTMLElement,
72189
72363
  * escapeEffect?: "cancel" | "close",
@@ -72201,7 +72375,29 @@ const PickerFirstResolver = props => {
72201
72375
  * variant that paints the trigger transparent leaves the popup a real sheet.
72202
72376
  * @param {number|string} [popupBorderRadius] The popup's corners. Left out they
72203
72377
  * echo the trigger's `borderRadius`.
72204
- * @param {import("ignore:preact").ComponentChildren | "default"} [ui] What the
72378
+ * @param {string} [popupBoxShadow] The popup's shadow, popover or dialog. Left
72379
+ * out it is the one every navi popup casts. `"none"` for a popup that is
72380
+ * not a sheet — a card lifted out of a page draws its own edges, and the
72381
+ * popup only carries it (see `dialogSizeFromAnchor`).
72382
+ * @param {"press"|"longpress"|"contextmenu"|string|string[]} [openOn="press"]
72383
+ * What opens the popup. The press, by default — the way a native select
72384
+ * opens. Any other name is an interaction navi detects (see
72385
+ * docs/interactions.md: `"longpress"`, `"contextmenu"`, `"dblclick"`…), or
72386
+ * a list of them — `["longpress", "contextmenu"]` is the hold on a phone and
72387
+ * the right click at a desk. The picker declares it on itself, so it is
72388
+ * arbitrated like any other gesture: a swipe on the same card takes the
72389
+ * press a hold would have taken. A tap then opens nothing — the press stays
72390
+ * free for what the `ui` holds: a link in the card navigates, a button in it
72391
+ * presses, a picker in it opens on its own click, with nothing to declare
72392
+ * (`selfInteractions` is for a drawing that DOES open on the press). That
72393
+ * is what lets a whole card be a picker without every touch on it opening
72394
+ * the sheet — and the keyboard keeps its ways in (Enter, Space, the
72395
+ * arrows). A hold declared INSIDE the card (`interactions={{ longpress }}`
72396
+ * on something it holds) answers before this one: the nearer hold takes the
72397
+ * press, the way a click is the innermost target's. Being a gesture, the open goes through
72398
+ * the interaction gate as one: a `readOnly` picker refuses it and says so
72399
+ * where the finger is, whatever `openWhileReadOnly` says.
72400
+ * @param {import("ignore:preact").ComponentChildren | "default" | import("ignore:preact").ComponentType} [ui] What the
72205
72401
  * trigger draws in place of the value's default rendering (a date, a list
72206
72402
  * joined by commas…) — and then all it draws: `placeholder` is not shown
72207
72403
  * next to it, and an empty value is not greyed as a placeholder either: what
@@ -72230,6 +72426,20 @@ const PickerFirstResolver = props => {
72230
72426
  * beside it, out of the flow so the rest keeps its width — is drawn and
72231
72427
  * opens nothing; `pressPadding` is how far the press area follows it out
72232
72428
  * there.
72429
+ *
72430
+ * A drawing that follows what the picker HOLDS — the value the popup just
72431
+ * closed on, before the server has answered, the same state navi's own
72432
+ * default `ui` reads, rolled back if the action fails (`resetOnError`) —
72433
+ * reads it one of two ways. As a component, `ui={MyCard}`: the picker
72434
+ * renders it and hands it `value`, `loading` and `interactive` as props.
72435
+ * As an element, `ui={<MyCard game={game} />}`, with `usePickerState()`
72436
+ * inside it returning the same three — for a drawing that needs props of
72437
+ * its own as well. Either way a card shows the score the moment the sheet
72438
+ * leaves and takes it back on a refusal, with nothing held by the caller.
72439
+ * `loading` is the wait it wears meanwhile: navi draws its loading outline
72440
+ * on every trigger, but on a card-sized `variant="bare"` a two-pixel run
72441
+ * around the box says nothing — a big surface draws its own waiting state
72442
+ * from that flag, or from `[data-loading]` on the picker root in css.
72233
72443
  * @param {boolean} [readOnly] Nothing in this picker can be changed — and it
72234
72444
  * still opens, so what is in the popup can be read: everything in there is
72235
72445
  * held read-only in turn, each control greying out and saying why on its own.
@@ -72245,7 +72455,10 @@ const PickerFirstResolver = props => {
72245
72455
  * refuse the open as well, for a popup with nothing to read: a form of
72246
72456
  * controls to fill in, a menu of gestures. Opening then only shows what is
72247
72457
  * refused, so the picker says why on the trigger instead — where the
72248
- * interaction happened.
72458
+ * interaction happened. A busy picker follows the same rule: it still
72459
+ * opens to be read while its action runs, and with `false` the press is
72460
+ * refused with the wait as its reason — what a card that is syncing wants
72461
+ * for the sheet that would write it again.
72249
72462
  * @param {boolean|string} [error] Something went wrong around this picker (its
72250
72463
  * content failed to load, its value could not be resolved…). Shown as a
72251
72464
  * callout on the trigger, open or closed — the caller has nothing to place.
@@ -72312,7 +72525,14 @@ const PickerFirstResolver = props => {
72312
72525
  * @param {boolean} [picksNothing] The popup asks something rather than holding
72313
72526
  * an answer, so the trigger draws a label and never a value: no chevron, no
72314
72527
  * clear cross, in any variant. `type="confirm"` says it for itself; say it
72315
- * for a popup of your own that is a menu of actions rather than a choice.
72528
+ * for a popup of your own that is a menu of actions rather than a choice —
72529
+ * or a DOOR: a drawing that grows to be looked at (a weather scene, a plan),
72530
+ * with no `action` at all. The picker is then a trigger and a popup, and
72531
+ * nothing more: its close does nothing, and what it keeps from being a
72532
+ * control is what a door still needs — the role of a button, the keyboard
72533
+ * opening it, the anchor being itself, and one popup per instance without
72534
+ * an id to wire. See "The trigger wears the wait" in docs/popup_open.md for
72535
+ * when that beats a `Button` opening a shared `Dialog`.
72316
72536
  * @param {string|import("ignore:preact").ComponentChildren} [clearConfirm] The
72317
72537
  * question asked before the clear cross clears anything — the `message` of
72318
72538
  * the `<Picker type="confirm">` the cross then is, plain text or JSX. Asked
@@ -72333,7 +72553,10 @@ const PickerFirstResolver = props => {
72333
72553
  * placed anywhere else. No right slot comes with it: a cross belongs inside
72334
72554
  * that drawing, at the place and the size the drawing decides, so it is
72335
72555
  * `<Picker.Clear />` the `ui` holds rather than `clearable` the picker
72336
- * takes. `"headless"` draws nothing either, and is not the `ui`'s box but
72556
+ * takes. What navi still draws on that box — the focus ring, the loading
72557
+ * outline — follows the picker's `borderRadius`, which stays the control's
72558
+ * unless told: a drawing with corners of its own states them on the picker
72559
+ * as well. `"headless"` draws nothing either, and is not the `ui`'s box but
72337
72560
  * its parent's: it stretches to whatever positioned element holds it, for a
72338
72561
  * picker put inside the thing that opens it (a button, a row) so that the
72339
72562
  * popup hangs off that whole element. A picker opened from something it does
@@ -72419,6 +72642,23 @@ const PickerFirstResolver = props => {
72419
72642
  * a dialog docked by `dockedOnSmallTouchScreen` withdraws it and stays
72420
72643
  * container-wide, so both can be stated at once.
72421
72644
  * @param {number|string} [dialogMaxHeight] Same, on the height.
72645
+ * @param {boolean|"auto"|"fading"|"scaling"|"sliding"|"growing"|`slide-from-${string}`} [animation]
72646
+ * The popup's own (see Popover/Dialog). `"growing"` is the one a picker
72647
+ * whose `ui` is a whole piece of the page wants: the popup is the browser
72648
+ * morphing the trigger's box into what carries `data-grow` inside the popup
72649
+ * (the popup itself when nothing does), and back on close. The trigger IS
72650
+ * the anchor, so nothing has to be named for it — `dialogSizeFromAnchor`
72651
+ * for a card that must keep its width on the way, left out for a drawing
72652
+ * that opens precisely to get bigger.
72653
+ * @param {string} [animationDuration] The popup's own (`--popup-animation-duration`).
72654
+ * @param {boolean} [dialogSizeFromAnchor] Dialog mode: the dialog is as wide
72655
+ * as the trigger — its box as a floor (Dialog's own `sizeFromAnchor`) and
72656
+ * as a ceiling, unless a `dialogMaxWidth` says otherwise. What keeps a card
72657
+ * its own width once lifted out of the page (`animation="growing"`, with
72658
+ * `data-grow` on the card inside the popup): it moves, and nothing else
72659
+ * about it changes. The ceiling is set here rather than through
72660
+ * `dialogMaxWidth="var(--anchor-width)"` because that variable lives on the
72661
+ * dialog element, and a prop on the picker is resolved on the picker.
72422
72662
  * @param {"cancel"|"close"} [escapeEffect="cancel"] What Escape does to an open
72423
72663
  * picker. "cancel" puts back the value the picker had at open, and a dialog
72424
72664
  * picker also goes back in history — so anything written to the url while it
@@ -84518,5 +84758,5 @@ const UserSvg = () => jsx("svg", {
84518
84758
  })
84519
84759
  });
84520
84760
 
84521
- export { ActionRenderer, ActiveKeyboardShortcuts, Address, Badge, BadgeCount, BadgeList, Binder, Box, Button, ButtonCopyToClipboard, CalloutStatusIcon, Caption, CardLayout, CheckSvg, CheckboxGroup, CloseSvg, Code, Col, Colgroup, Color, ConstructionSvg, ControlGroup, ControlSwap, DaySpin, Details, Dialog, Editable, ErrorBoundary, ErrorBoundaryContext, ExclamationSvg, Expandable, EyeClosedSvg, EyeSvg, Field, FixedBar, Form, Group, Head, HeartSvg, HomeSvg, Icon, Image, InfoSvg, Input, InputDuration, Interpolate, Label, Link, LinkAnchorSvg, LinkBlankTargetSvg, LinkCurrentSvg, List, ListItem, ListItemGroup, ListItems, Loading, LoadingDotsSvg, LoadingIndicator, LoadingIndicatorFluid, LoadingOutline, MessageBox, Meter, Nav, NaviDebug, NumberSpin, OfflineError, 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, TimeRange, TimeRangeSpin, TimeRangeWheel, TimeSpin, TimeWheel, Title, Tr, UITransition, Unit, UserSvg, ViewportLayout, Wheel, WheelGroup, WheelItem, actionRunEffect, anyMatchingRouteSignal, applySearch, arraySignalMembership, canNavBackSignal, canNavForwardSignal, coarsePointerSignal, compareTwoJsValues, constraintFromValidityRule, createAction, createAvailableConstraint, createRequestCanceller, createSearch, createSelectionKeyboardShortcuts, createSlot, defineInteractionDetector, defineRouteDefaultTransition, defineRouteTransition, detectHorizontalOverflow, dispatchRequestSetUIState, enableDebugActions, enableDebugOnDocumentLoading, ensureDocumentStartViewTransition, errorIsDisplayed, filterTableSelection, getNowHours, getNowHoursRoundedToStep, isCellSelected, isColumnSelected, isOfflineError, isRowSelected, isScrolling, isToday, languagesSignal, localStorageSignal, markAsOutsideTextFlow, markErrorAsDisplayedBy, moveArrayItemByIndex, moveFocusTo, navBack, navForward, navIntegratedVia, navTo, naviI18n, openCallout, preloadUrl, rawUrlPart, registerGlobalConstraint, reload, rerunActions, resource, route, routeAction, scrollActivitySignal, setBaseUrl, setNetworkPolicy, setPreferredLanguage, setSupportedLanguages, setUrlTargetOptions, setupRoutes, smallTouchScreenSignal, stateSignal, stopLoad, stringifyTableSelectionValue, swapArrayItemByIndex, syncOwnedResourceToSignals, syncResourceToSignals, triggerNaviCommand, updateActions, useActionStatus, useArraySignalMembership, useAsyncData, useCalloutElement, useCalloutRequestClose, useCanNavBack, useCanNavForward, useCancelPrevious, useCellGridFromRows, useConstraintValidityState, useDependenciesDiff, useDisplayedLayoutEffect, useDocumentResource, useDocumentState, useDocumentUrl, useEditionController, useFocusGroup, useInputGroup, useKeyboardShortcuts, useNavState, useNetworkPolicyReason, useOrderedColumns, usePopupMode, useRouteStatus, useSearchText, useSelectableElement, useSelectionController, useSignalSync, useSlideContainer, useSlideValue, useStateArray, useTitleLevel, useTransitionCover, useUrlSearchParam, useUrlTargetId, valueInLocalStorage, windowWidthSignal };
84761
+ export { ActionRenderer, ActiveKeyboardShortcuts, Address, Badge, BadgeCount, BadgeList, Binder, Box, Button, ButtonCopyToClipboard, CalloutStatusIcon, Caption, CardLayout, CheckSvg, CheckboxGroup, CloseSvg, Code, Col, Colgroup, Color, ConstructionSvg, ControlGroup, ControlSwap, DaySpin, Details, Dialog, Editable, ErrorBoundary, ErrorBoundaryContext, ExclamationSvg, Expandable, EyeClosedSvg, EyeSvg, Field, FixedBar, Form, Group, Head, HeartSvg, HomeSvg, Icon, Image, InfoSvg, Input, InputDuration, Interpolate, Label, Link, LinkAnchorSvg, LinkBlankTargetSvg, LinkCurrentSvg, List, ListItem, ListItemGroup, ListItems, Loading, LoadingDotsSvg, LoadingIndicator, LoadingIndicatorFluid, LoadingOutline, MessageBox, Meter, Nav, NaviDebug, NumberSpin, OfflineError, 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, TimeRange, TimeRangeSpin, TimeRangeWheel, TimeSpin, TimeWheel, Title, Tr, UITransition, Unit, UserSvg, ViewportLayout, Wheel, WheelGroup, WheelItem, actionRunEffect, anyMatchingRouteSignal, applySearch, arraySignalMembership, canNavBackSignal, canNavForwardSignal, coarsePointerSignal, compareTwoJsValues, constraintFromValidityRule, createAction, createAvailableConstraint, createRequestCanceller, createSearch, createSelectionKeyboardShortcuts, createSlot, defineInteractionDetector, defineRouteDefaultTransition, defineRouteTransition, detectHorizontalOverflow, dispatchRequestSetUIState, enableDebugActions, enableDebugOnDocumentLoading, ensureDocumentStartViewTransition, errorIsDisplayed, filterTableSelection, getNowHours, getNowHoursRoundedToStep, isCellSelected, isColumnSelected, isOfflineError, isRowSelected, isScrolling, isToday, languagesSignal, localStorageSignal, markAsOutsideTextFlow, markErrorAsDisplayedBy, moveArrayItemByIndex, moveFocusTo, navBack, navForward, navIntegratedVia, navTo, naviI18n, openCallout, preloadUrl, rawUrlPart, registerGlobalConstraint, reload, rerunActions, resource, route, routeAction, scrollActivitySignal, setBaseUrl, setNetworkPolicy, setPreferredLanguage, setSupportedLanguages, setUrlTargetOptions, setupRoutes, smallTouchScreenSignal, stateSignal, stopLoad, stringifyTableSelectionValue, swapArrayItemByIndex, syncOwnedResourceToSignals, syncResourceToSignals, triggerNaviCommand, updateActions, useActionStatus, useArraySignalMembership, useAsyncData, useCalloutElement, useCalloutRequestClose, useCanNavBack, useCanNavForward, useCancelPrevious, useCellGridFromRows, useConstraintValidityState, useDependenciesDiff, useDisplayedLayoutEffect, useDocumentResource, useDocumentState, useDocumentUrl, useEditionController, useFocusGroup, useInputGroup, useKeyboardShortcuts, useNavState, useNetworkPolicyReason, useOrderedColumns, usePickerState, usePopupMode, useRouteStatus, useSearchText, useSelectableElement, useSelectionController, useSignalSync, useSlideContainer, useSlideValue, useStateArray, useTitleLevel, useTransitionCover, useUrlSearchParam, useUrlTargetId, valueInLocalStorage, windowWidthSignal };
84522
84762
  //# sourceMappingURL=jsenv_navi.js.map