tldraw 3.16.0-canary.efdec30fc411 → 3.16.0-canary.f55016ece635
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 +133 -4
- package/dist-cjs/index.js +12 -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/canvas/TldrawScribble.js +1 -1
- package/dist-cjs/lib/canvas/TldrawScribble.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/arrow/ArrowShapeUtil.js +3 -3
- package/dist-cjs/lib/shapes/arrow/ArrowShapeUtil.js.map +2 -2
- package/dist-cjs/lib/shapes/arrow/elbow/ElbowArrowDebug.js +3 -3
- package/dist-cjs/lib/shapes/arrow/elbow/ElbowArrowDebug.js.map +1 -1
- package/dist-cjs/lib/shapes/draw/DrawShapeUtil.js +3 -3
- package/dist-cjs/lib/shapes/draw/DrawShapeUtil.js.map +2 -2
- package/dist-cjs/lib/shapes/embed/EmbedShapeUtil.js +1 -1
- package/dist-cjs/lib/shapes/embed/EmbedShapeUtil.js.map +1 -1
- package/dist-cjs/lib/shapes/frame/FrameShapeUtil.js +12 -12
- package/dist-cjs/lib/shapes/frame/FrameShapeUtil.js.map +2 -2
- package/dist-cjs/lib/shapes/frame/components/FrameHeading.js +1 -1
- package/dist-cjs/lib/shapes/frame/components/FrameHeading.js.map +2 -2
- package/dist-cjs/lib/shapes/geo/GeoShapeUtil.js +2 -2
- package/dist-cjs/lib/shapes/geo/GeoShapeUtil.js.map +2 -2
- package/dist-cjs/lib/shapes/geo/components/GeoShapeBody.js +2 -1
- package/dist-cjs/lib/shapes/geo/components/GeoShapeBody.js.map +2 -2
- package/dist-cjs/lib/shapes/highlight/HighlightShapeUtil.js +5 -1
- package/dist-cjs/lib/shapes/highlight/HighlightShapeUtil.js.map +2 -2
- package/dist-cjs/lib/shapes/image/ImageShapeUtil.js +3 -3
- package/dist-cjs/lib/shapes/image/ImageShapeUtil.js.map +1 -1
- package/dist-cjs/lib/shapes/line/LineShapeUtil.js +5 -1
- package/dist-cjs/lib/shapes/line/LineShapeUtil.js.map +2 -2
- package/dist-cjs/lib/shapes/note/NoteShapeUtil.js +4 -4
- package/dist-cjs/lib/shapes/note/NoteShapeUtil.js.map +2 -2
- package/dist-cjs/lib/shapes/shared/ShapeFill.js +4 -4
- package/dist-cjs/lib/shapes/shared/ShapeFill.js.map +2 -2
- package/dist-cjs/lib/shapes/shared/freehand/svg.js.map +2 -2
- package/dist-cjs/lib/shapes/text/TextShapeUtil.js +2 -2
- package/dist-cjs/lib/shapes/text/TextShapeUtil.js.map +2 -2
- package/dist-cjs/lib/shapes/video/VideoShapeUtil.js +3 -3
- package/dist-cjs/lib/shapes/video/VideoShapeUtil.js.map +1 -1
- package/dist-cjs/lib/tools/EraserTool/childStates/Erasing.js +25 -1
- package/dist-cjs/lib/tools/EraserTool/childStates/Erasing.js.map +2 -2
- package/dist-cjs/lib/tools/EraserTool/childStates/Pointing.js +12 -0
- package/dist-cjs/lib/tools/EraserTool/childStates/Pointing.js.map +2 -2
- package/dist-cjs/lib/ui/TldrawUi.js +27 -12
- package/dist-cjs/lib/ui/TldrawUi.js.map +3 -3
- 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/ActionsMenu/DefaultActionsMenu.js +10 -2
- package/dist-cjs/lib/ui/components/ActionsMenu/DefaultActionsMenu.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 +1 -1
- package/dist-cjs/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.js.map +1 -1
- package/dist-cjs/lib/ui/components/Minimap/MinimapManager.js +4 -4
- package/dist-cjs/lib/ui/components/Minimap/MinimapManager.js.map +2 -2
- package/dist-cjs/lib/ui/components/MobileStylePanel.js +5 -3
- package/dist-cjs/lib/ui/components/MobileStylePanel.js.map +2 -2
- 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/DefaultImageToolbarContent.js +1 -1
- package/dist-cjs/lib/ui/components/Toolbar/DefaultImageToolbarContent.js.map +2 -2
- package/dist-cjs/lib/ui/components/Toolbar/DefaultToolbar.js +66 -22
- package/dist-cjs/lib/ui/components/Toolbar/DefaultToolbar.js.map +3 -3
- package/dist-cjs/lib/ui/components/Toolbar/OverflowingToolbar.js +188 -78
- package/dist-cjs/lib/ui/components/Toolbar/OverflowingToolbar.js.map +3 -3
- package/dist-cjs/lib/ui/components/primitives/TldrawUiButtonPicker.js +1 -1
- package/dist-cjs/lib/ui/components/primitives/TldrawUiButtonPicker.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/TldrawUiToolbar.js +15 -3
- package/dist-cjs/lib/ui/components/primitives/TldrawUiToolbar.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js +146 -168
- package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/layout.js +30 -5
- package/dist-cjs/lib/ui/components/primitives/layout.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuContext.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuGroup.js +25 -12
- package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuGroup.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js +3 -19
- package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.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/hooks/useTools.js +21 -3
- package/dist-cjs/lib/ui/hooks/useTools.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 +133 -4
- package/dist-esm/index.mjs +18 -3
- 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/canvas/TldrawScribble.mjs +1 -1
- package/dist-esm/lib/canvas/TldrawScribble.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/arrow/ArrowShapeUtil.mjs +4 -3
- package/dist-esm/lib/shapes/arrow/ArrowShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/shapes/arrow/elbow/ElbowArrowDebug.mjs +3 -3
- package/dist-esm/lib/shapes/arrow/elbow/ElbowArrowDebug.mjs.map +1 -1
- package/dist-esm/lib/shapes/draw/DrawShapeUtil.mjs +4 -3
- package/dist-esm/lib/shapes/draw/DrawShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/shapes/embed/EmbedShapeUtil.mjs +1 -1
- package/dist-esm/lib/shapes/embed/EmbedShapeUtil.mjs.map +1 -1
- package/dist-esm/lib/shapes/frame/FrameShapeUtil.mjs +13 -12
- package/dist-esm/lib/shapes/frame/FrameShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/shapes/frame/components/FrameHeading.mjs +1 -1
- package/dist-esm/lib/shapes/frame/components/FrameHeading.mjs.map +2 -2
- package/dist-esm/lib/shapes/geo/GeoShapeUtil.mjs +3 -2
- package/dist-esm/lib/shapes/geo/GeoShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/shapes/geo/components/GeoShapeBody.mjs +2 -1
- package/dist-esm/lib/shapes/geo/components/GeoShapeBody.mjs.map +2 -2
- package/dist-esm/lib/shapes/highlight/HighlightShapeUtil.mjs +6 -1
- package/dist-esm/lib/shapes/highlight/HighlightShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/shapes/image/ImageShapeUtil.mjs +3 -3
- package/dist-esm/lib/shapes/image/ImageShapeUtil.mjs.map +1 -1
- package/dist-esm/lib/shapes/line/LineShapeUtil.mjs +6 -1
- package/dist-esm/lib/shapes/line/LineShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs +5 -4
- package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/shapes/shared/ShapeFill.mjs +5 -4
- package/dist-esm/lib/shapes/shared/ShapeFill.mjs.map +2 -2
- package/dist-esm/lib/shapes/shared/freehand/svg.mjs.map +2 -2
- package/dist-esm/lib/shapes/text/TextShapeUtil.mjs +3 -2
- package/dist-esm/lib/shapes/text/TextShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/shapes/video/VideoShapeUtil.mjs +3 -3
- package/dist-esm/lib/shapes/video/VideoShapeUtil.mjs.map +1 -1
- package/dist-esm/lib/tools/EraserTool/childStates/Erasing.mjs +26 -1
- package/dist-esm/lib/tools/EraserTool/childStates/Erasing.mjs.map +2 -2
- package/dist-esm/lib/tools/EraserTool/childStates/Pointing.mjs +13 -0
- package/dist-esm/lib/tools/EraserTool/childStates/Pointing.mjs.map +2 -2
- package/dist-esm/lib/ui/TldrawUi.mjs +29 -14
- package/dist-esm/lib/ui/TldrawUi.mjs.map +3 -3
- 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/ActionsMenu/DefaultActionsMenu.mjs +10 -2
- package/dist-esm/lib/ui/components/ActionsMenu/DefaultActionsMenu.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 +1 -1
- package/dist-esm/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.mjs.map +1 -1
- package/dist-esm/lib/ui/components/Minimap/MinimapManager.mjs +4 -4
- package/dist-esm/lib/ui/components/Minimap/MinimapManager.mjs.map +2 -2
- package/dist-esm/lib/ui/components/MobileStylePanel.mjs +6 -3
- package/dist-esm/lib/ui/components/MobileStylePanel.mjs.map +2 -2
- 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/DefaultImageToolbarContent.mjs +1 -1
- package/dist-esm/lib/ui/components/Toolbar/DefaultImageToolbarContent.mjs.map +2 -2
- package/dist-esm/lib/ui/components/Toolbar/DefaultToolbar.mjs +56 -22
- package/dist-esm/lib/ui/components/Toolbar/DefaultToolbar.mjs.map +2 -2
- package/dist-esm/lib/ui/components/Toolbar/OverflowingToolbar.mjs +192 -80
- package/dist-esm/lib/ui/components/Toolbar/OverflowingToolbar.mjs.map +3 -3
- package/dist-esm/lib/ui/components/primitives/TldrawUiButtonPicker.mjs +2 -1
- package/dist-esm/lib/ui/components/primitives/TldrawUiButtonPicker.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/TldrawUiToolbar.mjs +16 -4
- package/dist-esm/lib/ui/components/primitives/TldrawUiToolbar.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs +155 -170
- package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/layout.mjs +31 -6
- package/dist-esm/lib/ui/components/primitives/layout.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuContext.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuGroup.mjs +25 -12
- package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuGroup.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs +3 -19
- package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.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/hooks/useTools.mjs +22 -3
- package/dist-esm/lib/ui/hooks/useTools.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 +11 -34
- package/src/index.ts +11 -1
- package/src/lib/Tldraw.tsx +15 -2
- package/src/lib/canvas/TldrawScribble.tsx +1 -1
- package/src/lib/defaultExternalContentHandlers.ts +12 -4
- package/src/lib/shapes/arrow/ArrowShapeOptions.test.ts +2 -1
- package/src/lib/shapes/arrow/ArrowShapeTool.test.ts +4 -3
- package/src/lib/shapes/arrow/ArrowShapeUtil.test.ts +7 -6
- package/src/lib/shapes/arrow/ArrowShapeUtil.tsx +4 -3
- package/src/lib/shapes/arrow/elbow/ElbowArrowDebug.tsx +3 -3
- package/src/lib/shapes/draw/DrawShapeTool.test.ts +0 -5
- package/src/lib/shapes/draw/DrawShapeUtil.tsx +4 -3
- package/src/lib/shapes/embed/EmbedShapeUtil.tsx +1 -1
- package/src/lib/shapes/frame/FrameShapeUtil.tsx +21 -14
- package/src/lib/shapes/frame/components/FrameHeading.tsx +1 -1
- package/src/lib/shapes/geo/GeoShapeUtil.tsx +3 -2
- package/src/lib/shapes/geo/components/GeoShapeBody.tsx +2 -2
- package/src/lib/shapes/highlight/HighlightShapeUtil.tsx +7 -1
- package/src/lib/shapes/image/ImageShapeUtil.tsx +3 -3
- package/src/lib/shapes/line/LineShapeUtil.test.tsx +4 -3
- package/src/lib/shapes/line/LineShapeUtil.tsx +6 -1
- package/src/lib/shapes/line/__snapshots__/LineShapeUtil.test.tsx.snap +2 -2
- package/src/lib/shapes/note/NoteShapeUtil.tsx +9 -4
- package/src/lib/shapes/shared/ShapeFill.tsx +5 -4
- package/src/lib/shapes/shared/freehand/svg.ts +2 -0
- package/src/lib/shapes/text/TextShapeTool.test.ts +6 -5
- package/src/lib/shapes/text/TextShapeUtil.tsx +3 -2
- package/src/lib/shapes/video/VideoShapeUtil.tsx +3 -3
- package/src/lib/tools/EraserTool/childStates/Erasing.ts +34 -1
- package/src/lib/tools/EraserTool/childStates/Pointing.ts +20 -0
- package/src/lib/ui/TldrawUi.tsx +33 -12
- package/src/lib/ui/assetUrls.ts +13 -10
- package/src/lib/ui/components/ActionsMenu/DefaultActionsMenu.tsx +13 -2
- package/src/lib/ui/components/{FollowingIndicator.tsx → DefaultFollowingIndicator.tsx} +2 -1
- package/src/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.tsx +1 -1
- package/src/lib/ui/components/Minimap/MinimapManager.ts +4 -4
- package/src/lib/ui/components/MobileStylePanel.tsx +9 -6
- package/src/lib/ui/components/StylePanel/DropdownPicker.tsx +1 -1
- package/src/lib/ui/components/Toolbar/DefaultImageToolbarContent.tsx +1 -1
- package/src/lib/ui/components/Toolbar/DefaultToolbar.tsx +55 -24
- package/src/lib/ui/components/Toolbar/OverflowingToolbar.tsx +208 -56
- package/src/lib/ui/components/primitives/TldrawUiButtonPicker.tsx +3 -2
- package/src/lib/ui/components/primitives/TldrawUiToolbar.tsx +22 -5
- package/src/lib/ui/components/primitives/TldrawUiTooltip.tsx +184 -191
- package/src/lib/ui/components/primitives/layout.tsx +79 -5
- package/src/lib/ui/components/primitives/menus/TldrawUiMenuContext.tsx +0 -1
- package/src/lib/ui/components/primitives/menus/TldrawUiMenuGroup.tsx +29 -16
- package/src/lib/ui/components/primitives/menus/TldrawUiMenuItem.tsx +5 -18
- package/src/lib/ui/context/actions.tsx +16 -2
- package/src/lib/ui/context/components.tsx +3 -0
- package/src/lib/ui/hooks/useTools.tsx +25 -3
- package/src/lib/ui/version.ts +3 -3
- package/src/lib/ui.css +349 -243
- package/src/lib/utils/excalidraw/__snapshots__/putExcalidrawContent.test.tsx.snap +5 -5
- package/src/lib/utils/tldr/__snapshots__/buildFromV1Document.test.ts.snap +4 -4
- package/src/test/A11y.test.tsx +3 -2
- package/src/test/ClickManager.test.ts +7 -6
- package/src/test/Editor.test.tsx +20 -19
- package/src/test/EraserTool.test.ts +184 -13
- package/src/test/HandTool.test.ts +10 -9
- package/src/test/HighlightShape.test.ts +2 -1
- package/src/test/SelectTool.test.ts +3 -2
- package/src/test/TLUserPreferences.test.ts +4 -3
- package/src/test/TestEditor.ts +13 -15
- package/src/test/TldrawEditor.test.tsx +11 -10
- package/src/test/ZoomTool.test.ts +7 -6
- package/src/test/__snapshots__/drawing.test.ts.snap +2 -2
- package/src/test/__snapshots__/groups.test.tsx.snap +6 -6
- package/src/test/__snapshots__/resizing.test.ts.snap +2 -2
- package/src/test/arrows-megabus.test.tsx +5 -4
- package/src/test/bindings.test.tsx +24 -37
- package/src/test/bookmark-shapes.test.ts +1 -8
- package/src/test/commands/__snapshots__/getSvgString.test.ts.snap +23 -7
- package/src/test/commands/__snapshots__/packShapes.test.ts.snap +8 -8
- package/src/test/commands/__snapshots__/zoomToFit.test.ts.snap +2 -2
- package/src/test/commands/alignShapes.test.tsx +25 -24
- package/src/test/commands/animationSpeed.test.ts +2 -1
- package/src/test/commands/centerOnPoint.test.ts +3 -2
- package/src/test/commands/clipboard.test.ts +3 -2
- package/src/test/commands/createShapes.test.ts +2 -1
- package/src/test/commands/deleteShapes.test.ts +2 -1
- package/src/test/commands/distributeShapes.test.tsx +11 -10
- package/src/test/commands/getSvgString.test.ts +2 -1
- package/src/test/commands/packShapes.test.ts +5 -4
- package/src/test/commands/resizeShape.test.ts +2 -1
- package/src/test/commands/rotateShapes.test.ts +7 -6
- package/src/test/commands/setCamera.test.ts +4 -3
- package/src/test/commands/setCurrentPage.test.ts +3 -2
- package/src/test/commands/stackShapes.test.ts +11 -10
- package/src/test/commands/stretch.test.tsx +13 -12
- package/src/test/createDeepLink.test.tsx +2 -1
- package/src/test/cropping.test.ts +3 -2
- package/src/test/drawing.test.ts +2 -1
- package/src/test/flipShapes.test.ts +4 -3
- package/src/test/frames.test.ts +25 -24
- package/src/test/getCulledShapes.test.tsx +3 -2
- package/src/test/groups.test.tsx +1 -1
- package/src/test/handleDeepLink.test.tsx +2 -1
- package/src/test/maxShapes.test.ts +3 -2
- package/src/test/modifiers.test.ts +5 -4
- package/src/test/navigation.test.ts +12 -11
- package/src/test/panning.test.ts +2 -1
- package/src/test/perf/perf.test.ts +2 -1
- package/src/test/registerDeepLinkListener.test.tsx +10 -9
- package/src/test/resizing.test.ts +39 -38
- package/src/test/select.test.tsx +4 -3
- package/src/test/selection-omnibus.test.ts +11 -10
- package/src/test/shapeutils.test.ts +4 -3
- package/src/test/translating.test.ts +9 -8
- package/tldraw.css +650 -533
- package/dist-cjs/lib/ui/components/FollowingIndicator.js.map +0 -7
- package/dist-esm/lib/ui/components/FollowingIndicator.mjs.map +0 -7
|
@@ -1,7 +1,15 @@
|
|
|
1
|
-
import { assert, Editor, uniqueId, useMaybeEditor,
|
|
1
|
+
import { assert, Atom, atom, Editor, uniqueId, useMaybeEditor, useValue } from '@tldraw/editor'
|
|
2
2
|
import { Tooltip as _Tooltip } from 'radix-ui'
|
|
3
|
-
import React, {
|
|
4
|
-
|
|
3
|
+
import React, {
|
|
4
|
+
createContext,
|
|
5
|
+
forwardRef,
|
|
6
|
+
ReactNode,
|
|
7
|
+
useContext,
|
|
8
|
+
useEffect,
|
|
9
|
+
useRef,
|
|
10
|
+
useState,
|
|
11
|
+
} from 'react'
|
|
12
|
+
import { useTldrawUiOrientation } from './layout'
|
|
5
13
|
|
|
6
14
|
const DEFAULT_TOOLTIP_DELAY_MS = 700
|
|
7
15
|
|
|
@@ -12,19 +20,23 @@ export interface TldrawUiTooltipProps {
|
|
|
12
20
|
side?: 'top' | 'right' | 'bottom' | 'left'
|
|
13
21
|
sideOffset?: number
|
|
14
22
|
disabled?: boolean
|
|
23
|
+
showOnMobile?: boolean
|
|
24
|
+
delayDuration?: number
|
|
15
25
|
}
|
|
16
26
|
|
|
17
27
|
// Singleton tooltip manager
|
|
18
28
|
class TooltipManager {
|
|
19
29
|
private static instance: TooltipManager | null = null
|
|
20
|
-
private
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
30
|
+
private currentTooltip = atom<{
|
|
31
|
+
id: string
|
|
32
|
+
content: ReactNode
|
|
33
|
+
side: 'top' | 'right' | 'bottom' | 'left'
|
|
34
|
+
sideOffset: number
|
|
35
|
+
showOnMobile: boolean
|
|
36
|
+
targetElement: HTMLElement
|
|
37
|
+
delayDuration: number
|
|
38
|
+
} | null>('current tooltip', null)
|
|
24
39
|
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
40
|
|
|
29
41
|
static getInstance(): TooltipManager {
|
|
30
42
|
if (!TooltipManager.instance) {
|
|
@@ -33,25 +45,14 @@ class TooltipManager {
|
|
|
33
45
|
return TooltipManager.instance
|
|
34
46
|
}
|
|
35
47
|
|
|
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
48
|
showTooltip(
|
|
50
49
|
tooltipId: string,
|
|
51
50
|
content: string | React.ReactNode,
|
|
52
|
-
|
|
53
|
-
side: 'top' | 'right' | 'bottom' | 'left'
|
|
54
|
-
sideOffset: number
|
|
51
|
+
targetElement: HTMLElement,
|
|
52
|
+
side: 'top' | 'right' | 'bottom' | 'left',
|
|
53
|
+
sideOffset: number,
|
|
54
|
+
showOnMobile: boolean,
|
|
55
|
+
delayDuration: number
|
|
55
56
|
) {
|
|
56
57
|
// Clear any existing destroy timeout
|
|
57
58
|
if (this.destroyTimeoutId) {
|
|
@@ -60,51 +61,57 @@ class TooltipManager {
|
|
|
60
61
|
}
|
|
61
62
|
|
|
62
63
|
// Update current tooltip
|
|
63
|
-
this.
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
64
|
+
this.currentTooltip.set({
|
|
65
|
+
id: tooltipId,
|
|
66
|
+
content,
|
|
67
|
+
side,
|
|
68
|
+
sideOffset,
|
|
69
|
+
showOnMobile,
|
|
70
|
+
targetElement,
|
|
71
|
+
delayDuration,
|
|
72
|
+
})
|
|
70
73
|
}
|
|
71
74
|
|
|
72
|
-
hideTooltip(tooltipId: string, instant: boolean = false) {
|
|
75
|
+
hideTooltip(editor: Editor | null, tooltipId: string, instant: boolean = false) {
|
|
73
76
|
const hide = () => {
|
|
74
77
|
// Only hide if this is the current tooltip
|
|
75
|
-
if (this.
|
|
76
|
-
this.
|
|
77
|
-
this.currentContent = ''
|
|
78
|
-
this.activeElement = null
|
|
78
|
+
if (this.currentTooltip.get()?.id === tooltipId) {
|
|
79
|
+
this.currentTooltip.set(null)
|
|
79
80
|
this.destroyTimeoutId = null
|
|
80
|
-
this.notify()
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
-
if (instant) {
|
|
85
|
-
hide()
|
|
86
|
-
} else if (this.editor) {
|
|
84
|
+
if (editor && !instant) {
|
|
87
85
|
// Start destroy timeout (1 second)
|
|
88
|
-
this.destroyTimeoutId =
|
|
86
|
+
this.destroyTimeoutId = editor.timers.setTimeout(hide, 300)
|
|
87
|
+
} else {
|
|
88
|
+
hide()
|
|
89
89
|
}
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
hideAllTooltips() {
|
|
93
|
-
this.
|
|
94
|
-
this.currentContent = ''
|
|
95
|
-
this.activeElement = null
|
|
93
|
+
this.currentTooltip.set(null)
|
|
96
94
|
this.destroyTimeoutId = null
|
|
97
|
-
this.notify()
|
|
98
95
|
}
|
|
99
96
|
|
|
100
97
|
getCurrentTooltipData() {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
98
|
+
const currentTooltip = this.currentTooltip.get()
|
|
99
|
+
if (!currentTooltip) return null
|
|
100
|
+
if (!this.supportsHover() && !currentTooltip.showOnMobile) return null
|
|
101
|
+
return currentTooltip
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
private supportsHoverAtom: Atom<boolean> | null = null
|
|
105
|
+
supportsHover() {
|
|
106
|
+
if (!this.supportsHoverAtom) {
|
|
107
|
+
const mediaQuery = window.matchMedia('(hover: hover)')
|
|
108
|
+
const supportsHover = atom('has hover', mediaQuery.matches)
|
|
109
|
+
this.supportsHoverAtom = supportsHover
|
|
110
|
+
mediaQuery.addEventListener('change', (e) => {
|
|
111
|
+
supportsHover.set(e.matches)
|
|
112
|
+
})
|
|
107
113
|
}
|
|
114
|
+
return this.supportsHoverAtom.get()
|
|
108
115
|
}
|
|
109
116
|
}
|
|
110
117
|
|
|
@@ -132,66 +139,24 @@ export function TldrawUiTooltipProvider({ children }: TldrawUiTooltipProviderPro
|
|
|
132
139
|
|
|
133
140
|
// The singleton tooltip component that renders once
|
|
134
141
|
function TooltipSingleton() {
|
|
135
|
-
const editor = useMaybeEditor()
|
|
136
|
-
const [, forceUpdate] = useState({})
|
|
137
142
|
const [isOpen, setIsOpen] = useState(false)
|
|
138
143
|
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
144
|
const isFirstShowRef = useRef(true)
|
|
143
|
-
const showTimeoutRef = useRef<number | null>(null)
|
|
144
145
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
tooltipManager.
|
|
148
|
-
|
|
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()
|
|
146
|
+
const currentTooltip = useValue(
|
|
147
|
+
'current tooltip',
|
|
148
|
+
() => tooltipManager.getCurrentTooltipData(),
|
|
149
|
+
[]
|
|
150
|
+
)
|
|
159
151
|
|
|
160
152
|
// Update open state and trigger position
|
|
161
153
|
useEffect(() => {
|
|
162
|
-
|
|
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) {
|
|
154
|
+
let timer: ReturnType<typeof setTimeout> | null = null
|
|
155
|
+
if (currentTooltip && triggerRef.current) {
|
|
171
156
|
// Position the invisible trigger element over the active element
|
|
172
|
-
const activeRect =
|
|
157
|
+
const activeRect = currentTooltip.targetElement.getBoundingClientRect()
|
|
173
158
|
const trigger = triggerRef.current
|
|
174
159
|
|
|
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
160
|
trigger.style.position = 'fixed'
|
|
196
161
|
trigger.style.left = `${activeRect.left}px`
|
|
197
162
|
trigger.style.top = `${activeRect.top}px`
|
|
@@ -201,27 +166,31 @@ function TooltipSingleton() {
|
|
|
201
166
|
trigger.style.zIndex = '9999'
|
|
202
167
|
|
|
203
168
|
// Handle delay for first show
|
|
204
|
-
if (isFirstShowRef.current
|
|
205
|
-
|
|
169
|
+
if (isFirstShowRef.current) {
|
|
170
|
+
// eslint-disable-next-line no-restricted-globals
|
|
171
|
+
timer = setTimeout(() => {
|
|
206
172
|
setIsOpen(true)
|
|
207
173
|
isFirstShowRef.current = false
|
|
208
|
-
},
|
|
174
|
+
}, currentTooltip.delayDuration)
|
|
209
175
|
} else {
|
|
210
176
|
// Subsequent tooltips show immediately
|
|
211
177
|
setIsOpen(true)
|
|
212
178
|
}
|
|
213
|
-
} else
|
|
179
|
+
} else {
|
|
214
180
|
// Hide tooltip immediately
|
|
215
181
|
setIsOpen(false)
|
|
216
|
-
// Reset position tracking when tooltip closes
|
|
217
|
-
previousPositionRef.current = null
|
|
218
|
-
setShouldAnimate(false)
|
|
219
182
|
// Reset first show state after tooltip is hidden
|
|
220
183
|
isFirstShowRef.current = true
|
|
221
184
|
}
|
|
222
|
-
}, [tooltipData.id, tooltipData.element, editor, prefersReducedMotion])
|
|
223
185
|
|
|
224
|
-
|
|
186
|
+
return () => {
|
|
187
|
+
if (timer !== null) {
|
|
188
|
+
clearTimeout(timer)
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}, [currentTooltip])
|
|
192
|
+
|
|
193
|
+
if (!currentTooltip) {
|
|
225
194
|
return null
|
|
226
195
|
}
|
|
227
196
|
|
|
@@ -232,14 +201,13 @@ function TooltipSingleton() {
|
|
|
232
201
|
</_Tooltip.Trigger>
|
|
233
202
|
<_Tooltip.Content
|
|
234
203
|
className="tlui-tooltip"
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
sideOffset={tooltipData.sideOffset}
|
|
204
|
+
side={currentTooltip.side}
|
|
205
|
+
sideOffset={currentTooltip.sideOffset}
|
|
238
206
|
avoidCollisions
|
|
239
207
|
collisionPadding={8}
|
|
240
208
|
dir="ltr"
|
|
241
209
|
>
|
|
242
|
-
{
|
|
210
|
+
{currentTooltip.content}
|
|
243
211
|
<_Tooltip.Arrow className="tlui-tooltip__arrow" />
|
|
244
212
|
</_Tooltip.Content>
|
|
245
213
|
</_Tooltip.Root>
|
|
@@ -247,86 +215,111 @@ function TooltipSingleton() {
|
|
|
247
215
|
}
|
|
248
216
|
|
|
249
217
|
/** @public @react */
|
|
250
|
-
export
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
218
|
+
export const TldrawUiTooltip = forwardRef<HTMLButtonElement, TldrawUiTooltipProps>(
|
|
219
|
+
(
|
|
220
|
+
{
|
|
221
|
+
children,
|
|
222
|
+
content,
|
|
223
|
+
side,
|
|
224
|
+
sideOffset = 5,
|
|
225
|
+
disabled = false,
|
|
226
|
+
showOnMobile = false,
|
|
227
|
+
delayDuration,
|
|
228
|
+
},
|
|
229
|
+
ref
|
|
230
|
+
) => {
|
|
231
|
+
const editor = useMaybeEditor()
|
|
232
|
+
const tooltipId = useRef<string>(uniqueId())
|
|
233
|
+
const hasProvider = useContext(TooltipSingletonContext)
|
|
234
|
+
|
|
235
|
+
const orientationCtx = useTldrawUiOrientation()
|
|
236
|
+
const sideToUse = side ?? orientationCtx.tooltipSide
|
|
237
|
+
|
|
238
|
+
useEffect(() => {
|
|
239
|
+
const currentTooltipId = tooltipId.current
|
|
240
|
+
return () => {
|
|
241
|
+
if (hasProvider) {
|
|
242
|
+
tooltipManager.hideTooltip(editor, currentTooltipId, true)
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}, [editor, hasProvider])
|
|
265
246
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
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
|
-
}
|
|
247
|
+
// Don't show tooltip if disabled, no content, or UI labels are disabled
|
|
248
|
+
if (disabled || !content) {
|
|
249
|
+
return <>{children}</>
|
|
250
|
+
}
|
|
288
251
|
|
|
289
|
-
|
|
290
|
-
|
|
252
|
+
const delayDurationToUse =
|
|
253
|
+
delayDuration ?? (editor?.options.tooltipDelayMs || DEFAULT_TOOLTIP_DELAY_MS)
|
|
254
|
+
|
|
255
|
+
// Fallback to old behavior if no provider
|
|
256
|
+
if (!hasProvider) {
|
|
257
|
+
return (
|
|
258
|
+
<_Tooltip.Root delayDuration={delayDurationToUse} disableHoverableContent>
|
|
259
|
+
<_Tooltip.Trigger asChild ref={ref}>
|
|
260
|
+
{children}
|
|
261
|
+
</_Tooltip.Trigger>
|
|
262
|
+
<_Tooltip.Content
|
|
263
|
+
className="tlui-tooltip"
|
|
264
|
+
side={sideToUse}
|
|
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
|
+
}
|
|
291
276
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
277
|
+
const child = React.Children.only(children)
|
|
278
|
+
assert(React.isValidElement(child), 'TldrawUiTooltip children must be a single element')
|
|
279
|
+
|
|
280
|
+
const handleMouseEnter = (event: React.MouseEvent<HTMLElement>) => {
|
|
281
|
+
child.props.onMouseEnter?.(event)
|
|
282
|
+
tooltipManager.showTooltip(
|
|
283
|
+
tooltipId.current,
|
|
284
|
+
content,
|
|
285
|
+
event.currentTarget as HTMLElement,
|
|
286
|
+
sideToUse,
|
|
287
|
+
sideOffset,
|
|
288
|
+
showOnMobile,
|
|
289
|
+
delayDurationToUse
|
|
290
|
+
)
|
|
291
|
+
}
|
|
302
292
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
293
|
+
const handleMouseLeave = (event: React.MouseEvent<HTMLElement>) => {
|
|
294
|
+
child.props.onMouseLeave?.(event)
|
|
295
|
+
tooltipManager.hideTooltip(editor, tooltipId.current)
|
|
296
|
+
}
|
|
307
297
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
298
|
+
const handleFocus = (event: React.FocusEvent<HTMLElement>) => {
|
|
299
|
+
child.props.onFocus?.(event)
|
|
300
|
+
tooltipManager.showTooltip(
|
|
301
|
+
tooltipId.current,
|
|
302
|
+
content,
|
|
303
|
+
event.currentTarget as HTMLElement,
|
|
304
|
+
sideToUse,
|
|
305
|
+
sideOffset,
|
|
306
|
+
showOnMobile,
|
|
307
|
+
delayDurationToUse
|
|
308
|
+
)
|
|
309
|
+
}
|
|
318
310
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
311
|
+
const handleBlur = (event: React.FocusEvent<HTMLElement>) => {
|
|
312
|
+
child.props.onBlur?.(event)
|
|
313
|
+
tooltipManager.hideTooltip(editor, tooltipId.current)
|
|
314
|
+
}
|
|
323
315
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
316
|
+
const childrenWithHandlers = React.cloneElement(children as React.ReactElement, {
|
|
317
|
+
onMouseEnter: handleMouseEnter,
|
|
318
|
+
onMouseLeave: handleMouseLeave,
|
|
319
|
+
onFocus: handleFocus,
|
|
320
|
+
onBlur: handleBlur,
|
|
321
|
+
})
|
|
330
322
|
|
|
331
|
-
|
|
332
|
-
}
|
|
323
|
+
return childrenWithHandlers
|
|
324
|
+
}
|
|
325
|
+
)
|
|
@@ -1,10 +1,60 @@
|
|
|
1
1
|
import classNames from 'classnames'
|
|
2
2
|
import { Slot } from 'radix-ui'
|
|
3
|
-
import { HTMLAttributes, ReactNode, forwardRef } from 'react'
|
|
3
|
+
import { HTMLAttributes, ReactNode, createContext, forwardRef, useContext } from 'react'
|
|
4
|
+
|
|
5
|
+
/** @public */
|
|
6
|
+
export interface TldrawUiOrientationContext {
|
|
7
|
+
orientation: 'horizontal' | 'vertical'
|
|
8
|
+
tooltipSide: 'top' | 'right' | 'bottom' | 'left'
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const TldrawUiOrientationContext = createContext<TldrawUiOrientationContext>({
|
|
12
|
+
orientation: 'horizontal',
|
|
13
|
+
tooltipSide: 'bottom',
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
/** @public */
|
|
17
|
+
export interface TldrawUiOrientationProviderProps {
|
|
18
|
+
children: ReactNode
|
|
19
|
+
orientation: 'horizontal' | 'vertical'
|
|
20
|
+
tooltipSide?: 'top' | 'right' | 'bottom' | 'left'
|
|
21
|
+
}
|
|
22
|
+
/** @public @react */
|
|
23
|
+
export function TldrawUiOrientationProvider({
|
|
24
|
+
children,
|
|
25
|
+
orientation,
|
|
26
|
+
tooltipSide,
|
|
27
|
+
}: TldrawUiOrientationProviderProps) {
|
|
28
|
+
const prevContext = useTldrawUiOrientation()
|
|
29
|
+
// generally, we want tooltip side to cascade down through the layout - apart from when the
|
|
30
|
+
// orientation changes. If the tooltip side is "bottom", and then I include some vertical layout
|
|
31
|
+
// elements, keeping the tooltip side as bottom will cause the tooltip to overlap elements
|
|
32
|
+
// stacked on top of each other. In the absence of a tooltip side, we pick a default side based
|
|
33
|
+
// on the orientation whenever the orientation changes.
|
|
34
|
+
const tooltipSideToUse =
|
|
35
|
+
tooltipSide ??
|
|
36
|
+
(orientation === prevContext.orientation
|
|
37
|
+
? prevContext.tooltipSide
|
|
38
|
+
: orientation === 'horizontal'
|
|
39
|
+
? 'bottom'
|
|
40
|
+
: 'right')
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<TldrawUiOrientationContext.Provider value={{ orientation, tooltipSide: tooltipSideToUse }}>
|
|
44
|
+
{children}
|
|
45
|
+
</TldrawUiOrientationContext.Provider>
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** @public */
|
|
50
|
+
export function useTldrawUiOrientation() {
|
|
51
|
+
return useContext(TldrawUiOrientationContext)
|
|
52
|
+
}
|
|
4
53
|
|
|
5
54
|
/** @public */
|
|
6
55
|
export interface TLUiLayoutProps extends HTMLAttributes<HTMLDivElement> {
|
|
7
56
|
children: ReactNode
|
|
57
|
+
tooltipSide?: 'top' | 'right' | 'bottom' | 'left'
|
|
8
58
|
asChild?: boolean
|
|
9
59
|
}
|
|
10
60
|
|
|
@@ -14,9 +64,29 @@ export interface TLUiLayoutProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
14
64
|
* @public @react
|
|
15
65
|
*/
|
|
16
66
|
export const TldrawUiRow = forwardRef<HTMLDivElement, TLUiLayoutProps>(
|
|
17
|
-
({ asChild, className, ...props }, ref) => {
|
|
67
|
+
({ asChild, className, tooltipSide, ...props }, ref) => {
|
|
68
|
+
const Component = asChild ? Slot.Root : 'div'
|
|
69
|
+
return (
|
|
70
|
+
<TldrawUiOrientationProvider orientation="horizontal" tooltipSide={tooltipSide}>
|
|
71
|
+
<Component ref={ref} className={classNames('tlui-row', className)} {...props} />
|
|
72
|
+
</TldrawUiOrientationProvider>
|
|
73
|
+
)
|
|
74
|
+
}
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* A column, usually of UI controls like buttons, select dropdown, checkboxes, etc.
|
|
79
|
+
*
|
|
80
|
+
* @public @react
|
|
81
|
+
*/
|
|
82
|
+
export const TldrawUiColumn = forwardRef<HTMLDivElement, TLUiLayoutProps>(
|
|
83
|
+
({ asChild, className, tooltipSide, ...props }, ref) => {
|
|
18
84
|
const Component = asChild ? Slot.Root : 'div'
|
|
19
|
-
return
|
|
85
|
+
return (
|
|
86
|
+
<TldrawUiOrientationProvider orientation="vertical" tooltipSide={tooltipSide}>
|
|
87
|
+
<Component ref={ref} className={classNames('tlui-column', className)} {...props} />
|
|
88
|
+
</TldrawUiOrientationProvider>
|
|
89
|
+
)
|
|
20
90
|
}
|
|
21
91
|
)
|
|
22
92
|
|
|
@@ -26,8 +96,12 @@ export const TldrawUiRow = forwardRef<HTMLDivElement, TLUiLayoutProps>(
|
|
|
26
96
|
*
|
|
27
97
|
* @public @react */
|
|
28
98
|
export const TldrawUiGrid = forwardRef<HTMLDivElement, TLUiLayoutProps>(
|
|
29
|
-
({ asChild, className, ...props }, ref) => {
|
|
99
|
+
({ asChild, className, tooltipSide, ...props }, ref) => {
|
|
30
100
|
const Component = asChild ? Slot.Root : 'div'
|
|
31
|
-
return
|
|
101
|
+
return (
|
|
102
|
+
<TldrawUiOrientationProvider orientation="horizontal" tooltipSide={tooltipSide}>
|
|
103
|
+
<Component ref={ref} className={classNames('tlui-grid', className)} {...props} />
|
|
104
|
+
</TldrawUiOrientationProvider>
|
|
105
|
+
)
|
|
32
106
|
}
|
|
33
107
|
)
|
|
@@ -3,6 +3,7 @@ import { ReactNode } from 'react'
|
|
|
3
3
|
import { unwrapLabel } from '../../../context/actions'
|
|
4
4
|
import { TLUiTranslationKey } from '../../../hooks/useTranslation/TLUiTranslationKey'
|
|
5
5
|
import { useTranslation } from '../../../hooks/useTranslation/useTranslation'
|
|
6
|
+
import { TldrawUiColumn, TldrawUiGrid, TldrawUiRow, useTldrawUiOrientation } from '../layout'
|
|
6
7
|
import { TldrawUiDropdownMenuGroup } from '../TldrawUiDropdownMenu'
|
|
7
8
|
import { useTldrawUiMenuContext } from './TldrawUiMenuContext'
|
|
8
9
|
|
|
@@ -19,25 +20,19 @@ export interface TLUiMenuGroupProps<TranslationKey extends string = string> {
|
|
|
19
20
|
|
|
20
21
|
/** @public @react */
|
|
21
22
|
export function TldrawUiMenuGroup({ id, label, className, children }: TLUiMenuGroupProps) {
|
|
22
|
-
const
|
|
23
|
+
const menu = useTldrawUiMenuContext()
|
|
24
|
+
const { orientation } = useTldrawUiOrientation()
|
|
23
25
|
const msg = useTranslation()
|
|
24
|
-
const labelToUse = unwrapLabel(label,
|
|
26
|
+
const labelToUse = unwrapLabel(label, menu.type)
|
|
25
27
|
const labelStr = labelToUse ? msg(labelToUse as TLUiTranslationKey) : undefined
|
|
26
28
|
|
|
27
|
-
switch (
|
|
28
|
-
case 'panel': {
|
|
29
|
-
return (
|
|
30
|
-
<div
|
|
31
|
-
className={classNames('tlui-menu__group', className)}
|
|
32
|
-
data-testid={`${sourceId}-group.${id}`}
|
|
33
|
-
>
|
|
34
|
-
{children}
|
|
35
|
-
</div>
|
|
36
|
-
)
|
|
37
|
-
}
|
|
29
|
+
switch (menu.type) {
|
|
38
30
|
case 'menu': {
|
|
39
31
|
return (
|
|
40
|
-
<TldrawUiDropdownMenuGroup
|
|
32
|
+
<TldrawUiDropdownMenuGroup
|
|
33
|
+
className={className}
|
|
34
|
+
data-testid={`${menu.sourceId}-group.${id}`}
|
|
35
|
+
>
|
|
41
36
|
{children}
|
|
42
37
|
</TldrawUiDropdownMenuGroup>
|
|
43
38
|
)
|
|
@@ -47,7 +42,7 @@ export function TldrawUiMenuGroup({ id, label, className, children }: TLUiMenuGr
|
|
|
47
42
|
<div
|
|
48
43
|
dir="ltr"
|
|
49
44
|
className={classNames('tlui-menu__group', className)}
|
|
50
|
-
data-testid={`${sourceId}-group.${id}`}
|
|
45
|
+
data-testid={`${menu.sourceId}-group.${id}`}
|
|
51
46
|
>
|
|
52
47
|
{children}
|
|
53
48
|
</div>
|
|
@@ -56,12 +51,30 @@ export function TldrawUiMenuGroup({ id, label, className, children }: TLUiMenuGr
|
|
|
56
51
|
case 'keyboard-shortcuts': {
|
|
57
52
|
// todo: if groups need a label, let's give em a label
|
|
58
53
|
return (
|
|
59
|
-
<div className="tlui-shortcuts-dialog__group" data-testid={`${sourceId}-group.${id}`}>
|
|
54
|
+
<div className="tlui-shortcuts-dialog__group" data-testid={`${menu.sourceId}-group.${id}`}>
|
|
60
55
|
<h2 className="tlui-shortcuts-dialog__group__title">{labelStr}</h2>
|
|
61
56
|
<div className="tlui-shortcuts-dialog__group__content">{children}</div>
|
|
62
57
|
</div>
|
|
63
58
|
)
|
|
64
59
|
}
|
|
60
|
+
case 'toolbar': {
|
|
61
|
+
const Layout = orientation === 'horizontal' ? TldrawUiRow : TldrawUiColumn
|
|
62
|
+
return (
|
|
63
|
+
<Layout className="tlui-main-toolbar__group" data-testid={`${menu.sourceId}-group.${id}`}>
|
|
64
|
+
{children}
|
|
65
|
+
</Layout>
|
|
66
|
+
)
|
|
67
|
+
}
|
|
68
|
+
case 'toolbar-overflow': {
|
|
69
|
+
return (
|
|
70
|
+
<TldrawUiGrid
|
|
71
|
+
className="tlui-main-toolbar__group"
|
|
72
|
+
data-testid={`${menu.sourceId}-group.${id}`}
|
|
73
|
+
>
|
|
74
|
+
{children}
|
|
75
|
+
</TldrawUiGrid>
|
|
76
|
+
)
|
|
77
|
+
}
|
|
65
78
|
default: {
|
|
66
79
|
return children
|
|
67
80
|
}
|