@tldraw/commenting 5.3.0-next.7654e7ac2a02 → 5.3.0-next.aefb8773a7eb

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/commenting.css +34 -28
  2. package/dist-cjs/canvas/comment-tool.js +12 -6
  3. package/dist-cjs/canvas/comment-tool.js.map +2 -2
  4. package/dist-cjs/canvas/comments-filter-menu.js +1 -1
  5. package/dist-cjs/canvas/comments-filter-menu.js.map +2 -2
  6. package/dist-cjs/canvas/comments-overlay.js +4 -1
  7. package/dist-cjs/canvas/comments-overlay.js.map +2 -2
  8. package/dist-cjs/canvas/pending-composer.js +1 -0
  9. package/dist-cjs/canvas/pending-composer.js.map +2 -2
  10. package/dist-cjs/canvas/thread-pin.js +1 -1
  11. package/dist-cjs/canvas/thread-pin.js.map +2 -2
  12. package/dist-cjs/index.d.ts +4 -2
  13. package/dist-cjs/index.js +1 -1
  14. package/dist-cjs/ui/format-time.js +1 -1
  15. package/dist-cjs/ui/format-time.js.map +2 -2
  16. package/dist-cjs/ui/icons.js +52 -29
  17. package/dist-cjs/ui/icons.js.map +2 -2
  18. package/dist-esm/canvas/comment-tool.mjs +12 -6
  19. package/dist-esm/canvas/comment-tool.mjs.map +2 -2
  20. package/dist-esm/canvas/comments-filter-menu.mjs +2 -2
  21. package/dist-esm/canvas/comments-filter-menu.mjs.map +2 -2
  22. package/dist-esm/canvas/comments-overlay.mjs +4 -1
  23. package/dist-esm/canvas/comments-overlay.mjs.map +2 -2
  24. package/dist-esm/canvas/pending-composer.mjs +1 -0
  25. package/dist-esm/canvas/pending-composer.mjs.map +2 -2
  26. package/dist-esm/canvas/thread-pin.mjs +1 -1
  27. package/dist-esm/canvas/thread-pin.mjs.map +2 -2
  28. package/dist-esm/index.d.mts +4 -2
  29. package/dist-esm/index.mjs +1 -1
  30. package/dist-esm/ui/format-time.mjs +1 -1
  31. package/dist-esm/ui/format-time.mjs.map +2 -2
  32. package/dist-esm/ui/icons.mjs +53 -30
  33. package/dist-esm/ui/icons.mjs.map +2 -2
  34. package/package.json +7 -6
  35. package/src/canvas/comment-tool.test.ts +109 -4
  36. package/src/canvas/comment-tool.tsx +24 -8
  37. package/src/canvas/comments-filter-menu.tsx +2 -2
  38. package/src/canvas/comments-overlay.tsx +7 -2
  39. package/src/canvas/pending-composer.tsx +4 -0
  40. package/src/canvas/thread-pin.tsx +3 -2
  41. package/src/ui/comments.css +34 -28
  42. package/src/ui/format-time.test.ts +3 -3
  43. package/src/ui/format-time.ts +2 -2
  44. package/src/ui/icons.tsx +43 -21
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/canvas/thread-pin.tsx"],
4
- "sourcesContent": ["import { Avatar } from '@tldraw/mentions'\nimport {\n\tmemo,\n\ttype PointerEvent as ReactPointerEvent,\n\tuseEffect,\n\tuseMemo,\n\tuseRef,\n\tuseState,\n} from 'react'\nimport {\n\ttype BoxModel,\n\tEditor,\n\tTLCommentThread,\n\tuseContainer,\n\tusePassThroughWheelEvents,\n\tuseTranslation,\n\tuseValue,\n} from 'tldraw'\nimport { CommentPin } from '../ui/comment-pin'\nimport { forwardPointerEventToCanvas, isCanvasPanGesture } from './canvas-events'\nimport { commitCommentMutation } from './comment-mutations'\nimport { UNKNOWN_AUTHOR, UNKNOWN_COMMENT_AUTHOR } from './comment-render'\nimport { type CommentingContext } from './context'\nimport { useThreadComments } from './hooks'\nimport { getCommentingOptions, useCanComment, useCommentingOptions } from './options'\nimport {\n\tREGION_CORNERS,\n\tREGION_HANDLE_MARGIN_PX,\n\tRegionBox,\n\tRegionResizeHandles,\n} from './region-box'\nimport { openThreadId } from './state'\nimport { ThreadPreview, useMarkerPreview } from './thread-preview'\nimport {\n\tanchorPagePoint,\n\tcommentTargetShapeAt,\n\timpreciseShapePinInset,\n\tisBoxInInflatedViewport,\n\tisInInflatedViewport,\n\tREGION_PIN_CORNER,\n\tregionAnchorPinCorner,\n\tregionPinPoint,\n\tshapeAnchorAt,\n} from './thread-state'\nimport { POPOVER_OFFSET, ThreadPopover, ThreadView } from './thread-view'\n\n/** The opened popover has a header row the hover preview lacks, so it opens this much higher \u2014 the\n * first comment then lands where the preview's sat. Re-measure if the header height or the preview\n * panel padding changes. */\nconst THREAD_HEADER_BLOCK = 36\n\n/**\n * A single thread's pin: the marker at its anchor, the thread popover when it's open, the hover\n * preview, and \u2014 for a region anchor \u2014 the dashed box and its resize handles. Dragging the marker\n * re-anchors the thread.\n *\n * Memoized so a pin skips re-rendering when the layer re-renders for unrelated reasons; camera\n * tracking still works, since the pin subscribes to its own viewport position via signals.\n */\nexport const ThreadPin = memo(function ThreadPin({\n\teditor,\n\tthread,\n\t...props\n}: CommentingContext & {\n\teditor: Editor\n\tthread: TLCommentThread\n}) {\n\tconst { resolveAuthor } = props\n\tconst options = useCommentingOptions()\n\tconst canComment = useCanComment(props.currentUserId)\n\tconst container = useContainer()\n\tconst msg = useTranslation()\n\tconst comments = useThreadComments(editor, thread.id)\n\t// Only one thread's popover is open at a time \u2014 shared across pins via the atom.\n\tconst open = useValue('thread open', () => openThreadId.get(editor) === thread.id, [\n\t\teditor,\n\t\tthread.id,\n\t])\n\t// While dragging the marker, its page point overrides the anchor's; committed on drop.\n\tconst [dragPagePoint, setDragPagePoint] = useState<{ x: number; y: number } | null>(null)\n\tconst [resizeBounds, setResizeBounds] = useState<BoxModel | null>(null)\n\t// Hovering the marker previews the thread's opening comment, on the delay every marker uses.\n\tconst { previewShown, previewHandlers } = useMarkerPreview(editor, `pin:${thread.id}`)\n\tconst previewThreads = useMemo(() => [thread], [thread])\n\t// The 'pointer' reveal mode: is the pointer within the region's bounds (plus a grab margin)?\n\t// Driven by pointer position, not DOM hover, so moving from anywhere in the region out to a corner\n\t// handle never loses the affordance \u2014 the box stays `pointer-events: none`.\n\tconst pointerInRegion = useValue(\n\t\t'pointer in region',\n\t\t() => {\n\t\t\tif (thread.anchor.type !== 'region' || thread.pageId !== editor.getCurrentPageId())\n\t\t\t\treturn false\n\t\t\tconst m = REGION_HANDLE_MARGIN_PX / editor.getZoomLevel()\n\t\t\tconst p = editor.inputs.getCurrentPagePoint()\n\t\t\tconst a = thread.anchor\n\t\t\treturn p.x >= a.x - m && p.x <= a.x + a.w + m && p.y >= a.y - m && p.y <= a.y + a.h + m\n\t\t},\n\t\t[editor, thread.anchor, thread.pageId]\n\t)\n\t// A region's box and handles are revealed while open, mid-resize, or while the pointer is\n\t// within the region.\n\tconst revealed = open || resizeBounds != null || pointerInRegion\n\t// A region thread's pin corner is its own (the corner its creating drag released on), with\n\t// the default as the fallback for older records.\n\tconst pinCorner =\n\t\tthread.anchor.type === 'region' ? regionAnchorPinCorner(thread.anchor) : REGION_PIN_CORNER\n\t// A region resizes from its corners \u2014 every corner but the pin's own, which the pin owns.\n\tconst resizeHandles = useMemo(\n\t\t() => REGION_CORNERS.filter((c) => c.x !== pinCorner.x || c.y !== pinCorner.y),\n\t\t[pinCorner]\n\t)\n\tconst dragRef = useRef<{\n\t\tstartX: number\n\t\tstartY: number\n\t\tmoved: boolean\n\t\t// The anchor's page-space offset from the grab point, so a drag translates the pin by the\n\t\t// cursor's delta (like RegionBox's move) instead of snapping the anchor to the cursor.\n\t\toffsetX: number\n\t\toffsetY: number\n\t} | null>(null)\n\tconst markerRef = useRef<HTMLButtonElement>(null)\n\t// Wheel pass-through sits on the marker (which is never scrollable), not the layer root \u2014\n\t// see the note on the layer.\n\tusePassThroughWheelEvents(markerRef)\n\n\t// The drop-target hint is editor-global state with no automatic reset. If the pin unmounts\n\t// mid-drag (e.g. Shift+C hides comments), no pointer event will ever reach the drag handlers \u2014\n\t// clear the hint here or it stays on the shape indefinitely.\n\tuseEffect(() => {\n\t\treturn () => {\n\t\t\tif (dragRef.current) editor.setHintingShapes([])\n\t\t}\n\t}, [editor])\n\n\t// Clicking outside the open popover closes the thread. Capture phase + a class check rather than\n\t// stopPropagation, since the popover portals elsewhere in the DOM. The marker is excluded so its own\n\t// click-to-toggle handles it instead of this closing and the toggle reopening.\n\tuseEffect(() => {\n\t\tif (!open) return\n\t\tconst onPointerDown = (e: PointerEvent) => {\n\t\t\tconst target = e.target as HTMLElement | null\n\t\t\tif (!target) return\n\t\t\tif (target.closest('.tlui-cmt-canvas-popover')) return\n\t\t\tconst marker = markerRef.current\n\t\t\tif (marker && marker.contains(target)) return\n\t\t\t// A press on a region's resize handle edits this thread \u2014 don't dismiss it.\n\t\t\tif (target.closest('.tlui-cmt-canvas-region-handle')) return\n\t\t\t// A click inside a menu/popover layered above us (the sidebar's filter or overflow\n\t\t\t// dropdown, or the composer's mention picker \u2014 all portaled elsewhere) belongs to that\n\t\t\t// layer; defer to its own dismissal instead of closing the thread out from under it.\n\t\t\tif (\n\t\t\t\ttarget.closest('.tlui-menu, [data-radix-popper-content-wrapper], .tlui-cmt-mention-popup')\n\t\t\t)\n\t\t\t\treturn\n\t\t\topenThreadId.set(editor, null)\n\t\t}\n\t\tdocument.addEventListener('pointerdown', onPointerDown, true)\n\t\treturn () => document.removeEventListener('pointerdown', onPointerDown, true)\n\t}, [open, editor])\n\n\t// The pin must not unmount mid-interaction: an open thread's popover hangs off it, and a drag\n\t// or resize holds pointer capture on it \u2014 so those states are exempt from the viewport cull.\n\tconst exemptFromCull = open || dragPagePoint != null || resizeBounds != null\n\tconst point = useValue(\n\t\t'pin point',\n\t\t() => {\n\t\t\tif (thread.pageId !== editor.getCurrentPageId()) return null\n\t\t\tconst pagePoint = anchorPagePoint(editor, thread.anchor)\n\t\t\tif (!pagePoint) return null\n\t\t\tconst viewportPoint = editor.pageToViewport(pagePoint)\n\t\t\tconst inset = impreciseShapePinInset(editor, thread.anchor)\n\t\t\tconst point = inset\n\t\t\t\t? { x: viewportPoint.x + inset.x, y: viewportPoint.y + inset.y }\n\t\t\t\t: viewportPoint\n\t\t\t// Off-screen pins (plus a pre-mount margin) unmount rather than re-render every camera frame. A\n\t\t\t// region thread stays mounted while any part of its box is on screen, since the box renders here too.\n\t\t\tif (!exemptFromCull) {\n\t\t\t\tconst visible =\n\t\t\t\t\tthread.anchor.type === 'region'\n\t\t\t\t\t\t? isBoxInInflatedViewport(editor, thread.anchor)\n\t\t\t\t\t\t: isInInflatedViewport(editor, point)\n\t\t\t\tif (!visible) return null\n\t\t\t}\n\t\t\treturn point\n\t\t},\n\t\t[editor, thread.anchor, thread.pageId, exemptFromCull]\n\t)\n\tif (!point) return null\n\n\tconst PinContent = options.components.PinContent\n\tconst threadAuthor = resolveAuthor(thread.createdBy)\n\tconst pinContent = PinContent ? (\n\t\t<PinContent thread={thread} comments={comments} />\n\t) : (\n\t\t<Avatar author={threadAuthor ?? UNKNOWN_COMMENT_AUTHOR} />\n\t)\n\tconst pinLabel = msg(\n\t\tthread.resolved ? 'comments.pin-label-resolved' : 'comments.pin-label'\n\t).replace('{name}', threadAuthor?.name ?? UNKNOWN_AUTHOR)\n\n\t// Drag the marker to move the thread: position is overridden locally while dragging, then re-anchored\n\t// on drop. A region translates keeping its size; a barely-moved pointer is a click.\n\tconst isRegion = thread.anchor.type === 'region'\n\t// The marker is a button (so it's keyboard-reachable), so the drag handlers are typed to it.\n\tconst startDrag = (e: ReactPointerEvent<HTMLButtonElement>) => {\n\t\t// A middle/right-button or space-held press over a pin is a camera pan, not a pin drag \u2014\n\t\t// hand it to the canvas untouched.\n\t\tif (isCanvasPanGesture(editor, e)) {\n\t\t\tforwardPointerEventToCanvas(container, e)\n\t\t\treturn\n\t\t}\n\t\te.stopPropagation()\n\t\tconst grabPage = editor.screenToPage({ x: e.clientX, y: e.clientY })\n\t\tconst anchorPage = anchorPagePoint(editor, thread.anchor)\n\t\t// The drag delta is taken from where the pin is drawn, which for an imprecise shape pin\n\t\t// is inset from its anchor point \u2014 without this the pin jumps by the inset on drag start.\n\t\tconst inset = impreciseShapePinInset(editor, thread.anchor)\n\t\tif (anchorPage && inset) {\n\t\t\tconst zoom = editor.getZoomLevel()\n\t\t\tanchorPage.x += inset.x / zoom\n\t\t\tanchorPage.y += inset.y / zoom\n\t\t}\n\t\tdragRef.current = {\n\t\t\tstartX: e.clientX,\n\t\t\tstartY: e.clientY,\n\t\t\tmoved: false,\n\t\t\toffsetX: anchorPage ? anchorPage.x - grabPage.x : 0,\n\t\t\toffsetY: anchorPage ? anchorPage.y - grabPage.y : 0,\n\t\t}\n\t\te.currentTarget.setPointerCapture(e.pointerId)\n\t}\n\tconst onDrag = (e: ReactPointerEvent<HTMLButtonElement>) => {\n\t\tconst drag = dragRef.current\n\t\tif (!drag) return\n\t\t// Moving a pin re-anchors the thread record \u2014 a commenting write. Without the permission the\n\t\t// press stays a click (`moved` never sets, so release toggles the popover and never commits).\n\t\tif (!canComment) return\n\t\tif (!drag.moved && Math.hypot(e.clientX - drag.startX, e.clientY - drag.startY) < 4) return\n\t\tdrag.moved = true\n\t\tconst cursorPage = editor.screenToPage({ x: e.clientX, y: e.clientY })\n\t\tconst pagePoint = { x: cursorPage.x + drag.offsetX, y: cursorPage.y + drag.offsetY }\n\t\tsetDragPagePoint(pagePoint)\n\t\t// Hint the shape the pin would re-anchor to on drop \u2014 the same hit-test endDrag resolves\n\t\t// with. Regions translate rather than re-anchor, so they never hint.\n\t\tif (!isRegion) {\n\t\t\tconst hit = commentTargetShapeAt(editor, pagePoint)\n\t\t\teditor.setHintingShapes(hit ? [hit.id] : [])\n\t\t}\n\t}\n\t// A cancelled pointer (touch gesture takeover, browser interruption) aborts the drag outright:\n\t// no re-anchor commit, no click-toggle \u2014 the pin snaps back and the hint clears.\n\tconst cancelDrag = (e: ReactPointerEvent<HTMLButtonElement>) => {\n\t\tconst drag = dragRef.current\n\t\tdragRef.current = null\n\t\tif (e.currentTarget.hasPointerCapture(e.pointerId)) {\n\t\t\te.currentTarget.releasePointerCapture(e.pointerId)\n\t\t}\n\t\tif (!drag) return\n\t\tsetDragPagePoint(null)\n\t\teditor.setHintingShapes([])\n\t}\n\tconst endDrag = (e: ReactPointerEvent<HTMLButtonElement>) => {\n\t\tconst drag = dragRef.current\n\t\tdragRef.current = null\n\t\tif (e.currentTarget.hasPointerCapture(e.pointerId)) {\n\t\t\te.currentTarget.releasePointerCapture(e.pointerId)\n\t\t}\n\t\tif (!drag) return\n\t\teditor.setHintingShapes([])\n\t\tif (!drag.moved) {\n\t\t\topenThreadId.set(editor, openThreadId.get(editor) === thread.id ? null : thread.id)\n\t\t\treturn\n\t\t}\n\t\tconst cursorPage = editor.screenToPage({ x: e.clientX, y: e.clientY })\n\t\tconst pagePoint = { x: cursorPage.x + drag.offsetX, y: cursorPage.y + drag.offsetY }\n\t\tsetDragPagePoint(null)\n\t\tlet anchor: TLCommentThread['anchor']\n\t\tif (thread.anchor.type === 'region') {\n\t\t\t// Translate so the pin (the region's pin corner) lands at the drop; size unchanged.\n\t\t\tanchor = {\n\t\t\t\t...thread.anchor,\n\t\t\t\tx: pagePoint.x - pinCorner.x * thread.anchor.w,\n\t\t\t\ty: pagePoint.y - pinCorner.y * thread.anchor.h,\n\t\t\t}\n\t\t} else {\n\t\t\tconst hit = commentTargetShapeAt(editor, pagePoint)\n\t\t\tanchor = hit\n\t\t\t\t? shapeAnchorAt(\n\t\t\t\t\t\teditor,\n\t\t\t\t\t\thit.id,\n\t\t\t\t\t\tpagePoint,\n\t\t\t\t\t\tgetCommentingOptions(editor).shouldBePrecise(editor, {\n\t\t\t\t\t\t\tshapeId: hit.id,\n\t\t\t\t\t\t\tpoint: pagePoint,\n\t\t\t\t\t\t\taltKey: e.altKey,\n\t\t\t\t\t\t})\n\t\t\t\t\t)\n\t\t\t\t: { type: 'point', x: pagePoint.x, y: pagePoint.y }\n\t\t}\n\t\tcommitCommentMutation(editor, ({ put }) => put([{ ...thread, anchor }]), 'drag')\n\t}\n\n\t// The pin (and its popover) track the live edit: a resize moves it to the region's pin corner, a\n\t// move to the drag point; otherwise it sits at the stored anchor's viewport point.\n\tconst livePinPage = resizeBounds ? regionPinPoint(resizeBounds, pinCorner) : dragPagePoint\n\tconst renderPointBase = livePinPage ? editor.pageToViewport(livePinPage) : point\n\t// A region's pin centres on its corner \u2014 overlapping the box \u2014 rather than hanging off it.\n\t// The marker anchors bottom-left, so step half its 34px size left and down (screen px).\n\tconst renderPoint = isRegion\n\t\t? { x: renderPointBase.x - 17, y: renderPointBase.y + 17 }\n\t\t: renderPointBase\n\n\t// A region's live box bounds, by priority: a corner resize, else a pin-drag translation (the pin\n\t// corner tracks the cursor), else the stored anchor. Undefined for non-region threads.\n\tconst regionAnchor = thread.anchor.type === 'region' ? thread.anchor : undefined\n\tconst movedRegion =\n\t\tregionAnchor && dragPagePoint\n\t\t\t? {\n\t\t\t\t\t...regionAnchor,\n\t\t\t\t\tx: dragPagePoint.x - pinCorner.x * regionAnchor.w,\n\t\t\t\t\ty: dragPagePoint.y - pinCorner.y * regionAnchor.h,\n\t\t\t\t}\n\t\t\t: regionAnchor\n\tconst regionBoxBounds = resizeBounds ?? movedRegion\n\tconst commitResize = (bounds: BoxModel) => {\n\t\tsetResizeBounds(null)\n\t\tif (!canComment) return\n\t\t// Same commit path as a pin drag, so the configured `dragHistory` governs both \u2014 going\n\t\t// straight to `editor.run` here would make region resizes silently ignore the option.\n\t\tcommitCommentMutation(\n\t\t\teditor,\n\t\t\t// Spread the existing anchor first so the region's pin corner survives a resize.\n\t\t\t({ put }) => put([{ ...thread, anchor: { ...regionAnchor!, ...bounds } }]),\n\t\t\t'drag'\n\t\t)\n\t}\n\n\treturn (\n\t\t<>\n\t\t\t{regionBoxBounds && (dragPagePoint || revealed) && (\n\t\t\t\t<RegionBox editor={editor} box={regionBoxBounds} />\n\t\t\t)}\n\t\t\t{regionBoxBounds && revealed && !dragPagePoint && canComment && (\n\t\t\t\t<RegionResizeHandles\n\t\t\t\t\teditor={editor}\n\t\t\t\t\tbox={regionBoxBounds}\n\t\t\t\t\thandles={resizeHandles}\n\t\t\t\t\tonPreview={setResizeBounds}\n\t\t\t\t\tonCommit={commitResize}\n\t\t\t\t/>\n\t\t\t)}\n\t\t\t<div\n\t\t\t\tclassName={[\n\t\t\t\t\t'tlui-cmt-canvas-pin',\n\t\t\t\t\topen && 'tlui-cmt-canvas-pin--open',\n\t\t\t\t\tdragPagePoint && 'tlui-cmt-canvas-pin--dragging',\n\t\t\t\t]\n\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t.join(' ')}\n\t\t\t\tstyle={{ left: renderPoint.x, top: renderPoint.y }}\n\t\t\t>\n\t\t\t\t<button\n\t\t\t\t\tref={markerRef}\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclassName=\"tlui-cmt-button tlui-cmt-canvas-pin__marker\"\n\t\t\t\t\taria-label={pinLabel}\n\t\t\t\t\taria-expanded={open}\n\t\t\t\t\tonPointerDown={startDrag}\n\t\t\t\t\tonPointerMove={onDrag}\n\t\t\t\t\tonPointerUp={endDrag}\n\t\t\t\t\tonPointerCancel={cancelDrag}\n\t\t\t\t\t// Pointer activation is already handled by endDrag (which distinguishes a click\n\t\t\t\t\t// from a drag), so only take keyboard-synthesised clicks here \u2014 those report\n\t\t\t\t\t// `detail === 0` \u2014 or the thread would toggle twice per mouse click.\n\t\t\t\t\tonClick={(e) => {\n\t\t\t\t\t\tif (e.detail !== 0) return\n\t\t\t\t\t\topenThreadId.set(editor, openThreadId.get(editor) === thread.id ? null : thread.id)\n\t\t\t\t\t}}\n\t\t\t\t\tonPointerEnter={previewHandlers.onPointerEnter}\n\t\t\t\t\tonPointerLeave={previewHandlers.onPointerLeave}\n\t\t\t\t\t// Focus stands in for hover, so tabbing to a marker gets the same preview.\n\t\t\t\t\tonFocus={previewHandlers.onPointerEnter}\n\t\t\t\t\tonBlur={previewHandlers.onPointerLeave}\n\t\t\t\t>\n\t\t\t\t\t<CommentPin resolved={thread.resolved != null} open={open}>\n\t\t\t\t\t\t{pinContent}\n\t\t\t\t\t</CommentPin>\n\t\t\t\t</button>\n\t\t\t\t{/* The popover portals up to the menus layer (above the UI panels) so it isn't clipped;\n\t\t\t the pin itself stays in the canvas-in-front layer, beneath the UI. */}\n\t\t\t\t{open && (\n\t\t\t\t\t<ThreadPopover\n\t\t\t\t\t\tbase={{\n\t\t\t\t\t\t\tx: renderPoint.x + POPOVER_OFFSET.thread.x,\n\t\t\t\t\t\t\ty: renderPoint.y + POPOVER_OFFSET.thread.y - THREAD_HEADER_BLOCK,\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t<ThreadView editor={editor} thread={thread} {...props} />\n\t\t\t\t\t</ThreadPopover>\n\t\t\t\t)}\n\t\t\t\t{/* Not while dragging: the pin is being moved, not read, and a panel trailing the\n\t\t\t\t cursor would obscure the drop target. */}\n\t\t\t\t{previewShown && !dragPagePoint && (\n\t\t\t\t\t<ThreadPreview\n\t\t\t\t\t\teditor={editor}\n\t\t\t\t\t\tthreads={previewThreads}\n\t\t\t\t\t\tvariant=\"thread\"\n\t\t\t\t\t\tpoint={renderPoint}\n\t\t\t\t\t\tonSelectThread={() => openThreadId.set(editor, thread.id)}\n\t\t\t\t\t\t{...previewHandlers}\n\t\t\t\t\t\tcurrentUserId={props.currentUserId}\n\t\t\t\t\t\tresolveAuthor={resolveAuthor}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t</>\n\t)\n})\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { Avatar } from '@tldraw/mentions'\nimport {\n\tmemo,\n\ttype PointerEvent as ReactPointerEvent,\n\tuseEffect,\n\tuseMemo,\n\tuseRef,\n\tuseState,\n} from 'react'\nimport {\n\ttype BoxModel,\n\tEditor,\n\tTLCommentThread,\n\tuseContainer,\n\tusePassThroughWheelEvents,\n\tuseTranslation,\n\tuseValue,\n} from 'tldraw'\nimport { CommentPin } from '../ui/comment-pin'\nimport { forwardPointerEventToCanvas, isCanvasPanGesture } from './canvas-events'\nimport { commitCommentMutation } from './comment-mutations'\nimport { UNKNOWN_AUTHOR, UNKNOWN_COMMENT_AUTHOR } from './comment-render'\nimport { type CommentingContext } from './context'\nimport { useThreadComments } from './hooks'\nimport { getCommentingOptions, useCanComment, useCommentingOptions } from './options'\nimport {\n\tREGION_CORNERS,\n\tREGION_HANDLE_MARGIN_PX,\n\tRegionBox,\n\tRegionResizeHandles,\n} from './region-box'\nimport { openThreadId } from './state'\nimport { ThreadPreview, useMarkerPreview } from './thread-preview'\nimport {\n\tanchorPagePoint,\n\tcommentTargetShapeAt,\n\timpreciseShapePinInset,\n\tisBoxInInflatedViewport,\n\tisInInflatedViewport,\n\tREGION_PIN_CORNER,\n\tregionAnchorPinCorner,\n\tregionPinPoint,\n\tshapeAnchorAt,\n} from './thread-state'\nimport { POPOVER_OFFSET, ThreadPopover, ThreadView } from './thread-view'\n\n/** The opened popover has a header row the hover preview lacks, so it opens this much higher \u2014 the\n * first comment then lands where the preview's sat. Re-measure if the header height or the preview\n * panel padding changes. */\nconst THREAD_HEADER_BLOCK = 36\n\n/**\n * A single thread's pin: the marker at its anchor, the thread popover when it's open, the hover\n * preview, and \u2014 for a region anchor \u2014 the dashed box and its resize handles. Dragging the marker\n * re-anchors the thread.\n *\n * Memoized so a pin skips re-rendering when the layer re-renders for unrelated reasons; camera\n * tracking still works, since the pin subscribes to its own viewport position via signals.\n */\nexport const ThreadPin = memo(function ThreadPin({\n\teditor,\n\tthread,\n\t...props\n}: CommentingContext & {\n\teditor: Editor\n\tthread: TLCommentThread\n}) {\n\tconst { resolveAuthor } = props\n\tconst options = useCommentingOptions()\n\tconst canComment = useCanComment(props.currentUserId)\n\tconst container = useContainer()\n\tconst msg = useTranslation()\n\tconst comments = useThreadComments(editor, thread.id)\n\t// Only one thread's popover is open at a time \u2014 shared across pins via the atom.\n\tconst open = useValue('thread open', () => openThreadId.get(editor) === thread.id, [\n\t\teditor,\n\t\tthread.id,\n\t])\n\t// While dragging the marker, its page point overrides the anchor's; committed on drop.\n\tconst [dragPagePoint, setDragPagePoint] = useState<{ x: number; y: number } | null>(null)\n\tconst [resizeBounds, setResizeBounds] = useState<BoxModel | null>(null)\n\t// Hovering the marker previews the thread's opening comment, on the delay every marker uses.\n\tconst { previewShown, previewHandlers } = useMarkerPreview(editor, `pin:${thread.id}`)\n\tconst previewThreads = useMemo(() => [thread], [thread])\n\t// The 'pointer' reveal mode: is the pointer within the region's bounds (plus a grab margin)?\n\t// Driven by pointer position, not DOM hover, so moving from anywhere in the region out to a corner\n\t// handle never loses the affordance \u2014 the box stays `pointer-events: none`.\n\tconst pointerInRegion = useValue(\n\t\t'pointer in region',\n\t\t() => {\n\t\t\tif (thread.anchor.type !== 'region' || thread.pageId !== editor.getCurrentPageId())\n\t\t\t\treturn false\n\t\t\tconst m = REGION_HANDLE_MARGIN_PX / editor.getZoomLevel()\n\t\t\tconst p = editor.inputs.getCurrentPagePoint()\n\t\t\tconst a = thread.anchor\n\t\t\treturn p.x >= a.x - m && p.x <= a.x + a.w + m && p.y >= a.y - m && p.y <= a.y + a.h + m\n\t\t},\n\t\t[editor, thread.anchor, thread.pageId]\n\t)\n\t// A region's box and handles are revealed while open, mid-resize, or while the pointer is\n\t// within the region.\n\tconst revealed = open || resizeBounds != null || pointerInRegion\n\t// A region thread's pin corner is its own (the corner its creating drag released on), with\n\t// the default as the fallback for older records.\n\tconst pinCorner =\n\t\tthread.anchor.type === 'region' ? regionAnchorPinCorner(thread.anchor) : REGION_PIN_CORNER\n\t// A region resizes from its corners \u2014 every corner but the pin's own, which the pin owns.\n\tconst resizeHandles = useMemo(\n\t\t() => REGION_CORNERS.filter((c) => c.x !== pinCorner.x || c.y !== pinCorner.y),\n\t\t[pinCorner]\n\t)\n\tconst dragRef = useRef<{\n\t\tstartX: number\n\t\tstartY: number\n\t\tmoved: boolean\n\t\t// The anchor's page-space offset from the grab point, so a drag translates the pin by the\n\t\t// cursor's delta (like RegionBox's move) instead of snapping the anchor to the cursor.\n\t\toffsetX: number\n\t\toffsetY: number\n\t} | null>(null)\n\tconst markerRef = useRef<HTMLButtonElement>(null)\n\t// Wheel pass-through sits on the marker (which is never scrollable), not the layer root \u2014\n\t// see the note on the layer.\n\tusePassThroughWheelEvents(markerRef)\n\n\t// The drop-target hint is editor-global state with no automatic reset. If the pin unmounts\n\t// mid-drag (e.g. Shift+C hides comments), no pointer event will ever reach the drag handlers \u2014\n\t// clear the hint here or it stays on the shape indefinitely.\n\tuseEffect(() => {\n\t\treturn () => {\n\t\t\tif (dragRef.current) editor.setHintingShapes([])\n\t\t}\n\t}, [editor])\n\n\t// Clicking outside the open popover closes the thread. Capture phase + a class check rather than\n\t// stopPropagation, since the popover portals elsewhere in the DOM. The marker is excluded so its own\n\t// click-to-toggle handles it instead of this closing and the toggle reopening.\n\tuseEffect(() => {\n\t\tif (!open) return\n\t\tconst onPointerDown = (e: PointerEvent) => {\n\t\t\tconst target = e.target as HTMLElement | null\n\t\t\tif (!target) return\n\t\t\tif (target.closest('.tlui-cmt-canvas-popover')) return\n\t\t\tconst marker = markerRef.current\n\t\t\tif (marker && marker.contains(target)) return\n\t\t\t// A press on a region's resize handle edits this thread \u2014 don't dismiss it.\n\t\t\tif (target.closest('.tlui-cmt-canvas-region-handle')) return\n\t\t\t// A click inside a menu/popover layered above us (the sidebar's filter or overflow\n\t\t\t// dropdown, or the composer's mention picker \u2014 all portaled elsewhere) belongs to that\n\t\t\t// layer; defer to its own dismissal instead of closing the thread out from under it.\n\t\t\tif (\n\t\t\t\ttarget.closest('.tlui-menu, [data-radix-popper-content-wrapper], .tlui-cmt-mention-popup')\n\t\t\t)\n\t\t\t\treturn\n\t\t\topenThreadId.set(editor, null)\n\t\t}\n\t\tdocument.addEventListener('pointerdown', onPointerDown, true)\n\t\treturn () => document.removeEventListener('pointerdown', onPointerDown, true)\n\t}, [open, editor])\n\n\t// The pin must not unmount mid-interaction: an open thread's popover hangs off it, and a drag\n\t// or resize holds pointer capture on it \u2014 so those states are exempt from the viewport cull.\n\tconst exemptFromCull = open || dragPagePoint != null || resizeBounds != null\n\tconst point = useValue(\n\t\t'pin point',\n\t\t() => {\n\t\t\tif (thread.pageId !== editor.getCurrentPageId()) return null\n\t\t\tconst pagePoint = anchorPagePoint(editor, thread.anchor)\n\t\t\tif (!pagePoint) return null\n\t\t\tconst viewportPoint = editor.pageToViewport(pagePoint)\n\t\t\tconst inset = impreciseShapePinInset(editor, thread.anchor)\n\t\t\tconst point = inset\n\t\t\t\t? { x: viewportPoint.x + inset.x, y: viewportPoint.y + inset.y }\n\t\t\t\t: viewportPoint\n\t\t\t// Off-screen pins (plus a pre-mount margin) unmount rather than re-render every camera frame. A\n\t\t\t// region thread stays mounted while any part of its box is on screen, since the box renders here too.\n\t\t\tif (!exemptFromCull) {\n\t\t\t\tconst visible =\n\t\t\t\t\tthread.anchor.type === 'region'\n\t\t\t\t\t\t? isBoxInInflatedViewport(editor, thread.anchor)\n\t\t\t\t\t\t: isInInflatedViewport(editor, point)\n\t\t\t\tif (!visible) return null\n\t\t\t}\n\t\t\treturn point\n\t\t},\n\t\t[editor, thread.anchor, thread.pageId, exemptFromCull]\n\t)\n\tif (!point) return null\n\n\tconst PinContent = options.components.PinContent\n\tconst threadAuthor = resolveAuthor(thread.createdBy)\n\tconst pinContent = PinContent ? (\n\t\t<PinContent thread={thread} comments={comments} />\n\t) : (\n\t\t<Avatar author={threadAuthor ?? UNKNOWN_COMMENT_AUTHOR} />\n\t)\n\tconst pinLabel = msg(\n\t\tthread.resolved ? 'comments.pin-label-resolved' : 'comments.pin-label'\n\t).replace('{name}', threadAuthor?.name ?? UNKNOWN_AUTHOR)\n\n\t// Drag the marker to move the thread: position is overridden locally while dragging, then re-anchored\n\t// on drop. A region translates keeping its size; a barely-moved pointer is a click.\n\tconst isRegion = thread.anchor.type === 'region'\n\t// The marker is a button (so it's keyboard-reachable), so the drag handlers are typed to it.\n\tconst startDrag = (e: ReactPointerEvent<HTMLButtonElement>) => {\n\t\t// A middle/right-button or space-held press over a pin is a camera pan, not a pin drag \u2014\n\t\t// hand it to the canvas untouched.\n\t\tif (isCanvasPanGesture(editor, e)) {\n\t\t\tforwardPointerEventToCanvas(container, e)\n\t\t\treturn\n\t\t}\n\t\te.stopPropagation()\n\t\tconst grabPage = editor.screenToPage({ x: e.clientX, y: e.clientY })\n\t\tconst anchorPage = anchorPagePoint(editor, thread.anchor)\n\t\t// The drag delta is taken from where the pin is drawn, which for an imprecise shape pin\n\t\t// is inset from its anchor point \u2014 without this the pin jumps by the inset on drag start.\n\t\tconst inset = impreciseShapePinInset(editor, thread.anchor)\n\t\tif (anchorPage && inset) {\n\t\t\tconst zoom = editor.getZoomLevel()\n\t\t\tanchorPage.x += inset.x / zoom\n\t\t\tanchorPage.y += inset.y / zoom\n\t\t}\n\t\tdragRef.current = {\n\t\t\tstartX: e.clientX,\n\t\t\tstartY: e.clientY,\n\t\t\tmoved: false,\n\t\t\toffsetX: anchorPage ? anchorPage.x - grabPage.x : 0,\n\t\t\toffsetY: anchorPage ? anchorPage.y - grabPage.y : 0,\n\t\t}\n\t\te.currentTarget.setPointerCapture(e.pointerId)\n\t}\n\tconst onDrag = (e: ReactPointerEvent<HTMLButtonElement>) => {\n\t\tconst drag = dragRef.current\n\t\tif (!drag) return\n\t\t// Moving a pin re-anchors the thread record \u2014 a commenting write. Without the permission the\n\t\t// press stays a click (`moved` never sets, so release toggles the popover and never commits).\n\t\tif (!canComment) return\n\t\tif (!drag.moved && Math.hypot(e.clientX - drag.startX, e.clientY - drag.startY) < 4) return\n\t\tdrag.moved = true\n\t\tconst cursorPage = editor.screenToPage({ x: e.clientX, y: e.clientY })\n\t\tconst pagePoint = { x: cursorPage.x + drag.offsetX, y: cursorPage.y + drag.offsetY }\n\t\tsetDragPagePoint(pagePoint)\n\t\t// Hint the shape the pin would re-anchor to on drop \u2014 the same hit-test endDrag resolves\n\t\t// with. Regions translate rather than re-anchor, so they never hint.\n\t\tif (!isRegion) {\n\t\t\tconst hit = commentTargetShapeAt(editor, pagePoint)\n\t\t\teditor.setHintingShapes(hit ? [hit.id] : [])\n\t\t}\n\t}\n\t// A cancelled pointer (touch gesture takeover, browser interruption) aborts the drag outright:\n\t// no re-anchor commit, no click-toggle \u2014 the pin snaps back and the hint clears.\n\tconst cancelDrag = (e: ReactPointerEvent<HTMLButtonElement>) => {\n\t\tconst drag = dragRef.current\n\t\tdragRef.current = null\n\t\tif (e.currentTarget.hasPointerCapture(e.pointerId)) {\n\t\t\te.currentTarget.releasePointerCapture(e.pointerId)\n\t\t}\n\t\tif (!drag) return\n\t\tsetDragPagePoint(null)\n\t\teditor.setHintingShapes([])\n\t}\n\tconst endDrag = (e: ReactPointerEvent<HTMLButtonElement>) => {\n\t\tconst drag = dragRef.current\n\t\tdragRef.current = null\n\t\tif (e.currentTarget.hasPointerCapture(e.pointerId)) {\n\t\t\te.currentTarget.releasePointerCapture(e.pointerId)\n\t\t}\n\t\tif (!drag) return\n\t\teditor.setHintingShapes([])\n\t\tif (!drag.moved) {\n\t\t\topenThreadId.set(editor, openThreadId.get(editor) === thread.id ? null : thread.id)\n\t\t\treturn\n\t\t}\n\t\tconst cursorPage = editor.screenToPage({ x: e.clientX, y: e.clientY })\n\t\tconst pagePoint = { x: cursorPage.x + drag.offsetX, y: cursorPage.y + drag.offsetY }\n\t\tsetDragPagePoint(null)\n\t\tlet anchor: TLCommentThread['anchor']\n\t\tif (thread.anchor.type === 'region') {\n\t\t\t// Translate so the pin (the region's pin corner) lands at the drop; size unchanged.\n\t\t\tanchor = {\n\t\t\t\t...thread.anchor,\n\t\t\t\tx: pagePoint.x - pinCorner.x * thread.anchor.w,\n\t\t\t\ty: pagePoint.y - pinCorner.y * thread.anchor.h,\n\t\t\t}\n\t\t} else {\n\t\t\tconst hit = commentTargetShapeAt(editor, pagePoint)\n\t\t\tanchor = hit\n\t\t\t\t? shapeAnchorAt(\n\t\t\t\t\t\teditor,\n\t\t\t\t\t\thit.id,\n\t\t\t\t\t\tpagePoint,\n\t\t\t\t\t\tgetCommentingOptions(editor).shouldBePrecise(editor, {\n\t\t\t\t\t\t\tshapeId: hit.id,\n\t\t\t\t\t\t\tpoint: pagePoint,\n\t\t\t\t\t\t\taltKey: e.altKey,\n\t\t\t\t\t\t})\n\t\t\t\t\t)\n\t\t\t\t: { type: 'point', x: pagePoint.x, y: pagePoint.y }\n\t\t}\n\t\tcommitCommentMutation(editor, ({ put }) => put([{ ...thread, anchor }]), 'drag')\n\t}\n\n\t// The pin (and its popover) track the live edit: a resize moves it to the region's pin corner, a\n\t// move to the drag point; otherwise it sits at the stored anchor's viewport point.\n\tconst livePinPage = resizeBounds ? regionPinPoint(resizeBounds, pinCorner) : dragPagePoint\n\tconst renderPointBase = livePinPage ? editor.pageToViewport(livePinPage) : point\n\t// A region's pin centres on its corner \u2014 overlapping the box \u2014 rather than hanging off it.\n\t// The marker anchors bottom-left, so step half its 28px size (--tlui-cmt-pin-size) left and\n\t// down (screen px), matching the draft composer's --region centring on the same corner.\n\tconst renderPoint = isRegion\n\t\t? { x: renderPointBase.x - 14, y: renderPointBase.y + 14 }\n\t\t: renderPointBase\n\n\t// A region's live box bounds, by priority: a corner resize, else a pin-drag translation (the pin\n\t// corner tracks the cursor), else the stored anchor. Undefined for non-region threads.\n\tconst regionAnchor = thread.anchor.type === 'region' ? thread.anchor : undefined\n\tconst movedRegion =\n\t\tregionAnchor && dragPagePoint\n\t\t\t? {\n\t\t\t\t\t...regionAnchor,\n\t\t\t\t\tx: dragPagePoint.x - pinCorner.x * regionAnchor.w,\n\t\t\t\t\ty: dragPagePoint.y - pinCorner.y * regionAnchor.h,\n\t\t\t\t}\n\t\t\t: regionAnchor\n\tconst regionBoxBounds = resizeBounds ?? movedRegion\n\tconst commitResize = (bounds: BoxModel) => {\n\t\tsetResizeBounds(null)\n\t\tif (!canComment) return\n\t\t// Same commit path as a pin drag, so the configured `dragHistory` governs both \u2014 going\n\t\t// straight to `editor.run` here would make region resizes silently ignore the option.\n\t\tcommitCommentMutation(\n\t\t\teditor,\n\t\t\t// Spread the existing anchor first so the region's pin corner survives a resize.\n\t\t\t({ put }) => put([{ ...thread, anchor: { ...regionAnchor!, ...bounds } }]),\n\t\t\t'drag'\n\t\t)\n\t}\n\n\treturn (\n\t\t<>\n\t\t\t{regionBoxBounds && (dragPagePoint || revealed) && (\n\t\t\t\t<RegionBox editor={editor} box={regionBoxBounds} />\n\t\t\t)}\n\t\t\t{regionBoxBounds && revealed && !dragPagePoint && canComment && (\n\t\t\t\t<RegionResizeHandles\n\t\t\t\t\teditor={editor}\n\t\t\t\t\tbox={regionBoxBounds}\n\t\t\t\t\thandles={resizeHandles}\n\t\t\t\t\tonPreview={setResizeBounds}\n\t\t\t\t\tonCommit={commitResize}\n\t\t\t\t/>\n\t\t\t)}\n\t\t\t<div\n\t\t\t\tclassName={[\n\t\t\t\t\t'tlui-cmt-canvas-pin',\n\t\t\t\t\topen && 'tlui-cmt-canvas-pin--open',\n\t\t\t\t\tdragPagePoint && 'tlui-cmt-canvas-pin--dragging',\n\t\t\t\t]\n\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t.join(' ')}\n\t\t\t\tstyle={{ left: renderPoint.x, top: renderPoint.y }}\n\t\t\t>\n\t\t\t\t<button\n\t\t\t\t\tref={markerRef}\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclassName=\"tlui-cmt-button tlui-cmt-canvas-pin__marker\"\n\t\t\t\t\taria-label={pinLabel}\n\t\t\t\t\taria-expanded={open}\n\t\t\t\t\tonPointerDown={startDrag}\n\t\t\t\t\tonPointerMove={onDrag}\n\t\t\t\t\tonPointerUp={endDrag}\n\t\t\t\t\tonPointerCancel={cancelDrag}\n\t\t\t\t\t// Pointer activation is already handled by endDrag (which distinguishes a click\n\t\t\t\t\t// from a drag), so only take keyboard-synthesised clicks here \u2014 those report\n\t\t\t\t\t// `detail === 0` \u2014 or the thread would toggle twice per mouse click.\n\t\t\t\t\tonClick={(e) => {\n\t\t\t\t\t\tif (e.detail !== 0) return\n\t\t\t\t\t\topenThreadId.set(editor, openThreadId.get(editor) === thread.id ? null : thread.id)\n\t\t\t\t\t}}\n\t\t\t\t\tonPointerEnter={previewHandlers.onPointerEnter}\n\t\t\t\t\tonPointerLeave={previewHandlers.onPointerLeave}\n\t\t\t\t\t// Focus stands in for hover, so tabbing to a marker gets the same preview.\n\t\t\t\t\tonFocus={previewHandlers.onPointerEnter}\n\t\t\t\t\tonBlur={previewHandlers.onPointerLeave}\n\t\t\t\t>\n\t\t\t\t\t<CommentPin resolved={thread.resolved != null} open={open}>\n\t\t\t\t\t\t{pinContent}\n\t\t\t\t\t</CommentPin>\n\t\t\t\t</button>\n\t\t\t\t{/* The popover portals up to the menus layer (above the UI panels) so it isn't clipped;\n\t\t\t the pin itself stays in the canvas-in-front layer, beneath the UI. */}\n\t\t\t\t{open && (\n\t\t\t\t\t<ThreadPopover\n\t\t\t\t\t\tbase={{\n\t\t\t\t\t\t\tx: renderPoint.x + POPOVER_OFFSET.thread.x,\n\t\t\t\t\t\t\ty: renderPoint.y + POPOVER_OFFSET.thread.y - THREAD_HEADER_BLOCK,\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t<ThreadView editor={editor} thread={thread} {...props} />\n\t\t\t\t\t</ThreadPopover>\n\t\t\t\t)}\n\t\t\t\t{/* Not while dragging: the pin is being moved, not read, and a panel trailing the\n\t\t\t\t cursor would obscure the drop target. */}\n\t\t\t\t{previewShown && !dragPagePoint && (\n\t\t\t\t\t<ThreadPreview\n\t\t\t\t\t\teditor={editor}\n\t\t\t\t\t\tthreads={previewThreads}\n\t\t\t\t\t\tvariant=\"thread\"\n\t\t\t\t\t\tpoint={renderPoint}\n\t\t\t\t\t\tonSelectThread={() => openThreadId.set(editor, thread.id)}\n\t\t\t\t\t\t{...previewHandlers}\n\t\t\t\t\t\tcurrentUserId={props.currentUserId}\n\t\t\t\t\t\tresolveAuthor={resolveAuthor}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t</>\n\t)\n})\n"],
5
+ "mappings": "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",
6
6
  "names": ["ThreadPin", "point"]
