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
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
DefaultColorStyle,
|
|
4
4
|
DefaultFillStyle,
|
|
5
5
|
Editor,
|
|
6
|
+
GeoShapeGeoStyle,
|
|
6
7
|
HALF_PI,
|
|
7
8
|
PageRecordType,
|
|
8
9
|
Result,
|
|
@@ -583,10 +584,68 @@ export function ActionsProvider({ overrides, children }: ActionsProviderProps) {
|
|
|
583
584
|
}
|
|
584
585
|
},
|
|
585
586
|
},
|
|
587
|
+
{
|
|
588
|
+
id: 'frame-selection',
|
|
589
|
+
label: 'action.frame-selection',
|
|
590
|
+
kbd: 'cmd+alt+g',
|
|
591
|
+
onSelect(source) {
|
|
592
|
+
if (!canApplySelectionAction()) return
|
|
593
|
+
if (mustGoBackToSelectToolFirst()) return
|
|
594
|
+
|
|
595
|
+
const selectedShapes = editor.getSelectedShapes()
|
|
596
|
+
|
|
597
|
+
// If all selected shapes are frames, remove them (toggle behavior)
|
|
598
|
+
if (
|
|
599
|
+
selectedShapes.length > 0 &&
|
|
600
|
+
selectedShapes.every((shape) => editor.isShapeOfType(shape, 'frame'))
|
|
601
|
+
) {
|
|
602
|
+
trackEvent('remove-frame', { source })
|
|
603
|
+
editor.markHistoryStoppingPoint('remove-frame')
|
|
604
|
+
removeFrame(
|
|
605
|
+
editor,
|
|
606
|
+
selectedShapes.map((shape) => shape.id)
|
|
607
|
+
)
|
|
608
|
+
return
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
const ids = editor.getSelectedShapeIds()
|
|
612
|
+
if (ids.length < 2) return
|
|
613
|
+
|
|
614
|
+
const shapes = compact(ids.map((id) => editor.getShape(id)))
|
|
615
|
+
const pageBounds = editor.getSelectionPageBounds()
|
|
616
|
+
if (!pageBounds) return
|
|
617
|
+
|
|
618
|
+
trackEvent('frame-selection', { source })
|
|
619
|
+
editor.markHistoryStoppingPoint('frame-selection')
|
|
620
|
+
|
|
621
|
+
const parentId = editor.findCommonAncestor(shapes) ?? editor.getCurrentPageId()
|
|
622
|
+
|
|
623
|
+
const frameId = createShapeId()
|
|
624
|
+
const padding = 25 / editor.getZoomLevel()
|
|
625
|
+
|
|
626
|
+
editor.run(() => {
|
|
627
|
+
editor.createShapes([
|
|
628
|
+
{
|
|
629
|
+
id: frameId,
|
|
630
|
+
type: 'frame',
|
|
631
|
+
parentId,
|
|
632
|
+
x: pageBounds.x,
|
|
633
|
+
y: pageBounds.y,
|
|
634
|
+
props: {
|
|
635
|
+
w: pageBounds.w,
|
|
636
|
+
h: pageBounds.h,
|
|
637
|
+
},
|
|
638
|
+
},
|
|
639
|
+
])
|
|
640
|
+
editor.reparentShapes(ids, frameId)
|
|
641
|
+
fitFrameToContent(editor, frameId, { padding })
|
|
642
|
+
editor.select(frameId)
|
|
643
|
+
})
|
|
644
|
+
},
|
|
645
|
+
},
|
|
586
646
|
{
|
|
587
647
|
id: 'remove-frame',
|
|
588
648
|
label: 'action.remove-frame',
|
|
589
|
-
kbd: 'cmd+shift+f,ctrl+shift+f',
|
|
590
649
|
onSelect(source) {
|
|
591
650
|
if (!canApplySelectionAction()) return
|
|
592
651
|
|
|
@@ -1848,6 +1907,34 @@ export function ActionsProvider({ overrides, children }: ActionsProviderProps) {
|
|
|
1848
1907
|
trackEvent('download-original', { source })
|
|
1849
1908
|
},
|
|
1850
1909
|
},
|
|
1910
|
+
{
|
|
1911
|
+
id: 'copy-hovered-styles',
|
|
1912
|
+
label: 'action.copy-hovered-styles',
|
|
1913
|
+
kbd: 'shift+q',
|
|
1914
|
+
async onSelect(source) {
|
|
1915
|
+
const shape = editor.getShapeAtPoint(editor.inputs.getCurrentPagePoint(), {
|
|
1916
|
+
hitInside: false,
|
|
1917
|
+
hitLabels: false,
|
|
1918
|
+
hitLocked: editor.options.selectLockedShapes,
|
|
1919
|
+
margin: editor.options.hitTestMargin / editor.getZoomLevel(),
|
|
1920
|
+
})
|
|
1921
|
+
|
|
1922
|
+
const path = editor.getPath()
|
|
1923
|
+
if (!shape || !path.endsWith('.idle')) return
|
|
1924
|
+
|
|
1925
|
+
// Setting styles for the next shape is instance state, not document state, so it
|
|
1926
|
+
// isn't undoable and doesn't need a history stopping point.
|
|
1927
|
+
editor.run(() => {
|
|
1928
|
+
for (const style of editor.styleProps[shape.type].keys()) {
|
|
1929
|
+
const value = editor.getShapeStyleIfExists(shape, style)
|
|
1930
|
+
if (value === undefined || style === GeoShapeGeoStyle) continue
|
|
1931
|
+
editor.setStyleForNextShapes(style, value)
|
|
1932
|
+
}
|
|
1933
|
+
})
|
|
1934
|
+
|
|
1935
|
+
trackEvent('copy-hovered-styles', { source })
|
|
1936
|
+
},
|
|
1937
|
+
},
|
|
1851
1938
|
]
|
|
1852
1939
|
|
|
1853
1940
|
if (showCollaborationUi) {
|
|
@@ -21,16 +21,17 @@ export interface AssetUrlsProviderProps {
|
|
|
21
21
|
*/
|
|
22
22
|
export function AssetUrlsProvider({ assetUrls, children }: AssetUrlsProviderProps) {
|
|
23
23
|
useEffect(() => {
|
|
24
|
-
|
|
24
|
+
// Many icon URLs point at the same sprite sheet and differ only by their
|
|
25
|
+
// `#fragment` identifier (e.g. `0_merged.svg#tool-arrow`). The fragment
|
|
26
|
+
// doesn't change the underlying resource, so preload each unique resource
|
|
27
|
+
// once rather than creating hundreds of redundant Image decodes.
|
|
28
|
+
const preloaded = new Set<string>()
|
|
29
|
+
for (const src of [...Object.values(assetUrls.icons), ...Object.values(assetUrls.embedIcons)]) {
|
|
25
30
|
if (!src) continue
|
|
26
31
|
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
image.decode().catch(noop)
|
|
31
|
-
}
|
|
32
|
-
for (const src of Object.values(assetUrls.embedIcons)) {
|
|
33
|
-
if (!src) continue
|
|
32
|
+
const resource = src.split('#')[0]
|
|
33
|
+
if (preloaded.has(resource)) continue
|
|
34
|
+
preloaded.add(resource)
|
|
34
35
|
|
|
35
36
|
const image = Image()
|
|
36
37
|
image.crossOrigin = 'anonymous'
|
|
@@ -44,6 +44,7 @@ export interface TLUiEventMap {
|
|
|
44
44
|
'rename-document': null
|
|
45
45
|
'group-shapes': null
|
|
46
46
|
'ungroup-shapes': null
|
|
47
|
+
'frame-selection': null
|
|
47
48
|
'remove-frame': null
|
|
48
49
|
'fit-frame-to-content': null
|
|
49
50
|
'convert-to-embed': null
|
|
@@ -145,6 +146,7 @@ export interface TLUiEventMap {
|
|
|
145
146
|
| 'bulletList'
|
|
146
147
|
}
|
|
147
148
|
edit: null
|
|
149
|
+
'copy-hovered-styles': null
|
|
148
150
|
}
|
|
149
151
|
|
|
150
152
|
/** @public */
|
|
@@ -141,12 +141,35 @@ export function useKeyboardShortcuts() {
|
|
|
141
141
|
|
|
142
142
|
const body = editor.getContainerDocument().body
|
|
143
143
|
|
|
144
|
+
// Track which registration each physically-held key first triggered, keyed by
|
|
145
|
+
// `event.code`. While a key is held down, releasing a modifier should not let the
|
|
146
|
+
// auto-repeat keydown events trigger an adjacent shortcut (e.g. releasing shift while
|
|
147
|
+
// still holding shift+q shouldn't start firing the plain `q` shortcut). The same
|
|
148
|
+
// registration is still allowed to repeat (e.g. holding `=` to keep zooming).
|
|
149
|
+
const heldKeyRegistrations = new Map<string, Registration>()
|
|
150
|
+
|
|
144
151
|
const handleKeyDown = (e: KeyboardEvent) => {
|
|
145
152
|
if (shouldSkipEvent(e)) return
|
|
153
|
+
const code = e.code
|
|
146
154
|
for (const reg of registry) {
|
|
147
155
|
if (!reg.onKeyDown) continue
|
|
148
156
|
for (const p of reg.parsed) {
|
|
149
157
|
if (matchesEvent(e, p)) {
|
|
158
|
+
if (code) {
|
|
159
|
+
// We only guard auto-repeat events. A fresh keypress (`e.repeat` is
|
|
160
|
+
// false) is always free to trigger whatever it matches, even on the same
|
|
161
|
+
// physical key — e.g. cmd+z (undo) then cmd+shift+z (redo), where macOS
|
|
162
|
+
// swallows the `z` keyup while cmd stays held, so we can't rely on keyup
|
|
163
|
+
// to clear the previous registration.
|
|
164
|
+
if (e.repeat) {
|
|
165
|
+
const prev = heldKeyRegistrations.get(code)
|
|
166
|
+
// The held key already triggered a different shortcut; don't fall back
|
|
167
|
+
// to this one (or anything else) just because a modifier was released.
|
|
168
|
+
if (prev && prev !== reg) return
|
|
169
|
+
} else {
|
|
170
|
+
heldKeyRegistrations.set(code, reg)
|
|
171
|
+
}
|
|
172
|
+
}
|
|
150
173
|
reg.onKeyDown(e)
|
|
151
174
|
break
|
|
152
175
|
}
|
|
@@ -155,6 +178,10 @@ export function useKeyboardShortcuts() {
|
|
|
155
178
|
}
|
|
156
179
|
|
|
157
180
|
const handleKeyUp = (e: KeyboardEvent) => {
|
|
181
|
+
// Always release the held-key tracking, even for events we'd otherwise skip (e.g. the
|
|
182
|
+
// key was released after focus moved into a text input), so a stale entry can't block
|
|
183
|
+
// later shortcuts.
|
|
184
|
+
if (e.code) heldKeyRegistrations.delete(e.code)
|
|
158
185
|
if (shouldSkipEvent(e)) return
|
|
159
186
|
for (const reg of registry) {
|
|
160
187
|
if (!reg.onKeyUp) continue
|
|
@@ -195,7 +222,10 @@ export function areShortcutsDisabled(editor: Editor) {
|
|
|
195
222
|
// non-Latin layouts (Cyrillic, Greek, etc.) and macOS Option-letter dead-key combinations,
|
|
196
223
|
// where `event.key` is a non-ASCII glyph.
|
|
197
224
|
|
|
198
|
-
|
|
225
|
+
/**
|
|
226
|
+
* @internal
|
|
227
|
+
*/
|
|
228
|
+
export interface ParsedKbd {
|
|
199
229
|
key: string
|
|
200
230
|
shift: boolean
|
|
201
231
|
alt: boolean
|
|
@@ -319,7 +349,10 @@ const PHYSICAL_KEY_MAP: Record<string, string> = {
|
|
|
319
349
|
Backquote: '`',
|
|
320
350
|
}
|
|
321
351
|
|
|
322
|
-
|
|
352
|
+
/**
|
|
353
|
+
* @internal
|
|
354
|
+
*/
|
|
355
|
+
export function parseKbd(kbd: string): ParsedKbd[] {
|
|
323
356
|
const out: ParsedKbd[] = []
|
|
324
357
|
for (const shortcut of getKeys(kbd)) {
|
|
325
358
|
const parsed = parseShortcut(shortcut)
|
|
@@ -411,11 +444,16 @@ function shouldSkipEvent(e: KeyboardEvent): boolean {
|
|
|
411
444
|
return false
|
|
412
445
|
}
|
|
413
446
|
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
447
|
+
/**
|
|
448
|
+
* The "raw" kbd here will look something like "a" or a combination of keys
|
|
449
|
+
* "del,backspace". We need to first split them up by comma, then parse each
|
|
450
|
+
* key to ensure backwards compatibility with the old kbd format. We used to
|
|
451
|
+
* have symbols to denote cmd/alt/shift, using ! for shift, $ for cmd, and ?
|
|
452
|
+
* for alt.
|
|
453
|
+
*
|
|
454
|
+
* @internal
|
|
455
|
+
*/
|
|
456
|
+
export function getHotkeysStringFromKbd(kbd: string) {
|
|
419
457
|
return getKeys(kbd)
|
|
420
458
|
.map((kbd) => {
|
|
421
459
|
let str = ''
|
|
@@ -367,6 +367,12 @@ export interface OnDragFromToolbarToCreateShapesOpts {
|
|
|
367
367
|
* Called once the drag interaction has finished.
|
|
368
368
|
*/
|
|
369
369
|
onDragEnd?(id: TLShapeId): void
|
|
370
|
+
/**
|
|
371
|
+
* The id of the toolbar tool to keep highlighted while dragging. Defaults to the created shape's
|
|
372
|
+
* type. Set this when the dragged shape's type differs from the tool it's dragged from — for
|
|
373
|
+
* example, dragging a `draw` shape out from the select tool.
|
|
374
|
+
*/
|
|
375
|
+
maskedToolId?: string
|
|
370
376
|
}
|
|
371
377
|
|
|
372
378
|
/**
|
|
@@ -405,5 +411,5 @@ export function onDragFromToolbarToCreateShape(
|
|
|
405
411
|
},
|
|
406
412
|
})
|
|
407
413
|
|
|
408
|
-
editor.getCurrentTool().setCurrentToolIdMask(shape.type)
|
|
414
|
+
editor.getCurrentTool().setCurrentToolIdMask(opts.maskedToolId ?? shape.type)
|
|
409
415
|
}
|
|
@@ -29,6 +29,7 @@ export type TLUiTranslationKey =
|
|
|
29
29
|
| 'action.copy-as-svg.short'
|
|
30
30
|
| 'action.copy-as-svg'
|
|
31
31
|
| 'action.copy'
|
|
32
|
+
| 'action.copy-hovered-styles'
|
|
32
33
|
| 'action.cut'
|
|
33
34
|
| 'action.delete'
|
|
34
35
|
| 'action.unlock-all'
|
|
@@ -55,6 +56,7 @@ export type TLUiTranslationKey =
|
|
|
55
56
|
| 'action.flip-vertical.short'
|
|
56
57
|
| 'action.fork-project'
|
|
57
58
|
| 'action.fork-project-on-tldraw'
|
|
59
|
+
| 'action.frame-selection'
|
|
58
60
|
| 'action.group'
|
|
59
61
|
| 'action.insert-embed'
|
|
60
62
|
| 'action.insert-media'
|
|
@@ -29,6 +29,7 @@ export const DEFAULT_TRANSLATION = {
|
|
|
29
29
|
'action.copy-as-svg.short': 'SVG',
|
|
30
30
|
'action.copy-as-svg': 'Copy as SVG',
|
|
31
31
|
'action.copy': 'Copy',
|
|
32
|
+
'action.copy-hovered-styles': 'Copy hovered styles',
|
|
32
33
|
'action.cut': 'Cut',
|
|
33
34
|
'action.delete': 'Delete',
|
|
34
35
|
'action.unlock-all': 'Unlock all',
|
|
@@ -55,6 +56,7 @@ export const DEFAULT_TRANSLATION = {
|
|
|
55
56
|
'action.flip-vertical.short': 'Flip V',
|
|
56
57
|
'action.fork-project': 'Fork this project',
|
|
57
58
|
'action.fork-project-on-tldraw': 'Fork project on tldraw',
|
|
59
|
+
'action.frame-selection': 'Frame selection',
|
|
58
60
|
'action.group': 'Group',
|
|
59
61
|
'action.insert-embed': 'Insert embed…',
|
|
60
62
|
'action.insert-media': 'Upload media…',
|
package/src/lib/ui/version.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// This file is automatically generated by internal/scripts/refresh-assets.ts.
|
|
2
2
|
// Do not edit manually. Or do, I'm a comment, not a cop.
|
|
3
3
|
|
|
4
|
-
export const version = '5.2.0
|
|
4
|
+
export const version = '5.2.0'
|
|
5
5
|
export const publishDates = {
|
|
6
6
|
major: '2026-05-06T16:28:18.473Z',
|
|
7
|
-
minor: '2026-
|
|
8
|
-
patch: '2026-
|
|
7
|
+
minor: '2026-07-01T09:20:01.735Z',
|
|
8
|
+
patch: '2026-07-01T09:20:01.735Z',
|
|
9
9
|
}
|
package/src/lib/ui.css
CHANGED
|
@@ -12,9 +12,8 @@
|
|
|
12
12
|
* (which creates its own stacking context at z-index 300), so their
|
|
13
13
|
* z-indices are relative to the layout, not the container.
|
|
14
14
|
*
|
|
15
|
-
* cursor
|
|
16
|
-
*
|
|
17
|
-
* to that context.
|
|
15
|
+
* cursor is rendered inside canvas-in-front (stacking context at
|
|
16
|
+
* z-index 250), so their z-indices are relative to that context.
|
|
18
17
|
*/
|
|
19
18
|
--tl-layer-above: 1;
|
|
20
19
|
--tl-layer-focused-input: 10;
|
|
@@ -24,7 +23,6 @@
|
|
|
24
23
|
--tl-layer-toasts: 650;
|
|
25
24
|
--tl-layer-cursor: 700;
|
|
26
25
|
--tl-layer-header-footer: 999;
|
|
27
|
-
--tl-layer-following-indicator: 1000;
|
|
28
26
|
}
|
|
29
27
|
|
|
30
28
|
/* Button */
|
|
@@ -54,14 +52,14 @@
|
|
|
54
52
|
|
|
55
53
|
.tlui-button:disabled,
|
|
56
54
|
.tlui-button[data-disabled] {
|
|
57
|
-
color: var(--tl-color-text-
|
|
55
|
+
color: var(--tl-color-text-disabled);
|
|
58
56
|
text-shadow: none;
|
|
59
57
|
cursor: default;
|
|
60
58
|
}
|
|
61
59
|
|
|
62
60
|
.tlui-button:disabled .tlui-kbd,
|
|
63
61
|
.tlui-button[data-disabled] .tlui-kbd {
|
|
64
|
-
color: var(--tl-color-text-
|
|
62
|
+
color: var(--tl-color-text-disabled);
|
|
65
63
|
}
|
|
66
64
|
|
|
67
65
|
.tlui-button > * {
|
|
@@ -430,6 +428,11 @@
|
|
|
430
428
|
height: 15px;
|
|
431
429
|
}
|
|
432
430
|
|
|
431
|
+
.tlui-icon__tiny {
|
|
432
|
+
width: 12px;
|
|
433
|
+
height: 12px;
|
|
434
|
+
}
|
|
435
|
+
|
|
433
436
|
/* --------------------- Slider --------------------- */
|
|
434
437
|
|
|
435
438
|
.tlui-slider__container {
|
|
@@ -1043,7 +1046,7 @@
|
|
|
1043
1046
|
left: 8px;
|
|
1044
1047
|
}
|
|
1045
1048
|
|
|
1046
|
-
/*
|
|
1049
|
+
/*
|
|
1047
1050
|
* focusing skip-to-main-content hide top ui buttons to make sure we avoid
|
|
1048
1051
|
* z-index clashes on hover (see issue #8328)
|
|
1049
1052
|
*/
|
|
@@ -1690,8 +1693,17 @@ tldraw? probably.
|
|
|
1690
1693
|
height: 100%;
|
|
1691
1694
|
z-index: var(--tl-layer-canvas-overlays);
|
|
1692
1695
|
background-color: var(--tl-color-overlay);
|
|
1693
|
-
pointer-events: all;
|
|
1694
1696
|
animation: tl-fade-in 0.12s ease-out;
|
|
1697
|
+
}
|
|
1698
|
+
|
|
1699
|
+
.tlui-dialog__positioner {
|
|
1700
|
+
position: absolute;
|
|
1701
|
+
top: 0px;
|
|
1702
|
+
left: 0px;
|
|
1703
|
+
width: 100%;
|
|
1704
|
+
height: 100%;
|
|
1705
|
+
z-index: var(--tl-layer-canvas-overlays);
|
|
1706
|
+
pointer-events: all;
|
|
1695
1707
|
display: grid;
|
|
1696
1708
|
place-items: center;
|
|
1697
1709
|
overflow-y: auto;
|
|
@@ -2181,7 +2193,6 @@ tldraw? probably.
|
|
|
2181
2193
|
inset: 0px;
|
|
2182
2194
|
border-width: 2px;
|
|
2183
2195
|
border-style: solid;
|
|
2184
|
-
z-index: var(--tl-layer-following-indicator);
|
|
2185
2196
|
pointer-events: none;
|
|
2186
2197
|
}
|
|
2187
2198
|
|
|
@@ -5,6 +5,9 @@ import {
|
|
|
5
5
|
} from '../../defaultEmbedDefinitions'
|
|
6
6
|
import { getEmbedInfo, matchEmbedUrl, matchUrl } from './embeds'
|
|
7
7
|
|
|
8
|
+
const GOOGLE_MAPS_API_KEY = 'test-google-maps-api-key'
|
|
9
|
+
const TEST_EMBED_CONFIG = { google_maps: { apiKey: GOOGLE_MAPS_API_KEY } }
|
|
10
|
+
|
|
8
11
|
describe('embed sandbox permissions', () => {
|
|
9
12
|
function getSandboxString(permissions: Record<string, boolean | undefined>): string {
|
|
10
13
|
return Object.entries(permissions)
|
|
@@ -250,7 +253,7 @@ const MATCH_URL_TEST_URLS: (MatchUrlTestNoMatchDef | MatchUrlTestMatchDef)[] = [
|
|
|
250
253
|
match: true,
|
|
251
254
|
output: {
|
|
252
255
|
type: 'google_maps',
|
|
253
|
-
embedUrl: `https://google.com/maps/embed/v1/view?key=${
|
|
256
|
+
embedUrl: `https://google.com/maps/embed/v1/view?key=${GOOGLE_MAPS_API_KEY}¢er=52.2449313,0.0813192&zoom=14&maptype=roadmap`,
|
|
254
257
|
},
|
|
255
258
|
},
|
|
256
259
|
{
|
|
@@ -258,7 +261,7 @@ const MATCH_URL_TEST_URLS: (MatchUrlTestNoMatchDef | MatchUrlTestMatchDef)[] = [
|
|
|
258
261
|
match: true,
|
|
259
262
|
output: {
|
|
260
263
|
type: 'google_maps',
|
|
261
|
-
embedUrl: `https://google.co.uk/maps/embed/v1/view?key=${
|
|
264
|
+
embedUrl: `https://google.co.uk/maps/embed/v1/view?key=${GOOGLE_MAPS_API_KEY}¢er=52.2449313,0.0813192&zoom=14&maptype=roadmap`,
|
|
262
265
|
},
|
|
263
266
|
},
|
|
264
267
|
{
|
|
@@ -266,7 +269,7 @@ const MATCH_URL_TEST_URLS: (MatchUrlTestNoMatchDef | MatchUrlTestMatchDef)[] = [
|
|
|
266
269
|
match: true,
|
|
267
270
|
output: {
|
|
268
271
|
type: 'google_maps',
|
|
269
|
-
embedUrl: `https://google.com/maps/embed/v1/view?key=${
|
|
272
|
+
embedUrl: `https://google.com/maps/embed/v1/view?key=${GOOGLE_MAPS_API_KEY}¢er=51.5041626,-0.2468738&zoom=14&maptype=roadmap`,
|
|
270
273
|
},
|
|
271
274
|
},
|
|
272
275
|
{
|
|
@@ -282,7 +285,7 @@ const MATCH_URL_TEST_URLS: (MatchUrlTestNoMatchDef | MatchUrlTestMatchDef)[] = [
|
|
|
282
285
|
match: true,
|
|
283
286
|
output: {
|
|
284
287
|
type: 'google_maps',
|
|
285
|
-
embedUrl: `https://google.com/maps/embed/v1/view?key=${
|
|
288
|
+
embedUrl: `https://google.com/maps/embed/v1/view?key=${GOOGLE_MAPS_API_KEY}¢er=52.2449313,0.0813192&zoom=17.313261121327326&maptype=satellite`,
|
|
286
289
|
},
|
|
287
290
|
},
|
|
288
291
|
{
|
|
@@ -290,7 +293,7 @@ const MATCH_URL_TEST_URLS: (MatchUrlTestNoMatchDef | MatchUrlTestMatchDef)[] = [
|
|
|
290
293
|
match: true,
|
|
291
294
|
output: {
|
|
292
295
|
type: 'google_maps',
|
|
293
|
-
embedUrl: `https://google.co.uk/maps/embed/v1/view?key=${
|
|
296
|
+
embedUrl: `https://google.co.uk/maps/embed/v1/view?key=${GOOGLE_MAPS_API_KEY}¢er=51.5074,0.1278&zoom=16.984468114035085&maptype=satellite`,
|
|
294
297
|
},
|
|
295
298
|
},
|
|
296
299
|
{
|
|
@@ -604,7 +607,7 @@ const MATCH_EMBED_TEST_URLS: (MatchEmbedTestMatchDef | MatchEmbedTestNoMatchDef)
|
|
|
604
607
|
},
|
|
605
608
|
// google_maps
|
|
606
609
|
{
|
|
607
|
-
embedUrl: `https://google.com/maps/embed/v1/view?key=${
|
|
610
|
+
embedUrl: `https://google.com/maps/embed/v1/view?key=${GOOGLE_MAPS_API_KEY}¢er=52.2449313,0.0813192&zoom=14`,
|
|
608
611
|
match: true,
|
|
609
612
|
output: {
|
|
610
613
|
type: 'google_maps',
|
|
@@ -612,7 +615,7 @@ const MATCH_EMBED_TEST_URLS: (MatchEmbedTestMatchDef | MatchEmbedTestNoMatchDef)
|
|
|
612
615
|
},
|
|
613
616
|
},
|
|
614
617
|
{
|
|
615
|
-
embedUrl: `https://google.com/maps/embed/v1/view?key=${
|
|
618
|
+
embedUrl: `https://google.com/maps/embed/v1/view?key=${GOOGLE_MAPS_API_KEY}¢er=52.2449313,0.0813192&zoom=14&maptype=satellite`,
|
|
616
619
|
match: true,
|
|
617
620
|
output: {
|
|
618
621
|
type: 'google_maps',
|
|
@@ -620,7 +623,7 @@ const MATCH_EMBED_TEST_URLS: (MatchEmbedTestMatchDef | MatchEmbedTestNoMatchDef)
|
|
|
620
623
|
},
|
|
621
624
|
},
|
|
622
625
|
{
|
|
623
|
-
embedUrl: `https://google.co.uk/maps/embed/v1/view?key=${
|
|
626
|
+
embedUrl: `https://google.co.uk/maps/embed/v1/view?key=${GOOGLE_MAPS_API_KEY}¢er=51.5074,0.1278&zoom=12&maptype=roadmap`,
|
|
624
627
|
match: true,
|
|
625
628
|
output: {
|
|
626
629
|
type: 'google_maps',
|
|
@@ -628,8 +631,7 @@ const MATCH_EMBED_TEST_URLS: (MatchEmbedTestMatchDef | MatchEmbedTestNoMatchDef)
|
|
|
628
631
|
},
|
|
629
632
|
},
|
|
630
633
|
{
|
|
631
|
-
embedUrl:
|
|
632
|
-
'https://google.com/maps/embed?key=${process.env.NEXT_PUBLIC_GC_API_KEY}¢er=52.2449313,0.0813192&zoom=14',
|
|
634
|
+
embedUrl: 'https://google.com/maps/embed?key=KEY¢er=52.2449313,0.0813192&zoom=14',
|
|
633
635
|
match: false,
|
|
634
636
|
},
|
|
635
637
|
// google_calendar
|
|
@@ -786,7 +788,7 @@ const MATCH_EMBED_TEST_URLS: (MatchEmbedTestMatchDef | MatchEmbedTestNoMatchDef)
|
|
|
786
788
|
|
|
787
789
|
for (const testDef of MATCH_URL_TEST_URLS) {
|
|
788
790
|
test(`matchUrl("${testDef.url}")`, () => {
|
|
789
|
-
const result = matchUrl(DEFAULT_EMBED_DEFINITIONS, testDef.url)
|
|
791
|
+
const result = matchUrl(DEFAULT_EMBED_DEFINITIONS, testDef.url, TEST_EMBED_CONFIG)
|
|
790
792
|
if (testDef.match) {
|
|
791
793
|
expect(result).toBeDefined()
|
|
792
794
|
expect(result?.definition.type).toBe(testDef.output.type)
|
|
@@ -797,7 +799,7 @@ for (const testDef of MATCH_URL_TEST_URLS) {
|
|
|
797
799
|
})
|
|
798
800
|
|
|
799
801
|
test(`getEmbedInfo("${testDef.url}")`, () => {
|
|
800
|
-
const result = getEmbedInfo(DEFAULT_EMBED_DEFINITIONS, testDef.url)
|
|
802
|
+
const result = getEmbedInfo(DEFAULT_EMBED_DEFINITIONS, testDef.url, TEST_EMBED_CONFIG)
|
|
801
803
|
if (testDef.match) {
|
|
802
804
|
expect(result).toBeDefined()
|
|
803
805
|
expect(result?.definition.type).toBe(testDef.output.type)
|
|
@@ -47,13 +47,17 @@ const checkHostnames = (hostnames: readonly string[], targetHostname: string) =>
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
/** @public */
|
|
50
|
-
export function matchUrl(
|
|
50
|
+
export function matchUrl(
|
|
51
|
+
definitions: readonly TLEmbedDefinition[],
|
|
52
|
+
url: string,
|
|
53
|
+
embedConfig?: Record<string, unknown>
|
|
54
|
+
) {
|
|
51
55
|
const parsed = safeParseUrl(url)
|
|
52
56
|
if (!parsed) return undefined
|
|
53
57
|
const host = parsed.host.replace('www.', '')
|
|
54
58
|
for (const localEmbedDef of definitions) {
|
|
55
59
|
if (checkHostnames(localEmbedDef.hostnames, host)) {
|
|
56
|
-
const embedUrl = localEmbedDef.toEmbedUrl(url)
|
|
60
|
+
const embedUrl = localEmbedDef.toEmbedUrl(url, embedConfig?.[localEmbedDef.type])
|
|
57
61
|
|
|
58
62
|
if (embedUrl) {
|
|
59
63
|
return {
|
|
@@ -81,14 +85,16 @@ export type TLEmbedResult =
|
|
|
81
85
|
* return undefined.
|
|
82
86
|
*
|
|
83
87
|
* @param inputUrl - The URL to match
|
|
88
|
+
* @param embedConfig - Optional per-embed config, keyed by embed type, passed to `toEmbedUrl`
|
|
84
89
|
* @public
|
|
85
90
|
*/
|
|
86
91
|
export function getEmbedInfo(
|
|
87
92
|
definitions: readonly TLEmbedDefinition[],
|
|
88
|
-
inputUrl: string
|
|
93
|
+
inputUrl: string,
|
|
94
|
+
embedConfig?: Record<string, unknown>
|
|
89
95
|
): TLEmbedResult {
|
|
90
96
|
try {
|
|
91
|
-
return matchUrl(definitions, inputUrl) ?? matchEmbedUrl(definitions, inputUrl)
|
|
97
|
+
return matchUrl(definitions, inputUrl, embedConfig) ?? matchEmbedUrl(definitions, inputUrl)
|
|
92
98
|
} catch {
|
|
93
99
|
return undefined
|
|
94
100
|
}
|
|
@@ -24,14 +24,14 @@ export function pointsToBase64(points: VecModel[]): string {
|
|
|
24
24
|
*
|
|
25
25
|
* @example
|
|
26
26
|
* ```ts
|
|
27
|
-
* const points = base64ToPoints(shape.props.segments[0].path)
|
|
27
|
+
* const points = base64ToPoints(shape.props.segments[0].path, shape.props.segments[0].dim)
|
|
28
28
|
* expect(points[0].x).toBe(0)
|
|
29
29
|
* ```
|
|
30
30
|
*
|
|
31
31
|
* @public
|
|
32
32
|
*/
|
|
33
|
-
export function base64ToPoints(base64: string): VecModel[] {
|
|
34
|
-
return b64Vecs.decodePoints(base64)
|
|
33
|
+
export function base64ToPoints(base64: string, dim?: 2 | 3): VecModel[] {
|
|
34
|
+
return b64Vecs.decodePoints(base64, dim)
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
/**
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { TLRichText, toRichText } from '@tldraw/editor'
|
|
2
|
+
import { isEmptyRichText } from './richText'
|
|
3
|
+
|
|
4
|
+
describe('isEmptyRichText', () => {
|
|
5
|
+
it('treats a paragraph with no content key as empty (interactive editor output)', () => {
|
|
6
|
+
expect(isEmptyRichText(toRichText(''))).toBe(true)
|
|
7
|
+
})
|
|
8
|
+
|
|
9
|
+
it('treats a paragraph with an empty content array as empty (programmatic authoring)', () => {
|
|
10
|
+
const richText: TLRichText = {
|
|
11
|
+
type: 'doc',
|
|
12
|
+
content: [{ type: 'paragraph', attrs: { dir: 'auto' }, content: [] }],
|
|
13
|
+
}
|
|
14
|
+
expect(isEmptyRichText(richText)).toBe(true)
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
it('treats a doc with an empty content array as empty (hand-authored / importer form)', () => {
|
|
18
|
+
const richText: TLRichText = { type: 'doc', content: [] }
|
|
19
|
+
expect(isEmptyRichText(richText)).toBe(true)
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
it('treats a paragraph with text as non-empty', () => {
|
|
23
|
+
expect(isEmptyRichText(toRichText('Hello'))).toBe(false)
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
it('treats multiple paragraphs as non-empty', () => {
|
|
27
|
+
const richText: TLRichText = {
|
|
28
|
+
type: 'doc',
|
|
29
|
+
content: [
|
|
30
|
+
{ type: 'paragraph', content: [] },
|
|
31
|
+
{ type: 'paragraph', content: [] },
|
|
32
|
+
],
|
|
33
|
+
}
|
|
34
|
+
expect(isEmptyRichText(richText)).toBe(false)
|
|
35
|
+
})
|
|
36
|
+
})
|
|
@@ -107,8 +107,16 @@ export function renderHtmlFromRichTextForMeasurement(editor: Editor, richText: T
|
|
|
107
107
|
const plainTextFromRichTextCache = new WeakCache<TLRichText, string>()
|
|
108
108
|
|
|
109
109
|
export function isEmptyRichText(richText: TLRichText) {
|
|
110
|
+
// An empty document has no text. It can be encoded several equally-valid ways:
|
|
111
|
+
// an empty `content` array at the doc level, or a single paragraph whose own
|
|
112
|
+
// `content` is missing or an empty array. The interactive editor emits the
|
|
113
|
+
// single-paragraph / missing-`content` form; programmatic authoring (snapshot
|
|
114
|
+
// loads, and agents/importers emitting tldraw JSON) commonly emits the
|
|
115
|
+
// empty-array forms. Treat them all as empty.
|
|
116
|
+
if (richText.content.length === 0) return true
|
|
110
117
|
if (richText.content.length === 1) {
|
|
111
|
-
|
|
118
|
+
const node = richText.content[0] as any
|
|
119
|
+
if (!node.content || node.content.length === 0) return true
|
|
112
120
|
}
|
|
113
121
|
return false
|
|
114
122
|
}
|