{
  "version": 3,
  "sources": ["../../src/canvas/pin-stacking.ts"],
  "sourcesContent": ["import type { Editor, TLCommentThread } from 'tldraw'\nimport { anchorPagePoint } from './thread-state'\n\n/** Two anchors within this page-space distance (per axis) share a stack. Identical imprecise\n *  anchors on one shape resolve to the same point exactly; the tolerance only absorbs float noise. */\nconst PIN_STACK_QUANTUM = 0.1\n\n/**\n * The key a page point stacks under. Threads sharing a key are coincident. Stable identity for a\n * stack itself: it survives losing any member (the survivors keep the same key), unlike keying by\n * a particular thread id, so open-stack state stays put when the stack's oldest thread is deleted.\n */\nexport function pinStackKey(point: { x: number; y: number }): string {\n\treturn `${Math.round(point.x / PIN_STACK_QUANTUM)}:${Math.round(point.y / PIN_STACK_QUANTUM)}`\n}\n\n/**\n * Group threads whose pins land on the same page point \u2014 coincident pins (typically several\n * imprecise comments on one shape) that zooming can never separate. The overlay renders each\n * group as a single count-badge pin that opens the threads as a list. Every member id maps to\n * its group's ordered member ids (oldest first); threads without an entry pin individually.\n *\n * Keyed by page-space anchor point, not screen position, so the result only changes when threads\n * or their anchors move \u2014 never on camera moves.\n * @internal\n */\nexport function computePinStacks(\n\teditor: Editor,\n\tthreads: readonly TLCommentThread[]\n): Map<string, readonly string[]> {\n\tconst pageId = editor.getCurrentPageId()\n\tconst groups = new Map<string, TLCommentThread[]>()\n\n\tfor (const thread of threads) {\n\t\tif (thread.pageId !== pageId) continue\n\t\tconst point = anchorPagePoint(editor, thread.anchor)\n\t\tif (!point) continue\n\t\tconst key = pinStackKey(point)\n\t\tconst group = groups.get(key)\n\t\tif (group) {\n\t\t\tgroup.push(thread)\n\t\t} else {\n\t\t\tgroups.set(key, [thread])\n\t\t}\n\t}\n\n\tconst stacks = new Map<string, readonly string[]>()\n\tfor (const group of groups.values()) {\n\t\tif (group.length < 2) continue\n\t\tgroup.sort((a, b) => a.createdAt - b.createdAt || (a.id < b.id ? -1 : 1))\n\t\tconst ids = group.map((thread) => thread.id)\n\t\tfor (const id of ids) {\n\t\t\tstacks.set(id, ids)\n\t\t}\n\t}\n\treturn stacks\n}\n\n/**\n * Value equality for pin-stack maps, so the overlay can hold the map's identity across a recompute\n * that changed no grouping. Membership only: two equal maps can describe stacks at different page\n * points, so anything keyed on a stack's *point* must read the anchors itself, as\n * {@link isOpenStackKeyLive} does.\n * @internal\n */\nexport function pinStacksEqual(\n\ta: ReadonlyMap<string, readonly string[]>,\n\tb: ReadonlyMap<string, readonly string[]>\n): boolean {\n\tif (a === b) return true\n\tif (a.size !== b.size) return false\n\tfor (const [id, group] of b) {\n\t\tconst prevGroup = a.get(id)\n\t\tif (!prevGroup) return false\n\t\tif (prevGroup === group) continue\n\t\tif (prevGroup.length !== group.length) return false\n\t\tfor (let i = 0; i < group.length; i++) {\n\t\t\tif (prevGroup[i] !== group[i]) return false\n\t\t}\n\t}\n\treturn true\n}\n\n/**\n * Whether an open-stack key still names a stack on the canvas \u2014 false once that stack is emptied,\n * moved, or off the page, at which point the caller must clear the key. Reads the anchors, so a\n * reactive caller re-evaluates on a move that {@link pinStacksEqual} can't see.\n * @internal\n */\nexport function isOpenStackKeyLive(\n\teditor: Editor,\n\tkey: string,\n\tstacks: ReadonlyMap<string, readonly string[]>,\n\tthreadsById: ReadonlyMap<string, TLCommentThread>\n): boolean {\n\tfor (const id of stacks.keys()) {\n\t\tconst thread = threadsById.get(id)\n\t\tif (!thread) continue\n\t\tconst point = anchorPagePoint(editor, thread.anchor)\n\t\tif (point && pinStackKey(point) === key) return true\n\t}\n\treturn false\n}\n"],
  "mappings": "AACA,SAAS,uBAAuB;AAIhC,MAAM,oBAAoB;AAOnB,SAAS,YAAY,OAAyC;AACpE,SAAO,GAAG,KAAK,MAAM,MAAM,IAAI,iBAAiB,CAAC,IAAI,KAAK,MAAM,MAAM,IAAI,iBAAiB,CAAC;AAC7F;AAYO,SAAS,iBACf,QACA,SACiC;AACjC,QAAM,SAAS,OAAO,iBAAiB;AACvC,QAAM,SAAS,oBAAI,IAA+B;AAElD,aAAW,UAAU,SAAS;AAC7B,QAAI,OAAO,WAAW,OAAQ;AAC9B,UAAM,QAAQ,gBAAgB,QAAQ,OAAO,MAAM;AACnD,QAAI,CAAC,MAAO;AACZ,UAAM,MAAM,YAAY,KAAK;AAC7B,UAAM,QAAQ,OAAO,IAAI,GAAG;AAC5B,QAAI,OAAO;AACV,YAAM,KAAK,MAAM;AAAA,IAClB,OAAO;AACN,aAAO,IAAI,KAAK,CAAC,MAAM,CAAC;AAAA,IACzB;AAAA,EACD;AAEA,QAAM,SAAS,oBAAI,IAA+B;AAClD,aAAW,SAAS,OAAO,OAAO,GAAG;AACpC,QAAI,MAAM,SAAS,EAAG;AACtB,UAAM,KAAK,CAAC,GAAG,MAAM,EAAE,YAAY,EAAE,cAAc,EAAE,KAAK,EAAE,KAAK,KAAK,EAAE;AACxE,UAAM,MAAM,MAAM,IAAI,CAAC,WAAW,OAAO,EAAE;AAC3C,eAAW,MAAM,KAAK;AACrB,aAAO,IAAI,IAAI,GAAG;AAAA,IACnB;AAAA,EACD;AACA,SAAO;AACR;AASO,SAAS,eACf,GACA,GACU;AACV,MAAI,MAAM,EAAG,QAAO;AACpB,MAAI,EAAE,SAAS,EAAE,KAAM,QAAO;AAC9B,aAAW,CAAC,IAAI,KAAK,KAAK,GAAG;AAC5B,UAAM,YAAY,EAAE,IAAI,EAAE;AAC1B,QAAI,CAAC,UAAW,QAAO;AACvB,QAAI,cAAc,MAAO;AACzB,QAAI,UAAU,WAAW,MAAM,OAAQ,QAAO;AAC9C,aAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACtC,UAAI,UAAU,CAAC,MAAM,MAAM,CAAC,EAAG,QAAO;AAAA,IACvC;AAAA,EACD;AACA,SAAO;AACR;AAQO,SAAS,mBACf,QACA,KACA,QACA,aACU;AACV,aAAW,MAAM,OAAO,KAAK,GAAG;AAC/B,UAAM,SAAS,YAAY,IAAI,EAAE;AACjC,QAAI,CAAC,OAAQ;AACb,UAAM,QAAQ,gBAAgB,QAAQ,OAAO,MAAM;AACnD,QAAI,SAAS,YAAY,KAAK,MAAM,IAAK,QAAO;AAAA,EACjD;AACA,SAAO;AACR;",
  "names": []
}