7
7
  }
@@ -623,7 +623,9 @@ export declare interface CommentThreadProps {
623
623
  * The comment tool. Pressing down opens the comment composer at the pointer and it follows until
624
624
  * release — like placing a sticky note — settling on a point, or on a shape when released over one.
625
625
  * With region comments enabled, dragging past the threshold draws a region rectangle instead.
626
- * Placement only opens a composer; the records are created when the comment is posted.
626
+ * Placement only opens a composer; the records are created when the comment is posted. The tool
627
+ * stays active while the composer is open — posting returns to select, and clicking elsewhere
628
+ * re-places the composer.
627
629
  * @public
628
630
  */
629
631
  export declare class CommentTool extends StateNode {
@@ -836,7 +838,7 @@ export declare function focusThread(editor: Editor, thread: TLCommentThread): vo
836
838
  export declare function formatFullDateTime(iso: string, locale?: string): string;
837
839
 
838
840
  /**
839
- * Format an ISO datetime as short relative time ("2 hr. ago", "yesterday", "last wk.").
841
+ * Format an ISO datetime as compact relative time ("2h ago", "yesterday", "last wk.").
840
842
  * Locale-aware via Intl.RelativeTimeFormat.
841
843
  * @public
842
844
  */
package/dist-cjs/index.js CHANGED
@@ -144,7 +144,7 @@ var import_state = require("./canvas/state");
144
144
  var import_thread_state = require("./canvas/thread-state");
145
145
  (0, import_utils.registerTldrawLibraryVersion)(
146
146
  "@tldraw/commenting",
147
- "5.3.0-next.7654e7ac2a02",
147
+ "5.3.0-next.aefb8773a7eb",
148
148
  "cjs"
149
149
  );
150
150
  //# sourceMappingURL=index.js.map
@@ -34,7 +34,7 @@ const DIVISIONS = [
34
34
  function formatRelativeTime(iso, locale = "en") {
35
35
  const then = new Date(iso).getTime();
36
36
  if (Number.isNaN(then)) return "";
37
- const rtf = new Intl.RelativeTimeFormat(locale, { numeric: "auto", style: "short" });
37
+ const rtf = new Intl.RelativeTimeFormat(locale, { numeric: "auto", style: "narrow" });
38
38
  let duration = (then - Date.now()) / 1e3;
39
39
  if (Math.abs(duration) < 60) {
40
40
  return rtf.format(0, "second");
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/ui/format-time.ts"],
4
- "sourcesContent": ["const DIVISIONS = [\n\t{ amount: 60, unit: 'second' },\n\t{ amount: 60, unit: 'minute' },\n\t{ amount: 24, unit: 'hour' },\n\t{ amount: 7, unit: 'day' },\n\t{ amount: 4.34524, unit: 'week' },\n\t{ amount: 12, unit: 'month' },\n\t{ amount: Number.POSITIVE_INFINITY, unit: 'year' },\n] as const\n\n/**\n * Format an ISO datetime as short relative time (\"2 hr. ago\", \"yesterday\", \"last wk.\").\n * Locale-aware via Intl.RelativeTimeFormat.\n * @public\n */\nexport function formatRelativeTime(iso: string, locale = 'en'): string {\n\tconst then = new Date(iso).getTime()\n\tif (Number.isNaN(then)) return ''\n\n\tconst rtf = new Intl.RelativeTimeFormat(locale, { numeric: 'auto', style: 'short' })\n\tlet duration = (then - Date.now()) / 1000\n\t// Under a minute is just \"now\" \u2014 with second granularity the label visibly ticks while\n\t// typing a reply (every keystroke re-renders the card).\n\tif (Math.abs(duration) < 60) {\n\t\treturn rtf.format(0, 'second')\n\t}\n\tfor (const division of DIVISIONS) {\n\t\tif (Math.abs(duration) < division.amount) {\n\t\t\treturn rtf.format(Math.round(duration), division.unit)\n\t\t}\n\t\tduration /= division.amount\n\t}\n\treturn ''\n}\n\n// Cached per locale \u2014 comment cards re-render on every reply keystroke, and constructing a\n// DateTimeFormat is far more expensive than formatting with one.\nconst fullDateTimeFormatters = new Map<string, Intl.DateTimeFormat>()\n\n/**\n * Format an ISO datetime as a full date and time (\"Tuesday, July 22, 2025 at 4:44 PM\").\n * Locale-aware via Intl.DateTimeFormat.\n * @public\n */\nexport function formatFullDateTime(iso: string, locale = 'en'): string {\n\tconst date = new Date(iso)\n\tif (Number.isNaN(date.getTime())) return ''\n\tlet formatter = fullDateTimeFormatters.get(locale)\n\tif (!formatter) {\n\t\tformatter = new Intl.DateTimeFormat(locale, { dateStyle: 'full', timeStyle: 'short' })\n\t\tfullDateTimeFormatters.set(locale, formatter)\n\t}\n\treturn formatter.format(date)\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAAM,YAAY;AAAA,EACjB,EAAE,QAAQ,IAAI,MAAM,SAAS;AAAA,EAC7B,EAAE,QAAQ,IAAI,MAAM,SAAS;AAAA,EAC7B,EAAE,QAAQ,IAAI,MAAM,OAAO;AAAA,EAC3B,EAAE,QAAQ,GAAG,MAAM,MAAM;AAAA,EACzB,EAAE,QAAQ,SAAS,MAAM,OAAO;AAAA,EAChC,EAAE,QAAQ,IAAI,MAAM,QAAQ;AAAA,EAC5B,EAAE,QAAQ,OAAO,mBAAmB,MAAM,OAAO;AAClD;AAOO,SAAS,mBAAmB,KAAa,SAAS,MAAc;AACtE,QAAM,OAAO,IAAI,KAAK,GAAG,EAAE,QAAQ;AACnC,MAAI,OAAO,MAAM,IAAI,EAAG,QAAO;AAE/B,QAAM,MAAM,IAAI,KAAK,mBAAmB,QAAQ,EAAE,SAAS,QAAQ,OAAO,QAAQ,CAAC;AACnF,MAAI,YAAY,OAAO,KAAK,IAAI,KAAK;AAGrC,MAAI,KAAK,IAAI,QAAQ,IAAI,IAAI;AAC5B,WAAO,IAAI,OAAO,GAAG,QAAQ;AAAA,EAC9B;AACA,aAAW,YAAY,WAAW;AACjC,QAAI,KAAK,IAAI,QAAQ,IAAI,SAAS,QAAQ;AACzC,aAAO,IAAI,OAAO,KAAK,MAAM,QAAQ,GAAG,SAAS,IAAI;AAAA,IACtD;AACA,gBAAY,SAAS;AAAA,EACtB;AACA,SAAO;AACR;AAIA,MAAM,yBAAyB,oBAAI,IAAiC;AAO7D,SAAS,mBAAmB,KAAa,SAAS,MAAc;AACtE,QAAM,OAAO,IAAI,KAAK,GAAG;AACzB,MAAI,OAAO,MAAM,KAAK,QAAQ,CAAC,EAAG,QAAO;AACzC,MAAI,YAAY,uBAAuB,IAAI,MAAM;AACjD,MAAI,CAAC,WAAW;AACf,gBAAY,IAAI,KAAK,eAAe,QAAQ,EAAE,WAAW,QAAQ,WAAW,QAAQ,CAAC;AACrF,2BAAuB,IAAI,QAAQ,SAAS;AAAA,EAC7C;AACA,SAAO,UAAU,OAAO,IAAI;AAC7B;",
4
+ "sourcesContent": ["const DIVISIONS = [\n\t{ amount: 60, unit: 'second' },\n\t{ amount: 60, unit: 'minute' },\n\t{ amount: 24, unit: 'hour' },\n\t{ amount: 7, unit: 'day' },\n\t{ amount: 4.34524, unit: 'week' },\n\t{ amount: 12, unit: 'month' },\n\t{ amount: Number.POSITIVE_INFINITY, unit: 'year' },\n] as const\n\n/**\n * Format an ISO datetime as compact relative time (\"2h ago\", \"yesterday\", \"last wk.\").\n * Locale-aware via Intl.RelativeTimeFormat.\n * @public\n */\nexport function formatRelativeTime(iso: string, locale = 'en'): string {\n\tconst then = new Date(iso).getTime()\n\tif (Number.isNaN(then)) return ''\n\n\tconst rtf = new Intl.RelativeTimeFormat(locale, { numeric: 'auto', style: 'narrow' })\n\tlet duration = (then - Date.now()) / 1000\n\t// Under a minute is just \"now\" \u2014 with second granularity the label visibly ticks while\n\t// typing a reply (every keystroke re-renders the card).\n\tif (Math.abs(duration) < 60) {\n\t\treturn rtf.format(0, 'second')\n\t}\n\tfor (const division of DIVISIONS) {\n\t\tif (Math.abs(duration) < division.amount) {\n\t\t\treturn rtf.format(Math.round(duration), division.unit)\n\t\t}\n\t\tduration /= division.amount\n\t}\n\treturn ''\n}\n\n// Cached per locale \u2014 comment cards re-render on every reply keystroke, and constructing a\n// DateTimeFormat is far more expensive than formatting with one.\nconst fullDateTimeFormatters = new Map<string, Intl.DateTimeFormat>()\n\n/**\n * Format an ISO datetime as a full date and time (\"Tuesday, July 22, 2025 at 4:44 PM\").\n * Locale-aware via Intl.DateTimeFormat.\n * @public\n */\nexport function formatFullDateTime(iso: string, locale = 'en'): string {\n\tconst date = new Date(iso)\n\tif (Number.isNaN(date.getTime())) return ''\n\tlet formatter = fullDateTimeFormatters.get(locale)\n\tif (!formatter) {\n\t\tformatter = new Intl.DateTimeFormat(locale, { dateStyle: 'full', timeStyle: 'short' })\n\t\tfullDateTimeFormatters.set(locale, formatter)\n\t}\n\treturn formatter.format(date)\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAAM,YAAY;AAAA,EACjB,EAAE,QAAQ,IAAI,MAAM,SAAS;AAAA,EAC7B,EAAE,QAAQ,IAAI,MAAM,SAAS;AAAA,EAC7B,EAAE,QAAQ,IAAI,MAAM,OAAO;AAAA,EAC3B,EAAE,QAAQ,GAAG,MAAM,MAAM;AAAA,EACzB,EAAE,QAAQ,SAAS,MAAM,OAAO;AAAA,EAChC,EAAE,QAAQ,IAAI,MAAM,QAAQ;AAAA,EAC5B,EAAE,QAAQ,OAAO,mBAAmB,MAAM,OAAO;AAClD;AAOO,SAAS,mBAAmB,KAAa,SAAS,MAAc;AACtE,QAAM,OAAO,IAAI,KAAK,GAAG,EAAE,QAAQ;AACnC,MAAI,OAAO,MAAM,IAAI,EAAG,QAAO;AAE/B,QAAM,MAAM,IAAI,KAAK,mBAAmB,QAAQ,EAAE,SAAS,QAAQ,OAAO,SAAS,CAAC;AACpF,MAAI,YAAY,OAAO,KAAK,IAAI,KAAK;AAGrC,MAAI,KAAK,IAAI,QAAQ,IAAI,IAAI;AAC5B,WAAO,IAAI,OAAO,GAAG,QAAQ;AAAA,EAC9B;AACA,aAAW,YAAY,WAAW;AACjC,QAAI,KAAK,IAAI,QAAQ,IAAI,SAAS,QAAQ;AACzC,aAAO,IAAI,OAAO,KAAK,MAAM,QAAQ,GAAG,SAAS,IAAI;AAAA,IACtD;AACA,gBAAY,SAAS;AAAA,EACtB;AACA,SAAO;AACR;AAIA,MAAM,yBAAyB,oBAAI,IAAiC;AAO7D,SAAS,mBAAmB,KAAa,SAAS,MAAc;AACtE,QAAM,OAAO,IAAI,KAAK,GAAG;AACzB,MAAI,OAAO,MAAM,KAAK,QAAQ,CAAC,EAAG,QAAO;AACzC,MAAI,YAAY,uBAAuB,IAAI,MAAM;AACjD,MAAI,CAAC,WAAW;AACf,gBAAY,IAAI,KAAK,eAAe,QAAQ,EAAE,WAAW,QAAQ,WAAW,QAAQ,CAAC;AACrF,2BAAuB,IAAI,QAAQ,SAAS;AAAA,EAC7C;AACA,SAAO,UAAU,OAAO,IAAI;AAC7B;",
6
6
  "names": []
7
7
  }
@@ -21,7 +21,7 @@ __export(icons_exports, {
21
21
  CheckIcon: () => CheckIcon,
22
22
  EyeClosedIcon: () => EyeClosedIcon,
23
23
  EyeOpenIcon: () => EyeOpenIcon,
24
- FilterIcon: () => FilterIcon,
24
+ MoreMenuIcon: () => MoreMenuIcon,
25
25
  PinCheckIcon: () => PinCheckIcon,
26
26
  SendIcon: () => SendIcon,
27
27
  SmileyIcon: () => SmileyIcon
@@ -80,36 +80,59 @@ function SendIcon() {
80
80
  ) });
81
81
  }
82
82
  function EyeOpenIcon() {
83
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { width: "15", height: "15", viewBox: "0 0 15 15", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
84
- "path",
85
- {
86
- d: "M7.5 11C4.80285 11 2.52952 9.62184 1.09622 7.50001C2.52952 5.37816 4.80285 4 7.5 4C10.1971 4 12.4705 5.37816 13.9038 7.5C12.4705 9.62183 10.1971 11 7.5 11ZM7.5 3C4.30786 3 1.65639 4.70638 0.0760002 7.23501C-0.0253338 7.39715 -0.0253334 7.60288 0.0760014 7.76501C1.65639 10.2936 4.30786 12 7.5 12C10.6921 12 13.3436 10.2936 14.924 7.76501C15.0253 7.60288 15.0253 7.39715 14.924 7.23501C13.3436 4.70638 10.6921 3 7.5 3ZM7.5 9.5C8.60457 9.5 9.5 8.60457 9.5 7.5C9.5 6.39543 8.60457 5.5 7.5 5.5C6.39543 5.5 5.5 6.39543 5.5 7.5C5.5 8.60457 6.39543 9.5 7.5 9.5Z",
87
- fill: "currentColor",
88
- fillRule: "evenodd",
89
- clipRule: "evenodd"
90
- }
91
- ) });
83
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { width: "15", height: "15", viewBox: "0 0 30 30", fill: "none", "aria-hidden": "true", children: [
84
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { fill: "currentColor", d: "M19 15a4 4 0 1 1-8 0 4 4 0 0 1 8 0" }),
85
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
86
+ "path",
87
+ {
88
+ stroke: "currentColor",
89
+ strokeWidth: "2",
90
+ d: "M26 15c0 1.77-1.077 3.496-3.07 4.825C20.946 21.149 18.145 22 15 22s-5.945-.851-7.93-2.175C5.076 18.496 4 16.77 4 15c0-1.77 1.077-3.496 3.07-4.825C9.054 8.851 11.855 8 15 8s5.945.851 7.93 2.175C24.924 11.504 26 13.23 26 15Z"
91
+ }
92
+ )
93
+ ] });
92
94
  }
