@jsenv/navi 0.29.423 → 0.29.425

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.
@@ -14802,6 +14802,9 @@ const createOpenController = (
14802
14802
  // content is still waiting for a first open to be built. Called below,
14803
14803
  // before openEffect, so the popup measures and positions the real thing.
14804
14804
  mountContent: null,
14805
+ // Set alongside mountContent: the content asked for outside any opening,
14806
+ // by something that reads it while the popup is closed.
14807
+ buildContent: null,
14805
14808
  // The caller's own `onOpen`, set by Dialog/Popover from their props on
14806
14809
  // every render (like openEffect). Called BEFORE mountContent, so whatever
14807
14810
  // it decides — which record this dialog is opening on — is already true by
@@ -39204,7 +39207,11 @@ const flushSyncRendering = (fn) => {
39204
39207
  *
39205
39208
  * "always" is for content something else depends on before any opening: a
39206
39209
  * value the popup's owner reads off its own children, fields a form around it
39207
- * collects on submit, a size measured from outside.
39210
+ * collects on submit, a size measured from outside. When the popup's owner
39211
+ * cannot tell at mount whether anything will depend on it, the content waits
39212
+ * and whatever depends on it asks for it, closed, with
39213
+ * `openController.buildContent()` (a picker's drawing reading the value its
39214
+ * popup holds, see usePickerContext).
39208
39215
  *
39209
39216
  * "idle" is "always" minus the cost on the critical render: the page appears
39210
39217
  * without the content, and the browser builds it in an idle moment after
@@ -39331,6 +39338,14 @@ const usePopupContentMount = (
39331
39338
  }
39332
39339
  }
39333
39340
  };
39341
+ // A plain render rather than a flush: the popup stays closed, and nothing is
39342
+ // about to measure it.
39343
+ openController.buildContent = () => {
39344
+ if (contentMountedRef.current) {
39345
+ return;
39346
+ }
39347
+ setContentMounted(true);
39348
+ };
39334
39349
  openController.unmountContent =
39335
39350
  mount === "while-opened"
