{"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';\nimport type { FabricObject } from './FabricObject';\n\ntype TAncestor = StackedObject | Canvas | StaticCanvas;\ntype TCollection = Group | Canvas | StaticCanvas;\n\nexport type Ancestors =\n  | [StackedObject | Group]\n  | [StackedObject | Group, ...Group[]]\n  | Group[];\n\nexport type AncestryComparison = {\n  /**\n   * common ancestors of `this` and`other`(may include`this` | `other`)\n   */\n  common: Ancestors;\n  /**\n   * ancestors that are of `this` only\n   */\n  fork: Ancestors;\n  /**\n   * ancestors that are of `other` only\n   */\n  otherFork: Ancestors;\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   * @returns {Ancestors} ancestors (excluding `ActiveSelection`) from bottom to top\n   */\n  getAncestors(): Ancestors {\n    const ancestors: TAncestor[] = [];\n    // eslint-disable-next-line @typescript-eslint/no-this-alias\n    let parent: TAncestor | undefined = this;\n    do {\n      parent = parent instanceof StackedObject ? parent.parent : undefined;\n      parent && ancestors.push(parent);\n    } while (parent);\n    return ancestors as Ancestors;\n  }\n\n  /**\n   * Compare ancestors\n   *\n   * @param {StackedObject} other\n   * @returns {AncestryComparison} an object that represent the ancestry situation.\n   */\n  findCommonAncestors<T extends this>(other: T): AncestryComparison {\n    if (this === other) {\n      return {\n        fork: [],\n        otherFork: [],\n        common: [this, ...this.getAncestors()],\n      } as AncestryComparison;\n    }\n    const ancestors = this.getAncestors();\n    const otherAncestors = other.getAncestors();\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;\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;\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;\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;\n        }\n      }\n    }\n    // nothing shared\n    return {\n      fork: [this, ...ancestors],\n      otherFork: [other, ...otherAncestors],\n      common: [],\n    } as AncestryComparison;\n  }\n\n  /**\n   *\n   * @param {StackedObject} other\n   * @returns {boolean}\n   */\n  hasCommonAncestors<T extends this>(other: T): boolean {\n    const commonAncestors = this.findCommonAncestors(other);\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\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    // if there isn't a common ancestor, we take the canvas.\n    // if there is no canvas, there is nothing to compare\n    const firstCommonAncestor = ancestorData.common[0] || this.canvas;\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","ancestors","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":"0DA8BO,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,CAKAK,YAAAA,GACE,MAAMC,EAAyB,GAE/B,IAAIL,EAAgCE,KACpC,GACEF,EAASA,aAAkBJ,EAAgBI,EAAOA,YAASM,EAC3DN,GAAUK,EAAUE,KAAKP,SAClBA,GACT,OAAOK,CACT,CAQAG,mBAAAA,CAAoCC,GAClC,GAAIP,OAASO,EACX,MAAO,CACLC,KAAM,GACNC,UAAW,GACXC,OAAQ,CAACV,QAASA,KAAKE,iBAG3B,MAAMC,EAAYH,KAAKE,eACjBS,EAAiBJ,EAAML,eAE7B,GACuB,IAArBC,EAAUS,QACVD,EAAeC,OAAS,GACxBZ,OAASW,EAAeA,EAAeC,OAAS,GAEhD,MAAO,CACLJ,KAAM,GACNC,UAAW,CACTF,KACGI,EAAeE,MAAM,EAAGF,EAAeC,OAAS,IAErDF,OAAQ,CAACV,OAIb,IAAK,IAAWc,EAAPC,EAAI,EAAaA,EAAIZ,EAAUS,OAAQG,IAAK,CAEnD,GADAD,EAAWX,EAAUY,GACjBD,IAAaP,EACf,MAAO,CACLC,KAAM,CAACR,QAASG,EAAUU,MAAM,EAAGE,IACnCN,UAAW,GACXC,OAAQP,EAAUU,MAAME,IAG5B,IAAK,IAAIC,EAAI,EAAGA,EAAIL,EAAeC,OAAQI,IAAK,CAC9C,GAAIhB,OAASW,EAAeK,GAC1B,MAAO,CACLR,KAAM,GACNC,UAAW,CAACF,KAAUI,EAAeE,MAAM,EAAGG,IAC9CN,OAAQ,CAACV,QAASG,IAGtB,GAAIW,IAAaH,EAAeK,GAC9B,MAAO,CACLR,KAAM,CAACR,QAASG,EAAUU,MAAM,EAAGE,IACnCN,UAAW,CAACF,KAAUI,EAAeE,MAAM,EAAGG,IAC9CN,OAAQP,EAAUU,MAAME,GAG9B,CACF,CAEA,MAAO,CACLP,KAAM,CAACR,QAASG,GAChBM,UAAW,CAACF,KAAUI,GACtBD,OAAQ,GAEZ,CAOAO,kBAAAA,CAAmCV,GACjC,MAAMW,EAAkBlB,KAAKM,oBAAoBC,GACjD,OAAOW,KAAqBA,EAAgBR,OAAOE,MACrD,CAOAO,WAAAA,CAA4BZ,GAC1B,GAAIP,OAASO,EACX,OAEF,MAAMa,EAAepB,KAAKM,oBAAoBC,GAE9C,GAAIa,EAAaZ,KAAKa,SAASd,GAC7B,OAAO,EAET,GAAIa,EAAaX,UAAUY,SAASrB,MAClC,OAAO,EAIT,MAAMsB,EAAsBF,EAAaV,OAAO,IAAMV,KAAKC,OAC3D,IAAKqB,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"}