tldraw 3.16.0-next.fe14f1b4181f → 4.0.0

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 (299) hide show
  1. package/dist-cjs/index.d.ts +232 -114
  2. package/dist-cjs/index.js +30 -15
  3. package/dist-cjs/index.js.map +2 -2
  4. package/dist-cjs/lib/defaultExternalContentHandlers.js +10 -0
  5. package/dist-cjs/lib/defaultExternalContentHandlers.js.map +2 -2
  6. package/dist-cjs/lib/shapes/arrow/arrow-types.js.map +1 -1
  7. package/dist-cjs/lib/shapes/arrow/arrowLabel.js +6 -0
  8. package/dist-cjs/lib/shapes/arrow/arrowLabel.js.map +3 -3
  9. package/dist-cjs/lib/shapes/arrow/arrowTargetState.js +3 -2
  10. package/dist-cjs/lib/shapes/arrow/arrowTargetState.js.map +2 -2
  11. package/dist-cjs/lib/shapes/arrow/toolStates/Pointing.js +1 -1
  12. package/dist-cjs/lib/shapes/arrow/toolStates/Pointing.js.map +2 -2
  13. package/dist-cjs/lib/shapes/bookmark/BookmarkShapeUtil.js +4 -4
  14. package/dist-cjs/lib/shapes/bookmark/BookmarkShapeUtil.js.map +2 -2
  15. package/dist-cjs/lib/shapes/frame/FrameShapeUtil.js +5 -1
  16. package/dist-cjs/lib/shapes/frame/FrameShapeUtil.js.map +2 -2
  17. package/dist-cjs/lib/shapes/frame/components/FrameLabelInput.js +8 -2
  18. package/dist-cjs/lib/shapes/frame/components/FrameLabelInput.js.map +2 -2
  19. package/dist-cjs/lib/shapes/geo/GeoShapeUtil.js +1 -0
  20. package/dist-cjs/lib/shapes/geo/GeoShapeUtil.js.map +2 -2
  21. package/dist-cjs/lib/shapes/note/NoteShapeUtil.js +2 -1
  22. package/dist-cjs/lib/shapes/note/NoteShapeUtil.js.map +2 -2
  23. package/dist-cjs/lib/shapes/shared/HyperlinkButton.js +4 -4
  24. package/dist-cjs/lib/shapes/shared/HyperlinkButton.js.map +2 -2
  25. package/dist-cjs/lib/shapes/shared/PlainTextLabel.js +1 -3
  26. package/dist-cjs/lib/shapes/shared/PlainTextLabel.js.map +2 -2
  27. package/dist-cjs/lib/shapes/shared/useEditablePlainText.js +3 -5
  28. package/dist-cjs/lib/shapes/shared/useEditablePlainText.js.map +2 -2
  29. package/dist-cjs/lib/shapes/shared/useImageOrVideoAsset.js +0 -2
  30. package/dist-cjs/lib/shapes/shared/useImageOrVideoAsset.js.map +2 -2
  31. package/dist-cjs/lib/shapes/text/PlainTextArea.js +3 -2
  32. package/dist-cjs/lib/shapes/text/PlainTextArea.js.map +2 -2
  33. package/dist-cjs/lib/shapes/text/RichTextArea.js +3 -3
  34. package/dist-cjs/lib/shapes/text/RichTextArea.js.map +2 -2
  35. package/dist-cjs/lib/tools/SelectTool/childStates/DraggingHandle.js +3 -1
  36. package/dist-cjs/lib/tools/SelectTool/childStates/DraggingHandle.js.map +2 -2
  37. package/dist-cjs/lib/ui/components/A11y.js +1 -1
  38. package/dist-cjs/lib/ui/components/A11y.js.map +2 -2
  39. package/dist-cjs/lib/ui/components/AccessibilityMenu.js +1 -1
  40. package/dist-cjs/lib/ui/components/AccessibilityMenu.js.map +2 -2
  41. package/dist-cjs/lib/ui/components/InputModeMenu.js +77 -0
  42. package/dist-cjs/lib/ui/components/InputModeMenu.js.map +7 -0
  43. package/dist-cjs/lib/ui/components/LanguageMenu.js +1 -0
  44. package/dist-cjs/lib/ui/components/LanguageMenu.js.map +2 -2
  45. package/dist-cjs/lib/ui/components/MainMenu/DefaultMainMenuContent.js +2 -0
  46. package/dist-cjs/lib/ui/components/MainMenu/DefaultMainMenuContent.js.map +2 -2
  47. package/dist-cjs/lib/ui/components/Minimap/DefaultMinimap.js +2 -1
  48. package/dist-cjs/lib/ui/components/Minimap/DefaultMinimap.js.map +2 -2
  49. package/dist-cjs/lib/ui/components/PageMenu/DefaultPageMenu.js +1 -1
  50. package/dist-cjs/lib/ui/components/PageMenu/DefaultPageMenu.js.map +2 -2
  51. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanel.js +13 -6
  52. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanel.js.map +2 -2
  53. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanelContent.js +255 -316
  54. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanelContent.js.map +2 -2
  55. package/dist-cjs/lib/ui/components/StylePanel/StylePanelButtonPicker.js +147 -0
  56. package/dist-cjs/lib/ui/components/StylePanel/StylePanelButtonPicker.js.map +7 -0
  57. package/dist-cjs/lib/ui/components/StylePanel/StylePanelContext.js +70 -0
  58. package/dist-cjs/lib/ui/components/StylePanel/StylePanelContext.js.map +7 -0
  59. package/dist-cjs/lib/ui/components/StylePanel/{DoubleDropdownPicker.js → StylePanelDoubleDropdownPicker.js} +23 -22
  60. package/dist-cjs/lib/ui/components/StylePanel/StylePanelDoubleDropdownPicker.js.map +7 -0
  61. package/dist-cjs/lib/ui/components/StylePanel/{DropdownPicker.js → StylePanelDropdownPicker.js} +23 -20
  62. package/dist-cjs/lib/ui/components/StylePanel/StylePanelDropdownPicker.js.map +7 -0
  63. package/dist-cjs/lib/ui/components/StylePanel/StylePanelSubheading.js +28 -0
  64. package/dist-cjs/lib/ui/components/StylePanel/StylePanelSubheading.js.map +7 -0
  65. package/dist-cjs/lib/ui/components/Toolbar/AltTextEditor.js +2 -0
  66. package/dist-cjs/lib/ui/components/Toolbar/AltTextEditor.js.map +2 -2
  67. package/dist-cjs/lib/ui/components/Toolbar/DefaultImageToolbarContent.js +38 -9
  68. package/dist-cjs/lib/ui/components/Toolbar/DefaultImageToolbarContent.js.map +2 -2
  69. package/dist-cjs/lib/ui/components/Toolbar/DefaultVideoToolbarContent.js +15 -3
  70. package/dist-cjs/lib/ui/components/Toolbar/DefaultVideoToolbarContent.js.map +2 -2
  71. package/dist-cjs/lib/ui/components/Toolbar/LinkEditor.js +2 -1
  72. package/dist-cjs/lib/ui/components/Toolbar/LinkEditor.js.map +2 -2
  73. package/dist-cjs/lib/ui/components/Toolbar/OverflowingToolbar.js +1 -1
  74. package/dist-cjs/lib/ui/components/Toolbar/OverflowingToolbar.js.map +2 -2
  75. package/dist-cjs/lib/ui/components/Toolbar/ToggleToolLockedButton.js +6 -2
  76. package/dist-cjs/lib/ui/components/Toolbar/ToggleToolLockedButton.js.map +2 -2
  77. package/dist-cjs/lib/ui/components/menu-items.js +6 -4
  78. package/dist-cjs/lib/ui/components/menu-items.js.map +2 -2
  79. package/dist-cjs/lib/ui/components/primitives/TldrawUiContextualToolbar.js +11 -2
  80. package/dist-cjs/lib/ui/components/primitives/TldrawUiContextualToolbar.js.map +2 -2
  81. package/dist-cjs/lib/ui/components/primitives/TldrawUiInput.js +5 -3
  82. package/dist-cjs/lib/ui/components/primitives/TldrawUiInput.js.map +2 -2
  83. package/dist-cjs/lib/ui/components/primitives/TldrawUiSlider.js +13 -2
  84. package/dist-cjs/lib/ui/components/primitives/TldrawUiSlider.js.map +2 -2
  85. package/dist-cjs/lib/ui/components/primitives/TldrawUiToolbar.js +3 -0
  86. package/dist-cjs/lib/ui/components/primitives/TldrawUiToolbar.js.map +2 -2
  87. package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js +75 -20
  88. package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js.map +2 -2
  89. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.js +3 -0
  90. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.js.map +2 -2
  91. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js +8 -8
  92. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js.map +2 -2
  93. package/dist-cjs/lib/ui/context/actions.js +18 -33
  94. package/dist-cjs/lib/ui/context/actions.js.map +2 -2
  95. package/dist-cjs/lib/ui/context/events.js.map +2 -2
  96. package/dist-cjs/lib/ui/hooks/useClipboardEvents.js +1 -1
  97. package/dist-cjs/lib/ui/hooks/useClipboardEvents.js.map +2 -2
  98. package/dist-cjs/lib/ui/hooks/useExportAs.js +3 -2
  99. package/dist-cjs/lib/ui/hooks/useExportAs.js.map +2 -2
  100. package/dist-cjs/lib/ui/hooks/useTools.js +1 -1
  101. package/dist-cjs/lib/ui/hooks/useTools.js.map +2 -2
  102. package/dist-cjs/lib/ui/hooks/useTranslation/TLUiTranslationKey.js.map +1 -1
  103. package/dist-cjs/lib/ui/hooks/useTranslation/defaultTranslation.js +12 -3
  104. package/dist-cjs/lib/ui/hooks/useTranslation/defaultTranslation.js.map +2 -2
  105. package/dist-cjs/lib/ui/version.js +4 -4
  106. package/dist-cjs/lib/ui/version.js.map +1 -1
  107. package/dist-cjs/lib/utils/export/copyAs.js +1 -2
  108. package/dist-cjs/lib/utils/export/copyAs.js.map +2 -2
  109. package/dist-cjs/lib/utils/export/export.js +0 -20
  110. package/dist-cjs/lib/utils/export/export.js.map +2 -2
  111. package/dist-cjs/lib/utils/export/exportAs.js +1 -2
  112. package/dist-cjs/lib/utils/export/exportAs.js.map +2 -2
  113. package/dist-esm/index.d.mts +232 -114
  114. package/dist-esm/index.mjs +61 -30
  115. package/dist-esm/index.mjs.map +2 -2
  116. package/dist-esm/lib/defaultExternalContentHandlers.mjs +10 -0
  117. package/dist-esm/lib/defaultExternalContentHandlers.mjs.map +2 -2
  118. package/dist-esm/lib/shapes/arrow/arrowLabel.mjs +6 -0
  119. package/dist-esm/lib/shapes/arrow/arrowLabel.mjs.map +3 -3
  120. package/dist-esm/lib/shapes/arrow/arrowTargetState.mjs +3 -2
  121. package/dist-esm/lib/shapes/arrow/arrowTargetState.mjs.map +2 -2
  122. package/dist-esm/lib/shapes/arrow/toolStates/Pointing.mjs +1 -1
  123. package/dist-esm/lib/shapes/arrow/toolStates/Pointing.mjs.map +2 -2
  124. package/dist-esm/lib/shapes/bookmark/BookmarkShapeUtil.mjs +4 -5
  125. package/dist-esm/lib/shapes/bookmark/BookmarkShapeUtil.mjs.map +2 -2
  126. package/dist-esm/lib/shapes/frame/FrameShapeUtil.mjs +5 -1
  127. package/dist-esm/lib/shapes/frame/FrameShapeUtil.mjs.map +2 -2
  128. package/dist-esm/lib/shapes/frame/components/FrameLabelInput.mjs +9 -3
  129. package/dist-esm/lib/shapes/frame/components/FrameLabelInput.mjs.map +2 -2
  130. package/dist-esm/lib/shapes/geo/GeoShapeUtil.mjs +1 -0
  131. package/dist-esm/lib/shapes/geo/GeoShapeUtil.mjs.map +2 -2
  132. package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs +2 -1
  133. package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs.map +2 -2
  134. package/dist-esm/lib/shapes/shared/HyperlinkButton.mjs +5 -5
  135. package/dist-esm/lib/shapes/shared/HyperlinkButton.mjs.map +2 -2
  136. package/dist-esm/lib/shapes/shared/PlainTextLabel.mjs +1 -3
  137. package/dist-esm/lib/shapes/shared/PlainTextLabel.mjs.map +2 -2
  138. package/dist-esm/lib/shapes/shared/useEditablePlainText.mjs +3 -6
  139. package/dist-esm/lib/shapes/shared/useEditablePlainText.mjs.map +2 -2
  140. package/dist-esm/lib/shapes/shared/useImageOrVideoAsset.mjs +0 -2
  141. package/dist-esm/lib/shapes/shared/useImageOrVideoAsset.mjs.map +2 -2
  142. package/dist-esm/lib/shapes/text/PlainTextArea.mjs +4 -3
  143. package/dist-esm/lib/shapes/text/PlainTextArea.mjs.map +2 -2
  144. package/dist-esm/lib/shapes/text/RichTextArea.mjs +3 -4
  145. package/dist-esm/lib/shapes/text/RichTextArea.mjs.map +2 -2
  146. package/dist-esm/lib/tools/SelectTool/childStates/DraggingHandle.mjs +3 -1
  147. package/dist-esm/lib/tools/SelectTool/childStates/DraggingHandle.mjs.map +2 -2
  148. package/dist-esm/lib/ui/components/A11y.mjs +1 -2
  149. package/dist-esm/lib/ui/components/A11y.mjs.map +2 -2
  150. package/dist-esm/lib/ui/components/AccessibilityMenu.mjs +3 -3
  151. package/dist-esm/lib/ui/components/AccessibilityMenu.mjs.map +2 -2
  152. package/dist-esm/lib/ui/components/InputModeMenu.mjs +57 -0
  153. package/dist-esm/lib/ui/components/InputModeMenu.mjs.map +7 -0
  154. package/dist-esm/lib/ui/components/LanguageMenu.mjs +1 -0
  155. package/dist-esm/lib/ui/components/LanguageMenu.mjs.map +2 -2
  156. package/dist-esm/lib/ui/components/MainMenu/DefaultMainMenuContent.mjs +2 -0
  157. package/dist-esm/lib/ui/components/MainMenu/DefaultMainMenuContent.mjs.map +2 -2
  158. package/dist-esm/lib/ui/components/Minimap/DefaultMinimap.mjs +2 -1
  159. package/dist-esm/lib/ui/components/Minimap/DefaultMinimap.mjs.map +2 -2
  160. package/dist-esm/lib/ui/components/PageMenu/DefaultPageMenu.mjs +1 -2
  161. package/dist-esm/lib/ui/components/PageMenu/DefaultPageMenu.mjs.map +2 -2
  162. package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanel.mjs +18 -7
  163. package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanel.mjs.map +2 -2
  164. package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanelContent.mjs +257 -320
  165. package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanelContent.mjs.map +2 -2
  166. package/dist-esm/lib/ui/components/StylePanel/StylePanelButtonPicker.mjs +135 -0
  167. package/dist-esm/lib/ui/components/StylePanel/StylePanelButtonPicker.mjs.map +7 -0
  168. package/dist-esm/lib/ui/components/StylePanel/StylePanelContext.mjs +50 -0
  169. package/dist-esm/lib/ui/components/StylePanel/StylePanelContext.mjs.map +7 -0
  170. package/dist-esm/lib/ui/components/StylePanel/{DoubleDropdownPicker.mjs → StylePanelDoubleDropdownPicker.mjs} +20 -19
  171. package/dist-esm/lib/ui/components/StylePanel/StylePanelDoubleDropdownPicker.mjs.map +7 -0
  172. package/dist-esm/lib/ui/components/StylePanel/{DropdownPicker.mjs → StylePanelDropdownPicker.mjs} +20 -17
  173. package/dist-esm/lib/ui/components/StylePanel/StylePanelDropdownPicker.mjs.map +7 -0
  174. package/dist-esm/lib/ui/components/StylePanel/StylePanelSubheading.mjs +8 -0
  175. package/dist-esm/lib/ui/components/StylePanel/StylePanelSubheading.mjs.map +7 -0
  176. package/dist-esm/lib/ui/components/Toolbar/AltTextEditor.mjs +2 -0
  177. package/dist-esm/lib/ui/components/Toolbar/AltTextEditor.mjs.map +2 -2
  178. package/dist-esm/lib/ui/components/Toolbar/DefaultImageToolbarContent.mjs +38 -9
  179. package/dist-esm/lib/ui/components/Toolbar/DefaultImageToolbarContent.mjs.map +2 -2
  180. package/dist-esm/lib/ui/components/Toolbar/DefaultVideoToolbarContent.mjs +15 -3
  181. package/dist-esm/lib/ui/components/Toolbar/DefaultVideoToolbarContent.mjs.map +2 -2
  182. package/dist-esm/lib/ui/components/Toolbar/LinkEditor.mjs +2 -1
  183. package/dist-esm/lib/ui/components/Toolbar/LinkEditor.mjs.map +2 -2
  184. package/dist-esm/lib/ui/components/Toolbar/OverflowingToolbar.mjs +1 -1
  185. package/dist-esm/lib/ui/components/Toolbar/OverflowingToolbar.mjs.map +2 -2
  186. package/dist-esm/lib/ui/components/Toolbar/ToggleToolLockedButton.mjs +6 -2
  187. package/dist-esm/lib/ui/components/Toolbar/ToggleToolLockedButton.mjs.map +2 -2
  188. package/dist-esm/lib/ui/components/menu-items.mjs +6 -4
  189. package/dist-esm/lib/ui/components/menu-items.mjs.map +2 -2
  190. package/dist-esm/lib/ui/components/primitives/TldrawUiContextualToolbar.mjs +11 -3
  191. package/dist-esm/lib/ui/components/primitives/TldrawUiContextualToolbar.mjs.map +2 -2
  192. package/dist-esm/lib/ui/components/primitives/TldrawUiInput.mjs +6 -4
  193. package/dist-esm/lib/ui/components/primitives/TldrawUiInput.mjs.map +2 -2
  194. package/dist-esm/lib/ui/components/primitives/TldrawUiSlider.mjs +13 -2
  195. package/dist-esm/lib/ui/components/primitives/TldrawUiSlider.mjs.map +2 -2
  196. package/dist-esm/lib/ui/components/primitives/TldrawUiToolbar.mjs +3 -0
  197. package/dist-esm/lib/ui/components/primitives/TldrawUiToolbar.mjs.map +2 -2
  198. package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs +76 -20
  199. package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs.map +2 -2
  200. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.mjs +3 -0
  201. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.mjs.map +2 -2
  202. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs +8 -8
  203. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs.map +2 -2
  204. package/dist-esm/lib/ui/context/actions.mjs +18 -33
  205. package/dist-esm/lib/ui/context/actions.mjs.map +2 -2
  206. package/dist-esm/lib/ui/context/events.mjs.map +2 -2
  207. package/dist-esm/lib/ui/hooks/useClipboardEvents.mjs +1 -2
  208. package/dist-esm/lib/ui/hooks/useClipboardEvents.mjs.map +2 -2
  209. package/dist-esm/lib/ui/hooks/useExportAs.mjs +3 -2
  210. package/dist-esm/lib/ui/hooks/useExportAs.mjs.map +2 -2
  211. package/dist-esm/lib/ui/hooks/useTools.mjs +1 -1
  212. package/dist-esm/lib/ui/hooks/useTools.mjs.map +2 -2
  213. package/dist-esm/lib/ui/hooks/useTranslation/defaultTranslation.mjs +12 -3
  214. package/dist-esm/lib/ui/hooks/useTranslation/defaultTranslation.mjs.map +2 -2
  215. package/dist-esm/lib/ui/version.mjs +4 -4
  216. package/dist-esm/lib/ui/version.mjs.map +1 -1
  217. package/dist-esm/lib/utils/export/copyAs.mjs +1 -2
  218. package/dist-esm/lib/utils/export/copyAs.mjs.map +2 -2
  219. package/dist-esm/lib/utils/export/export.mjs +0 -20
  220. package/dist-esm/lib/utils/export/export.mjs.map +2 -2
  221. package/dist-esm/lib/utils/export/exportAs.mjs +1 -2
  222. package/dist-esm/lib/utils/export/exportAs.mjs.map +2 -2
  223. package/package.json +3 -3
  224. package/src/index.ts +46 -22
  225. package/src/lib/defaultExternalContentHandlers.ts +14 -0
  226. package/src/lib/shapes/arrow/ArrowShapeOptions.test.ts +83 -13
  227. package/src/lib/shapes/arrow/ArrowShapeTool.test.ts +99 -5
  228. package/src/lib/shapes/arrow/ArrowShapeUtil.test.ts +41 -0
  229. package/src/lib/shapes/arrow/arrow-types.ts +3 -5
  230. package/src/lib/shapes/arrow/arrowLabel.ts +8 -0
  231. package/src/lib/shapes/arrow/arrowTargetState.ts +34 -3
  232. package/src/lib/shapes/arrow/toolStates/Pointing.tsx +1 -1
  233. package/src/lib/shapes/bookmark/BookmarkShapeUtil.tsx +4 -5
  234. package/src/lib/shapes/frame/FrameShapeUtil.tsx +5 -0
  235. package/src/lib/shapes/frame/components/FrameLabelInput.tsx +10 -3
  236. package/src/lib/shapes/geo/GeoShapeUtil.tsx +1 -0
  237. package/src/lib/shapes/note/NoteShapeUtil.tsx +1 -0
  238. package/src/lib/shapes/shared/HyperlinkButton.tsx +5 -5
  239. package/src/lib/shapes/shared/PlainTextLabel.tsx +0 -6
  240. package/src/lib/shapes/shared/useEditablePlainText.ts +3 -10
  241. package/src/lib/shapes/shared/useImageOrVideoAsset.ts +0 -7
  242. package/src/lib/shapes/text/PlainTextArea.tsx +4 -3
  243. package/src/lib/shapes/text/RichTextArea.tsx +3 -4
  244. package/src/lib/tools/SelectTool/childStates/DraggingHandle.tsx +6 -2
  245. package/src/lib/ui/components/A11y.tsx +1 -2
  246. package/src/lib/ui/components/AccessibilityMenu.tsx +2 -2
  247. package/src/lib/ui/components/InputModeMenu.tsx +65 -0
  248. package/src/lib/ui/components/LanguageMenu.tsx +1 -0
  249. package/src/lib/ui/components/MainMenu/DefaultMainMenuContent.tsx +4 -0
  250. package/src/lib/ui/components/Minimap/DefaultMinimap.tsx +2 -1
  251. package/src/lib/ui/components/PageMenu/DefaultPageMenu.tsx +1 -2
  252. package/src/lib/ui/components/StylePanel/DefaultStylePanel.tsx +30 -14
  253. package/src/lib/ui/components/StylePanel/DefaultStylePanelContent.tsx +262 -381
  254. package/src/lib/ui/components/{primitives/TldrawUiButtonPicker.tsx → StylePanel/StylePanelButtonPicker.tsx} +70 -50
  255. package/src/lib/ui/components/StylePanel/StylePanelContext.tsx +65 -0
  256. package/src/lib/ui/components/StylePanel/{DoubleDropdownPicker.tsx → StylePanelDoubleDropdownPicker.tsx} +28 -19
  257. package/src/lib/ui/components/StylePanel/StylePanelDropdownPicker.tsx +119 -0
  258. package/src/lib/ui/components/StylePanel/StylePanelSubheading.tsx +9 -0
  259. package/src/lib/ui/components/Toolbar/AltTextEditor.tsx +2 -0
  260. package/src/lib/ui/components/Toolbar/DefaultImageToolbarContent.tsx +32 -15
  261. package/src/lib/ui/components/Toolbar/DefaultVideoToolbarContent.tsx +12 -4
  262. package/src/lib/ui/components/Toolbar/LinkEditor.tsx +1 -0
  263. package/src/lib/ui/components/Toolbar/OverflowingToolbar.tsx +1 -1
  264. package/src/lib/ui/components/Toolbar/ToggleToolLockedButton.tsx +9 -2
  265. package/src/lib/ui/components/menu-items.tsx +5 -3
  266. package/src/lib/ui/components/primitives/TldrawUiContextualToolbar.tsx +7 -3
  267. package/src/lib/ui/components/primitives/TldrawUiInput.tsx +6 -3
  268. package/src/lib/ui/components/primitives/TldrawUiSlider.tsx +19 -4
  269. package/src/lib/ui/components/primitives/TldrawUiToolbar.tsx +5 -1
  270. package/src/lib/ui/components/primitives/TldrawUiTooltip.tsx +75 -14
  271. package/src/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.tsx +4 -0
  272. package/src/lib/ui/components/primitives/menus/TldrawUiMenuItem.tsx +9 -9
  273. package/src/lib/ui/context/actions.tsx +25 -35
  274. package/src/lib/ui/context/events.tsx +3 -2
  275. package/src/lib/ui/hooks/useClipboardEvents.ts +1 -2
  276. package/src/lib/ui/hooks/useExportAs.ts +3 -2
  277. package/src/lib/ui/hooks/useTools.tsx +1 -1
  278. package/src/lib/ui/hooks/useTranslation/TLUiTranslationKey.ts +11 -2
  279. package/src/lib/ui/hooks/useTranslation/defaultTranslation.ts +12 -3
  280. package/src/lib/ui/version.ts +4 -4
  281. package/src/lib/ui.css +41 -4
  282. package/src/lib/utils/export/copyAs.ts +1 -24
  283. package/src/lib/utils/export/export.ts +0 -36
  284. package/src/lib/utils/export/exportAs.ts +1 -32
  285. package/src/test/TestEditor.ts +8 -2
  286. package/src/test/commands/setCamera.test.ts +13 -0
  287. package/src/test/custom-clipping.test.ts +436 -0
  288. package/src/test/frames.test.ts +15 -0
  289. package/src/test/getCulledShapes.test.tsx +71 -2
  290. package/tldraw.css +49 -7
  291. package/dist-cjs/lib/ui/components/StylePanel/DoubleDropdownPicker.js.map +0 -7
  292. package/dist-cjs/lib/ui/components/StylePanel/DropdownPicker.js.map +0 -7
  293. package/dist-cjs/lib/ui/components/primitives/TldrawUiButtonPicker.js +0 -131
  294. package/dist-cjs/lib/ui/components/primitives/TldrawUiButtonPicker.js.map +0 -7
  295. package/dist-esm/lib/ui/components/StylePanel/DoubleDropdownPicker.mjs.map +0 -7
  296. package/dist-esm/lib/ui/components/StylePanel/DropdownPicker.mjs.map +0 -7
  297. package/dist-esm/lib/ui/components/primitives/TldrawUiButtonPicker.mjs +0 -115
  298. package/dist-esm/lib/ui/components/primitives/TldrawUiButtonPicker.mjs.map +0 -7
  299. package/src/lib/ui/components/StylePanel/DropdownPicker.tsx +0 -110
