@mmstack/primitives 21.0.24 → 21.0.26

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,6 +1,6 @@
1
1
  {
2
2
  "name": "@mmstack/primitives",
3
- "version": "21.0.24",
3
+ "version": "21.0.26",
4
4
  "keywords": [
5
5
  "angular",
6
6
  "signals",
@@ -228,6 +228,55 @@ declare function mutable<T>(initial: T, opt?: CreateSignalOptions<T>): MutableSi
228
228
  */
229
229
  declare function isMutable<T = any>(value: WritableSignal<T>): value is MutableSignal<T>;
230
230
 
231
+ /** @internal Narrows `'array'` so it is only assignable when `T` is an array type. */
232
+ type VivifyArray<T> = T extends any[] ? 'array' : never;
233
+ /** @internal Narrows `'object'` so it is only assignable when `T` is an object type. */
234
+ type VivifyObject<T> = T extends object ? 'object' : never;
235
+ /**
236
+ * Controls **autovivification** — whether, and as what shape, a writable `derived` (or `store`)
237
+ * creates a missing container when the source value is `null`/`undefined` at the moment of a
238
+ * write. Without it, writing through a nullish value is a no-op; with it, a deep write such as
239
+ * `derived(user, 'name', { vivify: 'object' }).set('Ada')` materializes the missing object
240
+ * instead of silently dropping the write.
241
+ *
242
+ * A **present** value is always preserved — updated in place for a `MutableSignal` source,
243
+ * copied for an immutable one. Vivification only ever *creates*, it never *replaces*.
244
+ *
245
+ * Variants:
246
+ * - `false` — **default.** Off; a write through a nullish source does nothing.
247
+ * - `true` / `'auto'` — infer the shape from the key: an array (`[]`) for a numeric / index key,
248
+ * a plain object (`{}`) otherwise.
249
+ * - `'object'` — always create a plain object (`{}`). Only assignable when `T` is an object.
250
+ * - `'array'` — always create an array (`[]`). Only assignable when `T` is an array.
251
+ * - `() => T` — a factory producing the container to create. Called only on a nullish source,
252
+ * once per vivification (a fresh instance each time), so a present value is never clobbered.
253
+ * Useful for seeding defaults, e.g. `() => ({ items: [], total: 0 })`.
254
+ *
255
+ * @typeParam T - The type of the container that may be created (the source/parent value).
256
+ *
257
+ * @example
258
+ * ```ts
259
+ * const user = signal<{ name: string } | null>(null);
260
+ *
261
+ * derived(user, 'name').set('Ada'); // off: dropped, user() === null
262
+ * derived(user, 'name', { vivify: 'object' }).set('Ada'); // user() === { name: 'Ada' }
263
+ * ```
264
+ */
265
+ type Vivify<T = any> = 'auto' | boolean | (() => T) | VivifyArray<T> | VivifyObject<T>;
266
+ /**
267
+ * Options mix-in that adds an optional {@link Vivify} setting to the `options` argument of the
268
+ * `derived` / `store` key & index overloads.
269
+ *
270
+ * @typeParam T - The type of the container that may be vivified (the source/parent value).
271
+ */
272
+ type WithVivify<T> = {
273
+ /**
274
+ * Whether, and as what shape, to create a missing container when the source value is
275
+ * `null`/`undefined` at write time. Defaults to `false` (no vivification). See {@link Vivify}.
276
+ */
277
+ vivify?: Vivify<T>;
278
+ };
279
+
231
280
  /**
232
281
  * Options for creating a derived signal using the full `derived` function signature.
233
282
  * @typeParam T - The type of the source signal's value (parent).
@@ -290,7 +339,10 @@ declare function derived<T, U>(source: WritableSignal<T>, opt: CreateDerivedOpti
290
339
  * @typeParam TKey The key of the property to derive.
291
340
  * @param source The source `WritableSignal` (holding an object).
292
341
  * @param key The key of the property to derive.
293
- * @param options Optional signal options for the derived signal.
342
+ * @param options Optional signal options for the derived signal. Also accepts a
343
+ * {@link Vivify} `vivify` flag (off by default) that, when set, creates the missing
344
+ * container instead of dropping a write made through a `null`/`undefined` source —
345
+ * e.g. `derived(user, 'name', { vivify: 'object' })`. See {@link WithVivify}.
294
346
  * @returns A `DerivedSignal` instance.
295
347
  *
296
348
  * @example
@@ -306,7 +358,7 @@ declare function derived<T, U>(source: WritableSignal<T>, opt: CreateDerivedOpti
306
358
  * console.log(user().name); // Outputs: Jane
307
359
  * ```
308
360
  */
309
- declare function derived<T extends object, TKey extends keyof T>(source: MutableSignal<T>, key: TKey, opt?: CreateSignalOptions<T[TKey]>): DerivedSignal<T, T[TKey]> & MutableSignal<T[TKey]>;
361
+ declare function derived<T extends object, TKey extends keyof T>(source: MutableSignal<T>, key: TKey, opt?: CreateSignalOptions<T[TKey]> & WithVivify<T>): DerivedSignal<T, T[TKey]> & MutableSignal<T[TKey]>;
310
362
  /**
311
363
  * Creates a `DerivedSignal` that derives a property from an object held by the source signal.
312
364
  * This overload is a convenient shorthand for accessing object properties.
@@ -315,7 +367,10 @@ declare function derived<T extends object, TKey extends keyof T>(source: Mutable
315
367
  * @typeParam TKey The key of the property to derive.
316
368
  * @param source The source `WritableSignal` (holding an object).
317
369
  * @param key The key of the property to derive.
318
- * @param options Optional signal options for the derived signal.
370
+ * @param options Optional signal options for the derived signal. Also accepts a
371
+ * {@link Vivify} `vivify` flag (off by default) that, when set, creates the missing
372
+ * container instead of dropping a write made through a `null`/`undefined` source —
373
+ * e.g. `derived(user, 'name', { vivify: 'object' })`. See {@link WithVivify}.
319
374
  * @returns A `DerivedSignal` instance.
320
375
  *
321
376
  * @example
@@ -331,7 +386,7 @@ declare function derived<T extends object, TKey extends keyof T>(source: Mutable
331
386
  * console.log(user().name); // Outputs: Jane
332
387
  * ```
333
388
  */
334
- declare function derived<T extends object, TKey extends keyof T>(source: WritableSignal<T>, key: TKey, opt?: CreateSignalOptions<T[TKey]>): DerivedSignal<T, T[TKey]>;
389
+ declare function derived<T extends object, TKey extends keyof T>(source: WritableSignal<T>, key: TKey, opt?: CreateSignalOptions<T[TKey]> & WithVivify<T>): DerivedSignal<T, T[TKey]>;
335
390
  /**
336
391
  * Creates a `DerivedSignal` that derives its value from another `MutableSignal`.
337
392
  * Use mutuable signals with caution, but very useful for deeply nested structures.
@@ -354,7 +409,7 @@ declare function derived<T extends object, TKey extends keyof T>(source: Writabl
354
409
  * console.log(user().name); // Outputs: Jane
355
410
  * ```
356
411
  */
357
- declare function derived<T, U>(source: MutableSignal<T>, optOrKey: CreateDerivedOptions<T, U> | keyof T, opt?: CreateSignalOptions<U>): DerivedSignal<T, U> & MutableSignal<U>;
412
+ declare function derived<T, U>(source: MutableSignal<T>, optOrKey: CreateDerivedOptions<T, U> | keyof T, opt?: CreateSignalOptions<U> & WithVivify<T>): DerivedSignal<T, U> & MutableSignal<U>;
358
413
  /**
359
414
  * Creates a `DerivedSignal` from an array, deriving an element by its index.
360
415
  * This overload is a convenient shorthand for accessing array elements.
@@ -362,7 +417,10 @@ declare function derived<T, U>(source: MutableSignal<T>, optOrKey: CreateDerived
362
417
  * @typeParam T The type of the source signal's value (must be an array).
363
418
  * @param source The source `WritableSignal` (holding an array).
364
419
  * @param index The index of the element to derive.
365
- * @param options Optional signal options for the derived signal.
420
+ * @param options Optional signal options for the derived signal. Also accepts a
421
+ * {@link Vivify} `vivify` flag (off by default) that, when set, creates the missing
422
+ * container instead of dropping a write made through a `null`/`undefined` source —
423
+ * e.g. `derived(user, 'name', { vivify: 'object' })`. See {@link WithVivify}.
366
424
  * @returns A `DerivedSignal` instance.
367
425
  *
368
426
  * @example
@@ -378,7 +436,7 @@ declare function derived<T, U>(source: MutableSignal<T>, optOrKey: CreateDerived
378
436
  * console.log(numbers()); // Outputs: [1, 5, 3]
379
437
  * ```
380
438
  */
381
- declare function derived<T extends any[]>(source: WritableSignal<T>, index: number, opt?: CreateSignalOptions<T[number]>): DerivedSignal<T, T[number]>;
439
+ declare function derived<T extends any[]>(source: WritableSignal<T>, index: number, opt?: CreateSignalOptions<T[number]> & WithVivify<T>): DerivedSignal<T, T[number]>;
382
440
  /**
383
441
  * Creates a "fake" `DerivedSignal` from a simple value. This is useful for creating
384
442
  * `FormControlSignal` instances that are not directly derived from another signal.
@@ -1963,28 +2021,75 @@ type MutableArrayStore<T extends any[]> = MutableSignal<T> & {
1963
2021
  readonly length: Signal<number>;
1964
2022
  [Symbol.iterator](): Iterator<MutableSignalStore<T[number]>>;
1965
2023
  };
1966
- type SignalStore<T> = Signal<T> & (NonNullable<T> extends BaseType ? unknown : NonNullable<T> extends Array<any> ? SignalArrayStore<NonNullable<T>> : Readonly<{
2024
+ /**
2025
+ * @internal Resolves to `true` only for `any`. In a conditional type, `any` distributes across
2026
+ * *both* branches (`unknown | object`), and `unknown | X` collapses to `unknown` — which would
2027
+ * erase a store's property access and `extend`. Guarding on this routes an `any`-typed store to
2028
+ * the full object shape instead.
2029
+ */
2030
+ type IsAny<T> = 0 extends 1 & T ? true : false;
2031
+ /**
2032
+ * @internal Flattens an intersection (`A & B & C`) into a single object literal so editor
2033
+ * tooltips show the resolved members instead of the raw intersection chain. Display-only —
2034
+ * structurally identical to its input.
2035
+ */
2036
+ type Simplify<T> = {
2037
+ [K in keyof T]: T[K];
2038
+ } & {};
2039
+ /** @internal The object shape of a readonly store: a child store per key, plus `extend`. */
2040
+ type SignalStoreObject<T> = Simplify<Readonly<{
1967
2041
  [K in keyof Required<T>]: SignalStore<NonNullable<T>[K]>;
1968
- }>);
2042
+ }> & {
2043
+ readonly extend: {
2044
+ <L extends AnyRecord>(source: Signal<L>): SignalStore<Simplify<Omit<NonNullable<T>, keyof L> & L>>;
2045
+ <L extends AnyRecord>(props: L): SignalStore<Simplify<Omit<NonNullable<T>, keyof L> & L>>;
2046
+ };
2047
+ }>;
2048
+ /** @internal The object shape of a writable store. */
2049
+ type WritableSignalStoreObject<T> = Simplify<Readonly<{
2050
+ [K in keyof Required<T>]: WritableSignalStore<NonNullable<T>[K]>;
2051
+ }> & {
2052
+ readonly extend: {
2053
+ <L extends AnyRecord>(source: WritableSignal<L>): WritableSignalStore<Simplify<Omit<NonNullable<T>, keyof L> & L>>;
2054
+ <L extends AnyRecord>(props: L): WritableSignalStore<Simplify<Omit<NonNullable<T>, keyof L> & L>>;
2055
+ };
2056
+ }>;
2057
+ /** @internal The object shape of a mutable store. */
2058
+ type MutableSignalStoreObject<T> = Simplify<Readonly<{
2059
+ [K in keyof Required<T>]: MutableSignalStore<NonNullable<T>[K]>;
2060
+ }> & {
2061
+ readonly extend: {
2062
+ <L extends AnyRecord>(source: MutableSignal<L>): MutableSignalStore<Simplify<Omit<NonNullable<T>, keyof L> & L>>;
2063
+ <L extends AnyRecord>(props: L): MutableSignalStore<Simplify<Omit<NonNullable<T>, keyof L> & L>>;
2064
+ };
2065
+ }>;
2066
+ type SignalStore<T> = Signal<T> & (IsAny<T> extends true ? SignalStoreObject<T> : NonNullable<T> extends BaseType ? unknown : NonNullable<T> extends Array<any> ? SignalArrayStore<NonNullable<T>> : SignalStoreObject<T>);
1969
2067
  type WritableSignalStore<T> = WritableSignal<T> & {
1970
2068
  readonly asReadonlyStore: () => SignalStore<T>;
1971
- } & (NonNullable<T> extends BaseType ? unknown : NonNullable<T> extends Array<any> ? WritableArrayStore<NonNullable<T>> : Readonly<{
1972
- [K in keyof Required<T>]: WritableSignalStore<NonNullable<T>[K]>;
1973
- }>);
2069
+ } & (IsAny<T> extends true ? WritableSignalStoreObject<T> : NonNullable<T> extends BaseType ? unknown : NonNullable<T> extends Array<any> ? WritableArrayStore<NonNullable<T>> : WritableSignalStoreObject<T>);
1974
2070
  type MutableSignalStore<T> = MutableSignal<T> & {
1975
2071
  readonly asReadonlyStore: () => SignalStore<T>;
1976
- } & (NonNullable<T> extends BaseType ? unknown : NonNullable<T> extends Array<any> ? MutableArrayStore<NonNullable<T>> : Readonly<{
1977
- [K in keyof Required<T>]: MutableSignalStore<NonNullable<T>[K]>;
1978
- }>);
1979
- declare function toStore<T extends AnyRecord>(source: MutableSignal<T>, injector?: Injector): MutableSignalStore<T>;
1980
- declare function toStore<T extends AnyRecord>(source: WritableSignal<T>, injector?: Injector): WritableSignalStore<T>;
1981
- declare function toStore<T extends AnyRecord>(source: Signal<T>, injector?: Injector): SignalStore<T>;
2072
+ } & (IsAny<T> extends true ? MutableSignalStoreObject<T> : NonNullable<T> extends BaseType ? unknown : NonNullable<T> extends Array<any> ? MutableArrayStore<NonNullable<T>> : MutableSignalStoreObject<T>);
2073
+ declare function toStore<T extends AnyRecord>(source: MutableSignal<T>, injector?: Injector, vivify?: Vivify): MutableSignalStore<T>;
2074
+ declare function toStore<T extends AnyRecord>(source: WritableSignal<T>, injector?: Injector, vivify?: Vivify): WritableSignalStore<T>;
2075
+ declare function toStore<T extends AnyRecord>(source: Signal<T>, injector?: Injector, vivify?: Vivify): SignalStore<T>;
1982
2076
  /**
1983
2077
  * Creates a WritableSignalStore from a value.
1984
2078
  * @see {@link toStore}
1985
2079
  */
