tldraw 4.3.0-canary.b19495d1a0fa → 4.3.0-canary.b2e9b1218a6b

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 (113) hide show
  1. package/dist-cjs/index.d.ts +3 -0
  2. package/dist-cjs/index.js +2 -1
  3. package/dist-cjs/index.js.map +2 -2
  4. package/dist-cjs/lib/canvas/TldrawSelectionForeground.js +2 -2
  5. package/dist-cjs/lib/canvas/TldrawSelectionForeground.js.map +2 -2
  6. package/dist-cjs/lib/shapes/arrow/ArrowShapeUtil.js +5 -10
  7. package/dist-cjs/lib/shapes/arrow/ArrowShapeUtil.js.map +2 -2
  8. package/dist-cjs/lib/shapes/draw/DrawShapeUtil.js +3 -3
  9. package/dist-cjs/lib/shapes/draw/DrawShapeUtil.js.map +2 -2
  10. package/dist-cjs/lib/shapes/frame/FrameShapeUtil.js +1 -1
  11. package/dist-cjs/lib/shapes/frame/FrameShapeUtil.js.map +2 -2
  12. package/dist-cjs/lib/shapes/geo/GeoShapeUtil.js +3 -4
  13. package/dist-cjs/lib/shapes/geo/GeoShapeUtil.js.map +2 -2
  14. package/dist-cjs/lib/shapes/highlight/HighlightShapeUtil.js +1 -1
  15. package/dist-cjs/lib/shapes/highlight/HighlightShapeUtil.js.map +2 -2
  16. package/dist-cjs/lib/shapes/note/NoteShapeUtil.js +4 -5
  17. package/dist-cjs/lib/shapes/note/NoteShapeUtil.js.map +2 -2
  18. package/dist-cjs/lib/shapes/shared/HyperlinkButton.js +2 -1
  19. package/dist-cjs/lib/shapes/shared/HyperlinkButton.js.map +2 -2
  20. package/dist-cjs/lib/shapes/shared/ShapeFill.js +2 -2
  21. package/dist-cjs/lib/shapes/shared/ShapeFill.js.map +2 -2
  22. package/dist-cjs/lib/shapes/shared/{useForceSolid.js → useEfficientZoomThreshold.js} +10 -7
  23. package/dist-cjs/lib/shapes/shared/useEfficientZoomThreshold.js.map +7 -0
  24. package/dist-cjs/lib/shapes/shared/useImageOrVideoAsset.js +1 -1
  25. package/dist-cjs/lib/shapes/shared/useImageOrVideoAsset.js.map +2 -2
  26. package/dist-cjs/lib/shapes/video/VideoShapeUtil.js +1 -1
  27. package/dist-cjs/lib/shapes/video/VideoShapeUtil.js.map +2 -2
  28. package/dist-cjs/lib/ui/components/ActionsMenu/DefaultActionsMenuContent.js +3 -9
  29. package/dist-cjs/lib/ui/components/ActionsMenu/DefaultActionsMenuContent.js.map +2 -2
  30. package/dist-cjs/lib/ui/components/ZoomMenu/DefaultZoomMenu.js +1 -1
  31. package/dist-cjs/lib/ui/components/ZoomMenu/DefaultZoomMenu.js.map +2 -2
  32. package/dist-cjs/lib/ui/components/menu-items.js +3 -1
  33. package/dist-cjs/lib/ui/components/menu-items.js.map +2 -2
  34. package/dist-cjs/lib/ui/components/primitives/TldrawUiSlider.js +1 -1
  35. package/dist-cjs/lib/ui/components/primitives/TldrawUiSlider.js.map +2 -2
  36. package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js +143 -88
  37. package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js.map +2 -2
  38. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js +1 -1
  39. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js.map +2 -2
  40. package/dist-cjs/lib/ui/version.js +3 -3
  41. package/dist-cjs/lib/ui/version.js.map +1 -1
  42. package/dist-cjs/lib/utils/text/richText.js +7 -17
  43. package/dist-cjs/lib/utils/text/richText.js.map +3 -3
  44. package/dist-esm/index.d.mts +3 -0
  45. package/dist-esm/index.mjs +3 -1
  46. package/dist-esm/index.mjs.map +2 -2
  47. package/dist-esm/lib/canvas/TldrawSelectionForeground.mjs +2 -2
  48. package/dist-esm/lib/canvas/TldrawSelectionForeground.mjs.map +2 -2
  49. package/dist-esm/lib/shapes/arrow/ArrowShapeUtil.mjs +6 -12
  50. package/dist-esm/lib/shapes/arrow/ArrowShapeUtil.mjs.map +2 -2
  51. package/dist-esm/lib/shapes/draw/DrawShapeUtil.mjs +3 -3
  52. package/dist-esm/lib/shapes/draw/DrawShapeUtil.mjs.map +2 -2
  53. package/dist-esm/lib/shapes/frame/FrameShapeUtil.mjs +1 -1
  54. package/dist-esm/lib/shapes/frame/FrameShapeUtil.mjs.map +2 -2
  55. package/dist-esm/lib/shapes/geo/GeoShapeUtil.mjs +3 -4
  56. package/dist-esm/lib/shapes/geo/GeoShapeUtil.mjs.map +2 -2
  57. package/dist-esm/lib/shapes/highlight/HighlightShapeUtil.mjs +1 -1
  58. package/dist-esm/lib/shapes/highlight/HighlightShapeUtil.mjs.map +2 -2
  59. package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs +4 -5
  60. package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs.map +2 -2
  61. package/dist-esm/lib/shapes/shared/HyperlinkButton.mjs +3 -2
  62. package/dist-esm/lib/shapes/shared/HyperlinkButton.mjs.map +2 -2
  63. package/dist-esm/lib/shapes/shared/ShapeFill.mjs +2 -2
  64. package/dist-esm/lib/shapes/shared/ShapeFill.mjs.map +2 -2
  65. package/dist-esm/lib/shapes/shared/useEfficientZoomThreshold.mjs +12 -0
  66. package/dist-esm/lib/shapes/shared/useEfficientZoomThreshold.mjs.map +7 -0
  67. package/dist-esm/lib/shapes/shared/useImageOrVideoAsset.mjs +1 -1
  68. package/dist-esm/lib/shapes/shared/useImageOrVideoAsset.mjs.map +2 -2
  69. package/dist-esm/lib/shapes/video/VideoShapeUtil.mjs +1 -1
  70. package/dist-esm/lib/shapes/video/VideoShapeUtil.mjs.map +2 -2
  71. package/dist-esm/lib/ui/components/ActionsMenu/DefaultActionsMenuContent.mjs +2 -8
  72. package/dist-esm/lib/ui/components/ActionsMenu/DefaultActionsMenuContent.mjs.map +2 -2
  73. package/dist-esm/lib/ui/components/ZoomMenu/DefaultZoomMenu.mjs +1 -1
  74. package/dist-esm/lib/ui/components/ZoomMenu/DefaultZoomMenu.mjs.map +2 -2
  75. package/dist-esm/lib/ui/components/menu-items.mjs +3 -1
  76. package/dist-esm/lib/ui/components/menu-items.mjs.map +2 -2
  77. package/dist-esm/lib/ui/components/primitives/TldrawUiSlider.mjs +2 -2
  78. package/dist-esm/lib/ui/components/primitives/TldrawUiSlider.mjs.map +2 -2
  79. package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs +151 -90
  80. package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs.map +2 -2
  81. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs +2 -2
  82. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs.map +2 -2
  83. package/dist-esm/lib/ui/version.mjs +3 -3
  84. package/dist-esm/lib/ui/version.mjs.map +1 -1
  85. package/dist-esm/lib/utils/text/richText.mjs +3 -3
  86. package/dist-esm/lib/utils/text/richText.mjs.map +2 -2
  87. package/package.json +3 -3
  88. package/src/index.ts +1 -0
  89. package/src/lib/canvas/TldrawSelectionForeground.tsx +2 -2
  90. package/src/lib/shapes/arrow/ArrowShapeUtil.tsx +6 -11
  91. package/src/lib/shapes/draw/DrawShapeUtil.tsx +3 -3
  92. package/src/lib/shapes/frame/FrameShapeUtil.tsx +1 -1
  93. package/src/lib/shapes/geo/GeoShapeUtil.tsx +3 -4
  94. package/src/lib/shapes/highlight/HighlightShapeUtil.tsx +1 -1
  95. package/src/lib/shapes/note/NoteShapeUtil.tsx +6 -8
  96. package/src/lib/shapes/shared/HyperlinkButton.tsx +3 -2
  97. package/src/lib/shapes/shared/ShapeFill.tsx +2 -2
  98. package/src/lib/shapes/shared/useEfficientZoomThreshold.ts +10 -0
  99. package/src/lib/shapes/shared/useImageOrVideoAsset.ts +1 -1
  100. package/src/lib/shapes/video/VideoShapeUtil.tsx +2 -1
  101. package/src/lib/ui/components/ActionsMenu/DefaultActionsMenuContent.tsx +1 -9
  102. package/src/lib/ui/components/ZoomMenu/DefaultZoomMenu.tsx +1 -1
  103. package/src/lib/ui/components/menu-items.tsx +3 -1
  104. package/src/lib/ui/components/primitives/TldrawUiSlider.tsx +2 -2
  105. package/src/lib/ui/components/primitives/TldrawUiTooltip.tsx +196 -108
  106. package/src/lib/ui/components/primitives/menus/TldrawUiMenuItem.tsx +2 -2
  107. package/src/lib/ui/version.ts +3 -3
  108. package/src/lib/utils/text/richText.ts +3 -3
  109. package/src/test/commands/cameraState.test.ts +299 -0
  110. package/dist-cjs/lib/shapes/shared/useForceSolid.js.map +0 -7
  111. package/dist-esm/lib/shapes/shared/useForceSolid.mjs +0 -9
  112. package/dist-esm/lib/shapes/shared/useForceSolid.mjs.map +0 -7
  113. package/src/lib/shapes/shared/useForceSolid.ts +0 -6
