{"version":3,"file":"StackedObject.min.mjs","sources":["../../../../src/shapes/Object/StackedObject.ts"],"sourcesContent":["import type { ObjectEvents } from '../../EventTypeDefs';\nimport type { Group } from '../Group';\nimport type { Canvas } from '../../canvas/Canvas';\nimport type { StaticCanvas } from '../../canvas/StaticCanvas';\nimport { ObjectGeometry } from './ObjectGeometry';\n\ntype TAncestor = StackedObject | Canvas | StaticCanvas;\ntype TCollection = Group | Canvas | StaticCanvas;\n\n/**\n * Strict: only ancestors that are objects (without canvas)\n */\nexport type Ancestors<Strict> = Strict extends true\n  ? [StackedObject | Group] | [StackedObject | Group, ...Group[]] | Group[]\n  :\n      | [StackedObject | Group | Canvas | StaticCanvas]\n      | [StackedObject | Group, Canvas | StaticCanvas]\n      | [StackedObject, ...Group[]]\n      | Group[]\n      | [StackedObject | Group, ...Group[], Canvas | StaticCanvas];\n\nexport type AncestryComparison<Strict> = {\n  /**\n   * common ancestors of `this` and`other`(may include`this` | `other`)\n   */\n  common: Ancestors<Strict>;\n  /**\n   * ancestors that are of `this` only\n   */\n  fork: Ancestors<Strict>;\n  /**\n   * ancestors that are of `other` only\n   */\n  otherFork: Ancestors<Strict>;\n};\n\nexport class StackedObject<\n  EventSpec extends ObjectEvents = ObjectEvents\n> extends ObjectGeometry<EventSpec> {\n  /**\n   * A reference to the parent of the object\n   * Used to keep the original parent ref when the object has been added to an ActiveSelection, hence loosing the `group` ref\n   */\n  declare parent?: Group;\n\n  /**\n   * Checks if object is descendant of target\n   * Should be used instead of {@link Group.contains} or {@link StaticCanvas.contains} for performance reasons\n   * @param {TAncestor} target\n   * @returns {boolean}\n   */\n  isDescendantOf(target: TAncestor): boolean {\n    const { parent, group } = this;\n    return (\n      parent === target ||\n      group === target ||\n      this.canvas === target ||\n      // walk up\n      (!!parent && parent.isDescendantOf(target)) ||\n      (!!group && group !== parent && group.isDescendantOf(target))\n    );\n  }\n\n  /**\n   *\n   * @param {boolean} [strict] returns only ancestors that are objects (without canvas)\n   * @returns {Ancestors} ancestors (excluding `ActiveSelection`) from bottom to top\n   */\n  getAncestors<T extends boolean>(strict?: T): Ancestors<T> {\n    const ancestors: TAncestor[] = [];\n    // eslint-disable-next-line @typescript-eslint/no-this-alias\n    let parent: TAncestor | undefined = this;\n    do {\n      parent =\n        parent instanceof StackedObject\n          ? parent.parent ?? (!strict ? parent.canvas : undefined)\n          : undefined;\n      parent && ancestors.push(parent);\n    } while (parent);\n    return ancestors as Ancestors<T>;\n  }\n\n  /**\n   * Compare ancestors\n   *\n   * @param {StackedObject} other\n   * @param {boolean} [strict] finds only ancestors that are objects (without canvas)\n   * @returns {AncestryComparison} an object that represent the ancestry situation.\n   */\n  findCommonAncestors<T extends this, S extends boolean>(\n    other: T,\n    strict?: S\n  ): AncestryComparison<S> {\n    if (this === other) {\n      return {\n        fork: [],\n        otherFork: [],\n        common: [this, ...this.getAncestors(strict)],\n      } as AncestryComparison<S>;\n    }\n    const ancestors = this.getAncestors(strict);\n    const otherAncestors = other.getAncestors(strict);\n    //  if `this` has no ancestors and `this` is top ancestor of `other` we must handle the following case\n    if (\n      ancestors.length === 0 &&\n      otherAncestors.length > 0 &&\n      this === otherAncestors[otherAncestors.length - 1]\n    ) {\n      return {\n        fork: [],\n        otherFork: [\n          other,\n          ...otherAncestors.slice(0, otherAncestors.length - 1),\n        ],\n        common: [this],\n      } as AncestryComparison<S>;\n    }\n    //  compare ancestors\n    for (let i = 0, ancestor; i < ancestors.length; i++) {\n      ancestor = ancestors[i];\n      if (ancestor === other) {\n        return {\n          fork: [this, ...ancestors.slice(0, i)],\n          otherFork: [],\n          common: ancestors.slice(i),\n        } as AncestryComparison<S>;\n      }\n      for (let j = 0; j < otherAncestors.length; j++) {\n        if (this === otherAncestors[j]) {\n          return {\n            fork: [],\n            otherFork: [other, ...otherAncestors.slice(0, j)],\n            common: [this, ...ancestors],\n          } as AncestryComparison<S>;\n        }\n        if (ancestor === otherAncestors[j]) {\n          return {\n            fork: [this, ...ancestors.slice(0, i)],\n            otherFork: [other, ...otherAncestors.slice(0, j)],\n            common: ancestors.slice(i),\n          } as AncestryComparison<S>;\n        }\n      }\n    }\n    // nothing shared\n    return {\n      fork: [this, ...ancestors],\n      otherFork: [other, ...otherAncestors],\n      common: [],\n    } as AncestryComparison<S>;\n  }\n\n  /**\n   *\n   * @param {StackedObject} other\n   * @param {boolean} [strict] checks only ancestors that are objects (without canvas)\n   * @returns {boolean}\n   */\n  hasCommonAncestors<T extends this>(other: T, strict?: boolean): boolean {\n    const commonAncestors = this.findCommonAncestors(other, strict);\n    return commonAncestors && !!commonAncestors.common.length;\n  }\n\n  /**\n   *\n   * @param {FabricObject} other object to compare against\n   * @returns {boolean | undefined} if objects do not share a common ancestor or they are strictly equal it is impossible to determine which is in front of the other; in such cases the function returns `undefined`\n   */\n  isInFrontOf<T extends this>(other: T): boolean | undefined {\n    if (this === other) {\n      return undefined;\n    }\n    const ancestorData = this.findCommonAncestors(other);\n    if (!ancestorData) {\n      return undefined;\n    }\n    if (ancestorData.fork.includes(other as any)) {\n      return true;\n    }\n    if (ancestorData.otherFork.includes(this as any)) {\n      return false;\n    }\n    const firstCommonAncestor = ancestorData.common[0];\n    if (!firstCommonAncestor) {\n      return undefined;\n    }\n    const headOfFork = ancestorData.fork.pop(),\n      headOfOtherFork = ancestorData.otherFork.pop(),\n      thisIndex = (firstCommonAncestor as TCollection)._objects.indexOf(\n        headOfFork as any\n      ),\n      otherIndex = (firstCommonAncestor as TCollection)._objects.indexOf(\n        headOfOtherFork as any\n      );\n    return thisIndex > -1 && thisIndex > otherIndex;\n  }\n}\n"],"names":["StackedObject","ObjectGeometry","isDescendantOf","target","parent","group","this","canvas","getAncestors","strict","ancestors","_parent$parent","undefined","push","findCommonAncestors","other","fork","otherFork","common","otherAncestors","length","slice","ancestor","i","j","hasCommonAncestors","commonAncestors","isInFrontOf","ancestorData","includes","firstCommonAncestor","headOfFork","pop","headOfOtherFork","thisIndex","_objects","indexOf","otherIndex"],"mappings":"0DAoCO,MAAMA,UAEHC,EAaRC,cAAAA,CAAeC,GACb,MAAMC,OAAEA,EAAMC,MAAEA,GAAUC,KAC1B,OACEF,IAAWD,GACXE,IAAUF,GACVG,KAAKC,SAAWJ,KAEbC,GAAUA,EAAOF,eAAeC,MAChCE,GAASA,IAAUD,GAAUC,EAAMH,eAAeC,EAEzD,CAOAK,YAAAA,CAAgCC,GAC9B,MAAMC,EAAyB,GAE/B,IAAIN,EAAgCE,KACpC,EAAG,CAAA,IAAAK,EACDP,EACEA,aAAkBJ,EACDW,QADcA,EAC3BP,EAAOA,kBAAMO,EAAAA,EAAMF,OAAyBG,EAAhBR,EAAOG,YACnCK,EACNR,GAAUM,EAAUG,KAAKT,EAC1B,OAAQA,GACT,OAAOM,CACT,CASAI,mBAAAA,CACEC,EACAN,GAEA,GAAIH,OAASS,EACX,MAAO,CACLC,KAAM,GACNC,UAAW,GACXC,OAAQ,CAACZ,QAASA,KAAKE,aAAaC,KAGxC,MAAMC,EAAYJ,KAAKE,aAAaC,GAC9BU,EAAiBJ,EAAMP,aAAaC,GAE1C,GACuB,IAArBC,EAAUU,QACVD,EAAeC,OAAS,GACxBd,OAASa,EAAeA,EAAeC,OAAS,GAEhD,MAAO,CACLJ,KAAM,GACNC,UAAW,CACTF,KACGI,EAAeE,MAAM,EAAGF,EAAeC,OAAS,IAErDF,OAAQ,CAACZ,OAIb,IAAK,IAAWgB,EAAPC,EAAI,EAAaA,EAAIb,EAAUU,OAAQG,IAAK,CAEnD,GADAD,EAAWZ,EAAUa,GACjBD,IAAaP,EACf,MAAO,CACLC,KAAM,CAACV,QAASI,EAAUW,MAAM,EAAGE,IACnCN,UAAW,GACXC,OAAQR,EAAUW,MAAME,IAG5B,IAAK,IAAIC,EAAI,EAAGA,EAAIL,EAAeC,OAAQI,IAAK,CAC9C,GAAIlB,OAASa,EAAeK,GAC1B,MAAO,CACLR,KAAM,GACNC,UAAW,CAACF,KAAUI,EAAeE,MAAM,EAAGG,IAC9CN,OAAQ,CAACZ,QAASI,IAGtB,GAAIY,IAAaH,EAAeK,GAC9B,MAAO,CACLR,KAAM,CAACV,QAASI,EAAUW,MAAM,EAAGE,IACnCN,UAAW,CAACF,KAAUI,EAAeE,MAAM,EAAGG,IAC9CN,OAAQR,EAAUW,MAAME,GAG9B,CACF,CAEA,MAAO,CACLP,KAAM,CAACV,QAASI,GAChBO,UAAW,CAACF,KAAUI,GACtBD,OAAQ,GAEZ,CAQAO,kBAAAA,CAAmCV,EAAUN,GAC3C,MAAMiB,EAAkBpB,KAAKQ,oBAAoBC,EAAON,GACxD,OAAOiB,KAAqBA,EAAgBR,OAAOE,MACrD,CAOAO,WAAAA,CAA4BZ,GAC1B,GAAIT,OAASS,EACX,OAEF,MAAMa,EAAetB,KAAKQ,oBAAoBC,GAC9C,IAAKa,EACH,OAEF,GAAIA,EAAaZ,KAAKa,SAASd,GAC7B,OAAO,EAET,GAAIa,EAAaX,UAAUY,SAASvB,MAClC,OAAO,EAET,MAAMwB,EAAsBF,EAAaV,OAAO,GAChD,IAAKY,EACH,OAEF,MAAMC,EAAaH,EAAaZ,KAAKgB,MACnCC,EAAkBL,EAAaX,UAAUe,MACzCE,EAAaJ,EAAoCK,SAASC,QACxDL,GAEFM,EAAcP,EAAoCK,SAASC,QACzDH,GAEJ,OAAOC,GAAa,GAAKA,EAAYG,CACvC"}