1986
2080
  declare function store<T extends AnyRecord>(value: T, opt?: CreateSignalOptions<T> & {
1987
2081
  injector?: Injector;
2082
+ /**
2083
+ * Opt-in autovivification: when writing through a `null`/`undefined` path, create the
2084
+ * missing intermediate containers instead of dropping the write. Off by default.
2085
+ *
2086
+ * Levels whose current value is a known object/array re-vivify as that same shape — the
2087
+ * knowledge is captured when the path is first accessed and cached, so it holds even after
2088
+ * the value is later nulled. This option governs only genuinely-unknown (currently
2089
+ * `null`/`undefined`) levels: `'auto'` (an array for index keys, an object otherwise), an
2090
+ * explicit `'object'`/`'array'`, or a `() => container` factory. See {@link Vivify}.
2091
+ */
2092
+ vivify?: Vivify;
1988
2093
  }): WritableSignalStore<T>;
1989
2094
  /**
1990
2095
  * Creates a MutableSignalStore from a value.
@@ -1992,6 +2097,17 @@ declare function store<T extends AnyRecord>(value: T, opt?: CreateSignalOptions<
1992
2097
  */
1993
2098
  declare function mutableStore<T extends AnyRecord>(value: T, opt?: CreateSignalOptions<T> & {
1994
2099
  injector?: Injector;
2100
+ /**
2101
+ * Opt-in autovivification: when writing through a `null`/`undefined` path, create the
2102
+ * missing intermediate containers instead of dropping the write. Off by default.
2103
+ *
2104
+ * Levels whose current value is a known object/array re-vivify as that same shape — the
2105
+ * knowledge is captured when the path is first accessed and cached, so it holds even after
2106
+ * the value is later nulled. This option governs only genuinely-unknown (currently
2107
+ * `null`/`undefined`) levels: `'auto'` (an array for index keys, an object otherwise), an
2108
+ * explicit `'object'`/`'array'`, or a `() => container` factory. See {@link Vivify}.
2109
+ */
2110
+ vivify?: Vivify;
1995
2111
  }): MutableSignalStore<T>;
