tldraw 3.16.0-canary.5170ef6b6e20 → 3.16.0-canary.5462c7eac75a

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 (234) hide show
  1. package/dist-cjs/index.d.ts +138 -106
  2. package/dist-cjs/index.js +25 -14
  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/arrowLabel.js +6 -0
  7. package/dist-cjs/lib/shapes/arrow/arrowLabel.js.map +3 -3
  8. package/dist-cjs/lib/shapes/bookmark/BookmarkShapeUtil.js +4 -4
  9. package/dist-cjs/lib/shapes/bookmark/BookmarkShapeUtil.js.map +2 -2
  10. package/dist-cjs/lib/shapes/frame/FrameShapeUtil.js +2 -1
  11. package/dist-cjs/lib/shapes/frame/FrameShapeUtil.js.map +2 -2
  12. package/dist-cjs/lib/shapes/frame/components/FrameLabelInput.js +2 -2
  13. package/dist-cjs/lib/shapes/frame/components/FrameLabelInput.js.map +2 -2
  14. package/dist-cjs/lib/shapes/geo/GeoShapeUtil.js +1 -0
  15. package/dist-cjs/lib/shapes/geo/GeoShapeUtil.js.map +2 -2
  16. package/dist-cjs/lib/shapes/note/NoteShapeUtil.js +2 -1
  17. package/dist-cjs/lib/shapes/note/NoteShapeUtil.js.map +2 -2
  18. package/dist-cjs/lib/shapes/shared/HyperlinkButton.js +4 -4
  19. package/dist-cjs/lib/shapes/shared/HyperlinkButton.js.map +2 -2
  20. package/dist-cjs/lib/shapes/shared/PlainTextLabel.js +1 -3
  21. package/dist-cjs/lib/shapes/shared/PlainTextLabel.js.map +2 -2
  22. package/dist-cjs/lib/shapes/shared/useEditablePlainText.js +3 -4
  23. package/dist-cjs/lib/shapes/shared/useEditablePlainText.js.map +2 -2
  24. package/dist-cjs/lib/shapes/shared/useImageOrVideoAsset.js +0 -2
  25. package/dist-cjs/lib/shapes/shared/useImageOrVideoAsset.js.map +2 -2
  26. package/dist-cjs/lib/shapes/text/PlainTextArea.js +2 -2
  27. package/dist-cjs/lib/shapes/text/PlainTextArea.js.map +2 -2
  28. package/dist-cjs/lib/shapes/text/RichTextArea.js +3 -3
  29. package/dist-cjs/lib/shapes/text/RichTextArea.js.map +2 -2
  30. package/dist-cjs/lib/ui/components/A11y.js +1 -1
  31. package/dist-cjs/lib/ui/components/A11y.js.map +2 -2
  32. package/dist-cjs/lib/ui/components/LanguageMenu.js +1 -0
  33. package/dist-cjs/lib/ui/components/LanguageMenu.js.map +2 -2
  34. package/dist-cjs/lib/ui/components/Minimap/DefaultMinimap.js +1 -0
  35. package/dist-cjs/lib/ui/components/Minimap/DefaultMinimap.js.map +2 -2
  36. package/dist-cjs/lib/ui/components/PageMenu/DefaultPageMenu.js +1 -1
  37. package/dist-cjs/lib/ui/components/PageMenu/DefaultPageMenu.js.map +2 -2
  38. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanel.js +9 -4
  39. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanel.js.map +2 -2
  40. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanelContent.js +255 -316
  41. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanelContent.js.map +2 -2
  42. package/dist-cjs/lib/ui/components/StylePanel/StylePanelButtonPicker.js +147 -0
  43. package/dist-cjs/lib/ui/components/StylePanel/StylePanelButtonPicker.js.map +7 -0
  44. package/dist-cjs/lib/ui/components/StylePanel/StylePanelContext.js +68 -0
  45. package/dist-cjs/lib/ui/components/StylePanel/StylePanelContext.js.map +7 -0
  46. package/dist-cjs/lib/ui/components/StylePanel/{DoubleDropdownPicker.js → StylePanelDoubleDropdownPicker.js} +23 -22
  47. package/dist-cjs/lib/ui/components/StylePanel/StylePanelDoubleDropdownPicker.js.map +7 -0
  48. package/dist-cjs/lib/ui/components/StylePanel/{DropdownPicker.js → StylePanelDropdownPicker.js} +23 -20
  49. package/dist-cjs/lib/ui/components/StylePanel/StylePanelDropdownPicker.js.map +7 -0
  50. package/dist-cjs/lib/ui/components/StylePanel/StylePanelSubheading.js +28 -0
  51. package/dist-cjs/lib/ui/components/StylePanel/StylePanelSubheading.js.map +7 -0
  52. package/dist-cjs/lib/ui/components/Toolbar/AltTextEditor.js +1 -0
  53. package/dist-cjs/lib/ui/components/Toolbar/AltTextEditor.js.map +2 -2
  54. package/dist-cjs/lib/ui/components/Toolbar/LinkEditor.js +2 -1
  55. package/dist-cjs/lib/ui/components/Toolbar/LinkEditor.js.map +2 -2
  56. package/dist-cjs/lib/ui/components/primitives/TldrawUiContextualToolbar.js +1 -1
  57. package/dist-cjs/lib/ui/components/primitives/TldrawUiContextualToolbar.js.map +1 -1
  58. package/dist-cjs/lib/ui/components/primitives/TldrawUiInput.js +2 -2
  59. package/dist-cjs/lib/ui/components/primitives/TldrawUiInput.js.map +2 -2
  60. package/dist-cjs/lib/ui/components/primitives/TldrawUiSlider.js +1 -1
  61. package/dist-cjs/lib/ui/components/primitives/TldrawUiSlider.js.map +2 -2
  62. package/dist-cjs/lib/ui/components/primitives/TldrawUiToolbar.js +3 -0
  63. package/dist-cjs/lib/ui/components/primitives/TldrawUiToolbar.js.map +2 -2
  64. package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js +44 -5
  65. package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js.map +2 -2
  66. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.js +3 -0
  67. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.js.map +2 -2
  68. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js +5 -5
  69. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js.map +1 -1
  70. package/dist-cjs/lib/ui/context/actions.js +13 -8
  71. package/dist-cjs/lib/ui/context/actions.js.map +2 -2
  72. package/dist-cjs/lib/ui/hooks/useClipboardEvents.js +1 -1
  73. package/dist-cjs/lib/ui/hooks/useClipboardEvents.js.map +2 -2
  74. package/dist-cjs/lib/ui/hooks/useExportAs.js +3 -2
  75. package/dist-cjs/lib/ui/hooks/useExportAs.js.map +2 -2
  76. package/dist-cjs/lib/ui/hooks/useTools.js +1 -1
  77. package/dist-cjs/lib/ui/hooks/useTools.js.map +2 -2
  78. package/dist-cjs/lib/ui/hooks/useTranslation/TLUiTranslationKey.js.map +1 -1
  79. package/dist-cjs/lib/ui/hooks/useTranslation/defaultTranslation.js +4 -2
  80. package/dist-cjs/lib/ui/hooks/useTranslation/defaultTranslation.js.map +2 -2
  81. package/dist-cjs/lib/ui/version.js +3 -3
  82. package/dist-cjs/lib/ui/version.js.map +1 -1
  83. package/dist-cjs/lib/utils/export/copyAs.js +1 -2
  84. package/dist-cjs/lib/utils/export/copyAs.js.map +2 -2
  85. package/dist-cjs/lib/utils/export/export.js +0 -20
  86. package/dist-cjs/lib/utils/export/export.js.map +2 -2
  87. package/dist-cjs/lib/utils/export/exportAs.js +1 -2
  88. package/dist-cjs/lib/utils/export/exportAs.js.map +2 -2
  89. package/dist-esm/index.d.mts +138 -106
  90. package/dist-esm/index.mjs +51 -28
  91. package/dist-esm/index.mjs.map +2 -2
  92. package/dist-esm/lib/defaultExternalContentHandlers.mjs +10 -0
  93. package/dist-esm/lib/defaultExternalContentHandlers.mjs.map +2 -2
  94. package/dist-esm/lib/shapes/arrow/arrowLabel.mjs +6 -0
  95. package/dist-esm/lib/shapes/arrow/arrowLabel.mjs.map +3 -3
  96. package/dist-esm/lib/shapes/bookmark/BookmarkShapeUtil.mjs +5 -5
  97. package/dist-esm/lib/shapes/bookmark/BookmarkShapeUtil.mjs.map +2 -2
  98. package/dist-esm/lib/shapes/frame/FrameShapeUtil.mjs +2 -1
  99. package/dist-esm/lib/shapes/frame/FrameShapeUtil.mjs.map +2 -2
  100. package/dist-esm/lib/shapes/frame/components/FrameLabelInput.mjs +3 -3
  101. package/dist-esm/lib/shapes/frame/components/FrameLabelInput.mjs.map +2 -2
  102. package/dist-esm/lib/shapes/geo/GeoShapeUtil.mjs +1 -0
  103. package/dist-esm/lib/shapes/geo/GeoShapeUtil.mjs.map +2 -2
  104. package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs +2 -1
  105. package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs.map +2 -2
  106. package/dist-esm/lib/shapes/shared/HyperlinkButton.mjs +5 -5
  107. package/dist-esm/lib/shapes/shared/HyperlinkButton.mjs.map +2 -2
  108. package/dist-esm/lib/shapes/shared/PlainTextLabel.mjs +1 -3
  109. package/dist-esm/lib/shapes/shared/PlainTextLabel.mjs.map +2 -2
  110. package/dist-esm/lib/shapes/shared/useEditablePlainText.mjs +4 -5
  111. package/dist-esm/lib/shapes/shared/useEditablePlainText.mjs.map +2 -2
  112. package/dist-esm/lib/shapes/shared/useImageOrVideoAsset.mjs +0 -2
  113. package/dist-esm/lib/shapes/shared/useImageOrVideoAsset.mjs.map +2 -2
  114. package/dist-esm/lib/shapes/text/PlainTextArea.mjs +3 -3
  115. package/dist-esm/lib/shapes/text/PlainTextArea.mjs.map +2 -2
  116. package/dist-esm/lib/shapes/text/RichTextArea.mjs +3 -4
  117. package/dist-esm/lib/shapes/text/RichTextArea.mjs.map +2 -2
  118. package/dist-esm/lib/ui/components/A11y.mjs +2 -2
  119. package/dist-esm/lib/ui/components/A11y.mjs.map +2 -2
  120. package/dist-esm/lib/ui/components/LanguageMenu.mjs +1 -0
  121. package/dist-esm/lib/ui/components/LanguageMenu.mjs.map +2 -2
  122. package/dist-esm/lib/ui/components/Minimap/DefaultMinimap.mjs +1 -0
  123. package/dist-esm/lib/ui/components/Minimap/DefaultMinimap.mjs.map +2 -2
  124. package/dist-esm/lib/ui/components/PageMenu/DefaultPageMenu.mjs +2 -2
  125. package/dist-esm/lib/ui/components/PageMenu/DefaultPageMenu.mjs.map +2 -2
  126. package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanel.mjs +14 -5
  127. package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanel.mjs.map +2 -2
  128. package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanelContent.mjs +257 -320
  129. package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanelContent.mjs.map +2 -2
  130. package/dist-esm/lib/ui/components/StylePanel/StylePanelButtonPicker.mjs +135 -0
  131. package/dist-esm/lib/ui/components/StylePanel/StylePanelButtonPicker.mjs.map +7 -0
  132. package/dist-esm/lib/ui/components/StylePanel/StylePanelContext.mjs +48 -0
  133. package/dist-esm/lib/ui/components/StylePanel/StylePanelContext.mjs.map +7 -0
  134. package/dist-esm/lib/ui/components/StylePanel/{DoubleDropdownPicker.mjs → StylePanelDoubleDropdownPicker.mjs} +20 -19
  135. package/dist-esm/lib/ui/components/StylePanel/StylePanelDoubleDropdownPicker.mjs.map +7 -0
  136. package/dist-esm/lib/ui/components/StylePanel/{DropdownPicker.mjs → StylePanelDropdownPicker.mjs} +20 -17
  137. package/dist-esm/lib/ui/components/StylePanel/StylePanelDropdownPicker.mjs.map +7 -0
  138. package/dist-esm/lib/ui/components/StylePanel/StylePanelSubheading.mjs +8 -0
  139. package/dist-esm/lib/ui/components/StylePanel/StylePanelSubheading.mjs.map +7 -0
  140. package/dist-esm/lib/ui/components/Toolbar/AltTextEditor.mjs +1 -0
  141. package/dist-esm/lib/ui/components/Toolbar/AltTextEditor.mjs.map +2 -2
  142. package/dist-esm/lib/ui/components/Toolbar/LinkEditor.mjs +2 -1
  143. package/dist-esm/lib/ui/components/Toolbar/LinkEditor.mjs.map +2 -2
  144. package/dist-esm/lib/ui/components/primitives/TldrawUiContextualToolbar.mjs +2 -2
  145. package/dist-esm/lib/ui/components/primitives/TldrawUiContextualToolbar.mjs.map +1 -1
  146. package/dist-esm/lib/ui/components/primitives/TldrawUiInput.mjs +3 -3
  147. package/dist-esm/lib/ui/components/primitives/TldrawUiInput.mjs.map +2 -2
  148. package/dist-esm/lib/ui/components/primitives/TldrawUiSlider.mjs +1 -1
  149. package/dist-esm/lib/ui/components/primitives/TldrawUiSlider.mjs.map +2 -2
  150. package/dist-esm/lib/ui/components/primitives/TldrawUiToolbar.mjs +3 -0
  151. package/dist-esm/lib/ui/components/primitives/TldrawUiToolbar.mjs.map +2 -2
  152. package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs +45 -5
  153. package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs.map +2 -2
  154. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.mjs +3 -0
  155. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.mjs.map +2 -2
  156. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs +5 -5
  157. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs.map +1 -1
  158. package/dist-esm/lib/ui/context/actions.mjs +13 -8
  159. package/dist-esm/lib/ui/context/actions.mjs.map +2 -2
  160. package/dist-esm/lib/ui/hooks/useClipboardEvents.mjs +2 -2
  161. package/dist-esm/lib/ui/hooks/useClipboardEvents.mjs.map +2 -2
  162. package/dist-esm/lib/ui/hooks/useExportAs.mjs +3 -2
  163. package/dist-esm/lib/ui/hooks/useExportAs.mjs.map +2 -2
  164. package/dist-esm/lib/ui/hooks/useTools.mjs +1 -1
  165. package/dist-esm/lib/ui/hooks/useTools.mjs.map +2 -2
  166. package/dist-esm/lib/ui/hooks/useTranslation/defaultTranslation.mjs +4 -2
  167. package/dist-esm/lib/ui/hooks/useTranslation/defaultTranslation.mjs.map +2 -2
  168. package/dist-esm/lib/ui/version.mjs +3 -3
  169. package/dist-esm/lib/ui/version.mjs.map +1 -1
  170. package/dist-esm/lib/utils/export/copyAs.mjs +1 -2
  171. package/dist-esm/lib/utils/export/copyAs.mjs.map +2 -2
  172. package/dist-esm/lib/utils/export/export.mjs +0 -20
  173. package/dist-esm/lib/utils/export/export.mjs.map +2 -2
  174. package/dist-esm/lib/utils/export/exportAs.mjs +1 -2
  175. package/dist-esm/lib/utils/export/exportAs.mjs.map +2 -2
  176. package/package.json +3 -3
  177. package/src/index.ts +38 -21
  178. package/src/lib/defaultExternalContentHandlers.ts +14 -0
  179. package/src/lib/shapes/arrow/ArrowShapeTool.test.ts +2 -2
  180. package/src/lib/shapes/arrow/ArrowShapeUtil.test.ts +41 -0
  181. package/src/lib/shapes/arrow/arrowLabel.ts +8 -0
  182. package/src/lib/shapes/bookmark/BookmarkShapeUtil.tsx +5 -5
  183. package/src/lib/shapes/frame/FrameShapeUtil.tsx +1 -0
  184. package/src/lib/shapes/frame/components/FrameLabelInput.tsx +3 -3
  185. package/src/lib/shapes/geo/GeoShapeUtil.tsx +1 -0
  186. package/src/lib/shapes/note/NoteShapeUtil.tsx +1 -0
  187. package/src/lib/shapes/shared/HyperlinkButton.tsx +5 -5
  188. package/src/lib/shapes/shared/PlainTextLabel.tsx +0 -6
  189. package/src/lib/shapes/shared/useEditablePlainText.ts +5 -9
  190. package/src/lib/shapes/shared/useImageOrVideoAsset.ts +0 -7
  191. package/src/lib/shapes/text/PlainTextArea.tsx +3 -3
  192. package/src/lib/shapes/text/RichTextArea.tsx +3 -4
  193. package/src/lib/ui/components/A11y.tsx +2 -2
  194. package/src/lib/ui/components/LanguageMenu.tsx +1 -0
  195. package/src/lib/ui/components/Minimap/DefaultMinimap.tsx +1 -0
  196. package/src/lib/ui/components/PageMenu/DefaultPageMenu.tsx +2 -2
  197. package/src/lib/ui/components/StylePanel/DefaultStylePanel.tsx +27 -13
  198. package/src/lib/ui/components/StylePanel/DefaultStylePanelContent.tsx +260 -381
  199. package/src/lib/ui/components/{primitives/TldrawUiButtonPicker.tsx → StylePanel/StylePanelButtonPicker.tsx} +70 -50
  200. package/src/lib/ui/components/StylePanel/StylePanelContext.tsx +63 -0
  201. package/src/lib/ui/components/StylePanel/{DoubleDropdownPicker.tsx → StylePanelDoubleDropdownPicker.tsx} +28 -19
  202. package/src/lib/ui/components/StylePanel/StylePanelDropdownPicker.tsx +119 -0
  203. package/src/lib/ui/components/StylePanel/StylePanelSubheading.tsx +9 -0
  204. package/src/lib/ui/components/Toolbar/AltTextEditor.tsx +1 -0
  205. package/src/lib/ui/components/Toolbar/LinkEditor.tsx +1 -0
  206. package/src/lib/ui/components/primitives/TldrawUiContextualToolbar.tsx +2 -2
  207. package/src/lib/ui/components/primitives/TldrawUiInput.tsx +3 -3
  208. package/src/lib/ui/components/primitives/TldrawUiSlider.tsx +2 -2
  209. package/src/lib/ui/components/primitives/TldrawUiToolbar.tsx +5 -1
  210. package/src/lib/ui/components/primitives/TldrawUiTooltip.tsx +63 -16
  211. package/src/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.tsx +4 -0
  212. package/src/lib/ui/components/primitives/menus/TldrawUiMenuItem.tsx +6 -6
  213. package/src/lib/ui/context/actions.tsx +20 -8
  214. package/src/lib/ui/hooks/useClipboardEvents.ts +2 -2
  215. package/src/lib/ui/hooks/useExportAs.ts +3 -2
  216. package/src/lib/ui/hooks/useTools.tsx +1 -1
  217. package/src/lib/ui/hooks/useTranslation/TLUiTranslationKey.ts +2 -0
  218. package/src/lib/ui/hooks/useTranslation/defaultTranslation.ts +4 -2
  219. package/src/lib/ui/version.ts +3 -3
  220. package/src/lib/ui.css +26 -2
  221. package/src/lib/utils/export/copyAs.ts +1 -24
  222. package/src/lib/utils/export/export.ts +0 -36
  223. package/src/lib/utils/export/exportAs.ts +1 -32
  224. package/src/test/getCulledShapes.test.tsx +71 -2
  225. package/tldraw.css +34 -5
  226. package/dist-cjs/lib/ui/components/StylePanel/DoubleDropdownPicker.js.map +0 -7
  227. package/dist-cjs/lib/ui/components/StylePanel/DropdownPicker.js.map +0 -7
  228. package/dist-cjs/lib/ui/components/primitives/TldrawUiButtonPicker.js +0 -131
  229. package/dist-cjs/lib/ui/components/primitives/TldrawUiButtonPicker.js.map +0 -7
  230. package/dist-esm/lib/ui/components/StylePanel/DoubleDropdownPicker.mjs.map +0 -7
  231. package/dist-esm/lib/ui/components/StylePanel/DropdownPicker.mjs.map +0 -7
  232. package/dist-esm/lib/ui/components/primitives/TldrawUiButtonPicker.mjs +0 -115
  233. package/dist-esm/lib/ui/components/primitives/TldrawUiButtonPicker.mjs.map +0 -7
  234. package/src/lib/ui/components/StylePanel/DropdownPicker.tsx +0 -110
