@mmstack/primitives 20.0.0 → 20.0.1

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.
@@ -136,25 +136,112 @@ function debounce(source, opt) {
136
136
  return writable;
137
137
  }
138
138
 
139
+ const { is } = Object;
140
+ function mutable(initial, opt) {
141
+ const baseEqual = opt?.equal ?? is;
142
+ let trigger = false;
143
+ const equal = (a, b) => {
144
+ if (trigger)
145
+ return false;
146
+ return baseEqual(a, b);
147
+ };
148
+ const sig = signal(initial, {
149
+ ...opt,
150
+ equal,
151
+ });
152
+ const internalUpdate = sig.update;
153
+ sig.mutate = (updater) => {
154
+ trigger = true;
155
+ internalUpdate(updater);
156
+ trigger = false;
157
+ };
158
+ sig.inline = (updater) => {
159
+ sig.mutate((prev) => {
160
+ updater(prev);
161
+ return prev;
162
+ });
163
+ };
164
+ return sig;
165
+ }
166
+ /**
167
+ * Type guard function to check if a given `WritableSignal` is a `MutableSignal`. This is useful
168
+ * for situations where you need to conditionally use the `mutate` or `inline` methods.
169
+ *
170
+ * @typeParam T - The type of the signal's value (optional, defaults to `any`).
171
+ * @param value - The `WritableSignal` to check.
172
+ * @returns `true` if the signal is a `MutableSignal`, `false` otherwise.
173
+ *
174
+ * @example
175
+ * const mySignal = signal(0);
176
+ * const myMutableSignal = mutable(0);
177
+ *
178
+ * if (isMutable(mySignal)) {
179
+ * mySignal.mutate(x => x + 1); // This would cause a type error, as mySignal is not a MutableSignal.
180
+ * }
181
+ *
182
+ * if (isMutable(myMutableSignal)) {
183
+ * myMutableSignal.mutate(x => x + 1); // This is safe.
184
+ * }
185
+ */
186
+ function isMutable(value) {
187
+ return 'mutate' in value && typeof value.mutate === 'function';
188
+ }
189
+
139
190
  function derived(source, optOrKey, opt) {
140
191
  const isArray = Array.isArray(untracked(source)) && typeof optOrKey === 'number';
141
192
  const from = typeof optOrKey === 'object' ? optOrKey.from : (v) => v[optOrKey];
142
193
  const onChange = typeof optOrKey === 'object'
143
194
  ? optOrKey.onChange
144
195
  : isArray
145
- ? (next) => {
146
- source.update((cur) => {
147
- const newArray = [...cur];
148
- newArray[optOrKey] = next;
149
- return newArray;
150
- });
151
- }
152
- : (next) => {
153
- source.update((cur) => ({ ...cur, [optOrKey]: next }));
154
- };
196
+ ? isMutable(source)
197
+ ? (next) => {
198
+ source.mutate((cur) => {
199
+ cur[optOrKey] = next;
200
+ return cur;
201
+ });
202
+ }
203
+ : (next) => {
204
+ source.update((cur) => {
205
+ const newArray = [...cur];
206
+ newArray[optOrKey] = next;
207
+ return newArray;
208
+ });
209
+ }
210
+ : isMutable(source)
211
+ ? (next) => {
212
+ source.mutate((cur) => {
213
+ cur[optOrKey] = next;
214
+ return cur;
215
+ });
216
+ }
217
+ : (next) => {
218
+ source.update((cur) => ({ ...cur, [optOrKey]: next }));
219
+ };
155
220
  const rest = typeof optOrKey === 'object' ? optOrKey : opt;
156
- const sig = toWritable(computed(() => from(source()), rest), (newVal) => onChange(newVal));
221
+ let baseEqual = rest?.equal ?? Object.is;
222
+ let trigger = false;
223
+ const equal = isMutable(source)
224
+ ? (a, b) => {
225
+ if (trigger)
226
+ return false;
227
+ return baseEqual(a, b);
228
+ }
229
+ : baseEqual;
230
+ const sig = toWritable(computed(() => from(source()), { ...rest, equal }), (newVal) => onChange(newVal));
157
231
  sig.from = from;
232
+ if (isMutable(source)) {
233
+ sig.mutate = (updater) => {
234
+ trigger = true;
235
+ sig.update(updater);
236
+ trigger = false;
237
+ };
238
+ sig.inline = (updater) => {
239
+ sig.mutate((prev) => {
240
+ updater(prev);
241
+ return prev;
242
+ });
243
+ };
244
+ }
158
245
  return sig;
159
246
  }
160
247
  /**
@@ -387,57 +474,6 @@ function mapArray(source, map, opt) {
387
474
  });
388
475
  }
389
476
 
390
- const { is } = Object;
391
- function mutable(initial, opt) {
392
- const baseEqual = opt?.equal ?? is;
393
- let trigger = false;
394
- const equal = (a, b) => {
395
- if (trigger)
396
- return false;
397
- return baseEqual(a, b);
398
- };
399
- const sig = signal(initial, {
400
- ...opt,
401
- equal,
402
- });
403
- const internalUpdate = sig.update;
404
- sig.mutate = (updater) => {
405
- trigger = true;
406
- internalUpdate(updater);
407
- trigger = false;
408
- };
409
- sig.inline = (updater) => {
410
- sig.mutate((prev) => {
411
- updater(prev);
412
- return prev;
413
- });
414
- };
415
- return sig;
416
- }
417
- /**
418
- * Type guard function to check if a given `WritableSignal` is a `MutableSignal`. This is useful
419
- * for situations where you need to conditionally use the `mutate` or `inline` methods.
420
- *
421
- * @typeParam T - The type of the signal's value (optional, defaults to `any`).
422
- * @param value - The `WritableSignal` to check.
423
- * @returns `true` if the signal is a `MutableSignal`, `false` otherwise.
424
- *
425
- * @example
426
- * const mySignal = signal(0);
427
- * const myMutableSignal = mutable(0);
428
- *
429
- * if (isMutable(mySignal)) {
430
- * mySignal.mutate(x => x + 1); // This would cause a type error, as mySignal is not a MutableSignal.
431
- * }
432
- *
433
- * if (isMutable(myMutableSignal)) {
434
- * myMutableSignal.mutate(x => x + 1); // This is safe.
435
- * }
436
- */
437
- function isMutable(value) {
438
- return 'mutate' in value && typeof value.mutate === 'function';
439
- }
440
-
441
477
  /**
442
478
  * Creates a read-only signal that reactively tracks whether a CSS media query
443
479
  * string currently matches.