@@ -12,417 +12,335 @@ import {
12
12
  DefaultVerticalAlignStyle,
13
13
  GeoShapeGeoStyle,
14
14
  LineShapeSplineStyle,
15
- ReadonlySharedStyleMap,
16
- StyleProp,
17
15
  TLArrowShapeArrowheadStyle,
18
- TLDefaultColorTheme,
19
- getDefaultColorTheme,
20
16
  kickoutOccludedShapes,
21
17
  minBy,
22
18
  useEditor,
23
- useIsDarkMode,
24
19
  useValue,
25
20
  } from '@tldraw/editor'
26
- import React, { useCallback } from 'react'
21
+ import React from 'react'
27
22
  import { STYLES } from '../../../styles'
28
23
  import { useUiEvents } from '../../context/events'
29
- import { useRelevantStyles } from '../../hooks/useRelevantStyles'
30
24
  import { useTranslation } from '../../hooks/useTranslation/useTranslation'
31
25
  import { TldrawUiButtonIcon } from '../primitives/Button/TldrawUiButtonIcon'
32
- import { TldrawUiButtonPicker } from '../primitives/TldrawUiButtonPicker'
33
26
  import { TldrawUiSlider } from '../primitives/TldrawUiSlider'
34
27
  import { TldrawUiToolbar, TldrawUiToolbarButton } from '../primitives/TldrawUiToolbar'