93
95
  function EyeClosedIcon() {
94
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { width: "15", height: "15", viewBox: "0 0 15 15", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
95
- "path",
96
- {
97
- d: "M14.7649 6.07596C14.9991 6.22231 15.0703 6.53079 14.9239 6.76495C14.4849 7.46743 13.9632 8.10645 13.3702 8.66305L14.5712 9.86406C14.7664 10.0593 14.7664 10.3759 14.5712 10.5712C14.3759 10.7664 14.0593 10.7664 13.8641 10.5712L12.6011 9.30817C11.805 9.90283 10.9089 10.3621 9.93375 10.651L10.383 12.3277C10.4544 12.5944 10.2961 12.8685 10.0294 12.94C9.76267 13.0115 9.4885 12.8532 9.41704 12.5865L8.95917 10.8775C8.48743 10.958 8.00036 11 7.50001 11C6.99965 11 6.51257 10.958 6.04082 10.8775L5.58299 12.5864C5.51153 12.8532 5.23737 13.0115 4.97064 12.94C4.7039 12.8686 4.5456 12.5944 4.61706 12.3277L5.06625 10.651C4.09111 10.3621 3.19503 9.90282 2.39889 9.30815L1.1359 10.5712C0.940638 10.7664 0.624058 10.7664 0.428798 10.5712C0.233537 10.3759 0.233537 10.0593 0.428798 9.86405L1.62982 8.66303C1.03682 8.10643 0.515113 7.46742 0.0760677 6.76495C-0.0702867 6.53079 0.000898544 6.22231 0.235065 6.07596C0.469231 5.9296 0.777703 6.00079 0.924058 6.23496C1.40354 7.00213 1.989 7.68057 2.66233 8.2427C2.67315 8.25096 2.6837 8.25972 2.69397 8.26898C4.00897 9.35527 5.65537 10 7.50001 10C10.3078 10 12.6564 8.5063 14.076 6.23495C14.2223 6.00079 14.5308 5.9296 14.7649 6.07596Z",
98
- fill: "currentColor",
99
- fillRule: "evenodd",
100
- clipRule: "evenodd"
101
- }
102
- ) });
96
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { width: "15", height: "15", viewBox: "0 0 30 30", fill: "none", "aria-hidden": "true", children: [
97
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
98
+ "path",
99
+ {
100
+ stroke: "currentColor",
101
+ strokeWidth: "2",
102
+ strokeLinecap: "round",
103
+ d: "M27 15C27 19.4183 21.6274 23 15 23C8.37258 23 3 19.4183 3 15"
104
+ }
105
+ ),
106
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "4", cy: "20", r: "1.5", fill: "currentColor" }),
107
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "9", cy: "23", r: "1.5", fill: "currentColor" }),
108
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "15", cy: "24", r: "1.5", fill: "currentColor" }),
109
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "21", cy: "23", r: "1.5", fill: "currentColor" }),
110
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "26", cy: "20", r: "1.5", fill: "currentColor" })
111
+ ] });
103
112
  }
