@tldraw/state 4.0.2 → 4.1.0-canary.0259516ffb8c

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.
Files changed (56) hide show
  1. package/dist-cjs/index.d.ts +358 -43
  2. package/dist-cjs/index.js +3 -1
  3. package/dist-cjs/index.js.map +2 -2
  4. package/dist-cjs/lib/ArraySet.js +90 -6
  5. package/dist-cjs/lib/ArraySet.js.map +2 -2
  6. package/dist-cjs/lib/Atom.js +70 -0
  7. package/dist-cjs/lib/Atom.js.map +2 -2
  8. package/dist-cjs/lib/Computed.js +1 -1
  9. package/dist-cjs/lib/Computed.js.map +2 -2
  10. package/dist-cjs/lib/HistoryBuffer.js +57 -9
  11. package/dist-cjs/lib/HistoryBuffer.js.map +2 -2
  12. package/dist-cjs/lib/capture.js.map +2 -2
  13. package/dist-cjs/lib/constants.js.map +2 -2
  14. package/dist-cjs/lib/helpers.js.map +2 -2
  15. package/dist-cjs/lib/isSignal.js.map +2 -2
  16. package/dist-cjs/lib/localStorageAtom.js +60 -0
  17. package/dist-cjs/lib/localStorageAtom.js.map +7 -0
  18. package/dist-cjs/lib/transactions.js.map +2 -2
  19. package/dist-cjs/lib/types.js.map +2 -2
  20. package/dist-cjs/lib/warnings.js.map +2 -2
  21. package/dist-esm/index.d.mts +358 -43
  22. package/dist-esm/index.mjs +3 -1
  23. package/dist-esm/index.mjs.map +2 -2
  24. package/dist-esm/lib/ArraySet.mjs +90 -6
  25. package/dist-esm/lib/ArraySet.mjs.map +2 -2
  26. package/dist-esm/lib/Atom.mjs +70 -0
  27. package/dist-esm/lib/Atom.mjs.map +2 -2
  28. package/dist-esm/lib/Computed.mjs +1 -1
  29. package/dist-esm/lib/Computed.mjs.map +2 -2
  30. package/dist-esm/lib/HistoryBuffer.mjs +57 -9
  31. package/dist-esm/lib/HistoryBuffer.mjs.map +2 -2
  32. package/dist-esm/lib/capture.mjs.map +2 -2
  33. package/dist-esm/lib/constants.mjs.map +2 -2
  34. package/dist-esm/lib/helpers.mjs.map +2 -2
  35. package/dist-esm/lib/isSignal.mjs.map +2 -2
  36. package/dist-esm/lib/localStorageAtom.mjs +40 -0
  37. package/dist-esm/lib/localStorageAtom.mjs.map +7 -0
  38. package/dist-esm/lib/transactions.mjs.map +2 -2
  39. package/dist-esm/lib/types.mjs.map +2 -2
  40. package/dist-esm/lib/warnings.mjs.map +2 -2
  41. package/package.json +2 -2
  42. package/src/index.ts +1 -0
  43. package/src/lib/ArraySet.ts +101 -8
  44. package/src/lib/Atom.ts +92 -0
  45. package/src/lib/Computed.ts +169 -19
  46. package/src/lib/HistoryBuffer.ts +76 -10
  47. package/src/lib/__tests__/helpers.test.ts +168 -0
  48. package/src/lib/__tests__/localStorageAtom.test.ts +183 -0
  49. package/src/lib/capture.ts +56 -1
  50. package/src/lib/constants.ts +25 -1
  51. package/src/lib/helpers.ts +137 -13
  52. package/src/lib/isSignal.ts +24 -0
  53. package/src/lib/localStorageAtom.ts +87 -0
  54. package/src/lib/transactions.ts +79 -10
  55. package/src/lib/types.ts +173 -19
  56. package/src/lib/warnings.ts +36 -0
