{
  "version": 3,
  "sources": ["../../src/canvas/cluster-model.ts"],
  "sourcesContent": ["import { useEffect, useMemo, useRef, useState } from 'react'\nimport { Editor, react, TLCommentThread, useValue } from 'tldraw'\nimport { computeClusterTable } from '../clustering/computeClusterTable'\nimport { type ClusterRuntime, createClusterRuntime } from '../clustering/runtime'\nimport type { ClusterNode, ClusterTable, MergeEvent } from '../clustering/types'\nimport { type ClusterFadeNode, useFadeVisibleNodes } from './cluster-fade'\nimport {\n\ttype ClusterInput,\n\tclusterInputEqual,\n\tclusterInputIdsEqual,\n\tcollectClusterLeaves,\n} from './cluster-input'\nimport { type CommentingOptions } from './options'\nimport { openThreadId } from './state'\nimport { anchorPagePoint, commentCenterScreenOffset } from './thread-state'\n\n/** Duration of the click-a-badge zoom-to-split animation. */\nexport const CLUSTER_EXPAND_ZOOM_MS = 450\n/** How far past a cluster's split zoom to land when expanding it \u2014 a 5% overshoot, so the badge\n *  lands clear of the threshold it just crossed rather than flickering on it. */\nconst CLUSTER_SPLIT_ZOOM_FACTOR = 1.05\n\nconst EMPTY_SET: ReadonlySet<string> = new Set()\nconst MOVED_LEAF_EPSILON = 1e-6\n\n/** Default select-tool states that move shapes continuously, one store write per pointermove. A\n *  custom tool in their place just never matches, falling back to a rebuild per frame. */\nconst SHAPE_DRAG_STATE_PATHS = [\n\t'select.translating',\n\t'select.resizing',\n\t'select.rotating',\n\t'select.dragging_handle',\n\t'select.crop.cropping',\n] as const\n\n/** Reactive: `isInAny` reads the tool state path, so a computed reading this re-evaluates when the\n *  gesture starts or settles. */\nfunction isShapeDragInProgress(editor: Editor): boolean {\n\treturn editor.isInAny(...SHAPE_DRAG_STATE_PATHS)\n}\n\n/** The clustering table for the current scene, plus the runtime walking its merge events. */\nexport interface ClusterModel {\n\truntime: ClusterRuntime\n\ttable: ClusterTable\n}\n\nexport interface ClusterZoomBounds {\n\tminZoom: number\n\tmaxZoom: number\n}\n\nexport interface ClusterModelState {\n\t/** The partition actually on screen. See {@link useClusterModel} for why it can lag the input. */\n\tmodel: ClusterModel\n\tzoomBounds: ClusterZoomBounds\n\t/** The displayed nodes, each tagged with its cross-fade phase. */\n\tfadeNodes: ClusterFadeNode[]\n\t/** Threads in the input that the displayed partition doesn't show \u2014 render them as plain pins. */\n\torphanThreads: TLCommentThread[]\n\t/** Threads held out of clustering because their anchor moved while folded into a badge. */\n\theldThreads: TLCommentThread[]\n}\n\n/**\n * The clustering state machine behind the comments layer.\n *\n * The core invariant: the only thing that re-flows clustering doc-wide is zoom. Every rebuild is\n * computed immediately as `latestModel`, but the on-screen partition is `renderedModel`, which only\n * changes via (a) the cursor walking on zoom, (b) adoption of the pending rebuild on zoom-out, or\n * (c) LOCAL detach patches, where a leaf that left the input is detached from its own badge in\n * place and nothing else on the canvas moves.\n *\n * Threads the displayed partition can't represent are returned separately (`orphanThreads`,\n * `heldThreads`) for the layer to draw as ordinary pins.\n */\nexport function useClusterModel(\n\teditor: Editor,\n\tthreads: readonly TLCommentThread[],\n\topenId: string | null\n): ClusterModelState {\n\t// Threads held out of clustering because their anchor moved while folded inside a badge\n\t// (drag, nudge, align, undo, a collaborator \u2014 detected by position, not gesture). They render\n\t// as live pins riding their anchor and rejoin clustering on the next zoom-out.\n\tconst [heldThreadIds, setHeldThreadIds] = useState<ReadonlySet<string>>(EMPTY_SET)\n\tconst adoptOnRebuild = useRef(false)\n\t// This input's identity keys the O(N\u00B2) table rebuild below, so it's gated on value equality: a\n\t// reply, a reaction, a resolve \u2014 anything that touches comment records without moving a pin \u2014\n\t// returns the previous input and rebuilds nothing.\n\t//\n\t// Mid-drag the gate ignores positions too \u2014 except a folded leaf's, which a badge can't\n\t// follow. Its first move passes through, the pop-out below holds the pin out as a live pin,\n\t// and the input is static again for the rest of the drag.\n\tconst clusterInputRef = useRef<ClusterInput>({ leaves: [], screenOffsets: undefined })\n\tconst renderedModelRef = useRef<ClusterModel | null>(null)\n\tconst clusterInput = useValue(\n\t\t'comment cluster leaves',\n\t\t() => {\n\t\t\tconst next = collectClusterLeaves(\n\t\t\t\teditor,\n\t\t\t\tthreads.filter((thread) => !heldThreadIds.has(thread.id)),\n\t\t\t\topenThreadId.get(editor)\n\t\t\t)\n\t\t\tconst prev = clusterInputRef.current\n\t\t\tif (\n\t\t\t\tisShapeDragInProgress(editor) &&\n\t\t\t\tclusterInputIdsEqual(prev, next) &&\n\t\t\t\t!anyFoldedLeafMoved(prev, next, renderedModelRef.current)\n\t\t\t) {\n\t\t\t\treturn prev\n\t\t\t}\n\t\t\tif (clusterInputEqual(prev, next)) return prev\n\t\t\tclusterInputRef.current = next\n\t\t\treturn next\n\t\t},\n\t\t[editor, threads, heldThreadIds]\n\t)\n\tconst clusterZoomBounds = useValue(\n\t\t'comment cluster zoom bounds',\n\t\t() => getClusterZoomBounds(editor),\n\t\t[editor]\n\t)\n\tconst latestModel = useMemo(() => {\n\t\tconst table = computeClusterTable(\n\t\t\tclusterInput.leaves,\n\t\t\tclusterZoomBounds,\n\t\t\tclusterInput.screenOffsets\n\t\t)\n\t\tconst runtime = createClusterRuntime(table)\n\t\truntime.seed(editor.getZoomLevel())\n\t\treturn { runtime, table }\n\t}, [clusterInput, clusterZoomBounds, editor])\n\tconst [renderedModel, setRenderedModel] = useState(latestModel)\n\tlet clusterModel = renderedModel\n\t// A page switch replaces the whole scene: hard-reset rather than detach the world.\n\tconst pageId = useValue('comment cluster page', () => editor.getCurrentPageId(), [editor])\n\tconst pageRef = useRef(pageId)\n\tif (pageRef.current !== pageId) {\n\t\tpageRef.current = pageId\n\t\tadoptOnRebuild.current = false\n\t\tlatestModel.runtime.seed(editor.getZoomLevel())\n\t\tif (heldThreadIds.size > 0) setHeldThreadIds(EMPTY_SET)\n\t\tsetRenderedModel(latestModel)\n\t\tclusterModel = latestModel\n\t}\n\t// adoptOnRebuild is set outside React's render cycle, paired with clearing heldThreadIds. Only trust\n\t// it once that pairing is visible here, or an unrelated re-render can land in the gap.\n\tconst rejoinPending = heldThreadIds.size === 0 && adoptOnRebuild.current\n\tif (renderedModel !== latestModel && rejoinPending) {\n\t\tadoptOnRebuild.current = false\n\t\t// Carryover seed: band events inherit the outgoing partition's merged/unmerged state, so\n\t\t// nothing changes state because of the swap alone. Idempotent, so safe during render.\n\t\tlatestModel.runtime.seedFrom(editor.getZoomLevel(), renderedModel.runtime.getVisible())\n\t\tsetRenderedModel(latestModel)\n\t\tclusterModel = latestModel\n\t} else if (heldThreadIds.size === 0 && renderedModel === latestModel) {\n\t\t// Nothing pending and nothing to adopt: clear any leftover force-adopt intent so it can't\n\t\t// survive to force-adopt a later, unrelated rebuild.\n\t\tadoptOnRebuild.current = false\n\t}\n\t// For the input gate above: folded-vs-visible is judged against what's on screen.\n\trenderedModelRef.current = clusterModel\n\t// Pop-out detection: a leaf folded inside a badge can't follow its anchor (the badge position\n\t// is baked into the model), so when its live position drifts from the baked one, hold it out.\n\t// It renders as a live pin riding the anchor; the detach loop below shrinks its badge locally.\n\tconst newlyMovedIds = findMovedClusteredLeafIds(clusterModel, latestModel)\n\tif (newlyMovedIds.length > 0) {\n\t\tconst next = new Set(heldThreadIds)\n\t\tfor (const id of newlyMovedIds) next.add(id)\n\t\tsetHeldThreadIds(next)\n\t}\n\t// Local partition maintenance \u2014 the only non-zoom visual change. Any displayed leaf that has left the\n\t// cluster input is detached from its badge in place; the corrected rebuild already sits in latestModel\n\t// awaiting the next zoom-out. When the two models match, the leaf sets are identical, so skip the scan.\n\tif (clusterModel !== latestModel) {\n\t\tconst latestLeafIds = new Set(latestModel.table.leaves.map((leaf) => leaf.id))\n\t\tconst removedLeafIds: string[] = []\n\t\tfor (const leaf of clusterModel.table.leaves) {\n\t\t\tif (!latestLeafIds.has(leaf.id)) {\n\t\t\t\tremovedLeafIds.push(leaf.id)\n\t\t\t}\n\t\t}\n\t\t// Batched: one patch rebuild and one version bump for the whole set.\n\t\tif (removedLeafIds.length > 0) clusterModel.runtime.detachLeaves(removedLeafIds)\n\t}\n\t// Moved pins rejoin clustering on the next zoom-out motion: clear the set (so the rebuild\n\t// includes them again) and adopt that rebuild immediately instead of deferring it. Zooming in\n\t// never folds pins into clusters \u2014 merging is a zoom-out-only move, matching the runtime.\n\tuseEffect(() => {\n\t\tif (heldThreadIds.size === 0) return\n\t\tlet lastZoom = editor.getZoomLevel()\n\t\treturn react('rejoin moved comment pins on zoom out', () => {\n\t\t\tconst zoom = editor.getZoomLevel()\n\t\t\tconst prevZoom = lastZoom\n\t\t\tlastZoom = zoom\n\t\t\tif (zoom >= prevZoom) return\n\t\t\tadoptOnRebuild.current = true\n\t\t\tsetHeldThreadIds(EMPTY_SET)\n\t\t})\n\t}, [heldThreadIds, editor])\n\t// Adopt a pending rebuild only on zoom-out motion: folding deferred additions into clusters is\n\t// a merge, and merging only happens while zooming out. While zooming in, the stale table still\n\t// splits correctly on its own (split thresholds are direction-safe by the hysteresis invariant).\n\tuseEffect(() => {\n\t\tif (clusterModel === latestModel) return\n\t\tlet lastZoom = editor.getZoomLevel()\n\t\treturn react('adopt pending cluster model on zoom out', () => {\n\t\t\tconst zoom = editor.getZoomLevel()\n\t\t\tconst prevZoom = lastZoom\n\t\t\tlastZoom = zoom\n\t\t\tif (zoom >= prevZoom) return\n\t\t\tlatestModel.runtime.seedFrom(zoom, clusterModel.runtime.getVisible())\n\t\t\tsetRenderedModel(latestModel)\n\t\t})\n\t}, [clusterModel, latestModel, editor])\n\t// Threads the displayed partition doesn't show anywhere (new comments, reopened threads, undone\n\t// deletions) render as plain pins until the next zoom-out folds them in. Judged against the\n\t// displayed partition, so a detached-then-restored leaf reappears.\n\tconst partitionVersion = clusterModel.runtime.version\n\tconst orphanThreads = useMemo(() => {\n\t\tif (clusterModel === latestModel) return []\n\t\tconst displayed = new Set<string>()\n\t\tfor (const node of clusterModel.runtime.getVisible().values()) {\n\t\t\tfor (const member of node.members) displayed.add(member)\n\t\t}\n\t\tconst latestIds = new Set(latestModel.table.leaves.map((leaf) => leaf.id))\n\t\treturn threads.filter((thread) => latestIds.has(thread.id) && !displayed.has(thread.id))\n\t\t// The runtime mutates its partition in place; partitionVersion is its change stamp.\n\t\t// eslint-disable-next-line react-hooks/exhaustive-deps\n\t}, [clusterModel, latestModel, threads, partitionVersion])\n\tconst heldThreads = useMemo(\n\t\t() => threads.filter((thread) => heldThreadIds.has(thread.id) && thread.id !== openId),\n\t\t[threads, heldThreadIds, openId]\n\t)\n\t// Subscribe to the runtime's partition version, not the raw zoom, so this only re-renders on cluster\n\t// changes rather than every camera frame. The memo below re-reads the version inline because\n\t// render-time detaches bump it after the subscription's computed already evaluated.\n\tuseValue(\n\t\t'comment cluster version',\n\t\t() => {\n\t\t\tclusterModel.runtime.onCamera(editor.getZoomLevel())\n\t\t\treturn clusterModel.runtime.version\n\t\t},\n\t\t[clusterModel, editor]\n\t)\n\tconst visibleNodes = useMemo(() => {\n\t\treturn Array.from(clusterModel.runtime.getVisible().values())\n\t\t// The runtime mutates its partition in place; partitionVersion is its change stamp.\n\t\t// eslint-disable-next-line react-hooks/exhaustive-deps\n\t}, [clusterModel, partitionVersion])\n\tconst fadeNodes = useFadeVisibleNodes(visibleNodes, clusterModel)\n\n\treturn {\n\t\tmodel: clusterModel,\n\t\tzoomBounds: clusterZoomBounds,\n\t\tfadeNodes,\n\t\torphanThreads,\n\t\theldThreads,\n\t}\n}\n\n/**\n * Whether a position-only input change (ids equal, same order) moved a leaf folded inside a badge\n * of the rendered partition \u2014 the one move the mid-drag freeze must let through.\n *\n * Folded means a member of a displayed badge, not merely \"absent from the displayed partition\":\n * the input also carries orphans (threads the rendered partition has never seen) and detached\n * leaves, which already ride their anchors as plain pins. Neither is in the rendered table, so the\n * pop-out below can never hold one \u2014 counting them here would break the freeze on every\n * pointermove for the rest of the drag.\n * @internal\n */\nexport function anyFoldedLeafMoved(\n\tprev: ClusterInput,\n\tnext: ClusterInput,\n\trendered: ClusterModel | null\n): boolean {\n\tif (!rendered) return false\n\tif (prev.leaves.length !== next.leaves.length) return false\n\tconst folded = new Set<string>()\n\tfor (const node of rendered.runtime.getVisible().values()) {\n\t\tif (node.count < 2) continue\n\t\tfor (const member of node.members) folded.add(member)\n\t}\n\t// No badges on screen, so nothing can be folded \u2014 the common case, and the cheap way out of it.\n\tif (folded.size === 0) return false\n\tfor (let i = 0; i < next.leaves.length; i++) {\n\t\tif (!folded.has(next.leaves[i].id)) continue\n\t\tconst a = prev.leaves[i].point\n\t\tconst b = next.leaves[i].point\n\t\tif (Math.abs(a.x - b.x) > MOVED_LEAF_EPSILON || Math.abs(a.y - b.y) > MOVED_LEAF_EPSILON) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n/**\n * Leaves folded inside a badge whose live anchor no longer matches the position the rendered\n * model was built with. Visible (unclustered) leaf pins track their anchor live, so they can\n * stay deferred; a badge can't follow a member, so these must pop out of clustering.\n */\nfunction findMovedClusteredLeafIds(rendered: ClusterModel, latest: { table: ClusterTable }) {\n\tif (rendered.table === latest.table) return []\n\tconst visible = rendered.runtime.getVisible()\n\tconst latestById = new Map(latest.table.leaves.map((leaf) => [leaf.id, leaf]))\n\tconst moved: string[] = []\n\tfor (const leaf of rendered.table.leaves) {\n\t\tif (visible.has(leaf.id)) continue\n\t\tconst current = latestById.get(leaf.id)\n\t\tif (!current) continue\n\t\tif (\n\t\t\tMath.abs(current.centroid.x - leaf.centroid.x) > MOVED_LEAF_EPSILON ||\n\t\t\tMath.abs(current.centroid.y - leaf.centroid.y) > MOVED_LEAF_EPSILON\n\t\t) {\n\t\t\tmoved.push(leaf.id)\n\t\t}\n\t}\n\treturn moved\n}\n\nfunction getClusterZoomBounds(editor: Editor): ClusterZoomBounds {\n\tconst cameraOptions = editor.getCameraOptions()\n\tconst baseZoom = cameraOptions.constraints ? editor.getBaseZoom() : 1\n\tconst zoomSteps = cameraOptions.zoomSteps\n\treturn {\n\t\tminZoom: zoomSteps[0] * baseZoom,\n\t\tmaxZoom: zoomSteps[zoomSteps.length - 1] * baseZoom,\n\t}\n}\n\n/**\n * Bring a thread's pin into view: switch pages if needed, then zoom to the first cluster split\n * that unfolds it from its badge (or just centre on it when it isn't clustered).\n */\nexport function revealThreadPin(\n\teditor: Editor,\n\tthread: TLCommentThread,\n\ttable: ClusterTable,\n\tzoomBounds: ClusterZoomBounds,\n\toptions: CommentingOptions,\n\tduration = 200\n) {\n\tif (thread.pageId !== editor.getCurrentPageId()) {\n\t\teditor.setCurrentPage(thread.pageId as any)\n\t}\n\n\tconst point = anchorPagePoint(editor, thread.anchor)\n\tif (!point) return\n\n\t// With clustering off the pin always renders individually, so skip the zoom-to-split (its cluster\n\t// badge never exists) and just center on the pin.\n\tif (options.enableClustering) {\n\t\tconst parentEvent = findDirectParentEvent(table, thread.id)\n\t\tif (\n\t\t\tparentEvent &&\n\t\t\tNumber.isFinite(parentEvent.zSplit) &&\n\t\t\tparentEvent.zSplit <= zoomBounds.maxZoom\n\t\t) {\n\t\t\tconst zoom = clamp(\n\t\t\t\tparentEvent.zSplit * CLUSTER_SPLIT_ZOOM_FACTOR,\n\t\t\t\tzoomBounds.minZoom,\n\t\t\t\tzoomBounds.maxZoom\n\t\t\t)\n\t\t\tcenterOnPointAtZoom(editor, point, zoom, duration)\n\t\t\treturn\n\t\t}\n\t}\n\n\tconst offset = commentCenterScreenOffset(editor) / editor.getZoomLevel()\n\teditor.centerOnPoint({ x: point.x + offset, y: point.y }, { animation: { duration } })\n}\n\n/**\n * Zoom to just past the zoom at which a cluster first unclusters, centered on its centroid. The\n * event that created a visible cluster is the event that splits it, and has the smallest zSplit of\n * everything applied inside it \u2014 so its zSplit is exactly the first split within those comments.\n * The animated zoom drives the runtime cursor like any manual zoom. A no-op with no split event.\n */\nexport function zoomToClusterSplit(\n\teditor: Editor,\n\ttable: ClusterTable,\n\tzoomBounds: ClusterZoomBounds,\n\tnode: ClusterNode\n) {\n\tconst event = table.events.find((e) => e.result.id === node.id)\n\tif (!event || !Number.isFinite(event.zSplit)) return\n\tconst zoom = clamp(\n\t\tevent.zSplit * CLUSTER_SPLIT_ZOOM_FACTOR,\n\t\tzoomBounds.minZoom,\n\t\tzoomBounds.maxZoom\n\t)\n\tcenterOnPointAtZoom(editor, node.centroid, zoom, CLUSTER_EXPAND_ZOOM_MS)\n}\n\nfunction findDirectParentEvent(table: ClusterTable, threadId: string): MergeEvent | undefined {\n\treturn table.events.find((event) => event.children.some((child) => child.id === threadId))\n}\n\nfunction centerOnPointAtZoom(\n\teditor: Editor,\n\tpoint: { x: number; y: number },\n\tzoom: number,\n\tduration = 200\n) {\n\tconst viewport = editor.getViewportScreenBounds()\n\t// The open sidebar shifts the target left so the pin lands mid-uncovered-area, not under it.\n\tconst offset = commentCenterScreenOffset(editor)\n\teditor.setCamera(\n\t\t{\n\t\t\tx: (viewport.w / 2 - offset) / zoom - point.x,\n\t\t\ty: viewport.h / (2 * zoom) - point.y,\n\t\t\tz: zoom,\n\t\t},\n\t\t{ animation: { duration } }\n\t)\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n\treturn Math.max(min, Math.min(max, value))\n}\n"],
  "mappings": "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",
  "names": []
}