104
- function FilterIcon() {
105
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { width: "15", height: "15", viewBox: "0 0 15 15", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
106
- "path",
107
- {
108
- d: "M5.5 3C4.67157 3 4 3.67157 4 4.5C4 5.32843 4.67157 6 5.5 6C6.32843 6 7 5.32843 7 4.5C7 3.67157 6.32843 3 5.5 3ZM3 5C3.01671 5 3.03323 4.99918 3.04952 4.99758C3.28022 6.1399 4.28967 7 5.5 7C6.71033 7 7.71978 6.1399 7.95048 4.99758C7.96677 4.99918 7.98329 5 8 5H13.5C13.7761 5 14 4.77614 14 4.5C14 4.22386 13.7761 4 13.5 4H8C7.98329 4 7.96677 4.00082 7.95048 4.00242C7.71978 2.86009 6.71033 2 5.5 2C4.28967 2 3.28022 2.86009 3.04952 4.00242C3.03323 4.00082 3.01671 4 3 4H1.5C1.22386 4 1 4.22386 1 4.5C1 4.77614 1.22386 5 1.5 5H3ZM11.9505 10.9976C11.7198 12.1399 10.7103 13 9.5 13C8.28967 13 7.28022 12.1399 7.04952 10.9976C7.03323 10.9992 7.01671 11 7 11H1.5C1.22386 11 1 10.7761 1 10.5C1 10.2239 1.22386 10 1.5 10H7C7.01671 10 7.03323 10.0008 7.04952 10.0024C7.28022 8.8601 8.28967 8 9.5 8C10.7103 8 11.7198 8.8601 11.9505 10.0024C11.9668 10.0008 11.9833 10 12 10H13.5C13.7761 10 14 10.2239 14 10.5C14 10.7761 13.7761 11 13.5 11H12C11.9833 11 11.9668 10.9992 11.9505 10.9976ZM8 10.5C8 9.67157 8.67157 9 9.5 9C10.3284 9 11 9.67157 11 10.5C11 11.3284 10.3284 12 9.5 12C8.67157 12 8 11.3284 8 10.5Z",
109
- fill: "currentColor",
110
- fillRule: "evenodd",
111
- clipRule: "evenodd"
112
- }
113
- ) });
113
+ function MoreMenuIcon() {
114
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { width: "15", height: "15", viewBox: "0 0 30 30", fill: "none", "aria-hidden": "true", children: [
115
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
116
+ "path",
117
+ {
118
+ fill: "currentColor",
119
+ d: "M15 9.48975C14.3167 9.48975 13.7292 9.24747 13.2375 8.76293C12.7458 8.27003 12.5 7.67688 12.5 6.98348C12.5 6.29843 12.7458 5.71364 13.2375 5.22909C13.7292 4.73619 14.3167 4.48975 15 4.48975C15.6833 4.48975 16.2708 4.73619 16.7625 5.22909C17.2542 5.71364 17.5 6.29843 17.5 6.98348C17.5 7.44296 17.3833 7.86485 17.15 8.24914C16.925 8.62508 16.625 8.92583 16.25 9.1514C15.875 9.37696 15.4583 9.48975 15 9.48975Z"
120
+ }
121
+ ),
122
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
123
+ "path",
124
+ {
125
+ fill: "currentColor",
126
+ d: "M15 17.5C14.3167 17.5 13.7292 17.2577 13.2375 16.7732C12.7458 16.2803 12.5 15.6871 12.5 14.9937C12.5 14.3087 12.7458 13.7239 13.2375 13.2393C13.7292 12.7464 14.3167 12.5 15 12.5C15.6833 12.5 16.2708 12.7464 16.7625 13.2393C17.2542 13.7239 17.5 14.3087 17.5 14.9937C17.5 15.4532 17.3833 15.8751 17.15 16.2594C16.925 16.6353 16.625 16.9361 16.25 17.1617C15.875 17.3872 15.4583 17.5 15 17.5Z"
127
+ }
128
+ ),
129
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
130
+ "path",
131
+ {
132
+ fill: "currentColor",
133
+ d: "M15 25.5103C14.3167 25.5103 13.7292 25.268 13.2375 24.7834C12.7458 24.2905 12.5 23.6974 12.5 23.004C12.5 22.319 12.7458 21.7342 13.2375 21.2496C13.7292 20.7567 14.3167 20.5103 15 20.5103C15.6833 20.5103 16.2708 20.7567 16.7625 21.2496C17.2542 21.7342 17.5 22.319 17.5 23.004C17.5 23.4635 17.3833 23.8854 17.15 24.2697C16.925 24.6456 16.625 24.9463 16.25 25.1719C15.875 25.3975 15.4583 25.5103 15 25.5103Z"
134
+ }
135
+ )
136
+ ] });
114
137
  }
115
138
  //# sourceMappingURL=icons.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/ui/icons.tsx"],