@@ -4,46 +4,52 @@ import {
4
4
  SharedStyle,
5
5
  StyleProp,
6
6
  TLDefaultColorStyle,
7
- TLDefaultColorTheme,
8
7
  useEditor,
9
8
  } from '@tldraw/editor'
10
9
  import { memo, ReactElement, useMemo, useRef } from 'react'
10
+ import { useDefaultColorTheme } from '../../../shapes/shared/useDefaultColorTheme'
11
11
  import { StyleValuesForUi } from '../../../styles'
12
12
  import { PORTRAIT_BREAKPOINT } from '../../constants'
13
13
  import { useBreakpoint } from '../../context/breakpoints'
14
14
  import { TLUiTranslationKey } from '../../hooks/useTranslation/TLUiTranslationKey'
15
15
  import { useTranslation } from '../../hooks/useTranslation/useTranslation'
16
- import { TldrawUiButtonIcon } from './Button/TldrawUiButtonIcon'
17
- import { TldrawUiToolbarToggleGroup, TldrawUiToolbarToggleItem } from './TldrawUiToolbar'
18
- import { TldrawUiGrid, TldrawUiRow } from './layout'
16
+ import { TldrawUiButtonIcon } from '../primitives/Button/TldrawUiButtonIcon'
17
+ import {
18
+ TldrawUiToolbar,
19
+ TldrawUiToolbarToggleGroup,
20
+ TldrawUiToolbarToggleItem,
21
+ } from '../primitives/TldrawUiToolbar'
22
+ import { TldrawUiGrid, TldrawUiRow } from '../primitives/layout'
23
+ import { useStylePanelContext } from './StylePanelContext'
24
+ import { StylePanelSubheading } from './StylePanelSubheading'
19
25
 
