@mmstack/primitives 20.4.3 → 20.4.5

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/index.d.ts CHANGED
@@ -468,6 +468,102 @@ declare function mapArray<T, U>(source: Signal<T[]> | (() => T[]), map: (value:
468
468
  onDestroy?: (value: U) => void;
469
469
  }): Signal<U[]>;
470
470
 
471
+ /**
472
+ * A pure, synchronous transform from I -> O.
473
+ * Prefer transforms without side effects to keep derivations predictable.
474
+ */
475
+ type UnaryFunction<I, O> = (a: I) => O;
476
+ /** An Operator transforms a source Signal<I> into a derived Signal<O>. */
477
+ type Operator<I, O> = (src: Signal<I>) => Signal<O>;
478
+ type SignalMap<In> = {
479
+ (): PipeableSignal<In>;
480
+ <A>(fn1: UnaryFunction<In, A>, opt?: CreateSignalOptions<A>): PipeableSignal<A>;
481
+ <A, B>(fn1: UnaryFunction<In, A>, fn2: UnaryFunction<A, B>, opt?: CreateSignalOptions<B>): PipeableSignal<B>;
482
+ <A, B, C>(fn1: UnaryFunction<In, A>, fn2: UnaryFunction<A, B>, fn3: UnaryFunction<B, C>, opt?: CreateSignalOptions<C>): PipeableSignal<C>;
483
+ <A, B, C, D>(fn1: UnaryFunction<In, A>, fn2: UnaryFunction<A, B>, fn3: UnaryFunction<B, C>, fn4: UnaryFunction<C, D>, opt?: CreateSignalOptions<D>): PipeableSignal<D>;
484
+ <A, B, C, D, E>(fn1: UnaryFunction<In, A>, fn2: UnaryFunction<A, B>, fn3: UnaryFunction<B, C>, fn4: UnaryFunction<C, D>, fn5: UnaryFunction<D, E>, opt?: CreateSignalOptions<E>): PipeableSignal<E>;
485
+ <A, B, C, D, E, F>(fn1: UnaryFunction<In, A>, fn2: UnaryFunction<A, B>, fn3: UnaryFunction<B, C>, fn4: UnaryFunction<C, D>, fn5: UnaryFunction<D, E>, fn6: UnaryFunction<E, F>, opt?: CreateSignalOptions<F>): PipeableSignal<F>;
486
+ <A, B, C, D, E, F, G>(fn1: UnaryFunction<In, A>, fn2: UnaryFunction<A, B>, fn3: UnaryFunction<B, C>, fn4: UnaryFunction<C, D>, fn5: UnaryFunction<D, E>, fn6: UnaryFunction<E, F>, fn7: UnaryFunction<F, G>, opt?: CreateSignalOptions<G>): PipeableSignal<G>;
487
+ <A, B, C, D, E, F, G, H>(fn1: UnaryFunction<In, A>, fn2: UnaryFunction<A, B>, fn3: UnaryFunction<B, C>, fn4: UnaryFunction<C, D>, fn5: UnaryFunction<D, E>, fn6: UnaryFunction<E, F>, fn7: UnaryFunction<F, G>, fn8: UnaryFunction<G, H>, opt?: CreateSignalOptions<H>): PipeableSignal<H>;
488
+ <A, B, C, D, E, F, G, H, I>(fn1: UnaryFunction<In, A>, fn2: UnaryFunction<A, B>, fn3: UnaryFunction<B, C>, fn4: UnaryFunction<C, D>, fn5: UnaryFunction<D, E>, fn6: UnaryFunction<E, F>, fn7: UnaryFunction<F, G>, fn8: UnaryFunction<G, H>, fn9: UnaryFunction<H, I>, ...rest: UnaryFunction<any, any>[]): PipeableSignal<unknown>;
489
+ };
490
+ /** `.pipe(...)` — compose operators (Signal -> Signal). */
491
+ type SignalPipe<In> = {
492
+ (): PipeableSignal<In>;
493
+ <A>(op1: Operator<In, A>): PipeableSignal<A>;
494
+ <A, B>(op1: Operator<In, A>, op2: Operator<A, B>): PipeableSignal<B>;
495
+ <A, B, C>(op1: Operator<In, A>, op2: Operator<A, B>, op3: Operator<B, C>): PipeableSignal<C>;
496
+ <A, B, C, D>(op1: Operator<In, A>, op2: Operator<A, B>, op3: Operator<B, C>, op4: Operator<C, D>): PipeableSignal<D>;
497
+ <A, B, C, D, E>(op1: Operator<In, A>, op2: Operator<A, B>, op3: Operator<B, C>, op4: Operator<C, D>, op5: Operator<D, E>): PipeableSignal<E>;
498
+ <A, B, C, D, E, F>(op1: Operator<In, A>, op2: Operator<A, B>, op3: Operator<B, C>, op4: Operator<C, D>, op5: Operator<D, E>, op6: Operator<E, F>): PipeableSignal<F>;
499
+ <A, B, C, D, E, F, G>(op1: Operator<In, A>, op2: Operator<A, B>, op3: Operator<B, C>, op4: Operator<C, D>, op5: Operator<D, E>, op6: Operator<E, F>, op7: Operator<F, G>): PipeableSignal<G>;
500
+ <A, B, C, D, E, F, G, H>(op1: Operator<In, A>, op2: Operator<A, B>, op3: Operator<B, C>, op4: Operator<C, D>, op5: Operator<D, E>, op6: Operator<E, F>, op7: Operator<F, G>, op8: Operator<G, H>): PipeableSignal<H>;
501
+ <A, B, C, D, E, F, G, H, I>(op1: Operator<In, A>, op2: Operator<A, B>, op3: Operator<B, C>, op4: Operator<C, D>, op5: Operator<D, E>, op6: Operator<E, F>, op7: Operator<F, G>, op8: Operator<G, H>, op9: Operator<H, I>, ...rest: Operator<any, any>[]): PipeableSignal<unknown>;
502
+ };
503
+ /**
504
+ * A `Signal<T>` augmented with a chainable `.pipe(...)` method.
505
+ *
506
+ * The `.pipe(...)` returns **computed** signals wrapped with the same method,
507
+ * allowing fluent, strongly-typed pipelines.
508
+ * @see {@link SignalPipe}
509
+ * @example
510
+ * ```ts
511
+ * import { piped } from '@ngrx/signals';
512
+ *
513
+ * const count = piped(1);
514
+ *
515
+ * const doubled = count.pipe(x => x * 2); // PipeableSignal<number>
516
+ * // doubled() === 2
517
+ * const toString = doubled.pipe(String); // PipeableSignal<string>
518
+ * // toString() === '2'
519
+ * ```
520
+ */
521
+ type PipeableSignal<T, TSig extends Signal<T> = Signal<T>> = TSig & {
522
+ pipe: SignalPipe<T>;
523
+ /** Chain pure transforms to derive new signals. See {@link SignalMap}. */
524
+ map: SignalMap<T>;
525
+ };
526
+ /**
527
+ * Helper type to infer the value type of a signal.
528
+ * @internal
529
+ */
530
+ type SignalValue<TSig extends Signal<any>> = TSig extends Signal<infer V> ? V : never;
531
+
532
+ /** Project with optional equality. Pure & sync. */
533
+ declare const select: <I, O>(projector: (v: I) => O, opt?: CreateSignalOptions<O>) => Operator<I, O>;
534
+ /** Combine with another signal using a projector. */
535
+ declare const combineWith: <A, B, R>(other: Signal<B>, project: (a: A, b: B) => R, opt?: CreateSignalOptions<R>) => Operator<A, R>;
536
+ /** Only re-emit when equal(prev, next) is false. */
537
+ declare const distinct: <T>(equal?: (a: T, b: T) => boolean) => Operator<T, T>;
538
+ /** map to new value */
539
+ declare const map: <I, O>(fn: (v: I) => O) => Operator<I, O>;
540
+ /** filter values, keeping the last value if it was ever available, if first value is filtered will return undefined */
541
+ declare const filter: <T>(predicate: (v: T) => boolean) => Operator<T, T | undefined>;
542
+ /** tap into the value */
543
+ declare const tap: <T>(fn: (v: T) => void) => Operator<T, T>;
544
+
545
+ /**
546
+ * Decorate any `Signal<T>` with a chainable `.pipe(...)` method.
547
+ *
548
+ * @example
549
+ * const s = pipeable(signal(1)); // WritableSignal<number> (+ pipe)
550
+ * const label = s.pipe(n => n * 2, n => `#${n}`); // Signal<string> (+ pipe)
551
+ * label(); // "#2"
552
+ */
553
+ declare function pipeable<TSig extends Signal<any>>(signal: TSig): PipeableSignal<SignalValue<TSig>, TSig>;
554
+ /**
555
+ * Create a new **writable** signal and return it as a `PipableSignal`.
556
+ *
557
+ * The returned value is a `WritableSignal<T>` with `.set`, `.update`, `.asReadonly`
558
+ * still available (via intersection type), plus a chainable `.pipe(...)`.
559
+ *
560
+ * @example
561
+ * const count = piped(1); // WritableSignal<number> (+ pipe)
562
+ * const even = count.pipe(n => n % 2 === 0); // Signal<boolean> (+ pipe)
563
+ * count.update(n => n + 1);
564
+ */
565
+ declare function piped<T>(initial: T, opt?: CreateSignalOptions<T>): PipeableSignal<T, WritableSignal<T>>;
566
+
471
567
  /**
472
568
  * Creates a read-only signal that reactively tracks whether a CSS media query
473
569
  * string currently matches.
@@ -1064,6 +1160,48 @@ type StoredSignal<T> = WritableSignal<T> & {
1064
1160
  */
