tldraw 3.16.0-next.fe14f1b4181f → 4.0.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/dist-cjs/index.d.ts +232 -114
- package/dist-cjs/index.js +30 -15
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/defaultExternalContentHandlers.js +10 -0
- package/dist-cjs/lib/defaultExternalContentHandlers.js.map +2 -2
- package/dist-cjs/lib/shapes/arrow/arrow-types.js.map +1 -1
- package/dist-cjs/lib/shapes/arrow/arrowLabel.js +6 -0
- package/dist-cjs/lib/shapes/arrow/arrowLabel.js.map +3 -3
- package/dist-cjs/lib/shapes/arrow/arrowTargetState.js +3 -2
- package/dist-cjs/lib/shapes/arrow/arrowTargetState.js.map +2 -2
- package/dist-cjs/lib/shapes/arrow/toolStates/Pointing.js +1 -1
- package/dist-cjs/lib/shapes/arrow/toolStates/Pointing.js.map +2 -2
- package/dist-cjs/lib/shapes/bookmark/BookmarkShapeUtil.js +4 -4
- package/dist-cjs/lib/shapes/bookmark/BookmarkShapeUtil.js.map +2 -2
- package/dist-cjs/lib/shapes/frame/FrameShapeUtil.js +5 -1
- package/dist-cjs/lib/shapes/frame/FrameShapeUtil.js.map +2 -2
- package/dist-cjs/lib/shapes/frame/components/FrameLabelInput.js +8 -2
- package/dist-cjs/lib/shapes/frame/components/FrameLabelInput.js.map +2 -2
- package/dist-cjs/lib/shapes/geo/GeoShapeUtil.js +1 -0
- package/dist-cjs/lib/shapes/geo/GeoShapeUtil.js.map +2 -2
- package/dist-cjs/lib/shapes/note/NoteShapeUtil.js +2 -1
- package/dist-cjs/lib/shapes/note/NoteShapeUtil.js.map +2 -2
- package/dist-cjs/lib/shapes/shared/HyperlinkButton.js +4 -4
- package/dist-cjs/lib/shapes/shared/HyperlinkButton.js.map +2 -2
- package/dist-cjs/lib/shapes/shared/PlainTextLabel.js +1 -3
- package/dist-cjs/lib/shapes/shared/PlainTextLabel.js.map +2 -2
- package/dist-cjs/lib/shapes/shared/useEditablePlainText.js +3 -5
- package/dist-cjs/lib/shapes/shared/useEditablePlainText.js.map +2 -2
- package/dist-cjs/lib/shapes/shared/useImageOrVideoAsset.js +0 -2
- package/dist-cjs/lib/shapes/shared/useImageOrVideoAsset.js.map +2 -2
- package/dist-cjs/lib/shapes/text/PlainTextArea.js +3 -2
- package/dist-cjs/lib/shapes/text/PlainTextArea.js.map +2 -2
- package/dist-cjs/lib/shapes/text/RichTextArea.js +3 -3
- package/dist-cjs/lib/shapes/text/RichTextArea.js.map +2 -2
- package/dist-cjs/lib/tools/SelectTool/childStates/DraggingHandle.js +3 -1
- package/dist-cjs/lib/tools/SelectTool/childStates/DraggingHandle.js.map +2 -2
- package/dist-cjs/lib/ui/components/A11y.js +1 -1
- package/dist-cjs/lib/ui/components/A11y.js.map +2 -2
- package/dist-cjs/lib/ui/components/AccessibilityMenu.js +1 -1
- package/dist-cjs/lib/ui/components/AccessibilityMenu.js.map +2 -2
- package/dist-cjs/lib/ui/components/InputModeMenu.js +77 -0
- package/dist-cjs/lib/ui/components/InputModeMenu.js.map +7 -0
- package/dist-cjs/lib/ui/components/LanguageMenu.js +1 -0
- package/dist-cjs/lib/ui/components/LanguageMenu.js.map +2 -2
- package/dist-cjs/lib/ui/components/MainMenu/DefaultMainMenuContent.js +2 -0
- package/dist-cjs/lib/ui/components/MainMenu/DefaultMainMenuContent.js.map +2 -2
- package/dist-cjs/lib/ui/components/Minimap/DefaultMinimap.js +2 -1
- package/dist-cjs/lib/ui/components/Minimap/DefaultMinimap.js.map +2 -2
- package/dist-cjs/lib/ui/components/PageMenu/DefaultPageMenu.js +1 -1
- package/dist-cjs/lib/ui/components/PageMenu/DefaultPageMenu.js.map +2 -2
- package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanel.js +13 -6
- package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanel.js.map +2 -2
- package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanelContent.js +255 -316
- package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanelContent.js.map +2 -2
- package/dist-cjs/lib/ui/components/StylePanel/StylePanelButtonPicker.js +147 -0
- package/dist-cjs/lib/ui/components/StylePanel/StylePanelButtonPicker.js.map +7 -0
- package/dist-cjs/lib/ui/components/StylePanel/StylePanelContext.js +70 -0
- package/dist-cjs/lib/ui/components/StylePanel/StylePanelContext.js.map +7 -0
- package/dist-cjs/lib/ui/components/StylePanel/{DoubleDropdownPicker.js → StylePanelDoubleDropdownPicker.js} +23 -22
- package/dist-cjs/lib/ui/components/StylePanel/StylePanelDoubleDropdownPicker.js.map +7 -0
- package/dist-cjs/lib/ui/components/StylePanel/{DropdownPicker.js → StylePanelDropdownPicker.js} +23 -20
- package/dist-cjs/lib/ui/components/StylePanel/StylePanelDropdownPicker.js.map +7 -0
- package/dist-cjs/lib/ui/components/StylePanel/StylePanelSubheading.js +28 -0
- package/dist-cjs/lib/ui/components/StylePanel/StylePanelSubheading.js.map +7 -0
- package/dist-cjs/lib/ui/components/Toolbar/AltTextEditor.js +2 -0
- package/dist-cjs/lib/ui/components/Toolbar/AltTextEditor.js.map +2 -2
- package/dist-cjs/lib/ui/components/Toolbar/DefaultImageToolbarContent.js +38 -9
- package/dist-cjs/lib/ui/components/Toolbar/DefaultImageToolbarContent.js.map +2 -2
- package/dist-cjs/lib/ui/components/Toolbar/DefaultVideoToolbarContent.js +15 -3
- package/dist-cjs/lib/ui/components/Toolbar/DefaultVideoToolbarContent.js.map +2 -2
- package/dist-cjs/lib/ui/components/Toolbar/LinkEditor.js +2 -1
- package/dist-cjs/lib/ui/components/Toolbar/LinkEditor.js.map +2 -2
- package/dist-cjs/lib/ui/components/Toolbar/OverflowingToolbar.js +1 -1
- package/dist-cjs/lib/ui/components/Toolbar/OverflowingToolbar.js.map +2 -2
- package/dist-cjs/lib/ui/components/Toolbar/ToggleToolLockedButton.js +6 -2
- package/dist-cjs/lib/ui/components/Toolbar/ToggleToolLockedButton.js.map +2 -2
- package/dist-cjs/lib/ui/components/menu-items.js +6 -4
- package/dist-cjs/lib/ui/components/menu-items.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/TldrawUiContextualToolbar.js +11 -2
- package/dist-cjs/lib/ui/components/primitives/TldrawUiContextualToolbar.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/TldrawUiInput.js +5 -3
- package/dist-cjs/lib/ui/components/primitives/TldrawUiInput.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/TldrawUiSlider.js +13 -2
- package/dist-cjs/lib/ui/components/primitives/TldrawUiSlider.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/TldrawUiToolbar.js +3 -0
- package/dist-cjs/lib/ui/components/primitives/TldrawUiToolbar.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js +75 -20
- package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.js +3 -0
- package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js +8 -8
- package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js.map +2 -2
- package/dist-cjs/lib/ui/context/actions.js +18 -33
- package/dist-cjs/lib/ui/context/actions.js.map +2 -2
- package/dist-cjs/lib/ui/context/events.js.map +2 -2
- package/dist-cjs/lib/ui/hooks/useClipboardEvents.js +1 -1
- package/dist-cjs/lib/ui/hooks/useClipboardEvents.js.map +2 -2
- package/dist-cjs/lib/ui/hooks/useExportAs.js +3 -2
- package/dist-cjs/lib/ui/hooks/useExportAs.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 +12 -3
- package/dist-cjs/lib/ui/hooks/useTranslation/defaultTranslation.js.map +2 -2
- package/dist-cjs/lib/ui/version.js +4 -4
- package/dist-cjs/lib/ui/version.js.map +1 -1
- package/dist-cjs/lib/utils/export/copyAs.js +1 -2
- package/dist-cjs/lib/utils/export/copyAs.js.map +2 -2
- package/dist-cjs/lib/utils/export/export.js +0 -20
- package/dist-cjs/lib/utils/export/export.js.map +2 -2
- package/dist-cjs/lib/utils/export/exportAs.js +1 -2
- package/dist-cjs/lib/utils/export/exportAs.js.map +2 -2
- package/dist-esm/index.d.mts +232 -114
- package/dist-esm/index.mjs +61 -30
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/defaultExternalContentHandlers.mjs +10 -0
- package/dist-esm/lib/defaultExternalContentHandlers.mjs.map +2 -2
- package/dist-esm/lib/shapes/arrow/arrowLabel.mjs +6 -0
- package/dist-esm/lib/shapes/arrow/arrowLabel.mjs.map +3 -3
- package/dist-esm/lib/shapes/arrow/arrowTargetState.mjs +3 -2
- package/dist-esm/lib/shapes/arrow/arrowTargetState.mjs.map +2 -2
- package/dist-esm/lib/shapes/arrow/toolStates/Pointing.mjs +1 -1
- package/dist-esm/lib/shapes/arrow/toolStates/Pointing.mjs.map +2 -2
- package/dist-esm/lib/shapes/bookmark/BookmarkShapeUtil.mjs +4 -5
- package/dist-esm/lib/shapes/bookmark/BookmarkShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/shapes/frame/FrameShapeUtil.mjs +5 -1
- package/dist-esm/lib/shapes/frame/FrameShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/shapes/frame/components/FrameLabelInput.mjs +9 -3
- package/dist-esm/lib/shapes/frame/components/FrameLabelInput.mjs.map +2 -2
- package/dist-esm/lib/shapes/geo/GeoShapeUtil.mjs +1 -0
- package/dist-esm/lib/shapes/geo/GeoShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs +2 -1
- package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/shapes/shared/HyperlinkButton.mjs +5 -5
- package/dist-esm/lib/shapes/shared/HyperlinkButton.mjs.map +2 -2
- package/dist-esm/lib/shapes/shared/PlainTextLabel.mjs +1 -3
- package/dist-esm/lib/shapes/shared/PlainTextLabel.mjs.map +2 -2
- package/dist-esm/lib/shapes/shared/useEditablePlainText.mjs +3 -6
- package/dist-esm/lib/shapes/shared/useEditablePlainText.mjs.map +2 -2
- package/dist-esm/lib/shapes/shared/useImageOrVideoAsset.mjs +0 -2
- package/dist-esm/lib/shapes/shared/useImageOrVideoAsset.mjs.map +2 -2
- package/dist-esm/lib/shapes/text/PlainTextArea.mjs +4 -3
- package/dist-esm/lib/shapes/text/PlainTextArea.mjs.map +2 -2
- package/dist-esm/lib/shapes/text/RichTextArea.mjs +3 -4
- package/dist-esm/lib/shapes/text/RichTextArea.mjs.map +2 -2
- package/dist-esm/lib/tools/SelectTool/childStates/DraggingHandle.mjs +3 -1
- package/dist-esm/lib/tools/SelectTool/childStates/DraggingHandle.mjs.map +2 -2
- package/dist-esm/lib/ui/components/A11y.mjs +1 -2
- package/dist-esm/lib/ui/components/A11y.mjs.map +2 -2
- package/dist-esm/lib/ui/components/AccessibilityMenu.mjs +3 -3
- package/dist-esm/lib/ui/components/AccessibilityMenu.mjs.map +2 -2
- package/dist-esm/lib/ui/components/InputModeMenu.mjs +57 -0
- package/dist-esm/lib/ui/components/InputModeMenu.mjs.map +7 -0
- package/dist-esm/lib/ui/components/LanguageMenu.mjs +1 -0
- package/dist-esm/lib/ui/components/LanguageMenu.mjs.map +2 -2
- package/dist-esm/lib/ui/components/MainMenu/DefaultMainMenuContent.mjs +2 -0
- package/dist-esm/lib/ui/components/MainMenu/DefaultMainMenuContent.mjs.map +2 -2
- package/dist-esm/lib/ui/components/Minimap/DefaultMinimap.mjs +2 -1
- package/dist-esm/lib/ui/components/Minimap/DefaultMinimap.mjs.map +2 -2
- package/dist-esm/lib/ui/components/PageMenu/DefaultPageMenu.mjs +1 -2
- package/dist-esm/lib/ui/components/PageMenu/DefaultPageMenu.mjs.map +2 -2
- package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanel.mjs +18 -7
- package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanel.mjs.map +2 -2
- package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanelContent.mjs +257 -320
- package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanelContent.mjs.map +2 -2
- package/dist-esm/lib/ui/components/StylePanel/StylePanelButtonPicker.mjs +135 -0
- package/dist-esm/lib/ui/components/StylePanel/StylePanelButtonPicker.mjs.map +7 -0
- package/dist-esm/lib/ui/components/StylePanel/StylePanelContext.mjs +50 -0
- package/dist-esm/lib/ui/components/StylePanel/StylePanelContext.mjs.map +7 -0
- package/dist-esm/lib/ui/components/StylePanel/{DoubleDropdownPicker.mjs → StylePanelDoubleDropdownPicker.mjs} +20 -19
- package/dist-esm/lib/ui/components/StylePanel/StylePanelDoubleDropdownPicker.mjs.map +7 -0
- package/dist-esm/lib/ui/components/StylePanel/{DropdownPicker.mjs → StylePanelDropdownPicker.mjs} +20 -17
- package/dist-esm/lib/ui/components/StylePanel/StylePanelDropdownPicker.mjs.map +7 -0
- package/dist-esm/lib/ui/components/StylePanel/StylePanelSubheading.mjs +8 -0
- package/dist-esm/lib/ui/components/StylePanel/StylePanelSubheading.mjs.map +7 -0
- package/dist-esm/lib/ui/components/Toolbar/AltTextEditor.mjs +2 -0
- package/dist-esm/lib/ui/components/Toolbar/AltTextEditor.mjs.map +2 -2
- package/dist-esm/lib/ui/components/Toolbar/DefaultImageToolbarContent.mjs +38 -9
- package/dist-esm/lib/ui/components/Toolbar/DefaultImageToolbarContent.mjs.map +2 -2
- package/dist-esm/lib/ui/components/Toolbar/DefaultVideoToolbarContent.mjs +15 -3
- package/dist-esm/lib/ui/components/Toolbar/DefaultVideoToolbarContent.mjs.map +2 -2
- package/dist-esm/lib/ui/components/Toolbar/LinkEditor.mjs +2 -1
- package/dist-esm/lib/ui/components/Toolbar/LinkEditor.mjs.map +2 -2
- package/dist-esm/lib/ui/components/Toolbar/OverflowingToolbar.mjs +1 -1
- package/dist-esm/lib/ui/components/Toolbar/OverflowingToolbar.mjs.map +2 -2
- package/dist-esm/lib/ui/components/Toolbar/ToggleToolLockedButton.mjs +6 -2
- package/dist-esm/lib/ui/components/Toolbar/ToggleToolLockedButton.mjs.map +2 -2
- package/dist-esm/lib/ui/components/menu-items.mjs +6 -4
- package/dist-esm/lib/ui/components/menu-items.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/TldrawUiContextualToolbar.mjs +11 -3
- package/dist-esm/lib/ui/components/primitives/TldrawUiContextualToolbar.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/TldrawUiInput.mjs +6 -4
- package/dist-esm/lib/ui/components/primitives/TldrawUiInput.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/TldrawUiSlider.mjs +13 -2
- package/dist-esm/lib/ui/components/primitives/TldrawUiSlider.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/TldrawUiToolbar.mjs +3 -0
- package/dist-esm/lib/ui/components/primitives/TldrawUiToolbar.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs +76 -20
- package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.mjs +3 -0
- package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs +8 -8
- package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs.map +2 -2
- package/dist-esm/lib/ui/context/actions.mjs +18 -33
- package/dist-esm/lib/ui/context/actions.mjs.map +2 -2
- package/dist-esm/lib/ui/context/events.mjs.map +2 -2
- package/dist-esm/lib/ui/hooks/useClipboardEvents.mjs +1 -2
- package/dist-esm/lib/ui/hooks/useClipboardEvents.mjs.map +2 -2
- package/dist-esm/lib/ui/hooks/useExportAs.mjs +3 -2
- package/dist-esm/lib/ui/hooks/useExportAs.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 +12 -3
- package/dist-esm/lib/ui/hooks/useTranslation/defaultTranslation.mjs.map +2 -2
- package/dist-esm/lib/ui/version.mjs +4 -4
- package/dist-esm/lib/ui/version.mjs.map +1 -1
- package/dist-esm/lib/utils/export/copyAs.mjs +1 -2
- package/dist-esm/lib/utils/export/copyAs.mjs.map +2 -2
- package/dist-esm/lib/utils/export/export.mjs +0 -20
- package/dist-esm/lib/utils/export/export.mjs.map +2 -2
- package/dist-esm/lib/utils/export/exportAs.mjs +1 -2
- package/dist-esm/lib/utils/export/exportAs.mjs.map +2 -2
- package/package.json +3 -3
- package/src/index.ts +46 -22
- package/src/lib/defaultExternalContentHandlers.ts +14 -0
- package/src/lib/shapes/arrow/ArrowShapeOptions.test.ts +83 -13
- package/src/lib/shapes/arrow/ArrowShapeTool.test.ts +99 -5
- package/src/lib/shapes/arrow/ArrowShapeUtil.test.ts +41 -0
- package/src/lib/shapes/arrow/arrow-types.ts +3 -5
- package/src/lib/shapes/arrow/arrowLabel.ts +8 -0
- package/src/lib/shapes/arrow/arrowTargetState.ts +34 -3
- package/src/lib/shapes/arrow/toolStates/Pointing.tsx +1 -1
- package/src/lib/shapes/bookmark/BookmarkShapeUtil.tsx +4 -5
- package/src/lib/shapes/frame/FrameShapeUtil.tsx +5 -0
- package/src/lib/shapes/frame/components/FrameLabelInput.tsx +10 -3
- package/src/lib/shapes/geo/GeoShapeUtil.tsx +1 -0
- package/src/lib/shapes/note/NoteShapeUtil.tsx +1 -0
- package/src/lib/shapes/shared/HyperlinkButton.tsx +5 -5
- package/src/lib/shapes/shared/PlainTextLabel.tsx +0 -6
- package/src/lib/shapes/shared/useEditablePlainText.ts +3 -10
- package/src/lib/shapes/shared/useImageOrVideoAsset.ts +0 -7
- package/src/lib/shapes/text/PlainTextArea.tsx +4 -3
- package/src/lib/shapes/text/RichTextArea.tsx +3 -4
- package/src/lib/tools/SelectTool/childStates/DraggingHandle.tsx +6 -2
- package/src/lib/ui/components/A11y.tsx +1 -2
- package/src/lib/ui/components/AccessibilityMenu.tsx +2 -2
- package/src/lib/ui/components/InputModeMenu.tsx +65 -0
- package/src/lib/ui/components/LanguageMenu.tsx +1 -0
- package/src/lib/ui/components/MainMenu/DefaultMainMenuContent.tsx +4 -0
- package/src/lib/ui/components/Minimap/DefaultMinimap.tsx +2 -1
- package/src/lib/ui/components/PageMenu/DefaultPageMenu.tsx +1 -2
- package/src/lib/ui/components/StylePanel/DefaultStylePanel.tsx +30 -14
- package/src/lib/ui/components/StylePanel/DefaultStylePanelContent.tsx +262 -381
- package/src/lib/ui/components/{primitives/TldrawUiButtonPicker.tsx → StylePanel/StylePanelButtonPicker.tsx} +70 -50
- package/src/lib/ui/components/StylePanel/StylePanelContext.tsx +65 -0
- package/src/lib/ui/components/StylePanel/{DoubleDropdownPicker.tsx → StylePanelDoubleDropdownPicker.tsx} +28 -19
- package/src/lib/ui/components/StylePanel/StylePanelDropdownPicker.tsx +119 -0
- package/src/lib/ui/components/StylePanel/StylePanelSubheading.tsx +9 -0
- package/src/lib/ui/components/Toolbar/AltTextEditor.tsx +2 -0
- package/src/lib/ui/components/Toolbar/DefaultImageToolbarContent.tsx +32 -15
- package/src/lib/ui/components/Toolbar/DefaultVideoToolbarContent.tsx +12 -4
- package/src/lib/ui/components/Toolbar/LinkEditor.tsx +1 -0
- package/src/lib/ui/components/Toolbar/OverflowingToolbar.tsx +1 -1
- package/src/lib/ui/components/Toolbar/ToggleToolLockedButton.tsx +9 -2
- package/src/lib/ui/components/menu-items.tsx +5 -3
- package/src/lib/ui/components/primitives/TldrawUiContextualToolbar.tsx +7 -3
- package/src/lib/ui/components/primitives/TldrawUiInput.tsx +6 -3
- package/src/lib/ui/components/primitives/TldrawUiSlider.tsx +19 -4
- package/src/lib/ui/components/primitives/TldrawUiToolbar.tsx +5 -1
- package/src/lib/ui/components/primitives/TldrawUiTooltip.tsx +75 -14
- package/src/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.tsx +4 -0
- package/src/lib/ui/components/primitives/menus/TldrawUiMenuItem.tsx +9 -9
- package/src/lib/ui/context/actions.tsx +25 -35
- package/src/lib/ui/context/events.tsx +3 -2
- package/src/lib/ui/hooks/useClipboardEvents.ts +1 -2
- package/src/lib/ui/hooks/useExportAs.ts +3 -2
- package/src/lib/ui/hooks/useTools.tsx +1 -1
- package/src/lib/ui/hooks/useTranslation/TLUiTranslationKey.ts +11 -2
- package/src/lib/ui/hooks/useTranslation/defaultTranslation.ts +12 -3
- package/src/lib/ui/version.ts +4 -4
- package/src/lib/ui.css +41 -4
- package/src/lib/utils/export/copyAs.ts +1 -24
- package/src/lib/utils/export/export.ts +0 -36
- package/src/lib/utils/export/exportAs.ts +1 -32
- package/src/test/TestEditor.ts +8 -2
- package/src/test/commands/setCamera.test.ts +13 -0
- package/src/test/custom-clipping.test.ts +436 -0
- package/src/test/frames.test.ts +15 -0
- package/src/test/getCulledShapes.test.tsx +71 -2
- package/tldraw.css +49 -7
- package/dist-cjs/lib/ui/components/StylePanel/DoubleDropdownPicker.js.map +0 -7
- package/dist-cjs/lib/ui/components/StylePanel/DropdownPicker.js.map +0 -7
- package/dist-cjs/lib/ui/components/primitives/TldrawUiButtonPicker.js +0 -131
- package/dist-cjs/lib/ui/components/primitives/TldrawUiButtonPicker.js.map +0 -7
- package/dist-esm/lib/ui/components/StylePanel/DoubleDropdownPicker.mjs.map +0 -7
- package/dist-esm/lib/ui/components/StylePanel/DropdownPicker.mjs.map +0 -7
- package/dist-esm/lib/ui/components/primitives/TldrawUiButtonPicker.mjs +0 -115
- package/dist-esm/lib/ui/components/primitives/TldrawUiButtonPicker.mjs.map +0 -7
- package/src/lib/ui/components/StylePanel/DropdownPicker.tsx +0 -110
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
const version = "
|
|
1
|
+
const version = "4.0.0";
|
|
2
2
|
const publishDates = {
|
|
3
|
-
major: "
|
|
4
|
-
minor: "2025-
|
|
5
|
-
patch: "2025-
|
|
3
|
+
major: "2025-09-18T14:32:28.865Z",
|
|
4
|
+
minor: "2025-09-18T14:32:28.865Z",
|
|
5
|
+
patch: "2025-09-18T14:32:28.865Z"
|
|
6
6
|
};
|
|
7
7
|
export {
|
|
8
8
|
publishDates,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/ui/version.ts"],
|
|
4
|
-
"sourcesContent": ["// This file is automatically generated by internal/scripts/refresh-assets.ts.\n// Do not edit manually. Or do, I'm a comment, not a cop.\n\nexport const version = '
|
|
4
|
+
"sourcesContent": ["// This file is automatically generated by internal/scripts/refresh-assets.ts.\n// Do not edit manually. Or do, I'm a comment, not a cop.\n\nexport const version = '4.0.0'\nexport const publishDates = {\n\tmajor: '2025-09-18T14:32:28.865Z',\n\tminor: '2025-09-18T14:32:28.865Z',\n\tpatch: '2025-09-18T14:32:28.865Z',\n}\n"],
|
|
5
5
|
"mappings": "AAGO,MAAM,UAAU;AAChB,MAAM,eAAe;AAAA,EAC3B,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AACR;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -8,8 +8,7 @@ import {
|
|
|
8
8
|
getAdditionalClipboardWriteType
|
|
9
9
|
} from "../clipboard.mjs";
|
|
10
10
|
import { exportToImagePromiseForClipboard } from "./export.mjs";
|
|
11
|
-
function copyAs(
|
|
12
|
-
const [editor, ids, opts] = typeof args[2] === "string" ? [args[0], args[1], { ...args[3], format: args[2] }] : args;
|
|
11
|
+
function copyAs(editor, ids, opts) {
|
|
13
12
|
if (!navigator.clipboard) return Promise.reject(new Error("Copy not supported"));
|
|
14
13
|
if (navigator.clipboard.write) {
|
|
15
14
|
const { blobPromise, mimeType } = exportToImagePromiseForClipboard(editor, ids, opts);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/lib/utils/export/copyAs.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n\tEditor,\n\tFileHelpers,\n\tTLImageExportOptions,\n\tTLShapeId,\n\texhaustiveSwitchError,\n} from '@tldraw/editor'\nimport {\n\tclipboardWrite,\n\tdoesClipboardSupportType,\n\tgetAdditionalClipboardWriteType,\n} from '../clipboard'\nimport { exportToImagePromiseForClipboard } from './export'\n\n/** @public */\nexport type TLCopyType = 'svg' | 'png'\n\n/** @public */\nexport interface CopyAsOptions extends TLImageExportOptions {\n\t/** The format to copy as. */\n\tformat: TLCopyType\n}\n\n/**\n * Copy the given shapes to the clipboard.\n *\n * @param editor - The editor instance.\n * @param ids - The ids of the shapes to copy.\n * @param format - The format to copy as. Defaults to png.\n * @param opts - Options for the copy.\n *\n * @public\n */\nexport function copyAs(editor: Editor, ids: TLShapeId[], opts: CopyAsOptions): Promise<void
|
|
5
|
-
"mappings": "AAAA;AAAA,EAEC;AAAA,EAGA;AAAA,OACM;AACP;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,OACM;AACP,SAAS,wCAAwC;
|
|
4
|
+
"sourcesContent": ["import {\n\tEditor,\n\tFileHelpers,\n\tTLImageExportOptions,\n\tTLShapeId,\n\texhaustiveSwitchError,\n} from '@tldraw/editor'\nimport {\n\tclipboardWrite,\n\tdoesClipboardSupportType,\n\tgetAdditionalClipboardWriteType,\n} from '../clipboard'\nimport { exportToImagePromiseForClipboard } from './export'\n\n/** @public */\nexport type TLCopyType = 'svg' | 'png'\n\n/** @public */\nexport interface CopyAsOptions extends TLImageExportOptions {\n\t/** The format to copy as. */\n\tformat: TLCopyType\n}\n\n/**\n * Copy the given shapes to the clipboard.\n *\n * @param editor - The editor instance.\n * @param ids - The ids of the shapes to copy.\n * @param format - The format to copy as. Defaults to png.\n * @param opts - Options for the copy.\n *\n * @public\n */\nexport function copyAs(editor: Editor, ids: TLShapeId[], opts: CopyAsOptions): Promise<void> {\n\t// Note: it's important that this function itself isn't async and doesn't really use promises -\n\t// we need to create the relevant `ClipboardItem`s and call navigator.clipboard.write\n\t// synchronously to make sure safari knows that the user _wants_ to copy See\n\t// https://bugs.webkit.org/show_bug.cgi?id=222262\n\n\tif (!navigator.clipboard) return Promise.reject(new Error('Copy not supported'))\n\tif (navigator.clipboard.write as any) {\n\t\tconst { blobPromise, mimeType } = exportToImagePromiseForClipboard(editor, ids, opts)\n\n\t\tconst types: Record<string, Promise<Blob>> = { [mimeType]: blobPromise }\n\t\tconst additionalMimeType = getAdditionalClipboardWriteType(opts.format)\n\t\tif (additionalMimeType && doesClipboardSupportType(additionalMimeType)) {\n\t\t\ttypes[additionalMimeType] = blobPromise.then((blob) =>\n\t\t\t\tFileHelpers.rewriteMimeType(blob, additionalMimeType)\n\t\t\t)\n\t\t}\n\n\t\treturn clipboardWrite(types)\n\t}\n\n\tswitch (opts.format) {\n\t\tcase 'svg': {\n\t\t\treturn fallbackWriteTextAsync(async () => {\n\t\t\t\tconst result = await editor.getSvgString(ids, opts)\n\n\t\t\t\tif (!result) throw new Error('Failed to copy')\n\t\t\t\treturn result.svg\n\t\t\t})\n\t\t}\n\n\t\tcase 'png':\n\t\t\tthrow new Error('Copy not supported')\n\t\tdefault:\n\t\t\texhaustiveSwitchError(opts.format)\n\t}\n}\n\nasync function fallbackWriteTextAsync(getText: () => Promise<string>) {\n\tawait navigator.clipboard?.writeText?.(await getText())\n}\n"],
|
|
5
|
+
"mappings": "AAAA;AAAA,EAEC;AAAA,EAGA;AAAA,OACM;AACP;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,OACM;AACP,SAAS,wCAAwC;AAqB1C,SAAS,OAAO,QAAgB,KAAkB,MAAoC;AAM5F,MAAI,CAAC,UAAU,UAAW,QAAO,QAAQ,OAAO,IAAI,MAAM,oBAAoB,CAAC;AAC/E,MAAI,UAAU,UAAU,OAAc;AACrC,UAAM,EAAE,aAAa,SAAS,IAAI,iCAAiC,QAAQ,KAAK,IAAI;AAEpF,UAAM,QAAuC,EAAE,CAAC,QAAQ,GAAG,YAAY;AACvE,UAAM,qBAAqB,gCAAgC,KAAK,MAAM;AACtE,QAAI,sBAAsB,yBAAyB,kBAAkB,GAAG;AACvE,YAAM,kBAAkB,IAAI,YAAY;AAAA,QAAK,CAAC,SAC7C,YAAY,gBAAgB,MAAM,kBAAkB;AAAA,MACrD;AAAA,IACD;AAEA,WAAO,eAAe,KAAK;AAAA,EAC5B;AAEA,UAAQ,KAAK,QAAQ;AAAA,IACpB,KAAK,OAAO;AACX,aAAO,uBAAuB,YAAY;AACzC,cAAM,SAAS,MAAM,OAAO,aAAa,KAAK,IAAI;AAElD,YAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,gBAAgB;AAC7C,eAAO,OAAO;AAAA,MACf,CAAC;AAAA,IACF;AAAA,IAEA,KAAK;AACJ,YAAM,IAAI,MAAM,oBAAoB;AAAA,IACrC;AACC,4BAAsB,KAAK,MAAM;AAAA,EACnC;AACD;AAEA,eAAe,uBAAuB,SAAgC;AACrE,QAAM,UAAU,WAAW,YAAY,MAAM,QAAQ,CAAC;AACvD;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -23,25 +23,6 @@ async function exportToString(editor, ids, format, opts = {}) {
|
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
|
-
async function exportToBlob({
|
|
27
|
-
editor,
|
|
28
|
-
ids,
|
|
29
|
-
format,
|
|
30
|
-
opts = {}
|
|
31
|
-
}) {
|
|
32
|
-
const idsToUse = ids?.length ? ids : [...editor.getCurrentPageShapeIds()];
|
|
33
|
-
switch (format) {
|
|
34
|
-
case "jpeg":
|
|
35
|
-
case "png":
|
|
36
|
-
case "webp":
|
|
37
|
-
case "svg": {
|
|
38
|
-
return (await editor.toImage(idsToUse, { ...opts, format })).blob;
|
|
39
|
-
}
|
|
40
|
-
default: {
|
|
41
|
-
exhaustiveSwitchError(format);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
26
|
const clipboardMimeTypesByFormat = {
|
|
46
27
|
jpeg: "image/jpeg",
|
|
47
28
|
png: "image/png",
|
|
@@ -59,7 +40,6 @@ function exportToImagePromiseForClipboard(editor, ids, opts = {}) {
|
|
|
59
40
|
};
|
|
60
41
|
}
|
|
61
42
|
export {
|
|
62
|
-
exportToBlob,
|
|
63
43
|
exportToImagePromiseForClipboard,
|
|
64
44
|
exportToString
|
|
65
45
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/lib/utils/export/export.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n\tEditor,\n\tFileHelpers,\n\
|
|
5
|
-
"mappings": "AAAA;AAAA,EAEC;AAAA,
|
|
4
|
+
"sourcesContent": ["import {\n\tEditor,\n\tFileHelpers,\n\tTLImageExportOptions,\n\tTLShapeId,\n\texhaustiveSwitchError,\n} from '@tldraw/editor'\n\nasync function getSvgString(editor: Editor, ids: TLShapeId[], opts: TLImageExportOptions) {\n\tconst svg = await editor.getSvgString(ids, opts)\n\tif (!svg) {\n\t\tthrow new Error('Could not construct SVG.')\n\t}\n\treturn svg\n}\n\nexport async function exportToString(\n\teditor: Editor,\n\tids: TLShapeId[],\n\tformat: 'svg' | 'json',\n\topts: TLImageExportOptions = {}\n) {\n\tswitch (format) {\n\t\tcase 'svg': {\n\t\t\treturn (await getSvgString(editor, ids, opts))?.svg\n\t\t}\n\t\tcase 'json': {\n\t\t\tconst data = await editor.resolveAssetsInContent(editor.getContentFromCurrentPage(ids))\n\t\t\treturn JSON.stringify(data)\n\t\t}\n\t\tdefault: {\n\t\t\texhaustiveSwitchError(format)\n\t\t}\n\t}\n}\n\nconst clipboardMimeTypesByFormat = {\n\tjpeg: 'image/jpeg',\n\tpng: 'image/png',\n\twebp: 'image/webp',\n\tsvg: 'text/plain',\n}\n\nexport function exportToImagePromiseForClipboard(\n\teditor: Editor,\n\tids: TLShapeId[],\n\topts: TLImageExportOptions = {}\n): { blobPromise: Promise<Blob>; mimeType: string } {\n\tconst idsToUse = ids?.length ? ids : [...editor.getCurrentPageShapeIds()]\n\tconst format = opts.format ?? 'png'\n\treturn {\n\t\tblobPromise: editor\n\t\t\t.toImage(idsToUse, opts)\n\t\t\t.then((result) =>\n\t\t\t\tFileHelpers.rewriteMimeType(result.blob, clipboardMimeTypesByFormat[format])\n\t\t\t),\n\t\tmimeType: clipboardMimeTypesByFormat[format],\n\t}\n}\n"],
|
|
5
|
+
"mappings": "AAAA;AAAA,EAEC;AAAA,EAGA;AAAA,OACM;AAEP,eAAe,aAAa,QAAgB,KAAkB,MAA4B;AACzF,QAAM,MAAM,MAAM,OAAO,aAAa,KAAK,IAAI;AAC/C,MAAI,CAAC,KAAK;AACT,UAAM,IAAI,MAAM,0BAA0B;AAAA,EAC3C;AACA,SAAO;AACR;AAEA,eAAsB,eACrB,QACA,KACA,QACA,OAA6B,CAAC,GAC7B;AACD,UAAQ,QAAQ;AAAA,IACf,KAAK,OAAO;AACX,cAAQ,MAAM,aAAa,QAAQ,KAAK,IAAI,IAAI;AAAA,IACjD;AAAA,IACA,KAAK,QAAQ;AACZ,YAAM,OAAO,MAAM,OAAO,uBAAuB,OAAO,0BAA0B,GAAG,CAAC;AACtF,aAAO,KAAK,UAAU,IAAI;AAAA,IAC3B;AAAA,IACA,SAAS;AACR,4BAAsB,MAAM;AAAA,IAC7B;AAAA,EACD;AACD;AAEA,MAAM,6BAA6B;AAAA,EAClC,MAAM;AAAA,EACN,KAAK;AAAA,EACL,MAAM;AAAA,EACN,KAAK;AACN;AAEO,SAAS,iCACf,QACA,KACA,OAA6B,CAAC,GACqB;AACnD,QAAM,WAAW,KAAK,SAAS,MAAM,CAAC,GAAG,OAAO,uBAAuB,CAAC;AACxE,QAAM,SAAS,KAAK,UAAU;AAC9B,SAAO;AAAA,IACN,aAAa,OACX,QAAQ,UAAU,IAAI,EACtB;AAAA,MAAK,CAAC,WACN,YAAY,gBAAgB,OAAO,MAAM,2BAA2B,MAAM,CAAC;AAAA,IAC5E;AAAA,IACD,UAAU,2BAA2B,MAAM;AAAA,EAC5C;AACD;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
sanitizeId
|
|
3
3
|
} from "@tldraw/editor";
|
|
4
|
-
async function exportAs(
|
|
5
|
-
const [editor, ids, opts] = typeof args[2] === "object" ? args : [args[0], args[1], { ...args[4], format: args[2] ?? "png", name: args[3] }];
|
|
4
|
+
async function exportAs(editor, ids, opts) {
|
|
6
5
|
let name = opts.name;
|
|
7
6
|
if (!name) {
|
|
8
7
|
name = `shapes at ${getTimestamp()}`;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/lib/utils/export/exportAs.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n\tEditor,\n\tsanitizeId,\n\tTLExportType,\n\tTLFrameShape,\n\tTLImageExportOptions,\n\tTLShapeId,\n} from '@tldraw/editor'\n\n/** @public */\nexport interface ExportAsOptions extends TLImageExportOptions {\n\t/** {@inheritdoc @tldraw/editor#TLImageExportOptions.format} */\n\tformat: TLExportType\n\t/** Name of the exported file. If undefined a predefined name, based on the selection, will be used. */\n\tname?: string\n}\n\n/**\n * Export the given shapes as files.\n *\n * @param editor - The editor instance.\n * @param ids - The ids of the shapes to export.\n * @param opts - Options for the export.\n *\n * @public\n */\nexport async function exportAs(\n\teditor: Editor,\n\tids: TLShapeId[],\n\topts: ExportAsOptions\n): Promise<void
|
|
5
|
-
"mappings": "AAAA;AAAA,EAEC;AAAA,OAKM;
|
|
4
|
+
"sourcesContent": ["import {\n\tEditor,\n\tsanitizeId,\n\tTLExportType,\n\tTLFrameShape,\n\tTLImageExportOptions,\n\tTLShapeId,\n} from '@tldraw/editor'\n\n/** @public */\nexport interface ExportAsOptions extends TLImageExportOptions {\n\t/** {@inheritdoc @tldraw/editor#TLImageExportOptions.format} */\n\tformat: TLExportType\n\t/** Name of the exported file. If undefined a predefined name, based on the selection, will be used. */\n\tname?: string\n}\n\n/**\n * Export the given shapes as files.\n *\n * @param editor - The editor instance.\n * @param ids - The ids of the shapes to export.\n * @param opts - Options for the export.\n *\n * @public\n */\nexport async function exportAs(\n\teditor: Editor,\n\tids: TLShapeId[],\n\topts: ExportAsOptions\n): Promise<void> {\n\t// If we don't get name then use a predefined one\n\tlet name = opts.name\n\tif (!name) {\n\t\tname = `shapes at ${getTimestamp()}`\n\t\tif (ids.length === 1) {\n\t\t\tconst first = editor.getShape(ids[0])!\n\t\t\tif (editor.isShapeOfType<TLFrameShape>(first, 'frame')) {\n\t\t\t\tname = first.props.name || 'frame'\n\t\t\t} else {\n\t\t\t\tname = `${sanitizeId(first.id)} at ${getTimestamp()}`\n\t\t\t}\n\t\t}\n\t}\n\tname += `.${opts.format}`\n\n\tconst { blob } = await editor.toImage(ids, opts)\n\tconst file = new File([blob], name, { type: blob.type })\n\tdownloadFile(file)\n}\n\nfunction getTimestamp() {\n\tconst now = new Date()\n\n\tconst year = String(now.getFullYear()).slice(2)\n\tconst month = String(now.getMonth() + 1).padStart(2, '0')\n\tconst day = String(now.getDate()).padStart(2, '0')\n\tconst hours = String(now.getHours()).padStart(2, '0')\n\tconst minutes = String(now.getMinutes()).padStart(2, '0')\n\tconst seconds = String(now.getSeconds()).padStart(2, '0')\n\n\treturn `${year}-${month}-${day} ${hours}.${minutes}.${seconds}`\n}\n\n/** @internal */\nexport function downloadFile(file: File) {\n\tconst link = document.createElement('a')\n\tconst url = URL.createObjectURL(file)\n\tlink.href = url\n\tlink.download = file.name\n\tlink.click()\n\tURL.revokeObjectURL(url)\n}\n"],
|
|
5
|
+
"mappings": "AAAA;AAAA,EAEC;AAAA,OAKM;AAmBP,eAAsB,SACrB,QACA,KACA,MACgB;AAEhB,MAAI,OAAO,KAAK;AAChB,MAAI,CAAC,MAAM;AACV,WAAO,aAAa,aAAa,CAAC;AAClC,QAAI,IAAI,WAAW,GAAG;AACrB,YAAM,QAAQ,OAAO,SAAS,IAAI,CAAC,CAAC;AACpC,UAAI,OAAO,cAA4B,OAAO,OAAO,GAAG;AACvD,eAAO,MAAM,MAAM,QAAQ;AAAA,MAC5B,OAAO;AACN,eAAO,GAAG,WAAW,MAAM,EAAE,CAAC,OAAO,aAAa,CAAC;AAAA,MACpD;AAAA,IACD;AAAA,EACD;AACA,UAAQ,IAAI,KAAK,MAAM;AAEvB,QAAM,EAAE,KAAK,IAAI,MAAM,OAAO,QAAQ,KAAK,IAAI;AAC/C,QAAM,OAAO,IAAI,KAAK,CAAC,IAAI,GAAG,MAAM,EAAE,MAAM,KAAK,KAAK,CAAC;AACvD,eAAa,IAAI;AAClB;AAEA,SAAS,eAAe;AACvB,QAAM,MAAM,oBAAI,KAAK;AAErB,QAAM,OAAO,OAAO,IAAI,YAAY,CAAC,EAAE,MAAM,CAAC;AAC9C,QAAM,QAAQ,OAAO,IAAI,SAAS,IAAI,CAAC,EAAE,SAAS,GAAG,GAAG;AACxD,QAAM,MAAM,OAAO,IAAI,QAAQ,CAAC,EAAE,SAAS,GAAG,GAAG;AACjD,QAAM,QAAQ,OAAO,IAAI,SAAS,CAAC,EAAE,SAAS,GAAG,GAAG;AACpD,QAAM,UAAU,OAAO,IAAI,WAAW,CAAC,EAAE,SAAS,GAAG,GAAG;AACxD,QAAM,UAAU,OAAO,IAAI,WAAW,CAAC,EAAE,SAAS,GAAG,GAAG;AAExD,SAAO,GAAG,IAAI,IAAI,KAAK,IAAI,GAAG,IAAI,KAAK,IAAI,OAAO,IAAI,OAAO;AAC9D;AAGO,SAAS,aAAa,MAAY;AACxC,QAAM,OAAO,SAAS,cAAc,GAAG;AACvC,QAAM,MAAM,IAAI,gBAAgB,IAAI;AACpC,OAAK,OAAO;AACZ,OAAK,WAAW,KAAK;AACrB,OAAK,MAAM;AACX,MAAI,gBAAgB,GAAG;AACxB;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tldraw",
|
|
3
3
|
"description": "A tiny little drawing editor.",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "4.0.0",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "tldraw Inc.",
|
|
7
7
|
"email": "hello@tldraw.com"
|
|
@@ -55,8 +55,8 @@
|
|
|
55
55
|
"@tiptap/pm": "^2.9.1",
|
|
56
56
|
"@tiptap/react": "^2.9.1",
|
|
57
57
|
"@tiptap/starter-kit": "^2.9.1",
|
|
58
|
-
"@tldraw/editor": "
|
|
59
|
-
"@tldraw/store": "
|
|
58
|
+
"@tldraw/editor": "4.0.0",
|
|
59
|
+
"@tldraw/store": "4.0.0",
|
|
60
60
|
"classnames": "^2.5.1",
|
|
61
61
|
"hotkeys-js": "^3.13.9",
|
|
62
62
|
"idb": "^7.1.1",
|
package/src/index.ts
CHANGED
|
@@ -106,6 +106,13 @@ export {
|
|
|
106
106
|
} from './lib/shapes/arrow/arrow-types'
|
|
107
107
|
export { ArrowShapeTool } from './lib/shapes/arrow/ArrowShapeTool'
|
|
108
108
|
export { ArrowShapeUtil } from './lib/shapes/arrow/ArrowShapeUtil'
|
|
109
|
+
export {
|
|
110
|
+
clearArrowTargetState,
|
|
111
|
+
getArrowTargetState,
|
|
112
|
+
updateArrowTargetState,
|
|
113
|
+
type ArrowTargetState,
|
|
114
|
+
type UpdateArrowTargetStateOpts,
|
|
115
|
+
} from './lib/shapes/arrow/arrowTargetState'
|
|
109
116
|
export {
|
|
110
117
|
type ElbowArrowBox,
|
|
111
118
|
type ElbowArrowBoxEdges,
|
|
@@ -171,11 +178,7 @@ export {
|
|
|
171
178
|
export { getStrokePoints } from './lib/shapes/shared/freehand/getStrokePoints'
|
|
172
179
|
export { getSvgPathFromStrokePoints } from './lib/shapes/shared/freehand/svg'
|
|
173
180
|
export { type StrokeOptions, type StrokePoint } from './lib/shapes/shared/freehand/types'
|
|
174
|
-
export {
|
|
175
|
-
PlainTextLabel,
|
|
176
|
-
TextLabel,
|
|
177
|
-
type PlainTextLabelProps,
|
|
178
|
-
} from './lib/shapes/shared/PlainTextLabel'
|
|
181
|
+
export { PlainTextLabel, type PlainTextLabelProps } from './lib/shapes/shared/PlainTextLabel'
|
|
179
182
|
export {
|
|
180
183
|
RichTextLabel,
|
|
181
184
|
RichTextSVG,
|
|
@@ -183,10 +186,9 @@ export {
|
|
|
183
186
|
type RichTextSVGProps,
|
|
184
187
|
} from './lib/shapes/shared/RichTextLabel'
|
|
185
188
|
export { useDefaultColorTheme } from './lib/shapes/shared/useDefaultColorTheme'
|
|
186
|
-
export { useEditablePlainText
|
|
189
|
+
export { useEditablePlainText } from './lib/shapes/shared/useEditablePlainText'
|
|
187
190
|
export { useEditableRichText } from './lib/shapes/shared/useEditableRichText'
|
|
188
191
|
export {
|
|
189
|
-
useAsset,
|
|
190
192
|
useImageOrVideoAsset,
|
|
191
193
|
type UseImageOrVideoAssetOptions,
|
|
192
194
|
} from './lib/shapes/shared/useImageOrVideoAsset'
|
|
@@ -301,6 +303,7 @@ export {
|
|
|
301
303
|
ToggleDebugModeItem,
|
|
302
304
|
ToggleDynamicSizeModeItem,
|
|
303
305
|
ToggleEdgeScrollingItem,
|
|
306
|
+
ToggleEnhancedA11yModeItem,
|
|
304
307
|
ToggleFocusModeItem,
|
|
305
308
|
ToggleGridItem,
|
|
306
309
|
ToggleKeyboardShortcutsItem,
|
|
@@ -310,7 +313,6 @@ export {
|
|
|
310
313
|
ToggleSnapModeItem,
|
|
311
314
|
ToggleToolLockItem,
|
|
312
315
|
ToggleTransparentBgMenuItem,
|
|
313
|
-
ToggleUiLabelsItem,
|
|
314
316
|
ToggleWrapModeItem,
|
|
315
317
|
UngroupMenuItem,
|
|
316
318
|
UnlockAllMenuItem,
|
|
@@ -365,10 +367,6 @@ export {
|
|
|
365
367
|
TldrawUiMenuSubmenu,
|
|
366
368
|
type TLUiMenuSubmenuProps,
|
|
367
369
|
} from './lib/ui/components/primitives/menus/TldrawUiMenuSubmenu'
|
|
368
|
-
export {
|
|
369
|
-
TldrawUiButtonPicker,
|
|
370
|
-
type TLUiButtonPickerProps,
|
|
371
|
-
} from './lib/ui/components/primitives/TldrawUiButtonPicker'
|
|
372
370
|
export {
|
|
373
371
|
TldrawUiContextualToolbar,
|
|
374
372
|
type TLUiContextualToolbarProps,
|
|
@@ -448,17 +446,44 @@ export {
|
|
|
448
446
|
type TLUiStylePanelProps,
|
|
449
447
|
} from './lib/ui/components/StylePanel/DefaultStylePanel'
|
|
450
448
|
export {
|
|
451
|
-
ArrowheadStylePickerSet,
|
|
452
|
-
CommonStylePickerSet,
|
|
453
449
|
DefaultStylePanelContent,
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
450
|
+
StylePanelArrowheadPicker,
|
|
451
|
+
StylePanelArrowKindPicker,
|
|
452
|
+
StylePanelColorPicker,
|
|
453
|
+
StylePanelDashPicker,
|
|
454
|
+
StylePanelFillPicker,
|
|
455
|
+
StylePanelFontPicker,
|
|
456
|
+
StylePanelGeoShapePicker,
|
|
457
|
+
StylePanelLabelAlignPicker,
|
|
458
|
+
StylePanelOpacityPicker,
|
|
459
|
+
StylePanelSection,
|
|
460
|
+
StylePanelSizePicker,
|
|
461
|
+
StylePanelSplinePicker,
|
|
462
|
+
StylePanelTextAlignPicker,
|
|
463
|
+
type StylePanelSectionProps,
|
|
461
464
|
} from './lib/ui/components/StylePanel/DefaultStylePanelContent'
|
|
465
|
+
export {
|
|
466
|
+
StylePanelButtonPicker,
|
|
467
|
+
type StylePanelButtonPickerProps,
|
|
468
|
+
} from './lib/ui/components/StylePanel/StylePanelButtonPicker'
|
|
469
|
+
export {
|
|
470
|
+
StylePanelContextProvider,
|
|
471
|
+
useStylePanelContext,
|
|
472
|
+
type StylePanelContext,
|
|
473
|
+
type StylePanelContextProviderProps,
|
|
474
|
+
} from './lib/ui/components/StylePanel/StylePanelContext'
|
|
475
|
+
export {
|
|
476
|
+
StylePanelDoubleDropdownPicker,
|
|
477
|
+
type StylePanelDoubleDropdownPickerProps,
|
|
478
|
+
} from './lib/ui/components/StylePanel/StylePanelDoubleDropdownPicker'
|
|
479
|
+
export {
|
|
480
|
+
StylePanelDropdownPicker,
|
|
481
|
+
type StylePanelDropdownPickerProps,
|
|
482
|
+
} from './lib/ui/components/StylePanel/StylePanelDropdownPicker'
|
|
483
|
+
export {
|
|
484
|
+
StylePanelSubheading,
|
|
485
|
+
type StylePanelSubheadingProps,
|
|
486
|
+
} from './lib/ui/components/StylePanel/StylePanelSubheading'
|
|
462
487
|
export {
|
|
463
488
|
DefaultImageToolbar,
|
|
464
489
|
type TLUiImageToolbarProps,
|
|
@@ -636,7 +661,6 @@ export { preloadFont, type TLTypeFace } from './lib/utils/assets/preload-font'
|
|
|
636
661
|
export { getEmbedInfo, type TLEmbedResult } from './lib/utils/embeds/embeds'
|
|
637
662
|
export { putExcalidrawContent } from './lib/utils/excalidraw/putExcalidrawContent'
|
|
638
663
|
export { copyAs, type CopyAsOptions, type TLCopyType } from './lib/utils/export/copyAs'
|
|
639
|
-
export { exportToBlob } from './lib/utils/export/export'
|
|
640
664
|
export { downloadFile, exportAs, type ExportAsOptions } from './lib/utils/export/exportAs'
|
|
641
665
|
export { fitFrameToContent, removeFrame } from './lib/utils/frames/frames'
|
|
642
666
|
export {
|
|
@@ -901,8 +901,22 @@ export function notifyIfFileNotAllowed(file: File, options: TLDefaultExternalCon
|
|
|
901
901
|
}
|
|
902
902
|
|
|
903
903
|
if (file.size > maxAssetSize) {
|
|
904
|
+
const formatBytes = (bytes: number): string => {
|
|
905
|
+
if (bytes === 0) return '0 bytes'
|
|
906
|
+
|
|
907
|
+
const units = ['bytes', 'KB', 'MB', 'GB', 'TB', 'PB']
|
|
908
|
+
const base = 1024
|
|
909
|
+
const unitIndex = Math.floor(Math.log(bytes) / Math.log(base))
|
|
910
|
+
|
|
911
|
+
const value = bytes / Math.pow(base, unitIndex)
|
|
912
|
+
const formatted = value % 1 === 0 ? value.toString() : value.toFixed(1)
|
|
913
|
+
|
|
914
|
+
return `${formatted} ${units[unitIndex]}`
|
|
915
|
+
}
|
|
916
|
+
|
|
904
917
|
toasts.addToast({
|
|
905
918
|
title: msg('assets.files.size-too-big'),
|
|
919
|
+
description: msg('assets.files.maximum-size').replace('{size}', formatBytes(maxAssetSize)),
|
|
906
920
|
severity: 'error',
|
|
907
921
|
})
|
|
908
922
|
return false
|
|
@@ -47,13 +47,21 @@ describe('ArrowShapeOptions', () => {
|
|
|
47
47
|
it('should have correct default shouldBeExact behavior (alt key)', () => {
|
|
48
48
|
const util = editor.getShapeUtil<ArrowShapeUtil>('arrow')
|
|
49
49
|
|
|
50
|
-
// Test without alt key
|
|
50
|
+
// Test without alt key, not precise
|
|
51
51
|
editor.inputs.altKey = false
|
|
52
|
-
expect(util.options.shouldBeExact(editor)).toBe(false)
|
|
52
|
+
expect(util.options.shouldBeExact(editor, false)).toBe(false)
|
|
53
53
|
|
|
54
|
-
// Test
|
|
54
|
+
// Test without alt key, precise
|
|
55
|
+
editor.inputs.altKey = false
|
|
56
|
+
expect(util.options.shouldBeExact(editor, true)).toBe(false)
|
|
57
|
+
|
|
58
|
+
// Test with alt key, not precise
|
|
59
|
+
editor.inputs.altKey = true
|
|
60
|
+
expect(util.options.shouldBeExact(editor, false)).toBe(true)
|
|
61
|
+
|
|
62
|
+
// Test with alt key, precise
|
|
55
63
|
editor.inputs.altKey = true
|
|
56
|
-
expect(util.options.shouldBeExact(editor)).toBe(true)
|
|
64
|
+
expect(util.options.shouldBeExact(editor, true)).toBe(true)
|
|
57
65
|
})
|
|
58
66
|
|
|
59
67
|
it('should have correct default shouldIgnoreTargets behavior (ctrl key)', () => {
|
|
@@ -186,7 +194,7 @@ describe('ArrowShapeOptions', () => {
|
|
|
186
194
|
class CustomArrowShapeUtil extends ArrowShapeUtil {
|
|
187
195
|
override options = {
|
|
188
196
|
...baseUtil.options,
|
|
189
|
-
shouldBeExact: (editor: any) => editor.inputs.shiftKey, // Use shift instead of alt
|
|
197
|
+
shouldBeExact: (editor: any, _isPrecise: boolean) => editor.inputs.shiftKey, // Use shift instead of alt
|
|
190
198
|
}
|
|
191
199
|
}
|
|
192
200
|
|
|
@@ -195,12 +203,14 @@ describe('ArrowShapeOptions', () => {
|
|
|
195
203
|
// Test with shift key
|
|
196
204
|
editor.inputs.shiftKey = true
|
|
197
205
|
editor.inputs.altKey = false
|
|
198
|
-
expect(customUtil.options.shouldBeExact(editor)).toBe(true)
|
|
206
|
+
expect(customUtil.options.shouldBeExact(editor, false)).toBe(true)
|
|
207
|
+
expect(customUtil.options.shouldBeExact(editor, true)).toBe(true)
|
|
199
208
|
|
|
200
209
|
// Test without shift key
|
|
201
210
|
editor.inputs.shiftKey = false
|
|
202
211
|
editor.inputs.altKey = true // Alt key should not matter for custom implementation
|
|
203
|
-
expect(customUtil.options.shouldBeExact(editor)).toBe(false)
|
|
212
|
+
expect(customUtil.options.shouldBeExact(editor, false)).toBe(false)
|
|
213
|
+
expect(customUtil.options.shouldBeExact(editor, true)).toBe(false)
|
|
204
214
|
})
|
|
205
215
|
|
|
206
216
|
it('should allow customizing shouldIgnoreTargets behavior', () => {
|
|
@@ -232,9 +242,9 @@ describe('ArrowShapeOptions', () => {
|
|
|
232
242
|
class CustomArrowShapeUtil extends ArrowShapeUtil {
|
|
233
243
|
override options = {
|
|
234
244
|
...baseUtil.options,
|
|
235
|
-
shouldBeExact: (editor: any) => {
|
|
236
|
-
// Custom logic: exact when both alt and shift are pressed
|
|
237
|
-
return editor.inputs.altKey && editor.inputs.shiftKey
|
|
245
|
+
shouldBeExact: (editor: any, isPrecise: boolean) => {
|
|
246
|
+
// Custom logic: exact when both alt and shift are pressed, and only if precise
|
|
247
|
+
return editor.inputs.altKey && editor.inputs.shiftKey && isPrecise
|
|
238
248
|
},
|
|
239
249
|
shouldIgnoreTargets: (editor: any) => {
|
|
240
250
|
// Custom logic: ignore targets when any modifier key is pressed
|
|
@@ -245,15 +255,20 @@ describe('ArrowShapeOptions', () => {
|
|
|
245
255
|
|
|
246
256
|
const customUtil = new CustomArrowShapeUtil(editor)
|
|
247
257
|
|
|
248
|
-
// Test shouldBeExact with both keys
|
|
258
|
+
// Test shouldBeExact with both keys and precise
|
|
249
259
|
editor.inputs.altKey = true
|
|
250
260
|
editor.inputs.shiftKey = true
|
|
251
|
-
expect(customUtil.options.shouldBeExact(editor)).toBe(true)
|
|
261
|
+
expect(customUtil.options.shouldBeExact(editor, true)).toBe(true)
|
|
262
|
+
|
|
263
|
+
// Test shouldBeExact with both keys but not precise
|
|
264
|
+
editor.inputs.altKey = true
|
|
265
|
+
editor.inputs.shiftKey = true
|
|
266
|
+
expect(customUtil.options.shouldBeExact(editor, false)).toBe(false)
|
|
252
267
|
|
|
253
268
|
// Test shouldBeExact with only one key
|
|
254
269
|
editor.inputs.altKey = true
|
|
255
270
|
editor.inputs.shiftKey = false
|
|
256
|
-
expect(customUtil.options.shouldBeExact(editor)).toBe(false)
|
|
271
|
+
expect(customUtil.options.shouldBeExact(editor, true)).toBe(false)
|
|
257
272
|
|
|
258
273
|
// Test shouldIgnoreTargets with any key
|
|
259
274
|
editor.inputs.altKey = false
|
|
@@ -283,6 +298,61 @@ describe('ArrowShapeOptions', () => {
|
|
|
283
298
|
expect(editor.getCurrentToolId()).toBe('arrow')
|
|
284
299
|
})
|
|
285
300
|
|
|
301
|
+
it('should allow custom shouldBeExact logic based on isPrecise - example from arrow precise-exact', () => {
|
|
302
|
+
// This replicates the logic from the arrows-precise-exact example
|
|
303
|
+
const baseUtil = editor.getShapeUtil<ArrowShapeUtil>('arrow')
|
|
304
|
+
class ExampleArrowShapeUtil extends ArrowShapeUtil {
|
|
305
|
+
override options = {
|
|
306
|
+
...baseUtil.options,
|
|
307
|
+
shouldBeExact: (_editor: any, isPrecise: boolean) => isPrecise,
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// Replace the util temporarily for testing
|
|
312
|
+
const customUtil = new ExampleArrowShapeUtil(editor)
|
|
313
|
+
const originalShouldBeExact = baseUtil.options.shouldBeExact
|
|
314
|
+
baseUtil.options.shouldBeExact = customUtil.options.shouldBeExact
|
|
315
|
+
|
|
316
|
+
try {
|
|
317
|
+
editor.setCurrentTool('arrow')
|
|
318
|
+
editor.inputs.ctrlKey = false // Allow binding
|
|
319
|
+
|
|
320
|
+
// Set up fast pointer velocity to ensure precise remains false
|
|
321
|
+
editor.inputs.pointerVelocity = { x: 2, y: 2, len: () => 2.8 } as any
|
|
322
|
+
|
|
323
|
+
const targetState = updateArrowTargetState({
|
|
324
|
+
editor,
|
|
325
|
+
pointInPageSpace: { x: 150, y: 150 },
|
|
326
|
+
arrow: undefined,
|
|
327
|
+
isPrecise: true, // Input precise
|
|
328
|
+
currentBinding: undefined,
|
|
329
|
+
oppositeBinding: undefined,
|
|
330
|
+
})
|
|
331
|
+
|
|
332
|
+
// With the custom logic, precise arrows should be exact
|
|
333
|
+
expect(targetState?.isExact).toBe(true)
|
|
334
|
+
expect(targetState?.isPrecise).toBe(true)
|
|
335
|
+
|
|
336
|
+
// Test with non-precise movement (and fast velocity to avoid auto-precise)
|
|
337
|
+
const nonPreciseTargetState = updateArrowTargetState({
|
|
338
|
+
editor,
|
|
339
|
+
pointInPageSpace: { x: 150, y: 150 },
|
|
340
|
+
arrow: undefined,
|
|
341
|
+
isPrecise: false, // Not precise
|
|
342
|
+
currentBinding: undefined,
|
|
343
|
+
oppositeBinding: undefined,
|
|
344
|
+
})
|
|
345
|
+
|
|
346
|
+
// Non-precise arrows should not be exact with this custom logic,
|
|
347
|
+
// but they might still become precise due to internal logic
|
|
348
|
+
// The key test is that shouldBeExact gets the final computed precise value
|
|
349
|
+
expect(nonPreciseTargetState).toBeDefined()
|
|
350
|
+
} finally {
|
|
351
|
+
// Restore original function
|
|
352
|
+
baseUtil.options.shouldBeExact = originalShouldBeExact
|
|
353
|
+
}
|
|
354
|
+
})
|
|
355
|
+
|
|
286
356
|
it('should respect shouldIgnoreTargets when starting arrow creation', () => {
|
|
287
357
|
editor.setCurrentTool('arrow')
|
|
288
358
|
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { IndexKey, TLArrowShape, TLShapeId, Vec, createShapeId } from '@tldraw/editor'
|
|
2
2
|
import { vi } from 'vitest'
|
|
3
3
|
import { TestEditor } from '../../../test/TestEditor'
|
|
4
|
+
import { defaultShapeUtils } from '../../defaultShapeUtils'
|
|
5
|
+
import { ArrowShapeUtil } from './ArrowShapeUtil'
|
|
4
6
|
import { getArrowTargetState } from './arrowTargetState'
|
|
5
7
|
import { getArrowBindings } from './shared'
|
|
6
8
|
|
|
@@ -26,8 +28,8 @@ function bindings(id: TLShapeId) {
|
|
|
26
28
|
return getArrowBindings(editor, editor.getShape(id) as TLArrowShape)
|
|
27
29
|
}
|
|
28
30
|
|
|
29
|
-
|
|
30
|
-
editor = new TestEditor()
|
|
31
|
+
function init(opts?: ConstructorParameters<typeof TestEditor>[0]) {
|
|
32
|
+
editor = new TestEditor(opts)
|
|
31
33
|
editor
|
|
32
34
|
.selectAll()
|
|
33
35
|
.deleteShapes(editor.getSelectedShapeIds())
|
|
@@ -36,7 +38,9 @@ beforeEach(() => {
|
|
|
36
38
|
{ id: ids.box2, type: 'geo', x: 300, y: 300, props: { w: 100, h: 100 } },
|
|
37
39
|
{ id: ids.box3, type: 'geo', x: 350, y: 350, props: { w: 50, h: 50 } }, // overlapping box2, but smaller!
|
|
38
40
|
])
|
|
39
|
-
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
beforeEach(init)
|
|
40
44
|
|
|
41
45
|
it('enters the arrow state', () => {
|
|
42
46
|
editor.setCurrentTool('arrow')
|
|
@@ -569,12 +573,102 @@ describe('reparenting issue', () => {
|
|
|
569
573
|
const arrow1BoundIndex = editor.getShape(arrow1Id)!.index
|
|
570
574
|
const arrow2BoundIndex = editor.getShape(arrow2Id)!.index
|
|
571
575
|
expect(arrow1BoundIndex).toBe('a1V')
|
|
572
|
-
expect(arrow2BoundIndex).toBe('
|
|
576
|
+
expect(arrow2BoundIndex).toBe('a1G')
|
|
573
577
|
|
|
574
578
|
// nudge everything around and make sure we all stay in the right order
|
|
575
579
|
editor.selectAll().nudgeShapes(editor.getSelectedShapeIds(), { x: -1, y: 0 })
|
|
576
580
|
expect(editor.getShape(arrow1Id)!.index).toBe('a1V')
|
|
577
|
-
expect(editor.getShape(arrow2Id)!.index).toBe('
|
|
581
|
+
expect(editor.getShape(arrow2Id)!.index).toBe('a1G')
|
|
582
|
+
})
|
|
583
|
+
})
|
|
584
|
+
|
|
585
|
+
describe('precision timeout configuration', () => {
|
|
586
|
+
it('uses a timeout when dragging arrow handles', () => {
|
|
587
|
+
// Create an arrow first
|
|
588
|
+
|
|
589
|
+
editor.setCurrentTool('arrow').pointerDown(0, 0)
|
|
590
|
+
// Use high velocity to avoid precise mode immediately
|
|
591
|
+
editor.inputs.pointerVelocity = new Vec(1, 1)
|
|
592
|
+
editor.pointerMove(100, 100)
|
|
593
|
+
|
|
594
|
+
const arrow = editor.getCurrentPageShapes()[
|
|
595
|
+
editor.getCurrentPageShapes().length - 1
|
|
596
|
+
] as TLArrowShape
|
|
597
|
+
|
|
598
|
+
editor.expectToBeIn('select.dragging_handle')
|
|
599
|
+
|
|
600
|
+
expect(bindings(arrow.id)).toMatchObject({
|
|
601
|
+
end: {
|
|
602
|
+
toId: ids.box1,
|
|
603
|
+
props: {
|
|
604
|
+
isPrecise: false,
|
|
605
|
+
},
|
|
606
|
+
},
|
|
607
|
+
})
|
|
608
|
+
|
|
609
|
+
vi.advanceTimersByTime(1000)
|
|
610
|
+
|
|
611
|
+
expect(bindings(arrow.id)).toMatchObject({
|
|
612
|
+
end: {
|
|
613
|
+
toId: ids.box1,
|
|
614
|
+
props: {
|
|
615
|
+
isPrecise: true,
|
|
616
|
+
},
|
|
617
|
+
},
|
|
618
|
+
})
|
|
619
|
+
})
|
|
620
|
+
|
|
621
|
+
it('allows configuring the pointingPreciseTimeout', () => {
|
|
622
|
+
init({
|
|
623
|
+
shapeUtils: [
|
|
624
|
+
...defaultShapeUtils.map((s) =>
|
|
625
|
+
s.type === 'arrow' ? ArrowShapeUtil.configure({ pointingPreciseTimeout: 2000 }) : s
|
|
626
|
+
),
|
|
627
|
+
],
|
|
628
|
+
})
|
|
629
|
+
// Create an arrow first
|
|
630
|
+
|
|
631
|
+
editor.setCurrentTool('arrow').pointerDown(0, 0)
|
|
632
|
+
// Use high velocity to avoid precise mode immediately
|
|
633
|
+
editor.inputs.pointerVelocity = new Vec(1, 1)
|
|
634
|
+
editor.pointerMove(100, 100)
|
|
635
|
+
|
|
636
|
+
const arrow = editor.getCurrentPageShapes()[
|
|
637
|
+
editor.getCurrentPageShapes().length - 1
|
|
638
|
+
] as TLArrowShape
|
|
639
|
+
|
|
640
|
+
editor.expectToBeIn('select.dragging_handle')
|
|
641
|
+
|
|
642
|
+
expect(bindings(arrow.id)).toMatchObject({
|
|
643
|
+
end: {
|
|
644
|
+
toId: ids.box1,
|
|
645
|
+
props: {
|
|
646
|
+
isPrecise: false,
|
|
647
|
+
},
|
|
648
|
+
},
|
|
649
|
+
})
|
|
650
|
+
|
|
651
|
+
vi.advanceTimersByTime(1000)
|
|
652
|
+
|
|
653
|
+
expect(bindings(arrow.id)).toMatchObject({
|
|
654
|
+
end: {
|
|
655
|
+
toId: ids.box1,
|
|
656
|
+
props: {
|
|
657
|
+
isPrecise: false,
|
|
658
|
+
},
|
|
659
|
+
},
|
|
660
|
+
})
|
|
661
|
+
|
|
662
|
+
vi.advanceTimersByTime(1000)
|
|
663
|
+
|
|
664
|
+
expect(bindings(arrow.id)).toMatchObject({
|
|
665
|
+
end: {
|
|
666
|
+
toId: ids.box1,
|
|
667
|
+
props: {
|
|
668
|
+
isPrecise: true,
|
|
669
|
+
},
|
|
670
|
+
},
|
|
671
|
+
})
|
|
578
672
|
})
|
|
579
673
|
})
|
|
580
674
|
|
|
@@ -579,3 +579,44 @@ describe("an arrow's parents", () => {
|
|
|
579
579
|
})
|
|
580
580
|
})
|
|
581
581
|
})
|
|
582
|
+
|
|
583
|
+
describe('Arrow export bounds', () => {
|
|
584
|
+
it('excludes labels from shape bounds for export', () => {
|
|
585
|
+
editor.selectAll().deleteShapes(editor.getSelectedShapeIds())
|
|
586
|
+
|
|
587
|
+
// Create shapes for the arrow to bind to
|
|
588
|
+
editor.createShapes([
|
|
589
|
+
{ id: ids.box1, type: 'geo', x: 100, y: 100, props: { w: 100, h: 100 } },
|
|
590
|
+
{ id: ids.box2, type: 'geo', x: 300, y: 100, props: { w: 100, h: 100 } },
|
|
591
|
+
])
|
|
592
|
+
|
|
593
|
+
// Create an arrow with a label
|
|
594
|
+
editor.createShapes([
|
|
595
|
+
{
|
|
596
|
+
id: ids.arrow1,
|
|
597
|
+
type: 'arrow',
|
|
598
|
+
x: 0,
|
|
599
|
+
y: 0,
|
|
600
|
+
props: {
|
|
601
|
+
start: { x: 0, y: 0 },
|
|
602
|
+
end: { x: 0, y: 100 },
|
|
603
|
+
richText: toRichText('Test Label'),
|
|
604
|
+
},
|
|
605
|
+
},
|
|
606
|
+
])
|
|
607
|
+
|
|
608
|
+
// Get the page bounds (should exclude labels due to excludeFromShapeBounds flag)
|
|
609
|
+
const pageBounds = editor.getShapePageBounds(ids.arrow1)
|
|
610
|
+
expect(pageBounds).toBeDefined()
|
|
611
|
+
|
|
612
|
+
// The bounds should be smaller than if labels were included
|
|
613
|
+
// Since the arrow has a label that's excluded, the bounds should be minimal
|
|
614
|
+
expect(pageBounds!.width).toBeLessThan(200) // Should not include label width
|
|
615
|
+
expect(pageBounds!.height).toBeLessThan(200) // Should not include label height
|
|
616
|
+
|
|
617
|
+
// Verify that the arrow has a label (which should be excluded from shape bounds)
|
|
618
|
+
const arrow = editor.getShape(ids.arrow1) as TLArrowShape
|
|
619
|
+
expect(arrow.props.richText).toBeDefined()
|
|
620
|
+
expect(arrow.props.richText).not.toBeNull()
|
|
621
|
+
})
|
|
622
|
+
})
|