@jsenv/navi 0.29.472 → 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 +50 -12
- package/dist/dev/jsenv_navi.js.map +4 -4
- package/dist/jsenv_navi.js +50 -12
- package/dist/jsenv_navi.js.map +4 -4
- package/package.json +1 -1
package/dist/dev/jsenv_navi.js
CHANGED
|
@@ -43943,6 +43943,7 @@ const useRenderScope = (init, update) => {
|
|
|
43943
43943
|
* registerChild(child): void; // Called on child mount
|
|
43944
43944
|
* onChildUIAction(child, e, { stateChanged: boolean }): void; // Called when a child fires a UI action
|
|
43945
43945
|
* unregisterChild(child): void; // Called on child unmount
|
|
43946
|
+
* collectsChild(child): boolean; // Whether registerChild(child) would put it in a value, here or above
|
|
43946
43947
|
* props: Object;
|
|
43947
43948
|
* ref: Ref; // Used to dispatch DOM events
|
|
43948
43949
|
* getManagedControls(): UIStateController[]; // Returns controls whose validity is managed by this controller
|
|
@@ -44667,6 +44668,10 @@ const useUIStateController = (
|
|
|
44667
44668
|
unregisterChild: (childUIStateController) => {
|
|
44668
44669
|
s.parentUIStateController?.unregisterChild(childUIStateController);
|
|
44669
44670
|
},
|
|
44671
|
+
collectsChild: (childUIStateController) =>
|
|
44672
|
+
Boolean(
|
|
44673
|
+
s.parentUIStateController?.collectsChild(childUIStateController),
|
|
44674
|
+
),
|
|
44670
44675
|
onChildUIAction: (childUIStateController, e, options) => {
|
|
44671
44676
|
s.parentUIStateController?.onChildUIAction(
|
|
44672
44677
|
childUIStateController,
|
|
@@ -45053,10 +45058,13 @@ const readNamedChildUIStates = (children, { warnNameless }) => {
|
|
|
45053
45058
|
// Looked up in useUIGroupStateController to fill in omitted aggregateChildStates /
|
|
45054
45059
|
// distributeChildUIState. If neither a default nor an explicit impl is found for a
|
|
45055
45060
|
// group, creation throws so the caller knows it must supply them.
|
|
45061
|
+
// The radio/checkbox filters read `props.type`, which controlHostProps copies:
|
|
45062
|
+
// a child is also asked about while rendering, before its first render has
|
|
45063
|
+
// built controlHostProps (see collectsChild).
|
|
45056
45064
|
const GROUP_DEFAULTS = {
|
|
45057
45065
|
radio_group: {
|
|
45058
45066
|
childControlFilter: (child) =>
|
|
45059
|
-
child.controlType === "input" && child.
|
|
45067
|
+
child.controlType === "input" && child.props?.type === "radio",
|
|
45060
45068
|
aggregateChildStates: keptOrFirstDefinedChildUIState,
|
|
45061
45069
|
distributeChildUIState: (newUIState, childUIStateController) => {
|
|
45062
45070
|
const childSelected = childUIStateController.props.value === newUIState;
|
|
@@ -45068,8 +45076,7 @@ const GROUP_DEFAULTS = {
|
|
|
45068
45076
|
},
|
|
45069
45077
|
checkbox_group: {
|
|
45070
45078
|
childControlFilter: (child) =>
|
|
45071
|
-
child.controlType === "input" &&
|
|
45072
|
-
child.controlHostProps?.type === "checkbox",
|
|
45079
|
+
child.controlType === "input" && child.props?.type === "checkbox",
|
|
45073
45080
|
aggregateChildStates: keptAndCheckedChildUIStates,
|
|
45074
45081
|
distributeChildUIState: (newUIState, childUIStateController) => {
|
|
45075
45082
|
const childSelected =
|
|
@@ -45614,6 +45621,9 @@ const useUIGroupStateController = (
|
|
|
45614
45621
|
|
|
45615
45622
|
const controller = {
|
|
45616
45623
|
controlType,
|
|
45624
|
+
// Published from the first render, like a leaf's: a group asks its
|
|
45625
|
+
// parent whether anyone listens before its first update.
|
|
45626
|
+
parentUIStateController,
|
|
45617
45627
|
id,
|
|
45618
45628
|
name,
|
|
45619
45629
|
value,
|
|
@@ -45837,6 +45847,18 @@ const useUIGroupStateController = (
|
|
|
45837
45847
|
notifyExternal: "silent",
|
|
45838
45848
|
});
|
|
45839
45849
|
},
|
|
45850
|
+
// registerChild above, asked ahead: monitored here, handed up, or
|
|
45851
|
+
// captured and dropped.
|
|
45852
|
+
collectsChild: (childUIStateController) => {
|
|
45853
|
+
if (isMonitoringChild(childUIStateController)) {
|
|
45854
|
+
return true;
|
|
45855
|
+
}
|
|
45856
|
+
const currentParent = s.parentUIStateController;
|
|
45857
|
+
if (allowCapture || !currentParent) {
|
|
45858
|
+
return false;
|
|
45859
|
+
}
|
|
45860
|
+
return currentParent.collectsChild(childUIStateController);
|
|
45861
|
+
},
|
|
45840
45862
|
onChildUIAction: (
|
|
45841
45863
|
childUIStateController,
|
|
45842
45864
|
e,
|
|
@@ -46314,6 +46336,9 @@ const useUIFacadeStateController = (props, realUIStateController) => {
|
|
|
46314
46336
|
s.realUIStateController.facadeChild = null;
|
|
46315
46337
|
}
|
|
46316
46338
|
},
|
|
46339
|
+
// A refused child is not handed further up: the popup's controls
|
|
46340
|
+
// answer to the picker or to nobody.
|
|
46341
|
+
collectsChild: (child) => canRegisterAsFacadeChild(child),
|
|
46317
46342
|
getManagedControls: () => {
|
|
46318
46343
|
const child = firstChildControllerRef.current;
|
|
46319
46344
|
if (!child) {
|
|
@@ -46934,8 +46959,6 @@ const useControlProps = (props, {
|
|
|
46934
46959
|
const controlInfo = createControlInfo(props, {
|
|
46935
46960
|
controlType
|
|
46936
46961
|
});
|
|
46937
|
-
const readOnlyUncontrolled = useReadOnlyUncontrolled(props, controlInfo);
|
|
46938
|
-
controlInfo.readOnlyUncontrolled = readOnlyUncontrolled;
|
|
46939
46962
|
const uiStateController = useUIStateController(props, {
|
|
46940
46963
|
controlInfo,
|
|
46941
46964
|
syncDomState,
|
|
@@ -46943,6 +46966,9 @@ const useControlProps = (props, {
|
|
|
46943
46966
|
persists,
|
|
46944
46967
|
uiActionInternal
|
|
46945
46968
|
});
|
|
46969
|
+
// After the controller: whether a group listens is asked of the parent it
|
|
46970
|
+
// registers into. Read by useInteractiveProps below.
|
|
46971
|
+
controlInfo.readOnlyUncontrolled = useReadOnlyUncontrolled(props, controlInfo, uiStateController);
|
|
46946
46972
|
// What the control draws is what it holds by itself, and this read is what
|
|
46947
46973
|
// re-renders it when that changes. A button inheriting the value of the
|
|
46948
46974
|
// control around it (a submit in a form, see ownUIStateSignal) draws none of
|
|
@@ -47948,16 +47974,21 @@ const INPUT_TYPE_SUPPORTING_READONLY_SET = new Set(["text", "date", "datetime-lo
|
|
|
47948
47974
|
// warning below so a group can ask the same question a single control does: a
|
|
47949
47975
|
// control with a `value` and nobody listening cannot be changed by hand, and
|
|
47950
47976
|
// that is true whatever the control is.
|
|
47951
|
-
|
|
47977
|
+
// The group is asked, not assumed from a controller being above: a control in
|
|
47978
|
+
// between may only pass registration along (a <Details> holds none of the
|
|
47979
|
+
// values it folds), and a group may hand the control further up or drop it.
|
|
47980
|
+
const useIsControlListenedTo = (props, uiStateController) => {
|
|
47952
47981
|
const isProxy = Boolean(props["navi-control-proxy-for"]);
|
|
47953
47982
|
const formContext = useContext(FormContext);
|
|
47954
|
-
const
|
|
47983
|
+
const {
|
|
47984
|
+
parentUIStateController
|
|
47985
|
+
} = uiStateController;
|
|
47955
47986
|
return Boolean(props.signal ||
|
|
47956
47987
|
// a bound signal is written back on uiAction → interactive
|
|
47957
|
-
props.uiAction || props.action || formContext || parentUIStateController || isProxy || props.command);
|
|
47988
|
+
props.uiAction || props.action || formContext || parentUIStateController?.collectsChild(uiStateController) || isProxy || props.command);
|
|
47958
47989
|
};
|
|
47959
|
-
const useReadOnlyUncontrolled = (props, controlInfo) => {
|
|
47960
|
-
const listenedTo = useIsControlListenedTo(props);
|
|
47990
|
+
const useReadOnlyUncontrolled = (props, controlInfo, uiStateController) => {
|
|
47991
|
+
const listenedTo = useIsControlListenedTo(props, uiStateController);
|
|
47961
47992
|
const warnedRef = useRef(false);
|
|
47962
47993
|
if (!controlInfo.hasStateProp) {
|
|
47963
47994
|
return false;
|
|
@@ -48025,7 +48056,7 @@ const useControlgroupProps = (props, {
|
|
|
48025
48056
|
// makes the group read-only so children don't appear interactive when they
|
|
48026
48057
|
// can't change. A form or a group around it IS someone listening — that is
|
|
48027
48058
|
// what will send the value and hand a new one back.
|
|
48028
|
-
const listenedTo = useIsControlListenedTo(props);
|
|
48059
|
+
const listenedTo = useIsControlListenedTo(props, uiGroupStateController);
|
|
48029
48060
|
const implicitReadOnlyWarnedRef = useRef(false);
|
|
48030
48061
|
const implicitReadOnly = uiGroupStateController.hasValueProp && !listenedTo;
|
|
48031
48062
|
if (implicitReadOnly && !props.readOnly) {
|
|
@@ -74449,8 +74480,15 @@ const PickerCustom = props => {
|
|
|
74449
74480
|
// moment both exist. A picker that picks nothing holds none: its popup's
|
|
74450
74481
|
// controls are never adopted (see canRegisterAsFacadeChild).
|
|
74451
74482
|
const valueInPopup = !props.picksNothing && !isControlValueGivenByProps(props);
|
|
74483
|
+
// Asked of the chain, not read off the context: a control above may only
|
|
74484
|
+
// pass registration along (a <Details> holds none of the values it folds),
|
|
74485
|
+
// and a group may hand a picker further up or drop it. "picker" is what the
|
|
74486
|
+
// picker's own controller registers as (see picker.jsx).
|
|
74452
74487
|
const parentController = useContext(ParentUIStateControllerContext);
|
|
74453
|
-
const answersToGroup =
|
|
74488
|
+
const answersToGroup = !props.standalone && Boolean(parentController?.collectsChild({
|
|
74489
|
+
controlType: "picker",
|
|
74490
|
+
props
|
|
74491
|
+
}));
|
|
74454
74492
|
// Same narrow-container/maxWidth-compact heuristic Popup itself uses (see
|
|
74455
74493
|
// popup_mode.jsx's own useResolvedPopupMode) — frozen for the lifetime of an opening
|
|
74456
74494
|
// (computed when closed, stable while open, so a screen resize mid-session
|