@jsenv/navi 0.29.424 → 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 +150 -73
- package/dist/dev/jsenv_navi.js.map +8 -8
- package/dist/jsenv_navi.js +143 -69
- package/dist/jsenv_navi.js.map +8 -8
- package/docs/popup_open.md +16 -11
- package/package.json +1 -1
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
|
? () => {
|
|
@@ -67997,6 +68012,69 @@ const toPopoverAnimation = animation => {
|
|
|
67997
68012
|
return animation;
|
|
67998
68013
|
};
|
|
67999
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
|
+
|
|
68000
68078
|
installImportMetaCssBuild(import.meta);
|
|
68001
68079
|
const css$B = /* css */`.navi_picker_callout_dock > [data-picker-content] {
|
|
68002
68080
|
display: none;
|
|
@@ -68224,6 +68302,12 @@ const PickerCustom = props => {
|
|
|
68224
68302
|
const idDefault = useId();
|
|
68225
68303
|
const controlId = useContext(ControlIdContext);
|
|
68226
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;
|
|
68227
68311
|
// Same narrow-container/maxWidth-compact heuristic Popup itself uses (see
|
|
68228
68312
|
// popup_mode.jsx's own useResolvedPopupMode) — frozen for the lifetime of an opening
|
|
68229
68313
|
// (computed when closed, stable while open, so a screen resize mid-session
|
|
@@ -68456,12 +68540,20 @@ const PickerCustom = props => {
|
|
|
68456
68540
|
const requestInteraction = options => {
|
|
68457
68541
|
dispatchRequestInteraction(ref.current, options);
|
|
68458
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
|
+
});
|
|
68459
68550
|
const {
|
|
68460
68551
|
onActionStart,
|
|
68461
68552
|
children,
|
|
68462
68553
|
uiAction: uiActionProp
|
|
68463
68554
|
} = props;
|
|
68464
68555
|
Object.assign(pickerProps, {
|
|
68556
|
+
"requestValue": valueInPopup && props.mount === undefined ? requestValue : undefined,
|
|
68465
68557
|
"aria-expanded": Boolean(expanded),
|
|
68466
68558
|
"onActionStart": e => {
|
|
68467
68559
|
onActionStart?.(e);
|
|
@@ -68500,13 +68592,12 @@ const PickerCustom = props => {
|
|
|
68500
68592
|
anchor: props.anchor || props.ref,
|
|
68501
68593
|
openController,
|
|
68502
68594
|
// A picker whose value was never given to it reads it off the control in
|
|
68503
|
-
// its popup (see useUIFacadeStateController)
|
|
68504
|
-
//
|
|
68505
|
-
//
|
|
68506
|
-
//
|
|
68507
|
-
//
|
|
68508
|
-
|
|
68509
|
-
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),
|
|
68510
68601
|
// Not on pickerProps (the trigger): commands.js's own
|
|
68511
68602
|
// resolveClosestExpandable() does `el.closest("[aria-expanded]")` to
|
|
68512
68603
|
// find where to dispatch navi_request_open/navi_request_close — and
|
|
@@ -68793,6 +68884,29 @@ const PickerCustom = props => {
|
|
|
68793
68884
|
});
|
|
68794
68885
|
};
|
|
68795
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
|
+
|
|
68796
68910
|
// A hold declared on something AROUND the picker (a card opened by
|
|
68797
68911
|
// `openOn="longpress"`, holding this one in its drawing): the finger going
|
|
68798
68912
|
// down may be the start of that hold, so this picker opens on the click — which
|
|
@@ -69308,52 +69422,6 @@ const PickerConfirmBody = ({
|
|
|
69308
69422
|
});
|
|
69309
69423
|
};
|
|
69310
69424
|
|
|
69311
|
-
const PickerContext = createContext();
|
|
69312
|
-
|
|
69313
|
-
/*
|
|
69314
|
-
* A typed picker (`type="date"`, `type="array"`, …) draws its value with a ui
|
|
69315
|
-
* of navi's own, installed as the very "ui" prop a caller overrides to draw
|
|
69316
|
-
* that value themselves. Marking navi's own tells the two apart afterwards:
|
|
69317
|
-
* an empty value is greyed as a placeholder only when the drawing is navi's —
|
|
69318
|
-
* a caller's ui may well be their way of writing "no filter", which is an
|
|
69319
|
-
* answer, not a blank (see navi-placeholder in picker.jsx).
|
|
69320
|
-
*/
|
|
69321
|
-
const asPickerOwnUI = PickerUI => {
|
|
69322
|
-
PickerUI.isPickerOwnUI = true;
|
|
69323
|
-
return PickerUI;
|
|
69324
|
-
};
|
|
69325
|
-
const pickerUIIsNaviOwn = ui => {
|
|
69326
|
-
return Boolean(ui) && typeof ui === "object" && Boolean(ui.type?.isPickerOwnUI);
|
|
69327
|
-
};
|
|
69328
|
-
|
|
69329
|
-
/**
|
|
69330
|
-
* What the picker holds, read from inside its `ui` — for a drawing given as
|
|
69331
|
-
* an element (`ui={<MyCard game={game} />}`), which the picker cannot hand
|
|
69332
|
-
* props to. `value` is the state the picker holds right now: the answer the
|
|
69333
|
-
* popup just closed on, before the server has said anything, and put back if
|
|
69334
|
-
* the action fails. `loading` is the run in flight; `interactive` is false
|
|
69335
|
-
* while the picker is disabled, read-only or busy.
|
|
69336
|
-
*
|
|
69337
|
-
* @returns {{ value: any, loading: boolean, interactive: boolean } | null}
|
|
69338
|
-
* null outside a picker.
|
|
69339
|
-
*/
|
|
69340
|
-
const usePickerState = () => {
|
|
69341
|
-
const context = useContext(PickerContext);
|
|
69342
|
-
if (!context) {
|
|
69343
|
-
return null;
|
|
69344
|
-
}
|
|
69345
|
-
const {
|
|
69346
|
-
value,
|
|
69347
|
-
loading,
|
|
69348
|
-
interactive
|
|
69349
|
-
} = context;
|
|
69350
|
-
return {
|
|
69351
|
-
value,
|
|
69352
|
-
loading,
|
|
69353
|
-
interactive
|
|
69354
|
-
};
|
|
69355
|
-
};
|
|
69356
|
-
|
|
69357
69425
|
const PickerNaviMinute = props => {
|
|
69358
69426
|
const Next = useNextResolver();
|
|
69359
69427
|
const {
|
|
@@ -77763,7 +77831,7 @@ const PickerObjectUI = /*#__PURE__*/asPickerOwnUI(() => {
|
|
|
77763
77831
|
const {
|
|
77764
77832
|
value,
|
|
77765
77833
|
placeholder
|
|
77766
|
-
} =
|
|
77834
|
+
} = usePickerContext();
|
|
77767
77835
|
if (uiStateHoldsNothing(value)) {
|
|
77768
77836
|
if (!placeholder) {
|
|
77769
77837
|
return null;
|
|
@@ -77799,7 +77867,7 @@ const PickerArrayUI = /*#__PURE__*/asPickerOwnUI(() => {
|
|
|
77799
77867
|
value,
|
|
77800
77868
|
placeholder,
|
|
77801
77869
|
maxLines
|
|
77802
|
-
} =
|
|
77870
|
+
} = usePickerContext();
|
|
77803
77871
|
if (uiStateHoldsNothing(value)) {
|
|
77804
77872
|
if (!placeholder) {
|
|
77805
77873
|
return null;
|
|
@@ -77881,7 +77949,7 @@ const PickerColorUI = /*#__PURE__*/asPickerOwnUI(() => {
|
|
|
77881
77949
|
const {
|
|
77882
77950
|
value,
|
|
77883
77951
|
placeholder
|
|
77884
|
-
} =
|
|
77952
|
+
} = usePickerContext();
|
|
77885
77953
|
if (!value) {
|
|
77886
77954
|
if (!placeholder) {
|
|
77887
77955
|
return jsx(Color, {});
|
|
@@ -77905,7 +77973,7 @@ const PickerDateUI = /*#__PURE__*/asPickerOwnUI(props => {
|
|
|
77905
77973
|
const {
|
|
77906
77974
|
value,
|
|
77907
77975
|
placeholder
|
|
77908
|
-
} =
|
|
77976
|
+
} = usePickerContext();
|
|
77909
77977
|
if (!value) {
|
|
77910
77978
|
if (!placeholder) {
|
|
77911
77979
|
return jsx(Time, {
|
|
@@ -77937,7 +78005,7 @@ const PickerMonthUI = /*#__PURE__*/asPickerOwnUI(props => {
|
|
|
77937
78005
|
const {
|
|
77938
78006
|
value,
|
|
77939
78007
|
placeholder
|
|
77940
|
-
} =
|
|
78008
|
+
} = usePickerContext();
|
|
77941
78009
|
if (!value) {
|
|
77942
78010
|
if (!placeholder) {
|
|
77943
78011
|
return jsx(Time, {
|
|
@@ -77968,7 +78036,7 @@ const PickerWeekUI = /*#__PURE__*/asPickerOwnUI(props => {
|
|
|
77968
78036
|
const {
|
|
77969
78037
|
value,
|
|
77970
78038
|
placeholder
|
|
77971
|
-
} =
|
|
78039
|
+
} = usePickerContext();
|
|
77972
78040
|
if (!value) {
|
|
77973
78041
|
if (!placeholder) {
|
|
77974
78042
|
return jsx(Time, {
|
|
@@ -77999,7 +78067,7 @@ const PickerTimeUI = /*#__PURE__*/asPickerOwnUI(props => {
|
|
|
77999
78067
|
const {
|
|
78000
78068
|
value,
|
|
78001
78069
|
placeholder
|
|
78002
|
-
} =
|
|
78070
|
+
} = usePickerContext();
|
|
78003
78071
|
if (!value) {
|
|
78004
78072
|
if (!placeholder) {
|
|
78005
78073
|
return jsx(Time, {
|
|
@@ -78030,7 +78098,7 @@ const PickerDurationUI = /*#__PURE__*/asPickerOwnUI(props => {
|
|
|
78030
78098
|
const {
|
|
78031
78099
|
value,
|
|
78032
78100
|
placeholder
|
|
78033
|
-
} =
|
|
78101
|
+
} = usePickerContext();
|
|
78034
78102
|
if (!value) {
|
|
78035
78103
|
if (!placeholder) {
|
|
78036
78104
|
return jsx(Time, {
|
|
@@ -78060,7 +78128,7 @@ const PickerDatetimeUI = /*#__PURE__*/asPickerOwnUI(props => {
|
|
|
78060
78128
|
const {
|
|
78061
78129
|
value,
|
|
78062
78130
|
placeholder
|
|
78063
|
-
} =
|
|
78131
|
+
} = usePickerContext();
|
|
78064
78132
|
if (!value) {
|
|
78065
78133
|
if (!placeholder) {
|
|
78066
78134
|
return jsx(Time, {
|
|
@@ -78089,7 +78157,7 @@ const PickerFileUI = /*#__PURE__*/asPickerOwnUI(() => {
|
|
|
78089
78157
|
const {
|
|
78090
78158
|
value,
|
|
78091
78159
|
placeholder
|
|
78092
|
-
} =
|
|
78160
|
+
} = usePickerContext();
|
|
78093
78161
|
if (!value) {
|
|
78094
78162
|
if (!placeholder) {
|
|
78095
78163
|
return null;
|
|
@@ -78623,7 +78691,11 @@ const PickerButton = props => {
|
|
|
78623
78691
|
// a piece of, waiting as a whole (see the `loadingOutline` doc).
|
|
78624
78692
|
loadingOutline,
|
|
78625
78693
|
// Where the outline runs, in px from the picker's box: negative is outside.
|
|
78626
|
-
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
|
|
78627
78699
|
} = props;
|
|
78628
78700
|
// A word in a sentence is never truncated — and the clamp's overflow: hidden
|
|
78629
78701
|
// would cut its dotted underline, which sits on the edge of the line box
|
|
@@ -78719,7 +78791,8 @@ const PickerButton = props => {
|
|
|
78719
78791
|
id: inputProps.id,
|
|
78720
78792
|
interactive,
|
|
78721
78793
|
loading,
|
|
78722
|
-
clearConfirm
|
|
78794
|
+
clearConfirm,
|
|
78795
|
+
requestValue
|
|
78723
78796
|
};
|
|
78724
78797
|
return (
|
|
78725
78798
|
/* Read-only crosses into everything the picker is made of: what it really
|
|
@@ -78770,7 +78843,8 @@ const PickerButton = props => {
|
|
|
78770
78843
|
error: undefined,
|
|
78771
78844
|
dayLabel: undefined,
|
|
78772
78845
|
loadingOutline: undefined,
|
|
78773
|
-
loadingOutlineInset: undefined
|
|
78846
|
+
loadingOutlineInset: undefined,
|
|
78847
|
+
requestValue: undefined
|
|
78774
78848
|
// This wrapper will receive keyboard event bubbling from the picker popup content
|
|
78775
78849
|
// we re-dispatch on the input (to get escape to close for instance)
|
|
78776
78850
|
,
|
|
@@ -78984,7 +79058,7 @@ const PickerClear = ({
|
|
|
78984
79058
|
children,
|
|
78985
79059
|
...rest
|
|
78986
79060
|
}) => {
|
|
78987
|
-
const pickerContext =
|
|
79061
|
+
const pickerContext = usePickerContext();
|
|
78988
79062
|
if (!pickerContext) {
|
|
78989
79063
|
return null;
|
|
78990
79064
|
}
|
|
@@ -79256,7 +79330,7 @@ const PickerDefaultUI = () => {
|
|
|
79256
79330
|
const {
|
|
79257
79331
|
value,
|
|
79258
79332
|
placeholder
|
|
79259
|
-
} =
|
|
79333
|
+
} = usePickerContext();
|
|
79260
79334
|
if (!value) {
|
|
79261
79335
|
if (!placeholder) {
|
|
79262
79336
|
return null;
|