@@ -1,4 +1,12 @@
1
- import { assert, Atom, atom, Editor, uniqueId, useMaybeEditor, useValue } from '@tldraw/editor'
1
+ import {
2
+ assert,
3
+ atom,
4
+ Editor,
5
+ tlenvReactive,
6
+ uniqueId,
7
+ useMaybeEditor,
8
+ useValue,
9
+ } from '@tldraw/editor'
2
10
  import { Tooltip as _Tooltip } from 'radix-ui'
3
11
  import React, {
4
12
  createContext,
@@ -6,7 +14,6 @@ import React, {
6
14
  ReactNode,
7
15
  useContext,
8
16
  useEffect,
9
- useLayoutEffect,
10
17
  useRef,
11
18
  useState,
12
19
  } from 'react'
@@ -25,7 +32,7 @@ export interface TldrawUiTooltipProps {
25
32
  delayDuration?: number
26
33
  }
27
34
 
28
- interface CurrentTooltip {
35
+ interface TooltipData {
29
36
  id: string
30
37
  content: ReactNode
31
38
  side: 'top' | 'right' | 'bottom' | 'left'
@@ -35,11 +42,25 @@ interface CurrentTooltip {
35
42
  delayDuration: number
36
43
  }
37
44
 
38
- // Singleton tooltip manager
45
+ // State machine states
46
+ type TooltipState =
47
+ | { name: 'idle' }
48
+ | { name: 'pointer_down' }
49
+ | { name: 'showing'; tooltip: TooltipData }
50
+ | { name: 'waiting_to_hide'; tooltip: TooltipData; timeoutId: number }
51
+
52
+ // State machine events
53
+ type TooltipEvent =
54
+ | { type: 'pointer_down' }
55
+ | { type: 'pointer_up' }
56
+ | { type: 'show'; tooltip: TooltipData }
57
+ | { type: 'hide'; tooltipId: string; editor: Editor | null; instant: boolean }
58
+ | { type: 'hide_all' }
59
+
60
+ // Singleton tooltip manager using explicit state machine
39
61
  class TooltipManager {
40
62
  private static instance: TooltipManager | null = null
41
- private currentTooltip = atom<CurrentTooltip | null>('current tooltip', null)
42
- private destroyTimeoutId: number | null = null
63
+ private state = atom<TooltipState>('tooltip state', { name: 'idle' })
43
64
 
44
65
  static getInstance(): TooltipManager {
45
66
  if (!TooltipManager.instance) {
@@ -48,86 +69,117 @@ class TooltipManager {
48
69
  return TooltipManager.instance
49
70
  }
50
71
 
51
- showTooltip(
52
- tooltipId: string,
53
- content: string | React.ReactNode,
54
- targetElement: HTMLElement,
55
- side: 'top' | 'right' | 'bottom' | 'left',
56
- sideOffset: number,
57
- showOnMobile: boolean,
58
- delayDuration: number
59
- ) {
60
- // Clear any existing destroy timeout
61
- if (this.destroyTimeoutId) {
62
- clearTimeout(this.destroyTimeoutId)
63
- this.destroyTimeoutId = null
64
- }
65
-
66
- // Update current tooltip
67
- this.currentTooltip.set({
68
- id: tooltipId,
69
- content,
70
- side,
71
- sideOffset,
72
- showOnMobile,
73
- targetElement,
74
- delayDuration,
75
- })
72
+ hideAllTooltips() {
73
+ this.handleEvent({ type: 'hide_all' })
76
74
  }
77
75
 
78
- updateCurrentTooltip(tooltipId: string, update: (tooltip: CurrentTooltip) => CurrentTooltip) {
79
- this.currentTooltip.update((tooltip) => {
80
- if (tooltip?.id === tooltipId) {
81
- return update(tooltip)
76
+ handleEvent(event: TooltipEvent) {
77
+ const currentState = this.state.get()
78
+
79
+ switch (event.type) {
80
+ case 'pointer_down': {
81
+ // Transition to pointer_down from any state
82
+ if (currentState.name === 'waiting_to_hide') {
83
+ clearTimeout(currentState.timeoutId)
84
+ }
85
+ this.state.set({ name: 'pointer_down' })
86
+ break
82
87
  }
83
- return tooltip
84
- })
85
- }
86
88
 
87
- hideTooltip(editor: Editor | null, tooltipId: string, instant: boolean = false) {
88
- const hide = () => {
89
- // Only hide if this is the current tooltip
90
- if (this.currentTooltip.get()?.id === tooltipId) {
91
- this.currentTooltip.set(null)
92
- this.destroyTimeoutId = null
89
+ case 'pointer_up': {
90
+ // Only transition from pointer_down to idle
91
+ if (currentState.name === 'pointer_down') {
92
+ this.state.set({ name: 'idle' })
93
+ }
94
+ break
93
95
  }
94
- }
95
96
 
96
- if (editor && !instant) {
97
- // Start destroy timeout (1 second)
98
- this.destroyTimeoutId = editor.timers.setTimeout(hide, 300)
99
- } else {
100
- hide()
101
- }
102
- }
97
+ case 'show': {
98
+ // Don't show tooltips while pointer is down
99
+ if (currentState.name === 'pointer_down') {
100
+ return
101
+ }
103
102
 
104
- hideAllTooltips() {
105
- this.currentTooltip.set(null)
106
- this.destroyTimeoutId = null
107
- }
103
+ // Clear any existing timeout if transitioning from waiting_to_hide
104
+ if (currentState.name === 'waiting_to_hide') {
105
+ clearTimeout(currentState.timeoutId)
106
+ }
107
+
108
+ // Transition to showing state
109
+ this.state.set({ name: 'showing', tooltip: event.tooltip })
110
+ break
111
+ }
112
+
113
+ case 'hide': {
114
+ const { tooltipId, editor, instant } = event
115
+
116
+ // Only hide if the tooltip matches
117
+ if (currentState.name === 'showing' && currentState.tooltip.id === tooltipId) {
118
+ if (editor && !instant) {
119
+ // Transition to waiting_to_hide state
120
+ const timeoutId = editor.timers.setTimeout(() => {
121
+ const state = this.state.get()
122
+ if (state.name === 'waiting_to_hide' && state.tooltip.id === tooltipId) {
123
+ this.state.set({ name: 'idle' })
124
+ }
125
+ }, 300)
126
+ this.state.set({
127
+ name: 'waiting_to_hide',
128
+ tooltip: currentState.tooltip,
129
+ timeoutId,
130
+ })
131
+ } else {
132
+ this.state.set({ name: 'idle' })
133
+ }
134
+ } else if (
135
+ currentState.name === 'waiting_to_hide' &&
136
+ currentState.tooltip.id === tooltipId
137
+ ) {
138
+ // Already waiting to hide, make it instant if requested
139
+ if (instant) {
140
+ clearTimeout(currentState.timeoutId)
141
+ this.state.set({ name: 'idle' })
142
+ }
143
+ }
144
+ break
145
+ }
108
146
 
109
- getCurrentTooltipData() {
110
- const currentTooltip = this.currentTooltip.get()
111
- if (!currentTooltip) return null
112
- if (!this.supportsHover() && !currentTooltip.showOnMobile) return null
113
- return currentTooltip
147
+ case 'hide_all': {
148
+ if (currentState.name === 'waiting_to_hide') {
149
+ clearTimeout(currentState.timeoutId)
150
+ }
151
+ // Preserve pointer_down state if that's the current state
152
+ if (currentState.name === 'pointer_down') {
153
+ return
154
+ }
155
+ this.state.set({ name: 'idle' })
156
+ break
157
+ }
158
+ }
114
159
  }
115
160
 
116
- private supportsHoverAtom: Atom<boolean> | null = null
117
- supportsHover() {
118
- if (!this.supportsHoverAtom) {
119
- const mediaQuery = window.matchMedia('(hover: hover)')
120
- const supportsHover = atom('has hover', mediaQuery.matches)
121
- this.supportsHoverAtom = supportsHover
122
- mediaQuery.addEventListener('change', (e) => {
123
- supportsHover.set(e.matches)
124
- })
161
+ getCurrentTooltipData(): TooltipData | null {
162
+ const currentState = this.state.get()
163
+ let tooltip: TooltipData | null = null
164
+
165
+ if (currentState.name === 'showing') {
166
+ tooltip = currentState.tooltip
167
+ } else if (currentState.name === 'waiting_to_hide') {
168
+ tooltip = currentState.tooltip
125
169
  }
126
- return this.supportsHoverAtom.get()
170
+
171
+ if (!tooltip) return null
172
+ if (tlenvReactive.get().isCoarsePointer && !tooltip.showOnMobile) return null
173
+ return tooltip
127
174
  }
128
175
  }
129
176
 
130
- export const tooltipManager = TooltipManager.getInstance()
177
+ const tooltipManager = TooltipManager.getInstance()
178
+
179
+ /** @public */
180
+ export function hideAllTooltips() {
181
+ tooltipManager.hideAllTooltips()
182
+ }
131
183
 
132
184
  // Context for the tooltip singleton
133
185
  const TooltipSingletonContext = createContext<boolean>(false)
@@ -167,14 +219,19 @@ function TooltipSingleton() {
167
219
  // Hide tooltip when camera is moving (panning/zooming)
168
220
  useEffect(() => {
169
221
  if (cameraState === 'moving' && isOpen && currentTooltip) {
170
- tooltipManager.hideTooltip(editor, currentTooltip.id, true)
222
+ tooltipManager.handleEvent({
223
+ type: 'hide',
224
+ tooltipId: currentTooltip.id,
225
+ editor,
226
+ instant: true,
227
+ })
171
228
  }
172
229
  }, [cameraState, isOpen, currentTooltip, editor])
173
230
 
174
231
  useEffect(() => {
175
232
  function handleKeyDown(event: KeyboardEvent) {
176
233
  if (event.key === 'Escape' && currentTooltip && isOpen) {
177
- tooltipManager.hideTooltip(editor, currentTooltip.id)
234
+ hideAllTooltips()
178
235
  event.stopPropagation()
179
236
  }
180
237
  }
@@ -183,7 +240,29 @@ function TooltipSingleton() {
183
240
  return () => {
184
241
  document.removeEventListener('keydown', handleKeyDown, { capture: true })
185
242
  }
186
- }, [editor, currentTooltip, isOpen])
243
+ }, [currentTooltip, isOpen])
244
+
245
+ // Hide tooltip and prevent new ones from opening while pointer is down
246
+ useEffect(() => {
247
+ function handlePointerDown() {
248
+ tooltipManager.handleEvent({ type: 'pointer_down' })
249
+ }
250
+
251
+ function handlePointerUp() {
252
+ tooltipManager.handleEvent({ type: 'pointer_up' })
253
+ }
254
+
255
+ document.addEventListener('pointerdown', handlePointerDown, { capture: true })
256
+ document.addEventListener('pointerup', handlePointerUp, { capture: true })
257
+ document.addEventListener('pointercancel', handlePointerUp, { capture: true })
258
+ return () => {
259
+ document.removeEventListener('pointerdown', handlePointerDown, { capture: true })
260
+ document.removeEventListener('pointerup', handlePointerUp, { capture: true })
261
+ document.removeEventListener('pointercancel', handlePointerUp, { capture: true })
262
+ // Reset pointer state on unmount to prevent stuck state
263
+ tooltipManager.handleEvent({ type: 'pointer_up' })
264
+ }
265
+ }, [])
187
266
 
188
267
  // Update open state and trigger position
189
268
  useEffect(() => {
@@ -280,23 +359,16 @@ export const TldrawUiTooltip = forwardRef<HTMLButtonElement, TldrawUiTooltipProp
280
359
  const currentTooltipId = tooltipId.current
281
360
  return () => {
282
361
  if (hasProvider) {
283
- tooltipManager.hideTooltip(editor, currentTooltipId, true)
362
+ tooltipManager.handleEvent({
363
+ type: 'hide',
364
+ tooltipId: currentTooltipId,
365
+ editor,
366
+ instant: true,
367
+ })
284
368
  }
285
369
  }
286
370
  }, [editor, hasProvider])
287
371
 
288
- useLayoutEffect(() => {
289
- if (hasProvider && tooltipManager.getCurrentTooltipData()?.id === tooltipId.current) {
290
- tooltipManager.updateCurrentTooltip(tooltipId.current, (tooltip) => ({
291
- ...tooltip,
292
- content,
293
- side: sideToUse,
294
- sideOffset,
295
- showOnMobile,
296
- }))
297
- }
298
- }, [content, sideToUse, sideOffset, showOnMobile, hasProvider])
299
-
300
372
  // Don't show tooltip if disabled, no content, or enhanced accessibility mode is disabled
301
373
  if (disabled || !content) {
302
374
  return <>{children}</>
@@ -340,38 +412,54 @@ export const TldrawUiTooltip = forwardRef<HTMLButtonElement, TldrawUiTooltipProp
340
412
 
341
413
  const handleMouseEnter = (event: React.MouseEvent<HTMLElement>) => {
342
414
  child.props.onMouseEnter?.(event)
343
- tooltipManager.showTooltip(
344
- tooltipId.current,
345
- content,
346
- event.currentTarget as HTMLElement,
347
- sideToUse,
348
- sideOffset,
349
- showOnMobile,
350
- delayDurationToUse
351
- )
415
+ tooltipManager.handleEvent({
416
+ type: 'show',
417
+ tooltip: {
418
+ id: tooltipId.current,
419
+ content,
420
+ targetElement: event.currentTarget as HTMLElement,
421
+ side: sideToUse,
422
+ sideOffset,
423
+ showOnMobile,
424
+ delayDuration: delayDurationToUse,
425
+ },
426
+ })
352
427
  }
353
428
 
354
429
  const handleMouseLeave = (event: React.MouseEvent<HTMLElement>) => {
355
430
  child.props.onMouseLeave?.(event)
356
- tooltipManager.hideTooltip(editor, tooltipId.current)
431
+ tooltipManager.handleEvent({
432
+ type: 'hide',
433
+ tooltipId: tooltipId.current,
434
+ editor,
435
+ instant: false,
436
+ })
357
437
  }
358
438
 
359
439
  const handleFocus = (event: React.FocusEvent<HTMLElement>) => {
360
440
  child.props.onFocus?.(event)
361
- tooltipManager.showTooltip(
362
- tooltipId.current,
363
- content,
364
- event.currentTarget as HTMLElement,
365
- sideToUse,
366
- sideOffset,
367
- showOnMobile,
368
- delayDurationToUse
369
- )
441
+ tooltipManager.handleEvent({
442
+ type: 'show',
443
+ tooltip: {
444
+ id: tooltipId.current,
445
+ content,
446
+ targetElement: event.currentTarget as HTMLElement,
447
+ side: sideToUse,
448
+ sideOffset,
449
+ showOnMobile,
450
+ delayDuration: delayDurationToUse,
451
+ },
452
+ })
370
453
  }
371
454
 
372
455
  const handleBlur = (event: React.FocusEvent<HTMLElement>) => {
373
456
  child.props.onBlur?.(event)
374
- tooltipManager.hideTooltip(editor, tooltipId.current)
457
+ tooltipManager.handleEvent({
458
+ type: 'hide',
459
+ tooltipId: tooltipId.current,
460
+ editor,
461
+ instant: false,
462
+ })
375
463
  }
376
464
 
377
465
  const childrenWithHandlers = React.cloneElement(children as React.ReactElement, {
@@ -24,7 +24,7 @@ import { TldrawUiDropdownMenuItem } from '../TldrawUiDropdownMenu'
24
24
  import { TLUiIconJsx } from '../TldrawUiIcon'
25
25
  import { TldrawUiKbd } from '../TldrawUiKbd'
26
26
  import { TldrawUiToolbarButton } from '../TldrawUiToolbar'
27
- import { tooltipManager } from '../TldrawUiTooltip'
27
+ import { hideAllTooltips } from '../TldrawUiTooltip'
28
28
  import { useTldrawUiMenuContext } from './TldrawUiMenuContext'
29
29
 
30
30
  /** @public */
@@ -350,7 +350,7 @@ function useDraggableEvents(
350
350
  point: screenSpaceStart,
351
351
  })
352
352
 
353
- tooltipManager.hideAllTooltips()
353
+ hideAllTooltips()
354
354
  editor.getContainer().focus()
355
355
  })
356
356
  }
@@ -1,9 +1,9 @@
1
1
  // This file is automatically generated by internal/scripts/refresh-assets.ts.
2
2
  // Do not edit manually. Or do, I'm a comment, not a cop.
3
3
 
4
- export const version = '4.3.0-canary.b19495d1a0fa'
4
+ export const version = '4.3.0-canary.b2e9b1218a6b'
5
5
  export const publishDates = {
6
6
  major: '2025-09-18T14:39:22.803Z',
7
- minor: '2025-12-03T10:58:13.473Z',
8
- patch: '2025-12-03T10:58:13.473Z',
7
+ minor: '2025-12-06T16:52:15.885Z',
8
+ patch: '2025-12-06T16:52:15.885Z',
9
9
  }
@@ -6,10 +6,10 @@ import {
6
6
  generateText,
7
7
  JSONContent,
8
8
  } from '@tiptap/core'
9
- import Code from '@tiptap/extension-code'
10
- import Highlight from '@tiptap/extension-highlight'
9
+ import { Code } from '@tiptap/extension-code'
10
+ import { Highlight } from '@tiptap/extension-highlight'
11
11
  import { Node } from '@tiptap/pm/model'
12
- import StarterKit from '@tiptap/starter-kit'
12
+ import { StarterKit } from '@tiptap/starter-kit'
13
13
  import {
14
14
  Editor,
15
15
  getOwnProperty,