@mmstack/primitives 19.2.2 → 19.3.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/LICENSE +21 -21
- package/README.md +1038 -619
- package/fesm2022/mmstack-primitives.mjs +1176 -201
- package/fesm2022/mmstack-primitives.mjs.map +1 -1
- package/index.d.ts +6 -2
- package/lib/chunked.d.ts +36 -0
- package/lib/derived.d.ts +51 -2
- package/lib/effect/frame-stack.d.ts +10 -0
- package/lib/effect/index.d.ts +1 -0
- package/lib/effect/nested-effect.d.ts +77 -0
- package/lib/get-signal-equality.d.ts +1 -1
- package/lib/mappers/index-array.d.ts +54 -0
- package/lib/mappers/index.d.ts +3 -0
- package/lib/mappers/key-array.d.ts +28 -0
- package/lib/mappers/map-object.d.ts +15 -0
- package/lib/mappers/util.d.ts +9 -0
- package/lib/pipeable/operators.d.ts +14 -0
- package/lib/pipeable/pipeble.d.ts +23 -0
- package/lib/pipeable/public_api.d.ts +3 -0
- package/lib/pipeable/types.d.ts +62 -0
- package/lib/sensors/element-size.d.ts +35 -0
- package/lib/{element-visibility.d.ts → sensors/element-visibility.d.ts} +2 -2
- package/lib/sensors/index.d.ts +2 -0
- package/lib/sensors/media-query.d.ts +1 -1
- package/lib/sensors/mouse-position.d.ts +1 -1
- package/lib/sensors/network-status.d.ts +1 -1
- package/lib/sensors/page-visibility.d.ts +1 -1
- package/lib/sensors/sensor.d.ts +108 -22
- package/lib/sensors/window-size.d.ts +1 -1
- package/lib/store.d.ts +58 -0
- package/lib/stored.d.ts +6 -2
- package/lib/tabSync.d.ts +56 -0
- package/lib/throttled.d.ts +1 -1
- package/lib/to-writable.d.ts +9 -2
- package/lib/until.d.ts +28 -23
- package/package.json +6 -7
- package/lib/map-array.d.ts +0 -61
package/index.d.ts
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
|
+
export * from './lib/chunked';
|
|
1
2
|
export * from './lib/debounced';
|
|
2
3
|
export * from './lib/derived';
|
|
3
|
-
export
|
|
4
|
-
export * from './lib/
|
|
4
|
+
export { nestedEffect } from './lib/effect';
|
|
5
|
+
export * from './lib/mappers';
|
|
5
6
|
export * from './lib/mutable';
|
|
7
|
+
export * from './lib/pipeable/public_api';
|
|
6
8
|
export * from './lib/sensors';
|
|
9
|
+
export * from './lib/store';
|
|
7
10
|
export * from './lib/stored';
|
|
11
|
+
export { tabSync } from './lib/tabSync';
|
|
8
12
|
export * from './lib/throttled';
|
|
9
13
|
export * from './lib/to-writable';
|
|
10
14
|
export * from './lib/until';
|
package/lib/chunked.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { type Injector, type Signal, type ValueEqualityFn } from '@angular/core';
|
|
2
|
+
export type CreateChunkedOptions<T> = {
|
|
3
|
+
/**
|
|
4
|
+
* The number of items to process in each chunk.
|
|
5
|
+
* @default 50
|
|
6
|
+
*/
|
|
7
|
+
chunkSize?: number;
|
|
8
|
+
/**
|
|
9
|
+
* The delay between processing each chunk. Can be a number (milliseconds) or 'frame' to use `requestAnimationFrame`.
|
|
10
|
+
* @default 'frame'
|
|
11
|
+
*/
|
|
12
|
+
delay?: number | 'frame' | 'microtask';
|
|
13
|
+
/**
|
|
14
|
+
* A custom equality function to determine if the processed chunk has changed. This can help prevent unnecessary updates if the chunk content is the same as the previous one.
|
|
15
|
+
*/
|
|
16
|
+
equal?: ValueEqualityFn<T[]>;
|
|
17
|
+
/**
|
|
18
|
+
* An optional `Injector` to use for the internal effect. This allows the effect to have access to dependency injection if needed.
|
|
19
|
+
*/
|
|
20
|
+
injector?: Injector;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* 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.
|
|
24
|
+
*
|
|
25
|
+
* 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`.
|
|
26
|
+
*
|
|
27
|
+
* @template T The type of items in the array.
|
|
28
|
+
* @param source A `Signal` or a function that returns an array of items to be processed in chunks.
|
|
29
|
+
* @param options Configuration options for chunk size, delay duration, equality function, and injector.
|
|
30
|
+
* @returns A `Signal` that emits the current chunk of items being processed.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* const largeList = signal(Array.from({ length: 1000 }, (_, i) => i));
|
|
34
|
+
* const chunkedList = chunked(largeList, { chunkSize: 100, duration: 100 });
|
|
35
|
+
*/
|
|
36
|
+
export declare function chunked<T>(source: Signal<T[]> | (() => T[]), options?: CreateChunkedOptions<T>): Signal<T[]>;
|
package/lib/derived.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { CreateSignalOptions, type WritableSignal } from '@angular/core';
|
|
2
|
-
import type
|
|
1
|
+
import { type CreateSignalOptions, type WritableSignal } from '@angular/core';
|
|
2
|
+
import { type MutableSignal } from './mutable';
|
|
3
|
+
type UnknownObject = Record<PropertyKey, unknown>;
|
|
3
4
|
/**
|
|
4
5
|
* Options for creating a derived signal using the full `derived` function signature.
|
|
5
6
|
* @typeParam T - The type of the source signal's value (parent).
|
|
@@ -54,6 +55,31 @@ export type DerivedSignal<T, U> = WritableSignal<U> & {
|
|
|
54
55
|
* ```
|
|
55
56
|
*/
|
|
56
57
|
export declare function derived<T, U>(source: WritableSignal<T>, opt: CreateDerivedOptions<T, U>): DerivedSignal<T, U>;
|
|
58
|
+
/**
|
|
59
|
+
* Creates a `DerivedSignal` that derives a property from an object held by the source signal.
|
|
60
|
+
* This overload is a convenient shorthand for accessing object properties.
|
|
61
|
+
*
|
|
62
|
+
* @typeParam T The type of the source signal's value (must be an object).
|
|
63
|
+
* @typeParam TKey The key of the property to derive.
|
|
64
|
+
* @param source The source `WritableSignal` (holding an object).
|
|
65
|
+
* @param key The key of the property to derive.
|
|
66
|
+
* @param options Optional signal options for the derived signal.
|
|
67
|
+
* @returns A `DerivedSignal` instance.
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```ts
|
|
71
|
+
* const user = signal({ name: 'John', age: 30 });
|
|
72
|
+
* const name = derived(user, 'name');
|
|
73
|
+
*
|
|
74
|
+
* console.log(name()); // Outputs: John
|
|
75
|
+
*
|
|
76
|
+
* // Update the derived signal, which also updates the source
|
|
77
|
+
* name.set('Jane');
|
|
78
|
+
*
|
|
79
|
+
* console.log(user().name); // Outputs: Jane
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
export declare function derived<T extends UnknownObject, TKey extends keyof T>(source: MutableSignal<T>, key: TKey, opt?: CreateSignalOptions<T[TKey]>): DerivedSignal<T, T[TKey]> & MutableSignal<T[TKey]>;
|
|
57
83
|
/**
|
|
58
84
|
* Creates a `DerivedSignal` that derives a property from an object held by the source signal.
|
|
59
85
|
* This overload is a convenient shorthand for accessing object properties.
|
|
@@ -79,6 +105,29 @@ export declare function derived<T, U>(source: WritableSignal<T>, opt: CreateDeri
|
|
|
79
105
|
* ```
|
|
80
106
|
*/
|
|
81
107
|
export declare function derived<T extends UnknownObject, TKey extends keyof T>(source: WritableSignal<T>, key: TKey, opt?: CreateSignalOptions<T[TKey]>): DerivedSignal<T, T[TKey]>;
|
|
108
|
+
/**
|
|
109
|
+
* Creates a `DerivedSignal` that derives its value from another `MutableSignal`.
|
|
110
|
+
* Use mutuable signals with caution, but very useful for deeply nested structures.
|
|
111
|
+
*
|
|
112
|
+
* @typeParam T The type of the source signal's value.
|
|
113
|
+
* @typeParam U The type of the derived signal's value.
|
|
114
|
+
* @param source The source `WritableSignal`.
|
|
115
|
+
* @param options An object containing the `from` and `onChange` functions, and optional signal options.
|
|
116
|
+
* @returns A `DerivedSignal & MutableSignal` instance.
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* ```ts
|
|
120
|
+
* const user = signal({ name: 'John', age: 30 });
|
|
121
|
+
* const name = derived(user, {
|
|
122
|
+
* from: (u) => u.name,
|
|
123
|
+
* onChange: (newName) => user.update((u) => ({ ...u, name: newName })),
|
|
124
|
+
* });
|
|
125
|
+
*
|
|
126
|
+
* name.set('Jane'); // Updates the original signal
|
|
127
|
+
* console.log(user().name); // Outputs: Jane
|
|
128
|
+
* ```
|
|
129
|
+
*/
|
|
130
|
+
export declare function derived<T, U>(source: MutableSignal<T>, optOrKey: CreateDerivedOptions<T, U> | keyof T, opt?: CreateSignalOptions<U>): DerivedSignal<T, U> & MutableSignal<U>;
|
|
82
131
|
/**
|
|
83
132
|
* Creates a `DerivedSignal` from an array, deriving an element by its index.
|
|
84
133
|
* This overload is a convenient shorthand for accessing array elements.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type EffectRef, type Injector } from '@angular/core';
|
|
2
|
+
export type Frame = {
|
|
3
|
+
injector: Injector;
|
|
4
|
+
parent: Frame | null;
|
|
5
|
+
children: Set<EffectRef>;
|
|
6
|
+
};
|
|
7
|
+
export declare function currentFrame(): Frame | null;
|
|
8
|
+
export declare function clearFrame(frame: Frame, userCleanups: (() => void)[]): void;
|
|
9
|
+
export declare function pushFrame(frame: Frame): number;
|
|
10
|
+
export declare function popFrame(): Frame | undefined;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './nested-effect';
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { type CreateEffectOptions, type EffectCleanupRegisterFn, type EffectRef } from '@angular/core';
|
|
2
|
+
import { type Frame } from './frame-stack';
|
|
3
|
+
/**
|
|
4
|
+
* Creates an effect that can be nested, similar to SolidJS's `createEffect`.
|
|
5
|
+
*
|
|
6
|
+
* This primitive enables true hierarchical reactivity. A `nestedEffect` created
|
|
7
|
+
* within another `nestedEffect` is automatically destroyed and recreated when
|
|
8
|
+
* the parent re-runs.
|
|
9
|
+
*
|
|
10
|
+
* It automatically handles injector propagation and lifetime management, allowing
|
|
11
|
+
* you to create fine-grained, conditional side-effects that only track
|
|
12
|
+
* dependencies when they are "live".
|
|
13
|
+
*
|
|
14
|
+
* @param effectFn The side-effect function, which receives a cleanup register function.
|
|
15
|
+
* @param options (Optional) Angular's `CreateEffectOptions`.
|
|
16
|
+
* @returns An `EffectRef` for the created effect.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* // Assume `coldGuard` changes rarely, but `hotSignal` changes often.
|
|
21
|
+
* const coldGuard = signal(false);
|
|
22
|
+
* const hotSignal = signal(0);
|
|
23
|
+
*
|
|
24
|
+
* nestedEffect(() => {
|
|
25
|
+
* // This outer effect only tracks `coldGuard`.
|
|
26
|
+
* if (coldGuard()) {
|
|
27
|
+
*
|
|
28
|
+
* // This inner effect is CREATED when coldGuard is true
|
|
29
|
+
* // and DESTROYED when it becomes false.
|
|
30
|
+
* nestedEffect(() => {
|
|
31
|
+
* // It only tracks `hotSignal` while it exists.
|
|
32
|
+
* console.log('Hot signal is:', hotSignal());
|
|
33
|
+
* });
|
|
34
|
+
* }
|
|
35
|
+
* // If `coldGuard` is false, this outer effect does not track `hotSignal`.
|
|
36
|
+
* });
|
|
37
|
+
* ```
|
|
38
|
+
* @example
|
|
39
|
+
* ```ts
|
|
40
|
+
* const users = signal([
|
|
41
|
+
* { id: 1, name: 'Alice' },
|
|
42
|
+
* { id: 2, name: 'Bob' }
|
|
43
|
+
* ]);
|
|
44
|
+
*
|
|
45
|
+
* // The fine-grained mapped list
|
|
46
|
+
* const mappedUsers = mapArray(
|
|
47
|
+
* users,
|
|
48
|
+
* (userSignal, index) => {
|
|
49
|
+
* // 1. Create a fine-grained SIDE EFFECT for *this item*
|
|
50
|
+
* // This effect's lifetime is now tied to this specific item. created once on init of this index.
|
|
51
|
+
* const effectRef = nestedEffect(() => {
|
|
52
|
+
* // This only runs if *this* userSignal changes,
|
|
53
|
+
* // not if the whole list changes.
|
|
54
|
+
* console.log(`User ${index} updated:`, userSignal().name);
|
|
55
|
+
* });
|
|
56
|
+
*
|
|
57
|
+
* // 2. Return the data AND the cleanup logic
|
|
58
|
+
* return {
|
|
59
|
+
* // The mapped data
|
|
60
|
+
* label: computed(() => `User: ${userSignal().name}`),
|
|
61
|
+
*
|
|
62
|
+
* // The cleanup function
|
|
63
|
+
* destroyEffect: () => effectRef.destroy()
|
|
64
|
+
* };
|
|
65
|
+
* },
|
|
66
|
+
* {
|
|
67
|
+
* // 3. Tell mapArray HOW to clean up when an item is removed, this needs to be manual as it's not a nestedEffect itself
|
|
68
|
+
* onDestroy: (mappedItem) => {
|
|
69
|
+
* mappedItem.destroyEffect();
|
|
70
|
+
* }
|
|
71
|
+
* }
|
|
72
|
+
* );
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
export declare function nestedEffect(effectFn: (registerCleanup: EffectCleanupRegisterFn) => void, options?: CreateEffectOptions & {
|
|
76
|
+
bindToFrame?: (parent: Frame | null) => Frame | null;
|
|
77
|
+
}): EffectRef;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { type CreateSignalOptions, type Signal, type WritableSignal } from '@angular/core';
|
|
2
|
+
import { type MutableSignal } from '../mutable';
|
|
3
|
+
/**
|
|
4
|
+
* Reactively maps items from a source array to a new array, creating stable signals for each item.
|
|
5
|
+
*
|
|
6
|
+
* This function is highly optimized for performance, similar to SolidJS's `mapArray`.
|
|
7
|
+
* For each item in the source array, it creates a stable signal that is passed to the mapping function.
|
|
8
|
+
* This ensures that downstream consumers only re-evaluate for items that have actually changed,
|
|
9
|
+
* or when items are added or removed from the list.
|
|
10
|
+
*
|
|
11
|
+
* The type of signal passed to the `map` function depends on the source:
|
|
12
|
+
* - **Readonly `Signal`**: `map` receives a readonly `Signal<T>`.
|
|
13
|
+
* - **`WritableSignal`**: `map` receives a `WritableSignal<T>`, allowing two-way binding.
|
|
14
|
+
* - **`MutableSignal`**: `map` receives a `MutableSignal<T>`, allowing in-place mutation for performance.
|
|
15
|
+
*
|
|
16
|
+
* @template T The type of items in the source array.
|
|
17
|
+
* @template U The type of items in the resulting mapped array.
|
|
18
|
+
*
|
|
19
|
+
* @param source A `Signal<T[]>` or a function returning `T[]`.
|
|
20
|
+
* @param map The mapping function. It receives a stable signal for the item and its index.
|
|
21
|
+
* @param options Optional configuration, including `CreateSignalOptions` for the item signals
|
|
22
|
+
* (e.g., a custom `equal` function) and an `onDestroy` callback for cleanup.
|
|
23
|
+
* @returns A `Signal<U[]>` containing the mapped array.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* // Writable example
|
|
27
|
+
* const sourceItems = signal([
|
|
28
|
+
* { id: 1, name: 'Apple' },
|
|
29
|
+
* { id: 2, name: 'Banana' }
|
|
30
|
+
* ]);
|
|
31
|
+
*
|
|
32
|
+
* // The `itemSignal` is writable because `sourceItems` is a WritableSignal.
|
|
33
|
+
* const mappedItems = indexArray(sourceItems, (itemSignal, index) => ({
|
|
34
|
+
* label: computed(() => `${index}: ${itemSignal().name.toUpperCase()}`),
|
|
35
|
+
* setName: (newName: string) => itemSignal.update(item => ({ ...item, name: newName }))
|
|
36
|
+
* }));
|
|
37
|
+
*
|
|
38
|
+
* // This will update the original source signal.
|
|
39
|
+
* mappedItems()[0].setName('Avocado');
|
|
40
|
+
* // sourceItems() is now: [{ id: 1, name: 'Avocado' }, { id: 2, name: 'Banana' }]
|
|
41
|
+
*/
|
|
42
|
+
export declare function indexArray<T, U>(source: MutableSignal<T[]>, map: (value: MutableSignal<T>, index: number) => U, options?: CreateSignalOptions<T> & {
|
|
43
|
+
onDestroy?: (value: U) => void;
|
|
44
|
+
}): Signal<U[]>;
|
|
45
|
+
export declare function indexArray<T, U>(source: WritableSignal<T[]>, map: (value: WritableSignal<T>, index: number) => U, options?: CreateSignalOptions<T> & {
|
|
46
|
+
onDestroy?: (value: U) => void;
|
|
47
|
+
}): Signal<U[]>;
|
|
48
|
+
export declare function indexArray<T, U>(source: Signal<T[]> | (() => T[]), map: (value: Signal<T>, index: number) => U, options?: CreateSignalOptions<T> & {
|
|
49
|
+
onDestroy?: (value: U) => void;
|
|
50
|
+
}): Signal<U[]>;
|
|
51
|
+
/**
|
|
52
|
+
* @deprecated use indexArray instead
|
|
53
|
+
*/
|
|
54
|
+
export declare const mapArray: typeof indexArray;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type Signal } from '@angular/core';
|
|
2
|
+
/**
|
|
3
|
+
* Reactively maps items from a source array to a new array by value (identity).
|
|
4
|
+
*
|
|
5
|
+
* similar to `Array.prototype.map`, but:
|
|
6
|
+
* 1. The `mapFn` receives the `index` as a Signal.
|
|
7
|
+
* 2. If an item in the `source` array moves to a new position, the *result* of the map function is reused and moved.
|
|
8
|
+
* The `index` signal is updated to the new index.
|
|
9
|
+
* 3. The `mapFn` is only run for *new* items.
|
|
10
|
+
*
|
|
11
|
+
* This is useful for building efficient lists where DOM nodes or heavy instances should be reused
|
|
12
|
+
* when the list is reordered.
|
|
13
|
+
*
|
|
14
|
+
* @param source A `Signal<T[]>` or a function returning `T[]`.
|
|
15
|
+
* @param mapFn The mapping function. Receives the item and its index as a Signal.
|
|
16
|
+
* @param options Optional configuration:
|
|
17
|
+
* - `onDestroy`: A callback invoked when a mapped item is removed from the array.
|
|
18
|
+
* @returns A `Signal<U[]>` containing the mapped array.
|
|
19
|
+
*/
|
|
20
|
+
export declare function keyArray<T, U, K>(source: Signal<T[]> | (() => T[]), mapFn: (v: T, i: Signal<number>) => U, options?: {
|
|
21
|
+
onDestroy?: (value: U) => void;
|
|
22
|
+
/**
|
|
23
|
+
* Optional function to use a custom key for item comparison.
|
|
24
|
+
* Use this if you want to reuse mapped items based on a property (like an ID)
|
|
25
|
+
* even if the item reference changes.
|
|
26
|
+
*/
|
|
27
|
+
key?: (item: T) => K;
|
|
28
|
+
}): Signal<U[]>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type Signal, type WritableSignal } from '@angular/core';
|
|
2
|
+
import { type MutableSignal } from '../mutable';
|
|
3
|
+
type MappedObject<T extends Record<string, any>, U> = {
|
|
4
|
+
[K in keyof T]: U;
|
|
5
|
+
};
|
|
6
|
+
export declare function mapObject<T extends Record<string, any>, U>(source: MutableSignal<T>, mapFn: <K extends keyof T>(key: K, value: MutableSignal<T[K]>) => U, options?: {
|
|
7
|
+
onDestroy?: (value: U) => void;
|
|
8
|
+
}): Signal<MappedObject<T, U>>;
|
|
9
|
+
export declare function mapObject<T extends Record<string, any>, U>(source: WritableSignal<T>, mapFn: <K extends keyof T>(key: K, value: WritableSignal<T[K]>) => U, options?: {
|
|
10
|
+
onDestroy?: (value: U) => void;
|
|
11
|
+
}): Signal<MappedObject<T, U>>;
|
|
12
|
+
export declare function mapObject<T extends Record<string, any>, U>(source: (() => T) | Signal<T>, mapFn: <K extends keyof T>(key: K, value: Signal<T[K]>) => U, options?: {
|
|
13
|
+
onDestroy?: (value: U) => void;
|
|
14
|
+
}): Signal<MappedObject<T, U>>;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type Signal, type WritableSignal } from '@angular/core';
|
|
2
|
+
export declare function isWritableSignal<T>(value: Signal<T>): value is WritableSignal<T>;
|
|
3
|
+
/**
|
|
4
|
+
* @internal
|
|
5
|
+
* Creates a setter function for a source signal of type `Signal<T[]>` or a function returning `T[]`.
|
|
6
|
+
* @param source The source signal of type `Signal<T[]>` or a function returning `T[]`.
|
|
7
|
+
* @returns
|
|
8
|
+
*/
|
|
9
|
+
export declare function createSetter<T>(source: Signal<T[]>): (value: T, index: number) => void;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type CreateSignalOptions, type Signal } from '@angular/core';
|
|
2
|
+
import { type Operator } from './types';
|
|
3
|
+
/** Project with optional equality. Pure & sync. */
|
|
4
|
+
export declare const select: <I, O>(projector: (v: I) => O, opt?: CreateSignalOptions<O>) => Operator<I, O>;
|
|
5
|
+
/** Combine with another signal using a projector. */
|
|
6
|
+
export declare const combineWith: <A, B, R>(other: Signal<B>, project: (a: A, b: B) => R, opt?: CreateSignalOptions<R>) => Operator<A, R>;
|
|
7
|
+
/** Only re-emit when equal(prev, next) is false. */
|
|
8
|
+
export declare const distinct: <T>(equal?: (a: T, b: T) => boolean) => Operator<T, T>;
|
|
9
|
+
/** map to new value */
|
|
10
|
+
export declare const map: <I, O>(fn: (v: I) => O) => Operator<I, O>;
|
|
11
|
+
/** filter values, keeping the last value if it was ever available, if first value is filtered will return undefined */
|
|
12
|
+
export declare const filter: <T>(predicate: (v: T) => boolean) => Operator<T, T | undefined>;
|
|
13
|
+
/** tap into the value */
|
|
14
|
+
export declare const tap: <T>(fn: (v: T) => void) => Operator<T, T>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type CreateSignalOptions, type Signal, type WritableSignal } from '@angular/core';
|
|
2
|
+
import type { PipeableSignal, SignalValue } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Decorate any `Signal<T>` with a chainable `.pipe(...)` method.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* const s = pipeable(signal(1)); // WritableSignal<number> (+ pipe)
|
|
8
|
+
* const label = s.pipe(n => n * 2, n => `#${n}`); // Signal<string> (+ pipe)
|
|
9
|
+
* label(); // "#2"
|
|
10
|
+
*/
|
|
11
|
+
export declare function pipeable<TSig extends Signal<any>>(signal: TSig): PipeableSignal<SignalValue<TSig>, TSig>;
|
|
12
|
+
/**
|
|
13
|
+
* Create a new **writable** signal and return it as a `PipableSignal`.
|
|
14
|
+
*
|
|
15
|
+
* The returned value is a `WritableSignal<T>` with `.set`, `.update`, `.asReadonly`
|
|
16
|
+
* still available (via intersection type), plus a chainable `.pipe(...)`.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* const count = piped(1); // WritableSignal<number> (+ pipe)
|
|
20
|
+
* const even = count.pipe(n => n % 2 === 0); // Signal<boolean> (+ pipe)
|
|
21
|
+
* count.update(n => n + 1);
|
|
22
|
+
*/
|
|
23
|
+
export declare function piped<T>(initial: T, opt?: CreateSignalOptions<T>): PipeableSignal<T, WritableSignal<T>>;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { CreateSignalOptions, Signal } from '@angular/core';
|
|
2
|
+
/**
|
|
3
|
+
* A pure, synchronous transform from I -> O.
|
|
4
|
+
* Prefer transforms without side effects to keep derivations predictable.
|
|
5
|
+
*/
|
|
6
|
+
export type UnaryFunction<I, O> = (a: I) => O;
|
|
7
|
+
/** An Operator transforms a source Signal<I> into a derived Signal<O>. */
|
|
8
|
+
export type Operator<I, O> = (src: Signal<I>) => Signal<O>;
|
|
9
|
+
type SignalMap<In> = {
|
|
10
|
+
(): PipeableSignal<In>;
|
|
11
|
+
<A>(fn1: UnaryFunction<In, A>, opt?: CreateSignalOptions<A>): PipeableSignal<A>;
|
|
12
|
+
<A, B>(fn1: UnaryFunction<In, A>, fn2: UnaryFunction<A, B>, opt?: CreateSignalOptions<B>): PipeableSignal<B>;
|
|
13
|
+
<A, B, C>(fn1: UnaryFunction<In, A>, fn2: UnaryFunction<A, B>, fn3: UnaryFunction<B, C>, opt?: CreateSignalOptions<C>): PipeableSignal<C>;
|
|
14
|
+
<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>;
|
|
15
|
+
<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>;
|
|
16
|
+
<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>;
|
|
17
|
+
<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>;
|
|
18
|
+
<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>;
|
|
19
|
+
<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>;
|
|
20
|
+
};
|
|
21
|
+
/** `.pipe(...)` — compose operators (Signal -> Signal). */
|
|
22
|
+
type SignalPipe<In> = {
|
|
23
|
+
(): PipeableSignal<In>;
|
|
24
|
+
<A>(op1: Operator<In, A>): PipeableSignal<A>;
|
|
25
|
+
<A, B>(op1: Operator<In, A>, op2: Operator<A, B>): PipeableSignal<B>;
|
|
26
|
+
<A, B, C>(op1: Operator<In, A>, op2: Operator<A, B>, op3: Operator<B, C>): PipeableSignal<C>;
|
|
27
|
+
<A, B, C, D>(op1: Operator<In, A>, op2: Operator<A, B>, op3: Operator<B, C>, op4: Operator<C, D>): PipeableSignal<D>;
|
|
28
|
+
<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>;
|
|
29
|
+
<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>;
|
|
30
|
+
<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>;
|
|
31
|
+
<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>;
|
|
32
|
+
<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>;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* A `Signal<T>` augmented with a chainable `.pipe(...)` method.
|
|
36
|
+
*
|
|
37
|
+
* The `.pipe(...)` returns **computed** signals wrapped with the same method,
|
|
38
|
+
* allowing fluent, strongly-typed pipelines.
|
|
39
|
+
* @see {@link SignalPipe}
|
|
40
|
+
* @example
|
|
41
|
+
* ```ts
|
|
42
|
+
* import { piped } from '@ngrx/signals';
|
|
43
|
+
*
|
|
44
|
+
* const count = piped(1);
|
|
45
|
+
*
|
|
46
|
+
* const doubled = count.pipe(x => x * 2); // PipeableSignal<number>
|
|
47
|
+
* // doubled() === 2
|
|
48
|
+
* const toString = doubled.pipe(String); // PipeableSignal<string>
|
|
49
|
+
* // toString() === '2'
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export type PipeableSignal<T, TSig extends Signal<T> = Signal<T>> = TSig & {
|
|
53
|
+
pipe: SignalPipe<T>;
|
|
54
|
+
/** Chain pure transforms to derive new signals. See {@link SignalMap}. */
|
|
55
|
+
map: SignalMap<T>;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Helper type to infer the value type of a signal.
|
|
59
|
+
* @internal
|
|
60
|
+
*/
|
|
61
|
+
export type SignalValue<TSig extends Signal<any>> = TSig extends Signal<infer V> ? V : never;
|
|
62
|
+
export {};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { ElementRef, type Signal } from '@angular/core';
|
|
2
|
+
/**
|
|
3
|
+
* Represents the size of an element.
|
|
4
|
+
*/
|
|
5
|
+
export interface ElementSize {
|
|
6
|
+
width: number;
|
|
7
|
+
height: number;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Options for configuring the `elementSize` sensor.
|
|
11
|
+
*/
|
|
12
|
+
export type ElementSizeOptions = ResizeObserverOptions & {
|
|
13
|
+
/** Optional debug name for the internal signal. */
|
|
14
|
+
debugName?: string;
|
|
15
|
+
};
|
|
16
|
+
export type ElementSizeSignal = Signal<ElementSize | undefined>;
|
|
17
|
+
/**
|
|
18
|
+
* Creates a read-only signal that tracks the size of a target DOM element.
|
|
19
|
+
*
|
|
20
|
+
* By default, it observes the `border-box` size to align with `getBoundingClientRect()`,
|
|
21
|
+
* which is used to provide a synchronous initial value if possible.
|
|
22
|
+
*
|
|
23
|
+
* @param target The DOM element (or `ElementRef`, or a `Signal` resolving to one) to observe.
|
|
24
|
+
* @param options Optional configuration including `box` (defaults to 'border-box') and `debugName`.
|
|
25
|
+
* @returns A `Signal<ElementSize | undefined>`.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* const size = elementSize(elementRef);
|
|
30
|
+
* effect(() => {
|
|
31
|
+
* console.log('Size:', size()?.width, size()?.height);
|
|
32
|
+
* });
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export declare function elementSize(target?: ElementRef<Element> | Element | Signal<ElementRef<Element> | Element | null>, opt?: ElementSizeOptions): ElementSizeSignal;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ElementRef, Signal } from '@angular/core';
|
|
1
|
+
import { ElementRef, type Signal } from '@angular/core';
|
|
2
2
|
/**
|
|
3
3
|
* Options for configuring the `elementVisibility` sensor, extending
|
|
4
4
|
* standard `IntersectionObserverInit` options.
|
|
@@ -63,4 +63,4 @@ export type ElementVisibilitySignal = Signal<IntersectionObserverEntry | undefin
|
|
|
63
63
|
* }
|
|
64
64
|
* ```
|
|
65
65
|
*/
|
|
66
|
-
export declare function elementVisibility(target
|
|
66
|
+
export declare function elementVisibility(target?: ElementRef<Element> | Element | Signal<ElementRef<Element> | Element | null>, opt?: ElementVisibilityOptions): ElementVisibilitySignal;
|
package/lib/sensors/index.d.ts
CHANGED