tldraw 3.16.0-canary.ffdf566dd0a8 → 3.16.0-internal.51e99e128bd4

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 (310) hide show
  1. package/dist-cjs/index.d.ts +173 -5
  2. package/dist-cjs/index.js +12 -1
  3. package/dist-cjs/index.js.map +2 -2
  4. package/dist-cjs/lib/canvas/TldrawScribble.js +1 -1
  5. package/dist-cjs/lib/canvas/TldrawScribble.js.map +2 -2
  6. package/dist-cjs/lib/shapes/arrow/ArrowShapeUtil.js +3 -3
  7. package/dist-cjs/lib/shapes/arrow/ArrowShapeUtil.js.map +2 -2
  8. package/dist-cjs/lib/shapes/arrow/elbow/ElbowArrowDebug.js +3 -3
  9. package/dist-cjs/lib/shapes/arrow/elbow/ElbowArrowDebug.js.map +1 -1
  10. package/dist-cjs/lib/shapes/draw/DrawShapeUtil.js +3 -3
  11. package/dist-cjs/lib/shapes/draw/DrawShapeUtil.js.map +2 -2
  12. package/dist-cjs/lib/shapes/embed/EmbedShapeUtil.js +1 -1
  13. package/dist-cjs/lib/shapes/embed/EmbedShapeUtil.js.map +1 -1
  14. package/dist-cjs/lib/shapes/frame/FrameShapeUtil.js +12 -12
  15. package/dist-cjs/lib/shapes/frame/FrameShapeUtil.js.map +2 -2
  16. package/dist-cjs/lib/shapes/frame/components/FrameHeading.js +1 -1
  17. package/dist-cjs/lib/shapes/frame/components/FrameHeading.js.map +2 -2
  18. package/dist-cjs/lib/shapes/geo/GeoShapeUtil.js +2 -2
  19. package/dist-cjs/lib/shapes/geo/GeoShapeUtil.js.map +2 -2
  20. package/dist-cjs/lib/shapes/geo/components/GeoShapeBody.js +2 -1
  21. package/dist-cjs/lib/shapes/geo/components/GeoShapeBody.js.map +2 -2
  22. package/dist-cjs/lib/shapes/highlight/HighlightShapeUtil.js +5 -1
  23. package/dist-cjs/lib/shapes/highlight/HighlightShapeUtil.js.map +2 -2
  24. package/dist-cjs/lib/shapes/image/ImageShapeUtil.js +3 -3
  25. package/dist-cjs/lib/shapes/image/ImageShapeUtil.js.map +1 -1
  26. package/dist-cjs/lib/shapes/line/LineShapeUtil.js +5 -1
  27. package/dist-cjs/lib/shapes/line/LineShapeUtil.js.map +2 -2
  28. package/dist-cjs/lib/shapes/note/NoteShapeUtil.js +4 -4
  29. package/dist-cjs/lib/shapes/note/NoteShapeUtil.js.map +2 -2
  30. package/dist-cjs/lib/shapes/shared/ShapeFill.js +4 -4
  31. package/dist-cjs/lib/shapes/shared/ShapeFill.js.map +2 -2
  32. package/dist-cjs/lib/shapes/shared/freehand/svg.js.map +2 -2
  33. package/dist-cjs/lib/shapes/text/TextShapeUtil.js +2 -2
  34. package/dist-cjs/lib/shapes/text/TextShapeUtil.js.map +2 -2
  35. package/dist-cjs/lib/shapes/video/VideoShapeUtil.js +3 -3
  36. package/dist-cjs/lib/shapes/video/VideoShapeUtil.js.map +1 -1
  37. package/dist-cjs/lib/tools/EraserTool/childStates/Erasing.js +25 -1
  38. package/dist-cjs/lib/tools/EraserTool/childStates/Erasing.js.map +2 -2
  39. package/dist-cjs/lib/tools/EraserTool/childStates/Pointing.js +12 -0
  40. package/dist-cjs/lib/tools/EraserTool/childStates/Pointing.js.map +2 -2
  41. package/dist-cjs/lib/tools/SelectTool/childStates/Translating.js.map +2 -2
  42. package/dist-cjs/lib/ui/TldrawUi.js +14 -0
  43. package/dist-cjs/lib/ui/TldrawUi.js.map +3 -3
  44. package/dist-cjs/lib/ui/assetUrls.js +13 -10
  45. package/dist-cjs/lib/ui/assetUrls.js.map +2 -2
  46. package/dist-cjs/lib/ui/components/ActionsMenu/DefaultActionsMenu.js +12 -3
  47. package/dist-cjs/lib/ui/components/ActionsMenu/DefaultActionsMenu.js.map +2 -2
  48. package/dist-cjs/lib/ui/components/DefaultMenuPanel.js +3 -2
  49. package/dist-cjs/lib/ui/components/DefaultMenuPanel.js.map +2 -2
  50. package/dist-cjs/lib/ui/components/Minimap/MinimapManager.js +4 -4
  51. package/dist-cjs/lib/ui/components/Minimap/MinimapManager.js.map +2 -2
  52. package/dist-cjs/lib/ui/components/MobileStylePanel.js +5 -3
  53. package/dist-cjs/lib/ui/components/MobileStylePanel.js.map +2 -2
  54. package/dist-cjs/lib/ui/components/NavigationPanel/DefaultNavigationPanel.js +1 -1
  55. package/dist-cjs/lib/ui/components/NavigationPanel/DefaultNavigationPanel.js.map +2 -2
  56. package/dist-cjs/lib/ui/components/PageMenu/DefaultPageMenu.js +2 -1
  57. package/dist-cjs/lib/ui/components/PageMenu/DefaultPageMenu.js.map +2 -2
  58. package/dist-cjs/lib/ui/components/SharePanel/PeopleMenuItem.js +3 -2
  59. package/dist-cjs/lib/ui/components/SharePanel/PeopleMenuItem.js.map +2 -2
  60. package/dist-cjs/lib/ui/components/SharePanel/UserPresenceColorPicker.js +2 -2
  61. package/dist-cjs/lib/ui/components/SharePanel/UserPresenceColorPicker.js.map +2 -2
  62. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanelContent.js +14 -14
  63. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanelContent.js.map +2 -2
  64. package/dist-cjs/lib/ui/components/StylePanel/DoubleDropdownPicker.js +3 -3
  65. package/dist-cjs/lib/ui/components/StylePanel/DoubleDropdownPicker.js.map +2 -2
  66. package/dist-cjs/lib/ui/components/StylePanel/DropdownPicker.js +26 -25
  67. package/dist-cjs/lib/ui/components/StylePanel/DropdownPicker.js.map +3 -3
  68. package/dist-cjs/lib/ui/components/Toolbar/DefaultImageToolbarContent.js +1 -1
  69. package/dist-cjs/lib/ui/components/Toolbar/DefaultImageToolbarContent.js.map +2 -2
  70. package/dist-cjs/lib/ui/components/Toolbar/DefaultToolbar.js +66 -21
  71. package/dist-cjs/lib/ui/components/Toolbar/DefaultToolbar.js.map +3 -3
  72. package/dist-cjs/lib/ui/components/Toolbar/OverflowingToolbar.js +189 -80
  73. package/dist-cjs/lib/ui/components/Toolbar/OverflowingToolbar.js.map +3 -3
  74. package/dist-cjs/lib/ui/components/Toolbar/ToggleToolLockedButton.js +2 -2
  75. package/dist-cjs/lib/ui/components/Toolbar/ToggleToolLockedButton.js.map +2 -2
  76. package/dist-cjs/lib/ui/components/primitives/TldrawUiButtonPicker.js +5 -16
  77. package/dist-cjs/lib/ui/components/primitives/TldrawUiButtonPicker.js.map +3 -3
  78. package/dist-cjs/lib/ui/components/primitives/TldrawUiContextualToolbar.js +1 -1
  79. package/dist-cjs/lib/ui/components/primitives/TldrawUiContextualToolbar.js.map +2 -2
  80. package/dist-cjs/lib/ui/components/primitives/TldrawUiPopover.js +3 -2
  81. package/dist-cjs/lib/ui/components/primitives/TldrawUiPopover.js.map +3 -3
  82. package/dist-cjs/lib/ui/components/primitives/TldrawUiToolbar.js +19 -4
  83. package/dist-cjs/lib/ui/components/primitives/TldrawUiToolbar.js.map +2 -2
  84. package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js +153 -152
  85. package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js.map +2 -2
  86. package/dist-cjs/lib/ui/components/primitives/layout.js +76 -0
  87. package/dist-cjs/lib/ui/components/primitives/layout.js.map +7 -0
  88. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuContext.js.map +2 -2
  89. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuGroup.js +25 -12
  90. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuGroup.js.map +2 -2
  91. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js +154 -20
  92. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js.map +2 -2
  93. package/dist-cjs/lib/ui/context/events.js.map +2 -2
  94. package/dist-cjs/lib/ui/hooks/useTools.js +94 -9
  95. package/dist-cjs/lib/ui/hooks/useTools.js.map +2 -2
  96. package/dist-cjs/lib/ui/version.js +3 -3
  97. package/dist-cjs/lib/ui/version.js.map +1 -1
  98. package/dist-esm/index.d.mts +173 -5
  99. package/dist-esm/index.mjs +19 -1
  100. package/dist-esm/index.mjs.map +2 -2
  101. package/dist-esm/lib/canvas/TldrawScribble.mjs +1 -1
  102. package/dist-esm/lib/canvas/TldrawScribble.mjs.map +2 -2
  103. package/dist-esm/lib/shapes/arrow/ArrowShapeUtil.mjs +4 -3
  104. package/dist-esm/lib/shapes/arrow/ArrowShapeUtil.mjs.map +2 -2
  105. package/dist-esm/lib/shapes/arrow/elbow/ElbowArrowDebug.mjs +3 -3
  106. package/dist-esm/lib/shapes/arrow/elbow/ElbowArrowDebug.mjs.map +1 -1
  107. package/dist-esm/lib/shapes/draw/DrawShapeUtil.mjs +4 -3
  108. package/dist-esm/lib/shapes/draw/DrawShapeUtil.mjs.map +2 -2
  109. package/dist-esm/lib/shapes/embed/EmbedShapeUtil.mjs +1 -1
  110. package/dist-esm/lib/shapes/embed/EmbedShapeUtil.mjs.map +1 -1
  111. package/dist-esm/lib/shapes/frame/FrameShapeUtil.mjs +13 -12
  112. package/dist-esm/lib/shapes/frame/FrameShapeUtil.mjs.map +2 -2
  113. package/dist-esm/lib/shapes/frame/components/FrameHeading.mjs +1 -1
  114. package/dist-esm/lib/shapes/frame/components/FrameHeading.mjs.map +2 -2
  115. package/dist-esm/lib/shapes/geo/GeoShapeUtil.mjs +3 -2
  116. package/dist-esm/lib/shapes/geo/GeoShapeUtil.mjs.map +2 -2
  117. package/dist-esm/lib/shapes/geo/components/GeoShapeBody.mjs +2 -1
  118. package/dist-esm/lib/shapes/geo/components/GeoShapeBody.mjs.map +2 -2
  119. package/dist-esm/lib/shapes/highlight/HighlightShapeUtil.mjs +6 -1
  120. package/dist-esm/lib/shapes/highlight/HighlightShapeUtil.mjs.map +2 -2
  121. package/dist-esm/lib/shapes/image/ImageShapeUtil.mjs +3 -3
  122. package/dist-esm/lib/shapes/image/ImageShapeUtil.mjs.map +1 -1
  123. package/dist-esm/lib/shapes/line/LineShapeUtil.mjs +6 -1
  124. package/dist-esm/lib/shapes/line/LineShapeUtil.mjs.map +2 -2
  125. package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs +5 -4
  126. package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs.map +2 -2
  127. package/dist-esm/lib/shapes/shared/ShapeFill.mjs +5 -4
  128. package/dist-esm/lib/shapes/shared/ShapeFill.mjs.map +2 -2
  129. package/dist-esm/lib/shapes/shared/freehand/svg.mjs.map +2 -2
  130. package/dist-esm/lib/shapes/text/TextShapeUtil.mjs +3 -2
  131. package/dist-esm/lib/shapes/text/TextShapeUtil.mjs.map +2 -2
  132. package/dist-esm/lib/shapes/video/VideoShapeUtil.mjs +3 -3
  133. package/dist-esm/lib/shapes/video/VideoShapeUtil.mjs.map +1 -1
  134. package/dist-esm/lib/tools/EraserTool/childStates/Erasing.mjs +26 -1
  135. package/dist-esm/lib/tools/EraserTool/childStates/Erasing.mjs.map +2 -2
  136. package/dist-esm/lib/tools/EraserTool/childStates/Pointing.mjs +13 -0
  137. package/dist-esm/lib/tools/EraserTool/childStates/Pointing.mjs.map +2 -2
  138. package/dist-esm/lib/tools/SelectTool/childStates/Translating.mjs.map +2 -2
  139. package/dist-esm/lib/ui/TldrawUi.mjs +16 -2
  140. package/dist-esm/lib/ui/TldrawUi.mjs.map +3 -3
  141. package/dist-esm/lib/ui/assetUrls.mjs +13 -10
  142. package/dist-esm/lib/ui/assetUrls.mjs.map +2 -2
  143. package/dist-esm/lib/ui/components/ActionsMenu/DefaultActionsMenu.mjs +12 -3
  144. package/dist-esm/lib/ui/components/ActionsMenu/DefaultActionsMenu.mjs.map +2 -2
  145. package/dist-esm/lib/ui/components/DefaultMenuPanel.mjs +3 -2
  146. package/dist-esm/lib/ui/components/DefaultMenuPanel.mjs.map +2 -2
  147. package/dist-esm/lib/ui/components/Minimap/MinimapManager.mjs +4 -4
  148. package/dist-esm/lib/ui/components/Minimap/MinimapManager.mjs.map +2 -2
  149. package/dist-esm/lib/ui/components/MobileStylePanel.mjs +6 -3
  150. package/dist-esm/lib/ui/components/MobileStylePanel.mjs.map +2 -2
  151. package/dist-esm/lib/ui/components/NavigationPanel/DefaultNavigationPanel.mjs +1 -1
  152. package/dist-esm/lib/ui/components/NavigationPanel/DefaultNavigationPanel.mjs.map +2 -2
  153. package/dist-esm/lib/ui/components/PageMenu/DefaultPageMenu.mjs +2 -1
  154. package/dist-esm/lib/ui/components/PageMenu/DefaultPageMenu.mjs.map +2 -2
  155. package/dist-esm/lib/ui/components/SharePanel/PeopleMenuItem.mjs +3 -2
  156. package/dist-esm/lib/ui/components/SharePanel/PeopleMenuItem.mjs.map +2 -2
  157. package/dist-esm/lib/ui/components/SharePanel/UserPresenceColorPicker.mjs +2 -2
  158. package/dist-esm/lib/ui/components/SharePanel/UserPresenceColorPicker.mjs.map +2 -2
  159. package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanelContent.mjs +14 -14
  160. package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanelContent.mjs.map +2 -2
  161. package/dist-esm/lib/ui/components/StylePanel/DoubleDropdownPicker.mjs +3 -3
  162. package/dist-esm/lib/ui/components/StylePanel/DoubleDropdownPicker.mjs.map +2 -2
  163. package/dist-esm/lib/ui/components/StylePanel/DropdownPicker.mjs +26 -25
  164. package/dist-esm/lib/ui/components/StylePanel/DropdownPicker.mjs.map +2 -2
  165. package/dist-esm/lib/ui/components/Toolbar/DefaultImageToolbarContent.mjs +1 -1
  166. package/dist-esm/lib/ui/components/Toolbar/DefaultImageToolbarContent.mjs.map +2 -2
  167. package/dist-esm/lib/ui/components/Toolbar/DefaultToolbar.mjs +56 -21
  168. package/dist-esm/lib/ui/components/Toolbar/DefaultToolbar.mjs.map +2 -2
  169. package/dist-esm/lib/ui/components/Toolbar/OverflowingToolbar.mjs +192 -81
  170. package/dist-esm/lib/ui/components/Toolbar/OverflowingToolbar.mjs.map +3 -3
  171. package/dist-esm/lib/ui/components/Toolbar/ToggleToolLockedButton.mjs +2 -2
  172. package/dist-esm/lib/ui/components/Toolbar/ToggleToolLockedButton.mjs.map +2 -2
  173. package/dist-esm/lib/ui/components/primitives/TldrawUiButtonPicker.mjs +6 -6
  174. package/dist-esm/lib/ui/components/primitives/TldrawUiButtonPicker.mjs.map +2 -2
  175. package/dist-esm/lib/ui/components/primitives/TldrawUiContextualToolbar.mjs +1 -1
  176. package/dist-esm/lib/ui/components/primitives/TldrawUiContextualToolbar.mjs.map +2 -2
  177. package/dist-esm/lib/ui/components/primitives/TldrawUiPopover.mjs +3 -2
  178. package/dist-esm/lib/ui/components/primitives/TldrawUiPopover.mjs.map +2 -2
  179. package/dist-esm/lib/ui/components/primitives/TldrawUiToolbar.mjs +19 -4
  180. package/dist-esm/lib/ui/components/primitives/TldrawUiToolbar.mjs.map +2 -2
  181. package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs +162 -154
  182. package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs.map +2 -2
  183. package/dist-esm/lib/ui/components/primitives/layout.mjs +46 -0
  184. package/dist-esm/lib/ui/components/primitives/layout.mjs.map +7 -0
  185. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuContext.mjs.map +2 -2
  186. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuGroup.mjs +25 -12
  187. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuGroup.mjs.map +2 -2
  188. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs +162 -22
  189. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs.map +2 -2
  190. package/dist-esm/lib/ui/context/events.mjs.map +2 -2
  191. package/dist-esm/lib/ui/hooks/useTools.mjs +102 -10
  192. package/dist-esm/lib/ui/hooks/useTools.mjs.map +2 -2
  193. package/dist-esm/lib/ui/version.mjs +3 -3
  194. package/dist-esm/lib/ui/version.mjs.map +1 -1
  195. package/package.json +11 -34
  196. package/src/index.ts +15 -0
  197. package/src/lib/canvas/TldrawScribble.tsx +1 -1
  198. package/src/lib/shapes/arrow/ArrowShapeOptions.test.ts +2 -1
  199. package/src/lib/shapes/arrow/ArrowShapeTool.test.ts +4 -3
  200. package/src/lib/shapes/arrow/ArrowShapeUtil.test.ts +7 -6
  201. package/src/lib/shapes/arrow/ArrowShapeUtil.tsx +4 -3
  202. package/src/lib/shapes/arrow/elbow/ElbowArrowDebug.tsx +3 -3
  203. package/src/lib/shapes/draw/DrawShapeTool.test.ts +0 -5
  204. package/src/lib/shapes/draw/DrawShapeUtil.tsx +4 -3
  205. package/src/lib/shapes/embed/EmbedShapeUtil.tsx +1 -1
  206. package/src/lib/shapes/frame/FrameShapeUtil.tsx +21 -14
  207. package/src/lib/shapes/frame/components/FrameHeading.tsx +1 -1
  208. package/src/lib/shapes/geo/GeoShapeUtil.tsx +3 -2
  209. package/src/lib/shapes/geo/components/GeoShapeBody.tsx +2 -2
  210. package/src/lib/shapes/highlight/HighlightShapeUtil.tsx +7 -1
  211. package/src/lib/shapes/image/ImageShapeUtil.tsx +3 -3
  212. package/src/lib/shapes/line/LineShapeUtil.test.tsx +4 -3
  213. package/src/lib/shapes/line/LineShapeUtil.tsx +6 -1
  214. package/src/lib/shapes/line/__snapshots__/LineShapeUtil.test.tsx.snap +2 -2
  215. package/src/lib/shapes/note/NoteShapeUtil.tsx +9 -4
  216. package/src/lib/shapes/shared/ShapeFill.tsx +5 -4
  217. package/src/lib/shapes/shared/freehand/svg.ts +2 -0
  218. package/src/lib/shapes/text/TextShapeTool.test.ts +6 -5
  219. package/src/lib/shapes/text/TextShapeUtil.tsx +3 -2
  220. package/src/lib/shapes/video/VideoShapeUtil.tsx +3 -3
  221. package/src/lib/tools/EraserTool/childStates/Erasing.ts +34 -1
  222. package/src/lib/tools/EraserTool/childStates/Pointing.ts +20 -0
  223. package/src/lib/tools/SelectTool/childStates/Translating.ts +0 -1
  224. package/src/lib/ui/TldrawUi.tsx +17 -2
  225. package/src/lib/ui/assetUrls.ts +13 -10
  226. package/src/lib/ui/components/ActionsMenu/DefaultActionsMenu.tsx +15 -3
  227. package/src/lib/ui/components/DefaultMenuPanel.tsx +4 -3
  228. package/src/lib/ui/components/Minimap/MinimapManager.ts +4 -4
  229. package/src/lib/ui/components/MobileStylePanel.tsx +9 -6
  230. package/src/lib/ui/components/NavigationPanel/DefaultNavigationPanel.tsx +1 -1
  231. package/src/lib/ui/components/PageMenu/DefaultPageMenu.tsx +3 -2
  232. package/src/lib/ui/components/SharePanel/PeopleMenuItem.tsx +4 -3
  233. package/src/lib/ui/components/SharePanel/UserPresenceColorPicker.tsx +3 -3
  234. package/src/lib/ui/components/StylePanel/DefaultStylePanelContent.tsx +39 -43
  235. package/src/lib/ui/components/StylePanel/DoubleDropdownPicker.tsx +3 -3
  236. package/src/lib/ui/components/StylePanel/DropdownPicker.tsx +7 -6
  237. package/src/lib/ui/components/Toolbar/DefaultImageToolbarContent.tsx +1 -1
  238. package/src/lib/ui/components/Toolbar/DefaultToolbar.tsx +55 -23
  239. package/src/lib/ui/components/Toolbar/OverflowingToolbar.tsx +212 -61
  240. package/src/lib/ui/components/Toolbar/ToggleToolLockedButton.tsx +2 -2
  241. package/src/lib/ui/components/primitives/TldrawUiButtonPicker.tsx +40 -37
  242. package/src/lib/ui/components/primitives/TldrawUiContextualToolbar.tsx +1 -1
  243. package/src/lib/ui/components/primitives/TldrawUiPopover.tsx +4 -2
  244. package/src/lib/ui/components/primitives/TldrawUiToolbar.tsx +32 -9
  245. package/src/lib/ui/components/primitives/TldrawUiTooltip.tsx +186 -172
  246. package/src/lib/ui/components/primitives/layout.tsx +107 -0
  247. package/src/lib/ui/components/primitives/menus/TldrawUiMenuContext.tsx +0 -1
  248. package/src/lib/ui/components/primitives/menus/TldrawUiMenuGroup.tsx +29 -16
  249. package/src/lib/ui/components/primitives/menus/TldrawUiMenuItem.tsx +221 -19
  250. package/src/lib/ui/context/events.tsx +1 -0
  251. package/src/lib/ui/hooks/useTools.tsx +140 -10
  252. package/src/lib/ui/version.ts +3 -3
  253. package/src/lib/ui.css +363 -305
  254. package/src/lib/utils/excalidraw/__snapshots__/putExcalidrawContent.test.tsx.snap +5 -5
  255. package/src/lib/utils/tldr/__snapshots__/buildFromV1Document.test.ts.snap +4 -4
  256. package/src/test/A11y.test.tsx +3 -2
  257. package/src/test/ClickManager.test.ts +7 -6
  258. package/src/test/Editor.test.tsx +20 -19
  259. package/src/test/EraserTool.test.ts +184 -13
  260. package/src/test/HandTool.test.ts +10 -9
  261. package/src/test/HighlightShape.test.ts +2 -1
  262. package/src/test/SelectTool.test.ts +3 -2
  263. package/src/test/TLUserPreferences.test.ts +4 -3
  264. package/src/test/TestEditor.ts +13 -15
  265. package/src/test/TldrawEditor.test.tsx +11 -10
  266. package/src/test/ZoomTool.test.ts +7 -6
  267. package/src/test/__snapshots__/drawing.test.ts.snap +2 -2
  268. package/src/test/__snapshots__/groups.test.tsx.snap +6 -6
  269. package/src/test/__snapshots__/resizing.test.ts.snap +2 -2
  270. package/src/test/arrows-megabus.test.tsx +5 -4
  271. package/src/test/bindings.test.tsx +24 -37
  272. package/src/test/bookmark-shapes.test.ts +1 -8
  273. package/src/test/commands/__snapshots__/getSvgString.test.ts.snap +23 -7
  274. package/src/test/commands/__snapshots__/packShapes.test.ts.snap +8 -8
  275. package/src/test/commands/__snapshots__/zoomToFit.test.ts.snap +2 -2
  276. package/src/test/commands/alignShapes.test.tsx +25 -24
  277. package/src/test/commands/animationSpeed.test.ts +2 -1
  278. package/src/test/commands/centerOnPoint.test.ts +3 -2
  279. package/src/test/commands/clipboard.test.ts +3 -2
  280. package/src/test/commands/createShapes.test.ts +2 -1
  281. package/src/test/commands/deleteShapes.test.ts +2 -1
  282. package/src/test/commands/distributeShapes.test.tsx +11 -10
  283. package/src/test/commands/getSvgString.test.ts +2 -1
  284. package/src/test/commands/packShapes.test.ts +5 -4
  285. package/src/test/commands/resizeShape.test.ts +2 -1
  286. package/src/test/commands/rotateShapes.test.ts +7 -6
  287. package/src/test/commands/setCamera.test.ts +4 -3
  288. package/src/test/commands/setCurrentPage.test.ts +3 -2
  289. package/src/test/commands/stackShapes.test.ts +11 -10
  290. package/src/test/commands/stretch.test.tsx +13 -12
  291. package/src/test/createDeepLink.test.tsx +2 -1
  292. package/src/test/cropping.test.ts +3 -2
  293. package/src/test/drawing.test.ts +2 -1
  294. package/src/test/flipShapes.test.ts +4 -3
  295. package/src/test/frames.test.ts +25 -24
  296. package/src/test/getCulledShapes.test.tsx +3 -2
  297. package/src/test/groups.test.tsx +1 -1
  298. package/src/test/handleDeepLink.test.tsx +2 -1
  299. package/src/test/maxShapes.test.ts +3 -2
  300. package/src/test/modifiers.test.ts +5 -4
  301. package/src/test/navigation.test.ts +12 -11
  302. package/src/test/panning.test.ts +2 -1
  303. package/src/test/perf/perf.test.ts +2 -1
  304. package/src/test/registerDeepLinkListener.test.tsx +10 -9
  305. package/src/test/resizing.test.ts +39 -38
  306. package/src/test/select.test.tsx +4 -3
  307. package/src/test/selection-omnibus.test.ts +11 -10
  308. package/src/test/shapeutils.test.ts +4 -3
  309. package/src/test/translating.test.ts +9 -8
  310. package/tldraw.css +656 -595
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/lib/ui/components/primitives/TldrawUiContextualToolbar.tsx"],
4
- "sourcesContent": ["import {\n\tassert,\n\tBox,\n\tclamp,\n\tEditor,\n\treact,\n\tstopEventPropagation,\n\tuseAtom,\n\tuseEditor,\n\tusePassThroughMouseOverEvents,\n\tusePassThroughWheelEvents,\n\tuseValue,\n\tVec,\n} from '@tldraw/editor'\nimport classNames from 'classnames'\nimport React, { RefObject, useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react'\nimport { flushSync } from 'react-dom'\nimport { TldrawUiToolbar } from './TldrawUiToolbar'\n\nconst MOVE_TIMEOUT = 150\nconst HIDE_VISIBILITY_TIMEOUT = 16\nconst SHOW_VISIBILITY_TIMEOUT = 16\nconst MIN_DISTANCE_TO_REPOSITION_SQUARED = 16 ** 2\nconst TOOLBAR_GAP = 8\nconst SCREEN_MARGIN = 16\nconst HIDE_TOOLBAR_WHEN_CAMERA_IS_MOVING = false\nconst LEFT_ALIGN_TOOLBAR = false\n\n/** @public */\nexport interface TLUiContextualToolbarProps {\n\tchildren?: React.ReactNode\n\tclassName?: string\n\tisMousingDown?: boolean\n\tgetSelectionBounds(): Box | undefined\n\tchangeOnlyWhenYChanges?: boolean\n\tlabel: string\n}\n\n/**\n * A generic floating toolbar that can be used for things\n * like rich text editing, image toolbars, etc.\n *\n * @public @react\n */\nexport const TldrawUiContextualToolbar = ({\n\tchildren,\n\tclassName,\n\tisMousingDown,\n\tgetSelectionBounds,\n\tchangeOnlyWhenYChanges = false,\n\tlabel,\n}: TLUiContextualToolbarProps) => {\n\tconst editor = useEditor()\n\tconst toolbarRef = useRef<HTMLDivElement>(null)\n\n\tusePassThroughWheelEvents(toolbarRef as RefObject<HTMLDivElement>)\n\tusePassThroughMouseOverEvents(toolbarRef as RefObject<HTMLDivElement>)\n\n\tconst { isVisible, isInteractive, hide, show, position, move } =\n\t\tuseToolbarVisibilityStateMachine(changeOnlyWhenYChanges)\n\n\t// annoying react stuff: we don't want the toolbar position function to depend on the react state so we'll double with a ref\n\tconst rCouldShowToolbar = useRef(false)\n\tconst [hasValidToolbarPosition, setHasValidToolbarPosition] = useState(false)\n\n\tconst contentSizeUpdateCounter = useAtom('content size update counter', 0)\n\n\tuseEffect(() => {\n\t\tassert(toolbarRef.current)\n\t\tconst observer = new ResizeObserver(() => {\n\t\t\tcontentSizeUpdateCounter.update((n) => n + 1)\n\t\t})\n\t\tobserver.observe(toolbarRef.current)\n\t\treturn () => observer.disconnect()\n\t}, [contentSizeUpdateCounter])\n\n\tuseEffect(() => {\n\t\tlet lastContentSizeUpdateCounter = contentSizeUpdateCounter.get()\n\t\treturn react('toolbar position', function updateToolbarPositionAndDisplay() {\n\t\t\tconst toolbarElm = toolbarRef.current\n\t\t\tif (!toolbarElm) return\n\n\t\t\tconst nextContentSizeUpdateCounter = contentSizeUpdateCounter.get()\n\n\t\t\t// capture / force this to update when...\n\t\t\teditor.getCamera() // the camera moves\n\t\t\tcontentSizeUpdateCounter.get() // the toolbar size changes\n\t\t\t// undefined here means that we can't show the toolbar due to an incompatible position\n\t\t\tconst position = getToolbarScreenPosition(editor, toolbarElm, getSelectionBounds)\n\n\t\t\t// todo: when the toolbar is hidden due to the selection being off screen, it should be hidden immediately\n\t\t\t// rather than waiting for the position to settle. This is different than when the position changes due to\n\t\t\t// a change in the user's selection.\n\t\t\tif (!position) {\n\t\t\t\tif (rCouldShowToolbar.current) {\n\t\t\t\t\t// If we don't have a position, then we're not showing the toolbar\n\t\t\t\t\trCouldShowToolbar.current = false\n\t\t\t\t\tsetHasValidToolbarPosition(false)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// If the camera state is moving, we want to immediately update the position\n\t\t\t\t// todo: consider hiding the toolbar while the camera is moving\n\t\t\t\tconst cameraState = editor.getCameraState()\n\t\t\t\tif (cameraState === 'moving') {\n\t\t\t\t\t// ...if we wanted this to avoid prematurely updating any positions, we'd need\n\t\t\t\t\t// to have the last updated position in page space, so that we could convert\n\t\t\t\t\t// it to screen space and update it here\n\t\t\t\t\tconst elm = toolbarRef.current\n\t\t\t\t\telm.style.setProperty('transform', `translate(${position.x}px, ${position.y}px)`)\n\t\t\t\t} else {\n\t\t\t\t\tconst moveImmediately = lastContentSizeUpdateCounter !== nextContentSizeUpdateCounter\n\t\t\t\t\t// Schedule a move to its next location\n\t\t\t\t\tmove(position.x, position.y, moveImmediately)\n\t\t\t\t}\n\n\t\t\t\t// Finally, if the toolbar was previously hidden, show it again\n\t\t\t\tif (!rCouldShowToolbar.current) {\n\t\t\t\t\trCouldShowToolbar.current = true\n\t\t\t\t\tsetHasValidToolbarPosition(true)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlastContentSizeUpdateCounter = nextContentSizeUpdateCounter\n\t\t})\n\t}, [editor, getSelectionBounds, contentSizeUpdateCounter, move])\n\n\tconst cameraState = useValue('camera state', () => editor.getCameraState(), [editor])\n\n\t// Send the hide or show events based on whether the user is clicking\n\t// and whether the toolbar's position is valid\n\tuseEffect(() => {\n\t\tif (cameraState === 'moving' && HIDE_TOOLBAR_WHEN_CAMERA_IS_MOVING) {\n\t\t\thide(true)\n\t\t\treturn\n\t\t}\n\n\t\tif (isMousingDown || !hasValidToolbarPosition) {\n\t\t\thide()\n\t\t\treturn\n\t\t}\n\n\t\tshow()\n\t}, [hasValidToolbarPosition, cameraState, isMousingDown, show, hide])\n\n\t// When the visibility changes, update the toolbar's visibility\n\tuseLayoutEffect(() => {\n\t\tconst elm = toolbarRef.current\n\t\tif (!elm) return\n\t\telm.dataset.visible = `${isVisible}`\n\t}, [isVisible, position])\n\n\t// When the position changes, update the toolbar's position on screen\n\tuseLayoutEffect(() => {\n\t\tconst elm = toolbarRef.current\n\t\tif (!elm) return\n\t\telm.style.setProperty('transform', `translate(${position.x}px, ${position.y}px)`)\n\t}, [position])\n\n\t// When the interactivity changes, update the toolbar's interactivity\n\tuseLayoutEffect(() => {\n\t\tconst elm = toolbarRef.current\n\t\tif (!elm) return\n\t\telm.dataset.interactive = `${isInteractive}`\n\t}, [isInteractive])\n\n\treturn (\n\t\t<div\n\t\t\tref={toolbarRef}\n\t\t\tdata-interactive={false}\n\t\t\tdata-visible={false}\n\t\t\tdata-testid=\"contextual-toolbar\"\n\t\t\tclassName={classNames('tlui-contextual-toolbar', className)}\n\t\t\tonPointerDown={stopEventPropagation}\n\t\t>\n\t\t\t<TldrawUiToolbar className=\"tlui-menu tlui-buttons__horizontal\" label={label}>\n\t\t\t\t{children}\n\t\t\t</TldrawUiToolbar>\n\t\t</div>\n\t)\n}\n\n// For convenience, let's work just with boxes here\n/** @internal */\nexport function rectToBox(rect: DOMRect): Box {\n\treturn new Box(rect.x, rect.y, rect.width, rect.height)\n}\n\nexport function getToolbarScreenPosition(\n\teditor: Editor,\n\ttoolbarElm: HTMLElement,\n\tgetSelectionBounds: () => Box | undefined\n) {\n\tconst selectionBounds = getSelectionBounds()?.clone()\n\tif (!selectionBounds) return\n\n\t// Offset the selection bounds by the viewport screen bounds (if the editor is scrolled or inset, etc)\n\tconst vsb = editor.getViewportScreenBounds()\n\tselectionBounds.x -= vsb.x\n\tselectionBounds.y -= vsb.y\n\n\t// If the selection bounds are too far off of the screen, don't show the toolbar\n\tif (\n\t\tselectionBounds.midY < SCREEN_MARGIN ||\n\t\tselectionBounds.midY > vsb.h - SCREEN_MARGIN ||\n\t\tselectionBounds.midX < SCREEN_MARGIN ||\n\t\tselectionBounds.midX > vsb.w - SCREEN_MARGIN\n\t) {\n\t\treturn\n\t}\n\n\t// Get the toolbar's screen rect as a box. Do this after we verify that there is at least one selection.\n\tconst toolbarBounds = rectToBox(toolbarElm.getBoundingClientRect())\n\n\t// Chance these are NaN? Rare case.\n\tif (!toolbarBounds.width || !toolbarBounds.height) return\n\n\t// Thrashy, only do this if we're showing the toolbar\n\t// ! this might not be needed, the container never scrolls\n\tconst { scrollLeft, scrollTop } = editor.getContainer()\n\n\t// We want to position the toolbar so that it is centered over the selection\n\t// except in the cases where it would extend off the edge of the screen.\n\n\t// Start by placing the top left corner of the toolbar so that the\n\t// toolbar would be centered above the section bounds, bumped up by the\n\n\tlet x = LEFT_ALIGN_TOOLBAR ? selectionBounds.x : selectionBounds.midX - toolbarBounds.w / 2\n\tlet y = selectionBounds.y - toolbarBounds.h - TOOLBAR_GAP\n\n\t// Clamp the position on screen.\n\tx = clamp(x, SCREEN_MARGIN, vsb.w - toolbarBounds.w - SCREEN_MARGIN)\n\ty = clamp(y, SCREEN_MARGIN, vsb.h - toolbarBounds.h - SCREEN_MARGIN)\n\n\t// Offset the position by the container's scroll position\n\tx += scrollLeft\n\ty += scrollTop\n\n\t// Round the position to the nearest pixel\n\tx = Math.round(x)\n\ty = Math.round(y)\n\n\treturn { x, y }\n}\n\nfunction sufficientlyDistant(curr: Vec, next: Vec, changeOnlyWhenYChanges: boolean) {\n\tif (changeOnlyWhenYChanges) {\n\t\treturn Vec.Sub(next, curr).y ** 2 >= MIN_DISTANCE_TO_REPOSITION_SQUARED\n\t}\n\treturn Vec.Len2(Vec.Sub(next, curr)) >= MIN_DISTANCE_TO_REPOSITION_SQUARED\n}\n\nexport function useToolbarVisibilityStateMachine(changeOnlyWhenYChanges: boolean) {\n\tconst editor = useEditor()\n\n\tconst rState = useRef<\n\t\t{ name: 'hidden' } | { name: 'showing' } | { name: 'shown' } | { name: 'hiding' }\n\t>({ name: 'hidden' })\n\n\t// The toolbar should only be interactive when in the 'shown' state\n\tconst [isInteractive, setIsInteractive] = useState(false)\n\n\t// The toolbar is visible in the 'shown' and 'hiding' states\n\tconst [isVisible, setIsVisible] = useState(false)\n\n\t// The position is updated when entering the 'shown' state or when moving while in the 'shown' state\n\tconst [position, setPosition] = useState({ x: -1000, y: -1000 })\n\n\t// The toolbar's current position\n\tconst rCurrPosition = useRef(new Vec(-1000, -1000))\n\n\t// The toolbar's proposed next position\n\tconst rNextPosition = useRef(new Vec(-1000, -1000))\n\n\t// A timeout needs to be completed before the toolbar is shown or hidden\n\tconst rStableVisibilityTimeout = useRef<any>(-1)\n\n\t// A timeout needs to be completed before the toolbar's position changes moved\n\tconst rStablePositionTimeout = useRef<any>(-1)\n\n\t/**\n\t * Send the 'move' event whenever something happens that would cause the toolbar's position to change.\n\t * Any update here will cause\n\t * If the state is 'shown', it will start a new timeout that will update the toolbar's position after it completes.\n\t */\n\tconst move = useCallback(\n\t\t(x: number, y: number, immediate = false) => {\n\t\t\t// Update the next proposed position\n\t\t\trNextPosition.current.x = x\n\t\t\trNextPosition.current.y = y\n\n\t\t\t// If the toolbar is not yet visible, don't do anything\n\t\t\tif (rState.current.name === 'hidden' || rState.current.name === 'showing') return\n\n\t\t\t// If showing or hiding, cancel the position timeout and start a new one.\n\t\t\t// When the timeout ends, if we're in the 'shown' state and the position has changed sufficiently\n\t\t\t// from the last visible position, update the position.\n\t\t\tclearTimeout(rStablePositionTimeout.current)\n\n\t\t\tconst flushMove = () => {\n\t\t\t\tif (\n\t\t\t\t\trState.current.name === 'shown' &&\n\t\t\t\t\tsufficientlyDistant(rNextPosition.current, rCurrPosition.current, changeOnlyWhenYChanges)\n\t\t\t\t) {\n\t\t\t\t\tconst { x, y } = rNextPosition.current\n\t\t\t\t\trCurrPosition.current = new Vec(x, y)\n\t\t\t\t\tif (immediate) {\n\t\t\t\t\t\tflushSync(() => setPosition({ x, y }))\n\t\t\t\t\t} else {\n\t\t\t\t\t\tsetPosition({ x, y })\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (immediate) {\n\t\t\t\tflushMove()\n\t\t\t} else {\n\t\t\t\trStablePositionTimeout.current = editor.timers.setTimeout(flushMove, MOVE_TIMEOUT)\n\t\t\t}\n\t\t},\n\t\t[editor, changeOnlyWhenYChanges]\n\t)\n\n\t/**\n\t * Send the hide event whenever a change occurs that would cause the toolbar to become invisible.\n\t * If the state is 'shown', it will enter 'hiding' and then 'hidden' after a timeout completes.\n\t * If the state is 'showing', it will cancel the visibility timeout and enter 'hidden' immediately.\n\t */\n\tconst hide = useCallback(\n\t\t(immediate = false) => {\n\t\t\tswitch (rState.current.name) {\n\t\t\t\tcase 'showing': {\n\t\t\t\t\tclearTimeout(rStableVisibilityTimeout.current)\n\t\t\t\t\trState.current = { name: 'hidden' }\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tcase 'shown': {\n\t\t\t\t\trState.current = { name: 'hiding' }\n\t\t\t\t\tsetIsInteractive(false) // when leaving shown, turn back on interactions\n\n\t\t\t\t\tif (immediate) {\n\t\t\t\t\t\trState.current = { name: 'hidden' }\n\t\t\t\t\t\tsetIsVisible(false)\n\t\t\t\t\t} else {\n\t\t\t\t\t\trStableVisibilityTimeout.current = editor.timers.setTimeout(() => {\n\t\t\t\t\t\t\trState.current = { name: 'hidden' }\n\t\t\t\t\t\t\tsetIsVisible(false)\n\t\t\t\t\t\t}, HIDE_VISIBILITY_TIMEOUT)\n\t\t\t\t\t}\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tdefault: {\n\t\t\t\t\t// noop\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t[editor]\n\t)\n\n\t/**\n\t * Send the show event whenever a change occurs that would cause the toolbar to become visible.\n\t * If the state is 'hidden', it will enter 'showing' and then 'shown' after a timeout completes.\n\t * If the state is 'hiding', it will cancel the visibility timeout and enter 'shown' immediately.\n\t */\n\tconst show = useCallback(() => {\n\t\tswitch (rState.current.name) {\n\t\t\tcase 'hidden': {\n\t\t\t\trState.current = { name: 'showing' }\n\t\t\t\trStableVisibilityTimeout.current = editor.timers.setTimeout(() => {\n\t\t\t\t\t// position\n\t\t\t\t\tconst { x, y } = rNextPosition.current\n\t\t\t\t\trCurrPosition.current = new Vec(x, y)\n\t\t\t\t\tsetPosition({ x, y })\n\n\t\t\t\t\trState.current = { name: 'shown' }\n\t\t\t\t\tsetIsVisible(true)\n\t\t\t\t\tsetIsInteractive(true)\n\t\t\t\t}, SHOW_VISIBILITY_TIMEOUT)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'hiding': {\n\t\t\t\t// Go back to shown immediately\n\t\t\t\tclearTimeout(rStableVisibilityTimeout.current)\n\t\t\t\trState.current = { name: 'shown' }\n\t\t\t\tsetIsInteractive(true) // when entering shown, turn back on interactions\n\t\t\t\tmove(rNextPosition.current.x, rNextPosition.current.y)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tdefault: {\n\t\t\t\t// noop\n\t\t\t}\n\t\t}\n\t}, [editor, move])\n\n\treturn { isVisible, isInteractive, show, hide, move, position }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import {\n\tassert,\n\tBox,\n\tclamp,\n\tEditor,\n\treact,\n\tstopEventPropagation,\n\tuseAtom,\n\tuseEditor,\n\tusePassThroughMouseOverEvents,\n\tusePassThroughWheelEvents,\n\tuseValue,\n\tVec,\n} from '@tldraw/editor'\nimport classNames from 'classnames'\nimport React, { RefObject, useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react'\nimport { flushSync } from 'react-dom'\nimport { TldrawUiToolbar } from './TldrawUiToolbar'\n\nconst MOVE_TIMEOUT = 150\nconst HIDE_VISIBILITY_TIMEOUT = 16\nconst SHOW_VISIBILITY_TIMEOUT = 16\nconst MIN_DISTANCE_TO_REPOSITION_SQUARED = 16 ** 2\nconst TOOLBAR_GAP = 8\nconst SCREEN_MARGIN = 16\nconst HIDE_TOOLBAR_WHEN_CAMERA_IS_MOVING = false\nconst LEFT_ALIGN_TOOLBAR = false\n\n/** @public */\nexport interface TLUiContextualToolbarProps {\n\tchildren?: React.ReactNode\n\tclassName?: string\n\tisMousingDown?: boolean\n\tgetSelectionBounds(): Box | undefined\n\tchangeOnlyWhenYChanges?: boolean\n\tlabel: string\n}\n\n/**\n * A generic floating toolbar that can be used for things\n * like rich text editing, image toolbars, etc.\n *\n * @public @react\n */\nexport const TldrawUiContextualToolbar = ({\n\tchildren,\n\tclassName,\n\tisMousingDown,\n\tgetSelectionBounds,\n\tchangeOnlyWhenYChanges = false,\n\tlabel,\n}: TLUiContextualToolbarProps) => {\n\tconst editor = useEditor()\n\tconst toolbarRef = useRef<HTMLDivElement>(null)\n\n\tusePassThroughWheelEvents(toolbarRef as RefObject<HTMLDivElement>)\n\tusePassThroughMouseOverEvents(toolbarRef as RefObject<HTMLDivElement>)\n\n\tconst { isVisible, isInteractive, hide, show, position, move } =\n\t\tuseToolbarVisibilityStateMachine(changeOnlyWhenYChanges)\n\n\t// annoying react stuff: we don't want the toolbar position function to depend on the react state so we'll double with a ref\n\tconst rCouldShowToolbar = useRef(false)\n\tconst [hasValidToolbarPosition, setHasValidToolbarPosition] = useState(false)\n\n\tconst contentSizeUpdateCounter = useAtom('content size update counter', 0)\n\n\tuseEffect(() => {\n\t\tassert(toolbarRef.current)\n\t\tconst observer = new ResizeObserver(() => {\n\t\t\tcontentSizeUpdateCounter.update((n) => n + 1)\n\t\t})\n\t\tobserver.observe(toolbarRef.current)\n\t\treturn () => observer.disconnect()\n\t}, [contentSizeUpdateCounter])\n\n\tuseEffect(() => {\n\t\tlet lastContentSizeUpdateCounter = contentSizeUpdateCounter.get()\n\t\treturn react('toolbar position', function updateToolbarPositionAndDisplay() {\n\t\t\tconst toolbarElm = toolbarRef.current\n\t\t\tif (!toolbarElm) return\n\n\t\t\tconst nextContentSizeUpdateCounter = contentSizeUpdateCounter.get()\n\n\t\t\t// capture / force this to update when...\n\t\t\teditor.getCamera() // the camera moves\n\t\t\tcontentSizeUpdateCounter.get() // the toolbar size changes\n\t\t\t// undefined here means that we can't show the toolbar due to an incompatible position\n\t\t\tconst position = getToolbarScreenPosition(editor, toolbarElm, getSelectionBounds)\n\n\t\t\t// todo: when the toolbar is hidden due to the selection being off screen, it should be hidden immediately\n\t\t\t// rather than waiting for the position to settle. This is different than when the position changes due to\n\t\t\t// a change in the user's selection.\n\t\t\tif (!position) {\n\t\t\t\tif (rCouldShowToolbar.current) {\n\t\t\t\t\t// If we don't have a position, then we're not showing the toolbar\n\t\t\t\t\trCouldShowToolbar.current = false\n\t\t\t\t\tsetHasValidToolbarPosition(false)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// If the camera state is moving, we want to immediately update the position\n\t\t\t\t// todo: consider hiding the toolbar while the camera is moving\n\t\t\t\tconst cameraState = editor.getCameraState()\n\t\t\t\tif (cameraState === 'moving') {\n\t\t\t\t\t// ...if we wanted this to avoid prematurely updating any positions, we'd need\n\t\t\t\t\t// to have the last updated position in page space, so that we could convert\n\t\t\t\t\t// it to screen space and update it here\n\t\t\t\t\tconst elm = toolbarRef.current\n\t\t\t\t\telm.style.setProperty('transform', `translate(${position.x}px, ${position.y}px)`)\n\t\t\t\t} else {\n\t\t\t\t\tconst moveImmediately = lastContentSizeUpdateCounter !== nextContentSizeUpdateCounter\n\t\t\t\t\t// Schedule a move to its next location\n\t\t\t\t\tmove(position.x, position.y, moveImmediately)\n\t\t\t\t}\n\n\t\t\t\t// Finally, if the toolbar was previously hidden, show it again\n\t\t\t\tif (!rCouldShowToolbar.current) {\n\t\t\t\t\trCouldShowToolbar.current = true\n\t\t\t\t\tsetHasValidToolbarPosition(true)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlastContentSizeUpdateCounter = nextContentSizeUpdateCounter\n\t\t})\n\t}, [editor, getSelectionBounds, contentSizeUpdateCounter, move])\n\n\tconst cameraState = useValue('camera state', () => editor.getCameraState(), [editor])\n\n\t// Send the hide or show events based on whether the user is clicking\n\t// and whether the toolbar's position is valid\n\tuseEffect(() => {\n\t\tif (cameraState === 'moving' && HIDE_TOOLBAR_WHEN_CAMERA_IS_MOVING) {\n\t\t\thide(true)\n\t\t\treturn\n\t\t}\n\n\t\tif (isMousingDown || !hasValidToolbarPosition) {\n\t\t\thide()\n\t\t\treturn\n\t\t}\n\n\t\tshow()\n\t}, [hasValidToolbarPosition, cameraState, isMousingDown, show, hide])\n\n\t// When the visibility changes, update the toolbar's visibility\n\tuseLayoutEffect(() => {\n\t\tconst elm = toolbarRef.current\n\t\tif (!elm) return\n\t\telm.dataset.visible = `${isVisible}`\n\t}, [isVisible, position])\n\n\t// When the position changes, update the toolbar's position on screen\n\tuseLayoutEffect(() => {\n\t\tconst elm = toolbarRef.current\n\t\tif (!elm) return\n\t\telm.style.setProperty('transform', `translate(${position.x}px, ${position.y}px)`)\n\t}, [position])\n\n\t// When the interactivity changes, update the toolbar's interactivity\n\tuseLayoutEffect(() => {\n\t\tconst elm = toolbarRef.current\n\t\tif (!elm) return\n\t\telm.dataset.interactive = `${isInteractive}`\n\t}, [isInteractive])\n\n\treturn (\n\t\t<div\n\t\t\tref={toolbarRef}\n\t\t\tdata-interactive={false}\n\t\t\tdata-visible={false}\n\t\t\tdata-testid=\"contextual-toolbar\"\n\t\t\tclassName={classNames('tlui-contextual-toolbar', className)}\n\t\t\tonPointerDown={stopEventPropagation}\n\t\t>\n\t\t\t<TldrawUiToolbar orientation=\"horizontal\" className=\"tlui-menu\" label={label}>\n\t\t\t\t{children}\n\t\t\t</TldrawUiToolbar>\n\t\t</div>\n\t)\n}\n\n// For convenience, let's work just with boxes here\n/** @internal */\nexport function rectToBox(rect: DOMRect): Box {\n\treturn new Box(rect.x, rect.y, rect.width, rect.height)\n}\n\nexport function getToolbarScreenPosition(\n\teditor: Editor,\n\ttoolbarElm: HTMLElement,\n\tgetSelectionBounds: () => Box | undefined\n) {\n\tconst selectionBounds = getSelectionBounds()?.clone()\n\tif (!selectionBounds) return\n\n\t// Offset the selection bounds by the viewport screen bounds (if the editor is scrolled or inset, etc)\n\tconst vsb = editor.getViewportScreenBounds()\n\tselectionBounds.x -= vsb.x\n\tselectionBounds.y -= vsb.y\n\n\t// If the selection bounds are too far off of the screen, don't show the toolbar\n\tif (\n\t\tselectionBounds.midY < SCREEN_MARGIN ||\n\t\tselectionBounds.midY > vsb.h - SCREEN_MARGIN ||\n\t\tselectionBounds.midX < SCREEN_MARGIN ||\n\t\tselectionBounds.midX > vsb.w - SCREEN_MARGIN\n\t) {\n\t\treturn\n\t}\n\n\t// Get the toolbar's screen rect as a box. Do this after we verify that there is at least one selection.\n\tconst toolbarBounds = rectToBox(toolbarElm.getBoundingClientRect())\n\n\t// Chance these are NaN? Rare case.\n\tif (!toolbarBounds.width || !toolbarBounds.height) return\n\n\t// Thrashy, only do this if we're showing the toolbar\n\t// ! this might not be needed, the container never scrolls\n\tconst { scrollLeft, scrollTop } = editor.getContainer()\n\n\t// We want to position the toolbar so that it is centered over the selection\n\t// except in the cases where it would extend off the edge of the screen.\n\n\t// Start by placing the top left corner of the toolbar so that the\n\t// toolbar would be centered above the section bounds, bumped up by the\n\n\tlet x = LEFT_ALIGN_TOOLBAR ? selectionBounds.x : selectionBounds.midX - toolbarBounds.w / 2\n\tlet y = selectionBounds.y - toolbarBounds.h - TOOLBAR_GAP\n\n\t// Clamp the position on screen.\n\tx = clamp(x, SCREEN_MARGIN, vsb.w - toolbarBounds.w - SCREEN_MARGIN)\n\ty = clamp(y, SCREEN_MARGIN, vsb.h - toolbarBounds.h - SCREEN_MARGIN)\n\n\t// Offset the position by the container's scroll position\n\tx += scrollLeft\n\ty += scrollTop\n\n\t// Round the position to the nearest pixel\n\tx = Math.round(x)\n\ty = Math.round(y)\n\n\treturn { x, y }\n}\n\nfunction sufficientlyDistant(curr: Vec, next: Vec, changeOnlyWhenYChanges: boolean) {\n\tif (changeOnlyWhenYChanges) {\n\t\treturn Vec.Sub(next, curr).y ** 2 >= MIN_DISTANCE_TO_REPOSITION_SQUARED\n\t}\n\treturn Vec.Len2(Vec.Sub(next, curr)) >= MIN_DISTANCE_TO_REPOSITION_SQUARED\n}\n\nexport function useToolbarVisibilityStateMachine(changeOnlyWhenYChanges: boolean) {\n\tconst editor = useEditor()\n\n\tconst rState = useRef<\n\t\t{ name: 'hidden' } | { name: 'showing' } | { name: 'shown' } | { name: 'hiding' }\n\t>({ name: 'hidden' })\n\n\t// The toolbar should only be interactive when in the 'shown' state\n\tconst [isInteractive, setIsInteractive] = useState(false)\n\n\t// The toolbar is visible in the 'shown' and 'hiding' states\n\tconst [isVisible, setIsVisible] = useState(false)\n\n\t// The position is updated when entering the 'shown' state or when moving while in the 'shown' state\n\tconst [position, setPosition] = useState({ x: -1000, y: -1000 })\n\n\t// The toolbar's current position\n\tconst rCurrPosition = useRef(new Vec(-1000, -1000))\n\n\t// The toolbar's proposed next position\n\tconst rNextPosition = useRef(new Vec(-1000, -1000))\n\n\t// A timeout needs to be completed before the toolbar is shown or hidden\n\tconst rStableVisibilityTimeout = useRef<any>(-1)\n\n\t// A timeout needs to be completed before the toolbar's position changes moved\n\tconst rStablePositionTimeout = useRef<any>(-1)\n\n\t/**\n\t * Send the 'move' event whenever something happens that would cause the toolbar's position to change.\n\t * Any update here will cause\n\t * If the state is 'shown', it will start a new timeout that will update the toolbar's position after it completes.\n\t */\n\tconst move = useCallback(\n\t\t(x: number, y: number, immediate = false) => {\n\t\t\t// Update the next proposed position\n\t\t\trNextPosition.current.x = x\n\t\t\trNextPosition.current.y = y\n\n\t\t\t// If the toolbar is not yet visible, don't do anything\n\t\t\tif (rState.current.name === 'hidden' || rState.current.name === 'showing') return\n\n\t\t\t// If showing or hiding, cancel the position timeout and start a new one.\n\t\t\t// When the timeout ends, if we're in the 'shown' state and the position has changed sufficiently\n\t\t\t// from the last visible position, update the position.\n\t\t\tclearTimeout(rStablePositionTimeout.current)\n\n\t\t\tconst flushMove = () => {\n\t\t\t\tif (\n\t\t\t\t\trState.current.name === 'shown' &&\n\t\t\t\t\tsufficientlyDistant(rNextPosition.current, rCurrPosition.current, changeOnlyWhenYChanges)\n\t\t\t\t) {\n\t\t\t\t\tconst { x, y } = rNextPosition.current\n\t\t\t\t\trCurrPosition.current = new Vec(x, y)\n\t\t\t\t\tif (immediate) {\n\t\t\t\t\t\tflushSync(() => setPosition({ x, y }))\n\t\t\t\t\t} else {\n\t\t\t\t\t\tsetPosition({ x, y })\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (immediate) {\n\t\t\t\tflushMove()\n\t\t\t} else {\n\t\t\t\trStablePositionTimeout.current = editor.timers.setTimeout(flushMove, MOVE_TIMEOUT)\n\t\t\t}\n\t\t},\n\t\t[editor, changeOnlyWhenYChanges]\n\t)\n\n\t/**\n\t * Send the hide event whenever a change occurs that would cause the toolbar to become invisible.\n\t * If the state is 'shown', it will enter 'hiding' and then 'hidden' after a timeout completes.\n\t * If the state is 'showing', it will cancel the visibility timeout and enter 'hidden' immediately.\n\t */\n\tconst hide = useCallback(\n\t\t(immediate = false) => {\n\t\t\tswitch (rState.current.name) {\n\t\t\t\tcase 'showing': {\n\t\t\t\t\tclearTimeout(rStableVisibilityTimeout.current)\n\t\t\t\t\trState.current = { name: 'hidden' }\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tcase 'shown': {\n\t\t\t\t\trState.current = { name: 'hiding' }\n\t\t\t\t\tsetIsInteractive(false) // when leaving shown, turn back on interactions\n\n\t\t\t\t\tif (immediate) {\n\t\t\t\t\t\trState.current = { name: 'hidden' }\n\t\t\t\t\t\tsetIsVisible(false)\n\t\t\t\t\t} else {\n\t\t\t\t\t\trStableVisibilityTimeout.current = editor.timers.setTimeout(() => {\n\t\t\t\t\t\t\trState.current = { name: 'hidden' }\n\t\t\t\t\t\t\tsetIsVisible(false)\n\t\t\t\t\t\t}, HIDE_VISIBILITY_TIMEOUT)\n\t\t\t\t\t}\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tdefault: {\n\t\t\t\t\t// noop\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t[editor]\n\t)\n\n\t/**\n\t * Send the show event whenever a change occurs that would cause the toolbar to become visible.\n\t * If the state is 'hidden', it will enter 'showing' and then 'shown' after a timeout completes.\n\t * If the state is 'hiding', it will cancel the visibility timeout and enter 'shown' immediately.\n\t */\n\tconst show = useCallback(() => {\n\t\tswitch (rState.current.name) {\n\t\t\tcase 'hidden': {\n\t\t\t\trState.current = { name: 'showing' }\n\t\t\t\trStableVisibilityTimeout.current = editor.timers.setTimeout(() => {\n\t\t\t\t\t// position\n\t\t\t\t\tconst { x, y } = rNextPosition.current\n\t\t\t\t\trCurrPosition.current = new Vec(x, y)\n\t\t\t\t\tsetPosition({ x, y })\n\n\t\t\t\t\trState.current = { name: 'shown' }\n\t\t\t\t\tsetIsVisible(true)\n\t\t\t\t\tsetIsInteractive(true)\n\t\t\t\t}, SHOW_VISIBILITY_TIMEOUT)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'hiding': {\n\t\t\t\t// Go back to shown immediately\n\t\t\t\tclearTimeout(rStableVisibilityTimeout.current)\n\t\t\t\trState.current = { name: 'shown' }\n\t\t\t\tsetIsInteractive(true) // when entering shown, turn back on interactions\n\t\t\t\tmove(rNextPosition.current.x, rNextPosition.current.y)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tdefault: {\n\t\t\t\t// noop\n\t\t\t}\n\t\t}\n\t}, [editor, move])\n\n\treturn { isVisible, isInteractive, show, hide, move, position }\n}\n"],
5
+ "mappings": "AA8KG;AA9KH;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AACP,OAAO,gBAAgB;AACvB,SAA2B,aAAa,WAAW,iBAAiB,QAAQ,gBAAgB;AAC5F,SAAS,iBAAiB;AAC1B,SAAS,uBAAuB;AAEhC,MAAM,eAAe;AACrB,MAAM,0BAA0B;AAChC,MAAM,0BAA0B;AAChC,MAAM,qCAAqC,MAAM;AACjD,MAAM,cAAc;AACpB,MAAM,gBAAgB;AACtB,MAAM,qCAAqC;AAC3C,MAAM,qBAAqB;AAkBpB,MAAM,4BAA4B,CAAC;AAAA,EACzC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,yBAAyB;AAAA,EACzB;AACD,MAAkC;AACjC,QAAM,SAAS,UAAU;AACzB,QAAM,aAAa,OAAuB,IAAI;AAE9C,4BAA0B,UAAuC;AACjE,gCAA8B,UAAuC;AAErE,QAAM,EAAE,WAAW,eAAe,MAAM,MAAM,UAAU,KAAK,IAC5D,iCAAiC,sBAAsB;AAGxD,QAAM,oBAAoB,OAAO,KAAK;AACtC,QAAM,CAAC,yBAAyB,0BAA0B,IAAI,SAAS,KAAK;AAE5E,QAAM,2BAA2B,QAAQ,+BAA+B,CAAC;AAEzE,YAAU,MAAM;AACf,WAAO,WAAW,OAAO;AACzB,UAAM,WAAW,IAAI,eAAe,MAAM;AACzC,+BAAyB,OAAO,CAAC,MAAM,IAAI,CAAC;AAAA,IAC7C,CAAC;AACD,aAAS,QAAQ,WAAW,OAAO;AACnC,WAAO,MAAM,SAAS,WAAW;AAAA,EAClC,GAAG,CAAC,wBAAwB,CAAC;AAE7B,YAAU,MAAM;AACf,QAAI,+BAA+B,yBAAyB,IAAI;AAChE,WAAO,MAAM,oBAAoB,SAAS,kCAAkC;AAC3E,YAAM,aAAa,WAAW;AAC9B,UAAI,CAAC,WAAY;AAEjB,YAAM,+BAA+B,yBAAyB,IAAI;AAGlE,aAAO,UAAU;AACjB,+BAAyB,IAAI;AAE7B,YAAMA,YAAW,yBAAyB,QAAQ,YAAY,kBAAkB;AAKhF,UAAI,CAACA,WAAU;AACd,YAAI,kBAAkB,SAAS;AAE9B,4BAAkB,UAAU;AAC5B,qCAA2B,KAAK;AAAA,QACjC;AAAA,MACD,OAAO;AAGN,cAAMC,eAAc,OAAO,eAAe;AAC1C,YAAIA,iBAAgB,UAAU;AAI7B,gBAAM,MAAM,WAAW;AACvB,cAAI,MAAM,YAAY,aAAa,aAAaD,UAAS,CAAC,OAAOA,UAAS,CAAC,KAAK;AAAA,QACjF,OAAO;AACN,gBAAM,kBAAkB,iCAAiC;AAEzD,eAAKA,UAAS,GAAGA,UAAS,GAAG,eAAe;AAAA,QAC7C;AAGA,YAAI,CAAC,kBAAkB,SAAS;AAC/B,4BAAkB,UAAU;AAC5B,qCAA2B,IAAI;AAAA,QAChC;AAAA,MACD;AAEA,qCAA+B;AAAA,IAChC,CAAC;AAAA,EACF,GAAG,CAAC,QAAQ,oBAAoB,0BAA0B,IAAI,CAAC;AAE/D,QAAM,cAAc,SAAS,gBAAgB,MAAM,OAAO,eAAe,GAAG,CAAC,MAAM,CAAC;AAIpF,YAAU,MAAM;AACf,QAAI,gBAAgB,YAAY,oCAAoC;AACnE,WAAK,IAAI;AACT;AAAA,IACD;AAEA,QAAI,iBAAiB,CAAC,yBAAyB;AAC9C,WAAK;AACL;AAAA,IACD;AAEA,SAAK;AAAA,EACN,GAAG,CAAC,yBAAyB,aAAa,eAAe,MAAM,IAAI,CAAC;AAGpE,kBAAgB,MAAM;AACrB,UAAM,MAAM,WAAW;AACvB,QAAI,CAAC,IAAK;AACV,QAAI,QAAQ,UAAU,GAAG,SAAS;AAAA,EACnC,GAAG,CAAC,WAAW,QAAQ,CAAC;AAGxB,kBAAgB,MAAM;AACrB,UAAM,MAAM,WAAW;AACvB,QAAI,CAAC,IAAK;AACV,QAAI,MAAM,YAAY,aAAa,aAAa,SAAS,CAAC,OAAO,SAAS,CAAC,KAAK;AAAA,EACjF,GAAG,CAAC,QAAQ,CAAC;AAGb,kBAAgB,MAAM;AACrB,UAAM,MAAM,WAAW;AACvB,QAAI,CAAC,IAAK;AACV,QAAI,QAAQ,cAAc,GAAG,aAAa;AAAA,EAC3C,GAAG,CAAC,aAAa,CAAC;AAElB,SACC;AAAA,IAAC;AAAA;AAAA,MACA,KAAK;AAAA,MACL,oBAAkB;AAAA,MAClB,gBAAc;AAAA,MACd,eAAY;AAAA,MACZ,WAAW,WAAW,2BAA2B,SAAS;AAAA,MAC1D,eAAe;AAAA,MAEf,8BAAC,mBAAgB,aAAY,cAAa,WAAU,aAAY,OAC9D,UACF;AAAA;AAAA,EACD;AAEF;AAIO,SAAS,UAAU,MAAoB;AAC7C,SAAO,IAAI,IAAI,KAAK,GAAG,KAAK,GAAG,KAAK,OAAO,KAAK,MAAM;AACvD;AAEO,SAAS,yBACf,QACA,YACA,oBACC;AACD,QAAM,kBAAkB,mBAAmB,GAAG,MAAM;AACpD,MAAI,CAAC,gBAAiB;AAGtB,QAAM,MAAM,OAAO,wBAAwB;AAC3C,kBAAgB,KAAK,IAAI;AACzB,kBAAgB,KAAK,IAAI;AAGzB,MACC,gBAAgB,OAAO,iBACvB,gBAAgB,OAAO,IAAI,IAAI,iBAC/B,gBAAgB,OAAO,iBACvB,gBAAgB,OAAO,IAAI,IAAI,eAC9B;AACD;AAAA,EACD;AAGA,QAAM,gBAAgB,UAAU,WAAW,sBAAsB,CAAC;AAGlE,MAAI,CAAC,cAAc,SAAS,CAAC,cAAc,OAAQ;AAInD,QAAM,EAAE,YAAY,UAAU,IAAI,OAAO,aAAa;AAQtD,MAAI,IAAI,qBAAqB,gBAAgB,IAAI,gBAAgB,OAAO,cAAc,IAAI;AAC1F,MAAI,IAAI,gBAAgB,IAAI,cAAc,IAAI;AAG9C,MAAI,MAAM,GAAG,eAAe,IAAI,IAAI,cAAc,IAAI,aAAa;AACnE,MAAI,MAAM,GAAG,eAAe,IAAI,IAAI,cAAc,IAAI,aAAa;AAGnE,OAAK;AACL,OAAK;AAGL,MAAI,KAAK,MAAM,CAAC;AAChB,MAAI,KAAK,MAAM,CAAC;AAEhB,SAAO,EAAE,GAAG,EAAE;AACf;AAEA,SAAS,oBAAoB,MAAW,MAAW,wBAAiC;AACnF,MAAI,wBAAwB;AAC3B,WAAO,IAAI,IAAI,MAAM,IAAI,EAAE,KAAK,KAAK;AAAA,EACtC;AACA,SAAO,IAAI,KAAK,IAAI,IAAI,MAAM,IAAI,CAAC,KAAK;AACzC;AAEO,SAAS,iCAAiC,wBAAiC;AACjF,QAAM,SAAS,UAAU;AAEzB,QAAM,SAAS,OAEb,EAAE,MAAM,SAAS,CAAC;AAGpB,QAAM,CAAC,eAAe,gBAAgB,IAAI,SAAS,KAAK;AAGxD,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,KAAK;AAGhD,QAAM,CAAC,UAAU,WAAW,IAAI,SAAS,EAAE,GAAG,MAAO,GAAG,KAAM,CAAC;AAG/D,QAAM,gBAAgB,OAAO,IAAI,IAAI,MAAO,IAAK,CAAC;AAGlD,QAAM,gBAAgB,OAAO,IAAI,IAAI,MAAO,IAAK,CAAC;AAGlD,QAAM,2BAA2B,OAAY,EAAE;AAG/C,QAAM,yBAAyB,OAAY,EAAE;AAO7C,QAAM,OAAO;AAAA,IACZ,CAAC,GAAW,GAAW,YAAY,UAAU;AAE5C,oBAAc,QAAQ,IAAI;AAC1B,oBAAc,QAAQ,IAAI;AAG1B,UAAI,OAAO,QAAQ,SAAS,YAAY,OAAO,QAAQ,SAAS,UAAW;AAK3E,mBAAa,uBAAuB,OAAO;AAE3C,YAAM,YAAY,MAAM;AACvB,YACC,OAAO,QAAQ,SAAS,WACxB,oBAAoB,cAAc,SAAS,cAAc,SAAS,sBAAsB,GACvF;AACD,gBAAM,EAAE,GAAAE,IAAG,GAAAC,GAAE,IAAI,cAAc;AAC/B,wBAAc,UAAU,IAAI,IAAID,IAAGC,EAAC;AACpC,cAAI,WAAW;AACd,sBAAU,MAAM,YAAY,EAAE,GAAAD,IAAG,GAAAC,GAAE,CAAC,CAAC;AAAA,UACtC,OAAO;AACN,wBAAY,EAAE,GAAAD,IAAG,GAAAC,GAAE,CAAC;AAAA,UACrB;AAAA,QACD;AAAA,MACD;AAEA,UAAI,WAAW;AACd,kBAAU;AAAA,MACX,OAAO;AACN,+BAAuB,UAAU,OAAO,OAAO,WAAW,WAAW,YAAY;AAAA,MAClF;AAAA,IACD;AAAA,IACA,CAAC,QAAQ,sBAAsB;AAAA,EAChC;AAOA,QAAM,OAAO;AAAA,IACZ,CAAC,YAAY,UAAU;AACtB,cAAQ,OAAO,QAAQ,MAAM;AAAA,QAC5B,KAAK,WAAW;AACf,uBAAa,yBAAyB,OAAO;AAC7C,iBAAO,UAAU,EAAE,MAAM,SAAS;AAClC;AAAA,QACD;AAAA,QACA,KAAK,SAAS;AACb,iBAAO,UAAU,EAAE,MAAM,SAAS;AAClC,2BAAiB,KAAK;AAEtB,cAAI,WAAW;AACd,mBAAO,UAAU,EAAE,MAAM,SAAS;AAClC,yBAAa,KAAK;AAAA,UACnB,OAAO;AACN,qCAAyB,UAAU,OAAO,OAAO,WAAW,MAAM;AACjE,qBAAO,UAAU,EAAE,MAAM,SAAS;AAClC,2BAAa,KAAK;AAAA,YACnB,GAAG,uBAAuB;AAAA,UAC3B;AACA;AAAA,QACD;AAAA,QACA,SAAS;AAAA,QAET;AAAA,MACD;AAAA,IACD;AAAA,IACA,CAAC,MAAM;AAAA,EACR;AAOA,QAAM,OAAO,YAAY,MAAM;AAC9B,YAAQ,OAAO,QAAQ,MAAM;AAAA,MAC5B,KAAK,UAAU;AACd,eAAO,UAAU,EAAE,MAAM,UAAU;AACnC,iCAAyB,UAAU,OAAO,OAAO,WAAW,MAAM;AAEjE,gBAAM,EAAE,GAAG,EAAE,IAAI,cAAc;AAC/B,wBAAc,UAAU,IAAI,IAAI,GAAG,CAAC;AACpC,sBAAY,EAAE,GAAG,EAAE,CAAC;AAEpB,iBAAO,UAAU,EAAE,MAAM,QAAQ;AACjC,uBAAa,IAAI;AACjB,2BAAiB,IAAI;AAAA,QACtB,GAAG,uBAAuB;AAC1B;AAAA,MACD;AAAA,MACA,KAAK,UAAU;AAEd,qBAAa,yBAAyB,OAAO;AAC7C,eAAO,UAAU,EAAE,MAAM,QAAQ;AACjC,yBAAiB,IAAI;AACrB,aAAK,cAAc,QAAQ,GAAG,cAAc,QAAQ,CAAC;AACrD;AAAA,MACD;AAAA,MACA,SAAS;AAAA,MAET;AAAA,IACD;AAAA,EACD,GAAG,CAAC,QAAQ,IAAI,CAAC;AAEjB,SAAO,EAAE,WAAW,eAAe,MAAM,MAAM,MAAM,SAAS;AAC/D;",
6
6
  "names": ["position", "cameraState", "x", "y"]
