@mmstack/primitives 21.2.2 → 21.4.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,6 +1,6 @@
1
1
  {
2
2
  "name": "@mmstack/primitives",
3
- "version": "21.2.2",
3
+ "version": "21.4.0",
4
4
  "keywords": [
5
5
  "angular",
6
6
  "signals",
@@ -189,8 +189,9 @@ declare function providePaused(source: Signal<boolean>): Provider;
189
189
  declare function holdUntilReady<T>(target: Signal<T>, ready: () => boolean): Signal<T>;
190
190
 
191
191
  /**
192
- * Handle for an in-progress transition: a `pending` signal (true while the transition's
193
- * resources are in flight) and a `done` promise that resolves once they all settle.
192
+ * Handle for an in-progress transition: a `pending` signal (true while the transition's OWN
193
+ * resources are in flight loads already in flight when it started are not attributed) and a
194
+ * `done` promise that resolves once they all settle.
194
195
  */
195
196
  type TransitionRef = {
196
197
  readonly pending: Signal<boolean>;
@@ -292,6 +293,15 @@ declare function createForwardingScope(): ForwardingTransitionScope;
292
293
  declare function provideForwardingTransitionScope(): Provider;
293
294
  /** Read the transition scope reachable from `injector`, or null if none is provided there. */
294
295
  declare function getTransitionScope(injector: Injector): TransitionScope | null;
296
+ /**
297
+ * @internal Transaction-attributed pending for `startTransition`/`startTransaction`: like
298
+ * `scope.pending`, but loads already in flight when the tracker is created are NOT attributed —
299
+ * a pre-existing background load can neither settle the transaction early nor block its settle
300
+ * forever. A pre-existing flight is excluded only until it first settles; a later re-trigger of
301
+ * the same resource (e.g. the transaction's write changed its request) counts as the
302
+ * transaction's own work.
303
+ */
304
+ declare function createAttributedPending(scope: TransitionScope): Signal<boolean>;
295
305
  /**
296
306
  * Returns a register function bound to the nearest transition scope: it adds a resource
297
307
  * to the scope and removes it when the caller's injection context is destroyed. Pass any
@@ -342,8 +352,7 @@ declare class SuspenseBoundary extends SuspenseBoundaryBase {
342
352
  }
343
353
  /**
344
354
  * Unscoped suspense boundary — **reads the ambient scope** instead of providing one. For cases where
345
- * the resources to coordinate are registered *above* the boundary (e.g. an app-builder page whose
346
- * manifests/connectors register at a higher injector), so the boundary observes that outer scope
355
+ * the resources to coordinate are registered *above* the boundary so the boundary observes that outer scope
347
356
  * rather than opening a fresh one. Pair with a `provideTransitionScope()` (or another boundary) in an
348
357
  * ancestor.
349
358
  */
@@ -368,7 +377,8 @@ type Transaction = {
368
377
  declare function createTransaction(): Transaction;
369
378
  /** The transaction in effect right now, or `null`. Stateful actions consult this to record undo. */
370
379
  declare function activeTransaction(): Transaction | null;
371
- /** Handle for an in-progress transaction (Tier 3): the transition `pending`/`done`, plus `abort`. */
380
+ /** Handle for an in-progress transaction (Tier 3): the transaction's own `pending`/`done`
381
+ * (loads already in flight at start are not attributed to it), plus `abort`. */
372
382
  type TransactionRef = {
373
383
  readonly pending: Signal<boolean>;
374
384
  readonly done: Promise<void>;
@@ -1937,6 +1947,21 @@ type PointerDragState = {
1937
1947
  modifiers: PointerModifiers;
1938
1948
  /** Mouse button that started the gesture (`-1` when idle). */
1939
1949
  button: number;
1950
+ /** The pointing device: `'mouse' | 'touch' | 'pen'` (`''` when idle). */
1951
+ pointerType: string;
1952
+ /**
1953
+ * The element the gesture started on: the `handleSelector` match when one is
1954
+ * set (so a single delegated listener can tell which child started the drag),
1955
+ * otherwise the listener's element. `null` when idle.
1956
+ */
1957
+ origin: HTMLElement | null;
1958
+ /**
1959
+ * Whether the LAST gesture ended by being aborted (`pointercancel` /
1960
+ * `lostpointercapture` / Escape / `cancel()`) rather than a normal `pointerup`.
1961
+ * Only meaningful on the idle transition — consumers ending a drag branch on it
1962
+ * to distinguish "drop here" from "abort". Sticky until the next `pointerdown`.
1963
+ */
1964
+ cancelled: boolean;
1940
1965
  };
1941
1966
  type PointerDragOptions = SensorRunOptions & {
1942
1967
  /**
@@ -1949,12 +1974,24 @@ type PointerDragOptions = SensorRunOptions & {
1949
1974
  coordinateSpace?: 'client' | 'page';
1950
1975
  /** Pixels the pointer must travel before `active` flips true. @default 3 */
1951
1976
  activationThreshold?: number;
1952
- /** Throttle (ms) for `current`/`delta` updates. @default 16 */
1977
+ /**
1978
+ * Throttle (ms) for `current`/`delta` updates. @default 16
1979
+ *
1980
+ * Note: a final sub-throttle move right before `pointerup` may not surface on
1981
+ * the throttled view (it coalesces into the terminal idle). Logic that must act
1982
+ * on the *exact* release position should read {@link PointerDragSignal.unthrottled}.
1983
+ */
1953
1984
  throttle?: number;
1954
1985
  /** Only start when the pointerdown target matches this selector (delegated handles). */
1955
1986
  handleSelector?: string;
1956
1987
  /** Mouse buttons that may start a gesture. @default [0] (primary) */
1957
1988
  buttons?: number[];
1989
+ /**
1990
+ * Stop the `pointerdown` from propagating once this sensor claims it. Lets an
1991
+ * inner sensor win over an outer one on the same element tree (e.g. a nested
1992
+ * sortable inside another). @default false
1993
+ */
1994
+ stopPropagation?: boolean;
1958
1995
  };
1959
1996
  /** A gesture signal with an `unthrottled` view and an imperative `cancel()`. */
1960
1997
  type PointerDragSignal = Signal<PointerDragState> & {
@@ -2592,18 +2629,64 @@ type MutableSignalStore<T> = MutableSignal<UnwrapOpaque<T>> & {
2592
2629
  readonly [LEAF]: () => boolean;
2593
2630
  } : NonNullable<T> extends any[] ? MutableArrayStore<NonNullable<T>> : MutableSignalStoreObject<T>);
2594
2631
 
2632
+ declare const STORE_SHARED_GLOBALS: unique symbol;
2633
+ /**
2634
+ * @internal
2635
+ * Maps a store's backing signal to its lazily-built child proxies, each held via a `WeakRef`.
2636
+ */
2637
+ type ProxyCache = WeakMap<object, Map<PropertyKey, WeakRef<Signal<any>>>>;
2638
+ /**
2639
+ * @internal
2640
+ * Prunes a cache entry once its proxy is reclaimed by the GC.
2641
+ */
2642
+ type ProxyCleanupRegistry = FinalizationRegistry<{
2643
+ target: object;
2644
+ prop: PropertyKey;
2645
+ }>;
2595
2646
  /**
2596
2647
  * @internal
2597
2648
  * Validates whether a value is a Signal Store.
2598
2649
  */
2599
2650
  declare function isStore<T>(value: unknown): value is SignalStore<T>;
2600
2651
 
2601
- declare function toStore<T extends AnyRecord>(source: MutableSignal<T>, injector?: Injector, vivify?: Vivify, noUnionLeaves?: boolean): MutableSignalStore<T>;
2602
- declare function toStore<T extends AnyRecord>(source: WritableSignal<T>, injector?: Injector, vivify?: Vivify, noUnionLeaves?: boolean): WritableSignalStore<T>;
2603
- declare function toStore<T extends AnyRecord>(source: Signal<T>, injector?: Injector, vivify?: Vivify, noUnionLeaves?: boolean): SignalStore<T>;
2604
- declare function extendStore<T extends AnyRecord, L extends AnyRecord>(store: MutableSignalStore<T>, source: MutableSignal<L> | L, injector?: Injector): MutableSignalStore<Simplify<Omit<NonNullable<T>, keyof L> & L>>;
2605
- declare function extendStore<T extends AnyRecord, L extends AnyRecord>(store: WritableSignalStore<T>, source: WritableSignal<L> | L, injector?: Injector): WritableSignalStore<Simplify<Omit<NonNullable<T>, keyof L> & L>>;
2606
- declare function extendStore<T extends AnyRecord, L extends AnyRecord>(store: SignalStore<T>, source: Signal<L> | L, injector?: Injector): SignalStore<Simplify<Omit<NonNullable<T>, keyof L> & L>>;
2652
+ type toStoreOptions = {
2653
+ injector?: Injector;
2654
+ /**
2655
+ * Opt-in autovivification: when writing through a `null`/`undefined` path, create the
2656
+ * missing intermediate containers instead of dropping the write. Off by default.
2657
+ *
2658
+ * Levels whose current value is a known object/array re-vivify as that same shape — the
2659
+ * knowledge is captured when the path is first accessed and cached, so it holds even after
2660
+ * the value is later nulled. This option governs only genuinely-unknown (currently
2661
+ * `null`/`undefined`) levels: `'auto'` (an array for index keys, an object otherwise), an
2662
+ * explicit `'object'`/`'array'`, or a `() => container` factory. See {@link Vivify}.
2663
+ */
2664
+ vivify?: Vivify;
2665
+ /**
2666
+ * Performance opt-in: promise that no node ever switches between leaf and substore (i.e. no
2667
+ * unions mixing a primitive with an object/array). With this on, each node's leaf-ness is
2668
+ * resolved once on the first {@link isLeaf} probe and cached as a constant, skipping the
2669
+ * reactive `computed`. If a node's shape does change anyway, {@link isLeaf} keeps its first
2670
+ * answer. Off by default.
2671
+ */
2672
+ noUnionLeaves?: boolean;
2673
+ /**
2674
+ * @internal
2675
+ * Shared cleanup singletons, they get injected/passed automatically
2676
+ */
2677
+ [STORE_SHARED_GLOBALS]?: {
2678
+ cache: ProxyCache;
2679
+ registry: ProxyCleanupRegistry;
2680
+ };
2681
+ };
2682
+ type StoreOptions<T> = CreateSignalOptions<T> & toStoreOptions;
2683
+ declare function toStore<T extends AnyRecord>(source: MutableSignal<T>, options?: toStoreOptions): MutableSignalStore<T>;
2684
+ declare function toStore<T extends AnyRecord>(source: WritableSignal<T>, options?: toStoreOptions): WritableSignalStore<T>;
2685
+ declare function toStore<T extends AnyRecord>(source: Signal<T>, options?: toStoreOptions): SignalStore<T>;
2686
+ type ExtendStoreOptions = Omit<toStoreOptions, 'vivify' | 'noUnionLeaves' | typeof STORE_SHARED_GLOBALS>;
2687
+ declare function extendStore<T extends AnyRecord, L extends AnyRecord>(store: MutableSignalStore<T>, source: MutableSignal<L> | L, options?: ExtendStoreOptions): MutableSignalStore<Simplify<Omit<NonNullable<T>, keyof L> & L>>;
2688
+ declare function extendStore<T extends AnyRecord, L extends AnyRecord>(store: WritableSignalStore<T>, source: WritableSignal<L> | L, options?: ExtendStoreOptions): WritableSignalStore<Simplify<Omit<NonNullable<T>, keyof L> & L>>;
2689
+ declare function extendStore<T extends AnyRecord, L extends AnyRecord>(store: SignalStore<T>, source: Signal<L> | L, options?: ExtendStoreOptions): SignalStore<Simplify<Omit<NonNullable<T>, keyof L> & L>>;
2607
2690
  /**
2608
2691
  * Creates a WritableSignalStore from a value.
2609
2692
  * @see {@link toStore}
@@ -2717,22 +2800,13 @@ type Fork<T> = {
2717
2800
  * leaves compare by value, so equal primitives are correctly seen as unchanged.
2718
2801
  */
2719
2802
  declare function merge3<T>(ancestor: T, mine: T, theirs: T): T;
2720
- declare function forkStore<T extends Record<string, any>>(base: WritableSignalStore<T>, opt?: {
2803
+ /**
2804
+ * ForkStoreOptions, vivify/noUnionLeaves should remain the same & are automatically inherited, override carefully (advanced usecases)
2805
+ */
2806
+ type ForkStoreOptions<T> = toStoreOptions & {
2721
2807
  strategy?: ForkStrategy<T>;
2722
- injector?: Injector;
2723
- /**
2724
- * Store config for the FORK's store — NOT inherited from `base` (it's closed over inside
2725
- * the base's `toStore` and can't be read back). If the base was created with these, pass
2726
- * the same values or the fork's write semantics will differ:
2727
- * - `vivify`: without it, a write through a `null`/`undefined` path is silently dropped on
2728
- * the fork even though the base would have created the container. Match the base.
2729
- * - `noUnionLeaves`: a perf promise; off just means the slower reactive leaf-probe. NOTE it
2730
- * is a whole-store guarantee — a fork that flips a node's type (leaf↔substore) violates it,
2731
- * and on `commit` the base receives the flipped value with stale cached leaf-ness.
2732
- */
2733
- vivify?: Vivify;
2734
- noUnionLeaves?: boolean;
2735
- }): Fork<T>;
2808
+ };
2809
+ declare function forkStore<T extends Record<string, any>>(base: WritableSignalStore<T>, opt?: ForkStoreOptions<T>): Fork<T>;
2736
2810
 
2737
2811
  /**
2738
2812
  * Interface for storage mechanisms compatible with the `stored` signal.
@@ -3192,5 +3266,5 @@ type CreateHistoryOptions<T> = Omit<CreateSignalOptions<T[]>, 'equal'> & {
3192
3266
  */
3193
3267
  declare function withHistory<T>(sourceOrValue: WritableSignal<T> | T, opt?: CreateHistoryOptions<T>): SignalWithHistory<T>;
3194
3268
 
3195
- export { MmActivity, PAUSABLE_OPTIONS, SuspenseBoundary, SuspenseBoundaryBase, UnscopedSuspenseBoundary, activeTransaction, batteryStatus, chunked, clipboard, combineWith, createForwardingScope, createTransaction, createTransitionScope, debounce, debounced, derived, distinct, elementSize, elementVisibility, extendStore, 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, pointerDrag, pooled, pooledArray, pooledMap, pooledSet, prefersDarkMode, prefersReducedMotion, provideForwardingTransitionScope, providePausableOptions, providePaused, provideTransitionScope, registerResource, resolvePause, scan, scrollPosition, select, sensor, sensors, signalFromEvent, startWith, store, stored, tabSync, tap, throttle, throttled, toFakeDerivation, toFakeSignalDerivation, toStore, toWritable, until, windowSize, withHistory };
3196
- 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, PointerDragOptions, PointerDragSignal, PointerDragState, PointerModifiers, PointerPoint, 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 };
3269
+ export { MmActivity, PAUSABLE_OPTIONS, SuspenseBoundary, SuspenseBoundaryBase, UnscopedSuspenseBoundary, activeTransaction, batteryStatus, chunked, clipboard, combineWith, createAttributedPending, createForwardingScope, createTransaction, createTransitionScope, debounce, debounced, derived, distinct, elementSize, elementVisibility, extendStore, 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, pointerDrag, pooled, pooledArray, pooledMap, pooledSet, prefersDarkMode, prefersReducedMotion, provideForwardingTransitionScope, providePausableOptions, providePaused, provideTransitionScope, registerResource, resolvePause, scan, scrollPosition, select, sensor, sensors, signalFromEvent, startWith, store, stored, tabSync, tap, throttle, throttled, toFakeDerivation, toFakeSignalDerivation, toStore, toWritable, until, windowSize, withHistory };
3270
+ export type { BatteryStatus, ClipboardSignal, Computation, CreateChunkedOptions, CreateDebouncedOptions, CreateHistoryOptions, CreatePooledOptions, CreateProvidedPooledOptions, CreateStoredOptions, CreateThrottledOptions, DebouncedSignal, DerivedSignal, ElementSize, ElementSizeOptions, ElementSizeSignal, ElementVisibilityOptions, ElementVisibilitySignal, ExtendStoreOptions, Fork, ForkStoreOptions, ForkStrategy, ForwardingTransitionScope, Frame, GeolocationOptions, GeolocationSignal, IdleOptions, IdleSignal, MousePositionOptions, MousePositionSignal, MutableSignal, MutableSignalStore, NetworkStatusSignal, Opaque, PausableOptions, PauseOption, PipeableSignal, PointerDragOptions, PointerDragSignal, PointerDragState, PointerModifiers, PointerPoint, ReconcileFn, RegisterOptions, ScreenOrientation, ScreenOrientationState, ScrollPosition, ScrollPositionOptions, ScrollPositionSignal, SensorRunOptions, SignalFromEventOptions, SignalStore, SignalWithHistory, StoreOptions, StoredSignal, SuspendType, ThrottledSignal, Transaction, TransactionRef, TransitionRef, TransitionScope, UntilOptions, Vivify, WindowSize, WindowSizeOptions, WindowSizeSignal, WithVivify, WritableSignalStore, toStoreOptions };