4
- "sourcesContent": ["/* The commenting UI's inline icons, kept together so the set is visible in one place.\n *\n * Anything with an equivalent in tldraw's icon assets goes through `TldrawUiIcon` instead (the \u22EF\n * menu, the dismiss cross, the resolve button's check). What's left lives here because the asset\n * set has no counterpart \u2014 a smiley, a send arrow, the eye pair, a filter \u2014 or because the asset\n * reads wrong at the size it's needed, which is the case for both resolved checks below. Inline\n * also means they render without an `AssetUrlsProvider` and without the consumer serving files.\n *\n * All internal \u2014 none are exported from the package. */\n\n/** The check inside a resolved comment pin. A drawn check, not the '\u2713' glyph \u2014 that character sits\n * off-baseline and varies by font. Heavier and rounder than `CheckIcon`: it has to hold its weight\n * against the pin's 28px filled face, where the asset check reads too light. */\nexport function PinCheckIcon() {\n\treturn (\n\t\t<svg\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\twidth=\"15\"\n\t\t\theight=\"15\"\n\t\t\tfill=\"none\"\n\t\t\tstroke=\"currentColor\"\n\t\t\tstrokeWidth=\"2.5\"\n\t\t\tstrokeLinecap=\"round\"\n\t\t\tstrokeLinejoin=\"round\"\n\t\t\taria-hidden=\"true\"\n\t\t>\n\t\t\t<path d=\"M4 12.5l5 5L20 6.5\" />\n\t\t</svg>\n\t)\n}\n\n/** The check beside the \"Resolved\" label on a comments list row. Thinner than `PinCheckIcon` \u2014 it\n * sits next to text at 12px, so it's drawn to match the label's weight rather than shout. */\nexport function CheckIcon() {\n\treturn (\n\t\t<svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" aria-hidden=\"true\">\n\t\t\t<path\n\t\t\t\td=\"M2.5 6.2 4.7 8.4 9.5 3.6\"\n\t\t\t\tstroke=\"currentColor\"\n\t\t\t\tstrokeWidth=\"1.5\"\n\t\t\t\tstrokeLinecap=\"round\"\n\t\t\t\tstrokeLinejoin=\"round\"\n\t\t\t/>\n\t\t</svg>\n\t)\n}\n\n/** The reaction picker's trigger. */\nexport function SmileyIcon() {\n\treturn (\n\t\t<svg width=\"15\" height=\"15\" viewBox=\"0 0 15 15\" fill=\"none\" aria-hidden=\"true\">\n\t\t\t<path\n\t\t\t\td=\"M7.49991 0.876892C3.84222 0.876892 0.877075 3.84204 0.877075 7.49972C0.877075 11.1574 3.84222 14.1226 7.49991 14.1226C11.1576 14.1226 14.1227 11.1574 14.1227 7.49972C14.1227 3.84204 11.1576 0.876892 7.49991 0.876892ZM1.82708 7.49972C1.82708 4.36671 4.36689 1.82689 7.49991 1.82689C10.6329 1.82689 13.1727 4.36671 13.1727 7.49972C13.1727 10.6327 10.6329 13.1726 7.49991 13.1726C4.36689 13.1726 1.82708 10.6327 1.82708 7.49972ZM5.03747 9.21395C4.87949 8.98746 4.56782 8.93193 4.34133 9.08991C4.11484 9.24789 4.05931 9.55956 4.21729 9.78605C4.93926 10.8211 6.14033 11.5 7.50004 11.5C8.85974 11.5 10.0608 10.8211 10.7828 9.78605C10.9408 9.55956 10.8852 9.24789 10.6587 9.08991C10.4323 8.93193 10.1206 8.98746 9.9626 9.21395C9.41963 9.99238 8.51907 10.5 7.50004 10.5C6.481 10.5 5.58044 9.99238 5.03747 9.21395ZM5.37503 6.84998C5.85828 6.84998 6.25003 6.45815 6.25003 5.97498C6.25003 5.4918 5.85828 5.09998 5.37503 5.09998C4.89179 5.09998 4.50003 5.4918 4.50003 5.97498C4.50003 6.45815 4.89179 6.84998 5.37503 6.84998ZM10.5 5.97498C10.5 6.45815 10.1083 6.84998 9.62503 6.84998C9.14179 6.84998 8.75003 6.45815 8.75003 5.97498C8.75003 5.4918 9.14179 5.09998 9.62503 5.09998C10.1083 5.09998 10.5 5.4918 10.5 5.97498Z\"\n\t\t\t\tfill=\"currentColor\"\n\t\t\t\tfillRule=\"evenodd\"\n\t\t\t\tclipRule=\"evenodd\"\n\t\t\t/>\n\t\t</svg>\n\t)\n}\n\n/** The composer's post button \u2014 an up arrow. */\nexport function SendIcon() {\n\treturn (\n\t\t<svg width=\"15\" height=\"15\" viewBox=\"0 0 15 15\" fill=\"none\" aria-hidden=\"true\">\n\t\t\t<path\n\t\t\t\td=\"M7.14645 2.14645C7.34171 1.95118 7.65829 1.95118 7.85355 2.14645L11.8536 6.14645C12.0488 6.34171 12.0488 6.65829 11.8536 6.85355C11.6583 7.04882 11.3417 7.04882 11.1464 6.85355L8 3.70711L8 12.5C8 12.7761 7.77614 13 7.5 13C7.22386 13 7 12.7761 7 12.5L7 3.70711L3.85355 6.85355C3.65829 7.04882 3.34171 7.04882 3.14645 6.85355C2.95118 6.65829 2.95118 6.34171 3.14645 6.14645L7.14645 2.14645Z\"\n\t\t\t\tfill=\"currentColor\"\n\t\t\t\tfillRule=\"evenodd\"\n\t\t\t\tclipRule=\"evenodd\"\n\t\t\t/>\n\t\t</svg>\n\t)\n}\n\n/** Comment pins are showing. Pairs with `EyeClosedIcon` \u2014 the two must stay the same family. */\nexport function EyeOpenIcon() {\n\treturn (\n\t\t<svg width=\"15\" height=\"15\" viewBox=\"0 0 15 15\" fill=\"none\" aria-hidden=\"true\">\n\t\t\t<path\n\t\t\t\td=\"M7.5 11C4.80285 11 2.52952 9.62184 1.09622 7.50001C2.52952 5.37816 4.80285 4 7.5 4C10.1971 4 12.4705 5.37816 13.9038 7.5C12.4705 9.62183 10.1971 11 7.5 11ZM7.5 3C4.30786 3 1.65639 4.70638 0.0760002 7.23501C-0.0253338 7.39715 -0.0253334 7.60288 0.0760014 7.76501C1.65639 10.2936 4.30786 12 7.5 12C10.6921 12 13.3436 10.2936 14.924 7.76501C15.0253 7.60288 15.0253 7.39715 14.924 7.23501C13.3436 4.70638 10.6921 3 7.5 3ZM7.5 9.5C8.60457 9.5 9.5 8.60457 9.5 7.5C9.5 6.39543 8.60457 5.5 7.5 5.5C6.39543 5.5 5.5 6.39543 5.5 7.5C5.5 8.60457 6.39543 9.5 7.5 9.5Z\"\n\t\t\t\tfill=\"currentColor\"\n\t\t\t\tfillRule=\"evenodd\"\n\t\t\t\tclipRule=\"evenodd\"\n\t\t\t/>\n\t\t</svg>\n\t)\n}\n\n/** Comment pins are hidden. */\nexport function EyeClosedIcon() {\n\treturn (\n\t\t<svg width=\"15\" height=\"15\" viewBox=\"0 0 15 15\" fill=\"none\" aria-hidden=\"true\">\n\t\t\t<path\n\t\t\t\td=\"M14.7649 6.07596C14.9991 6.22231 15.0703 6.53079 14.9239 6.76495C14.4849 7.46743 13.9632 8.10645 13.3702 8.66305L14.5712 9.86406C14.7664 10.0593 14.7664 10.3759 14.5712 10.5712C14.3759 10.7664 14.0593 10.7664 13.8641 10.5712L12.6011 9.30817C11.805 9.90283 10.9089 10.3621 9.93375 10.651L10.383 12.3277C10.4544 12.5944 10.2961 12.8685 10.0294 12.94C9.76267 13.0115 9.4885 12.8532 9.41704 12.5865L8.95917 10.8775C8.48743 10.958 8.00036 11 7.50001 11C6.99965 11 6.51257 10.958 6.04082 10.8775L5.58299 12.5864C5.51153 12.8532 5.23737 13.0115 4.97064 12.94C4.7039 12.8686 4.5456 12.5944 4.61706 12.3277L5.06625 10.651C4.09111 10.3621 3.19503 9.90282 2.39889 9.30815L1.1359 10.5712C0.940638 10.7664 0.624058 10.7664 0.428798 10.5712C0.233537 10.3759 0.233537 10.0593 0.428798 9.86405L1.62982 8.66303C1.03682 8.10643 0.515113 7.46742 0.0760677 6.76495C-0.0702867 6.53079 0.000898544 6.22231 0.235065 6.07596C0.469231 5.9296 0.777703 6.00079 0.924058 6.23496C1.40354 7.00213 1.989 7.68057 2.66233 8.2427C2.67315 8.25096 2.6837 8.25972 2.69397 8.26898C4.00897 9.35527 5.65537 10 7.50001 10C10.3078 10 12.6564 8.5063 14.076 6.23495C14.2223 6.00079 14.5308 5.9296 14.7649 6.07596Z\"\n\t\t\t\tfill=\"currentColor\"\n\t\t\t\tfillRule=\"evenodd\"\n\t\t\t\tclipRule=\"evenodd\"\n\t\t\t/>\n\t\t</svg>\n\t)\n}\n\n/** The sidebar's filter menu trigger. */\nexport function FilterIcon() {\n\treturn (\n\t\t<svg width=\"15\" height=\"15\" viewBox=\"0 0 15 15\" fill=\"none\" aria-hidden=\"true\">\n\t\t\t<path\n\t\t\t\td=\"M5.5 3C4.67157 3 4 3.67157 4 4.5C4 5.32843 4.67157 6 5.5 6C6.32843 6 7 5.32843 7 4.5C7 3.67157 6.32843 3 5.5 3ZM3 5C3.01671 5 3.03323 4.99918 3.04952 4.99758C3.28022 6.1399 4.28967 7 5.5 7C6.71033 7 7.71978 6.1399 7.95048 4.99758C7.96677 4.99918 7.98329 5 8 5H13.5C13.7761 5 14 4.77614 14 4.5C14 4.22386 13.7761 4 13.5 4H8C7.98329 4 7.96677 4.00082 7.95048 4.00242C7.71978 2.86009 6.71033 2 5.5 2C4.28967 2 3.28022 2.86009 3.04952 4.00242C3.03323 4.00082 3.01671 4 3 4H1.5C1.22386 4 1 4.22386 1 4.5C1 4.77614 1.22386 5 1.5 5H3ZM11.9505 10.9976C11.7198 12.1399 10.7103 13 9.5 13C8.28967 13 7.28022 12.1399 7.04952 10.9976C7.03323 10.9992 7.01671 11 7 11H1.5C1.22386 11 1 10.7761 1 10.5C1 10.2239 1.22386 10 1.5 10H7C7.01671 10 7.03323 10.0008 7.04952 10.0024C7.28022 8.8601 8.28967 8 9.5 8C10.7103 8 11.7198 8.8601 11.9505 10.0024C11.9668 10.0008 11.9833 10 12 10H13.5C13.7761 10 14 10.2239 14 10.5C14 10.7761 13.7761 11 13.5 11H12C11.9833 11 11.9668 10.9992 11.9505 10.9976ZM8 10.5C8 9.67157 8.67157 9 9.5 9C10.3284 9 11 9.67157 11 10.5C11 11.3284 10.3284 12 9.5 12C8.67157 12 8 11.3284 8 10.5Z\"\n\t\t\t\tfill=\"currentColor\"\n\t\t\t\tfillRule=\"evenodd\"\n\t\t\t\tclipRule=\"evenodd\"\n\t\t\t/>\n\t\t</svg>\n\t)\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA0BG;AAbI,SAAS,eAAe;AAC9B,SACC;AAAA,IAAC;AAAA;AAAA,MACA,SAAQ;AAAA,MACR,OAAM;AAAA,MACN,QAAO;AAAA,MACP,MAAK;AAAA,MACL,QAAO;AAAA,MACP,aAAY;AAAA,MACZ,eAAc;AAAA,MACd,gBAAe;AAAA,MACf,eAAY;AAAA,MAEZ,sDAAC,UAAK,GAAE,sBAAqB;AAAA;AAAA,EAC9B;AAEF;AAIO,SAAS,YAAY;AAC3B,SACC,4CAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,eAAY,QACvE;AAAA,IAAC;AAAA;AAAA,MACA,GAAE;AAAA,MACF,QAAO;AAAA,MACP,aAAY;AAAA,MACZ,eAAc;AAAA,MACd,gBAAe;AAAA;AAAA,EAChB,GACD;AAEF;AAGO,SAAS,aAAa;AAC5B,SACC,4CAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,eAAY,QACvE;AAAA,IAAC;AAAA;AAAA,MACA,GAAE;AAAA,MACF,MAAK;AAAA,MACL,UAAS;AAAA,MACT,UAAS;AAAA;AAAA,EACV,GACD;AAEF;AAGO,SAAS,WAAW;AAC1B,SACC,4CAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,eAAY,QACvE;AAAA,IAAC;AAAA;AAAA,MACA,GAAE;AAAA,MACF,MAAK;AAAA,MACL,UAAS;AAAA,MACT,UAAS;AAAA;AAAA,EACV,GACD;AAEF;AAGO,SAAS,cAAc;AAC7B,SACC,4CAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,eAAY,QACvE;AAAA,IAAC;AAAA;AAAA,MACA,GAAE;AAAA,MACF,MAAK;AAAA,MACL,UAAS;AAAA,MACT,UAAS;AAAA;AAAA,EACV,GACD;AAEF;AAGO,SAAS,gBAAgB;AAC/B,SACC,4CAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,eAAY,QACvE;AAAA,IAAC;AAAA;AAAA,MACA,GAAE;AAAA,MACF,MAAK;AAAA,MACL,UAAS;AAAA,MACT,UAAS;AAAA;AAAA,EACV,GACD;AAEF;AAGO,SAAS,aAAa;AAC5B,SACC,4CAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,eAAY,QACvE;AAAA,IAAC;AAAA;AAAA,MACA,GAAE;AAAA,MACF,MAAK;AAAA,MACL,UAAS;AAAA,MACT,UAAS;AAAA;AAAA,EACV,GACD;AAEF;",
4
+ "sourcesContent": ["/* The commenting UI's inline icons, kept together so the set is visible in one place.\n *\n * Anything with an equivalent in tldraw's icon assets goes through `TldrawUiIcon` instead (the \u22EF\n * menu, the dismiss cross, the resolve button's check). What's left lives here because the asset\n * set has no counterpart \u2014 a smiley, a send arrow, a filter \u2014 or because the asset reads wrong at\n * the size it's needed, which is the case for both resolved checks below. The eye pair mirrors\n * tldraw's presence glyphs: the open state is the `follow` icon \u2014 the almond eye whose pupil\n * tracks presence \u2014 and the closed state the `closed` icon, its shut-lid companion. Both are in\n * the asset set, but they're inlined because the package renders without an `AssetUrlsProvider`,\n * so `TldrawUiIcon` can't reach them. Inline also means they render without the consumer serving\n * files.\n *\n * All internal \u2014 none are exported from the package. */\n\n/** The check inside a resolved comment pin. A drawn check, not the '\u2713' glyph \u2014 that character sits\n * off-baseline and varies by font. Heavier and rounder than `CheckIcon`: it has to hold its weight\n * against the pin's 28px filled face, where the asset check reads too light. */\nexport function PinCheckIcon() {\n\treturn (\n\t\t<svg\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\twidth=\"15\"\n\t\t\theight=\"15\"\n\t\t\tfill=\"none\"\n\t\t\tstroke=\"currentColor\"\n\t\t\tstrokeWidth=\"2.5\"\n\t\t\tstrokeLinecap=\"round\"\n\t\t\tstrokeLinejoin=\"round\"\n\t\t\taria-hidden=\"true\"\n\t\t>\n\t\t\t<path d=\"M4 12.5l5 5L20 6.5\" />\n\t\t</svg>\n\t)\n}\n\n/** The check beside the \"Resolved\" label on a comments list row. Thinner than `PinCheckIcon` \u2014 it\n * sits next to text at 12px, so it's drawn to match the label's weight rather than shout. */\nexport function CheckIcon() {\n\treturn (\n\t\t<svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" aria-hidden=\"true\">\n\t\t\t<path\n\t\t\t\td=\"M2.5 6.2 4.7 8.4 9.5 3.6\"\n\t\t\t\tstroke=\"currentColor\"\n\t\t\t\tstrokeWidth=\"1.5\"\n\t\t\t\tstrokeLinecap=\"round\"\n\t\t\t\tstrokeLinejoin=\"round\"\n\t\t\t/>\n\t\t</svg>\n\t)\n}\n\n/** The reaction picker's trigger. */\nexport function SmileyIcon() {\n\treturn (\n\t\t<svg width=\"15\" height=\"15\" viewBox=\"0 0 15 15\" fill=\"none\" aria-hidden=\"true\">\n\t\t\t<path\n\t\t\t\td=\"M7.49991 0.876892C3.84222 0.876892 0.877075 3.84204 0.877075 7.49972C0.877075 11.1574 3.84222 14.1226 7.49991 14.1226C11.1576 14.1226 14.1227 11.1574 14.1227 7.49972C14.1227 3.84204 11.1576 0.876892 7.49991 0.876892ZM1.82708 7.49972C1.82708 4.36671 4.36689 1.82689 7.49991 1.82689C10.6329 1.82689 13.1727 4.36671 13.1727 7.49972C13.1727 10.6327 10.6329 13.1726 7.49991 13.1726C4.36689 13.1726 1.82708 10.6327 1.82708 7.49972ZM5.03747 9.21395C4.87949 8.98746 4.56782 8.93193 4.34133 9.08991C4.11484 9.24789 4.05931 9.55956 4.21729 9.78605C4.93926 10.8211 6.14033 11.5 7.50004 11.5C8.85974 11.5 10.0608 10.8211 10.7828 9.78605C10.9408 9.55956 10.8852 9.24789 10.6587 9.08991C10.4323 8.93193 10.1206 8.98746 9.9626 9.21395C9.41963 9.99238 8.51907 10.5 7.50004 10.5C6.481 10.5 5.58044 9.99238 5.03747 9.21395ZM5.37503 6.84998C5.85828 6.84998 6.25003 6.45815 6.25003 5.97498C6.25003 5.4918 5.85828 5.09998 5.37503 5.09998C4.89179 5.09998 4.50003 5.4918 4.50003 5.97498C4.50003 6.45815 4.89179 6.84998 5.37503 6.84998ZM10.5 5.97498C10.5 6.45815 10.1083 6.84998 9.62503 6.84998C9.14179 6.84998 8.75003 6.45815 8.75003 5.97498C8.75003 5.4918 9.14179 5.09998 9.62503 5.09998C10.1083 5.09998 10.5 5.4918 10.5 5.97498Z\"\n\t\t\t\tfill=\"currentColor\"\n\t\t\t\tfillRule=\"evenodd\"\n\t\t\t\tclipRule=\"evenodd\"\n\t\t\t/>\n\t\t</svg>\n\t)\n}\n\n/** The composer's post button \u2014 an up arrow. */\nexport function SendIcon() {\n\treturn (\n\t\t<svg width=\"15\" height=\"15\" viewBox=\"0 0 15 15\" fill=\"none\" aria-hidden=\"true\">\n\t\t\t<path\n\t\t\t\td=\"M7.14645 2.14645C7.34171 1.95118 7.65829 1.95118 7.85355 2.14645L11.8536 6.14645C12.0488 6.34171 12.0488 6.65829 11.8536 6.85355C11.6583 7.04882 11.3417 7.04882 11.1464 6.85355L8 3.70711L8 12.5C8 12.7761 7.77614 13 7.5 13C7.22386 13 7 12.7761 7 12.5L7 3.70711L3.85355 6.85355C3.65829 7.04882 3.34171 7.04882 3.14645 6.85355C2.95118 6.65829 2.95118 6.34171 3.14645 6.14645L7.14645 2.14645Z\"\n\t\t\t\tfill=\"currentColor\"\n\t\t\t\tfillRule=\"evenodd\"\n\t\t\t\tclipRule=\"evenodd\"\n\t\t\t/>\n\t\t</svg>\n\t)\n}\n\n/** Comment pins are showing. tldraw's `follow` glyph (icons/icon/follow.svg) inlined at its native\n * weight \u2014 the almond eye with a centred pupil. Pairs with `EyeClosedIcon`; the two must stay the\n * same family. */\nexport function EyeOpenIcon() {\n\treturn (\n\t\t<svg width=\"15\" height=\"15\" viewBox=\"0 0 30 30\" fill=\"none\" aria-hidden=\"true\">\n\t\t\t<path fill=\"currentColor\" d=\"M19 15a4 4 0 1 1-8 0 4 4 0 0 1 8 0\" />\n\t\t\t<path\n\t\t\t\tstroke=\"currentColor\"\n\t\t\t\tstrokeWidth=\"2\"\n\t\t\t\td=\"M26 15c0 1.77-1.077 3.496-3.07 4.825C20.946 21.149 18.145 22 15 22s-5.945-.851-7.93-2.175C5.076 18.496 4 16.77 4 15c0-1.77 1.077-3.496 3.07-4.825C9.054 8.851 11.855 8 15 8s5.945.851 7.93 2.175C24.924 11.504 26 13.23 26 15Z\"\n\t\t\t/>\n\t\t</svg>\n\t)\n}\n\n/** Comment pins are hidden. tldraw's `closed` eye glyph (icons/icon/closed.svg) \u2014 a shut lower lid\n * with lashes, the design pair to `follow`. Inlined like the open eye: the package renders without\n * an `AssetUrlsProvider`. Lash dots are `r=1.5` (vs the asset's `r=1`) because at the 15px header\n * size the asset's finer lashes fall below a pixel; the lid keeps `follow`'s native stroke. */\nexport function EyeClosedIcon() {\n\treturn (\n\t\t<svg width=\"15\" height=\"15\" viewBox=\"0 0 30 30\" fill=\"none\" aria-hidden=\"true\">\n\t\t\t<path\n\t\t\t\tstroke=\"currentColor\"\n\t\t\t\tstrokeWidth=\"2\"\n\t\t\t\tstrokeLinecap=\"round\"\n\t\t\t\td=\"M27 15C27 19.4183 21.6274 23 15 23C8.37258 23 3 19.4183 3 15\"\n\t\t\t/>\n\t\t\t<circle cx=\"4\" cy=\"20\" r=\"1.5\" fill=\"currentColor\" />\n\t\t\t<circle cx=\"9\" cy=\"23\" r=\"1.5\" fill=\"currentColor\" />\n\t\t\t<circle cx=\"15\" cy=\"24\" r=\"1.5\" fill=\"currentColor\" />\n\t\t\t<circle cx=\"21\" cy=\"23\" r=\"1.5\" fill=\"currentColor\" />\n\t\t\t<circle cx=\"26\" cy=\"20\" r=\"1.5\" fill=\"currentColor\" />\n\t\t</svg>\n\t)\n}\n\n/** The sidebar's comment-menu trigger \u2014 tldraw's `dots-vertical` glyph (icons/icon/dots-vertical.svg)\n * inlined, a vertical kebab. Inlined like the eye pair because the package renders without an\n * `AssetUrlsProvider`. */\nexport function MoreMenuIcon() {\n\treturn (\n\t\t<svg width=\"15\" height=\"15\" viewBox=\"0 0 30 30\" fill=\"none\" aria-hidden=\"true\">\n\t\t\t<path\n\t\t\t\tfill=\"currentColor\"\n\t\t\t\td=\"M15 9.48975C14.3167 9.48975 13.7292 9.24747 13.2375 8.76293C12.7458 8.27003 12.5 7.67688 12.5 6.98348C12.5 6.29843 12.7458 5.71364 13.2375 5.22909C13.7292 4.73619 14.3167 4.48975 15 4.48975C15.6833 4.48975 16.2708 4.73619 16.7625 5.22909C17.2542 5.71364 17.5 6.29843 17.5 6.98348C17.5 7.44296 17.3833 7.86485 17.15 8.24914C16.925 8.62508 16.625 8.92583 16.25 9.1514C15.875 9.37696 15.4583 9.48975 15 9.48975Z\"\n\t\t\t/>\n\t\t\t<path\n\t\t\t\tfill=\"currentColor\"\n\t\t\t\td=\"M15 17.5C14.3167 17.5 13.7292 17.2577 13.2375 16.7732C12.7458 16.2803 12.5 15.6871 12.5 14.9937C12.5 14.3087 12.7458 13.7239 13.2375 13.2393C13.7292 12.7464 14.3167 12.5 15 12.5C15.6833 12.5 16.2708 12.7464 16.7625 13.2393C17.2542 13.7239 17.5 14.3087 17.5 14.9937C17.5 15.4532 17.3833 15.8751 17.15 16.2594C16.925 16.6353 16.625 16.9361 16.25 17.1617C15.875 17.3872 15.4583 17.5 15 17.5Z\"\n\t\t\t/>\n\t\t\t<path\n\t\t\t\tfill=\"currentColor\"\n\t\t\t\td=\"M15 25.5103C14.3167 25.5103 13.7292 25.268 13.2375 24.7834C12.7458 24.2905 12.5 23.6974 12.5 23.004C12.5 22.319 12.7458 21.7342 13.2375 21.2496C13.7292 20.7567 14.3167 20.5103 15 20.5103C15.6833 20.5103 16.2708 20.7567 16.7625 21.2496C17.2542 21.7342 17.5 22.319 17.5 23.004C17.5 23.4635 17.3833 23.8854 17.15 24.2697C16.925 24.6456 16.625 24.9463 16.25 25.1719C15.875 25.3975 15.4583 25.5103 15 25.5103Z\"\n\t\t\t/>\n\t\t</svg>\n\t)\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA8BG;AAbI,SAAS,eAAe;AAC9B,SACC;AAAA,IAAC;AAAA;AAAA,MACA,SAAQ;AAAA,MACR,OAAM;AAAA,MACN,QAAO;AAAA,MACP,MAAK;AAAA,MACL,QAAO;AAAA,MACP,aAAY;AAAA,MACZ,eAAc;AAAA,MACd,gBAAe;AAAA,MACf,eAAY;AAAA,MAEZ,sDAAC,UAAK,GAAE,sBAAqB;AAAA;AAAA,EAC9B;AAEF;AAIO,SAAS,YAAY;AAC3B,SACC,4CAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,eAAY,QACvE;AAAA,IAAC;AAAA;AAAA,MACA,GAAE;AAAA,MACF,QAAO;AAAA,MACP,aAAY;AAAA,MACZ,eAAc;AAAA,MACd,gBAAe;AAAA;AAAA,EAChB,GACD;AAEF;AAGO,SAAS,aAAa;AAC5B,SACC,4CAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,eAAY,QACvE;AAAA,IAAC;AAAA;AAAA,MACA,GAAE;AAAA,MACF,MAAK;AAAA,MACL,UAAS;AAAA,MACT,UAAS;AAAA;AAAA,EACV,GACD;AAEF;AAGO,SAAS,WAAW;AAC1B,SACC,4CAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,eAAY,QACvE;AAAA,IAAC;AAAA;AAAA,MACA,GAAE;AAAA,MACF,MAAK;AAAA,MACL,UAAS;AAAA,MACT,UAAS;AAAA;AAAA,EACV,GACD;AAEF;AAKO,SAAS,cAAc;AAC7B,SACC,6CAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,eAAY,QACvE;AAAA,gDAAC,UAAK,MAAK,gBAAe,GAAE,sCAAqC;AAAA,IACjE;AAAA,MAAC;AAAA;AAAA,QACA,QAAO;AAAA,QACP,aAAY;AAAA,QACZ,GAAE;AAAA;AAAA,IACH;AAAA,KACD;AAEF;AAMO,SAAS,gBAAgB;AAC/B,SACC,6CAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,eAAY,QACvE;AAAA;AAAA,MAAC;AAAA;AAAA,QACA,QAAO;AAAA,QACP,aAAY;AAAA,QACZ,eAAc;AAAA,QACd,GAAE;AAAA;AAAA,IACH;AAAA,IACA,4CAAC,YAAO,IAAG,KAAI,IAAG,MAAK,GAAE,OAAM,MAAK,gBAAe;AAAA,IACnD,4CAAC,YAAO,IAAG,KAAI,IAAG,MAAK,GAAE,OAAM,MAAK,gBAAe;AAAA,IACnD,4CAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,OAAM,MAAK,gBAAe;AAAA,IACpD,4CAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,OAAM,MAAK,gBAAe;AAAA,IACpD,4CAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,OAAM,MAAK,gBAAe;AAAA,KACrD;AAEF;AAKO,SAAS,eAAe;AAC9B,SACC,6CAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,eAAY,QACvE;AAAA;AAAA,MAAC;AAAA;AAAA,QACA,MAAK;AAAA,QACL,GAAE;AAAA;AAAA,IACH;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACA,MAAK;AAAA,QACL,GAAE;AAAA;AAAA,IACH;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACA,MAAK;AAAA,QACL,GAAE;AAAA;AAAA,IACH;AAAA,KACD;AAEF;",
6
6
  "names": []
7
7
  }
@@ -52,6 +52,8 @@ class CommentTool extends StateNode {
52
52
  }
53
53
  onExit() {
54
54
  this.editor.setHintingShapes([]);
55
+ pendingComment.set(this.editor, null);
56
+ regionDraft.set(this.editor, null);
55
57
  }
56
58
  // Escape leaves the tool, like the built-in tools (the editor dispatches `cancel` on Escape).
57
59
  onCancel() {
@@ -66,7 +68,11 @@ class CommentIdle extends StateNode {
66
68
  static id = "idle";
67
69
  onEnter() {
68
70
  this.editor.setCursor({ type: "comment", rotation: 0 });
69
- updateAnchorHint(this.editor);
71
+ if (pendingComment.get(this.editor)?.anchor.type === "region") {
72
+ this.editor.setHintingShapes([]);
73
+ } else {
74
+ updateAnchorHint(this.editor);
75
+ }
70
76
  }
71
77
  onPointerMove() {
72
78
  updateAnchorHint(this.editor);
@@ -112,7 +118,7 @@ class CommentPointing extends StateNode {
112
118
  })
113
119
  ) : { type: "point", x: point.x, y: point.y };
114
120
  pendingComment.set(editor, { anchor, point: { x: point.x, y: point.y } });
115
- editor.setCurrentTool("select");
121
+ this.parent.transition("idle");
116
122
  }
117
123
  onCancel() {
118
124
  this.cancel();
@@ -120,9 +126,9 @@ class CommentPointing extends StateNode {
120
126
  onInterrupt() {
121
127
  this.cancel();
122
128
  }
123
- // Abandon the follow composer if placement is interrupted (Escape, focus loss, etc.).
129
+ // Abandon the follow composer if placement is interrupted (Escape, focus loss, etc.). The
130
+ // tool's onExit drops the draft.
124
131
  cancel() {
125
- pendingComment.set(this.editor, null);
126
132
  this.editor.setCurrentTool("select");
127
133
  }
128
134
  }
@@ -149,7 +155,7 @@ class CommentDragging extends StateNode {
149
155
  anchor: { type: "region", ...region, pinX: pin.x, pinY: pin.y },
150
156
  point: regionPinPoint(region, pin)
151
157
  });
152
- editor.setCurrentTool("select");
158
+ this.parent.transition("idle");
153
159
  }
