@tldraw/state 4.6.0-next.5a871ec02ff3 → 4.6.0-next.6594d48ace27

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 (46) hide show
  1. package/dist-cjs/index.js +1 -1
  2. package/dist-cjs/lib/ArraySet.js +1 -1
  3. package/dist-cjs/lib/ArraySet.js.map +1 -1
  4. package/dist-cjs/lib/Atom.js +3 -1
  5. package/dist-cjs/lib/Atom.js.map +2 -2
  6. package/dist-cjs/lib/Computed.js +11 -7
  7. package/dist-cjs/lib/Computed.js.map +2 -2
  8. package/dist-cjs/lib/EffectScheduler.js +5 -3
  9. package/dist-cjs/lib/EffectScheduler.js.map +2 -2
  10. package/dist-cjs/lib/HistoryBuffer.js +1 -0
  11. package/dist-cjs/lib/HistoryBuffer.js.map +1 -1
  12. package/dist-cjs/lib/capture.js +2 -0
  13. package/dist-cjs/lib/capture.js.map +1 -1
  14. package/dist-cjs/lib/helpers.js +1 -1
  15. package/dist-cjs/lib/helpers.js.map +1 -1
  16. package/dist-cjs/lib/transactions.js +3 -1
  17. package/dist-cjs/lib/transactions.js.map +2 -2
  18. package/dist-cjs/lib/types.js +1 -1
  19. package/dist-cjs/lib/types.js.map +1 -1
  20. package/dist-esm/index.mjs +1 -1
  21. package/dist-esm/lib/ArraySet.mjs +1 -1
  22. package/dist-esm/lib/ArraySet.mjs.map +1 -1
  23. package/dist-esm/lib/Atom.mjs +3 -1
  24. package/dist-esm/lib/Atom.mjs.map +2 -2
  25. package/dist-esm/lib/Computed.mjs +11 -7
  26. package/dist-esm/lib/Computed.mjs.map +2 -2
  27. package/dist-esm/lib/EffectScheduler.mjs +5 -3
  28. package/dist-esm/lib/EffectScheduler.mjs.map +2 -2
  29. package/dist-esm/lib/HistoryBuffer.mjs +1 -0
  30. package/dist-esm/lib/HistoryBuffer.mjs.map +1 -1
  31. package/dist-esm/lib/capture.mjs +2 -0
  32. package/dist-esm/lib/capture.mjs.map +1 -1
  33. package/dist-esm/lib/helpers.mjs +1 -1
  34. package/dist-esm/lib/helpers.mjs.map +1 -1
  35. package/dist-esm/lib/transactions.mjs +3 -1
  36. package/dist-esm/lib/transactions.mjs.map +2 -2
  37. package/dist-esm/lib/types.mjs +1 -1
  38. package/dist-esm/lib/types.mjs.map +1 -1
  39. package/package.json +2 -2
  40. package/src/lib/ArraySet.ts +1 -1
  41. package/src/lib/Atom.ts +1 -1
  42. package/src/lib/Computed.ts +2 -2
  43. package/src/lib/EffectScheduler.ts +4 -4
  44. package/src/lib/__tests__/capture.test.ts +2 -2
  45. package/src/lib/__tests__/fuzz.tlstate.test.ts +2 -2
  46. package/src/lib/transactions.ts +1 -1
package/dist-cjs/index.js CHANGED
@@ -61,7 +61,7 @@ if (actualApiVersion !== currentApiVersion) {
61
61
  }
62
62
  (0, import_utils.registerTldrawLibraryVersion)(
63
63
  "@tldraw/state",
64
- "4.6.0-next.5a871ec02ff3",
64
+ "4.6.0-next.6594d48ace27",
65
65
  "cjs"
66
66
  );
67
67
  //# sourceMappingURL=index.js.map
