@mmstack/primitives 21.0.27 → 21.0.29
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.
|
@@ -2404,9 +2404,120 @@ function signalFromEvent(target, eventName, initial, projectOrOpt, maybeOpt) {
|
|
|
2404
2404
|
* has a `unique symbol` type, so the same symbol serves as both the property key written
|
|
2405
2405
|
* by {@link opaque} and the type-level brand carried by {@link Opaque}.
|
|
2406
2406
|
*/
|
|
2407
|
-
const OPAQUE = Symbol('
|
|
2408
|
-
|
|
2409
|
-
|
|
2407
|
+
const OPAQUE = Symbol('@mmstack/primitives::store/OPAQUE');
|
|
2408
|
+
/**
|
|
2409
|
+
* Marks a plain object as opaque so {@link store} treats it as an indivisible leaf
|
|
2410
|
+
* (returned whole, never deep-proxied) — the same way it treats a `Date` or `RegExp`.
|
|
2411
|
+
* The marker is a non-enumerable symbol, so it never appears in spreads or iteration.
|
|
2412
|
+
* Idempotent. Call before freezing (`defineProperty` fails on a frozen object).
|
|
2413
|
+
*
|
|
2414
|
+
* @example
|
|
2415
|
+
* const s = store({ config: opaque({ theme: 'dark', nested: { a: 1 } }) });
|
|
2416
|
+
* s.config(); // the whole object, not a child store
|
|
2417
|
+
* s.config.set(opaque({ theme: 'light', nested: { a: 2 } }));
|
|
2418
|
+
*/
|
|
2419
|
+
function opaque(value) {
|
|
2420
|
+
if (value[OPAQUE] !== true)
|
|
2421
|
+
Object.defineProperty(value, OPAQUE, { value: true, enumerable: false });
|
|
2422
|
+
return value;
|
|
2423
|
+
}
|
|
2424
|
+
/**
|
|
2425
|
+
* Type guard companion to {@link opaque}: returns `true` when `value` carries the
|
|
2426
|
+
* {@link OPAQUE} brand, narrowing it to {@link Opaque}. This is the same check the
|
|
2427
|
+
* store uses to route opaque values to its leaf branch (alongside `Date`/`RegExp`).
|
|
2428
|
+
*
|
|
2429
|
+
* @internal Exposed for advanced/niche interop only — not part of the supported public
|
|
2430
|
+
* surface and may change without a major version bump. Reach for {@link opaque} for
|
|
2431
|
+
* normal usage.
|
|
2432
|
+
*
|
|
2433
|
+
* @example
|
|
2434
|
+
* if (isOpaque(value)) {
|
|
2435
|
+
* // value: Opaque<object> — `store` would treat it as an indivisible leaf
|
|
2436
|
+
* }
|
|
2437
|
+
*/
|
|
2438
|
+
function isOpaque(value) {
|
|
2439
|
+
return (typeof value === 'object' &&
|
|
2440
|
+
value !== null &&
|
|
2441
|
+
value[OPAQUE] === true);
|
|
2442
|
+
}
|
|
2443
|
+
/**
|
|
2444
|
+
* @internal Runtime brand carrying a store node's lazily-built leaf probe. Exported (like
|
|
2445
|
+
* {@link OPAQUE}) only so the `{ readonly [LEAF]: () => boolean }` brand on the store types is
|
|
2446
|
+
* nameable in the emitted declarations — not part of the supported surface; use {@link isLeaf}.
|
|
2447
|
+
*/
|
|
2448
|
+
const LEAF = Symbol('@mmstack/primitives::store/LEAF');
|
|
2449
|
+
/**
|
|
2450
|
+
* @internal Whether a value is a terminal leaf: a concrete non-record/non-array value always is;
|
|
2451
|
+
* `null`/`undefined` is a leaf only when vivification is disabled (with vivify on it can still
|
|
2452
|
+
* materialize a container, so it stays a descendable substore).
|
|
2453
|
+
*/
|
|
2454
|
+
function isLeafValue(value, vivifyEnabled) {
|
|
2455
|
+
if (value == null)
|
|
2456
|
+
return !vivifyEnabled;
|
|
2457
|
+
if (isOpaque(value))
|
|
2458
|
+
return true; // opaque always wins — even arrays
|
|
2459
|
+
return !Array.isArray(value) && !isRecord(value);
|
|
2460
|
+
}
|
|
2461
|
+
/**
|
|
2462
|
+
* @internal Constant leaf probes for nodes whose leaf-ness is statically known, so the reactive
|
|
2463
|
+
* `computed` can be skipped entirely.
|
|
2464
|
+
*/
|
|
2465
|
+
function alwaysTrue() {
|
|
2466
|
+
return true;
|
|
2467
|
+
}
|
|
2468
|
+
function alwaysFalse() {
|
|
2469
|
+
return false;
|
|
2470
|
+
}
|
|
2471
|
+
/**
|
|
2472
|
+
* @internal Attaches a lazy, memoized leaf probe to a store node. The probe (`() => boolean`)
|
|
2473
|
+
* closes over the node's value signal and its (stable) vivify setting, building the backing
|
|
2474
|
+
* `computed` on first call so leaf-ness tracks the live value reactively without taxing every
|
|
2475
|
+
* node access. Idempotent.
|
|
2476
|
+
*/
|
|
2477
|
+
function markAsLeaf(sig, value, vivifyEnabled, noUnionLeaves) {
|
|
2478
|
+
if (typeof sig[LEAF] !== 'function') {
|
|
2479
|
+
let memo;
|
|
2480
|
+
const probe = () => {
|
|
2481
|
+
if (memo)
|
|
2482
|
+
return memo();
|
|
2483
|
+
const v = untracked(value);
|
|
2484
|
+
memo =
|
|
2485
|
+
isOpaque(v) || (v == null && !vivifyEnabled) || noUnionLeaves
|
|
2486
|
+
? isLeafValue(v, vivifyEnabled)
|
|
2487
|
+
? alwaysTrue
|
|
2488
|
+
: alwaysFalse
|
|
2489
|
+
: computed(() => isLeafValue(value(), vivifyEnabled));
|
|
2490
|
+
return memo();
|
|
2491
|
+
};
|
|
2492
|
+
Object.defineProperty(sig, LEAF, {
|
|
2493
|
+
value: probe,
|
|
2494
|
+
enumerable: false,
|
|
2495
|
+
configurable: true,
|
|
2496
|
+
});
|
|
2497
|
+
}
|
|
2498
|
+
return sig;
|
|
2499
|
+
}
|
|
2500
|
+
/**
|
|
2501
|
+
* Reports whether a store node is currently a **leaf** — a terminal value the store does not
|
|
2502
|
+
* descend into (a primitive, `Date`, `RegExp`, {@link opaque} object, class instance, or a
|
|
2503
|
+
* `null`/`undefined` hole when vivification is off) rather than a record/array substore.
|
|
2504
|
+
*
|
|
2505
|
+
* Leaf-ness reflects the node's **live** value: the probe is reactive and memoized, so calling
|
|
2506
|
+
* `isLeaf` inside a `computed`/`effect` re-evaluates when the node's shape changes.
|
|
2507
|
+
*
|
|
2508
|
+
* @internal Exposed for advanced/niche interop only — not part of the supported public surface
|
|
2509
|
+
* and may change without a major version bump.
|
|
2510
|
+
*
|
|
2511
|
+
* @example
|
|
2512
|
+
* const s = store({ name: 'Ada', address: { city: 'London' } });
|
|
2513
|
+
* isLeaf(s.name); // true
|
|
2514
|
+
* isLeaf(s.address); // false — a substore
|
|
2515
|
+
*/
|
|
2516
|
+
function isLeaf(value) {
|
|
2517
|
+
return isStore(value) && value[LEAF]?.() === true;
|
|
2518
|
+
}
|
|
2519
|
+
const IS_STORE = Symbol('@mmstack/primitives::store/IS_STORE');
|
|
2520
|
+
const SCOPE_PARENT = Symbol('@mmstack/primitives::store/SCOPE_PARENT');
|
|
2410
2521
|
/**
|
|
2411
2522
|
* @internal
|
|
2412
2523
|
* Test-only handle on the proxy cache (deliberately NOT re-exported from the public barrel).
|
|
@@ -2440,10 +2551,8 @@ function isStore(value) {
|
|
|
2440
2551
|
value[IS_STORE] === true);
|
|
2441
2552
|
}
|
|
2442
2553
|
function isRecord(value) {
|
|
2443
|
-
if (value === null || typeof value !== 'object')
|
|
2554
|
+
if (value === null || typeof value !== 'object' || isOpaque(value))
|
|
2444
2555
|
return false;
|
|
2445
|
-
if (value[OPAQUE] === true)
|
|
2446
|
-
return false; // opaque → leaf
|
|
2447
2556
|
const proto = Object.getPrototypeOf(value);
|
|
2448
2557
|
return proto === Object.prototype || proto === null;
|
|
2449
2558
|
}
|
|
@@ -2469,7 +2578,7 @@ function hasOwnKey(value, key) {
|
|
|
2469
2578
|
* @internal
|
|
2470
2579
|
* Makes an array store
|
|
2471
2580
|
*/
|
|
2472
|
-
function toArrayStore(source, injector, vivify) {
|
|
2581
|
+
function toArrayStore(source, injector, vivify, noUnionLeaves = false) {
|
|
2473
2582
|
if (isStore(source))
|
|
2474
2583
|
return source;
|
|
2475
2584
|
const isMutableSource = isMutable(source);
|
|
@@ -2579,9 +2688,10 @@ function toArrayStore(source, injector, vivify) {
|
|
|
2579
2688
|
});
|
|
2580
2689
|
const childSample = untracked(computation);
|
|
2581
2690
|
const childVivify = resolveVivify(childSample, vivify);
|
|
2582
|
-
const proxy = Array.isArray(childSample)
|
|
2583
|
-
? toArrayStore(computation, injector, childVivify)
|
|
2584
|
-
: toStore(computation, injector, childVivify);
|
|
2691
|
+
const proxy = Array.isArray(childSample) && !isOpaque(childSample)
|
|
2692
|
+
? toArrayStore(computation, injector, childVivify, noUnionLeaves)
|
|
2693
|
+
: toStore(computation, injector, childVivify, noUnionLeaves);
|
|
2694
|
+
markAsLeaf(proxy, computation, childVivify !== false, noUnionLeaves);
|
|
2585
2695
|
const ref = new WeakRef(proxy);
|
|
2586
2696
|
storeCache.set(idx, ref);
|
|
2587
2697
|
PROXY_CLEANUP.register(proxy, { target, prop: idx }, ref);
|
|
@@ -2598,7 +2708,7 @@ function toArrayStore(source, injector, vivify) {
|
|
|
2598
2708
|
* const state = store({ user: { name: 'John' } });
|
|
2599
2709
|
* const nameSignal = state.user.name; // WritableSignal<string>
|
|
2600
2710
|
*/
|
|
2601
|
-
function toStore(source, injector, vivify = false) {
|
|
2711
|
+
function toStore(source, injector, vivify = false, noUnionLeaves = false) {
|
|
2602
2712
|
if (isStore(source))
|
|
2603
2713
|
return source;
|
|
2604
2714
|
if (!injector)
|
|
@@ -2639,7 +2749,7 @@ function toStore(source, injector, vivify = false) {
|
|
|
2639
2749
|
return () => {
|
|
2640
2750
|
if (!isWritableSource)
|
|
2641
2751
|
return s;
|
|
2642
|
-
return untracked(() => toStore(source.asReadonly(), injector, vivify));
|
|
2752
|
+
return untracked(() => toStore(source.asReadonly(), injector, vivify, noUnionLeaves));
|
|
2643
2753
|
};
|
|
2644
2754
|
if (prop === 'extend')
|
|
2645
2755
|
return (seed) => scopedStore(s, seed, isMutableSource
|
|
@@ -2692,9 +2802,10 @@ function toStore(source, injector, vivify = false) {
|
|
|
2692
2802
|
});
|
|
2693
2803
|
const childSample = untracked(computation);
|
|
2694
2804
|
const childVivify = resolveVivify(childSample, vivify);
|
|
2695
|
-
const proxy = Array.isArray(childSample)
|
|
2696
|
-
? toArrayStore(computation, injector, childVivify)
|
|
2697
|
-
: toStore(computation, injector, childVivify);
|
|
2805
|
+
const proxy = Array.isArray(childSample) && !isOpaque(childSample)
|
|
2806
|
+
? toArrayStore(computation, injector, childVivify, noUnionLeaves)
|
|
2807
|
+
: toStore(computation, injector, childVivify, noUnionLeaves);
|
|
2808
|
+
markAsLeaf(proxy, computation, childVivify !== false, noUnionLeaves);
|
|
2698
2809
|
const ref = new WeakRef(proxy);
|
|
2699
2810
|
storeCache.set(prop, ref);
|
|
2700
2811
|
PROXY_CLEANUP.register(proxy, { target, prop }, ref);
|
|
@@ -2769,12 +2880,7 @@ function scopedStore(parent, seed, kind, injector) {
|
|
|
2769
2880
|
return hasOwnKey(localValue(), prop) || hasOwnKey(parentValue(), prop);
|
|
2770
2881
|
},
|
|
2771
2882
|
ownKeys() {
|
|
2772
|
-
return
|
|
2773
|
-
...new Set([
|
|
2774
|
-
...Reflect.ownKeys(parentValue()),
|
|
2775
|
-
...Reflect.ownKeys(localValue()),
|
|
2776
|
-
]),
|
|
2777
|
-
];
|
|
2883
|
+
return Reflect.ownKeys(untracked(view));
|
|
2778
2884
|
},
|
|
2779
2885
|
getOwnPropertyDescriptor(_, prop) {
|
|
2780
2886
|
if (hasOwnKey(localValue(), prop) || hasOwnKey(parentValue(), prop))
|
|
@@ -2792,30 +2898,14 @@ function scopedStore(parent, seed, kind, injector) {
|
|
|
2792
2898
|
* @see {@link toStore}
|
|
2793
2899
|
*/
|
|
2794
2900
|
function store(value, opt) {
|
|
2795
|
-
return toStore(signal(value, opt), opt?.injector, opt?.vivify ?? false);
|
|
2901
|
+
return toStore(signal(value, opt), opt?.injector, opt?.vivify ?? false, opt?.noUnionLeaves ?? false);
|
|
2796
2902
|
}
|
|
2797
2903
|
/**
|
|
2798
2904
|
* Creates a MutableSignalStore from a value.
|
|
2799
2905
|
* @see {@link toStore}
|
|
2800
2906
|
*/
|
|
2801
2907
|
function mutableStore(value, opt) {
|
|
2802
|
-
return toStore(mutable(value, opt), opt?.injector, opt?.vivify ?? false);
|
|
2803
|
-
}
|
|
2804
|
-
/**
|
|
2805
|
-
* Marks a plain object as opaque so {@link store} treats it as an indivisible leaf
|
|
2806
|
-
* (returned whole, never deep-proxied) — the same way it treats a `Date` or `RegExp`.
|
|
2807
|
-
* The marker is a non-enumerable symbol, so it never appears in spreads or iteration.
|
|
2808
|
-
* Idempotent. Call before freezing (`defineProperty` fails on a frozen object).
|
|
2809
|
-
*
|
|
2810
|
-
* @example
|
|
2811
|
-
* const s = store({ config: opaque({ theme: 'dark', nested: { a: 1 } }) });
|
|
2812
|
-
* s.config(); // the whole object, not a child store
|
|
2813
|
-
* s.config.set(opaque({ theme: 'light', nested: { a: 2 } }));
|
|
2814
|
-
*/
|
|
2815
|
-
function opaque(value) {
|
|
2816
|
-
if (value[OPAQUE] !== true)
|
|
2817
|
-
Object.defineProperty(value, OPAQUE, { value: true, enumerable: false });
|
|
2818
|
-
return value;
|
|
2908
|
+
return toStore(mutable(value, opt), opt?.injector, opt?.vivify ?? false, opt?.noUnionLeaves ?? false);
|
|
2819
2909
|
}
|
|
2820
2910
|
|
|
2821
2911
|
// Internal dummy store for server-side rendering
|
|
@@ -3292,5 +3382,5 @@ function withHistory(sourceOrValue, opt) {
|
|
|
3292
3382
|
* Generated bundle index. Do not edit.
|
|
3293
3383
|
*/
|
|
3294
3384
|
|
|
3295
|
-
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 };
|
|
3385
|
+
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 };
|
|
3296
3386
|
//# sourceMappingURL=mmstack-primitives.mjs.map
|