UNPKG

@excalidraw/math

Version:

Excalidraw math functions

217 lines (216 loc) 10.2 kB
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<T> { readonly deleted: Partial<T>; readonly inserted: Partial<T>; private constructor(); static create<T>(deleted: Partial<T>, inserted: Partial<T>, modifier?: (delta: Partial<T>, partialType: "deleted" | "inserted") => Partial<T>, modifierOptions?: "deleted" | "inserted" | "both"): Delta<T>; /** * 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<T extends { [key: string]: any; }>(prevObject: T, nextObject: T, modifier?: (partial: Partial<T>) => Partial<T>, postProcess?: (deleted: Partial<T>, inserted: Partial<T>) => [Partial<T>, Partial<T>]): Delta<T>; static empty(): Delta<unknown>; static isEmpty<T>(delta: Delta<T>): boolean; /** * Merges deleted and inserted object partials. */ static mergeObjects<T extends { [key: string]: unknown; }>(prev: T, added: T, removed: T): T; /** * Merges deleted and inserted array partials. */ static mergeArrays<T>(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<T, K extends keyof T, V extends ValueOf<T[K]>>(deleted: Partial<T>, inserted: Partial<T>, property: K, setValue: (prevValue: V | undefined) => V): void; /** * Diff array partials as part of the `postProcess`. */ static diffArrays<T, K extends keyof T, V extends T[K]>(deleted: Partial<T>, inserted: Partial<T>, property: K, groupBy: (value: V extends ArrayLike<infer T> ? T : never) => string): void; /** * Compares if object1 contains any different value compared to the object2. */ static isLeftDifferent<T extends {}>(object1: T, object2: T, skipShallowCompare?: boolean): boolean; /** * Compares if object2 contains any different value compared to the object1. */ static isRightDifferent<T extends {}>(object1: T, object2: T, skipShallowCompare?: boolean): boolean; /** * Compares if shared properties of object1 and object2 contain any different value (aka inner join). */ static isInnerDifferent<T extends {}>(object1: T, object2: T, skipShallowCompare?: boolean): boolean; /** * Compares if any properties of object1 and object2 contain any different value (aka full join). */ static isDifferent<T extends {}>(object1: T, object2: T, skipShallowCompare?: boolean): boolean; /** * Returns sorted object1 keys that have distinct values. */ static getLeftDifferences<T extends {}>(object1: T, object2: T, skipShallowCompare?: boolean): string[]; /** * Returns sorted object2 keys that have distinct values. */ static getRightDifferences<T extends {}>(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<T extends {}>(object1: T, object2: T, skipShallowCompare?: boolean): string[]; /** * Returns sorted keys that have distinct values between object1 and object2 (aka full join). */ static getDifferences<T extends {}>(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<T> { /** * Inverses the `Delta`s while creating a new `DeltaContainer` instance. */ inverse(): DeltaContainer<T>; /** * 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]; /** * Checks whether all `Delta`s are empty. */ isEmpty(): boolean; } export declare class AppStateDelta implements DeltaContainer<AppState> { readonly delta: Delta<ObservedAppState>; private constructor(); static calculate<T extends ObservedAppState>(prevAppState: T, nextAppState: T): AppStateDelta; static restore(appStateDeltaDTO: DTO<AppStateDelta>): AppStateDelta; static empty(): AppStateDelta; inverse(): AppStateDelta; 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 convertToAppStateKey; 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<TElement extends ExcalidrawElement = ExcalidrawElement> = Omit<Partial<Ordered<TElement>>, "id" | "updated" | "seed">; export type ApplyToOptions = { excludedProperties: Set<keyof ElementPartial>; }; /** * 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<SceneElementsMap> { readonly added: Record<string, Delta<ElementPartial>>; readonly removed: Record<string, Delta<ElementPartial>>; readonly updated: Record<string, Delta<ElementPartial>>; private constructor(); static create(added: Record<string, Delta<ElementPartial>>, removed: Record<string, Delta<ElementPartial>>, updated: Record<string, Delta<ElementPartial>>, options?: { shouldRedistribute: boolean; }): ElementsDelta; static restore(elementsDeltaDTO: DTO<ElementsDelta>): ElementsDelta; private static satisfiesAddition; private static satisfiesRemoval; private static satisfiesUpdate; private static satisfiesCommmonInvariants; 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<T extends OrderedExcalidrawElement>(prevElements: Map<string, T>, nextElements: Map<string, T>): 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]; 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; 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 {};