tldraw 3.16.0-canary.9e000da8269c → 3.16.0-canary.a03de714c746
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.
- package/dist-cjs/index.d.ts +31 -2
- package/dist-cjs/index.js +7 -1
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/shapes/shared/usePrefersReducedMotion.js +10 -1
- package/dist-cjs/lib/shapes/shared/usePrefersReducedMotion.js.map +2 -2
- package/dist-cjs/lib/ui/components/AccessibilityMenu.js +35 -0
- package/dist-cjs/lib/ui/components/AccessibilityMenu.js.map +7 -0
- package/dist-cjs/lib/ui/components/MainMenu/DefaultMainMenuContent.js +3 -3
- package/dist-cjs/lib/ui/components/MainMenu/DefaultMainMenuContent.js.map +2 -2
- package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanel.js +2 -0
- package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanel.js.map +2 -2
- package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanelContent.js +168 -137
- package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanelContent.js.map +2 -2
- package/dist-cjs/lib/ui/components/Toolbar/OverflowingToolbar.js +3 -3
- package/dist-cjs/lib/ui/components/Toolbar/OverflowingToolbar.js.map +2 -2
- package/dist-cjs/lib/ui/components/Toolbar/ToggleToolLockedButton.js +3 -2
- package/dist-cjs/lib/ui/components/Toolbar/ToggleToolLockedButton.js.map +2 -2
- package/dist-cjs/lib/ui/components/menu-items.js +6 -0
- package/dist-cjs/lib/ui/components/menu-items.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/TldrawUiToolbar.js +11 -3
- package/dist-cjs/lib/ui/components/primitives/TldrawUiToolbar.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js +267 -0
- package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js.map +7 -0
- package/dist-cjs/lib/ui/context/TldrawUiContextProvider.js +3 -2
- package/dist-cjs/lib/ui/context/TldrawUiContextProvider.js.map +2 -2
- package/dist-cjs/lib/ui/context/actions.js +15 -0
- package/dist-cjs/lib/ui/context/actions.js.map +2 -2
- package/dist-cjs/lib/ui/context/events.js.map +2 -2
- package/dist-cjs/lib/ui/hooks/useTranslation/TLUiTranslationKey.js.map +1 -1
- package/dist-cjs/lib/ui/hooks/useTranslation/defaultTranslation.js +3 -0
- package/dist-cjs/lib/ui/hooks/useTranslation/defaultTranslation.js.map +2 -2
- package/dist-cjs/lib/ui/version.js +3 -3
- package/dist-cjs/lib/ui/version.js.map +1 -1
- package/dist-esm/index.d.mts +31 -2
- package/dist-esm/index.mjs +11 -1
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/shapes/shared/usePrefersReducedMotion.mjs +10 -1
- package/dist-esm/lib/shapes/shared/usePrefersReducedMotion.mjs.map +2 -2
- package/dist-esm/lib/ui/components/AccessibilityMenu.mjs +19 -0
- package/dist-esm/lib/ui/components/AccessibilityMenu.mjs.map +7 -0
- package/dist-esm/lib/ui/components/MainMenu/DefaultMainMenuContent.mjs +3 -5
- package/dist-esm/lib/ui/components/MainMenu/DefaultMainMenuContent.mjs.map +2 -2
- package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanel.mjs +3 -1
- package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanel.mjs.map +2 -2
- package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanelContent.mjs +168 -137
- package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanelContent.mjs.map +2 -2
- package/dist-esm/lib/ui/components/Toolbar/OverflowingToolbar.mjs +3 -3
- package/dist-esm/lib/ui/components/Toolbar/OverflowingToolbar.mjs.map +2 -2
- package/dist-esm/lib/ui/components/Toolbar/ToggleToolLockedButton.mjs +3 -2
- package/dist-esm/lib/ui/components/Toolbar/ToggleToolLockedButton.mjs.map +2 -2
- package/dist-esm/lib/ui/components/menu-items.mjs +6 -0
- package/dist-esm/lib/ui/components/menu-items.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/TldrawUiToolbar.mjs +11 -3
- package/dist-esm/lib/ui/components/primitives/TldrawUiToolbar.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs +237 -0
- package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs.map +7 -0
- package/dist-esm/lib/ui/context/TldrawUiContextProvider.mjs +3 -2
- package/dist-esm/lib/ui/context/TldrawUiContextProvider.mjs.map +2 -2
- package/dist-esm/lib/ui/context/actions.mjs +15 -0
- package/dist-esm/lib/ui/context/actions.mjs.map +2 -2
- package/dist-esm/lib/ui/context/events.mjs.map +2 -2
- package/dist-esm/lib/ui/hooks/useTranslation/defaultTranslation.mjs +3 -0
- package/dist-esm/lib/ui/hooks/useTranslation/defaultTranslation.mjs.map +2 -2
- package/dist-esm/lib/ui/version.mjs +3 -3
- package/dist-esm/lib/ui/version.mjs.map +1 -1
- package/package.json +3 -3
- package/src/index.ts +8 -0
- package/src/lib/shapes/shared/usePrefersReducedMotion.tsx +11 -1
- package/src/lib/ui/components/AccessibilityMenu.tsx +20 -0
- package/src/lib/ui/components/MainMenu/DefaultMainMenuContent.tsx +4 -4
- package/src/lib/ui/components/StylePanel/DefaultStylePanel.tsx +3 -1
- package/src/lib/ui/components/StylePanel/DefaultStylePanelContent.tsx +171 -128
- package/src/lib/ui/components/Toolbar/OverflowingToolbar.tsx +3 -3
- package/src/lib/ui/components/Toolbar/ToggleToolLockedButton.tsx +14 -11
- package/src/lib/ui/components/menu-items.tsx +8 -0
- package/src/lib/ui/components/primitives/TldrawUiToolbar.tsx +19 -3
- package/src/lib/ui/components/primitives/TldrawUiTooltip.tsx +313 -0
- package/src/lib/ui/context/TldrawUiContextProvider.tsx +23 -20
- package/src/lib/ui/context/actions.tsx +15 -0
- package/src/lib/ui/context/events.tsx +1 -0
- package/src/lib/ui/hooks/useTranslation/TLUiTranslationKey.ts +3 -0
- package/src/lib/ui/hooks/useTranslation/defaultTranslation.ts +3 -0
- package/src/lib/ui/version.ts +3 -3
- package/src/lib/ui.css +57 -1
- package/tldraw.css +59 -1
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
import { Editor, uniqueId, useMaybeEditor, Vec } from '@tldraw/editor'
|
|
2
|
+
import { Tooltip as _Tooltip } from 'radix-ui'
|
|
3
|
+
import React, { createContext, useContext, useEffect, useRef, useState } from 'react'
|
|
4
|
+
import { usePrefersReducedMotion } from '../../../shapes/shared/usePrefersReducedMotion'
|
|
5
|
+
|
|
6
|
+
const DEFAULT_TOOLTIP_DELAY_MS = 700
|
|
7
|
+
|
|
8
|
+
/** @public */
|
|
9
|
+
export interface TldrawUiTooltipProps {
|
|
10
|
+
children: React.ReactNode
|
|
11
|
+
content?: string | React.ReactNode
|
|
12
|
+
side?: 'top' | 'right' | 'bottom' | 'left'
|
|
13
|
+
sideOffset?: number
|
|
14
|
+
disabled?: boolean
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Singleton tooltip manager
|
|
18
|
+
class TooltipManager {
|
|
19
|
+
private static instance: TooltipManager | null = null
|
|
20
|
+
private currentTooltipId: string | null = null
|
|
21
|
+
private currentContent: string | React.ReactNode = ''
|
|
22
|
+
private currentSide: 'top' | 'right' | 'bottom' | 'left' = 'bottom'
|
|
23
|
+
private currentSideOffset: number = 5
|
|
24
|
+
private destroyTimeoutId: number | null = null
|
|
25
|
+
private subscribers: Set<() => void> = new Set()
|
|
26
|
+
private activeElement: HTMLElement | null = null
|
|
27
|
+
private editor: Editor | null = null
|
|
28
|
+
|
|
29
|
+
static getInstance(): TooltipManager {
|
|
30
|
+
if (!TooltipManager.instance) {
|
|
31
|
+
TooltipManager.instance = new TooltipManager()
|
|
32
|
+
}
|
|
33
|
+
return TooltipManager.instance
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
setEditor(editor: Editor | null) {
|
|
37
|
+
this.editor = editor
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
subscribe(callback: () => void): () => void {
|
|
41
|
+
this.subscribers.add(callback)
|
|
42
|
+
return () => this.subscribers.delete(callback)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
private notify() {
|
|
46
|
+
this.subscribers.forEach((callback) => callback())
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
showTooltip(
|
|
50
|
+
tooltipId: string,
|
|
51
|
+
content: string | React.ReactNode,
|
|
52
|
+
element: HTMLElement,
|
|
53
|
+
side: 'top' | 'right' | 'bottom' | 'left' = 'bottom',
|
|
54
|
+
sideOffset: number = 5
|
|
55
|
+
) {
|
|
56
|
+
// Clear any existing destroy timeout
|
|
57
|
+
if (this.destroyTimeoutId) {
|
|
58
|
+
clearTimeout(this.destroyTimeoutId)
|
|
59
|
+
this.destroyTimeoutId = null
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Update current tooltip
|
|
63
|
+
this.currentTooltipId = tooltipId
|
|
64
|
+
this.currentContent = content
|
|
65
|
+
this.currentSide = side
|
|
66
|
+
this.currentSideOffset = sideOffset
|
|
67
|
+
this.activeElement = element
|
|
68
|
+
|
|
69
|
+
this.notify()
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
hideTooltip(tooltipId: string) {
|
|
73
|
+
// Only hide if this is the current tooltip
|
|
74
|
+
if (this.currentTooltipId === tooltipId) {
|
|
75
|
+
// Start destroy timeout (1 second)
|
|
76
|
+
if (this.editor) {
|
|
77
|
+
this.destroyTimeoutId = this.editor.timers.setTimeout(() => {
|
|
78
|
+
this.currentTooltipId = null
|
|
79
|
+
this.currentContent = ''
|
|
80
|
+
this.activeElement = null
|
|
81
|
+
this.destroyTimeoutId = null
|
|
82
|
+
this.notify()
|
|
83
|
+
}, 300)
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
getCurrentTooltipData() {
|
|
89
|
+
return {
|
|
90
|
+
id: this.currentTooltipId,
|
|
91
|
+
content: this.currentContent,
|
|
92
|
+
side: this.currentSide,
|
|
93
|
+
sideOffset: this.currentSideOffset,
|
|
94
|
+
element: this.activeElement,
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const tooltipManager = TooltipManager.getInstance()
|
|
100
|
+
|
|
101
|
+
// Context for the tooltip singleton
|
|
102
|
+
const TooltipSingletonContext = createContext<boolean>(false)
|
|
103
|
+
|
|
104
|
+
/** @public */
|
|
105
|
+
export interface TldrawUiTooltipProviderProps {
|
|
106
|
+
children: React.ReactNode
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** @public @react */
|
|
110
|
+
export function TldrawUiTooltipProvider({ children }: TldrawUiTooltipProviderProps) {
|
|
111
|
+
return (
|
|
112
|
+
<_Tooltip.Provider skipDelayDuration={700}>
|
|
113
|
+
<TooltipSingletonContext.Provider value={true}>
|
|
114
|
+
{children}
|
|
115
|
+
<TooltipSingleton />
|
|
116
|
+
</TooltipSingletonContext.Provider>
|
|
117
|
+
</_Tooltip.Provider>
|
|
118
|
+
)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// The singleton tooltip component that renders once
|
|
122
|
+
function TooltipSingleton() {
|
|
123
|
+
const editor = useMaybeEditor()
|
|
124
|
+
const [, forceUpdate] = useState({})
|
|
125
|
+
const [isOpen, setIsOpen] = useState(false)
|
|
126
|
+
const triggerRef = useRef<HTMLDivElement>(null)
|
|
127
|
+
const previousPositionRef = useRef<{ x: number; y: number } | null>(null)
|
|
128
|
+
const prefersReducedMotion = usePrefersReducedMotion()
|
|
129
|
+
const [shouldAnimate, setShouldAnimate] = useState(false)
|
|
130
|
+
const isFirstShowRef = useRef(true)
|
|
131
|
+
const showTimeoutRef = useRef<number | null>(null)
|
|
132
|
+
|
|
133
|
+
// Set editor in tooltip manager
|
|
134
|
+
useEffect(() => {
|
|
135
|
+
tooltipManager.setEditor(editor)
|
|
136
|
+
}, [editor])
|
|
137
|
+
|
|
138
|
+
// Subscribe to tooltip manager updates
|
|
139
|
+
useEffect(() => {
|
|
140
|
+
const unsubscribe = tooltipManager.subscribe(() => {
|
|
141
|
+
forceUpdate({})
|
|
142
|
+
})
|
|
143
|
+
return unsubscribe
|
|
144
|
+
}, [])
|
|
145
|
+
|
|
146
|
+
const tooltipData = tooltipManager.getCurrentTooltipData()
|
|
147
|
+
|
|
148
|
+
// Update open state and trigger position
|
|
149
|
+
useEffect(() => {
|
|
150
|
+
const shouldBeOpen = Boolean(tooltipData.id && tooltipData.element)
|
|
151
|
+
|
|
152
|
+
// Clear any existing show timeout
|
|
153
|
+
if (showTimeoutRef.current) {
|
|
154
|
+
clearTimeout(showTimeoutRef.current)
|
|
155
|
+
showTimeoutRef.current = null
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (shouldBeOpen && tooltipData.element && triggerRef.current) {
|
|
159
|
+
// Position the invisible trigger element over the active element
|
|
160
|
+
const activeRect = tooltipData.element.getBoundingClientRect()
|
|
161
|
+
const trigger = triggerRef.current
|
|
162
|
+
|
|
163
|
+
const newPosition = {
|
|
164
|
+
x: activeRect.left + activeRect.width / 2,
|
|
165
|
+
y: activeRect.top + activeRect.height / 2,
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Determine if we should animate
|
|
169
|
+
let shouldAnimateCheck = false
|
|
170
|
+
if (previousPositionRef.current) {
|
|
171
|
+
const isNearPrevious = Vec.DistMin(previousPositionRef.current, newPosition, 200)
|
|
172
|
+
// Only animate if the distance is less than 200px (nearby tooltips)
|
|
173
|
+
shouldAnimateCheck =
|
|
174
|
+
!prefersReducedMotion &&
|
|
175
|
+
isNearPrevious &&
|
|
176
|
+
Math.abs(newPosition.y - previousPositionRef.current.y) < 50
|
|
177
|
+
}
|
|
178
|
+
// Don't animate on initial show (previousPositionRef.current is null)
|
|
179
|
+
|
|
180
|
+
setShouldAnimate(isFirstShowRef.current ? false : shouldAnimateCheck)
|
|
181
|
+
previousPositionRef.current = newPosition
|
|
182
|
+
|
|
183
|
+
trigger.style.position = 'fixed'
|
|
184
|
+
trigger.style.left = `${activeRect.left}px`
|
|
185
|
+
trigger.style.top = `${activeRect.top}px`
|
|
186
|
+
trigger.style.width = `${activeRect.width}px`
|
|
187
|
+
trigger.style.height = `${activeRect.height}px`
|
|
188
|
+
trigger.style.pointerEvents = 'none'
|
|
189
|
+
trigger.style.zIndex = '9999'
|
|
190
|
+
|
|
191
|
+
// Handle delay for first show
|
|
192
|
+
if (isFirstShowRef.current && editor) {
|
|
193
|
+
showTimeoutRef.current = editor.timers.setTimeout(() => {
|
|
194
|
+
setIsOpen(true)
|
|
195
|
+
isFirstShowRef.current = false
|
|
196
|
+
}, editor.options.tooltipDelayMs)
|
|
197
|
+
} else {
|
|
198
|
+
// Subsequent tooltips show immediately
|
|
199
|
+
setIsOpen(true)
|
|
200
|
+
}
|
|
201
|
+
} else if (!shouldBeOpen) {
|
|
202
|
+
// Hide tooltip immediately
|
|
203
|
+
setIsOpen(false)
|
|
204
|
+
// Reset position tracking when tooltip closes
|
|
205
|
+
previousPositionRef.current = null
|
|
206
|
+
setShouldAnimate(false)
|
|
207
|
+
// Reset first show state after tooltip is hidden
|
|
208
|
+
isFirstShowRef.current = true
|
|
209
|
+
}
|
|
210
|
+
}, [tooltipData.id, tooltipData.element, editor, prefersReducedMotion])
|
|
211
|
+
|
|
212
|
+
if (!tooltipData.id) {
|
|
213
|
+
return null
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
return (
|
|
217
|
+
<_Tooltip.Root open={isOpen} delayDuration={0}>
|
|
218
|
+
<_Tooltip.Trigger asChild>
|
|
219
|
+
<div ref={triggerRef} />
|
|
220
|
+
</_Tooltip.Trigger>
|
|
221
|
+
<_Tooltip.Content
|
|
222
|
+
className="tlui-tooltip"
|
|
223
|
+
data-should-animate={shouldAnimate}
|
|
224
|
+
side={tooltipData.side}
|
|
225
|
+
sideOffset={tooltipData.sideOffset}
|
|
226
|
+
avoidCollisions
|
|
227
|
+
collisionPadding={8}
|
|
228
|
+
dir="ltr"
|
|
229
|
+
>
|
|
230
|
+
{tooltipData.content}
|
|
231
|
+
<_Tooltip.Arrow className="tlui-tooltip__arrow" />
|
|
232
|
+
</_Tooltip.Content>
|
|
233
|
+
</_Tooltip.Root>
|
|
234
|
+
)
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/** @public @react */
|
|
238
|
+
export function TldrawUiTooltip({
|
|
239
|
+
children,
|
|
240
|
+
content,
|
|
241
|
+
side = 'bottom',
|
|
242
|
+
sideOffset = 5,
|
|
243
|
+
disabled = false,
|
|
244
|
+
}: TldrawUiTooltipProps) {
|
|
245
|
+
const editor = useMaybeEditor()
|
|
246
|
+
const tooltipId = useRef<string>(uniqueId())
|
|
247
|
+
const hasProvider = useContext(TooltipSingletonContext)
|
|
248
|
+
|
|
249
|
+
// Don't show tooltip if disabled, no content, or UI labels are disabled
|
|
250
|
+
if (disabled || !content) {
|
|
251
|
+
return <>{children}</>
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Fallback to old behavior if no provider
|
|
255
|
+
if (!hasProvider) {
|
|
256
|
+
return (
|
|
257
|
+
<_Tooltip.Root
|
|
258
|
+
delayDuration={editor?.options.tooltipDelayMs || DEFAULT_TOOLTIP_DELAY_MS}
|
|
259
|
+
disableHoverableContent
|
|
260
|
+
>
|
|
261
|
+
<_Tooltip.Trigger asChild>{children}</_Tooltip.Trigger>
|
|
262
|
+
<_Tooltip.Content
|
|
263
|
+
className="tlui-tooltip"
|
|
264
|
+
side={side}
|
|
265
|
+
sideOffset={sideOffset}
|
|
266
|
+
avoidCollisions
|
|
267
|
+
collisionPadding={8}
|
|
268
|
+
dir="ltr"
|
|
269
|
+
>
|
|
270
|
+
{content}
|
|
271
|
+
<_Tooltip.Arrow className="tlui-tooltip__arrow" />
|
|
272
|
+
</_Tooltip.Content>
|
|
273
|
+
</_Tooltip.Root>
|
|
274
|
+
)
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const handleMouseEnter = (event: React.MouseEvent<HTMLElement>) => {
|
|
278
|
+
tooltipManager.showTooltip(
|
|
279
|
+
tooltipId.current,
|
|
280
|
+
content,
|
|
281
|
+
event.currentTarget as HTMLElement,
|
|
282
|
+
side,
|
|
283
|
+
sideOffset
|
|
284
|
+
)
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
const handleMouseLeave = () => {
|
|
288
|
+
tooltipManager.hideTooltip(tooltipId.current)
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
const handleFocus = (event: React.FocusEvent<HTMLElement>) => {
|
|
292
|
+
tooltipManager.showTooltip(
|
|
293
|
+
tooltipId.current,
|
|
294
|
+
content,
|
|
295
|
+
event.currentTarget as HTMLElement,
|
|
296
|
+
side,
|
|
297
|
+
sideOffset
|
|
298
|
+
)
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
const handleBlur = () => {
|
|
302
|
+
tooltipManager.hideTooltip(tooltipId.current)
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
const childrenWithHandlers = React.cloneElement(children as React.ReactElement, {
|
|
306
|
+
onMouseEnter: handleMouseEnter,
|
|
307
|
+
onMouseLeave: handleMouseLeave,
|
|
308
|
+
onFocus: handleFocus,
|
|
309
|
+
onBlur: handleBlur,
|
|
310
|
+
})
|
|
311
|
+
|
|
312
|
+
return childrenWithHandlers
|
|
313
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { RecursivePartial, defaultUserPreferences, track, useMaybeEditor } from '@tldraw/editor'
|
|
2
2
|
import { ReactNode } from 'react'
|
|
3
3
|
import { TLUiAssetUrls, useDefaultUiAssetUrlsWithOverrides } from '../assetUrls'
|
|
4
|
+
import { TldrawUiTooltipProvider } from '../components/primitives/TldrawUiTooltip'
|
|
4
5
|
import { ToolsProvider } from '../hooks/useTools'
|
|
5
6
|
import { TldrawUiTranslationProvider } from '../hooks/useTranslation/useTranslation'
|
|
6
7
|
import {
|
|
@@ -72,26 +73,28 @@ export const TldrawUiContextProvider = track(function TldrawUiContextProvider({
|
|
|
72
73
|
const editor = useMaybeEditor()
|
|
73
74
|
return (
|
|
74
75
|
<MimeTypeContext.Provider value={mediaMimeTypes}>
|
|
75
|
-
<
|
|
76
|
-
<
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
<
|
|
82
|
-
<
|
|
83
|
-
<
|
|
84
|
-
<
|
|
85
|
-
<
|
|
86
|
-
<
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
76
|
+
<TldrawUiTooltipProvider>
|
|
77
|
+
<AssetUrlsProvider assetUrls={useDefaultUiAssetUrlsWithOverrides(assetUrls)}>
|
|
78
|
+
<TldrawUiTranslationProvider
|
|
79
|
+
overrides={useMergedTranslationOverrides(overrides)}
|
|
80
|
+
locale={editor?.user.getLocale() ?? defaultUserPreferences.locale}
|
|
81
|
+
>
|
|
82
|
+
<TldrawUiEventsProvider onEvent={onUiEvent}>
|
|
83
|
+
<TldrawUiToastsProvider>
|
|
84
|
+
<TldrawUiDialogsProvider context={'tla'}>
|
|
85
|
+
<TldrawUiA11yProvider>
|
|
86
|
+
<BreakPointProvider forceMobile={forceMobile}>
|
|
87
|
+
<TldrawUiComponentsProvider overrides={components}>
|
|
88
|
+
<InternalProviders overrides={overrides}>{children}</InternalProviders>
|
|
89
|
+
</TldrawUiComponentsProvider>
|
|
90
|
+
</BreakPointProvider>
|
|
91
|
+
</TldrawUiA11yProvider>
|
|
92
|
+
</TldrawUiDialogsProvider>
|
|
93
|
+
</TldrawUiToastsProvider>
|
|
94
|
+
</TldrawUiEventsProvider>
|
|
95
|
+
</TldrawUiTranslationProvider>
|
|
96
|
+
</AssetUrlsProvider>
|
|
97
|
+
</TldrawUiTooltipProvider>
|
|
95
98
|
</MimeTypeContext.Provider>
|
|
96
99
|
)
|
|
97
100
|
})
|
|
@@ -1266,6 +1266,21 @@ export function ActionsProvider({ overrides, children }: ActionsProviderProps) {
|
|
|
1266
1266
|
},
|
|
1267
1267
|
checkbox: true,
|
|
1268
1268
|
},
|
|
1269
|
+
{
|
|
1270
|
+
id: 'toggle-ui-labels',
|
|
1271
|
+
label: {
|
|
1272
|
+
default: 'action.toggle-ui-labels',
|
|
1273
|
+
menu: 'action.toggle-ui-labels.menu',
|
|
1274
|
+
},
|
|
1275
|
+
readonlyOk: true,
|
|
1276
|
+
onSelect(source) {
|
|
1277
|
+
trackEvent('toggle-ui-labels', { source })
|
|
1278
|
+
editor.user.updateUserPreferences({
|
|
1279
|
+
showUiLabels: !editor.user.getShowUiLabels(),
|
|
1280
|
+
})
|
|
1281
|
+
},
|
|
1282
|
+
checkbox: true,
|
|
1283
|
+
},
|
|
1269
1284
|
{
|
|
1270
1285
|
id: 'toggle-edge-scrolling',
|
|
1271
1286
|
label: {
|
|
@@ -93,6 +93,8 @@ export type TLUiTranslationKey =
|
|
|
93
93
|
| 'action.toggle-reduce-motion'
|
|
94
94
|
| 'action.toggle-keyboard-shortcuts.menu'
|
|
95
95
|
| 'action.toggle-keyboard-shortcuts'
|
|
96
|
+
| 'action.toggle-ui-labels.menu'
|
|
97
|
+
| 'action.toggle-ui-labels'
|
|
96
98
|
| 'action.toggle-edge-scrolling.menu'
|
|
97
99
|
| 'action.toggle-edge-scrolling'
|
|
98
100
|
| 'action.toggle-debug-mode.menu'
|
|
@@ -298,6 +300,7 @@ export type TLUiTranslationKey =
|
|
|
298
300
|
| 'a11y.open-keyboard-shortcuts'
|
|
299
301
|
| 'menu.title'
|
|
300
302
|
| 'menu.theme'
|
|
303
|
+
| 'menu.accessibility'
|
|
301
304
|
| 'menu.copy-as'
|
|
302
305
|
| 'menu.edit'
|
|
303
306
|
| 'menu.export-as'
|
|
@@ -94,6 +94,8 @@ export const DEFAULT_TRANSLATION = {
|
|
|
94
94
|
'action.toggle-reduce-motion': 'Toggle reduce motion',
|
|
95
95
|
'action.toggle-keyboard-shortcuts.menu': 'Keyboard shortcuts',
|
|
96
96
|
'action.toggle-keyboard-shortcuts': 'Toggle keyboard shortcuts',
|
|
97
|
+
'action.toggle-ui-labels.menu': 'UI labels',
|
|
98
|
+
'action.toggle-ui-labels': 'Toggle UI labels',
|
|
97
99
|
'action.toggle-edge-scrolling.menu': 'Edge scrolling',
|
|
98
100
|
'action.toggle-edge-scrolling': 'Toggle edge scrolling',
|
|
99
101
|
'action.toggle-debug-mode.menu': 'Debug mode',
|
|
@@ -299,6 +301,7 @@ export const DEFAULT_TRANSLATION = {
|
|
|
299
301
|
'a11y.open-keyboard-shortcuts': 'Open keyboard shortcuts',
|
|
300
302
|
'menu.title': 'Menu',
|
|
301
303
|
'menu.theme': 'Theme',
|
|
304
|
+
'menu.accessibility': 'Accessibility',
|
|
302
305
|
'menu.copy-as': 'Copy as',
|
|
303
306
|
'menu.edit': 'Edit',
|
|
304
307
|
'menu.export-as': 'Export as',
|
package/src/lib/ui/version.ts
CHANGED
|
@@ -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 = '3.16.0-canary.
|
|
4
|
+
export const version = '3.16.0-canary.a03de714c746'
|
|
5
5
|
export const publishDates = {
|
|
6
6
|
major: '2024-09-13T14:36:29.063Z',
|
|
7
|
-
minor: '2025-08-
|
|
8
|
-
patch: '2025-08-
|
|
7
|
+
minor: '2025-08-06T14:07:34.822Z',
|
|
8
|
+
patch: '2025-08-06T14:07:34.822Z',
|
|
9
9
|
}
|
package/src/lib/ui.css
CHANGED
|
@@ -97,7 +97,7 @@
|
|
|
97
97
|
opacity: 1;
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
.tlui-button[aria-expanded='true'][data-direction='left']
|
|
100
|
+
.tlui-button[aria-expanded='true'][data-direction='left'] {
|
|
101
101
|
background: linear-gradient(270deg, rgba(144, 144, 144, 0) 0%, var(--color-muted-2) 100%);
|
|
102
102
|
opacity: 1;
|
|
103
103
|
}
|
|
@@ -1000,6 +1000,12 @@
|
|
|
1000
1000
|
max-width: 148px;
|
|
1001
1001
|
}
|
|
1002
1002
|
|
|
1003
|
+
.tlui-style-panel[data-show-ui-labels='true'] .tlui-button[data-isactive='true'] {
|
|
1004
|
+
border-radius: 10px;
|
|
1005
|
+
outline: 2px solid var(--color-text);
|
|
1006
|
+
outline-offset: -5px;
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1003
1009
|
.tlui-style-panel::-webkit-scrollbar {
|
|
1004
1010
|
display: none;
|
|
1005
1011
|
}
|
|
@@ -1064,6 +1070,26 @@
|
|
|
1064
1070
|
}
|
|
1065
1071
|
}
|
|
1066
1072
|
|
|
1073
|
+
/* Accessibility subheadings */
|
|
1074
|
+
|
|
1075
|
+
.tlui-style-panel__section .tlui-style-panel__subheading,
|
|
1076
|
+
.tlui-style-panel__section__common .tlui-style-panel__subheading,
|
|
1077
|
+
.tlui-style-panel__subheading + .tlui-slider__container {
|
|
1078
|
+
margin: 0;
|
|
1079
|
+
padding: var(--space-2) var(--space-3) 0px var(--space-4);
|
|
1080
|
+
font-size: 12px;
|
|
1081
|
+
font-weight: inherit;
|
|
1082
|
+
line-height: inherit;
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
.tlui-style-panel .tlui-style-panel__subheading:nth-of-type(1) {
|
|
1086
|
+
padding-top: var(--space-3);
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
.tlui-style-panel__subheading + .tlui-slider__container {
|
|
1090
|
+
padding-top: 0px;
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1067
1093
|
/* --------------------- Bottom --------------------- */
|
|
1068
1094
|
|
|
1069
1095
|
.tlui-layout__bottom {
|
|
@@ -1222,6 +1248,36 @@
|
|
|
1222
1248
|
transition: transform 0.15s ease-out 0.05s;
|
|
1223
1249
|
}
|
|
1224
1250
|
|
|
1251
|
+
/* ------------------- Tooltip -------------------- */
|
|
1252
|
+
|
|
1253
|
+
.tlui-tooltip {
|
|
1254
|
+
font-size: 12px;
|
|
1255
|
+
padding: 2px 8px;
|
|
1256
|
+
border-radius: 4px;
|
|
1257
|
+
background-color: var(--color-tooltip);
|
|
1258
|
+
box-shadow: none;
|
|
1259
|
+
color: var(--color-text-shadow);
|
|
1260
|
+
max-width: 400px;
|
|
1261
|
+
width: fit-content;
|
|
1262
|
+
text-align: center;
|
|
1263
|
+
pointer-events: none;
|
|
1264
|
+
will-change: transform, opacity;
|
|
1265
|
+
z-index: 2;
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1268
|
+
.tlui-tooltip__arrow {
|
|
1269
|
+
fill: var(--color-tooltip);
|
|
1270
|
+
will-change: opacity;
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
[data-radix-popper-content-wrapper]:has(.tlui-tooltip) {
|
|
1274
|
+
z-index: var(--layer-toasts) !important;
|
|
1275
|
+
}
|
|
1276
|
+
|
|
1277
|
+
[data-radix-popper-content-wrapper]:has(.tlui-tooltip[data-should-animate='true']) {
|
|
1278
|
+
transition: all 0.1s ease-out;
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1225
1281
|
/* ------------------- Debug panel ------------------ */
|
|
1226
1282
|
|
|
1227
1283
|
.tlui-debug-panel {
|
package/tldraw.css
CHANGED
|
@@ -167,6 +167,7 @@
|
|
|
167
167
|
--color-selected: hsl(214, 84%, 56%);
|
|
168
168
|
--color-selected-contrast: hsl(0, 0%, 100%);
|
|
169
169
|
--color-focus: hsl(219, 65%, 50%);
|
|
170
|
+
--color-tooltip: hsla(200, 14%, 4%, 1);
|
|
170
171
|
/* Text */
|
|
171
172
|
--color-text: hsl(0, 0%, 0%);
|
|
172
173
|
--color-text-0: hsl(0, 0%, 11%);
|
|
@@ -222,6 +223,7 @@
|
|
|
222
223
|
--color-selected: hsl(217, 89%, 61%);
|
|
223
224
|
--color-selected-contrast: hsl(0, 0%, 100%);
|
|
224
225
|
--color-focus: hsl(217, 76%, 80%);
|
|
226
|
+
--color-tooltip: hsla(0, 0%, 100%, 1);
|
|
225
227
|
/* Text */
|
|
226
228
|
--color-text: hsl(210, 17%, 98%);
|
|
227
229
|
--color-text-0: hsl(0, 9%, 94%);
|
|
@@ -1875,7 +1877,7 @@ it from receiving any pointer events or affecting the cursor. */
|
|
|
1875
1877
|
opacity: 1;
|
|
1876
1878
|
}
|
|
1877
1879
|
|
|
1878
|
-
.tlui-button[aria-expanded='true'][data-direction='left']
|
|
1880
|
+
.tlui-button[aria-expanded='true'][data-direction='left'] {
|
|
1879
1881
|
background: linear-gradient(270deg, rgba(144, 144, 144, 0) 0%, var(--color-muted-2) 100%);
|
|
1880
1882
|
opacity: 1;
|
|
1881
1883
|
}
|
|
@@ -2778,6 +2780,12 @@ it from receiving any pointer events or affecting the cursor. */
|
|
|
2778
2780
|
max-width: 148px;
|
|
2779
2781
|
}
|
|
2780
2782
|
|
|
2783
|
+
.tlui-style-panel[data-show-ui-labels='true'] .tlui-button[data-isactive='true'] {
|
|
2784
|
+
border-radius: 10px;
|
|
2785
|
+
outline: 2px solid var(--color-text);
|
|
2786
|
+
outline-offset: -5px;
|
|
2787
|
+
}
|
|
2788
|
+
|
|
2781
2789
|
.tlui-style-panel::-webkit-scrollbar {
|
|
2782
2790
|
display: none;
|
|
2783
2791
|
}
|
|
@@ -2842,6 +2850,26 @@ it from receiving any pointer events or affecting the cursor. */
|
|
|
2842
2850
|
}
|
|
2843
2851
|
}
|
|
2844
2852
|
|
|
2853
|
+
/* Accessibility subheadings */
|
|
2854
|
+
|
|
2855
|
+
.tlui-style-panel__section .tlui-style-panel__subheading,
|
|
2856
|
+
.tlui-style-panel__section__common .tlui-style-panel__subheading,
|
|
2857
|
+
.tlui-style-panel__subheading + .tlui-slider__container {
|
|
2858
|
+
margin: 0;
|
|
2859
|
+
padding: var(--space-2) var(--space-3) 0px var(--space-4);
|
|
2860
|
+
font-size: 12px;
|
|
2861
|
+
font-weight: inherit;
|
|
2862
|
+
line-height: inherit;
|
|
2863
|
+
}
|
|
2864
|
+
|
|
2865
|
+
.tlui-style-panel .tlui-style-panel__subheading:nth-of-type(1) {
|
|
2866
|
+
padding-top: var(--space-3);
|
|
2867
|
+
}
|
|
2868
|
+
|
|
2869
|
+
.tlui-style-panel__subheading + .tlui-slider__container {
|
|
2870
|
+
padding-top: 0px;
|
|
2871
|
+
}
|
|
2872
|
+
|
|
2845
2873
|
/* --------------------- Bottom --------------------- */
|
|
2846
2874
|
|
|
2847
2875
|
.tlui-layout__bottom {
|
|
@@ -3000,6 +3028,36 @@ it from receiving any pointer events or affecting the cursor. */
|
|
|
3000
3028
|
transition: transform 0.15s ease-out 0.05s;
|
|
3001
3029
|
}
|
|
3002
3030
|
|
|
3031
|
+
/* ------------------- Tooltip -------------------- */
|
|
3032
|
+
|
|
3033
|
+
.tlui-tooltip {
|
|
3034
|
+
font-size: 12px;
|
|
3035
|
+
padding: 2px 8px;
|
|
3036
|
+
border-radius: 4px;
|
|
3037
|
+
background-color: var(--color-tooltip);
|
|
3038
|
+
box-shadow: none;
|
|
3039
|
+
color: var(--color-text-shadow);
|
|
3040
|
+
max-width: 400px;
|
|
3041
|
+
width: fit-content;
|
|
3042
|
+
text-align: center;
|
|
3043
|
+
pointer-events: none;
|
|
3044
|
+
will-change: transform, opacity;
|
|
3045
|
+
z-index: 2;
|
|
3046
|
+
}
|
|
3047
|
+
|
|
3048
|
+
.tlui-tooltip__arrow {
|
|
3049
|
+
fill: var(--color-tooltip);
|
|
3050
|
+
will-change: opacity;
|
|
3051
|
+
}
|
|
3052
|
+
|
|
3053
|
+
[data-radix-popper-content-wrapper]:has(.tlui-tooltip) {
|
|
3054
|
+
z-index: var(--layer-toasts) !important;
|
|
3055
|
+
}
|
|
3056
|
+
|
|
3057
|
+
[data-radix-popper-content-wrapper]:has(.tlui-tooltip[data-should-animate='true']) {
|
|
3058
|
+
transition: all 0.1s ease-out;
|
|
3059
|
+
}
|
|
3060
|
+
|
|
3003
3061
|
/* ------------------- Debug panel ------------------ */
|
|
3004
3062
|
|
|
3005
3063
|
.tlui-debug-panel {
|