@mmstack/primitives 21.8.3 → 21.9.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.
@@ -2021,7 +2021,9 @@ function effectiveKeys(arr, getKey, report) {
2021
2021
  * when the list is reordered.
2022
2022
  *
2023
2023
  * @param source A `Signal<T[]>` or a function returning `T[]`.
2024
- * @param mapFn The mapping function. Receives the item and its index as a Signal.
2024
+ * @param mapFn The mapping function. Receives the item, its index as a Signal, and the
2025
+ * entry's key (the effective ordinal key when `duplicateKeys` is enabled, otherwise
2026
+ * the raw key) — stable for the lifetime of the mapped entry.
2025
2027
  * @param options Optional configuration:
2026
2028
  * - `onDestroy`: A callback invoked when a mapped item is removed from the array.
2027
2029
  * - `key`: A custom key extractor for identity matching (e.g. `(item) => item.id`)
@@ -2098,7 +2100,7 @@ function keyArray(source, mapFn, options = {}) {
2098
2100
  items[j] = item;
2099
2101
  const indexSignal = signal(j, ...(ngDevMode ? [{ debugName: "indexSignal" }] : /* istanbul ignore next */ []));
2100
2102
  newIndexes[j] = indexSignal;
2101
- newMapped[j] = mapFn(item, indexSignal);
2103
+ newMapped[j] = mapFn(item, indexSignal, newKeys ? newKeys[j] : getKey(item));
2102
2104
  }
2103
2105
  }