35
- import { DoubleDropdownPicker } from './DoubleDropdownPicker'
36
- import { DropdownPicker } from './DropdownPicker'
28
+ import { StylePanelButtonPicker } from './StylePanelButtonPicker'
29
+ import { useStylePanelContext } from './StylePanelContext'
30
+ import { StylePanelDoubleDropdownPicker } from './StylePanelDoubleDropdownPicker'
31
+ import { StylePanelDropdownPicker } from './StylePanelDropdownPicker'
32
+ import { StylePanelSubheading } from './StylePanelSubheading'
37
33
 
38
- // Local component for style panel subheadings
39
- function StylePanelSubheading({ children }: { children: React.ReactNode }) {
40
- return <h3 className="tlui-style-panel__subheading">{children}</h3>
34
+ /** @public @react */
35
+ export function DefaultStylePanelContent() {
36
+ return (
37
+ <>
38
+ <StylePanelSection>
39
+ <StylePanelColorPicker />
40
+ <StylePanelOpacityPicker />
41
+ </StylePanelSection>
42
+ <StylePanelSection>
43
+ <StylePanelFillPicker />
44
+ <StylePanelDashPicker />
45
+ <StylePanelSizePicker />
46
+ </StylePanelSection>
47
+ <StylePanelSection>
48
+ <StylePanelFontPicker />
49
+ <StylePanelTextAlignPicker />
50
+ <StylePanelLabelAlignPicker />
51
+ </StylePanelSection>
52
+ <StylePanelSection>
53
+ <StylePanelGeoShapePicker />
54
+ <StylePanelArrowKindPicker />
55
+ <StylePanelArrowheadPicker />
56
+ <StylePanelSplinePicker />
57
+ </StylePanelSection>
58
+ </>
59
+ )
41
60
  }
42
61
 
43
62
  /** @public */
44
- export interface TLUiStylePanelContentProps {
45
- styles: ReturnType<typeof useRelevantStyles>
63
+ export interface StylePanelSectionProps {
64
+ children: React.ReactNode
46
65
  }
47
66
 
48
67
  /** @public @react */
49
- export function DefaultStylePanelContent({ styles }: TLUiStylePanelContentProps) {
50
- const isDarkMode = useIsDarkMode()
51
-
52
- if (!styles) return null
53
-
54
- const geo = styles.get(GeoShapeGeoStyle)
55
- const arrowheadEnd = styles.get(ArrowShapeArrowheadEndStyle)
56
- const arrowheadStart = styles.get(ArrowShapeArrowheadStartStyle)
57
- const arrowKind = styles.get(ArrowShapeKindStyle)
58
- const spline = styles.get(LineShapeSplineStyle)
59
- const font = styles.get(DefaultFontStyle)
60
-
61
- const hideGeo = geo === undefined
62
- const hideArrowHeads = arrowheadEnd === undefined && arrowheadStart === undefined
63
- const hideSpline = spline === undefined
64
- const hideArrowKind = arrowKind === undefined
65
- const hideText = font === undefined
68
+ export function StylePanelSection({ children }: StylePanelSectionProps) {
69
+ return <div className="tlui-style-panel__section">{children}</div>
70
+ }
66
71
 
67
- const theme = getDefaultColorTheme({ isDarkMode: isDarkMode })
72
+ /** @public @react */
73
+ export function StylePanelColorPicker() {
74
+ const { styles } = useStylePanelContext()
75
+ const msg = useTranslation()
76
+ const color = styles.get(DefaultColorStyle)
77
+ if (color === undefined) return null
68
78
 
69
79
  return (
70
- <>
71
- <CommonStylePickerSet theme={theme} styles={styles} />
72
- {!hideText && <TextStylePickerSet theme={theme} styles={styles} />}
73
- {!(hideGeo && hideArrowHeads && hideSpline && hideArrowKind) && (
74
- <div className="tlui-style-panel__section">
75
- <GeoStylePickerSet styles={styles} />
76
- <ArrowStylePickerSet styles={styles} />
77
- <ArrowheadStylePickerSet styles={styles} />
78
- <SplineStylePickerSet styles={styles} />
79
- </div>
80
- )}
81
- </>
80
+ <StylePanelButtonPicker
81
+ title={msg('style-panel.color')}
82
+ uiType="color"
83
+ style={DefaultColorStyle}
84
+ items={STYLES.color}
85
+ value={color}
86
+ />
82
87
  )
83
88
  }
84
89
 
85
- function useStyleChangeCallback() {
90
+ const tldrawSupportedOpacities = [0.1, 0.25, 0.5, 0.75, 1] as const
91
+ /** @public @react */
92
+ export function StylePanelOpacityPicker() {
86
93
  const editor = useEditor()
94
+ const { onHistoryMark, enhancedA11yMode } = useStylePanelContext()
95
+
96
+ const opacity = useValue('opacity', () => editor.getSharedOpacity(), [editor])
87
97
  const trackEvent = useUiEvents()
98
+ const msg = useTranslation()
99
+
100
+ const handleOpacityValueChange = React.useCallback(
101
+ (value: number) => {
102
+ const item = tldrawSupportedOpacities[value]
103
+ editor.run(() => {
104
+ if (editor.isIn('select')) {
105
+ editor.setOpacityForSelectedShapes(item)
106
+ }
107
+ editor.setOpacityForNextShapes(item)
108
+ editor.updateInstanceState({ isChangingStyle: true })
109
+ })
88
110
 
89
- return React.useMemo(
90
- () =>
91
- function handleStyleChange<T>(style: StyleProp<T>, value: T) {
92
- editor.run(() => {
93
- if (editor.isIn('select')) {
94
- editor.setStyleForSelectedShapes(style, value)
95
- }
96
- editor.setStyleForNextShapes(style, value)
97
- editor.updateInstanceState({ isChangingStyle: true })
98
- })
99
-
100
- trackEvent('set-style', { source: 'style-panel', id: style.id, value: value as string })
101
- },
111
+ trackEvent('set-style', { source: 'style-panel', id: 'opacity', value })
112
+ },
102
113
  [editor, trackEvent]
103
114
  )
104
- }
105
115
 
106
- /** @public */
107
- export interface ThemeStylePickerSetProps {
108
- styles: ReadonlySharedStyleMap
109
- theme: TLDefaultColorTheme
110
- }
116
+ if (opacity === undefined) return null
111
117
 
112
- /** @public */
113
- export interface StylePickerSetProps {
114
- styles: ReadonlySharedStyleMap
118
+ const opacityIndex =
119
+ opacity.type === 'mixed'
120
+ ? -1
121
+ : tldrawSupportedOpacities.indexOf(
122
+ minBy(tldrawSupportedOpacities, (supportedOpacity) =>
123
+ Math.abs(supportedOpacity - opacity.value)
124
+ )!
125
+ )
126
+
127
+ return (
128
+ <>
129
+ {enhancedA11yMode && (
130
+ <StylePanelSubheading>{msg('style-panel.opacity')}</StylePanelSubheading>
131
+ )}
132
+ <TldrawUiSlider
133
+ data-testid="style.opacity"
134
+ value={opacityIndex >= 0 ? opacityIndex : tldrawSupportedOpacities.length - 1}
135
+ label={opacity.type === 'mixed' ? 'style-panel.mixed' : `opacity-style.${opacity.value}`}
136
+ onValueChange={handleOpacityValueChange}
137
+ steps={tldrawSupportedOpacities.length - 1}
138
+ title={msg('style-panel.opacity')}
139
+ onHistoryMark={onHistoryMark}
140
+ ariaValueModifier={25}
141
+ />
142
+ </>
143
+ )
115
144
  }
116
145
 
117
146
  /** @public @react */
118
- export function CommonStylePickerSet({ styles, theme }: ThemeStylePickerSetProps) {
147
+ export function StylePanelFillPicker() {
148
+ const { styles } = useStylePanelContext()
119
149
  const msg = useTranslation()
120
- const editor = useEditor()
121
-
122
- const onHistoryMark = useCallback((id: string) => editor.markHistoryStoppingPoint(id), [editor])
123
- const showUiLabels = useValue('showUiLabels', () => editor.user.getShowUiLabels(), [editor])
150
+ const fill = styles.get(DefaultFillStyle)
151
+ if (fill === undefined) return null
124
152
 
125
- const handleValueChange = useStyleChangeCallback()
153
+ return (
154
+ <StylePanelButtonPicker
155
+ title={msg('style-panel.fill')}
156
+ uiType="fill"
157
+ style={DefaultFillStyle}
158
+ items={STYLES.fill}
159
+ value={fill}
160
+ />
161
+ )
162
+ }
126
163
 
127
- const color = styles.get(DefaultColorStyle)
128
- const fill = styles.get(DefaultFillStyle)
164
+ /** @public @react */
165
+ export function StylePanelDashPicker() {
166
+ const { styles } = useStylePanelContext()
167
+ const msg = useTranslation()
129
168
  const dash = styles.get(DefaultDashStyle)
130
- const size = styles.get(DefaultSizeStyle)
131
-
132
- const showPickers = fill !== undefined || dash !== undefined || size !== undefined
169
+ if (dash === undefined) return null
133
170
 
134
171
  return (
135
- <>
136
- <div className="tlui-style-panel__section__common" data-testid="style.panel">
137
- {color === undefined ? null : (
138
- <>
139
- {showUiLabels && (
140
- <StylePanelSubheading>{msg('style-panel.color')}</StylePanelSubheading>
141
- )}
142
- <TldrawUiToolbar orientation="horizontal" label={msg('style-panel.color')}>
143
- <TldrawUiButtonPicker
144
- title={msg('style-panel.color')}
145
- uiType="color"
146
- style={DefaultColorStyle}
147
- items={STYLES.color}
148
- value={color}
149
- onValueChange={handleValueChange}
150
- theme={theme}
151
- onHistoryMark={onHistoryMark}
152
- />
153
- </TldrawUiToolbar>
154
- </>
155
- )}
156
- <OpacitySlider />
157
- </div>
158
- {showPickers && (
159
- <div className="tlui-style-panel__section">
160
- {fill === undefined ? null : (
161
- <>
162
- {showUiLabels && (
163
- <StylePanelSubheading>{msg('style-panel.fill')}</StylePanelSubheading>
164
- )}
165
- <TldrawUiToolbar orientation="horizontal" label={msg('style-panel.fill')}>
166
- <TldrawUiButtonPicker
167
- title={msg('style-panel.fill')}
168
- uiType="fill"
169
- style={DefaultFillStyle}
170
- items={STYLES.fill}
171
- value={fill}
172
- onValueChange={handleValueChange}
173
- theme={theme}
174
- onHistoryMark={onHistoryMark}
175
- />
176
- </TldrawUiToolbar>
177
- </>
178
- )}
179
- {dash === undefined ? null : (
180
- <>
181
- {showUiLabels && (
182
- <StylePanelSubheading>{msg('style-panel.dash')}</StylePanelSubheading>
183
- )}
184
- <TldrawUiToolbar orientation="horizontal" label={msg('style-panel.dash')}>
185
- <TldrawUiButtonPicker
186
- title={msg('style-panel.dash')}
187
- uiType="dash"
188
- style={DefaultDashStyle}
189
- items={STYLES.dash}
190
- value={dash}
191
- onValueChange={handleValueChange}
192
- theme={theme}
193
- onHistoryMark={onHistoryMark}
194
- />
195
- </TldrawUiToolbar>
196
- </>
197
- )}
198
- {size === undefined ? null : (
199
- <>
200
- {showUiLabels && (
201
- <StylePanelSubheading>{msg('style-panel.size')}</StylePanelSubheading>
202
- )}
203
- <TldrawUiToolbar orientation="horizontal" label={msg('style-panel.size')}>
204
- <TldrawUiButtonPicker
205
- title={msg('style-panel.size')}
206
- uiType="size"
207
- style={DefaultSizeStyle}
208
- items={STYLES.size}
209
- value={size}
210
- onValueChange={(style, value) => {
211
- handleValueChange(style, value)
212
- const selectedShapeIds = editor.getSelectedShapeIds()
213
- if (selectedShapeIds.length > 0) {
214
- kickoutOccludedShapes(editor, selectedShapeIds)
215
- }
216
- }}
217
- theme={theme}
218
- onHistoryMark={onHistoryMark}
219
- />
220
- </TldrawUiToolbar>
221
- </>
222
- )}
223
- </div>
224
- )}
225
- </>
172
+ <StylePanelButtonPicker
173
+ title={msg('style-panel.dash')}
174
+ uiType="dash"
175
+ style={DefaultDashStyle}
176
+ items={STYLES.dash}
177
+ value={dash}
178
+ />
226
179
  )
227
180
  }
228
181
 
229
182
  /** @public @react */
230
- export function TextStylePickerSet({ theme, styles }: ThemeStylePickerSetProps) {
183
+ export function StylePanelSizePicker() {
184
+ const editor = useEditor()
185
+ const { styles, onValueChange } = useStylePanelContext()
231
186
  const msg = useTranslation()
232
- const handleValueChange = useStyleChangeCallback()
187
+ const size = styles.get(DefaultSizeStyle)
188
+ if (size === undefined) return null
233
189
 
234
- const editor = useEditor()
235
- const onHistoryMark = useCallback((id: string) => editor.markHistoryStoppingPoint(id), [editor])
236
- const showUiLabels = useValue('showUiLabels', () => editor.user.getShowUiLabels(), [editor])
237
- const labelStr = showUiLabels && msg('style-panel.font')
190
+ return (
191
+ <StylePanelButtonPicker
192
+ title={msg('style-panel.size')}
193
+ uiType="size"
194
+ style={DefaultSizeStyle}
195
+ items={STYLES.size}
196
+ value={size}
197
+ onValueChange={(style, value) => {
198
+ onValueChange(style, value)
199
+ const selectedShapeIds = editor.getSelectedShapeIds()
200
+ if (selectedShapeIds.length > 0) {
201
+ kickoutOccludedShapes(editor, selectedShapeIds)
202
+ }
203
+ }}
204
+ />
205
+ )
206
+ }
238
207
 
208
+ /** @public @react */
209
+ export function StylePanelFontPicker() {
210
+ const { styles } = useStylePanelContext()
211
+ const msg = useTranslation()
239
212
  const font = styles.get(DefaultFontStyle)
240
- const textAlign = styles.get(DefaultTextAlignStyle)
241
- const labelAlign = styles.get(DefaultHorizontalAlignStyle)
242
- const verticalLabelAlign = styles.get(DefaultVerticalAlignStyle)
243
- if (font === undefined && labelAlign === undefined) {
244
- return null
245
- }
213
+ if (font === undefined) return null
246
214
 
247
215
  return (
248
- <div className="tlui-style-panel__section">
249
- {font === undefined ? null : (
250
- <>
251
- {labelStr && <StylePanelSubheading>{labelStr}</StylePanelSubheading>}
252
- <TldrawUiToolbar orientation="horizontal" label={msg('style-panel.font')}>
253
- <TldrawUiButtonPicker
254
- title={msg('style-panel.font')}
255
- uiType="font"
256
- style={DefaultFontStyle}
257
- items={STYLES.font}
258
- value={font}
259
- onValueChange={handleValueChange}
260
- theme={theme}
261
- onHistoryMark={onHistoryMark}
262
- />
263
- </TldrawUiToolbar>
264
- </>
265
- )}
266
-
267
- {textAlign === undefined ? null : (
268
- <>
269
- {showUiLabels && <StylePanelSubheading>{msg('style-panel.align')}</StylePanelSubheading>}
270
- <TldrawUiToolbar orientation="horizontal" label={msg('style-panel.align')}>
271
- <TldrawUiButtonPicker
272
- title={msg('style-panel.align')}
273
- uiType="align"
274
- style={DefaultTextAlignStyle}
275
- items={STYLES.textAlign}
276
- value={textAlign}
277
- onValueChange={handleValueChange}
278
- theme={theme}
279
- onHistoryMark={onHistoryMark}
280
- />
281
- <TldrawUiToolbarButton
282
- type="icon"
283
- title={msg('style-panel.vertical-align')}
284
- data-testid="vertical-align"
285
- disabled
286
- >
287
- <TldrawUiButtonIcon icon="vertical-align-middle" />
288
- </TldrawUiToolbarButton>
289
- </TldrawUiToolbar>
290
- </>
291
- )}
292
-
293
- {labelAlign === undefined ? null : (
294
- <>
295
- {showUiLabels && (
296
- <StylePanelSubheading>{msg('style-panel.label-align')}</StylePanelSubheading>
297
- )}
298
- <TldrawUiToolbar orientation="horizontal" label={msg('style-panel.label-align')}>
299
- <TldrawUiButtonPicker
300
- title={msg('style-panel.label-align')}
301
- uiType="align"
302
- style={DefaultHorizontalAlignStyle}
303
- items={STYLES.horizontalAlign}
304
- value={labelAlign}
305
- onValueChange={handleValueChange}
306
- theme={theme}
307
- onHistoryMark={onHistoryMark}
308
- />
309
- {verticalLabelAlign === undefined ? (
310
- <TldrawUiToolbarButton
311
- type="icon"
312
- title={msg('style-panel.vertical-align')}
313
- data-testid="vertical-align"
314
- disabled
315
- >
316
- <TldrawUiButtonIcon icon="vertical-align-middle" />
317
- </TldrawUiToolbarButton>
318
- ) : (
319
- <DropdownPicker
320
- type="icon"
321
- id="geo-vertical-alignment"
322
- uiType="verticalAlign"
323
- stylePanelType="vertical-align"
324
- style={DefaultVerticalAlignStyle}
325
- items={STYLES.verticalAlign}
326
- value={verticalLabelAlign}
327
- onValueChange={handleValueChange}
328
- />
329
- )}
330
- </TldrawUiToolbar>
331
- </>
332
- )}
333
- </div>
216
+ <StylePanelButtonPicker
217
+ title={msg('style-panel.font')}
218
+ uiType="font"
219
+ style={DefaultFontStyle}
220
+ items={STYLES.font}
221
+ value={font}
222
+ />
334
223
  )
335
224
  }
225
+
336
226
  /** @public @react */
337
- export function GeoStylePickerSet({ styles }: StylePickerSetProps) {
227
+ export function StylePanelTextAlignPicker() {
228
+ const { styles } = useStylePanelContext()
338
229
  const msg = useTranslation()
339
- const handleValueChange = useStyleChangeCallback()
340
-
341
- const geo = styles.get(GeoShapeGeoStyle)
342
- if (geo === undefined) {
343
- return null
344
- }
230
+ const textAlign = styles.get(DefaultTextAlignStyle)
231
+ if (textAlign === undefined) return null
345
232
 
346
233
  return (
347
- <TldrawUiToolbar orientation="horizontal" label={msg('style-panel.geo')}>
348
- <DropdownPicker
349
- id="geo"
350
- type="menu"
351
- label={'style-panel.geo'}
352
- uiType="geo"
353
- stylePanelType="geo"
354
- style={GeoShapeGeoStyle}
355
- items={STYLES.geo}
356
- value={geo}
357
- onValueChange={handleValueChange}
234
+ <TldrawUiToolbar orientation="horizontal" label={msg('style-panel.align')}>
235
+ <StylePanelButtonPicker
236
+ title={msg('style-panel.align')}
237
+ uiType="align"
238
+ style={DefaultTextAlignStyle}
239
+ items={STYLES.textAlign}
240
+ value={textAlign}
358
241
  />
242
+ <TldrawUiToolbarButton
243
+ type="icon"
244
+ title={msg('style-panel.vertical-align')}
245
+ data-testid="vertical-align"
246
+ disabled
247
+ >
248
+ <TldrawUiButtonIcon icon="vertical-align-middle" />
249
+ </TldrawUiToolbarButton>
359
250
  </TldrawUiToolbar>
360
251
  )
361
252
  }
253
+
362
254
  /** @public @react */
363
- export function SplineStylePickerSet({ styles }: StylePickerSetProps) {
255
+ export function StylePanelLabelAlignPicker() {
256
+ const { styles } = useStylePanelContext()
364
257
  const msg = useTranslation()
365
- const handleValueChange = useStyleChangeCallback()
366
-
367
- const spline = styles.get(LineShapeSplineStyle)
368
- if (spline === undefined) {
369
- return null
370
- }
258
+ const labelAlign = styles.get(DefaultHorizontalAlignStyle)
259
+ const verticalLabelAlign = styles.get(DefaultVerticalAlignStyle)
260
+ if (labelAlign === undefined) return null
371
261
 
372
262
  return (
373
- <TldrawUiToolbar orientation="horizontal" label={msg('style-panel.spline')}>
374
- <DropdownPicker
375
- id="spline"
376
- type="menu"
377
- label={'style-panel.spline'}
378
- uiType="spline"
379
- stylePanelType="spline"
380
- style={LineShapeSplineStyle}
381
- items={STYLES.spline}
382
- value={spline}
383
- onValueChange={handleValueChange}
263
+ <TldrawUiToolbar orientation="horizontal" label={msg('style-panel.label-align')}>
264
+ <StylePanelButtonPicker
265
+ title={msg('style-panel.label-align')}
266
+ uiType="align"
267
+ style={DefaultHorizontalAlignStyle}
268
+ items={STYLES.horizontalAlign}
269
+ value={labelAlign}
384
270
  />
271
+ {verticalLabelAlign === undefined ? (
272
+ <TldrawUiToolbarButton
273
+ type="icon"
274
+ title={msg('style-panel.vertical-align')}
275
+ data-testid="vertical-align"
276
+ disabled
277
+ >
278
+ <TldrawUiButtonIcon icon="vertical-align-middle" />
279
+ </TldrawUiToolbarButton>
280
+ ) : (
281
+ <StylePanelDropdownPicker
282
+ type="icon"
283
+ id="geo-vertical-alignment"
284
+ uiType="verticalAlign"
285
+ stylePanelType="vertical-align"
286
+ style={DefaultVerticalAlignStyle}
287
+ items={STYLES.verticalAlign}
288
+ value={verticalLabelAlign}
289
+ />
290
+ )}
385
291
  </TldrawUiToolbar>
386
292
  )
387
293
  }
294
+
388
295
  /** @public @react */
389
- export function ArrowStylePickerSet({ styles }: StylePickerSetProps) {
390
- const msg = useTranslation()
391
- const handleValueChange = useStyleChangeCallback()
296
+ export function StylePanelGeoShapePicker() {
297
+ const { styles } = useStylePanelContext()
298
+ const geo = styles.get(GeoShapeGeoStyle)
299
+ if (geo === undefined) return null
300
+
301
+ return (
302
+ <StylePanelDropdownPicker
303
+ label="style-panel.geo"
304
+ type="menu"
305
+ id="geo"
306
+ uiType="geo"
307
+ stylePanelType="geo"
308
+ style={GeoShapeGeoStyle}
309
+ items={STYLES.geo}
310
+ value={geo}
311
+ />
312
+ )
313
+ }
392
314
 
315
+ /** @public @react */
316
+ export function StylePanelArrowKindPicker() {
317
+ const { styles } = useStylePanelContext()
393
318
  const arrowKind = styles.get(ArrowShapeKindStyle)
394
- if (arrowKind === undefined) {
395
- return null
396
- }
319
+ if (arrowKind === undefined) return null
397
320
 
398
321
  return (
399
- <TldrawUiToolbar orientation="horizontal" label={msg('style-panel.arrow-kind')}>
400
- <DropdownPicker
401
- id="arrow-kind"
402
- type="menu"
403
- label={'style-panel.arrow-kind'}
404
- uiType="arrow-kind"
405
- stylePanelType="arrow-kind"
406
- style={ArrowShapeKindStyle}
407
- items={STYLES.arrowKind}
408
- value={arrowKind}
409
- onValueChange={handleValueChange}
410
- />
411
- </TldrawUiToolbar>
322
+ <StylePanelDropdownPicker
323
+ id="arrow-kind"
324
+ type="menu"
325
+ label={'style-panel.arrow-kind'}
326
+ uiType="arrow-kind"
327
+ stylePanelType="arrow-kind"
328
+ style={ArrowShapeKindStyle}
329
+ items={STYLES.arrowKind}
330
+ value={arrowKind}
331
+ />
412
332
  )
413
333
  }
414
- /** @public @react */
415
- export function ArrowheadStylePickerSet({ styles }: StylePickerSetProps) {
416
- const handleValueChange = useStyleChangeCallback()
417
334
 
335
+ /** @public @react */
336
+ export function StylePanelArrowheadPicker() {
337
+ const { styles } = useStylePanelContext()
418
338
  const arrowheadEnd = styles.get(ArrowShapeArrowheadEndStyle)
419
339
  const arrowheadStart = styles.get(ArrowShapeArrowheadStartStyle)
420
- if (!arrowheadEnd || !arrowheadStart) {
421
- return null
422
- }
340
+ if (arrowheadEnd === undefined || arrowheadStart === undefined) return null
423
341
 
424
342
  return (
425
- <DoubleDropdownPicker<TLArrowShapeArrowheadStyle>
343
+ <StylePanelDoubleDropdownPicker<TLArrowShapeArrowheadStyle>
426
344
  label={'style-panel.arrowheads'}
427
345
  uiTypeA="arrowheadStart"
428
346
  styleA={ArrowShapeArrowheadStartStyle}
@@ -432,65 +350,28 @@ export function ArrowheadStylePickerSet({ styles }: StylePickerSetProps) {
432
350
  styleB={ArrowShapeArrowheadEndStyle}
433
351
  itemsB={STYLES.arrowheadEnd}
434
352
  valueB={arrowheadEnd}
435
- onValueChange={handleValueChange}
436
353
  labelA="style-panel.arrowhead-start"
437
354
  labelB="style-panel.arrowhead-end"
438
355
  />
439
356
  )
440
357
  }
441
358
 
442
- const tldrawSupportedOpacities = [0.1, 0.25, 0.5, 0.75, 1] as const
443
359
  /** @public @react */
444
- export function OpacitySlider() {
445
- const editor = useEditor()
446
-
447
- const onHistoryMark = useCallback((id: string) => editor.markHistoryStoppingPoint(id), [editor])
448
- const showUiLabels = useValue('showUiLabels', () => editor.user.getShowUiLabels(), [editor])
449
-
450
- const opacity = useValue('opacity', () => editor.getSharedOpacity(), [editor])
451
- const trackEvent = useUiEvents()
452
- const msg = useTranslation()
453
-
454
- const handleOpacityValueChange = React.useCallback(
455
- (value: number) => {
456
- const item = tldrawSupportedOpacities[value]
457
- editor.run(() => {
458
- if (editor.isIn('select')) {
459
- editor.setOpacityForSelectedShapes(item)
460
- }
461
- editor.setOpacityForNextShapes(item)
462
- editor.updateInstanceState({ isChangingStyle: true })
463
- })
464
-
465
- trackEvent('set-style', { source: 'style-panel', id: 'opacity', value })
466
- },
467
- [editor, trackEvent]
468
- )
469
-
470
- if (opacity === undefined) return null
471
-
472
- const opacityIndex =
473
- opacity.type === 'mixed'
474
- ? -1
475
- : tldrawSupportedOpacities.indexOf(
476
- minBy(tldrawSupportedOpacities, (supportedOpacity) =>
477
- Math.abs(supportedOpacity - opacity.value)
478
- )!
479
- )
360
+ export function StylePanelSplinePicker() {
361
+ const { styles } = useStylePanelContext()
362
+ const spline = styles.get(LineShapeSplineStyle)
363
+ if (spline === undefined) return null
480
364
 
481
365
  return (
482
- <>
483
- {showUiLabels && <StylePanelSubheading>{msg('style-panel.opacity')}</StylePanelSubheading>}
484
- <TldrawUiSlider
485
- data-testid="style.opacity"
486
- value={opacityIndex >= 0 ? opacityIndex : tldrawSupportedOpacities.length - 1}
487
- label={opacity.type === 'mixed' ? 'style-panel.mixed' : `opacity-style.${opacity.value}`}
488
- onValueChange={handleOpacityValueChange}
489
- steps={tldrawSupportedOpacities.length - 1}
490
- title={msg('style-panel.opacity')}
491
- onHistoryMark={onHistoryMark}
492
- ariaValueModifier={25}
493
- />
494
- </>
366
+ <StylePanelDropdownPicker
367
+ type="menu"
368
+ id="spline"
369
+ uiType="spline"
370
+ stylePanelType="spline"
371
+ label="style-panel.spline"
372
+ style={LineShapeSplineStyle}
373
+ items={STYLES.spline}
374
+ value={spline}
375
+ />
495
376
  )
496
377
  }