154
160
  onCancel() {
155
161
  this.cancel();
@@ -164,8 +170,8 @@ class CommentDragging extends StateNode {
164
170
  regionBetween(editor.inputs.getOriginPagePoint(), editor.inputs.getCurrentPagePoint())
165
171
  );
166
172
  }
173
+ // The tool's onExit drops the region draft.
167
174
  cancel() {
168
- regionDraft.set(this.editor, null);
169
175
  this.editor.setCurrentTool("select");
170
176
  }
171
177
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/canvas/comment-tool.tsx"],
4
- "sourcesContent": ["import {\n\tBoxModel,\n\tEditor,\n\tStateNode,\n\tTLCommentAnchor,\n\tTLStateNodeConstructor,\n\tTLUiOverrides,\n\tVecLike,\n} from 'tldraw'\nimport { type CommentingOptions, defaultCommentingOptions, getCommentingOptions } from './options'\nimport { commentsSidebarOpen, pendingComment, regionDraft } from './state'\nimport { commentTargetShapeAt, regionPinPoint, shapeAnchorAt } from './thread-state'\n\n/** A comment being placed but not yet posted: where its composer sits and what it will anchor\n * to. Shared between the tool (which sets it on click) and the overlay (which renders the\n * composer) through the internal `pendingComment` atom.\n * @internal */\nexport interface PendingComment {\n\tanchor: TLCommentAnchor\n\t/** Page point where the composer opens (the click location, or a region's pin corner). */\n\tpoint: VecLike\n}\n\n/**\n * Merge configure options over a base. Shallow for scalars; `components` is merged rather than\n * replaced so chained `configure` calls layer their slots \u2014 a later `{ components: { PinContent } }`\n * doesn't drop an earlier `{ components: { CommentBody } }`.\n */\nfunction mergeCommentingOptions(\n\tbase: CommentingOptions,\n\toverrides: Partial<CommentingOptions>\n): CommentingOptions {\n\treturn {\n\t\t...base,\n\t\t...overrides,\n\t\tcomponents: { ...base.components, ...overrides.components },\n\t}\n}\n\n/** The page-space rectangle spanned by two points, normalized so w/h are non-negative. Shared by\n * region creation (pointer-down \u2192 cursor) and corner resize (fixed corner \u2192 cursor). */\nexport function regionBetween(a: VecLike, b: VecLike): BoxModel {\n\treturn {\n\t\tx: Math.min(a.x, b.x),\n\t\ty: Math.min(a.y, b.y),\n\t\tw: Math.abs(a.x - b.x),\n\t\th: Math.abs(a.y - b.y),\n\t}\n}\n\n/**\n * The comment tool. Pressing down opens the comment composer at the pointer and it follows until\n * release \u2014 like placing a sticky note \u2014 settling on a point, or on a shape when released over one.\n * With region comments enabled, dragging past the threshold draws a region rectangle instead.\n * Placement only opens a composer; the records are created when the comment is posted.\n * @public\n */\nexport class CommentTool extends StateNode {\n\tstatic override id = 'comment'\n\tstatic override initial = 'idle'\n\tstatic override children(): TLStateNodeConstructor[] {\n\t\treturn [CommentIdle, CommentPointing, CommentDragging]\n\t}\n\n\t/**\n\t * Configure this tool's {@link CommentTool.options | `options`}, returning a configured subclass\n\t * to register via `tools`. Mirrors `ShapeUtil.configure`. Layers over any prior `configure`, so\n\t * calls can be chained.\n\t *\n\t * @example\n\t * ```tsx\n\t * <Tldraw tools={[CommentTool.configure({ history: 'ignore', enableClustering: false })]} />\n\t * ```\n\t */\n\tstatic configure<T extends TLStateNodeConstructor>(\n\t\tthis: T,\n\t\toptions: T extends new (...args: any[]) => { options: infer Options } ? Partial<Options> : never\n\t): T {\n\t\t// @ts-expect-error -- mirrors ShapeUtil.configure; extending `this` is sound at runtime.\n\t\treturn class extends this {\n\t\t\t// @ts-expect-error\n\t\t\toptions = mergeCommentingOptions(this.options, options)\n\t\t}\n\t}\n\n\t/**\n\t * The merged commenting options for this editor. Read from anywhere via\n\t * {@link getCommentingOptions}. Override with {@link CommentTool.configure}.\n\t */\n\toptions: CommentingOptions = defaultCommentingOptions\n\n\toverride onEnter() {\n\t\tthis.editor.setCursor({ type: 'comment', rotation: 0 })\n\t\t// Placing comments is canvas-focused \u2014 the thread list gets out of the way while the tool is\n\t\t// active. Reopened via its own control (a button), never by leaving the tool.\n\t\tcommentsSidebarOpen.set(this.editor, false)\n\t}\n\n\toverride onExit() {\n\t\t// Drop the hover hint painted while pointing at shapes (see CommentIdle). The cursor resets\n\t\t// when the next tool takes over.\n\t\tthis.editor.setHintingShapes([])\n\t}\n\n\t// Escape leaves the tool, like the built-in tools (the editor dispatches `cancel` on Escape).\n\toverride onCancel() {\n\t\tthis.editor.setCurrentTool('select')\n\t}\n}\n\n/** Hint the shape a comment placed at the pointer would anchor to, using the same hit-test as the\n * anchor resolution on release. Hinting shapes render an indicator ungated by the active tool, so\n * this shows the select-style outline while the comment tool \u2014 not select \u2014 is active. */\nfunction updateAnchorHint(editor: Editor) {\n\tconst hit = commentTargetShapeAt(editor, editor.inputs.getCurrentPagePoint())\n\teditor.setHintingShapes(hit ? [hit.id] : [])\n}\n\nclass CommentIdle extends StateNode {\n\tstatic override id = 'idle'\n\n\toverride onEnter() {\n\t\t// Back to hovering: restore the pin cursor (a prior placing state may have hidden it).\n\t\tthis.editor.setCursor({ type: 'comment', rotation: 0 })\n\t\tupdateAnchorHint(this.editor)\n\t}\n\n\toverride onPointerMove() {\n\t\tupdateAnchorHint(this.editor)\n\t}\n\n\toverride onPointerDown() {\n\t\tthis.parent.transition('pointing')\n\t}\n}\n\nclass CommentPointing extends StateNode {\n\tstatic override id = 'pointing'\n\n\toverride onEnter() {\n\t\t// Open the composer immediately at the press point so it's visible from pointer-down (not just\n\t\t// on release), and let it trail the pointer while dragging \u2014 like placing a sticky note. The\n\t\t// anchor is a bare point for now; it's resolved (shape or point) on pointer up.\n\t\tconst { editor } = this\n\t\t// Hide the cursor while placing: the draft composer is the pointer's stand-in now, so the pin\n\t\t// cursor sitting over it just reads as clutter.\n\t\teditor.setCursor({ type: 'none', rotation: 0 })\n\t\tconst point = editor.inputs.getCurrentPagePoint()\n\t\tpendingComment.set(editor, {\n\t\t\tanchor: { type: 'point', x: point.x, y: point.y },\n\t\t\tpoint: { x: point.x, y: point.y },\n\t\t})\n\t}\n\n\toverride onPointerMove() {\n\t\tconst { editor } = this\n\t\t// Once the pointer passes the drag threshold with region comments enabled, this is a region,\n\t\t// not a follow \u2014 hand off to the region drag (which clears this composer and draws the box).\n\t\tif (getCommentingOptions(editor).enableRegions && editor.inputs.getIsDragging()) {\n\t\t\tthis.parent.transition('dragging')\n\t\t\treturn\n\t\t}\n\t\t// Otherwise the composer trails the pointer \u2014 keep hinting the shape a release here would\n\t\t// anchor to, like the idle hover does.\n\t\tupdateAnchorHint(editor)\n\t\tconst point = editor.inputs.getCurrentPagePoint()\n\t\tpendingComment.update(editor, (p) => (p ? { ...p, point: { x: point.x, y: point.y } } : p))\n\t}\n\n\t// Settle where the pointer is released: anchor to the shape under it, or drop a point.\n\toverride onPointerUp() {\n\t\tconst { editor } = this\n\t\tconst point = editor.inputs.getCurrentPagePoint()\n\t\tconst hit = commentTargetShapeAt(editor, point)\n\t\tconst anchor: TLCommentAnchor = hit\n\t\t\t? shapeAnchorAt(\n\t\t\t\t\teditor,\n\t\t\t\t\thit.id,\n\t\t\t\t\tpoint,\n\t\t\t\t\tgetCommentingOptions(editor).shouldBePrecise(editor, {\n\t\t\t\t\t\tshapeId: hit.id,\n\t\t\t\t\t\tpoint,\n\t\t\t\t\t\taltKey: editor.inputs.getAltKey(),\n\t\t\t\t\t})\n\t\t\t\t)\n\t\t\t: { type: 'point', x: point.x, y: point.y }\n\t\tpendingComment.set(editor, { anchor, point: { x: point.x, y: point.y } })\n\t\teditor.setCurrentTool('select')\n\t}\n\n\toverride onCancel() {\n\t\tthis.cancel()\n\t}\n\n\toverride onInterrupt() {\n\t\tthis.cancel()\n\t}\n\n\t// Abandon the follow composer if placement is interrupted (Escape, focus loss, etc.).\n\tprivate cancel() {\n\t\tpendingComment.set(this.editor, null)\n\t\tthis.editor.setCurrentTool('select')\n\t}\n}\n\nclass CommentDragging extends StateNode {\n\tstatic override id = 'dragging'\n\n\toverride onEnter() {\n\t\t// A region drag supersedes the point-follow composer opened in `pointing`. Show a crosshair again,\n\t\t// since the composer no longer stands in for the pointer, and drop the placement hint \u2014 a region\n\t\t// anchors to its rectangle, so a single-shape outline would be stale.\n\t\tpendingComment.set(this.editor, null)\n\t\tthis.editor.setHintingShapes([])\n\t\tthis.editor.setCursor({ type: 'cross', rotation: 0 })\n\t\tthis.updateDraft()\n\t}\n\n\toverride onPointerMove() {\n\t\tthis.updateDraft()\n\t}\n\n\t// Commit the dragged rectangle as a region anchor; the composer opens at its pin corner.\n\toverride onPointerUp() {\n\t\tconst { editor } = this\n\t\tconst origin = editor.inputs.getOriginPagePoint()\n\t\tconst current = editor.inputs.getCurrentPagePoint()\n\t\tconst region = regionBetween(origin, current)\n\t\t// The pin lives on the corner the drag released on \u2014 drag up-left, pin top-left.\n\t\tconst pin = { x: current.x >= origin.x ? 1 : 0, y: current.y >= origin.y ? 1 : 0 }\n\t\tregionDraft.set(editor, null)\n\t\tpendingComment.set(editor, {\n\t\t\tanchor: { type: 'region', ...region, pinX: pin.x, pinY: pin.y },\n\t\t\tpoint: regionPinPoint(region, pin),\n\t\t})\n\t\teditor.setCurrentTool('select')\n\t}\n\n\toverride onCancel() {\n\t\tthis.cancel()\n\t}\n\n\toverride onInterrupt() {\n\t\tthis.cancel()\n\t}\n\n\tprivate updateDraft() {\n\t\tconst { editor } = this\n\t\tregionDraft.set(\n\t\t\teditor,\n\t\t\tregionBetween(editor.inputs.getOriginPagePoint(), editor.inputs.getCurrentPagePoint())\n\t\t)\n\t}\n\n\tprivate cancel() {\n\t\tregionDraft.set(this.editor, null)\n\t\tthis.editor.setCurrentTool('select')\n\t}\n}\n\n/** @public */\nexport const commentTools = [CommentTool]\n\n/** Registers the comment tool in the UI (icon, label, shortcut). Compose into your overrides.\n * Once registered, tldraw's `DefaultQuickActionsContent` shows the comment button.\n * @public */\nexport const commentToolOverrides: TLUiOverrides = {\n\ttools(editor, tools) {\n\t\ttools.comment = {\n\t\t\tid: 'comment',\n\t\t\ticon: 'comment',\n\t\t\tlabel: 'Comment',\n\t\t\tkbd: 'c',\n\t\t\tonSelect: () => editor.setCurrentTool('comment'),\n\t\t}\n\t\treturn tools\n\t},\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import {\n\tBoxModel,\n\tEditor,\n\tStateNode,\n\tTLCommentAnchor,\n\tTLStateNodeConstructor,\n\tTLUiOverrides,\n\tVecLike,\n} from 'tldraw'\nimport { type CommentingOptions, defaultCommentingOptions, getCommentingOptions } from './options'\nimport { commentsSidebarOpen, pendingComment, regionDraft } from './state'\nimport { commentTargetShapeAt, regionPinPoint, shapeAnchorAt } from './thread-state'\n\n/** A comment being placed but not yet posted: where its composer sits and what it will anchor\n * to. Shared between the tool (which sets it on click) and the overlay (which renders the\n * composer) through the internal `pendingComment` atom.\n * @internal */\nexport interface PendingComment {\n\tanchor: TLCommentAnchor\n\t/** Page point where the composer opens (the click location, or a region's pin corner). */\n\tpoint: VecLike\n}\n\n/**\n * Merge configure options over a base. Shallow for scalars; `components` is merged rather than\n * replaced so chained `configure` calls layer their slots \u2014 a later `{ components: { PinContent } }`\n * doesn't drop an earlier `{ components: { CommentBody } }`.\n */\nfunction mergeCommentingOptions(\n\tbase: CommentingOptions,\n\toverrides: Partial<CommentingOptions>\n): CommentingOptions {\n\treturn {\n\t\t...base,\n\t\t...overrides,\n\t\tcomponents: { ...base.components, ...overrides.components },\n\t}\n}\n\n/** The page-space rectangle spanned by two points, normalized so w/h are non-negative. Shared by\n * region creation (pointer-down \u2192 cursor) and corner resize (fixed corner \u2192 cursor). */\nexport function regionBetween(a: VecLike, b: VecLike): BoxModel {\n\treturn {\n\t\tx: Math.min(a.x, b.x),\n\t\ty: Math.min(a.y, b.y),\n\t\tw: Math.abs(a.x - b.x),\n\t\th: Math.abs(a.y - b.y),\n\t}\n}\n\n/**\n * The comment tool. Pressing down opens the comment composer at the pointer and it follows until\n * release \u2014 like placing a sticky note \u2014 settling on a point, or on a shape when released over one.\n * With region comments enabled, dragging past the threshold draws a region rectangle instead.\n * Placement only opens a composer; the records are created when the comment is posted. The tool\n * stays active while the composer is open \u2014 posting returns to select, and clicking elsewhere\n * re-places the composer.\n * @public\n */\nexport class CommentTool extends StateNode {\n\tstatic override id = 'comment'\n\tstatic override initial = 'idle'\n\tstatic override children(): TLStateNodeConstructor[] {\n\t\treturn [CommentIdle, CommentPointing, CommentDragging]\n\t}\n\n\t/**\n\t * Configure this tool's {@link CommentTool.options | `options`}, returning a configured subclass\n\t * to register via `tools`. Mirrors `ShapeUtil.configure`. Layers over any prior `configure`, so\n\t * calls can be chained.\n\t *\n\t * @example\n\t * ```tsx\n\t * <Tldraw tools={[CommentTool.configure({ history: 'ignore', enableClustering: false })]} />\n\t * ```\n\t */\n\tstatic configure<T extends TLStateNodeConstructor>(\n\t\tthis: T,\n\t\toptions: T extends new (...args: any[]) => { options: infer Options } ? Partial<Options> : never\n\t): T {\n\t\t// @ts-expect-error -- mirrors ShapeUtil.configure; extending `this` is sound at runtime.\n\t\treturn class extends this {\n\t\t\t// @ts-expect-error\n\t\t\toptions = mergeCommentingOptions(this.options, options)\n\t\t}\n\t}\n\n\t/**\n\t * The merged commenting options for this editor. Read from anywhere via\n\t * {@link getCommentingOptions}. Override with {@link CommentTool.configure}.\n\t */\n\toptions: CommentingOptions = defaultCommentingOptions\n\n\toverride onEnter() {\n\t\tthis.editor.setCursor({ type: 'comment', rotation: 0 })\n\t\t// Placing comments is canvas-focused \u2014 the thread list gets out of the way while the tool is\n\t\t// active. Reopened via its own control (a button), never by leaving the tool.\n\t\tcommentsSidebarOpen.set(this.editor, false)\n\t}\n\n\toverride onExit() {\n\t\t// Drop the hover hint painted while pointing at shapes (see CommentIdle). The cursor resets\n\t\t// when the next tool takes over. The draft composer and region draft belong to the tool, so\n\t\t// they leave with it; the draft's text survives in the comment draft store.\n\t\tthis.editor.setHintingShapes([])\n\t\tpendingComment.set(this.editor, null)\n\t\tregionDraft.set(this.editor, null)\n\t}\n\n\t// Escape leaves the tool, like the built-in tools (the editor dispatches `cancel` on Escape).\n\toverride onCancel() {\n\t\tthis.editor.setCurrentTool('select')\n\t}\n}\n\n/** Hint the shape a comment placed at the pointer would anchor to, using the same hit-test as the\n * anchor resolution on release. Hinting shapes render an indicator ungated by the active tool, so\n * this shows the select-style outline while the comment tool \u2014 not select \u2014 is active. */\nfunction updateAnchorHint(editor: Editor) {\n\tconst hit = commentTargetShapeAt(editor, editor.inputs.getCurrentPagePoint())\n\teditor.setHintingShapes(hit ? [hit.id] : [])\n}\n\nclass CommentIdle extends StateNode {\n\tstatic override id = 'idle'\n\n\toverride onEnter() {\n\t\t// Back to hovering: restore the pin cursor (a prior placing state may have hidden it).\n\t\tthis.editor.setCursor({ type: 'comment', rotation: 0 })\n\t\t// With a region composer open, a shape outline under its pin corner would imply a shape\n\t\t// anchor the region will never use \u2014 and it would stick, since moves over the composer\n\t\t// never reach the canvas. Point placements keep the hint: it previews the next click.\n\t\tif (pendingComment.get(this.editor)?.anchor.type === 'region') {\n\t\t\tthis.editor.setHintingShapes([])\n\t\t} else {\n\t\t\tupdateAnchorHint(this.editor)\n\t\t}\n\t}\n\n\toverride onPointerMove() {\n\t\tupdateAnchorHint(this.editor)\n\t}\n\n\toverride onPointerDown() {\n\t\tthis.parent.transition('pointing')\n\t}\n}\n\nclass CommentPointing extends StateNode {\n\tstatic override id = 'pointing'\n\n\toverride onEnter() {\n\t\t// Open the composer immediately at the press point so it's visible from pointer-down (not just\n\t\t// on release), and let it trail the pointer while dragging \u2014 like placing a sticky note. The\n\t\t// anchor is a bare point for now; it's resolved (shape or point) on pointer up.\n\t\tconst { editor } = this\n\t\t// Hide the cursor while placing: the draft composer is the pointer's stand-in now, so the pin\n\t\t// cursor sitting over it just reads as clutter.\n\t\teditor.setCursor({ type: 'none', rotation: 0 })\n\t\tconst point = editor.inputs.getCurrentPagePoint()\n\t\tpendingComment.set(editor, {\n\t\t\tanchor: { type: 'point', x: point.x, y: point.y },\n\t\t\tpoint: { x: point.x, y: point.y },\n\t\t})\n\t}\n\n\toverride onPointerMove() {\n\t\tconst { editor } = this\n\t\t// Once the pointer passes the drag threshold with region comments enabled, this is a region,\n\t\t// not a follow \u2014 hand off to the region drag (which clears this composer and draws the box).\n\t\tif (getCommentingOptions(editor).enableRegions && editor.inputs.getIsDragging()) {\n\t\t\tthis.parent.transition('dragging')\n\t\t\treturn\n\t\t}\n\t\t// Otherwise the composer trails the pointer \u2014 keep hinting the shape a release here would\n\t\t// anchor to, like the idle hover does.\n\t\tupdateAnchorHint(editor)\n\t\tconst point = editor.inputs.getCurrentPagePoint()\n\t\tpendingComment.update(editor, (p) => (p ? { ...p, point: { x: point.x, y: point.y } } : p))\n\t}\n\n\t// Settle where the pointer is released: anchor to the shape under it, or drop a point.\n\toverride onPointerUp() {\n\t\tconst { editor } = this\n\t\tconst point = editor.inputs.getCurrentPagePoint()\n\t\tconst hit = commentTargetShapeAt(editor, point)\n\t\tconst anchor: TLCommentAnchor = hit\n\t\t\t? shapeAnchorAt(\n\t\t\t\t\teditor,\n\t\t\t\t\thit.id,\n\t\t\t\t\tpoint,\n\t\t\t\t\tgetCommentingOptions(editor).shouldBePrecise(editor, {\n\t\t\t\t\t\tshapeId: hit.id,\n\t\t\t\t\t\tpoint,\n\t\t\t\t\t\taltKey: editor.inputs.getAltKey(),\n\t\t\t\t\t})\n\t\t\t\t)\n\t\t\t: { type: 'point', x: point.x, y: point.y }\n\t\tpendingComment.set(editor, { anchor, point: { x: point.x, y: point.y } })\n\t\t// Stay in the tool while the composer is open \u2014 the interaction isn't over until the\n\t\t// comment is posted or dismissed, and staying keeps the surrounding UI (style panel,\n\t\t// sidebar) from churning mid-placement.\n\t\tthis.parent.transition('idle')\n\t}\n\n\toverride onCancel() {\n\t\tthis.cancel()\n\t}\n\n\toverride onInterrupt() {\n\t\tthis.cancel()\n\t}\n\n\t// Abandon the follow composer if placement is interrupted (Escape, focus loss, etc.). The\n\t// tool's onExit drops the draft.\n\tprivate cancel() {\n\t\tthis.editor.setCurrentTool('select')\n\t}\n}\n\nclass CommentDragging extends StateNode {\n\tstatic override id = 'dragging'\n\n\toverride onEnter() {\n\t\t// A region drag supersedes the point-follow composer opened in `pointing`. Show a crosshair again,\n\t\t// since the composer no longer stands in for the pointer, and drop the placement hint \u2014 a region\n\t\t// anchors to its rectangle, so a single-shape outline would be stale.\n\t\tpendingComment.set(this.editor, null)\n\t\tthis.editor.setHintingShapes([])\n\t\tthis.editor.setCursor({ type: 'cross', rotation: 0 })\n\t\tthis.updateDraft()\n\t}\n\n\toverride onPointerMove() {\n\t\tthis.updateDraft()\n\t}\n\n\t// Commit the dragged rectangle as a region anchor; the composer opens at its pin corner.\n\toverride onPointerUp() {\n\t\tconst { editor } = this\n\t\tconst origin = editor.inputs.getOriginPagePoint()\n\t\tconst current = editor.inputs.getCurrentPagePoint()\n\t\tconst region = regionBetween(origin, current)\n\t\t// The pin lives on the corner the drag released on \u2014 drag up-left, pin top-left.\n\t\tconst pin = { x: current.x >= origin.x ? 1 : 0, y: current.y >= origin.y ? 1 : 0 }\n\t\tregionDraft.set(editor, null)\n\t\tpendingComment.set(editor, {\n\t\t\tanchor: { type: 'region', ...region, pinX: pin.x, pinY: pin.y },\n\t\t\tpoint: regionPinPoint(region, pin),\n\t\t})\n\t\t// Same as the point placement: the tool stays active while the composer is open.\n\t\tthis.parent.transition('idle')\n\t}\n\n\toverride onCancel() {\n\t\tthis.cancel()\n\t}\n\n\toverride onInterrupt() {\n\t\tthis.cancel()\n\t}\n\n\tprivate updateDraft() {\n\t\tconst { editor } = this\n\t\tregionDraft.set(\n\t\t\teditor,\n\t\t\tregionBetween(editor.inputs.getOriginPagePoint(), editor.inputs.getCurrentPagePoint())\n\t\t)\n\t}\n\n\t// The tool's onExit drops the region draft.\n\tprivate cancel() {\n\t\tthis.editor.setCurrentTool('select')\n\t}\n}\n\n/** @public */\nexport const commentTools = [CommentTool]\n\n/** Registers the comment tool in the UI (icon, label, shortcut). Compose into your overrides.\n * Once registered, tldraw's `DefaultQuickActionsContent` shows the comment button.\n * @public */\nexport const commentToolOverrides: TLUiOverrides = {\n\ttools(editor, tools) {\n\t\ttools.comment = {\n\t\t\tid: 'comment',\n\t\t\ticon: 'comment',\n\t\t\tlabel: 'Comment',\n\t\t\tkbd: 'c',\n\t\t\tonSelect: () => editor.setCurrentTool('comment'),\n\t\t}\n\t\treturn tools\n\t},\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -11,7 +11,7 @@ import {
11
11
  useTranslation,
12
12
  useValue
13
13
  } from "tldraw";