@@ -95,13 +95,27 @@ export declare interface AtomOptions<Value, Diff> {
95
95
  /* Excluded from this release type: Child */
96
96
 
97
97
  /**
98
- * A computed signal created via `computed`.
98
+ * A computed signal created via the `computed` function or `@computed` decorator.
99
+ * Computed signals derive their values from other signals and automatically update when their dependencies change.
100
+ * They use lazy evaluation, only recalculating when accessed and dependencies have changed.
101
+ *
102
+ * @example
103
+ * ```ts
104
+ * const firstName = atom('firstName', 'John')
105
+ * const lastName = atom('lastName', 'Doe')
106
+ * const fullName = computed('fullName', () => `${firstName.get()} ${lastName.get()}`)
107
+ *
108
+ * console.log(fullName.get()) // "John Doe"
109
+ * firstName.set('Jane')
110
+ * console.log(fullName.get()) // "Jane Doe"
111
+ * ```
99
112
  *
100
113
  * @public
101
114
  */
102
115
  export declare interface Computed<Value, Diff = unknown> extends Signal<Value, Diff> {
103
116
  /**
104
- * Whether this computed child is involved in an actively-running effect graph.
117
+ * Whether this computed signal is involved in an actively-running effect graph.
118
+ * Returns true if there are any reactions or other computed signals depending on this one.
105
119
  * @public
106
120
  */
107
121
  readonly isActivelyListening: boolean;
@@ -111,7 +125,9 @@ export declare interface Computed<Value, Diff = unknown> extends Signal<Value, D
111
125
  }
112
126
 
113
127
  /**
114
- * Creates a computed signal.
128
+ * Creates a computed signal that derives its value from other signals.
129
+ * Computed signals automatically update when their dependencies change and use lazy evaluation
130
+ * for optimal performance.
115
131
  *
116
132
  * @example
117
133
  * ```ts
@@ -149,43 +165,135 @@ export declare interface Computed<Value, Diff = unknown> extends Signal<Value, D
149
165
  * }
150
166
  * ```
151
167
  *
152
- * @param name - The name of the signal.
153
- * @param compute - The function that computes the value of the signal.
154
- * @param options - Options for the signal.
155
- *
168
+ * @param name - The name of the signal for debugging purposes
169
+ * @param compute - The function that computes the value of the signal. Receives the previous value and last computed epoch
170
+ * @param options - Optional configuration for the computed signal
171
+ * @returns A new computed signal
156
172
  * @public
157
173
  */
158
174
  export declare function computed<Value, Diff = unknown>(name: string, compute: (previousValue: typeof UNINITIALIZED | Value, lastComputedEpoch: number) => Value | WithDiff<Value, Diff>, options?: ComputedOptions<Value, Diff>): Computed<Value, Diff>;
159
175
 
160
176
  /**
161
- * `@computed` decorator (TC39 decorators).
177
+ * TC39 decorator for creating computed methods in classes.
178
+ *
179
+ * @example
180
+ * ```ts
181
+ * class MyClass {
182
+ * value = atom('value', 10)
183
+ *
184
+ * @computed
185
+ * doubled() {
186
+ * return this.value.get() * 2
187
+ * }
188
+ * }
189
+ * ```
190
+ *
191
+ * @param compute - The method to be decorated
192
+ * @param context - The decorator context provided by TypeScript
193
+ * @returns The decorated method
162
194
  * @public
163
195
  */
164
196
  export declare function computed<This extends object, Value>(compute: () => Value, context: ClassMethodDecoratorContext<This, () => Value>): () => Value;
165
197
 
166
198
  /**
167
- * `@computed` decorator (legacy typescript decorator syntax).
199
+ * Legacy TypeScript decorator for creating computed methods in classes.
200
+ *
201
+ * @example
202
+ * ```ts
203
+ * class MyClass {
204
+ * value = atom('value', 10)
205
+ *
206
+ * @computed
207
+ * doubled() {
208
+ * return this.value.get() * 2
209
+ * }
210
+ * }
211
+ * ```
168
212
  *
169
- * @public */
213
+ * @param target - The class prototype
214
+ * @param key - The property key
215
+ * @param descriptor - The property descriptor
216
+ * @returns The modified property descriptor
217
+ * @public
218
+ */
170
219
  export declare function computed(target: any, key: string, descriptor: PropertyDescriptor): PropertyDescriptor;
171
220
 
172
221
  /**
173
- * `@computed` decorator with options.
222
+ * Decorator factory for creating computed methods with options.
223
+ *
224
+ * @example
225
+ * ```ts
226
+ * class MyClass {
227
+ * items = atom('items', [1, 2, 3])
228
+ *
229
+ * @computed({ historyLength: 10 })
230
+ * sum() {
231
+ * return this.items.get().reduce((a, b) => a + b, 0)
232
+ * }
233
+ * }
234
+ * ```
235
+ *
236
+ * @param options - Configuration options for the computed signal
237
+ * @returns A decorator function that can be applied to methods
174
238
  * @public
175
239
  */
176
240
  export declare function computed<Value, Diff = unknown>(options?: ComputedOptions<Value, Diff>): ((target: any, key: string, descriptor: PropertyDescriptor) => PropertyDescriptor) & (<This>(compute: () => Value, context: ClassMethodDecoratorContext<This, () => Value>) => () => Value);
177
241
 
178
242
  /**
179
- * Computes the diff between the previous and current value.
243
+ * A function type that computes the difference between two values of a signal.
244
+ *
245
+ * This function is used to generate incremental diffs that can be applied to
246
+ * reconstruct state changes over time. It's particularly useful for features
247
+ * like undo/redo, synchronization, and change tracking.
248
+ *
249
+ * The function should analyze the previous and current values and return a
250
+ * diff object that represents the change. If the diff cannot be computed
251
+ * (e.g., the values are too different or incompatible), it should return
252
+ * the unique symbol RESET_VALUE to indicate that a full state reset is required.
253
+ *
254
+ * @param previousValue - The previous value of the signal
255
+ * @param currentValue - The current value of the signal
256
+ * @param lastComputedEpoch - The epoch when the previous value was set
257
+ * @param currentEpoch - The epoch when the current value was set
258
+ * @returns A diff object representing the change, or the unique symbol RESET_VALUE if no diff can be computed
259
+ *
260
+ * @example
261
+ * ```ts
262
+ * import { atom, RESET_VALUE } from '@tldraw/state'
180
263
  *
181
- * If the diff cannot be computed for whatever reason, it should return {@link state#RESET_VALUE}.
264
+ * // Simple numeric diff
265
+ * const numberDiff: ComputeDiff<number, number> = (prev, curr) => curr - prev
266
+ *
267
+ * // Array diff with reset fallback
268
+ * const arrayDiff: ComputeDiff<string[], { added: string[], removed: string[] }> = (prev, curr) => {
269
+ * if (prev.length > 1000 || curr.length > 1000) {
270
+ * return RESET_VALUE // Too complex, force reset
271
+ * }
272
+ * return {
273
+ * added: curr.filter(item => !prev.includes(item)),
274
+ * removed: prev.filter(item => !curr.includes(item))
275
+ * }
276
+ * }
277
+ *
278
+ * const count = atom('count', 0, { computeDiff: numberDiff })
279
+ * ```
182
280
  *
183
281
  * @public
184
282
  */
185
283
  export declare type ComputeDiff<Value, Diff> = (previousValue: Value, currentValue: Value, lastComputedEpoch: number, currentEpoch: number) => Diff | RESET_VALUE;
186
284
 
187
285
  /**
188
- * Options for creating computed signals. Used when calling `computed`.
286
+ * Options for configuring computed signals. Used when calling `computed` or using the `@computed` decorator.
287
+ *
288
+ * @example
289
+ * ```ts
290
+ * const greeting = computed('greeting', () => `Hello ${name.get()}!`, {
291
+ * historyLength: 10,
292
+ * isEqual: (a, b) => a === b,
293
+ * computeDiff: (oldVal, newVal) => ({ type: 'change', from: oldVal, to: newVal })
294
+ * })
295
+ * ```
296
+ *
189
297
  * @public
190
298
  */
191
299
  export declare interface ComputedOptions<Value, Diff> {
@@ -347,11 +455,46 @@ export declare function getComputedInstance<Obj extends object, Prop extends key
347
455
 
348
456
  /**
349
457
  * Returns true if the given value is an {@link Atom}.
458
+ *
459
+ * @param value - The value to check
460
+ * @returns True if the value is an Atom, false otherwise
461
+ * @example
462
+ * ```ts
463
+ * const myAtom = atom('test', 42)
464
+ * const notAtom = 'hello'
465
+ *
466
+ * console.log(isAtom(myAtom)) // true
467
+ * console.log(isAtom(notAtom)) // false
468
+ * ```
350
469
  * @public
351
470
  */
352
471
  export declare function isAtom(value: unknown): value is Atom<unknown>;
353
472
 
354
473
  /**
474
+ * Type guard function that determines whether a value is a signal (either an Atom or Computed).
475
+ *
476
+ * This utility function is helpful when working with mixed data types and you need to
477
+ * differentiate between regular values and reactive signal containers. It returns `true`
478
+ * if the provided value is either an atomic signal created with `atom()` or a computed
479
+ * signal created with `computed()`.
480
+ *
481
+ * @param value - The value to check, can be of any type
482
+ * @returns `true` if the value is a Signal (Atom or Computed), `false` otherwise
483
+ *
484
+ * @example
485
+ * ```ts
486
+ * import { atom, computed, isSignal } from '@tldraw/state'
487
+ *
488
+ * const count = atom('count', 5)
489
+ * const doubled = computed('doubled', () => count.get() * 2)
490
+ * const regularValue = 'hello'
491
+ *
492
+ * console.log(isSignal(count)) // true
493
+ * console.log(isSignal(doubled)) // true
494
+ * console.log(isSignal(regularValue)) // false
495
+ * console.log(isSignal(null)) // false
496
+ * ```
497
+ *
355
498
  * @public
356
499
  */
357
500
  export declare function isSignal(value: any): value is Signal<any>;
@@ -377,6 +520,35 @@ export declare function isSignal(value: any): value is Signal<any>;
377
520
  */
378
521
  export declare function isUninitialized(value: any): value is UNINITIALIZED;
379
522
 
523
+ /**
524
+ * Creates a new {@link Atom} that persists its value to localStorage.
525
+ *
526
+ * The atom is automatically synced with localStorage - changes to the atom are saved to localStorage,
527
+ * and the initial value is read from localStorage if it exists. Returns both the atom and a cleanup
528
+ * function that should be called to stop syncing when the atom is no longer needed. If you need to delete
529
+ * the atom, you should do it manually after all cleanup functions have been called.
530
+ *
531
+ * @example
532
+ * ```ts
533
+ * const [theme, cleanup] = localStorageAtom('theme', 'light')
534
+ *
535
+ * theme.get() // 'light' or value from localStorage if it exists
536
+ *
537
+ * theme.set('dark') // updates atom and saves to localStorage
538
+ *
539
+ * // When done:
540
+ * cleanup() // stops syncing to localStorage
541
+ * ```
542
+ *
543
+ * @param name - The localStorage key and atom name. This is used for both localStorage persistence
544
+ * and debugging/profiling purposes.
545
+ * @param initialValue - The initial value of the atom, used if no value exists in localStorage.
546
+ * @param options - Optional atom configuration. See {@link AtomOptions}.
547
+ * @returns A tuple containing the atom and a cleanup function to stop localStorage syncing.
548
+ * @public
549
+ */
550
+ export declare function localStorageAtom<Value, Diff = unknown>(name: string, initialValue: Value, options?: AtomOptions<Value, Diff>): [Atom<Value, Diff>, () => void];
551
+
380
552
  /**
381
553
  * Starts a new effect scheduler, scheduling the effect immediately.
382
554
  *
@@ -450,47 +622,125 @@ export declare interface Reactor<T = unknown> {
450
622
  */
451
623
  export declare function reactor<Result>(name: string, fn: (lastReactedEpoch: number) => Result, options?: EffectSchedulerOptions): Reactor<Result>;
452
624
 
453
- /** @public */
625
+ /**
626
+ * A unique symbol used to indicate that a signal's value should be reset or that
627
+ * there is insufficient history to compute diffs between epochs.
628
+ *
629
+ * This value is returned by {@link Signal.getDiffSince} when the requested epoch
630
+ * is too far in the past and the diff sequence cannot be reconstructed.
631
+ *
632
+ * @example
633
+ * ```ts
634
+ * import { atom, getGlobalEpoch, RESET_VALUE } from '@tldraw/state'
635
+ *
636
+ * const count = atom('count', 0, { historyLength: 3 })
637
+ * const oldEpoch = getGlobalEpoch()
638
+ *
639
+ * // Make many changes that exceed history length
640
+ * count.set(1)
641
+ * count.set(2)
642
+ * count.set(3)
643
+ * count.set(4)
644
+ *
645
+ * const diffs = count.getDiffSince(oldEpoch)
646
+ * if (diffs === RESET_VALUE) {
647
+ * console.log('Too many changes, need to reset state')
648
+ * }
649
+ * ```
650
+ *
651
+ * @public
652
+ */
454
653
  export declare const RESET_VALUE: unique symbol;
455
654
 
456
- /** @public */
655
+ /**
656
+ * Type representing the the unique symbol RESET_VALUE symbol, used in type annotations
657
+ * to indicate when a signal value should be reset or when diff computation
658
+ * cannot proceed due to insufficient history.
659
+ *
660
+ * @public
661
+ */
457
662
  export declare type RESET_VALUE = typeof RESET_VALUE;
458
663
 
459
664
  /**
460
- * A Signal is a reactive value container. The value may change over time, and it may keep track of the diffs between sequential values.
665
+ * A reactive value container that can change over time and track diffs between sequential values.
666
+ *
667
+ * Signals are the foundation of the \@tldraw/state reactive system. They automatically manage
668
+ * dependencies and trigger updates when their values change. Any computed signal or effect
669
+ * that reads from this signal will be automatically recomputed when the signal's value changes.
461
670
  *
462
671
  * There are two types of signal:
672
+ * - **Atomic signals** - Created using `atom()`. These are mutable containers that can be
673
+ * directly updated using `set()` or `update()` methods.
674
+ * - **Computed signals** - Created using `computed()`. These derive their values from other
675
+ * signals and are automatically recomputed when dependencies change.
676
+ *
677
+ * @example
678
+ * ```ts
679
+ * import { atom, computed } from '@tldraw/state'
463
680
  *
464
- * - Atomic signals, created using {@link atom}. These are mutable references to values that can be changed using {@link Atom.set}.
465
- * - Computed signals, created using `computed`. These are values that are computed from other signals. They are recomputed lazily if their dependencies change.
681
+ * // Create an atomic signal
682
+ * const count = atom('count', 0)
683
+ *
684
+ * // Create a computed signal that derives from the atom
685
+ * const doubled = computed('doubled', () => count.get() * 2)
686
+ *
687
+ * console.log(doubled.get()) // 0
688
+ * count.set(5)
689
+ * console.log(doubled.get()) // 10
690
+ * ```
466
691
  *
467
692
  * @public
468
693
  */
469
694
  export declare interface Signal<Value, Diff = unknown> {
470
695
  /**
471
- * The name of the signal. This is used at runtime for debugging and perf profiling only. It does not need to be globally unique.
696
+ * A human-readable identifier for this signal, used primarily for debugging and performance profiling.
697
+ *
698
+ * The name is displayed in debug output from {@link whyAmIRunning} and other diagnostic tools.
699
+ * It does not need to be globally unique within your application.
472
700
  */
473
701
  name: string;
474
702
  /**
475
- * The current value of the signal. This is a reactive value, and will update when the signal changes.
476
- * Any computed signal that depends on this signal will be lazily recomputed if this signal changes.
477
- * Any effect that depends on this signal will be rescheduled if this signal changes.
703
+ * Gets the current value of the signal and establishes a dependency relationship.
704
+ *
705
+ * When called from within a computed signal or effect, this signal will be automatically
706
+ * tracked as a dependency. If this signal's value changes, any dependent computations
707
+ * or effects will be marked for re-execution.
708
+ *
709
+ * @returns The current value stored in the signal
478
710
  */
479
711
  get(): Value;
480
712
  /**
481
- * The epoch when this signal's value last changed. Note that this is not the same as when the value was last computed.
482
- * A signal may recompute it's value without changing it.
713
+ * The global epoch number when this signal's value last changed.
714
+ *
715
+ * Note that this represents when the value actually changed, not when it was last computed.
716
+ * A computed signal may recalculate and produce the same value without changing its epoch.
717
+ * This is used internally for dependency tracking and history management.
483
718
  */
484
719
  lastChangedEpoch: number;
485
720
  /**
486
- * Returns the sequence of diffs between the the value at the given epoch and the current value.
487
- * Returns the `RESET_VALUE` constant if there is not enough information to compute the diff sequence.
488
- * @param epoch - The epoch to get diffs since.
721
+ * Gets the sequence of diffs that occurred between a specific epoch and the current state.
722
+ *
723
+ * This method enables incremental synchronization by providing a list of changes that
724
+ * have occurred since a specific point in time. If the requested epoch is too far in
725
+ * the past or the signal doesn't have enough history, it returns the unique symbol RESET_VALUE
726
+ * to indicate that a full state reset is required.
727
+ *
728
+ * @param epoch - The epoch timestamp to get diffs since
729
+ * @returns An array of diff objects representing changes since the epoch, or the unique symbol RESET_VALUE if insufficient history is available
489
730
  */
490
731
  getDiffSince(epoch: number): Diff[] | RESET_VALUE;
491
732
  /**
492
- * Returns the current value of the signal without capturing it as a dependency.
493
- * Use this if you need to retrieve the signal's value in a hot loop where the performance overhead of dependency tracking is too high.
733
+ * Gets the current value of the signal without establishing a dependency relationship.
734
+ *
735
+ * This method bypasses the automatic dependency tracking system, making it useful for
736
+ * performance-critical code paths where the overhead of dependency capture would be
737
+ * problematic. Use with caution as it breaks the reactive guarantees of the system.
738
+ *
739
+ * **Warning**: This method should only be used when you're certain that you don't need
740
+ * the calling context to react to changes in this signal.
741
+ *
742
+ * @param ignoreErrors - Whether to suppress errors during value retrieval (optional)
743
+ * @returns The current value without establishing dependencies
494
744
  */
495
745
  __unsafe__getWithoutCapture(ignoreErrors?: boolean): Value;
496
746
  /* Excluded from this release type: children */
@@ -498,22 +748,42 @@ export declare interface Signal<Value, Diff = unknown> {
498
748
 
499
749
  /**
500
750
  * Like {@link transaction}, but does not create a new transaction if there is already one in progress.
751
+ * This is the preferred way to batch state updates when you don't need the rollback functionality.
752
+ *
753
+ * @example
754
+ * ```ts
755
+ * const count = atom('count', 0)
756
+ * const doubled = atom('doubled', 0)
501
757
  *
502
- * @param fn - The function to run in a transaction.
758
+ * react('update doubled', () => {
759
+ * console.log(`Count: ${count.get()}, Doubled: ${doubled.get()}`)
760
+ * })
761
+ *
762
+ * // This batches both updates into a single reaction
763
+ * transact(() => {
764
+ * count.set(5)
765
+ * doubled.set(count.get() * 2)
766
+ * })
767
+ * // Logs: "Count: 5, Doubled: 10"
768
+ * ```
769
+ *
770
+ * @param fn - The function to run in a transaction
771
+ * @returns The return value of the function
503
772
  * @public
504
773
  */
505
774
  export declare function transact<T>(fn: () => T): T;
506
775
 
507
776
  /**
508
777
  * Batches state updates, deferring side effects until after the transaction completes.
778
+ * Unlike {@link transact}, this function always creates a new transaction, allowing for nested transactions.
509
779
  *
510
780
  * @example
511
781
  * ```ts
512
- * const firstName = atom('John')
513
- * const lastName = atom('Doe')
782
+ * const firstName = atom('firstName', 'John')
783
+ * const lastName = atom('lastName', 'Doe')
514
784
  *
515
785
  * react('greet', () => {
516
- * print(`Hello, ${firstName.get()} ${lastName.get()}!`)
786
+ * console.log(`Hello, ${firstName.get()} ${lastName.get()}!`)
517
787
  * })
518
788
  *
519
789
  * // Logs "Hello, John Doe!"
@@ -530,11 +800,11 @@ export declare function transact<T>(fn: () => T): T;
530
800
  *
531
801
  * @example
532
802
  * ```ts
533
- * const firstName = atom('John')
534
- * const lastName = atom('Doe')
803
+ * const firstName = atom('firstName', 'John')
804
+ * const lastName = atom('lastName', 'Doe')
535
805
  *
536
806
  * react('greet', () => {
537
- * print(`Hello, ${firstName.get()} ${lastName.get()}!`)
807
+ * console.log(`Hello, ${firstName.get()} ${lastName.get()}!`)
538
808
  * })
539
809
  *
540
810
  * // Logs "Hello, John Doe!"
@@ -553,11 +823,11 @@ export declare function transact<T>(fn: () => T): T;
553
823
  *
554
824
  * @example
555
825
  * ```ts
556
- * const firstName = atom('John')
557
- * const lastName = atom('Doe')
826
+ * const firstName = atom('firstName', 'John')
827
+ * const lastName = atom('lastName', 'Doe')
558
828
  *
559
829
  * react('greet', () => {
560
- * print(`Hello, ${firstName.get()} ${lastName.get()}!`)
830
+ * console.log(`Hello, ${firstName.get()} ${lastName.get()}!`)
561
831
  * })
562
832
  *
563
833
  * // Logs "Hello, John Doe!"
@@ -574,19 +844,35 @@ export declare function transact<T>(fn: () => T): T;
574
844
  * ```
575
845
  *
576
846
  * @param fn - The function to run in a transaction, called with a function to roll back the change.
847
+ * @returns The return value of the function
577
848
  * @public
578
849
  */
579
850
  export declare function transaction<T>(fn: (rollback: () => void) => T): T;
580
851
 
581
852
  /**
853
+ * A special symbol used to indicate that a computed signal has not been initialized yet.
854
+ * This is passed as the `previousValue` parameter to a computed signal function on its first run.
855
+ *
856
+ * @example
857
+ * ```ts
858
+ * const count = atom('count', 0)
859
+ * const double = computed('double', (prevValue) => {
860
+ * if (isUninitialized(prevValue)) {
861
+ * console.log('First computation!')
862
+ * }
863
+ * return count.get() * 2
864
+ * })
865
+ * ```
866
+ *
582
867
  * @public
583
868
  */
584
869
  export declare const UNINITIALIZED: unique symbol;
585
870
 
586
871
  /**
587
872
  * The type of the first value passed to a computed signal function as the 'prevValue' parameter.
873
+ * This type represents the uninitialized state of a computed signal before its first calculation.
588
874
  *
589
- * @see {@link isUninitialized}.
875
+ * @see {@link isUninitialized}
590
876
  * @public
591
877
  */
592
878
  export declare type UNINITIALIZED = typeof UNINITIALIZED;
@@ -638,7 +924,25 @@ export declare function unsafe__withoutCapture<T>(fn: () => T): T;
638
924
  */
639
925
  export declare function whyAmIRunning(): void;
640
926
 
641
- /** @public */
927
+ /**
928
+ * A singleton class used to wrap computed signal values along with their diffs.
929
+ * This class is used internally by the {@link withDiff} function to provide both
930
+ * the computed value and its diff to the signal system.
931
+ *
932
+ * @example
933
+ * ```ts
934
+ * const count = atom('count', 0)
935
+ * const double = computed('double', (prevValue) => {
936
+ * const nextValue = count.get() * 2
937
+ * if (isUninitialized(prevValue)) {
938
+ * return nextValue
939
+ * }
940
+ * return withDiff(nextValue, nextValue - prevValue)
941
+ * })
942
+ * ```
943
+ *
944
+ * @public
945
+ */
642
946
  export declare const WithDiff: {
643
947
  new <Value, Diff>(value: Value, diff: Diff): {
644
948
  diff: Diff;
@@ -646,9 +950,20 @@ export declare const WithDiff: {
646
950
  };
647
951
  };
648
952
 
649
- /** @public */
953
+ /**
954
+ * Interface representing a value wrapped with its corresponding diff.
955
+ * Used in incremental computation to provide both the new value and the diff from the previous value.
956
+ *
957
+ * @public
958
+ */
650
959
  export declare interface WithDiff<Value, Diff> {
960
+ /**
961
+ * The computed value.
962
+ */
651
963
  value: Value;
964
+ /**
965
+ * The diff between the previous and current value.
966
+ */
652
967
  diff: Diff;
653
968
  }
654
969
 
package/dist-cjs/index.js CHANGED
@@ -30,6 +30,7 @@ __export(index_exports, {
30
30
  isAtom: () => import_Atom.isAtom,
31
31
  isSignal: () => import_isSignal.isSignal,
32
32
  isUninitialized: () => import_Computed.isUninitialized,
33
+ localStorageAtom: () => import_localStorageAtom.localStorageAtom,
33
34
  react: () => import_EffectScheduler.react,
34
35
  reactor: () => import_EffectScheduler.reactor,
35
36
  transact: () => import_transactions.transact,
@@ -48,6 +49,7 @@ var import_Computed = require("./lib/Computed");
48
49
  var import_EffectScheduler = require("./lib/EffectScheduler");
49
50
  var import_helpers2 = require("./lib/helpers");
50
51
  var import_isSignal = require("./lib/isSignal");
52
+ var import_localStorageAtom = require("./lib/localStorageAtom");
51
53
  var import_transactions = require("./lib/transactions");
52
54
  var import_types = require("./lib/types");
53
55
  const currentApiVersion = 1;
@@ -59,7 +61,7 @@ if (actualApiVersion !== currentApiVersion) {
59
61
  }
60
62
  (0, import_utils.registerTldrawLibraryVersion)(
61
63
  "@tldraw/state",
62
- "4.0.2",
64
+ "4.1.0-canary.0259516ffb8c",
63
65
  "cjs"
64
66
  );
65
67
  //# sourceMappingURL=index.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/index.ts"],
4
- "sourcesContent": ["import { registerTldrawLibraryVersion } from '@tldraw/utils'\nimport { singleton } from './lib/helpers'\n\nexport { ArraySet } from './lib/ArraySet'\nexport { atom, isAtom } from './lib/Atom'\nexport type { Atom, AtomOptions } from './lib/Atom'\nexport { unsafe__withoutCapture, whyAmIRunning } from './lib/capture'\nexport {\n\tcomputed,\n\tgetComputedInstance,\n\tisUninitialized,\n\tUNINITIALIZED,\n\twithDiff,\n} from './lib/Computed'\nexport type { Computed, ComputedOptions, WithDiff } from './lib/Computed'\nexport { EffectScheduler, react, reactor } from './lib/EffectScheduler'\nexport type { EffectSchedulerOptions, Reactor } from './lib/EffectScheduler'\nexport { EMPTY_ARRAY } from './lib/helpers'\nexport { isSignal } from './lib/isSignal'\nexport { deferAsyncEffects, transact, transaction } from './lib/transactions'\nexport { RESET_VALUE } from './lib/types'\nexport type { Child, ComputeDiff, Signal } from './lib/types'\n\n// This should be incremented any time an API change is made. i.e. for additions or removals.\n// Bugfixes need not increment this.\nconst currentApiVersion = 1\n\nconst actualApiVersion = singleton('apiVersion', () => currentApiVersion)\n\nif (actualApiVersion !== currentApiVersion) {\n\tthrow new Error(\n\t\t`You have multiple incompatible versions of @tldraw/state in your app. Please deduplicate the package.`\n\t)\n}\n\nregisterTldrawLibraryVersion(\n\t(globalThis as any).TLDRAW_LIBRARY_NAME,\n\t(globalThis as any).TLDRAW_LIBRARY_VERSION,\n\t(globalThis as any).TLDRAW_LIBRARY_MODULES\n)\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAA6C;AAC7C,qBAA0B;AAE1B,sBAAyB;AACzB,kBAA6B;AAE7B,qBAAsD;AACtD,sBAMO;AAEP,6BAAgD;AAEhD,IAAAA,kBAA4B;AAC5B,sBAAyB;AACzB,0BAAyD;AACzD,mBAA4B;AAK5B,MAAM,oBAAoB;AAE1B,MAAM,uBAAmB,0BAAU,cAAc,MAAM,iBAAiB;AAExE,IAAI,qBAAqB,mBAAmB;AAC3C,QAAM,IAAI;AAAA,IACT;AAAA,EACD;AACD;AAAA,IAEA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AACF;",
4
+ "sourcesContent": ["import { registerTldrawLibraryVersion } from '@tldraw/utils'\nimport { singleton } from './lib/helpers'\n\nexport { ArraySet } from './lib/ArraySet'\nexport { atom, isAtom } from './lib/Atom'\nexport type { Atom, AtomOptions } from './lib/Atom'\nexport { unsafe__withoutCapture, whyAmIRunning } from './lib/capture'\nexport {\n\tcomputed,\n\tgetComputedInstance,\n\tisUninitialized,\n\tUNINITIALIZED,\n\twithDiff,\n} from './lib/Computed'\nexport type { Computed, ComputedOptions, WithDiff } from './lib/Computed'\nexport { EffectScheduler, react, reactor } from './lib/EffectScheduler'\nexport type { EffectSchedulerOptions, Reactor } from './lib/EffectScheduler'\nexport { EMPTY_ARRAY } from './lib/helpers'\nexport { isSignal } from './lib/isSignal'\nexport { localStorageAtom } from './lib/localStorageAtom'\nexport { deferAsyncEffects, transact, transaction } from './lib/transactions'\nexport { RESET_VALUE } from './lib/types'\nexport type { Child, ComputeDiff, Signal } from './lib/types'\n\n// This should be incremented any time an API change is made. i.e. for additions or removals.\n// Bugfixes need not increment this.\nconst currentApiVersion = 1\n\nconst actualApiVersion = singleton('apiVersion', () => currentApiVersion)\n\nif (actualApiVersion !== currentApiVersion) {\n\tthrow new Error(\n\t\t`You have multiple incompatible versions of @tldraw/state in your app. Please deduplicate the package.`\n\t)\n}\n\nregisterTldrawLibraryVersion(\n\t(globalThis as any).TLDRAW_LIBRARY_NAME,\n\t(globalThis as any).TLDRAW_LIBRARY_VERSION,\n\t(globalThis as any).TLDRAW_LIBRARY_MODULES\n)\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAA6C;AAC7C,qBAA0B;AAE1B,sBAAyB;AACzB,kBAA6B;AAE7B,qBAAsD;AACtD,sBAMO;AAEP,6BAAgD;AAEhD,IAAAA,kBAA4B;AAC5B,sBAAyB;AACzB,8BAAiC;AACjC,0BAAyD;AACzD,mBAA4B;AAK5B,MAAM,oBAAoB;AAE1B,MAAM,uBAAmB,0BAAU,cAAc,MAAM,iBAAiB;AAExE,IAAI,qBAAqB,mBAAmB;AAC3C,QAAM,IAAI;AAAA,IACT;AAAA,EACD;AACD;AAAA,IAEA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AACF;",
6
6
  "names": ["import_helpers"]
7
7
  }