@@ -32,7 +32,7 @@ class ArraySet {
32
32
  *
33
33
  * @returns True if this ArraySet has any elements, false otherwise.
34
34
  */
35
- // eslint-disable-next-line no-restricted-syntax
35
+ // eslint-disable-next-line tldraw/no-setter-getter
36
36
  get isEmpty() {
37
37
  if (this.array) {
38
38
  return this.arraySize === 0;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/lib/ArraySet.ts"],
4
- "sourcesContent": ["/**\n * The maximum number of items that can be stored in an ArraySet in array mode before switching to Set mode.\n *\n * @public\n * @example\n * ```ts\n * import { ARRAY_SIZE_THRESHOLD } from '@tldraw/state'\n *\n * console.log(ARRAY_SIZE_THRESHOLD) // 8\n * ```\n */\nexport const ARRAY_SIZE_THRESHOLD = 8\n\n/**\n * An ArraySet operates as an array until it reaches a certain size, after which a Set is used\n * instead. In either case, the same methods are used to get, set, remove, and visit the items.\n * @internal\n */\nexport class ArraySet<T> {\n\tprivate arraySize = 0\n\n\tprivate array: (T | undefined)[] | null = Array(ARRAY_SIZE_THRESHOLD)\n\n\tprivate set: Set<T> | null = null\n\n\t/**\n\t * Get whether this ArraySet has any elements.\n\t *\n\t * @returns True if this ArraySet has any elements, false otherwise.\n\t */\n\t// eslint-disable-next-line no-restricted-syntax\n\tget isEmpty() {\n\t\tif (this.array) {\n\t\t\treturn this.arraySize === 0\n\t\t}\n\n\t\tif (this.set) {\n\t\t\treturn this.set.size === 0\n\t\t}\n\n\t\tthrow new Error('no set or array')\n\t}\n\n\t/**\n\t * Add an element to the ArraySet if it is not already present.\n\t *\n\t * @param elem - The element to add to the set\n\t * @returns `true` if the element was added, `false` if it was already present\n\t * @example\n\t * ```ts\n\t * const arraySet = new ArraySet<string>()\n\t *\n\t * console.log(arraySet.add('hello')) // true\n\t * console.log(arraySet.add('hello')) // false (already exists)\n\t * ```\n\t */\n\tadd(elem: T) {\n\t\tif (this.array) {\n\t\t\tconst idx = this.array.indexOf(elem)\n\n\t\t\t// Return false if the element is already in the array.\n\t\t\tif (idx !== -1) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\tif (this.arraySize < ARRAY_SIZE_THRESHOLD) {\n\t\t\t\t// If the array is below the size threshold, push items into the array.\n\n\t\t\t\t// Insert the element into the array's next available slot.\n\t\t\t\tthis.array[this.arraySize] = elem\n\t\t\t\tthis.arraySize++\n\n\t\t\t\treturn true\n\t\t\t} else {\n\t\t\t\t// If the array is full, convert it to a set and remove the array.\n\t\t\t\tthis.set = new Set(this.array as any)\n\t\t\t\tthis.array = null\n\t\t\t\tthis.set.add(elem)\n\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\n\t\tif (this.set) {\n\t\t\t// Return false if the element is already in the set.\n\t\t\tif (this.set.has(elem)) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\tthis.set.add(elem)\n\t\t\treturn true\n\t\t}\n\n\t\tthrow new Error('no set or array')\n\t}\n\n\t/**\n\t * Remove an element from the ArraySet if it is present.\n\t *\n\t * @param elem - The element to remove from the set\n\t * @returns `true` if the element was removed, `false` if it was not present\n\t * @example\n\t * ```ts\n\t * const arraySet = new ArraySet<string>()\n\t * arraySet.add('hello')\n\t *\n\t * console.log(arraySet.remove('hello')) // true\n\t * console.log(arraySet.remove('hello')) // false (not present)\n\t * ```\n\t */\n\tremove(elem: T) {\n\t\tif (this.array) {\n\t\t\tconst idx = this.array.indexOf(elem)\n\n\t\t\t// If the item is not in the array, return false.\n\t\t\tif (idx === -1) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\tthis.array[idx] = undefined\n\t\t\tthis.arraySize--\n\n\t\t\tif (idx !== this.arraySize) {\n\t\t\t\t// If the item is not the last item in the array, move the last item into the\n\t\t\t\t// removed item's slot.\n\t\t\t\tthis.array[idx] = this.array[this.arraySize]\n\t\t\t\tthis.array[this.arraySize] = undefined\n\t\t\t}\n\n\t\t\treturn true\n\t\t}\n\n\t\tif (this.set) {\n\t\t\t// If the item is not in the set, return false.\n\t\t\tif (!this.set.has(elem)) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\tthis.set.delete(elem)\n\n\t\t\treturn true\n\t\t}\n\n\t\tthrow new Error('no set or array')\n\t}\n\n\t/**\n\t * Execute a callback function for each element in the ArraySet.\n\t *\n\t * @param visitor - A function to call for each element in the set\n\t * @example\n\t * ```ts\n\t * const arraySet = new ArraySet<string>()\n\t * arraySet.add('hello')\n\t * arraySet.add('world')\n\t *\n\t * arraySet.visit((item) => {\n\t * console.log(item) // 'hello', 'world'\n\t * })\n\t * ```\n\t */\n\tvisit(visitor: (item: T) => void) {\n\t\tif (this.array) {\n\t\t\tfor (let i = 0; i < this.arraySize; i++) {\n\t\t\t\tconst elem = this.array[i]\n\n\t\t\t\tif (typeof elem !== 'undefined') {\n\t\t\t\t\tvisitor(elem)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn\n\t\t}\n\n\t\tif (this.set) {\n\t\t\tthis.set.forEach(visitor)\n\n\t\t\treturn\n\t\t}\n\n\t\tthrow new Error('no set or array')\n\t}\n\n\t/**\n\t * Make the ArraySet iterable, allowing it to be used in for...of loops and with spread syntax.\n\t *\n\t * @returns An iterator that yields each element in the set\n\t * @example\n\t * ```ts\n\t * const arraySet = new ArraySet<number>()\n\t * arraySet.add(1)\n\t * arraySet.add(2)\n\t *\n\t * for (const item of arraySet) {\n\t * console.log(item) // 1, 2\n\t * }\n\t *\n\t * const items = [...arraySet] // [1, 2]\n\t * ```\n\t */\n\t*[Symbol.iterator]() {\n\t\tif (this.array) {\n\t\t\tfor (let i = 0; i < this.arraySize; i++) {\n\t\t\t\tconst elem = this.array[i]\n\n\t\t\t\tif (typeof elem !== 'undefined') {\n\t\t\t\t\tyield elem\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (this.set) {\n\t\t\tyield* this.set\n\t\t} else {\n\t\t\tthrow new Error('no set or array')\n\t\t}\n\t}\n\n\t/**\n\t * Check whether an element is present in the ArraySet.\n\t *\n\t * @param elem - The element to check for\n\t * @returns `true` if the element is present, `false` otherwise\n\t * @example\n\t * ```ts\n\t * const arraySet = new ArraySet<string>()\n\t * arraySet.add('hello')\n\t *\n\t * console.log(arraySet.has('hello')) // true\n\t * console.log(arraySet.has('world')) // false\n\t * ```\n\t */\n\thas(elem: T) {\n\t\tif (this.array) {\n\t\t\treturn this.array.indexOf(elem) !== -1\n\t\t} else {\n\t\t\treturn this.set!.has(elem)\n\t\t}\n\t}\n\n\t/**\n\t * Remove all elements from the ArraySet.\n\t *\n\t * @example\n\t * ```ts\n\t * const arraySet = new ArraySet<string>()\n\t * arraySet.add('hello')\n\t * arraySet.add('world')\n\t *\n\t * arraySet.clear()\n\t * console.log(arraySet.size()) // 0\n\t * ```\n\t */\n\tclear() {\n\t\tif (this.set) {\n\t\t\tthis.set.clear()\n\t\t} else {\n\t\t\tthis.arraySize = 0\n\t\t\tthis.array = []\n\t\t}\n\t}\n\n\t/**\n\t * Get the number of elements in the ArraySet.\n\t *\n\t * @returns The number of elements in the set\n\t * @example\n\t * ```ts\n\t * const arraySet = new ArraySet<string>()\n\t * console.log(arraySet.size()) // 0\n\t *\n\t * arraySet.add('hello')\n\t * console.log(arraySet.size()) // 1\n\t * ```\n\t */\n\tsize() {\n\t\tif (this.set) {\n\t\t\treturn this.set.size\n\t\t} else {\n\t\t\treturn this.arraySize\n\t\t}\n\t}\n}\n"],
4
+ "sourcesContent": ["/**\n * The maximum number of items that can be stored in an ArraySet in array mode before switching to Set mode.\n *\n * @public\n * @example\n * ```ts\n * import { ARRAY_SIZE_THRESHOLD } from '@tldraw/state'\n *\n * console.log(ARRAY_SIZE_THRESHOLD) // 8\n * ```\n */\nexport const ARRAY_SIZE_THRESHOLD = 8\n\n/**\n * An ArraySet operates as an array until it reaches a certain size, after which a Set is used\n * instead. In either case, the same methods are used to get, set, remove, and visit the items.\n * @internal\n */\nexport class ArraySet<T> {\n\tprivate arraySize = 0\n\n\tprivate array: (T | undefined)[] | null = Array(ARRAY_SIZE_THRESHOLD)\n\n\tprivate set: Set<T> | null = null\n\n\t/**\n\t * Get whether this ArraySet has any elements.\n\t *\n\t * @returns True if this ArraySet has any elements, false otherwise.\n\t */\n\t// eslint-disable-next-line tldraw/no-setter-getter\n\tget isEmpty() {\n\t\tif (this.array) {\n\t\t\treturn this.arraySize === 0\n\t\t}\n\n\t\tif (this.set) {\n\t\t\treturn this.set.size === 0\n\t\t}\n\n\t\tthrow new Error('no set or array')\n\t}\n\n\t/**\n\t * Add an element to the ArraySet if it is not already present.\n\t *\n\t * @param elem - The element to add to the set\n\t * @returns `true` if the element was added, `false` if it was already present\n\t * @example\n\t * ```ts\n\t * const arraySet = new ArraySet<string>()\n\t *\n\t * console.log(arraySet.add('hello')) // true\n\t * console.log(arraySet.add('hello')) // false (already exists)\n\t * ```\n\t */\n\tadd(elem: T) {\n\t\tif (this.array) {\n\t\t\tconst idx = this.array.indexOf(elem)\n\n\t\t\t// Return false if the element is already in the array.\n\t\t\tif (idx !== -1) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\tif (this.arraySize < ARRAY_SIZE_THRESHOLD) {\n\t\t\t\t// If the array is below the size threshold, push items into the array.\n\n\t\t\t\t// Insert the element into the array's next available slot.\n\t\t\t\tthis.array[this.arraySize] = elem\n\t\t\t\tthis.arraySize++\n\n\t\t\t\treturn true\n\t\t\t} else {\n\t\t\t\t// If the array is full, convert it to a set and remove the array.\n\t\t\t\tthis.set = new Set(this.array as any)\n\t\t\t\tthis.array = null\n\t\t\t\tthis.set.add(elem)\n\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\n\t\tif (this.set) {\n\t\t\t// Return false if the element is already in the set.\n\t\t\tif (this.set.has(elem)) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\tthis.set.add(elem)\n\t\t\treturn true\n\t\t}\n\n\t\tthrow new Error('no set or array')\n\t}\n\n\t/**\n\t * Remove an element from the ArraySet if it is present.\n\t *\n\t * @param elem - The element to remove from the set\n\t * @returns `true` if the element was removed, `false` if it was not present\n\t * @example\n\t * ```ts\n\t * const arraySet = new ArraySet<string>()\n\t * arraySet.add('hello')\n\t *\n\t * console.log(arraySet.remove('hello')) // true\n\t * console.log(arraySet.remove('hello')) // false (not present)\n\t * ```\n\t */\n\tremove(elem: T) {\n\t\tif (this.array) {\n\t\t\tconst idx = this.array.indexOf(elem)\n\n\t\t\t// If the item is not in the array, return false.\n\t\t\tif (idx === -1) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\tthis.array[idx] = undefined\n\t\t\tthis.arraySize--\n\n\t\t\tif (idx !== this.arraySize) {\n\t\t\t\t// If the item is not the last item in the array, move the last item into the\n\t\t\t\t// removed item's slot.\n\t\t\t\tthis.array[idx] = this.array[this.arraySize]\n\t\t\t\tthis.array[this.arraySize] = undefined\n\t\t\t}\n\n\t\t\treturn true\n\t\t}\n\n\t\tif (this.set) {\n\t\t\t// If the item is not in the set, return false.\n\t\t\tif (!this.set.has(elem)) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\tthis.set.delete(elem)\n\n\t\t\treturn true\n\t\t}\n\n\t\tthrow new Error('no set or array')\n\t}\n\n\t/**\n\t * Execute a callback function for each element in the ArraySet.\n\t *\n\t * @param visitor - A function to call for each element in the set\n\t * @example\n\t * ```ts\n\t * const arraySet = new ArraySet<string>()\n\t * arraySet.add('hello')\n\t * arraySet.add('world')\n\t *\n\t * arraySet.visit((item) => {\n\t * console.log(item) // 'hello', 'world'\n\t * })\n\t * ```\n\t */\n\tvisit(visitor: (item: T) => void) {\n\t\tif (this.array) {\n\t\t\tfor (let i = 0; i < this.arraySize; i++) {\n\t\t\t\tconst elem = this.array[i]\n\n\t\t\t\tif (typeof elem !== 'undefined') {\n\t\t\t\t\tvisitor(elem)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn\n\t\t}\n\n\t\tif (this.set) {\n\t\t\tthis.set.forEach(visitor)\n\n\t\t\treturn\n\t\t}\n\n\t\tthrow new Error('no set or array')\n\t}\n\n\t/**\n\t * Make the ArraySet iterable, allowing it to be used in for...of loops and with spread syntax.\n\t *\n\t * @returns An iterator that yields each element in the set\n\t * @example\n\t * ```ts\n\t * const arraySet = new ArraySet<number>()\n\t * arraySet.add(1)\n\t * arraySet.add(2)\n\t *\n\t * for (const item of arraySet) {\n\t * console.log(item) // 1, 2\n\t * }\n\t *\n\t * const items = [...arraySet] // [1, 2]\n\t * ```\n\t */\n\t*[Symbol.iterator]() {\n\t\tif (this.array) {\n\t\t\tfor (let i = 0; i < this.arraySize; i++) {\n\t\t\t\tconst elem = this.array[i]\n\n\t\t\t\tif (typeof elem !== 'undefined') {\n\t\t\t\t\tyield elem\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (this.set) {\n\t\t\tyield* this.set\n\t\t} else {\n\t\t\tthrow new Error('no set or array')\n\t\t}\n\t}\n\n\t/**\n\t * Check whether an element is present in the ArraySet.\n\t *\n\t * @param elem - The element to check for\n\t * @returns `true` if the element is present, `false` otherwise\n\t * @example\n\t * ```ts\n\t * const arraySet = new ArraySet<string>()\n\t * arraySet.add('hello')\n\t *\n\t * console.log(arraySet.has('hello')) // true\n\t * console.log(arraySet.has('world')) // false\n\t * ```\n\t */\n\thas(elem: T) {\n\t\tif (this.array) {\n\t\t\treturn this.array.indexOf(elem) !== -1\n\t\t} else {\n\t\t\treturn this.set!.has(elem)\n\t\t}\n\t}\n\n\t/**\n\t * Remove all elements from the ArraySet.\n\t *\n\t * @example\n\t * ```ts\n\t * const arraySet = new ArraySet<string>()\n\t * arraySet.add('hello')\n\t * arraySet.add('world')\n\t *\n\t * arraySet.clear()\n\t * console.log(arraySet.size()) // 0\n\t * ```\n\t */\n\tclear() {\n\t\tif (this.set) {\n\t\t\tthis.set.clear()\n\t\t} else {\n\t\t\tthis.arraySize = 0\n\t\t\tthis.array = []\n\t\t}\n\t}\n\n\t/**\n\t * Get the number of elements in the ArraySet.\n\t *\n\t * @returns The number of elements in the set\n\t * @example\n\t * ```ts\n\t * const arraySet = new ArraySet<string>()\n\t * console.log(arraySet.size()) // 0\n\t *\n\t * arraySet.add('hello')\n\t * console.log(arraySet.size()) // 1\n\t * ```\n\t */\n\tsize() {\n\t\tif (this.set) {\n\t\t\treturn this.set.size\n\t\t} else {\n\t\t\treturn this.arraySize\n\t\t}\n\t}\n}\n"],
5
5
  "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -24,9 +24,9 @@ __export(Atom_exports, {
24
24
  });
25
25
  module.exports = __toCommonJS(Atom_exports);
26
26
  var import_ArraySet = require("./ArraySet");
27
- var import_HistoryBuffer = require("./HistoryBuffer");
28
27
  var import_capture = require("./capture");
29
28
  var import_helpers = require("./helpers");
29
+ var import_HistoryBuffer = require("./HistoryBuffer");
30
30
  var import_transactions = require("./transactions");
31
31
  var import_types = require("./types");
32
32
  class __Atom__ {
@@ -40,6 +40,8 @@ class __Atom__ {
40
40
  }
41
41
  this.computeDiff = options.computeDiff;
42
42
  }
43
+ name;
44
+ current;
43
45
  /**
44
46
  * Custom equality function for comparing values, or null to use default equality.
45
47
  * @internal
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/lib/Atom.ts"],
4
- "sourcesContent": ["import { ArraySet } from './ArraySet'\nimport { HistoryBuffer } from './HistoryBuffer'\nimport { maybeCaptureParent } from './capture'\nimport { EMPTY_ARRAY, equals, singleton } from './helpers'\nimport { advanceGlobalEpoch, atomDidChange, getGlobalEpoch } from './transactions'\nimport { Child, ComputeDiff, RESET_VALUE, Signal } from './types'\n\n/**\n * The options to configure an atom, passed into the {@link atom} function.\n * @public\n */\nexport interface AtomOptions<Value, Diff> {\n\t/**\n\t * The maximum number of diffs to keep in the history buffer.\n\t *\n\t * If you don't need to compute diffs, or if you will supply diffs manually via {@link Atom.set}, you can leave this as `undefined` and no history buffer will be created.\n\t *\n\t * If you expect the value to be part of an active effect subscription all the time, and to not change multiple times inside of a single transaction, you can set this to a relatively low number (e.g. 10).\n\t *\n\t * Otherwise, set this to a higher number based on your usage pattern and memory constraints.\n\t *\n\t */\n\thistoryLength?: number\n\t/**\n\t * A method used to compute a diff between the atom's old and new values. If provided, it will not be used unless you also specify {@link AtomOptions.historyLength}.\n\t */\n\tcomputeDiff?: ComputeDiff<Value, Diff>\n\t/**\n\t * If provided, this will be used to compare the old and new values of the atom to determine if the value has changed.\n\t * By default, values are compared using first using strict equality (`===`), then `Object.is`, and finally any `.equals` method present in the object's prototype chain.\n\t * @param a - The old value\n\t * @param b - The new value\n\t * @returns True if the values are equal, false otherwise.\n\t */\n\tisEqual?(a: any, b: any): boolean\n}\n\n/**\n * An Atom is a signal that can be updated directly by calling {@link Atom.set} or {@link Atom.update}.\n *\n * Atoms are created using the {@link atom} function.\n *\n * @example\n * ```ts\n * const name = atom('name', 'John')\n *\n * print(name.get()) // 'John'\n * ```\n *\n * @public\n */\nexport interface Atom<Value, Diff = unknown> extends Signal<Value, Diff> {\n\t/**\n\t * Sets the value of this atom to the given value. If the value is the same as the current value, this is a no-op.\n\t *\n\t * @param value - The new value to set.\n\t * @param diff - The diff to use for the update. If not provided, the diff will be computed using {@link AtomOptions.computeDiff}.\n\t */\n\tset(value: Value, diff?: Diff): Value\n\t/**\n\t * Updates the value of this atom using the given updater function. If the returned value is the same as the current value, this is a no-op.\n\t *\n\t * @param updater - A function that takes the current value and returns the new value.\n\t */\n\tupdate(updater: (value: Value) => Value): Value\n}\n\n/**\n * Internal implementation of the Atom interface. This class should not be used directly - use the {@link atom} function instead.\n *\n * @internal\n */\nclass __Atom__<Value, Diff = unknown> implements Atom<Value, Diff> {\n\tconstructor(\n\t\tpublic readonly name: string,\n\t\tprivate current: Value,\n\t\toptions?: AtomOptions<Value, Diff>\n\t) {\n\t\tthis.isEqual = options?.isEqual ?? null\n\n\t\tif (!options) return\n\n\t\tif (options.historyLength) {\n\t\t\tthis.historyBuffer = new HistoryBuffer(options.historyLength)\n\t\t}\n\n\t\tthis.computeDiff = options.computeDiff\n\t}\n\n\t/**\n\t * Custom equality function for comparing values, or null to use default equality.\n\t * @internal\n\t */\n\treadonly isEqual: null | ((a: any, b: any) => boolean)\n\n\t/**\n\t * Optional function to compute diffs between old and new values.\n\t * @internal\n\t */\n\tcomputeDiff?: ComputeDiff<Value, Diff>\n\n\t/**\n\t * The global epoch when this atom was last changed.\n\t * @internal\n\t */\n\tlastChangedEpoch = getGlobalEpoch()\n\n\t/**\n\t * Set of child signals that depend on this atom.\n\t * @internal\n\t */\n\tchildren = new ArraySet<Child>()\n\n\t/**\n\t * Optional history buffer for tracking changes over time.\n\t * @internal\n\t */\n\thistoryBuffer?: HistoryBuffer<Diff>\n\n\t/**\n\t * Gets the current value without capturing it as a dependency in the current reactive context.\n\t * This is unsafe because it breaks the reactivity chain - use with caution.\n\t *\n\t * @param _ignoreErrors - Unused parameter for API compatibility\n\t * @returns The current value\n\t * @internal\n\t */\n\t__unsafe__getWithoutCapture(_ignoreErrors?: boolean): Value {\n\t\treturn this.current\n\t}\n\n\t/**\n\t * Gets the current value of this atom. When called within a computed signal or reaction,\n\t * this atom will be automatically captured as a dependency.\n\t *\n\t * @returns The current value\n\t * @example\n\t * ```ts\n\t * const count = atom('count', 5)\n\t * console.log(count.get()) // 5\n\t * ```\n\t */\n\tget() {\n\t\tmaybeCaptureParent(this)\n\t\treturn this.current\n\t}\n\n\t/**\n\t * Sets the value of this atom to the given value. If the value is the same as the current value, this is a no-op.\n\t *\n\t * @param value - The new value to set\n\t * @param diff - The diff to use for the update. If not provided, the diff will be computed using {@link AtomOptions.computeDiff}\n\t * @returns The new value\n\t * @example\n\t * ```ts\n\t * const count = atom('count', 0)\n\t * count.set(5) // count.get() is now 5\n\t * ```\n\t */\n\tset(value: Value, diff?: Diff): Value {\n\t\t// If the value has not changed, do nothing.\n\t\tif (this.isEqual?.(this.current, value) ?? equals(this.current, value)) {\n\t\t\treturn this.current\n\t\t}\n\n\t\t// Tick forward the global epoch\n\t\tadvanceGlobalEpoch()\n\n\t\t// Add the diff to the history buffer.\n\t\tif (this.historyBuffer) {\n\t\t\tthis.historyBuffer.pushEntry(\n\t\t\t\tthis.lastChangedEpoch,\n\t\t\t\tgetGlobalEpoch(),\n\t\t\t\tdiff ??\n\t\t\t\t\tthis.computeDiff?.(this.current, value, this.lastChangedEpoch, getGlobalEpoch()) ??\n\t\t\t\t\tRESET_VALUE\n\t\t\t)\n\t\t}\n\n\t\t// Update the atom's record of the epoch when last changed.\n\t\tthis.lastChangedEpoch = getGlobalEpoch()\n\n\t\tconst oldValue = this.current\n\t\tthis.current = value\n\n\t\t// Notify all children that this atom has changed.\n\t\tatomDidChange(this as any, oldValue)\n\n\t\treturn value\n\t}\n\n\t/**\n\t * Updates the value of this atom using the given updater function. If the returned value is the same as the current value, this is a no-op.\n\t *\n\t * @param updater - A function that takes the current value and returns the new value\n\t * @returns The new value\n\t * @example\n\t * ```ts\n\t * const count = atom('count', 5)\n\t * count.update(n => n + 1) // count.get() is now 6\n\t * ```\n\t */\n\tupdate(updater: (value: Value) => Value): Value {\n\t\treturn this.set(updater(this.current))\n\t}\n\n\t/**\n\t * Gets all the diffs that have occurred since the given epoch. When called within a computed\n\t * signal or reaction, this atom will be automatically captured as a dependency.\n\t *\n\t * @param epoch - The epoch to get changes since\n\t * @returns An array of diffs, or RESET_VALUE if history is insufficient\n\t * @internal\n\t */\n\tgetDiffSince(epoch: number): RESET_VALUE | Diff[] {\n\t\tmaybeCaptureParent(this)\n\n\t\t// If no changes have occurred since the given epoch, return an empty array.\n\t\tif (epoch >= this.lastChangedEpoch) {\n\t\t\treturn EMPTY_ARRAY\n\t\t}\n\n\t\treturn this.historyBuffer?.getChangesSince(epoch) ?? RESET_VALUE\n\t}\n}\n\n/**\n * Singleton reference to the Atom constructor. Used internally to create atom instances.\n * @internal\n */\nexport const _Atom = singleton('Atom', () => __Atom__)\n\n/**\n * Type alias for instances of the internal Atom class.\n * @internal\n */\nexport type _Atom = InstanceType<typeof _Atom>\n\n/**\n * Creates a new {@link Atom}.\n *\n * An Atom is a signal that can be updated directly by calling {@link Atom.set} or {@link Atom.update}.\n *\n * @example\n * ```ts\n * const name = atom('name', 'John')\n *\n * name.get() // 'John'\n *\n * name.set('Jane')\n *\n * name.get() // 'Jane'\n * ```\n *\n * @public\n */\nexport function atom<Value, Diff = unknown>(\n\t/**\n\t * A name for the signal. This is used for debugging and profiling purposes, it does not need to be unique.\n\t */\n\tname: string,\n\t/**\n\t * The initial value of the signal.\n\t */\n\tinitialValue: Value,\n\t/**\n\t * The options to configure the atom. See {@link AtomOptions}.\n\t */\n\toptions?: AtomOptions<Value, Diff>\n): Atom<Value, Diff> {\n\treturn new _Atom(name, initialValue, options)\n}\n\n/**\n * Returns true if the given value is an {@link Atom}.\n *\n * @param value - The value to check\n * @returns True if the value is an Atom, false otherwise\n * @example\n * ```ts\n * const myAtom = atom('test', 42)\n * const notAtom = 'hello'\n *\n * console.log(isAtom(myAtom)) // true\n * console.log(isAtom(notAtom)) // false\n * ```\n * @public\n */\nexport function isAtom(value: unknown): value is Atom<unknown> {\n\treturn value instanceof _Atom\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sBAAyB;AACzB,2BAA8B;AAC9B,qBAAmC;AACnC,qBAA+C;AAC/C,0BAAkE;AAClE,mBAAwD;AAmExD,MAAM,SAA6D;AAAA,EAClE,YACiB,MACR,SACR,SACC;AAHe;AACR;AAGR,SAAK,UAAU,SAAS,WAAW;AAEnC,QAAI,CAAC,QAAS;AAEd,QAAI,QAAQ,eAAe;AAC1B,WAAK,gBAAgB,IAAI,mCAAc,QAAQ,aAAa;AAAA,IAC7D;AAEA,SAAK,cAAc,QAAQ;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMS;AAAA;AAAA;AAAA;AAAA;AAAA,EAMT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,uBAAmB,oCAAe;AAAA;AAAA;AAAA;AAAA;AAAA,EAMlC,WAAW,IAAI,yBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA,EAM/B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,4BAA4B,eAAgC;AAC3D,WAAO,KAAK;AAAA,EACb;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,MAAM;AACL,2CAAmB,IAAI;AACvB,WAAO,KAAK;AAAA,EACb;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcA,IAAI,OAAc,MAAoB;AAErC,QAAI,KAAK,UAAU,KAAK,SAAS,KAAK,SAAK,uBAAO,KAAK,SAAS,KAAK,GAAG;AACvE,aAAO,KAAK;AAAA,IACb;AAGA,gDAAmB;AAGnB,QAAI,KAAK,eAAe;AACvB,WAAK,cAAc;AAAA,QAClB,KAAK;AAAA,YACL,oCAAe;AAAA,QACf,QACC,KAAK,cAAc,KAAK,SAAS,OAAO,KAAK,sBAAkB,oCAAe,CAAC,KAC/E;AAAA,MACF;AAAA,IACD;AAGA,SAAK,uBAAmB,oCAAe;AAEvC,UAAM,WAAW,KAAK;AACtB,SAAK,UAAU;AAGf,2CAAc,MAAa,QAAQ;AAEnC,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,OAAO,SAAyC;AAC/C,WAAO,KAAK,IAAI,QAAQ,KAAK,OAAO,CAAC;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,aAAa,OAAqC;AACjD,2CAAmB,IAAI;AAGvB,QAAI,SAAS,KAAK,kBAAkB;AACnC,aAAO;AAAA,IACR;AAEA,WAAO,KAAK,eAAe,gBAAgB,KAAK,KAAK;AAAA,EACtD;AACD;AAMO,MAAM,YAAQ,0BAAU,QAAQ,MAAM,QAAQ;AA0B9C,SAAS,KAIf,MAIA,cAIA,SACoB;AACpB,SAAO,IAAI,MAAM,MAAM,cAAc,OAAO;AAC7C;AAiBO,SAAS,OAAO,OAAwC;AAC9D,SAAO,iBAAiB;AACzB;",
4
+ "sourcesContent": ["import { ArraySet } from './ArraySet'\nimport { maybeCaptureParent } from './capture'\nimport { EMPTY_ARRAY, equals, singleton } from './helpers'\nimport { HistoryBuffer } from './HistoryBuffer'\nimport { advanceGlobalEpoch, atomDidChange, getGlobalEpoch } from './transactions'\nimport { Child, ComputeDiff, RESET_VALUE, Signal } from './types'\n\n/**\n * The options to configure an atom, passed into the {@link atom} function.\n * @public\n */\nexport interface AtomOptions<Value, Diff> {\n\t/**\n\t * The maximum number of diffs to keep in the history buffer.\n\t *\n\t * If you don't need to compute diffs, or if you will supply diffs manually via {@link Atom.set}, you can leave this as `undefined` and no history buffer will be created.\n\t *\n\t * If you expect the value to be part of an active effect subscription all the time, and to not change multiple times inside of a single transaction, you can set this to a relatively low number (e.g. 10).\n\t *\n\t * Otherwise, set this to a higher number based on your usage pattern and memory constraints.\n\t *\n\t */\n\thistoryLength?: number\n\t/**\n\t * A method used to compute a diff between the atom's old and new values. If provided, it will not be used unless you also specify {@link AtomOptions.historyLength}.\n\t */\n\tcomputeDiff?: ComputeDiff<Value, Diff>\n\t/**\n\t * If provided, this will be used to compare the old and new values of the atom to determine if the value has changed.\n\t * By default, values are compared using first using strict equality (`===`), then `Object.is`, and finally any `.equals` method present in the object's prototype chain.\n\t * @param a - The old value\n\t * @param b - The new value\n\t * @returns True if the values are equal, false otherwise.\n\t */\n\tisEqual?(a: any, b: any): boolean\n}\n\n/**\n * An Atom is a signal that can be updated directly by calling {@link Atom.set} or {@link Atom.update}.\n *\n * Atoms are created using the {@link atom} function.\n *\n * @example\n * ```ts\n * const name = atom('name', 'John')\n *\n * print(name.get()) // 'John'\n * ```\n *\n * @public\n */\nexport interface Atom<Value, Diff = unknown> extends Signal<Value, Diff> {\n\t/**\n\t * Sets the value of this atom to the given value. If the value is the same as the current value, this is a no-op.\n\t *\n\t * @param value - The new value to set.\n\t * @param diff - The diff to use for the update. If not provided, the diff will be computed using {@link AtomOptions.computeDiff}.\n\t */\n\tset(value: Value, diff?: Diff): Value\n\t/**\n\t * Updates the value of this atom using the given updater function. If the returned value is the same as the current value, this is a no-op.\n\t *\n\t * @param updater - A function that takes the current value and returns the new value.\n\t */\n\tupdate(updater: (value: Value) => Value): Value\n}\n\n/**\n * Internal implementation of the Atom interface. This class should not be used directly - use the {@link atom} function instead.\n *\n * @internal\n */\nclass __Atom__<Value, Diff = unknown> implements Atom<Value, Diff> {\n\tconstructor(\n\t\tpublic readonly name: string,\n\t\tprivate current: Value,\n\t\toptions?: AtomOptions<Value, Diff>\n\t) {\n\t\tthis.isEqual = options?.isEqual ?? null\n\n\t\tif (!options) return\n\n\t\tif (options.historyLength) {\n\t\t\tthis.historyBuffer = new HistoryBuffer(options.historyLength)\n\t\t}\n\n\t\tthis.computeDiff = options.computeDiff\n\t}\n\n\t/**\n\t * Custom equality function for comparing values, or null to use default equality.\n\t * @internal\n\t */\n\treadonly isEqual: null | ((a: any, b: any) => boolean)\n\n\t/**\n\t * Optional function to compute diffs between old and new values.\n\t * @internal\n\t */\n\tcomputeDiff?: ComputeDiff<Value, Diff>\n\n\t/**\n\t * The global epoch when this atom was last changed.\n\t * @internal\n\t */\n\tlastChangedEpoch = getGlobalEpoch()\n\n\t/**\n\t * Set of child signals that depend on this atom.\n\t * @internal\n\t */\n\tchildren = new ArraySet<Child>()\n\n\t/**\n\t * Optional history buffer for tracking changes over time.\n\t * @internal\n\t */\n\thistoryBuffer?: HistoryBuffer<Diff>\n\n\t/**\n\t * Gets the current value without capturing it as a dependency in the current reactive context.\n\t * This is unsafe because it breaks the reactivity chain - use with caution.\n\t *\n\t * @param _ignoreErrors - Unused parameter for API compatibility\n\t * @returns The current value\n\t * @internal\n\t */\n\t__unsafe__getWithoutCapture(_ignoreErrors?: boolean): Value {\n\t\treturn this.current\n\t}\n\n\t/**\n\t * Gets the current value of this atom. When called within a computed signal or reaction,\n\t * this atom will be automatically captured as a dependency.\n\t *\n\t * @returns The current value\n\t * @example\n\t * ```ts\n\t * const count = atom('count', 5)\n\t * console.log(count.get()) // 5\n\t * ```\n\t */\n\tget() {\n\t\tmaybeCaptureParent(this)\n\t\treturn this.current\n\t}\n\n\t/**\n\t * Sets the value of this atom to the given value. If the value is the same as the current value, this is a no-op.\n\t *\n\t * @param value - The new value to set\n\t * @param diff - The diff to use for the update. If not provided, the diff will be computed using {@link AtomOptions.computeDiff}\n\t * @returns The new value\n\t * @example\n\t * ```ts\n\t * const count = atom('count', 0)\n\t * count.set(5) // count.get() is now 5\n\t * ```\n\t */\n\tset(value: Value, diff?: Diff): Value {\n\t\t// If the value has not changed, do nothing.\n\t\tif (this.isEqual?.(this.current, value) ?? equals(this.current, value)) {\n\t\t\treturn this.current\n\t\t}\n\n\t\t// Tick forward the global epoch\n\t\tadvanceGlobalEpoch()\n\n\t\t// Add the diff to the history buffer.\n\t\tif (this.historyBuffer) {\n\t\t\tthis.historyBuffer.pushEntry(\n\t\t\t\tthis.lastChangedEpoch,\n\t\t\t\tgetGlobalEpoch(),\n\t\t\t\tdiff ??\n\t\t\t\t\tthis.computeDiff?.(this.current, value, this.lastChangedEpoch, getGlobalEpoch()) ??\n\t\t\t\t\tRESET_VALUE\n\t\t\t)\n\t\t}\n\n\t\t// Update the atom's record of the epoch when last changed.\n\t\tthis.lastChangedEpoch = getGlobalEpoch()\n\n\t\tconst oldValue = this.current\n\t\tthis.current = value\n\n\t\t// Notify all children that this atom has changed.\n\t\tatomDidChange(this as any, oldValue)\n\n\t\treturn value\n\t}\n\n\t/**\n\t * Updates the value of this atom using the given updater function. If the returned value is the same as the current value, this is a no-op.\n\t *\n\t * @param updater - A function that takes the current value and returns the new value\n\t * @returns The new value\n\t * @example\n\t * ```ts\n\t * const count = atom('count', 5)\n\t * count.update(n => n + 1) // count.get() is now 6\n\t * ```\n\t */\n\tupdate(updater: (value: Value) => Value): Value {\n\t\treturn this.set(updater(this.current))\n\t}\n\n\t/**\n\t * Gets all the diffs that have occurred since the given epoch. When called within a computed\n\t * signal or reaction, this atom will be automatically captured as a dependency.\n\t *\n\t * @param epoch - The epoch to get changes since\n\t * @returns An array of diffs, or RESET_VALUE if history is insufficient\n\t * @internal\n\t */\n\tgetDiffSince(epoch: number): RESET_VALUE | Diff[] {\n\t\tmaybeCaptureParent(this)\n\n\t\t// If no changes have occurred since the given epoch, return an empty array.\n\t\tif (epoch >= this.lastChangedEpoch) {\n\t\t\treturn EMPTY_ARRAY\n\t\t}\n\n\t\treturn this.historyBuffer?.getChangesSince(epoch) ?? RESET_VALUE\n\t}\n}\n\n/**\n * Singleton reference to the Atom constructor. Used internally to create atom instances.\n * @internal\n */\nexport const _Atom = singleton('Atom', () => __Atom__)\n\n/**\n * Type alias for instances of the internal Atom class.\n * @internal\n */\nexport type _Atom = InstanceType<typeof _Atom>\n\n/**\n * Creates a new {@link Atom}.\n *\n * An Atom is a signal that can be updated directly by calling {@link Atom.set} or {@link Atom.update}.\n *\n * @example\n * ```ts\n * const name = atom('name', 'John')\n *\n * name.get() // 'John'\n *\n * name.set('Jane')\n *\n * name.get() // 'Jane'\n * ```\n *\n * @public\n */\nexport function atom<Value, Diff = unknown>(\n\t/**\n\t * A name for the signal. This is used for debugging and profiling purposes, it does not need to be unique.\n\t */\n\tname: string,\n\t/**\n\t * The initial value of the signal.\n\t */\n\tinitialValue: Value,\n\t/**\n\t * The options to configure the atom. See {@link AtomOptions}.\n\t */\n\toptions?: AtomOptions<Value, Diff>\n): Atom<Value, Diff> {\n\treturn new _Atom(name, initialValue, options)\n}\n\n/**\n * Returns true if the given value is an {@link Atom}.\n *\n * @param value - The value to check\n * @returns True if the value is an Atom, false otherwise\n * @example\n * ```ts\n * const myAtom = atom('test', 42)\n * const notAtom = 'hello'\n *\n * console.log(isAtom(myAtom)) // true\n * console.log(isAtom(notAtom)) // false\n * ```\n * @public\n */\nexport function isAtom(value: unknown): value is Atom<unknown> {\n\treturn value instanceof _Atom\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sBAAyB;AACzB,qBAAmC;AACnC,qBAA+C;AAC/C,2BAA8B;AAC9B,0BAAkE;AAClE,mBAAwD;AAmExD,MAAM,SAA6D;AAAA,EAClE,YACiB,MACR,SACR,SACC;AAHe;AACR;AAGR,SAAK,UAAU,SAAS,WAAW;AAEnC,QAAI,CAAC,QAAS;AAEd,QAAI,QAAQ,eAAe;AAC1B,WAAK,gBAAgB,IAAI,mCAAc,QAAQ,aAAa;AAAA,IAC7D;AAEA,SAAK,cAAc,QAAQ;AAAA,EAC5B;AAAA,EAbiB;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA,EAkBA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,uBAAmB,oCAAe;AAAA;AAAA;AAAA;AAAA;AAAA,EAMlC,WAAW,IAAI,yBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA,EAM/B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,4BAA4B,eAAgC;AAC3D,WAAO,KAAK;AAAA,EACb;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,MAAM;AACL,2CAAmB,IAAI;AACvB,WAAO,KAAK;AAAA,EACb;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcA,IAAI,OAAc,MAAoB;AAErC,QAAI,KAAK,UAAU,KAAK,SAAS,KAAK,SAAK,uBAAO,KAAK,SAAS,KAAK,GAAG;AACvE,aAAO,KAAK;AAAA,IACb;AAGA,gDAAmB;AAGnB,QAAI,KAAK,eAAe;AACvB,WAAK,cAAc;AAAA,QAClB,KAAK;AAAA,YACL,oCAAe;AAAA,QACf,QACC,KAAK,cAAc,KAAK,SAAS,OAAO,KAAK,sBAAkB,oCAAe,CAAC,KAC/E;AAAA,MACF;AAAA,IACD;AAGA,SAAK,uBAAmB,oCAAe;AAEvC,UAAM,WAAW,KAAK;AACtB,SAAK,UAAU;AAGf,2CAAc,MAAa,QAAQ;AAEnC,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,OAAO,SAAyC;AAC/C,WAAO,KAAK,IAAI,QAAQ,KAAK,OAAO,CAAC;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,aAAa,OAAqC;AACjD,2CAAmB,IAAI;AAGvB,QAAI,SAAS,KAAK,kBAAkB;AACnC,aAAO;AAAA,IACR;AAEA,WAAO,KAAK,eAAe,gBAAgB,KAAK,KAAK;AAAA,EACtD;AACD;AAMO,MAAM,YAAQ,0BAAU,QAAQ,MAAM,QAAQ;AA0B9C,SAAS,KAIf,MAIA,cAIA,SACoB;AACpB,SAAO,IAAI,MAAM,MAAM,cAAc,OAAO;AAC7C;AAiBO,SAAS,OAAO,OAAwC;AAC9D,SAAO,iBAAiB;AACzB;",
6
6
  "names": []
7
7
  }
@@ -30,15 +30,15 @@ __export(Computed_exports, {
30
30
  module.exports = __toCommonJS(Computed_exports);
31
31
  var import_utils = require("@tldraw/utils");
32
32
  var import_ArraySet = require("./ArraySet");
33
- var import_HistoryBuffer = require("./HistoryBuffer");
34
33
  var import_capture = require("./capture");
35
34
  var import_constants = require("./constants");
36
35
  var import_helpers = require("./helpers");
36
+ var import_HistoryBuffer = require("./HistoryBuffer");
37
37
  var import_transactions = require("./transactions");
38
38
  var import_types = require("./types");
39
39
  var import_warnings = require("./warnings");
40
40
  var import_isComputed = require("./isComputed");
41
- const UNINITIALIZED = Symbol.for("com.tldraw.state/UNINITIALIZED");
41
+ const UNINITIALIZED = /* @__PURE__ */ Symbol.for("com.tldraw.state/UNINITIALIZED");
42
42
  function isUninitialized(value) {
43
43
  return value === UNINITIALIZED;
44
44
  }
@@ -49,6 +49,8 @@ const WithDiff = (0, import_helpers.singleton)(
49
49
  this.value = value;
50
50
  this.diff = diff;
51
51
  }
52
+ value;
53
+ diff;
52
54
  }
53
55
  );
54
56
  function withDiff(value, diff) {
@@ -64,6 +66,8 @@ class __UNSAFE__Computed {
64
66
  this.computeDiff = options?.computeDiff;
65
67
  this.isEqual = options?.isEqual ?? import_helpers.equals;
66
68
  }
69
+ name;
70
+ derive;
67
71
  __isComputed = true;
68
72
  lastChangedEpoch = import_constants.GLOBAL_START_EPOCH;
69
73
  lastTraversedEpoch = import_constants.GLOBAL_START_EPOCH;
@@ -76,7 +80,7 @@ class __UNSAFE__Computed {
76
80
  parents = [];
77
81
  parentEpochs = [];
78
82
  children = new import_ArraySet.ArraySet();
79
- // eslint-disable-next-line no-restricted-syntax
83
+ // eslint-disable-next-line tldraw/no-setter-getter
80
84
  get isActivelyListening() {
81
85
  return !this.children.isEmpty;
82
86
  }
@@ -157,7 +161,7 @@ class __UNSAFE__Computed {
157
161
  const _Computed = (0, import_helpers.singleton)("Computed", () => __UNSAFE__Computed);
158
162
  function computedMethodLegacyDecorator(options = {}, _target, key, descriptor) {
159
163
  const originalMethod = descriptor.value;
160
- const derivationKey = Symbol.for("__@tldraw/state__computed__" + key);
164
+ const derivationKey = /* @__PURE__ */ Symbol.for("__@tldraw/state__computed__" + key);
161
165
  descriptor.value = function() {
162
166
  let d = this[derivationKey];
163
167
  if (!d) {
@@ -176,7 +180,7 @@ function computedMethodLegacyDecorator(options = {}, _target, key, descriptor) {
176
180
  }
177
181
  function computedGetterLegacyDecorator(options = {}, _target, key, descriptor) {
178
182
  const originalMethod = descriptor.get;
179
- const derivationKey = Symbol.for("__@tldraw/state__computed__" + key);
183
+ const derivationKey = /* @__PURE__ */ Symbol.for("__@tldraw/state__computed__" + key);
180
184
  descriptor.get = function() {
181
185
  let d = this[derivationKey];
182
186
  if (!d) {
@@ -194,7 +198,7 @@ function computedGetterLegacyDecorator(options = {}, _target, key, descriptor) {
194
198
  }
195
199
  function computedMethodTc39Decorator(options, compute, context) {
196
200
  (0, import_utils.assert)(context.kind === "method", "@computed can only be used on methods");
197
- const derivationKey = Symbol.for("__@tldraw/state__computed__" + String(context.name));
201
+ const derivationKey = /* @__PURE__ */ Symbol.for("__@tldraw/state__computed__" + String(context.name));
198
202
  const fn = function() {
199
203
  let d = this[derivationKey];
200
204
  if (!d) {
@@ -227,7 +231,7 @@ function computedDecorator(options = {}, args) {
227
231
  }
228
232
  const isComputedMethodKey = "@@__isComputedMethod__@@";
229
233
  function getComputedInstance(obj, propertyName) {
230
- const key = Symbol.for("__@tldraw/state__computed__" + propertyName.toString());
234
+ const key = /* @__PURE__ */ Symbol.for("__@tldraw/state__computed__" + propertyName.toString());
231
235
  let inst = obj[key];
232
236
  if (!inst) {
233
237
  const val = obj[propertyName];
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/lib/Computed.ts"],
4
- "sourcesContent": ["/* eslint-disable prefer-rest-params */\nimport { assert } from '@tldraw/utils'\nimport { ArraySet } from './ArraySet'\nimport { HistoryBuffer } from './HistoryBuffer'\nimport { maybeCaptureParent, startCapturingParents, stopCapturingParents } from './capture'\nimport { GLOBAL_START_EPOCH } from './constants'\nimport { EMPTY_ARRAY, equals, haveParentsChanged, singleton } from './helpers'\nimport { getGlobalEpoch, getIsReacting, getReactionEpoch } from './transactions'\nimport { Child, ComputeDiff, RESET_VALUE, Signal } from './types'\nimport { logComputedGetterWarning } from './warnings'\n\n/**\n * A special symbol used to indicate that a computed signal has not been initialized yet.\n * This is passed as the `previousValue` parameter to a computed signal function on its first run.\n *\n * @example\n * ```ts\n * const count = atom('count', 0)\n * const double = computed('double', (prevValue) => {\n * if (isUninitialized(prevValue)) {\n * console.log('First computation!')\n * }\n * return count.get() * 2\n * })\n * ```\n *\n * @public\n */\nexport const UNINITIALIZED = Symbol.for('com.tldraw.state/UNINITIALIZED')\n/**\n * The type of the first value passed to a computed signal function as the 'prevValue' parameter.\n * This type represents the uninitialized state of a computed signal before its first calculation.\n *\n * @see {@link isUninitialized}\n * @public\n */\nexport type UNINITIALIZED = typeof UNINITIALIZED\n\n/**\n * Call this inside a computed signal function to determine whether it is the first time the function is being called.\n *\n * Mainly useful for incremental signal computation.\n *\n * @example\n * ```ts\n * const count = atom('count', 0)\n * const double = computed('double', (prevValue) => {\n * if (isUninitialized(prevValue)) {\n * print('First time!')\n * }\n * return count.get() * 2\n * })\n * ```\n *\n * @param value - The value to check.\n * @public\n */\nexport function isUninitialized(value: any): value is UNINITIALIZED {\n\treturn value === UNINITIALIZED\n}\n\n/**\n * A singleton class used to wrap computed signal values along with their diffs.\n * This class is used internally by the {@link withDiff} function to provide both\n * the computed value and its diff to the signal system.\n *\n * @example\n * ```ts\n * const count = atom('count', 0)\n * const double = computed('double', (prevValue) => {\n * const nextValue = count.get() * 2\n * if (isUninitialized(prevValue)) {\n * return nextValue\n * }\n * return withDiff(nextValue, nextValue - prevValue)\n * })\n * ```\n *\n * @public\n */\nexport const WithDiff = singleton(\n\t'WithDiff',\n\t() =>\n\t\tclass WithDiff<Value, Diff> {\n\t\t\tconstructor(\n\t\t\t\tpublic value: Value,\n\t\t\t\tpublic diff: Diff\n\t\t\t) {}\n\t\t}\n)\n\n/**\n * Interface representing a value wrapped with its corresponding diff.\n * Used in incremental computation to provide both the new value and the diff from the previous value.\n *\n * @public\n */\nexport interface WithDiff<Value, Diff> {\n\t/**\n\t * The computed value.\n\t */\n\tvalue: Value\n\t/**\n\t * The diff between the previous and current value.\n\t */\n\tdiff: Diff\n}\n\n/**\n * When writing incrementally-computed signals it is convenient (and usually more performant) to incrementally compute the diff too.\n *\n * You can use this function to wrap the return value of a computed signal function to indicate that the diff should be used instead of calculating a new one with {@link AtomOptions.computeDiff}.\n *\n * @example\n * ```ts\n * const count = atom('count', 0)\n * const double = computed('double', (prevValue) => {\n * const nextValue = count.get() * 2\n * if (isUninitialized(prevValue)) {\n * return nextValue\n * }\n * return withDiff(nextValue, nextValue - prevValue)\n * }, { historyLength: 10 })\n * ```\n *\n *\n * @param value - The value.\n * @param diff - The diff.\n * @public\n */\nexport function withDiff<Value, Diff>(value: Value, diff: Diff): WithDiff<Value, Diff> {\n\treturn new WithDiff(value, diff)\n}\n\n/**\n * Options for configuring computed signals. Used when calling `computed` or using the `@computed` decorator.\n *\n * @example\n * ```ts\n * const greeting = computed('greeting', () => `Hello ${name.get()}!`, {\n * historyLength: 10,\n * isEqual: (a, b) => a === b,\n * computeDiff: (oldVal, newVal) => ({ type: 'change', from: oldVal, to: newVal })\n * })\n * ```\n *\n * @public\n */\nexport interface ComputedOptions<Value, Diff> {\n\t/**\n\t * The maximum number of diffs to keep in the history buffer.\n\t *\n\t * If you don't need to compute diffs, or if you will supply diffs manually via {@link Atom.set}, you can leave this as `undefined` and no history buffer will be created.\n\t *\n\t * If you expect the value to be part of an active effect subscription all the time, and to not change multiple times inside of a single transaction, you can set this to a relatively low number (e.g. 10).\n\t *\n\t * Otherwise, set this to a higher number based on your usage pattern and memory constraints.\n\t *\n\t */\n\thistoryLength?: number\n\t/**\n\t * A method used to compute a diff between the computed's old and new values. If provided, it will not be used unless you also specify {@link ComputedOptions.historyLength}.\n\t */\n\tcomputeDiff?: ComputeDiff<Value, Diff>\n\t/**\n\t * If provided, this will be used to compare the old and new values of the computed to determine if the value has changed.\n\t * By default, values are compared using first using strict equality (`===`), then `Object.is`, and finally any `.equals` method present in the object's prototype chain.\n\t * @param a - The old value\n\t * @param b - The new value\n\t * @returns True if the values are equal, false otherwise.\n\t */\n\tisEqual?(a: any, b: any): boolean\n}\n\n/**\n * A computed signal created via the `computed` function or `@computed` decorator.\n * Computed signals derive their values from other signals and automatically update when their dependencies change.\n * They use lazy evaluation, only recalculating when accessed and dependencies have changed.\n *\n * @example\n * ```ts\n * const firstName = atom('firstName', 'John')\n * const lastName = atom('lastName', 'Doe')\n * const fullName = computed('fullName', () => `${firstName.get()} ${lastName.get()}`)\n *\n * console.log(fullName.get()) // \"John Doe\"\n * firstName.set('Jane')\n * console.log(fullName.get()) // \"Jane Doe\"\n * ```\n *\n * @public\n */\nexport interface Computed<Value, Diff = unknown> extends Signal<Value, Diff> {\n\t/**\n\t * Whether this computed signal is involved in an actively-running effect graph.\n\t * Returns true if there are any reactions or other computed signals depending on this one.\n\t * @public\n\t */\n\treadonly isActivelyListening: boolean\n\n\t/** @internal */\n\treadonly parentSet: ArraySet<Signal<any, any>>\n\t/** @internal */\n\treadonly parents: Signal<any, any>[]\n\t/** @internal */\n\treadonly parentEpochs: number[]\n}\n\n/**\n * @internal\n */\nclass __UNSAFE__Computed<Value, Diff = unknown> implements Computed<Value, Diff> {\n\treadonly __isComputed = true as const\n\tlastChangedEpoch = GLOBAL_START_EPOCH\n\tlastTraversedEpoch = GLOBAL_START_EPOCH\n\n\t__debug_ancestor_epochs__: Map<Signal<any, any>, number> | null = null\n\n\t/**\n\t * The epoch when the reactor was last checked.\n\t */\n\tprivate lastCheckedEpoch = GLOBAL_START_EPOCH\n\n\tparentSet = new ArraySet<Signal<any, any>>()\n\tparents: Signal<any, any>[] = []\n\tparentEpochs: number[] = []\n\n\tchildren = new ArraySet<Child>()\n\n\t// eslint-disable-next-line no-restricted-syntax\n\tget isActivelyListening(): boolean {\n\t\treturn !this.children.isEmpty\n\t}\n\n\thistoryBuffer?: HistoryBuffer<Diff>\n\n\t// The last-computed value of this signal.\n\tprivate state: Value = UNINITIALIZED as unknown as Value\n\t// If the signal throws an error we stash it so we can rethrow it on the next get()\n\tprivate error: null | { thrownValue: any } = null\n\n\tprivate computeDiff?: ComputeDiff<Value, Diff>\n\n\tprivate readonly isEqual: (a: any, b: any) => boolean\n\n\tconstructor(\n\t\t/**\n\t\t * The name of the signal. This is used for debugging and performance profiling purposes. It does not need to be globally unique.\n\t\t */\n\t\tpublic readonly name: string,\n\t\t/**\n\t\t * The function that computes the value of the signal.\n\t\t */\n\t\tprivate readonly derive: (\n\t\t\tpreviousValue: Value | UNINITIALIZED,\n\t\t\tlastComputedEpoch: number\n\t\t) => Value | WithDiff<Value, Diff>,\n\t\toptions?: ComputedOptions<Value, Diff>\n\t) {\n\t\tif (options?.historyLength) {\n\t\t\tthis.historyBuffer = new HistoryBuffer(options.historyLength)\n\t\t}\n\t\tthis.computeDiff = options?.computeDiff\n\t\tthis.isEqual = options?.isEqual ?? equals\n\t}\n\n\t__unsafe__getWithoutCapture(ignoreErrors?: boolean): Value {\n\t\tconst isNew = this.lastChangedEpoch === GLOBAL_START_EPOCH\n\n\t\tconst globalEpoch = getGlobalEpoch()\n\n\t\tif (\n\t\t\t!isNew &&\n\t\t\t(this.lastCheckedEpoch === globalEpoch ||\n\t\t\t\t(this.isActivelyListening &&\n\t\t\t\t\tgetIsReacting() &&\n\t\t\t\t\tthis.lastTraversedEpoch < getReactionEpoch()) ||\n\t\t\t\t!haveParentsChanged(this))\n\t\t) {\n\t\t\tthis.lastCheckedEpoch = globalEpoch\n\t\t\tif (this.error) {\n\t\t\t\tif (!ignoreErrors) {\n\t\t\t\t\tthrow this.error.thrownValue\n\t\t\t\t} else {\n\t\t\t\t\treturn this.state // will be UNINITIALIZED\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treturn this.state\n\t\t\t}\n\t\t}\n\n\t\ttry {\n\t\t\tstartCapturingParents(this)\n\t\t\tconst result = this.derive(this.state, this.lastCheckedEpoch)\n\t\t\tconst newState = result instanceof WithDiff ? result.value : result\n\t\t\tconst isUninitialized = this.state === UNINITIALIZED\n\t\t\tif (isUninitialized || !this.isEqual(newState, this.state)) {\n\t\t\t\tif (this.historyBuffer && !isUninitialized) {\n\t\t\t\t\tconst diff = result instanceof WithDiff ? result.diff : undefined\n\t\t\t\t\tthis.historyBuffer.pushEntry(\n\t\t\t\t\t\tthis.lastChangedEpoch,\n\t\t\t\t\t\tgetGlobalEpoch(),\n\t\t\t\t\t\tdiff ??\n\t\t\t\t\t\t\tthis.computeDiff?.(this.state, newState, this.lastCheckedEpoch, getGlobalEpoch()) ??\n\t\t\t\t\t\t\tRESET_VALUE\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\tthis.lastChangedEpoch = getGlobalEpoch()\n\t\t\t\tthis.state = newState\n\t\t\t}\n\t\t\tthis.error = null\n\t\t\tthis.lastCheckedEpoch = getGlobalEpoch()\n\n\t\t\treturn this.state\n\t\t} catch (e) {\n\t\t\t// if a derived value throws an error, we reset the state to UNINITIALIZED\n\t\t\tif (this.state !== UNINITIALIZED) {\n\t\t\t\tthis.state = UNINITIALIZED as unknown as Value\n\t\t\t\tthis.lastChangedEpoch = getGlobalEpoch()\n\t\t\t}\n\t\t\tthis.lastCheckedEpoch = getGlobalEpoch()\n\t\t\t// we also clear the history buffer if an error was thrown\n\t\t\tif (this.historyBuffer) {\n\t\t\t\tthis.historyBuffer.clear()\n\t\t\t}\n\t\t\tthis.error = { thrownValue: e }\n\t\t\t// we don't wish to propagate errors when derefed via haveParentsChanged()\n\t\t\tif (!ignoreErrors) throw e\n\t\t\treturn this.state\n\t\t} finally {\n\t\t\tstopCapturingParents()\n\t\t}\n\t}\n\n\tget(): Value {\n\t\ttry {\n\t\t\treturn this.__unsafe__getWithoutCapture()\n\t\t} finally {\n\t\t\t// if the deriver throws an error we still need to capture\n\t\t\tmaybeCaptureParent(this)\n\t\t}\n\t}\n\n\tgetDiffSince(epoch: number): RESET_VALUE | Diff[] {\n\t\t// we can ignore any errors thrown during derive\n\t\tthis.__unsafe__getWithoutCapture(true)\n\t\t// and we still need to capture this signal as a parent\n\t\tmaybeCaptureParent(this)\n\n\t\tif (epoch >= this.lastChangedEpoch) {\n\t\t\treturn EMPTY_ARRAY\n\t\t}\n\n\t\treturn this.historyBuffer?.getChangesSince(epoch) ?? RESET_VALUE\n\t}\n}\n\n/**\n * Singleton reference to the computed signal implementation class.\n * Used internally by the library to create computed signal instances.\n *\n * @internal\n */\nexport const _Computed = singleton('Computed', () => __UNSAFE__Computed)\n\n/**\n * Type alias for the computed signal implementation class.\n *\n * @internal\n */\nexport type _Computed = InstanceType<typeof __UNSAFE__Computed>\n\nfunction computedMethodLegacyDecorator(\n\toptions: ComputedOptions<any, any> = {},\n\t_target: any,\n\tkey: string,\n\tdescriptor: PropertyDescriptor\n) {\n\tconst originalMethod = descriptor.value\n\tconst derivationKey = Symbol.for('__@tldraw/state__computed__' + key)\n\n\tdescriptor.value = function (this: any) {\n\t\tlet d = this[derivationKey] as Computed<any> | undefined\n\n\t\tif (!d) {\n\t\t\td = new _Computed(key, originalMethod!.bind(this) as any, options)\n\t\t\tObject.defineProperty(this, derivationKey, {\n\t\t\t\tenumerable: false,\n\t\t\t\tconfigurable: false,\n\t\t\t\twritable: false,\n\t\t\t\tvalue: d,\n\t\t\t})\n\t\t}\n\t\treturn d.get()\n\t}\n\tdescriptor.value[isComputedMethodKey] = true\n\n\treturn descriptor\n}\n\nfunction computedGetterLegacyDecorator(\n\toptions: ComputedOptions<any, any> = {},\n\t_target: any,\n\tkey: string,\n\tdescriptor: PropertyDescriptor\n) {\n\tconst originalMethod = descriptor.get\n\tconst derivationKey = Symbol.for('__@tldraw/state__computed__' + key)\n\n\tdescriptor.get = function (this: any) {\n\t\tlet d = this[derivationKey] as Computed<any> | undefined\n\n\t\tif (!d) {\n\t\t\td = new _Computed(key, originalMethod!.bind(this) as any, options)\n\t\t\tObject.defineProperty(this, derivationKey, {\n\t\t\t\tenumerable: false,\n\t\t\t\tconfigurable: false,\n\t\t\t\twritable: false,\n\t\t\t\tvalue: d,\n\t\t\t})\n\t\t}\n\t\treturn d.get()\n\t}\n\n\treturn descriptor\n}\n\nfunction computedMethodTc39Decorator<This extends object, Value>(\n\toptions: ComputedOptions<Value, any>,\n\tcompute: () => Value,\n\tcontext: ClassMethodDecoratorContext<This, () => Value>\n) {\n\tassert(context.kind === 'method', '@computed can only be used on methods')\n\tconst derivationKey = Symbol.for('__@tldraw/state__computed__' + String(context.name))\n\n\tconst fn = function (this: any) {\n\t\tlet d = this[derivationKey] as Computed<any> | undefined\n\n\t\tif (!d) {\n\t\t\td = new _Computed(String(context.name), compute.bind(this) as any, options)\n\t\t\tObject.defineProperty(this, derivationKey, {\n\t\t\t\tenumerable: false,\n\t\t\t\tconfigurable: false,\n\t\t\t\twritable: false,\n\t\t\t\tvalue: d,\n\t\t\t})\n\t\t}\n\t\treturn d.get()\n\t}\n\tfn[isComputedMethodKey] = true\n\treturn fn\n}\n\nfunction computedDecorator(\n\toptions: ComputedOptions<any, any> = {},\n\targs:\n\t\t| [target: any, key: string, descriptor: PropertyDescriptor]\n\t\t| [originalMethod: () => any, context: ClassMethodDecoratorContext]\n) {\n\tif (args.length === 2) {\n\t\tconst [originalMethod, context] = args\n\t\treturn computedMethodTc39Decorator(options, originalMethod, context)\n\t} else {\n\t\tconst [_target, key, descriptor] = args\n\t\tif (descriptor.get) {\n\t\t\tlogComputedGetterWarning()\n\t\t\treturn computedGetterLegacyDecorator(options, _target, key, descriptor)\n\t\t} else {\n\t\t\treturn computedMethodLegacyDecorator(options, _target, key, descriptor)\n\t\t}\n\t}\n}\n\nconst isComputedMethodKey = '@@__isComputedMethod__@@'\n\n/**\n * Retrieves the underlying computed instance for a given property created with the `computed`\n * decorator.\n *\n * @example\n * ```ts\n * class Counter {\n * max = 100\n * count = atom(0)\n *\n * @computed getRemaining() {\n * return this.max - this.count.get()\n * }\n * }\n *\n * const c = new Counter()\n * const remaining = getComputedInstance(c, 'getRemaining')\n * remaining.get() === 100 // true\n * c.count.set(13)\n * remaining.get() === 87 // true\n * ```\n *\n * @param obj - The object\n * @param propertyName - The property name\n * @public\n */\nexport function getComputedInstance<Obj extends object, Prop extends keyof Obj>(\n\tobj: Obj,\n\tpropertyName: Prop\n): Computed<Obj[Prop]> {\n\tconst key = Symbol.for('__@tldraw/state__computed__' + propertyName.toString())\n\tlet inst = obj[key as keyof typeof obj] as Computed<Obj[Prop]> | undefined\n\tif (!inst) {\n\t\t// deref to make sure it exists first\n\t\tconst val = obj[propertyName]\n\t\tif (typeof val === 'function' && (val as any)[isComputedMethodKey]) {\n\t\t\tval.call(obj)\n\t\t}\n\n\t\tinst = obj[key as keyof typeof obj] as Computed<Obj[Prop]> | undefined\n\t}\n\treturn inst as any\n}\n\n/**\n * Creates a computed signal that derives its value from other signals.\n * Computed signals automatically update when their dependencies change and use lazy evaluation\n * for optimal performance.\n *\n * @example\n * ```ts\n * const name = atom('name', 'John')\n * const greeting = computed('greeting', () => `Hello ${name.get()}!`)\n * console.log(greeting.get()) // 'Hello John!'\n * ```\n *\n * `computed` may also be used as a decorator for creating computed getter methods.\n *\n * @example\n * ```ts\n * class Counter {\n * max = 100\n * count = atom<number>(0)\n *\n * @computed getRemaining() {\n * return this.max - this.count.get()\n * }\n * }\n * ```\n *\n * You may optionally pass in a {@link ComputedOptions} when used as a decorator:\n *\n * @example\n * ```ts\n * class Counter {\n * max = 100\n * count = atom<number>(0)\n *\n * @computed({isEqual: (a, b) => a === b})\n * getRemaining() {\n * return this.max - this.count.get()\n * }\n * }\n * ```\n *\n * @param name - The name of the signal for debugging purposes\n * @param compute - The function that computes the value of the signal. Receives the previous value and last computed epoch\n * @param options - Optional configuration for the computed signal\n * @returns A new computed signal\n * @public\n */\nexport function computed<Value, Diff = unknown>(\n\tname: string,\n\tcompute: (\n\t\tpreviousValue: Value | typeof UNINITIALIZED,\n\t\tlastComputedEpoch: number\n\t) => Value | WithDiff<Value, Diff>,\n\toptions?: ComputedOptions<Value, Diff>\n): Computed<Value, Diff>\n/**\n * TC39 decorator for creating computed methods in classes.\n *\n * @example\n * ```ts\n * class MyClass {\n * value = atom('value', 10)\n *\n * @computed\n * doubled() {\n * return this.value.get() * 2\n * }\n * }\n * ```\n *\n * @param compute - The method to be decorated\n * @param context - The decorator context provided by TypeScript\n * @returns The decorated method\n * @public\n */\nexport function computed<This extends object, Value>(\n\tcompute: () => Value,\n\tcontext: ClassMethodDecoratorContext<This, () => Value>\n): () => Value\n/**\n * Legacy TypeScript decorator for creating computed methods in classes.\n *\n * @example\n * ```ts\n * class MyClass {\n * value = atom('value', 10)\n *\n * @computed\n * doubled() {\n * return this.value.get() * 2\n * }\n * }\n * ```\n *\n * @param target - The class prototype\n * @param key - The property key\n * @param descriptor - The property descriptor\n * @returns The modified property descriptor\n * @public\n */\nexport function computed(\n\ttarget: any,\n\tkey: string,\n\tdescriptor: PropertyDescriptor\n): PropertyDescriptor\n/**\n * Decorator factory for creating computed methods with options.\n *\n * @example\n * ```ts\n * class MyClass {\n * items = atom('items', [1, 2, 3])\n *\n * @computed({ historyLength: 10 })\n * sum() {\n * return this.items.get().reduce((a, b) => a + b, 0)\n * }\n * }\n * ```\n *\n * @param options - Configuration options for the computed signal\n * @returns A decorator function that can be applied to methods\n * @public\n */\nexport function computed<Value, Diff = unknown>(\n\toptions?: ComputedOptions<Value, Diff>\n): ((target: any, key: string, descriptor: PropertyDescriptor) => PropertyDescriptor) &\n\t(<This>(\n\t\tcompute: () => Value,\n\t\tcontext: ClassMethodDecoratorContext<This, () => Value>\n\t) => () => Value)\n\n/**\n * Implementation function that handles all computed signal creation and decoration scenarios.\n * This function is overloaded to support multiple usage patterns:\n * - Creating computed signals directly\n * - Using as a TC39 decorator\n * - Using as a legacy decorator\n * - Using as a decorator factory with options\n *\n * @returns Either a computed signal instance or a decorator function depending on usage\n * @public\n */\nexport function computed() {\n\tif (arguments.length === 1) {\n\t\tconst options = arguments[0]\n\t\treturn (...args: any) => computedDecorator(options, args)\n\t} else if (typeof arguments[0] === 'string') {\n\t\treturn new _Computed(arguments[0], arguments[1], arguments[2])\n\t} else {\n\t\treturn computedDecorator(undefined, arguments as any)\n\t}\n}\n\nimport { isComputed as _isComputed } from './isComputed'\n\n/**\n * Returns true if the given value is a computed signal.\n * @public\n */\nexport function isComputed(value: any): value is Computed<any> {\n\treturn _isComputed(value)\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/* eslint-disable prefer-rest-params */\nimport { assert } from '@tldraw/utils'\nimport { ArraySet } from './ArraySet'\nimport { maybeCaptureParent, startCapturingParents, stopCapturingParents } from './capture'\nimport { GLOBAL_START_EPOCH } from './constants'\nimport { EMPTY_ARRAY, equals, haveParentsChanged, singleton } from './helpers'\nimport { HistoryBuffer } from './HistoryBuffer'\nimport { getGlobalEpoch, getIsReacting, getReactionEpoch } from './transactions'\nimport { Child, ComputeDiff, RESET_VALUE, Signal } from './types'\nimport { logComputedGetterWarning } from './warnings'\n\n/**\n * A special symbol used to indicate that a computed signal has not been initialized yet.\n * This is passed as the `previousValue` parameter to a computed signal function on its first run.\n *\n * @example\n * ```ts\n * const count = atom('count', 0)\n * const double = computed('double', (prevValue) => {\n * if (isUninitialized(prevValue)) {\n * console.log('First computation!')\n * }\n * return count.get() * 2\n * })\n * ```\n *\n * @public\n */\nexport const UNINITIALIZED = Symbol.for('com.tldraw.state/UNINITIALIZED')\n/**\n * The type of the first value passed to a computed signal function as the 'prevValue' parameter.\n * This type represents the uninitialized state of a computed signal before its first calculation.\n *\n * @see {@link isUninitialized}\n * @public\n */\nexport type UNINITIALIZED = typeof UNINITIALIZED\n\n/**\n * Call this inside a computed signal function to determine whether it is the first time the function is being called.\n *\n * Mainly useful for incremental signal computation.\n *\n * @example\n * ```ts\n * const count = atom('count', 0)\n * const double = computed('double', (prevValue) => {\n * if (isUninitialized(prevValue)) {\n * print('First time!')\n * }\n * return count.get() * 2\n * })\n * ```\n *\n * @param value - The value to check.\n * @public\n */\nexport function isUninitialized(value: any): value is UNINITIALIZED {\n\treturn value === UNINITIALIZED\n}\n\n/**\n * A singleton class used to wrap computed signal values along with their diffs.\n * This class is used internally by the {@link withDiff} function to provide both\n * the computed value and its diff to the signal system.\n *\n * @example\n * ```ts\n * const count = atom('count', 0)\n * const double = computed('double', (prevValue) => {\n * const nextValue = count.get() * 2\n * if (isUninitialized(prevValue)) {\n * return nextValue\n * }\n * return withDiff(nextValue, nextValue - prevValue)\n * })\n * ```\n *\n * @public\n */\nexport const WithDiff = singleton(\n\t'WithDiff',\n\t() =>\n\t\tclass WithDiff<Value, Diff> {\n\t\t\tconstructor(\n\t\t\t\tpublic value: Value,\n\t\t\t\tpublic diff: Diff\n\t\t\t) {}\n\t\t}\n)\n\n/**\n * Interface representing a value wrapped with its corresponding diff.\n * Used in incremental computation to provide both the new value and the diff from the previous value.\n *\n * @public\n */\nexport interface WithDiff<Value, Diff> {\n\t/**\n\t * The computed value.\n\t */\n\tvalue: Value\n\t/**\n\t * The diff between the previous and current value.\n\t */\n\tdiff: Diff\n}\n\n/**\n * When writing incrementally-computed signals it is convenient (and usually more performant) to incrementally compute the diff too.\n *\n * You can use this function to wrap the return value of a computed signal function to indicate that the diff should be used instead of calculating a new one with {@link AtomOptions.computeDiff}.\n *\n * @example\n * ```ts\n * const count = atom('count', 0)\n * const double = computed('double', (prevValue) => {\n * const nextValue = count.get() * 2\n * if (isUninitialized(prevValue)) {\n * return nextValue\n * }\n * return withDiff(nextValue, nextValue - prevValue)\n * }, { historyLength: 10 })\n * ```\n *\n *\n * @param value - The value.\n * @param diff - The diff.\n * @public\n */\nexport function withDiff<Value, Diff>(value: Value, diff: Diff): WithDiff<Value, Diff> {\n\treturn new WithDiff(value, diff)\n}\n\n/**\n * Options for configuring computed signals. Used when calling `computed` or using the `@computed` decorator.\n *\n * @example\n * ```ts\n * const greeting = computed('greeting', () => `Hello ${name.get()}!`, {\n * historyLength: 10,\n * isEqual: (a, b) => a === b,\n * computeDiff: (oldVal, newVal) => ({ type: 'change', from: oldVal, to: newVal })\n * })\n * ```\n *\n * @public\n */\nexport interface ComputedOptions<Value, Diff> {\n\t/**\n\t * The maximum number of diffs to keep in the history buffer.\n\t *\n\t * If you don't need to compute diffs, or if you will supply diffs manually via {@link Atom.set}, you can leave this as `undefined` and no history buffer will be created.\n\t *\n\t * If you expect the value to be part of an active effect subscription all the time, and to not change multiple times inside of a single transaction, you can set this to a relatively low number (e.g. 10).\n\t *\n\t * Otherwise, set this to a higher number based on your usage pattern and memory constraints.\n\t *\n\t */\n\thistoryLength?: number\n\t/**\n\t * A method used to compute a diff between the computed's old and new values. If provided, it will not be used unless you also specify {@link ComputedOptions.historyLength}.\n\t */\n\tcomputeDiff?: ComputeDiff<Value, Diff>\n\t/**\n\t * If provided, this will be used to compare the old and new values of the computed to determine if the value has changed.\n\t * By default, values are compared using first using strict equality (`===`), then `Object.is`, and finally any `.equals` method present in the object's prototype chain.\n\t * @param a - The old value\n\t * @param b - The new value\n\t * @returns True if the values are equal, false otherwise.\n\t */\n\tisEqual?(a: any, b: any): boolean\n}\n\n/**\n * A computed signal created via the `computed` function or `@computed` decorator.\n * Computed signals derive their values from other signals and automatically update when their dependencies change.\n * They use lazy evaluation, only recalculating when accessed and dependencies have changed.\n *\n * @example\n * ```ts\n * const firstName = atom('firstName', 'John')\n * const lastName = atom('lastName', 'Doe')\n * const fullName = computed('fullName', () => `${firstName.get()} ${lastName.get()}`)\n *\n * console.log(fullName.get()) // \"John Doe\"\n * firstName.set('Jane')\n * console.log(fullName.get()) // \"Jane Doe\"\n * ```\n *\n * @public\n */\nexport interface Computed<Value, Diff = unknown> extends Signal<Value, Diff> {\n\t/**\n\t * Whether this computed signal is involved in an actively-running effect graph.\n\t * Returns true if there are any reactions or other computed signals depending on this one.\n\t * @public\n\t */\n\treadonly isActivelyListening: boolean\n\n\t/** @internal */\n\treadonly parentSet: ArraySet<Signal<any, any>>\n\t/** @internal */\n\treadonly parents: Signal<any, any>[]\n\t/** @internal */\n\treadonly parentEpochs: number[]\n}\n\n/**\n * @internal\n */\nclass __UNSAFE__Computed<Value, Diff = unknown> implements Computed<Value, Diff> {\n\treadonly __isComputed = true as const\n\tlastChangedEpoch = GLOBAL_START_EPOCH\n\tlastTraversedEpoch = GLOBAL_START_EPOCH\n\n\t__debug_ancestor_epochs__: Map<Signal<any, any>, number> | null = null\n\n\t/**\n\t * The epoch when the reactor was last checked.\n\t */\n\tprivate lastCheckedEpoch = GLOBAL_START_EPOCH\n\n\tparentSet = new ArraySet<Signal<any, any>>()\n\tparents: Signal<any, any>[] = []\n\tparentEpochs: number[] = []\n\n\tchildren = new ArraySet<Child>()\n\n\t// eslint-disable-next-line tldraw/no-setter-getter\n\tget isActivelyListening(): boolean {\n\t\treturn !this.children.isEmpty\n\t}\n\n\thistoryBuffer?: HistoryBuffer<Diff>\n\n\t// The last-computed value of this signal.\n\tprivate state: Value = UNINITIALIZED as unknown as Value\n\t// If the signal throws an error we stash it so we can rethrow it on the next get()\n\tprivate error: null | { thrownValue: any } = null\n\n\tprivate computeDiff?: ComputeDiff<Value, Diff>\n\n\tprivate readonly isEqual: (a: any, b: any) => boolean\n\n\tconstructor(\n\t\t/**\n\t\t * The name of the signal. This is used for debugging and performance profiling purposes. It does not need to be globally unique.\n\t\t */\n\t\tpublic readonly name: string,\n\t\t/**\n\t\t * The function that computes the value of the signal.\n\t\t */\n\t\tprivate readonly derive: (\n\t\t\tpreviousValue: Value | UNINITIALIZED,\n\t\t\tlastComputedEpoch: number\n\t\t) => Value | WithDiff<Value, Diff>,\n\t\toptions?: ComputedOptions<Value, Diff>\n\t) {\n\t\tif (options?.historyLength) {\n\t\t\tthis.historyBuffer = new HistoryBuffer(options.historyLength)\n\t\t}\n\t\tthis.computeDiff = options?.computeDiff\n\t\tthis.isEqual = options?.isEqual ?? equals\n\t}\n\n\t__unsafe__getWithoutCapture(ignoreErrors?: boolean): Value {\n\t\tconst isNew = this.lastChangedEpoch === GLOBAL_START_EPOCH\n\n\t\tconst globalEpoch = getGlobalEpoch()\n\n\t\tif (\n\t\t\t!isNew &&\n\t\t\t(this.lastCheckedEpoch === globalEpoch ||\n\t\t\t\t(this.isActivelyListening &&\n\t\t\t\t\tgetIsReacting() &&\n\t\t\t\t\tthis.lastTraversedEpoch < getReactionEpoch()) ||\n\t\t\t\t!haveParentsChanged(this))\n\t\t) {\n\t\t\tthis.lastCheckedEpoch = globalEpoch\n\t\t\tif (this.error) {\n\t\t\t\tif (!ignoreErrors) {\n\t\t\t\t\tthrow this.error.thrownValue\n\t\t\t\t} else {\n\t\t\t\t\treturn this.state // will be UNINITIALIZED\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treturn this.state\n\t\t\t}\n\t\t}\n\n\t\ttry {\n\t\t\tstartCapturingParents(this)\n\t\t\tconst result = this.derive(this.state, this.lastCheckedEpoch)\n\t\t\tconst newState = result instanceof WithDiff ? result.value : result\n\t\t\tconst isUninitialized = this.state === UNINITIALIZED\n\t\t\tif (isUninitialized || !this.isEqual(newState, this.state)) {\n\t\t\t\tif (this.historyBuffer && !isUninitialized) {\n\t\t\t\t\tconst diff = result instanceof WithDiff ? result.diff : undefined\n\t\t\t\t\tthis.historyBuffer.pushEntry(\n\t\t\t\t\t\tthis.lastChangedEpoch,\n\t\t\t\t\t\tgetGlobalEpoch(),\n\t\t\t\t\t\tdiff ??\n\t\t\t\t\t\t\tthis.computeDiff?.(this.state, newState, this.lastCheckedEpoch, getGlobalEpoch()) ??\n\t\t\t\t\t\t\tRESET_VALUE\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\tthis.lastChangedEpoch = getGlobalEpoch()\n\t\t\t\tthis.state = newState\n\t\t\t}\n\t\t\tthis.error = null\n\t\t\tthis.lastCheckedEpoch = getGlobalEpoch()\n\n\t\t\treturn this.state\n\t\t} catch (e) {\n\t\t\t// if a derived value throws an error, we reset the state to UNINITIALIZED\n\t\t\tif (this.state !== UNINITIALIZED) {\n\t\t\t\tthis.state = UNINITIALIZED as unknown as Value\n\t\t\t\tthis.lastChangedEpoch = getGlobalEpoch()\n\t\t\t}\n\t\t\tthis.lastCheckedEpoch = getGlobalEpoch()\n\t\t\t// we also clear the history buffer if an error was thrown\n\t\t\tif (this.historyBuffer) {\n\t\t\t\tthis.historyBuffer.clear()\n\t\t\t}\n\t\t\tthis.error = { thrownValue: e }\n\t\t\t// we don't wish to propagate errors when derefed via haveParentsChanged()\n\t\t\tif (!ignoreErrors) throw e\n\t\t\treturn this.state\n\t\t} finally {\n\t\t\tstopCapturingParents()\n\t\t}\n\t}\n\n\tget(): Value {\n\t\ttry {\n\t\t\treturn this.__unsafe__getWithoutCapture()\n\t\t} finally {\n\t\t\t// if the deriver throws an error we still need to capture\n\t\t\tmaybeCaptureParent(this)\n\t\t}\n\t}\n\n\tgetDiffSince(epoch: number): RESET_VALUE | Diff[] {\n\t\t// we can ignore any errors thrown during derive\n\t\tthis.__unsafe__getWithoutCapture(true)\n\t\t// and we still need to capture this signal as a parent\n\t\tmaybeCaptureParent(this)\n\n\t\tif (epoch >= this.lastChangedEpoch) {\n\t\t\treturn EMPTY_ARRAY\n\t\t}\n\n\t\treturn this.historyBuffer?.getChangesSince(epoch) ?? RESET_VALUE\n\t}\n}\n\n/**\n * Singleton reference to the computed signal implementation class.\n * Used internally by the library to create computed signal instances.\n *\n * @internal\n */\nexport const _Computed = singleton('Computed', () => __UNSAFE__Computed)\n\n/**\n * Type alias for the computed signal implementation class.\n *\n * @internal\n */\nexport type _Computed = InstanceType<typeof __UNSAFE__Computed>\n\nfunction computedMethodLegacyDecorator(\n\toptions: ComputedOptions<any, any> = {},\n\t_target: any,\n\tkey: string,\n\tdescriptor: PropertyDescriptor\n) {\n\tconst originalMethod = descriptor.value\n\tconst derivationKey = Symbol.for('__@tldraw/state__computed__' + key)\n\n\tdescriptor.value = function (this: any) {\n\t\tlet d = this[derivationKey] as Computed<any> | undefined\n\n\t\tif (!d) {\n\t\t\td = new _Computed(key, originalMethod!.bind(this) as any, options)\n\t\t\tObject.defineProperty(this, derivationKey, {\n\t\t\t\tenumerable: false,\n\t\t\t\tconfigurable: false,\n\t\t\t\twritable: false,\n\t\t\t\tvalue: d,\n\t\t\t})\n\t\t}\n\t\treturn d.get()\n\t}\n\tdescriptor.value[isComputedMethodKey] = true\n\n\treturn descriptor\n}\n\nfunction computedGetterLegacyDecorator(\n\toptions: ComputedOptions<any, any> = {},\n\t_target: any,\n\tkey: string,\n\tdescriptor: PropertyDescriptor\n) {\n\tconst originalMethod = descriptor.get\n\tconst derivationKey = Symbol.for('__@tldraw/state__computed__' + key)\n\n\tdescriptor.get = function (this: any) {\n\t\tlet d = this[derivationKey] as Computed<any> | undefined\n\n\t\tif (!d) {\n\t\t\td = new _Computed(key, originalMethod!.bind(this) as any, options)\n\t\t\tObject.defineProperty(this, derivationKey, {\n\t\t\t\tenumerable: false,\n\t\t\t\tconfigurable: false,\n\t\t\t\twritable: false,\n\t\t\t\tvalue: d,\n\t\t\t})\n\t\t}\n\t\treturn d.get()\n\t}\n\n\treturn descriptor\n}\n\nfunction computedMethodTc39Decorator<This extends object, Value>(\n\toptions: ComputedOptions<Value, any>,\n\tcompute: () => Value,\n\tcontext: ClassMethodDecoratorContext<This, () => Value>\n) {\n\tassert(context.kind === 'method', '@computed can only be used on methods')\n\tconst derivationKey = Symbol.for('__@tldraw/state__computed__' + String(context.name))\n\n\tconst fn = function (this: any) {\n\t\tlet d = this[derivationKey] as Computed<any> | undefined\n\n\t\tif (!d) {\n\t\t\td = new _Computed(String(context.name), compute.bind(this) as any, options)\n\t\t\tObject.defineProperty(this, derivationKey, {\n\t\t\t\tenumerable: false,\n\t\t\t\tconfigurable: false,\n\t\t\t\twritable: false,\n\t\t\t\tvalue: d,\n\t\t\t})\n\t\t}\n\t\treturn d.get()\n\t}\n\tfn[isComputedMethodKey] = true\n\treturn fn\n}\n\nfunction computedDecorator(\n\toptions: ComputedOptions<any, any> = {},\n\targs:\n\t\t| [target: any, key: string, descriptor: PropertyDescriptor]\n\t\t| [originalMethod: () => any, context: ClassMethodDecoratorContext]\n) {\n\tif (args.length === 2) {\n\t\tconst [originalMethod, context] = args\n\t\treturn computedMethodTc39Decorator(options, originalMethod, context)\n\t} else {\n\t\tconst [_target, key, descriptor] = args\n\t\tif (descriptor.get) {\n\t\t\tlogComputedGetterWarning()\n\t\t\treturn computedGetterLegacyDecorator(options, _target, key, descriptor)\n\t\t} else {\n\t\t\treturn computedMethodLegacyDecorator(options, _target, key, descriptor)\n\t\t}\n\t}\n}\n\nconst isComputedMethodKey = '@@__isComputedMethod__@@'\n\n/**\n * Retrieves the underlying computed instance for a given property created with the `computed`\n * decorator.\n *\n * @example\n * ```ts\n * class Counter {\n * max = 100\n * count = atom(0)\n *\n * @computed getRemaining() {\n * return this.max - this.count.get()\n * }\n * }\n *\n * const c = new Counter()\n * const remaining = getComputedInstance(c, 'getRemaining')\n * remaining.get() === 100 // true\n * c.count.set(13)\n * remaining.get() === 87 // true\n * ```\n *\n * @param obj - The object\n * @param propertyName - The property name\n * @public\n */\nexport function getComputedInstance<Obj extends object, Prop extends keyof Obj>(\n\tobj: Obj,\n\tpropertyName: Prop\n): Computed<Obj[Prop]> {\n\tconst key = Symbol.for('__@tldraw/state__computed__' + propertyName.toString())\n\tlet inst = obj[key as keyof typeof obj] as Computed<Obj[Prop]> | undefined\n\tif (!inst) {\n\t\t// deref to make sure it exists first\n\t\tconst val = obj[propertyName]\n\t\tif (typeof val === 'function' && (val as any)[isComputedMethodKey]) {\n\t\t\tval.call(obj)\n\t\t}\n\n\t\tinst = obj[key as keyof typeof obj] as Computed<Obj[Prop]> | undefined\n\t}\n\treturn inst as any\n}\n\n/**\n * Creates a computed signal that derives its value from other signals.\n * Computed signals automatically update when their dependencies change and use lazy evaluation\n * for optimal performance.\n *\n * @example\n * ```ts\n * const name = atom('name', 'John')\n * const greeting = computed('greeting', () => `Hello ${name.get()}!`)\n * console.log(greeting.get()) // 'Hello John!'\n * ```\n *\n * `computed` may also be used as a decorator for creating computed getter methods.\n *\n * @example\n * ```ts\n * class Counter {\n * max = 100\n * count = atom<number>(0)\n *\n * @computed getRemaining() {\n * return this.max - this.count.get()\n * }\n * }\n * ```\n *\n * You may optionally pass in a {@link ComputedOptions} when used as a decorator:\n *\n * @example\n * ```ts\n * class Counter {\n * max = 100\n * count = atom<number>(0)\n *\n * @computed({isEqual: (a, b) => a === b})\n * getRemaining() {\n * return this.max - this.count.get()\n * }\n * }\n * ```\n *\n * @param name - The name of the signal for debugging purposes\n * @param compute - The function that computes the value of the signal. Receives the previous value and last computed epoch\n * @param options - Optional configuration for the computed signal\n * @returns A new computed signal\n * @public\n */\nexport function computed<Value, Diff = unknown>(\n\tname: string,\n\tcompute: (\n\t\tpreviousValue: Value | typeof UNINITIALIZED,\n\t\tlastComputedEpoch: number\n\t) => Value | WithDiff<Value, Diff>,\n\toptions?: ComputedOptions<Value, Diff>\n): Computed<Value, Diff>\n/**\n * TC39 decorator for creating computed methods in classes.\n *\n * @example\n * ```ts\n * class MyClass {\n * value = atom('value', 10)\n *\n * @computed\n * doubled() {\n * return this.value.get() * 2\n * }\n * }\n * ```\n *\n * @param compute - The method to be decorated\n * @param context - The decorator context provided by TypeScript\n * @returns The decorated method\n * @public\n */\nexport function computed<This extends object, Value>(\n\tcompute: () => Value,\n\tcontext: ClassMethodDecoratorContext<This, () => Value>\n): () => Value\n/**\n * Legacy TypeScript decorator for creating computed methods in classes.\n *\n * @example\n * ```ts\n * class MyClass {\n * value = atom('value', 10)\n *\n * @computed\n * doubled() {\n * return this.value.get() * 2\n * }\n * }\n * ```\n *\n * @param target - The class prototype\n * @param key - The property key\n * @param descriptor - The property descriptor\n * @returns The modified property descriptor\n * @public\n */\nexport function computed(\n\ttarget: any,\n\tkey: string,\n\tdescriptor: PropertyDescriptor\n): PropertyDescriptor\n/**\n * Decorator factory for creating computed methods with options.\n *\n * @example\n * ```ts\n * class MyClass {\n * items = atom('items', [1, 2, 3])\n *\n * @computed({ historyLength: 10 })\n * sum() {\n * return this.items.get().reduce((a, b) => a + b, 0)\n * }\n * }\n * ```\n *\n * @param options - Configuration options for the computed signal\n * @returns A decorator function that can be applied to methods\n * @public\n */\nexport function computed<Value, Diff = unknown>(\n\toptions?: ComputedOptions<Value, Diff>\n): ((target: any, key: string, descriptor: PropertyDescriptor) => PropertyDescriptor) &\n\t(<This>(\n\t\tcompute: () => Value,\n\t\tcontext: ClassMethodDecoratorContext<This, () => Value>\n\t) => () => Value)\n\n/**\n * Implementation function that handles all computed signal creation and decoration scenarios.\n * This function is overloaded to support multiple usage patterns:\n * - Creating computed signals directly\n * - Using as a TC39 decorator\n * - Using as a legacy decorator\n * - Using as a decorator factory with options\n *\n * @returns Either a computed signal instance or a decorator function depending on usage\n * @public\n */\nexport function computed() {\n\tif (arguments.length === 1) {\n\t\tconst options = arguments[0]\n\t\treturn (...args: any) => computedDecorator(options, args)\n\t} else if (typeof arguments[0] === 'string') {\n\t\treturn new _Computed(arguments[0], arguments[1], arguments[2])\n\t} else {\n\t\treturn computedDecorator(undefined, arguments as any)\n\t}\n}\n\nimport { isComputed as _isComputed } from './isComputed'\n\n/**\n * Returns true if the given value is a computed signal.\n * @public\n */\nexport function isComputed(value: any): value is Computed<any> {\n\treturn _isComputed(value)\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,mBAAuB;AACvB,sBAAyB;AACzB,qBAAgF;AAChF,uBAAmC;AACnC,qBAAmE;AACnE,2BAA8B;AAC9B,0BAAgE;AAChE,mBAAwD;AACxD,sBAAyC;AAwpBzC,wBAA0C;AAroBnC,MAAM,gBAAgB,uBAAO,IAAI,gCAAgC;AA6BjE,SAAS,gBAAgB,OAAoC;AACnE,SAAO,UAAU;AAClB;AAqBO,MAAM,eAAW;AAAA,EACvB;AAAA,EACA,MACC,MAAM,SAAsB;AAAA,IAC3B,YACQ,OACA,MACN;AAFM;AACA;AAAA,IACL;AAAA,IAFK;AAAA,IACA;AAAA,EAET;AACF;AAyCO,SAAS,SAAsB,OAAc,MAAmC;AACtF,SAAO,IAAI,SAAS,OAAO,IAAI;AAChC;AA+EA,MAAM,mBAA2E;AAAA,EAkChF,YAIiB,MAIC,QAIjB,SACC;AATe;AAIC;AAMjB,QAAI,SAAS,eAAe;AAC3B,WAAK,gBAAgB,IAAI,mCAAc,QAAQ,aAAa;AAAA,IAC7D;AACA,SAAK,cAAc,SAAS;AAC5B,SAAK,UAAU,SAAS,WAAW;AAAA,EACpC;AAAA,EAfiB;AAAA,EAIC;AAAA,EAzCT,eAAe;AAAA,EACxB,mBAAmB;AAAA,EACnB,qBAAqB;AAAA,EAErB,4BAAkE;AAAA;AAAA;AAAA;AAAA,EAK1D,mBAAmB;AAAA,EAE3B,YAAY,IAAI,yBAA2B;AAAA,EAC3C,UAA8B,CAAC;AAAA,EAC/B,eAAyB,CAAC;AAAA,EAE1B,WAAW,IAAI,yBAAgB;AAAA;AAAA,EAG/B,IAAI,sBAA+B;AAClC,WAAO,CAAC,KAAK,SAAS;AAAA,EACvB;AAAA,EAEA;AAAA;AAAA,EAGQ,QAAe;AAAA;AAAA,EAEf,QAAqC;AAAA,EAErC;AAAA,EAES;AAAA,EAuBjB,4BAA4B,cAA+B;AAC1D,UAAM,QAAQ,KAAK,qBAAqB;AAExC,UAAM,kBAAc,oCAAe;AAEnC,QACC,CAAC,UACA,KAAK,qBAAqB,eACzB,KAAK,2BACL,mCAAc,KACd,KAAK,yBAAqB,sCAAiB,KAC5C,KAAC,mCAAmB,IAAI,IACxB;AACD,WAAK,mBAAmB;AACxB,UAAI,KAAK,OAAO;AACf,YAAI,CAAC,cAAc;AAClB,gBAAM,KAAK,MAAM;AAAA,QAClB,OAAO;AACN,iBAAO,KAAK;AAAA,QACb;AAAA,MACD,OAAO;AACN,eAAO,KAAK;AAAA,MACb;AAAA,IACD;AAEA,QAAI;AACH,gDAAsB,IAAI;AAC1B,YAAM,SAAS,KAAK,OAAO,KAAK,OAAO,KAAK,gBAAgB;AAC5D,YAAM,WAAW,kBAAkB,WAAW,OAAO,QAAQ;AAC7D,YAAMA,mBAAkB,KAAK,UAAU;AACvC,UAAIA,oBAAmB,CAAC,KAAK,QAAQ,UAAU,KAAK,KAAK,GAAG;AAC3D,YAAI,KAAK,iBAAiB,CAACA,kBAAiB;AAC3C,gBAAM,OAAO,kBAAkB,WAAW,OAAO,OAAO;AACxD,eAAK,cAAc;AAAA,YAClB,KAAK;AAAA,gBACL,oCAAe;AAAA,YACf,QACC,KAAK,cAAc,KAAK,OAAO,UAAU,KAAK,sBAAkB,oCAAe,CAAC,KAChF;AAAA,UACF;AAAA,QACD;AACA,aAAK,uBAAmB,oCAAe;AACvC,aAAK,QAAQ;AAAA,MACd;AACA,WAAK,QAAQ;AACb,WAAK,uBAAmB,oCAAe;AAEvC,aAAO,KAAK;AAAA,IACb,SAAS,GAAG;AAEX,UAAI,KAAK,UAAU,eAAe;AACjC,aAAK,QAAQ;AACb,aAAK,uBAAmB,oCAAe;AAAA,MACxC;AACA,WAAK,uBAAmB,oCAAe;AAEvC,UAAI,KAAK,eAAe;AACvB,aAAK,cAAc,MAAM;AAAA,MAC1B;AACA,WAAK,QAAQ,EAAE,aAAa,EAAE;AAE9B,UAAI,CAAC,aAAc,OAAM;AACzB,aAAO,KAAK;AAAA,IACb,UAAE;AACD,+CAAqB;AAAA,IACtB;AAAA,EACD;AAAA,EAEA,MAAa;AACZ,QAAI;AACH,aAAO,KAAK,4BAA4B;AAAA,IACzC,UAAE;AAED,6CAAmB,IAAI;AAAA,IACxB;AAAA,EACD;AAAA,EAEA,aAAa,OAAqC;AAEjD,SAAK,4BAA4B,IAAI;AAErC,2CAAmB,IAAI;AAEvB,QAAI,SAAS,KAAK,kBAAkB;AACnC,aAAO;AAAA,IACR;AAEA,WAAO,KAAK,eAAe,gBAAgB,KAAK,KAAK;AAAA,EACtD;AACD;AAQO,MAAM,gBAAY,0BAAU,YAAY,MAAM,kBAAkB;AASvE,SAAS,8BACR,UAAqC,CAAC,GACtC,SACA,KACA,YACC;AACD,QAAM,iBAAiB,WAAW;AAClC,QAAM,gBAAgB,uBAAO,IAAI,gCAAgC,GAAG;AAEpE,aAAW,QAAQ,WAAqB;AACvC,QAAI,IAAI,KAAK,aAAa;AAE1B,QAAI,CAAC,GAAG;AACP,UAAI,IAAI,UAAU,KAAK,eAAgB,KAAK,IAAI,GAAU,OAAO;AACjE,aAAO,eAAe,MAAM,eAAe;AAAA,QAC1C,YAAY;AAAA,QACZ,cAAc;AAAA,QACd,UAAU;AAAA,QACV,OAAO;AAAA,MACR,CAAC;AAAA,IACF;AACA,WAAO,EAAE,IAAI;AAAA,EACd;AACA,aAAW,MAAM,mBAAmB,IAAI;AAExC,SAAO;AACR;AAEA,SAAS,8BACR,UAAqC,CAAC,GACtC,SACA,KACA,YACC;AACD,QAAM,iBAAiB,WAAW;AAClC,QAAM,gBAAgB,uBAAO,IAAI,gCAAgC,GAAG;AAEpE,aAAW,MAAM,WAAqB;AACrC,QAAI,IAAI,KAAK,aAAa;AAE1B,QAAI,CAAC,GAAG;AACP,UAAI,IAAI,UAAU,KAAK,eAAgB,KAAK,IAAI,GAAU,OAAO;AACjE,aAAO,eAAe,MAAM,eAAe;AAAA,QAC1C,YAAY;AAAA,QACZ,cAAc;AAAA,QACd,UAAU;AAAA,QACV,OAAO;AAAA,MACR,CAAC;AAAA,IACF;AACA,WAAO,EAAE,IAAI;AAAA,EACd;AAEA,SAAO;AACR;AAEA,SAAS,4BACR,SACA,SACA,SACC;AACD,2BAAO,QAAQ,SAAS,UAAU,uCAAuC;AACzE,QAAM,gBAAgB,uBAAO,IAAI,gCAAgC,OAAO,QAAQ,IAAI,CAAC;AAErF,QAAM,KAAK,WAAqB;AAC/B,QAAI,IAAI,KAAK,aAAa;AAE1B,QAAI,CAAC,GAAG;AACP,UAAI,IAAI,UAAU,OAAO,QAAQ,IAAI,GAAG,QAAQ,KAAK,IAAI,GAAU,OAAO;AAC1E,aAAO,eAAe,MAAM,eAAe;AAAA,QAC1C,YAAY;AAAA,QACZ,cAAc;AAAA,QACd,UAAU;AAAA,QACV,OAAO;AAAA,MACR,CAAC;AAAA,IACF;AACA,WAAO,EAAE,IAAI;AAAA,EACd;AACA,KAAG,mBAAmB,IAAI;AAC1B,SAAO;AACR;AAEA,SAAS,kBACR,UAAqC,CAAC,GACtC,MAGC;AACD,MAAI,KAAK,WAAW,GAAG;AACtB,UAAM,CAAC,gBAAgB,OAAO,IAAI;AAClC,WAAO,4BAA4B,SAAS,gBAAgB,OAAO;AAAA,EACpE,OAAO;AACN,UAAM,CAAC,SAAS,KAAK,UAAU,IAAI;AACnC,QAAI,WAAW,KAAK;AACnB,oDAAyB;AACzB,aAAO,8BAA8B,SAAS,SAAS,KAAK,UAAU;AAAA,IACvE,OAAO;AACN,aAAO,8BAA8B,SAAS,SAAS,KAAK,UAAU;AAAA,IACvE;AAAA,EACD;AACD;AAEA,MAAM,sBAAsB;AA4BrB,SAAS,oBACf,KACA,cACsB;AACtB,QAAM,MAAM,uBAAO,IAAI,gCAAgC,aAAa,SAAS,CAAC;AAC9E,MAAI,OAAO,IAAI,GAAuB;AACtC,MAAI,CAAC,MAAM;AAEV,UAAM,MAAM,IAAI,YAAY;AAC5B,QAAI,OAAO,QAAQ,cAAe,IAAY,mBAAmB,GAAG;AACnE,UAAI,KAAK,GAAG;AAAA,IACb;AAEA,WAAO,IAAI,GAAuB;AAAA,EACnC;AACA,SAAO;AACR;AAiJO,SAAS,WAAW;AAC1B,MAAI,UAAU,WAAW,GAAG;AAC3B,UAAM,UAAU,UAAU,CAAC;AAC3B,WAAO,IAAI,SAAc,kBAAkB,SAAS,IAAI;AAAA,EACzD,WAAW,OAAO,UAAU,CAAC,MAAM,UAAU;AAC5C,WAAO,IAAI,UAAU,UAAU,CAAC,GAAG,UAAU,CAAC,GAAG,UAAU,CAAC,CAAC;AAAA,EAC9D,OAAO;AACN,WAAO,kBAAkB,QAAW,SAAgB;AAAA,EACrD;AACD;AAQO,SAAS,WAAW,OAAoC;AAC9D,aAAO,kBAAAC,YAAY,KAAK;AACzB;",
6
6
  "names": ["isUninitialized", "_isComputed"]
7
7
  }
@@ -34,6 +34,8 @@ class __EffectScheduler__ {
34
34
  this.runEffect = runEffect;
35
35
  this._scheduleEffect = options?.scheduleEffect;
36
36
  }
37
+ name;
38
+ runEffect;
37
39
  __isEffectScheduler = true;
38
40
  /** @internal */
39
41
  _isActivelyListening = false;
@@ -41,7 +43,7 @@ class __EffectScheduler__ {
41
43
  * Whether this scheduler is attached and actively listening to its parents.
42
44
  * @public
43
45
  */
44
- // eslint-disable-next-line no-restricted-syntax
46
+ // eslint-disable-next-line tldraw/no-setter-getter
45
47
  get isActivelyListening() {
46
48
  return this._isActivelyListening;
47
49
  }
@@ -57,7 +59,7 @@ class __EffectScheduler__ {
57
59
  * The number of times this effect has been scheduled.
58
60
  * @public
59
61
  */
60
- // eslint-disable-next-line no-restricted-syntax
62
+ // eslint-disable-next-line tldraw/no-setter-getter
61
63
  get scheduleCount() {
62
64
  return this._scheduleCount;
63
65
  }
@@ -89,7 +91,7 @@ class __EffectScheduler__ {
89
91
  }
90
92
  }
91
93
  /** @internal */
92
- // eslint-disable-next-line local/prefer-class-methods
94
+ // eslint-disable-next-line tldraw/prefer-class-methods
93
95
  maybeExecute = () => {
94
96
  if (!this._isActivelyListening) return;
95
97
  this.execute();
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/lib/EffectScheduler.ts"],
4
- "sourcesContent": ["import { ArraySet } from './ArraySet'\nimport { startCapturingParents, stopCapturingParents } from './capture'\nimport { GLOBAL_START_EPOCH } from './constants'\nimport { attach, detach, haveParentsChanged, singleton } from './helpers'\nimport { getGlobalEpoch } from './transactions'\nimport { Signal } from './types'\n\n/** @public */\nexport interface EffectSchedulerOptions {\n\t/**\n\t * scheduleEffect is a function that will be called when the effect is scheduled.\n\t *\n\t * It can be used to defer running effects until a later time, for example to batch them together with requestAnimationFrame.\n\t *\n\t *\n\t * @example\n\t * ```ts\n\t * let isRafScheduled = false\n\t * const scheduledEffects: Array<() => void> = []\n\t * const scheduleEffect = (runEffect: () => void) => {\n\t * \tscheduledEffects.push(runEffect)\n\t * \tif (!isRafScheduled) {\n\t * \t\tisRafScheduled = true\n\t * \t\trequestAnimationFrame(() => {\n\t * \t\t\tisRafScheduled = false\n\t * \t\t\tscheduledEffects.forEach((runEffect) => runEffect())\n\t * \t\t\tscheduledEffects.length = 0\n\t * \t\t})\n\t * \t}\n\t * }\n\t * const stop = react('set page title', () => {\n\t * \tdocument.title = doc.title,\n\t * }, scheduleEffect)\n\t * ```\n\t *\n\t * @param execute - A function that will execute the effect.\n\t * @returns void\n\t */\n\t// eslint-disable-next-line @typescript-eslint/method-signature-style\n\tscheduleEffect?: (execute: () => void) => void\n}\n\nclass __EffectScheduler__<Result> implements EffectScheduler<Result> {\n\treadonly __isEffectScheduler = true as const\n\t/** @internal */\n\tprivate _isActivelyListening = false\n\t/**\n\t * Whether this scheduler is attached and actively listening to its parents.\n\t * @public\n\t */\n\t// eslint-disable-next-line no-restricted-syntax\n\tget isActivelyListening() {\n\t\treturn this._isActivelyListening\n\t}\n\t/** @internal */\n\tlastTraversedEpoch = GLOBAL_START_EPOCH\n\n\t/** @internal */\n\tprivate lastReactedEpoch = GLOBAL_START_EPOCH\n\n\t/** @internal */\n\tprivate _scheduleCount = 0\n\t/** @internal */\n\t__debug_ancestor_epochs__: Map<Signal<any, any>, number> | null = null\n\n\t/**\n\t * The number of times this effect has been scheduled.\n\t * @public\n\t */\n\t// eslint-disable-next-line no-restricted-syntax\n\tget scheduleCount() {\n\t\treturn this._scheduleCount\n\t}\n\n\t/** @internal */\n\treadonly parentSet = new ArraySet<Signal<any, any>>()\n\t/** @internal */\n\treadonly parentEpochs: number[] = []\n\t/** @internal */\n\treadonly parents: Signal<any, any>[] = []\n\t/** @internal */\n\tprivate readonly _scheduleEffect?: (execute: () => void) => void\n\tconstructor(\n\t\tpublic readonly name: string,\n\t\tprivate readonly runEffect: (lastReactedEpoch: number) => Result,\n\t\toptions?: EffectSchedulerOptions\n\t) {\n\t\tthis._scheduleEffect = options?.scheduleEffect\n\t}\n\n\t/** @internal */\n\tmaybeScheduleEffect() {\n\t\t// bail out if we have been cancelled by another effect\n\t\tif (!this._isActivelyListening) return\n\t\t// bail out if no atoms have changed since the last time we ran this effect\n\t\tif (this.lastReactedEpoch === getGlobalEpoch()) return\n\n\t\t// bail out if we have parents and they have not changed since last time\n\t\tif (this.parents.length && !haveParentsChanged(this)) {\n\t\t\tthis.lastReactedEpoch = getGlobalEpoch()\n\t\t\treturn\n\t\t}\n\t\t// if we don't have parents it's probably the first time this is running.\n\t\tthis.scheduleEffect()\n\t}\n\n\t/** @internal */\n\tscheduleEffect() {\n\t\tthis._scheduleCount++\n\t\tif (this._scheduleEffect) {\n\t\t\t// if the effect should be deferred (e.g. until a react render), do so\n\t\t\tthis._scheduleEffect(this.maybeExecute)\n\t\t} else {\n\t\t\t// otherwise execute right now!\n\t\t\tthis.execute()\n\t\t}\n\t}\n\n\t/** @internal */\n\t// eslint-disable-next-line local/prefer-class-methods\n\treadonly maybeExecute = () => {\n\t\t// bail out if we have been detached before this runs\n\t\tif (!this._isActivelyListening) return\n\t\tthis.execute()\n\t}\n\n\t/**\n\t * Makes this scheduler become 'actively listening' to its parents.\n\t * If it has been executed before it will immediately become eligible to receive 'maybeScheduleEffect' calls.\n\t * If it has not executed before it will need to be manually executed once to become eligible for scheduling, i.e. by calling `EffectScheduler.execute`.\n\t * @public\n\t */\n\tattach() {\n\t\tthis._isActivelyListening = true\n\t\tfor (let i = 0, n = this.parents.length; i < n; i++) {\n\t\t\tattach(this.parents[i], this)\n\t\t}\n\t}\n\n\t/**\n\t * Makes this scheduler stop 'actively listening' to its parents.\n\t * It will no longer be eligible to receive 'maybeScheduleEffect' calls until `EffectScheduler.attach` is called again.\n\t * @public\n\t */\n\tdetach() {\n\t\tthis._isActivelyListening = false\n\t\tfor (let i = 0, n = this.parents.length; i < n; i++) {\n\t\t\tdetach(this.parents[i], this)\n\t\t}\n\t}\n\n\t/**\n\t * Executes the effect immediately and returns the result.\n\t * @returns The result of the effect.\n\t * @public\n\t */\n\texecute(): Result {\n\t\ttry {\n\t\t\tstartCapturingParents(this)\n\t\t\t// Important! We have to make a note of the current epoch before running the effect.\n\t\t\t// We allow atoms to be updated during effects, which increments the global epoch,\n\t\t\t// so if we were to wait until after the effect runs, the this.lastReactedEpoch value might get ahead of itself.\n\t\t\tconst currentEpoch = getGlobalEpoch()\n\t\t\tconst result = this.runEffect(this.lastReactedEpoch)\n\t\t\tthis.lastReactedEpoch = currentEpoch\n\t\t\treturn result\n\t\t} finally {\n\t\t\tstopCapturingParents()\n\t\t}\n\t}\n}\n\n/**\n * An EffectScheduler is responsible for executing side effects in response to changes in state.\n *\n * You probably don't need to use this directly unless you're integrating this library with a framework of some kind.\n *\n * Instead, use the {@link react} and {@link reactor} functions.\n *\n * @example\n * ```ts\n * const render = new EffectScheduler('render', drawToCanvas)\n *\n * render.attach()\n * render.execute()\n * ```\n *\n * @public\n */\nexport const EffectScheduler = singleton(\n\t'EffectScheduler',\n\t(): {\n\t\tnew <Result>(\n\t\t\tname: string,\n\t\t\trunEffect: (lastReactedEpoch: number) => Result,\n\t\t\toptions?: EffectSchedulerOptions\n\t\t): EffectScheduler<Result>\n\t} => __EffectScheduler__\n)\n/** @public */\nexport interface EffectScheduler<Result> {\n\t/**\n\t * Whether this scheduler is attached and actively listening to its parents.\n\t * @public\n\t */\n\treadonly isActivelyListening: boolean\n\n\t/** @internal */\n\treadonly lastTraversedEpoch: number\n\n\t/** @public */\n\treadonly name: string\n\n\t/** @internal */\n\t__debug_ancestor_epochs__: Map<Signal<any, any>, number> | null\n\n\t/**\n\t * The number of times this effect has been scheduled.\n\t * @public\n\t */\n\treadonly scheduleCount: number\n\n\t/** @internal */\n\treadonly parentSet: ArraySet<Signal<any, any>>\n\n\t/** @internal */\n\treadonly parentEpochs: number[]\n\n\t/** @internal */\n\treadonly parents: Signal<any, any>[]\n\n\t/** @internal */\n\tmaybeScheduleEffect(): void\n\n\t/** @internal */\n\tscheduleEffect(): void\n\n\t/** @internal */\n\tmaybeExecute(): void\n\n\t/**\n\t * Makes this scheduler become 'actively listening' to its parents.\n\t * If it has been executed before it will immediately become eligible to receive 'maybeScheduleEffect' calls.\n\t * If it has not executed before it will need to be manually executed once to become eligible for scheduling, i.e. by calling `EffectScheduler.execute`.\n\t * @public\n\t */\n\tattach(): void\n\n\t/**\n\t * Makes this scheduler stop 'actively listening' to its parents.\n\t * It will no longer be eligible to receive 'maybeScheduleEffect' calls until `EffectScheduler.attach` is called again.\n\t * @public\n\t */\n\tdetach(): void\n\n\t/**\n\t * Executes the effect immediately and returns the result.\n\t * @returns The result of the effect.\n\t * @public\n\t */\n\texecute(): Result\n}\n\n/**\n * Starts a new effect scheduler, scheduling the effect immediately.\n *\n * Returns a function that can be called to stop the scheduler.\n *\n * @example\n * ```ts\n * const color = atom('color', 'red')\n * const stop = react('set style', () => {\n * divElem.style.color = color.get()\n * })\n * color.set('blue')\n * // divElem.style.color === 'blue'\n * stop()\n * color.set('green')\n * // divElem.style.color === 'blue'\n * ```\n *\n *\n * Also useful in React applications for running effects outside of the render cycle.\n *\n * @example\n * ```ts\n * useEffect(() => react('set style', () => {\n * divRef.current.style.color = color.get()\n * }), [])\n * ```\n *\n * @public\n */\nexport function react(\n\tname: string,\n\tfn: (lastReactedEpoch: number) => any,\n\toptions?: EffectSchedulerOptions\n) {\n\tconst scheduler = new EffectScheduler(name, fn, options)\n\tscheduler.attach()\n\tscheduler.scheduleEffect()\n\treturn () => {\n\t\tscheduler.detach()\n\t}\n}\n\n/**\n * The reactor is a user-friendly interface for starting and stopping an `EffectScheduler`.\n *\n * Calling `.start()` will attach the scheduler and execute the effect immediately the first time it is called.\n *\n * If the reactor is stopped, calling `.start()` will re-attach the scheduler but will only execute the effect if any of its parents have changed since it was stopped.\n *\n * You can create a reactor with {@link reactor}.\n * @public\n */\nexport interface Reactor<T = unknown> {\n\t/**\n\t * The underlying effect scheduler.\n\t * @public\n\t */\n\tscheduler: EffectScheduler<T>\n\t/**\n\t * Start the scheduler. The first time this is called the effect will be scheduled immediately.\n\t *\n\t * If the reactor is stopped, calling this will start the scheduler again but will only execute the effect if any of its parents have changed since it was stopped.\n\t *\n\t * If you need to force re-execution of the effect, pass `{ force: true }`.\n\t * @public\n\t */\n\tstart(options?: { force?: boolean }): void\n\t/**\n\t * Stop the scheduler.\n\t * @public\n\t */\n\tstop(): void\n}\n\n/**\n * Creates a {@link Reactor}, which is a thin wrapper around an `EffectScheduler`.\n *\n * @public\n */\nexport function reactor<Result>(\n\tname: string,\n\tfn: (lastReactedEpoch: number) => Result,\n\toptions?: EffectSchedulerOptions\n): Reactor<Result> {\n\tconst scheduler = new EffectScheduler<Result>(name, fn, options)\n\treturn {\n\t\tscheduler,\n\t\tstart: (options?: { force?: boolean }) => {\n\t\t\tconst force = options?.force ?? false\n\t\t\tscheduler.attach()\n\t\t\tif (force) {\n\t\t\t\tscheduler.scheduleEffect()\n\t\t\t} else {\n\t\t\t\tscheduler.maybeScheduleEffect()\n\t\t\t}\n\t\t},\n\t\tstop: () => {\n\t\t\tscheduler.detach()\n\t\t},\n\t}\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { ArraySet } from './ArraySet'\nimport { startCapturingParents, stopCapturingParents } from './capture'\nimport { GLOBAL_START_EPOCH } from './constants'\nimport { attach, detach, haveParentsChanged, singleton } from './helpers'\nimport { getGlobalEpoch } from './transactions'\nimport { Signal } from './types'\n\n/** @public */\nexport interface EffectSchedulerOptions {\n\t/**\n\t * scheduleEffect is a function that will be called when the effect is scheduled.\n\t *\n\t * It can be used to defer running effects until a later time, for example to batch them together with requestAnimationFrame.\n\t *\n\t *\n\t * @example\n\t * ```ts\n\t * let isRafScheduled = false\n\t * const scheduledEffects: Array<() => void> = []\n\t * const scheduleEffect = (runEffect: () => void) => {\n\t * \tscheduledEffects.push(runEffect)\n\t * \tif (!isRafScheduled) {\n\t * \t\tisRafScheduled = true\n\t * \t\trequestAnimationFrame(() => {\n\t * \t\t\tisRafScheduled = false\n\t * \t\t\tscheduledEffects.forEach((runEffect) => runEffect())\n\t * \t\t\tscheduledEffects.length = 0\n\t * \t\t})\n\t * \t}\n\t * }\n\t * const stop = react('set page title', () => {\n\t * \tdocument.title = doc.title,\n\t * }, scheduleEffect)\n\t * ```\n\t *\n\t * @param execute - A function that will execute the effect.\n\t * @returns void\n\t */\n\t// eslint-disable-next-line tldraw/method-signature-style\n\tscheduleEffect?: (execute: () => void) => void\n}\n\nclass __EffectScheduler__<Result> implements EffectScheduler<Result> {\n\treadonly __isEffectScheduler = true as const\n\t/** @internal */\n\tprivate _isActivelyListening = false\n\t/**\n\t * Whether this scheduler is attached and actively listening to its parents.\n\t * @public\n\t */\n\t// eslint-disable-next-line tldraw/no-setter-getter\n\tget isActivelyListening() {\n\t\treturn this._isActivelyListening\n\t}\n\t/** @internal */\n\tlastTraversedEpoch = GLOBAL_START_EPOCH\n\n\t/** @internal */\n\tprivate lastReactedEpoch = GLOBAL_START_EPOCH\n\n\t/** @internal */\n\tprivate _scheduleCount = 0\n\t/** @internal */\n\t__debug_ancestor_epochs__: Map<Signal<any, any>, number> | null = null\n\n\t/**\n\t * The number of times this effect has been scheduled.\n\t * @public\n\t */\n\t// eslint-disable-next-line tldraw/no-setter-getter\n\tget scheduleCount() {\n\t\treturn this._scheduleCount\n\t}\n\n\t/** @internal */\n\treadonly parentSet = new ArraySet<Signal<any, any>>()\n\t/** @internal */\n\treadonly parentEpochs: number[] = []\n\t/** @internal */\n\treadonly parents: Signal<any, any>[] = []\n\t/** @internal */\n\tprivate readonly _scheduleEffect?: (execute: () => void) => void\n\tconstructor(\n\t\tpublic readonly name: string,\n\t\tprivate readonly runEffect: (lastReactedEpoch: number) => Result,\n\t\toptions?: EffectSchedulerOptions\n\t) {\n\t\tthis._scheduleEffect = options?.scheduleEffect\n\t}\n\n\t/** @internal */\n\tmaybeScheduleEffect() {\n\t\t// bail out if we have been cancelled by another effect\n\t\tif (!this._isActivelyListening) return\n\t\t// bail out if no atoms have changed since the last time we ran this effect\n\t\tif (this.lastReactedEpoch === getGlobalEpoch()) return\n\n\t\t// bail out if we have parents and they have not changed since last time\n\t\tif (this.parents.length && !haveParentsChanged(this)) {\n\t\t\tthis.lastReactedEpoch = getGlobalEpoch()\n\t\t\treturn\n\t\t}\n\t\t// if we don't have parents it's probably the first time this is running.\n\t\tthis.scheduleEffect()\n\t}\n\n\t/** @internal */\n\tscheduleEffect() {\n\t\tthis._scheduleCount++\n\t\tif (this._scheduleEffect) {\n\t\t\t// if the effect should be deferred (e.g. until a react render), do so\n\t\t\tthis._scheduleEffect(this.maybeExecute)\n\t\t} else {\n\t\t\t// otherwise execute right now!\n\t\t\tthis.execute()\n\t\t}\n\t}\n\n\t/** @internal */\n\t// eslint-disable-next-line tldraw/prefer-class-methods\n\treadonly maybeExecute = () => {\n\t\t// bail out if we have been detached before this runs\n\t\tif (!this._isActivelyListening) return\n\t\tthis.execute()\n\t}\n\n\t/**\n\t * Makes this scheduler become 'actively listening' to its parents.\n\t * If it has been executed before it will immediately become eligible to receive 'maybeScheduleEffect' calls.\n\t * If it has not executed before it will need to be manually executed once to become eligible for scheduling, i.e. by calling `EffectScheduler.execute`.\n\t * @public\n\t */\n\tattach() {\n\t\tthis._isActivelyListening = true\n\t\tfor (let i = 0, n = this.parents.length; i < n; i++) {\n\t\t\tattach(this.parents[i], this)\n\t\t}\n\t}\n\n\t/**\n\t * Makes this scheduler stop 'actively listening' to its parents.\n\t * It will no longer be eligible to receive 'maybeScheduleEffect' calls until `EffectScheduler.attach` is called again.\n\t * @public\n\t */\n\tdetach() {\n\t\tthis._isActivelyListening = false\n\t\tfor (let i = 0, n = this.parents.length; i < n; i++) {\n\t\t\tdetach(this.parents[i], this)\n\t\t}\n\t}\n\n\t/**\n\t * Executes the effect immediately and returns the result.\n\t * @returns The result of the effect.\n\t * @public\n\t */\n\texecute(): Result {\n\t\ttry {\n\t\t\tstartCapturingParents(this)\n\t\t\t// Important! We have to make a note of the current epoch before running the effect.\n\t\t\t// We allow atoms to be updated during effects, which increments the global epoch,\n\t\t\t// so if we were to wait until after the effect runs, the this.lastReactedEpoch value might get ahead of itself.\n\t\t\tconst currentEpoch = getGlobalEpoch()\n\t\t\tconst result = this.runEffect(this.lastReactedEpoch)\n\t\t\tthis.lastReactedEpoch = currentEpoch\n\t\t\treturn result\n\t\t} finally {\n\t\t\tstopCapturingParents()\n\t\t}\n\t}\n}\n\n/**\n * An EffectScheduler is responsible for executing side effects in response to changes in state.\n *\n * You probably don't need to use this directly unless you're integrating this library with a framework of some kind.\n *\n * Instead, use the {@link react} and {@link reactor} functions.\n *\n * @example\n * ```ts\n * const render = new EffectScheduler('render', drawToCanvas)\n *\n * render.attach()\n * render.execute()\n * ```\n *\n * @public\n */\nexport const EffectScheduler = singleton(\n\t'EffectScheduler',\n\t(): {\n\t\tnew <Result>(\n\t\t\tname: string,\n\t\t\trunEffect: (lastReactedEpoch: number) => Result,\n\t\t\toptions?: EffectSchedulerOptions\n\t\t): EffectScheduler<Result>\n\t} => __EffectScheduler__\n)\n/** @public */\nexport interface EffectScheduler<Result> {\n\t/**\n\t * Whether this scheduler is attached and actively listening to its parents.\n\t * @public\n\t */\n\treadonly isActivelyListening: boolean\n\n\t/** @internal */\n\treadonly lastTraversedEpoch: number\n\n\t/** @public */\n\treadonly name: string\n\n\t/** @internal */\n\t__debug_ancestor_epochs__: Map<Signal<any, any>, number> | null\n\n\t/**\n\t * The number of times this effect has been scheduled.\n\t * @public\n\t */\n\treadonly scheduleCount: number\n\n\t/** @internal */\n\treadonly parentSet: ArraySet<Signal<any, any>>\n\n\t/** @internal */\n\treadonly parentEpochs: number[]\n\n\t/** @internal */\n\treadonly parents: Signal<any, any>[]\n\n\t/** @internal */\n\tmaybeScheduleEffect(): void\n\n\t/** @internal */\n\tscheduleEffect(): void\n\n\t/** @internal */\n\tmaybeExecute(): void\n\n\t/**\n\t * Makes this scheduler become 'actively listening' to its parents.\n\t * If it has been executed before it will immediately become eligible to receive 'maybeScheduleEffect' calls.\n\t * If it has not executed before it will need to be manually executed once to become eligible for scheduling, i.e. by calling `EffectScheduler.execute`.\n\t * @public\n\t */\n\tattach(): void\n\n\t/**\n\t * Makes this scheduler stop 'actively listening' to its parents.\n\t * It will no longer be eligible to receive 'maybeScheduleEffect' calls until `EffectScheduler.attach` is called again.\n\t * @public\n\t */\n\tdetach(): void\n\n\t/**\n\t * Executes the effect immediately and returns the result.\n\t * @returns The result of the effect.\n\t * @public\n\t */\n\texecute(): Result\n}\n\n/**\n * Starts a new effect scheduler, scheduling the effect immediately.\n *\n * Returns a function that can be called to stop the scheduler.\n *\n * @example\n * ```ts\n * const color = atom('color', 'red')\n * const stop = react('set style', () => {\n * divElem.style.color = color.get()\n * })\n * color.set('blue')\n * // divElem.style.color === 'blue'\n * stop()\n * color.set('green')\n * // divElem.style.color === 'blue'\n * ```\n *\n *\n * Also useful in React applications for running effects outside of the render cycle.\n *\n * @example\n * ```ts\n * useEffect(() => react('set style', () => {\n * divRef.current.style.color = color.get()\n * }), [])\n * ```\n *\n * @public\n */\nexport function react(\n\tname: string,\n\tfn: (lastReactedEpoch: number) => any,\n\toptions?: EffectSchedulerOptions\n) {\n\tconst scheduler = new EffectScheduler(name, fn, options)\n\tscheduler.attach()\n\tscheduler.scheduleEffect()\n\treturn () => {\n\t\tscheduler.detach()\n\t}\n}\n\n/**\n * The reactor is a user-friendly interface for starting and stopping an `EffectScheduler`.\n *\n * Calling `.start()` will attach the scheduler and execute the effect immediately the first time it is called.\n *\n * If the reactor is stopped, calling `.start()` will re-attach the scheduler but will only execute the effect if any of its parents have changed since it was stopped.\n *\n * You can create a reactor with {@link reactor}.\n * @public\n */\nexport interface Reactor<T = unknown> {\n\t/**\n\t * The underlying effect scheduler.\n\t * @public\n\t */\n\tscheduler: EffectScheduler<T>\n\t/**\n\t * Start the scheduler. The first time this is called the effect will be scheduled immediately.\n\t *\n\t * If the reactor is stopped, calling this will start the scheduler again but will only execute the effect if any of its parents have changed since it was stopped.\n\t *\n\t * If you need to force re-execution of the effect, pass `{ force: true }`.\n\t * @public\n\t */\n\tstart(options?: { force?: boolean }): void\n\t/**\n\t * Stop the scheduler.\n\t * @public\n\t */\n\tstop(): void\n}\n\n/**\n * Creates a {@link Reactor}, which is a thin wrapper around an `EffectScheduler`.\n *\n * @public\n */\nexport function reactor<Result>(\n\tname: string,\n\tfn: (lastReactedEpoch: number) => Result,\n\toptions?: EffectSchedulerOptions\n): Reactor<Result> {\n\tconst scheduler = new EffectScheduler<Result>(name, fn, options)\n\treturn {\n\t\tscheduler,\n\t\tstart: (options?: { force?: boolean }) => {\n\t\t\tconst force = options?.force ?? false\n\t\t\tscheduler.attach()\n\t\t\tif (force) {\n\t\t\t\tscheduler.scheduleEffect()\n\t\t\t} else {\n\t\t\t\tscheduler.maybeScheduleEffect()\n\t\t\t}\n\t\t},\n\t\tstop: () => {\n\t\t\tscheduler.detach()\n\t\t},\n\t}\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["options"]
7
7
  }
@@ -36,6 +36,7 @@ class HistoryBuffer {
36
36
  this.capacity = capacity;
37
37
  this.buffer = new Array(capacity);
38
38
  }
39
+ capacity;
39
40
  /**
40
41
  * Current write position in the circular buffer.
41
42
  * @internal
@@ -2,6 +2,6 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/lib/HistoryBuffer.ts"],
4
4
  "sourcesContent": ["import { RESET_VALUE } from './types'\n\n/**\n * A tuple representing a range of epochs and the associated diff.\n * Used internally by HistoryBuffer to store change information.\n *\n * @internal\n */\ntype RangeTuple<Diff> = [fromEpoch: number, toEpoch: number, diff: Diff]\n\n/**\n * A circular buffer that stores diffs between sequential values of an atom or computed signal.\n * This enables efficient change tracking and history retrieval for features like undo/redo.\n *\n * The buffer uses a wrap-around strategy to maintain a fixed-size history of the most recent\n * changes, automatically overwriting older entries when the capacity is exceeded.\n *\n * @example\n * ```ts\n * const buffer = new HistoryBuffer<string>(5)\n * buffer.pushEntry(0, 1, 'first change')\n * buffer.pushEntry(1, 2, 'second change')\n * const changes = buffer.getChangesSince(0) // ['first change', 'second change']\n * ```\n *\n * @internal\n */\nexport class HistoryBuffer<Diff> {\n\t/**\n\t * Current write position in the circular buffer.\n\t * @internal\n\t */\n\tprivate index = 0\n\n\t/**\n\t * Circular buffer storing range tuples. Uses undefined to represent empty slots.\n\t * @internal\n\t */\n\tbuffer: Array<RangeTuple<Diff> | undefined>\n\n\t/**\n\t * Creates a new HistoryBuffer with the specified capacity.\n\t *\n\t * capacity - Maximum number of diffs to store in the buffer\n\t * @example\n\t * ```ts\n\t * const buffer = new HistoryBuffer<number>(10) // Store up to 10 diffs\n\t * ```\n\t */\n\tconstructor(private readonly capacity: number) {\n\t\tthis.buffer = new Array(capacity)\n\t}\n\n\t/**\n\t * Adds a diff entry to the history buffer, representing a change between two epochs.\n\t *\n\t * If the diff is undefined, the operation is ignored. If the diff is RESET_VALUE,\n\t * the entire buffer is cleared to indicate that historical tracking should restart.\n\t *\n\t * @param lastComputedEpoch - The epoch when the previous value was computed\n\t * @param currentEpoch - The epoch when the current value was computed\n\t * @param diff - The diff representing the change, or RESET_VALUE to clear history\n\t * @example\n\t * ```ts\n\t * const buffer = new HistoryBuffer<string>(5)\n\t * buffer.pushEntry(0, 1, 'added text')\n\t * buffer.pushEntry(1, 2, RESET_VALUE) // Clears the buffer\n\t * ```\n\t */\n\tpushEntry(lastComputedEpoch: number, currentEpoch: number, diff: Diff | RESET_VALUE) {\n\t\tif (diff === undefined) {\n\t\t\treturn\n\t\t}\n\n\t\tif (diff === RESET_VALUE) {\n\t\t\tthis.clear()\n\t\t\treturn\n\t\t}\n\n\t\t// Add the diff to the buffer as a range tuple.\n\t\tthis.buffer[this.index] = [lastComputedEpoch, currentEpoch, diff]\n\n\t\t// Bump the index, wrapping around if necessary.\n\t\tthis.index = (this.index + 1) % this.capacity\n\t}\n\n\t/**\n\t * Clears all entries from the history buffer and resets the write position.\n\t * This is called when a RESET_VALUE diff is encountered.\n\t *\n\t * @example\n\t * ```ts\n\t * const buffer = new HistoryBuffer<string>(5)\n\t * buffer.pushEntry(0, 1, 'change')\n\t * buffer.clear()\n\t * console.log(buffer.getChangesSince(0)) // RESET_VALUE\n\t * ```\n\t */\n\tclear() {\n\t\tthis.index = 0\n\t\tthis.buffer.fill(undefined)\n\t}\n\n\t/**\n\t * Retrieves all diffs that occurred since the specified epoch.\n\t *\n\t * The method searches backwards through the circular buffer to find changes\n\t * that occurred after the given epoch. If insufficient history is available\n\t * or the requested epoch is too old, returns RESET_VALUE indicating that\n\t * a complete state rebuild is required.\n\t *\n\t * @param sinceEpoch - The epoch from which to retrieve changes\n\t * @returns Array of diffs since the epoch, or RESET_VALUE if history is insufficient\n\t * @example\n\t * ```ts\n\t * const buffer = new HistoryBuffer<string>(5)\n\t * buffer.pushEntry(0, 1, 'first')\n\t * buffer.pushEntry(1, 2, 'second')\n\t * const changes = buffer.getChangesSince(0) // ['first', 'second']\n\t * const recentChanges = buffer.getChangesSince(1) // ['second']\n\t * const tooOld = buffer.getChangesSince(-100) // RESET_VALUE\n\t * ```\n\t */\n\tgetChangesSince(sinceEpoch: number): RESET_VALUE | Diff[] {\n\t\tconst { index, capacity, buffer } = this\n\n\t\t// For each item in the buffer...\n\t\tfor (let i = 0; i < capacity; i++) {\n\t\t\tconst offset = (index - 1 + capacity - i) % capacity\n\n\t\t\tconst elem = buffer[offset]\n\n\t\t\t// If there's no element in the offset position, return the reset value\n\t\t\tif (!elem) {\n\t\t\t\treturn RESET_VALUE\n\t\t\t}\n\n\t\t\tconst [fromEpoch, toEpoch] = elem\n\n\t\t\t// If the first element is already too early, bail\n\t\t\tif (i === 0 && sinceEpoch >= toEpoch) {\n\t\t\t\treturn []\n\t\t\t}\n\n\t\t\t// If the element is since the given epoch, return an array with all diffs from this element and all following elements\n\t\t\tif (fromEpoch <= sinceEpoch && sinceEpoch < toEpoch) {\n\t\t\t\tconst len = i + 1\n\t\t\t\tconst result = new Array(len)\n\n\t\t\t\tfor (let j = 0; j < len; j++) {\n\t\t\t\t\tresult[j] = buffer[(offset + j) % capacity]![2]\n\t\t\t\t}\n\n\t\t\t\treturn result\n\t\t\t}\n\t\t}\n\n\t\t// If we haven't returned yet, return the reset value\n\t\treturn RESET_VALUE\n\t}\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAA4B;AA2BrB,MAAM,cAAoB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAsBhC,YAA6B,UAAkB;AAAlB;AAC5B,SAAK,SAAS,IAAI,MAAM,QAAQ;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA;AAAA,EAnBQ,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA,EAMhB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA+BA,UAAU,mBAA2B,cAAsB,MAA0B;AACpF,QAAI,SAAS,QAAW;AACvB;AAAA,IACD;AAEA,QAAI,SAAS,0BAAa;AACzB,WAAK,MAAM;AACX;AAAA,IACD;AAGA,SAAK,OAAO,KAAK,KAAK,IAAI,CAAC,mBAAmB,cAAc,IAAI;AAGhE,SAAK,SAAS,KAAK,QAAQ,KAAK,KAAK;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcA,QAAQ;AACP,SAAK,QAAQ;AACb,SAAK,OAAO,KAAK,MAAS;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAsBA,gBAAgB,YAA0C;AACzD,UAAM,EAAE,OAAO,UAAU,OAAO,IAAI;AAGpC,aAAS,IAAI,GAAG,IAAI,UAAU,KAAK;AAClC,YAAM,UAAU,QAAQ,IAAI,WAAW,KAAK;AAE5C,YAAM,OAAO,OAAO,MAAM;AAG1B,UAAI,CAAC,MAAM;AACV,eAAO;AAAA,MACR;AAEA,YAAM,CAAC,WAAW,OAAO,IAAI;AAG7B,UAAI,MAAM,KAAK,cAAc,SAAS;AACrC,eAAO,CAAC;AAAA,MACT;AAGA,UAAI,aAAa,cAAc,aAAa,SAAS;AACpD,cAAM,MAAM,IAAI;AAChB,cAAM,SAAS,IAAI,MAAM,GAAG;AAE5B,iBAAS,IAAI,GAAG,IAAI,KAAK,KAAK;AAC7B,iBAAO,CAAC,IAAI,QAAQ,SAAS,KAAK,QAAQ,EAAG,CAAC;AAAA,QAC/C;AAEA,eAAO;AAAA,MACR;AAAA,IACD;AAGA,WAAO;AAAA,EACR;AACD;",
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAA4B;AA2BrB,MAAM,cAAoB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAsBhC,YAA6B,UAAkB;AAAlB;AAC5B,SAAK,SAAS,IAAI,MAAM,QAAQ;AAAA,EACjC;AAAA,EAF6B;AAAA;AAAA;AAAA;AAAA;AAAA,EAjBrB,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA,EAMhB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA+BA,UAAU,mBAA2B,cAAsB,MAA0B;AACpF,QAAI,SAAS,QAAW;AACvB;AAAA,IACD;AAEA,QAAI,SAAS,0BAAa;AACzB,WAAK,MAAM;AACX;AAAA,IACD;AAGA,SAAK,OAAO,KAAK,KAAK,IAAI,CAAC,mBAAmB,cAAc,IAAI;AAGhE,SAAK,SAAS,KAAK,QAAQ,KAAK,KAAK;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcA,QAAQ;AACP,SAAK,QAAQ;AACb,SAAK,OAAO,KAAK,MAAS;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAsBA,gBAAgB,YAA0C;AACzD,UAAM,EAAE,OAAO,UAAU,OAAO,IAAI;AAGpC,aAAS,IAAI,GAAG,IAAI,UAAU,KAAK;AAClC,YAAM,UAAU,QAAQ,IAAI,WAAW,KAAK;AAE5C,YAAM,OAAO,OAAO,MAAM;AAG1B,UAAI,CAAC,MAAM;AACV,eAAO;AAAA,MACR;AAEA,YAAM,CAAC,WAAW,OAAO,IAAI;AAG7B,UAAI,MAAM,KAAK,cAAc,SAAS;AACrC,eAAO,CAAC;AAAA,MACT;AAGA,UAAI,aAAa,cAAc,aAAa,SAAS;AACpD,cAAM,MAAM,IAAI;AAChB,cAAM,SAAS,IAAI,MAAM,GAAG;AAE5B,iBAAS,IAAI,GAAG,IAAI,KAAK,KAAK;AAC7B,iBAAO,CAAC,IAAI,QAAQ,SAAS,KAAK,QAAQ,EAAG,CAAC;AAAA,QAC/C;AAEA,eAAO;AAAA,MACR;AAAA,IACD;AAGA,WAAO;AAAA,EACR;AACD;",
6
6
  "names": []
7
7
  }
@@ -32,6 +32,8 @@ class CaptureStackFrame {
32
32
  this.below = below;
33
33
  this.child = child;
34
34
  }
35
+ below;
36
+ child;
35
37
  offset = 0;
36
38
  maybeRemoved;
37
39
  }
@@ -2,6 +2,6 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/lib/capture.ts"],
4
4
  "sourcesContent": ["import { attach, detach, singleton } from './helpers'\nimport { isComputed } from './isComputed'\nimport type { Child, Signal } from './types'\n\nclass CaptureStackFrame {\n\toffset = 0\n\n\tmaybeRemoved?: Signal<any>[]\n\n\tconstructor(\n\t\tpublic readonly below: CaptureStackFrame | null,\n\t\tpublic readonly child: Child\n\t) {}\n}\n\nconst inst = singleton('capture', () => ({ stack: null as null | CaptureStackFrame }))\n\n/**\n * Executes the given function without capturing any parents in the current capture context.\n *\n * This is mainly useful if you want to run an effect only when certain signals change while also\n * dereferencing other signals which should not cause the effect to rerun on their own.\n *\n * @example\n * ```ts\n * const name = atom('name', 'Sam')\n * const time = atom('time', () => new Date().getTime())\n *\n * setInterval(() => {\n * time.set(new Date().getTime())\n * })\n *\n * react('log name changes', () => {\n * \t print(name.get(), 'was changed at', unsafe__withoutCapture(() => time.get()))\n * })\n *\n * ```\n *\n * @public\n */\nexport function unsafe__withoutCapture<T>(fn: () => T): T {\n\tconst oldStack = inst.stack\n\tinst.stack = null\n\ttry {\n\t\treturn fn()\n\t} finally {\n\t\tinst.stack = oldStack\n\t}\n}\n\n/**\n * Begins capturing parent signal dependencies for the given child signal.\n *\n * This function initiates a capture session where any signal accessed via `.get()`\n * will be automatically registered as a dependency of the child signal. It sets up\n * the capture stack frame and clears the existing parent set to prepare for fresh\n * dependency tracking.\n *\n * @param child - The child signal (computed or effect) that will capture dependencies\n *\n * @example\n * ```ts\n * const effect = createEffect('myEffect', () => { /* ... *\\/ })\n * startCapturingParents(effect)\n * // Now any signal.get() calls will be captured as dependencies\n * ```\n *\n * @internal\n */\nexport function startCapturingParents(child: Child) {\n\tinst.stack = new CaptureStackFrame(inst.stack, child)\n\tif (child.__debug_ancestor_epochs__) {\n\t\tconst previousAncestorEpochs = child.__debug_ancestor_epochs__\n\t\tchild.__debug_ancestor_epochs__ = null\n\t\tfor (const p of child.parents) {\n\t\t\tp.__unsafe__getWithoutCapture(true)\n\t\t}\n\t\tlogChangedAncestors(child, previousAncestorEpochs)\n\t}\n\tchild.parentSet.clear()\n}\n\n/**\n * Completes the parent dependency capture session and finalizes the dependency graph.\n *\n * This function cleans up the capture session by removing dependencies that are no\n * longer needed, detaching signals that should no longer be parents, and updating\n * the dependency arrays to reflect the current set of captured parents. It must be\n * called after `startCapturingParents` to complete the capture cycle.\n *\n * @example\n * ```ts\n * startCapturingParents(effect)\n * // ... signal.get() calls happen here ...\n * stopCapturingParents() // Finalizes the dependency graph\n * ```\n *\n * @internal\n */\nexport function stopCapturingParents() {\n\tconst frame = inst.stack!\n\tinst.stack = frame.below\n\n\tif (frame.offset < frame.child.parents.length) {\n\t\tfor (let i = frame.offset; i < frame.child.parents.length; i++) {\n\t\t\tconst maybeRemovedParent = frame.child.parents[i]\n\t\t\tif (!frame.child.parentSet.has(maybeRemovedParent)) {\n\t\t\t\tdetach(maybeRemovedParent, frame.child)\n\t\t\t}\n\t\t}\n\n\t\tframe.child.parents.length = frame.offset\n\t\tframe.child.parentEpochs.length = frame.offset\n\t}\n\n\tif (frame.maybeRemoved) {\n\t\tfor (let i = 0; i < frame.maybeRemoved.length; i++) {\n\t\t\tconst maybeRemovedParent = frame.maybeRemoved[i]\n\t\t\tif (!frame.child.parentSet.has(maybeRemovedParent)) {\n\t\t\t\tdetach(maybeRemovedParent, frame.child)\n\t\t\t}\n\t\t}\n\t}\n\n\tif (frame.child.__debug_ancestor_epochs__) {\n\t\tcaptureAncestorEpochs(frame.child, frame.child.__debug_ancestor_epochs__)\n\t}\n}\n\n/**\n * Conditionally captures a signal as a parent dependency during an active capture session.\n *\n * This function is called whenever a signal's `.get()` method is invoked during a\n * capture session. It checks if the signal should be added as a dependency and manages\n * the parent-child relationship in the reactive graph. The function handles deduplication,\n * attachment/detachment, and tracks changes in dependency order.\n *\n * Note: This must be called after the parent signal is up to date.\n *\n * @param p - The signal that might be captured as a parent dependency\n *\n * @example\n * ```ts\n * // This is called internally when you do:\n * const value = someAtom.get() // maybeCaptureParent(someAtom) is called\n * ```\n *\n * @internal\n */\nexport function maybeCaptureParent(p: Signal<any, any>) {\n\tif (inst.stack) {\n\t\tconst wasCapturedAlready = inst.stack.child.parentSet.has(p)\n\t\t// if the child didn't deref this parent last time it executed, then idx will be -1\n\t\t// if the child did deref this parent last time but in a different order relative to other parents, then idx will be greater than stack.offset\n\t\t// if the child did deref this parent last time in the same order, then idx will be the same as stack.offset\n\t\t// if the child did deref this parent already during this capture session then 0 <= idx < stack.offset\n\n\t\tif (wasCapturedAlready) {\n\t\t\treturn\n\t\t}\n\n\t\tinst.stack.child.parentSet.add(p)\n\t\tif (inst.stack.child.isActivelyListening) {\n\t\t\tattach(p, inst.stack.child)\n\t\t}\n\n\t\tif (inst.stack.offset < inst.stack.child.parents.length) {\n\t\t\tconst maybeRemovedParent = inst.stack.child.parents[inst.stack.offset]\n\t\t\tif (maybeRemovedParent !== p) {\n\t\t\t\tif (!inst.stack.maybeRemoved) {\n\t\t\t\t\tinst.stack.maybeRemoved = [maybeRemovedParent]\n\t\t\t\t} else {\n\t\t\t\t\tinst.stack.maybeRemoved.push(maybeRemovedParent)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tinst.stack.child.parents[inst.stack.offset] = p\n\t\tinst.stack.child.parentEpochs[inst.stack.offset] = p.lastChangedEpoch\n\t\tinst.stack.offset++\n\t}\n}\n\n/**\n * A debugging tool that tells you why a computed signal or effect is running.\n * Call in the body of a computed signal or effect function.\n *\n * @example\n * ```ts\n * const name = atom('name', 'Bob')\n * react('greeting', () => {\n * \twhyAmIRunning()\n *\tprint('Hello', name.get())\n * })\n *\n * name.set('Alice')\n *\n * // 'greeting' is running because:\n * // 'name' changed => 'Alice'\n * ```\n *\n * @public\n */\nexport function whyAmIRunning() {\n\tconst child = inst.stack?.child\n\tif (!child) {\n\t\tthrow new Error('whyAmIRunning() called outside of a reactive context')\n\t}\n\tchild.__debug_ancestor_epochs__ = new Map()\n}\n\nfunction captureAncestorEpochs(child: Child, ancestorEpochs: Map<Signal<any>, number>) {\n\tfor (let i = 0; i < child.parents.length; i++) {\n\t\tconst parent = child.parents[i]\n\t\tconst epoch = child.parentEpochs[i]\n\t\tancestorEpochs.set(parent, epoch)\n\t\tif (isComputed(parent)) {\n\t\t\tcaptureAncestorEpochs(parent as any, ancestorEpochs)\n\t\t}\n\t}\n\treturn ancestorEpochs\n}\n\ntype ChangeTree = { [signalName: string]: ChangeTree } | null\nfunction collectChangedAncestors(\n\tchild: Child,\n\tancestorEpochs: Map<Signal<any>, number>\n): NonNullable<ChangeTree> {\n\tconst changeTree: ChangeTree = {}\n\tfor (let i = 0; i < child.parents.length; i++) {\n\t\tconst parent = child.parents[i]\n\t\tif (!ancestorEpochs.has(parent)) {\n\t\t\tcontinue\n\t\t}\n\t\tconst prevEpoch = ancestorEpochs.get(parent)\n\t\tconst currentEpoch = parent.lastChangedEpoch\n\t\tif (currentEpoch !== prevEpoch) {\n\t\t\tif (isComputed(parent)) {\n\t\t\t\tchangeTree[parent.name] = collectChangedAncestors(parent as any, ancestorEpochs)\n\t\t\t} else {\n\t\t\t\tchangeTree[parent.name] = null\n\t\t\t}\n\t\t}\n\t}\n\treturn changeTree\n}\n\nfunction logChangedAncestors(child: Child, ancestorEpochs: Map<Signal<any>, number>) {\n\tconst changeTree = collectChangedAncestors(child, ancestorEpochs)\n\tif (Object.keys(changeTree).length === 0) {\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.log(`Effect(${child.name}) was executed manually.`)\n\t\treturn\n\t}\n\n\tlet str = isComputed(child)\n\t\t? `Computed(${child.name}) is recomputing because:`\n\t\t: `Effect(${child.name}) is executing because:`\n\n\tfunction logParent(tree: NonNullable<ChangeTree>, indent: number) {\n\t\tconst indentStr = '\\n' + ' '.repeat(indent) + '\u21B3 '\n\t\tfor (const [name, val] of Object.entries(tree)) {\n\t\t\tif (val) {\n\t\t\t\tstr += `${indentStr}Computed(${name}) changed`\n\t\t\t\tlogParent(val, indent + 2)\n\t\t\t} else {\n\t\t\t\tstr += `${indentStr}Atom(${name}) changed`\n\t\t\t}\n\t\t}\n\t}\n\n\tlogParent(changeTree, 1)\n\n\t// eslint-disable-next-line no-console\n\tconsole.log(str)\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAA0C;AAC1C,wBAA2B;AAG3B,MAAM,kBAAkB;AAAA,EAKvB,YACiB,OACA,OACf;AAFe;AACA;AAAA,EACd;AAAA,EAPH,SAAS;AAAA,EAET;AAMD;AAEA,MAAM,WAAO,0BAAU,WAAW,OAAO,EAAE,OAAO,KAAiC,EAAE;AAyB9E,SAAS,uBAA0B,IAAgB;AACzD,QAAM,WAAW,KAAK;AACtB,OAAK,QAAQ;AACb,MAAI;AACH,WAAO,GAAG;AAAA,EACX,UAAE;AACD,SAAK,QAAQ;AAAA,EACd;AACD;AAqBO,SAAS,sBAAsB,OAAc;AACnD,OAAK,QAAQ,IAAI,kBAAkB,KAAK,OAAO,KAAK;AACpD,MAAI,MAAM,2BAA2B;AACpC,UAAM,yBAAyB,MAAM;AACrC,UAAM,4BAA4B;AAClC,eAAW,KAAK,MAAM,SAAS;AAC9B,QAAE,4BAA4B,IAAI;AAAA,IACnC;AACA,wBAAoB,OAAO,sBAAsB;AAAA,EAClD;AACA,QAAM,UAAU,MAAM;AACvB;AAmBO,SAAS,uBAAuB;AACtC,QAAM,QAAQ,KAAK;AACnB,OAAK,QAAQ,MAAM;AAEnB,MAAI,MAAM,SAAS,MAAM,MAAM,QAAQ,QAAQ;AAC9C,aAAS,IAAI,MAAM,QAAQ,IAAI,MAAM,MAAM,QAAQ,QAAQ,KAAK;AAC/D,YAAM,qBAAqB,MAAM,MAAM,QAAQ,CAAC;AAChD,UAAI,CAAC,MAAM,MAAM,UAAU,IAAI,kBAAkB,GAAG;AACnD,mCAAO,oBAAoB,MAAM,KAAK;AAAA,MACvC;AAAA,IACD;AAEA,UAAM,MAAM,QAAQ,SAAS,MAAM;AACnC,UAAM,MAAM,aAAa,SAAS,MAAM;AAAA,EACzC;AAEA,MAAI,MAAM,cAAc;AACvB,aAAS,IAAI,GAAG,IAAI,MAAM,aAAa,QAAQ,KAAK;AACnD,YAAM,qBAAqB,MAAM,aAAa,CAAC;AAC/C,UAAI,CAAC,MAAM,MAAM,UAAU,IAAI,kBAAkB,GAAG;AACnD,mCAAO,oBAAoB,MAAM,KAAK;AAAA,MACvC;AAAA,IACD;AAAA,EACD;AAEA,MAAI,MAAM,MAAM,2BAA2B;AAC1C,0BAAsB,MAAM,OAAO,MAAM,MAAM,yBAAyB;AAAA,EACzE;AACD;AAsBO,SAAS,mBAAmB,GAAqB;AACvD,MAAI,KAAK,OAAO;AACf,UAAM,qBAAqB,KAAK,MAAM,MAAM,UAAU,IAAI,CAAC;AAM3D,QAAI,oBAAoB;AACvB;AAAA,IACD;AAEA,SAAK,MAAM,MAAM,UAAU,IAAI,CAAC;AAChC,QAAI,KAAK,MAAM,MAAM,qBAAqB;AACzC,iCAAO,GAAG,KAAK,MAAM,KAAK;AAAA,IAC3B;AAEA,QAAI,KAAK,MAAM,SAAS,KAAK,MAAM,MAAM,QAAQ,QAAQ;AACxD,YAAM,qBAAqB,KAAK,MAAM,MAAM,QAAQ,KAAK,MAAM,MAAM;AACrE,UAAI,uBAAuB,GAAG;AAC7B,YAAI,CAAC,KAAK,MAAM,cAAc;AAC7B,eAAK,MAAM,eAAe,CAAC,kBAAkB;AAAA,QAC9C,OAAO;AACN,eAAK,MAAM,aAAa,KAAK,kBAAkB;AAAA,QAChD;AAAA,MACD;AAAA,IACD;AAEA,SAAK,MAAM,MAAM,QAAQ,KAAK,MAAM,MAAM,IAAI;AAC9C,SAAK,MAAM,MAAM,aAAa,KAAK,MAAM,MAAM,IAAI,EAAE;AACrD,SAAK,MAAM;AAAA,EACZ;AACD;AAsBO,SAAS,gBAAgB;AAC/B,QAAM,QAAQ,KAAK,OAAO;AAC1B,MAAI,CAAC,OAAO;AACX,UAAM,IAAI,MAAM,sDAAsD;AAAA,EACvE;AACA,QAAM,4BAA4B,oBAAI,IAAI;AAC3C;AAEA,SAAS,sBAAsB,OAAc,gBAA0C;AACtF,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,QAAQ,KAAK;AAC9C,UAAM,SAAS,MAAM,QAAQ,CAAC;AAC9B,UAAM,QAAQ,MAAM,aAAa,CAAC;AAClC,mBAAe,IAAI,QAAQ,KAAK;AAChC,YAAI,8BAAW,MAAM,GAAG;AACvB,4BAAsB,QAAe,cAAc;AAAA,IACpD;AAAA,EACD;AACA,SAAO;AACR;AAGA,SAAS,wBACR,OACA,gBAC0B;AAC1B,QAAM,aAAyB,CAAC;AAChC,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,QAAQ,KAAK;AAC9C,UAAM,SAAS,MAAM,QAAQ,CAAC;AAC9B,QAAI,CAAC,eAAe,IAAI,MAAM,GAAG;AAChC;AAAA,IACD;AACA,UAAM,YAAY,eAAe,IAAI,MAAM;AAC3C,UAAM,eAAe,OAAO;AAC5B,QAAI,iBAAiB,WAAW;AAC/B,cAAI,8BAAW,MAAM,GAAG;AACvB,mBAAW,OAAO,IAAI,IAAI,wBAAwB,QAAe,cAAc;AAAA,MAChF,OAAO;AACN,mBAAW,OAAO,IAAI,IAAI;AAAA,MAC3B;AAAA,IACD;AAAA,EACD;AACA,SAAO;AACR;AAEA,SAAS,oBAAoB,OAAc,gBAA0C;AACpF,QAAM,aAAa,wBAAwB,OAAO,cAAc;AAChE,MAAI,OAAO,KAAK,UAAU,EAAE,WAAW,GAAG;AAEzC,YAAQ,IAAI,UAAU,MAAM,IAAI,0BAA0B;AAC1D;AAAA,EACD;AAEA,MAAI,UAAM,8BAAW,KAAK,IACvB,YAAY,MAAM,IAAI,8BACtB,UAAU,MAAM,IAAI;AAEvB,WAAS,UAAU,MAA+B,QAAgB;AACjE,UAAM,YAAY,OAAO,IAAI,OAAO,MAAM,IAAI;AAC9C,eAAW,CAAC,MAAM,GAAG,KAAK,OAAO,QAAQ,IAAI,GAAG;AAC/C,UAAI,KAAK;AACR,eAAO,GAAG,SAAS,YAAY,IAAI;AACnC,kBAAU,KAAK,SAAS,CAAC;AAAA,MAC1B,OAAO;AACN,eAAO,GAAG,SAAS,QAAQ,IAAI;AAAA,MAChC;AAAA,IACD;AAAA,EACD;AAEA,YAAU,YAAY,CAAC;AAGvB,UAAQ,IAAI,GAAG;AAChB;",
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -64,7 +64,7 @@ function equals(a, b) {
64
64
  return shallowEquals;
65
65
  }
66
66
  function singleton(key, init) {
67
- const symbol = Symbol.for(`com.tldraw.state/${key}`);
67
+ const symbol = /* @__PURE__ */ Symbol.for(`com.tldraw.state/${key}`);
68
68
  const global = globalThis;
69
69
  global[symbol] ??= init();
70
70
  return global[symbol];
@@ -2,6 +2,6 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/lib/helpers.ts"],
4
4
  "sourcesContent": ["import { Child, Signal } from './types'\n\n/**\n * Get whether the given value is a child.\n *\n * @param x The value to check.\n * @returns True if the value is a child, false otherwise.\n * @internal\n */\nfunction isChild(x: any): x is Child {\n\treturn x && typeof x === 'object' && 'parents' in x\n}\n\n/**\n * Checks if any of a child's parent signals have changed by comparing their current epochs\n * with the child's cached view of those epochs.\n *\n * This function is used internally to determine if a computed signal or effect needs to\n * be re-evaluated because one of its dependencies has changed.\n *\n * @param child - The child (computed signal or effect) to check for parent changes\n * @returns `true` if any parent signal has changed since the child last observed it, `false` otherwise\n * @example\n * ```ts\n * const childSignal = computed('child', () => parentAtom.get())\n * // Check if the child needs to recompute\n * if (haveParentsChanged(childSignal)) {\n * // Recompute the child's value\n * }\n * ```\n * @internal\n */\nexport function haveParentsChanged(child: Child): boolean {\n\tfor (let i = 0, n = child.parents.length; i < n; i++) {\n\t\t// Get the parent's value without capturing it.\n\t\tchild.parents[i].__unsafe__getWithoutCapture(true)\n\n\t\t// If the parent's epoch does not match the child's view of the parent's epoch, then the parent has changed.\n\t\tif (child.parents[i].lastChangedEpoch !== child.parentEpochs[i]) {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\n/**\n * Detaches a child signal from its parent signal, removing the parent-child relationship\n * in the reactive dependency graph. If the parent has no remaining children and is itself\n * a child, it will recursively detach from its own parents.\n *\n * This function is used internally to clean up the dependency graph when signals are no\n * longer needed or when dependencies change.\n *\n * @param parent - The parent signal to detach from\n * @param child - The child signal to detach\n * @example\n * ```ts\n * // When a computed signal's dependencies change\n * const oldParent = atom('old', 1)\n * const child = computed('child', () => oldParent.get())\n * // Later, detach the child from the old parent\n * detach(oldParent, child)\n * ```\n * @internal\n */\nexport function detach(parent: Signal<any>, child: Child) {\n\t// If the child is not attached to the parent, do nothing.\n\tif (!parent.children.remove(child)) {\n\t\treturn\n\t}\n\n\t// If the parent has no more children, then detach the parent from its parents.\n\tif (parent.children.isEmpty && isChild(parent)) {\n\t\tfor (let i = 0, n = parent.parents.length; i < n; i++) {\n\t\t\tdetach(parent.parents[i], parent)\n\t\t}\n\t}\n}\n\n/**\n * Attaches a child signal to its parent signal, establishing a parent-child relationship\n * in the reactive dependency graph. If the parent is itself a child, it will recursively\n * attach to its own parents to maintain the dependency chain.\n *\n * This function is used internally when dependencies are captured during computed signal\n * evaluation or effect execution.\n *\n * @param parent - The parent signal to attach to\n * @param child - The child signal to attach\n * @example\n * ```ts\n * // When a computed signal captures a new dependency\n * const parentAtom = atom('parent', 1)\n * const child = computed('child', () => parentAtom.get())\n * // Internally, attach is called to establish the dependency\n * attach(parentAtom, child)\n * ```\n * @internal\n */\nexport function attach(parent: Signal<any>, child: Child) {\n\t// If the child is already attached to the parent, do nothing.\n\tif (!parent.children.add(child)) {\n\t\treturn\n\t}\n\n\t// If the parent itself is a child, add the parent to the parent's parents.\n\tif (isChild(parent)) {\n\t\tfor (let i = 0, n = parent.parents.length; i < n; i++) {\n\t\t\tattach(parent.parents[i], parent)\n\t\t}\n\t}\n}\n\n/**\n * Checks if two values are equal using the equality semantics of @tldraw/state.\n *\n * This function performs equality checks in the following order:\n * 1. Reference equality (`===`)\n * 2. `Object.is()` equality (handles NaN and -0/+0 cases)\n * 3. Custom `.equals()` method when the left-hand value provides one\n *\n * This is used internally to determine if a signal's value has actually changed\n * when setting new values, preventing unnecessary updates and re-computations.\n *\n * @param a - The first value to compare\n * @param b - The second value to compare\n * @returns `true` if the values are considered equal, `false` otherwise\n * @example\n * ```ts\n * equals(1, 1) // true\n * equals(NaN, NaN) // true (unlike === which returns false)\n * equals({ equals: (other: any) => other.id === 1 }, { id: 1 }) // Uses custom equals method\n * ```\n * @internal\n */\nexport function equals(a: any, b: any): boolean {\n\tconst shallowEquals =\n\t\ta === b || Object.is(a, b) || Boolean(a && b && typeof a.equals === 'function' && a.equals(b))\n\treturn shallowEquals\n}\n\n/**\n * A TypeScript utility function for exhaustiveness checking in switch statements and\n * conditional branches. This function should never be called at runtime\u2014it exists\n * purely for compile-time type checking and is `undefined` in emitted JavaScript.\n *\n * @param x - A value that should be of type `never`\n * @throws Always at runtime because the identifier is undefined\n * @example\n * ```ts\n * type Color = 'red' | 'blue'\n *\n * function handleColor(color: Color) {\n * switch (color) {\n * case 'red':\n * return 'Stop'\n * case 'blue':\n * return 'Go'\n * default:\n * return assertNever(color) // TypeScript error if not all cases handled\n * }\n * }\n * ```\n * @public\n */\nexport declare function assertNever(x: never): never\n\n/**\n * Creates or retrieves a singleton instance using a global symbol registry.\n * This ensures that the same instance is shared across all code that uses\n * the same key, even across different module boundaries.\n *\n * The singleton is stored on `globalThis` using a symbol created with\n * `Symbol.for()`, which ensures global uniqueness across realms.\n *\n * @param key - A unique string identifier for the singleton\n * @param init - A function that creates the initial value if it doesn't exist\n * @returns The singleton instance\n * @example\n * ```ts\n * // Create a singleton logger\n * const logger = singleton('logger', () => new Logger())\n *\n * // Elsewhere in the codebase, get the same logger instance\n * const sameLogger = singleton('logger', () => new Logger())\n * // logger === sameLogger\n * ```\n * @internal\n */\nexport function singleton<T>(key: string, init: () => T): T {\n\tconst symbol = Symbol.for(`com.tldraw.state/${key}`)\n\tconst global = globalThis as any\n\tglobal[symbol] ??= init()\n\treturn global[symbol]\n}\n\n/**\n * @public\n */\nexport const EMPTY_ARRAY: [] = singleton('empty_array', () => Object.freeze([]) as any)\n\n/**\n * Checks if a signal has any active reactors (effects or computed signals) that are\n * currently listening to it. This determines whether changes to the signal will\n * cause any side effects or recomputations to occur.\n *\n * A signal is considered to have active reactors if any of its child dependencies\n * are actively listening for changes.\n *\n * @param signal - The signal to check for active reactors\n * @returns `true` if the signal has active reactors, `false` otherwise\n * @example\n * ```ts\n * const count = atom('count', 0)\n *\n * console.log(hasReactors(count)) // false - no effects listening\n *\n * const stop = react('logger', () => console.log(count.get()))\n * console.log(hasReactors(count)) // true - effect is listening\n *\n * stop()\n * console.log(hasReactors(count)) // false - effect stopped\n * ```\n * @public\n */\nexport function hasReactors(signal: Signal<any>) {\n\tfor (const child of signal.children) {\n\t\tif (child.isActivelyListening) {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASA,SAAS,QAAQ,GAAoB;AACpC,SAAO,KAAK,OAAO,MAAM,YAAY,aAAa;AACnD;AAqBO,SAAS,mBAAmB,OAAuB;AACzD,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,QAAQ,IAAI,GAAG,KAAK;AAErD,UAAM,QAAQ,CAAC,EAAE,4BAA4B,IAAI;AAGjD,QAAI,MAAM,QAAQ,CAAC,EAAE,qBAAqB,MAAM,aAAa,CAAC,GAAG;AAChE,aAAO;AAAA,IACR;AAAA,EACD;AAEA,SAAO;AACR;AAsBO,SAAS,OAAO,QAAqB,OAAc;AAEzD,MAAI,CAAC,OAAO,SAAS,OAAO,KAAK,GAAG;AACnC;AAAA,EACD;AAGA,MAAI,OAAO,SAAS,WAAW,QAAQ,MAAM,GAAG;AAC/C,aAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,QAAQ,IAAI,GAAG,KAAK;AACtD,aAAO,OAAO,QAAQ,CAAC,GAAG,MAAM;AAAA,IACjC;AAAA,EACD;AACD;AAsBO,SAAS,OAAO,QAAqB,OAAc;AAEzD,MAAI,CAAC,OAAO,SAAS,IAAI,KAAK,GAAG;AAChC;AAAA,EACD;AAGA,MAAI,QAAQ,MAAM,GAAG;AACpB,aAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,QAAQ,IAAI,GAAG,KAAK;AACtD,aAAO,OAAO,QAAQ,CAAC,GAAG,MAAM;AAAA,IACjC;AAAA,EACD;AACD;AAwBO,SAAS,OAAO,GAAQ,GAAiB;AAC/C,QAAM,gBACL,MAAM,KAAK,OAAO,GAAG,GAAG,CAAC,KAAK,QAAQ,KAAK,KAAK,OAAO,EAAE,WAAW,cAAc,EAAE,OAAO,CAAC,CAAC;AAC9F,SAAO;AACR;AAkDO,SAAS,UAAa,KAAa,MAAkB;AAC3D,QAAM,SAAS,OAAO,IAAI,oBAAoB,GAAG,EAAE;AACnD,QAAM,SAAS;AACf,SAAO,MAAM,MAAM,KAAK;AACxB,SAAO,OAAO,MAAM;AACrB;AAKO,MAAM,cAAkB,UAAU,eAAe,MAAM,OAAO,OAAO,CAAC,CAAC,CAAQ;AA0B/E,SAAS,YAAY,QAAqB;AAChD,aAAW,SAAS,OAAO,UAAU;AACpC,QAAI,MAAM,qBAAqB;AAC9B,aAAO;AAAA,IACR;AAAA,EACD;AAEA,SAAO;AACR;",
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASA,SAAS,QAAQ,GAAoB;AACpC,SAAO,KAAK,OAAO,MAAM,YAAY,aAAa;AACnD;AAqBO,SAAS,mBAAmB,OAAuB;AACzD,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,QAAQ,IAAI,GAAG,KAAK;AAErD,UAAM,QAAQ,CAAC,EAAE,4BAA4B,IAAI;AAGjD,QAAI,MAAM,QAAQ,CAAC,EAAE,qBAAqB,MAAM,aAAa,CAAC,GAAG;AAChE,aAAO;AAAA,IACR;AAAA,EACD;AAEA,SAAO;AACR;AAsBO,SAAS,OAAO,QAAqB,OAAc;AAEzD,MAAI,CAAC,OAAO,SAAS,OAAO,KAAK,GAAG;AACnC;AAAA,EACD;AAGA,MAAI,OAAO,SAAS,WAAW,QAAQ,MAAM,GAAG;AAC/C,aAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,QAAQ,IAAI,GAAG,KAAK;AACtD,aAAO,OAAO,QAAQ,CAAC,GAAG,MAAM;AAAA,IACjC;AAAA,EACD;AACD;AAsBO,SAAS,OAAO,QAAqB,OAAc;AAEzD,MAAI,CAAC,OAAO,SAAS,IAAI,KAAK,GAAG;AAChC;AAAA,EACD;AAGA,MAAI,QAAQ,MAAM,GAAG;AACpB,aAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,QAAQ,IAAI,GAAG,KAAK;AACtD,aAAO,OAAO,QAAQ,CAAC,GAAG,MAAM;AAAA,IACjC;AAAA,EACD;AACD;AAwBO,SAAS,OAAO,GAAQ,GAAiB;AAC/C,QAAM,gBACL,MAAM,KAAK,OAAO,GAAG,GAAG,CAAC,KAAK,QAAQ,KAAK,KAAK,OAAO,EAAE,WAAW,cAAc,EAAE,OAAO,CAAC,CAAC;AAC9F,SAAO;AACR;AAkDO,SAAS,UAAa,KAAa,MAAkB;AAC3D,QAAM,SAAS,uBAAO,IAAI,oBAAoB,GAAG,EAAE;AACnD,QAAM,SAAS;AACf,SAAO,MAAM,MAAM,KAAK;AACxB,SAAO,OAAO,MAAM;AACrB;AAKO,MAAM,cAAkB,UAAU,eAAe,MAAM,OAAO,OAAO,CAAC,CAAC,CAAQ;AA0B/E,SAAS,YAAY,QAAqB;AAChD,aAAW,SAAS,OAAO,UAAU;AACpC,QAAI,MAAM,qBAAqB;AAC9B,aAAO;AAAA,IACR;AAAA,EACD;AAEA,SAAO;AACR;",
6
6
  "names": []
7
7
  }