14
- import { FilterIcon } from "../ui/icons.mjs";
14
+ import { MoreMenuIcon } from "../ui/icons.mjs";
15
15
  import { sidebarFilters } from "./state.mjs";
16
16
  function CommentsFilterMenu({
17
17
  canFilterByAuthor,
@@ -31,7 +31,7 @@ function CommentsFilterMenu({
31
31
  tooltip: msg("comments.filter"),
32
32
  title: msg("comments.filter"),
33
33
  className: "tlui-cmt-header-btn",
34
- children: /* @__PURE__ */ jsx(FilterIcon, {})
34
+ children: /* @__PURE__ */ jsx(MoreMenuIcon, {})
35
35
  }
36
36
  ) }),
37
37
  /* @__PURE__ */ jsx(TldrawUiDropdownMenuContent, { side: "bottom", align: "end", alignOffset: 0, children: /* @__PURE__ */ jsx(TldrawUiMenuContextProvider, { type: "menu", sourceId: "menu", children: /* @__PURE__ */ jsxs(TldrawUiMenuGroup, { id: "comments-filter", children: [
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/canvas/comments-filter-menu.tsx"],
4
- "sourcesContent": ["import {\n\tTldrawUiButton,\n\tTldrawUiDropdownMenuContent,\n\tTldrawUiDropdownMenuRoot,\n\tTldrawUiDropdownMenuTrigger,\n\tTldrawUiMenuCheckboxItem,\n\tTldrawUiMenuContextProvider,\n\tTldrawUiMenuGroup,\n\tuseEditor,\n\tuseTranslation,\n\tuseValue,\n} from 'tldraw'\nimport { FilterIcon } from '../ui/icons'\nimport { SidebarFilters } from './sidebar-filters'\nimport { sidebarFilters } from './state'\n\n/** @public */\nexport interface CommentsFilterMenuProps {\n\t/** Whether to offer the \"only your threads\" toggle (needs a known current user). */\n\tcanFilterByAuthor?: boolean\n\t/** Whether to offer the \"only unread\" toggle (needs a read-status source). */\n\tcanFilterByUnread?: boolean\n}\n\n/** The funnel dropdown in the sidebar header: toggles for which threads the list shows.\n * @public @react */\nexport function CommentsFilterMenu({\n\tcanFilterByAuthor,\n\tcanFilterByUnread,\n}: CommentsFilterMenuProps) {\n\tconst editor = useEditor()\n\tconst msg = useTranslation()\n\tconst filters = useValue('sidebar filters', () => sidebarFilters.get(editor), [editor])\n\tconst toggle = (key: keyof SidebarFilters) => {\n\t\tsidebarFilters.update(editor, (f) => ({ ...f, [key]: !f[key] }))\n\t}\n\n\treturn (\n\t\t<TldrawUiDropdownMenuRoot id=\"comments-filter\">\n\t\t\t<TldrawUiDropdownMenuTrigger>\n\t\t\t\t<TldrawUiButton\n\t\t\t\t\ttype=\"icon\"\n\t\t\t\t\ttooltip={msg('comments.filter')}\n\t\t\t\t\ttitle={msg('comments.filter')}\n\t\t\t\t\tclassName=\"tlui-cmt-header-btn\"\n\t\t\t\t>\n\t\t\t\t\t<FilterIcon />\n\t\t\t\t</TldrawUiButton>\n\t\t\t</TldrawUiDropdownMenuTrigger>\n\t\t\t{/* No tlui-cmt-menu here: the rows are tldraw menu items, which carry their own insets \u2014\n\t\t\t the extra padding would set this menu apart from the canvas menus it should match. */}\n\t\t\t<TldrawUiDropdownMenuContent side=\"bottom\" align=\"end\" alignOffset={0}>\n\t\t\t\t<TldrawUiMenuContextProvider type=\"menu\" sourceId=\"menu\">\n\t\t\t\t\t<TldrawUiMenuGroup id=\"comments-filter\">\n\t\t\t\t\t\t<TldrawUiMenuCheckboxItem\n\t\t\t\t\t\t\tid=\"show-all-pages\"\n\t\t\t\t\t\t\tlabel=\"comments.show-all-pages\"\n\t\t\t\t\t\t\tchecked={!filters.onlyCurrentPage}\n\t\t\t\t\t\t\tonSelect={() => toggle('onlyCurrentPage')}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t{canFilterByAuthor && (\n\t\t\t\t\t\t\t<TldrawUiMenuCheckboxItem\n\t\t\t\t\t\t\t\tid=\"only-my-comments\"\n\t\t\t\t\t\t\t\tlabel=\"comments.only-my-comments\"\n\t\t\t\t\t\t\t\tchecked={filters.onlyMine}\n\t\t\t\t\t\t\t\tonSelect={() => toggle('onlyMine')}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t)}\n\t\t\t\t\t\t{canFilterByUnread && (\n\t\t\t\t\t\t\t<TldrawUiMenuCheckboxItem\n\t\t\t\t\t\t\t\tid=\"only-unread\"\n\t\t\t\t\t\t\t\tlabel=\"comments.only-unread\"\n\t\t\t\t\t\t\t\tchecked={filters.onlyUnread}\n\t\t\t\t\t\t\t\tonSelect={() => toggle('onlyUnread')}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t)}\n\t\t\t\t\t\t<TldrawUiMenuCheckboxItem\n\t\t\t\t\t\t\tid=\"show-resolved\"\n\t\t\t\t\t\t\tlabel=\"comments.show-resolved\"\n\t\t\t\t\t\t\tchecked={filters.showResolved}\n\t\t\t\t\t\t\tonSelect={() => toggle('showResolved')}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</TldrawUiMenuGroup>\n\t\t\t\t</TldrawUiMenuContextProvider>\n\t\t\t</TldrawUiDropdownMenuContent>\n\t\t</TldrawUiDropdownMenuRoot>\n\t)\n}\n"],
5
- "mappings": "AA8CK,cAOA,YAPA;AA9CL;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AACP,SAAS,kBAAkB;AAE3B,SAAS,sBAAsB;AAYxB,SAAS,mBAAmB;AAAA,EAClC;AAAA,EACA;AACD,GAA4B;AAC3B,QAAM,SAAS,UAAU;AACzB,QAAM,MAAM,eAAe;AAC3B,QAAM,UAAU,SAAS,mBAAmB,MAAM,eAAe,IAAI,MAAM,GAAG,CAAC,MAAM,CAAC;AACtF,QAAM,SAAS,CAAC,QAA8B;AAC7C,mBAAe,OAAO,QAAQ,CAAC,OAAO,EAAE,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,EAAE,GAAG,EAAE,EAAE;AAAA,EAChE;AAEA,SACC,qBAAC,4BAAyB,IAAG,mBAC5B;AAAA,wBAAC,+BACA;AAAA,MAAC;AAAA;AAAA,QACA,MAAK;AAAA,QACL,SAAS,IAAI,iBAAiB;AAAA,QAC9B,OAAO,IAAI,iBAAiB;AAAA,QAC5B,WAAU;AAAA,QAEV,8BAAC,cAAW;AAAA;AAAA,IACb,GACD;AAAA,IAGA,oBAAC,+BAA4B,MAAK,UAAS,OAAM,OAAM,aAAa,GACnE,8BAAC,+BAA4B,MAAK,QAAO,UAAS,QACjD,+BAAC,qBAAkB,IAAG,mBACrB;AAAA;AAAA,QAAC;AAAA;AAAA,UACA,IAAG;AAAA,UACH,OAAM;AAAA,UACN,SAAS,CAAC,QAAQ;AAAA,UAClB,UAAU,MAAM,OAAO,iBAAiB;AAAA;AAAA,MACzC;AAAA,MACC,qBACA;AAAA,QAAC;AAAA;AAAA,UACA,IAAG;AAAA,UACH,OAAM;AAAA,UACN,SAAS,QAAQ;AAAA,UACjB,UAAU,MAAM,OAAO,UAAU;AAAA;AAAA,MAClC;AAAA,MAEA,qBACA;AAAA,QAAC;AAAA;AAAA,UACA,IAAG;AAAA,UACH,OAAM;AAAA,UACN,SAAS,QAAQ;AAAA,UACjB,UAAU,MAAM,OAAO,YAAY;AAAA;AAAA,MACpC;AAAA,MAED;AAAA,QAAC;AAAA;AAAA,UACA,IAAG;AAAA,UACH,OAAM;AAAA,UACN,SAAS,QAAQ;AAAA,UACjB,UAAU,MAAM,OAAO,cAAc;AAAA;AAAA,MACtC;AAAA,OACD,GACD,GACD;AAAA,KACD;AAEF;",
4
+ "sourcesContent": ["import {\n\tTldrawUiButton,\n\tTldrawUiDropdownMenuContent,\n\tTldrawUiDropdownMenuRoot,\n\tTldrawUiDropdownMenuTrigger,\n\tTldrawUiMenuCheckboxItem,\n\tTldrawUiMenuContextProvider,\n\tTldrawUiMenuGroup,\n\tuseEditor,\n\tuseTranslation,\n\tuseValue,\n} from 'tldraw'\nimport { MoreMenuIcon } from '../ui/icons'\nimport { SidebarFilters } from './sidebar-filters'\nimport { sidebarFilters } from './state'\n\n/** @public */\nexport interface CommentsFilterMenuProps {\n\t/** Whether to offer the \"only your threads\" toggle (needs a known current user). */\n\tcanFilterByAuthor?: boolean\n\t/** Whether to offer the \"only unread\" toggle (needs a read-status source). */\n\tcanFilterByUnread?: boolean\n}\n\n/** The funnel dropdown in the sidebar header: toggles for which threads the list shows.\n * @public @react */\nexport function CommentsFilterMenu({\n\tcanFilterByAuthor,\n\tcanFilterByUnread,\n}: CommentsFilterMenuProps) {\n\tconst editor = useEditor()\n\tconst msg = useTranslation()\n\tconst filters = useValue('sidebar filters', () => sidebarFilters.get(editor), [editor])\n\tconst toggle = (key: keyof SidebarFilters) => {\n\t\tsidebarFilters.update(editor, (f) => ({ ...f, [key]: !f[key] }))\n\t}\n\n\treturn (\n\t\t<TldrawUiDropdownMenuRoot id=\"comments-filter\">\n\t\t\t<TldrawUiDropdownMenuTrigger>\n\t\t\t\t<TldrawUiButton\n\t\t\t\t\ttype=\"icon\"\n\t\t\t\t\ttooltip={msg('comments.filter')}\n\t\t\t\t\ttitle={msg('comments.filter')}\n\t\t\t\t\tclassName=\"tlui-cmt-header-btn\"\n\t\t\t\t>\n\t\t\t\t\t<MoreMenuIcon />\n\t\t\t\t</TldrawUiButton>\n\t\t\t</TldrawUiDropdownMenuTrigger>\n\t\t\t{/* No tlui-cmt-menu here: the rows are tldraw menu items, which carry their own insets \u2014\n\t\t\t the extra padding would set this menu apart from the canvas menus it should match. */}\n\t\t\t<TldrawUiDropdownMenuContent side=\"bottom\" align=\"end\" alignOffset={0}>\n\t\t\t\t<TldrawUiMenuContextProvider type=\"menu\" sourceId=\"menu\">\n\t\t\t\t\t<TldrawUiMenuGroup id=\"comments-filter\">\n\t\t\t\t\t\t<TldrawUiMenuCheckboxItem\n\t\t\t\t\t\t\tid=\"show-all-pages\"\n\t\t\t\t\t\t\tlabel=\"comments.show-all-pages\"\n\t\t\t\t\t\t\tchecked={!filters.onlyCurrentPage}\n\t\t\t\t\t\t\tonSelect={() => toggle('onlyCurrentPage')}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t{canFilterByAuthor && (\n\t\t\t\t\t\t\t<TldrawUiMenuCheckboxItem\n\t\t\t\t\t\t\t\tid=\"only-my-comments\"\n\t\t\t\t\t\t\t\tlabel=\"comments.only-my-comments\"\n\t\t\t\t\t\t\t\tchecked={filters.onlyMine}\n\t\t\t\t\t\t\t\tonSelect={() => toggle('onlyMine')}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t)}\n\t\t\t\t\t\t{canFilterByUnread && (\n\t\t\t\t\t\t\t<TldrawUiMenuCheckboxItem\n\t\t\t\t\t\t\t\tid=\"only-unread\"\n\t\t\t\t\t\t\t\tlabel=\"comments.only-unread\"\n\t\t\t\t\t\t\t\tchecked={filters.onlyUnread}\n\t\t\t\t\t\t\t\tonSelect={() => toggle('onlyUnread')}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t)}\n\t\t\t\t\t\t<TldrawUiMenuCheckboxItem\n\t\t\t\t\t\t\tid=\"show-resolved\"\n\t\t\t\t\t\t\tlabel=\"comments.show-resolved\"\n\t\t\t\t\t\t\tchecked={filters.showResolved}\n\t\t\t\t\t\t\tonSelect={() => toggle('showResolved')}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</TldrawUiMenuGroup>\n\t\t\t\t</TldrawUiMenuContextProvider>\n\t\t\t</TldrawUiDropdownMenuContent>\n\t\t</TldrawUiDropdownMenuRoot>\n\t)\n}\n"],
5
+ "mappings": "AA8CK,cAOA,YAPA;AA9CL;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AACP,SAAS,oBAAoB;AAE7B,SAAS,sBAAsB;AAYxB,SAAS,mBAAmB;AAAA,EAClC;AAAA,EACA;AACD,GAA4B;AAC3B,QAAM,SAAS,UAAU;AACzB,QAAM,MAAM,eAAe;AAC3B,QAAM,UAAU,SAAS,mBAAmB,MAAM,eAAe,IAAI,MAAM,GAAG,CAAC,MAAM,CAAC;AACtF,QAAM,SAAS,CAAC,QAA8B;AAC7C,mBAAe,OAAO,QAAQ,CAAC,OAAO,EAAE,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,EAAE,GAAG,EAAE,EAAE;AAAA,EAChE;AAEA,SACC,qBAAC,4BAAyB,IAAG,mBAC5B;AAAA,wBAAC,+BACA;AAAA,MAAC;AAAA;AAAA,QACA,MAAK;AAAA,QACL,SAAS,IAAI,iBAAiB;AAAA,QAC9B,OAAO,IAAI,iBAAiB;AAAA,QAC5B,WAAU;AAAA,QAEV,8BAAC,gBAAa;AAAA;AAAA,IACf,GACD;AAAA,IAGA,oBAAC,+BAA4B,MAAK,UAAS,OAAM,OAAM,aAAa,GACnE,8BAAC,+BAA4B,MAAK,QAAO,UAAS,QACjD,+BAAC,qBAAkB,IAAG,mBACrB;AAAA;AAAA,QAAC;AAAA;AAAA,UACA,IAAG;AAAA,UACH,OAAM;AAAA,UACN,SAAS,CAAC,QAAQ;AAAA,UAClB,UAAU,MAAM,OAAO,iBAAiB;AAAA;AAAA,MACzC;AAAA,MACC,qBACA;AAAA,QAAC;AAAA;AAAA,UACA,IAAG;AAAA,UACH,OAAM;AAAA,UACN,SAAS,QAAQ;AAAA,UACjB,UAAU,MAAM,OAAO,UAAU;AAAA;AAAA,MAClC;AAAA,MAEA,qBACA;AAAA,QAAC;AAAA;AAAA,UACA,IAAG;AAAA,UACH,OAAM;AAAA,UACN,SAAS,QAAQ;AAAA,UACjB,UAAU,MAAM,OAAO,YAAY;AAAA;AAAA,MACpC;AAAA,MAED;AAAA,QAAC;AAAA;AAAA,UACA,IAAG;AAAA,UACH,OAAM;AAAA,UACN,SAAS,QAAQ;AAAA,UACjB,UAAU,MAAM,OAAO,cAAc;AAAA;AAAA,MACtC;AAAA,OACD,GACD,GACD;AAAA,KACD;AAEF;",
6
6
  "names": []
7
7
  }
@@ -44,7 +44,10 @@ function CanvasCommentsLayer(props) {
44
44
  const canRenderComposer = canComment || options.components.ComposerFallback != null;
45
45
  const showPendingComposer = pending != null && canRenderComposer;
46
46
  useEffect(() => {
47
- if (pending && !showPendingComposer) pendingComment.set(editor, null);
47
+ if (pending && !showPendingComposer) {
48
+ pendingComment.set(editor, null);
49
+ if (editor.isIn("comment")) editor.setCurrentTool("select");
50
+ }
48
51
  }, [editor, pending, showPendingComposer]);
49
52
  const openId = useValue("open thread id", () => openThreadId.get(editor), [editor]);
50
53
  const showResolved = useValue("show resolved", () => sidebarFilters.get(editor).showResolved, [