tldraw 3.16.0-canary.614a556981b7 → 3.16.0-canary.654b4007a087

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 (124) hide show
  1. package/dist-cjs/index.d.ts +74 -1
  2. package/dist-cjs/index.js +5 -1
  3. package/dist-cjs/index.js.map +2 -2
  4. package/dist-cjs/lib/shapes/frame/FrameShapeUtil.js +4 -4
  5. package/dist-cjs/lib/shapes/frame/FrameShapeUtil.js.map +2 -2
  6. package/dist-cjs/lib/shapes/shared/ShapeFill.js +1 -1
  7. package/dist-cjs/lib/shapes/shared/ShapeFill.js.map +2 -2
  8. package/dist-cjs/lib/shapes/shared/freehand/svg.js.map +2 -2
  9. package/dist-cjs/lib/tools/EraserTool/childStates/Erasing.js +25 -1
  10. package/dist-cjs/lib/tools/EraserTool/childStates/Erasing.js.map +2 -2
  11. package/dist-cjs/lib/tools/EraserTool/childStates/Pointing.js +12 -0
  12. package/dist-cjs/lib/tools/EraserTool/childStates/Pointing.js.map +2 -2
  13. package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js +68 -91
  14. package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js.map +2 -2
  15. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuContext.js.map +2 -2
  16. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuGroup.js +0 -10
  17. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuGroup.js.map +2 -2
  18. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js +3 -19
  19. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js.map +2 -2
  20. package/dist-cjs/lib/ui/hooks/useTools.js +21 -3
  21. package/dist-cjs/lib/ui/hooks/useTools.js.map +2 -2
  22. package/dist-cjs/lib/ui/version.js +3 -3
  23. package/dist-cjs/lib/ui/version.js.map +1 -1
  24. package/dist-esm/index.d.mts +74 -1
  25. package/dist-esm/index.mjs +5 -1
  26. package/dist-esm/index.mjs.map +2 -2
  27. package/dist-esm/lib/shapes/frame/FrameShapeUtil.mjs +4 -4
  28. package/dist-esm/lib/shapes/frame/FrameShapeUtil.mjs.map +2 -2
  29. package/dist-esm/lib/shapes/shared/ShapeFill.mjs +1 -1
  30. package/dist-esm/lib/shapes/shared/ShapeFill.mjs.map +2 -2
  31. package/dist-esm/lib/shapes/shared/freehand/svg.mjs.map +2 -2
  32. package/dist-esm/lib/tools/EraserTool/childStates/Erasing.mjs +26 -1
  33. package/dist-esm/lib/tools/EraserTool/childStates/Erasing.mjs.map +2 -2
  34. package/dist-esm/lib/tools/EraserTool/childStates/Pointing.mjs +13 -0
  35. package/dist-esm/lib/tools/EraserTool/childStates/Pointing.mjs.map +2 -2
  36. package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs +77 -93
  37. package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs.map +2 -2
  38. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuContext.mjs.map +2 -2
  39. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuGroup.mjs +0 -10
  40. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuGroup.mjs.map +2 -2
  41. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs +3 -19
  42. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs.map +2 -2
  43. package/dist-esm/lib/ui/hooks/useTools.mjs +22 -3
  44. package/dist-esm/lib/ui/hooks/useTools.mjs.map +2 -2
  45. package/dist-esm/lib/ui/version.mjs +3 -3
  46. package/dist-esm/lib/ui/version.mjs.map +1 -1
  47. package/package.json +9 -33
  48. package/src/index.ts +3 -0
  49. package/src/lib/shapes/arrow/ArrowShapeOptions.test.ts +2 -1
  50. package/src/lib/shapes/arrow/ArrowShapeTool.test.ts +4 -3
  51. package/src/lib/shapes/arrow/ArrowShapeUtil.test.ts +7 -6
  52. package/src/lib/shapes/draw/DrawShapeTool.test.ts +0 -5
  53. package/src/lib/shapes/frame/FrameShapeUtil.tsx +12 -4
  54. package/src/lib/shapes/line/LineShapeUtil.test.tsx +4 -3
  55. package/src/lib/shapes/line/__snapshots__/LineShapeUtil.test.tsx.snap +2 -2
  56. package/src/lib/shapes/shared/ShapeFill.tsx +1 -1
  57. package/src/lib/shapes/shared/freehand/svg.ts +2 -0
  58. package/src/lib/shapes/text/TextShapeTool.test.ts +6 -5
  59. package/src/lib/tools/EraserTool/childStates/Erasing.ts +34 -1
  60. package/src/lib/tools/EraserTool/childStates/Pointing.ts +20 -0
  61. package/src/lib/ui/components/primitives/TldrawUiTooltip.tsx +98 -114
  62. package/src/lib/ui/components/primitives/menus/TldrawUiMenuContext.tsx +0 -1
  63. package/src/lib/ui/components/primitives/menus/TldrawUiMenuGroup.tsx +0 -10
  64. package/src/lib/ui/components/primitives/menus/TldrawUiMenuItem.tsx +5 -18
  65. package/src/lib/ui/hooks/useTools.tsx +25 -3
  66. package/src/lib/ui/version.ts +3 -3
  67. package/src/lib/ui.css +5 -6
  68. package/src/lib/utils/excalidraw/__snapshots__/putExcalidrawContent.test.tsx.snap +5 -5
  69. package/src/lib/utils/tldr/__snapshots__/buildFromV1Document.test.ts.snap +4 -4
  70. package/src/test/A11y.test.tsx +3 -2
  71. package/src/test/ClickManager.test.ts +7 -6
  72. package/src/test/Editor.test.tsx +20 -19
  73. package/src/test/EraserTool.test.ts +184 -13
  74. package/src/test/HandTool.test.ts +10 -9
  75. package/src/test/HighlightShape.test.ts +2 -1
  76. package/src/test/SelectTool.test.ts +3 -2
  77. package/src/test/TLUserPreferences.test.ts +4 -3
  78. package/src/test/TestEditor.ts +13 -15
  79. package/src/test/TldrawEditor.test.tsx +11 -10
  80. package/src/test/ZoomTool.test.ts +7 -6
  81. package/src/test/__snapshots__/drawing.test.ts.snap +2 -2
  82. package/src/test/__snapshots__/groups.test.tsx.snap +6 -6
  83. package/src/test/__snapshots__/resizing.test.ts.snap +2 -2
  84. package/src/test/arrows-megabus.test.tsx +5 -4
  85. package/src/test/bindings.test.tsx +24 -37
  86. package/src/test/bookmark-shapes.test.ts +1 -8
  87. package/src/test/commands/__snapshots__/getSvgString.test.ts.snap +23 -7
  88. package/src/test/commands/__snapshots__/packShapes.test.ts.snap +8 -8
  89. package/src/test/commands/__snapshots__/zoomToFit.test.ts.snap +2 -2
  90. package/src/test/commands/alignShapes.test.tsx +25 -24
  91. package/src/test/commands/animationSpeed.test.ts +2 -1
  92. package/src/test/commands/centerOnPoint.test.ts +3 -2
  93. package/src/test/commands/clipboard.test.ts +3 -2
  94. package/src/test/commands/createShapes.test.ts +2 -1
  95. package/src/test/commands/deleteShapes.test.ts +2 -1
  96. package/src/test/commands/distributeShapes.test.tsx +11 -10
  97. package/src/test/commands/getSvgString.test.ts +2 -1
  98. package/src/test/commands/packShapes.test.ts +5 -4
  99. package/src/test/commands/resizeShape.test.ts +2 -1
  100. package/src/test/commands/rotateShapes.test.ts +7 -6
  101. package/src/test/commands/setCamera.test.ts +4 -3
  102. package/src/test/commands/setCurrentPage.test.ts +3 -2
  103. package/src/test/commands/stackShapes.test.ts +11 -10
  104. package/src/test/commands/stretch.test.tsx +13 -12
  105. package/src/test/createDeepLink.test.tsx +2 -1
  106. package/src/test/cropping.test.ts +3 -2
  107. package/src/test/drawing.test.ts +2 -1
  108. package/src/test/flipShapes.test.ts +4 -3
  109. package/src/test/frames.test.ts +25 -24
  110. package/src/test/getCulledShapes.test.tsx +3 -2
  111. package/src/test/groups.test.tsx +1 -1
  112. package/src/test/handleDeepLink.test.tsx +2 -1
  113. package/src/test/maxShapes.test.ts +3 -2
  114. package/src/test/modifiers.test.ts +5 -4
  115. package/src/test/navigation.test.ts +12 -11
  116. package/src/test/panning.test.ts +2 -1
  117. package/src/test/perf/perf.test.ts +2 -1
  118. package/src/test/registerDeepLinkListener.test.tsx +10 -9
  119. package/src/test/resizing.test.ts +39 -38
  120. package/src/test/select.test.tsx +4 -3
  121. package/src/test/selection-omnibus.test.ts +11 -10
  122. package/src/test/shapeutils.test.ts +4 -3
  123. package/src/test/translating.test.ts +9 -8
  124. package/tldraw.css +5 -6
@@ -24,7 +24,9 @@ module.exports = __toCommonJS(Pointing_exports);
24
24
  var import_editor = require("@tldraw/editor");
25
25
  class Pointing extends import_editor.StateNode {
26
26
  static id = "pointing";
27
+ _isHoldingAccelKey = false;
27
28
  onEnter() {
29
+ this._isHoldingAccelKey = (0, import_editor.isAccelKey)(this.editor.inputs);
28
30
  const zoomLevel = this.editor.getZoomLevel();
29
31
  const currentPageShapesSorted = this.editor.getCurrentPageRenderingShapesSorted();
30
32
  const {
@@ -46,10 +48,19 @@ class Pointing extends import_editor.StateNode {
46
48
  break;
47
49
  }
48
50
  erasing.add(hitShape.id);
51
+ if (this._isHoldingAccelKey) {
52
+ break;
53
+ }
49
54
  }
50
55
  }
51
56
  this.editor.setErasingShapes([...erasing]);
52
57
  }
58
+ onKeyUp() {
59
+ this._isHoldingAccelKey = (0, import_editor.isAccelKey)(this.editor.inputs);
60
+ }
61
+ onKeyDown() {
62
+ this._isHoldingAccelKey = (0, import_editor.isAccelKey)(this.editor.inputs);
63
+ }
53
64
  onLongPress(info) {
54
65
  this.startErasing(info);
55
66
  }
@@ -59,6 +70,7 @@ class Pointing extends import_editor.StateNode {
59
70
  }
60
71
  }