1065
1161
  declare function stored<T>(fallback: T, { key, store: providedStore, serialize, deserialize, syncTabs, equal, onKeyChange, cleanupOldKey, ...rest }: CreateStoredOptions<T>): StoredSignal<T>;
1066
1162
 
1163
+ type SyncSignalOptions = {
1164
+ id?: string;
1165
+ };
1166
+ /**
1167
+ * Synchronizes a WritableSignal across browser tabs using BroadcastChannel API.
1168
+ *
1169
+ * Creates a shared signal that automatically syncs its value between all tabs
1170
+ * of the same application. When the signal is updated in one tab, all other
1171
+ * tabs will receive the new value automatically.
1172
+ *
1173
+ * @template T - The type of the WritableSignal
1174
+ * @param sig - The WritableSignal to synchronize across tabs
1175
+ * @param opt - Optional configuration object
1176
+ * @param opt.id - Explicit channel ID for synchronization. If not provided,
1177
+ * a deterministic ID is generated based on the call site.
1178
+ * Use explicit IDs in production for reliability.
1179
+ *
1180
+ * @returns The same WritableSignal instance, now synchronized across tabs
1181
+ *
1182
+ * @throws {Error} When deterministic ID generation fails and no explicit ID is provided
1183
+ *
1184
+ * @example
1185
+ * ```typescript
1186
+ * // Basic usage - auto-generates channel ID from call site
1187
+ * const theme = tabSync(signal('dark'));
1188
+ *
1189
+ * // With explicit ID (recommended for production)
1190
+ * const userPrefs = tabSync(signal({ lang: 'en' }), { id: 'user-preferences' });
1191
+ *
1192
+ * // Changes in one tab will sync to all other tabs
1193
+ * theme.set('light'); // All tabs will update to 'light'
1194
+ * ```
1195
+ *
1196
+ * @remarks
1197
+ * - Only works in browser environments (returns original signal on server)
1198
+ * - Uses a single BroadcastChannel for all synchronized signals
1199
+ * - Automatically cleans up listeners when the injection context is destroyed
1200
+ * - Initial signal value after sync setup is not broadcasted to prevent loops
1201
+ *
1202
+ */
1203
+ declare function tabSync<T extends WritableSignal<any>>(sig: T, opt?: SyncSignalOptions): T;
1204
+
1067
1205
  /**
1068
1206
  * Options for creating a throttled writable signal.
1069
1207
  * Extends Angular's `CreateSignalOptions` with a throttle time setting.
@@ -1318,5 +1456,5 @@ type CreateHistoryOptions<T> = Omit<CreateSignalOptions<T[]>, 'equal'> & {
1318
1456
  */