7
7
  }
@@ -1,11 +1,12 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
2
  import { useContainer } from "@tldraw/editor";
3
+ import classNames from "classnames";
3
4
  import { Popover as _Popover } from "radix-ui";
4
5
  import React from "react";
5
6
  import { useMenuIsOpen } from "../../hooks/useMenuIsOpen.mjs";
6
- function TldrawUiPopover({ id, children, onOpenChange, open }) {
7
+ function TldrawUiPopover({ id, children, onOpenChange, open, className }) {
7
8
  const [isOpen, handleOpenChange] = useMenuIsOpen(id, onOpenChange);
8
- return /* @__PURE__ */ jsx(_Popover.Root, { onOpenChange: handleOpenChange, open: open || isOpen, children: /* @__PURE__ */ jsx("div", { className: "tlui-popover", children }) });
9
+ return /* @__PURE__ */ jsx(_Popover.Root, { onOpenChange: handleOpenChange, open: open || isOpen, children: /* @__PURE__ */ jsx("div", { className: classNames("tlui-popover", className), children }) });
9
10
  }
10
11
  function TldrawUiPopoverTrigger({ children }) {
11
12
  return /* @__PURE__ */ jsx(_Popover.Trigger, { asChild: true, dir: "ltr", children });
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/lib/ui/components/primitives/TldrawUiPopover.tsx"],
4
- "sourcesContent": ["import { useContainer } from '@tldraw/editor'\nimport { Popover as _Popover } from 'radix-ui'\nimport React from 'react'\nimport { useMenuIsOpen } from '../../hooks/useMenuIsOpen'\n\n/** @public */\nexport interface TLUiPopoverProps {\n\tid: string\n\topen?: boolean\n\tchildren: React.ReactNode\n\tonOpenChange?(isOpen: boolean): void\n}\n\n/** @public @react */\nexport function TldrawUiPopover({ id, children, onOpenChange, open }: TLUiPopoverProps) {\n\tconst [isOpen, handleOpenChange] = useMenuIsOpen(id, onOpenChange)\n\n\treturn (\n\t\t<_Popover.Root onOpenChange={handleOpenChange} open={open || isOpen /* allow debugging */}>\n\t\t\t<div className=\"tlui-popover\">{children}</div>\n\t\t</_Popover.Root>\n\t)\n}\n\n/** @public */\nexport interface TLUiPopoverTriggerProps {\n\tchildren?: React.ReactNode\n}\n\n/** @public @react */\nexport function TldrawUiPopoverTrigger({ children }: TLUiPopoverTriggerProps) {\n\treturn (\n\t\t<_Popover.Trigger asChild dir=\"ltr\">\n\t\t\t{children}\n\t\t</_Popover.Trigger>\n\t)\n}\n\n/** @public */\nexport interface TLUiPopoverContentProps {\n\tchildren: React.ReactNode\n\tside: 'top' | 'bottom' | 'left' | 'right'\n\talign?: 'start' | 'center' | 'end'\n\talignOffset?: number\n\tsideOffset?: number\n\tdisableEscapeKeyDown?: boolean\n\tautoFocusFirstButton?: boolean\n}\n\n/** @public @react */\nexport function TldrawUiPopoverContent({\n\tside,\n\tchildren,\n\talign = 'center',\n\tsideOffset = 8,\n\talignOffset = 0,\n\tdisableEscapeKeyDown = false,\n\tautoFocusFirstButton = true,\n}: TLUiPopoverContentProps) {\n\tconst container = useContainer()\n\tconst ref = React.useRef<HTMLDivElement>(null)\n\n\tconst handleOpenAutoFocus = React.useCallback(() => {\n\t\tif (!autoFocusFirstButton) return\n\t\tconst buttons = (ref.current?.querySelectorAll('button:not([disabled])') ?? []) as HTMLElement[]\n\t\tconst visibleButtons = [...buttons].filter(\n\t\t\t(button) => button.offsetWidth || button.offsetHeight\n\t\t)\n\t\tconst firstButton = visibleButtons[0]\n\t\tif (firstButton) firstButton.focus()\n\t}, [autoFocusFirstButton])\n\n\treturn (\n\t\t<_Popover.Portal container={container}>\n\t\t\t<_Popover.Content\n\t\t\t\tclassName=\"tlui-popover__content\"\n\t\t\t\tside={side}\n\t\t\t\tsideOffset={sideOffset}\n\t\t\t\talign={align}\n\t\t\t\talignOffset={alignOffset}\n\t\t\t\tdir=\"ltr\"\n\t\t\t\tref={ref}\n\t\t\t\tonOpenAutoFocus={handleOpenAutoFocus}\n\t\t\t\tonEscapeKeyDown={(e) => disableEscapeKeyDown && e.preventDefault()}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t\t{/* <StyledArrow /> */}\n\t\t\t</_Popover.Content>\n\t\t</_Popover.Portal>\n\t)\n}\n"],
5
- "mappings": "AAmBG;AAnBH,SAAS,oBAAoB;AAC7B,SAAS,WAAW,gBAAgB;AACpC,OAAO,WAAW;AAClB,SAAS,qBAAqB;AAWvB,SAAS,gBAAgB,EAAE,IAAI,UAAU,cAAc,KAAK,GAAqB;AACvF,QAAM,CAAC,QAAQ,gBAAgB,IAAI,cAAc,IAAI,YAAY;AAEjE,SACC,oBAAC,SAAS,MAAT,EAAc,cAAc,kBAAkB,MAAM,QAAQ,QAC5D,8BAAC,SAAI,WAAU,gBAAgB,UAAS,GACzC;AAEF;AAQO,SAAS,uBAAuB,EAAE,SAAS,GAA4B;AAC7E,SACC,oBAAC,SAAS,SAAT,EAAiB,SAAO,MAAC,KAAI,OAC5B,UACF;AAEF;AAcO,SAAS,uBAAuB;AAAA,EACtC;AAAA,EACA;AAAA,EACA,QAAQ;AAAA,EACR,aAAa;AAAA,EACb,cAAc;AAAA,EACd,uBAAuB;AAAA,EACvB,uBAAuB;AACxB,GAA4B;AAC3B,QAAM,YAAY,aAAa;AAC/B,QAAM,MAAM,MAAM,OAAuB,IAAI;AAE7C,QAAM,sBAAsB,MAAM,YAAY,MAAM;AACnD,QAAI,CAAC,qBAAsB;AAC3B,UAAM,UAAW,IAAI,SAAS,iBAAiB,wBAAwB,KAAK,CAAC;AAC7E,UAAM,iBAAiB,CAAC,GAAG,OAAO,EAAE;AAAA,MACnC,CAAC,WAAW,OAAO,eAAe,OAAO;AAAA,IAC1C;AACA,UAAM,cAAc,eAAe,CAAC;AACpC,QAAI,YAAa,aAAY,MAAM;AAAA,EACpC,GAAG,CAAC,oBAAoB,CAAC;AAEzB,SACC,oBAAC,SAAS,QAAT,EAAgB,WAChB;AAAA,IAAC,SAAS;AAAA,IAAT;AAAA,MACA,WAAU;AAAA,MACV;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,KAAI;AAAA,MACJ;AAAA,MACA,iBAAiB;AAAA,MACjB,iBAAiB,CAAC,MAAM,wBAAwB,EAAE,eAAe;AAAA,MAEhE;AAAA;AAAA,EAEF,GACD;AAEF;",
4
+ "sourcesContent": ["import { useContainer } from '@tldraw/editor'\nimport classNames from 'classnames'\nimport { Popover as _Popover } from 'radix-ui'\nimport React from 'react'\nimport { useMenuIsOpen } from '../../hooks/useMenuIsOpen'\n\n/** @public */\nexport interface TLUiPopoverProps {\n\tid: string\n\topen?: boolean\n\tchildren: React.ReactNode\n\tonOpenChange?(isOpen: boolean): void\n\tclassName?: string\n}\n\n/** @public @react */\nexport function TldrawUiPopover({ id, children, onOpenChange, open, className }: TLUiPopoverProps) {\n\tconst [isOpen, handleOpenChange] = useMenuIsOpen(id, onOpenChange)\n\n\treturn (\n\t\t<_Popover.Root onOpenChange={handleOpenChange} open={open || isOpen /* allow debugging */}>\n\t\t\t<div className={classNames('tlui-popover', className)}>{children}</div>\n\t\t</_Popover.Root>\n\t)\n}\n\n/** @public */\nexport interface TLUiPopoverTriggerProps {\n\tchildren?: React.ReactNode\n}\n\n/** @public @react */\nexport function TldrawUiPopoverTrigger({ children }: TLUiPopoverTriggerProps) {\n\treturn (\n\t\t<_Popover.Trigger asChild dir=\"ltr\">\n\t\t\t{children}\n\t\t</_Popover.Trigger>\n\t)\n}\n\n/** @public */\nexport interface TLUiPopoverContentProps {\n\tchildren: React.ReactNode\n\tside: 'top' | 'bottom' | 'left' | 'right'\n\talign?: 'start' | 'center' | 'end'\n\talignOffset?: number\n\tsideOffset?: number\n\tdisableEscapeKeyDown?: boolean\n\tautoFocusFirstButton?: boolean\n}\n\n/** @public @react */\nexport function TldrawUiPopoverContent({\n\tside,\n\tchildren,\n\talign = 'center',\n\tsideOffset = 8,\n\talignOffset = 0,\n\tdisableEscapeKeyDown = false,\n\tautoFocusFirstButton = true,\n}: TLUiPopoverContentProps) {\n\tconst container = useContainer()\n\tconst ref = React.useRef<HTMLDivElement>(null)\n\n\tconst handleOpenAutoFocus = React.useCallback(() => {\n\t\tif (!autoFocusFirstButton) return\n\t\tconst buttons = (ref.current?.querySelectorAll('button:not([disabled])') ?? []) as HTMLElement[]\n\t\tconst visibleButtons = [...buttons].filter(\n\t\t\t(button) => button.offsetWidth || button.offsetHeight\n\t\t)\n\t\tconst firstButton = visibleButtons[0]\n\t\tif (firstButton) firstButton.focus()\n\t}, [autoFocusFirstButton])\n\n\treturn (\n\t\t<_Popover.Portal container={container}>\n\t\t\t<_Popover.Content\n\t\t\t\tclassName=\"tlui-popover__content\"\n\t\t\t\tside={side}\n\t\t\t\tsideOffset={sideOffset}\n\t\t\t\talign={align}\n\t\t\t\talignOffset={alignOffset}\n\t\t\t\tdir=\"ltr\"\n\t\t\t\tref={ref}\n\t\t\t\tonOpenAutoFocus={handleOpenAutoFocus}\n\t\t\t\tonEscapeKeyDown={(e) => disableEscapeKeyDown && e.preventDefault()}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t\t{/* <StyledArrow /> */}\n\t\t\t</_Popover.Content>\n\t\t</_Popover.Portal>\n\t)\n}\n"],
5
+ "mappings": "AAqBG;AArBH,SAAS,oBAAoB;AAC7B,OAAO,gBAAgB;AACvB,SAAS,WAAW,gBAAgB;AACpC,OAAO,WAAW;AAClB,SAAS,qBAAqB;AAYvB,SAAS,gBAAgB,EAAE,IAAI,UAAU,cAAc,MAAM,UAAU,GAAqB;AAClG,QAAM,CAAC,QAAQ,gBAAgB,IAAI,cAAc,IAAI,YAAY;AAEjE,SACC,oBAAC,SAAS,MAAT,EAAc,cAAc,kBAAkB,MAAM,QAAQ,QAC5D,8BAAC,SAAI,WAAW,WAAW,gBAAgB,SAAS,GAAI,UAAS,GAClE;AAEF;AAQO,SAAS,uBAAuB,EAAE,SAAS,GAA4B;AAC7E,SACC,oBAAC,SAAS,SAAT,EAAiB,SAAO,MAAC,KAAI,OAC5B,UACF;AAEF;AAcO,SAAS,uBAAuB;AAAA,EACtC;AAAA,EACA;AAAA,EACA,QAAQ;AAAA,EACR,aAAa;AAAA,EACb,cAAc;AAAA,EACd,uBAAuB;AAAA,EACvB,uBAAuB;AACxB,GAA4B;AAC3B,QAAM,YAAY,aAAa;AAC/B,QAAM,MAAM,MAAM,OAAuB,IAAI;AAE7C,QAAM,sBAAsB,MAAM,YAAY,MAAM;AACnD,QAAI,CAAC,qBAAsB;AAC3B,UAAM,UAAW,IAAI,SAAS,iBAAiB,wBAAwB,KAAK,CAAC;AAC7E,UAAM,iBAAiB,CAAC,GAAG,OAAO,EAAE;AAAA,MACnC,CAAC,WAAW,OAAO,eAAe,OAAO;AAAA,IAC1C;AACA,UAAM,cAAc,eAAe,CAAC;AACpC,QAAI,YAAa,aAAY,MAAM;AAAA,EACpC,GAAG,CAAC,oBAAoB,CAAC;AAEzB,SACC,oBAAC,SAAS,QAAT,EAAgB,WAChB;AAAA,IAAC,SAAS;AAAA,IAAT;AAAA,MACA,WAAU;AAAA,MACV;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,KAAI;AAAA,MACJ;AAAA,MACA,iBAAiB;AAAA,MACjB,iBAAiB,CAAC,MAAM,wBAAwB,EAAE,eAAe;AAAA,MAEhE;AAAA;AAAA,EAEF,GACD;AAEF;",
6
6
  "names": []
7
7
  }
@@ -2,19 +2,34 @@ import { jsx } from "react/jsx-runtime";
2
2
  import classnames from "classnames";
3
3
  import { Toolbar as _Toolbar } from "radix-ui";
4
4
  import React from "react";
5
+ import { TldrawUiColumn, TldrawUiGrid, TldrawUiRow } from "./layout.mjs";
5
6
  import { TldrawUiTooltip } from "./TldrawUiTooltip.mjs";
7
+ const LayoutByOrientation = {
8
+ horizontal: TldrawUiRow,
9
+ vertical: TldrawUiColumn,
10
+ grid: TldrawUiGrid
11
+ };
6
12
  const TldrawUiToolbar = React.forwardRef(
7
- ({ children, className, label, ...props }, ref) => {
8
- return /* @__PURE__ */ jsx(
13
+ ({
14
+ children,
15
+ className,
16
+ label,
17
+ orientation = "horizontal",
18
+ tooltipSide,
19
+ ...props
20
+ }, ref) => {
21
+ const Layout = LayoutByOrientation[orientation];
22
+ return /* @__PURE__ */ jsx(Layout, { asChild: true, tooltipSide, children: /* @__PURE__ */ jsx(
9
23
  _Toolbar.Root,
10
24
  {
11
25
  ref,
12
26
  ...props,
13
- className: classnames("tlui-toolbar-container", className),
27
+ className: classnames("tlui-toolbar", className),
14
28
  "aria-label": label,
29
+ orientation: orientation === "grid" ? "horizontal" : orientation,
15
30
  children
16
31
  }
17
- );
32
+ ) });
18
33
  }
19
34
  );
20
35
  const TldrawUiToolbarButton = React.forwardRef(
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/lib/ui/components/primitives/TldrawUiToolbar.tsx"],
4
- "sourcesContent": ["import classnames from 'classnames'\nimport { Toolbar as _Toolbar } from 'radix-ui'\nimport React from 'react'\nimport { TldrawUiTooltip } from './TldrawUiTooltip'\n\n/** @public */\nexport interface TLUiToolbarProps extends React.HTMLAttributes<HTMLDivElement> {\n\tchildren?: React.ReactNode\n\tclassName?: string\n\tdir?: 'ltr' | 'rtl'\n\tlabel: string\n}\n\n/** @public @react */\nexport const TldrawUiToolbar = React.forwardRef<HTMLDivElement, TLUiToolbarProps>(\n\t({ children, className, label, ...props }: TLUiToolbarProps, ref) => {\n\t\treturn (\n\t\t\t<_Toolbar.Root\n\t\t\t\tref={ref}\n\t\t\t\t{...props}\n\t\t\t\tclassName={classnames('tlui-toolbar-container', className)}\n\t\t\t\taria-label={label}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</_Toolbar.Root>\n\t\t)\n\t}\n)\n\n/** @public */\nexport interface TLUiToolbarButtonProps extends React.HTMLAttributes<HTMLButtonElement> {\n\tasChild?: boolean\n\tchildren?: React.ReactNode\n\tclassName?: string\n\tdisabled?: boolean\n\tisActive?: boolean\n\ttype: 'icon' | 'tool' | 'menu'\n\ttooltip?: string\n}\n\n/** @public @react */\nexport const TldrawUiToolbarButton = React.forwardRef<HTMLButtonElement, TLUiToolbarButtonProps>(\n\t({ asChild, children, type, isActive, tooltip, ...props }: TLUiToolbarButtonProps, ref) => {\n\t\tconst button = (\n\t\t\t<_Toolbar.Button\n\t\t\t\tref={ref}\n\t\t\t\tasChild={asChild}\n\t\t\t\tdraggable={false}\n\t\t\t\tdata-isactive={isActive}\n\t\t\t\t{...props}\n\t\t\t\t// The tooltip takes care of this.\n\t\t\t\ttitle={undefined}\n\t\t\t\tclassName={classnames('tlui-button', `tlui-button__${type}`, props.className)}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</_Toolbar.Button>\n\t\t)\n\n\t\tconst tooltipContent = tooltip || props.title\n\n\t\treturn <TldrawUiTooltip content={tooltipContent}>{button}</TldrawUiTooltip>\n\t}\n)\n\n/** @public */\nexport interface TLUiToolbarToggleGroupProps extends React.HTMLAttributes<HTMLDivElement> {\n\tchildren?: React.ReactNode\n\tclassName?: string\n\tdir?: 'ltr' | 'rtl'\n\tvalue: any\n\t// TODO: fix up this type later\n\tdefaultValue?: any\n\ttype: 'single' | 'multiple'\n}\n\n/** @public @react */\nexport const TldrawUiToolbarToggleGroup = ({\n\tchildren,\n\tclassName,\n\ttype,\n\t...props\n}: TLUiToolbarToggleGroupProps) => {\n\treturn (\n\t\t<_Toolbar.ToggleGroup\n\t\t\ttype={type}\n\t\t\t{...props}\n\t\t\t// TODO: this fixes a bug in Radix until they fix it.\n\t\t\t// https://github.com/radix-ui/primitives/issues/3188\n\t\t\t// https://github.com/radix-ui/primitives/pull/3189\n\t\t\trole=\"radiogroup\"\n\t\t\tclassName={classnames('tlui-toolbar-toggle-group', className)}\n\t\t>\n\t\t\t{children}\n\t\t</_Toolbar.ToggleGroup>\n\t)\n}\n\n/** @public */\nexport interface TLUiToolbarToggleItemProps extends React.HTMLAttributes<HTMLButtonElement> {\n\tchildren?: React.ReactNode\n\tclassName?: string\n\ttype: 'icon' | 'tool'\n\tvalue: string\n\ttooltip?: string\n}\n\n/** @public @react */\nexport const TldrawUiToolbarToggleItem = ({\n\tchildren,\n\tclassName,\n\ttype,\n\tvalue,\n\ttooltip,\n\t...props\n}: TLUiToolbarToggleItemProps) => {\n\tconst toggleItem = (\n\t\t<_Toolbar.ToggleItem\n\t\t\t{...props}\n\t\t\t// The tooltip takes care of this.\n\t\t\ttitle={undefined}\n\t\t\tclassName={classnames(\n\t\t\t\t'tlui-button',\n\t\t\t\t`tlui-button__${type}`,\n\t\t\t\t'tlui-toolbar-toggle-group-item',\n\t\t\t\tclassName\n\t\t\t)}\n\t\t\tvalue={value}\n\t\t>\n\t\t\t{children}\n\t\t</_Toolbar.ToggleItem>\n\t)\n\n\tconst tooltipContent = tooltip || props.title\n\n\treturn <TldrawUiTooltip content={tooltipContent}>{toggleItem}</TldrawUiTooltip>\n}\n"],
5
- "mappings": "AAiBG;AAjBH,OAAO,gBAAgB;AACvB,SAAS,WAAW,gBAAgB;AACpC,OAAO,WAAW;AAClB,SAAS,uBAAuB;AAWzB,MAAM,kBAAkB,MAAM;AAAA,EACpC,CAAC,EAAE,UAAU,WAAW,OAAO,GAAG,MAAM,GAAqB,QAAQ;AACpE,WACC;AAAA,MAAC,SAAS;AAAA,MAAT;AAAA,QACA;AAAA,QACC,GAAG;AAAA,QACJ,WAAW,WAAW,0BAA0B,SAAS;AAAA,QACzD,cAAY;AAAA,QAEX;AAAA;AAAA,IACF;AAAA,EAEF;AACD;AAcO,MAAM,wBAAwB,MAAM;AAAA,EAC1C,CAAC,EAAE,SAAS,UAAU,MAAM,UAAU,SAAS,GAAG,MAAM,GAA2B,QAAQ;AAC1F,UAAM,SACL;AAAA,MAAC,SAAS;AAAA,MAAT;AAAA,QACA;AAAA,QACA;AAAA,QACA,WAAW;AAAA,QACX,iBAAe;AAAA,QACd,GAAG;AAAA,QAEJ,OAAO;AAAA,QACP,WAAW,WAAW,eAAe,gBAAgB,IAAI,IAAI,MAAM,SAAS;AAAA,QAE3E;AAAA;AAAA,IACF;AAGD,UAAM,iBAAiB,WAAW,MAAM;AAExC,WAAO,oBAAC,mBAAgB,SAAS,gBAAiB,kBAAO;AAAA,EAC1D;AACD;AAcO,MAAM,6BAA6B,CAAC;AAAA,EAC1C;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACJ,MAAmC;AAClC,SACC;AAAA,IAAC,SAAS;AAAA,IAAT;AAAA,MACA;AAAA,MACC,GAAG;AAAA,MAIJ,MAAK;AAAA,MACL,WAAW,WAAW,6BAA6B,SAAS;AAAA,MAE3D;AAAA;AAAA,EACF;AAEF;AAYO,MAAM,4BAA4B,CAAC;AAAA,EACzC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACJ,MAAkC;AACjC,QAAM,aACL;AAAA,IAAC,SAAS;AAAA,IAAT;AAAA,MACC,GAAG;AAAA,MAEJ,OAAO;AAAA,MACP,WAAW;AAAA,QACV;AAAA,QACA,gBAAgB,IAAI;AAAA,QACpB;AAAA,QACA;AAAA,MACD;AAAA,MACA;AAAA,MAEC;AAAA;AAAA,EACF;AAGD,QAAM,iBAAiB,WAAW,MAAM;AAExC,SAAO,oBAAC,mBAAgB,SAAS,gBAAiB,sBAAW;AAC9D;",
4
+ "sourcesContent": ["import classnames from 'classnames'\nimport { Toolbar as _Toolbar } from 'radix-ui'\nimport React from 'react'\nimport { TldrawUiColumn, TldrawUiGrid, TldrawUiRow } from './layout'\nimport { TldrawUiTooltip } from './TldrawUiTooltip'\n\n/** @public */\nexport interface TLUiToolbarProps extends React.HTMLAttributes<HTMLDivElement> {\n\tchildren?: React.ReactNode\n\tclassName?: string\n\tdir?: 'ltr' | 'rtl'\n\tlabel: string\n\torientation?: 'horizontal' | 'vertical' | 'grid'\n\ttooltipSide?: 'top' | 'right' | 'bottom' | 'left'\n}\n\nconst LayoutByOrientation = {\n\thorizontal: TldrawUiRow,\n\tvertical: TldrawUiColumn,\n\tgrid: TldrawUiGrid,\n}\n\n/** @public @react */\nexport const TldrawUiToolbar = React.forwardRef<HTMLDivElement, TLUiToolbarProps>(\n\t(\n\t\t{\n\t\t\tchildren,\n\t\t\tclassName,\n\t\t\tlabel,\n\t\t\torientation = 'horizontal',\n\t\t\ttooltipSide,\n\t\t\t...props\n\t\t}: TLUiToolbarProps,\n\t\tref\n\t) => {\n\t\tconst Layout = LayoutByOrientation[orientation]\n\t\treturn (\n\t\t\t<Layout asChild tooltipSide={tooltipSide}>\n\t\t\t\t<_Toolbar.Root\n\t\t\t\t\tref={ref}\n\t\t\t\t\t{...props}\n\t\t\t\t\tclassName={classnames('tlui-toolbar', className)}\n\t\t\t\t\taria-label={label}\n\t\t\t\t\torientation={orientation === 'grid' ? 'horizontal' : orientation}\n\t\t\t\t>\n\t\t\t\t\t{children}\n\t\t\t\t</_Toolbar.Root>\n\t\t\t</Layout>\n\t\t)\n\t}\n)\n\n/** @public */\nexport interface TLUiToolbarButtonProps extends React.HTMLAttributes<HTMLButtonElement> {\n\tasChild?: boolean\n\tchildren?: React.ReactNode\n\tclassName?: string\n\tdisabled?: boolean\n\tisActive?: boolean\n\ttype: 'icon' | 'tool' | 'menu'\n\ttooltip?: string\n}\n\n/** @public @react */\nexport const TldrawUiToolbarButton = React.forwardRef<HTMLButtonElement, TLUiToolbarButtonProps>(\n\t({ asChild, children, type, isActive, tooltip, ...props }: TLUiToolbarButtonProps, ref) => {\n\t\tconst button = (\n\t\t\t<_Toolbar.Button\n\t\t\t\tref={ref}\n\t\t\t\tasChild={asChild}\n\t\t\t\tdraggable={false}\n\t\t\t\tdata-isactive={isActive}\n\t\t\t\t{...props}\n\t\t\t\t// The tooltip takes care of this.\n\t\t\t\ttitle={undefined}\n\t\t\t\tclassName={classnames('tlui-button', `tlui-button__${type}`, props.className)}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</_Toolbar.Button>\n\t\t)\n\n\t\tconst tooltipContent = tooltip || props.title\n\n\t\treturn <TldrawUiTooltip content={tooltipContent}>{button}</TldrawUiTooltip>\n\t}\n)\n\n/** @public */\nexport interface TLUiToolbarToggleGroupProps extends React.HTMLAttributes<HTMLDivElement> {\n\tchildren?: React.ReactNode\n\tclassName?: string\n\tdir?: 'ltr' | 'rtl'\n\tvalue: any\n\t// TODO: fix up this type later\n\tdefaultValue?: any\n\ttype: 'single' | 'multiple'\n}\n\n/** @public @react */\nexport const TldrawUiToolbarToggleGroup = ({\n\tchildren,\n\tclassName,\n\ttype,\n\t...props\n}: TLUiToolbarToggleGroupProps) => {\n\treturn (\n\t\t<_Toolbar.ToggleGroup\n\t\t\ttype={type}\n\t\t\t{...props}\n\t\t\t// TODO: this fixes a bug in Radix until they fix it.\n\t\t\t// https://github.com/radix-ui/primitives/issues/3188\n\t\t\t// https://github.com/radix-ui/primitives/pull/3189\n\t\t\trole=\"radiogroup\"\n\t\t\tclassName={classnames('tlui-toolbar-toggle-group', className)}\n\t\t>\n\t\t\t{children}\n\t\t</_Toolbar.ToggleGroup>\n\t)\n}\n\n/** @public */\nexport interface TLUiToolbarToggleItemProps extends React.HTMLAttributes<HTMLButtonElement> {\n\tchildren?: React.ReactNode\n\tclassName?: string\n\ttype: 'icon' | 'tool'\n\tvalue: string\n\ttooltip?: string\n}\n\n/** @public @react */\nexport const TldrawUiToolbarToggleItem = ({\n\tchildren,\n\tclassName,\n\ttype,\n\tvalue,\n\ttooltip,\n\t...props\n}: TLUiToolbarToggleItemProps) => {\n\tconst toggleItem = (\n\t\t<_Toolbar.ToggleItem\n\t\t\t{...props}\n\t\t\t// The tooltip takes care of this.\n\t\t\ttitle={undefined}\n\t\t\tclassName={classnames(\n\t\t\t\t'tlui-button',\n\t\t\t\t`tlui-button__${type}`,\n\t\t\t\t'tlui-toolbar-toggle-group-item',\n\t\t\t\tclassName\n\t\t\t)}\n\t\t\tvalue={value}\n\t\t>\n\t\t\t{children}\n\t\t</_Toolbar.ToggleItem>\n\t)\n\n\tconst tooltipContent = tooltip || props.title\n\n\treturn <TldrawUiTooltip content={tooltipContent}>{toggleItem}</TldrawUiTooltip>\n}\n"],
5
+ "mappings": "AAsCI;AAtCJ,OAAO,gBAAgB;AACvB,SAAS,WAAW,gBAAgB;AACpC,OAAO,WAAW;AAClB,SAAS,gBAAgB,cAAc,mBAAmB;AAC1D,SAAS,uBAAuB;AAYhC,MAAM,sBAAsB;AAAA,EAC3B,YAAY;AAAA,EACZ,UAAU;AAAA,EACV,MAAM;AACP;AAGO,MAAM,kBAAkB,MAAM;AAAA,EACpC,CACC;AAAA,IACC;AAAA,IACA;AAAA,IACA;AAAA,IACA,cAAc;AAAA,IACd;AAAA,IACA,GAAG;AAAA,EACJ,GACA,QACI;AACJ,UAAM,SAAS,oBAAoB,WAAW;AAC9C,WACC,oBAAC,UAAO,SAAO,MAAC,aACf;AAAA,MAAC,SAAS;AAAA,MAAT;AAAA,QACA;AAAA,QACC,GAAG;AAAA,QACJ,WAAW,WAAW,gBAAgB,SAAS;AAAA,QAC/C,cAAY;AAAA,QACZ,aAAa,gBAAgB,SAAS,eAAe;AAAA,QAEpD;AAAA;AAAA,IACF,GACD;AAAA,EAEF;AACD;AAcO,MAAM,wBAAwB,MAAM;AAAA,EAC1C,CAAC,EAAE,SAAS,UAAU,MAAM,UAAU,SAAS,GAAG,MAAM,GAA2B,QAAQ;AAC1F,UAAM,SACL;AAAA,MAAC,SAAS;AAAA,MAAT;AAAA,QACA;AAAA,QACA;AAAA,QACA,WAAW;AAAA,QACX,iBAAe;AAAA,QACd,GAAG;AAAA,QAEJ,OAAO;AAAA,QACP,WAAW,WAAW,eAAe,gBAAgB,IAAI,IAAI,MAAM,SAAS;AAAA,QAE3E;AAAA;AAAA,IACF;AAGD,UAAM,iBAAiB,WAAW,MAAM;AAExC,WAAO,oBAAC,mBAAgB,SAAS,gBAAiB,kBAAO;AAAA,EAC1D;AACD;AAcO,MAAM,6BAA6B,CAAC;AAAA,EAC1C;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACJ,MAAmC;AAClC,SACC;AAAA,IAAC,SAAS;AAAA,IAAT;AAAA,MACA;AAAA,MACC,GAAG;AAAA,MAIJ,MAAK;AAAA,MACL,WAAW,WAAW,6BAA6B,SAAS;AAAA,MAE3D;AAAA;AAAA,EACF;AAEF;AAYO,MAAM,4BAA4B,CAAC;AAAA,EACzC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACJ,MAAkC;AACjC,QAAM,aACL;AAAA,IAAC,SAAS;AAAA,IAAT;AAAA,MACC,GAAG;AAAA,MAEJ,OAAO;AAAA,MACP,WAAW;AAAA,QACV;AAAA,QACA,gBAAgB,IAAI;AAAA,QACpB;AAAA,QACA;AAAA,MACD;AAAA,MACA;AAAA,MAEC;AAAA;AAAA,EACF;AAGD,QAAM,iBAAiB,WAAW,MAAM;AAExC,SAAO,oBAAC,mBAAgB,SAAS,gBAAiB,sBAAW;AAC9D;",
6
6
  "names": []
7
7
  }
@@ -1,68 +1,75 @@
1
1
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
- import { uniqueId, useMaybeEditor, Vec } from "@tldraw/editor";
2
+ import { assert, atom, uniqueId, useMaybeEditor, useValue } from "@tldraw/editor";
3
3
  import { Tooltip as _Tooltip } from "radix-ui";
4
- import React, { createContext, useContext, useEffect, useRef, useState } from "react";
5
- import { usePrefersReducedMotion } from "../../../shapes/shared/usePrefersReducedMotion.mjs";
4
+ import React, {
5
+ createContext,
6
+ forwardRef,
7
+ useContext,
8
+ useEffect,
9
+ useRef,
10
+ useState
11
+ } from "react";
12
+ import { useTldrawUiOrientation } from "./layout.mjs";
6
13
  const DEFAULT_TOOLTIP_DELAY_MS = 700;
7
14
  class TooltipManager {
8
15
  static instance = null;
9
- currentTooltipId = null;
10
- currentContent = "";
11
- currentSide = "bottom";
12
- currentSideOffset = 5;
16
+ currentTooltip = atom("current tooltip", null);
13
17
  destroyTimeoutId = null;
14
- subscribers = /* @__PURE__ */ new Set();
15
- activeElement = null;
16
- editor = null;
17
18
  static getInstance() {
18
19
  if (!TooltipManager.instance) {
19
20
  TooltipManager.instance = new TooltipManager();
20
21
  }
21
22
  return TooltipManager.instance;
22
23
  }
23
- setEditor(editor) {
24
- this.editor = editor;
25
- }
26
- subscribe(callback) {
27
- this.subscribers.add(callback);
28
- return () => this.subscribers.delete(callback);
29
- }
30
- notify() {
31
- this.subscribers.forEach((callback) => callback());
32
- }
33
- showTooltip(tooltipId, content, element, side = "bottom", sideOffset = 5) {
24
+ showTooltip(tooltipId, content, targetElement, side, sideOffset, showOnMobile, delayDuration) {
34
25
  if (this.destroyTimeoutId) {
35
26
  clearTimeout(this.destroyTimeoutId);
36
27
  this.destroyTimeoutId = null;
37
28
  }
38
- this.currentTooltipId = tooltipId;
39
- this.currentContent = content;
40
- this.currentSide = side;
41
- this.currentSideOffset = sideOffset;
42
- this.activeElement = element;
43
- this.notify();
29
+ this.currentTooltip.set({
30
+ id: tooltipId,
31
+ content,
32
+ side,
33
+ sideOffset,
34
+ showOnMobile,
35
+ targetElement,
36
+ delayDuration
37
+ });
44
38
  }
45
- hideTooltip(tooltipId) {
46
- if (this.currentTooltipId === tooltipId) {
47
- if (this.editor) {
48
- this.destroyTimeoutId = this.editor.timers.setTimeout(() => {
49
- this.currentTooltipId = null;
50
- this.currentContent = "";
51
- this.activeElement = null;
52
- this.destroyTimeoutId = null;
53
- this.notify();
54
- }, 300);
39
+ hideTooltip(editor, tooltipId, instant = false) {
40
+ const hide = () => {
41
+ if (this.currentTooltip.get()?.id === tooltipId) {
42
+ this.currentTooltip.set(null);
43
+ this.destroyTimeoutId = null;
55
44
  }
45
+ };
46
+ if (editor && !instant) {
47
+ this.destroyTimeoutId = editor.timers.setTimeout(hide, 300);
48
+ } else {
49
+ hide();
56
50
  }
57
51
  }
52
+ hideAllTooltips() {
53
+ this.currentTooltip.set(null);
54
+ this.destroyTimeoutId = null;
55
+ }
58
56
  getCurrentTooltipData() {
59
- return {
60
- id: this.currentTooltipId,
61
- content: this.currentContent,
62
- side: this.currentSide,
63
- sideOffset: this.currentSideOffset,
64
- element: this.activeElement
65
- };
57
+ const currentTooltip = this.currentTooltip.get();
58
+ if (!currentTooltip) return null;
59
+ if (!this.supportsHover() && !currentTooltip.showOnMobile) return null;
60
+ return currentTooltip;
61
+ }
62
+ supportsHoverAtom = null;
63
+ supportsHover() {
64
+ if (!this.supportsHoverAtom) {
65
+ const mediaQuery = window.matchMedia("(hover: hover)");
66
+ const supportsHover = atom("has hover", mediaQuery.matches);
67
+ this.supportsHoverAtom = supportsHover;
68
+ mediaQuery.addEventListener("change", (e) => {
69
+ supportsHover.set(e.matches);
70
+ });
71
+ }
72
+ return this.supportsHoverAtom.get();
66
73
  }
67
74
  }
68
75
  const tooltipManager = TooltipManager.getInstance();
@@ -75,44 +82,23 @@ function TldrawUiTooltipProvider({ children }) {
75
82
  }
76
83
  function TooltipSingleton() {
77
84
  const editor = useMaybeEditor();
78
- const [, forceUpdate] = useState({});
79
85
  const [isOpen, setIsOpen] = useState(false);
80
86
  const triggerRef = useRef(null);
81
- const previousPositionRef = useRef(null);
82
- const prefersReducedMotion = usePrefersReducedMotion();
83
- const [shouldAnimate, setShouldAnimate] = useState(false);
84
87
  const isFirstShowRef = useRef(true);
85
88
  const showTimeoutRef = useRef(null);
89
+ const currentTooltip = useValue(
90
+ "current tooltip",
91
+ () => tooltipManager.getCurrentTooltipData(),
92
+ []
93
+ );
86
94
  useEffect(() => {
87
- tooltipManager.setEditor(editor);
88
- }, [editor]);
89
- useEffect(() => {
90
- const unsubscribe = tooltipManager.subscribe(() => {
91
- forceUpdate({});
92
- });
93
- return unsubscribe;
94
- }, []);
95
- const tooltipData = tooltipManager.getCurrentTooltipData();
96
- useEffect(() => {
97
- const shouldBeOpen = Boolean(tooltipData.id && tooltipData.element);
98
95
  if (showTimeoutRef.current) {
99
96
  clearTimeout(showTimeoutRef.current);
100
97
  showTimeoutRef.current = null;
101
98
  }
102
- if (shouldBeOpen && tooltipData.element && triggerRef.current) {
103
- const activeRect = tooltipData.element.getBoundingClientRect();
99
+ if (currentTooltip && triggerRef.current) {
100
+ const activeRect = currentTooltip.targetElement.getBoundingClientRect();
104
101
  const trigger = triggerRef.current;
105
- const newPosition = {
106
- x: activeRect.left + activeRect.width / 2,
107
- y: activeRect.top + activeRect.height / 2
108
- };
109
- let shouldAnimateCheck = false;
110
- if (previousPositionRef.current) {
111
- const isNearPrevious = Vec.DistMin(previousPositionRef.current, newPosition, 200);
112
- shouldAnimateCheck = !prefersReducedMotion && isNearPrevious && Math.abs(newPosition.y - previousPositionRef.current.y) < 50;
113
- }
114
- setShouldAnimate(isFirstShowRef.current ? false : shouldAnimateCheck);
115
- previousPositionRef.current = newPosition;
116
102
  trigger.style.position = "fixed";
117
103
  trigger.style.left = `${activeRect.left}px`;
118
104
  trigger.style.top = `${activeRect.top}px`;
@@ -124,18 +110,16 @@ function TooltipSingleton() {
124
110
  showTimeoutRef.current = editor.timers.setTimeout(() => {
125
111
  setIsOpen(true);
126
112
  isFirstShowRef.current = false;
127
- }, editor.options.tooltipDelayMs);
113
+ }, currentTooltip.delayDuration ?? editor.options.tooltipDelayMs);
128
114
  } else {
129
115
  setIsOpen(true);
130
116
  }
131
- } else if (!shouldBeOpen) {
117
+ } else {
132
118
  setIsOpen(false);
133
- previousPositionRef.current = null;
134
- setShouldAnimate(false);
135
119
  isFirstShowRef.current = true;
136
120
  }
137
- }, [tooltipData.id, tooltipData.element, editor, prefersReducedMotion]);
138
- if (!tooltipData.id) {
121
+ }, [editor, currentTooltip]);
122
+ if (!currentTooltip) {
139
123
  return null;
140
124
  }
141
125
  return /* @__PURE__ */ jsxs(_Tooltip.Root, { open: isOpen, delayDuration: 0, children: [
@@ -144,94 +128,118 @@ function TooltipSingleton() {
144
128
  _Tooltip.Content,
145
129
  {
146
130
  className: "tlui-tooltip",
147
- "data-should-animate": shouldAnimate,
148
- side: tooltipData.side,
149
- sideOffset: tooltipData.sideOffset,
131
+ side: currentTooltip.side,
132
+ sideOffset: currentTooltip.sideOffset,
150
133
  avoidCollisions: true,
151
134
  collisionPadding: 8,
152
135
  dir: "ltr",
153
136
  children: [
154
- tooltipData.content,
137
+ currentTooltip.content,
155
138
  /* @__PURE__ */ jsx(_Tooltip.Arrow, { className: "tlui-tooltip__arrow" })
156
139
  ]
157
140
  }
158
141
  )
159
142
  ] });
160
143
  }
161
- function TldrawUiTooltip({
162
- children,
163
- content,
164
- side = "bottom",
165
- sideOffset = 5,
166
- disabled = false
167
- }) {
168
- const editor = useMaybeEditor();
169
- const tooltipId = useRef(uniqueId());
170
- const hasProvider = useContext(TooltipSingletonContext);
171
- if (disabled || !content) {
172
- return /* @__PURE__ */ jsx(Fragment, { children });
173
- }
174
- if (!hasProvider) {
175
- return /* @__PURE__ */ jsxs(
176
- _Tooltip.Root,
177
- {
178
- delayDuration: editor?.options.tooltipDelayMs || DEFAULT_TOOLTIP_DELAY_MS,
179
- disableHoverableContent: true,
180
- children: [
181
- /* @__PURE__ */ jsx(_Tooltip.Trigger, { asChild: true, children }),
182
- /* @__PURE__ */ jsxs(
183
- _Tooltip.Content,
184
- {
185
- className: "tlui-tooltip",
186
- side,
187
- sideOffset,
188
- avoidCollisions: true,
189
- collisionPadding: 8,
190
- dir: "ltr",
191
- children: [
192
- content,
193
- /* @__PURE__ */ jsx(_Tooltip.Arrow, { className: "tlui-tooltip__arrow" })
194
- ]
195
- }
196
- )
197
- ]
198
- }
199
- );
144
+ const TldrawUiTooltip = forwardRef(
145
+ ({
146
+ children,
147
+ content,
148
+ side,
149
+ sideOffset = 5,
150
+ disabled = false,
151
+ showOnMobile = false,
152
+ delayDuration
153
+ }, ref) => {
154
+ const editor = useMaybeEditor();
155
+ const tooltipId = useRef(uniqueId());
156
+ const hasProvider = useContext(TooltipSingletonContext);
157
+ const orientationCtx = useTldrawUiOrientation();
158
+ const sideToUse = side ?? orientationCtx.tooltipSide;
159
+ useEffect(() => {
160
+ const currentTooltipId = tooltipId.current;
161
+ return () => {
162
+ if (hasProvider) {
163
+ tooltipManager.hideTooltip(editor, currentTooltipId, true);
164
+ }
165
+ };
166
+ }, [editor, hasProvider]);
167
+ if (disabled || !content) {
168
+ return /* @__PURE__ */ jsx(Fragment, { children });
169
+ }
170
+ if (!hasProvider) {
171
+ return /* @__PURE__ */ jsxs(
172
+ _Tooltip.Root,
173
+ {
174
+ delayDuration: delayDuration ?? (editor?.options.tooltipDelayMs || DEFAULT_TOOLTIP_DELAY_MS),
175
+ disableHoverableContent: true,
176
+ children: [
177
+ /* @__PURE__ */ jsx(_Tooltip.Trigger, { asChild: true, ref, children }),
178
+ /* @__PURE__ */ jsxs(
179
+ _Tooltip.Content,
180
+ {
181
+ className: "tlui-tooltip",
182
+ side: sideToUse,
183
+ sideOffset,
184
+ avoidCollisions: true,
185
+ collisionPadding: 8,
186
+ dir: "ltr",
187
+ children: [
188
+ content,
189
+ /* @__PURE__ */ jsx(_Tooltip.Arrow, { className: "tlui-tooltip__arrow" })
190
+ ]
191
+ }
192
+ )
193
+ ]
194
+ }
195
+ );
196
+ }
197
+ const child = React.Children.only(children);
198
+ assert(React.isValidElement(child), "TldrawUiTooltip children must be a single element");
199
+ const handleMouseEnter = (event) => {
200
+ child.props.onMouseEnter?.(event);
201
+ tooltipManager.showTooltip(
202
+ tooltipId.current,
203
+ content,
204
+ event.currentTarget,
205
+ sideToUse,
206
+ sideOffset,
207
+ showOnMobile,
208
+ delayDuration
209
+ );
210
+ };
211
+ const handleMouseLeave = (event) => {
212
+ child.props.onMouseLeave?.(event);
213
+ tooltipManager.hideTooltip(editor, tooltipId.current);
214
+ };
215
+ const handleFocus = (event) => {
216
+ child.props.onFocus?.(event);
217
+ tooltipManager.showTooltip(
218
+ tooltipId.current,
219
+ content,
220
+ event.currentTarget,
221
+ sideToUse,
222
+ sideOffset,
223
+ showOnMobile,
224
+ delayDuration
225
+ );
226
+ };
227
+ const handleBlur = (event) => {
228
+ child.props.onBlur?.(event);
229
+ tooltipManager.hideTooltip(editor, tooltipId.current);
230
+ };
231
+ const childrenWithHandlers = React.cloneElement(children, {
232
+ onMouseEnter: handleMouseEnter,
233
+ onMouseLeave: handleMouseLeave,
234
+ onFocus: handleFocus,
235
+ onBlur: handleBlur
236
+ });
237
+ return childrenWithHandlers;
200
238
  }
201
- const handleMouseEnter = (event) => {
202
- tooltipManager.showTooltip(
203
- tooltipId.current,
204
- content,
205
- event.currentTarget,
206
- side,
207
- sideOffset
208
- );
209
- };
210
- const handleMouseLeave = () => {
211
- tooltipManager.hideTooltip(tooltipId.current);
212
- };
213
- const handleFocus = (event) => {
214
- tooltipManager.showTooltip(
215
- tooltipId.current,
216
- content,
217
- event.currentTarget,
218
- side,
219
- sideOffset
220
- );
221
- };
222
- const handleBlur = () => {
223
- tooltipManager.hideTooltip(tooltipId.current);
224
- };
225
- const childrenWithHandlers = React.cloneElement(children, {
226
- onMouseEnter: handleMouseEnter,
227
- onMouseLeave: handleMouseLeave,
228
- onFocus: handleFocus,
229
- onBlur: handleBlur
230
- });
231
- return childrenWithHandlers;
232
- }
239
+ );
233
240
  export {
234
241
  TldrawUiTooltip,
235
- TldrawUiTooltipProvider
242
+ TldrawUiTooltipProvider,
243
+ tooltipManager
236
244
  };
237
245
  //# sourceMappingURL=TldrawUiTooltip.mjs.map