tldraw 3.16.0-canary.c1bcdabc9513 → 3.16.0-canary.c7d3f7d5729d
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 +22 -2
- package/dist-cjs/index.js +5 -1
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/Tldraw.js +12 -2
- package/dist-cjs/lib/Tldraw.js.map +2 -2
- package/dist-cjs/lib/defaultExternalContentHandlers.js +5 -4
- package/dist-cjs/lib/defaultExternalContentHandlers.js.map +2 -2
- package/dist-cjs/lib/shapes/frame/FrameShapeUtil.js +6 -0
- package/dist-cjs/lib/shapes/frame/FrameShapeUtil.js.map +2 -2
- package/dist-cjs/lib/shapes/image/ImageShapeUtil.js +3 -0
- package/dist-cjs/lib/shapes/image/ImageShapeUtil.js.map +2 -2
- package/dist-cjs/lib/ui/TldrawUi.js +13 -12
- package/dist-cjs/lib/ui/TldrawUi.js.map +2 -2
- package/dist-cjs/lib/ui/assetUrls.js +13 -10
- package/dist-cjs/lib/ui/assetUrls.js.map +2 -2
- package/dist-cjs/lib/ui/components/{FollowingIndicator.js → DefaultFollowingIndicator.js} +6 -6
- package/dist-cjs/lib/ui/components/DefaultFollowingIndicator.js.map +7 -0
- package/dist-cjs/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.js +6 -6
- package/dist-cjs/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.js.map +1 -1
- package/dist-cjs/lib/ui/components/StylePanel/DropdownPicker.js +1 -1
- package/dist-cjs/lib/ui/components/StylePanel/DropdownPicker.js.map +2 -2
- package/dist-cjs/lib/ui/components/Toolbar/AltTextEditor.js +3 -2
- package/dist-cjs/lib/ui/components/Toolbar/AltTextEditor.js.map +2 -2
- package/dist-cjs/lib/ui/components/Toolbar/DefaultImageToolbarContent.js +38 -9
- package/dist-cjs/lib/ui/components/Toolbar/DefaultImageToolbarContent.js.map +2 -2
- package/dist-cjs/lib/ui/components/Toolbar/DefaultVideoToolbarContent.js +15 -3
- package/dist-cjs/lib/ui/components/Toolbar/DefaultVideoToolbarContent.js.map +2 -2
- package/dist-cjs/lib/ui/components/Toolbar/LinkEditor.js +3 -3
- package/dist-cjs/lib/ui/components/Toolbar/LinkEditor.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/TldrawUiContextualToolbar.js +10 -1
- package/dist-cjs/lib/ui/components/primitives/TldrawUiContextualToolbar.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/TldrawUiSlider.js +17 -4
- package/dist-cjs/lib/ui/components/primitives/TldrawUiSlider.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js +35 -37
- package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js.map +2 -2
- package/dist-cjs/lib/ui/context/actions.js +16 -2
- package/dist-cjs/lib/ui/context/actions.js.map +2 -2
- package/dist-cjs/lib/ui/context/components.js +2 -0
- package/dist-cjs/lib/ui/context/components.js.map +2 -2
- package/dist-cjs/lib/ui/context/events.js.map +1 -1
- package/dist-cjs/lib/ui/hooks/useTranslation/TLUiTranslationKey.js.map +1 -1
- package/dist-cjs/lib/ui/hooks/useTranslation/defaultTranslation.js +2 -0
- package/dist-cjs/lib/ui/hooks/useTranslation/defaultTranslation.js.map +2 -2
- package/dist-cjs/lib/ui/kbd-utils.js +9 -3
- package/dist-cjs/lib/ui/kbd-utils.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 +22 -2
- package/dist-esm/index.mjs +7 -2
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/Tldraw.mjs +14 -4
- package/dist-esm/lib/Tldraw.mjs.map +2 -2
- package/dist-esm/lib/defaultExternalContentHandlers.mjs +5 -4
- package/dist-esm/lib/defaultExternalContentHandlers.mjs.map +2 -2
- package/dist-esm/lib/shapes/frame/FrameShapeUtil.mjs +6 -0
- package/dist-esm/lib/shapes/frame/FrameShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/shapes/image/ImageShapeUtil.mjs +3 -0
- package/dist-esm/lib/shapes/image/ImageShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/ui/TldrawUi.mjs +13 -12
- package/dist-esm/lib/ui/TldrawUi.mjs.map +2 -2
- package/dist-esm/lib/ui/assetUrls.mjs +13 -10
- package/dist-esm/lib/ui/assetUrls.mjs.map +2 -2
- package/dist-esm/lib/ui/components/{FollowingIndicator.mjs → DefaultFollowingIndicator.mjs} +3 -3
- package/dist-esm/lib/ui/components/DefaultFollowingIndicator.mjs.map +7 -0
- package/dist-esm/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.mjs +6 -6
- package/dist-esm/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.mjs.map +1 -1
- package/dist-esm/lib/ui/components/StylePanel/DropdownPicker.mjs +1 -1
- package/dist-esm/lib/ui/components/StylePanel/DropdownPicker.mjs.map +2 -2
- package/dist-esm/lib/ui/components/Toolbar/AltTextEditor.mjs +3 -2
- package/dist-esm/lib/ui/components/Toolbar/AltTextEditor.mjs.map +2 -2
- package/dist-esm/lib/ui/components/Toolbar/DefaultImageToolbarContent.mjs +38 -9
- package/dist-esm/lib/ui/components/Toolbar/DefaultImageToolbarContent.mjs.map +2 -2
- package/dist-esm/lib/ui/components/Toolbar/DefaultVideoToolbarContent.mjs +15 -3
- package/dist-esm/lib/ui/components/Toolbar/DefaultVideoToolbarContent.mjs.map +2 -2
- package/dist-esm/lib/ui/components/Toolbar/LinkEditor.mjs +3 -3
- package/dist-esm/lib/ui/components/Toolbar/LinkEditor.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/TldrawUiContextualToolbar.mjs +10 -1
- package/dist-esm/lib/ui/components/primitives/TldrawUiContextualToolbar.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/TldrawUiSlider.mjs +17 -4
- package/dist-esm/lib/ui/components/primitives/TldrawUiSlider.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs +35 -37
- package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs.map +2 -2
- package/dist-esm/lib/ui/context/actions.mjs +16 -2
- package/dist-esm/lib/ui/context/actions.mjs.map +2 -2
- package/dist-esm/lib/ui/context/components.mjs +2 -0
- package/dist-esm/lib/ui/context/components.mjs.map +2 -2
- package/dist-esm/lib/ui/context/events.mjs.map +1 -1
- package/dist-esm/lib/ui/hooks/useTranslation/defaultTranslation.mjs +2 -0
- package/dist-esm/lib/ui/hooks/useTranslation/defaultTranslation.mjs.map +2 -2
- package/dist-esm/lib/ui/kbd-utils.mjs +9 -3
- package/dist-esm/lib/ui/kbd-utils.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 +3 -1
- package/src/lib/Tldraw.tsx +15 -2
- package/src/lib/defaultExternalContentHandlers.ts +12 -4
- package/src/lib/shapes/frame/FrameShapeUtil.tsx +8 -0
- package/src/lib/shapes/image/ImageShapeUtil.tsx +3 -0
- package/src/lib/ui/TldrawUi.tsx +16 -10
- package/src/lib/ui/assetUrls.ts +13 -10
- package/src/lib/ui/components/{FollowingIndicator.tsx → DefaultFollowingIndicator.tsx} +2 -1
- package/src/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.tsx +6 -6
- package/src/lib/ui/components/StylePanel/DropdownPicker.tsx +1 -1
- package/src/lib/ui/components/Toolbar/AltTextEditor.tsx +4 -3
- package/src/lib/ui/components/Toolbar/DefaultImageToolbarContent.tsx +32 -15
- package/src/lib/ui/components/Toolbar/DefaultVideoToolbarContent.tsx +12 -4
- package/src/lib/ui/components/Toolbar/LinkEditor.tsx +5 -5
- package/src/lib/ui/components/primitives/TldrawUiContextualToolbar.tsx +6 -1
- package/src/lib/ui/components/primitives/TldrawUiSlider.tsx +50 -30
- package/src/lib/ui/components/primitives/TldrawUiTooltip.tsx +26 -22
- package/src/lib/ui/context/actions.tsx +16 -2
- package/src/lib/ui/context/components.tsx +3 -0
- package/src/lib/ui/context/events.tsx +1 -1
- package/src/lib/ui/hooks/useTranslation/TLUiTranslationKey.ts +2 -0
- package/src/lib/ui/hooks/useTranslation/defaultTranslation.ts +2 -0
- package/src/lib/ui/kbd-utils.ts +10 -3
- package/src/lib/ui/version.ts +3 -3
- package/src/lib/ui.css +3 -0
- package/src/test/custom-clipping.test.ts +436 -0
- package/tldraw.css +11 -0
- package/dist-cjs/lib/ui/components/FollowingIndicator.js.map +0 -7
- package/dist-esm/lib/ui/components/FollowingIndicator.mjs.map +0 -7
|
@@ -22,7 +22,6 @@ import {
|
|
|
22
22
|
import { useActions } from '../../context/actions'
|
|
23
23
|
import { useUiEvents } from '../../context/events'
|
|
24
24
|
import { useTranslation } from '../../hooks/useTranslation/useTranslation'
|
|
25
|
-
import { TldrawUiButton } from '../primitives/Button/TldrawUiButton'
|
|
26
25
|
import { TldrawUiButtonIcon } from '../primitives/Button/TldrawUiButtonIcon'
|
|
27
26
|
import { TldrawUiButtonLabel } from '../primitives/Button/TldrawUiButtonLabel'
|
|
28
27
|
import {
|
|
@@ -32,6 +31,7 @@ import {
|
|
|
32
31
|
TldrawUiDropdownMenuTrigger,
|
|
33
32
|
} from '../primitives/TldrawUiDropdownMenu'
|
|
34
33
|
import { TldrawUiSlider } from '../primitives/TldrawUiSlider'
|
|
34
|
+
import { TldrawUiToolbarButton } from '../primitives/TldrawUiToolbar'
|
|
35
35
|
|
|
36
36
|
/** @public */
|
|
37
37
|
export interface DefaultImageToolbarContentProps {
|
|
@@ -226,9 +226,13 @@ export const DefaultImageToolbarContent = track(function DefaultImageToolbarCont
|
|
|
226
226
|
/>
|
|
227
227
|
<TldrawUiDropdownMenuRoot id="image-toolbar-aspect-ratio">
|
|
228
228
|
<TldrawUiDropdownMenuTrigger>
|
|
229
|
-
<
|
|
229
|
+
<TldrawUiToolbarButton
|
|
230
|
+
title={msg('tool.aspect-ratio')}
|
|
231
|
+
type="icon"
|
|
232
|
+
data-testid="tool.image-aspect-ratio"
|
|
233
|
+
>
|
|
230
234
|
<TldrawUiButtonIcon icon="corners" />
|
|
231
|
-
</
|
|
235
|
+
</TldrawUiToolbarButton>
|
|
232
236
|
</TldrawUiDropdownMenuTrigger>
|
|
233
237
|
<TldrawUiDropdownMenuContent side="top" align="center">
|
|
234
238
|
{ASPECT_RATIO_OPTIONS.map((aspectRatio) => {
|
|
@@ -268,14 +272,15 @@ export const DefaultImageToolbarContent = track(function DefaultImageToolbarCont
|
|
|
268
272
|
})}
|
|
269
273
|
</TldrawUiDropdownMenuContent>
|
|
270
274
|
</TldrawUiDropdownMenuRoot>
|
|
271
|
-
<
|
|
275
|
+
<TldrawUiToolbarButton
|
|
272
276
|
type="icon"
|
|
273
277
|
onClick={onManipulatingEnd}
|
|
274
|
-
data-testid="tool.image-confirm"
|
|
278
|
+
data-testid="tool.image-crop-confirm"
|
|
275
279
|
style={{ borderLeft: '1px solid var(--tl-color-divider)', marginLeft: '2px' }}
|
|
280
|
+
title={msg('tool.image-crop-confirm')}
|
|
276
281
|
>
|
|
277
282
|
<TldrawUiButtonIcon small icon="check" />
|
|
278
|
-
</
|
|
283
|
+
</TldrawUiToolbarButton>
|
|
279
284
|
</>
|
|
280
285
|
)
|
|
281
286
|
}
|
|
@@ -283,33 +288,45 @@ export const DefaultImageToolbarContent = track(function DefaultImageToolbarCont
|
|
|
283
288
|
return (
|
|
284
289
|
<>
|
|
285
290
|
{!isReadonly && (
|
|
286
|
-
<
|
|
291
|
+
<TldrawUiToolbarButton
|
|
292
|
+
type="icon"
|
|
293
|
+
data-testid="tool.image-replace"
|
|
294
|
+
onClick={handleImageReplace}
|
|
295
|
+
title={msg('tool.replace-media')}
|
|
296
|
+
>
|
|
287
297
|
<TldrawUiButtonIcon small icon="tool-media" />
|
|
288
|
-
</
|
|
298
|
+
</TldrawUiToolbarButton>
|
|
289
299
|
)}
|
|
290
300
|
{!isReadonly && (
|
|
291
|
-
<
|
|
301
|
+
<TldrawUiToolbarButton
|
|
302
|
+
type="icon"
|
|
303
|
+
title={msg('tool.image-crop')}
|
|
304
|
+
onClick={onManipulatingStart}
|
|
305
|
+
data-testid="tool.image-crop"
|
|
306
|
+
>
|
|
292
307
|
<TldrawUiButtonIcon small icon="crop" />
|
|
293
|
-
</
|
|
308
|
+
</TldrawUiToolbarButton>
|
|
294
309
|
)}
|
|
295
|
-
<
|
|
310
|
+
<TldrawUiToolbarButton
|
|
296
311
|
type="icon"
|
|
297
312
|
title={msg('action.download-original')}
|
|
298
313
|
onClick={handleImageDownload}
|
|
314
|
+
data-testid="tool.image-download"
|
|
299
315
|
>
|
|
300
316
|
<TldrawUiButtonIcon small icon="download" />
|
|
301
|
-
</
|
|
317
|
+
</TldrawUiToolbarButton>
|
|
302
318
|
{(altText || !isReadonly) && (
|
|
303
|
-
<
|
|
304
|
-
type="
|
|
319
|
+
<TldrawUiToolbarButton
|
|
320
|
+
type="icon"
|
|
305
321
|
title={msg('tool.media-alt-text')}
|
|
322
|
+
data-testid="tool.image-alt-text"
|
|
306
323
|
onClick={() => {
|
|
307
324
|
trackEvent('alt-text-start', { source })
|
|
308
325
|
onEditAltTextStart()
|
|
309
326
|
}}
|
|
310
327
|
>
|
|
311
328
|
<TldrawUiButtonIcon small icon="alt" />
|
|
312
|
-
</
|
|
329
|
+
</TldrawUiToolbarButton>
|
|
313
330
|
)}
|
|
314
331
|
</>
|
|
315
332
|
)
|
|
@@ -5,6 +5,7 @@ import { useUiEvents } from '../../context/events'
|
|
|
5
5
|
import { useTranslation } from '../../hooks/useTranslation/useTranslation'
|
|
6
6
|
import { TldrawUiButton } from '../primitives/Button/TldrawUiButton'
|
|
7
7
|
import { TldrawUiButtonIcon } from '../primitives/Button/TldrawUiButtonIcon'
|
|
8
|
+
import { TldrawUiToolbarButton } from '../primitives/TldrawUiToolbar'
|
|
8
9
|
|
|
9
10
|
/** @public */
|
|
10
11
|
export interface DefaultVideoToolbarContentProps {
|
|
@@ -44,7 +45,12 @@ export const DefaultVideoToolbarContent = track(function DefaultVideoToolbarCont
|
|
|
44
45
|
return (
|
|
45
46
|
<>
|
|
46
47
|
{!isReadonly && (
|
|
47
|
-
<TldrawUiButton
|
|
48
|
+
<TldrawUiButton
|
|
49
|
+
type="icon"
|
|
50
|
+
title={msg('tool.replace-media')}
|
|
51
|
+
onClick={handleVideoReplace}
|
|
52
|
+
data-testid="tool.video-replace"
|
|
53
|
+
>
|
|
48
54
|
<TldrawUiButtonIcon small icon="tool-media" />
|
|
49
55
|
</TldrawUiButton>
|
|
50
56
|
)}
|
|
@@ -52,21 +58,23 @@ export const DefaultVideoToolbarContent = track(function DefaultVideoToolbarCont
|
|
|
52
58
|
type="icon"
|
|
53
59
|
title={msg('action.download-original')}
|
|
54
60
|
onClick={handleVideoDownload}
|
|
61
|
+
data-testid="tool.video-download"
|
|
55
62
|
>
|
|
56
63
|
<TldrawUiButtonIcon small icon="download" />
|
|
57
64
|
</TldrawUiButton>
|
|
58
65
|
{(altText || !isReadonly) && (
|
|
59
|
-
<
|
|
60
|
-
type="
|
|
66
|
+
<TldrawUiToolbarButton
|
|
67
|
+
type="icon"
|
|
61
68
|
isActive={!!altText}
|
|
62
69
|
title={msg('tool.media-alt-text')}
|
|
70
|
+
data-testid="tool.video-alt-text"
|
|
63
71
|
onClick={() => {
|
|
64
72
|
trackEvent('alt-text-start', { source })
|
|
65
73
|
onEditAltTextStart()
|
|
66
74
|
}}
|
|
67
75
|
>
|
|
68
76
|
<TldrawUiButtonIcon small icon="alt" />
|
|
69
|
-
</
|
|
77
|
+
</TldrawUiToolbarButton>
|
|
70
78
|
)}
|
|
71
79
|
</>
|
|
72
80
|
)
|
|
@@ -2,9 +2,9 @@ import { preventDefault, TiptapEditor, useEditor } from '@tldraw/editor'
|
|
|
2
2
|
import { useEffect, useRef, useState } from 'react'
|
|
3
3
|
import { useUiEvents } from '../../context/events'
|
|
4
4
|
import { useTranslation } from '../../hooks/useTranslation/useTranslation'
|
|
5
|
-
import { TldrawUiButton } from '../primitives/Button/TldrawUiButton'
|
|
6
5
|
import { TldrawUiButtonIcon } from '../primitives/Button/TldrawUiButtonIcon'
|
|
7
6
|
import { TldrawUiInput } from '../primitives/TldrawUiInput'
|
|
7
|
+
import { TldrawUiToolbarButton } from '../primitives/TldrawUiToolbar'
|
|
8
8
|
|
|
9
9
|
/** @public */
|
|
10
10
|
export interface LinkEditorProps {
|
|
@@ -76,7 +76,7 @@ export function LinkEditor({ textEditor, value: initialValue, onClose }: LinkEdi
|
|
|
76
76
|
onCancel={handleLinkCancel}
|
|
77
77
|
placeholder="example.com"
|
|
78
78
|
/>
|
|
79
|
-
<
|
|
79
|
+
<TldrawUiToolbarButton
|
|
80
80
|
className="tlui-rich-text__toolbar-link-visit"
|
|
81
81
|
title={msg('tool.rich-text-link-visit')}
|
|
82
82
|
type="icon"
|
|
@@ -85,8 +85,8 @@ export function LinkEditor({ textEditor, value: initialValue, onClose }: LinkEdi
|
|
|
85
85
|
disabled={!value}
|
|
86
86
|
>
|
|
87
87
|
<TldrawUiButtonIcon small icon="external-link" />
|
|
88
|
-
</
|
|
89
|
-
<
|
|
88
|
+
</TldrawUiToolbarButton>
|
|
89
|
+
<TldrawUiToolbarButton
|
|
90
90
|
className="tlui-rich-text__toolbar-link-remove"
|
|
91
91
|
title={msg('tool.rich-text-link-remove')}
|
|
92
92
|
data-testid="rich-text.link-remove"
|
|
@@ -95,7 +95,7 @@ export function LinkEditor({ textEditor, value: initialValue, onClose }: LinkEdi
|
|
|
95
95
|
onClick={handleRemoveLink}
|
|
96
96
|
>
|
|
97
97
|
<TldrawUiButtonIcon small icon="trash" />
|
|
98
|
-
</
|
|
98
|
+
</TldrawUiToolbarButton>
|
|
99
99
|
</>
|
|
100
100
|
)
|
|
101
101
|
}
|
|
@@ -172,7 +172,12 @@ export const TldrawUiContextualToolbar = ({
|
|
|
172
172
|
className={classNames('tlui-contextual-toolbar', className)}
|
|
173
173
|
onPointerDown={stopEventPropagation}
|
|
174
174
|
>
|
|
175
|
-
<TldrawUiToolbar
|
|
175
|
+
<TldrawUiToolbar
|
|
176
|
+
orientation="horizontal"
|
|
177
|
+
className="tlui-menu"
|
|
178
|
+
label={label}
|
|
179
|
+
tooltipSide="top"
|
|
180
|
+
>
|
|
176
181
|
{children}
|
|
177
182
|
</TldrawUiToolbar>
|
|
178
183
|
</div>
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import { tltime } from '@tldraw/editor'
|
|
1
2
|
import { Slider as _Slider } from 'radix-ui'
|
|
2
3
|
import React, { useCallback, useEffect, useState } from 'react'
|
|
3
4
|
import { TLUiTranslationKey } from '../../hooks/useTranslation/TLUiTranslationKey'
|
|
4
5
|
import { useTranslation } from '../../hooks/useTranslation/useTranslation'
|
|
6
|
+
import { TldrawUiTooltip, tooltipManager } from './TldrawUiTooltip'
|
|
5
7
|
|
|
6
8
|
/** @public */
|
|
7
9
|
export interface TLUiSliderProps {
|
|
@@ -32,6 +34,7 @@ export const TldrawUiSlider = React.forwardRef<HTMLDivElement, TLUiSliderProps>(
|
|
|
32
34
|
ref
|
|
33
35
|
) {
|
|
34
36
|
const msg = useTranslation()
|
|
37
|
+
const [titleAndLabel, setTitleAndLabel] = useState('')
|
|
35
38
|
|
|
36
39
|
// XXX: Radix starts out our slider with a tabIndex of 0
|
|
37
40
|
// This causes some tab focusing issues, most prevelant in MobileStylePanel,
|
|
@@ -49,9 +52,25 @@ export const TldrawUiSlider = React.forwardRef<HTMLDivElement, TLUiSliderProps>(
|
|
|
49
52
|
)
|
|
50
53
|
|
|
51
54
|
const handlePointerDown = useCallback(() => {
|
|
55
|
+
tooltipManager.hideAllTooltips()
|
|
52
56
|
onHistoryMark('click slider')
|
|
53
57
|
}, [onHistoryMark])
|
|
54
58
|
|
|
59
|
+
// N.B. This is a bit silly. The Radix slider auto-focuses which
|
|
60
|
+
// triggers TldrawUiTooltip handleFocus when we dbl-click to edit an image,
|
|
61
|
+
// which in turn makes the tooltip display prematurely.
|
|
62
|
+
// This makes it wait until we've focused to show the tooltip.
|
|
63
|
+
useEffect(() => {
|
|
64
|
+
const timeout = tltime.setTimeout(
|
|
65
|
+
'set title and label',
|
|
66
|
+
() => {
|
|
67
|
+
setTitleAndLabel(title + ' — ' + msg(label as TLUiTranslationKey))
|
|
68
|
+
},
|
|
69
|
+
0
|
|
70
|
+
)
|
|
71
|
+
return () => clearTimeout(timeout)
|
|
72
|
+
}, [label, msg, title])
|
|
73
|
+
|
|
55
74
|
// N.B. Annoying. For a11y purposes, we need Tab to work.
|
|
56
75
|
// For some reason, Radix has some custom behavior here
|
|
57
76
|
// that interferes with tabbing past the slider and then
|
|
@@ -64,36 +83,37 @@ export const TldrawUiSlider = React.forwardRef<HTMLDivElement, TLUiSliderProps>(
|
|
|
64
83
|
|
|
65
84
|
return (
|
|
66
85
|
<div className="tlui-slider__container">
|
|
67
|
-
<
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
86
|
+
<TldrawUiTooltip content={titleAndLabel}>
|
|
87
|
+
<_Slider.Root
|
|
88
|
+
data-testid={testId}
|
|
89
|
+
className="tlui-slider"
|
|
90
|
+
dir="ltr"
|
|
91
|
+
min={min ?? 0}
|
|
92
|
+
max={steps}
|
|
93
|
+
step={1}
|
|
94
|
+
value={value !== null ? [value] : undefined}
|
|
95
|
+
onPointerDown={handlePointerDown}
|
|
96
|
+
onValueChange={handleValueChange}
|
|
97
|
+
onKeyDownCapture={handleKeyEvent}
|
|
98
|
+
onKeyUpCapture={handleKeyEvent}
|
|
99
|
+
>
|
|
100
|
+
<_Slider.Track className="tlui-slider__track" dir="ltr">
|
|
101
|
+
{value !== null && <_Slider.Range className="tlui-slider__range" dir="ltr" />}
|
|
102
|
+
</_Slider.Track>
|
|
103
|
+
{value !== null && (
|
|
104
|
+
<_Slider.Thumb
|
|
105
|
+
aria-valuemin={(min ?? 0) * ariaValueModifier}
|
|
106
|
+
aria-valuenow={value * ariaValueModifier}
|
|
107
|
+
aria-valuemax={steps * ariaValueModifier}
|
|
108
|
+
aria-label={titleAndLabel}
|
|
109
|
+
className="tlui-slider__thumb"
|
|
110
|
+
dir="ltr"
|
|
111
|
+
ref={ref}
|
|
112
|
+
tabIndex={tabIndex}
|
|
113
|
+
/>
|
|
114
|
+
)}
|
|
115
|
+
</_Slider.Root>
|
|
116
|
+
</TldrawUiTooltip>
|
|
97
117
|
</div>
|
|
98
118
|
)
|
|
99
119
|
})
|
|
@@ -34,7 +34,7 @@ class TooltipManager {
|
|
|
34
34
|
sideOffset: number
|
|
35
35
|
showOnMobile: boolean
|
|
36
36
|
targetElement: HTMLElement
|
|
37
|
-
delayDuration: number
|
|
37
|
+
delayDuration: number
|
|
38
38
|
} | null>('current tooltip', null)
|
|
39
39
|
private destroyTimeoutId: number | null = null
|
|
40
40
|
|
|
@@ -52,7 +52,7 @@ class TooltipManager {
|
|
|
52
52
|
side: 'top' | 'right' | 'bottom' | 'left',
|
|
53
53
|
sideOffset: number,
|
|
54
54
|
showOnMobile: boolean,
|
|
55
|
-
delayDuration: number
|
|
55
|
+
delayDuration: number
|
|
56
56
|
) {
|
|
57
57
|
// Clear any existing destroy timeout
|
|
58
58
|
if (this.destroyTimeoutId) {
|
|
@@ -139,11 +139,9 @@ export function TldrawUiTooltipProvider({ children }: TldrawUiTooltipProviderPro
|
|
|
139
139
|
|
|
140
140
|
// The singleton tooltip component that renders once
|
|
141
141
|
function TooltipSingleton() {
|
|
142
|
-
const editor = useMaybeEditor()
|
|
143
142
|
const [isOpen, setIsOpen] = useState(false)
|
|
144
143
|
const triggerRef = useRef<HTMLDivElement>(null)
|
|
145
144
|
const isFirstShowRef = useRef(true)
|
|
146
|
-
const showTimeoutRef = useRef<number | null>(null)
|
|
147
145
|
|
|
148
146
|
const currentTooltip = useValue(
|
|
149
147
|
'current tooltip',
|
|
@@ -153,12 +151,7 @@ function TooltipSingleton() {
|
|
|
153
151
|
|
|
154
152
|
// Update open state and trigger position
|
|
155
153
|
useEffect(() => {
|
|
156
|
-
|
|
157
|
-
if (showTimeoutRef.current) {
|
|
158
|
-
clearTimeout(showTimeoutRef.current)
|
|
159
|
-
showTimeoutRef.current = null
|
|
160
|
-
}
|
|
161
|
-
|
|
154
|
+
let timer: ReturnType<typeof setTimeout> | null = null
|
|
162
155
|
if (currentTooltip && triggerRef.current) {
|
|
163
156
|
// Position the invisible trigger element over the active element
|
|
164
157
|
const activeRect = currentTooltip.targetElement.getBoundingClientRect()
|
|
@@ -173,11 +166,12 @@ function TooltipSingleton() {
|
|
|
173
166
|
trigger.style.zIndex = '9999'
|
|
174
167
|
|
|
175
168
|
// Handle delay for first show
|
|
176
|
-
if (isFirstShowRef.current
|
|
177
|
-
|
|
169
|
+
if (isFirstShowRef.current) {
|
|
170
|
+
// eslint-disable-next-line no-restricted-globals
|
|
171
|
+
timer = setTimeout(() => {
|
|
178
172
|
setIsOpen(true)
|
|
179
173
|
isFirstShowRef.current = false
|
|
180
|
-
}, currentTooltip.delayDuration
|
|
174
|
+
}, currentTooltip.delayDuration)
|
|
181
175
|
} else {
|
|
182
176
|
// Subsequent tooltips show immediately
|
|
183
177
|
setIsOpen(true)
|
|
@@ -188,7 +182,13 @@ function TooltipSingleton() {
|
|
|
188
182
|
// Reset first show state after tooltip is hidden
|
|
189
183
|
isFirstShowRef.current = true
|
|
190
184
|
}
|
|
191
|
-
|
|
185
|
+
|
|
186
|
+
return () => {
|
|
187
|
+
if (timer !== null) {
|
|
188
|
+
clearTimeout(timer)
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}, [currentTooltip])
|
|
192
192
|
|
|
193
193
|
if (!currentTooltip) {
|
|
194
194
|
return null
|
|
@@ -235,6 +235,8 @@ export const TldrawUiTooltip = forwardRef<HTMLButtonElement, TldrawUiTooltipProp
|
|
|
235
235
|
const orientationCtx = useTldrawUiOrientation()
|
|
236
236
|
const sideToUse = side ?? orientationCtx.tooltipSide
|
|
237
237
|
|
|
238
|
+
const camera = useValue('camera', () => editor?.getCamera(), [])
|
|
239
|
+
|
|
238
240
|
useEffect(() => {
|
|
239
241
|
const currentTooltipId = tooltipId.current
|
|
240
242
|
return () => {
|
|
@@ -244,20 +246,22 @@ export const TldrawUiTooltip = forwardRef<HTMLButtonElement, TldrawUiTooltipProp
|
|
|
244
246
|
}
|
|
245
247
|
}, [editor, hasProvider])
|
|
246
248
|
|
|
249
|
+
useEffect(() => {
|
|
250
|
+
tooltipManager.hideTooltip(editor, tooltipId.current, true)
|
|
251
|
+
}, [editor, camera])
|
|
252
|
+
|
|
247
253
|
// Don't show tooltip if disabled, no content, or UI labels are disabled
|
|
248
254
|
if (disabled || !content) {
|
|
249
255
|
return <>{children}</>
|
|
250
256
|
}
|
|
251
257
|
|
|
258
|
+
const delayDurationToUse =
|
|
259
|
+
delayDuration ?? (editor?.options.tooltipDelayMs || DEFAULT_TOOLTIP_DELAY_MS)
|
|
260
|
+
|
|
252
261
|
// Fallback to old behavior if no provider
|
|
253
262
|
if (!hasProvider) {
|
|
254
263
|
return (
|
|
255
|
-
<_Tooltip.Root
|
|
256
|
-
delayDuration={
|
|
257
|
-
delayDuration ?? (editor?.options.tooltipDelayMs || DEFAULT_TOOLTIP_DELAY_MS)
|
|
258
|
-
}
|
|
259
|
-
disableHoverableContent
|
|
260
|
-
>
|
|
264
|
+
<_Tooltip.Root delayDuration={delayDurationToUse} disableHoverableContent>
|
|
261
265
|
<_Tooltip.Trigger asChild ref={ref}>
|
|
262
266
|
{children}
|
|
263
267
|
</_Tooltip.Trigger>
|
|
@@ -288,7 +292,7 @@ export const TldrawUiTooltip = forwardRef<HTMLButtonElement, TldrawUiTooltipProp
|
|
|
288
292
|
sideToUse,
|
|
289
293
|
sideOffset,
|
|
290
294
|
showOnMobile,
|
|
291
|
-
|
|
295
|
+
delayDurationToUse
|
|
292
296
|
)
|
|
293
297
|
}
|
|
294
298
|
|
|
@@ -306,7 +310,7 @@ export const TldrawUiTooltip = forwardRef<HTMLButtonElement, TldrawUiTooltipProp
|
|
|
306
310
|
sideToUse,
|
|
307
311
|
sideOffset,
|
|
308
312
|
showOnMobile,
|
|
309
|
-
|
|
313
|
+
delayDurationToUse
|
|
310
314
|
)
|
|
311
315
|
}
|
|
312
316
|
|
|
@@ -36,6 +36,7 @@ import { useTranslation } from '../hooks/useTranslation/useTranslation'
|
|
|
36
36
|
import { TLUiIconType } from '../icon-types'
|
|
37
37
|
import { TLUiOverrideHelpers, useDefaultHelpers } from '../overrides'
|
|
38
38
|
import { useA11y } from './a11y'
|
|
39
|
+
import { useTldrawUiComponents } from './components'
|
|
39
40
|
import { TLUiEventSource, useUiEvents } from './events'
|
|
40
41
|
|
|
41
42
|
/** @public */
|
|
@@ -98,6 +99,7 @@ export function ActionsProvider({ overrides, children }: ActionsProviderProps) {
|
|
|
98
99
|
const _editor = useMaybeEditor()
|
|
99
100
|
const showCollaborationUi = useShowCollaborationUi()
|
|
100
101
|
const helpers = useDefaultHelpers()
|
|
102
|
+
const components = useTldrawUiComponents()
|
|
101
103
|
const trackEvent = useUiEvents()
|
|
102
104
|
const a11y = useA11y()
|
|
103
105
|
const msg = useTranslation()
|
|
@@ -176,7 +178,9 @@ export function ActionsProvider({ overrides, children }: ActionsProviderProps) {
|
|
|
176
178
|
kbd: 'cmd+alt+/,ctrl+alt+/',
|
|
177
179
|
onSelect(source) {
|
|
178
180
|
trackEvent('open-kbd-shortcuts', { source })
|
|
179
|
-
helpers.addDialog({
|
|
181
|
+
helpers.addDialog({
|
|
182
|
+
component: components.KeyboardShortcutsDialog ?? DefaultKeyboardShortcutsDialog,
|
|
183
|
+
})
|
|
180
184
|
},
|
|
181
185
|
},
|
|
182
186
|
{
|
|
@@ -1755,7 +1759,17 @@ export function ActionsProvider({ overrides, children }: ActionsProviderProps) {
|
|
|
1755
1759
|
}
|
|
1756
1760
|
|
|
1757
1761
|
return actions
|
|
1758
|
-
}, [
|
|
1762
|
+
}, [
|
|
1763
|
+
helpers,
|
|
1764
|
+
_editor,
|
|
1765
|
+
trackEvent,
|
|
1766
|
+
overrides,
|
|
1767
|
+
defaultDocumentName,
|
|
1768
|
+
showCollaborationUi,
|
|
1769
|
+
msg,
|
|
1770
|
+
a11y,
|
|
1771
|
+
components,
|
|
1772
|
+
])
|
|
1759
1773
|
|
|
1760
1774
|
return <ActionsContext.Provider value={asActions(actions)}>{children}</ActionsContext.Provider>
|
|
1761
1775
|
}
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
import { CursorChatBubble } from '../components/CursorChatBubble'
|
|
13
13
|
import { DefaultDebugMenu } from '../components/DebugMenu/DefaultDebugMenu'
|
|
14
14
|
import { DefaultDebugPanel } from '../components/DefaultDebugPanel'
|
|
15
|
+
import { DefaultFollowingIndicator } from '../components/DefaultFollowingIndicator'
|
|
15
16
|
import { DefaultMenuPanel } from '../components/DefaultMenuPanel'
|
|
16
17
|
import { DefaultDialogs } from '../components/Dialogs'
|
|
17
18
|
import { TLUiHelpMenuProps } from '../components/HelpMenu/DefaultHelpMenu'
|
|
@@ -72,6 +73,7 @@ export interface TLUiComponents {
|
|
|
72
73
|
Dialogs?: ComponentType | null
|
|
73
74
|
Toasts?: ComponentType | null
|
|
74
75
|
A11y?: ComponentType | null
|
|
76
|
+
FollowingIndicator?: ComponentType | null
|
|
75
77
|
}
|
|
76
78
|
|
|
77
79
|
const TldrawUiComponentsContext = createContext<TLUiComponents | null>(null)
|
|
@@ -119,6 +121,7 @@ export function TldrawUiComponentsProvider({
|
|
|
119
121
|
Dialogs: DefaultDialogs,
|
|
120
122
|
Toasts: DefaultToasts,
|
|
121
123
|
A11y: DefaultA11yAnnouncer,
|
|
124
|
+
FollowingIndicator: DefaultFollowingIndicator,
|
|
122
125
|
..._overrides,
|
|
123
126
|
}),
|
|
124
127
|
[_overrides, showCollaborationUi]
|
|
@@ -123,7 +123,7 @@ export interface TLUiEventMap {
|
|
|
123
123
|
'shrink-shapes': null
|
|
124
124
|
'flatten-to-image': null
|
|
125
125
|
'a11y-repeat-shape-announce': null
|
|
126
|
-
'open-url': {
|
|
126
|
+
'open-url': { destinationUrl: string }
|
|
127
127
|
'open-context-menu': null
|
|
128
128
|
'adjust-shape-styles': null
|
|
129
129
|
'copy-link': null
|
|
@@ -186,6 +186,7 @@ export type TLUiTranslationKey =
|
|
|
186
186
|
| 'geo-style.pentagon'
|
|
187
187
|
| 'geo-style.rectangle'
|
|
188
188
|
| 'geo-style.rhombus'
|
|
189
|
+
| 'geo-style.rhombus-2'
|
|
189
190
|
| 'geo-style.star'
|
|
190
191
|
| 'geo-style.trapezoid'
|
|
191
192
|
| 'geo-style.triangle'
|
|
@@ -260,6 +261,7 @@ export type TLUiTranslationKey =
|
|
|
260
261
|
| 'tool.aspect-ratio.wide'
|
|
261
262
|
| 'tool.image-toolbar-title'
|
|
262
263
|
| 'tool.image-crop'
|
|
264
|
+
| 'tool.image-crop-confirm'
|
|
263
265
|
| 'tool.media-alt-text'
|
|
264
266
|
| 'tool.media-alt-text-desc'
|
|
265
267
|
| 'tool.media-alt-text-confirm'
|
|
@@ -187,6 +187,7 @@ export const DEFAULT_TRANSLATION = {
|
|
|
187
187
|
'geo-style.pentagon': 'Pentagon',
|
|
188
188
|
'geo-style.rectangle': 'Rectangle',
|
|
189
189
|
'geo-style.rhombus': 'Rhombus',
|
|
190
|
+
'geo-style.rhombus-2': 'Rhombus left',
|
|
190
191
|
'geo-style.star': 'Star',
|
|
191
192
|
'geo-style.trapezoid': 'Trapezoid',
|
|
192
193
|
'geo-style.triangle': 'Triangle',
|
|
@@ -261,6 +262,7 @@ export const DEFAULT_TRANSLATION = {
|
|
|
261
262
|
'tool.aspect-ratio.wide': 'Wide (16:9)',
|
|
262
263
|
'tool.image-toolbar-title': 'Image tools',
|
|
263
264
|
'tool.image-crop': 'Crop image',
|
|
265
|
+
'tool.image-crop-confirm': 'Confirm',
|
|
264
266
|
'tool.media-alt-text': 'Alternative text',
|
|
265
267
|
'tool.media-alt-text-desc': 'Give a description…',
|
|
266
268
|
'tool.media-alt-text-confirm': 'Confirm',
|
package/src/lib/ui/kbd-utils.ts
CHANGED
|
@@ -31,9 +31,16 @@ export function kbd(str: string) {
|
|
|
31
31
|
)
|
|
32
32
|
.flat()
|
|
33
33
|
.map((sub, index) => {
|
|
34
|
-
if (sub === '
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
if (sub[0] === '+') return []
|
|
35
|
+
|
|
36
|
+
let modifiedKey
|
|
37
|
+
if (sub === '__CTRL__') {
|
|
38
|
+
modifiedKey = 'Ctrl'
|
|
39
|
+
} else if (sub === '__ALT__') {
|
|
40
|
+
modifiedKey = 'Alt'
|
|
41
|
+
} else {
|
|
42
|
+
modifiedKey = sub[0].toUpperCase() + sub.slice(1)
|
|
43
|
+
}
|
|
37
44
|
return tlenv.isDarwin || !index ? modifiedKey : ['+', modifiedKey]
|
|
38
45
|
})
|
|
39
46
|
.flat()
|
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.c7d3f7d5729d'
|
|
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-28T15:31:21.677Z',
|
|
8
|
+
patch: '2025-08-28T15:31:21.677Z',
|
|
9
9
|
}
|
package/src/lib/ui.css
CHANGED
|
@@ -1047,6 +1047,9 @@
|
|
|
1047
1047
|
}
|
|
1048
1048
|
|
|
1049
1049
|
@media (hover: hover) {
|
|
1050
|
+
.tlui-style-panel .tlui-button[aria-expanded='true'] {
|
|
1051
|
+
background: none;
|
|
1052
|
+
}
|
|
1050
1053
|
.tlui-style-panel .tlui-button[data-state='open']:not(:hover)::after {
|
|
1051
1054
|
opacity: 1;
|
|
1052
1055
|
background: linear-gradient(270deg, rgba(144, 144, 144, 0) 0%, var(--tl-color-muted-2) 100%);
|