20
26
  /** @public */
21
- export interface TLUiButtonPickerProps<T extends string> {
27
+ export interface StylePanelButtonPickerProps<T extends string> {
22
28
  title: string
23
29
  uiType: string
24
30
  style: StyleProp<T>
25
31
  value: SharedStyle<T>
26
32
  items: StyleValuesForUi<T>
27
- theme: TLDefaultColorTheme
28
- onValueChange(style: StyleProp<T>, value: T): void
33
+ onValueChange?(style: StyleProp<T>, value: T): void
29
34
  onHistoryMark?(id: string): void
30
35
  }
31
36
 
32
37
  /** @public */
33
- export const TldrawUiButtonPicker = memo(function TldrawUiButtonPicker<T extends string>(
34
- props: TLUiButtonPickerProps<T>
38
+ export const StylePanelButtonPicker = memo(function StylePanelButtonPicker<T extends string>(
39
+ props: StylePanelButtonPickerProps<T>
35
40
  ) {
41
+ const ctx = useStylePanelContext()
42
+
36
43
  const {
37
44
  uiType,
38
45
  items,
39
46
  title,
40
47
  style,
41
48
  value,
42
- // columns = clamp(items.length, 2, 4),
43
- onValueChange,
44
- onHistoryMark,
45
- theme,
49
+ onValueChange = ctx.onValueChange,
50
+ onHistoryMark = ctx.onHistoryMark,
46
51
  } = props
52
+ const theme = useDefaultColorTheme()
47
53
  const editor = useEditor()
48
54
  const msg = useTranslation()
49
55
  const breakpoint = useBreakpoint()
@@ -117,43 +123,57 @@ export const TldrawUiButtonPicker = memo(function TldrawUiButtonPicker<T extends
117
123
  }
118
124
  }, [editor, breakpoint, value, onHistoryMark, onValueChange, style])
119
125
 
120
- const Wrapper = items.length > 4 ? TldrawUiGrid : TldrawUiRow
126
+ const Layout = items.length > 4 ? TldrawUiGrid : TldrawUiRow
121
127
 
122
128
  return (
123
- <Wrapper asChild>
124
- <TldrawUiToolbarToggleGroup
125
- data-testid={`style.${uiType}`}
126
- type="single"
127
- value={value.type === 'shared' ? value.value : undefined}
128
- >
129
- {items.map((item) => {
130
- const label = title + ' — ' + msg(`${uiType}-style.${item.value}` as TLUiTranslationKey)
131
- return (
132
- <TldrawUiToolbarToggleItem
133
- type="icon"
134
- key={item.value}
135
- data-id={item.value}
136
- data-testid={`style.${uiType}.${item.value}`}
137
- aria-label={label}
138
- value={item.value}
139
- data-state={value.type === 'shared' && value.value === item.value ? 'on' : 'off'}
140
- data-isactive={value.type === 'shared' && value.value === item.value}
141
- title={label}
142
- style={
143
- style === (DefaultColorStyle as StyleProp<unknown>)
144
- ? { color: getColorValue(theme, item.value as TLDefaultColorStyle, 'solid') }
145
- : undefined
146
- }
147
- onPointerEnter={handleButtonPointerEnter}
148
- onPointerDown={handleButtonPointerDown}
149
- onPointerUp={handleButtonPointerUp}
150
- onClick={handleButtonClick}
151
- >
152
- <TldrawUiButtonIcon icon={item.icon} />
153
- </TldrawUiToolbarToggleItem>
154
- )
155
- })}
156
- </TldrawUiToolbarToggleGroup>
157
- </Wrapper>
129
+ <>
130
+ {ctx.showUiLabels && <StylePanelSubheading>{title}</StylePanelSubheading>}
131
+ <TldrawUiToolbar label={title}>
132
+ <TldrawUiToolbarToggleGroup
133
+ data-testid={`style.${uiType}`}
134
+ type="single"
135
+ value={value.type === 'shared' ? value.value : undefined}
136
+ asChild
137
+ >
138
+ <Layout>
139
+ {items.map((item) => {
140
+ const isActive = value.type === 'shared' && value.value === item.value
141
+ const label =
142
+ title + ' — ' + msg(`${uiType}-style.${item.value}` as TLUiTranslationKey)
143
+ return (
144
+ <TldrawUiToolbarToggleItem
145
+ type="icon"
146
+ key={item.value}
147
+ data-id={item.value}
148
+ data-testid={`style.${uiType}.${item.value}`}
149
+ aria-label={label + (isActive ? ` (${msg('style-panel.selected')})` : '')}
150
+ tooltip={
151
+ <>
152
+ <div>{label}</div>
153
+ {isActive ? <div>({msg('style-panel.selected')})</div> : null}
154
+ </>
155
+ }
156
+ value={item.value}
157
+ data-state={value.type === 'shared' && value.value === item.value ? 'on' : 'off'}
158
+ data-isactive={isActive}
159
+ title={label}
160
+ style={
161
+ style === (DefaultColorStyle as StyleProp<unknown>)
162
+ ? { color: getColorValue(theme, item.value as TLDefaultColorStyle, 'solid') }
163
+ : undefined
164
+ }
165
+ onPointerEnter={handleButtonPointerEnter}
166
+ onPointerDown={handleButtonPointerDown}
167
+ onPointerUp={handleButtonPointerUp}
168
+ onClick={handleButtonClick}
169
+ >
170
+ <TldrawUiButtonIcon icon={item.icon} />
171
+ </TldrawUiToolbarToggleItem>
172
+ )
173
+ })}
174
+ </Layout>
175
+ </TldrawUiToolbarToggleGroup>
176
+ </TldrawUiToolbar>
177
+ </>
158
178
  )
159
- }) as <T extends string>(props: TLUiButtonPickerProps<T>) => ReactElement
179
+ }) as <T extends string>(props: StylePanelButtonPickerProps<T>) => ReactElement
@@ -0,0 +1,63 @@
1
+ import { ReadonlySharedStyleMap, StyleProp, useEditor, useValue } from '@tldraw/editor'
2
+ import { createContext, useCallback, useContext } from 'react'
3
+ import { useUiEvents } from '../../context/events'
4
+
5
+ /** @public */
6
+ export interface StylePanelContext {
7
+ styles: ReadonlySharedStyleMap
8
+ showUiLabels: boolean
9
+ onHistoryMark(id: string): void
10
+ onValueChange<T>(style: StyleProp<T>, value: T): void
11
+ }
12
+ const StylePanelContext = createContext<null | StylePanelContext>(null)
13
+
14
+ /** @public */
15
+ export interface StylePanelContextProviderProps {
16
+ children: React.ReactNode
17
+ styles: ReadonlySharedStyleMap
18
+ }
19
+
20
+ /** @public @react */
21
+ export function StylePanelContextProvider({ children, styles }: StylePanelContextProviderProps) {
22
+ const editor = useEditor()
23
+ const trackEvent = useUiEvents()
24
+
25
+ const onHistoryMark = useCallback((id: string) => editor.markHistoryStoppingPoint(id), [editor])
26
+ const showUiLabels = useValue('showUiLabels', () => editor.user.getShowUiLabels(), [editor])
27
+ const onValueChange = useCallback(
28
+ function <T>(style: StyleProp<T>, value: T) {
29
+ editor.run(() => {
30
+ if (editor.isIn('select')) {
31
+ editor.setStyleForSelectedShapes(style, value)
32
+ }
33
+ editor.setStyleForNextShapes(style, value)
34
+ editor.updateInstanceState({ isChangingStyle: true })
35
+ })
36
+
37
+ trackEvent('set-style', { source: 'style-panel', id: style.id, value: value as string })
38
+ },
39
+ [editor, trackEvent]
40
+ )
41
+
42
+ return (
43
+ <StylePanelContext.Provider
44
+ value={{
45
+ styles: styles,
46
+ showUiLabels,
47
+ onHistoryMark,
48
+ onValueChange,
49
+ }}
50
+ >
51
+ {children}
52
+ </StylePanelContext.Provider>
53
+ )
54
+ }
55
+
56
+ /** @public */
57
+ export function useStylePanelContext() {
58
+ const context = useContext(StylePanelContext)
59
+ if (!context) {
60
+ throw new Error('useStylePanelContext must be used within a StylePanelContextProvider')
61
+ }
62
+ return context
63
+ }
@@ -11,8 +11,10 @@ import {
11
11
  } from '../primitives/TldrawUiPopover'