1996
2112
 
1997
2113
  /**
@@ -2422,4 +2538,4 @@ type CreateHistoryOptions<T> = Omit<CreateSignalOptions<T[]>, 'equal'> & {
2422
2538
  declare function withHistory<T>(sourceOrValue: WritableSignal<T> | T, opt?: CreateHistoryOptions<T>): SignalWithHistory<T>;
2423
2539
 
2424
2540
  export { batteryStatus, chunked, clipboard, combineWith, debounce, debounced, derived, distinct, elementSize, elementVisibility, filter, filterWith, focusWithin, geolocation, idle, indexArray, isDerivation, isMutable, isStore, keyArray, map, mapArray, mapObject, mediaQuery, mousePosition, mutable, mutableStore, nestedEffect, networkStatus, orientation, pageVisibility, pairwise, pipeable, piped, pooled, pooledArray, pooledMap, pooledSet, prefersDarkMode, prefersReducedMotion, scan, scrollPosition, select, sensor, sensors, signalFromEvent, startWith, store, stored, tabSync, tap, throttle, throttled, toFakeDerivation, toFakeSignalDerivation, toStore, toWritable, until, windowSize, withHistory };
2425
- export type { BatteryStatus, ClipboardSignal, Computation, CreateChunkedOptions, CreateDebouncedOptions, CreateHistoryOptions, CreatePooledOptions, CreateProvidedPooledOptions, CreateStoredOptions, CreateThrottledOptions, DebouncedSignal, DerivedSignal, ElementSize, ElementSizeOptions, ElementSizeSignal, ElementVisibilityOptions, ElementVisibilitySignal, GeolocationOptions, GeolocationSignal, IdleOptions, IdleSignal, MousePositionOptions, MousePositionSignal, MutableSignal, MutableSignalStore, NetworkStatusSignal, PipeableSignal, ScreenOrientation, ScrollPosition, ScrollPositionOptions, ScrollPositionSignal, SignalFromEventOptions, SignalStore, SignalWithHistory, StoredSignal, ThrottledSignal, UntilOptions, WindowSize, WindowSizeOptions, WindowSizeSignal, WritableSignalStore };
2541
+ export type { BatteryStatus, ClipboardSignal, Computation, CreateChunkedOptions, CreateDebouncedOptions, CreateHistoryOptions, CreatePooledOptions, CreateProvidedPooledOptions, CreateStoredOptions, CreateThrottledOptions, DebouncedSignal, DerivedSignal, ElementSize, ElementSizeOptions, ElementSizeSignal, ElementVisibilityOptions, ElementVisibilitySignal, GeolocationOptions, GeolocationSignal, IdleOptions, IdleSignal, MousePositionOptions, MousePositionSignal, MutableSignal, MutableSignalStore, NetworkStatusSignal, PipeableSignal, ScreenOrientation, ScrollPosition, ScrollPositionOptions, ScrollPositionSignal, SignalFromEventOptions, SignalStore, SignalWithHistory, StoredSignal, ThrottledSignal, UntilOptions, Vivify, WindowSize, WindowSizeOptions, WindowSizeSignal, WithVivify, WritableSignalStore };