{
  "version": 3,
  "sources": ["../../../../src/lib/tools/SelectTool/GestureShapeChangeTracker.ts"],
  "sourcesContent": ["import { Editor, TLShapeId } from '@tldraw/editor'\n\n/**\n * Tracks changes made to a gesture's shapes from outside the gesture itself.\n *\n * Snapshot-based gestures (translate, resize, rotate) recompute their shapes'\n * positions from a snapshot taken at the start of the gesture, recomputed every\n * frame as `snapshot + gesture delta`. That math reads nothing live, so a change\n * made to those shapes by something other than the gesture mid-interaction (e.g.\n * a `rotateShapesBy` or `nudgeShapes` keyboard shortcut) is stomped by the next\n * frame.\n *\n * This tracker lets a gesture notice such a change cheaply so it can re-anchor\n * its snapshot onto the current shapes:\n *\n * - wrap the gesture's own writes in {@link GestureShapeChangeTracker.ignoreChanges}\n *   so they aren't mistaken for external changes; each resulting shape-change\n *   callback exits in O(1) before the tracked-ID lookup,\n * - check {@link GestureShapeChangeTracker.getAndClearChanged} at the top of each\n *   update; when it returns true, the gesture re-anchors its snapshot.\n *\n * @internal\n */\nexport class GestureShapeChangeTracker {\n\tprivate isApplyingOwnChange = false\n\tprivate changed = false\n\tprivate dispose?: () => void\n\tprivate trackedShapeIds = new Set<TLShapeId>()\n\n\tconstructor(private readonly editor: Editor) {}\n\n\tstart(shapeIds: Iterable<TLShapeId>) {\n\t\tthis.changed = false\n\t\tthis.setTrackedShapeIds(shapeIds)\n\t\tthis.dispose = this.editor.sideEffects.registerAfterChangeHandler('shape', (_prev, next) => {\n\t\t\t// Our own writes are wrapped in `ignoreChanges`, so anything that lands\n\t\t\t// while that flag is set is the gesture moving its shapes.\n\t\t\tif (this.isApplyingOwnChange || this.changed) return\n\t\t\tif (this.trackedShapeIds.has(next.id)) this.changed = true\n\t\t})\n\t}\n\n\tstop() {\n\t\tthis.dispose?.()\n\t\tthis.dispose = undefined\n\t\tthis.trackedShapeIds.clear()\n\t}\n\n\tsetTrackedShapeIds(shapeIds: Iterable<TLShapeId>) {\n\t\tthis.trackedShapeIds.clear()\n\t\tfor (const id of shapeIds) this.trackedShapeIds.add(id)\n\t}\n\n\t/** Forget any pending external change, e.g. after bailing to a mark. */\n\tclear() {\n\t\tthis.changed = false\n\t}\n\n\t/** Returns whether an external change has happened since the last call, and resets the flag. */\n\tgetAndClearChanged() {\n\t\tconst { changed } = this\n\t\tthis.changed = false\n\t\treturn changed\n\t}\n\n\t/** Run the gesture's own writes so the tracker doesn't treat them as external. */\n\tignoreChanges<T>(fn: () => T): T {\n\t\tconst wasApplyingOwnChange = this.isApplyingOwnChange\n\t\tthis.isApplyingOwnChange = true\n\t\ttry {\n\t\t\treturn fn()\n\t\t} finally {\n\t\t\tthis.isApplyingOwnChange = wasApplyingOwnChange\n\t\t}\n\t}\n}\n"],
  "mappings": "AAuBO,MAAM,0BAA0B;AAAA,EAMtC,YAA6B,QAAgB;AAAhB;AAAA,EAAiB;AAAA,EAAjB;AAAA,EALrB,sBAAsB;AAAA,EACtB,UAAU;AAAA,EACV;AAAA,EACA,kBAAkB,oBAAI,IAAe;AAAA,EAI7C,MAAM,UAA+B;AACpC,SAAK,UAAU;AACf,SAAK,mBAAmB,QAAQ;AAChC,SAAK,UAAU,KAAK,OAAO,YAAY,2BAA2B,SAAS,CAAC,OAAO,SAAS;AAG3F,UAAI,KAAK,uBAAuB,KAAK,QAAS;AAC9C,UAAI,KAAK,gBAAgB,IAAI,KAAK,EAAE,EAAG,MAAK,UAAU;AAAA,IACvD,CAAC;AAAA,EACF;AAAA,EAEA,OAAO;AACN,SAAK,UAAU;AACf,SAAK,UAAU;AACf,SAAK,gBAAgB,MAAM;AAAA,EAC5B;AAAA,EAEA,mBAAmB,UAA+B;AACjD,SAAK,gBAAgB,MAAM;AAC3B,eAAW,MAAM,SAAU,MAAK,gBAAgB,IAAI,EAAE;AAAA,EACvD;AAAA;AAAA,EAGA,QAAQ;AACP,SAAK,UAAU;AAAA,EAChB;AAAA;AAAA,EAGA,qBAAqB;AACpB,UAAM,EAAE,QAAQ,IAAI;AACpB,SAAK,UAAU;AACf,WAAO;AAAA,EACR;AAAA;AAAA,EAGA,cAAiB,IAAgB;AAChC,UAAM,uBAAuB,KAAK;AAClC,SAAK,sBAAsB;AAC3B,QAAI;AACH,aAAO,GAAG;AAAA,IACX,UAAE;AACD,WAAK,sBAAsB;AAAA,IAC5B;AAAA,EACD;AACD;",
  "names": []
}