12
12
  import { TldrawUiToolbar, TldrawUiToolbarButton } from '../primitives/TldrawUiToolbar'
13
13
  import { TldrawUiMenuContextProvider } from '../primitives/menus/TldrawUiMenuContext'
14
+ import { useStylePanelContext } from './StylePanelContext'
14
15
 
15
- interface DoubleDropdownPickerProps<T extends string> {
16
+ /** @public */
17
+ export interface StylePanelDoubleDropdownPickerProps<T extends string> {
16
18
  uiTypeA: string
17
19
  uiTypeB: string
18
20
  label: TLUiTranslationKey | Exclude<string, TLUiTranslationKey>
@@ -24,23 +26,27 @@ interface DoubleDropdownPickerProps<T extends string> {
24
26
  styleB: StyleProp<T>
25
27
  valueA: SharedStyle<T>
26
28
  valueB: SharedStyle<T>
27
- onValueChange(style: StyleProp<T>, value: T): void
29
+ onValueChange?(style: StyleProp<T>, value: T): void
28
30
  }
29
31
 
30
- function DoubleDropdownPickerInner<T extends string>({
31
- label,
32
- uiTypeA,
33
- uiTypeB,
34
- labelA,
35
- labelB,
36
- itemsA,
37
- itemsB,
38
- styleA,
39
- styleB,
40
- valueA,
41
- valueB,
42
- onValueChange,
43
- }: DoubleDropdownPickerProps<T>) {
32
+ function DoubleDropdownPickerInner<T extends string>(
33
+ props: StylePanelDoubleDropdownPickerProps<T>
34
+ ) {
35
+ const ctx = useStylePanelContext()
36
+ const {
37
+ label,
38
+ uiTypeA,
39
+ uiTypeB,
40
+ labelA,
41
+ labelB,
42
+ itemsA,
43
+ itemsB,
44
+ styleA,
45
+ styleB,
46
+ valueA,
47
+ valueB,
48
+ onValueChange = ctx.onValueChange,
49
+ } = props
44
50
  const editor = useEditor()
45
51
  const msg = useTranslation()
46
52
  const [isOpenA, setIsOpenA] = React.useState(false)
@@ -155,6 +161,9 @@ function DoubleDropdownPickerInner<T extends string>({
155
161
  }
156
162
 
157
163
  // need to memo like this to get generics
158
- export const DoubleDropdownPicker = React.memo(
159
- DoubleDropdownPickerInner
160
- ) as typeof DoubleDropdownPickerInner
164
+ /** @public @react */
165
+ export const StylePanelDoubleDropdownPicker = React.memo(DoubleDropdownPickerInner) as <
166
+ T extends string,
167
+ >(
168
+ props: StylePanelDoubleDropdownPickerProps<T>
169
+ ) => React.JSX.Element
@@ -0,0 +1,119 @@
1
+ import { SharedStyle, StyleProp, tlmenus, useEditor } from '@tldraw/editor'
2
+ import * as React from 'react'
3
+ import { StyleValuesForUi } from '../../../styles'
4
+ import { TLUiTranslationKey } from '../../hooks/useTranslation/TLUiTranslationKey'
5
+ import { useTranslation } from '../../hooks/useTranslation/useTranslation'
6
+ import { TLUiIconType } from '../../icon-types'
7
+ import { TldrawUiButtonIcon } from '../primitives/Button/TldrawUiButtonIcon'
8
+ import { TldrawUiButtonLabel } from '../primitives/Button/TldrawUiButtonLabel'
9
+ import {
10
+ TldrawUiPopover,
11
+ TldrawUiPopoverContent,
12
+ TldrawUiPopoverTrigger,
13
+ } from '../primitives/TldrawUiPopover'
14
+ import { TldrawUiToolbar, TldrawUiToolbarButton } from '../primitives/TldrawUiToolbar'
15
+ import { TldrawUiMenuContextProvider } from '../primitives/menus/TldrawUiMenuContext'
16
+ import { useStylePanelContext } from './StylePanelContext'
17
+
18
+ /** @public */
19
+ export interface StylePanelDropdownPickerProps<T extends string> {
20
+ id: string
21
+ label?: TLUiTranslationKey | Exclude<string, TLUiTranslationKey>
22
+ uiType: string
23
+ stylePanelType: string
24
+ style: StyleProp<T>
25
+ value: SharedStyle<T>
26
+ items: StyleValuesForUi<T>
27
+ type: 'icon' | 'tool' | 'menu'
28
+ onValueChange?(style: StyleProp<T>, value: T): void
29
+ }
30
+
31
+ function DropdownPickerInner<T extends string>(props: StylePanelDropdownPickerProps<T>) {
32
+ const ctx = useStylePanelContext()
33
+ const {
34
+ id,
35
+ label,
36
+ uiType,
37
+ stylePanelType,
38
+ style,
39
+ items,
40
+ type,
41
+ value,
42
+ onValueChange = ctx.onValueChange,
43
+ } = props
44
+ const msg = useTranslation()
45
+ const editor = useEditor()
46
+ const [isOpen, setIsOpen] = React.useState(false)
47
+
48
+ const icon = React.useMemo(
49
+ () => items.find((item) => value.type === 'shared' && item.value === value.value)?.icon,
50
+ [items, value]
51
+ )
52
+
53
+ const stylePanelName = msg(`style-panel.${stylePanelType}` as TLUiTranslationKey)
54
+
55
+ const titleStr =
56
+ value.type === 'mixed'
57
+ ? msg('style-panel.mixed')
58
+ : stylePanelName + ' — ' + msg(`${uiType}-style.${value.value}` as TLUiTranslationKey)
59
+ const labelStr = label ? msg(label) : ''
60
+
61
+ const popoverId = `style panel ${id}`
62
+ return (
63
+ <TldrawUiToolbar label={stylePanelName}>
64
+ <TldrawUiPopover
65
+ id={popoverId}
66
+ open={isOpen}
67
+ onOpenChange={setIsOpen}
68
+ className="tlui-style-panel__dropdown-picker"
69
+ >
70
+ <TldrawUiPopoverTrigger>
71
+ <TldrawUiToolbarButton
72
+ type={type}
73
+ data-testid={`style.${uiType}`}
74
+ data-direction="left"
75
+ title={titleStr}
76
+ >
77
+ {labelStr && <TldrawUiButtonLabel>{labelStr}</TldrawUiButtonLabel>}
78
+ <TldrawUiButtonIcon icon={(icon as TLUiIconType) ?? 'mixed'} />
79
+ </TldrawUiToolbarButton>
80
+ </TldrawUiPopoverTrigger>
81
+ <TldrawUiPopoverContent side="left" align="center">
82
+ <TldrawUiToolbar orientation={items.length > 4 ? 'grid' : 'horizontal'} label={labelStr}>
83
+ <TldrawUiMenuContextProvider type="icons" sourceId="style-panel">
84
+ {items.map((item) => {
85
+ return (
86
+ <TldrawUiToolbarButton
87
+ key={item.value}
88
+ type="icon"
89
+ data-testid={`style.${uiType}.${item.value}`}
90
+ title={
91
+ stylePanelName +
92
+ ' — ' +
93
+ msg(`${uiType}-style.${item.value}` as TLUiTranslationKey)
94
+ }
95
+ isActive={icon === item.icon}
96
+ onClick={() => {
97
+ ctx.onHistoryMark('select style dropdown item')
98
+ onValueChange(style, item.value)
99
+ tlmenus.deleteOpenMenu(popoverId, editor.contextId)
100
+ setIsOpen(false)
101
+ }}
102
+ >
103
+ <TldrawUiButtonIcon icon={item.icon} />
104
+ </TldrawUiToolbarButton>
105
+ )
106
+ })}
107
+ </TldrawUiMenuContextProvider>
108
+ </TldrawUiToolbar>
109
+ </TldrawUiPopoverContent>
110
+ </TldrawUiPopover>
111
+ </TldrawUiToolbar>
112
+ )
113
+ }
114
+
115
+ // need to export like this to get generics
116
+ /** @public @react */
117
+ export const StylePanelDropdownPicker = React.memo(DropdownPickerInner) as <T extends string>(
118
+ props: StylePanelDropdownPickerProps<T>
119
+ ) => React.JSX.Element
@@ -0,0 +1,9 @@
1
+ /** @public */
2
+ export interface StylePanelSubheadingProps {
3
+ children: React.ReactNode
4
+ }
5
+
6
+ /** @public @react */
7
+ export function StylePanelSubheading({ children }: StylePanelSubheadingProps) {
8
+ return <h3 className="tlui-style-panel__subheading">{children}</h3>
9
+ }
@@ -70,6 +70,7 @@ export function AltTextEditor({ shapeId, onClose, source }: AltTextEditorProps)
70
70
  data-testid="media-toolbar.alt-text-input"
71
71
  value={altText}
72
72
  placeholder={msg('tool.media-alt-text-desc')}
73
+ aria-label={msg('tool.media-alt-text-desc')}
73
74
  onValueChange={handleValueChange}
74
75
  onComplete={handleComplete}
75
76
  onCancel={handleAltTextCancel}
@@ -75,6 +75,7 @@ export function LinkEditor({ textEditor, value: initialValue, onClose }: LinkEdi
75
75
  onComplete={handleLinkComplete}
76
76
  onCancel={handleLinkCancel}
77
77
  placeholder="example.com"
78
+ aria-label="example.com"
78
79
  />
79
80
  <TldrawUiToolbarButton
80
81
  className="tlui-rich-text__toolbar-link-visit"
@@ -3,8 +3,8 @@ import {
3
3
  Box,
4
4
  clamp,
5
5
  Editor,
6
+ markEventAsHandled,
6
7
  react,
7
- stopEventPropagation,
8
8
  useAtom,
9
9
  useEditor,
10
10
  usePassThroughMouseOverEvents,
@@ -170,7 +170,7 @@ export const TldrawUiContextualToolbar = ({
170
170
  data-visible={false}
171
171
  data-testid="contextual-toolbar"
172
172
  className={classNames('tlui-contextual-toolbar', className)}
173
- onPointerDown={stopEventPropagation}
173
+ onPointerDown={markEventAsHandled}
174
174
  >
175
175
  <TldrawUiToolbar
176
176
  orientation="horizontal"
@@ -1,4 +1,4 @@
1
- import { stopEventPropagation, tlenv, tltime, useMaybeEditor } from '@tldraw/editor'
1
+ import { tlenv, tltime, useMaybeEditor } from '@tldraw/editor'
2
2
  import classNames from 'classnames'
3
3
  import * as React from 'react'
4
4
  import { TLUiTranslationKey } from '../../hooks/useTranslation/TLUiTranslationKey'
@@ -118,7 +118,7 @@ export const TldrawUiInput = React.forwardRef<HTMLInputElement, TLUiInputProps>(
118
118
  // `onChange` with a duplicated text value.
119
119
  if (isComposing.current) return
120
120
  e.currentTarget.blur()
121
- stopEventPropagation(e)
121
+ e.stopPropagation()
122
122
  onComplete?.(e.currentTarget.value)
123
123
  break
124
124
  }
@@ -126,7 +126,7 @@ export const TldrawUiInput = React.forwardRef<HTMLInputElement, TLUiInputProps>(
126
126
  e.currentTarget.value = rInitialValue.current
127
127
  onCancel?.(e.currentTarget.value)
128
128
  e.currentTarget.blur()
129
- stopEventPropagation(e)
129
+ e.stopPropagation()
130
130
  break
131
131
  }
132
132
  }
@@ -13,7 +13,7 @@ export interface TLUiSliderProps {
13
13
  label: string
14
14
  title: string
15
15
  onValueChange(value: number): void
16
- onHistoryMark(id: string): void
16
+ onHistoryMark?(id: string): void
17
17
  'data-testid'?: string
18
18
  ariaValueModifier?: number
19
19
  }
@@ -53,7 +53,7 @@ export const TldrawUiSlider = React.forwardRef<HTMLDivElement, TLUiSliderProps>(
53
53
 
54
54
  const handlePointerDown = useCallback(() => {
55
55
  tooltipManager.hideAllTooltips()
56
- onHistoryMark('click slider')
56
+ onHistoryMark?.('click slider')
57
57
  }, [onHistoryMark])
58
58
 
59
59
  // N.B. This is a bit silly. The Radix slider auto-focuses which
@@ -71,6 +71,7 @@ export const TldrawUiToolbarButton = React.forwardRef<HTMLButtonElement, TLUiToo
71
71
  draggable={false}
72
72
  data-isactive={isActive}
73
73
  {...props}
74
+ aria-label={props.title}
74
75
  // The tooltip takes care of this.
75
76
  title={undefined}
76
77
  className={classnames('tlui-button', `tlui-button__${type}`, props.className)}
@@ -94,6 +95,7 @@ export interface TLUiToolbarToggleGroupProps extends React.HTMLAttributes<HTMLDi
94
95
  // TODO: fix up this type later
95
96
  defaultValue?: any
96
97
  type: 'single' | 'multiple'
98
+ asChild?: boolean
97
99
  }
98
100
 
99
101
  /** @public @react */
@@ -101,10 +103,12 @@ export const TldrawUiToolbarToggleGroup = ({
101
103
  children,
102
104
  className,
103
105
  type,
106
+ asChild,
104
107
  ...props
105
108
  }: TLUiToolbarToggleGroupProps) => {
106
109
  return (
107
110
  <_Toolbar.ToggleGroup
111
+ asChild={asChild}
108
112
  type={type}
109
113
  {...props}
110
114
  // TODO: this fixes a bug in Radix until they fix it.
@@ -124,7 +128,7 @@ export interface TLUiToolbarToggleItemProps extends React.HTMLAttributes<HTMLBut
124
128
  className?: string
125
129
  type: 'icon' | 'tool'
126
130
  value: string
127
- tooltip?: string
131
+ tooltip?: React.ReactNode
128
132
  }
129
133
 
130
134
  /** @public @react */
@@ -6,6 +6,7 @@ import React, {
6
6
  ReactNode,
7
7
  useContext,
8
8
  useEffect,
9
+ useLayoutEffect,
9
10
  useRef,
10
11
  useState,
11
12
  } from 'react'
@@ -24,18 +25,20 @@ export interface TldrawUiTooltipProps {
24
25
  delayDuration?: number
25
26
  }
26
27
 
28
+ interface CurrentTooltip {
29
+ id: string
30
+ content: ReactNode
31
+ side: 'top' | 'right' | 'bottom' | 'left'
32
+ sideOffset: number
33
+ showOnMobile: boolean
34
+ targetElement: HTMLElement
35
+ delayDuration: number
36
+ }
37
+
27
38
  // Singleton tooltip manager
28
39
  class TooltipManager {
29
40
  private static instance: TooltipManager | null = null
30
- private currentTooltip = atom<{
31
- id: string
32
- content: ReactNode
33
- side: 'top' | 'right' | 'bottom' | 'left'
34
- sideOffset: number
35
- showOnMobile: boolean
36
- targetElement: HTMLElement
37
- delayDuration: number
38
- } | null>('current tooltip', null)
41
+ private currentTooltip = atom<CurrentTooltip | null>('current tooltip', null)
39
42
  private destroyTimeoutId: number | null = null
40
43
 
41
44
  static getInstance(): TooltipManager {
@@ -72,6 +75,15 @@ class TooltipManager {
72
75
  })
73
76
  }
74
77
 
78
+ updateCurrentTooltip(tooltipId: string, update: (tooltip: CurrentTooltip) => CurrentTooltip) {
79
+ this.currentTooltip.update((tooltip) => {
80
+ if (tooltip?.id === tooltipId) {
81
+ return update(tooltip)
82
+ }
83
+ return tooltip
84
+ })
85
+ }
86
+
75
87
  hideTooltip(editor: Editor | null, tooltipId: string, instant: boolean = false) {
76
88
  const hide = () => {
77
89
  // Only hide if this is the current tooltip
@@ -142,6 +154,7 @@ function TooltipSingleton() {
142
154
  const [isOpen, setIsOpen] = useState(false)
143
155
  const triggerRef = useRef<HTMLDivElement>(null)
144
156
  const isFirstShowRef = useRef(true)
157
+ const editor = useMaybeEditor()
145
158
 
146
159
  const currentTooltip = useValue(
147
160
  'current tooltip',
@@ -149,6 +162,28 @@ function TooltipSingleton() {
149
162
  []
150
163
  )
151
164
 
165
+ const cameraState = useValue('camera state', () => editor?.getCameraState(), [editor])
166
+
167
+ // Hide tooltip when camera is moving (panning/zooming)
168
+ useEffect(() => {
169
+ if (cameraState === 'moving' && isOpen && currentTooltip) {
170
+ tooltipManager.hideTooltip(editor, currentTooltip.id, true)
171
+ }
172
+ }, [cameraState, isOpen, currentTooltip, editor])
173
+
174
+ useEffect(() => {
175
+ function handleKeyDown(event: KeyboardEvent) {
176
+ if (event.key === 'Escape' && currentTooltip) {
177
+ tooltipManager.hideTooltip(editor, currentTooltip.id)
178
+ }
179
+ }
180
+
181
+ document.addEventListener('keydown', handleKeyDown)
182
+ return () => {
183
+ document.removeEventListener('keydown', handleKeyDown)
184
+ }
185
+ }, [editor, currentTooltip])
186
+
152
187
  // Update open state and trigger position
153
188
  useEffect(() => {
154
189
  let timer: ReturnType<typeof setTimeout> | null = null
@@ -231,12 +266,11 @@ export const TldrawUiTooltip = forwardRef<HTMLButtonElement, TldrawUiTooltipProp
231
266
  const editor = useMaybeEditor()
232
267
  const tooltipId = useRef<string>(uniqueId())
233
268
  const hasProvider = useContext(TooltipSingletonContext)
269
+ const showUiLabels = useValue('showUiLabels', () => editor?.user.getShowUiLabels(), [editor])
234
270
 
235
271
  const orientationCtx = useTldrawUiOrientation()
236
272
  const sideToUse = side ?? orientationCtx.tooltipSide
237
273
 
238
- const camera = useValue('camera', () => editor?.getCamera(), [])
239
-
240
274
  useEffect(() => {
241
275
  const currentTooltipId = tooltipId.current
242
276
  return () => {
@@ -246,17 +280,30 @@ export const TldrawUiTooltip = forwardRef<HTMLButtonElement, TldrawUiTooltipProp
246
280
  }
247
281
  }, [editor, hasProvider])
248
282
 
249
- useEffect(() => {
250
- tooltipManager.hideTooltip(editor, tooltipId.current, true)
251
- }, [editor, camera])
283
+ useLayoutEffect(() => {
284
+ if (hasProvider && tooltipManager.getCurrentTooltipData()?.id === tooltipId.current) {
285
+ tooltipManager.updateCurrentTooltip(tooltipId.current, (tooltip) => ({
286
+ ...tooltip,
287
+ content,
288
+ side: sideToUse,
289
+ sideOffset,
290
+ showOnMobile,
291
+ }))
292
+ }
293
+ }, [content, sideToUse, sideOffset, showOnMobile, hasProvider])
252
294
 
253
295
  // Don't show tooltip if disabled, no content, or UI labels are disabled
254
296
  if (disabled || !content) {
255
297
  return <>{children}</>
256
298
  }
257
299
 
258
- const delayDurationToUse =
259
- delayDuration ?? (editor?.options.tooltipDelayMs || DEFAULT_TOOLTIP_DELAY_MS)
300
+ let delayDurationToUse
301
+ if (showUiLabels) {
302
+ delayDurationToUse = 0
303
+ } else {
304
+ delayDurationToUse =
305
+ delayDuration ?? (editor?.options.tooltipDelayMs || DEFAULT_TOOLTIP_DELAY_MS)
306
+ }
260
307
 
261
308
  // Fallback to old behavior if no provider
262
309
  if (!hasProvider) {