import type { ExcalidrawElement, Ordered, OrderedExcalidrawElement, SceneElementsMap } from "@excalidraw/element/types"; import type { DTO, ValueOf } from "@excalidraw/common/utility-types"; import type { AppState, ObservedAppState } from "@excalidraw/excalidraw/types"; import { StoreSnapshot } from "./store"; /** * Represents the difference between two objects of the same type. * * Both `deleted` and `inserted` partials represent the same set of added, removed or updated properties, where: * - `deleted` is a set of all the deleted values * - `inserted` is a set of all the inserted (added, updated) values * * Keeping it as pure object (without transient state, side-effects, etc.), so we won't have to instantiate it on load. */ export declare class Delta { readonly deleted: Partial; readonly inserted: Partial; private constructor(); static create(deleted: Partial, inserted: Partial, modifier?: (delta: Partial, partialType: "deleted" | "inserted") => Partial, modifierOptions?: "deleted" | "inserted" | "both"): Delta; /** * Calculates the delta between two objects. * * @param prevObject - The previous state of the object. * @param nextObject - The next state of the object. * * @returns new delta instance. */ static calculate(prevObject: T, nextObject: T, modifier?: (partial: Partial) => Partial, postProcess?: (deleted: Partial, inserted: Partial) => [Partial, Partial]): Delta; static empty(): Delta; static isEmpty(delta: Delta): boolean; /** * Merges two deltas into a new one. */ static merge(delta1: Delta, delta2: Delta, delta3?: Delta): Delta; /** * Merges deleted and inserted object partials. */ static mergeObjects(prev: T, added: T, removed?: T): T; /** * Merges deleted and inserted array partials. */ static mergeArrays(prev: readonly T[] | null, added: readonly T[] | null | undefined, removed: readonly T[] | null | undefined, predicate?: (value: T) => string): T[]; /** * Diff object partials as part of the `postProcess`. */ static diffObjects>(deleted: Partial, inserted: Partial, property: K, setValue: (prevValue: V | undefined) => V): void; /** * Diff array partials as part of the `postProcess`. */ static diffArrays(deleted: Partial, inserted: Partial, property: K, groupBy: (value: V extends ArrayLike ? T : never) => string): void; /** * Compares if object1 contains any different value compared to the object2. */ static isLeftDifferent(object1: T, object2: T, skipShallowCompare?: boolean): boolean; /** * Compares if object2 contains any different value compared to the object1. */ static isRightDifferent(object1: T, object2: T, skipShallowCompare?: boolean): boolean; /** * Compares if shared properties of object1 and object2 contain any different value (aka inner join). */ static isInnerDifferent(object1: T, object2: T, skipShallowCompare?: boolean): boolean; /** * Compares if any properties of object1 and object2 contain any different value (aka full join). */ static isDifferent(object1: T, object2: T, skipShallowCompare?: boolean): boolean; /** * Returns sorted object1 keys that have distinct values. */ static getLeftDifferences(object1: T, object2: T, skipShallowCompare?: boolean): string[]; /** * Returns sorted object2 keys that have distinct values. */ static getRightDifferences(object1: T, object2: T, skipShallowCompare?: boolean): string[]; /** * Returns sorted keys of shared object1 and object2 properties that have distinct values (aka inner join). */ static getInnerDifferences(object1: T, object2: T, skipShallowCompare?: boolean): string[]; /** * Returns sorted keys that have distinct values between object1 and object2 (aka full join). */ static getDifferences(object1: T, object2: T, skipShallowCompare?: boolean): string[]; /** * Iterator comparing values of object properties based on the passed joining strategy. * * @yields keys of properties with different values * * WARN: it's based on shallow compare performed only on the first level and doesn't go deeper than that. */ private static distinctKeysIterator; } /** * Encapsulates a set of application-level `Delta`s. */ export interface DeltaContainer { /** * Inverses the `Delta`s while creating a new `DeltaContainer` instance. */ inverse(): DeltaContainer; /** * Applies the `Delta`s to the previous object. * * @returns a tuple of the next object `T` with applied `Delta`s, and `boolean`, indicating whether the applied deltas resulted in a visible change. */ applyTo(previous: T, ...options: unknown[]): [T, boolean]; /** * Squashes the current delta with the given one. */ squash(delta: DeltaContainer): this; /** * Checks whether all `Delta`s are empty. */ isEmpty(): boolean; } export declare class AppStateDelta implements DeltaContainer { delta: Delta; private constructor(); static create(delta: Delta): AppStateDelta; static calculate(prevAppState: T, nextAppState: T): AppStateDelta; static restore(appStateDeltaDTO: DTO): AppStateDelta; static empty(): AppStateDelta; inverse(): AppStateDelta; squash(delta: AppStateDelta): this; applyTo(appState: AppState, nextElements: SceneElementsMap): [AppState, boolean]; isEmpty(): boolean; /** * Mutates `nextAppState` be filtering out state related to deleted elements. * * @returns `true` if a visible change is found, `false` otherwise. */ private filterInvisibleChanges; private static filterSelectedElements; private static filterSelectedGroups; private static stripElementsProps; private static stripStandaloneProps; /** * It is necessary to post process the partials in case of reference values, * for which we need to calculate the real diff between `deleted` and `inserted`. */ private static postProcess; private static orderAppStateKeys; } type ElementPartial = Omit>, "id" | "updated" | "seed">; export type ApplyToOptions = { excludedProperties?: Set; }; /** * Elements change is a low level primitive to capture a change between two sets of elements. * It does so by encapsulating forward and backward `Delta`s, allowing to time-travel in both directions. */ export declare class ElementsDelta implements DeltaContainer { readonly added: Record>; readonly removed: Record>; readonly updated: Record>; private constructor(); static create(added: Record>, removed: Record>, updated: Record>, options?: { shouldRedistribute: boolean; }): ElementsDelta; static restore(elementsDeltaDTO: DTO): ElementsDelta; private static satisfiesAddition; private static satisfiesRemoval; private static satisfiesUpdate; private static satisfiesCommmonInvariants; private static satisfiesUniqueInvariants; private static validate; /** * Calculates the `Delta`s between the previous and next set of elements. * * @param prevElements - Map representing the previous state of elements. * @param nextElements - Map representing the next state of elements. * * @returns `ElementsDelta` instance representing the `Delta` changes between the two sets of elements. */ static calculate(prevElements: Map, nextElements: Map): ElementsDelta; static empty(): ElementsDelta; inverse(): ElementsDelta; isEmpty(): boolean; /** * Update delta/s based on the existing elements. * * @param nextElements current elements * @param modifierOptions defines which of the delta (`deleted` or `inserted`) will be updated * @returns new instance with modified delta/s */ applyLatestChanges(prevElements: SceneElementsMap, nextElements: SceneElementsMap, modifierOptions?: "deleted" | "inserted"): ElementsDelta; applyTo(elements: SceneElementsMap, snapshot?: StoreSnapshot["elements"], options?: ApplyToOptions): [SceneElementsMap, boolean]; squash(delta: ElementsDelta): this; private static createApplier; private static createGetter; private static applyDelta; /** * Check for visible changes regardless of whether they were removed, added or updated. */ private static checkForVisibleDifference; /** * Resolves conflicts for all previously added, removed and updated elements. * Updates the previous deltas with all the changes after conflict resolution. * * // TODO: revisit since some bound arrows seem to be often redrawn incorrectly * * @returns all elements affected by the conflict resolution */ private resolveConflicts; /** * Non deleted affected elements of removed elements (before and after applying delta), * should be unbound ~ bindings should not point from non deleted into the deleted element/s. */ private static unbindAffected; /** * Non deleted affected elements of added or updated element/s (before and after applying delta), * should be rebound (if possible) with the current element ~ bindings should be bidirectional. */ private static rebindAffected; static redrawElements(nextElements: SceneElementsMap, changedElements: Map): SceneElementsMap; private static redrawTextBoundingBoxes; private static redrawBoundArrows; private static reorderElements; /** * It is necessary to post process the partials in case of reference values, * for which we need to calculate the real diff between `deleted` and `inserted`. */ private static postProcess; private static stripIrrelevantProps; } export {};