tldraw/packages/state/api-report.md
David Sheldrick b133c59391
Use a global singleton for tlstate (#2322)
One minor issue with signia is that it uses global state for
bookkeeping, so it is potentially disastrous if there is more than one
version of it included in a bundle.

To prevent that being an issue before we had a warning that would
trigger if signia detects multiple initializations.

> Multiple versions of @tldraw/state detected. This will cause
unexpected behavior. Please add "resolutions" (yarn/pnpm) or "overrides"
(npm) in your package.json to ensure only one version of @tldraw/state
is loaded.

Alas I think this warning triggers too often in development
environments, e.g. during HMR or janky bundlers.


Something that can prevent the need for this particular warning is
having a global singleton version of signia that we only instantiate
once, and then re-use that one on subsequent module initializations. We
didn't do this before because it has a few downsides:

- breaks HMR if you are working on signia itself, since updated modules
won't be used and you'll need to do a full refresh.
- introduces the possibility of breakage if we remove or even add APIs
to signia. We can't rely on having the latest version of signia be the
first to instantiate, and we can't allow later instantiations to take
precedence since atoms n stuff may have already been created with the
prior version. To mitigate this I've introduced a `apiVersion` const
that we can increment when we make any kind of additions or removals. If
there is a mismatch between the `apiVersion` in the global singleton vs
the currently-initializing module, then it throws.

Ultimately i think the pros outweigh the cons here, i.e. far fewer
people will see and have to deal with the error message shown above, and
fewer people should encounter a situation where the editor appears to
load but nothing changes when you interact with it.


### Change Type

- [x] `patch` — Bug fix

[^1]: publishes a `patch` release, for devDependencies use `internal`
[^2]: will not publish a new version

### Release Notes

- Make a global singleton for tlstate.
2023-12-14 13:35:34 +00:00

7.3 KiB

API Report File for "@tldraw/state"

Do not edit this file. It is a report generated by API Extractor.


import { FunctionComponent } from 'react';
import { default as React_2 } from 'react';

// @public
export interface Atom<Value, Diff = unknown> extends Signal<Value, Diff> {
    set(value: Value, diff?: Diff): Value;
    update(updater: (value: Value) => Value): Value;
}

// @public
export const
/**
* Creates a new [[Atom]].
*
* An Atom is a signal that can be updated directly by calling [[Atom.set]] or [[Atom.update]].
*
* @example
* ```ts
* const name = atom('name', 'John')
*
* name.get() // 'John'
*
* name.set('Jane')
*
* name.get() // 'Jane'
* ```
*
* @public
*/
atom: typeof atom_2;

// @public
export interface AtomOptions<Value, Diff> {
    computeDiff?: ComputeDiff<Value, Diff>;
    historyLength?: number;
    isEqual?: (a: any, b: any) => boolean;
}

// @public
export interface Computed<Value, Diff = unknown> extends Signal<Value, Diff> {
    readonly isActivelyListening: boolean;
    // @internal (undocumented)
    readonly parentEpochs: number[];
    // @internal (undocumented)
    readonly parents: Signal<any, any>[];
}

// @public
export const
/**
* Creates a new [[Atom]].
*
* An Atom is a signal that can be updated directly by calling [[Atom.set]] or [[Atom.update]].
*
* @example
* ```ts
* const name = atom('name', 'John')
*
* name.get() // 'John'
*
* name.set('Jane')
*
* name.get() // 'Jane'
* ```
*
* @public
*/
computed: typeof computed_2;

// @public
export interface ComputedOptions<Value, Diff> {
    computeDiff?: ComputeDiff<Value, Diff>;
    historyLength?: number;
    isEqual?: (a: any, b: any) => boolean;
}

// @public
export const
/**
* Creates a new [[Atom]].
*
* An Atom is a signal that can be updated directly by calling [[Atom.set]] or [[Atom.update]].
*
* @example
* ```ts
* const name = atom('name', 'John')
*
* name.get() // 'John'
*
* name.set('Jane')
*
* name.get() // 'Jane'
* ```
*
* @public
*/
EffectScheduler: typeof EffectScheduler_2;

// @public (undocumented)
export const
/**
* Creates a new [[Atom]].
*
* An Atom is a signal that can be updated directly by calling [[Atom.set]] or [[Atom.update]].
*
* @example
* ```ts
* const name = atom('name', 'John')
*
* name.get() // 'John'
*
* name.set('Jane')
*
* name.get() // 'Jane'
* ```
*
* @public
*/
EMPTY_ARRAY: [];

// @public
export function getComputedInstance<Obj extends object, Prop extends keyof Obj>(obj: Obj, propertyName: Prop): Computed<Obj[Prop]>;

// @public
export const
/**
* Creates a new [[Atom]].
*
* An Atom is a signal that can be updated directly by calling [[Atom.set]] or [[Atom.update]].
*
* @example
* ```ts
* const name = atom('name', 'John')
*
* name.get() // 'John'
*
* name.set('Jane')
*
* name.get() // 'Jane'
* ```
*
* @public
*/
isAtom: typeof isAtom_2;

// @public
export const
/**
* Creates a new [[Atom]].
*
* An Atom is a signal that can be updated directly by calling [[Atom.set]] or [[Atom.update]].
*
* @example
* ```ts
* const name = atom('name', 'John')
*
* name.get() // 'John'
*
* name.set('Jane')
*
* name.get() // 'Jane'
* ```
*
* @public
*/
isSignal: typeof isSignal_2;

// @public
export const isUninitialized: (value: any) => value is typeof UNINITIALIZED;

// @public
export const
/**
* Creates a new [[Atom]].
*
* An Atom is a signal that can be updated directly by calling [[Atom.set]] or [[Atom.update]].
*
* @example
* ```ts
* const name = atom('name', 'John')
*
* name.get() // 'John'
*
* name.set('Jane')
*
* name.get() // 'Jane'
* ```
*
* @public
*/
react: typeof react_2;

// @public
export interface Reactor<T = unknown> {
    scheduler: EffectScheduler_2<T>;
    start(options?: {
        force?: boolean;
    }): void;
    stop(): void;
}

// @public
export const
/**
* Creates a new [[Atom]].
*
* An Atom is a signal that can be updated directly by calling [[Atom.set]] or [[Atom.update]].
*
* @example
* ```ts
* const name = atom('name', 'John')
*
* name.get() // 'John'
*
* name.set('Jane')
*
* name.get() // 'Jane'
* ```
*
* @public
*/
reactor: typeof reactor_2;

// @public (undocumented)
export const RESET_VALUE: unique symbol;

// @public (undocumented)
export type RESET_VALUE = typeof RESET_VALUE;

// @public
export interface Signal<Value, Diff = unknown> {
    __unsafe__getWithoutCapture(): Value;
    // @internal (undocumented)
    children: ArraySet<Child>;
    get(): Value;
    getDiffSince(epoch: number): Diff[] | RESET_VALUE;
    lastChangedEpoch: number;
    name: string;
    // @deprecated (undocumented)
    value: Value;
}

// @public
export function track<T extends FunctionComponent<any>>(baseComponent: T): T extends React_2.MemoExoticComponent<any> ? T : React_2.MemoExoticComponent<T>;

// @public
export const
/**
* Creates a new [[Atom]].
*
* An Atom is a signal that can be updated directly by calling [[Atom.set]] or [[Atom.update]].
*
* @example
* ```ts
* const name = atom('name', 'John')
*
* name.get() // 'John'
*
* name.set('Jane')
*
* name.get() // 'Jane'
* ```
*
* @public
*/
transact: typeof transact_2;

// @public
export const
/**
* Creates a new [[Atom]].
*
* An Atom is a signal that can be updated directly by calling [[Atom.set]] or [[Atom.update]].
*
* @example
* ```ts
* const name = atom('name', 'John')
*
* name.get() // 'John'
*
* name.set('Jane')
*
* name.get() // 'Jane'
* ```
*
* @public
*/
transaction: typeof transaction_2;

// @public
export const
/**
* Creates a new [[Atom]].
*
* An Atom is a signal that can be updated directly by calling [[Atom.set]] or [[Atom.update]].
*
* @example
* ```ts
* const name = atom('name', 'John')
*
* name.get() // 'John'
*
* name.set('Jane')
*
* name.get() // 'Jane'
* ```
*
* @public
*/
unsafe__withoutCapture: typeof unsafe__withoutCapture_2;

// @public
export function useAtom<Value, Diff = unknown>(
name: string,
valueOrInitialiser: (() => Value) | Value,
options?: AtomOptions<Value, Diff>): Atom<Value, Diff>;

// @public
export function useComputed<Value>(name: string, compute: () => Value, deps: any[]): Computed<Value>;

// @public (undocumented)
export function useComputed<Value, Diff = unknown>(name: string, compute: () => Value, opts: ComputedOptions<Value, Diff>, deps: any[]): Computed<Value>;

// @public (undocumented)
export function useQuickReactor(name: string, reactFn: () => void, deps?: any[]): void;

// @public (undocumented)
export function useReactor(name: string, reactFn: () => void, deps?: any[] | undefined): void;

// @internal (undocumented)
export function useStateTracking<T>(name: string, render: () => T): T;

// @public
export function useValue<Value>(value: Signal<Value>): Value;

// @public (undocumented)
export function useValue<Value>(name: string, fn: () => Value, deps: unknown[]): Value;

// @public
export const
/**
* Creates a new [[Atom]].
*
* An Atom is a signal that can be updated directly by calling [[Atom.set]] or [[Atom.update]].
*
* @example
* ```ts
* const name = atom('name', 'John')
*
* name.get() // 'John'
*
* name.set('Jane')
*
* name.get() // 'Jane'
* ```
*
* @public
*/
whyAmIRunning: typeof whyAmIRunning_2;

// @public
export const
/**
* Creates a new [[Atom]].
*
* An Atom is a signal that can be updated directly by calling [[Atom.set]] or [[Atom.update]].
*
* @example
* ```ts
* const name = atom('name', 'John')
*
* name.get() // 'John'
*
* name.set('Jane')
*
* name.get() // 'Jane'
* ```
*
* @public
*/
withDiff: typeof withDiff_2;

// (No @packageDocumentation comment for this package)