@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.
- package/dist/dev/jsenv_navi.js +273 -80
- package/dist/dev/jsenv_navi.js.map +9 -9
- package/dist/jsenv_navi.js +266 -76
- package/dist/jsenv_navi.js.map +9 -9
- package/docs/popup_open.md +16 -11
- package/package.json +2 -2
package/dist/jsenv_navi.js
CHANGED
|
@@ -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 (
|
|
60477
|
-
|
|
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)
|
|
68388
|
-
//
|
|
68389
|
-
//
|
|
68390
|
-
//
|
|
68391
|
-
//
|
|
68392
|
-
|
|
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
|
-
} =
|
|
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
|
-
} =
|
|
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
|
-
} =
|
|
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
|
-
} =
|
|
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
|
-
} =
|
|
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
|
-
} =
|
|
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
|
-
} =
|
|
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
|
-
} =
|
|
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
|
-
} =
|
|
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
|
-
} =
|
|
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 =
|
|
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
|
-
} =
|
|
79333
|
+
} = usePickerContext();
|
|
79144
79334
|
if (!value) {
|
|
79145
79335
|
if (!placeholder) {
|
|
79146
79336
|
return null;
|