@jsenv/navi 0.16.27 → 0.16.28
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 +59 -9
- package/dist/jsenv_navi.js.map +3 -3
- package/package.json +1 -1
package/dist/jsenv_navi.js
CHANGED
|
@@ -2401,15 +2401,18 @@ const generateSignalId = () => {
|
|
|
2401
2401
|
* 2. When explicitly set (programmatically or via localStorage), the explicit value takes precedence
|
|
2402
2402
|
* 3. When default signal changes, it only updates if no explicit value was ever set
|
|
2403
2403
|
* 4. Calling reset() or setting to undefined makes the signal use the dynamic default again
|
|
2404
|
+
* 5. If dynamic default is undefined and options.default is provided, uses the static fallback
|
|
2404
2405
|
*
|
|
2405
2406
|
* This is useful for:
|
|
2406
2407
|
* - Backend data that can change but shouldn't override user preferences
|
|
2407
2408
|
* - Route parameters with dynamic defaults based on other state
|
|
2408
2409
|
* - Cascading configuration where defaults can be updated without losing user customizations
|
|
2410
|
+
* - Having a static fallback when dynamic defaults might be undefined
|
|
2409
2411
|
*
|
|
2410
2412
|
* @param {any|import("@preact/signals").Signal} defaultValue - Static default value OR signal for dynamic default behavior
|
|
2411
2413
|
* @param {Object} [options={}] - Configuration options
|
|
2412
2414
|
* @param {string|number} [options.id] - Custom ID for the signal. If not provided, an auto-generated ID will be used. Used for localStorage key and route pattern detection.
|
|
2415
|
+
* @param {any} [options.default] - Static fallback value used when defaultValue is a signal and that signal's value is undefined
|
|
2413
2416
|
* @param {boolean} [options.persists=false] - Whether to persist the signal value in localStorage using the signal ID as key
|
|
2414
2417
|
* @param {"string" | "number" | "boolean" | "object"} [options.type="string"] - Type for localStorage serialization/deserialization
|
|
2415
2418
|
* @param {Array} [options.oneOf] - Array of valid values for validation. Signal will be marked invalid if value is not in this array
|
|
@@ -2450,6 +2453,21 @@ const generateSignalId = () => {
|
|
|
2450
2453
|
* // Reset: userTheme.value = undefined; // Now follows dynamic default again
|
|
2451
2454
|
*
|
|
2452
2455
|
* @example
|
|
2456
|
+
* // Dynamic default with static fallback
|
|
2457
|
+
* const backendValue = signal(undefined); // might be undefined initially
|
|
2458
|
+
* const userValue = stateSignal(backendValue, {
|
|
2459
|
+
* default: "fallback",
|
|
2460
|
+
* persists: true
|
|
2461
|
+
* });
|
|
2462
|
+
*
|
|
2463
|
+
* // Initially: userValue.value = "fallback" (static fallback since dynamic is undefined)
|
|
2464
|
+
* // Backend loads: backendValue.value = "loaded"; userValue.value = "loaded" (follows dynamic)
|
|
2465
|
+
* // User sets: userValue.value = "custom" (explicit choice, persisted)
|
|
2466
|
+
* // Backend changes: backendValue.value = "updated"
|
|
2467
|
+
* // Result: userValue.value = "custom" (user choice preserved)
|
|
2468
|
+
* // Reset: userValue.value = undefined; userValue.value = "updated" (follows dynamic again)
|
|
2469
|
+
*
|
|
2470
|
+
* @example
|
|
2453
2471
|
* // Route parameter with dynamic default from parent route
|
|
2454
2472
|
* const parentTab = signal("overview");
|
|
2455
2473
|
* const childTab = stateSignal(parentTab);
|
|
@@ -2464,6 +2482,7 @@ const stateSignal = (defaultValue, options = {}) => {
|
|
|
2464
2482
|
autoFix,
|
|
2465
2483
|
persists = false,
|
|
2466
2484
|
debug,
|
|
2485
|
+
default: staticFallback,
|
|
2467
2486
|
} = options;
|
|
2468
2487
|
|
|
2469
2488
|
// Check if defaultValue is a signal (dynamic default) or static value
|
|
@@ -2473,7 +2492,7 @@ const stateSignal = (defaultValue, options = {}) => {
|
|
|
2473
2492
|
"value" in defaultValue &&
|
|
2474
2493
|
"peek" in defaultValue;
|
|
2475
2494
|
const dynamicDefaultSignal = isDynamicDefault ? defaultValue : null;
|
|
2476
|
-
const staticDefaultValue = isDynamicDefault ?
|
|
2495
|
+
const staticDefaultValue = isDynamicDefault ? staticFallback : defaultValue;
|
|
2477
2496
|
const signalId = id || generateSignalId();
|
|
2478
2497
|
// Convert numeric IDs to strings for consistency
|
|
2479
2498
|
const signalIdString = String(signalId);
|
|
@@ -2505,7 +2524,15 @@ const stateSignal = (defaultValue, options = {}) => {
|
|
|
2505
2524
|
if (dynamicDefaultSignal) {
|
|
2506
2525
|
const dynamicValue = dynamicDefaultSignal.peek();
|
|
2507
2526
|
if (dynamicValue === undefined) {
|
|
2508
|
-
|
|
2527
|
+
if (staticDefaultValue === undefined) {
|
|
2528
|
+
return undefined;
|
|
2529
|
+
}
|
|
2530
|
+
if (debug) {
|
|
2531
|
+
console.debug(
|
|
2532
|
+
`[stateSignal:${signalIdString}] dynamic default is undefined, using static default=${staticDefaultValue}`,
|
|
2533
|
+
);
|
|
2534
|
+
}
|
|
2535
|
+
return staticDefaultValue;
|
|
2509
2536
|
}
|
|
2510
2537
|
if (debug) {
|
|
2511
2538
|
console.debug(
|
|
@@ -2526,7 +2553,11 @@ const stateSignal = (defaultValue, options = {}) => {
|
|
|
2526
2553
|
return false;
|
|
2527
2554
|
}
|
|
2528
2555
|
if (dynamicDefaultSignal) {
|
|
2529
|
-
|
|
2556
|
+
const dynamicValue = dynamicDefaultSignal.peek();
|
|
2557
|
+
if (dynamicValue === undefined) {
|
|
2558
|
+
return value !== staticDefaultValue;
|
|
2559
|
+
}
|
|
2560
|
+
return value !== dynamicValue;
|
|
2530
2561
|
}
|
|
2531
2562
|
return value !== staticDefaultValue;
|
|
2532
2563
|
};
|
|
@@ -2577,21 +2608,40 @@ const stateSignal = (defaultValue, options = {}) => {
|
|
|
2577
2608
|
dynamicDefaultPreviousValue = dynamicDefaultValue;
|
|
2578
2609
|
return;
|
|
2579
2610
|
}
|
|
2580
|
-
if
|
|
2611
|
+
// Check if current signal value matches the PREVIOUS dynamic default
|
|
2612
|
+
// If so, it was following the dynamic default and should update
|
|
2613
|
+
// Special case: if previous was undefined and we were using static fallback
|
|
2614
|
+
let wasFollowingDefault = false;
|
|
2615
|
+
if (
|
|
2616
|
+
dynamicDefaultPreviousValue === undefined &&
|
|
2617
|
+
staticDefaultValue !== undefined
|
|
2618
|
+
) {
|
|
2619
|
+
// Signal might have been using static fallback
|
|
2620
|
+
wasFollowingDefault = value === staticDefaultValue;
|
|
2621
|
+
} else {
|
|
2622
|
+
// Signal was following the previous dynamic default
|
|
2623
|
+
wasFollowingDefault = value === dynamicDefaultPreviousValue;
|
|
2624
|
+
}
|
|
2625
|
+
|
|
2626
|
+
if (!wasFollowingDefault) {
|
|
2627
|
+
// Signal has a custom value, don't update even if dynamic default changes
|
|
2581
2628
|
dynamicDefaultPreviousValue = dynamicDefaultValue;
|
|
2582
2629
|
return;
|
|
2583
2630
|
}
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2631
|
+
|
|
2632
|
+
// Signal was using default value, update to new default
|
|
2633
|
+
const newDefaultValue = getDefaultValue();
|
|
2634
|
+
if (newDefaultValue === value) {
|
|
2635
|
+
dynamicDefaultPreviousValue = dynamicDefaultValue;
|
|
2587
2636
|
return;
|
|
2588
2637
|
}
|
|
2589
2638
|
if (debug) {
|
|
2590
2639
|
console.debug(
|
|
2591
|
-
`[stateSignal:${signalIdString}] dynamic default updated, update to ${
|
|
2640
|
+
`[stateSignal:${signalIdString}] dynamic default updated, update to ${newDefaultValue}`,
|
|
2592
2641
|
);
|
|
2593
2642
|
}
|
|
2594
|
-
|
|
2643
|
+
dynamicDefaultPreviousValue = dynamicDefaultValue;
|
|
2644
|
+
advancedSignal.value = newDefaultValue;
|
|
2595
2645
|
});
|
|
2596
2646
|
}
|
|
2597
2647
|
persist_in_local_storage: {
|