tldraw 3.16.0-canary.ed8bd30c0f28 → 3.16.0-canary.efdec30fc411
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 +89 -4
- package/dist-cjs/index.js +11 -1
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/shapes/arrow/arrowTargetState.js +1 -1
- package/dist-cjs/lib/shapes/arrow/arrowTargetState.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/tools/SelectTool/childStates/Translating.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/ActionsMenu/DefaultActionsMenu.js +2 -1
- package/dist-cjs/lib/ui/components/ActionsMenu/DefaultActionsMenu.js.map +2 -2
- package/dist-cjs/lib/ui/components/DefaultMenuPanel.js +3 -2
- package/dist-cjs/lib/ui/components/DefaultMenuPanel.js.map +2 -2
- 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/NavigationPanel/DefaultNavigationPanel.js +1 -1
- package/dist-cjs/lib/ui/components/NavigationPanel/DefaultNavigationPanel.js.map +2 -2
- package/dist-cjs/lib/ui/components/PageMenu/DefaultPageMenu.js +2 -1
- package/dist-cjs/lib/ui/components/PageMenu/DefaultPageMenu.js.map +2 -2
- package/dist-cjs/lib/ui/components/SharePanel/PeopleMenuItem.js +3 -2
- package/dist-cjs/lib/ui/components/SharePanel/PeopleMenuItem.js.map +2 -2
- package/dist-cjs/lib/ui/components/SharePanel/UserPresenceColorPicker.js +2 -2
- package/dist-cjs/lib/ui/components/SharePanel/UserPresenceColorPicker.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 +171 -140
- package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanelContent.js.map +2 -2
- package/dist-cjs/lib/ui/components/StylePanel/DoubleDropdownPicker.js +3 -3
- package/dist-cjs/lib/ui/components/StylePanel/DoubleDropdownPicker.js.map +2 -2
- package/dist-cjs/lib/ui/components/StylePanel/DropdownPicker.js +26 -25
- package/dist-cjs/lib/ui/components/StylePanel/DropdownPicker.js.map +3 -3
- package/dist-cjs/lib/ui/components/Toolbar/DefaultToolbar.js +6 -5
- package/dist-cjs/lib/ui/components/Toolbar/DefaultToolbar.js.map +2 -2
- package/dist-cjs/lib/ui/components/Toolbar/OverflowingToolbar.js +9 -10
- package/dist-cjs/lib/ui/components/Toolbar/OverflowingToolbar.js.map +2 -2
- package/dist-cjs/lib/ui/components/Toolbar/ToggleToolLockedButton.js +5 -4
- 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/TldrawUiButtonPicker.js +4 -15
- package/dist-cjs/lib/ui/components/primitives/TldrawUiButtonPicker.js.map +3 -3
- package/dist-cjs/lib/ui/components/primitives/TldrawUiContextualToolbar.js +1 -1
- package/dist-cjs/lib/ui/components/primitives/TldrawUiContextualToolbar.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/TldrawUiPopover.js +3 -2
- package/dist-cjs/lib/ui/components/primitives/TldrawUiPopover.js.map +3 -3
- package/dist-cjs/lib/ui/components/primitives/TldrawUiToolbar.js +18 -7
- package/dist-cjs/lib/ui/components/primitives/TldrawUiToolbar.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js +284 -0
- package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js.map +7 -0
- package/dist-cjs/lib/ui/components/primitives/layout.js +51 -0
- package/dist-cjs/lib/ui/components/primitives/layout.js.map +7 -0
- package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js +152 -2
- package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js.map +2 -2
- 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/useTools.js +76 -9
- package/dist-cjs/lib/ui/hooks/useTools.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 +89 -4
- package/dist-esm/index.mjs +19 -1
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/shapes/arrow/arrowTargetState.mjs +1 -1
- package/dist-esm/lib/shapes/arrow/arrowTargetState.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/tools/SelectTool/childStates/Translating.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/ActionsMenu/DefaultActionsMenu.mjs +2 -1
- package/dist-esm/lib/ui/components/ActionsMenu/DefaultActionsMenu.mjs.map +2 -2
- package/dist-esm/lib/ui/components/DefaultMenuPanel.mjs +3 -2
- package/dist-esm/lib/ui/components/DefaultMenuPanel.mjs.map +2 -2
- 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/NavigationPanel/DefaultNavigationPanel.mjs +1 -1
- package/dist-esm/lib/ui/components/NavigationPanel/DefaultNavigationPanel.mjs.map +2 -2
- package/dist-esm/lib/ui/components/PageMenu/DefaultPageMenu.mjs +2 -1
- package/dist-esm/lib/ui/components/PageMenu/DefaultPageMenu.mjs.map +2 -2
- package/dist-esm/lib/ui/components/SharePanel/PeopleMenuItem.mjs +3 -2
- package/dist-esm/lib/ui/components/SharePanel/PeopleMenuItem.mjs.map +2 -2
- package/dist-esm/lib/ui/components/SharePanel/UserPresenceColorPicker.mjs +2 -2
- package/dist-esm/lib/ui/components/SharePanel/UserPresenceColorPicker.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 +171 -140
- package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanelContent.mjs.map +2 -2
- package/dist-esm/lib/ui/components/StylePanel/DoubleDropdownPicker.mjs +3 -3
- package/dist-esm/lib/ui/components/StylePanel/DoubleDropdownPicker.mjs.map +2 -2
- package/dist-esm/lib/ui/components/StylePanel/DropdownPicker.mjs +26 -25
- package/dist-esm/lib/ui/components/StylePanel/DropdownPicker.mjs.map +2 -2
- package/dist-esm/lib/ui/components/Toolbar/DefaultToolbar.mjs +6 -5
- package/dist-esm/lib/ui/components/Toolbar/DefaultToolbar.mjs.map +2 -2
- package/dist-esm/lib/ui/components/Toolbar/OverflowingToolbar.mjs +9 -10
- package/dist-esm/lib/ui/components/Toolbar/OverflowingToolbar.mjs.map +2 -2
- package/dist-esm/lib/ui/components/Toolbar/ToggleToolLockedButton.mjs +5 -4
- 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/TldrawUiButtonPicker.mjs +4 -5
- package/dist-esm/lib/ui/components/primitives/TldrawUiButtonPicker.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/TldrawUiContextualToolbar.mjs +1 -1
- package/dist-esm/lib/ui/components/primitives/TldrawUiContextualToolbar.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/TldrawUiPopover.mjs +3 -2
- package/dist-esm/lib/ui/components/primitives/TldrawUiPopover.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/TldrawUiToolbar.mjs +18 -7
- package/dist-esm/lib/ui/components/primitives/TldrawUiToolbar.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs +254 -0
- package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs.map +7 -0
- package/dist-esm/lib/ui/components/primitives/layout.mjs +21 -0
- package/dist-esm/lib/ui/components/primitives/layout.mjs.map +7 -0
- package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs +160 -4
- package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs.map +2 -2
- 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/useTools.mjs +83 -10
- package/dist-esm/lib/ui/hooks/useTools.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 +15 -0
- package/src/lib/shapes/arrow/arrowTargetState.ts +2 -1
- package/src/lib/shapes/shared/usePrefersReducedMotion.tsx +11 -1
- package/src/lib/tools/SelectTool/childStates/Translating.ts +0 -1
- package/src/lib/ui/components/AccessibilityMenu.tsx +20 -0
- package/src/lib/ui/components/ActionsMenu/DefaultActionsMenu.tsx +2 -1
- package/src/lib/ui/components/DefaultMenuPanel.tsx +4 -3
- package/src/lib/ui/components/MainMenu/DefaultMainMenuContent.tsx +4 -4
- package/src/lib/ui/components/NavigationPanel/DefaultNavigationPanel.tsx +1 -1
- package/src/lib/ui/components/PageMenu/DefaultPageMenu.tsx +3 -2
- package/src/lib/ui/components/SharePanel/PeopleMenuItem.tsx +4 -3
- package/src/lib/ui/components/SharePanel/UserPresenceColorPicker.tsx +3 -3
- package/src/lib/ui/components/StylePanel/DefaultStylePanel.tsx +3 -1
- package/src/lib/ui/components/StylePanel/DefaultStylePanelContent.tsx +146 -107
- package/src/lib/ui/components/StylePanel/DoubleDropdownPicker.tsx +3 -3
- package/src/lib/ui/components/StylePanel/DropdownPicker.tsx +7 -6
- package/src/lib/ui/components/Toolbar/DefaultToolbar.tsx +7 -6
- package/src/lib/ui/components/Toolbar/OverflowingToolbar.tsx +10 -11
- 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/TldrawUiButtonPicker.tsx +38 -36
- package/src/lib/ui/components/primitives/TldrawUiContextualToolbar.tsx +1 -1
- package/src/lib/ui/components/primitives/TldrawUiPopover.tsx +4 -2
- package/src/lib/ui/components/primitives/TldrawUiToolbar.tsx +34 -12
- package/src/lib/ui/components/primitives/TldrawUiTooltip.tsx +332 -0
- package/src/lib/ui/components/primitives/layout.tsx +33 -0
- package/src/lib/ui/components/primitives/menus/TldrawUiMenuItem.tsx +218 -3
- 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 +2 -0
- package/src/lib/ui/hooks/useTools.tsx +118 -10
- 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 +80 -69
- package/src/test/arrows-megabus.test.tsx +12 -6
- package/src/test/inner-outer-margin.test.ts +315 -0
- package/tldraw.css +82 -69
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
TldrawUiPopoverTrigger,
|
|
21
21
|
} from '../primitives/TldrawUiPopover'
|
|
22
22
|
import { TldrawUiToolbar, TldrawUiToolbarButton } from '../primitives/TldrawUiToolbar'
|
|
23
|
+
import { TldrawUiRow } from '../primitives/layout'
|
|
23
24
|
import { TldrawUiMenuContextProvider } from '../primitives/menus/TldrawUiMenuContext'
|
|
24
25
|
|
|
25
26
|
export const IsInOverflowContext = createContext(false)
|
|
@@ -61,15 +62,12 @@ export function OverflowingToolbar({ children }: OverflowingToolbarProps) {
|
|
|
61
62
|
const activeCss = lastActiveOverflowItem ? `:not([data-value="${lastActiveOverflowItem}"])` : ''
|
|
62
63
|
|
|
63
64
|
return `
|
|
64
|
-
#${id}_main > *:nth-
|
|
65
|
+
#${id}_main > *:nth-of-type(n + ${overflowIndex + (lastActiveOverflowItem ? 1 : 2)}):not([data-radix-popper-content-wrapper])${activeCss} {
|
|
65
66
|
display: none;
|
|
66
67
|
}
|
|
67
|
-
#${id}_more > *:nth-
|
|
68
|
+
#${id}_more > *:nth-of-type(-n + ${overflowIndex}):not([data-radix-popper-content-wrapper]) {
|
|
68
69
|
display: none;
|
|
69
70
|
}
|
|
70
|
-
#${id}_more > *:nth-child(-n + ${overflowIndex + 4}) {
|
|
71
|
-
margin-top: 0;
|
|
72
|
-
}
|
|
73
71
|
`
|
|
74
72
|
}, [lastActiveOverflowItem, id, overflowIndex])
|
|
75
73
|
|
|
@@ -158,16 +156,17 @@ export function OverflowingToolbar({ children }: OverflowingToolbarProps) {
|
|
|
158
156
|
<>
|
|
159
157
|
<style nonce={editor.options.nonce}>{css}</style>
|
|
160
158
|
<TldrawUiToolbar
|
|
161
|
-
|
|
162
|
-
|
|
159
|
+
orientation="horizontal"
|
|
160
|
+
className={classNames('tlui-main-toolbar__tools', {
|
|
161
|
+
'tlui-main-toolbar__tools__mobile': breakpoint < PORTRAIT_BREAKPOINT.TABLET_SM,
|
|
163
162
|
})}
|
|
164
163
|
label={msg('tool-panel.title')}
|
|
165
164
|
>
|
|
166
|
-
<
|
|
165
|
+
<TldrawUiRow id={`${id}_main`} ref={mainToolsRef}>
|
|
167
166
|
<TldrawUiMenuContextProvider type="toolbar" sourceId="toolbar">
|
|
168
167
|
{children}
|
|
169
168
|
</TldrawUiMenuContextProvider>
|
|
170
|
-
</
|
|
169
|
+
</TldrawUiRow>
|
|
171
170
|
{/* There is a +1 because if the menu is just one item, it's not necessary. */}
|
|
172
171
|
{totalItems > overflowIndex + 1 && (
|
|
173
172
|
<IsInOverflowContext.Provider value={true}>
|
|
@@ -176,7 +175,7 @@ export function OverflowingToolbar({ children }: OverflowingToolbarProps) {
|
|
|
176
175
|
<TldrawUiToolbarButton
|
|
177
176
|
title={msg('tool-panel.more')}
|
|
178
177
|
type="tool"
|
|
179
|
-
className="tlui-toolbar__overflow"
|
|
178
|
+
className="tlui-main-toolbar__overflow"
|
|
180
179
|
data-testid="tools.more-button"
|
|
181
180
|
>
|
|
182
181
|
<TldrawUiButtonIcon icon="chevron-up" />
|
|
@@ -184,7 +183,7 @@ export function OverflowingToolbar({ children }: OverflowingToolbarProps) {
|
|
|
184
183
|
</TldrawUiPopoverTrigger>
|
|
185
184
|
<TldrawUiPopoverContent side="top" align="center">
|
|
186
185
|
<TldrawUiToolbar
|
|
187
|
-
|
|
186
|
+
orientation="grid"
|
|
188
187
|
data-testid="tools.more-content"
|
|
189
188
|
label={msg('tool-panel.more')}
|
|
190
189
|
id={`${id}_more`}
|
|
@@ -5,6 +5,7 @@ import { useBreakpoint } from '../../context/breakpoints'
|
|
|
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 { TldrawUiTooltip } from '../primitives/TldrawUiTooltip'
|
|
8
9
|
|
|
9
10
|
/** @public */
|
|
10
11
|
export interface ToggleToolLockedButtonProps {
|
|
@@ -25,16 +26,18 @@ export function ToggleToolLockedButton({ activeToolId }: ToggleToolLockedButtonP
|
|
|
25
26
|
if (!activeToolId || !tool.isLockable) return null
|
|
26
27
|
|
|
27
28
|
return (
|
|
28
|
-
<
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
'tlui-toolbar__lock-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
29
|
+
<TldrawUiTooltip content={msg('action.toggle-tool-lock')}>
|
|
30
|
+
<TldrawUiButton
|
|
31
|
+
type="normal"
|
|
32
|
+
title={msg('action.toggle-tool-lock')}
|
|
33
|
+
data-testid="tool-lock"
|
|
34
|
+
className={classNames('tlui-main-toolbar__lock-button', {
|
|
35
|
+
'tlui-main-toolbar__lock-button__mobile': breakpoint < PORTRAIT_BREAKPOINT.TABLET_SM,
|
|
36
|
+
})}
|
|
37
|
+
onClick={() => editor.updateInstanceState({ isToolLocked: !isToolLocked })}
|
|
38
|
+
>
|
|
39
|
+
<TldrawUiButtonIcon icon={isToolLocked ? 'lock' : 'unlock'} small />
|
|
40
|
+
</TldrawUiButton>
|
|
41
|
+
</TldrawUiTooltip>
|
|
39
42
|
)
|
|
40
43
|
}
|
|
@@ -651,6 +651,14 @@ export function ToggleKeyboardShortcutsItem() {
|
|
|
651
651
|
)
|
|
652
652
|
}
|
|
653
653
|
|
|
654
|
+
/** @public @react */
|
|
655
|
+
export function ToggleUiLabelsItem() {
|
|
656
|
+
const editor = useEditor()
|
|
657
|
+
const showUiLabels = useValue('showUiLabels', () => editor.user.getShowUiLabels(), [editor])
|
|
658
|
+
|
|
659
|
+
return <TldrawUiMenuActionCheckboxItem actionId="toggle-ui-labels" checked={showUiLabels} />
|
|
660
|
+
}
|
|
661
|
+
|
|
654
662
|
/** @public @react */
|
|
655
663
|
export function ToggleDebugModeItem() {
|
|
656
664
|
const editor = useEditor()
|
|
@@ -6,7 +6,6 @@ import {
|
|
|
6
6
|
TLDefaultColorTheme,
|
|
7
7
|
useEditor,
|
|
8
8
|
} from '@tldraw/editor'
|
|
9
|
-
import classNames from 'classnames'
|
|
10
9
|
import { ReactElement, memo, useMemo, useRef } from 'react'
|
|
11
10
|
import { StyleValuesForUi } from '../../../styles'
|
|
12
11
|
import { PORTRAIT_BREAKPOINT } from '../../constants'
|
|
@@ -15,6 +14,7 @@ import { TLUiTranslationKey } from '../../hooks/useTranslation/TLUiTranslationKe
|
|
|
15
14
|
import { useTranslation } from '../../hooks/useTranslation/useTranslation'
|
|
16
15
|
import { TldrawUiButtonIcon } from './Button/TldrawUiButtonIcon'
|
|
17
16
|
import { TldrawUiToolbarToggleGroup, TldrawUiToolbarToggleItem } from './TldrawUiToolbar'
|
|
17
|
+
import { TldrawUiGrid, TldrawUiRow } from './layout'
|
|
18
18
|
|
|
19
19
|
/** @public */
|
|
20
20
|
export interface TLUiButtonPickerProps<T extends string> {
|
|
@@ -116,41 +116,43 @@ export const TldrawUiButtonPicker = memo(function TldrawUiButtonPicker<T extends
|
|
|
116
116
|
}
|
|
117
117
|
}, [editor, breakpoint, value, onHistoryMark, onValueChange, style])
|
|
118
118
|
|
|
119
|
+
const Wrapper = items.length > 4 ? TldrawUiGrid : TldrawUiRow
|
|
120
|
+
|
|
119
121
|
return (
|
|
120
|
-
<
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
)
|
|
153
|
-
|
|
154
|
-
</
|
|
122
|
+
<Wrapper asChild>
|
|
123
|
+
<TldrawUiToolbarToggleGroup
|
|
124
|
+
data-testid={`style.${uiType}`}
|
|
125
|
+
type="single"
|
|
126
|
+
value={value.type === 'shared' ? value.value : undefined}
|
|
127
|
+
>
|
|
128
|
+
{items.map((item) => {
|
|
129
|
+
const label = title + ' — ' + msg(`${uiType}-style.${item.value}` as TLUiTranslationKey)
|
|
130
|
+
return (
|
|
131
|
+
<TldrawUiToolbarToggleItem
|
|
132
|
+
type="icon"
|
|
133
|
+
key={item.value}
|
|
134
|
+
data-id={item.value}
|
|
135
|
+
data-testid={`style.${uiType}.${item.value}`}
|
|
136
|
+
aria-label={label}
|
|
137
|
+
value={item.value}
|
|
138
|
+
data-state={value.type === 'shared' && value.value === item.value ? 'on' : 'off'}
|
|
139
|
+
data-isactive={value.type === 'shared' && value.value === item.value}
|
|
140
|
+
title={label}
|
|
141
|
+
style={
|
|
142
|
+
style === (DefaultColorStyle as StyleProp<unknown>)
|
|
143
|
+
? { color: theme[item.value as TLDefaultColorStyle].solid }
|
|
144
|
+
: undefined
|
|
145
|
+
}
|
|
146
|
+
onPointerEnter={handleButtonPointerEnter}
|
|
147
|
+
onPointerDown={handleButtonPointerDown}
|
|
148
|
+
onPointerUp={handleButtonPointerUp}
|
|
149
|
+
onClick={handleButtonClick}
|
|
150
|
+
>
|
|
151
|
+
<TldrawUiButtonIcon icon={item.icon} />
|
|
152
|
+
</TldrawUiToolbarToggleItem>
|
|
153
|
+
)
|
|
154
|
+
})}
|
|
155
|
+
</TldrawUiToolbarToggleGroup>
|
|
156
|
+
</Wrapper>
|
|
155
157
|
)
|
|
156
158
|
}) as <T extends string>(props: TLUiButtonPickerProps<T>) => ReactElement
|
|
@@ -172,7 +172,7 @@ export const TldrawUiContextualToolbar = ({
|
|
|
172
172
|
className={classNames('tlui-contextual-toolbar', className)}
|
|
173
173
|
onPointerDown={stopEventPropagation}
|
|
174
174
|
>
|
|
175
|
-
<TldrawUiToolbar className="tlui-menu
|
|
175
|
+
<TldrawUiToolbar orientation="horizontal" className="tlui-menu" label={label}>
|
|
176
176
|
{children}
|
|
177
177
|
</TldrawUiToolbar>
|
|
178
178
|
</div>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useContainer } from '@tldraw/editor'
|
|
2
|
+
import classNames from 'classnames'
|
|
2
3
|
import { Popover as _Popover } from 'radix-ui'
|
|
3
4
|
import React from 'react'
|
|
4
5
|
import { useMenuIsOpen } from '../../hooks/useMenuIsOpen'
|
|
@@ -9,15 +10,16 @@ export interface TLUiPopoverProps {
|
|
|
9
10
|
open?: boolean
|
|
10
11
|
children: React.ReactNode
|
|
11
12
|
onOpenChange?(isOpen: boolean): void
|
|
13
|
+
className?: string
|
|
12
14
|
}
|
|
13
15
|
|
|
14
16
|
/** @public @react */
|
|
15
|
-
export function TldrawUiPopover({ id, children, onOpenChange, open }: TLUiPopoverProps) {
|
|
17
|
+
export function TldrawUiPopover({ id, children, onOpenChange, open, className }: TLUiPopoverProps) {
|
|
16
18
|
const [isOpen, handleOpenChange] = useMenuIsOpen(id, onOpenChange)
|
|
17
19
|
|
|
18
20
|
return (
|
|
19
21
|
<_Popover.Root onOpenChange={handleOpenChange} open={open || isOpen /* allow debugging */}>
|
|
20
|
-
<div className=
|
|
22
|
+
<div className={classNames('tlui-popover', className)}>{children}</div>
|
|
21
23
|
</_Popover.Root>
|
|
22
24
|
)
|
|
23
25
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import classnames from 'classnames'
|
|
2
2
|
import { Toolbar as _Toolbar } from 'radix-ui'
|
|
3
3
|
import React from 'react'
|
|
4
|
+
import { TldrawUiGrid, TldrawUiRow } from './layout'
|
|
5
|
+
import { TldrawUiTooltip } from './TldrawUiTooltip'
|
|
4
6
|
|
|
5
7
|
/** @public */
|
|
6
8
|
export interface TLUiToolbarProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
@@ -8,20 +10,25 @@ export interface TLUiToolbarProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
|
8
10
|
className?: string
|
|
9
11
|
dir?: 'ltr' | 'rtl'
|
|
10
12
|
label: string
|
|
13
|
+
orientation?: 'horizontal' | 'grid'
|
|
11
14
|
}
|
|
12
15
|
|
|
13
16
|
/** @public @react */
|
|
14
17
|
export const TldrawUiToolbar = React.forwardRef<HTMLDivElement, TLUiToolbarProps>(
|
|
15
|
-
({ children, className, label, ...props }: TLUiToolbarProps, ref) => {
|
|
18
|
+
({ children, className, label, orientation = 'horizontal', ...props }: TLUiToolbarProps, ref) => {
|
|
19
|
+
const Layout = orientation === 'grid' ? TldrawUiGrid : TldrawUiRow
|
|
16
20
|
return (
|
|
17
|
-
<
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
<Layout asChild>
|
|
22
|
+
<_Toolbar.Root
|
|
23
|
+
ref={ref}
|
|
24
|
+
{...props}
|
|
25
|
+
className={classnames('tlui-toolbar', className)}
|
|
26
|
+
aria-label={label}
|
|
27
|
+
orientation={orientation === 'grid' ? 'horizontal' : orientation}
|
|
28
|
+
>
|
|
29
|
+
{children}
|
|
30
|
+
</_Toolbar.Root>
|
|
31
|
+
</Layout>
|
|
25
32
|
)
|
|
26
33
|
}
|
|
27
34
|
)
|
|
@@ -34,23 +41,30 @@ export interface TLUiToolbarButtonProps extends React.HTMLAttributes<HTMLButtonE
|
|
|
34
41
|
disabled?: boolean
|
|
35
42
|
isActive?: boolean
|
|
36
43
|
type: 'icon' | 'tool' | 'menu'
|
|
44
|
+
tooltip?: string
|
|
37
45
|
}
|
|
38
46
|
|
|
39
47
|
/** @public @react */
|
|
40
48
|
export const TldrawUiToolbarButton = React.forwardRef<HTMLButtonElement, TLUiToolbarButtonProps>(
|
|
41
|
-
({ asChild, children, type, isActive, ...props }: TLUiToolbarButtonProps, ref) => {
|
|
42
|
-
|
|
49
|
+
({ asChild, children, type, isActive, tooltip, ...props }: TLUiToolbarButtonProps, ref) => {
|
|
50
|
+
const button = (
|
|
43
51
|
<_Toolbar.Button
|
|
44
52
|
ref={ref}
|
|
45
53
|
asChild={asChild}
|
|
46
54
|
draggable={false}
|
|
47
55
|
data-isactive={isActive}
|
|
48
56
|
{...props}
|
|
57
|
+
// The tooltip takes care of this.
|
|
58
|
+
title={undefined}
|
|
49
59
|
className={classnames('tlui-button', `tlui-button__${type}`, props.className)}
|
|
50
60
|
>
|
|
51
61
|
{children}
|
|
52
62
|
</_Toolbar.Button>
|
|
53
63
|
)
|
|
64
|
+
|
|
65
|
+
const tooltipContent = tooltip || props.title
|
|
66
|
+
|
|
67
|
+
return <TldrawUiTooltip content={tooltipContent}>{button}</TldrawUiTooltip>
|
|
54
68
|
}
|
|
55
69
|
)
|
|
56
70
|
|
|
@@ -93,6 +107,7 @@ export interface TLUiToolbarToggleItemProps extends React.HTMLAttributes<HTMLBut
|
|
|
93
107
|
className?: string
|
|
94
108
|
type: 'icon' | 'tool'
|
|
95
109
|
value: string
|
|
110
|
+
tooltip?: string
|
|
96
111
|
}
|
|
97
112
|
|
|
98
113
|
/** @public @react */
|
|
@@ -101,11 +116,14 @@ export const TldrawUiToolbarToggleItem = ({
|
|
|
101
116
|
className,
|
|
102
117
|
type,
|
|
103
118
|
value,
|
|
119
|
+
tooltip,
|
|
104
120
|
...props
|
|
105
121
|
}: TLUiToolbarToggleItemProps) => {
|
|
106
|
-
|
|
122
|
+
const toggleItem = (
|
|
107
123
|
<_Toolbar.ToggleItem
|
|
108
124
|
{...props}
|
|
125
|
+
// The tooltip takes care of this.
|
|
126
|
+
title={undefined}
|
|
109
127
|
className={classnames(
|
|
110
128
|
'tlui-button',
|
|
111
129
|
`tlui-button__${type}`,
|
|
@@ -117,4 +135,8 @@ export const TldrawUiToolbarToggleItem = ({
|
|
|
117
135
|
{children}
|
|
118
136
|
</_Toolbar.ToggleItem>
|
|
119
137
|
)
|
|
138
|
+
|
|
139
|
+
const tooltipContent = tooltip || props.title
|
|
140
|
+
|
|
141
|
+
return <TldrawUiTooltip content={tooltipContent}>{toggleItem}</TldrawUiTooltip>
|
|
120
142
|
}
|
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
import { assert, 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, instant: boolean = false) {
|
|
73
|
+
const hide = () => {
|
|
74
|
+
// Only hide if this is the current tooltip
|
|
75
|
+
if (this.currentTooltipId === tooltipId) {
|
|
76
|
+
this.currentTooltipId = null
|
|
77
|
+
this.currentContent = ''
|
|
78
|
+
this.activeElement = null
|
|
79
|
+
this.destroyTimeoutId = null
|
|
80
|
+
this.notify()
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (instant) {
|
|
85
|
+
hide()
|
|
86
|
+
} else if (this.editor) {
|
|
87
|
+
// Start destroy timeout (1 second)
|
|
88
|
+
this.destroyTimeoutId = this.editor.timers.setTimeout(hide, 300)
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
hideAllTooltips() {
|
|
93
|
+
this.currentTooltipId = null
|
|
94
|
+
this.currentContent = ''
|
|
95
|
+
this.activeElement = null
|
|
96
|
+
this.destroyTimeoutId = null
|
|
97
|
+
this.notify()
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
getCurrentTooltipData() {
|
|
101
|
+
return {
|
|
102
|
+
id: this.currentTooltipId,
|
|
103
|
+
content: this.currentContent,
|
|
104
|
+
side: this.currentSide,
|
|
105
|
+
sideOffset: this.currentSideOffset,
|
|
106
|
+
element: this.activeElement,
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export const tooltipManager = TooltipManager.getInstance()
|
|
112
|
+
|
|
113
|
+
// Context for the tooltip singleton
|
|
114
|
+
const TooltipSingletonContext = createContext<boolean>(false)
|
|
115
|
+
|
|
116
|
+
/** @public */
|
|
117
|
+
export interface TldrawUiTooltipProviderProps {
|
|
118
|
+
children: React.ReactNode
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** @public @react */
|
|
122
|
+
export function TldrawUiTooltipProvider({ children }: TldrawUiTooltipProviderProps) {
|
|
123
|
+
return (
|
|
124
|
+
<_Tooltip.Provider skipDelayDuration={700}>
|
|
125
|
+
<TooltipSingletonContext.Provider value={true}>
|
|
126
|
+
{children}
|
|
127
|
+
<TooltipSingleton />
|
|
128
|
+
</TooltipSingletonContext.Provider>
|
|
129
|
+
</_Tooltip.Provider>
|
|
130
|
+
)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// The singleton tooltip component that renders once
|
|
134
|
+
function TooltipSingleton() {
|
|
135
|
+
const editor = useMaybeEditor()
|
|
136
|
+
const [, forceUpdate] = useState({})
|
|
137
|
+
const [isOpen, setIsOpen] = useState(false)
|
|
138
|
+
const triggerRef = useRef<HTMLDivElement>(null)
|
|
139
|
+
const previousPositionRef = useRef<{ x: number; y: number } | null>(null)
|
|
140
|
+
const prefersReducedMotion = usePrefersReducedMotion()
|
|
141
|
+
const [shouldAnimate, setShouldAnimate] = useState(false)
|
|
142
|
+
const isFirstShowRef = useRef(true)
|
|
143
|
+
const showTimeoutRef = useRef<number | null>(null)
|
|
144
|
+
|
|
145
|
+
// Set editor in tooltip manager
|
|
146
|
+
useEffect(() => {
|
|
147
|
+
tooltipManager.setEditor(editor)
|
|
148
|
+
}, [editor])
|
|
149
|
+
|
|
150
|
+
// Subscribe to tooltip manager updates
|
|
151
|
+
useEffect(() => {
|
|
152
|
+
const unsubscribe = tooltipManager.subscribe(() => {
|
|
153
|
+
forceUpdate({})
|
|
154
|
+
})
|
|
155
|
+
return unsubscribe
|
|
156
|
+
}, [])
|
|
157
|
+
|
|
158
|
+
const tooltipData = tooltipManager.getCurrentTooltipData()
|
|
159
|
+
|
|
160
|
+
// Update open state and trigger position
|
|
161
|
+
useEffect(() => {
|
|
162
|
+
const shouldBeOpen = Boolean(tooltipData.id && tooltipData.element)
|
|
163
|
+
|
|
164
|
+
// Clear any existing show timeout
|
|
165
|
+
if (showTimeoutRef.current) {
|
|
166
|
+
clearTimeout(showTimeoutRef.current)
|
|
167
|
+
showTimeoutRef.current = null
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (shouldBeOpen && tooltipData.element && triggerRef.current) {
|
|
171
|
+
// Position the invisible trigger element over the active element
|
|
172
|
+
const activeRect = tooltipData.element.getBoundingClientRect()
|
|
173
|
+
const trigger = triggerRef.current
|
|
174
|
+
|
|
175
|
+
const newPosition = {
|
|
176
|
+
x: activeRect.left + activeRect.width / 2,
|
|
177
|
+
y: activeRect.top + activeRect.height / 2,
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Determine if we should animate
|
|
181
|
+
let shouldAnimateCheck = false
|
|
182
|
+
if (previousPositionRef.current) {
|
|
183
|
+
const isNearPrevious = Vec.DistMin(previousPositionRef.current, newPosition, 200)
|
|
184
|
+
// Only animate if the distance is less than 200px (nearby tooltips)
|
|
185
|
+
shouldAnimateCheck =
|
|
186
|
+
!prefersReducedMotion &&
|
|
187
|
+
isNearPrevious &&
|
|
188
|
+
Math.abs(newPosition.y - previousPositionRef.current.y) < 50
|
|
189
|
+
}
|
|
190
|
+
// Don't animate on initial show (previousPositionRef.current is null)
|
|
191
|
+
|
|
192
|
+
setShouldAnimate(isFirstShowRef.current ? false : shouldAnimateCheck)
|
|
193
|
+
previousPositionRef.current = newPosition
|
|
194
|
+
|
|
195
|
+
trigger.style.position = 'fixed'
|
|
196
|
+
trigger.style.left = `${activeRect.left}px`
|
|
197
|
+
trigger.style.top = `${activeRect.top}px`
|
|
198
|
+
trigger.style.width = `${activeRect.width}px`
|
|
199
|
+
trigger.style.height = `${activeRect.height}px`
|
|
200
|
+
trigger.style.pointerEvents = 'none'
|
|
201
|
+
trigger.style.zIndex = '9999'
|
|
202
|
+
|
|
203
|
+
// Handle delay for first show
|
|
204
|
+
if (isFirstShowRef.current && editor) {
|
|
205
|
+
showTimeoutRef.current = editor.timers.setTimeout(() => {
|
|
206
|
+
setIsOpen(true)
|
|
207
|
+
isFirstShowRef.current = false
|
|
208
|
+
}, editor.options.tooltipDelayMs)
|
|
209
|
+
} else {
|
|
210
|
+
// Subsequent tooltips show immediately
|
|
211
|
+
setIsOpen(true)
|
|
212
|
+
}
|
|
213
|
+
} else if (!shouldBeOpen) {
|
|
214
|
+
// Hide tooltip immediately
|
|
215
|
+
setIsOpen(false)
|
|
216
|
+
// Reset position tracking when tooltip closes
|
|
217
|
+
previousPositionRef.current = null
|
|
218
|
+
setShouldAnimate(false)
|
|
219
|
+
// Reset first show state after tooltip is hidden
|
|
220
|
+
isFirstShowRef.current = true
|
|
221
|
+
}
|
|
222
|
+
}, [tooltipData.id, tooltipData.element, editor, prefersReducedMotion])
|
|
223
|
+
|
|
224
|
+
if (!tooltipData.id) {
|
|
225
|
+
return null
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return (
|
|
229
|
+
<_Tooltip.Root open={isOpen} delayDuration={0}>
|
|
230
|
+
<_Tooltip.Trigger asChild>
|
|
231
|
+
<div ref={triggerRef} />
|
|
232
|
+
</_Tooltip.Trigger>
|
|
233
|
+
<_Tooltip.Content
|
|
234
|
+
className="tlui-tooltip"
|
|
235
|
+
data-should-animate={shouldAnimate}
|
|
236
|
+
side={tooltipData.side}
|
|
237
|
+
sideOffset={tooltipData.sideOffset}
|
|
238
|
+
avoidCollisions
|
|
239
|
+
collisionPadding={8}
|
|
240
|
+
dir="ltr"
|
|
241
|
+
>
|
|
242
|
+
{tooltipData.content}
|
|
243
|
+
<_Tooltip.Arrow className="tlui-tooltip__arrow" />
|
|
244
|
+
</_Tooltip.Content>
|
|
245
|
+
</_Tooltip.Root>
|
|
246
|
+
)
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/** @public @react */
|
|
250
|
+
export function TldrawUiTooltip({
|
|
251
|
+
children,
|
|
252
|
+
content,
|
|
253
|
+
side = 'bottom',
|
|
254
|
+
sideOffset = 5,
|
|
255
|
+
disabled = false,
|
|
256
|
+
}: TldrawUiTooltipProps) {
|
|
257
|
+
const editor = useMaybeEditor()
|
|
258
|
+
const tooltipId = useRef<string>(uniqueId())
|
|
259
|
+
const hasProvider = useContext(TooltipSingletonContext)
|
|
260
|
+
|
|
261
|
+
// Don't show tooltip if disabled, no content, or UI labels are disabled
|
|
262
|
+
if (disabled || !content) {
|
|
263
|
+
return <>{children}</>
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Fallback to old behavior if no provider
|
|
267
|
+
if (!hasProvider) {
|
|
268
|
+
return (
|
|
269
|
+
<_Tooltip.Root
|
|
270
|
+
delayDuration={editor?.options.tooltipDelayMs || DEFAULT_TOOLTIP_DELAY_MS}
|
|
271
|
+
disableHoverableContent
|
|
272
|
+
>
|
|
273
|
+
<_Tooltip.Trigger asChild>{children}</_Tooltip.Trigger>
|
|
274
|
+
<_Tooltip.Content
|
|
275
|
+
className="tlui-tooltip"
|
|
276
|
+
side={side}
|
|
277
|
+
sideOffset={sideOffset}
|
|
278
|
+
avoidCollisions
|
|
279
|
+
collisionPadding={8}
|
|
280
|
+
dir="ltr"
|
|
281
|
+
>
|
|
282
|
+
{content}
|
|
283
|
+
<_Tooltip.Arrow className="tlui-tooltip__arrow" />
|
|
284
|
+
</_Tooltip.Content>
|
|
285
|
+
</_Tooltip.Root>
|
|
286
|
+
)
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const child = React.Children.only(children)
|
|
290
|
+
assert(React.isValidElement(child), 'TldrawUiTooltip children must be a single element')
|
|
291
|
+
|
|
292
|
+
const handleMouseEnter = (event: React.MouseEvent<HTMLElement>) => {
|
|
293
|
+
child.props.onMouseEnter?.(event)
|
|
294
|
+
tooltipManager.showTooltip(
|
|
295
|
+
tooltipId.current,
|
|
296
|
+
content,
|
|
297
|
+
event.currentTarget as HTMLElement,
|
|
298
|
+
side,
|
|
299
|
+
sideOffset
|
|
300
|
+
)
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
const handleMouseLeave = (event: React.MouseEvent<HTMLElement>) => {
|
|
304
|
+
child.props.onMouseLeave?.(event)
|
|
305
|
+
tooltipManager.hideTooltip(tooltipId.current)
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
const handleFocus = (event: React.FocusEvent<HTMLElement>) => {
|
|
309
|
+
child.props.onFocus?.(event)
|
|
310
|
+
tooltipManager.showTooltip(
|
|
311
|
+
tooltipId.current,
|
|
312
|
+
content,
|
|
313
|
+
event.currentTarget as HTMLElement,
|
|
314
|
+
side,
|
|
315
|
+
sideOffset
|
|
316
|
+
)
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const handleBlur = (event: React.FocusEvent<HTMLElement>) => {
|
|
320
|
+
child.props.onBlur?.(event)
|
|
321
|
+
tooltipManager.hideTooltip(tooltipId.current)
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
const childrenWithHandlers = React.cloneElement(children as React.ReactElement, {
|
|
325
|
+
onMouseEnter: handleMouseEnter,
|
|
326
|
+
onMouseLeave: handleMouseLeave,
|
|
327
|
+
onFocus: handleFocus,
|
|
328
|
+
onBlur: handleBlur,
|
|
329
|
+
})
|
|
330
|
+
|
|
331
|
+
return childrenWithHandlers
|
|
332
|
+
}
|