@mmstack/primitives 22.1.1 → 22.2.0

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,11 +1,11 @@
1
1
  {
2
2
  "name": "@mmstack/primitives",
3
- "version": "22.1.1",
3
+ "version": "22.2.0",
4
4
  "keywords": [
5
5
  "angular",
6
6
  "signals",
7
7
  "debounce",
8
- "mapArray",
8
+ "indexArray",
9
9
  "primitives"
10
10
  ],
11
11
  "license": "MIT",
@@ -25,7 +25,7 @@ type CreateChunkedOptions<T> = {
25
25
  /**
26
26
  * Creates a new `Signal` that processes an array of items in time-sliced chunks. This is useful for handling large lists without blocking the main thread.
27
27
  *
28
- * The returned signal will initially contain the first `chunkSize` items from the source array. It will then schedule updates to include additional chunks of items based on the specified `duration`.
28
+ * The returned signal will initially contain the first `chunkSize` items from the source array. It will then schedule updates to include additional chunks of items based on the specified `delay`.
29
29
  *
30
30
  * @template T The type of items in the array.
31
31
  * @param source A `Signal` or a function that returns an array of items to be processed in chunks.
@@ -34,7 +34,7 @@ type CreateChunkedOptions<T> = {
34
34
  *
35
35
  * @example
36
36
  * const largeList = signal(Array.from({ length: 1000 }, (_, i) => i));
37
- * const chunkedList = chunked(largeList, { chunkSize: 100, duration: 100 });
37
+ * const chunkedList = chunked(largeList, { chunkSize: 100, delay: 100 });
38
38
  */
39
39
  declare function chunked<T>(source: Signal<T[]> | (() => T[]), options?: CreateChunkedOptions<T>): Signal<T[]>;
40
40
 
@@ -141,8 +141,9 @@ declare function pausableEffect(effectFn: (registerCleanup: EffectCleanupRegiste
141
141
  /**
142
142
  * Like `signal`, but pausable. While paused, READS hold the last value; writes still land on the
143
143
  * underlying signal and surface on resume. Built on the `keepPrevious`/`hold` shape — a
144
- * `linkedSignal` gated on the pause predicate, with `set`/`update`/`asReadonly` forwarded to the
145
- * source signal. With no `pause` option it defaults to the ambient `PAUSED_CONTEXT`; `pause: false`
144
+ * `linkedSignal` gated on the pause predicate, with `set`/`update` forwarded to the source signal.
145
+ * `asReadonly()` returns the held (gated) view, so both views of the signal agree while paused.
146
+ * With no `pause` option it defaults to the ambient `PAUSED_CONTEXT`; `pause: false`
146
147
  * makes it a plain `signal` — no `linkedSignal` is created.
147
148
  *
148
149
  * NOTE: while paused, `set(x)` followed by a read returns the *held* (pre-pause) value, not `x` — the
@@ -176,6 +177,11 @@ type TransitionRef = {
176
177
  *
177
178
  * Must be called in an injection context. This is the *async* generalization (Tier 2): it adds
178
179
  * no rendering cost and needs no fork — holding direct/sync readers is a separate, deferred tier.
180
+ *
181
+ * Caveat: work must go in flight by the first post-write render to be awaited. A loader that
182
+ * starts later (a debounced request signal, a chained/deferred resource) is not attributable to
183
+ * this transition — the no-async fallback will have already resolved `done`. Trigger such work
184
+ * eagerly inside `fn`, or coordinate it separately.
179
185
  */
180
186
  declare function injectStartTransition(): (fn: () => void) => TransitionRef;
181
187
 
@@ -244,6 +250,20 @@ declare function createTransitionScope(): TransitionScope;
244
250
  /** Provide a fresh transition scope at a boundary so its subtree's resources are tracked independently. */
245
251
  declare function provideTransitionScope(): Provider;
246
252
  declare function injectTransitionScope(): TransitionScope;
253
+ /**
254
+ * A transition scope that can be re-pointed at a delegate target at runtime. Reads and
255
+ * commit/hold follow the current target; `add`/`remove` pin to the target that was current
256
+ * at add-time, so re-pointing between a resource's registration and its destroy-time removal
257
+ * never strands it in the wrong scope. With no target it behaves as a plain own-scope.
258
+ */
259
+ type ForwardingTransitionScope = TransitionScope & {
260
+ setTarget(target: TransitionScope | null): void;
261
+ };
262
+ declare function createForwardingScope(): ForwardingTransitionScope;
263
+ /** Provide a forwarding transition scope at a boundary (used by the transition outlet). */
264
+ declare function provideForwardingTransitionScope(): Provider;
265
+ /** Read the transition scope reachable from `injector`, or null if none is provided there. */
266
+ declare function getTransitionScope(injector: Injector): TransitionScope | null;
247
267
  /**
248
268
  * Returns a register function bound to the nearest transition scope: it adds a resource
249
269
  * to the scope and removes it when the caller's injection context is destroyed. Pass any
@@ -331,6 +351,11 @@ type TransactionRef = {
331
351
  * The writes land on LIVE state immediately (so derived variables and connector requests see the
332
352
  * new values and refetch); only the *display* is held, via `scope.hold`. Must run in an injection
333
353
  * context.
354
+ *
355
+ * Caveat: work must go in flight by the first post-write render to be part of the transaction. A
356
+ * loader that starts later (a debounced request signal, a chained/deferred resource) is not
357
+ * attributable to it — the no-async fallback will have already committed and released the hold,
358
+ * after which `abort()` is a no-op. Trigger such work eagerly inside `fn`.
334
359
  */
335
360
  declare function injectStartTransaction(): (fn: () => void) => TransactionRef;
336
361
 
@@ -524,7 +549,7 @@ declare function mutable<T>(initial: T, opt?: CreateSignalOptions<T>): MutableSi
524
549
  * myMutableSignal.mutate(x => x + 1); // This is safe.
525
550
  * }
526
551
  */
527
- declare function isMutable<T = any>(value: WritableSignal<T>): value is MutableSignal<T>;
552
+ declare function isMutable<T = unknown>(value: WritableSignal<T>): value is MutableSignal<T>;
528
553
 
529
554
  /** @internal Narrows `'array'` so it is only assignable when `T` is an array type. */
530
555
  type VivifyArray<T> = T extends any[] ? 'array' : never;
@@ -818,7 +843,7 @@ type Frame = {
818
843
  * ]);
819
844
  *
820
845
  * // The fine-grained mapped list
821
- * const mappedUsers = mapArray(
846
+ * const mappedUsers = indexArray(
822
847
  * users,
823
848
  * (userSignal, index) => {
824
849
  * // 1. Create a fine-grained SIDE EFFECT for *this item*
@@ -839,7 +864,7 @@ type Frame = {
839
864
  * };
840
865
  * },
841
866
  * {
842
- * // 3. Tell mapArray HOW to clean up when an item is removed, this needs to be manual as it's not a nestedEffect itself
867
+ * // 3. Tell indexArray HOW to clean up when an item is removed, this needs to be manual as it's not a nestedEffect itself
843
868
  * onDestroy: (mappedItem) => {
844
869
  * mappedItem.destroyEffect();
845
870
  * }
@@ -1085,7 +1110,7 @@ type SignalPipe<In> = {
1085
1110
  * @see {@link SignalPipe}
1086
1111
  * @example
1087
1112
  * ```ts
1088
- * import { piped } from '@ngrx/signals';
1113
+ * import { piped } from '@mmstack/primitives';
1089
1114
  *
1090
1115
  * const count = piped(1);
1091
1116
  *
@@ -1248,7 +1273,7 @@ declare const scan: <T, R>(reducer: (acc: R, curr: T) => R, seed: R) => Operator
1248
1273
  */
1249
1274
  declare function pipeable<TSig extends Signal<any>>(signal: TSig): PipeableSignal<SignalValue<TSig>, TSig>;
1250
1275
  /**
1251
- * Create a new **writable** signal and return it as a `PipableSignal`.
1276
+ * Create a new **writable** signal and return it as a `PipeableSignal`.
1252
1277
  *
1253
1278
  * The returned value is a `WritableSignal<T>` with `.set`, `.update`, `.asReadonly`
1254
1279
  * still available (via intersection type), plus a chainable `.pipe(...)`.
@@ -1382,6 +1407,22 @@ declare function pooledSet<T extends Set<unknown>, U = T>(opt: CreateProvidedPoo
1382
1407
  declare function pooledMap<T extends Map<unknown, unknown>, U = T>(computation: Computation<T, U>, opt?: CreateSignalOptions<U>): Signal<U>;
1383
1408
  declare function pooledMap<T extends Map<unknown, unknown>, U = T>(opt: CreateProvidedPooledOptions<T, U>): Signal<U>;
1384
1409
 
1410
+ /**
1411
+ * Options shared by every sensor: an optional `debugName` for the produced signal(s) and an
1412
+ * optional `Injector` that lifts the injection-context requirement.
1413
+ */
1414
+ type SensorRunOptions = {
1415
+ /** Optional debug name for the produced signal(s). */
1416
+ debugName?: string;
1417
+ /**
1418
+ * Injector used to resolve the sensor's dependencies (`PLATFORM_ID`, `DestroyRef`, default
1419
+ * `ElementRef` targets, ...). Provide it when creating the sensor outside an injection
1420
+ * context — e.g. in `ngOnInit`, an event handler, or an effect body. When omitted, the
1421
+ * sensor must be created in an injection context (a constructor / field initializer).
1422
+ */
1423
+ injector?: Injector;
1424
+ };
1425
+
1385
1426
  type BatteryStatus = {
1386
1427
  readonly level: number;
1387
1428
  readonly charging: boolean;
@@ -1403,7 +1444,7 @@ type BatteryStatus = {
1403
1444
  * });
1404
1445
  * ```
1405
1446
  */
1406
- declare function batteryStatus(debugName?: string): Signal<BatteryStatus | null>;
1447
+ declare function batteryStatus(opt?: string | SensorRunOptions): Signal<BatteryStatus | null>;
1407
1448
 
1408
1449
  type ClipboardSignal = Signal<string> & {
1409
1450
  /**
@@ -1425,7 +1466,7 @@ type ClipboardSignal = Signal<string> & {
1425
1466
  * in browsers that gate it. Errors from `navigator.clipboard.readText` are
1426
1467
  * swallowed silently to keep the signal value stable.
1427
1468
  */
1428
- declare function clipboard(debugName?: string): ClipboardSignal;
1469
+ declare function clipboard(opt?: string | SensorRunOptions): ClipboardSignal;
1429
1470
 
1430
1471
  /**
1431
1472
  * Represents the size of an element.
@@ -1437,10 +1478,7 @@ interface ElementSize {
1437
1478
  /**
1438
1479
  * Options for configuring the `elementSize` sensor.
1439
1480
  */
1440
- type ElementSizeOptions = ResizeObserverOptions & {
1441
- /** Optional debug name for the internal signal. */
1442
- debugName?: string;
1443
- };
1481
+ type ElementSizeOptions = ResizeObserverOptions & SensorRunOptions;
1444
1482
  type ElementSizeSignal = Signal<ElementSize | undefined>;
1445
1483
  /**
1446
1484
  * Creates a read-only signal that tracks the size of a target DOM element.
@@ -1466,10 +1504,7 @@ declare function elementSize(target?: ElementRef<Element> | Element | Signal<Ele
1466
1504
  * Options for configuring the `elementVisibility` sensor, extending
1467
1505
  * standard `IntersectionObserverInit` options.
1468
1506
  */
1469
- type ElementVisibilityOptions = IntersectionObserverInit & {
1470
- /** Optional debug name for the internal signal. */
1471
- debugName?: string;
1472
- };
1507
+ type ElementVisibilityOptions = IntersectionObserverInit & SensorRunOptions;
1473
1508
  type ElementVisibilitySignal = Signal<IntersectionObserverEntry | undefined> & {
1474
1509
  readonly visible: Signal<boolean>;
1475
1510
  };
@@ -1546,17 +1581,15 @@ type FocusWithinTarget = ElementRef<Element> | Element | Signal<ElementRef<Eleme
1546
1581
  * }
1547
1582
  * ```
1548
1583
  */
1549
- declare function focusWithin(target?: FocusWithinTarget): Signal<boolean>;
1584
+ declare function focusWithin(target?: FocusWithinTarget, opt?: SensorRunOptions): Signal<boolean>;
1550
1585
 
1551
- type GeolocationOptions = PositionOptions & {
1586
+ type GeolocationOptions = PositionOptions & SensorRunOptions & {
1552
1587
  /**
1553
1588
  * If `true`, uses `navigator.geolocation.watchPosition` and updates the
1554
1589
  * signal continuously. Otherwise a single `getCurrentPosition` call is made.
1555
1590
  * @default false
1556
1591
  */
1557
1592
  watch?: boolean;
1558
- /** Optional debug name for the produced signal. */
1559
- debugName?: string;
1560
1593
  };
1561
1594
  type GeolocationSignal = Signal<GeolocationPosition | null> & {
1562
1595
  readonly error: Signal<GeolocationPositionError | null>;
@@ -1577,7 +1610,7 @@ type GeolocationSignal = Signal<GeolocationPosition | null> & {
1577
1610
  */
1578
1611
  declare function geolocation(opt?: GeolocationOptions): GeolocationSignal;
1579
1612
 
1580
- type IdleOptions = {
1613
+ type IdleOptions = SensorRunOptions & {
1581
1614
  /**
1582
1615
  * Milliseconds of user inactivity before the signal flips to `true`.
1583
1616
  * @default 60_000
@@ -1588,11 +1621,12 @@ type IdleOptions = {
1588
1621
  * @default ['mousemove','keydown','touchstart','scroll','visibilitychange']
1589
1622
  */
1590
1623
  events?: string[];
1591
- /** Optional debug name for the produced signal. */
1592
- debugName?: string;
1593
1624
  };
1594
1625
  type IdleSignal = Signal<boolean> & {
1595
- /** Timestamp of the last idle/active transition. */
1626
+ /**
1627
+ * Timestamp of the last idle/active transition. Before any transition has occurred it
1628
+ * holds the sensor's creation time, not an actual transition.
1629
+ */
1596
1630
  readonly since: Signal<Date>;
1597
1631
  };
1598
1632
  /**
@@ -1656,7 +1690,7 @@ declare function idle(opt?: IdleOptions): IdleSignal;
1656
1690
  * }
1657
1691
  * ```
1658
1692
  */
1659
- declare function mediaQuery(query: string, debugName?: string): Signal<boolean>;
1693
+ declare function mediaQuery(query: string, opt?: string | SensorRunOptions): Signal<boolean>;
1660
1694
  /**
1661
1695
  * Creates a read-only signal that tracks the user's OS/browser preference
1662
1696
  * for a dark color scheme using the `(prefers-color-scheme: dark)` media query.
@@ -1678,7 +1712,7 @@ declare function mediaQuery(query: string, debugName?: string): Signal<boolean>;
1678
1712
  * });
1679
1713
  * ```
1680
1714
  */
1681
- declare function prefersDarkMode(debugName?: string): Signal<boolean>;
1715
+ declare function prefersDarkMode(opt?: string | SensorRunOptions): Signal<boolean>;
1682
1716
  /**
1683
1717
  * Creates a read-only signal that tracks the user's OS/browser preference
1684
1718
  * for reduced motion using the `(prefers-reduced-motion: reduce)` media query.
@@ -1704,7 +1738,7 @@ declare function prefersDarkMode(debugName?: string): Signal<boolean>;
1704
1738
  * });
1705
1739
  * ```
1706
1740
  */
1707
- declare function prefersReducedMotion(debugName?: string): Signal<boolean>;
1741
+ declare function prefersReducedMotion(opt?: string | SensorRunOptions): Signal<boolean>;
1708
1742
 
1709
1743
  type MousePosition = {
1710
1744
  x: number;
@@ -1713,13 +1747,15 @@ type MousePosition = {
1713
1747
  /**
1714
1748
  * Options for configuring the `mousePosition` sensor.
1715
1749
  */
1716
- type MousePositionOptions = {
1750
+ type MousePositionOptions = SensorRunOptions & {
1717
1751
  /**
1718
1752
  * The target element to listen for mouse movements on.
1719
- * Can be `window`, `document`, an `HTMLElement`, or an `ElementRef<HTMLElement>`.
1753
+ * Can be `window`, `document`, an `HTMLElement`, an `ElementRef<HTMLElement>`, or a
1754
+ * `Signal` resolving to one (e.g. a `viewChild` result) — listeners re-attach when the
1755
+ * signal's element changes, and nothing is tracked while it is `null`/`undefined`.
1720
1756
  * @default window
1721
1757
  */
1722
- target?: Window | Document | HTMLElement | ElementRef<HTMLElement>;
1758
+ target?: Window | Document | HTMLElement | ElementRef<HTMLElement> | Signal<HTMLElement | ElementRef<HTMLElement> | null | undefined>;
1723
1759
  /**
1724
1760
  * Defines the coordinate system for the reported position.
1725
1761
  * - `'client'`: Coordinates relative to the viewport (`clientX`, `clientY`).
@@ -1733,10 +1769,6 @@ type MousePositionOptions = {
1733
1769
  * @default false
1734
1770
  */
1735
1771
  touch?: boolean;
1736
- /**
1737
- * Optional debug name for the internal signal.
1738
- */
1739
- debugName?: string;
1740
1772
  /**
1741
1773
  * Optional delay in milliseconds to throttle the updates.
1742
1774
  * @default 100
@@ -1790,7 +1822,10 @@ declare function mousePosition(opt?: MousePositionOptions): MousePositionSignal;
1790
1822
  * It's a boolean signal with an attached `since` signal.
1791
1823
  */
1792
1824
  type NetworkStatusSignal = Signal<boolean> & {
1793
- /** A signal tracking the timestamp of the last status change. */
1825
+ /**
1826
+ * A signal tracking the timestamp of the last status change. Before any change has
1827
+ * occurred it holds the sensor's creation time, not an actual transition.
1828
+ */
1794
1829
  readonly since: Signal<Date>;
1795
1830
  };
1796
1831
  /**
@@ -1800,7 +1835,8 @@ type NetworkStatusSignal = Signal<boolean> & {
1800
1835
  * An additional `since` signal is attached, tracking when the status last changed.
1801
1836
  * It's SSR-safe and automatically cleans up its event listeners.
1802
1837
  *
1803
- * @param debugName Optional debug name for the signal.
1838
+ * @param opt Optional debug name for the signal, or a {@link SensorRunOptions} object
1839
+ * (with an optional `injector` for creation outside an injection context).
1804
1840
  * @returns A `NetworkStatusSignal` instance.
1805
1841
  *
1806
1842
  * @example
@@ -1811,14 +1847,20 @@ type NetworkStatusSignal = Signal<boolean> & {
1811
1847
  * });
1812
1848
  * ```
1813
1849
  */
1814
- declare function networkStatus(debugName?: string): NetworkStatusSignal;
1850
+ declare function networkStatus(opt?: string | SensorRunOptions): NetworkStatusSignal;
1815
1851
 
1816
- type ScreenOrientation = {
1852
+ type ScreenOrientationState = {
1817
1853
  /** Angle in degrees relative to the natural orientation. */
1818
1854
  readonly angle: number;
1819
1855
  /** One of the four `OrientationType` strings. */
1820
1856
  readonly type: OrientationType;
1821
1857
  };
1858
+ /**
1859
+ * @deprecated Use {@link ScreenOrientationState} instead — this name shadows the DOM's global
1860
+ * `ScreenOrientation` interface in any module that imports it, silently changing the meaning of
1861
+ * `screen.orientation`-related typings there.
1862
+ */
1863
+ type ScreenOrientation = ScreenOrientationState;
1822
1864
  /**
1823
1865
  * Creates a read-only signal that tracks `screen.orientation`.
1824
1866
  *
@@ -1834,7 +1876,7 @@ type ScreenOrientation = {
1834
1876
  * });
1835
1877
  * ```
1836
1878
  */
1837
- declare function orientation(debugName?: string): Signal<ScreenOrientation>;
1879
+ declare function orientation(opt?: string | SensorRunOptions): Signal<ScreenOrientationState>;
1838
1880
 
1839
1881
  /**
1840
1882
  * Creates a read-only signal that tracks the page's visibility state.
@@ -1844,7 +1886,8 @@ declare function orientation(debugName?: string): Signal<ScreenOrientation>;
1844
1886
  * The primitive is SSR-safe and automatically cleans up its event listeners
1845
1887
  * when the creating context is destroyed.
1846
1888
  *
1847
- * @param debugName Optional debug name for the signal.
1889
+ * @param opt Optional debug name for the signal, or a {@link SensorRunOptions} object
1890
+ * (with an optional `injector` for creation outside an injection context).
1848
1891
  * @returns A read-only `Signal<DocumentVisibilityState>`. On the server,
1849
1892
  * it returns a static signal with a value of `'visible'`.
1850
1893
  *
@@ -1872,7 +1915,7 @@ declare function orientation(debugName?: string): Signal<ScreenOrientation>;
1872
1915
  * }
1873
1916
  * ```
1874
1917
  */
1875
- declare function pageVisibility(debugName?: string): Signal<DocumentVisibilityState>;
1918
+ declare function pageVisibility(opt?: string | SensorRunOptions): Signal<DocumentVisibilityState>;
1876
1919
 
1877
1920
  /**
1878
1921
  * Represents the scroll position.
@@ -1886,21 +1929,21 @@ type ScrollPosition = {
1886
1929
  /**
1887
1930
  * Options for configuring the `scrollPosition` sensor.
1888
1931
  */
1889
- type ScrollPositionOptions = {
1932
+ type ScrollPositionOptions = SensorRunOptions & {
1890
1933
  /**
1891
1934
  * The target to listen for scroll events on.
1892
- * Can be `window` (for page scroll) or an `HTMLElement`/`ElementRef<HTMLElement>`.
1935
+ * Can be `window` (for page scroll), an `HTMLElement`/`ElementRef<HTMLElement>`, or a
1936
+ * `Signal` resolving to one (e.g. a `viewChild` result) — listeners re-attach when the
1937
+ * signal's element changes, and nothing is tracked while it is `null`/`undefined`.
1893
1938
  * @default window
1894
1939
  */
1895
- target?: Window | HTMLElement | ElementRef<HTMLElement>;
1940
+ target?: Window | HTMLElement | ElementRef<HTMLElement> | Signal<HTMLElement | ElementRef<HTMLElement> | null | undefined>;
1896
1941
  /**
1897
1942
  * Optional delay in milliseconds to throttle the updates.
1898
1943
  * Scroll events can fire very rapidly.
1899
1944
  * @default 100 // A common default for scroll throttling
1900
1945
  */
1901
1946
  throttle?: number;
1902
- /** Optional debug name for the internal signal. */
1903
- debugName?: string;
1904
1947
  };
1905
1948
  /**
1906
1949
  * A specialized Signal that tracks scroll position.
@@ -1931,26 +1974,17 @@ type ScrollPositionSignal = Signal<ScrollPosition> & {
1931
1974
  * selector: 'app-scroll-tracker',
1932
1975
  * template: `
1933
1976
  * <p>Window Scroll: X: {{ windowScroll().x }}, Y: {{ windowScroll().y }}</p>
1934
- * <div #scrollableDiv style="height: 200px; width: 200px; overflow: auto; border: 1px solid black;">
1935
- * <div style="height: 400px; width: 400px;">Scroll me!</div>
1936
- * </div>
1937
- * @if (divScroll()) {
1938
- * <p>Div Scroll: X: {{ divScroll().x }}, Y: {{ divScroll().y }}</p>
1939
- * }
1977
+ * <p>Host Scroll: X: {{ hostScroll().x }}, Y: {{ hostScroll().y }}</p>
1940
1978
  * `
1941
1979
  * })
1942
1980
  * export class ScrollTrackerComponent {
1943
1981
  * readonly windowScroll = scrollPosition(); // Defaults to window
1982
+ * // Signal targets (e.g. viewChild) attach once the element exists:
1944
1983
  * readonly scrollableDiv = viewChild<ElementRef<HTMLDivElement>>('scrollableDiv');
1945
- * readonly divScroll = scrollPosition({ target: this.scrollableDiv() }); // Example with element target
1984
+ * readonly divScroll = scrollPosition({ target: this.scrollableDiv });
1946
1985
  *
1947
1986
  * constructor() {
1948
- * effect(() => {
1949
- * console.log('Window scrolled to:', this.windowScroll());
1950
- * if (this.divScroll()) {
1951
- * console.log('Div scrolled to:', this.divScroll());
1952
- * }
1953
- * });
1987
+ * effect(() => console.log('Window scrolled to:', this.windowScroll()));
1954
1988
  * }
1955
1989
  * }
1956
1990
  * ```
@@ -1967,13 +2001,9 @@ type WindowSize = {
1967
2001
  readonly height: number;
1968
2002
  };
1969
2003
  /**
1970
- * Options for configuring the `mousePosition` sensor.
2004
+ * Options for configuring the `windowSize` sensor.
1971
2005
  */
1972
- type WindowSizeOptions = {
1973
- /**
1974
- * Optional debug name for the internal signal.
1975
- */
1976
- debugName?: string;
2006
+ type WindowSizeOptions = SensorRunOptions & {
1977
2007
  /**
1978
2008
  * Optional delay in milliseconds to throttle the updates.
1979
2009
  * @default 100
@@ -2050,27 +2080,19 @@ type SensorTypedOptions = {
2050
2080
  returnType: MousePositionSignal;
2051
2081
  };
2052
2082
  networkStatus: {
2053
- opt: {
2054
- debugName?: string;
2055
- };
2083
+ opt: SensorRunOptions;
2056
2084
  returnType: NetworkStatusSignal;
2057
2085
  };
2058
2086
  pageVisibility: {
2059
- opt: {
2060
- debugName?: string;
2061
- };
2087
+ opt: SensorRunOptions;
2062
2088
  returnType: Signal<DocumentVisibilityState>;
2063
2089
  };
2064
2090
  darkMode: {
2065
- opt: {
2066
- debugName?: string;
2067
- };
2091
+ opt: SensorRunOptions;
2068
2092
  returnType: Signal<boolean>;
2069
2093
  };
2070
2094
  reducedMotion: {
2071
- opt: {
2072
- debugName?: string;
2073
- };
2095
+ opt: SensorRunOptions;
2074
2096
  returnType: Signal<boolean>;
2075
2097
  };
2076
2098
  scrollPosition: {
@@ -2082,9 +2104,8 @@ type SensorTypedOptions = {
2082
2104
  returnType: WindowSizeSignal;
2083
2105
  };
2084
2106
  mediaQuery: {
2085
- opt: {
2107
+ opt: SensorRunOptions & {
2086
2108
  query: string;
2087
- debugName?: string;
2088
2109
  };
2089
2110
  returnType: Signal<boolean>;
2090
2111
  };
@@ -2093,21 +2114,15 @@ type SensorTypedOptions = {
2093
2114
  returnType: GeolocationSignal;
2094
2115
  };
2095
2116
  clipboard: {
2096
- opt: {
2097
- debugName?: string;
2098
- };
2117
+ opt: SensorRunOptions;
2099
2118
  returnType: ClipboardSignal;
2100
2119
  };
2101
2120
  orientation: {
2102
- opt: {
2103
- debugName?: string;
2104
- };
2105
- returnType: Signal<ScreenOrientation>;
2121
+ opt: SensorRunOptions;
2122
+ returnType: Signal<ScreenOrientationState>;
2106
2123
  };
2107
2124
  batteryStatus: {
2108
- opt: {
2109
- debugName?: string;
2110
- };
2125
+ opt: SensorRunOptions;
2111
2126
  returnType: Signal<BatteryStatus | null>;
2112
2127
  };
2113
2128
  idle: {
@@ -2115,8 +2130,7 @@ type SensorTypedOptions = {
2115
2130
  returnType: IdleSignal;
2116
2131
  };
2117
2132
  focusWithin: {
2118
- opt: {
2119
- debugName?: string;
2133
+ opt: SensorRunOptions & {
2120
2134
  target?: ElementRef<Element> | Element | Signal<ElementRef<Element> | Element | null>;
2121
2135
  };
2122
2136
  returnType: Signal<boolean>;
@@ -2188,12 +2202,12 @@ declare function sensor(type: 'reducedMotion' | 'reduced-motion', options?: Sens
2188
2202
  /**
2189
2203
  * Creates a sensor signal that tracks the provided media query.
2190
2204
  * @param type Must be `'mediaQuery'`.
2191
- * @param options Optional configuration for the media query sensor, including `query` and `debugName`.
2205
+ * @param options Required configuration for the media query sensor `query` is mandatory, `debugName` optional.
2192
2206
  * @returns A `Signal<boolean>` which is `true` if the media query currently matches.
2193
2207
  * @see {mediaQuery} for detailed documentation and examples.
2194
2208
  * @example const isDesktop = sensor('mediaQuery', { query: '(min-width: 1024px)' });
2195
2209
  */
2196
- declare function sensor(type: 'mediaQuery', options?: SensorTypedOptions['mediaQuery']['opt']): Signal<boolean>;
2210
+ declare function sensor(type: 'mediaQuery', options: SensorTypedOptions['mediaQuery']['opt']): Signal<boolean>;
2197
2211
  /**
2198
2212
  * Creates a sensor signal that tracks the browser window's inner dimensions (width and height).
2199
2213
  * @param type Must be `'windowSize'`.
@@ -2226,7 +2240,7 @@ declare function sensor(type: 'clipboard', options?: SensorTypedOptions['clipboa
2226
2240
  * Creates a sensor signal tracking the screen orientation.
2227
2241
  * @see {orientation}
2228
2242
  */
2229
- declare function sensor(type: 'orientation', options?: SensorTypedOptions['orientation']['opt']): Signal<ScreenOrientation>;
2243
+ declare function sensor(type: 'orientation', options?: SensorTypedOptions['orientation']['opt']): Signal<ScreenOrientationState>;
2230
2244
  /**
2231
2245
  * Creates a sensor signal tracking the system battery status.
2232
2246
  * @see {batteryStatus}
@@ -2378,7 +2392,7 @@ type Opaque<T> = T & {
2378
2392
  readonly [OPAQUE]: true;
2379
2393
  };
2380
2394
  /** @internal Strips the opaque brand from the value a leaf signal carries. */
2381
- type UnwrapOpqaue<T> = T extends {
2395
+ type UnwrapOpaque<T> = T extends {
2382
2396
  readonly [OPAQUE]: true;
2383
2397
  } ? Omit<T, typeof OPAQUE> : T;
2384
2398
  type BaseType = string | number | boolean | symbol | bigint | undefined | null | Function | Date | RegExp | {
@@ -2450,15 +2464,15 @@ type MutableSignalStoreObject<T> = Simplify<Readonly<{
2450
2464
  <L extends AnyRecord>(props: L): MutableSignalStore<Simplify<Omit<NonNullable<T>, keyof L> & L>>;
2451
2465
  };
2452
2466
  }>;
2453
- type SignalStore<T> = Signal<UnwrapOpqaue<T>> & (IsAny<T> extends true ? SignalStoreObject<T> : NonNullable<T> extends BaseType ? {
2467
+ type SignalStore<T> = Signal<UnwrapOpaque<T>> & (IsAny<T> extends true ? SignalStoreObject<T> : NonNullable<T> extends BaseType ? {
2454
2468
  readonly [LEAF]: () => boolean;
2455
2469
  } : NonNullable<T> extends any[] ? SignalArrayStore<NonNullable<T>> : SignalStoreObject<T>);
2456
- type WritableSignalStore<T> = WritableSignal<UnwrapOpqaue<T>> & {
2470
+ type WritableSignalStore<T> = WritableSignal<UnwrapOpaque<T>> & {
2457
2471
  readonly asReadonlyStore: () => SignalStore<T>;
2458
2472
  } & (IsAny<T> extends true ? WritableSignalStoreObject<T> : NonNullable<T> extends BaseType ? {
2459
2473
  readonly [LEAF]: () => boolean;
2460
2474
  } : NonNullable<T> extends any[] ? WritableArrayStore<NonNullable<T>> : WritableSignalStoreObject<T>);
2461
- type MutableSignalStore<T> = MutableSignal<UnwrapOpqaue<T>> & {
2475
+ type MutableSignalStore<T> = MutableSignal<UnwrapOpaque<T>> & {
2462
2476
  readonly asReadonlyStore: () => SignalStore<T>;
2463
2477
  } & (IsAny<T> extends true ? MutableSignalStoreObject<T> : NonNullable<T> extends BaseType ? {
2464
2478
  readonly [LEAF]: () => boolean;
@@ -2692,8 +2706,8 @@ type StoredSignal<T> = WritableSignal<T> & {
2692
2706
  *
2693
2707
  * @template T The type of value held by the signal and stored (after serialization).
2694
2708
  * @param fallback The default value of type `T` to use when no value is found in storage
2695
- * or when deserialization fails. The signal's value will never be `null` or `undefined`
2696
- * publicly, it will always revert to this fallback.
2709
+ * or when deserialization fails. A stored value (including a legitimate `null` for a
2710
+ * nullable `T`) always round-trips; the fallback only surfaces when the entry is absent.
2697
2711
  * @param options Configuration options (`CreateStoredOptions<T>`). Requires at least the `key`.
2698
2712
  * @returns A `StoredSignal<T>` instance. This signal behaves like a standard `WritableSignal<T>`,
2699
2713
  * but its value is persisted. It includes a `.clear()` method to remove the item from storage
@@ -2706,7 +2720,8 @@ type StoredSignal<T> = WritableSignal<T> & {
2706
2720
  * - **Error Handling:** Catches and logs errors during serialization/deserialization in dev mode.
2707
2721
  * - **Tab Sync:** If `syncTabs` is true, listens to `storage` events to keep the signal value
2708
2722
  * consistent across browser tabs using the same key. Cleanup is handled automatically
2709
- * using `DestroyRef`.
2723
+ * using `DestroyRef`. Web Storage only: the `storage` event never fires for custom `store`
2724
+ * adapters, so `syncTabs` has no effect with one.
2710
2725
  * - **Removal:** Use the `.clear()` method on the returned signal to remove the item from storage.
2711
2726
  * Setting the signal to the fallback value will store the fallback value, not remove the item.
2712
2727
  *
@@ -2741,7 +2756,7 @@ type SyncSignalOptions = {
2741
2756
  id: string;
2742
2757
  };
2743
2758
  /**
2744
- * @example tabSync(signal('dark), {id: 'theme})
2759
+ * @example tabSync(signal('dark'), { id: 'theme' })
2745
2760
  */
2746
2761
  declare function tabSync<T extends WritableSignal<any>>(sig: T, opt: SyncSignalOptions | string): T;
2747
2762
  /**
@@ -2778,6 +2793,8 @@ type CreateThrottledOptions<T> = CreateSignalOptions<T> & {
2778
2793
  /**
2779
2794
  * If `true`, the throttled signal emits the latest pending value at the end
2780
2795
  * of each cooldown window (only when at least one write occurred during it).
2796
+ * Note: with both `leading` and `trailing` set to `false` the throttled view
2797
+ * never updates (writes still reach `.original`).
2781
2798
  * @default true
2782
2799
  */
2783
2800
  trailing?: boolean;
@@ -2868,6 +2885,10 @@ declare function toWritable<T>(source: Signal<T>, set: (value: T) => void, updat
2868
2885
  /**
2869
2886
  * If `true` (the default), the returned signal will be a computed signal that depends on the source signal.
2870
2887
  * If `false`, the returned signal will be a direct wrapper around the source signal without creating a new computed signal.
2888
+ *
2889
+ * CAUTION: with `pure: false` the `set`/`update`/`asReadonly` methods are patched directly
2890
+ * onto the signal object you passed in — every other holder of that signal sees it become
2891
+ * writable. Only use it with a signal you created and own exclusively.
2871
2892
  * @default true
2872
2893
  */
2873
2894
  pure?: boolean;
@@ -3023,5 +3044,5 @@ type CreateHistoryOptions<T> = Omit<CreateSignalOptions<T[]>, 'equal'> & {
3023
3044
  */
3024
3045
  declare function withHistory<T>(sourceOrValue: WritableSignal<T> | T, opt?: CreateHistoryOptions<T>): SignalWithHistory<T>;
3025
3046
 
3026
- export { MmActivity, SuspenseBoundary, SuspenseBoundaryBase, UnscopedSuspenseBoundary, activeTransaction, batteryStatus, chunked, clipboard, combineWith, createTransaction, createTransitionScope, debounce, debounced, derived, distinct, elementSize, elementVisibility, filter, filterWith, focusWithin, forkStore, geolocation, holdUntilReady, idle, indexArray, injectPaused, injectRegisterResource, injectStartTransaction, injectStartTransition, injectTransitionScope, isDerivation, isLeaf, isMutable, isOpaque, isStore, keepPrevious, keyArray, map, mapArray, mapObject, mediaQuery, merge3, mousePosition, mutable, mutableStore, nestedEffect, networkStatus, opaque, orientation, pageVisibility, pairwise, pausableComputed, pausableEffect, pausableSignal, pipeable, piped, pooled, pooledArray, pooledMap, pooledSet, prefersDarkMode, prefersReducedMotion, providePaused, provideTransitionScope, registerResource, resolvePause, scan, scrollPosition, select, sensor, sensors, signalFromEvent, startWith, store, stored, tabSync, tap, throttle, throttled, toFakeDerivation, toFakeSignalDerivation, toStore, toWritable, until, windowSize, withHistory };
3027
- export type { BatteryStatus, ClipboardSignal, Computation, CreateChunkedOptions, CreateDebouncedOptions, CreateHistoryOptions, CreatePooledOptions, CreateProvidedPooledOptions, CreateStoredOptions, CreateThrottledOptions, DebouncedSignal, DerivedSignal, ElementSize, ElementSizeOptions, ElementSizeSignal, ElementVisibilityOptions, ElementVisibilitySignal, Fork, ForkStrategy, GeolocationOptions, GeolocationSignal, IdleOptions, IdleSignal, MousePositionOptions, MousePositionSignal, MutableSignal, MutableSignalStore, NetworkStatusSignal, Opaque, PausableOptions, PauseOption, PipeableSignal, ReconcileFn, RegisterOptions, ScreenOrientation, ScrollPosition, ScrollPositionOptions, ScrollPositionSignal, SignalFromEventOptions, SignalStore, SignalWithHistory, StoredSignal, SuspendType, ThrottledSignal, Transaction, TransactionRef, TransitionRef, TransitionScope, UntilOptions, Vivify, WindowSize, WindowSizeOptions, WindowSizeSignal, WithVivify, WritableSignalStore };
3047
+ export { MmActivity, SuspenseBoundary, SuspenseBoundaryBase, UnscopedSuspenseBoundary, activeTransaction, batteryStatus, chunked, clipboard, combineWith, createForwardingScope, createTransaction, createTransitionScope, debounce, debounced, derived, distinct, elementSize, elementVisibility, filter, filterWith, focusWithin, forkStore, geolocation, getTransitionScope, holdUntilReady, idle, indexArray, injectPaused, injectRegisterResource, injectStartTransaction, injectStartTransition, injectTransitionScope, isDerivation, isLeaf, isMutable, isOpaque, isStore, keepPrevious, keyArray, map, mapArray, mapObject, mediaQuery, merge3, mousePosition, mutable, mutableStore, nestedEffect, networkStatus, opaque, orientation, pageVisibility, pairwise, pausableComputed, pausableEffect, pausableSignal, pipeable, piped, pooled, pooledArray, pooledMap, pooledSet, prefersDarkMode, prefersReducedMotion, provideForwardingTransitionScope, providePaused, provideTransitionScope, registerResource, resolvePause, scan, scrollPosition, select, sensor, sensors, signalFromEvent, startWith, store, stored, tabSync, tap, throttle, throttled, toFakeDerivation, toFakeSignalDerivation, toStore, toWritable, until, windowSize, withHistory };
3048
+ export type { BatteryStatus, ClipboardSignal, Computation, CreateChunkedOptions, CreateDebouncedOptions, CreateHistoryOptions, CreatePooledOptions, CreateProvidedPooledOptions, CreateStoredOptions, CreateThrottledOptions, DebouncedSignal, DerivedSignal, ElementSize, ElementSizeOptions, ElementSizeSignal, ElementVisibilityOptions, ElementVisibilitySignal, Fork, ForkStrategy, ForwardingTransitionScope, Frame, GeolocationOptions, GeolocationSignal, IdleOptions, IdleSignal, MousePositionOptions, MousePositionSignal, MutableSignal, MutableSignalStore, NetworkStatusSignal, Opaque, PausableOptions, PauseOption, PipeableSignal, ReconcileFn, RegisterOptions, ScreenOrientation, ScreenOrientationState, ScrollPosition, ScrollPositionOptions, ScrollPositionSignal, SensorRunOptions, SignalFromEventOptions, SignalStore, SignalWithHistory, StoredSignal, SuspendType, ThrottledSignal, Transaction, TransactionRef, TransitionRef, TransitionScope, UntilOptions, Vivify, WindowSize, WindowSizeOptions, WindowSizeSignal, WithVivify, WritableSignalStore };