@jsenv/navi 0.29.382 → 0.29.384
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 +78 -18
- package/dist/dev/jsenv_navi.js.map +4 -4
- package/dist/jsenv_navi.js +78 -18
- package/dist/jsenv_navi.js.map +4 -4
- package/package.json +1 -1
package/dist/jsenv_navi.js
CHANGED
|
@@ -17320,6 +17320,11 @@ const generateSignalId = () => {
|
|
|
17320
17320
|
* `?level=3,4` becomes `[3, 4]` instead of `["3", "4"]`. Without it items stay strings.
|
|
17321
17321
|
* @param {number} [options.step] - For number type: step size for precision. Values will be rounded to nearest multiple of step.
|
|
17322
17322
|
* @param {Array} [options.oneOf] - Array of valid values for validation. Signal will be marked invalid if value is not in this array
|
|
17323
|
+
* @param {boolean} [options.autoFix=false] - Hold the repaired value instead of the refused one: a number
|
|
17324
|
+
* clamped to `min`/`max` and rounded to `step`, a value outside `oneOf` replaced by the signal's
|
|
17325
|
+
* default value (an enumeration has no nearest value, and its order says nothing). Without it the
|
|
17326
|
+
* refused value is held as-is, marked invalid, and `validSignal` reads `undefined`. When the value
|
|
17327
|
+
* came from the address, the address is rewritten with the repaired one (a replace).
|
|
17323
17328
|
* @param {boolean} [options.weak=false] - The param qualifies one visit, not the screen: it is written into a
|
|
17324
17329
|
* url only when explicitly named (`routeParams={{ edit: id }}`), never inherited from the signal's current
|
|
17325
17330
|
* value, and it goes back to the default value when the route stops matching. Use it for params like an
|
|
@@ -17354,11 +17359,11 @@ const generateSignalId = () => {
|
|
|
17354
17359
|
* });
|
|
17355
17360
|
*
|
|
17356
17361
|
* @example
|
|
17357
|
-
* // Signal with validation and auto-fix
|
|
17362
|
+
* // Signal with validation and auto-fix: an unknown tab falls back to "overview"
|
|
17358
17363
|
* const tab = stateSignal("overview", {
|
|
17359
17364
|
* id: "current-tab",
|
|
17360
17365
|
* oneOf: ["overview", "details", "settings"],
|
|
17361
|
-
* autoFix:
|
|
17366
|
+
* autoFix: true,
|
|
17362
17367
|
* persists: true
|
|
17363
17368
|
* });
|
|
17364
17369
|
*
|
|
@@ -17455,6 +17460,10 @@ const stateSignal = (defaultValue, options = {}) => {
|
|
|
17455
17460
|
oneOf,
|
|
17456
17461
|
localStorageRepresentation,
|
|
17457
17462
|
autoFix,
|
|
17463
|
+
// What a value no rule can repair falls back to: the default is what the
|
|
17464
|
+
// state is when nothing says otherwise, read at repair time (from
|
|
17465
|
+
// processValue, below) so a dynamic default is read where it stands.
|
|
17466
|
+
fallback: () => getDefaultValue(false),
|
|
17458
17467
|
});
|
|
17459
17468
|
const readFromLocalStorage = persists
|
|
17460
17469
|
? () => {
|
|
@@ -26433,6 +26442,14 @@ This prevents cross-test pollution and ensures clean state.`,
|
|
|
26433
26442
|
// Apply all signal updates in a batch
|
|
26434
26443
|
const matchingRouteSet = new Set();
|
|
26435
26444
|
const routeUpdateSet = new Set();
|
|
26445
|
+
// Params the address gave and the state could not hold as written
|
|
26446
|
+
// (autoFix): the address is rewritten with what the state holds, once
|
|
26447
|
+
// the sync is over, so the repaired value is not left in the url to be
|
|
26448
|
+
// replayed by a reload or a copied link.
|
|
26449
|
+
const repairedParamsByRoute = new Map();
|
|
26450
|
+
// A query connection is inherited by the child routes of the one
|
|
26451
|
+
// declaring it: the first route to record a param answers for all.
|
|
26452
|
+
const repairedParamNameSet = new Set();
|
|
26436
26453
|
batch(() => {
|
|
26437
26454
|
for (const {
|
|
26438
26455
|
route,
|
|
@@ -26615,6 +26632,29 @@ This prevents cross-test pollution and ensures clean state.`,
|
|
|
26615
26632
|
);
|
|
26616
26633
|
}
|
|
26617
26634
|
paramSignal.value = urlParamValue;
|
|
26635
|
+
if (
|
|
26636
|
+
paramSignal.validity?.autoFixed &&
|
|
26637
|
+
!repairedParamNameSet.has(paramName)
|
|
26638
|
+
) {
|
|
26639
|
+
repairedParamNameSet.add(paramName);
|
|
26640
|
+
const repairedValue = paramSignal.peek();
|
|
26641
|
+
if (debug) {
|
|
26642
|
+
console.debug(
|
|
26643
|
+
`[route] URL->Signal: ${paramName}=${urlParamValue} repaired to ${repairedValue}, the url will be rewritten`,
|
|
26644
|
+
);
|
|
26645
|
+
}
|
|
26646
|
+
let repairedParams = repairedParamsByRoute.get(route);
|
|
26647
|
+
if (!repairedParams) {
|
|
26648
|
+
repairedParams = {};
|
|
26649
|
+
repairedParamsByRoute.set(route, repairedParams);
|
|
26650
|
+
}
|
|
26651
|
+
// A default is not written in an address (see the signal -> url sync)
|
|
26652
|
+
repairedParams[paramName] = connection.isDefaultValue(
|
|
26653
|
+
repairedValue,
|
|
26654
|
+
)
|
|
26655
|
+
? undefined
|
|
26656
|
+
: repairedValue;
|
|
26657
|
+
}
|
|
26618
26658
|
continue;
|
|
26619
26659
|
}
|
|
26620
26660
|
}
|
|
@@ -26625,6 +26665,12 @@ This prevents cross-test pollution and ensures clean state.`,
|
|
|
26625
26665
|
// Reset flag after URL -> Signal synchronization is complete
|
|
26626
26666
|
isUpdatingRoutesFromUrl = false;
|
|
26627
26667
|
Object.assign(returnValue, { matchingRouteSet });
|
|
26668
|
+
for (const [route, repairedParams] of repairedParamsByRoute) {
|
|
26669
|
+
route.replaceParams(repairedParams, {
|
|
26670
|
+
callReason: `url params repaired on ${route}: ${Object.keys(repairedParams).join(", ")}`,
|
|
26671
|
+
history: "replace",
|
|
26672
|
+
});
|
|
26673
|
+
}
|
|
26628
26674
|
}
|
|
26629
26675
|
|
|
26630
26676
|
return returnValue;
|
|
@@ -60144,10 +60190,12 @@ let releaseLiftInProgress = null;
|
|
|
60144
60190
|
// cancelled with the movement so a finished one cannot go on applying its
|
|
60145
60191
|
// last values to the next movement's picture.
|
|
60146
60192
|
let boxAnimationInProgress = null;
|
|
60147
|
-
// The page held still
|
|
60148
|
-
// anyway, and the browser keeps following the
|
|
60149
|
-
// carry the arriving box along under a page that
|
|
60150
|
-
// clip to the room between the bars, computed
|
|
60193
|
+
// The page held still from the first read about it to the end of the
|
|
60194
|
+
// movement. Its picture is frozen anyway, and the browser keeps following the
|
|
60195
|
+
// live anchor: a scroll would carry the arriving box along under a page that
|
|
60196
|
+
// does not move, and past the clip to the room between the bars, computed
|
|
60197
|
+
// where the boxes stood — and read once, before the opening waits for its
|
|
60198
|
+
// target (see liftPopupFromAnchor).
|
|
60151
60199
|
let releaseScrollHold = null;
|
|
60152
60200
|
|
|
60153
60201
|
/**
|
|
@@ -60173,11 +60221,20 @@ const liftPopupFromAnchor = (
|
|
|
60173
60221
|
releaseLiftInProgress?.();
|
|
60174
60222
|
|
|
60175
60223
|
const elementLeaving = opened ? resolveAnchor() : resolveLiftTarget(popupEl);
|
|
60176
|
-
//
|
|
60177
|
-
//
|
|
60224
|
+
// Everything read about the leaving side, before the first write. A read
|
|
60225
|
+
// brings the style up to date, and the writes below land on the root — an
|
|
60226
|
+
// attribute or an unregistered custom property there invalidates the
|
|
60227
|
+
// computed style of every element — so a read placed after any of them is
|
|
60228
|
+
// the whole document's style over again. Nothing on the leaving side moves
|
|
60229
|
+
// before the movement, the page being held from here on.
|
|
60230
|
+
releaseScrollHold = trapScrollInside(popupEl, { backdrop: true });
|
|
60178
60231
|
const duration = getComputedStyle(popupEl)
|
|
60179
60232
|
.getPropertyValue("--popup-animation-duration")
|
|
60180
60233
|
.trim();
|
|
60234
|
+
const cornersLeaving = readCorners(elementLeaving);
|
|
60235
|
+
const room = measureRoomBetweenBars();
|
|
60236
|
+
const boxLeaving = elementLeaving.getBoundingClientRect();
|
|
60237
|
+
const paintLeaving = opened ? null : readBoxPaint(elementLeaving);
|
|
60181
60238
|
const giveBackNameLeaving = wearLiftName(elementLeaving);
|
|
60182
60239
|
const root = document.documentElement;
|
|
60183
60240
|
root.setAttribute(ROOT_ATTRIBUTE, opened ? "opening" : "closing");
|
|
@@ -60188,11 +60245,10 @@ const liftPopupFromAnchor = (
|
|
|
60188
60245
|
// browser's own pace.
|
|
60189
60246
|
root.style.setProperty(DURATION_PROPERTY, duration);
|
|
60190
60247
|
}
|
|
60191
|
-
if (!opened) {
|
|
60192
|
-
publishBoxPaint(elementLeaving);
|
|
60193
|
-
}
|
|
60194
|
-
const cornersLeaving = readCorners(elementLeaving);
|
|
60195
60248
|
root.style.setProperty(BORDER_RADIUS_PROPERTY, cornersLeaving);
|
|
60249
|
+
if (paintLeaving) {
|
|
60250
|
+
publishBoxPaint(paintLeaving);
|
|
60251
|
+
}
|
|
60196
60252
|
|
|
60197
60253
|
let giveBackNameArriving = null;
|
|
60198
60254
|
let stopWaitingForTarget = null;
|
|
@@ -60224,10 +60280,6 @@ const liftPopupFromAnchor = (
|
|
|
60224
60280
|
releaseLiftInProgress = release;
|
|
60225
60281
|
|
|
60226
60282
|
const startMovement = (change, resolveElementArriving) => {
|
|
60227
|
-
releaseScrollHold?.();
|
|
60228
|
-
releaseScrollHold = trapScrollInside(popupEl, { backdrop: true });
|
|
60229
|
-
const room = measureRoomBetweenBars();
|
|
60230
|
-
const boxLeaving = elementLeaving.getBoundingClientRect();
|
|
60231
60283
|
let boxArriving = null;
|
|
60232
60284
|
let cornersArriving = null;
|
|
60233
60285
|
const viewTransition = startViewTransition(async () => {
|
|
@@ -60296,7 +60348,9 @@ const liftPopupFromAnchor = (
|
|
|
60296
60348
|
popupEl.removeAttribute(ARRIVING_ATTRIBUTE);
|
|
60297
60349
|
};
|
|
60298
60350
|
const liftTarget = (target) => {
|
|
60299
|
-
|
|
60351
|
+
// The last write before the transition: nothing reads between it and the
|
|
60352
|
+
// style pass the browser makes on its own to take the first picture.
|
|
60353
|
+
publishBoxPaint(readBoxPaint(target));
|
|
60300
60354
|
startMovement(reveal, () => target);
|
|
60301
60355
|
};
|
|
60302
60356
|
const targetNow = findLiftTarget(popupEl);
|
|
@@ -60314,10 +60368,16 @@ const liftPopupFromAnchor = (
|
|
|
60314
60368
|
});
|
|
60315
60369
|
};
|
|
60316
60370
|
|
|
60317
|
-
|
|
60371
|
+
// Read and published apart, so that a closing can read the paint with the
|
|
60372
|
+
// rest of what it reads and write it with the rest of what it writes.
|
|
60373
|
+
const readBoxPaint = (liftedElement) => {
|
|
60318
60374
|
const { backgroundColor, backgroundImage } = getComputedStyle(
|
|
60319
60375
|
findPaintedBox(liftedElement),
|
|
60320
60376
|
);
|
|
60377
|
+
return { backgroundColor, backgroundImage };
|
|
60378
|
+
};
|
|
60379
|
+
|
|
60380
|
+
const publishBoxPaint = ({ backgroundColor, backgroundImage }) => {
|
|
60321
60381
|
const root = document.documentElement;
|
|
60322
60382
|
root.style.setProperty(BACKGROUND_COLOR_PROPERTY, backgroundColor);
|
|
60323
60383
|
root.style.setProperty(BACKGROUND_IMAGE_PROPERTY, backgroundImage);
|