@tldraw/state 4.6.0-canary.6d34f9a01c8a → 4.6.0-canary.6fdc07d3e5f0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-cjs/index.js +1 -1
- package/dist-cjs/lib/Atom.js +1 -1
- package/dist-cjs/lib/Atom.js.map +2 -2
- package/dist-cjs/lib/Computed.js +6 -6
- package/dist-cjs/lib/Computed.js.map +2 -2
- package/dist-cjs/lib/helpers.js +1 -1
- package/dist-cjs/lib/helpers.js.map +1 -1
- package/dist-cjs/lib/types.js +1 -1
- package/dist-cjs/lib/types.js.map +1 -1
- package/dist-esm/index.mjs +1 -1
- package/dist-esm/lib/Atom.mjs +1 -1
- package/dist-esm/lib/Atom.mjs.map +2 -2
- package/dist-esm/lib/Computed.mjs +6 -6
- package/dist-esm/lib/Computed.mjs.map +2 -2
- package/dist-esm/lib/helpers.mjs +1 -1
- package/dist-esm/lib/helpers.mjs.map +1 -1
- package/dist-esm/lib/types.mjs +1 -1
- package/dist-esm/lib/types.mjs.map +1 -1
- package/package.json +3 -3
- package/src/lib/Atom.ts +1 -1
- package/src/lib/Computed.ts +1 -1
- package/src/lib/__tests__/capture.test.ts +2 -2
package/dist-cjs/index.js
CHANGED
package/dist-cjs/lib/Atom.js
CHANGED
|
@@ -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__ {
|
package/dist-cjs/lib/Atom.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/lib/Atom.ts"],
|
|
4
|
-
"sourcesContent": ["import { ArraySet } from './ArraySet'\nimport {
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sBAAyB;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;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;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist-cjs/lib/Computed.js
CHANGED
|
@@ -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
|
}
|
|
@@ -157,7 +157,7 @@ class __UNSAFE__Computed {
|
|
|
157
157
|
const _Computed = (0, import_helpers.singleton)("Computed", () => __UNSAFE__Computed);
|
|
158
158
|
function computedMethodLegacyDecorator(options = {}, _target, key, descriptor) {
|
|
159
159
|
const originalMethod = descriptor.value;
|
|
160
|
-
const derivationKey = Symbol.for("__@tldraw/state__computed__" + key);
|
|
160
|
+
const derivationKey = /* @__PURE__ */ Symbol.for("__@tldraw/state__computed__" + key);
|
|
161
161
|
descriptor.value = function() {
|
|
162
162
|
let d = this[derivationKey];
|
|
163
163
|
if (!d) {
|
|
@@ -176,7 +176,7 @@ function computedMethodLegacyDecorator(options = {}, _target, key, descriptor) {
|
|
|
176
176
|
}
|
|
177
177
|
function computedGetterLegacyDecorator(options = {}, _target, key, descriptor) {
|
|
178
178
|
const originalMethod = descriptor.get;
|
|
179
|
-
const derivationKey = Symbol.for("__@tldraw/state__computed__" + key);
|
|
179
|
+
const derivationKey = /* @__PURE__ */ Symbol.for("__@tldraw/state__computed__" + key);
|
|
180
180
|
descriptor.get = function() {
|
|
181
181
|
let d = this[derivationKey];
|
|
182
182
|
if (!d) {
|
|
@@ -194,7 +194,7 @@ function computedGetterLegacyDecorator(options = {}, _target, key, descriptor) {
|
|
|
194
194
|
}
|
|
195
195
|
function computedMethodTc39Decorator(options, compute, context) {
|
|
196
196
|
(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));
|
|
197
|
+
const derivationKey = /* @__PURE__ */ Symbol.for("__@tldraw/state__computed__" + String(context.name));
|
|
198
198
|
const fn = function() {
|
|
199
199
|
let d = this[derivationKey];
|
|
200
200
|
if (!d) {
|
|
@@ -227,7 +227,7 @@ function computedDecorator(options = {}, args) {
|
|
|
227
227
|
}
|
|
228
228
|
const isComputedMethodKey = "@@__isComputedMethod__@@";
|
|
229
229
|
function getComputedInstance(obj, propertyName) {
|
|
230
|
-
const key = Symbol.for("__@tldraw/state__computed__" + propertyName.toString());
|
|
230
|
+
const key = /* @__PURE__ */ Symbol.for("__@tldraw/state__computed__" + propertyName.toString());
|
|
231
231
|
let inst = obj[key];
|
|
232
232
|
if (!inst) {
|
|
233
233
|
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 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,
|
|
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": "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",
|
|
6
6
|
"names": ["isUninitialized", "_isComputed"]
|
|
7
7
|
}
|
package/dist-cjs/lib/helpers.js
CHANGED
|
@@ -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,
|
|
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
|
}
|
package/dist-cjs/lib/types.js
CHANGED
|
@@ -21,5 +21,5 @@ __export(types_exports, {
|
|
|
21
21
|
RESET_VALUE: () => RESET_VALUE
|
|
22
22
|
});
|
|
23
23
|
module.exports = __toCommonJS(types_exports);
|
|
24
|
-
const RESET_VALUE = Symbol.for("com.tldraw.state/RESET_VALUE");
|
|
24
|
+
const RESET_VALUE = /* @__PURE__ */ Symbol.for("com.tldraw.state/RESET_VALUE");
|
|
25
25
|
//# sourceMappingURL=types.js.map
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/lib/types.ts"],
|
|
4
4
|
"sourcesContent": ["import { ArraySet } from './ArraySet'\n\n/**\n * A unique symbol used to indicate that a signal's value should be reset or that\n * there is insufficient history to compute diffs between epochs.\n *\n * This value is returned by {@link Signal.getDiffSince} when the requested epoch\n * is too far in the past and the diff sequence cannot be reconstructed.\n *\n * @example\n * ```ts\n * import { atom, getGlobalEpoch, RESET_VALUE } from '@tldraw/state'\n *\n * const count = atom('count', 0, { historyLength: 3 })\n * const oldEpoch = getGlobalEpoch()\n *\n * // Make many changes that exceed history length\n * count.set(1)\n * count.set(2)\n * count.set(3)\n * count.set(4)\n *\n * const diffs = count.getDiffSince(oldEpoch)\n * if (diffs === RESET_VALUE) {\n * console.log('Too many changes, need to reset state')\n * }\n * ```\n *\n * @public\n */\nexport const RESET_VALUE: unique symbol = Symbol.for('com.tldraw.state/RESET_VALUE')\n\n/**\n * Type representing the the unique symbol RESET_VALUE symbol, used in type annotations\n * to indicate when a signal value should be reset or when diff computation\n * cannot proceed due to insufficient history.\n *\n * @public\n */\nexport type RESET_VALUE = typeof RESET_VALUE\n\n/**\n * A reactive value container that can change over time and track diffs between sequential values.\n *\n * Signals are the foundation of the \\@tldraw/state reactive system. They automatically manage\n * dependencies and trigger updates when their values change. Any computed signal or effect\n * that reads from this signal will be automatically recomputed when the signal's value changes.\n *\n * There are two types of signal:\n * - **Atomic signals** - Created using `atom()`. These are mutable containers that can be\n * directly updated using `set()` or `update()` methods.\n * - **Computed signals** - Created using `computed()`. These derive their values from other\n * signals and are automatically recomputed when dependencies change.\n *\n * @example\n * ```ts\n * import { atom, computed } from '@tldraw/state'\n *\n * // Create an atomic signal\n * const count = atom('count', 0)\n *\n * // Create a computed signal that derives from the atom\n * const doubled = computed('doubled', () => count.get() * 2)\n *\n * console.log(doubled.get()) // 0\n * count.set(5)\n * console.log(doubled.get()) // 10\n * ```\n *\n * @public\n */\nexport interface Signal<Value, Diff = unknown> {\n\t/**\n\t * A human-readable identifier for this signal, used primarily for debugging and performance profiling.\n\t *\n\t * The name is displayed in debug output from {@link whyAmIRunning} and other diagnostic tools.\n\t * It does not need to be globally unique within your application.\n\t */\n\tname: string\n\t/**\n\t * Gets the current value of the signal and establishes a dependency relationship.\n\t *\n\t * When called from within a computed signal or effect, this signal will be automatically\n\t * tracked as a dependency. If this signal's value changes, any dependent computations\n\t * or effects will be marked for re-execution.\n\t *\n\t * @returns The current value stored in the signal\n\t */\n\tget(): Value\n\n\t/**\n\t * The global epoch number when this signal's value last changed.\n\t *\n\t * Note that this represents when the value actually changed, not when it was last computed.\n\t * A computed signal may recalculate and produce the same value without changing its epoch.\n\t * This is used internally for dependency tracking and history management.\n\t */\n\tlastChangedEpoch: number\n\t/**\n\t * Gets the sequence of diffs that occurred between a specific epoch and the current state.\n\t *\n\t * This method enables incremental synchronization by providing a list of changes that\n\t * have occurred since a specific point in time. If the requested epoch is too far in\n\t * the past or the signal doesn't have enough history, it returns the unique symbol RESET_VALUE\n\t * to indicate that a full state reset is required.\n\t *\n\t * @param epoch - The epoch timestamp to get diffs since\n\t * @returns An array of diff objects representing changes since the epoch, or the unique symbol RESET_VALUE if insufficient history is available\n\t */\n\tgetDiffSince(epoch: number): RESET_VALUE | Diff[]\n\t/**\n\t * Gets the current value of the signal without establishing a dependency relationship.\n\t *\n\t * This method bypasses the automatic dependency tracking system, making it useful for\n\t * performance-critical code paths where the overhead of dependency capture would be\n\t * problematic. Use with caution as it breaks the reactive guarantees of the system.\n\t *\n\t * **Warning**: This method should only be used when you're certain that you don't need\n\t * the calling context to react to changes in this signal.\n\t *\n\t * @param ignoreErrors - Whether to suppress errors during value retrieval (optional)\n\t * @returns The current value without establishing dependencies\n\t */\n\t__unsafe__getWithoutCapture(ignoreErrors?: boolean): Value\n\t/** @internal */\n\tchildren: ArraySet<Child>\n}\n\n/**\n * Internal interface representing a child node in the signal dependency graph.\n *\n * This interface is used internally by the reactive system to manage dependencies\n * between signals, computed values, and effects. Each child tracks its parent\n * signals and maintains state needed for efficient dependency graph traversal\n * and change propagation.\n *\n * @internal\n */\nexport interface Child {\n\t/**\n\t * The epoch when this child was last traversed during dependency graph updates.\n\t * Used to prevent redundant traversals during change propagation.\n\t */\n\tlastTraversedEpoch: number\n\n\t/**\n\t * Set of parent signals that this child depends on.\n\t * Used for efficient lookup and cleanup operations.\n\t */\n\treadonly parentSet: ArraySet<Signal<any, any>>\n\n\t/**\n\t * Array of parent signals that this child depends on.\n\t * Maintained in parallel with parentSet for ordered access.\n\t */\n\treadonly parents: Signal<any, any>[]\n\n\t/**\n\t * Array of epochs corresponding to each parent signal.\n\t * Used to detect which parents have changed since last computation.\n\t */\n\treadonly parentEpochs: number[]\n\n\t/**\n\t * Human-readable name for this child, used in debugging output.\n\t */\n\treadonly name: string\n\n\t/**\n\t * Whether this child is currently subscribed to change notifications.\n\t * Used to optimize resource usage by unsubscribing inactive dependencies.\n\t */\n\tisActivelyListening: boolean\n\n\t/**\n\t * Debug information tracking ancestor epochs in the dependency graph.\n\t * Only populated in debug builds for diagnostic purposes.\n\t */\n\t__debug_ancestor_epochs__: Map<Signal<any, any>, number> | null\n}\n\n/**\n * A function type that computes the difference between two values of a signal.\n *\n * This function is used to generate incremental diffs that can be applied to\n * reconstruct state changes over time. It's particularly useful for features\n * like undo/redo, synchronization, and change tracking.\n *\n * The function should analyze the previous and current values and return a\n * diff object that represents the change. If the diff cannot be computed\n * (e.g., the values are too different or incompatible), it should return\n * the unique symbol RESET_VALUE to indicate that a full state reset is required.\n *\n * @param previousValue - The previous value of the signal\n * @param currentValue - The current value of the signal\n * @param lastComputedEpoch - The epoch when the previous value was set\n * @param currentEpoch - The epoch when the current value was set\n * @returns A diff object representing the change, or the unique symbol RESET_VALUE if no diff can be computed\n *\n * @example\n * ```ts\n * import { atom, RESET_VALUE } from '@tldraw/state'\n *\n * // Simple numeric diff\n * const numberDiff: ComputeDiff<number, number> = (prev, curr) => curr - prev\n *\n * // Array diff with reset fallback\n * const arrayDiff: ComputeDiff<string[], { added: string[], removed: string[] }> = (prev, curr) => {\n * if (prev.length > 1000 || curr.length > 1000) {\n * return RESET_VALUE // Too complex, force reset\n * }\n * return {\n * added: curr.filter(item => !prev.includes(item)),\n * removed: prev.filter(item => !curr.includes(item))\n * }\n * }\n *\n * const count = atom('count', 0, { computeDiff: numberDiff })\n * ```\n *\n * @public\n */\nexport type ComputeDiff<Value, Diff> = (\n\tpreviousValue: Value,\n\tcurrentValue: Value,\n\tlastComputedEpoch: number,\n\tcurrentEpoch: number\n) => Diff | RESET_VALUE\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA8BO,MAAM,cAA6B,
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA8BO,MAAM,cAA6B,uBAAO,IAAI,8BAA8B;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist-esm/index.mjs
CHANGED
package/dist-esm/lib/Atom.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ArraySet } from "./ArraySet.mjs";
|
|
2
|
-
import { HistoryBuffer } from "./HistoryBuffer.mjs";
|
|
3
2
|
import { maybeCaptureParent } from "./capture.mjs";
|
|
4
3
|
import { EMPTY_ARRAY, equals, singleton } from "./helpers.mjs";
|
|
4
|
+
import { HistoryBuffer } from "./HistoryBuffer.mjs";
|
|
5
5
|
import { advanceGlobalEpoch, atomDidChange, getGlobalEpoch } from "./transactions.mjs";
|
|
6
6
|
import { RESET_VALUE } from "./types.mjs";
|
|
7
7
|
class __Atom__ {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/lib/Atom.ts"],
|
|
4
|
-
"sourcesContent": ["import { ArraySet } from './ArraySet'\nimport {
|
|
5
|
-
"mappings": "AAAA,SAAS,gBAAgB;AACzB,SAAS,
|
|
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,SAAS,gBAAgB;AACzB,SAAS,0BAA0B;AACnC,SAAS,aAAa,QAAQ,iBAAiB;AAC/C,SAAS,qBAAqB;AAC9B,SAAS,oBAAoB,eAAe,sBAAsB;AAClE,SAA6B,mBAA2B;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,cAAc,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,mBAAmB,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA,EAMlC,WAAW,IAAI,SAAgB;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,uBAAmB,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,KAAK,OAAO,KAAK,SAAS,KAAK,GAAG;AACvE,aAAO,KAAK;AAAA,IACb;AAGA,uBAAmB;AAGnB,QAAI,KAAK,eAAe;AACvB,WAAK,cAAc;AAAA,QAClB,KAAK;AAAA,QACL,eAAe;AAAA,QACf,QACC,KAAK,cAAc,KAAK,SAAS,OAAO,KAAK,kBAAkB,eAAe,CAAC,KAC/E;AAAA,MACF;AAAA,IACD;AAGA,SAAK,mBAAmB,eAAe;AAEvC,UAAM,WAAW,KAAK;AACtB,SAAK,UAAU;AAGf,kBAAc,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,uBAAmB,IAAI;AAGvB,QAAI,SAAS,KAAK,kBAAkB;AACnC,aAAO;AAAA,IACR;AAEA,WAAO,KAAK,eAAe,gBAAgB,KAAK,KAAK;AAAA,EACtD;AACD;AAMO,MAAM,QAAQ,UAAU,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
|
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { assert } from "@tldraw/utils";
|
|
2
2
|
import { ArraySet } from "./ArraySet.mjs";
|
|
3
|
-
import { HistoryBuffer } from "./HistoryBuffer.mjs";
|
|
4
3
|
import { maybeCaptureParent, startCapturingParents, stopCapturingParents } from "./capture.mjs";
|
|
5
4
|
import { GLOBAL_START_EPOCH } from "./constants.mjs";
|
|
6
5
|
import { EMPTY_ARRAY, equals, haveParentsChanged, singleton } from "./helpers.mjs";
|
|
6
|
+
import { HistoryBuffer } from "./HistoryBuffer.mjs";
|
|
7
7
|
import { getGlobalEpoch, getIsReacting, getReactionEpoch } from "./transactions.mjs";
|
|
8
8
|
import { RESET_VALUE } from "./types.mjs";
|
|
9
9
|
import { logComputedGetterWarning } from "./warnings.mjs";
|
|
10
|
-
const UNINITIALIZED = Symbol.for("com.tldraw.state/UNINITIALIZED");
|
|
10
|
+
const UNINITIALIZED = /* @__PURE__ */ Symbol.for("com.tldraw.state/UNINITIALIZED");
|
|
11
11
|
function isUninitialized(value) {
|
|
12
12
|
return value === UNINITIALIZED;
|
|
13
13
|
}
|
|
@@ -126,7 +126,7 @@ class __UNSAFE__Computed {
|
|
|
126
126
|
const _Computed = singleton("Computed", () => __UNSAFE__Computed);
|
|
127
127
|
function computedMethodLegacyDecorator(options = {}, _target, key, descriptor) {
|
|
128
128
|
const originalMethod = descriptor.value;
|
|
129
|
-
const derivationKey = Symbol.for("__@tldraw/state__computed__" + key);
|
|
129
|
+
const derivationKey = /* @__PURE__ */ Symbol.for("__@tldraw/state__computed__" + key);
|
|
130
130
|
descriptor.value = function() {
|
|
131
131
|
let d = this[derivationKey];
|
|
132
132
|
if (!d) {
|
|
@@ -145,7 +145,7 @@ function computedMethodLegacyDecorator(options = {}, _target, key, descriptor) {
|
|
|
145
145
|
}
|
|
146
146
|
function computedGetterLegacyDecorator(options = {}, _target, key, descriptor) {
|
|
147
147
|
const originalMethod = descriptor.get;
|
|
148
|
-
const derivationKey = Symbol.for("__@tldraw/state__computed__" + key);
|
|
148
|
+
const derivationKey = /* @__PURE__ */ Symbol.for("__@tldraw/state__computed__" + key);
|
|
149
149
|
descriptor.get = function() {
|
|
150
150
|
let d = this[derivationKey];
|
|
151
151
|
if (!d) {
|
|
@@ -163,7 +163,7 @@ function computedGetterLegacyDecorator(options = {}, _target, key, descriptor) {
|
|
|
163
163
|
}
|
|
164
164
|
function computedMethodTc39Decorator(options, compute, context) {
|
|
165
165
|
assert(context.kind === "method", "@computed can only be used on methods");
|
|
166
|
-
const derivationKey = Symbol.for("__@tldraw/state__computed__" + String(context.name));
|
|
166
|
+
const derivationKey = /* @__PURE__ */ Symbol.for("__@tldraw/state__computed__" + String(context.name));
|
|
167
167
|
const fn = function() {
|
|
168
168
|
let d = this[derivationKey];
|
|
169
169
|
if (!d) {
|
|
@@ -196,7 +196,7 @@ function computedDecorator(options = {}, args) {
|
|
|
196
196
|
}
|
|
197
197
|
const isComputedMethodKey = "@@__isComputedMethod__@@";
|
|
198
198
|
function getComputedInstance(obj, propertyName) {
|
|
199
|
-
const key = Symbol.for("__@tldraw/state__computed__" + propertyName.toString());
|
|
199
|
+
const key = /* @__PURE__ */ Symbol.for("__@tldraw/state__computed__" + propertyName.toString());
|
|
200
200
|
let inst = obj[key];
|
|
201
201
|
if (!inst) {
|
|
202
202
|
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 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": "AACA,SAAS,cAAc;AACvB,SAAS,gBAAgB;AACzB,SAAS,
|
|
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": "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",
|
|
6
6
|
"names": ["isUninitialized"]
|
|
7
7
|
}
|
package/dist-esm/lib/helpers.mjs
CHANGED
|
@@ -35,7 +35,7 @@ function equals(a, b) {
|
|
|
35
35
|
return shallowEquals;
|
|
36
36
|
}
|
|
37
37
|
function singleton(key, init) {
|
|
38
|
-
const symbol = Symbol.for(`com.tldraw.state/${key}`);
|
|
38
|
+
const symbol = /* @__PURE__ */ Symbol.for(`com.tldraw.state/${key}`);
|
|
39
39
|
const global = globalThis;
|
|
40
40
|
global[symbol] ??= init();
|
|
41
41
|
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": "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,
|
|
5
|
+
"mappings": "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
|
}
|
package/dist-esm/lib/types.mjs
CHANGED
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/lib/types.ts"],
|
|
4
4
|
"sourcesContent": ["import { ArraySet } from './ArraySet'\n\n/**\n * A unique symbol used to indicate that a signal's value should be reset or that\n * there is insufficient history to compute diffs between epochs.\n *\n * This value is returned by {@link Signal.getDiffSince} when the requested epoch\n * is too far in the past and the diff sequence cannot be reconstructed.\n *\n * @example\n * ```ts\n * import { atom, getGlobalEpoch, RESET_VALUE } from '@tldraw/state'\n *\n * const count = atom('count', 0, { historyLength: 3 })\n * const oldEpoch = getGlobalEpoch()\n *\n * // Make many changes that exceed history length\n * count.set(1)\n * count.set(2)\n * count.set(3)\n * count.set(4)\n *\n * const diffs = count.getDiffSince(oldEpoch)\n * if (diffs === RESET_VALUE) {\n * console.log('Too many changes, need to reset state')\n * }\n * ```\n *\n * @public\n */\nexport const RESET_VALUE: unique symbol = Symbol.for('com.tldraw.state/RESET_VALUE')\n\n/**\n * Type representing the the unique symbol RESET_VALUE symbol, used in type annotations\n * to indicate when a signal value should be reset or when diff computation\n * cannot proceed due to insufficient history.\n *\n * @public\n */\nexport type RESET_VALUE = typeof RESET_VALUE\n\n/**\n * A reactive value container that can change over time and track diffs between sequential values.\n *\n * Signals are the foundation of the \\@tldraw/state reactive system. They automatically manage\n * dependencies and trigger updates when their values change. Any computed signal or effect\n * that reads from this signal will be automatically recomputed when the signal's value changes.\n *\n * There are two types of signal:\n * - **Atomic signals** - Created using `atom()`. These are mutable containers that can be\n * directly updated using `set()` or `update()` methods.\n * - **Computed signals** - Created using `computed()`. These derive their values from other\n * signals and are automatically recomputed when dependencies change.\n *\n * @example\n * ```ts\n * import { atom, computed } from '@tldraw/state'\n *\n * // Create an atomic signal\n * const count = atom('count', 0)\n *\n * // Create a computed signal that derives from the atom\n * const doubled = computed('doubled', () => count.get() * 2)\n *\n * console.log(doubled.get()) // 0\n * count.set(5)\n * console.log(doubled.get()) // 10\n * ```\n *\n * @public\n */\nexport interface Signal<Value, Diff = unknown> {\n\t/**\n\t * A human-readable identifier for this signal, used primarily for debugging and performance profiling.\n\t *\n\t * The name is displayed in debug output from {@link whyAmIRunning} and other diagnostic tools.\n\t * It does not need to be globally unique within your application.\n\t */\n\tname: string\n\t/**\n\t * Gets the current value of the signal and establishes a dependency relationship.\n\t *\n\t * When called from within a computed signal or effect, this signal will be automatically\n\t * tracked as a dependency. If this signal's value changes, any dependent computations\n\t * or effects will be marked for re-execution.\n\t *\n\t * @returns The current value stored in the signal\n\t */\n\tget(): Value\n\n\t/**\n\t * The global epoch number when this signal's value last changed.\n\t *\n\t * Note that this represents when the value actually changed, not when it was last computed.\n\t * A computed signal may recalculate and produce the same value without changing its epoch.\n\t * This is used internally for dependency tracking and history management.\n\t */\n\tlastChangedEpoch: number\n\t/**\n\t * Gets the sequence of diffs that occurred between a specific epoch and the current state.\n\t *\n\t * This method enables incremental synchronization by providing a list of changes that\n\t * have occurred since a specific point in time. If the requested epoch is too far in\n\t * the past or the signal doesn't have enough history, it returns the unique symbol RESET_VALUE\n\t * to indicate that a full state reset is required.\n\t *\n\t * @param epoch - The epoch timestamp to get diffs since\n\t * @returns An array of diff objects representing changes since the epoch, or the unique symbol RESET_VALUE if insufficient history is available\n\t */\n\tgetDiffSince(epoch: number): RESET_VALUE | Diff[]\n\t/**\n\t * Gets the current value of the signal without establishing a dependency relationship.\n\t *\n\t * This method bypasses the automatic dependency tracking system, making it useful for\n\t * performance-critical code paths where the overhead of dependency capture would be\n\t * problematic. Use with caution as it breaks the reactive guarantees of the system.\n\t *\n\t * **Warning**: This method should only be used when you're certain that you don't need\n\t * the calling context to react to changes in this signal.\n\t *\n\t * @param ignoreErrors - Whether to suppress errors during value retrieval (optional)\n\t * @returns The current value without establishing dependencies\n\t */\n\t__unsafe__getWithoutCapture(ignoreErrors?: boolean): Value\n\t/** @internal */\n\tchildren: ArraySet<Child>\n}\n\n/**\n * Internal interface representing a child node in the signal dependency graph.\n *\n * This interface is used internally by the reactive system to manage dependencies\n * between signals, computed values, and effects. Each child tracks its parent\n * signals and maintains state needed for efficient dependency graph traversal\n * and change propagation.\n *\n * @internal\n */\nexport interface Child {\n\t/**\n\t * The epoch when this child was last traversed during dependency graph updates.\n\t * Used to prevent redundant traversals during change propagation.\n\t */\n\tlastTraversedEpoch: number\n\n\t/**\n\t * Set of parent signals that this child depends on.\n\t * Used for efficient lookup and cleanup operations.\n\t */\n\treadonly parentSet: ArraySet<Signal<any, any>>\n\n\t/**\n\t * Array of parent signals that this child depends on.\n\t * Maintained in parallel with parentSet for ordered access.\n\t */\n\treadonly parents: Signal<any, any>[]\n\n\t/**\n\t * Array of epochs corresponding to each parent signal.\n\t * Used to detect which parents have changed since last computation.\n\t */\n\treadonly parentEpochs: number[]\n\n\t/**\n\t * Human-readable name for this child, used in debugging output.\n\t */\n\treadonly name: string\n\n\t/**\n\t * Whether this child is currently subscribed to change notifications.\n\t * Used to optimize resource usage by unsubscribing inactive dependencies.\n\t */\n\tisActivelyListening: boolean\n\n\t/**\n\t * Debug information tracking ancestor epochs in the dependency graph.\n\t * Only populated in debug builds for diagnostic purposes.\n\t */\n\t__debug_ancestor_epochs__: Map<Signal<any, any>, number> | null\n}\n\n/**\n * A function type that computes the difference between two values of a signal.\n *\n * This function is used to generate incremental diffs that can be applied to\n * reconstruct state changes over time. It's particularly useful for features\n * like undo/redo, synchronization, and change tracking.\n *\n * The function should analyze the previous and current values and return a\n * diff object that represents the change. If the diff cannot be computed\n * (e.g., the values are too different or incompatible), it should return\n * the unique symbol RESET_VALUE to indicate that a full state reset is required.\n *\n * @param previousValue - The previous value of the signal\n * @param currentValue - The current value of the signal\n * @param lastComputedEpoch - The epoch when the previous value was set\n * @param currentEpoch - The epoch when the current value was set\n * @returns A diff object representing the change, or the unique symbol RESET_VALUE if no diff can be computed\n *\n * @example\n * ```ts\n * import { atom, RESET_VALUE } from '@tldraw/state'\n *\n * // Simple numeric diff\n * const numberDiff: ComputeDiff<number, number> = (prev, curr) => curr - prev\n *\n * // Array diff with reset fallback\n * const arrayDiff: ComputeDiff<string[], { added: string[], removed: string[] }> = (prev, curr) => {\n * if (prev.length > 1000 || curr.length > 1000) {\n * return RESET_VALUE // Too complex, force reset\n * }\n * return {\n * added: curr.filter(item => !prev.includes(item)),\n * removed: prev.filter(item => !curr.includes(item))\n * }\n * }\n *\n * const count = atom('count', 0, { computeDiff: numberDiff })\n * ```\n *\n * @public\n */\nexport type ComputeDiff<Value, Diff> = (\n\tpreviousValue: Value,\n\tcurrentValue: Value,\n\tlastComputedEpoch: number,\n\tcurrentEpoch: number\n) => Diff | RESET_VALUE\n"],
|
|
5
|
-
"mappings": "AA8BO,MAAM,cAA6B,
|
|
5
|
+
"mappings": "AA8BO,MAAM,cAA6B,uBAAO,IAAI,8BAA8B;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tldraw/state",
|
|
3
3
|
"description": "tldraw infinite canvas SDK (state).",
|
|
4
|
-
"version": "4.6.0-canary.
|
|
4
|
+
"version": "4.6.0-canary.6fdc07d3e5f0",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "tldraw Inc.",
|
|
7
7
|
"email": "hello@tldraw.com"
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"prepack": "yarn run -T tsx ../../internal/scripts/prepack.ts",
|
|
41
41
|
"postpack": "../../internal/scripts/postpack.sh",
|
|
42
42
|
"pack-tarball": "yarn pack",
|
|
43
|
-
"lint": "
|
|
43
|
+
"lint": "yarn run -T tsx ../../internal/scripts/lint.ts"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@types/lodash": "^4.17.14",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"vitest": "^3.2.4"
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@tldraw/utils": "4.6.0-canary.
|
|
51
|
+
"@tldraw/utils": "4.6.0-canary.6fdc07d3e5f0"
|
|
52
52
|
},
|
|
53
53
|
"typedoc": {
|
|
54
54
|
"readmeFile": "none",
|
package/src/lib/Atom.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ArraySet } from './ArraySet'
|
|
2
|
-
import { HistoryBuffer } from './HistoryBuffer'
|
|
3
2
|
import { maybeCaptureParent } from './capture'
|
|
4
3
|
import { EMPTY_ARRAY, equals, singleton } from './helpers'
|
|
4
|
+
import { HistoryBuffer } from './HistoryBuffer'
|
|
5
5
|
import { advanceGlobalEpoch, atomDidChange, getGlobalEpoch } from './transactions'
|
|
6
6
|
import { Child, ComputeDiff, RESET_VALUE, Signal } from './types'
|
|
7
7
|
|
package/src/lib/Computed.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/* eslint-disable prefer-rest-params */
|
|
2
2
|
import { assert } from '@tldraw/utils'
|
|
3
3
|
import { ArraySet } from './ArraySet'
|
|
4
|
-
import { HistoryBuffer } from './HistoryBuffer'
|
|
5
4
|
import { maybeCaptureParent, startCapturingParents, stopCapturingParents } from './capture'
|
|
6
5
|
import { GLOBAL_START_EPOCH } from './constants'
|
|
7
6
|
import { EMPTY_ARRAY, equals, haveParentsChanged, singleton } from './helpers'
|
|
7
|
+
import { HistoryBuffer } from './HistoryBuffer'
|
|
8
8
|
import { getGlobalEpoch, getIsReacting, getReactionEpoch } from './transactions'
|
|
9
9
|
import { Child, ComputeDiff, RESET_VALUE, Signal } from './types'
|
|
10
10
|
import { logComputedGetterWarning } from './warnings'
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { ArraySet } from '../ArraySet'
|
|
2
2
|
import { atom } from '../Atom'
|
|
3
|
-
import { computed } from '../Computed'
|
|
4
|
-
import { react } from '../EffectScheduler'
|
|
5
3
|
import {
|
|
6
4
|
maybeCaptureParent,
|
|
7
5
|
startCapturingParents,
|
|
8
6
|
stopCapturingParents,
|
|
9
7
|
unsafe__withoutCapture,
|
|
10
8
|
} from '../capture'
|
|
9
|
+
import { computed } from '../Computed'
|
|
10
|
+
import { react } from '../EffectScheduler'
|
|
11
11
|
import { advanceGlobalEpoch, getGlobalEpoch } from '../transactions'
|
|
12
12
|
import { Child } from '../types'
|
|
13
13
|
|