@mmstack/primitives 20.0.2 → 20.0.4

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
@@ -420,65 +420,51 @@ type ElementVisibilitySignal = Signal<IntersectionObserverEntry | undefined> & {
420
420
  declare function elementVisibility(target?: ElementRef<Element> | Element | Signal<ElementRef<Element> | Element | null>, opt?: ElementVisibilityOptions): ElementVisibilitySignal;
421
421
 
422
422
  /**
423
- * Reactively maps items from a source array (or signal of an array) using a provided mapping function.
423
+ * Reactively maps items from a source array to a new array, creating stable signals for each item.
424
424
  *
425
- * This function serves a similar purpose to SolidJS's `mapArray` by providing stability
426
- * for mapped items. It receives a source function returning an array (or a Signal<T[]>)
427
- * and a mapping function.
425
+ * This function is highly optimized for performance, similar to SolidJS's `mapArray`.
426
+ * For each item in the source array, it creates a stable signal that is passed to the mapping function.
427
+ * This ensures that downstream consumers only re-evaluate for items that have actually changed,
428
+ * or when items are added or removed from the list.
428
429
  *
429
- * For each item in the source array, it creates a stable `computed` signal representing
430
- * that item's value at its current index. This stable signal (`Signal<T>`) is passed
431
- * to the mapping function. This ensures that downstream computations or components
432
- * depending on the mapped result only re-render or re-calculate for the specific items
433
- * that have changed, or when items are added/removed, rather than re-evaluating everything
434
- * when the source array reference changes but items remain the same.
435
- *
436
- * It efficiently handles changes in the source array's length by reusing existing mapped
437
- * results when possible, slicing when the array shrinks, and appending new mapped items
438
- * when it grows.
430
+ * The type of signal passed to the `map` function depends on the source:
431
+ * - **Readonly `Signal`**: `map` receives a readonly `Signal<T>`.
432
+ * - **`WritableSignal`**: `map` receives a `WritableSignal<T>`, allowing two-way binding.
433
+ * - **`MutableSignal`**: `map` receives a `MutableSignal<T>`, allowing in-place mutation for performance.
439
434
  *
440
435
  * @template T The type of items in the source array.
441
436
  * @template U The type of items in the resulting mapped array.
442
437
  *
443
- * @param source A function returning the source array `T[]`, or a `Signal<T[]>` itself.
444
- * The `mapArray` function will reactively update based on changes to this source.
445
- * @param map The mapping function. It is called for each item in the source array.
446
- * It receives:
447
- * - `value`: A stable `Signal<T>` representing the item at the current index.
448
- * Use this signal within your mapping logic if you need reactivity
449
- * tied to the specific item's value changes.
450
- * - `index`: The number index of the item in the array.
451
- * It should return the mapped value `U`.
452
- * @param [opt] Optional `CreateSignalOptions<T>`. These options are passed directly
453
- * to the `computed` signal created for each individual item (`Signal<T>`).
454
- * This allows specifying options like a custom `equal` function for item comparison.
455
- *
456
- * @returns A `Signal<U[]>` containing the mapped array. This signal updates whenever
457
- * the source array changes (either length or the values of its items).
438
+ * @param source A `Signal<T[]>` or a function returning `T[]`.
439
+ * @param map The mapping function. It receives a stable signal for the item and its index.
440
+ * @param options Optional configuration, including `CreateSignalOptions` for the item signals
441
+ * (e.g., a custom `equal` function) and an `onDestroy` callback for cleanup.
442
+ * @returns A `Signal<U[]>` containing the mapped array.
458
443
  *
459
444
  * @example
460
- * ```ts
445
+ * // Writable example
461
446
  * const sourceItems = signal([
462
447
  * { id: 1, name: 'Apple' },
463
448
  * { id: 2, name: 'Banana' }
464
449
  * ]);
465
450
  *
466
- * const mappedItems = mapArray(
467
- * sourceItems,
468
- * (itemSignal, index) => {
469
- * // itemSignal is stable for a given item based on its index.
470
- * // We create a computed here to react to changes in the item's name.
471
- * return computed(() => `${index}: ${itemSignal().name.toUpperCase()}`);
472
- * },
473
- * // Example optional options (e.g., custom equality for item signals)
474
- * { equal: (a, b) => a.id === b.id && a.name === b.name }
475
- * );
476
- * ```
477
- * @remarks
478
- * This function achieves its high performance by leveraging the new `linkedSignal`
479
- * API from Angular, which allows for efficient memoization and reuse of array items.
451
+ * // The `itemSignal` is writable because `sourceItems` is a WritableSignal.
452
+ * const mappedItems = mapArray(sourceItems, (itemSignal, index) => ({
453
+ * label: computed(() => `${index}: ${itemSignal().name.toUpperCase()}`),
454
+ * setName: (newName: string) => itemSignal.update(item => ({ ...item, name: newName }))
455
+ * }));
456
+ *
457
+ * // This will update the original source signal.
458
+ * mappedItems()[0].setName('Avocado');
459
+ * // sourceItems() is now: [{ id: 1, name: 'Avocado' }, { id: 2, name: 'Banana' }]
480
460
  */
481
- declare function mapArray<T, U>(source: () => T[], map: (value: Signal<T>, index: number) => U, opt?: CreateSignalOptions<T> & {
461
+ declare function mapArray<T, U>(source: MutableSignal<T[]>, map: (value: MutableSignal<T>, index: number) => U, options?: CreateSignalOptions<T> & {
462
+ onDestroy?: (value: U) => void;
463
+ }): Signal<U[]>;
464
+ declare function mapArray<T, U>(source: WritableSignal<T[]>, map: (value: WritableSignal<T>, index: number) => U, options?: CreateSignalOptions<T> & {
465
+ onDestroy?: (value: U) => void;
466
+ }): Signal<U[]>;
467
+ declare function mapArray<T, U>(source: Signal<T[]> | (() => T[]), map: (value: Signal<T>, index: number) => U, options?: CreateSignalOptions<T> & {
482
468
  onDestroy?: (value: U) => void;
483
469
  }): Signal<U[]>;
484
470
 
@@ -1196,6 +1182,33 @@ type UntilOptions = {
1196
1182
  destroyRef?: DestroyRef;
1197
1183
  injector?: Injector;
1198
1184
  };
1185
+ /**
1186
+ * Creates a Promise that resolves when a signal's value satisfies a type predicate.
1187
+ *
1188
+ * This overload is used when the predicate function is a type guard (e.g., `(v): v is MyType`).
1189
+ * The returned promise will resolve with the narrowed type.
1190
+ *
1191
+ * @template T The base type of the signal's value.
1192
+ * @template U The narrowed type asserted by the predicate.
1193
+ * @param sourceSignal The signal to observe.
1194
+ * @param predicate A type guard function that returns `true` if the value is of type `U`.
1195
+ * @param options Optional configuration for timeout and explicit destruction.
1196
+ * @returns A Promise that resolves with the signal's value, narrowed to type `U`.
1197
+ *
1198
+ * @example
1199
+ * ```ts
1200
+ * const event = signal<Event | null>(null);
1201
+ *
1202
+ * // The returned promise is `Promise<MouseEvent>`
1203
+ * const mouseEventPromise = until(event, (e): e is MouseEvent => e instanceof MouseEvent);
1204
+ *
1205
+ * async function logMouseEvent() {
1206
+ * const me = await mouseEventPromise;
1207
+ * console.log(me.clientX); // `me` is correctly typed as MouseEvent
1208
+ * }
1209
+ * ```
1210
+ */
1211
+ declare function until<T, U extends T>(sourceSignal: Signal<T>, predicate: (value: T) => value is U, options?: UntilOptions): Promise<U>;
1199
1212
  /**
1200
1213
  * Creates a Promise that resolves when a signal's value satisfies a given predicate.
1201
1214
  *
@@ -1208,28 +1221,6 @@ type UntilOptions = {
1208
1221
  * @param options Optional configuration for timeout and explicit destruction.
1209
1222
  * @returns A Promise that resolves with the signal's value when the predicate is true,
1210
1223
  * or rejects on timeout or context destruction.
1211
- *
1212
- * @example
1213
- * ```ts
1214
- * const count = signal(0);
1215
- *
1216
- * async function waitForCount() {
1217
- * console.log('Waiting for count to be >= 3...');
1218
- * try {
1219
- * const finalCount = await until(count, c => c >= 3, { timeout: 5000 });
1220
- * console.log(`Count reached: ${finalCount}`);
1221
- * } catch (e: any) { // Ensure 'e' is typed if you access properties like e.message
1222
- * console.error(e.message); // e.g., "until: Timeout after 5000ms."
1223
- * }
1224
- * }
1225
- *
1226
- * // Simulate updates
1227
- * setTimeout(() => count.set(1), 500);
1228
- * setTimeout(() => count.set(2), 1000);
1229
- * setTimeout(() => count.set(3), 1500);
1230
- *
1231
- * waitForCount();
1232
- * ```
1233
1224
  */
1234
1225
  declare function until<T>(sourceSignal: Signal<T>, predicate: (value: T) => boolean, options?: UntilOptions): Promise<T>;
1235
1226
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mmstack/primitives",
3
- "version": "20.0.2",
3
+ "version": "20.0.4",
4
4
  "keywords": [
5
5
  "angular",
6
6
  "signals",