1319
1457
  declare function withHistory<T>(source: WritableSignal<T>, opt?: CreateHistoryOptions<T>): SignalWithHistory<T>;
1320
1458
 
1321
- export { debounce, debounced, derived, elementVisibility, isDerivation, isMutable, mapArray, mediaQuery, mousePosition, mutable, networkStatus, pageVisibility, prefersDarkMode, prefersReducedMotion, scrollPosition, sensor, stored, throttle, throttled, toFakeDerivation, toFakeSignalDerivation, toWritable, until, windowSize, withHistory };
1322
- export type { CreateDebouncedOptions, CreateHistoryOptions, CreateStoredOptions, CreateThrottledOptions, DebouncedSignal, DerivedSignal, ElementVisibilityOptions, ElementVisibilitySignal, MousePositionOptions, MousePositionSignal, MutableSignal, NetworkStatusSignal, ScrollPosition, ScrollPositionOptions, ScrollPositionSignal, SignalWithHistory, StoredSignal, ThrottledSignal, UntilOptions, WindowSize, WindowSizeOptions, WindowSizeSignal };
1459
+ export { combineWith, debounce, debounced, derived, distinct, elementVisibility, filter, isDerivation, isMutable, map, mapArray, mediaQuery, mousePosition, mutable, networkStatus, pageVisibility, pipeable, piped, prefersDarkMode, prefersReducedMotion, scrollPosition, select, sensor, stored, tabSync, tap, throttle, throttled, toFakeDerivation, toFakeSignalDerivation, toWritable, until, windowSize, withHistory };
1460
+ export type { CreateDebouncedOptions, CreateHistoryOptions, CreateStoredOptions, CreateThrottledOptions, DebouncedSignal, DerivedSignal, ElementVisibilityOptions, ElementVisibilitySignal, MousePositionOptions, MousePositionSignal, MutableSignal, NetworkStatusSignal, PipeableSignal, ScrollPosition, ScrollPositionOptions, ScrollPositionSignal, SignalWithHistory, StoredSignal, ThrottledSignal, UntilOptions, WindowSize, WindowSizeOptions, WindowSizeSignal };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mmstack/primitives",
3
- "version": "20.4.3",
3
+ "version": "20.4.5",
4
4
  "keywords": [
5
5
  "angular",
6
6
  "signals",