@mmstack/primitives 21.0.8 → 21.0.10
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/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CreateSignalOptions, DestroyRef, WritableSignal, Signal,
|
|
1
|
+
import { CreateSignalOptions, DestroyRef, WritableSignal, Signal, Injector, EffectRef, EffectCleanupRegisterFn, CreateEffectOptions, ElementRef, ValueEqualityFn } from '@angular/core';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Options for creating a debounced writable signal.
|
|
@@ -378,6 +378,109 @@ declare function toFakeSignalDerivation<T, U>(initial: WritableSignal<U>): Deriv
|
|
|
378
378
|
*/
|
|
379
379
|
declare function isDerivation<T, U>(sig: WritableSignal<U>): sig is DerivedSignal<T, U>;
|
|
380
380
|
|
|
381
|
+
type Frame = {
|
|
382
|
+
injector: Injector;
|
|
383
|
+
parent: Frame | null;
|
|
384
|
+
children: Set<EffectRef>;
|
|
385
|
+
};
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* Creates an effect that can be nested, similar to SolidJS's `createEffect`.
|
|
389
|
+
*
|
|
390
|
+
* This primitive enables true hierarchical reactivity. A `nestedEffect` created
|
|
391
|
+
* within another `nestedEffect` is automatically destroyed and recreated when
|
|
392
|
+
* the parent re-runs.
|
|
393
|
+
*
|
|
394
|
+
* It automatically handles injector propagation and lifetime management, allowing
|
|
395
|
+
* you to create fine-grained, conditional side-effects that only track
|
|
396
|
+
* dependencies when they are "live".
|
|
397
|
+
*
|
|
398
|
+
* @param effectFn The side-effect function, which receives a cleanup register function.
|
|
399
|
+
* @param options (Optional) Angular's `CreateEffectOptions`.
|
|
400
|
+
* @returns An `EffectRef` for the created effect.
|
|
401
|
+
*
|
|
402
|
+
* @example
|
|
403
|
+
* ```ts
|
|
404
|
+
* // Assume `coldGuard` changes rarely, but `hotSignal` changes often.
|
|
405
|
+
* const coldGuard = signal(false);
|
|
406
|
+
* const hotSignal = signal(0);
|
|
407
|
+
*
|
|
408
|
+
* nestedEffect(() => {
|
|
409
|
+
* // This outer effect only tracks `coldGuard`.
|
|
410
|
+
* if (coldGuard()) {
|
|
411
|
+
*
|
|
412
|
+
* // This inner effect is CREATED when coldGuard is true
|
|
413
|
+
* // and DESTROYED when it becomes false.
|
|
414
|
+
* nestedEffect(() => {
|
|
415
|
+
* // It only tracks `hotSignal` while it exists.
|
|
416
|
+
* console.log('Hot signal is:', hotSignal());
|
|
417
|
+
* });
|
|
418
|
+
* }
|
|
419
|
+
* // If `coldGuard` is false, this outer effect does not track `hotSignal`.
|
|
420
|
+
* });
|
|
421
|
+
* ```
|
|
422
|
+
* @example
|
|
423
|
+
* ```ts
|
|
424
|
+
* const users = signal([
|
|
425
|
+
* { id: 1, name: 'Alice' },
|
|
426
|
+
* { id: 2, name: 'Bob' }
|
|
427
|
+
* ]);
|
|
428
|
+
*
|
|
429
|
+
* // The fine-grained mapped list
|
|
430
|
+
* const mappedUsers = mapArray(
|
|
431
|
+
* users,
|
|
432
|
+
* (userSignal, index) => {
|
|
433
|
+
* // 1. Create a fine-grained SIDE EFFECT for *this item*
|
|
434
|
+
* // This effect's lifetime is now tied to this specific item. created once on init of this index.
|
|
435
|
+
* const effectRef = nestedEffect(() => {
|
|
436
|
+
* // This only runs if *this* userSignal changes,
|
|
437
|
+
* // not if the whole list changes.
|
|
438
|
+
* console.log(`User ${index} updated:`, userSignal().name);
|
|
439
|
+
* });
|
|
440
|
+
*
|
|
441
|
+
* // 2. Return the data AND the cleanup logic
|
|
442
|
+
* return {
|
|
443
|
+
* // The mapped data
|
|
444
|
+
* label: computed(() => `User: ${userSignal().name}`),
|
|
445
|
+
*
|
|
446
|
+
* // The cleanup function
|
|
447
|
+
* destroyEffect: () => effectRef.destroy()
|
|
448
|
+
* };
|
|
449
|
+
* },
|
|
450
|
+
* {
|
|
451
|
+
* // 3. Tell mapArray HOW to clean up when an item is removed, this needs to be manual as it's not a nestedEffect itself
|
|
452
|
+
* onDestroy: (mappedItem) => {
|
|
453
|
+
* mappedItem.destroyEffect();
|
|
454
|
+
* }
|
|
455
|
+
* }
|
|
456
|
+
* );
|
|
457
|
+
* ```
|
|
458
|
+
*/
|
|
459
|
+
declare function nestedEffect(effectFn: (registerCleanup: EffectCleanupRegisterFn) => void, options?: CreateEffectOptions & {
|
|
460
|
+
bindToFrame?: (parent: Frame | null) => Frame | null;
|
|
461
|
+
}): {
|
|
462
|
+
destroy: () => void;
|
|
463
|
+
};
|
|
464
|
+
|
|
465
|
+
declare function batch(fn: () => void): void;
|
|
466
|
+
/**
|
|
467
|
+
* A synchronous version of Angular's effect, optimized for DOM-heavy renderers.
|
|
468
|
+
* Runs immediately on creation and on dependency changes, bypassing the microtask queue.
|
|
469
|
+
* * @example
|
|
470
|
+
* renderEffect((onCleanup) => {
|
|
471
|
+
* const el = document.createElement('div');
|
|
472
|
+
* el.textContent = count();
|
|
473
|
+
* container.appendChild(el);
|
|
474
|
+
* onCleanup(() => el.remove());
|
|
475
|
+
* });
|
|
476
|
+
*/
|
|
477
|
+
declare function renderEffect(effectFn: (onCleanup: (fn: () => void) => void) => void, options?: {
|
|
478
|
+
injector?: Injector;
|
|
479
|
+
}): {
|
|
480
|
+
run: (isFromBridge?: boolean) => void;
|
|
481
|
+
destroy: () => void;
|
|
482
|
+
};
|
|
483
|
+
|
|
381
484
|
/**
|
|
382
485
|
* Reactively maps items from a source array to a new array, creating stable signals for each item.
|
|
383
486
|
*
|
|
@@ -472,89 +575,6 @@ declare function mapObject<T extends Record<string, any>, U>(source: (() => T) |
|
|
|
472
575
|
onDestroy?: (value: U) => void;
|
|
473
576
|
}): Signal<MappedObject<T, U>>;
|
|
474
577
|
|
|
475
|
-
type Frame = {
|
|
476
|
-
injector: Injector;
|
|
477
|
-
parent: Frame | null;
|
|
478
|
-
children: Set<EffectRef>;
|
|
479
|
-
};
|
|
480
|
-
/**
|
|
481
|
-
* Creates an effect that can be nested, similar to SolidJS's `createEffect`.
|
|
482
|
-
*
|
|
483
|
-
* This primitive enables true hierarchical reactivity. A `nestedEffect` created
|
|
484
|
-
* within another `nestedEffect` is automatically destroyed and recreated when
|
|
485
|
-
* the parent re-runs.
|
|
486
|
-
*
|
|
487
|
-
* It automatically handles injector propagation and lifetime management, allowing
|
|
488
|
-
* you to create fine-grained, conditional side-effects that only track
|
|
489
|
-
* dependencies when they are "live".
|
|
490
|
-
*
|
|
491
|
-
* @param effectFn The side-effect function, which receives a cleanup register function.
|
|
492
|
-
* @param options (Optional) Angular's `CreateEffectOptions`.
|
|
493
|
-
* @returns An `EffectRef` for the created effect.
|
|
494
|
-
*
|
|
495
|
-
* @example
|
|
496
|
-
* ```ts
|
|
497
|
-
* // Assume `coldGuard` changes rarely, but `hotSignal` changes often.
|
|
498
|
-
* const coldGuard = signal(false);
|
|
499
|
-
* const hotSignal = signal(0);
|
|
500
|
-
*
|
|
501
|
-
* nestedEffect(() => {
|
|
502
|
-
* // This outer effect only tracks `coldGuard`.
|
|
503
|
-
* if (coldGuard()) {
|
|
504
|
-
*
|
|
505
|
-
* // This inner effect is CREATED when coldGuard is true
|
|
506
|
-
* // and DESTROYED when it becomes false.
|
|
507
|
-
* nestedEffect(() => {
|
|
508
|
-
* // It only tracks `hotSignal` while it exists.
|
|
509
|
-
* console.log('Hot signal is:', hotSignal());
|
|
510
|
-
* });
|
|
511
|
-
* }
|
|
512
|
-
* // If `coldGuard` is false, this outer effect does not track `hotSignal`.
|
|
513
|
-
* });
|
|
514
|
-
* ```
|
|
515
|
-
* @example
|
|
516
|
-
* ```ts
|
|
517
|
-
* const users = signal([
|
|
518
|
-
* { id: 1, name: 'Alice' },
|
|
519
|
-
* { id: 2, name: 'Bob' }
|
|
520
|
-
* ]);
|
|
521
|
-
*
|
|
522
|
-
* // The fine-grained mapped list
|
|
523
|
-
* const mappedUsers = mapArray(
|
|
524
|
-
* users,
|
|
525
|
-
* (userSignal, index) => {
|
|
526
|
-
* // 1. Create a fine-grained SIDE EFFECT for *this item*
|
|
527
|
-
* // This effect's lifetime is now tied to this specific item. created once on init of this index.
|
|
528
|
-
* const effectRef = nestedEffect(() => {
|
|
529
|
-
* // This only runs if *this* userSignal changes,
|
|
530
|
-
* // not if the whole list changes.
|
|
531
|
-
* console.log(`User ${index} updated:`, userSignal().name);
|
|
532
|
-
* });
|
|
533
|
-
*
|
|
534
|
-
* // 2. Return the data AND the cleanup logic
|
|
535
|
-
* return {
|
|
536
|
-
* // The mapped data
|
|
537
|
-
* label: computed(() => `User: ${userSignal().name}`),
|
|
538
|
-
*
|
|
539
|
-
* // The cleanup function
|
|
540
|
-
* destroyEffect: () => effectRef.destroy()
|
|
541
|
-
* };
|
|
542
|
-
* },
|
|
543
|
-
* {
|
|
544
|
-
* // 3. Tell mapArray HOW to clean up when an item is removed, this needs to be manual as it's not a nestedEffect itself
|
|
545
|
-
* onDestroy: (mappedItem) => {
|
|
546
|
-
* mappedItem.destroyEffect();
|
|
547
|
-
* }
|
|
548
|
-
* }
|
|
549
|
-
* );
|
|
550
|
-
* ```
|
|
551
|
-
*/
|
|
552
|
-
declare function nestedEffect(effectFn: (registerCleanup: EffectCleanupRegisterFn) => void, options?: CreateEffectOptions & {
|
|
553
|
-
bindToFrame?: (parent: Frame | null) => Frame | null;
|
|
554
|
-
}): {
|
|
555
|
-
destroy: () => void;
|
|
556
|
-
};
|
|
557
|
-
|
|
558
578
|
/**
|
|
559
579
|
* A pure, synchronous transform from I -> O.
|
|
560
580
|
* Prefer transforms without side effects to keep derivations predictable.
|
|
@@ -1756,5 +1776,5 @@ type CreateHistoryOptions<T> = Omit<CreateSignalOptions<T[]>, 'equal'> & {
|
|
|
1756
1776
|
*/
|
|
1757
1777
|
declare function withHistory<T>(source: WritableSignal<T>, opt?: CreateHistoryOptions<T>): SignalWithHistory<T>;
|
|
1758
1778
|
|
|
1759
|
-
export { combineWith, debounce, debounced, derived, distinct, elementSize, elementVisibility, filter, indexArray, isDerivation, isMutable, keyArray, map, mapArray, mapObject, mediaQuery, mousePosition, mutable, mutableStore, nestedEffect, networkStatus, pageVisibility, pipeable, piped, prefersDarkMode, prefersReducedMotion, scrollPosition, select, sensor, sensors, store, stored, tabSync, tap, throttle, throttled, toFakeDerivation, toFakeSignalDerivation, toStore, toWritable, until, windowSize, withHistory };
|
|
1779
|
+
export { batch, combineWith, debounce, debounced, derived, distinct, elementSize, elementVisibility, filter, indexArray, isDerivation, isMutable, keyArray, map, mapArray, mapObject, mediaQuery, mousePosition, mutable, mutableStore, nestedEffect, networkStatus, pageVisibility, pipeable, piped, prefersDarkMode, prefersReducedMotion, renderEffect, scrollPosition, select, sensor, sensors, store, stored, tabSync, tap, throttle, throttled, toFakeDerivation, toFakeSignalDerivation, toStore, toWritable, until, windowSize, withHistory };
|
|
1760
1780
|
export type { CreateDebouncedOptions, CreateHistoryOptions, CreateStoredOptions, CreateThrottledOptions, DebouncedSignal, DerivedSignal, ElementSize, ElementSizeOptions, ElementSizeSignal, ElementVisibilityOptions, ElementVisibilitySignal, MousePositionOptions, MousePositionSignal, MutableSignal, MutableSignalStore, NetworkStatusSignal, PipeableSignal, ScrollPosition, ScrollPositionOptions, ScrollPositionSignal, SignalStore, SignalWithHistory, StoredSignal, ThrottledSignal, UntilOptions, WindowSize, WindowSizeOptions, WindowSizeSignal, WritableSignalStore };
|