{"version":3,"file":"ActiveSelection.min.mjs","sources":["../../../src/shapes/ActiveSelection.ts"],"sourcesContent":["import type { ControlRenderingStyleOverride } from '../controls/controlRendering';\nimport { classRegistry } from '../ClassRegistry';\nimport type { GroupProps } from './Group';\nimport { Group } from './Group';\nimport type { FabricObject } from './Object/FabricObject';\nimport {\n  LAYOUT_TYPE_ADDED,\n  LAYOUT_TYPE_REMOVED,\n} from '../LayoutManager/constants';\nimport type { TClassProperties } from '../typedefs';\nimport { log } from '../util/internals/console';\nimport { ActiveSelectionLayoutManager } from '../LayoutManager/ActiveSelectionLayoutManager';\n\nexport type MultiSelectionStacking = 'canvas-stacking' | 'selection-order';\n\nexport interface ActiveSelectionOptions extends GroupProps {\n  multiSelectionStacking: MultiSelectionStacking;\n}\n\nconst activeSelectionDefaultValues: Partial<TClassProperties<ActiveSelection>> =\n  {\n    multiSelectionStacking: 'canvas-stacking',\n    cornerStyle: 'circle',\n    cornerColor: 'white',\n    cornerStrokeColor: 'gray',\n    transparentCorners: false,\n  };\n\n/**\n * Used by Canvas to manage selection.\n *\n * @example\n * class MyActiveSelection extends ActiveSelection {\n *   ...\n * }\n *\n * // override the default `ActiveSelection` class\n * classRegistry.setClass(MyActiveSelection)\n */\nexport class ActiveSelection extends Group {\n  static type = 'ActiveSelection';\n\n  static ownDefaults: Record<string, any> = activeSelectionDefaultValues;\n\n  static getDefaults(): Record<string, any> {\n    return { ...super.getDefaults(), ...ActiveSelection.ownDefaults };\n  }\n\n  /**\n   * The ActiveSelection needs to use the ActiveSelectionLayoutManager\n   * or selections on interactive groups may be broken\n   */\n  declare layoutManager: ActiveSelectionLayoutManager;\n\n  /**\n   * controls how selected objects are added during a multiselection event\n   * - `canvas-stacking` adds the selected object to the active selection while respecting canvas object stacking order\n   * - `selection-order` adds the selected object to the top of the stack,\n   * meaning that the stack is ordered by the order in which objects were selected\n   * @default `canvas-stacking`\n   */\n  declare multiSelectionStacking: MultiSelectionStacking;\n\n  constructor(\n    objects: FabricObject[] = [],\n    options: Partial<ActiveSelectionOptions> = {}\n  ) {\n    super(objects, {\n      ...options,\n      layoutManager:\n        options.layoutManager ?? new ActiveSelectionLayoutManager(),\n    });\n  }\n\n  /**\n   * @private\n   */\n  _shouldSetNestedCoords() {\n    return true;\n  }\n\n  /**\n   * @private\n   * @override we don't want the selection monitor to be active\n   */\n  __objectSelectionMonitor() {\n    //  noop\n  }\n\n  /**\n   * Adds objects with respect to {@link multiSelectionStacking}\n   * @param targets object to add to selection\n   */\n  multiSelectAdd(...targets: FabricObject[]) {\n    if (this.multiSelectionStacking === 'selection-order') {\n      this.add(...targets);\n    } else {\n      //  respect object stacking as it is on canvas\n      //  perf enhancement for large ActiveSelection: consider a binary search of `isInFrontOf`\n      targets.forEach((target) => {\n        const index = this._objects.findIndex((obj) => obj.isInFrontOf(target));\n        const insertAt =\n          index === -1\n            ? //  `target` is in front of all other objects\n              this.size()\n            : index;\n        this.insertAt(insertAt, target);\n      });\n    }\n  }\n\n  /**\n   * @override block ancestors/descendants of selected objects from being selected to prevent a circular object tree\n   */\n  canEnterGroup(object: FabricObject) {\n    if (\n      this.getObjects().some(\n        (o) => o.isDescendantOf(object) || object.isDescendantOf(o)\n      )\n    ) {\n      //  prevent circular object tree\n      log(\n        'error',\n        'ActiveSelection: circular object trees are not supported, this call has no effect'\n      );\n      return false;\n    }\n\n    return super.canEnterGroup(object);\n  }\n\n  /**\n   * Change an object so that it can be part of an active selection.\n   * this method is called by multiselectAdd from canvas code.\n   * @private\n   * @param {FabricObject} object\n   * @param {boolean} [removeParentTransform] true if object is in canvas coordinate plane\n   */\n  enterGroup(object: FabricObject, removeParentTransform?: boolean) {\n    console.log('enterGroup');\n    // This condition check that the object has currently a group, and the group\n    // is also its parent, meaning that is not in an active selection, but is\n    // in a normal group.\n    if (object.parent && object.parent === object.group) {\n      // Disconnect the object from the group functionalities, but keep the ref parent intact\n      // for later re-enter\n      object.parent._exitGroup(object);\n      // in this case the object is probably inside an active selection.\n    } else if (object.group && object.parent !== object.group) {\n      // in this case group.remove will also clear the old parent reference.\n      object.group.remove(object);\n    }\n    // enter the active selection from a render perspective\n    // the object will be in the objects array of both the ActiveSelection and the Group\n    // but referenced in the group's _activeObjects so that it won't be rendered twice.\n    this._enterGroup(object, removeParentTransform);\n  }\n\n  /**\n   * we want objects to retain their canvas ref when exiting instance\n   * @private\n   * @param {FabricObject} object\n   * @param {boolean} [removeParentTransform] true if object should exit group without applying group's transform to it\n   */\n  exitGroup(object: FabricObject, removeParentTransform?: boolean) {\n    this._exitGroup(object, removeParentTransform);\n    // return to parent\n    object.parent && object.parent._enterGroup(object, true);\n  }\n\n  /**\n   * @private\n   * @param {'added'|'removed'} type\n   * @param {FabricObject[]} targets\n   */\n  _onAfterObjectsChange(type: 'added' | 'removed', targets: FabricObject[]) {\n    super._onAfterObjectsChange(type, targets);\n    const groups = new Set<Group>();\n    targets.forEach((object) => {\n      const { parent } = object;\n      parent && groups.add(parent);\n    });\n    if (type === LAYOUT_TYPE_REMOVED) {\n      //  invalidate groups' layout and mark as dirty\n      groups.forEach((group) => {\n        group._onAfterObjectsChange(LAYOUT_TYPE_ADDED, targets);\n      });\n    } else {\n      //  mark groups as dirty\n      groups.forEach((group) => {\n        group._set('dirty', true);\n      });\n    }\n  }\n\n  /**\n   * @override remove all objects\n   */\n  onDeselect() {\n    this.removeAll();\n    return false;\n  }\n\n  /**\n   * Returns string representation of a group\n   * @return {String}\n   */\n  toString() {\n    return `#<ActiveSelection: (${this.complexity()})>`;\n  }\n\n  /**\n   * Decide if the object should cache or not. Create its own cache level\n   * objectCaching is a global flag, wins over everything\n   * needsItsOwnCache should be used when the object drawing method requires\n   * a cache step. None of the fabric classes requires it.\n   * Generally you do not cache objects in groups because the group outside is cached.\n   * @return {Boolean}\n   */\n  shouldCache() {\n    return false;\n  }\n\n  /**\n   * Check if this group or its parent group are caching, recursively up\n   * @return {Boolean}\n   */\n  isOnACache() {\n    return false;\n  }\n\n  /**\n   * Renders controls and borders for the object\n   * @param {CanvasRenderingContext2D} ctx Context to render on\n   * @param {Object} [styleOverride] properties to override the object style\n   * @param {Object} [childrenOverride] properties to override the children overrides\n   */\n  _renderControls(\n    ctx: CanvasRenderingContext2D,\n    styleOverride?: ControlRenderingStyleOverride,\n    childrenOverride?: ControlRenderingStyleOverride\n  ) {\n    ctx.save();\n    ctx.globalAlpha = this.isMoving ? this.borderOpacityWhenMoving : 1;\n    super._renderControls(ctx, styleOverride);\n    const options = {\n      hasControls: false,\n      ...childrenOverride,\n      forActiveSelection: true,\n    };\n    for (let i = 0; i < this._objects.length; i++) {\n      this._objects[i]._renderControls(ctx, options);\n    }\n    ctx.restore();\n  }\n\n  //  override the default behavior of `getText` to return a concatenated string of all text objects\\\n  // canvasX custoom method\n  getText(): any {\n    if (this.getObjects().length > 1) {\n      const textsArray = this.getObjects().map((item) => item.getText());\n      return textsArray.join('/n').trim();\n    } else {\n      return '';\n    }\n  }\n}\n\nclassRegistry.setClass(ActiveSelection);\nclassRegistry.setClass(ActiveSelection, 'activeSelection');\n"],"names":["ActiveSelection","Group","getDefaults","_objectSpread","super","ownDefaults","constructor","_options$layoutManage","options","arguments","length","undefined","layoutManager","ActiveSelectionLayoutManager","_shouldSetNestedCoords","__objectSelectionMonitor","multiSelectAdd","_len","targets","Array","_key","this","multiSelectionStacking","add","forEach","target","index","_objects","findIndex","obj","isInFrontOf","insertAt","size","canEnterGroup","object","getObjects","some","o","isDescendantOf","log","enterGroup","removeParentTransform","console","parent","group","_exitGroup","remove","_enterGroup","exitGroup","_onAfterObjectsChange","type","groups","Set","LAYOUT_TYPE_REMOVED","LAYOUT_TYPE_ADDED","_set","onDeselect","removeAll","toString","concat","complexity","shouldCache","isOnACache","_renderControls","ctx","styleOverride","childrenOverride","save","globalAlpha","isMoving","borderOpacityWhenMoving","hasControls","forActiveSelection","i","restore","getText","map","item","join","trim","_defineProperty","cornerStyle","cornerColor","cornerStrokeColor","transparentCorners","classRegistry","setClass"],"mappings":"mcAuCO,MAAMA,UAAwBC,EAKnC,kBAAOC,GACL,OAAAC,EAAAA,EAAA,GAAYC,MAAMF,eAAkBF,EAAgBK,YACtD,CAiBAC,WAAAA,GAGE,IAAAC,EAAA,IADAC,EAAwCC,UAAAC,OAAA,QAAAC,IAAAF,UAAA,GAAAA,UAAA,GAAG,CAAA,EAE3CL,MAHuBK,UAAAC,OAAA,QAAAC,IAAAF,UAAA,GAAAA,UAAA,GAAG,GAGbN,EAAAA,KACRK,GAAO,GAAA,CACVI,cACuBL,QADVA,EACXC,EAAQI,qBAAaL,IAAAA,EAAAA,EAAI,IAAIM,IAEnC,CAKAC,sBAAAA,GACE,OAAO,CACT,CAMAC,wBAAAA,GACE,CAOFC,cAAAA,GAA2C,IAAA,IAAAC,EAAAR,UAAAC,OAAzBQ,EAAOC,IAAAA,MAAAF,GAAAG,EAAA,EAAAA,EAAAH,EAAAG,IAAPF,EAAOE,GAAAX,UAAAW,GACa,oBAAhCC,KAAKC,uBACPD,KAAKE,OAAOL,GAIZA,EAAQM,SAASC,IACf,MAAMC,EAAQL,KAAKM,SAASC,WAAWC,GAAQA,EAAIC,YAAYL,KACzDM,GACO,IAAXL,EAEIL,KAAKW,OACLN,EACNL,KAAKU,SAASA,EAAUN,EAAO,GAGrC,CAKAQ,aAAAA,CAAcC,GACZ,OACEb,KAAKc,aAAaC,MACfC,GAAMA,EAAEC,eAAeJ,IAAWA,EAAOI,eAAeD,MAI3DE,EACE,QACA,sFAEK,GAGFnC,MAAM6B,cAAcC,EAC7B,CASAM,UAAAA,CAAWN,EAAsBO,GAC/BC,QAAQH,IAAI,cAIRL,EAAOS,QAAUT,EAAOS,SAAWT,EAAOU,MAG5CV,EAAOS,OAAOE,WAAWX,GAEhBA,EAAOU,OAASV,EAAOS,SAAWT,EAAOU,OAElDV,EAAOU,MAAME,OAAOZ,GAKtBb,KAAK0B,YAAYb,EAAQO,EAC3B,CAQAO,SAAAA,CAAUd,EAAsBO,GAC9BpB,KAAKwB,WAAWX,EAAQO,GAExBP,EAAOS,QAAUT,EAAOS,OAAOI,YAAYb,GAAQ,EACrD,CAOAe,qBAAAA,CAAsBC,EAA2BhC,GAC/Cd,MAAM6C,sBAAsBC,EAAMhC,GAClC,MAAMiC,EAAS,IAAIC,IACnBlC,EAAQM,SAASU,IACf,MAAMS,OAAEA,GAAWT,EACnBS,GAAUQ,EAAO5B,IAAIoB,EAAO,IAE1BO,IAASG,EAEXF,EAAO3B,SAASoB,IACdA,EAAMK,sBAAsBK,EAAmBpC,EAAQ,IAIzDiC,EAAO3B,SAASoB,IACdA,EAAMW,KAAK,SAAS,EAAK,GAG/B,CAKAC,UAAAA,GAEE,OADAnC,KAAKoC,aACE,CACT,CAMAC,QAAAA,GACE,MAAA,uBAAAC,OAA8BtC,KAAKuC,aAAY,KACjD,CAUAC,WAAAA,GACE,OAAO,CACT,CAMAC,UAAAA,GACE,OAAO,CACT,CAQAC,eAAAA,CACEC,EACAC,EACAC,GAEAF,EAAIG,OACJH,EAAII,YAAc/C,KAAKgD,SAAWhD,KAAKiD,wBAA0B,EACjElE,MAAM2D,gBAAgBC,EAAKC,GAC3B,MAAMzD,EAAOL,EAAAA,EAAA,CACXoE,aAAa,GACVL,GAAgB,GAAA,CACnBM,oBAAoB,IAEtB,IAAK,IAAIC,EAAI,EAAGA,EAAIpD,KAAKM,SAASjB,OAAQ+D,IACxCpD,KAAKM,SAAS8C,GAAGV,gBAAgBC,EAAKxD,GAExCwD,EAAIU,SACN,CAIAC,OAAAA,GACE,GAAItD,KAAKc,aAAazB,OAAS,EAAG,CAEhC,OADmBW,KAAKc,aAAayC,KAAKC,GAASA,EAAKF,YACtCG,KAAK,MAAMC,MAC/B,CACE,MAAO,EAEX,EACDC,EAnOYhF,EAAe,OACZ,mBAAiBgF,EADpBhF,EAAe,cAnB1B,CACEsB,uBAAwB,kBACxB2D,YAAa,SACbC,YAAa,QACbC,kBAAmB,OACnBC,oBAAoB,IAmPxBC,EAAcC,SAAStF,GACvBqF,EAAcC,SAAStF,EAAiB"}