@mmstack/primitives 22.0.1 → 22.0.3
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.
|
@@ -2423,9 +2423,120 @@ function signalFromEvent(target, eventName, initial, projectOrOpt, maybeOpt) {
|
|
|
2423
2423
|
* has a `unique symbol` type, so the same symbol serves as both the property key written
|
|
2424
2424
|
* by {@link opaque} and the type-level brand carried by {@link Opaque}.
|
|
2425
2425
|
*/
|
|
2426
|
-
const OPAQUE = Symbol('
|
|
2427
|
-
|
|
2428
|
-
|
|
2426
|
+
const OPAQUE = Symbol('@mmstack/primitives::store/OPAQUE');
|
|
2427
|
+
/**
|
|
2428
|
+
* Marks a plain object as opaque so {@link store} treats it as an indivisible leaf
|
|
2429
|
+
* (returned whole, never deep-proxied) — the same way it treats a `Date` or `RegExp`.
|
|
2430
|
+
* The marker is a non-enumerable symbol, so it never appears in spreads or iteration.
|
|
2431
|
+
* Idempotent. Call before freezing (`defineProperty` fails on a frozen object).
|
|
2432
|
+
*
|
|
2433
|
+
* @example
|
|
2434
|
+
* const s = store({ config: opaque({ theme: 'dark', nested: { a: 1 } }) });
|
|
2435
|
+
* s.config(); // the whole object, not a child store
|
|
2436
|
+
* s.config.set(opaque({ theme: 'light', nested: { a: 2 } }));
|
|
2437
|
+
*/
|
|
2438
|
+
function opaque(value) {
|
|
2439
|
+
if (value[OPAQUE] !== true)
|
|
2440
|
+
Object.defineProperty(value, OPAQUE, { value: true, enumerable: false });
|
|
2441
|
+
return value;
|
|
2442
|
+
}
|
|
2443
|
+
/**
|
|
2444
|
+
* Type guard companion to {@link opaque}: returns `true` when `value` carries the
|
|
2445
|
+
* {@link OPAQUE} brand, narrowing it to {@link Opaque}. This is the same check the
|
|
2446
|
+
* store uses to route opaque values to its leaf branch (alongside `Date`/`RegExp`).
|
|
2447
|
+
*
|
|
2448
|
+
* @internal Exposed for advanced/niche interop only — not part of the supported public
|
|
2449
|
+
* surface and may change without a major version bump. Reach for {@link opaque} for
|
|
2450
|
+
* normal usage.
|
|
2451
|
+
*
|
|
2452
|
+
* @example
|
|
2453
|
+
* if (isOpaque(value)) {
|
|
2454
|
+
* // value: Opaque<object> — `store` would treat it as an indivisible leaf
|
|
2455
|
+
* }
|
|
2456
|
+
*/
|
|
2457
|
+
function isOpaque(value) {
|
|
2458
|
+
return (typeof value === 'object' &&
|
|
2459
|
+
value !== null &&
|
|
2460
|
+
value[OPAQUE] === true);
|
|
2461
|
+
}
|
|
2462
|
+
/**
|
|
2463
|
+
* @internal Runtime brand carrying a store node's lazily-built leaf probe. Exported (like
|
|
2464
|
+
* {@link OPAQUE}) only so the `{ readonly [LEAF]: () => boolean }` brand on the store types is
|
|
2465
|
+
* nameable in the emitted declarations — not part of the supported surface; use {@link isLeaf}.
|
|
2466
|
+
*/
|
|
2467
|
+
const LEAF = Symbol('@mmstack/primitives::store/LEAF');
|
|
2468
|
+
/**
|
|
2469
|
+
* @internal Whether a value is a terminal leaf: a concrete non-record/non-array value always is;
|
|
2470
|
+
* `null`/`undefined` is a leaf only when vivification is disabled (with vivify on it can still
|
|
2471
|
+
* materialize a container, so it stays a descendable substore).
|
|
2472
|
+
*/
|
|
2473
|
+
function isLeafValue(value, vivifyEnabled) {
|
|
2474
|
+
if (value == null)
|
|
2475
|
+
return !vivifyEnabled;
|
|
2476
|
+
if (isOpaque(value))
|
|
2477
|
+
return true; // opaque always wins — even arrays
|
|
2478
|
+
return !Array.isArray(value) && !isRecord(value);
|
|
2479
|
+
}
|
|
2480
|
+
/**
|
|
2481
|
+
* @internal Constant leaf probes for nodes whose leaf-ness is statically known, so the reactive
|
|
2482
|
+
* `computed` can be skipped entirely.
|
|
2483
|
+
*/
|
|
2484
|
+
function alwaysTrue() {
|
|
2485
|
+
return true;
|
|
2486
|
+
}
|
|
2487
|
+
function alwaysFalse() {
|
|
2488
|
+
return false;
|
|
2489
|
+
}
|
|
2490
|
+
/**
|
|
2491
|
+
* @internal Attaches a lazy, memoized leaf probe to a store node. The probe (`() => boolean`)
|
|
2492
|
+
* closes over the node's value signal and its (stable) vivify setting, building the backing
|
|
2493
|
+
* `computed` on first call so leaf-ness tracks the live value reactively without taxing every
|
|
2494
|
+
* node access. Idempotent.
|
|
2495
|
+
*/
|
|
2496
|
+
function markAsLeaf(sig, value, vivifyEnabled, noUnionLeaves) {
|
|
2497
|
+
if (typeof sig[LEAF] !== 'function') {
|
|
2498
|
+
let memo;
|
|
2499
|
+
const probe = () => {
|
|
2500
|
+
if (memo)
|
|
2501
|
+
return memo();
|
|
2502
|
+
const v = untracked(value);
|
|
2503
|
+
memo =
|
|
2504
|
+
isOpaque(v) || (v == null && !vivifyEnabled) || noUnionLeaves
|
|
2505
|
+
? isLeafValue(v, vivifyEnabled)
|
|
2506
|
+
? alwaysTrue
|
|
2507
|
+
: alwaysFalse
|
|
2508
|
+
: computed(() => isLeafValue(value(), vivifyEnabled));
|
|
2509
|
+
return memo();
|
|
2510
|
+
};
|
|
2511
|
+
Object.defineProperty(sig, LEAF, {
|
|
2512
|
+
value: probe,
|
|
2513
|
+
enumerable: false,
|
|
2514
|
+
configurable: true,
|
|
2515
|
+
});
|
|
2516
|
+
}
|
|
2517
|
+
return sig;
|
|
2518
|
+
}
|
|
2519
|
+
/**
|
|
2520
|
+
* Reports whether a store node is currently a **leaf** — a terminal value the store does not
|
|
2521
|
+
* descend into (a primitive, `Date`, `RegExp`, {@link opaque} object, class instance, or a
|
|
2522
|
+
* `null`/`undefined` hole when vivification is off) rather than a record/array substore.
|
|
2523
|
+
*
|
|
2524
|
+
* Leaf-ness reflects the node's **live** value: the probe is reactive and memoized, so calling
|
|
2525
|
+
* `isLeaf` inside a `computed`/`effect` re-evaluates when the node's shape changes.
|
|
2526
|
+
*
|
|
2527
|
+
* @internal Exposed for advanced/niche interop only — not part of the supported public surface
|
|
2528
|
+
* and may change without a major version bump.
|
|
2529
|
+
*
|
|
2530
|
+
* @example
|
|
2531
|
+
* const s = store({ name: 'Ada', address: { city: 'London' } });
|
|
2532
|
+
* isLeaf(s.name); // true
|
|
2533
|
+
* isLeaf(s.address); // false — a substore
|
|
2534
|
+
*/
|
|
2535
|
+
function isLeaf(value) {
|
|
2536
|
+
return isStore(value) && value[LEAF]?.() === true;
|
|
2537
|
+
}
|
|
2538
|
+
const IS_STORE = Symbol('@mmstack/primitives::store/IS_STORE');
|
|
2539
|
+
const SCOPE_PARENT = Symbol('@mmstack/primitives::store/SCOPE_PARENT');
|
|
2429
2540
|
/**
|
|
2430
2541
|
* @internal
|
|
2431
2542
|
* Test-only handle on the proxy cache (deliberately NOT re-exported from the public barrel).
|
|
@@ -2459,10 +2570,8 @@ function isStore(value) {
|
|
|
2459
2570
|
value[IS_STORE] === true);
|
|
2460
2571
|
}
|
|
2461
2572
|
function isRecord(value) {
|
|
2462
|
-
if (value === null || typeof value !== 'object')
|
|
2573
|
+
if (value === null || typeof value !== 'object' || isOpaque(value))
|
|
2463
2574
|
return false;
|
|
2464
|
-
if (value[OPAQUE] === true)
|
|
2465
|
-
return false; // opaque → leaf
|
|
2466
2575
|
const proto = Object.getPrototypeOf(value);
|
|
2467
2576
|
return proto === Object.prototype || proto === null;
|
|
2468
2577
|
}
|
|
@@ -2488,7 +2597,7 @@ function hasOwnKey(value, key) {
|
|
|
2488
2597
|
* @internal
|
|
2489
2598
|
* Makes an array store
|
|
2490
2599
|
*/
|
|
2491
|
-
function toArrayStore(source, injector, vivify) {
|
|
2600
|
+
function toArrayStore(source, injector, vivify, noUnionLeaves = false) {
|
|
2492
2601
|
if (isStore(source))
|
|
2493
2602
|
return source;
|
|
2494
2603
|
const isMutableSource = isMutable(source);
|
|
@@ -2599,9 +2708,10 @@ function toArrayStore(source, injector, vivify) {
|
|
|
2599
2708
|
});
|
|
2600
2709
|
const childSample = untracked(computation);
|
|
2601
2710
|
const childVivify = resolveVivify(childSample, vivify);
|
|
2602
|
-
const proxy = Array.isArray(childSample)
|
|
2603
|
-
? toArrayStore(computation, injector, childVivify)
|
|
2604
|
-
: toStore(computation, injector, childVivify);
|
|
2711
|
+
const proxy = Array.isArray(childSample) && !isOpaque(childSample)
|
|
2712
|
+
? toArrayStore(computation, injector, childVivify, noUnionLeaves)
|
|
2713
|
+
: toStore(computation, injector, childVivify, noUnionLeaves);
|
|
2714
|
+
markAsLeaf(proxy, computation, childVivify !== false, noUnionLeaves);
|
|
2605
2715
|
const ref = new WeakRef(proxy);
|
|
2606
2716
|
storeCache.set(idx, ref);
|
|
2607
2717
|
PROXY_CLEANUP.register(proxy, { target, prop: idx }, ref);
|
|
@@ -2618,7 +2728,7 @@ function toArrayStore(source, injector, vivify) {
|
|
|
2618
2728
|
* const state = store({ user: { name: 'John' } });
|
|
2619
2729
|
* const nameSignal = state.user.name; // WritableSignal<string>
|
|
2620
2730
|
*/
|
|
2621
|
-
function toStore(source, injector, vivify = false) {
|
|
2731
|
+
function toStore(source, injector, vivify = false, noUnionLeaves = false) {
|
|
2622
2732
|
if (isStore(source))
|
|
2623
2733
|
return source;
|
|
2624
2734
|
if (!injector)
|
|
@@ -2659,7 +2769,7 @@ function toStore(source, injector, vivify = false) {
|
|
|
2659
2769
|
return () => {
|
|
2660
2770
|
if (!isWritableSource)
|
|
2661
2771
|
return s;
|
|
2662
|
-
return untracked(() => toStore(source.asReadonly(), injector, vivify));
|
|
2772
|
+
return untracked(() => toStore(source.asReadonly(), injector, vivify, noUnionLeaves));
|
|
2663
2773
|
};
|
|
2664
2774
|
if (prop === 'extend')
|
|
2665
2775
|
return (seed) => scopedStore(s, seed, isMutableSource
|
|
@@ -2712,9 +2822,10 @@ function toStore(source, injector, vivify = false) {
|
|
|
2712
2822
|
});
|
|
2713
2823
|
const childSample = untracked(computation);
|
|
2714
2824
|
const childVivify = resolveVivify(childSample, vivify);
|
|
2715
|
-
const proxy = Array.isArray(childSample)
|
|
2716
|
-
? toArrayStore(computation, injector, childVivify)
|
|
2717
|
-
: toStore(computation, injector, childVivify);
|
|
2825
|
+
const proxy = Array.isArray(childSample) && !isOpaque(childSample)
|
|
2826
|
+
? toArrayStore(computation, injector, childVivify, noUnionLeaves)
|
|
2827
|
+
: toStore(computation, injector, childVivify, noUnionLeaves);
|
|
2828
|
+
markAsLeaf(proxy, computation, childVivify !== false, noUnionLeaves);
|
|
2718
2829
|
const ref = new WeakRef(proxy);
|
|
2719
2830
|
storeCache.set(prop, ref);
|
|
2720
2831
|
PROXY_CLEANUP.register(proxy, { target, prop }, ref);
|
|
@@ -2790,12 +2901,7 @@ function scopedStore(parent, seed, kind, injector) {
|
|
|
2790
2901
|
return hasOwnKey(localValue(), prop) || hasOwnKey(parentValue(), prop);
|
|
2791
2902
|
},
|
|
2792
2903
|
ownKeys() {
|
|
2793
|
-
return
|
|
2794
|
-
...new Set([
|
|
2795
|
-
...Reflect.ownKeys(parentValue()),
|
|
2796
|
-
...Reflect.ownKeys(localValue()),
|
|
2797
|
-
]),
|
|
2798
|
-
];
|
|
2904
|
+
return Reflect.ownKeys(untracked(view));
|
|
2799
2905
|
},
|
|
2800
2906
|
getOwnPropertyDescriptor(_, prop) {
|
|
2801
2907
|
if (hasOwnKey(localValue(), prop) || hasOwnKey(parentValue(), prop))
|
|
@@ -2813,30 +2919,14 @@ function scopedStore(parent, seed, kind, injector) {
|
|
|
2813
2919
|
* @see {@link toStore}
|
|
2814
2920
|
*/
|
|
2815
2921
|
function store(value, opt) {
|
|
2816
|
-
return toStore(signal(value, opt), opt?.injector, opt?.vivify ?? false);
|
|
2922
|
+
return toStore(signal(value, opt), opt?.injector, opt?.vivify ?? false, opt?.noUnionLeaves ?? false);
|
|
2817
2923
|
}
|
|
2818
2924
|
/**
|
|
2819
2925
|
* Creates a MutableSignalStore from a value.
|
|
2820
2926
|
* @see {@link toStore}
|
|
2821
2927
|
*/
|
|
2822
2928
|
function mutableStore(value, opt) {
|
|
2823
|
-
return toStore(mutable(value, opt), opt?.injector, opt?.vivify ?? false);
|
|
2824
|
-
}
|
|
2825
|
-
/**
|
|
2826
|
-
* Marks a plain object as opaque so {@link store} treats it as an indivisible leaf
|
|
2827
|
-
* (returned whole, never deep-proxied) — the same way it treats a `Date` or `RegExp`.
|
|
2828
|
-
* The marker is a non-enumerable symbol, so it never appears in spreads or iteration.
|
|
2829
|
-
* Idempotent. Call before freezing (`defineProperty` fails on a frozen object).
|
|
2830
|
-
*
|
|
2831
|
-
* @example
|
|
2832
|
-
* const s = store({ config: opaque({ theme: 'dark', nested: { a: 1 } }) });
|
|
2833
|
-
* s.config(); // the whole object, not a child store
|
|
2834
|
-
* s.config.set(opaque({ theme: 'light', nested: { a: 2 } }));
|
|
2835
|
-
*/
|
|
2836
|
-
function opaque(value) {
|
|
2837
|
-
if (value[OPAQUE] !== true)
|
|
2838
|
-
Object.defineProperty(value, OPAQUE, { value: true, enumerable: false });
|
|
2839
|
-
return value;
|
|
2929
|
+
return toStore(mutable(value, opt), opt?.injector, opt?.vivify ?? false, opt?.noUnionLeaves ?? false);
|
|
2840
2930
|
}
|
|
2841
2931
|
|
|
2842
2932
|
// Internal dummy store for server-side rendering
|
|
@@ -3317,5 +3407,5 @@ function withHistory(sourceOrValue, opt) {
|
|
|
3317
3407
|
* Generated bundle index. Do not edit.
|
|
3318
3408
|
*/
|
|
3319
3409
|
|
|
3320
|
-
export { batteryStatus, chunked, clipboard, combineWith, debounce, debounced, derived, distinct, elementSize, elementVisibility, filter, filterWith, focusWithin, geolocation, idle, indexArray, isDerivation, isMutable, isStore, keyArray, map, mapArray, mapObject, mediaQuery, mousePosition, mutable, mutableStore, nestedEffect, networkStatus, opaque, orientation, pageVisibility, pairwise, pipeable, piped, pooled, pooledArray, pooledMap, pooledSet, prefersDarkMode, prefersReducedMotion, scan, scrollPosition, select, sensor, sensors, signalFromEvent, startWith, store, stored, tabSync, tap, throttle, throttled, toFakeDerivation, toFakeSignalDerivation, toStore, toWritable, until, windowSize, withHistory };
|
|
3410
|
+
export { batteryStatus, chunked, clipboard, combineWith, debounce, debounced, derived, distinct, elementSize, elementVisibility, filter, filterWith, focusWithin, geolocation, idle, indexArray, isDerivation, isLeaf, isMutable, isOpaque, isStore, keyArray, map, mapArray, mapObject, mediaQuery, mousePosition, mutable, mutableStore, nestedEffect, networkStatus, opaque, orientation, pageVisibility, pairwise, pipeable, piped, pooled, pooledArray, pooledMap, pooledSet, prefersDarkMode, prefersReducedMotion, scan, scrollPosition, select, sensor, sensors, signalFromEvent, startWith, store, stored, tabSync, tap, throttle, throttled, toFakeDerivation, toFakeSignalDerivation, toStore, toWritable, until, windowSize, withHistory };
|
|
3321
3411
|
//# sourceMappingURL=mmstack-primitives.mjs.map
|