tldraw 5.2.0-next.e2b8d10bf10e → 5.2.0
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/DOCS.md +20294 -0
- package/README.md +13 -1
- package/RELEASE_NOTES.md +2908 -0
- package/dist-cjs/index.d.ts +110 -23
- package/dist-cjs/index.js +3 -3
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/TldrawImage.js +0 -1
- package/dist-cjs/lib/TldrawImage.js.map +2 -2
- package/dist-cjs/lib/bindings/arrow/ArrowBindingUtil.js +2 -1
- package/dist-cjs/lib/bindings/arrow/ArrowBindingUtil.js.map +2 -2
- package/dist-cjs/lib/defaultEmbedDefinitions.js +3 -2
- package/dist-cjs/lib/defaultEmbedDefinitions.js.map +2 -2
- package/dist-cjs/lib/defaultOverlayUtils.js +11 -11
- package/dist-cjs/lib/defaultOverlayUtils.js.map +2 -2
- package/dist-cjs/lib/overlays/SelectionForegroundOverlayUtil.js +76 -64
- package/dist-cjs/lib/overlays/SelectionForegroundOverlayUtil.js.map +2 -2
- package/dist-cjs/lib/overlays/ShapeHandleOverlayUtil.js +1 -1
- package/dist-cjs/lib/overlays/ShapeHandleOverlayUtil.js.map +2 -2
- package/dist-cjs/lib/overlays/ShapeIndicatorOverlayUtil.js +107 -0
- package/dist-cjs/lib/overlays/ShapeIndicatorOverlayUtil.js.map +7 -0
- package/dist-cjs/lib/shapes/arrow/toolStates/Pointing.js +3 -0
- package/dist-cjs/lib/shapes/arrow/toolStates/Pointing.js.map +2 -2
- package/dist-cjs/lib/shapes/bookmark/BookmarkShapeUtil.js +12 -3
- package/dist-cjs/lib/shapes/bookmark/BookmarkShapeUtil.js.map +2 -2
- package/dist-cjs/lib/shapes/bookmark/bookmarks.js +54 -6
- package/dist-cjs/lib/shapes/bookmark/bookmarks.js.map +2 -2
- package/dist-cjs/lib/shapes/draw/DrawShapeUtil.js +2 -1
- package/dist-cjs/lib/shapes/draw/DrawShapeUtil.js.map +2 -2
- package/dist-cjs/lib/shapes/draw/getPath.js +1 -1
- package/dist-cjs/lib/shapes/draw/getPath.js.map +2 -2
- package/dist-cjs/lib/shapes/draw/toolStates/Drawing.js +45 -47
- package/dist-cjs/lib/shapes/draw/toolStates/Drawing.js.map +2 -2
- package/dist-cjs/lib/shapes/embed/EmbedShapeUtil.js +2 -1
- package/dist-cjs/lib/shapes/embed/EmbedShapeUtil.js.map +2 -2
- package/dist-cjs/lib/shapes/frame/FrameShapeTool.js +23 -18
- package/dist-cjs/lib/shapes/frame/FrameShapeTool.js.map +2 -2
- package/dist-cjs/lib/shapes/geo/GeoShapeUtil.js +1 -1
- package/dist-cjs/lib/shapes/geo/GeoShapeUtil.js.map +2 -2
- package/dist-cjs/lib/shapes/geo/toolStates/Pointing.js +3 -0
- package/dist-cjs/lib/shapes/geo/toolStates/Pointing.js.map +2 -2
- package/dist-cjs/lib/shapes/highlight/HighlightShapeUtil.js +11 -7
- package/dist-cjs/lib/shapes/highlight/HighlightShapeUtil.js.map +2 -2
- package/dist-cjs/lib/shapes/image/ImageShapeUtil.js +3 -11
- package/dist-cjs/lib/shapes/image/ImageShapeUtil.js.map +2 -2
- package/dist-cjs/lib/shapes/line/toolStates/Pointing.js +5 -1
- package/dist-cjs/lib/shapes/line/toolStates/Pointing.js.map +2 -2
- package/dist-cjs/lib/shapes/note/NoteShapeUtil.js +31 -41
- package/dist-cjs/lib/shapes/note/NoteShapeUtil.js.map +2 -2
- package/dist-cjs/lib/shapes/note/noteHelpers.js +1 -1
- package/dist-cjs/lib/shapes/note/noteHelpers.js.map +2 -2
- package/dist-cjs/lib/shapes/note/toolStates/Pointing.js +28 -6
- package/dist-cjs/lib/shapes/note/toolStates/Pointing.js.map +2 -2
- package/dist-cjs/lib/shapes/shared/PlainTextLabel.js +3 -2
- package/dist-cjs/lib/shapes/shared/PlainTextLabel.js.map +2 -2
- package/dist-cjs/lib/shapes/shared/RichTextLabel.js +3 -3
- package/dist-cjs/lib/shapes/shared/RichTextLabel.js.map +2 -2
- package/dist-cjs/lib/shapes/shared/defaultStyleDefs.js +17 -3
- package/dist-cjs/lib/shapes/shared/defaultStyleDefs.js.map +2 -2
- package/dist-cjs/lib/shapes/shared/freehand/core.js +424 -0
- package/dist-cjs/lib/shapes/shared/freehand/core.js.map +7 -0
- package/dist-cjs/lib/shapes/shared/freehand/fmt.js +106 -0
- package/dist-cjs/lib/shapes/shared/freehand/fmt.js.map +7 -0
- package/dist-cjs/lib/shapes/shared/freehand/getStroke.js +6 -6
- package/dist-cjs/lib/shapes/shared/freehand/getStroke.js.map +2 -2
- package/dist-cjs/lib/shapes/shared/freehand/getStrokeOutlinePoints.js +320 -86
- package/dist-cjs/lib/shapes/shared/freehand/getStrokeOutlinePoints.js.map +3 -3
- package/dist-cjs/lib/shapes/shared/freehand/getStrokePoints.js +20 -96
- package/dist-cjs/lib/shapes/shared/freehand/getStrokePoints.js.map +3 -3
- package/dist-cjs/lib/shapes/shared/freehand/svg.js +55 -19
- package/dist-cjs/lib/shapes/shared/freehand/svg.js.map +2 -2
- package/dist-cjs/lib/shapes/shared/freehand/svgInk.js +189 -97
- package/dist-cjs/lib/shapes/shared/freehand/svgInk.js.map +3 -3
- package/dist-cjs/lib/shapes/shared/freehand/types.js.map +1 -1
- package/dist-cjs/lib/shapes/shared/interpolate-props.js +6 -2
- package/dist-cjs/lib/shapes/shared/interpolate-props.js.map +2 -2
- package/dist-cjs/lib/shapes/text/toolStates/Pointing.js +3 -0
- package/dist-cjs/lib/shapes/text/toolStates/Pointing.js.map +2 -2
- package/dist-cjs/lib/tools/HandTool/HandTool.js +16 -6
- package/dist-cjs/lib/tools/HandTool/HandTool.js.map +2 -2
- package/dist-cjs/lib/tools/HandTool/childStates/Dragging.js +10 -1
- package/dist-cjs/lib/tools/HandTool/childStates/Dragging.js.map +2 -2
- package/dist-cjs/lib/tools/HandTool/childStates/OneFingerZooming.js +84 -0
- package/dist-cjs/lib/tools/HandTool/childStates/OneFingerZooming.js.map +7 -0
- package/dist-cjs/lib/tools/SelectTool/childStates/Idle.js +12 -0
- package/dist-cjs/lib/tools/SelectTool/childStates/Idle.js.map +2 -2
- package/dist-cjs/lib/tools/SelectTool/childStates/PointingShape.js +4 -0
- package/dist-cjs/lib/tools/SelectTool/childStates/PointingShape.js.map +2 -2
- package/dist-cjs/lib/tools/SelectTool/childStates/Resizing.js +107 -46
- package/dist-cjs/lib/tools/SelectTool/childStates/Resizing.js.map +2 -2
- package/dist-cjs/lib/ui/TldrawUi.js +4 -3
- package/dist-cjs/lib/ui/TldrawUi.js.map +2 -2
- package/dist-cjs/lib/ui/components/A11y.js +2 -0
- package/dist-cjs/lib/ui/components/A11y.js.map +2 -2
- package/dist-cjs/lib/ui/components/ContextMenu/DefaultContextMenu.js +14 -1
- package/dist-cjs/lib/ui/components/ContextMenu/DefaultContextMenu.js.map +2 -2
- package/dist-cjs/lib/ui/components/ContextMenu/DefaultContextMenuContent.js +0 -6
- package/dist-cjs/lib/ui/components/ContextMenu/DefaultContextMenuContent.js.map +2 -2
- package/dist-cjs/lib/ui/components/DefaultFollowingIndicator.js.map +2 -2
- package/dist-cjs/lib/ui/components/Dialogs.js +17 -37
- package/dist-cjs/lib/ui/components/Dialogs.js.map +2 -2
- package/dist-cjs/lib/ui/components/HelperButtons/BackToContent.js +19 -4
- package/dist-cjs/lib/ui/components/HelperButtons/BackToContent.js.map +2 -2
- package/dist-cjs/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.js +12 -2
- package/dist-cjs/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.js.map +2 -2
- package/dist-cjs/lib/ui/components/Minimap/DefaultMinimap.js +47 -70
- package/dist-cjs/lib/ui/components/Minimap/DefaultMinimap.js.map +2 -2
- package/dist-cjs/lib/ui/components/Minimap/MinimapManager.js +25 -46
- package/dist-cjs/lib/ui/components/Minimap/MinimapManager.js.map +2 -2
- package/dist-cjs/lib/ui/components/SharePanel/DefaultPeopleMenuAvatar.js.map +2 -2
- package/dist-cjs/lib/ui/components/SharePanel/DefaultPeopleMenuContent.js.map +2 -2
- package/dist-cjs/lib/ui/components/SharePanel/DefaultPeopleMenuFacePile.js.map +2 -2
- package/dist-cjs/lib/ui/components/SharePanel/DefaultPeopleMenuItem.js +1 -1
- package/dist-cjs/lib/ui/components/SharePanel/DefaultPeopleMenuItem.js.map +2 -2
- package/dist-cjs/lib/ui/components/StylePanel/StylePanelButtonPicker.js +1 -0
- package/dist-cjs/lib/ui/components/StylePanel/StylePanelButtonPicker.js.map +2 -2
- package/dist-cjs/lib/ui/components/menu-items.js +7 -0
- package/dist-cjs/lib/ui/components/menu-items.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/TldrawUiDropdownMenu.js +2 -1
- package/dist-cjs/lib/ui/components/primitives/TldrawUiDropdownMenu.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/TldrawUiIcon.js +14 -3
- package/dist-cjs/lib/ui/components/primitives/TldrawUiIcon.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/TldrawUiInput.js +2 -0
- package/dist-cjs/lib/ui/components/primitives/TldrawUiInput.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/TldrawUiPopover.js +2 -0
- package/dist-cjs/lib/ui/components/primitives/TldrawUiPopover.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.js +0 -2
- package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuSubmenu.js +1 -2
- package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuSubmenu.js.map +2 -2
- package/dist-cjs/lib/ui/context/actions.js +70 -1
- package/dist-cjs/lib/ui/context/actions.js.map +2 -2
- package/dist-cjs/lib/ui/context/asset-urls.js +5 -8
- package/dist-cjs/lib/ui/context/asset-urls.js.map +2 -2
- package/dist-cjs/lib/ui/context/events.js.map +2 -2
- package/dist-cjs/lib/ui/hooks/useKeyboardShortcuts.js +13 -0
- package/dist-cjs/lib/ui/hooks/useKeyboardShortcuts.js.map +2 -2
- package/dist-cjs/lib/ui/hooks/useTools.js +1 -1
- 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 +2 -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-cjs/lib/utils/embeds/embeds.js +4 -4
- package/dist-cjs/lib/utils/embeds/embeds.js.map +2 -2
- package/dist-cjs/lib/utils/test-helpers.js +2 -2
- package/dist-cjs/lib/utils/test-helpers.js.map +2 -2
- package/dist-cjs/lib/utils/text/richText.js +3 -1
- package/dist-cjs/lib/utils/text/richText.js.map +2 -2
- package/dist-esm/index.d.mts +110 -23
- package/dist-esm/index.mjs +5 -3
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/TldrawImage.mjs +0 -1
- package/dist-esm/lib/TldrawImage.mjs.map +2 -2
- package/dist-esm/lib/bindings/arrow/ArrowBindingUtil.mjs +2 -1
- package/dist-esm/lib/bindings/arrow/ArrowBindingUtil.mjs.map +2 -2
- package/dist-esm/lib/defaultEmbedDefinitions.mjs +3 -2
- package/dist-esm/lib/defaultEmbedDefinitions.mjs.map +2 -2
- package/dist-esm/lib/defaultOverlayUtils.mjs +11 -11
- package/dist-esm/lib/defaultOverlayUtils.mjs.map +2 -2
- package/dist-esm/lib/overlays/SelectionForegroundOverlayUtil.mjs +77 -65
- package/dist-esm/lib/overlays/SelectionForegroundOverlayUtil.mjs.map +2 -2
- package/dist-esm/lib/overlays/ShapeHandleOverlayUtil.mjs +1 -1
- package/dist-esm/lib/overlays/ShapeHandleOverlayUtil.mjs.map +2 -2
- package/dist-esm/lib/overlays/ShapeIndicatorOverlayUtil.mjs +87 -0
- package/dist-esm/lib/overlays/ShapeIndicatorOverlayUtil.mjs.map +7 -0
- package/dist-esm/lib/shapes/arrow/toolStates/Pointing.mjs +9 -1
- package/dist-esm/lib/shapes/arrow/toolStates/Pointing.mjs.map +2 -2
- package/dist-esm/lib/shapes/bookmark/BookmarkShapeUtil.mjs +15 -3
- package/dist-esm/lib/shapes/bookmark/BookmarkShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/shapes/bookmark/bookmarks.mjs +54 -6
- package/dist-esm/lib/shapes/bookmark/bookmarks.mjs.map +2 -2
- package/dist-esm/lib/shapes/draw/DrawShapeUtil.mjs +3 -1
- package/dist-esm/lib/shapes/draw/DrawShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/shapes/draw/getPath.mjs +1 -1
- package/dist-esm/lib/shapes/draw/getPath.mjs.map +2 -2
- package/dist-esm/lib/shapes/draw/toolStates/Drawing.mjs +46 -47
- package/dist-esm/lib/shapes/draw/toolStates/Drawing.mjs.map +2 -2
- package/dist-esm/lib/shapes/embed/EmbedShapeUtil.mjs +2 -1
- package/dist-esm/lib/shapes/embed/EmbedShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/shapes/frame/FrameShapeTool.mjs +23 -18
- package/dist-esm/lib/shapes/frame/FrameShapeTool.mjs.map +2 -2
- package/dist-esm/lib/shapes/geo/GeoShapeUtil.mjs +2 -1
- package/dist-esm/lib/shapes/geo/GeoShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/shapes/geo/toolStates/Pointing.mjs +4 -0
- package/dist-esm/lib/shapes/geo/toolStates/Pointing.mjs.map +2 -2
- package/dist-esm/lib/shapes/highlight/HighlightShapeUtil.mjs +12 -7
- package/dist-esm/lib/shapes/highlight/HighlightShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/shapes/image/ImageShapeUtil.mjs +3 -11
- package/dist-esm/lib/shapes/image/ImageShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/shapes/line/toolStates/Pointing.mjs +6 -1
- package/dist-esm/lib/shapes/line/toolStates/Pointing.mjs.map +2 -2
- package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs +32 -42
- package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/shapes/note/noteHelpers.mjs +1 -1
- package/dist-esm/lib/shapes/note/noteHelpers.mjs.map +2 -2
- package/dist-esm/lib/shapes/note/toolStates/Pointing.mjs +29 -6
- package/dist-esm/lib/shapes/note/toolStates/Pointing.mjs.map +2 -2
- package/dist-esm/lib/shapes/shared/PlainTextLabel.mjs +3 -2
- package/dist-esm/lib/shapes/shared/PlainTextLabel.mjs.map +2 -2
- package/dist-esm/lib/shapes/shared/RichTextLabel.mjs +4 -3
- package/dist-esm/lib/shapes/shared/RichTextLabel.mjs.map +2 -2
- package/dist-esm/lib/shapes/shared/defaultStyleDefs.mjs +17 -3
- package/dist-esm/lib/shapes/shared/defaultStyleDefs.mjs.map +2 -2
- package/dist-esm/lib/shapes/shared/freehand/core.mjs +404 -0
- package/dist-esm/lib/shapes/shared/freehand/core.mjs.map +7 -0
- package/dist-esm/lib/shapes/shared/freehand/fmt.mjs +86 -0
- package/dist-esm/lib/shapes/shared/freehand/fmt.mjs.map +7 -0
- package/dist-esm/lib/shapes/shared/freehand/getStroke.mjs +7 -7
- package/dist-esm/lib/shapes/shared/freehand/getStroke.mjs.map +2 -2
- package/dist-esm/lib/shapes/shared/freehand/getStrokeOutlinePoints.mjs +332 -86
- package/dist-esm/lib/shapes/shared/freehand/getStrokeOutlinePoints.mjs.map +3 -3
- package/dist-esm/lib/shapes/shared/freehand/getStrokePoints.mjs +31 -96
- package/dist-esm/lib/shapes/shared/freehand/getStrokePoints.mjs.map +3 -3
- package/dist-esm/lib/shapes/shared/freehand/svg.mjs +55 -19
- package/dist-esm/lib/shapes/shared/freehand/svg.mjs.map +2 -2
- package/dist-esm/lib/shapes/shared/freehand/svgInk.mjs +214 -99
- package/dist-esm/lib/shapes/shared/freehand/svgInk.mjs.map +3 -3
- package/dist-esm/lib/shapes/shared/interpolate-props.mjs +6 -2
- package/dist-esm/lib/shapes/shared/interpolate-props.mjs.map +2 -2
- package/dist-esm/lib/shapes/text/toolStates/Pointing.mjs +4 -0
- package/dist-esm/lib/shapes/text/toolStates/Pointing.mjs.map +2 -2
- package/dist-esm/lib/tools/HandTool/HandTool.mjs +16 -6
- package/dist-esm/lib/tools/HandTool/HandTool.mjs.map +2 -2
- package/dist-esm/lib/tools/HandTool/childStates/Dragging.mjs +10 -1
- package/dist-esm/lib/tools/HandTool/childStates/Dragging.mjs.map +2 -2
- package/dist-esm/lib/tools/HandTool/childStates/OneFingerZooming.mjs +64 -0
- package/dist-esm/lib/tools/HandTool/childStates/OneFingerZooming.mjs.map +7 -0
- package/dist-esm/lib/tools/SelectTool/childStates/Idle.mjs +12 -0
- package/dist-esm/lib/tools/SelectTool/childStates/Idle.mjs.map +2 -2
- package/dist-esm/lib/tools/SelectTool/childStates/PointingShape.mjs +4 -0
- package/dist-esm/lib/tools/SelectTool/childStates/PointingShape.mjs.map +2 -2
- package/dist-esm/lib/tools/SelectTool/childStates/Resizing.mjs +108 -46
- package/dist-esm/lib/tools/SelectTool/childStates/Resizing.mjs.map +2 -2
- package/dist-esm/lib/ui/TldrawUi.mjs +4 -3
- package/dist-esm/lib/ui/TldrawUi.mjs.map +2 -2
- package/dist-esm/lib/ui/components/A11y.mjs +2 -0
- package/dist-esm/lib/ui/components/A11y.mjs.map +2 -2
- package/dist-esm/lib/ui/components/ContextMenu/DefaultContextMenu.mjs +21 -2
- package/dist-esm/lib/ui/components/ContextMenu/DefaultContextMenu.mjs.map +2 -2
- package/dist-esm/lib/ui/components/ContextMenu/DefaultContextMenuContent.mjs +0 -6
- package/dist-esm/lib/ui/components/ContextMenu/DefaultContextMenuContent.mjs.map +2 -2
- package/dist-esm/lib/ui/components/DefaultFollowingIndicator.mjs.map +2 -2
- package/dist-esm/lib/ui/components/Dialogs.mjs +19 -39
- package/dist-esm/lib/ui/components/Dialogs.mjs.map +2 -2
- package/dist-esm/lib/ui/components/HelperButtons/BackToContent.mjs +20 -5
- package/dist-esm/lib/ui/components/HelperButtons/BackToContent.mjs.map +2 -2
- package/dist-esm/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.mjs +12 -2
- package/dist-esm/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.mjs.map +2 -2
- package/dist-esm/lib/ui/components/Minimap/DefaultMinimap.mjs +47 -70
- package/dist-esm/lib/ui/components/Minimap/DefaultMinimap.mjs.map +2 -2
- package/dist-esm/lib/ui/components/Minimap/MinimapManager.mjs +25 -46
- package/dist-esm/lib/ui/components/Minimap/MinimapManager.mjs.map +2 -2
- package/dist-esm/lib/ui/components/SharePanel/DefaultPeopleMenuAvatar.mjs.map +2 -2
- package/dist-esm/lib/ui/components/SharePanel/DefaultPeopleMenuContent.mjs.map +2 -2
- package/dist-esm/lib/ui/components/SharePanel/DefaultPeopleMenuFacePile.mjs.map +2 -2
- package/dist-esm/lib/ui/components/SharePanel/DefaultPeopleMenuItem.mjs +1 -1
- package/dist-esm/lib/ui/components/SharePanel/DefaultPeopleMenuItem.mjs.map +2 -2
- package/dist-esm/lib/ui/components/StylePanel/StylePanelButtonPicker.mjs +1 -0
- package/dist-esm/lib/ui/components/StylePanel/StylePanelButtonPicker.mjs.map +2 -2
- package/dist-esm/lib/ui/components/menu-items.mjs +7 -0
- package/dist-esm/lib/ui/components/menu-items.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/TldrawUiDropdownMenu.mjs +2 -1
- package/dist-esm/lib/ui/components/primitives/TldrawUiDropdownMenu.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/TldrawUiIcon.mjs +14 -3
- package/dist-esm/lib/ui/components/primitives/TldrawUiIcon.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/TldrawUiInput.mjs +2 -0
- package/dist-esm/lib/ui/components/primitives/TldrawUiInput.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/TldrawUiPopover.mjs +2 -0
- package/dist-esm/lib/ui/components/primitives/TldrawUiPopover.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.mjs +0 -2
- package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuSubmenu.mjs +1 -2
- package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuSubmenu.mjs.map +2 -2
- package/dist-esm/lib/ui/context/actions.mjs +71 -1
- package/dist-esm/lib/ui/context/actions.mjs.map +2 -2
- package/dist-esm/lib/ui/context/asset-urls.mjs +5 -8
- package/dist-esm/lib/ui/context/asset-urls.mjs.map +2 -2
- package/dist-esm/lib/ui/context/events.mjs.map +2 -2
- package/dist-esm/lib/ui/hooks/useKeyboardShortcuts.mjs +13 -0
- package/dist-esm/lib/ui/hooks/useKeyboardShortcuts.mjs.map +2 -2
- package/dist-esm/lib/ui/hooks/useTools.mjs +1 -1
- package/dist-esm/lib/ui/hooks/useTools.mjs.map +2 -2
- 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/version.mjs +3 -3
- package/dist-esm/lib/ui/version.mjs.map +1 -1
- package/dist-esm/lib/utils/embeds/embeds.mjs +4 -4
- package/dist-esm/lib/utils/embeds/embeds.mjs.map +2 -2
- package/dist-esm/lib/utils/test-helpers.mjs +2 -2
- package/dist-esm/lib/utils/test-helpers.mjs.map +2 -2
- package/dist-esm/lib/utils/text/richText.mjs +3 -1
- package/dist-esm/lib/utils/text/richText.mjs.map +2 -2
- package/package.json +11 -6
- package/src/index.ts +6 -1
- package/src/lib/TldrawImage.tsx +2 -2
- package/src/lib/bindings/arrow/ArrowBindingUtil.ts +5 -1
- package/src/lib/defaultEmbedDefinitions.ts +28 -6
- package/src/lib/defaultOverlayUtils.ts +11 -11
- package/src/lib/overlays/SelectionForegroundOverlayUtil.ts +91 -72
- package/src/lib/overlays/ShapeHandleOverlayUtil.ts +3 -1
- package/src/lib/overlays/ShapeIndicatorOverlayUtil.ts +133 -0
- package/src/lib/shapes/arrow/toolStates/Pointing.tsx +11 -1
- package/src/lib/shapes/bookmark/BookmarkShapeUtil.tsx +16 -3
- package/src/lib/shapes/bookmark/bookmarks.ts +105 -15
- package/src/lib/shapes/draw/DrawShapeUtil.tsx +7 -5
- package/src/lib/shapes/draw/getPath.ts +1 -1
- package/src/lib/shapes/draw/toolStates/Drawing.ts +55 -48
- package/src/lib/shapes/embed/EmbedShapeUtil.tsx +14 -4
- package/src/lib/shapes/frame/FrameShapeTool.ts +35 -24
- package/src/lib/shapes/geo/GeoShapeUtil.test.tsx +46 -0
- package/src/lib/shapes/geo/GeoShapeUtil.tsx +2 -1
- package/src/lib/shapes/geo/toolStates/Pointing.ts +5 -0
- package/src/lib/shapes/highlight/HighlightShapeUtil.tsx +14 -11
- package/src/lib/shapes/image/ImageShapeUtil.tsx +7 -11
- package/src/lib/shapes/line/LineShapeTool.test.ts +41 -0
- package/src/lib/shapes/line/toolStates/Pointing.ts +12 -2
- package/src/lib/shapes/note/NoteShapeUtil.tsx +36 -51
- package/src/lib/shapes/note/noteCloning.test.ts +5 -5
- package/src/lib/shapes/note/noteHelpers.ts +1 -1
- package/src/lib/shapes/note/toolStates/Pointing.ts +40 -7
- package/src/lib/shapes/shared/PlainTextLabel.tsx +3 -3
- package/src/lib/shapes/shared/RichTextLabel.tsx +4 -3
- package/src/lib/shapes/shared/defaultStyleDefs.tsx +25 -3
- package/src/lib/shapes/shared/freehand/core.ts +547 -0
- package/src/lib/shapes/shared/freehand/fmt.ts +106 -0
- package/src/lib/shapes/shared/freehand/getStroke.ts +7 -7
- package/src/lib/shapes/shared/freehand/getStrokeOutlinePoints.ts +451 -139
- package/src/lib/shapes/shared/freehand/getStrokePoints.ts +33 -153
- package/src/lib/shapes/shared/freehand/svg.ts +72 -23
- package/src/lib/shapes/shared/freehand/svgInk.ts +281 -136
- package/src/lib/shapes/shared/freehand/types.ts +0 -1
- package/src/lib/shapes/shared/interpolate-props.ts +6 -2
- package/src/lib/shapes/text/toolStates/Pointing.ts +5 -0
- package/src/lib/tools/HandTool/HandTool.ts +19 -6
- package/src/lib/tools/HandTool/childStates/Dragging.ts +17 -1
- package/src/lib/tools/HandTool/childStates/OneFingerZooming.ts +79 -0
- package/src/lib/tools/SelectTool/childStates/Idle.ts +16 -2
- package/src/lib/tools/SelectTool/childStates/PointingShape.ts +8 -0
- package/src/lib/tools/SelectTool/childStates/Resizing.ts +137 -49
- package/src/lib/ui/TldrawUi.tsx +3 -3
- package/src/lib/ui/components/A11y.tsx +2 -0
- package/src/lib/ui/components/ContextMenu/DefaultContextMenu.tsx +32 -2
- package/src/lib/ui/components/ContextMenu/DefaultContextMenuContent.tsx +5 -6
- package/src/lib/ui/components/DefaultFollowingIndicator.tsx +2 -2
- package/src/lib/ui/components/Dialogs.tsx +20 -23
- package/src/lib/ui/components/HelperButtons/BackToContent.tsx +32 -4
- package/src/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.tsx +10 -0
- package/src/lib/ui/components/Minimap/DefaultMinimap.tsx +60 -74
- package/src/lib/ui/components/Minimap/MinimapManager.ts +35 -57
- package/src/lib/ui/components/SharePanel/DefaultPeopleMenuAvatar.tsx +2 -2
- package/src/lib/ui/components/SharePanel/DefaultPeopleMenuContent.tsx +2 -1
- package/src/lib/ui/components/SharePanel/DefaultPeopleMenuFacePile.tsx +2 -1
- package/src/lib/ui/components/SharePanel/DefaultPeopleMenuItem.tsx +3 -3
- package/src/lib/ui/components/StylePanel/StylePanelButtonPicker.tsx +5 -0
- package/src/lib/ui/components/menu-items.tsx +9 -0
- package/src/lib/ui/components/primitives/TldrawUiDropdownMenu.tsx +3 -1
- package/src/lib/ui/components/primitives/TldrawUiIcon.tsx +15 -3
- package/src/lib/ui/components/primitives/TldrawUiInput.tsx +4 -0
- package/src/lib/ui/components/primitives/TldrawUiPopover.tsx +7 -0
- package/src/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.tsx +0 -2
- package/src/lib/ui/components/primitives/menus/TldrawUiMenuSubmenu.tsx +0 -1
- package/src/lib/ui/context/actions.tsx +88 -1
- package/src/lib/ui/context/asset-urls.tsx +9 -8
- package/src/lib/ui/context/events.tsx +2 -0
- package/src/lib/ui/hooks/useKeyboardShortcuts.ts +45 -7
- package/src/lib/ui/hooks/useTools.tsx +7 -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/version.ts +3 -3
- package/src/lib/ui.css +20 -9
- package/src/lib/utils/embeds/embeds.test.ts +14 -12
- package/src/lib/utils/embeds/embeds.ts +10 -4
- package/src/lib/utils/test-helpers.ts +3 -3
- package/src/lib/utils/text/richText.test.ts +36 -0
- package/src/lib/utils/text/richText.ts +9 -1
- package/src/test/HandTool.test.ts +93 -0
- package/src/test/ImageShapeUtil.test.ts +88 -0
- package/src/test/SelectTool.test.ts +102 -1
- package/src/test/__snapshots__/drawing.test.ts.snap +2 -1
- package/src/test/attribution.test.ts +40 -29
- package/src/test/bookmark-shapes.test.ts +256 -28
- package/src/test/commands/__snapshots__/getSvgString.test.ts.snap +2 -2
- package/src/test/commands/clipboardCallbacks.test.ts +3 -1
- package/src/test/commands/getSvgString.test.ts +30 -0
- package/src/test/commands/penmode.test.ts +97 -1
- package/src/test/commands/setCamera.test.ts +12 -0
- package/src/test/dragFromToolbar.test.ts +67 -0
- package/src/test/drawing.test.ts +48 -7
- package/src/test/frames.test.ts +72 -0
- package/src/test/freehand/corpus/presets.ts +71 -0
- package/src/test/freehand/corpus/real.ts +370 -0
- package/src/test/freehand/corpus/strokes.ts +50 -0
- package/src/test/freehand/svg.test.ts +20 -0
- package/src/test/freehand/wellformed.test.ts +30 -0
- package/src/test/long-press-create.test.ts +102 -0
- package/src/test/overlays/CollaboratorBrushOverlayUtil.test.ts +4 -4
- package/src/test/overlays/CollaboratorCursorOverlayUtil.test.ts +18 -18
- package/src/test/overlays/CollaboratorHintOverlayUtil.test.ts +7 -7
- package/src/test/overlays/CollaboratorScribbleOverlayUtil.test.ts +3 -3
- package/src/test/overlays/OverlayManager.test.ts +1 -1
- package/src/test/overlays/SelectionForegroundOverlayUtil.test.ts +58 -0
- package/src/test/overlays/ShapeHandleOverlayUtil.test.ts +2 -2
- package/src/test/overlays/ShapeIndicatorOverlayUtil.test.ts +36 -0
- package/src/test/resizing.test.ts +250 -0
- package/src/test/right-click-context-menu.test.ts +90 -0
- package/src/test/rightClickPanning.test.ts +11 -0
- package/src/test/selection-omnibus.test.ts +15 -2
- package/src/test/spatialIndex.test.ts +132 -0
- package/src/test/translating.test.ts +0 -6
- package/src/test/ui/ContextMenu.test.tsx +146 -3
- package/src/test/ui/Dialogs.test.tsx +256 -0
- package/src/test/ui/copyHoveredStyles.test.tsx +154 -0
- package/src/test/ui/keyboardShortcuts.test.tsx +266 -0
- package/tldraw.css +35 -12
- package/dist-cjs/lib/shapes/shared/freehand/setStrokePointRadii.js +0 -100
- package/dist-cjs/lib/shapes/shared/freehand/setStrokePointRadii.js.map +0 -7
- package/dist-esm/lib/shapes/shared/freehand/setStrokePointRadii.mjs +0 -80
- package/dist-esm/lib/shapes/shared/freehand/setStrokePointRadii.mjs.map +0 -7
- package/src/lib/shapes/shared/freehand/setStrokePointRadii.ts +0 -127
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
GapsSnapIndicator,
|
|
3
|
+
Mat,
|
|
3
4
|
PI,
|
|
4
5
|
PI2,
|
|
5
6
|
PointsSnapIndicator,
|
|
6
7
|
RotateCorner,
|
|
8
|
+
TLArrowShape,
|
|
7
9
|
TLGeoShape,
|
|
8
10
|
TLSelectionHandle,
|
|
9
11
|
TLShapeId,
|
|
@@ -16,6 +18,7 @@ import {
|
|
|
16
18
|
toRichText,
|
|
17
19
|
} from '@tldraw/editor'
|
|
18
20
|
import { vi } from 'vitest'
|
|
21
|
+
import { getArrowBindings, getArrowTerminalsInArrowSpace } from '../lib/shapes/arrow/shared'
|
|
19
22
|
import { NoteShapeUtil } from '../lib/shapes/note/NoteShapeUtil'
|
|
20
23
|
import { createDrawSegments } from '../lib/utils/test-helpers'
|
|
21
24
|
import { getSnapLines } from './getSnapLines'
|
|
@@ -867,6 +870,253 @@ describe('When resizing a shape with children', () => {
|
|
|
867
870
|
})
|
|
868
871
|
})
|
|
869
872
|
|
|
873
|
+
describe('When resizing nested shapes', () => {
|
|
874
|
+
// A document with the common kinds of nesting: a geo shape on the page, a
|
|
875
|
+
// group of two geo shapes, a frame with a geo child, and arrows bound from
|
|
876
|
+
// the page shape to a group child and from a group child to the frame child.
|
|
877
|
+
//
|
|
878
|
+
// 0 100 200 500
|
|
879
|
+
//
|
|
880
|
+
// 0 ┌─group1─────────┐
|
|
881
|
+
// │ ┌─────┐ │
|
|
882
|
+
// │ │ A │ ┌─────┐│
|
|
883
|
+
// 100 │ └─────┘ │ B ││
|
|
884
|
+
// 200 ┌─────┐ └─────────┴─────┘│
|
|
885
|
+
// │page │
|
|
886
|
+
// 300 └─────┘
|
|
887
|
+
// 400 ┌─frame1─────────┐
|
|
888
|
+
// │ ┌─────┐ │
|
|
889
|
+
// │ │ C │ │
|
|
890
|
+
// 600 └─┴─────┴────────┘
|
|
891
|
+
const nestedIds = {
|
|
892
|
+
pageBox: createShapeId('pageBox'),
|
|
893
|
+
group1: createShapeId('group1'),
|
|
894
|
+
groupBoxA: createShapeId('groupBoxA'),
|
|
895
|
+
groupBoxB: createShapeId('groupBoxB'),
|
|
896
|
+
frame1: createShapeId('frame1'),
|
|
897
|
+
frameBox: createShapeId('frameBox'),
|
|
898
|
+
arrowPageToGroup: createShapeId('arrowPageToGroup'),
|
|
899
|
+
arrowGroupToFrame: createShapeId('arrowGroupToFrame'),
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
beforeEach(() => {
|
|
903
|
+
editor.selectAll().deleteShapes(editor.getSelectedShapeIds())
|
|
904
|
+
editor
|
|
905
|
+
.createShapes([
|
|
906
|
+
{ id: nestedIds.pageBox, type: 'geo', x: 0, y: 200, props: { w: 100, h: 100 } },
|
|
907
|
+
{ id: nestedIds.groupBoxA, type: 'geo', x: 200, y: 0, props: { w: 100, h: 100 } },
|
|
908
|
+
{ id: nestedIds.groupBoxB, type: 'geo', x: 400, y: 100, props: { w: 100, h: 100 } },
|
|
909
|
+
{ id: nestedIds.frame1, type: 'frame', x: 200, y: 400, props: { w: 300, h: 200 } },
|
|
910
|
+
{
|
|
911
|
+
id: nestedIds.frameBox,
|
|
912
|
+
type: 'geo',
|
|
913
|
+
parentId: nestedIds.frame1,
|
|
914
|
+
x: 50,
|
|
915
|
+
y: 50,
|
|
916
|
+
props: { w: 100, h: 100 },
|
|
917
|
+
},
|
|
918
|
+
])
|
|
919
|
+
.groupShapes([nestedIds.groupBoxA, nestedIds.groupBoxB], { groupId: nestedIds.group1 })
|
|
920
|
+
.createShapes([
|
|
921
|
+
{
|
|
922
|
+
id: nestedIds.arrowPageToGroup,
|
|
923
|
+
type: 'arrow',
|
|
924
|
+
x: 150,
|
|
925
|
+
y: 200,
|
|
926
|
+
props: { start: { x: 0, y: 0 }, end: { x: 50, y: -100 } },
|
|
927
|
+
},
|
|
928
|
+
{
|
|
929
|
+
id: nestedIds.arrowGroupToFrame,
|
|
930
|
+
type: 'arrow',
|
|
931
|
+
x: 450,
|
|
932
|
+
y: 250,
|
|
933
|
+
props: { start: { x: 0, y: 0 }, end: { x: -150, y: 250 } },
|
|
934
|
+
},
|
|
935
|
+
])
|
|
936
|
+
.createBindings([
|
|
937
|
+
{
|
|
938
|
+
type: 'arrow',
|
|
939
|
+
fromId: nestedIds.arrowPageToGroup,
|
|
940
|
+
toId: nestedIds.pageBox,
|
|
941
|
+
props: {
|
|
942
|
+
terminal: 'start',
|
|
943
|
+
isExact: false,
|
|
944
|
+
isPrecise: true,
|
|
945
|
+
normalizedAnchor: { x: 0.5, y: 0.5 },
|
|
946
|
+
},
|
|
947
|
+
},
|
|
948
|
+
{
|
|
949
|
+
type: 'arrow',
|
|
950
|
+
fromId: nestedIds.arrowPageToGroup,
|
|
951
|
+
toId: nestedIds.groupBoxA,
|
|
952
|
+
props: {
|
|
953
|
+
terminal: 'end',
|
|
954
|
+
isExact: false,
|
|
955
|
+
isPrecise: true,
|
|
956
|
+
normalizedAnchor: { x: 0.5, y: 0.5 },
|
|
957
|
+
},
|
|
958
|
+
},
|
|
959
|
+
{
|
|
960
|
+
type: 'arrow',
|
|
961
|
+
fromId: nestedIds.arrowGroupToFrame,
|
|
962
|
+
toId: nestedIds.groupBoxB,
|
|
963
|
+
props: {
|
|
964
|
+
terminal: 'start',
|
|
965
|
+
isExact: false,
|
|
966
|
+
isPrecise: true,
|
|
967
|
+
normalizedAnchor: { x: 0.5, y: 0.5 },
|
|
968
|
+
},
|
|
969
|
+
},
|
|
970
|
+
{
|
|
971
|
+
type: 'arrow',
|
|
972
|
+
fromId: nestedIds.arrowGroupToFrame,
|
|
973
|
+
toId: nestedIds.frameBox,
|
|
974
|
+
props: {
|
|
975
|
+
terminal: 'end',
|
|
976
|
+
isExact: false,
|
|
977
|
+
isPrecise: true,
|
|
978
|
+
normalizedAnchor: { x: 0.5, y: 0.5 },
|
|
979
|
+
},
|
|
980
|
+
},
|
|
981
|
+
])
|
|
982
|
+
.selectNone()
|
|
983
|
+
})
|
|
984
|
+
|
|
985
|
+
const getArrowTerminalPagePoints = (arrowId: TLShapeId) => {
|
|
986
|
+
const arrow = editor.getShape<TLArrowShape>(arrowId)!
|
|
987
|
+
const bindings = getArrowBindings(editor, arrow)
|
|
988
|
+
const terminals = getArrowTerminalsInArrowSpace(editor, arrow, bindings)
|
|
989
|
+
const pageTransform = editor.getShapePageTransform(arrowId)!
|
|
990
|
+
return {
|
|
991
|
+
start: Mat.applyToPoint(pageTransform, terminals.start),
|
|
992
|
+
end: Mat.applyToPoint(pageTransform, terminals.end),
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
it('resizes the children of a group', () => {
|
|
997
|
+
editor
|
|
998
|
+
.select(nestedIds.group1)
|
|
999
|
+
// the group's page bounds are (200,0) -> (500,200); double them
|
|
1000
|
+
.pointerDownOnHandle('bottom_right')
|
|
1001
|
+
.pointerMove(800, 400)
|
|
1002
|
+
|
|
1003
|
+
expect(roundedPageBounds(nestedIds.group1)).toMatchObject({ x: 200, y: 0, w: 600, h: 400 })
|
|
1004
|
+
expect(roundedPageBounds(nestedIds.groupBoxA)).toMatchObject({ x: 200, y: 0, w: 200, h: 200 })
|
|
1005
|
+
expect(roundedPageBounds(nestedIds.groupBoxB)).toMatchObject({
|
|
1006
|
+
x: 600,
|
|
1007
|
+
y: 200,
|
|
1008
|
+
w: 200,
|
|
1009
|
+
h: 200,
|
|
1010
|
+
})
|
|
1011
|
+
|
|
1012
|
+
// shapes outside of the group are unaffected
|
|
1013
|
+
expect(roundedPageBounds(nestedIds.pageBox)).toMatchObject({ x: 0, y: 200, w: 100, h: 100 })
|
|
1014
|
+
expect(roundedPageBounds(nestedIds.frameBox)).toMatchObject({ x: 250, y: 450, w: 100, h: 100 })
|
|
1015
|
+
})
|
|
1016
|
+
|
|
1017
|
+
it('resizes the children of nested groups on every pointer move', () => {
|
|
1018
|
+
const boxP = createShapeId('boxP')
|
|
1019
|
+
const boxQ = createShapeId('boxQ')
|
|
1020
|
+
const boxR = createShapeId('boxR')
|
|
1021
|
+
const innerGroup = createShapeId('innerGroup')
|
|
1022
|
+
const outerGroup = createShapeId('outerGroup')
|
|
1023
|
+
|
|
1024
|
+
editor
|
|
1025
|
+
.selectAll()
|
|
1026
|
+
.deleteShapes(editor.getSelectedShapeIds())
|
|
1027
|
+
.createShapes([
|
|
1028
|
+
{ id: boxP, type: 'geo', x: 0, y: 0, props: { w: 100, h: 100 } },
|
|
1029
|
+
{ id: boxQ, type: 'geo', x: 200, y: 200, props: { w: 100, h: 100 } },
|
|
1030
|
+
])
|
|
1031
|
+
.groupShapes([boxP, boxQ], { groupId: innerGroup })
|
|
1032
|
+
.createShapes([{ id: boxR, type: 'geo', x: 400, y: 400, props: { w: 100, h: 100 } }])
|
|
1033
|
+
.groupShapes([innerGroup, boxR], { groupId: outerGroup })
|
|
1034
|
+
.select(outerGroup)
|
|
1035
|
+
|
|
1036
|
+
expect(roundedPageBounds(outerGroup)).toMatchObject({ x: 0, y: 0, w: 500, h: 500 })
|
|
1037
|
+
|
|
1038
|
+
// grow to double the size; each pointer move must update the outer
|
|
1039
|
+
// group, then the inner group, then the innermost children, since each
|
|
1040
|
+
// level's new position depends on its parent's committed transform
|
|
1041
|
+
editor.pointerDownOnHandle('bottom_right').pointerMove(1000, 1000)
|
|
1042
|
+
|
|
1043
|
+
expect(roundedPageBounds(outerGroup)).toMatchObject({ x: 0, y: 0, w: 1000, h: 1000 })
|
|
1044
|
+
expect(roundedPageBounds(innerGroup)).toMatchObject({ x: 0, y: 0, w: 600, h: 600 })
|
|
1045
|
+
expect(roundedPageBounds(boxP)).toMatchObject({ x: 0, y: 0, w: 200, h: 200 })
|
|
1046
|
+
expect(roundedPageBounds(boxQ)).toMatchObject({ x: 400, y: 400, w: 200, h: 200 })
|
|
1047
|
+
expect(roundedPageBounds(boxR)).toMatchObject({ x: 800, y: 800, w: 200, h: 200 })
|
|
1048
|
+
|
|
1049
|
+
// then shrink to half the original size in the same gesture
|
|
1050
|
+
editor.pointerMove(250, 250)
|
|
1051
|
+
|
|
1052
|
+
expect(roundedPageBounds(outerGroup)).toMatchObject({ x: 0, y: 0, w: 250, h: 250 })
|
|
1053
|
+
expect(roundedPageBounds(innerGroup)).toMatchObject({ x: 0, y: 0, w: 150, h: 150 })
|
|
1054
|
+
expect(roundedPageBounds(boxP)).toMatchObject({ x: 0, y: 0, w: 50, h: 50 })
|
|
1055
|
+
expect(roundedPageBounds(boxQ)).toMatchObject({ x: 100, y: 100, w: 50, h: 50 })
|
|
1056
|
+
expect(roundedPageBounds(boxR)).toMatchObject({ x: 200, y: 200, w: 50, h: 50 })
|
|
1057
|
+
|
|
1058
|
+
editor.pointerUp()
|
|
1059
|
+
|
|
1060
|
+
expect(roundedPageBounds(boxP)).toMatchObject({ x: 0, y: 0, w: 50, h: 50 })
|
|
1061
|
+
expect(roundedPageBounds(boxQ)).toMatchObject({ x: 100, y: 100, w: 50, h: 50 })
|
|
1062
|
+
expect(roundedPageBounds(boxR)).toMatchObject({ x: 200, y: 200, w: 50, h: 50 })
|
|
1063
|
+
})
|
|
1064
|
+
|
|
1065
|
+
it('keeps arrows bound to shapes inside a resized group', () => {
|
|
1066
|
+
editor
|
|
1067
|
+
.select(nestedIds.group1)
|
|
1068
|
+
.pointerDownOnHandle('bottom_right')
|
|
1069
|
+
.pointerMove(800, 400)
|
|
1070
|
+
.pointerUp()
|
|
1071
|
+
|
|
1072
|
+
const bindings = getArrowBindings(
|
|
1073
|
+
editor,
|
|
1074
|
+
editor.getShape<TLArrowShape>(nestedIds.arrowPageToGroup)!
|
|
1075
|
+
)
|
|
1076
|
+
expect(bindings.start).toMatchObject({ toId: nestedIds.pageBox })
|
|
1077
|
+
expect(bindings.end).toMatchObject({ toId: nestedIds.groupBoxA })
|
|
1078
|
+
|
|
1079
|
+
const terminals = getArrowTerminalPagePoints(nestedIds.arrowPageToGroup)
|
|
1080
|
+
// the start terminal stays at the center of the unselected page shape
|
|
1081
|
+
expect(terminals.start).toCloselyMatchObject({ x: 50, y: 250 })
|
|
1082
|
+
// the end terminal follows the center of the resized group child
|
|
1083
|
+
expect(terminals.end).toCloselyMatchObject({ x: 300, y: 100 })
|
|
1084
|
+
})
|
|
1085
|
+
|
|
1086
|
+
it('resizes a mixed selection of page, group, and frame shapes', () => {
|
|
1087
|
+
editor
|
|
1088
|
+
.selectAll()
|
|
1089
|
+
// the selection's page bounds are (0,0) -> (500,600); double them
|
|
1090
|
+
.pointerDownOnHandle('bottom_right')
|
|
1091
|
+
.pointerMove(1000, 1200)
|
|
1092
|
+
.pointerUp()
|
|
1093
|
+
|
|
1094
|
+
expect(roundedPageBounds(nestedIds.pageBox)).toMatchObject({ x: 0, y: 400, w: 200, h: 200 })
|
|
1095
|
+
expect(roundedPageBounds(nestedIds.group1)).toMatchObject({ x: 400, y: 0, w: 600, h: 400 })
|
|
1096
|
+
expect(roundedPageBounds(nestedIds.groupBoxA)).toMatchObject({ x: 400, y: 0, w: 200, h: 200 })
|
|
1097
|
+
expect(roundedPageBounds(nestedIds.groupBoxB)).toMatchObject({
|
|
1098
|
+
x: 800,
|
|
1099
|
+
y: 200,
|
|
1100
|
+
w: 200,
|
|
1101
|
+
h: 200,
|
|
1102
|
+
})
|
|
1103
|
+
expect(roundedPageBounds(nestedIds.frame1)).toMatchObject({ x: 400, y: 800, w: 600, h: 400 })
|
|
1104
|
+
|
|
1105
|
+
// the frame's child is not resized; it keeps its position within the frame
|
|
1106
|
+
expect(editor.getShape(nestedIds.frameBox)).toMatchObject({ x: 50, y: 50 })
|
|
1107
|
+
expect(roundedPageBounds(nestedIds.frameBox)).toMatchObject({ x: 450, y: 850, w: 100, h: 100 })
|
|
1108
|
+
|
|
1109
|
+
// the arrow terminals follow the shapes they are bound to
|
|
1110
|
+
const pageToGroup = getArrowTerminalPagePoints(nestedIds.arrowPageToGroup)
|
|
1111
|
+
expect(pageToGroup.start).toCloselyMatchObject({ x: 100, y: 500 })
|
|
1112
|
+
expect(pageToGroup.end).toCloselyMatchObject({ x: 500, y: 100 })
|
|
1113
|
+
|
|
1114
|
+
const groupToFrame = getArrowTerminalPagePoints(nestedIds.arrowGroupToFrame)
|
|
1115
|
+
expect(groupToFrame.start).toCloselyMatchObject({ x: 900, y: 300 })
|
|
1116
|
+
expect(groupToFrame.end).toCloselyMatchObject({ x: 500, y: 900 })
|
|
1117
|
+
})
|
|
1118
|
+
})
|
|
1119
|
+
|
|
870
1120
|
function getGapAndPointLines() {
|
|
871
1121
|
const gapLines = editor.snaps
|
|
872
1122
|
.getIndicators()
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { createShapeId } from '@tldraw/editor'
|
|
2
|
+
import { TestEditor } from './TestEditor'
|
|
3
|
+
|
|
4
|
+
let editor: TestEditor
|
|
5
|
+
|
|
6
|
+
beforeEach(() => {
|
|
7
|
+
editor = new TestEditor()
|
|
8
|
+
})
|
|
9
|
+
afterEach(() => {
|
|
10
|
+
editor?.dispose()
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
// A right-click opens the context menu, which is a select-tool surface — every
|
|
14
|
+
// item acts on the current selection. The editor routes every right-click
|
|
15
|
+
// through the select tool before the event reaches the state chart, so the
|
|
16
|
+
// select tool's idle resolves the selection at the click point (selecting the
|
|
17
|
+
// shape under the pointer, or clearing the selection) regardless of which tool
|
|
18
|
+
// was active. This keeps the menu consistent with the click in any tool, and
|
|
19
|
+
// never creates a shape from a creation tool. See #8277 and #8828.
|
|
20
|
+
|
|
21
|
+
// Shape-creation tools: right-click must switch to select and never create a shape.
|
|
22
|
+
const CREATION_TOOLS = ['geo', 'note', 'text', 'line', 'arrow', 'draw', 'frame'] as const
|
|
23
|
+
|
|
24
|
+
// Other non-select tools: right-click must still switch to select so the menu
|
|
25
|
+
// reflects the click rather than a stale selection.
|
|
26
|
+
const OTHER_TOOLS = ['hand', 'eraser', 'laser', 'zoom'] as const
|
|
27
|
+
|
|
28
|
+
describe('right click routes through the select tool', () => {
|
|
29
|
+
it.each(CREATION_TOOLS)('%s switches to the select tool and creates no shape', (tool) => {
|
|
30
|
+
editor.setCurrentTool(tool)
|
|
31
|
+
|
|
32
|
+
editor.rightClick(100, 100)
|
|
33
|
+
|
|
34
|
+
editor.expectToBeIn('select.idle')
|
|
35
|
+
expect(editor.getCurrentPageShapes()).toHaveLength(0)
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
it.each(OTHER_TOOLS)('%s switches to the select tool', (tool) => {
|
|
39
|
+
editor.setCurrentTool(tool)
|
|
40
|
+
|
|
41
|
+
editor.rightClick(100, 100)
|
|
42
|
+
|
|
43
|
+
editor.expectToBeIn('select.idle')
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
it('stays in the select tool when already active', () => {
|
|
47
|
+
editor.setCurrentTool('select')
|
|
48
|
+
|
|
49
|
+
editor.rightClick(100, 100)
|
|
50
|
+
|
|
51
|
+
editor.expectToBeIn('select.idle')
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
it('selects the shape under the pointer so the menu reflects it', () => {
|
|
55
|
+
const id = createShapeId()
|
|
56
|
+
editor.createShape({
|
|
57
|
+
id,
|
|
58
|
+
type: 'geo',
|
|
59
|
+
x: 0,
|
|
60
|
+
y: 0,
|
|
61
|
+
props: { w: 100, h: 100, geo: 'rectangle' },
|
|
62
|
+
})
|
|
63
|
+
editor.selectNone()
|
|
64
|
+
|
|
65
|
+
editor.setCurrentTool('geo')
|
|
66
|
+
editor.rightClick(50, 50)
|
|
67
|
+
|
|
68
|
+
editor.expectToBeIn('select.idle')
|
|
69
|
+
expect(editor.getSelectedShapeIds()).toEqual([id])
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
it('clears a stale selection when right-clicking empty canvas from another tool', () => {
|
|
73
|
+
const id = createShapeId()
|
|
74
|
+
editor.createShape({
|
|
75
|
+
id,
|
|
76
|
+
type: 'geo',
|
|
77
|
+
x: 0,
|
|
78
|
+
y: 0,
|
|
79
|
+
props: { w: 100, h: 100, geo: 'rectangle' },
|
|
80
|
+
})
|
|
81
|
+
editor.select(id)
|
|
82
|
+
|
|
83
|
+
// right-click far from the selected shape, while a non-select tool is active
|
|
84
|
+
editor.setCurrentTool('hand')
|
|
85
|
+
editor.rightClick(500, 500)
|
|
86
|
+
|
|
87
|
+
editor.expectToBeIn('select.idle')
|
|
88
|
+
expect(editor.getSelectedShapeIds()).toEqual([])
|
|
89
|
+
})
|
|
90
|
+
})
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Vec } from '@tldraw/editor'
|
|
1
2
|
import { TestEditor } from './TestEditor'
|
|
2
3
|
|
|
3
4
|
describe('with rightClickPanning enabled (default)', () => {
|
|
@@ -17,6 +18,16 @@ describe('with rightClickPanning enabled (default)', () => {
|
|
|
17
18
|
expect(editor.inputs.getIsPanning()).toBe(false)
|
|
18
19
|
})
|
|
19
20
|
|
|
21
|
+
it('does not zoom when momentum panning on release', () => {
|
|
22
|
+
editor.pointerDown(100, 100, { button: 2 })
|
|
23
|
+
editor.pointerMove(200, 200)
|
|
24
|
+
expect(editor.inputs.getIsPanning()).toBe(true)
|
|
25
|
+
editor.inputs.setPointerVelocity(new Vec(1, 1))
|
|
26
|
+
editor.pointerUp(200, 200, { button: 2 }).forceTick()
|
|
27
|
+
|
|
28
|
+
expect(editor.getCamera().z).toBe(1)
|
|
29
|
+
})
|
|
30
|
+
|
|
20
31
|
it('does not pan on a static right-click', () => {
|
|
21
32
|
editor.pointerDown(100, 100, { button: 2 })
|
|
22
33
|
editor.pointerUp(100, 100, { button: 2 })
|
|
@@ -1785,7 +1785,7 @@ describe('right clicking', () => {
|
|
|
1785
1785
|
expect(editor.getSelectedShapeIds()).toEqual([ids.box1])
|
|
1786
1786
|
})
|
|
1787
1787
|
|
|
1788
|
-
it('keeps selection when right-clicking
|
|
1788
|
+
it('keeps selection when right-clicking inside the selection bounds', () => {
|
|
1789
1789
|
editor.createShapes([{ id: ids.box1, type: 'geo' }])
|
|
1790
1790
|
editor.selectAll()
|
|
1791
1791
|
editor.pointerMove(30, 30)
|
|
@@ -1817,7 +1817,7 @@ describe('right clicking', () => {
|
|
|
1817
1817
|
expect(editor.getSelectedShapeIds()).toEqual([ids.box2, ids.box3])
|
|
1818
1818
|
})
|
|
1819
1819
|
|
|
1820
|
-
it('
|
|
1820
|
+
it('clears selection when right-clicking outside the selected arrow', () => {
|
|
1821
1821
|
editor
|
|
1822
1822
|
.selectAll()
|
|
1823
1823
|
.deleteShapes(editor.getSelectedShapeIds())
|
|
@@ -2188,6 +2188,19 @@ describe('control pointing', () => {
|
|
|
2188
2188
|
// ...and expect menu to be open, but that's a native thing
|
|
2189
2189
|
})
|
|
2190
2190
|
|
|
2191
|
+
it('selects locked shapes on ctrl click when on a mac', () => {
|
|
2192
|
+
tlenv.isDarwin = true
|
|
2193
|
+
|
|
2194
|
+
editor.createShape({ id: ids.box4, type: 'geo', x: 600, isLocked: true })
|
|
2195
|
+
|
|
2196
|
+
expect(editor.getSelectedShapeIds()).toEqual([ids.box1])
|
|
2197
|
+
editor.keyDown('Control')
|
|
2198
|
+
editor.pointerMove(650, 50) // inside of locked box 4
|
|
2199
|
+
editor.pointerDown()
|
|
2200
|
+
editor.pointerUp()
|
|
2201
|
+
expect(editor.getSelectedShapeIds()).toEqual([ids.box4])
|
|
2202
|
+
})
|
|
2203
|
+
|
|
2191
2204
|
it('selects on ctrl click when on a pc or other device', () => {
|
|
2192
2205
|
tlenv.isDarwin = false
|
|
2193
2206
|
|
|
@@ -223,6 +223,138 @@ describe('SpatialIndexManager - step-2 transitive bounds sweep', () => {
|
|
|
223
223
|
})
|
|
224
224
|
})
|
|
225
225
|
|
|
226
|
+
describe('SpatialIndexManager - binding-only diffs', () => {
|
|
227
|
+
it('refreshes arrow bounds when bindings are created in a separate step from the shapes', () => {
|
|
228
|
+
// Regression: an arrow's bounds derive from its bindings, but a
|
|
229
|
+
// binding-only transaction contains no shape diff. If the index was
|
|
230
|
+
// queried between createShapes and createBindings (the hover side
|
|
231
|
+
// effect does this on every store change), the arrow stayed indexed
|
|
232
|
+
// at its unbound bounds and parts of the bound body were
|
|
233
|
+
// un-hoverable.
|
|
234
|
+
const boxAId = createShapeId('boxA')
|
|
235
|
+
const boxBId = createShapeId('boxB')
|
|
236
|
+
const arrowId = createShapeId('arrow')
|
|
237
|
+
|
|
238
|
+
editor.createShapes([
|
|
239
|
+
{ id: boxAId, type: 'geo', x: 0, y: 0, props: { w: 100, h: 100, fill: 'none' } },
|
|
240
|
+
{ id: boxBId, type: 'geo', x: 500, y: 0, props: { w: 100, h: 100, fill: 'none' } },
|
|
241
|
+
// The arrow's own terminals are far from the shapes it will be
|
|
242
|
+
// bound to, as happens when content is created via the API.
|
|
243
|
+
{
|
|
244
|
+
id: arrowId,
|
|
245
|
+
type: 'arrow',
|
|
246
|
+
x: 2000,
|
|
247
|
+
y: 2000,
|
|
248
|
+
props: { kind: 'arc', bend: -50, start: { x: 0, y: 0 }, end: { x: 100, y: 0 } },
|
|
249
|
+
},
|
|
250
|
+
])
|
|
251
|
+
|
|
252
|
+
const unboundBounds = editor.getShapePageBounds(arrowId)!
|
|
253
|
+
|
|
254
|
+
// Pull the spatial index so the arrow is indexed at its unbound
|
|
255
|
+
// bounds before the bindings exist.
|
|
256
|
+
expect(editor.getShapeIdsInsideBounds(unboundBounds).has(arrowId)).toBe(true)
|
|
257
|
+
|
|
258
|
+
editor.createBindings([
|
|
259
|
+
{
|
|
260
|
+
type: 'arrow',
|
|
261
|
+
fromId: arrowId,
|
|
262
|
+
toId: boxAId,
|
|
263
|
+
props: {
|
|
264
|
+
terminal: 'start',
|
|
265
|
+
isExact: false,
|
|
266
|
+
isPrecise: false,
|
|
267
|
+
normalizedAnchor: { x: 0.5, y: 0.5 },
|
|
268
|
+
},
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
type: 'arrow',
|
|
272
|
+
fromId: arrowId,
|
|
273
|
+
toId: boxBId,
|
|
274
|
+
props: {
|
|
275
|
+
terminal: 'end',
|
|
276
|
+
isExact: false,
|
|
277
|
+
isPrecise: false,
|
|
278
|
+
normalizedAnchor: { x: 0.5, y: 0.5 },
|
|
279
|
+
},
|
|
280
|
+
},
|
|
281
|
+
])
|
|
282
|
+
|
|
283
|
+
const boundBounds = editor.getShapePageBounds(arrowId)!
|
|
284
|
+
expect(boundBounds.equals(unboundBounds)).toBe(false)
|
|
285
|
+
|
|
286
|
+
// The index must reflect the bound bounds...
|
|
287
|
+
expect(editor.getShapeIdsInsideBounds(boundBounds).has(arrowId)).toBe(true)
|
|
288
|
+
|
|
289
|
+
// ...and the arrow must be hit-testable on its bound body.
|
|
290
|
+
const apex = { x: boundBounds.midX, y: boundBounds.minY + 1 }
|
|
291
|
+
expect(editor.getShapeAtPoint(apex, { hitInside: false, margin: 8 })?.id).toBe(arrowId)
|
|
292
|
+
})
|
|
293
|
+
|
|
294
|
+
it('ticks the epoch and refreshes arrow bounds when a binding update moves the arrow', () => {
|
|
295
|
+
const boxAId = createShapeId('boxA')
|
|
296
|
+
const boxBId = createShapeId('boxB')
|
|
297
|
+
const arrowId = createShapeId('arrow')
|
|
298
|
+
|
|
299
|
+
editor.createShapes([
|
|
300
|
+
{ id: boxAId, type: 'geo', x: 0, y: 0, props: { w: 100, h: 100, fill: 'none' } },
|
|
301
|
+
{ id: boxBId, type: 'geo', x: 500, y: 500, props: { w: 100, h: 100, fill: 'none' } },
|
|
302
|
+
{
|
|
303
|
+
id: arrowId,
|
|
304
|
+
type: 'arrow',
|
|
305
|
+
x: 0,
|
|
306
|
+
y: 0,
|
|
307
|
+
props: { start: { x: 0, y: 0 }, end: { x: 100, y: 0 } },
|
|
308
|
+
},
|
|
309
|
+
])
|
|
310
|
+
editor.createBindings([
|
|
311
|
+
{
|
|
312
|
+
type: 'arrow',
|
|
313
|
+
fromId: arrowId,
|
|
314
|
+
toId: boxAId,
|
|
315
|
+
props: {
|
|
316
|
+
terminal: 'start',
|
|
317
|
+
isExact: false,
|
|
318
|
+
isPrecise: true,
|
|
319
|
+
normalizedAnchor: { x: 0, y: 0 },
|
|
320
|
+
},
|
|
321
|
+
},
|
|
322
|
+
{
|
|
323
|
+
type: 'arrow',
|
|
324
|
+
fromId: arrowId,
|
|
325
|
+
toId: boxBId,
|
|
326
|
+
props: {
|
|
327
|
+
terminal: 'end',
|
|
328
|
+
isExact: false,
|
|
329
|
+
isPrecise: true,
|
|
330
|
+
normalizedAnchor: { x: 0, y: 0 },
|
|
331
|
+
},
|
|
332
|
+
},
|
|
333
|
+
])
|
|
334
|
+
|
|
335
|
+
const boundsBefore = editor.getShapePageBounds(arrowId)!
|
|
336
|
+
const tracker = trackSpatialIndexInvalidations(editor, boundsBefore.clone())
|
|
337
|
+
|
|
338
|
+
// Move the end terminal across the target shape with a binding-only
|
|
339
|
+
// update; the arrow record itself is untouched.
|
|
340
|
+
const binding = editor
|
|
341
|
+
.getBindingsFromShape(arrowId, 'arrow')
|
|
342
|
+
.find((b) => b.props.terminal === 'end')!
|
|
343
|
+
editor.updateBinding({
|
|
344
|
+
...binding,
|
|
345
|
+
props: { ...binding.props, normalizedAnchor: { x: 0.5, y: 1 } },
|
|
346
|
+
})
|
|
347
|
+
|
|
348
|
+
const boundsAfter = editor.getShapePageBounds(arrowId)!
|
|
349
|
+
expect(boundsAfter.equals(boundsBefore)).toBe(false)
|
|
350
|
+
expect(tracker.delta).toBe(1)
|
|
351
|
+
|
|
352
|
+
const probe = probeOnlyInAfter(boundsBefore, boundsAfter)
|
|
353
|
+
expect(editor.getShapeIdsInsideBounds(probe).has(arrowId)).toBe(true)
|
|
354
|
+
tracker.stop()
|
|
355
|
+
})
|
|
356
|
+
})
|
|
357
|
+
|
|
226
358
|
describe('SpatialIndexManager - basic queries', () => {
|
|
227
359
|
it('returns shapes inside the queried bounds', () => {
|
|
228
360
|
const insideId = createShapeId('inside')
|
|
@@ -783,9 +783,6 @@ describe('snapping with multiple shapes', () => {
|
|
|
783
783
|
})
|
|
784
784
|
|
|
785
785
|
describe('Snap-between behavior', () => {
|
|
786
|
-
beforeEach(() => {
|
|
787
|
-
editor?.dispose()
|
|
788
|
-
})
|
|
789
786
|
it('snaps a shape horizontally between two others', () => {
|
|
790
787
|
// ┌─────┐ ┌─────┐
|
|
791
788
|
// │ │ │ │
|
|
@@ -1160,9 +1157,6 @@ describe('Snap-between behavior', () => {
|
|
|
1160
1157
|
})
|
|
1161
1158
|
|
|
1162
1159
|
describe('Snap-next-to behavior', () => {
|
|
1163
|
-
beforeEach(() => {
|
|
1164
|
-
editor?.dispose()
|
|
1165
|
-
})
|
|
1166
1160
|
it('snaps a shape to the left of two others, matching the gap size', () => {
|
|
1167
1161
|
// ┌───┐
|
|
1168
1162
|
// │ X │
|