39336
39351
  ? () => {
@@ -59590,6 +59605,20 @@ const readArea = slideElement => slideElement.getAttribute("data-slide-area") ||
59590
59605
  * `sizing={loading ? "largest" : "frozen"}` and is measured once the real
59591
59606
  * content is there. The freeze holds against what happens INSIDE the box, not
59592
59607
  * against the room it is given: a window resize measures again.
59608
+ * @param {"always"|"near"} [props.mount="always"] - when a slide's CONTENT is
59609
+ * rendered. The <Slide> element always is, so areas, tabs following the box
59610
+ * and `aria-labelledby` are the same either way. "always": every slide's,
59611
+ * from the start. "near": once a travel can show it — the slide on screen,
59612
+ * the one a travel is going to, and at rest the ones a hand dragging the box
59613
+ * would bring alongside (neighbours on the map, along the axes
59614
+ * `travelByDrag` opens, the other end of a `loop` included) — and kept from
59615
+ * then on. For slides that are costly to build (a grid of a few hundred
59616
+ * controls each): opening builds the slide shown and its neighbours rather
59617
+ * than all of them, and a jump to a far slide builds that one and none of
59618
+ * those in between, which a travel never shows. The box is then as large as
59619
+ * the largest slide BUILT so far (see `sizing`), so it grows as a larger one
59620
+ * is reached: give it a size of its own when the slides differ.
59621
+ * `<Slide mount>` says it for one slide — a heavy one among light ones.
59593
59622
  */
59594
59623
  const SlideContainer = ({
59595
59624
  layout = "row",
@@ -59605,6 +59634,7 @@ const SlideContainer = ({
59605
59634
  travelByScroll = "x",
59606
59635
  duration = "300ms",
59607
59636
  sizing = "largest",
59637
+ mount = "always",
59608
59638
  children,
59609
59639
  ...rest
59610
59640
  }) => {
@@ -59717,6 +59747,15 @@ const SlideContainer = ({
59717
59747
  // Undefined at mount on purpose: the first area held outside is news like any
59718
59748
  // other, and it is walked to rather than opened on.
59719
59749
  const areaAskedSeenRef = useRef(undefined);
59750
+ // An area held outside that this container has not answered yet: the effect
59751
+ // reading currentFromCaller walks to it, after the render that brings it.
59752
+ const requestIsNews = () => currentFromCaller !== undefined && currentFromCaller !== areaAskedSeenRef.current;
59753
+ // The slide about to be on screen, as far as a render can tell: the area
59754
+ // asked from outside while it is news — the picture is walked there before
59755
+ // it is painted, the first request included — and the container's own answer
59756
+ // otherwise. What a slide waiting for a travel reads to have its content in
59757
+ // the very render that shows it (see Slide's `mount`).
59758
+ const areaShownNext = requestIsNews() ? currentFromCaller : current;
59720
59759
  // Where the container stands, said where the caller holds it.
59721
59760
  //
59722
59761
  // Whether a slide is a place one came from is the STATE's own business (see
@@ -59771,6 +59810,22 @@ const SlideContainer = ({
59771
59810
  // state: nothing on screen depends on it, and a travel must read what the
59772
59811
  // one before it wrote, not what the last render saw.
59773
59812
  const cameFromRef = useRef({});
59813
+ // The slides a travel has come near while their content was not rendered
59814
+ // (mount="near", see renderNear): only ever grows, and only for a slide that
59815
+ // was waiting — a container whose slides all render never re-renders for it.
59816
+ const [nearAreas, setNearAreas] = useState([]);
59817
+ // Nothing names the slide on screen (no area held outside, no default): it
59818
+ // is the first one in the DOM, which the first render cannot read yet. The
59819
+ // first Slide to render is that one, so it claims it — the slide on screen
59820
+ // then has its content from the first commit (a size frozen at mount, a
59821
+ // focus landing in it) rather than one render late.
59822
+ const openingClaimRef = useRef(null);
59823
+ const claimOpening = area => {
59824
+ if (openingClaimRef.current === null) {
59825
+ openingClaimRef.current = area;
59826
+ }
59827
+ return openingClaimRef.current === area;
59828
+ };
59774
59829
 
59775
59830
  // The controller has caught up with the slide the container went to on its
59776
59831
  // own (commit="rest"): there are no longer two answers to give, so the
@@ -59911,6 +59966,44 @@ const SlideContainer = ({
59911
59966
  }
59912
59967
  };
59913
59968
 
59969
+ // The slides a hand dragging the box from this area would bring alongside:
59970
+ // the map's neighbours on the axes it drags, read the way the drag reads them
59971
+ // (areaTowards knows the holes and a loop's two ends).
59972
+ const areasAlongside = area => {
59973
+ const alongside = [];
59974
+ if (dragAxes?.includes("x")) {
59975
+ alongside.push(areaTowards(-1, 0, area), areaTowards(1, 0, area));
59976
+ }
59977
+ if (dragAxes?.includes("y")) {
59978
+ alongside.push(areaTowards(0, -1, area), areaTowards(0, 1, area));
59979
+ }
59980
+ return alongside;
59981
+ };
59982
+
59983
+ // mount="near": the content of a slide is asked for before a travel shows
59984
+ // it. The neighbours are asked for AT REST, never when a travel sets off: the
59985
+ // travel shows the slide it goes to and nothing past it, and a slide built in
59986
+ // the render that starts it is a frame the travel waits for. At rest nothing
59987
+ // moves, and a hand landing next is still answered after the build.
59988
+ const renderNear = (area, {
59989
+ alongside
59990
+ }) => {
59991
+ // Asked on every render: a container with nothing waiting stops here.
59992
+ if (!trackRef.current?.querySelector(":scope > [data-slide-unrendered]")) {
59993
+ return;
59994
+ }
59995
+ const unrendered = readMap().slideElements.filter(slideElement => slideElement.hasAttribute("data-slide-unrendered")).map(readArea);
59996
+ const near = alongside ? [area, ...areasAlongside(area)] : [area];
59997
+ const toRender = near.filter(nearArea => unrendered.includes(nearArea));
59998
+ if (!toRender.length) {
59999
+ return;
60000
+ }
60001
+ setNearAreas(previous => {
60002
+ const added = toRender.filter(nearArea => !previous.includes(nearArea));
60003
+ return added.length ? [...previous, ...added] : previous;
60004
+ });
60005
+ };
60006
+
59914
60007
  // The travel is over: the stage is struck and every slide goes back where the
59915
60008
  // map says it is. Nothing is seen moving for it — the slide on screen sits at
59916
60009
  // the same place whatever the arrangement (its own offset and the track's are
@@ -59959,6 +60052,9 @@ const SlideContainer = ({
59959
60052
  const offset = `${-x * 100}% ${-y * 100}%`;
59960
60053
  offsetRef.current = offset;
59961
60054
  track.style.setProperty("--slide-container-offset", offset);
60055
+ renderNear(currentArea, {
60056
+ alongside: true
60057
+ });
59962
60058
  // Arrived, so the change can be told (commit="rest"): the picture is at
59963
60059
  // rest and whatever the caller does with it — write the URL, ask a server —
59964
60060
  // costs the gesture nothing anymore.
@@ -60236,6 +60332,15 @@ const SlideContainer = ({
60236
60332
  if (!stageRef.current) {
60237
60333
  drawnAreaRef.current = currentArea;
60238
60334
  }
60335
+ // What a travel can show next (mount="near"), around where the picture
60336
+ // SETTLES: a request from outside is walked to by an effect running after
60337
+ // this one, in the same commit, and the slides around a picture about to be
60338
+ // walked away from would be built for nothing. The neighbours only at
60339
+ // rest, see renderNear.
60340
+ const settlingArea = requestIsNews() && reachableTowards(currentArea, currentFromCaller) || currentArea;
60341
+ renderNear(settlingArea, {
60342
+ alongside: !stageRef.current
60343
+ });
60239
60344
  // Said last, and after data-current has been written: what a travel would do
60240
60345
  // is read off the map from the slide that is now current, and off the locks
60241
60346
  // that slide is wearing in this very commit.
@@ -60473,12 +60578,9 @@ const SlideContainer = ({
60473
60578
  // request later), and what nothing has answered yet must still be answered
60474
60579
  // once it can be.
60475
60580
  useLayoutEffect(() => {
60476
- if (currentFromCaller === undefined) {
60477
- return;
60478
- }
60479
- if (currentFromCaller === areaAskedSeenRef.current) {
60480
- // Not news: either nothing moved, or this container is reading back what
60481
- // it wrote itself.
60581
+ if (!requestIsNews()) {
60582
+ // Not news: nothing held outside, nothing moved, or this container
60583
+ // reading back what it wrote itself.
60482
60584
  return;
60483
60585
  }
60484
60586
  // The slide asked for is not rendered yet — no slides at all, or one whose
@@ -61308,6 +61410,11 @@ const SlideContainer = ({
61308
61410
  if (!past) {
61309
61411
  return false;
61310
61412
  }
61413
+ // Two slides from the one at rest, so possibly never rendered: asked
61414
+ // for now, and built before the frame that brings it in is painted.
61415
+ renderNear(past, {
61416
+ alongside: false
61417
+ });
61311
61418
  const currentElement = slideElements.find(slideElement => slideElement.hasAttribute("data-current")) || slideElements[0];
61312
61419
  const basePlace = stageRef.current?.placeByArea.get(reached) || placeOf.get(reached) || {
61313
61420
  x: 0,
@@ -61766,6 +61873,12 @@ const SlideContainer = ({
61766
61873
  done,
61767
61874
  valueByArea,
61768
61875
  settleFocus,
61876
+ // What a slide reads to know whether its content is rendered yet
61877
+ // (see Slide's `mount`).
61878
+ mount,
61879
+ areaShownNext,
61880
+ nearAreas,
61881
+ claimOpening: areaShownNext === undefined ? claimOpening : null,
61769
61882
  // The box itself, for what is written INSIDE it to read the same
61770
61883
  // facts what is written outside reads by id (useSlideContainer):
61771
61884
  // a way out is a way out on either side of the box.
@@ -61805,9 +61918,12 @@ const SlideContainer = ({
61805
61918
  * try to leave.
61806
61919
  * @param {boolean} [props.preventNavNext] - hold them from going right or down.
61807
61920
  * @param {boolean} [props.preventNavPrevious] - …left or up.
61921
+ * @param {"always"|"near"} [props.mount] - when this slide's content is
61922
+ * rendered; the container's `mount` when not said (see there).
61808
61923
  */
61809
61924
  const Slide = ({
61810
61925
  area,
61926
+ mount,
61811
61927
  required,
61812
61928
  preventNav,
61813
61929
  preventNavNext = preventNav,
@@ -61817,6 +61933,17 @@ const Slide = ({
61817
61933
  }) => {
61818
61934
  const container = useContext(SlideContainerContext);
61819
61935
  const slideArea = area ?? rest.id;
61936
+ // Asked by every slide, whatever its own mode: the claim goes to the first
61937
+ // slide to RENDER, and a slide that skipped asking would hand it to the one
61938
+ // after it.
61939
+ const opening = container?.claimOpening?.(slideArea);
61940
+ // Kept once rendered (mount="near"): going back builds nothing again, and a
61941
+ // slide being left keeps its content for as long as it is still in the frame.
61942
+ const renderedRef = useRef(false);
61943
+ if (!renderedRef.current && (!container || (mount ?? container.mount) !== "near" || opening || slideArea === container.areaShownNext || container.nearAreas.includes(slideArea))) {
61944
+ renderedRef.current = true;
61945
+ }
61946
+ const rendered = renderedRef.current;
61820
61947
  const answered = Boolean(container?.answeredAreas.includes(slideArea));
61821
61948
  const holdsUntilAnswered = Boolean(required) && !answered;
61822
61949
  const nextIsLocked = Boolean(preventNavNext) || holdsUntilAnswered;
@@ -61866,13 +61993,17 @@ const Slide = ({
61866
61993
  "data-slide-area": slideArea,
61867
61994
  "data-prevent-nav-next": nextIsLocked ? "" : undefined,
61868
61995
  "data-prevent-nav-previous": preventNavPrevious ? "" : undefined
61996
+ // What the container reads to know a slide is waiting for a travel
61997
+ // to come near (see renderNear).
61998
+ ,
61999
+ "data-slide-unrendered": rendered ? undefined : ""
61869
62000
  // A surface one interacts with says what state it is in, the way every
61870
62001
  // other surface does — a dialog carries the very same set.
61871
62002
  // :focus-within is the one a slide is really about: it is what tells
61872
62003
  // the slide holding the keyboard from the ones waiting.
61873
62004
  ,
61874
62005
  pseudoClasses: SLIDE_PSEUDO_CLASSES,
61875
- children: children
62006
+ children: rendered ? children : null
61876
62007
  })
61877
62008
  })
61878
62009
  });
@@ -67881,6 +68012,69 @@ const toPopoverAnimation = animation => {
67881
68012
  return animation;
67882
68013
  };
67883
68014
 
68015
+ const PickerContext = createContext();
68016
+
68017
+ /*
68018
+ * The picker's context, for whatever draws its value. A picker told no value
68019
+ * holds what the control in its popup holds, and builds that popup only when
68020
+ * something reads it (see the mount decision in picker_custom.jsx): what the
68021
+ * picker draws itself it knows about, a drawing given as an element is the
68022
+ * caller's, and says so here by reading. In a layout effect, so the frame that
68023
+ * first shows the drawing already shows the value.
68024
+ */
68025
+ const usePickerContext = () => {
68026
+ const context = useContext(PickerContext);
68027
+ const requestValue = context?.requestValue;
68028
+ useLayoutEffect(() => {
68029
+ requestValue?.();
68030
+ }, [requestValue]);
68031
+ return context;
68032
+ };
68033
+
68034
+ /*
68035
+ * A typed picker (`type="date"`, `type="array"`, …) draws its value with a ui
68036
+ * of navi's own, installed as the very "ui" prop a caller overrides to draw
68037
+ * that value themselves. Marking navi's own tells the two apart afterwards:
68038
+ * an empty value is greyed as a placeholder only when the drawing is navi's —
68039
+ * a caller's ui may well be their way of writing "no filter", which is an
68040
+ * answer, not a blank (see navi-placeholder in picker.jsx).
68041
+ */
68042
+ const asPickerOwnUI = PickerUI => {
68043
+ PickerUI.isPickerOwnUI = true;
68044
+ return PickerUI;
68045
+ };
68046
+ const pickerUIIsNaviOwn = ui => {
68047
+ return Boolean(ui) && typeof ui === "object" && Boolean(ui.type?.isPickerOwnUI);
68048
+ };
68049
+
68050
+ /**
68051
+ * What the picker holds, read from inside its `ui` — for a drawing given as
68052
+ * an element (`ui={<MyCard game={game} />}`), which the picker cannot hand
68053
+ * props to. `value` is the state the picker holds right now: the answer the
68054
+ * popup just closed on, before the server has said anything, and put back if
68055
+ * the action fails. `loading` is the run in flight; `interactive` is false
68056
+ * while the picker is disabled, read-only or busy.
68057
+ *
68058
+ * @returns {{ value: any, loading: boolean, interactive: boolean } | null}
68059
+ * null outside a picker.
68060
+ */
68061
+ const usePickerState = () => {
68062
+ const context = usePickerContext();
68063
+ if (!context) {
68064
+ return null;
68065
+ }
68066
+ const {
68067
+ value,
68068
+ loading,
68069
+ interactive
68070
+ } = context;
68071
+ return {
68072
+ value,
68073
+ loading,
68074
+ interactive
68075
+ };
68076
+ };
68077
+
67884
68078
  installImportMetaCssBuild(import.meta);
67885
68079
  const css$B = /* css */`.navi_picker_callout_dock > [data-picker-content] {
67886
68080
  display: none;
@@ -68108,6 +68302,12 @@ const PickerCustom = props => {
68108
68302
  const idDefault = useId();
68109
68303
  const controlId = useContext(ControlIdContext);
68110
68304
  props.id = props.id || controlId || idDefault;
68305
+ // Given no value, the picker holds what the control in its popup holds (see
68306
+ // the `mount` decision below) — and a group around it collects that from the
68307
+ // moment both exist.
68308
+ const valueInPopup = !isControlValueGivenByProps(props);
68309
+ const parentController = useContext(ParentUIStateControllerContext);
68310
+ const answersToGroup = Boolean(parentController) && !props.standalone;
68111
68311
  // Same narrow-container/maxWidth-compact heuristic Popup itself uses (see
68112
68312
  // popup_mode.jsx's own useResolvedPopupMode) — frozen for the lifetime of an opening
68113
68313
  // (computed when closed, stable while open, so a screen resize mid-session
@@ -68340,12 +68540,20 @@ const PickerCustom = props => {
68340
68540
  const requestInteraction = options => {
68341
68541
  dispatchRequestInteraction(ref.current, options);
68342
68542
  };
68543
+
68544
+ // What a drawing of the caller's calls as it reads the value (see
68545
+ // usePickerContext): the popup holding it, built while closed. Only when
68546
+ // `mount` is left to the picker — a caller who set it has said when.
68547
+ const requestValue = useStableCallback(() => {
68548
+ openController.buildContent();
68549
+ });
68343
68550
  const {
68344
68551
  onActionStart,
68345
68552
  children,
68346
68553
  uiAction: uiActionProp
68347
68554
  } = props;
68348
68555
  Object.assign(pickerProps, {
68556
+ "requestValue": valueInPopup && props.mount === undefined ? requestValue : undefined,
68349
68557
  "aria-expanded": Boolean(expanded),
68350
68558
  "onActionStart": e => {
68351
68559
  onActionStart?.(e);
@@ -68384,13 +68592,12 @@ const PickerCustom = props => {
68384
68592
  anchor: props.anchor || props.ref,
68385
68593
  openController,
68386
68594
  // A picker whose value was never given to it reads it off the control in
68387
- // its popup (see useUIFacadeStateController): the trigger shows what the
68388
- // list inside says is selected, so that list has to exist before anyone
68389
- // opens anything. Told a value — even an empty one — the picker owns it
68390
- // and pushes it down instead, leaving the popup free to build its
68391
- // content only when it is first opened (see popup_content_mount.js).
68392
- // A caller who knows better says so with the popup's own props.
68393
- mount: props.mount ?? (isControlValueGivenByProps(props) ? MOUNT_DEFAULT : "always"),
68595
+ // its popup (see useUIFacadeStateController), so that control is built as
68596
+ // soon as something reads the value: at mount when the picker sees the
68597
+ // reader, otherwise when a drawing of the caller's asks (requestValue
68598
+ // above). Told a value — even an empty one — the picker pushes it down,
68599
+ // and the popup waits for its first open (see popup_content_mount.js).
68600
+ mount: props.mount ?? (valueInPopup && isPickerValueReadAtMount(props, answersToGroup) ? "always" : MOUNT_DEFAULT),
68394
68601
  // Not on pickerProps (the trigger): commands.js's own
68395
68602
  // resolveClosestExpandable() does `el.closest("[aria-expanded]")` to
68396
68603
  // find where to dispatch navi_request_open/navi_request_close — and
@@ -68677,6 +68884,29 @@ const PickerCustom = props => {
68677
68884
  });
68678
68885
  };
68679
68886
 
68887
+ // Whether something reads a picker's value before its popup has opened, as
68888
+ // far as the picker sees from its own props: the drawing navi renders for it
68889
+ // (its own, or the typed one PickerTypeResolver installs — `ui` is still unset
68890
+ // here), one of navi's Picker.UI.*, a component handed `value`, the clear
68891
+ // cross, a form submitting it by name, a group it answers to. A headless
68892
+ // picker draws nothing, and an element `ui` is the caller's: it reads through
68893
+ // usePickerContext, which asks for the value then.
68894
+ const isPickerValueReadAtMount = (props, answersToGroup) => {
68895
+ if (props.name !== undefined || answersToGroup) {
68896
+ return true;
68897
+ }
68898
+ if (props.variant === "headless") {
68899
+ return false;
68900
+ }
68901
+ if (props.clearable) {
68902
+ return true;
68903
+ }
68904
+ const {
68905
+ ui
68906
+ } = props;
68907
+ return ui === undefined || typeof ui === "function" || pickerUIIsNaviOwn(ui);
68908
+ };
68909
+
68680
68910
  // A hold declared on something AROUND the picker (a card opened by
68681
68911
  // `openOn="longpress"`, holding this one in its drawing): the finger going
68682
68912
  // down may be the start of that hold, so this picker opens on the click — which
@@ -69192,52 +69422,6 @@ const PickerConfirmBody = ({
69192
69422
  });
69193
69423
  };
69194
69424
 
69195
- const PickerContext = createContext();
69196
-
69197
- /*
69198
- * A typed picker (`type="date"`, `type="array"`, …) draws its value with a ui
69199
- * of navi's own, installed as the very "ui" prop a caller overrides to draw
69200
- * that value themselves. Marking navi's own tells the two apart afterwards:
69201
- * an empty value is greyed as a placeholder only when the drawing is navi's —
69202
- * a caller's ui may well be their way of writing "no filter", which is an
69203
- * answer, not a blank (see navi-placeholder in picker.jsx).
69204
- */
69205
- const asPickerOwnUI = PickerUI => {
69206
- PickerUI.isPickerOwnUI = true;
69207
- return PickerUI;
69208
- };
69209
- const pickerUIIsNaviOwn = ui => {
69210
- return Boolean(ui) && typeof ui === "object" && Boolean(ui.type?.isPickerOwnUI);
69211
- };
69212
-
69213
- /**
69214
- * What the picker holds, read from inside its `ui` — for a drawing given as
69215
- * an element (`ui={<MyCard game={game} />}`), which the picker cannot hand
69216
- * props to. `value` is the state the picker holds right now: the answer the
69217
- * popup just closed on, before the server has said anything, and put back if
69218
- * the action fails. `loading` is the run in flight; `interactive` is false
69219
- * while the picker is disabled, read-only or busy.
69220
- *
69221
- * @returns {{ value: any, loading: boolean, interactive: boolean } | null}
69222
- * null outside a picker.
69223
- */
69224
- const usePickerState = () => {
69225
- const context = useContext(PickerContext);
69226
- if (!context) {
69227
- return null;
69228
- }
69229
- const {
69230
- value,
69231
- loading,
69232
- interactive
69233
- } = context;
69234
- return {
69235
- value,
69236
- loading,
69237
- interactive
69238
- };
69239
- };
69240
-
69241
69425
  const PickerNaviMinute = props => {
69242
69426
  const Next = useNextResolver();
69243
69427
  const {
@@ -77647,7 +77831,7 @@ const PickerObjectUI = /*#__PURE__*/asPickerOwnUI(() => {
77647
77831
  const {
77648
77832
  value,
77649
77833
  placeholder
77650
- } = useContext(PickerContext);
77834
+ } = usePickerContext();
77651
77835
  if (uiStateHoldsNothing(value)) {
77652
77836
  if (!placeholder) {
77653
77837
  return null;
@@ -77683,7 +77867,7 @@ const PickerArrayUI = /*#__PURE__*/asPickerOwnUI(() => {
77683
77867
  value,
77684
77868
  placeholder,
77685
77869
  maxLines
77686
- } = useContext(PickerContext);
77870
+ } = usePickerContext();
77687
77871
  if (uiStateHoldsNothing(value)) {
77688
77872
  if (!placeholder) {
77689
77873
  return null;
@@ -77765,7 +77949,7 @@ const PickerColorUI = /*#__PURE__*/asPickerOwnUI(() => {
77765
77949
  const {
77766
77950
  value,
77767
77951
  placeholder
77768
- } = useContext(PickerContext);
77952
+ } = usePickerContext();
77769
77953
  if (!value) {
77770
77954
  if (!placeholder) {
77771
77955
  return jsx(Color, {});
@@ -77789,7 +77973,7 @@ const PickerDateUI = /*#__PURE__*/asPickerOwnUI(props => {
77789
77973
  const {
77790
77974
  value,
77791
77975
  placeholder
77792
- } = useContext(PickerContext);
77976
+ } = usePickerContext();
77793
77977
  if (!value) {
77794
77978
  if (!placeholder) {
77795
77979
  return jsx(Time, {
@@ -77821,7 +78005,7 @@ const PickerMonthUI = /*#__PURE__*/asPickerOwnUI(props => {
77821
78005
  const {
77822
78006
  value,
77823
78007
  placeholder
77824
- } = useContext(PickerContext);
78008
+ } = usePickerContext();
77825
78009
  if (!value) {
77826
78010
  if (!placeholder) {
77827
78011
  return jsx(Time, {
@@ -77852,7 +78036,7 @@ const PickerWeekUI = /*#__PURE__*/asPickerOwnUI(props => {
77852
78036
  const {
77853
78037
  value,
77854
78038
  placeholder
77855
- } = useContext(PickerContext);
78039
+ } = usePickerContext();
77856
78040
  if (!value) {
77857
78041
  if (!placeholder) {
77858
78042
  return jsx(Time, {
@@ -77883,7 +78067,7 @@ const PickerTimeUI = /*#__PURE__*/asPickerOwnUI(props => {
77883
78067
  const {
77884
78068
  value,
77885
78069
  placeholder
77886
- } = useContext(PickerContext);
78070
+ } = usePickerContext();
77887
78071
  if (!value) {
77888
78072
  if (!placeholder) {
77889
78073
  return jsx(Time, {
@@ -77914,7 +78098,7 @@ const PickerDurationUI = /*#__PURE__*/asPickerOwnUI(props => {
77914
78098
  const {
77915
78099
  value,
77916
78100
  placeholder
77917
- } = useContext(PickerContext);
78101
+ } = usePickerContext();
77918
78102
  if (!value) {
77919
78103
  if (!placeholder) {
77920
78104
  return jsx(Time, {
@@ -77944,7 +78128,7 @@ const PickerDatetimeUI = /*#__PURE__*/asPickerOwnUI(props => {
77944
78128
  const {
77945
78129
  value,
77946
78130
  placeholder
77947
- } = useContext(PickerContext);
78131
+ } = usePickerContext();
77948
78132
  if (!value) {
77949
78133
  if (!placeholder) {
77950
78134
  return jsx(Time, {
@@ -77973,7 +78157,7 @@ const PickerFileUI = /*#__PURE__*/asPickerOwnUI(() => {
77973
78157
  const {
77974
78158
  value,
77975
78159
  placeholder
77976
- } = useContext(PickerContext);
78160
+ } = usePickerContext();
77977
78161
  if (!value) {
77978
78162
  if (!placeholder) {
77979
78163
  return null;
@@ -78507,7 +78691,11 @@ const PickerButton = props => {
78507
78691
  // a piece of, waiting as a whole (see the `loadingOutline` doc).
78508
78692
  loadingOutline,
78509
78693
  // Where the outline runs, in px from the picker's box: negative is outside.
78510
- loadingOutlineInset = -2
78694
+ loadingOutlineInset = -2,
78695
+ // Builds the popup this picker's value is read from, for a drawing that
78696
+ // reads it (see usePickerContext). Set by PickerCustom, only while that
78697
+ // value lives in the popup.
78698
+ requestValue
78511
78699
  } = props;
78512
78700
  // A word in a sentence is never truncated — and the clamp's overflow: hidden
78513
78701
  // would cut its dotted underline, which sits on the edge of the line box
@@ -78603,7 +78791,8 @@ const PickerButton = props => {
78603
78791
  id: inputProps.id,
78604
78792
  interactive,
78605
78793
  loading,
78606
- clearConfirm
78794
+ clearConfirm,
78795
+ requestValue
78607
78796
  };
78608
78797
  return (
78609
78798
  /* Read-only crosses into everything the picker is made of: what it really
@@ -78654,7 +78843,8 @@ const PickerButton = props => {
78654
78843
  error: undefined,
78655
78844
  dayLabel: undefined,
78656
78845
  loadingOutline: undefined,
78657
- loadingOutlineInset: undefined
78846
+ loadingOutlineInset: undefined,
78847
+ requestValue: undefined
78658
78848
  // This wrapper will receive keyboard event bubbling from the picker popup content
78659
78849
  // we re-dispatch on the input (to get escape to close for instance)
78660
78850
  ,
@@ -78868,7 +79058,7 @@ const PickerClear = ({
78868
79058
  children,
78869
79059
  ...rest
78870
79060
  }) => {
78871
- const pickerContext = useContext(PickerContext);
79061
+ const pickerContext = usePickerContext();
78872
79062
  if (!pickerContext) {
78873
79063
  return null;
78874
79064
  }
@@ -79140,7 +79330,7 @@ const PickerDefaultUI = () => {
79140
79330
  const {
79141
79331
  value,
79142
79332
  placeholder
79143
- } = useContext(PickerContext);
79333
+ } = usePickerContext();
79144
79334
  if (!value) {
79145
79335
  if (!placeholder) {
79146
79336
  return null;