@jsenv/navi 0.29.471 → 0.29.473
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 +69 -22
- package/dist/dev/jsenv_navi.js.map +8 -8
- package/dist/jsenv_navi.js +60 -20
- package/dist/jsenv_navi.js.map +8 -8
- package/package.json +1 -1
package/dist/jsenv_navi.js
CHANGED
|
@@ -42894,6 +42894,7 @@ const useRenderScope = (init, update) => {
|
|
|
42894
42894
|
* registerChild(child): void; // Called on child mount
|
|
42895
42895
|
* onChildUIAction(child, e, { stateChanged: boolean }): void; // Called when a child fires a UI action
|
|
42896
42896
|
* unregisterChild(child): void; // Called on child unmount
|
|
42897
|
+
* collectsChild(child): boolean; // Whether registerChild(child) would put it in a value, here or above
|
|
42897
42898
|
* props: Object;
|
|
42898
42899
|
* ref: Ref; // Used to dispatch DOM events
|
|
42899
42900
|
* getManagedControls(): UIStateController[]; // Returns controls whose validity is managed by this controller
|
|
@@ -43596,6 +43597,10 @@ const useUIStateController = (
|
|
|
43596
43597
|
unregisterChild: (childUIStateController) => {
|
|
43597
43598
|
s.parentUIStateController?.unregisterChild(childUIStateController);
|
|
43598
43599
|
},
|
|
43600
|
+
collectsChild: (childUIStateController) =>
|
|
43601
|
+
Boolean(
|
|
43602
|
+
s.parentUIStateController?.collectsChild(childUIStateController),
|
|
43603
|
+
),
|
|
43599
43604
|
onChildUIAction: (childUIStateController, e, options) => {
|
|
43600
43605
|
s.parentUIStateController?.onChildUIAction(
|
|
43601
43606
|
childUIStateController,
|
|
@@ -43982,10 +43987,13 @@ const readNamedChildUIStates = (children, { warnNameless }) => {
|
|
|
43982
43987
|
// Looked up in useUIGroupStateController to fill in omitted aggregateChildStates /
|
|
43983
43988
|
// distributeChildUIState. If neither a default nor an explicit impl is found for a
|
|
43984
43989
|
// group, creation throws so the caller knows it must supply them.
|
|
43990
|
+
// The radio/checkbox filters read `props.type`, which controlHostProps copies:
|
|
43991
|
+
// a child is also asked about while rendering, before its first render has
|
|
43992
|
+
// built controlHostProps (see collectsChild).
|
|
43985
43993
|
const GROUP_DEFAULTS = {
|
|
43986
43994
|
radio_group: {
|
|
43987
43995
|
childControlFilter: (child) =>
|
|
43988
|
-
child.controlType === "input" && child.
|
|
43996
|
+
child.controlType === "input" && child.props?.type === "radio",
|
|
43989
43997
|
aggregateChildStates: keptOrFirstDefinedChildUIState,
|
|
43990
43998
|
distributeChildUIState: (newUIState, childUIStateController) => {
|
|
43991
43999
|
const childSelected = childUIStateController.props.value === newUIState;
|
|
@@ -43997,8 +44005,7 @@ const GROUP_DEFAULTS = {
|
|
|
43997
44005
|
},
|
|
43998
44006
|
checkbox_group: {
|
|
43999
44007
|
childControlFilter: (child) =>
|
|
44000
|
-
child.controlType === "input" &&
|
|
44001
|
-
child.controlHostProps?.type === "checkbox",
|
|
44008
|
+
child.controlType === "input" && child.props?.type === "checkbox",
|
|
44002
44009
|
aggregateChildStates: keptAndCheckedChildUIStates,
|
|
44003
44010
|
distributeChildUIState: (newUIState, childUIStateController) => {
|
|
44004
44011
|
const childSelected =
|
|
@@ -44533,6 +44540,9 @@ const useUIGroupStateController = (
|
|
|
44533
44540
|
|
|
44534
44541
|
const controller = {
|
|
44535
44542
|
controlType,
|
|
44543
|
+
// Published from the first render, like a leaf's: a group asks its
|
|
44544
|
+
// parent whether anyone listens before its first update.
|
|
44545
|
+
parentUIStateController,
|
|
44536
44546
|
id,
|
|
44537
44547
|
name,
|
|
44538
44548
|
value,
|
|
@@ -44756,6 +44766,18 @@ const useUIGroupStateController = (
|
|
|
44756
44766
|
notifyExternal: "silent",
|
|
44757
44767
|
});
|
|
44758
44768
|
},
|
|
44769
|
+
// registerChild above, asked ahead: monitored here, handed up, or
|
|
44770
|
+
// captured and dropped.
|
|
44771
|
+
collectsChild: (childUIStateController) => {
|
|
44772
|
+
if (isMonitoringChild(childUIStateController)) {
|
|
44773
|
+
return true;
|
|
44774
|
+
}
|
|
44775
|
+
const currentParent = s.parentUIStateController;
|
|
44776
|
+
if (allowCapture || !currentParent) {
|
|
44777
|
+
return false;
|
|
44778
|
+
}
|
|
44779
|
+
return currentParent.collectsChild(childUIStateController);
|
|
44780
|
+
},
|
|
44759
44781
|
onChildUIAction: (
|
|
44760
44782
|
childUIStateController,
|
|
44761
44783
|
e,
|
|
@@ -45228,6 +45250,9 @@ const useUIFacadeStateController = (props, realUIStateController) => {
|
|
|
45228
45250
|
s.realUIStateController.facadeChild = null;
|
|
45229
45251
|
}
|
|
45230
45252
|
},
|
|
45253
|
+
// A refused child is not handed further up: the popup's controls
|
|
45254
|
+
// answer to the picker or to nobody.
|
|
45255
|
+
collectsChild: (child) => canRegisterAsFacadeChild(child),
|
|
45231
45256
|
getManagedControls: () => {
|
|
45232
45257
|
const child = firstChildControllerRef.current;
|
|
45233
45258
|
if (!child) {
|
|
@@ -45769,8 +45794,6 @@ const useControlProps = (props, {
|
|
|
45769
45794
|
const controlInfo = createControlInfo(props, {
|
|
45770
45795
|
controlType
|
|
45771
45796
|
});
|
|
45772
|
-
const readOnlyUncontrolled = useReadOnlyUncontrolled(props, controlInfo);
|
|
45773
|
-
controlInfo.readOnlyUncontrolled = readOnlyUncontrolled;
|
|
45774
45797
|
const uiStateController = useUIStateController(props, {
|
|
45775
45798
|
controlInfo,
|
|
45776
45799
|
syncDomState,
|
|
@@ -45778,6 +45801,9 @@ const useControlProps = (props, {
|
|
|
45778
45801
|
persists,
|
|
45779
45802
|
uiActionInternal
|
|
45780
45803
|
});
|
|
45804
|
+
// After the controller: whether a group listens is asked of the parent it
|
|
45805
|
+
// registers into. Read by useInteractiveProps below.
|
|
45806
|
+
controlInfo.readOnlyUncontrolled = useReadOnlyUncontrolled(props, controlInfo, uiStateController);
|
|
45781
45807
|
// What the control draws is what it holds by itself, and this read is what
|
|
45782
45808
|
// re-renders it when that changes. A button inheriting the value of the
|
|
45783
45809
|
// control around it (a submit in a form, see ownUIStateSignal) draws none of
|
|
@@ -46773,16 +46799,21 @@ const INPUT_TYPE_SUPPORTING_READONLY_SET = new Set(["text", "date", "datetime-lo
|
|
|
46773
46799
|
// warning below so a group can ask the same question a single control does: a
|
|
46774
46800
|
// control with a `value` and nobody listening cannot be changed by hand, and
|
|
46775
46801
|
// that is true whatever the control is.
|
|
46776
|
-
|
|
46802
|
+
// The group is asked, not assumed from a controller being above: a control in
|
|
46803
|
+
// between may only pass registration along (a <Details> holds none of the
|
|
46804
|
+
// values it folds), and a group may hand the control further up or drop it.
|
|
46805
|
+
const useIsControlListenedTo = (props, uiStateController) => {
|
|
46777
46806
|
const isProxy = Boolean(props["navi-control-proxy-for"]);
|
|
46778
46807
|
const formContext = useContext(FormContext);
|
|
46779
|
-
const
|
|
46808
|
+
const {
|
|
46809
|
+
parentUIStateController
|
|
46810
|
+
} = uiStateController;
|
|
46780
46811
|
return Boolean(props.signal ||
|
|
46781
46812
|
// a bound signal is written back on uiAction → interactive
|
|
46782
|
-
props.uiAction || props.action || formContext || parentUIStateController || isProxy || props.command);
|
|
46813
|
+
props.uiAction || props.action || formContext || parentUIStateController?.collectsChild(uiStateController) || isProxy || props.command);
|
|
46783
46814
|
};
|
|
46784
|
-
const useReadOnlyUncontrolled = (props, controlInfo) => {
|
|
46785
|
-
const listenedTo = useIsControlListenedTo(props);
|
|
46815
|
+
const useReadOnlyUncontrolled = (props, controlInfo, uiStateController) => {
|
|
46816
|
+
const listenedTo = useIsControlListenedTo(props, uiStateController);
|
|
46786
46817
|
useRef(false);
|
|
46787
46818
|
if (!controlInfo.hasStateProp) {
|
|
46788
46819
|
return false;
|
|
@@ -46841,7 +46872,7 @@ const useControlgroupProps = (props, {
|
|
|
46841
46872
|
// makes the group read-only so children don't appear interactive when they
|
|
46842
46873
|
// can't change. A form or a group around it IS someone listening — that is
|
|
46843
46874
|
// what will send the value and hand a new one back.
|
|
46844
|
-
const listenedTo = useIsControlListenedTo(props);
|
|
46875
|
+
const listenedTo = useIsControlListenedTo(props, uiGroupStateController);
|
|
46845
46876
|
useRef(false);
|
|
46846
46877
|
const implicitReadOnly = uiGroupStateController.hasValueProp && !listenedTo;
|
|
46847
46878
|
if (implicitReadOnly && !props.readOnly) {
|
|
@@ -51664,6 +51695,9 @@ const LinkWithRoute = ({
|
|
|
51664
51695
|
currentExcept,
|
|
51665
51696
|
currentAlso,
|
|
51666
51697
|
children,
|
|
51698
|
+
// Kept out of `rest`: spread after the route's url, an `href={undefined}`
|
|
51699
|
+
// riding along would erase it.
|
|
51700
|
+
href,
|
|
51667
51701
|
...rest
|
|
51668
51702
|
}) => {
|
|
51669
51703
|
const url = route.buildUrl(routeParams);
|
|
@@ -56836,11 +56870,14 @@ const ButtonRouteResolver = props => {
|
|
|
56836
56870
|
};
|
|
56837
56871
|
const ButtonWithRoute = props => {
|
|
56838
56872
|
const Next = useNextResolver();
|
|
56873
|
+
// `href` is kept out of `rest`: spread after the route's url, an
|
|
56874
|
+
// `href={undefined}` riding along would erase it.
|
|
56839
56875
|
const {
|
|
56840
56876
|
route,
|
|
56841
56877
|
routeParams,
|
|
56842
56878
|
children,
|
|
56843
56879
|
pseudoState,
|
|
56880
|
+
href,
|
|
56844
56881
|
...rest
|
|
56845
56882
|
} = props;
|
|
56846
56883
|
const url = route.buildUrl(routeParams);
|
|
@@ -73028,10 +73065,18 @@ const PickerCustom = props => {
|
|
|
73028
73065
|
props.id = props.id || controlId || idDefault;
|
|
73029
73066
|
// Given no value, the picker holds what the control in its popup holds (see
|
|
73030
73067
|
// the `mount` decision below) — and a group around it collects that from the
|
|
73031
|
-
// moment both exist.
|
|
73032
|
-
|
|
73068
|
+
// moment both exist. A picker that picks nothing holds none: its popup's
|
|
73069
|
+
// controls are never adopted (see canRegisterAsFacadeChild).
|
|
73070
|
+
const valueInPopup = !props.picksNothing && !isControlValueGivenByProps(props);
|
|
73071
|
+
// Asked of the chain, not read off the context: a control above may only
|
|
73072
|
+
// pass registration along (a <Details> holds none of the values it folds),
|
|
73073
|
+
// and a group may hand a picker further up or drop it. "picker" is what the
|
|
73074
|
+
// picker's own controller registers as (see picker.jsx).
|
|
73033
73075
|
const parentController = useContext(ParentUIStateControllerContext);
|
|
73034
|
-
const answersToGroup =
|
|
73076
|
+
const answersToGroup = !props.standalone && Boolean(parentController?.collectsChild({
|
|
73077
|
+
controlType: "picker",
|
|
73078
|
+
props
|
|
73079
|
+
}));
|
|
73035
73080
|
// Same narrow-container/maxWidth-compact heuristic Popup itself uses (see
|
|
73036
73081
|
// popup_mode.jsx's own useResolvedPopupMode) — frozen for the lifetime of an opening
|
|
73037
73082
|
// (computed when closed, stable while open, so a screen resize mid-session
|
|
@@ -74211,12 +74256,7 @@ const PickerConfirmResolver = props => {
|
|
|
74211
74256
|
mode: mode,
|
|
74212
74257
|
focusCapture: focusCapture,
|
|
74213
74258
|
openWhileReadOnly: openWhileReadOnly,
|
|
74214
|
-
onConfirm: onConfirm
|
|
74215
|
-
// A question holds no value to read before it is asked: the popup is
|
|
74216
|
-
// built on the first open, like that of a picker told its value (see
|
|
74217
|
-
// the `mount` resolution in picker_custom.jsx).
|
|
74218
|
-
,
|
|
74219
|
-
mount: MOUNT_DEFAULT,
|
|
74259
|
+
onConfirm: onConfirm,
|
|
74220
74260
|
message: undefined,
|
|
74221
74261
|
confirmLabel: undefined,
|
|
74222
74262
|
cancelLabel: undefined,
|