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
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
TLHighlightShapeProps,
|
|
11
11
|
TLResizeInfo,
|
|
12
12
|
VecLike,
|
|
13
|
+
b64Vecs,
|
|
13
14
|
debugFlags,
|
|
14
15
|
getColorValue,
|
|
15
16
|
highlightShapeMigrations,
|
|
@@ -23,9 +24,8 @@ import {
|
|
|
23
24
|
} from '@tldraw/editor'
|
|
24
25
|
import { getHighlightFreehandSettings, getPointsFromDrawSegments } from '../draw/getPath'
|
|
25
26
|
import { FONT_SIZES } from '../shared/default-shape-constants'
|
|
26
|
-
import {
|
|
27
|
+
import { getStroke } from '../shared/freehand/getStroke'
|
|
27
28
|
import { getStrokePoints } from '../shared/freehand/getStrokePoints'
|
|
28
|
-
import { setStrokePointRadii } from '../shared/freehand/setStrokePointRadii'
|
|
29
29
|
import { getSvgPathFromStrokePoints } from '../shared/freehand/svg'
|
|
30
30
|
import type { ShapeOptionsWithDisplayValues } from '../shared/getDisplayValues'
|
|
31
31
|
import { getDisplayValues } from '../shared/getDisplayValues'
|
|
@@ -113,12 +113,16 @@ export class HighlightShapeUtil extends ShapeUtil<TLHighlightShape> {
|
|
|
113
113
|
})
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
|
|
116
|
+
const allPointsFromSegments = getPointsFromDrawSegments(
|
|
117
|
+
shape.props.segments,
|
|
118
|
+
shape.props.scaleX,
|
|
119
|
+
shape.props.scaleY
|
|
120
|
+
)
|
|
121
|
+
const showAsComplete = shape.props.isComplete || last(shape.props.segments)?.type === 'straight'
|
|
122
|
+
const opts = getHighlightFreehandSettings({ strokeWidth, showAsComplete })
|
|
119
123
|
|
|
120
124
|
return new Polygon2d({
|
|
121
|
-
points:
|
|
125
|
+
points: getStroke(allPointsFromSegments, opts),
|
|
122
126
|
isFilled: true,
|
|
123
127
|
})
|
|
124
128
|
}
|
|
@@ -286,11 +290,10 @@ function getHighlightStrokePoints(
|
|
|
286
290
|
}
|
|
287
291
|
|
|
288
292
|
function getIsDot(shape: TLHighlightShape) {
|
|
289
|
-
//
|
|
290
|
-
//
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
return shape.props.segments.length === 1 && shape.props.segments[0].path.length < 24
|
|
293
|
+
// A dot is a single-point segment. isSinglePoint knows the per-encoding length
|
|
294
|
+
// (and takes the segment's dim), so this stays correct for both 2D and 3D paths.
|
|
295
|
+
const segment = shape.props.segments[0]
|
|
296
|
+
return shape.props.segments.length === 1 && b64Vecs.isSinglePoint(segment.path, segment.dim)
|
|
294
297
|
}
|
|
295
298
|
|
|
296
299
|
function HighlightRenderer({
|
|
@@ -170,7 +170,7 @@ export class ImageShapeUtil extends BaseBoxShapeUtil<TLImageShape> {
|
|
|
170
170
|
override onResize(shape: TLImageShape, info: TLResizeInfo<TLImageShape>) {
|
|
171
171
|
let resized: TLImageShape = resizeBox(shape, info)
|
|
172
172
|
const { flipX, flipY } = info.initialShape.props
|
|
173
|
-
const { scaleX, scaleY
|
|
173
|
+
const { scaleX, scaleY } = info
|
|
174
174
|
|
|
175
175
|
resized = {
|
|
176
176
|
...resized,
|
|
@@ -182,16 +182,12 @@ export class ImageShapeUtil extends BaseBoxShapeUtil<TLImageShape> {
|
|
|
182
182
|
}
|
|
183
183
|
if (!shape.props.crop) return resized
|
|
184
184
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
const flipCropVertically =
|
|
191
|
-
// We used the flip vertically feature
|
|
192
|
-
(mode === 'scale_shape' && scaleY === -1) ||
|
|
193
|
-
// We resized the shape past it's bounds, so it flipped
|
|
194
|
-
(mode === 'resize_bounds' && flipY !== resized.props.flipY)
|
|
185
|
+
// Mirror the crop whenever the shape is flipped along an axis. This happens both when
|
|
186
|
+
// using the flip command and when dragging a resize handle (including a group's handle)
|
|
187
|
+
// past the opposite edge. We can't check for an exact scale of -1 here because a group
|
|
188
|
+
// flip resizes its children by an arbitrary negative scale, not just -1.
|
|
189
|
+
const flipCropHorizontally = scaleX < 0
|
|
190
|
+
const flipCropVertically = scaleY < 0
|
|
195
191
|
|
|
196
192
|
const { topLeft, bottomRight } = shape.props.crop
|
|
197
193
|
resized.props.crop = {
|
|
@@ -205,6 +205,47 @@ describe('When extending the line with the shift-key in tool-lock mode', () => {
|
|
|
205
205
|
})
|
|
206
206
|
})
|
|
207
207
|
|
|
208
|
+
describe('minimum bend distance for shift-clicked handles is measured in screen space', () => {
|
|
209
|
+
// regression for #7661: minimum bend distance for shift-clicked handles is measured in screen space
|
|
210
|
+
// Creates a two-point line whose end handle sits at screen point (200, 200), the
|
|
211
|
+
// camera being static so the handle's screen position matches the pointer-up location.
|
|
212
|
+
function createTwoPointLine() {
|
|
213
|
+
editor
|
|
214
|
+
.setCurrentTool('line')
|
|
215
|
+
.pointerDown(100, 100, { target: 'canvas' })
|
|
216
|
+
.pointerMove(200, 200)
|
|
217
|
+
.pointerUp(200, 200)
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
beforeEach(() => {
|
|
221
|
+
editor.updateInstanceState({ isToolLocked: true })
|
|
222
|
+
})
|
|
223
|
+
|
|
224
|
+
it('adds a point when the click is more than 2 screen pixels away while zoomed in', () => {
|
|
225
|
+
editor.setCamera({ x: 0, y: 0, z: 4 })
|
|
226
|
+
createTwoPointLine()
|
|
227
|
+
// 4 screen pixels from the end handle: past the 2px screen threshold, but only 1
|
|
228
|
+
// page unit — under the old page-space threshold this would have merged.
|
|
229
|
+
editor.keyDown('Shift').pointerDown(204, 200, { target: 'canvas' }).pointerUp(204, 200)
|
|
230
|
+
|
|
231
|
+
const line = editor.getCurrentPageShapes()[editor.getCurrentPageShapes().length - 1]
|
|
232
|
+
assert(editor.isShapeOfType(line, 'line'))
|
|
233
|
+
expect(Object.keys(line.props.points).length).toBe(3)
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
it('merges the click when within 2 screen pixels while zoomed out', () => {
|
|
237
|
+
editor.setCamera({ x: 0, y: 0, z: 0.25 })
|
|
238
|
+
createTwoPointLine()
|
|
239
|
+
// 1 screen pixel from the end handle: within the 2px screen threshold, but 4 page
|
|
240
|
+
// units — under the old page-space threshold this would have added a point.
|
|
241
|
+
editor.keyDown('Shift').pointerDown(201, 200, { target: 'canvas' }).pointerUp(201, 200)
|
|
242
|
+
|
|
243
|
+
const line = editor.getCurrentPageShapes()[editor.getCurrentPageShapes().length - 1]
|
|
244
|
+
assert(editor.isShapeOfType(line, 'line'))
|
|
245
|
+
expect(Object.keys(line.props.points).length).toBe(2)
|
|
246
|
+
})
|
|
247
|
+
})
|
|
248
|
+
|
|
208
249
|
describe('tool lock bug', () => {
|
|
209
250
|
it('works as expected when tool lock is on but shift is off', () => {
|
|
210
251
|
expect(editor.getCurrentPageShapes().length).toBe(0)
|
|
@@ -6,12 +6,14 @@ import {
|
|
|
6
6
|
Vec,
|
|
7
7
|
createShapeId,
|
|
8
8
|
getIndexAbove,
|
|
9
|
+
cancelShapeCreationOnLongPress,
|
|
9
10
|
last,
|
|
10
11
|
maybeSnapToGrid,
|
|
11
12
|
sortByIndex,
|
|
12
13
|
structuredClone,
|
|
13
14
|
} from '@tldraw/editor'
|
|
14
15
|
|
|
16
|
+
// Minimum distance, in screen pixels, between two shift-clicked handles before we merge them
|
|
15
17
|
const MINIMUM_DISTANCE_BETWEEN_SHIFT_CLICKED_HANDLES = 2
|
|
16
18
|
|
|
17
19
|
export class Pointing extends StateNode {
|
|
@@ -51,9 +53,13 @@ export class Pointing extends StateNode {
|
|
|
51
53
|
const nextPoint = maybeSnapToGrid(nudgedPoint, this.editor)
|
|
52
54
|
const points = structuredClone(this.shape.props.points)
|
|
53
55
|
|
|
56
|
+
// compare in screen space
|
|
57
|
+
const minDistance =
|
|
58
|
+
MINIMUM_DISTANCE_BETWEEN_SHIFT_CLICKED_HANDLES / this.editor.getZoomLevel()
|
|
59
|
+
|
|
54
60
|
if (
|
|
55
|
-
Vec.DistMin(endHandle, prevEndHandle,
|
|
56
|
-
Vec.DistMin(nextPoint, endHandle,
|
|
61
|
+
Vec.DistMin(endHandle, prevEndHandle, minDistance) ||
|
|
62
|
+
Vec.DistMin(nextPoint, endHandle, minDistance)
|
|
57
63
|
) {
|
|
58
64
|
// Don't add a new point if the distance between the last two points is too small
|
|
59
65
|
points[endHandle.id] = {
|
|
@@ -136,6 +142,10 @@ export class Pointing extends StateNode {
|
|
|
136
142
|
this.complete()
|
|
137
143
|
}
|
|
138
144
|
|
|
145
|
+
override onLongPress() {
|
|
146
|
+
cancelShapeCreationOnLongPress(this.editor, () => this.cancel())
|
|
147
|
+
}
|
|
148
|
+
|
|
139
149
|
override onCancel() {
|
|
140
150
|
this.cancel()
|
|
141
151
|
}
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
/* eslint-disable react-hooks/rules-of-hooks */
|
|
2
2
|
import {
|
|
3
3
|
Box,
|
|
4
|
-
DefaultFontFamilies,
|
|
5
4
|
EMPTY_ARRAY,
|
|
6
|
-
Editor,
|
|
7
5
|
Group2d,
|
|
8
6
|
IndexKey,
|
|
9
7
|
Rectangle2d,
|
|
@@ -26,6 +24,7 @@ import {
|
|
|
26
24
|
noteShapeMigrations,
|
|
27
25
|
noteShapeProps,
|
|
28
26
|
resizeScaled,
|
|
27
|
+
resolveLineHeightPx,
|
|
29
28
|
rng,
|
|
30
29
|
toRichText,
|
|
31
30
|
useColorMode,
|
|
@@ -179,7 +178,7 @@ export class NoteShapeUtil extends ShapeUtil<TLNoteShape> {
|
|
|
179
178
|
fontSizeAdjustment: 1,
|
|
180
179
|
url: '',
|
|
181
180
|
scale: 1,
|
|
182
|
-
|
|
181
|
+
textLastEditedBy: null,
|
|
183
182
|
}
|
|
184
183
|
}
|
|
185
184
|
|
|
@@ -297,7 +296,7 @@ export class NoteShapeUtil extends ShapeUtil<TLNoteShape> {
|
|
|
297
296
|
}
|
|
298
297
|
|
|
299
298
|
override getReferencedUserIds(shape: TLNoteShape) {
|
|
300
|
-
return shape.props.
|
|
299
|
+
return shape.props.textLastEditedBy ? [shape.props.textLastEditedBy] : []
|
|
301
300
|
}
|
|
302
301
|
|
|
303
302
|
override getFontFaces(shape: TLNoteShape) {
|
|
@@ -309,7 +308,7 @@ export class NoteShapeUtil extends ShapeUtil<TLNoteShape> {
|
|
|
309
308
|
style: 'normal',
|
|
310
309
|
})
|
|
311
310
|
|
|
312
|
-
if (shape.props.
|
|
311
|
+
if (shape.props.textLastEditedBy && !isEmptyRichText(shape.props.richText)) {
|
|
313
312
|
return [...fonts, DefaultFontFaces.tldraw_sans.normal.normal]
|
|
314
313
|
}
|
|
315
314
|
const themeFaces = getThemeFontFaces(this.editor.getCurrentTheme(), shape.props.font)
|
|
@@ -320,7 +319,7 @@ export class NoteShapeUtil extends ShapeUtil<TLNoteShape> {
|
|
|
320
319
|
|
|
321
320
|
component(shape: TLNoteShape) {
|
|
322
321
|
const { id, type, props } = shape
|
|
323
|
-
const { scale, richText, fontSizeAdjustment,
|
|
322
|
+
const { scale, richText, fontSizeAdjustment, textLastEditedBy } = props
|
|
324
323
|
|
|
325
324
|
const handleKeyDown = useNoteKeydownHandler(id)
|
|
326
325
|
|
|
@@ -347,12 +346,12 @@ export class NoteShapeUtil extends ShapeUtil<TLNoteShape> {
|
|
|
347
346
|
const attribution = useValue(
|
|
348
347
|
'attribution',
|
|
349
348
|
() => {
|
|
350
|
-
if (!
|
|
351
|
-
const name = this.editor.getAttributionDisplayName(
|
|
349
|
+
if (!textLastEditedBy || isEmpty) return null
|
|
350
|
+
const name = this.editor.getAttributionDisplayName(textLastEditedBy)
|
|
352
351
|
if (!name) return null
|
|
353
352
|
return { short: name.split(' ')[0], full: name }
|
|
354
353
|
},
|
|
355
|
-
[
|
|
354
|
+
[textLastEditedBy, isEmpty, this.editor]
|
|
356
355
|
)
|
|
357
356
|
|
|
358
357
|
return (
|
|
@@ -459,14 +458,11 @@ export class NoteShapeUtil extends ShapeUtil<TLNoteShape> {
|
|
|
459
458
|
),
|
|
460
459
|
})
|
|
461
460
|
|
|
462
|
-
const {
|
|
463
|
-
const
|
|
464
|
-
|
|
465
|
-
? this.editor.getAttributionDisplayName(
|
|
461
|
+
const { textLastEditedBy } = shape.props
|
|
462
|
+
const attributionName =
|
|
463
|
+
textLastEditedBy && !isEmptyRichText(shape.props.richText)
|
|
464
|
+
? (this.editor.getAttributionDisplayName(textLastEditedBy)?.split(' ')[0] ?? null)
|
|
466
465
|
: null
|
|
467
|
-
const attributionName = attributionFirstName
|
|
468
|
-
? truncateAttributionForSvg(this.editor, attributionFirstName, dv.noteWidth)
|
|
469
|
-
: null
|
|
470
466
|
|
|
471
467
|
return (
|
|
472
468
|
<>
|
|
@@ -493,17 +489,26 @@ export class NoteShapeUtil extends ShapeUtil<TLNoteShape> {
|
|
|
493
489
|
showTextOutline={false}
|
|
494
490
|
/>
|
|
495
491
|
{attributionName && (
|
|
496
|
-
<
|
|
497
|
-
x={
|
|
498
|
-
y={
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
fill={dv.labelColor}
|
|
503
|
-
opacity={0.6}
|
|
492
|
+
<foreignObject
|
|
493
|
+
x={0}
|
|
494
|
+
y={0}
|
|
495
|
+
width={dv.noteWidth}
|
|
496
|
+
height={bounds.h}
|
|
497
|
+
className="tl-export-embed-styles"
|
|
504
498
|
>
|
|
505
|
-
{
|
|
506
|
-
|
|
499
|
+
<div style={{ position: 'relative', width: '100%', height: '100%' }}>
|
|
500
|
+
<div
|
|
501
|
+
className="tl-note__attribution"
|
|
502
|
+
style={{
|
|
503
|
+
fontSize: 11,
|
|
504
|
+
color: dv.labelColor,
|
|
505
|
+
opacity: 0.6,
|
|
506
|
+
}}
|
|
507
|
+
>
|
|
508
|
+
{attributionName}
|
|
509
|
+
</div>
|
|
510
|
+
</div>
|
|
511
|
+
</foreignObject>
|
|
507
512
|
)}
|
|
508
513
|
</>
|
|
509
514
|
)
|
|
@@ -529,12 +534,12 @@ export class NoteShapeUtil extends ShapeUtil<TLNoteShape> {
|
|
|
529
534
|
if (isEmptyRichText(next.props.richText)) {
|
|
530
535
|
shape = {
|
|
531
536
|
...shape,
|
|
532
|
-
props: { ...shape.props,
|
|
537
|
+
props: { ...shape.props, textLastEditedBy: null },
|
|
533
538
|
}
|
|
534
|
-
} else
|
|
539
|
+
} else {
|
|
535
540
|
shape = {
|
|
536
541
|
...shape,
|
|
537
|
-
props: { ...shape.props,
|
|
542
|
+
props: { ...shape.props, textLastEditedBy: this.editor.getAttributionUserId() },
|
|
538
543
|
}
|
|
539
544
|
}
|
|
540
545
|
}
|
|
@@ -596,7 +601,8 @@ export class NoteShapeUtil extends ShapeUtil<TLNoteShape> {
|
|
|
596
601
|
const { richText } = shape.props
|
|
597
602
|
|
|
598
603
|
if (isEmptyRichText(richText)) {
|
|
599
|
-
const minHeight =
|
|
604
|
+
const minHeight =
|
|
605
|
+
resolveLineHeightPx(dv.labelFontSize, dv.labelLineHeight) + dv.labelPadding * 2
|
|
600
606
|
return { labelHeight: minHeight, labelWidth: 100, fontSizeAdjustment: 1 }
|
|
601
607
|
}
|
|
602
608
|
|
|
@@ -737,27 +743,6 @@ function getNoteHeight(shape: TLNoteShape, noteHeight: number) {
|
|
|
737
743
|
return (noteHeight + shape.props.growY) * shape.props.scale
|
|
738
744
|
}
|
|
739
745
|
|
|
740
|
-
// Matches `.tl-note__attribution { max-width: 60% }` so SVG export truncates the same way.
|
|
741
|
-
const ATTRIBUTION_MAX_WIDTH_RATIO = 0.6
|
|
742
|
-
|
|
743
|
-
function truncateAttributionForSvg(editor: Editor, name: string, noteWidth: number) {
|
|
744
|
-
if (process.env.NODE_ENV === 'test') return name
|
|
745
|
-
const spans = editor.textMeasure.measureTextSpans(name, {
|
|
746
|
-
fontSize: 11,
|
|
747
|
-
fontFamily: DefaultFontFamilies['sans'],
|
|
748
|
-
textAlign: 'end',
|
|
749
|
-
width: noteWidth * ATTRIBUTION_MAX_WIDTH_RATIO,
|
|
750
|
-
height: 16,
|
|
751
|
-
padding: 0,
|
|
752
|
-
lineHeight: 1,
|
|
753
|
-
fontStyle: 'normal',
|
|
754
|
-
fontWeight: 'normal',
|
|
755
|
-
overflow: 'truncate-ellipsis',
|
|
756
|
-
})
|
|
757
|
-
if (spans.length === 0) return name
|
|
758
|
-
return spans.map((s) => s.text).join('')
|
|
759
|
-
}
|
|
760
|
-
|
|
761
746
|
function getNoteShadow(id: string, rotation: number, scale: number) {
|
|
762
747
|
const random = rng(id) // seeded based on id
|
|
763
748
|
const lift = Math.abs(random()) + 0.5 // 0 to 1.5
|
|
@@ -241,11 +241,11 @@ describe('Clone handles and attribution', () => {
|
|
|
241
241
|
})
|
|
242
242
|
const updated = editor.getShape<TLNoteShape>(shape.id)!
|
|
243
243
|
// Sanity check - the source note has attribution set
|
|
244
|
-
expect(updated.props.
|
|
244
|
+
expect(updated.props.textLastEditedBy).not.toBeNull()
|
|
245
245
|
return updated
|
|
246
246
|
}
|
|
247
247
|
|
|
248
|
-
it('Does not preserve
|
|
248
|
+
it('Does not preserve textLastEditedBy when creating an adjacent note via click', () => {
|
|
249
249
|
const shape = createNoteWithAttribution()
|
|
250
250
|
|
|
251
251
|
editor.select(shape.id)
|
|
@@ -261,10 +261,10 @@ describe('Clone handles and attribution', () => {
|
|
|
261
261
|
|
|
262
262
|
const newShape = editor.getLastCreatedShape<TLNoteShape>()
|
|
263
263
|
expect(newShape.id).not.toBe(shape.id)
|
|
264
|
-
expect(newShape.props.
|
|
264
|
+
expect(newShape.props.textLastEditedBy).toBeNull()
|
|
265
265
|
})
|
|
266
266
|
|
|
267
|
-
it('Does not preserve
|
|
267
|
+
it('Does not preserve textLastEditedBy when creating an adjacent note via drag', () => {
|
|
268
268
|
const shape = createNoteWithAttribution()
|
|
269
269
|
|
|
270
270
|
editor.select(shape.id)
|
|
@@ -282,7 +282,7 @@ describe('Clone handles and attribution', () => {
|
|
|
282
282
|
|
|
283
283
|
const newShape = editor.getLastCreatedShape<TLNoteShape>()
|
|
284
284
|
expect(newShape.id).not.toBe(shape.id)
|
|
285
|
-
expect(newShape.props.
|
|
285
|
+
expect(newShape.props.textLastEditedBy).toBeNull()
|
|
286
286
|
|
|
287
287
|
editor.pointerUp()
|
|
288
288
|
})
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
TLShapeId,
|
|
7
7
|
Vec,
|
|
8
8
|
createShapeId,
|
|
9
|
+
cancelShapeCreationOnLongPress,
|
|
9
10
|
maybeSnapToGrid,
|
|
10
11
|
} from '@tldraw/editor'
|
|
11
12
|
import { startEditingShapeWithRichText } from '../../../tools/SelectTool/selectHelpers'
|
|
@@ -27,33 +28,57 @@ export class Pointing extends StateNode {
|
|
|
27
28
|
|
|
28
29
|
shape = {} as TLNoteShape
|
|
29
30
|
|
|
31
|
+
private shapeId!: TLShapeId
|
|
32
|
+
|
|
33
|
+
private shapeCenter = new Vec()
|
|
34
|
+
|
|
35
|
+
private hasCreatedShape = false
|
|
36
|
+
|
|
30
37
|
override onEnter() {
|
|
31
38
|
const { editor } = this
|
|
32
39
|
|
|
33
|
-
|
|
34
|
-
this.
|
|
40
|
+
this.hasCreatedShape = false
|
|
41
|
+
this.shapeId = createShapeId()
|
|
42
|
+
this.markId = editor.markHistoryStoppingPoint(`creating_note:${this.shapeId}`)
|
|
35
43
|
|
|
36
44
|
// Resolve note dimensions from the util's defaults
|
|
37
45
|
const noteUtil = editor.getShapeUtil('note') as NoteShapeUtil
|
|
38
46
|
const dv = getDisplayValues(noteUtil, { props: noteUtil.getDefaultProps() } as TLNoteShape)
|
|
39
47
|
|
|
40
48
|
// Check for note pits; if the pointer is close to one, place the note centered on the pit
|
|
41
|
-
const center =
|
|
49
|
+
const center = editor.inputs.getOriginPagePoint().clone()
|
|
42
50
|
const offset = getNoteShapeAdjacentPositionOffset(
|
|
43
|
-
|
|
51
|
+
editor,
|
|
44
52
|
center,
|
|
45
|
-
|
|
53
|
+
editor.getResizeScaleFactor(),
|
|
46
54
|
dv.noteWidth,
|
|
47
55
|
dv.noteHeight
|
|
48
56
|
)
|
|
49
57
|
if (offset) {
|
|
50
58
|
center.sub(offset)
|
|
51
59
|
}
|
|
60
|
+
this.shapeCenter = center
|
|
61
|
+
|
|
62
|
+
// On a coarse pointer, defer creating the note until the gesture commits (a
|
|
63
|
+
// drag or a release). The note is created on press, and a long-press cancels
|
|
64
|
+
// the pending creation, so without deferral the note appears on press and
|
|
65
|
+
// vanishes at the long-press mark — a visible flash. On a fine pointer there
|
|
66
|
+
// is no long-press cancel, so create immediately to keep the press-and-drag feel.
|
|
67
|
+
if (!editor.getInstanceState().isCoarsePointer) {
|
|
68
|
+
this.ensureShapeCreated()
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Create the note now if it hasn't been created yet (idempotent). The deferred
|
|
73
|
+
// drag and release paths route through here; a max-shapes failure cancels the
|
|
74
|
+
// gesture, matching the original onEnter behaviour.
|
|
75
|
+
private ensureShapeCreated() {
|
|
76
|
+
if (this.hasCreatedShape) return
|
|
52
77
|
|
|
53
|
-
|
|
54
|
-
const shape = createNoteShape(this.editor, id, center)
|
|
78
|
+
const shape = createNoteShape(this.editor, this.shapeId, this.shapeCenter)
|
|
55
79
|
if (shape) {
|
|
56
80
|
this.shape = shape
|
|
81
|
+
this.hasCreatedShape = true
|
|
57
82
|
} else {
|
|
58
83
|
this.cancel()
|
|
59
84
|
}
|
|
@@ -61,6 +86,8 @@ export class Pointing extends StateNode {
|
|
|
61
86
|
|
|
62
87
|
override onPointerMove(info: TLPointerEventInfo) {
|
|
63
88
|
if (this.editor.inputs.getIsDragging()) {
|
|
89
|
+
this.ensureShapeCreated()
|
|
90
|
+
if (!this.hasCreatedShape) return
|
|
64
91
|
this.editor.setCurrentTool('select.translating', {
|
|
65
92
|
...info,
|
|
66
93
|
target: 'shape',
|
|
@@ -79,6 +106,10 @@ export class Pointing extends StateNode {
|
|
|
79
106
|
this.complete()
|
|
80
107
|
}
|
|
81
108
|
|
|
109
|
+
override onLongPress() {
|
|
110
|
+
cancelShapeCreationOnLongPress(this.editor, () => this.cancel())
|
|
111
|
+
}
|
|
112
|
+
|
|
82
113
|
override onInterrupt() {
|
|
83
114
|
this.cancel()
|
|
84
115
|
}
|
|
@@ -92,6 +123,8 @@ export class Pointing extends StateNode {
|
|
|
92
123
|
}
|
|
93
124
|
|
|
94
125
|
private complete() {
|
|
126
|
+
this.ensureShapeCreated()
|
|
127
|
+
if (!this.hasCreatedShape) return
|
|
95
128
|
if (this.editor.getInstanceState().isToolLocked) {
|
|
96
129
|
this.parent.transition('idle')
|
|
97
130
|
} else {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Box, ExtractShapeByProps, TLShapeId } from '@tldraw/editor'
|
|
1
|
+
import { Box, ExtractShapeByProps, TLShapeId, resolveLineHeightPx } from '@tldraw/editor'
|
|
2
2
|
import classNames from 'classnames'
|
|
3
3
|
import React from 'react'
|
|
4
4
|
import { PlainTextArea } from '../text/PlainTextArea'
|
|
@@ -105,8 +105,8 @@ export const PlainTextLabel = React.memo(function PlainTextLabel({
|
|
|
105
105
|
className={`${cssPrefix}-label__inner tl-text-content__wrapper`}
|
|
106
106
|
style={{
|
|
107
107
|
fontSize,
|
|
108
|
-
lineHeight: lineHeight
|
|
109
|
-
minHeight:
|
|
108
|
+
lineHeight: `${resolveLineHeightPx(fontSize, lineHeight)}px`,
|
|
109
|
+
minHeight: `${resolveLineHeightPx(fontSize, lineHeight)}px`,
|
|
110
110
|
minWidth: Math.ceil(textWidth || 0),
|
|
111
111
|
color: labelColor,
|
|
112
112
|
width: textWidth ? Math.ceil(textWidth) : undefined,
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
TLShapeId,
|
|
7
7
|
openWindow,
|
|
8
8
|
preventDefault,
|
|
9
|
+
resolveLineHeightPx,
|
|
9
10
|
useEditor,
|
|
10
11
|
useReactor,
|
|
11
12
|
useValue,
|
|
@@ -161,8 +162,8 @@ export const RichTextLabel = React.memo(function RichTextLabel({
|
|
|
161
162
|
className={`${cssPrefix}-label__inner tl-text-content__wrapper`}
|
|
162
163
|
style={{
|
|
163
164
|
fontSize,
|
|
164
|
-
lineHeight: lineHeight
|
|
165
|
-
minHeight:
|
|
165
|
+
lineHeight: `${resolveLineHeightPx(fontSize, lineHeight)}px`,
|
|
166
|
+
minHeight: `${resolveLineHeightPx(fontSize, lineHeight)}px`,
|
|
166
167
|
minWidth: Math.ceil(textWidth || 0),
|
|
167
168
|
color: labelColor,
|
|
168
169
|
width: textWidth ? Math.ceil(textWidth) : undefined,
|
|
@@ -254,7 +255,7 @@ export function RichTextSVG({
|
|
|
254
255
|
fontSize: `${fontSize}px`,
|
|
255
256
|
wrap: wrap ? 'wrap' : 'nowrap',
|
|
256
257
|
color: labelColor,
|
|
257
|
-
lineHeight,
|
|
258
|
+
lineHeight: `${resolveLineHeightPx(fontSize, lineHeight)}px`,
|
|
258
259
|
textAlign,
|
|
259
260
|
width: '100%',
|
|
260
261
|
wordWrap: 'break-word' as const,
|
|
@@ -74,7 +74,10 @@ const generateImage = (dpr: number, currentZoom: number, solid: string) => {
|
|
|
74
74
|
canvasEl.height = size
|
|
75
75
|
|
|
76
76
|
const ctx = canvasEl.getContext('2d')
|
|
77
|
-
if (!ctx)
|
|
77
|
+
if (!ctx) {
|
|
78
|
+
reject()
|
|
79
|
+
return
|
|
80
|
+
}
|
|
78
81
|
|
|
79
82
|
ctx.fillStyle = solid
|
|
80
83
|
ctx.fillRect(0, 0, size, size)
|
|
@@ -109,6 +112,25 @@ const generateImage = (dpr: number, currentZoom: number, solid: string) => {
|
|
|
109
112
|
})
|
|
110
113
|
}
|
|
111
114
|
|
|
115
|
+
// Generating the pattern images is expensive (canvas draw + encode), but the result only depends
|
|
116
|
+
// on the device pixel ratio, zoom level, and solid color. Cache the blobs at the module level so
|
|
117
|
+
// the work is done once and reused across editor mounts and instances. Object URLs are still
|
|
118
|
+
// created and revoked per-instance; only the underlying blobs are shared.
|
|
119
|
+
const patternImageBlobCache = new Map<string, Promise<Blob>>()
|
|
120
|
+
|
|
121
|
+
function getPatternImageBlob(dpr: number, zoom: number, solid: string): Promise<Blob> {
|
|
122
|
+
const key = `${dpr}_${zoom}_${solid}`
|
|
123
|
+
let blob = patternImageBlobCache.get(key)
|
|
124
|
+
if (!blob) {
|
|
125
|
+
blob = generateImage(dpr, zoom, solid)
|
|
126
|
+
// Don't keep a rejected promise around (e.g. the throwToBlob debug flag), so a later call
|
|
127
|
+
// can retry once the failure condition is gone.
|
|
128
|
+
blob.catch(() => patternImageBlobCache.delete(key))
|
|
129
|
+
patternImageBlobCache.set(key, blob)
|
|
130
|
+
}
|
|
131
|
+
return blob
|
|
132
|
+
}
|
|
133
|
+
|
|
112
134
|
const canvasBlob = (size: [number, number], fn: (ctx: CanvasRenderingContext2D) => void) => {
|
|
113
135
|
const canvas = getGlobalDocument().createElement('canvas')
|
|
114
136
|
canvas.width = size[0]
|
|
@@ -208,12 +230,12 @@ function usePattern() {
|
|
|
208
230
|
|
|
209
231
|
const promise = Promise.all(
|
|
210
232
|
getPatternLodsToGenerate(maxEffectiveZoom).flatMap<Promise<PatternDef>>((zoom) => [
|
|
211
|
-
|
|
233
|
+
getPatternImageBlob(dpr, zoom, lightSolid).then((blob) => ({
|
|
212
234
|
zoom,
|
|
213
235
|
theme: 'light',
|
|
214
236
|
url: URL.createObjectURL(blob),
|
|
215
237
|
})),
|
|
216
|
-
|
|
238
|
+
getPatternImageBlob(dpr, zoom, darkSolid).then((blob) => ({
|
|
217
239
|
zoom,
|
|
218
240
|
theme: 'dark',
|
|
219
241
|
url: URL.createObjectURL(blob),
|