2104
2106
  else {
@@ -2151,7 +2153,7 @@ function keyArray(source, mapFn, options = {}) {
2151
2153
  else {
2152
2154
  const indexSignal = signal(j, ...(ngDevMode ? [{ debugName: "indexSignal" }] : /* istanbul ignore next */ []));
2153
2155
  newIndexes[j] = indexSignal;
2154
- newMapped[j] = mapFn(newItems[j], indexSignal);
2156
+ newMapped[j] = mapFn(newItems[j], indexSignal, kNew(j));
2155
2157
  }
2156
2158
  }
2157
2159
  items.length = newLen;
@@ -6822,6 +6824,9 @@ function stored(fallback, { key, store: providedStore, serialize = JSON.stringif
6822
6824
  writable.key = keySig;
6823
6825
  return writable;
6824
6826
  }
6827
+ function isStored(value) {
6828
+ return 'clear' in value && typeof value.clear === 'function' && 'key' in value;
6829
+ }
6825
6830
 
6826
6831
  /** Op-mode sync for a writable store: hello exchange, then live envelopes. */
6827
6832
  function storeTabSync(sig, opt, bus, injector) {
@@ -7059,6 +7064,125 @@ function tabSync(sig, opt) {
7059
7064
  return sig;
7060
7065
  }
7061
7066
 
7067
+ /**
7068
+ * Wraps any member of the writable-signal family so that every synchronous write
7069
+ * first records an ambient "cause" (via the caller-provided `capture` function)
7070
+ * and then delegates to the original write, preserving the wrapped signal's exact
7071
+ * write semantics. The recorded cause is exposed through a plain {@link Traced.causedBy}
7072
+ * read, letting a downstream consumer attribute a change to whatever caused it —
7073
+ * without any dependency on a particular telemetry system.
7074
+ *
7075
+ * Capture is **synchronous-only** and last-writer-wins: the cause is whatever
7076
+ * `capture()` returns during the `set`/`update`/`mutate`/`inline` call. A write
7077
+ * performed after an `await` (once the ambient cause has been cleared) records
7078
+ * `undefined`; a write while `capture()` returns `undefined` clears the cause.
7079
+ * `causedBy()` is a plain read, not a signal — reading it never subscribes, and
7080
+ * a cause-only change (a write with a different cause but no dependent-visible
7081
+ * value change) never invalidates a consumer.
7082
+ *
7083
+ * The traced twin behaves like the original except for `causedBy`: it carries the
7084
+ * wrapped signal's surface — `asReadonly`, the `mutate`/`inline` methods of a
7085
+ * mutable, and the `from` of a derived — and the underlying write semantics survive
7086
+ * (a traced `derived` still writes through to its source; a traced `toWritable` still
7087
+ * runs its custom `set`). Reads through the twin stay tracked — consumers subscribe
7088
+ * exactly as they would to the source.
7089
+ *
7090
+ * @typeParam S - The wrapped writable-signal type.
7091
+ * @typeParam C - The type of the captured cause.
7092
+ *
7093
+ * @param sig - The writable signal to trace. Any family member is accepted
7094
+ * (`signal`, `mutable`, `derived`, `toWritable`, `stored`, ...).
7095
+ * @param capture - A function invoked synchronously at the start of every write.
7096
+ * Its return value becomes the current cause; returning `undefined`
7097
+ * clears it.
7098
+ * @param opt - Optional configuration.
7099
+ * @param opt.pure - If `true` (the default), the returned twin is a **new** signal
7100
+ * that reads through to `sig`; `sig` itself is left untouched, so
7101
+ * tracing a shared signal never makes the original writable or
7102
+ * alters its behaviour.
7103
+ *
7104
+ * CAUTION: with `pure: false` the write methods are patched
7105
+ * directly onto the `sig` object you passed in — every other
7106
+ * holder of that signal now records causes on write. Only use it
7107
+ * with a signal you created and own exclusively.
7108
+ *
7109
+ * @returns A {@link Traced} twin of `sig` exposing `causedBy()`.
7110
+ *
7111
+ * @example
7112
+ * // A refetch attributing itself to whatever wrote the query.
7113
+ * let activeCause: string | undefined;
7114
+ * const query = traced(signal(''), () => activeCause);
7115
+ *
7116
+ * activeCause = 'user-typed';
7117
+ * query.set('hello');
7118
+ * query.causedBy(); // 'user-typed'
7119
+ *
7120
+ * @example
7121
+ * // Tracing a shared, read-only-exposed signal without making it writable.
7122
+ * const shared = signal(0);
7123
+ * const twin = traced(shared, () => currentInteraction());
7124
+ * twin === shared; // false — the original is untouched
7125
+ */
7126
+ function traced(sig, capture, opt) {
7127
+ const twin = (opt?.pure === false ? sig : facadeOf(sig));
7128
+ let cause;
7129
+ const setOriginal = sig.set.bind(sig);
7130
+ twin.set = (value) => {
7131
+ cause = capture();
7132
+ setOriginal(value);
7133
+ };
7134
+ const updateOriginal = sig.update.bind(sig);
7135
+ twin.update = (updater) => {
7136
+ cause = capture();
7137
+ updateOriginal(updater);
7138
+ };
7139
+ if (isMutable(sig)) {
7140
+ const source = sig;
7141
+ const mutableTwin = twin;
7142
+ const mutateOriginal = source.mutate.bind(source);
7143
+ mutableTwin.mutate = (updater) => {
7144
+ cause = capture();
7145
+ mutateOriginal(updater);
7146
+ };
7147
+ const inlineOriginal = source.inline.bind(source);
7148
+ mutableTwin.inline = (updater) => {
7149
+ cause = capture();
7150
+ inlineOriginal(updater);
7151
+ };
7152
+ }
7153
+ if (isStored(sig)) {
7154
+ const source = sig;
7155
+ const storedTwin = twin;
7156
+ const clearOriginal = source.clear.bind(source);
7157
+ storedTwin.clear = () => {
7158
+ cause = capture();
7159
+ clearOriginal();
7160
+ };
7161
+ }
7162
+ twin.causedBy = () => cause;
7163
+ return twin;
7164
+ }
7165
+ /**
7166
+ * Builds a read-through facade over `sig`: a fresh signal whose reads track `sig`,
7167
+ * carrying `sig`'s non-write surface (`asReadonly`, and `from` on a derived signal)
7168
+ * by explicit delegation. The write methods are attached by {@link traced}. The
7169
+ * facade's `equal` always reports "changed", so it forwards every notification `sig`
7170
+ * emits — including the same-reference `mutate`/`inline` force-notifies that a default
7171
+ * `computed` would swallow (see `mutable`'s docs). The change decision is thereby
7172
+ * delegated entirely to `sig`.
7173
+ */
7174
+ function facadeOf(sig) {
7175
+ const facade = computed(sig, { equal: () => false });
7176
+ facade.asReadonly = sig.asReadonly.bind(sig);
7177
+ if (isDerivation(sig)) {
7178
+ facade.from = sig.from;
7179
+ }
7180
+ if (isStored(sig)) {
7181
+ facade.key = sig.key;
7182
+ }
7183
+ return facade;
7184
+ }
7185
+
7062
7186
  function until(sourceSignal, predicate, options = {}) {
7063
7187
  return new Promise((resolve, reject) => {
7064
7188
  let effectRef;
@@ -7256,5 +7380,5 @@ function withHistory(sourceOrValue, opt) {
7256
7380
  * Generated bundle index. Do not edit.
7257
7381
  */
7258
7382
 
7259
- export { CONCURRENCY_INSTRUMENTATION, MmActivity, MmTransition, MmViewTransitionName, OP_PROTO_VERSION, PAUSABLE_OPTIONS, PERSISTED_STORE_OPTIONS, POS_SEGMENT, SuspenseBoundary, SuspenseBoundaryBase, UnscopedSuspenseBoundary, activeTransaction, applyOps, batteryStatus, bridgeScopeToPendingTasks, chunked, clipboard, combineWith, compareHlc, compareSiblings, compareTotal, createAttributedPending, createConvergingApply, createForwardingScope, createHlcClock, createStoreContext, createTransaction, createTransitionScope, debounce, debounced, defaultFold, deferredValue, derived, diffOps, distinct, elementSize, elementVisibility, extendStore, filter, filterWith, focusWithin, forkStore, geolocation, getTransitionScope, holdUntilReady, idle, indexArray, injectPaused, injectRegisterResource, injectStartTransaction, injectStartTransition, injectTransitionScope, insertElement, invertBatch, isConflicted, isDerivation, isLeaf, isMutable, isOpaque, isStore, keepPrevious, keyArray, keyedArray, latest, lww, map, mapArray, mapObject, mediaQuery, merge3, mergeThree, mousePosition, moveElement, mutable, mutableStore, nestedEffect, networkStatus, opLog, opSync, opaque, orderedEntries, orientation, pageVisibility, pairwise, pausableComputed, pausableEffect, pausableSignal, perfCustomTracks, persist, persistedStore, pipeable, piped, pointerDrag, policyStrategy, pooled, pooledArray, pooledMap, pooledSet, posBetween, prefersDarkMode, prefersReducedMotion, preserve, projection, provideConcurrencyInstrumentation, provideForwardingTransitionScope, providePausableOptions, providePaused, providePersistedStoreOptions, provideTransitionScope, rebalanceContainer, rebaseOps, reconcile, registerResource, removeElement, resolvePause, scan, scrollPosition, select, sensor, sensors, signalFromEvent, startWith, store, storeHistory, stored, syncedFork, tabSync, tap, throttle, throttled, toFakeDerivation, toFakeSignalDerivation, toStore, toWritable, until, use, validateEnvelope, windowSize, withHistory };
7383
+ export { CONCURRENCY_INSTRUMENTATION, MmActivity, MmTransition, MmViewTransitionName, OP_PROTO_VERSION, PAUSABLE_OPTIONS, PERSISTED_STORE_OPTIONS, POS_SEGMENT, SuspenseBoundary, SuspenseBoundaryBase, UnscopedSuspenseBoundary, activeTransaction, applyOps, batteryStatus, bridgeScopeToPendingTasks, chunked, clipboard, combineWith, compareHlc, compareSiblings, compareTotal, createAttributedPending, createConvergingApply, createForwardingScope, createHlcClock, createStoreContext, createTransaction, createTransitionScope, debounce, debounced, defaultFold, deferredValue, derived, diffOps, distinct, elementSize, elementVisibility, extendStore, filter, filterWith, focusWithin, forkStore, geolocation, getTransitionScope, holdUntilReady, idle, indexArray, injectPaused, injectRegisterResource, injectStartTransaction, injectStartTransition, injectTransitionScope, insertElement, invertBatch, isConflicted, isDerivation, isLeaf, isMutable, isOpaque, isStore, isStored, keepPrevious, keyArray, keyedArray, latest, lww, map, mapArray, mapObject, mediaQuery, merge3, mergeThree, mousePosition, moveElement, mutable, mutableStore, nestedEffect, networkStatus, opLog, opSync, opaque, orderedEntries, orientation, pageVisibility, pairwise, pausableComputed, pausableEffect, pausableSignal, perfCustomTracks, persist, persistedStore, pipeable, piped, pointerDrag, policyStrategy, pooled, pooledArray, pooledMap, pooledSet, posBetween, prefersDarkMode, prefersReducedMotion, preserve, projection, provideConcurrencyInstrumentation, provideForwardingTransitionScope, providePausableOptions, providePaused, providePersistedStoreOptions, provideTransitionScope, rebalanceContainer, rebaseOps, reconcile, registerResource, removeElement, resolvePause, scan, scrollPosition, select, sensor, sensors, signalFromEvent, startWith, store, storeHistory, stored, syncedFork, tabSync, tap, throttle, throttled, toFakeDerivation, toFakeSignalDerivation, toStore, toWritable, traced, until, use, validateEnvelope, windowSize, withHistory };
7260
7384
  //# sourceMappingURL=mmstack-primitives.mjs.map