61
72
  onPointerMove(info) {
73
+ if (this._isHoldingAccelKey) return;
62
74
  if (this.editor.inputs.isDragging) {
63
75
  this.startErasing(info);
64
76
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/lib/tools/EraserTool/childStates/Pointing.ts"],
4
- "sourcesContent": ["import {\n\tStateNode,\n\tTLFrameShape,\n\tTLGroupShape,\n\tTLPointerEventInfo,\n\tTLShapeId,\n} from '@tldraw/editor'\n\nexport class Pointing extends StateNode {\n\tstatic override id = 'pointing'\n\n\toverride onEnter() {\n\t\tconst zoomLevel = this.editor.getZoomLevel()\n\t\tconst currentPageShapesSorted = this.editor.getCurrentPageRenderingShapesSorted()\n\t\tconst {\n\t\t\tinputs: { currentPagePoint },\n\t\t} = this.editor\n\n\t\tconst erasing = new Set<TLShapeId>()\n\n\t\tconst initialSize = erasing.size\n\n\t\tfor (let n = currentPageShapesSorted.length, i = n - 1; i >= 0; i--) {\n\t\t\tconst shape = currentPageShapesSorted[i]\n\t\t\tif (\n\t\t\t\tthis.editor.isShapeOrAncestorLocked(shape) ||\n\t\t\t\tthis.editor.isShapeOfType<TLGroupShape>(shape, 'group')\n\t\t\t) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\tthis.editor.isPointInShape(shape, currentPagePoint, {\n\t\t\t\t\thitInside: false,\n\t\t\t\t\tmargin: this.editor.options.hitTestMargin / zoomLevel,\n\t\t\t\t})\n\t\t\t) {\n\t\t\t\tconst hitShape = this.editor.getOutermostSelectableShape(shape)\n\t\t\t\t// If we've hit a frame after hitting any other shape, stop here\n\t\t\t\tif (\n\t\t\t\t\tthis.editor.isShapeOfType<TLFrameShape>(hitShape, 'frame') &&\n\t\t\t\t\terasing.size > initialSize\n\t\t\t\t) {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\terasing.add(hitShape.id)\n\t\t\t}\n\t\t}\n\n\t\tthis.editor.setErasingShapes([...erasing])\n\t}\n\n\toverride onLongPress(info: TLPointerEventInfo) {\n\t\tthis.startErasing(info)\n\t}\n\n\toverride onExit(_info: any, to: string) {\n\t\tif (to !== 'erasing') {\n\t\t\tthis.editor.setErasingShapes([])\n\t\t}\n\t}\n\n\toverride onPointerMove(info: TLPointerEventInfo) {\n\t\tif (this.editor.inputs.isDragging) {\n\t\t\tthis.startErasing(info)\n\t\t}\n\t}\n\n\toverride onPointerUp() {\n\t\tthis.complete()\n\t}\n\n\toverride onCancel() {\n\t\tthis.cancel()\n\t}\n\n\toverride onComplete() {\n\t\tthis.complete()\n\t}\n\n\toverride onInterrupt() {\n\t\tthis.cancel()\n\t}\n\n\tprivate startErasing(info: TLPointerEventInfo) {\n\t\tthis.parent.transition('erasing', info)\n\t}\n\n\tcomplete() {\n\t\tconst erasingShapeIds = this.editor.getErasingShapeIds()\n\n\t\tif (erasingShapeIds.length) {\n\t\t\tthis.editor.markHistoryStoppingPoint('erase end')\n\t\t\tthis.editor.deleteShapes(erasingShapeIds)\n\t\t}\n\n\t\tthis.parent.transition('idle')\n\t}\n\n\tcancel() {\n\t\tthis.parent.transition('idle')\n\t}\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAMO;AAEA,MAAM,iBAAiB,wBAAU;AAAA,EACvC,OAAgB,KAAK;AAAA,EAEZ,UAAU;AAClB,UAAM,YAAY,KAAK,OAAO,aAAa;AAC3C,UAAM,0BAA0B,KAAK,OAAO,oCAAoC;AAChF,UAAM;AAAA,MACL,QAAQ,EAAE,iBAAiB;AAAA,IAC5B,IAAI,KAAK;AAET,UAAM,UAAU,oBAAI,IAAe;AAEnC,UAAM,cAAc,QAAQ;AAE5B,aAAS,IAAI,wBAAwB,QAAQ,IAAI,IAAI,GAAG,KAAK,GAAG,KAAK;AACpE,YAAM,QAAQ,wBAAwB,CAAC;AACvC,UACC,KAAK,OAAO,wBAAwB,KAAK,KACzC,KAAK,OAAO,cAA4B,OAAO,OAAO,GACrD;AACD;AAAA,MACD;AAEA,UACC,KAAK,OAAO,eAAe,OAAO,kBAAkB;AAAA,QACnD,WAAW;AAAA,QACX,QAAQ,KAAK,OAAO,QAAQ,gBAAgB;AAAA,MAC7C,CAAC,GACA;AACD,cAAM,WAAW,KAAK,OAAO,4BAA4B,KAAK;AAE9D,YACC,KAAK,OAAO,cAA4B,UAAU,OAAO,KACzD,QAAQ,OAAO,aACd;AACD;AAAA,QACD;AAEA,gBAAQ,IAAI,SAAS,EAAE;AAAA,MACxB;AAAA,IACD;AAEA,SAAK,OAAO,iBAAiB,CAAC,GAAG,OAAO,CAAC;AAAA,EAC1C;AAAA,EAES,YAAY,MAA0B;AAC9C,SAAK,aAAa,IAAI;AAAA,EACvB;AAAA,EAES,OAAO,OAAY,IAAY;AACvC,QAAI,OAAO,WAAW;AACrB,WAAK,OAAO,iBAAiB,CAAC,CAAC;AAAA,IAChC;AAAA,EACD;AAAA,EAES,cAAc,MAA0B;AAChD,QAAI,KAAK,OAAO,OAAO,YAAY;AAClC,WAAK,aAAa,IAAI;AAAA,IACvB;AAAA,EACD;AAAA,EAES,cAAc;AACtB,SAAK,SAAS;AAAA,EACf;AAAA,EAES,WAAW;AACnB,SAAK,OAAO;AAAA,EACb;AAAA,EAES,aAAa;AACrB,SAAK,SAAS;AAAA,EACf;AAAA,EAES,cAAc;AACtB,SAAK,OAAO;AAAA,EACb;AAAA,EAEQ,aAAa,MAA0B;AAC9C,SAAK,OAAO,WAAW,WAAW,IAAI;AAAA,EACvC;AAAA,EAEA,WAAW;AACV,UAAM,kBAAkB,KAAK,OAAO,mBAAmB;AAEvD,QAAI,gBAAgB,QAAQ;AAC3B,WAAK,OAAO,yBAAyB,WAAW;AAChD,WAAK,OAAO,aAAa,eAAe;AAAA,IACzC;AAEA,SAAK,OAAO,WAAW,MAAM;AAAA,EAC9B;AAAA,EAEA,SAAS;AACR,SAAK,OAAO,WAAW,MAAM;AAAA,EAC9B;AACD;",
4
+ "sourcesContent": ["import {\n\tisAccelKey,\n\tStateNode,\n\tTLFrameShape,\n\tTLGroupShape,\n\tTLPointerEventInfo,\n\tTLShapeId,\n} from '@tldraw/editor'\n\nexport class Pointing extends StateNode {\n\tstatic override id = 'pointing'\n\n\t_isHoldingAccelKey = false\n\n\toverride onEnter() {\n\t\tthis._isHoldingAccelKey = isAccelKey(this.editor.inputs)\n\n\t\tconst zoomLevel = this.editor.getZoomLevel()\n\t\tconst currentPageShapesSorted = this.editor.getCurrentPageRenderingShapesSorted()\n\t\tconst {\n\t\t\tinputs: { currentPagePoint },\n\t\t} = this.editor\n\n\t\tconst erasing = new Set<TLShapeId>()\n\n\t\tconst initialSize = erasing.size\n\n\t\tfor (let n = currentPageShapesSorted.length, i = n - 1; i >= 0; i--) {\n\t\t\tconst shape = currentPageShapesSorted[i]\n\t\t\tif (\n\t\t\t\tthis.editor.isShapeOrAncestorLocked(shape) ||\n\t\t\t\tthis.editor.isShapeOfType<TLGroupShape>(shape, 'group')\n\t\t\t) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\tthis.editor.isPointInShape(shape, currentPagePoint, {\n\t\t\t\t\thitInside: false,\n\t\t\t\t\tmargin: this.editor.options.hitTestMargin / zoomLevel,\n\t\t\t\t})\n\t\t\t) {\n\t\t\t\tconst hitShape = this.editor.getOutermostSelectableShape(shape)\n\t\t\t\t// If we've hit a frame after hitting any other shape, stop here\n\t\t\t\tif (\n\t\t\t\t\tthis.editor.isShapeOfType<TLFrameShape>(hitShape, 'frame') &&\n\t\t\t\t\terasing.size > initialSize\n\t\t\t\t) {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\terasing.add(hitShape.id)\n\n\t\t\t\t// If the user is holding the meta / ctrl key, stop after the first shape\n\t\t\t\tif (this._isHoldingAccelKey) {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthis.editor.setErasingShapes([...erasing])\n\t}\n\n\toverride onKeyUp() {\n\t\tthis._isHoldingAccelKey = isAccelKey(this.editor.inputs)\n\t}\n\n\toverride onKeyDown() {\n\t\tthis._isHoldingAccelKey = isAccelKey(this.editor.inputs)\n\t}\n\n\toverride onLongPress(info: TLPointerEventInfo) {\n\t\tthis.startErasing(info)\n\t}\n\n\toverride onExit(_info: any, to: string) {\n\t\tif (to !== 'erasing') {\n\t\t\tthis.editor.setErasingShapes([])\n\t\t}\n\t}\n\n\toverride onPointerMove(info: TLPointerEventInfo) {\n\t\tif (this._isHoldingAccelKey) return\n\n\t\tif (this.editor.inputs.isDragging) {\n\t\t\tthis.startErasing(info)\n\t\t}\n\t}\n\n\toverride onPointerUp() {\n\t\tthis.complete()\n\t}\n\n\toverride onCancel() {\n\t\tthis.cancel()\n\t}\n\n\toverride onComplete() {\n\t\tthis.complete()\n\t}\n\n\toverride onInterrupt() {\n\t\tthis.cancel()\n\t}\n\n\tprivate startErasing(info: TLPointerEventInfo) {\n\t\tthis.parent.transition('erasing', info)\n\t}\n\n\tcomplete() {\n\t\tconst erasingShapeIds = this.editor.getErasingShapeIds()\n\n\t\tif (erasingShapeIds.length) {\n\t\t\tthis.editor.markHistoryStoppingPoint('erase end')\n\t\t\tthis.editor.deleteShapes(erasingShapeIds)\n\t\t}\n\n\t\tthis.parent.transition('idle')\n\t}\n\n\tcancel() {\n\t\tthis.parent.transition('idle')\n\t}\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAOO;AAEA,MAAM,iBAAiB,wBAAU;AAAA,EACvC,OAAgB,KAAK;AAAA,EAErB,qBAAqB;AAAA,EAEZ,UAAU;AAClB,SAAK,yBAAqB,0BAAW,KAAK,OAAO,MAAM;AAEvD,UAAM,YAAY,KAAK,OAAO,aAAa;AAC3C,UAAM,0BAA0B,KAAK,OAAO,oCAAoC;AAChF,UAAM;AAAA,MACL,QAAQ,EAAE,iBAAiB;AAAA,IAC5B,IAAI,KAAK;AAET,UAAM,UAAU,oBAAI,IAAe;AAEnC,UAAM,cAAc,QAAQ;AAE5B,aAAS,IAAI,wBAAwB,QAAQ,IAAI,IAAI,GAAG,KAAK,GAAG,KAAK;AACpE,YAAM,QAAQ,wBAAwB,CAAC;AACvC,UACC,KAAK,OAAO,wBAAwB,KAAK,KACzC,KAAK,OAAO,cAA4B,OAAO,OAAO,GACrD;AACD;AAAA,MACD;AAEA,UACC,KAAK,OAAO,eAAe,OAAO,kBAAkB;AAAA,QACnD,WAAW;AAAA,QACX,QAAQ,KAAK,OAAO,QAAQ,gBAAgB;AAAA,MAC7C,CAAC,GACA;AACD,cAAM,WAAW,KAAK,OAAO,4BAA4B,KAAK;AAE9D,YACC,KAAK,OAAO,cAA4B,UAAU,OAAO,KACzD,QAAQ,OAAO,aACd;AACD;AAAA,QACD;AAEA,gBAAQ,IAAI,SAAS,EAAE;AAGvB,YAAI,KAAK,oBAAoB;AAC5B;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAEA,SAAK,OAAO,iBAAiB,CAAC,GAAG,OAAO,CAAC;AAAA,EAC1C;AAAA,EAES,UAAU;AAClB,SAAK,yBAAqB,0BAAW,KAAK,OAAO,MAAM;AAAA,EACxD;AAAA,EAES,YAAY;AACpB,SAAK,yBAAqB,0BAAW,KAAK,OAAO,MAAM;AAAA,EACxD;AAAA,EAES,YAAY,MAA0B;AAC9C,SAAK,aAAa,IAAI;AAAA,EACvB;AAAA,EAES,OAAO,OAAY,IAAY;AACvC,QAAI,OAAO,WAAW;AACrB,WAAK,OAAO,iBAAiB,CAAC,CAAC;AAAA,IAChC;AAAA,EACD;AAAA,EAES,cAAc,MAA0B;AAChD,QAAI,KAAK,mBAAoB;AAE7B,QAAI,KAAK,OAAO,OAAO,YAAY;AAClC,WAAK,aAAa,IAAI;AAAA,IACvB;AAAA,EACD;AAAA,EAES,cAAc;AACtB,SAAK,SAAS;AAAA,EACf;AAAA,EAES,WAAW;AACnB,SAAK,OAAO;AAAA,EACb;AAAA,EAES,aAAa;AACrB,SAAK,SAAS;AAAA,EACf;AAAA,EAES,cAAc;AACtB,SAAK,OAAO;AAAA,EACb;AAAA,EAEQ,aAAa,MAA0B;AAC9C,SAAK,OAAO,WAAW,WAAW,IAAI;AAAA,EACvC;AAAA,EAEA,WAAW;AACV,UAAM,kBAAkB,KAAK,OAAO,mBAAmB;AAEvD,QAAI,gBAAgB,QAAQ;AAC3B,WAAK,OAAO,yBAAyB,WAAW;AAChD,WAAK,OAAO,aAAa,eAAe;AAAA,IACzC;AAEA,SAAK,OAAO,WAAW,MAAM;AAAA,EAC9B;AAAA,EAEA,SAAS;AACR,SAAK,OAAO,WAAW,MAAM;AAAA,EAC9B;AACD;",
6
6
  "names": []
7
7
  }
@@ -37,78 +37,67 @@ var import_jsx_runtime = require("react/jsx-runtime");
37
37
  var import_editor = require("@tldraw/editor");
38
38
  var import_radix_ui = require("radix-ui");
39
39
  var import_react = __toESM(require("react"));
40
- var import_usePrefersReducedMotion = require("../../../shapes/shared/usePrefersReducedMotion");
41
40
  var import_layout = require("./layout");
42
41
  const DEFAULT_TOOLTIP_DELAY_MS = 700;
43
42
  class TooltipManager {
44
43
  static instance = null;
45
- currentTooltipId = null;
46
- currentContent = "";
47
- currentSide = "bottom";
48
- currentSideOffset = 5;
44
+ currentTooltip = (0, import_editor.atom)("current tooltip", null);
49
45
  destroyTimeoutId = null;
50
- subscribers = /* @__PURE__ */ new Set();
51
- activeElement = null;
52
- editor = null;
53
46
  static getInstance() {
54
47
  if (!TooltipManager.instance) {
55
48
  TooltipManager.instance = new TooltipManager();
56
49
  }
57
50
  return TooltipManager.instance;
58
51
  }
59
- setEditor(editor) {
60
- this.editor = editor;
61
- }
62
- subscribe(callback) {
63
- this.subscribers.add(callback);
64
- return () => this.subscribers.delete(callback);
65
- }
66
- notify() {
67
- this.subscribers.forEach((callback) => callback());
68
- }
69
- showTooltip(tooltipId, content, element, side = "bottom", sideOffset = 5) {
52
+ showTooltip(tooltipId, content, targetElement, side, sideOffset, showOnMobile, delayDuration) {
70
53
  if (this.destroyTimeoutId) {
71
54
  clearTimeout(this.destroyTimeoutId);
72
55
  this.destroyTimeoutId = null;
73
56
  }
74
- this.currentTooltipId = tooltipId;
75
- this.currentContent = content;
76
- this.currentSide = side;
77
- this.currentSideOffset = sideOffset;
78
- this.activeElement = element;
79
- this.notify();
57
+ this.currentTooltip.set({
58
+ id: tooltipId,
59
+ content,
60
+ side,
61
+ sideOffset,
62
+ showOnMobile,
63
+ targetElement,
64
+ delayDuration
65
+ });
80
66
  }
81
- hideTooltip(tooltipId, instant = false) {
67
+ hideTooltip(editor, tooltipId, instant = false) {
82
68
  const hide = () => {
83
- if (this.currentTooltipId === tooltipId) {
84
- this.currentTooltipId = null;
85
- this.currentContent = "";
86
- this.activeElement = null;
69
+ if (this.currentTooltip.get()?.id === tooltipId) {
70
+ this.currentTooltip.set(null);
87
71
  this.destroyTimeoutId = null;
88
- this.notify();
89
72
  }
90
73
  };
91
- if (instant) {
74
+ if (editor && !instant) {
75
+ this.destroyTimeoutId = editor.timers.setTimeout(hide, 300);
76
+ } else {
92
77
  hide();
93
- } else if (this.editor) {
94
- this.destroyTimeoutId = this.editor.timers.setTimeout(hide, 300);
95
78
  }
96
79
  }
97
80
  hideAllTooltips() {
98
- this.currentTooltipId = null;
99
- this.currentContent = "";
100
- this.activeElement = null;
81
+ this.currentTooltip.set(null);
101
82
  this.destroyTimeoutId = null;
102
- this.notify();
103
83
  }
104
84
  getCurrentTooltipData() {
105
- return {
106
- id: this.currentTooltipId,
107
- content: this.currentContent,
108
- side: this.currentSide,
109
- sideOffset: this.currentSideOffset,
110
- element: this.activeElement
111
- };
85
+ const currentTooltip = this.currentTooltip.get();
86
+ if (!currentTooltip) return null;
87
+ if (!this.supportsHover() && !currentTooltip.showOnMobile) return null;
88
+ return currentTooltip;
89
+ }
90
+ supportsHoverAtom = null;
91
+ supportsHover() {
92
+ if (!this.supportsHoverAtom) {
93
+ const mediaQuery = window.matchMedia("(hover: hover)");
94
+ const supportsHover = (0, import_editor.atom)("has hover", mediaQuery.matches);
95
+ this.supportsHoverAtom = supportsHover;
96
+ mediaQuery.addEventListener("change", (e) => {
97
+ supportsHover.set(e.matches);
98
+ });
99
+ }
100
+ return this.supportsHoverAtom.get();
112
101
  }
113
102
  }
114
103
  const tooltipManager = TooltipManager.getInstance();
@@ -121,44 +110,23 @@ function TldrawUiTooltipProvider({ children }) {
121
110
  }
122
111
  function TooltipSingleton() {
123
112
  const editor = (0, import_editor.useMaybeEditor)();
124
- const [, forceUpdate] = (0, import_react.useState)({});
125
113
  const [isOpen, setIsOpen] = (0, import_react.useState)(false);
126
114
  const triggerRef = (0, import_react.useRef)(null);
127
- const previousPositionRef = (0, import_react.useRef)(null);
128
- const prefersReducedMotion = (0, import_usePrefersReducedMotion.usePrefersReducedMotion)();
129
- const [shouldAnimate, setShouldAnimate] = (0, import_react.useState)(false);
130
115
  const isFirstShowRef = (0, import_react.useRef)(true);
131
116
  const showTimeoutRef = (0, import_react.useRef)(null);
117
+ const currentTooltip = (0, import_editor.useValue)(
118
+ "current tooltip",
119
+ () => tooltipManager.getCurrentTooltipData(),
120
+ []
121
+ );
132
122
  (0, import_react.useEffect)(() => {
133
- tooltipManager.setEditor(editor);
134
- }, [editor]);
135
- (0, import_react.useEffect)(() => {
136
- const unsubscribe = tooltipManager.subscribe(() => {
137
- forceUpdate({});
138
- });
139
- return unsubscribe;
140
- }, []);
141
- const tooltipData = tooltipManager.getCurrentTooltipData();
142
- (0, import_react.useEffect)(() => {
143
- const shouldBeOpen = Boolean(tooltipData.id && tooltipData.element);
144
123
  if (showTimeoutRef.current) {
145
124
  clearTimeout(showTimeoutRef.current);
146
125
  showTimeoutRef.current = null;
147
126
  }
148
- if (shouldBeOpen && tooltipData.element && triggerRef.current) {
149
- const activeRect = tooltipData.element.getBoundingClientRect();
127
+ if (currentTooltip && triggerRef.current) {
128
+ const activeRect = currentTooltip.targetElement.getBoundingClientRect();
150
129
  const trigger = triggerRef.current;
151
- const newPosition = {
152
- x: activeRect.left + activeRect.width / 2,
153
- y: activeRect.top + activeRect.height / 2
154
- };
155
- let shouldAnimateCheck = false;
156
- if (previousPositionRef.current) {
157
- const isNearPrevious = import_editor.Vec.DistMin(previousPositionRef.current, newPosition, 200);
158
- shouldAnimateCheck = !prefersReducedMotion && isNearPrevious && Math.abs(newPosition.y - previousPositionRef.current.y) < 50;
159
- }
160
- setShouldAnimate(isFirstShowRef.current ? false : shouldAnimateCheck);
161
- previousPositionRef.current = newPosition;
162
130
  trigger.style.position = "fixed";
163
131
  trigger.style.left = `${activeRect.left}px`;
164
132
  trigger.style.top = `${activeRect.top}px`;
@@ -170,18 +138,16 @@ function TooltipSingleton() {
170
138
  showTimeoutRef.current = editor.timers.setTimeout(() => {
171
139
  setIsOpen(true);
172
140
  isFirstShowRef.current = false;
173
- }, editor.options.tooltipDelayMs);
141
+ }, currentTooltip.delayDuration ?? editor.options.tooltipDelayMs);
174
142
  } else {
175
143
  setIsOpen(true);
176
144
  }
177
- } else if (!shouldBeOpen) {
145
+ } else {
178
146
  setIsOpen(false);
179
- previousPositionRef.current = null;
180
- setShouldAnimate(false);
181
147
  isFirstShowRef.current = true;
182
148
  }
183
- }, [tooltipData.id, tooltipData.element, editor, prefersReducedMotion]);
184
- if (!tooltipData.id) {
149
+ }, [editor, currentTooltip]);
150
+ if (!currentTooltip) {
185
151
  return null;
186
152
  }
187
153
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_radix_ui.Tooltip.Root, { open: isOpen, delayDuration: 0, children: [
@@ -190,14 +156,13 @@ function TooltipSingleton() {
190
156
  import_radix_ui.Tooltip.Content,
191
157
  {
192
158
  className: "tlui-tooltip",
193
- "data-should-animate": shouldAnimate,
194
- side: tooltipData.side,
195
- sideOffset: tooltipData.sideOffset,
159
+ side: currentTooltip.side,
160
+ sideOffset: currentTooltip.sideOffset,
196
161
  avoidCollisions: true,
197
162
  collisionPadding: 8,
198
163
  dir: "ltr",
199
164
  children: [
200
- tooltipData.content,
165
+ currentTooltip.content,
201
166
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_radix_ui.Tooltip.Arrow, { className: "tlui-tooltip__arrow" })
202
167
  ]
203
168
  }
@@ -205,7 +170,15 @@ function TooltipSingleton() {
205
170
  ] });
206
171
  }
207
172
  const TldrawUiTooltip = (0, import_react.forwardRef)(
208
- ({ children, content, side, sideOffset = 5, disabled = false }, ref) => {
173
+ ({
174
+ children,
175
+ content,
176
+ side,
177
+ sideOffset = 5,
178
+ disabled = false,
179
+ showOnMobile = false,
180
+ delayDuration
181
+ }, ref) => {
209
182
  const editor = (0, import_editor.useMaybeEditor)();
210
183
  const tooltipId = (0, import_react.useRef)((0, import_editor.uniqueId)());
211
184
  const hasProvider = (0, import_react.useContext)(TooltipSingletonContext);
@@ -215,10 +188,10 @@ const TldrawUiTooltip = (0, import_react.forwardRef)(
215
188
  const currentTooltipId = tooltipId.current;
216
189
  return () => {
217
190
  if (hasProvider) {
218
- tooltipManager.hideTooltip(currentTooltipId, true);
191
+ tooltipManager.hideTooltip(editor, currentTooltipId, true);
219
192
  }
220
193
  };
221
- }, [hasProvider]);
194
+ }, [editor, hasProvider]);
222
195
  if (disabled || !content) {
223
196
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children });
224
197
  }
@@ -226,7 +199,7 @@ const TldrawUiTooltip = (0, import_react.forwardRef)(
226
199
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
227
200
  import_radix_ui.Tooltip.Root,
228
201
  {
229
- delayDuration: editor?.options.tooltipDelayMs || DEFAULT_TOOLTIP_DELAY_MS,
202
+ delayDuration: delayDuration ?? (editor?.options.tooltipDelayMs || DEFAULT_TOOLTIP_DELAY_MS),
230
203
  disableHoverableContent: true,
231
204
  children: [
232
205
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_radix_ui.Tooltip.Trigger, { asChild: true, ref, children }),
@@ -258,12 +231,14 @@ const TldrawUiTooltip = (0, import_react.forwardRef)(
258
231
  content,
259
232
  event.currentTarget,
260
233
  sideToUse,
261
- sideOffset
234
+ sideOffset,
235
+ showOnMobile,
236
+ delayDuration
262
237
  );
263
238
  };
264
239
  const handleMouseLeave = (event) => {
265
240
  child.props.onMouseLeave?.(event);
266
- tooltipManager.hideTooltip(tooltipId.current);
241
+ tooltipManager.hideTooltip(editor, tooltipId.current);
267
242
  };
268
243
  const handleFocus = (event) => {
269
244
  child.props.onFocus?.(event);
@@ -272,12 +247,14 @@ const TldrawUiTooltip = (0, import_react.forwardRef)(
272
247
  content,
273
248
  event.currentTarget,
274
249
  sideToUse,
275
- sideOffset
250
+ sideOffset,
251
+ showOnMobile,
252
+ delayDuration
276
253
  );
277
254
  };
278
255
  const handleBlur = (event) => {
279
256
  child.props.onBlur?.(event);
280
- tooltipManager.hideTooltip(tooltipId.current);
257
+ tooltipManager.hideTooltip(editor, tooltipId.current);
281
258
  };
282
259
  const childrenWithHandlers = import_react.default.cloneElement(children, {
283
260
  onMouseEnter: handleMouseEnter,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/lib/ui/components/primitives/TldrawUiTooltip.tsx"],
4
- "sourcesContent": ["import { assert, Editor, uniqueId, useMaybeEditor, Vec } from '@tldraw/editor'\nimport { Tooltip as _Tooltip } from 'radix-ui'\nimport React, { createContext, forwardRef, useContext, useEffect, useRef, useState } from 'react'\nimport { usePrefersReducedMotion } from '../../../shapes/shared/usePrefersReducedMotion'\nimport { useTldrawUiOrientation } from './layout'\n\nconst DEFAULT_TOOLTIP_DELAY_MS = 700\n\n/** @public */\nexport interface TldrawUiTooltipProps {\n\tchildren: React.ReactNode\n\tcontent?: string | React.ReactNode\n\tside?: 'top' | 'right' | 'bottom' | 'left'\n\tsideOffset?: number\n\tdisabled?: boolean\n}\n\n// Singleton tooltip manager\nclass TooltipManager {\n\tprivate static instance: TooltipManager | null = null\n\tprivate currentTooltipId: string | null = null\n\tprivate currentContent: string | React.ReactNode = ''\n\tprivate currentSide: 'top' | 'right' | 'bottom' | 'left' = 'bottom'\n\tprivate currentSideOffset: number = 5\n\tprivate destroyTimeoutId: number | null = null\n\tprivate subscribers: Set<() => void> = new Set()\n\tprivate activeElement: HTMLElement | null = null\n\tprivate editor: Editor | null = null\n\n\tstatic getInstance(): TooltipManager {\n\t\tif (!TooltipManager.instance) {\n\t\t\tTooltipManager.instance = new TooltipManager()\n\t\t}\n\t\treturn TooltipManager.instance\n\t}\n\n\tsetEditor(editor: Editor | null) {\n\t\tthis.editor = editor\n\t}\n\n\tsubscribe(callback: () => void): () => void {\n\t\tthis.subscribers.add(callback)\n\t\treturn () => this.subscribers.delete(callback)\n\t}\n\n\tprivate notify() {\n\t\tthis.subscribers.forEach((callback) => callback())\n\t}\n\n\tshowTooltip(\n\t\ttooltipId: string,\n\t\tcontent: string | React.ReactNode,\n\t\telement: HTMLElement,\n\t\tside: 'top' | 'right' | 'bottom' | 'left' = 'bottom',\n\t\tsideOffset: number = 5\n\t) {\n\t\t// Clear any existing destroy timeout\n\t\tif (this.destroyTimeoutId) {\n\t\t\tclearTimeout(this.destroyTimeoutId)\n\t\t\tthis.destroyTimeoutId = null\n\t\t}\n\n\t\t// Update current tooltip\n\t\tthis.currentTooltipId = tooltipId\n\t\tthis.currentContent = content\n\t\tthis.currentSide = side\n\t\tthis.currentSideOffset = sideOffset\n\t\tthis.activeElement = element\n\n\t\tthis.notify()\n\t}\n\n\thideTooltip(tooltipId: string, instant: boolean = false) {\n\t\tconst hide = () => {\n\t\t\t// Only hide if this is the current tooltip\n\t\t\tif (this.currentTooltipId === tooltipId) {\n\t\t\t\tthis.currentTooltipId = null\n\t\t\t\tthis.currentContent = ''\n\t\t\t\tthis.activeElement = null\n\t\t\t\tthis.destroyTimeoutId = null\n\t\t\t\tthis.notify()\n\t\t\t}\n\t\t}\n\n\t\tif (instant) {\n\t\t\thide()\n\t\t} else if (this.editor) {\n\t\t\t// Start destroy timeout (1 second)\n\t\t\tthis.destroyTimeoutId = this.editor.timers.setTimeout(hide, 300)\n\t\t}\n\t}\n\n\thideAllTooltips() {\n\t\tthis.currentTooltipId = null\n\t\tthis.currentContent = ''\n\t\tthis.activeElement = null\n\t\tthis.destroyTimeoutId = null\n\t\tthis.notify()\n\t}\n\n\tgetCurrentTooltipData() {\n\t\treturn {\n\t\t\tid: this.currentTooltipId,\n\t\t\tcontent: this.currentContent,\n\t\t\tside: this.currentSide,\n\t\t\tsideOffset: this.currentSideOffset,\n\t\t\telement: this.activeElement,\n\t\t}\n\t}\n}\n\nexport const tooltipManager = TooltipManager.getInstance()\n\n// Context for the tooltip singleton\nconst TooltipSingletonContext = createContext<boolean>(false)\n\n/** @public */\nexport interface TldrawUiTooltipProviderProps {\n\tchildren: React.ReactNode\n}\n\n/** @public @react */\nexport function TldrawUiTooltipProvider({ children }: TldrawUiTooltipProviderProps) {\n\treturn (\n\t\t<_Tooltip.Provider skipDelayDuration={700}>\n\t\t\t<TooltipSingletonContext.Provider value={true}>\n\t\t\t\t{children}\n\t\t\t\t<TooltipSingleton />\n\t\t\t</TooltipSingletonContext.Provider>\n\t\t</_Tooltip.Provider>\n\t)\n}\n\n// The singleton tooltip component that renders once\nfunction TooltipSingleton() {\n\tconst editor = useMaybeEditor()\n\tconst [, forceUpdate] = useState({})\n\tconst [isOpen, setIsOpen] = useState(false)\n\tconst triggerRef = useRef<HTMLDivElement>(null)\n\tconst previousPositionRef = useRef<{ x: number; y: number } | null>(null)\n\tconst prefersReducedMotion = usePrefersReducedMotion()\n\tconst [shouldAnimate, setShouldAnimate] = useState(false)\n\tconst isFirstShowRef = useRef(true)\n\tconst showTimeoutRef = useRef<number | null>(null)\n\n\t// Set editor in tooltip manager\n\tuseEffect(() => {\n\t\ttooltipManager.setEditor(editor)\n\t}, [editor])\n\n\t// Subscribe to tooltip manager updates\n\tuseEffect(() => {\n\t\tconst unsubscribe = tooltipManager.subscribe(() => {\n\t\t\tforceUpdate({})\n\t\t})\n\t\treturn unsubscribe\n\t}, [])\n\n\tconst tooltipData = tooltipManager.getCurrentTooltipData()\n\n\t// Update open state and trigger position\n\tuseEffect(() => {\n\t\tconst shouldBeOpen = Boolean(tooltipData.id && tooltipData.element)\n\n\t\t// Clear any existing show timeout\n\t\tif (showTimeoutRef.current) {\n\t\t\tclearTimeout(showTimeoutRef.current)\n\t\t\tshowTimeoutRef.current = null\n\t\t}\n\n\t\tif (shouldBeOpen && tooltipData.element && triggerRef.current) {\n\t\t\t// Position the invisible trigger element over the active element\n\t\t\tconst activeRect = tooltipData.element.getBoundingClientRect()\n\t\t\tconst trigger = triggerRef.current\n\n\t\t\tconst newPosition = {\n\t\t\t\tx: activeRect.left + activeRect.width / 2,\n\t\t\t\ty: activeRect.top + activeRect.height / 2,\n\t\t\t}\n\n\t\t\t// Determine if we should animate\n\t\t\tlet shouldAnimateCheck = false\n\t\t\tif (previousPositionRef.current) {\n\t\t\t\tconst isNearPrevious = Vec.DistMin(previousPositionRef.current, newPosition, 200)\n\t\t\t\t// Only animate if the distance is less than 200px (nearby tooltips)\n\t\t\t\tshouldAnimateCheck =\n\t\t\t\t\t!prefersReducedMotion &&\n\t\t\t\t\tisNearPrevious &&\n\t\t\t\t\tMath.abs(newPosition.y - previousPositionRef.current.y) < 50\n\t\t\t}\n\t\t\t// Don't animate on initial show (previousPositionRef.current is null)\n\n\t\t\tsetShouldAnimate(isFirstShowRef.current ? false : shouldAnimateCheck)\n\t\t\tpreviousPositionRef.current = newPosition\n\n\t\t\ttrigger.style.position = 'fixed'\n\t\t\ttrigger.style.left = `${activeRect.left}px`\n\t\t\ttrigger.style.top = `${activeRect.top}px`\n\t\t\ttrigger.style.width = `${activeRect.width}px`\n\t\t\ttrigger.style.height = `${activeRect.height}px`\n\t\t\ttrigger.style.pointerEvents = 'none'\n\t\t\ttrigger.style.zIndex = '9999'\n\n\t\t\t// Handle delay for first show\n\t\t\tif (isFirstShowRef.current && editor) {\n\t\t\t\tshowTimeoutRef.current = editor.timers.setTimeout(() => {\n\t\t\t\t\tsetIsOpen(true)\n\t\t\t\t\tisFirstShowRef.current = false\n\t\t\t\t}, editor.options.tooltipDelayMs)\n\t\t\t} else {\n\t\t\t\t// Subsequent tooltips show immediately\n\t\t\t\tsetIsOpen(true)\n\t\t\t}\n\t\t} else if (!shouldBeOpen) {\n\t\t\t// Hide tooltip immediately\n\t\t\tsetIsOpen(false)\n\t\t\t// Reset position tracking when tooltip closes\n\t\t\tpreviousPositionRef.current = null\n\t\t\tsetShouldAnimate(false)\n\t\t\t// Reset first show state after tooltip is hidden\n\t\t\tisFirstShowRef.current = true\n\t\t}\n\t}, [tooltipData.id, tooltipData.element, editor, prefersReducedMotion])\n\n\tif (!tooltipData.id) {\n\t\treturn null\n\t}\n\n\treturn (\n\t\t<_Tooltip.Root open={isOpen} delayDuration={0}>\n\t\t\t<_Tooltip.Trigger asChild>\n\t\t\t\t<div ref={triggerRef} />\n\t\t\t</_Tooltip.Trigger>\n\t\t\t<_Tooltip.Content\n\t\t\t\tclassName=\"tlui-tooltip\"\n\t\t\t\tdata-should-animate={shouldAnimate}\n\t\t\t\tside={tooltipData.side}\n\t\t\t\tsideOffset={tooltipData.sideOffset}\n\t\t\t\tavoidCollisions\n\t\t\t\tcollisionPadding={8}\n\t\t\t\tdir=\"ltr\"\n\t\t\t>\n\t\t\t\t{tooltipData.content}\n\t\t\t\t<_Tooltip.Arrow className=\"tlui-tooltip__arrow\" />\n\t\t\t</_Tooltip.Content>\n\t\t</_Tooltip.Root>\n\t)\n}\n\n/** @public @react */\nexport const TldrawUiTooltip = forwardRef<HTMLButtonElement, TldrawUiTooltipProps>(\n\t({ children, content, side, sideOffset = 5, disabled = false }, ref) => {\n\t\tconst editor = useMaybeEditor()\n\t\tconst tooltipId = useRef<string>(uniqueId())\n\t\tconst hasProvider = useContext(TooltipSingletonContext)\n\n\t\tconst orientationCtx = useTldrawUiOrientation()\n\t\tconst sideToUse = side ?? orientationCtx.tooltipSide\n\n\t\tuseEffect(() => {\n\t\t\tconst currentTooltipId = tooltipId.current\n\t\t\treturn () => {\n\t\t\t\tif (hasProvider) {\n\t\t\t\t\ttooltipManager.hideTooltip(currentTooltipId, true)\n\t\t\t\t}\n\t\t\t}\n\t\t}, [hasProvider])\n\n\t\t// Don't show tooltip if disabled, no content, or UI labels are disabled\n\t\tif (disabled || !content) {\n\t\t\treturn <>{children}</>\n\t\t}\n\n\t\t// Fallback to old behavior if no provider\n\t\tif (!hasProvider) {\n\t\t\treturn (\n\t\t\t\t<_Tooltip.Root\n\t\t\t\t\tdelayDuration={editor?.options.tooltipDelayMs || DEFAULT_TOOLTIP_DELAY_MS}\n\t\t\t\t\tdisableHoverableContent\n\t\t\t\t>\n\t\t\t\t\t<_Tooltip.Trigger asChild ref={ref}>\n\t\t\t\t\t\t{children}\n\t\t\t\t\t</_Tooltip.Trigger>\n\t\t\t\t\t<_Tooltip.Content\n\t\t\t\t\t\tclassName=\"tlui-tooltip\"\n\t\t\t\t\t\tside={sideToUse}\n\t\t\t\t\t\tsideOffset={sideOffset}\n\t\t\t\t\t\tavoidCollisions\n\t\t\t\t\t\tcollisionPadding={8}\n\t\t\t\t\t\tdir=\"ltr\"\n\t\t\t\t\t>\n\t\t\t\t\t\t{content}\n\t\t\t\t\t\t<_Tooltip.Arrow className=\"tlui-tooltip__arrow\" />\n\t\t\t\t\t</_Tooltip.Content>\n\t\t\t\t</_Tooltip.Root>\n\t\t\t)\n\t\t}\n\n\t\tconst child = React.Children.only(children)\n\t\tassert(React.isValidElement(child), 'TldrawUiTooltip children must be a single element')\n\n\t\tconst handleMouseEnter = (event: React.MouseEvent<HTMLElement>) => {\n\t\t\tchild.props.onMouseEnter?.(event)\n\t\t\ttooltipManager.showTooltip(\n\t\t\t\ttooltipId.current,\n\t\t\t\tcontent,\n\t\t\t\tevent.currentTarget as HTMLElement,\n\t\t\t\tsideToUse,\n\t\t\t\tsideOffset\n\t\t\t)\n\t\t}\n\n\t\tconst handleMouseLeave = (event: React.MouseEvent<HTMLElement>) => {\n\t\t\tchild.props.onMouseLeave?.(event)\n\t\t\ttooltipManager.hideTooltip(tooltipId.current)\n\t\t}\n\n\t\tconst handleFocus = (event: React.FocusEvent<HTMLElement>) => {\n\t\t\tchild.props.onFocus?.(event)\n\t\t\ttooltipManager.showTooltip(\n\t\t\t\ttooltipId.current,\n\t\t\t\tcontent,\n\t\t\t\tevent.currentTarget as HTMLElement,\n\t\t\t\tsideToUse,\n\t\t\t\tsideOffset\n\t\t\t)\n\t\t}\n\n\t\tconst handleBlur = (event: React.FocusEvent<HTMLElement>) => {\n\t\t\tchild.props.onBlur?.(event)\n\t\t\ttooltipManager.hideTooltip(tooltipId.current)\n\t\t}\n\n\t\tconst childrenWithHandlers = React.cloneElement(children as React.ReactElement, {\n\t\t\tonMouseEnter: handleMouseEnter,\n\t\t\tonMouseLeave: handleMouseLeave,\n\t\t\tonFocus: handleFocus,\n\t\t\tonBlur: handleBlur,\n\t\t})\n\n\t\treturn childrenWithHandlers\n\t}\n)\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { assert, Atom, atom, Editor, uniqueId, useMaybeEditor, useValue } from '@tldraw/editor'\nimport { Tooltip as _Tooltip } from 'radix-ui'\nimport React, {\n\tcreateContext,\n\tforwardRef,\n\tReactNode,\n\tuseContext,\n\tuseEffect,\n\tuseRef,\n\tuseState,\n} from 'react'\nimport { useTldrawUiOrientation } from './layout'\n\nconst DEFAULT_TOOLTIP_DELAY_MS = 700\n\n/** @public */\nexport interface TldrawUiTooltipProps {\n\tchildren: React.ReactNode\n\tcontent?: string | React.ReactNode\n\tside?: 'top' | 'right' | 'bottom' | 'left'\n\tsideOffset?: number\n\tdisabled?: boolean\n\tshowOnMobile?: boolean\n\tdelayDuration?: number\n}\n\n// Singleton tooltip manager\nclass TooltipManager {\n\tprivate static instance: TooltipManager | null = null\n\tprivate currentTooltip = atom<{\n\t\tid: string\n\t\tcontent: ReactNode\n\t\tside: 'top' | 'right' | 'bottom' | 'left'\n\t\tsideOffset: number\n\t\tshowOnMobile: boolean\n\t\ttargetElement: HTMLElement\n\t\tdelayDuration: number | undefined\n\t} | null>('current tooltip', null)\n\tprivate destroyTimeoutId: number | null = null\n\n\tstatic getInstance(): TooltipManager {\n\t\tif (!TooltipManager.instance) {\n\t\t\tTooltipManager.instance = new TooltipManager()\n\t\t}\n\t\treturn TooltipManager.instance\n\t}\n\n\tshowTooltip(\n\t\ttooltipId: string,\n\t\tcontent: string | React.ReactNode,\n\t\ttargetElement: HTMLElement,\n\t\tside: 'top' | 'right' | 'bottom' | 'left',\n\t\tsideOffset: number,\n\t\tshowOnMobile: boolean,\n\t\tdelayDuration: number | undefined\n\t) {\n\t\t// Clear any existing destroy timeout\n\t\tif (this.destroyTimeoutId) {\n\t\t\tclearTimeout(this.destroyTimeoutId)\n\t\t\tthis.destroyTimeoutId = null\n\t\t}\n\n\t\t// Update current tooltip\n\t\tthis.currentTooltip.set({\n\t\t\tid: tooltipId,\n\t\t\tcontent,\n\t\t\tside,\n\t\t\tsideOffset,\n\t\t\tshowOnMobile,\n\t\t\ttargetElement,\n\t\t\tdelayDuration,\n\t\t})\n\t}\n\n\thideTooltip(editor: Editor | null, tooltipId: string, instant: boolean = false) {\n\t\tconst hide = () => {\n\t\t\t// Only hide if this is the current tooltip\n\t\t\tif (this.currentTooltip.get()?.id === tooltipId) {\n\t\t\t\tthis.currentTooltip.set(null)\n\t\t\t\tthis.destroyTimeoutId = null\n\t\t\t}\n\t\t}\n\n\t\tif (editor && !instant) {\n\t\t\t// Start destroy timeout (1 second)\n\t\t\tthis.destroyTimeoutId = editor.timers.setTimeout(hide, 300)\n\t\t} else {\n\t\t\thide()\n\t\t}\n\t}\n\n\thideAllTooltips() {\n\t\tthis.currentTooltip.set(null)\n\t\tthis.destroyTimeoutId = null\n\t}\n\n\tgetCurrentTooltipData() {\n\t\tconst currentTooltip = this.currentTooltip.get()\n\t\tif (!currentTooltip) return null\n\t\tif (!this.supportsHover() && !currentTooltip.showOnMobile) return null\n\t\treturn currentTooltip\n\t}\n\n\tprivate supportsHoverAtom: Atom<boolean> | null = null\n\tsupportsHover() {\n\t\tif (!this.supportsHoverAtom) {\n\t\t\tconst mediaQuery = window.matchMedia('(hover: hover)')\n\t\t\tconst supportsHover = atom('has hover', mediaQuery.matches)\n\t\t\tthis.supportsHoverAtom = supportsHover\n\t\t\tmediaQuery.addEventListener('change', (e) => {\n\t\t\t\tsupportsHover.set(e.matches)\n\t\t\t})\n\t\t}\n\t\treturn this.supportsHoverAtom.get()\n\t}\n}\n\nexport const tooltipManager = TooltipManager.getInstance()\n\n// Context for the tooltip singleton\nconst TooltipSingletonContext = createContext<boolean>(false)\n\n/** @public */\nexport interface TldrawUiTooltipProviderProps {\n\tchildren: React.ReactNode\n}\n\n/** @public @react */\nexport function TldrawUiTooltipProvider({ children }: TldrawUiTooltipProviderProps) {\n\treturn (\n\t\t<_Tooltip.Provider skipDelayDuration={700}>\n\t\t\t<TooltipSingletonContext.Provider value={true}>\n\t\t\t\t{children}\n\t\t\t\t<TooltipSingleton />\n\t\t\t</TooltipSingletonContext.Provider>\n\t\t</_Tooltip.Provider>\n\t)\n}\n\n// The singleton tooltip component that renders once\nfunction TooltipSingleton() {\n\tconst editor = useMaybeEditor()\n\tconst [isOpen, setIsOpen] = useState(false)\n\tconst triggerRef = useRef<HTMLDivElement>(null)\n\tconst isFirstShowRef = useRef(true)\n\tconst showTimeoutRef = useRef<number | null>(null)\n\n\tconst currentTooltip = useValue(\n\t\t'current tooltip',\n\t\t() => tooltipManager.getCurrentTooltipData(),\n\t\t[]\n\t)\n\n\t// Update open state and trigger position\n\tuseEffect(() => {\n\t\t// Clear any existing show timeout\n\t\tif (showTimeoutRef.current) {\n\t\t\tclearTimeout(showTimeoutRef.current)\n\t\t\tshowTimeoutRef.current = null\n\t\t}\n\n\t\tif (currentTooltip && triggerRef.current) {\n\t\t\t// Position the invisible trigger element over the active element\n\t\t\tconst activeRect = currentTooltip.targetElement.getBoundingClientRect()\n\t\t\tconst trigger = triggerRef.current\n\n\t\t\ttrigger.style.position = 'fixed'\n\t\t\ttrigger.style.left = `${activeRect.left}px`\n\t\t\ttrigger.style.top = `${activeRect.top}px`\n\t\t\ttrigger.style.width = `${activeRect.width}px`\n\t\t\ttrigger.style.height = `${activeRect.height}px`\n\t\t\ttrigger.style.pointerEvents = 'none'\n\t\t\ttrigger.style.zIndex = '9999'\n\n\t\t\t// Handle delay for first show\n\t\t\tif (isFirstShowRef.current && editor) {\n\t\t\t\tshowTimeoutRef.current = editor.timers.setTimeout(() => {\n\t\t\t\t\tsetIsOpen(true)\n\t\t\t\t\tisFirstShowRef.current = false\n\t\t\t\t}, currentTooltip.delayDuration ?? editor.options.tooltipDelayMs)\n\t\t\t} else {\n\t\t\t\t// Subsequent tooltips show immediately\n\t\t\t\tsetIsOpen(true)\n\t\t\t}\n\t\t} else {\n\t\t\t// Hide tooltip immediately\n\t\t\tsetIsOpen(false)\n\t\t\t// Reset first show state after tooltip is hidden\n\t\t\tisFirstShowRef.current = true\n\t\t}\n\t}, [editor, currentTooltip])\n\n\tif (!currentTooltip) {\n\t\treturn null\n\t}\n\n\treturn (\n\t\t<_Tooltip.Root open={isOpen} delayDuration={0}>\n\t\t\t<_Tooltip.Trigger asChild>\n\t\t\t\t<div ref={triggerRef} />\n\t\t\t</_Tooltip.Trigger>\n\t\t\t<_Tooltip.Content\n\t\t\t\tclassName=\"tlui-tooltip\"\n\t\t\t\tside={currentTooltip.side}\n\t\t\t\tsideOffset={currentTooltip.sideOffset}\n\t\t\t\tavoidCollisions\n\t\t\t\tcollisionPadding={8}\n\t\t\t\tdir=\"ltr\"\n\t\t\t>\n\t\t\t\t{currentTooltip.content}\n\t\t\t\t<_Tooltip.Arrow className=\"tlui-tooltip__arrow\" />\n\t\t\t</_Tooltip.Content>\n\t\t</_Tooltip.Root>\n\t)\n}\n\n/** @public @react */\nexport const TldrawUiTooltip = forwardRef<HTMLButtonElement, TldrawUiTooltipProps>(\n\t(\n\t\t{\n\t\t\tchildren,\n\t\t\tcontent,\n\t\t\tside,\n\t\t\tsideOffset = 5,\n\t\t\tdisabled = false,\n\t\t\tshowOnMobile = false,\n\t\t\tdelayDuration,\n\t\t},\n\t\tref\n\t) => {\n\t\tconst editor = useMaybeEditor()\n\t\tconst tooltipId = useRef<string>(uniqueId())\n\t\tconst hasProvider = useContext(TooltipSingletonContext)\n\n\t\tconst orientationCtx = useTldrawUiOrientation()\n\t\tconst sideToUse = side ?? orientationCtx.tooltipSide\n\n\t\tuseEffect(() => {\n\t\t\tconst currentTooltipId = tooltipId.current\n\t\t\treturn () => {\n\t\t\t\tif (hasProvider) {\n\t\t\t\t\ttooltipManager.hideTooltip(editor, currentTooltipId, true)\n\t\t\t\t}\n\t\t\t}\n\t\t}, [editor, hasProvider])\n\n\t\t// Don't show tooltip if disabled, no content, or UI labels are disabled\n\t\tif (disabled || !content) {\n\t\t\treturn <>{children}</>\n\t\t}\n\n\t\t// Fallback to old behavior if no provider\n\t\tif (!hasProvider) {\n\t\t\treturn (\n\t\t\t\t<_Tooltip.Root\n\t\t\t\t\tdelayDuration={\n\t\t\t\t\t\tdelayDuration ?? (editor?.options.tooltipDelayMs || DEFAULT_TOOLTIP_DELAY_MS)\n\t\t\t\t\t}\n\t\t\t\t\tdisableHoverableContent\n\t\t\t\t>\n\t\t\t\t\t<_Tooltip.Trigger asChild ref={ref}>\n\t\t\t\t\t\t{children}\n\t\t\t\t\t</_Tooltip.Trigger>\n\t\t\t\t\t<_Tooltip.Content\n\t\t\t\t\t\tclassName=\"tlui-tooltip\"\n\t\t\t\t\t\tside={sideToUse}\n\t\t\t\t\t\tsideOffset={sideOffset}\n\t\t\t\t\t\tavoidCollisions\n\t\t\t\t\t\tcollisionPadding={8}\n\t\t\t\t\t\tdir=\"ltr\"\n\t\t\t\t\t>\n\t\t\t\t\t\t{content}\n\t\t\t\t\t\t<_Tooltip.Arrow className=\"tlui-tooltip__arrow\" />\n\t\t\t\t\t</_Tooltip.Content>\n\t\t\t\t</_Tooltip.Root>\n\t\t\t)\n\t\t}\n\n\t\tconst child = React.Children.only(children)\n\t\tassert(React.isValidElement(child), 'TldrawUiTooltip children must be a single element')\n\n\t\tconst handleMouseEnter = (event: React.MouseEvent<HTMLElement>) => {\n\t\t\tchild.props.onMouseEnter?.(event)\n\t\t\ttooltipManager.showTooltip(\n\t\t\t\ttooltipId.current,\n\t\t\t\tcontent,\n\t\t\t\tevent.currentTarget as HTMLElement,\n\t\t\t\tsideToUse,\n\t\t\t\tsideOffset,\n\t\t\t\tshowOnMobile,\n\t\t\t\tdelayDuration\n\t\t\t)\n\t\t}\n\n\t\tconst handleMouseLeave = (event: React.MouseEvent<HTMLElement>) => {\n\t\t\tchild.props.onMouseLeave?.(event)\n\t\t\ttooltipManager.hideTooltip(editor, tooltipId.current)\n\t\t}\n\n\t\tconst handleFocus = (event: React.FocusEvent<HTMLElement>) => {\n\t\t\tchild.props.onFocus?.(event)\n\t\t\ttooltipManager.showTooltip(\n\t\t\t\ttooltipId.current,\n\t\t\t\tcontent,\n\t\t\t\tevent.currentTarget as HTMLElement,\n\t\t\t\tsideToUse,\n\t\t\t\tsideOffset,\n\t\t\t\tshowOnMobile,\n\t\t\t\tdelayDuration\n\t\t\t)\n\t\t}\n\n\t\tconst handleBlur = (event: React.FocusEvent<HTMLElement>) => {\n\t\t\tchild.props.onBlur?.(event)\n\t\t\ttooltipManager.hideTooltip(editor, tooltipId.current)\n\t\t}\n\n\t\tconst childrenWithHandlers = React.cloneElement(children as React.ReactElement, {\n\t\t\tonMouseEnter: handleMouseEnter,\n\t\t\tonMouseLeave: handleMouseLeave,\n\t\t\tonFocus: handleFocus,\n\t\t\tonBlur: handleBlur,\n\t\t})\n\n\t\treturn childrenWithHandlers\n\t}\n)\n"],
5
+ "mappings": "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",
6
6
  "names": ["_Tooltip", "React"]
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/lib/ui/components/primitives/menus/TldrawUiMenuContext.tsx"],
4
- "sourcesContent": ["import { createContext, useContext } from 'react'\nimport { TLUiEventSource } from '../../../context/events'\n\n/** @public */\nexport type TLUiMenuContextType =\n\t| 'panel'\n\t| 'menu'\n\t| 'small-icons'\n\t| 'context-menu'\n\t| 'icons'\n\t| 'keyboard-shortcuts'\n\t| 'helper-buttons'\n\t| 'toolbar'\n\t| 'toolbar-overflow'\n\nconst menuContext = createContext<{\n\ttype: TLUiMenuContextType\n\tsourceId: TLUiEventSource\n} | null>(null)\n\n/** @public */\nexport function useTldrawUiMenuContext() {\n\tconst context = useContext(menuContext)\n\tif (!context) {\n\t\tthrow new Error('useTldrawUiMenuContext must be used within a TldrawUiMenuContextProvider')\n\t}\n\treturn context\n}\n\n/** @public */\nexport interface TLUiMenuContextProviderProps {\n\ttype: TLUiMenuContextType\n\tsourceId: TLUiEventSource\n\tchildren: React.ReactNode\n}\n\n/** @public @react */\nexport function TldrawUiMenuContextProvider({\n\ttype,\n\tsourceId,\n\tchildren,\n}: TLUiMenuContextProviderProps) {\n\treturn <menuContext.Provider value={{ type, sourceId }}>{children}</menuContext.Provider>\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA0CQ;AA1CR,mBAA0C;AAe1C,MAAM,kBAAc,4BAGV,IAAI;AAGP,SAAS,yBAAyB;AACxC,QAAM,cAAU,yBAAW,WAAW;AACtC,MAAI,CAAC,SAAS;AACb,UAAM,IAAI,MAAM,0EAA0E;AAAA,EAC3F;AACA,SAAO;AACR;AAUO,SAAS,4BAA4B;AAAA,EAC3C;AAAA,EACA;AAAA,EACA;AACD,GAAiC;AAChC,SAAO,4CAAC,YAAY,UAAZ,EAAqB,OAAO,EAAE,MAAM,SAAS,GAAI,UAAS;AACnE;",
4
+ "sourcesContent": ["import { createContext, useContext } from 'react'\nimport { TLUiEventSource } from '../../../context/events'\n\n/** @public */\nexport type TLUiMenuContextType =\n\t| 'menu'\n\t| 'small-icons'\n\t| 'context-menu'\n\t| 'icons'\n\t| 'keyboard-shortcuts'\n\t| 'helper-buttons'\n\t| 'toolbar'\n\t| 'toolbar-overflow'\n\nconst menuContext = createContext<{\n\ttype: TLUiMenuContextType\n\tsourceId: TLUiEventSource\n} | null>(null)\n\n/** @public */\nexport function useTldrawUiMenuContext() {\n\tconst context = useContext(menuContext)\n\tif (!context) {\n\t\tthrow new Error('useTldrawUiMenuContext must be used within a TldrawUiMenuContextProvider')\n\t}\n\treturn context\n}\n\n/** @public */\nexport interface TLUiMenuContextProviderProps {\n\ttype: TLUiMenuContextType\n\tsourceId: TLUiEventSource\n\tchildren: React.ReactNode\n}\n\n/** @public @react */\nexport function TldrawUiMenuContextProvider({\n\ttype,\n\tsourceId,\n\tchildren,\n}: TLUiMenuContextProviderProps) {\n\treturn <menuContext.Provider value={{ type, sourceId }}>{children}</menuContext.Provider>\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAyCQ;AAzCR,mBAA0C;AAc1C,MAAM,kBAAc,4BAGV,IAAI;AAGP,SAAS,yBAAyB;AACxC,QAAM,cAAU,yBAAW,WAAW;AACtC,MAAI,CAAC,SAAS;AACb,UAAM,IAAI,MAAM,0EAA0E;AAAA,EAC3F;AACA,SAAO;AACR;AAUO,SAAS,4BAA4B;AAAA,EAC3C;AAAA,EACA;AAAA,EACA;AACD,GAAiC;AAChC,SAAO,4CAAC,YAAY,UAAZ,EAAqB,OAAO,EAAE,MAAM,SAAS,GAAI,UAAS;AACnE;",
6
6
  "names": []
7
7
  }
@@ -45,16 +45,6 @@ function TldrawUiMenuGroup({ id, label, className, children }) {
45
45
  const labelToUse = (0, import_actions.unwrapLabel)(label, menu.type);
46
46
  const labelStr = labelToUse ? msg(labelToUse) : void 0;
47
47
  switch (menu.type) {
48
- case "panel": {
49
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
50
- "div",
51
- {
52
- className: (0, import_classnames.default)("tlui-menu__group", className),
53
- "data-testid": `${menu.sourceId}-group.${id}`,
54
- children
55
- }
56
- );
57
- }
58
48
  case "menu": {
59
49
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
60
50
  import_TldrawUiDropdownMenu.TldrawUiDropdownMenuGroup,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/lib/ui/components/primitives/menus/TldrawUiMenuGroup.tsx"],
4
- "sourcesContent": ["import classNames from 'classnames'\nimport { ReactNode } from 'react'\nimport { unwrapLabel } from '../../../context/actions'\nimport { TLUiTranslationKey } from '../../../hooks/useTranslation/TLUiTranslationKey'\nimport { useTranslation } from '../../../hooks/useTranslation/useTranslation'\nimport { TldrawUiColumn, TldrawUiGrid, TldrawUiRow, useTldrawUiOrientation } from '../layout'\nimport { TldrawUiDropdownMenuGroup } from '../TldrawUiDropdownMenu'\nimport { useTldrawUiMenuContext } from './TldrawUiMenuContext'\n\n/** @public */\nexport interface TLUiMenuGroupProps<TranslationKey extends string = string> {\n\tid: string\n\t/**\n\t * The label to display on the item. If it's a string, it will be translated. If it's an object, the keys will be used as the language keys and the values will be translated.\n\t */\n\tlabel?: TranslationKey | { [key: string]: TranslationKey }\n\tclassName?: string\n\tchildren?: ReactNode\n}\n\n/** @public @react */\nexport function TldrawUiMenuGroup({ id, label, className, children }: TLUiMenuGroupProps) {\n\tconst menu = useTldrawUiMenuContext()\n\tconst { orientation } = useTldrawUiOrientation()\n\tconst msg = useTranslation()\n\tconst labelToUse = unwrapLabel(label, menu.type)\n\tconst labelStr = labelToUse ? msg(labelToUse as TLUiTranslationKey) : undefined\n\n\tswitch (menu.type) {\n\t\tcase 'panel': {\n\t\t\treturn (\n\t\t\t\t<div\n\t\t\t\t\tclassName={classNames('tlui-menu__group', className)}\n\t\t\t\t\tdata-testid={`${menu.sourceId}-group.${id}`}\n\t\t\t\t>\n\t\t\t\t\t{children}\n\t\t\t\t</div>\n\t\t\t)\n\t\t}\n\t\tcase 'menu': {\n\t\t\treturn (\n\t\t\t\t<TldrawUiDropdownMenuGroup\n\t\t\t\t\tclassName={className}\n\t\t\t\t\tdata-testid={`${menu.sourceId}-group.${id}`}\n\t\t\t\t>\n\t\t\t\t\t{children}\n\t\t\t\t</TldrawUiDropdownMenuGroup>\n\t\t\t)\n\t\t}\n\t\tcase 'context-menu': {\n\t\t\treturn (\n\t\t\t\t<div\n\t\t\t\t\tdir=\"ltr\"\n\t\t\t\t\tclassName={classNames('tlui-menu__group', className)}\n\t\t\t\t\tdata-testid={`${menu.sourceId}-group.${id}`}\n\t\t\t\t>\n\t\t\t\t\t{children}\n\t\t\t\t</div>\n\t\t\t)\n\t\t}\n\t\tcase 'keyboard-shortcuts': {\n\t\t\t// todo: if groups need a label, let's give em a label\n\t\t\treturn (\n\t\t\t\t<div className=\"tlui-shortcuts-dialog__group\" data-testid={`${menu.sourceId}-group.${id}`}>\n\t\t\t\t\t<h2 className=\"tlui-shortcuts-dialog__group__title\">{labelStr}</h2>\n\t\t\t\t\t<div className=\"tlui-shortcuts-dialog__group__content\">{children}</div>\n\t\t\t\t</div>\n\t\t\t)\n\t\t}\n\t\tcase 'toolbar': {\n\t\t\tconst Layout = orientation === 'horizontal' ? TldrawUiRow : TldrawUiColumn\n\t\t\treturn (\n\t\t\t\t<Layout className=\"tlui-main-toolbar__group\" data-testid={`${menu.sourceId}-group.${id}`}>\n\t\t\t\t\t{children}\n\t\t\t\t</Layout>\n\t\t\t)\n\t\t}\n\t\tcase 'toolbar-overflow': {\n\t\t\treturn (\n\t\t\t\t<TldrawUiGrid\n\t\t\t\t\tclassName=\"tlui-main-toolbar__group\"\n\t\t\t\t\tdata-testid={`${menu.sourceId}-group.${id}`}\n\t\t\t\t>\n\t\t\t\t\t{children}\n\t\t\t\t</TldrawUiGrid>\n\t\t\t)\n\t\t}\n\t\tdefault: {\n\t\t\treturn children\n\t\t}\n\t}\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA+BI;AA/BJ,wBAAuB;AAEvB,qBAA4B;AAE5B,4BAA+B;AAC/B,oBAAkF;AAClF,kCAA0C;AAC1C,iCAAuC;AAchC,SAAS,kBAAkB,EAAE,IAAI,OAAO,WAAW,SAAS,GAAuB;AACzF,QAAM,WAAO,mDAAuB;AACpC,QAAM,EAAE,YAAY,QAAI,sCAAuB;AAC/C,QAAM,UAAM,sCAAe;AAC3B,QAAM,iBAAa,4BAAY,OAAO,KAAK,IAAI;AAC/C,QAAM,WAAW,aAAa,IAAI,UAAgC,IAAI;AAEtE,UAAQ,KAAK,MAAM;AAAA,IAClB,KAAK,SAAS;AACb,aACC;AAAA,QAAC;AAAA;AAAA,UACA,eAAW,kBAAAA,SAAW,oBAAoB,SAAS;AAAA,UACnD,eAAa,GAAG,KAAK,QAAQ,UAAU,EAAE;AAAA,UAExC;AAAA;AAAA,MACF;AAAA,IAEF;AAAA,IACA,KAAK,QAAQ;AACZ,aACC;AAAA,QAAC;AAAA;AAAA,UACA;AAAA,UACA,eAAa,GAAG,KAAK,QAAQ,UAAU,EAAE;AAAA,UAExC;AAAA;AAAA,MACF;AAAA,IAEF;AAAA,IACA,KAAK,gBAAgB;AACpB,aACC;AAAA,QAAC;AAAA;AAAA,UACA,KAAI;AAAA,UACJ,eAAW,kBAAAA,SAAW,oBAAoB,SAAS;AAAA,UACnD,eAAa,GAAG,KAAK,QAAQ,UAAU,EAAE;AAAA,UAExC;AAAA;AAAA,MACF;AAAA,IAEF;AAAA,IACA,KAAK,sBAAsB;AAE1B,aACC,6CAAC,SAAI,WAAU,gCAA+B,eAAa,GAAG,KAAK,QAAQ,UAAU,EAAE,IACtF;AAAA,oDAAC,QAAG,WAAU,uCAAuC,oBAAS;AAAA,QAC9D,4CAAC,SAAI,WAAU,yCAAyC,UAAS;AAAA,SAClE;AAAA,IAEF;AAAA,IACA,KAAK,WAAW;AACf,YAAM,SAAS,gBAAgB,eAAe,4BAAc;AAC5D,aACC,4CAAC,UAAO,WAAU,4BAA2B,eAAa,GAAG,KAAK,QAAQ,UAAU,EAAE,IACpF,UACF;AAAA,IAEF;AAAA,IACA,KAAK,oBAAoB;AACxB,aACC;AAAA,QAAC;AAAA;AAAA,UACA,WAAU;AAAA,UACV,eAAa,GAAG,KAAK,QAAQ,UAAU,EAAE;AAAA,UAExC;AAAA;AAAA,MACF;AAAA,IAEF;AAAA,IACA,SAAS;AACR,aAAO;AAAA,IACR;AAAA,EACD;AACD;",
4
+ "sourcesContent": ["import classNames from 'classnames'\nimport { ReactNode } from 'react'\nimport { unwrapLabel } from '../../../context/actions'\nimport { TLUiTranslationKey } from '../../../hooks/useTranslation/TLUiTranslationKey'\nimport { useTranslation } from '../../../hooks/useTranslation/useTranslation'\nimport { TldrawUiColumn, TldrawUiGrid, TldrawUiRow, useTldrawUiOrientation } from '../layout'\nimport { TldrawUiDropdownMenuGroup } from '../TldrawUiDropdownMenu'\nimport { useTldrawUiMenuContext } from './TldrawUiMenuContext'\n\n/** @public */\nexport interface TLUiMenuGroupProps<TranslationKey extends string = string> {\n\tid: string\n\t/**\n\t * The label to display on the item. If it's a string, it will be translated. If it's an object, the keys will be used as the language keys and the values will be translated.\n\t */\n\tlabel?: TranslationKey | { [key: string]: TranslationKey }\n\tclassName?: string\n\tchildren?: ReactNode\n}\n\n/** @public @react */\nexport function TldrawUiMenuGroup({ id, label, className, children }: TLUiMenuGroupProps) {\n\tconst menu = useTldrawUiMenuContext()\n\tconst { orientation } = useTldrawUiOrientation()\n\tconst msg = useTranslation()\n\tconst labelToUse = unwrapLabel(label, menu.type)\n\tconst labelStr = labelToUse ? msg(labelToUse as TLUiTranslationKey) : undefined\n\n\tswitch (menu.type) {\n\t\tcase 'menu': {\n\t\t\treturn (\n\t\t\t\t<TldrawUiDropdownMenuGroup\n\t\t\t\t\tclassName={className}\n\t\t\t\t\tdata-testid={`${menu.sourceId}-group.${id}`}\n\t\t\t\t>\n\t\t\t\t\t{children}\n\t\t\t\t</TldrawUiDropdownMenuGroup>\n\t\t\t)\n\t\t}\n\t\tcase 'context-menu': {\n\t\t\treturn (\n\t\t\t\t<div\n\t\t\t\t\tdir=\"ltr\"\n\t\t\t\t\tclassName={classNames('tlui-menu__group', className)}\n\t\t\t\t\tdata-testid={`${menu.sourceId}-group.${id}`}\n\t\t\t\t>\n\t\t\t\t\t{children}\n\t\t\t\t</div>\n\t\t\t)\n\t\t}\n\t\tcase 'keyboard-shortcuts': {\n\t\t\t// todo: if groups need a label, let's give em a label\n\t\t\treturn (\n\t\t\t\t<div className=\"tlui-shortcuts-dialog__group\" data-testid={`${menu.sourceId}-group.${id}`}>\n\t\t\t\t\t<h2 className=\"tlui-shortcuts-dialog__group__title\">{labelStr}</h2>\n\t\t\t\t\t<div className=\"tlui-shortcuts-dialog__group__content\">{children}</div>\n\t\t\t\t</div>\n\t\t\t)\n\t\t}\n\t\tcase 'toolbar': {\n\t\t\tconst Layout = orientation === 'horizontal' ? TldrawUiRow : TldrawUiColumn\n\t\t\treturn (\n\t\t\t\t<Layout className=\"tlui-main-toolbar__group\" data-testid={`${menu.sourceId}-group.${id}`}>\n\t\t\t\t\t{children}\n\t\t\t\t</Layout>\n\t\t\t)\n\t\t}\n\t\tcase 'toolbar-overflow': {\n\t\t\treturn (\n\t\t\t\t<TldrawUiGrid\n\t\t\t\t\tclassName=\"tlui-main-toolbar__group\"\n\t\t\t\t\tdata-testid={`${menu.sourceId}-group.${id}`}\n\t\t\t\t>\n\t\t\t\t\t{children}\n\t\t\t\t</TldrawUiGrid>\n\t\t\t)\n\t\t}\n\t\tdefault: {\n\t\t\treturn children\n\t\t}\n\t}\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA+BI;AA/BJ,wBAAuB;AAEvB,qBAA4B;AAE5B,4BAA+B;AAC/B,oBAAkF;AAClF,kCAA0C;AAC1C,iCAAuC;AAchC,SAAS,kBAAkB,EAAE,IAAI,OAAO,WAAW,SAAS,GAAuB;AACzF,QAAM,WAAO,mDAAuB;AACpC,QAAM,EAAE,YAAY,QAAI,sCAAuB;AAC/C,QAAM,UAAM,sCAAe;AAC3B,QAAM,iBAAa,4BAAY,OAAO,KAAK,IAAI;AAC/C,QAAM,WAAW,aAAa,IAAI,UAAgC,IAAI;AAEtE,UAAQ,KAAK,MAAM;AAAA,IAClB,KAAK,QAAQ;AACZ,aACC;AAAA,QAAC;AAAA;AAAA,UACA;AAAA,UACA,eAAa,GAAG,KAAK,QAAQ,UAAU,EAAE;AAAA,UAExC;AAAA;AAAA,MACF;AAAA,IAEF;AAAA,IACA,KAAK,gBAAgB;AACpB,aACC;AAAA,QAAC;AAAA;AAAA,UACA,KAAI;AAAA,UACJ,eAAW,kBAAAA,SAAW,oBAAoB,SAAS;AAAA,UACnD,eAAa,GAAG,KAAK,QAAQ,UAAU,EAAE;AAAA,UAExC;AAAA;AAAA,MACF;AAAA,IAEF;AAAA,IACA,KAAK,sBAAsB;AAE1B,aACC,6CAAC,SAAI,WAAU,gCAA+B,eAAa,GAAG,KAAK,QAAQ,UAAU,EAAE,IACtF;AAAA,oDAAC,QAAG,WAAU,uCAAuC,oBAAS;AAAA,QAC9D,4CAAC,SAAI,WAAU,yCAAyC,UAAS;AAAA,SAClE;AAAA,IAEF;AAAA,IACA,KAAK,WAAW;AACf,YAAM,SAAS,gBAAgB,eAAe,4BAAc;AAC5D,aACC,4CAAC,UAAO,WAAU,4BAA2B,eAAa,GAAG,KAAK,QAAQ,UAAU,EAAE,IACpF,UACF;AAAA,IAEF;AAAA,IACA,KAAK,oBAAoB;AACxB,aACC;AAAA,QAAC;AAAA;AAAA,UACA,WAAU;AAAA,UACV,eAAa,GAAG,KAAK,QAAQ,UAAU,EAAE;AAAA,UAExC;AAAA;AAAA,MACF;AAAA,IAEF;AAAA,IACA,SAAS;AACR,aAAO;AAAA,IACR;AAAA,EACD;AACD;",
6
6
  "names": ["classNames"]
7
7
  }
@@ -69,7 +69,6 @@ function TldrawUiMenuItem({
69
69
  type: "menu",
70
70
  "data-testid": `${sourceId}.${id}`,
71
71
  disabled,
72
- title: titleStr,
73
72
  onClick: (e) => {
74
73
  if (noClose) {
75
74
  (0, import_editor.preventDefault)(e);
@@ -94,7 +93,6 @@ function TldrawUiMenuItem({
94
93
  import_radix_ui.ContextMenu.Item,
95
94
  {
96
95
  dir: "ltr",
97
- title: titleStr,
98
96
  draggable: false,
99
97
  className: "tlui-button tlui-button__menu",
100
98
  "data-testid": `${sourceId}.${id}`,
@@ -115,22 +113,6 @@ function TldrawUiMenuItem({
115
113
  }
116
114
  );
117
115
  }
118
- case "panel": {
119
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
120
- import_TldrawUiButton.TldrawUiButton,
121
- {
122
- "data-testid": `${sourceId}.${id}`,
123
- type: "menu",
124
- title: titleStr,
125
- disabled,
126
- onClick: () => onSelect(sourceId),
127
- children: [
128
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_TldrawUiButtonLabel.TldrawUiButtonLabel, { children: labelStr }),
129
- spinner ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_Spinner.Spinner, {}) : icon && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_TldrawUiButtonIcon.TldrawUiButtonIcon, { icon })
130
- ]
131
- }
132
- );
133
- }
134
116
  case "small-icons":
135
117
  case "icons": {
136
118
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
@@ -251,13 +233,14 @@ function useDraggableEvents(onDragStart, onSelect) {
251
233
  if (e.isSpecialRedispatchedEvent) return;
252
234
  if (state.name === "pointing") {
253
235
  const distanceSq = import_editor.Vec.Dist2(state.screenSpaceStart, { x: e.clientX, y: e.clientY });
254
- if (distanceSq > (editor.getInstanceState().isCoarsePointer ? editor.options.coarseDragDistanceSquared : editor.options.dragDistanceSquared)) {
236
+ if (distanceSq > (editor.getInstanceState().isCoarsePointer ? editor.options.uiCoarseDragDistanceSquared : editor.options.uiDragDistanceSquared)) {
255
237
  const screenSpaceStart = state.screenSpaceStart;
256
238
  state = {
257
239
  name: "dragging",
258
240
  screenSpaceStart
259
241
  };
260
242
  editor.run(() => {
243
+ editor.setCurrentTool("select");
261
244
  editor.dispatch({
262
245
  type: "pointer",
263
246
  target: "canvas",
@@ -274,6 +257,7 @@ function useDraggableEvents(onDragStart, onSelect) {
274
257
  point: screenSpaceStart
275
258
  });
276
259
  import_TldrawUiTooltip.tooltipManager.hideAllTooltips();
260
+ editor.getContainer().focus();
277
261
  });
278
262
  }
279
263
  }