@jsenv/navi 0.29.38 → 0.29.40
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/jsenv_navi.js +68 -46
- package/dist/jsenv_navi.js.map +6 -6
- package/docs/AI_INSTRUCTIONS.md +5 -0
- package/docs/actions.md +3 -0
- package/docs/control_value.md +132 -0
- package/docs/popup_open.md +105 -1
- package/package.json +2 -2
package/dist/jsenv_navi.js
CHANGED
|
@@ -23708,13 +23708,13 @@ const useUIGroupStateController = (
|
|
|
23708
23708
|
);
|
|
23709
23709
|
}
|
|
23710
23710
|
const parentUIStateController = useContext(ParentUIStateControllerContext);
|
|
23711
|
-
const hasValueProp = Object.hasOwn(props, "value");
|
|
23712
|
-
const hasOwnDefaultValueProp = Object.hasOwn(props, "defaultValue");
|
|
23713
23711
|
// A bound signal seeds the group the way `defaultValue` does — uncontrolled,
|
|
23714
23712
|
// with the signal's current value as what it starts on. Write-back is handled
|
|
23715
23713
|
// by applyState's own boundSignal; the read half is below: children are
|
|
23716
23714
|
// placed from it when they register, and again whenever it moves.
|
|
23717
|
-
const boundSignal =
|
|
23715
|
+
const boundSignal = props.signal;
|
|
23716
|
+
const hasValueProp = !boundSignal && Object.hasOwn(props, "value");
|
|
23717
|
+
const hasOwnDefaultValueProp = Object.hasOwn(props, "defaultValue");
|
|
23718
23718
|
const hasDefaultValueProp = hasOwnDefaultValueProp || Boolean(boundSignal);
|
|
23719
23719
|
const { id, name, value, uiAction } = props;
|
|
23720
23720
|
// A signal holding something wins over `defaultValue`: the default is a
|
|
@@ -24124,6 +24124,11 @@ const useUIGroupStateController = (
|
|
|
24124
24124
|
parentUIStateController,
|
|
24125
24125
|
uiAction,
|
|
24126
24126
|
uiActionInternal,
|
|
24127
|
+
// `props` is what writeBoundSignal reads to find the bound `signal`.
|
|
24128
|
+
// Missing here, a group whose component never re-renders between mount
|
|
24129
|
+
// and the first choice wrote nothing back into its signal — and said
|
|
24130
|
+
// nothing about it: the list showed the choice, the signal stayed empty.
|
|
24131
|
+
props,
|
|
24127
24132
|
};
|
|
24128
24133
|
},
|
|
24129
24134
|
// ── update: runs every render after the first ─────────────────────────
|
|
@@ -25322,22 +25327,25 @@ const createControlInfo = (props, {
|
|
|
25322
25327
|
defaultStatePropName = "defaultChecked";
|
|
25323
25328
|
value = props.value || "on";
|
|
25324
25329
|
signalHoldsChecked = true;
|
|
25325
|
-
if (
|
|
25330
|
+
if (signal) {
|
|
25331
|
+
if (props.defaultChecked) {
|
|
25332
|
+
// resolveInputProps may seed defaultChecked from a bound signal's
|
|
25333
|
+
// default: the control stays uncontrolled and follows the signal
|
|
25334
|
+
// through stateFromSignal.
|
|
25335
|
+
hasStateProp = false;
|
|
25336
|
+
stateInitial = value;
|
|
25337
|
+
stateFromSignal = signal.value ? value : undefined;
|
|
25338
|
+
} else {
|
|
25339
|
+
// A bound signal with no resolved default: its live value seeds state.
|
|
25340
|
+
hasStateProp = true;
|
|
25341
|
+
stateInitial = signal.value ? value : undefined;
|
|
25342
|
+
}
|
|
25343
|
+
} else if (Object.hasOwn(props, "checked")) {
|
|
25326
25344
|
hasStateProp = true;
|
|
25327
25345
|
stateInitial = props.checked ? value : undefined;
|
|
25328
25346
|
} else if (props.defaultChecked) {
|
|
25329
|
-
// resolveInputProps may seed defaultChecked from a bound signal's
|
|
25330
|
-
// default: the control stays uncontrolled and follows the signal
|
|
25331
|
-
// through stateFromSignal.
|
|
25332
25347
|
hasStateProp = false;
|
|
25333
25348
|
stateInitial = value;
|
|
25334
|
-
if (signal) {
|
|
25335
|
-
stateFromSignal = signal.value ? value : undefined;
|
|
25336
|
-
}
|
|
25337
|
-
} else if (signal) {
|
|
25338
|
-
// A bound signal with no resolved default: its live value seeds state.
|
|
25339
|
-
hasStateProp = true;
|
|
25340
|
-
stateInitial = signal.value ? value : undefined;
|
|
25341
25349
|
} else {
|
|
25342
25350
|
hasStateProp = false;
|
|
25343
25351
|
stateInitial = undefined;
|
|
@@ -25345,30 +25353,33 @@ const createControlInfo = (props, {
|
|
|
25345
25353
|
} else {
|
|
25346
25354
|
statePropName = "value";
|
|
25347
25355
|
defaultStatePropName = "defaultValue";
|
|
25348
|
-
if (
|
|
25356
|
+
if (signal) {
|
|
25357
|
+
if (Object.hasOwn(props, "defaultValue")) {
|
|
25358
|
+
// resolveInputProps seeds defaultValue from a bound signal's default,
|
|
25359
|
+
// so an input+signal is uncontrolled-with-default; the signal only
|
|
25360
|
+
// receives write-backs (onUIAction).
|
|
25361
|
+
hasStateProp = false;
|
|
25362
|
+
// A signal holding something wins over the default: `defaultValue` is
|
|
25363
|
+
// a suggestion of what to start from (and what a reset goes back to),
|
|
25364
|
+
// not an answer — while the signal's value IS the answer, restored
|
|
25365
|
+
// from the url or set by whoever owns it. Taking the default here
|
|
25366
|
+
// would show a suggestion in place of the value on every reload.
|
|
25367
|
+
stateInitial = signal.value !== undefined ? signal.value : props.defaultValue;
|
|
25368
|
+
stateFromSignal = stateInitial;
|
|
25369
|
+
} else {
|
|
25370
|
+
// A plain bound signal with no default (e.g. Wheel): its live value
|
|
25371
|
+
// seeds and controls the state.
|
|
25372
|
+
hasStateProp = true;
|
|
25373
|
+
value = signal.value;
|
|
25374
|
+
stateInitial = value;
|
|
25375
|
+
}
|
|
25376
|
+
} else if (Object.hasOwn(props, "value")) {
|
|
25349
25377
|
hasStateProp = true;
|
|
25350
25378
|
value = props.value;
|
|
25351
25379
|
stateInitial = value;
|
|
25352
25380
|
} else if (Object.hasOwn(props, "defaultValue")) {
|
|
25353
|
-
// resolveInputProps seeds defaultValue from a bound signal's default,
|
|
25354
|
-
// so an input+signal is uncontrolled-with-default; the signal only
|
|
25355
|
-
// receives write-backs (onUIAction).
|
|
25356
25381
|
hasStateProp = false;
|
|
25357
|
-
|
|
25358
|
-
// suggestion of what to start from (and what a reset goes back to), not
|
|
25359
|
-
// an answer — while the signal's value IS the answer, restored from the
|
|
25360
|
-
// url or set by whoever owns it. Taking the default here would show a
|
|
25361
|
-
// suggestion in place of the value on every reload.
|
|
25362
|
-
stateInitial = signal && signal.value !== undefined ? signal.value : props.defaultValue;
|
|
25363
|
-
if (signal) {
|
|
25364
|
-
stateFromSignal = stateInitial;
|
|
25365
|
-
}
|
|
25366
|
-
} else if (signal) {
|
|
25367
|
-
// A plain bound signal with no default (e.g. Wheel): its live value
|
|
25368
|
-
// seeds and controls the state.
|
|
25369
|
-
hasStateProp = true;
|
|
25370
|
-
value = signal.value;
|
|
25371
|
-
stateInitial = value;
|
|
25382
|
+
stateInitial = props.defaultValue;
|
|
25372
25383
|
} else {
|
|
25373
25384
|
hasStateProp = false;
|
|
25374
25385
|
stateInitial = undefined;
|
|
@@ -25388,20 +25399,23 @@ const createControlInfo = (props, {
|
|
|
25388
25399
|
} else if (controlType === "picker" || controlType === "select") {
|
|
25389
25400
|
statePropName = "value";
|
|
25390
25401
|
defaultStatePropName = "defaultValue";
|
|
25391
|
-
if (
|
|
25402
|
+
if (signal) {
|
|
25403
|
+
if (Object.hasOwn(props, "defaultValue")) {
|
|
25404
|
+
hasStateProp = false;
|
|
25405
|
+
// The signal's value is the answer, defaultValue only the suggestion to
|
|
25406
|
+
// start from.
|
|
25407
|
+
stateInitial = signal.value !== undefined ? signal.value : props.defaultValue;
|
|
25408
|
+
stateFromSignal = stateInitial;
|
|
25409
|
+
} else {
|
|
25410
|
+
hasStateProp = true;
|
|
25411
|
+
stateInitial = signal.value;
|
|
25412
|
+
}
|
|
25413
|
+
} else if (Object.hasOwn(props, "value")) {
|
|
25392
25414
|
hasStateProp = true;
|
|
25393
25415
|
stateInitial = props.value;
|
|
25394
25416
|
} else if (Object.hasOwn(props, "defaultValue")) {
|
|
25395
25417
|
hasStateProp = false;
|
|
25396
|
-
|
|
25397
|
-
// defaultValue only the suggestion to start from.
|
|
25398
|
-
stateInitial = signal && signal.value !== undefined ? signal.value : props.defaultValue;
|
|
25399
|
-
if (signal) {
|
|
25400
|
-
stateFromSignal = stateInitial;
|
|
25401
|
-
}
|
|
25402
|
-
} else if (signal) {
|
|
25403
|
-
hasStateProp = true;
|
|
25404
|
-
stateInitial = signal.value;
|
|
25418
|
+
stateInitial = props.defaultValue;
|
|
25405
25419
|
} else {
|
|
25406
25420
|
hasStateProp = false;
|
|
25407
25421
|
stateInitial = undefined;
|
|
@@ -46878,7 +46892,10 @@ const resolveInputProps = (props) => {
|
|
|
46878
46892
|
if (Object.hasOwn(props, "defaultChecked")) ; else {
|
|
46879
46893
|
// If no explicit defaultChecked, derive it from the signal's default
|
|
46880
46894
|
// value so that resetUIState restores to the original default.
|
|
46881
|
-
|
|
46895
|
+
// Only a stateSignal carries a default of its own; a plain signal has
|
|
46896
|
+
// no `options` at all, and asking it for one used to throw on mount —
|
|
46897
|
+
// the same optional read every other branch here already does.
|
|
46898
|
+
const defaultVal = signalOptions?.getDefaultValue(false);
|
|
46882
46899
|
if (defaultVal === undefined) ; else if (props.type === "radio") {
|
|
46883
46900
|
if (defaultVal === true) {
|
|
46884
46901
|
props.defaultChecked = true;
|
|
@@ -58928,10 +58945,15 @@ const PickerFirstResolver = props => {
|
|
|
58928
58945
|
* picker. "cancel" puts back the value the picker had at open, and a dialog
|
|
58929
58946
|
* picker also goes back in history — so anything written to the url while it
|
|
58930
58947
|
* was open (a route `stateSignal`, a search param) goes back with it. "close"
|
|
58931
|
-
* makes Escape say what clicking outside says: keep what was chosen, close
|
|
58948
|
+
* makes Escape say what clicking outside says: keep what was chosen, close —
|
|
58949
|
+
* a last resort, see docs/popup_open.md ("Escape cancels, the other gestures
|
|
58950
|
+
* keep") for why Escape should go on meaning cancel, and for what the value
|
|
58951
|
+
* at open is on the picker's very first open.
|
|
58932
58952
|
* @param {"close"|"cancel"|"capture"} [pointerInteractionOutsideEffect="close"]
|
|
58933
58953
|
* What a click outside the popup does: close and keep ("close"), close and
|
|
58934
|
-
* put back the value at open ("cancel"), or nothing at all ("capture").
|
|
58954
|
+
* put back the value at open ("cancel"), or nothing at all ("capture"). The
|
|
58955
|
+
* default is what gives a popup with no confirm button its way out that
|
|
58956
|
+
* keeps — see the same section.
|
|
58935
58957
|
* @param {number|string} [marginWithContainer] Minimum gap kept between the
|
|
58936
58958
|
* popup and the edges of what contains it (the viewport, or the picker's own
|
|
58937
58959
|
* positioned ancestor for `popupLayer="local"`). Caps the popup's size as
|