tldraw 3.16.0-canary.7cd3b8a5bfd6 → 3.16.0-canary.7facbd2d2b7f
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 +315 -110
- package/dist-cjs/index.js +37 -14
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/Tldraw.js +12 -2
- package/dist-cjs/lib/Tldraw.js.map +2 -2
- package/dist-cjs/lib/defaultExternalContentHandlers.js +15 -4
- 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 +8 -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/image/ImageShapeUtil.js +3 -0
- package/dist-cjs/lib/shapes/image/ImageShapeUtil.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/freehand/svg.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/EraserTool/childStates/Erasing.js +25 -1
- package/dist-cjs/lib/tools/EraserTool/childStates/Erasing.js.map +2 -2
- package/dist-cjs/lib/tools/EraserTool/childStates/Pointing.js +12 -0
- package/dist-cjs/lib/tools/EraserTool/childStates/Pointing.js.map +2 -2
- package/dist-cjs/lib/tools/SelectTool/childStates/DraggingHandle.js +3 -1
- package/dist-cjs/lib/tools/SelectTool/childStates/DraggingHandle.js.map +2 -2
- package/dist-cjs/lib/ui/TldrawUi.js +13 -12
- package/dist-cjs/lib/ui/TldrawUi.js.map +2 -2
- package/dist-cjs/lib/ui/assetUrls.js +13 -10
- package/dist-cjs/lib/ui/assetUrls.js.map +2 -2
- package/dist-cjs/lib/ui/components/A11y.js +1 -1
- package/dist-cjs/lib/ui/components/A11y.js.map +2 -2
- package/dist-cjs/lib/ui/components/{FollowingIndicator.js → DefaultFollowingIndicator.js} +6 -6
- package/dist-cjs/lib/ui/components/DefaultFollowingIndicator.js.map +7 -0
- package/dist-cjs/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.js +6 -6
- package/dist-cjs/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.js.map +1 -1
- 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/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 +9 -4
- 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 +68 -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} +24 -21
- 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/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 +18 -5
- 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 -37
- 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 +10 -9
- package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js.map +2 -2
- package/dist-cjs/lib/ui/context/actions.js +29 -10
- package/dist-cjs/lib/ui/context/actions.js.map +2 -2
- package/dist-cjs/lib/ui/context/components.js +2 -0
- package/dist-cjs/lib/ui/context/components.js.map +2 -2
- package/dist-cjs/lib/ui/context/events.js.map +1 -1
- 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 +6 -2
- package/dist-cjs/lib/ui/hooks/useTranslation/defaultTranslation.js.map +2 -2
- package/dist-cjs/lib/ui/kbd-utils.js +9 -3
- package/dist-cjs/lib/ui/kbd-utils.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/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 +315 -110
- package/dist-esm/index.mjs +69 -29
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/Tldraw.mjs +14 -4
- package/dist-esm/lib/Tldraw.mjs.map +2 -2
- package/dist-esm/lib/defaultExternalContentHandlers.mjs +15 -4
- 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 +8 -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/image/ImageShapeUtil.mjs +3 -0
- package/dist-esm/lib/shapes/image/ImageShapeUtil.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/freehand/svg.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/EraserTool/childStates/Erasing.mjs +26 -1
- package/dist-esm/lib/tools/EraserTool/childStates/Erasing.mjs.map +2 -2
- package/dist-esm/lib/tools/EraserTool/childStates/Pointing.mjs +13 -0
- package/dist-esm/lib/tools/EraserTool/childStates/Pointing.mjs.map +2 -2
- package/dist-esm/lib/tools/SelectTool/childStates/DraggingHandle.mjs +3 -1
- package/dist-esm/lib/tools/SelectTool/childStates/DraggingHandle.mjs.map +2 -2
- package/dist-esm/lib/ui/TldrawUi.mjs +13 -12
- package/dist-esm/lib/ui/TldrawUi.mjs.map +2 -2
- package/dist-esm/lib/ui/assetUrls.mjs +13 -10
- package/dist-esm/lib/ui/assetUrls.mjs.map +2 -2
- package/dist-esm/lib/ui/components/A11y.mjs +1 -2
- package/dist-esm/lib/ui/components/A11y.mjs.map +2 -2
- package/dist-esm/lib/ui/components/{FollowingIndicator.mjs → DefaultFollowingIndicator.mjs} +3 -3
- package/dist-esm/lib/ui/components/DefaultFollowingIndicator.mjs.map +7 -0
- package/dist-esm/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.mjs +6 -6
- package/dist-esm/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.mjs.map +1 -1
- 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/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 +14 -5
- 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 +48 -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} +21 -18
- 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/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 +18 -5
- 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 -37
- 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 +10 -9
- package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs.map +2 -2
- package/dist-esm/lib/ui/context/actions.mjs +29 -10
- package/dist-esm/lib/ui/context/actions.mjs.map +2 -2
- package/dist-esm/lib/ui/context/components.mjs +2 -0
- package/dist-esm/lib/ui/context/components.mjs.map +2 -2
- package/dist-esm/lib/ui/context/events.mjs.map +1 -1
- 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 +6 -2
- package/dist-esm/lib/ui/hooks/useTranslation/defaultTranslation.mjs.map +2 -2
- package/dist-esm/lib/ui/kbd-utils.mjs +9 -3
- package/dist-esm/lib/ui/kbd-utils.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/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 +11 -34
- package/src/index.ts +51 -22
- package/src/lib/Tldraw.tsx +15 -2
- package/src/lib/defaultExternalContentHandlers.ts +26 -4
- package/src/lib/shapes/arrow/ArrowShapeOptions.test.ts +85 -14
- package/src/lib/shapes/arrow/ArrowShapeTool.test.ts +103 -8
- package/src/lib/shapes/arrow/ArrowShapeUtil.test.ts +48 -6
- 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/draw/DrawShapeTool.test.ts +0 -5
- package/src/lib/shapes/frame/FrameShapeUtil.tsx +9 -0
- package/src/lib/shapes/frame/components/FrameLabelInput.tsx +10 -3
- package/src/lib/shapes/geo/GeoShapeUtil.tsx +1 -0
- package/src/lib/shapes/image/ImageShapeUtil.tsx +3 -0
- package/src/lib/shapes/line/LineShapeUtil.test.tsx +4 -3
- package/src/lib/shapes/line/__snapshots__/LineShapeUtil.test.tsx.snap +2 -2
- 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/freehand/svg.ts +2 -0
- 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/shapes/text/TextShapeTool.test.ts +6 -5
- package/src/lib/tools/EraserTool/childStates/Erasing.ts +34 -1
- package/src/lib/tools/EraserTool/childStates/Pointing.ts +20 -0
- package/src/lib/tools/SelectTool/childStates/DraggingHandle.tsx +6 -2
- package/src/lib/ui/TldrawUi.tsx +16 -10
- package/src/lib/ui/assetUrls.ts +13 -10
- package/src/lib/ui/components/A11y.tsx +1 -2
- package/src/lib/ui/components/{FollowingIndicator.tsx → DefaultFollowingIndicator.tsx} +2 -1
- package/src/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.tsx +6 -6
- package/src/lib/ui/components/LanguageMenu.tsx +1 -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 +27 -13
- package/src/lib/ui/components/StylePanel/DefaultStylePanelContent.tsx +260 -381
- package/src/lib/ui/components/{primitives/TldrawUiButtonPicker.tsx → StylePanel/StylePanelButtonPicker.tsx} +70 -50
- package/src/lib/ui/components/StylePanel/StylePanelContext.tsx +63 -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/primitives/TldrawUiContextualToolbar.tsx +7 -3
- package/src/lib/ui/components/primitives/TldrawUiInput.tsx +6 -3
- package/src/lib/ui/components/primitives/TldrawUiSlider.tsx +52 -32
- package/src/lib/ui/components/primitives/TldrawUiToolbar.tsx +5 -1
- package/src/lib/ui/components/primitives/TldrawUiTooltip.tsx +82 -30
- package/src/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.tsx +4 -0
- package/src/lib/ui/components/primitives/menus/TldrawUiMenuItem.tsx +12 -11
- package/src/lib/ui/context/actions.tsx +36 -10
- package/src/lib/ui/context/components.tsx +3 -0
- package/src/lib/ui/context/events.tsx +1 -1
- 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 +4 -0
- package/src/lib/ui/hooks/useTranslation/defaultTranslation.ts +6 -2
- package/src/lib/ui/kbd-utils.ts +10 -3
- package/src/lib/ui/version.ts +3 -3
- package/src/lib/ui.css +43 -3
- package/src/lib/utils/excalidraw/__snapshots__/putExcalidrawContent.test.tsx.snap +5 -5
- 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/lib/utils/tldr/__snapshots__/buildFromV1Document.test.ts.snap +4 -4
- package/src/test/A11y.test.tsx +3 -2
- package/src/test/ClickManager.test.ts +7 -6
- package/src/test/Editor.test.tsx +20 -19
- package/src/test/EraserTool.test.ts +184 -13
- package/src/test/HandTool.test.ts +10 -9
- package/src/test/HighlightShape.test.ts +2 -1
- package/src/test/SelectTool.test.ts +3 -2
- package/src/test/TLUserPreferences.test.ts +4 -3
- package/src/test/TestEditor.ts +21 -17
- package/src/test/TldrawEditor.test.tsx +11 -10
- package/src/test/ZoomTool.test.ts +7 -6
- package/src/test/__snapshots__/drawing.test.ts.snap +2 -2
- package/src/test/__snapshots__/groups.test.tsx.snap +6 -6
- package/src/test/__snapshots__/resizing.test.ts.snap +2 -2
- package/src/test/arrows-megabus.test.tsx +5 -4
- package/src/test/bindings.test.tsx +24 -37
- package/src/test/bookmark-shapes.test.ts +1 -8
- package/src/test/commands/__snapshots__/getSvgString.test.ts.snap +23 -7
- package/src/test/commands/__snapshots__/packShapes.test.ts.snap +8 -8
- package/src/test/commands/__snapshots__/zoomToFit.test.ts.snap +2 -2
- package/src/test/commands/alignShapes.test.tsx +25 -24
- package/src/test/commands/animationSpeed.test.ts +2 -1
- package/src/test/commands/centerOnPoint.test.ts +3 -2
- package/src/test/commands/clipboard.test.ts +3 -2
- package/src/test/commands/createShapes.test.ts +2 -1
- package/src/test/commands/deleteShapes.test.ts +2 -1
- package/src/test/commands/distributeShapes.test.tsx +11 -10
- package/src/test/commands/getSvgString.test.ts +2 -1
- package/src/test/commands/packShapes.test.ts +5 -4
- package/src/test/commands/resizeShape.test.ts +2 -1
- package/src/test/commands/rotateShapes.test.ts +7 -6
- package/src/test/commands/setCamera.test.ts +4 -3
- package/src/test/commands/setCurrentPage.test.ts +3 -2
- package/src/test/commands/stackShapes.test.ts +11 -10
- package/src/test/commands/stretch.test.tsx +13 -12
- package/src/test/createDeepLink.test.tsx +2 -1
- package/src/test/cropping.test.ts +3 -2
- package/src/test/custom-clipping.test.ts +436 -0
- package/src/test/drawing.test.ts +2 -1
- package/src/test/flipShapes.test.ts +4 -3
- package/src/test/frames.test.ts +25 -24
- package/src/test/getCulledShapes.test.tsx +74 -4
- package/src/test/groups.test.tsx +1 -1
- package/src/test/handleDeepLink.test.tsx +2 -1
- package/src/test/maxShapes.test.ts +3 -2
- package/src/test/modifiers.test.ts +5 -4
- package/src/test/navigation.test.ts +12 -11
- package/src/test/panning.test.ts +2 -1
- package/src/test/perf/perf.test.ts +2 -1
- package/src/test/registerDeepLinkListener.test.tsx +10 -9
- package/src/test/resizing.test.ts +39 -38
- package/src/test/select.test.tsx +4 -3
- package/src/test/selection-omnibus.test.ts +11 -10
- package/src/test/shapeutils.test.ts +4 -3
- package/src/test/translating.test.ts +9 -8
- package/tldraw.css +59 -6
- package/dist-cjs/lib/ui/components/FollowingIndicator.js.map +0 -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/FollowingIndicator.mjs.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
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
import {
|
|
2
|
+
atom,
|
|
3
|
+
BaseBoxShapeUtil,
|
|
4
|
+
Circle2d,
|
|
5
|
+
createShapeId,
|
|
6
|
+
Geometry2d,
|
|
7
|
+
RecordProps,
|
|
8
|
+
resizeBox,
|
|
9
|
+
StateNode,
|
|
10
|
+
T,
|
|
11
|
+
TLBaseShape,
|
|
12
|
+
TLEventHandlers,
|
|
13
|
+
TLGeoShape,
|
|
14
|
+
TLResizeInfo,
|
|
15
|
+
TLShape,
|
|
16
|
+
TLTextShape,
|
|
17
|
+
toRichText,
|
|
18
|
+
Vec,
|
|
19
|
+
} from '@tldraw/editor'
|
|
20
|
+
import { TestEditor } from './TestEditor'
|
|
21
|
+
|
|
22
|
+
// Custom Circle Clip Shape Definition
|
|
23
|
+
export type CircleClipShape = TLBaseShape<
|
|
24
|
+
'circle-clip',
|
|
25
|
+
{
|
|
26
|
+
w: number
|
|
27
|
+
h: number
|
|
28
|
+
}
|
|
29
|
+
>
|
|
30
|
+
|
|
31
|
+
export const isClippingEnabled$ = atom('isClippingEnabled', true)
|
|
32
|
+
|
|
33
|
+
export class CircleClipShapeUtil extends BaseBoxShapeUtil<CircleClipShape> {
|
|
34
|
+
static override type = 'circle-clip' as const
|
|
35
|
+
static override props: RecordProps<CircleClipShape> = {
|
|
36
|
+
w: T.number,
|
|
37
|
+
h: T.number,
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
override canBind() {
|
|
41
|
+
return false
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
override canReceiveNewChildrenOfType(shape: TLShape) {
|
|
45
|
+
return !shape.isLocked
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
override getDefaultProps(): CircleClipShape['props'] {
|
|
49
|
+
return {
|
|
50
|
+
w: 200,
|
|
51
|
+
h: 200,
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
override getGeometry(shape: CircleClipShape): Geometry2d {
|
|
56
|
+
const radius = Math.min(shape.props.w, shape.props.h) / 2
|
|
57
|
+
return new Circle2d({
|
|
58
|
+
radius,
|
|
59
|
+
x: shape.props.w / 2 - radius,
|
|
60
|
+
y: shape.props.h / 2 - radius,
|
|
61
|
+
isFilled: true,
|
|
62
|
+
})
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
override getClipPath(shape: CircleClipShape): Vec[] | undefined {
|
|
66
|
+
// Generate a polygon approximation of the circle
|
|
67
|
+
const centerX = shape.props.w / 2
|
|
68
|
+
const centerY = shape.props.h / 2
|
|
69
|
+
const radius = Math.min(shape.props.w, shape.props.h) / 2
|
|
70
|
+
const segments = 48 // More segments = smoother circle
|
|
71
|
+
|
|
72
|
+
const points: Vec[] = []
|
|
73
|
+
for (let i = 0; i < segments; i++) {
|
|
74
|
+
const angle = (i / segments) * Math.PI * 2
|
|
75
|
+
const x = centerX + Math.cos(angle) * radius
|
|
76
|
+
const y = centerY + Math.sin(angle) * radius
|
|
77
|
+
points.push(new Vec(x, y))
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return points
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
override shouldClipChild(_child: TLShape): boolean {
|
|
84
|
+
// For now, clip all children - we removed the onlyClipText feature for simplicity
|
|
85
|
+
return isClippingEnabled$.get()
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
override component(_shape: CircleClipShape) {
|
|
89
|
+
// For testing purposes, we'll just return null
|
|
90
|
+
// In a real implementation, this would return JSX
|
|
91
|
+
return null as any
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
override indicator(_shape: CircleClipShape) {
|
|
95
|
+
// For testing purposes, we'll just return null
|
|
96
|
+
// In a real implementation, this would return JSX
|
|
97
|
+
return null as any
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
override onResize(shape: CircleClipShape, info: TLResizeInfo<CircleClipShape>) {
|
|
101
|
+
return resizeBox(shape, info)
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export class CircleClipShapeTool extends StateNode {
|
|
106
|
+
static override id = 'circle-clip'
|
|
107
|
+
|
|
108
|
+
override onEnter(): void {
|
|
109
|
+
this.editor.setCursor({ type: 'cross', rotation: 0 })
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
override onPointerDown(info: Parameters<TLEventHandlers['onPointerDown']>[0]) {
|
|
113
|
+
if (info.target === 'canvas') {
|
|
114
|
+
const { originPagePoint } = this.editor.inputs
|
|
115
|
+
|
|
116
|
+
this.editor.createShape<CircleClipShape>({
|
|
117
|
+
type: 'circle-clip',
|
|
118
|
+
x: originPagePoint.x - 100,
|
|
119
|
+
y: originPagePoint.y - 100,
|
|
120
|
+
props: {
|
|
121
|
+
w: 200,
|
|
122
|
+
h: 200,
|
|
123
|
+
},
|
|
124
|
+
})
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
let editor: TestEditor
|
|
130
|
+
|
|
131
|
+
afterEach(() => {
|
|
132
|
+
editor?.dispose()
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
const ids = {
|
|
136
|
+
circleClip1: createShapeId('circleClip1'),
|
|
137
|
+
circleClip2: createShapeId('circleClip2'),
|
|
138
|
+
text1: createShapeId('text1'),
|
|
139
|
+
geo1: createShapeId('geo1'),
|
|
140
|
+
geo2: createShapeId('geo2'),
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
beforeEach(() => {
|
|
144
|
+
editor = new TestEditor({
|
|
145
|
+
shapeUtils: [CircleClipShapeUtil],
|
|
146
|
+
tools: [CircleClipShapeTool],
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
// Reset clipping state
|
|
150
|
+
isClippingEnabled$.set(true)
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
describe('CircleClipShapeUtil', () => {
|
|
154
|
+
describe('shape creation and properties', () => {
|
|
155
|
+
it('should create a circle clip shape with default properties', () => {
|
|
156
|
+
editor.createShape<CircleClipShape>({
|
|
157
|
+
id: ids.circleClip1,
|
|
158
|
+
type: 'circle-clip',
|
|
159
|
+
x: 100,
|
|
160
|
+
y: 100,
|
|
161
|
+
props: {
|
|
162
|
+
w: 200,
|
|
163
|
+
h: 200,
|
|
164
|
+
},
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
const shape = editor.getShape<CircleClipShape>(ids.circleClip1)
|
|
168
|
+
expect(shape).toBeDefined()
|
|
169
|
+
expect(shape!.type).toBe('circle-clip')
|
|
170
|
+
expect(shape!.props.w).toBe(200)
|
|
171
|
+
expect(shape!.props.h).toBe(200)
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
it('should use default props when not specified', () => {
|
|
175
|
+
editor.createShape<CircleClipShape>({
|
|
176
|
+
id: ids.circleClip1,
|
|
177
|
+
type: 'circle-clip',
|
|
178
|
+
x: 100,
|
|
179
|
+
y: 100,
|
|
180
|
+
props: {},
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
const shape = editor.getShape<CircleClipShape>(ids.circleClip1)
|
|
184
|
+
expect(shape!.props.w).toBe(200) // default from getDefaultProps
|
|
185
|
+
expect(shape!.props.h).toBe(200) // default from getDefaultProps
|
|
186
|
+
})
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
describe('geometry and clipping', () => {
|
|
190
|
+
it('should generate correct circle geometry', () => {
|
|
191
|
+
editor.createShape<CircleClipShape>({
|
|
192
|
+
id: ids.circleClip1,
|
|
193
|
+
type: 'circle-clip',
|
|
194
|
+
x: 100,
|
|
195
|
+
y: 100,
|
|
196
|
+
props: {
|
|
197
|
+
w: 200,
|
|
198
|
+
h: 200,
|
|
199
|
+
},
|
|
200
|
+
})
|
|
201
|
+
|
|
202
|
+
const shape = editor.getShape<CircleClipShape>(ids.circleClip1)
|
|
203
|
+
const util = editor.getShapeUtil<CircleClipShape>('circle-clip')
|
|
204
|
+
const geometry = util.getGeometry(shape!)
|
|
205
|
+
|
|
206
|
+
expect(geometry).toBeDefined()
|
|
207
|
+
expect(geometry.bounds).toBeDefined()
|
|
208
|
+
expect(geometry.bounds.width).toBe(200)
|
|
209
|
+
expect(geometry.bounds.height).toBe(200)
|
|
210
|
+
})
|
|
211
|
+
|
|
212
|
+
it('should generate clip path for circle', () => {
|
|
213
|
+
editor.createShape<CircleClipShape>({
|
|
214
|
+
id: ids.circleClip1,
|
|
215
|
+
type: 'circle-clip',
|
|
216
|
+
x: 100,
|
|
217
|
+
y: 100,
|
|
218
|
+
props: {
|
|
219
|
+
w: 200,
|
|
220
|
+
h: 200,
|
|
221
|
+
},
|
|
222
|
+
})
|
|
223
|
+
|
|
224
|
+
const shape = editor.getShape<CircleClipShape>(ids.circleClip1)
|
|
225
|
+
const util = editor.getShapeUtil<CircleClipShape>('circle-clip')
|
|
226
|
+
const clipPath = util.getClipPath?.(shape!)
|
|
227
|
+
if (!clipPath) throw new Error('Clip path is undefined')
|
|
228
|
+
|
|
229
|
+
expect(clipPath).toBeDefined()
|
|
230
|
+
expect(Array.isArray(clipPath)).toBe(true)
|
|
231
|
+
expect(clipPath.length).toBeGreaterThan(0)
|
|
232
|
+
|
|
233
|
+
// Should be a polygon approximation of a circle
|
|
234
|
+
// Check that points are roughly in a circle pattern
|
|
235
|
+
const centerX = 100 // shape.x
|
|
236
|
+
const centerY = 100 // shape.y
|
|
237
|
+
const radius = 100 // min(w, h) / 2
|
|
238
|
+
|
|
239
|
+
clipPath.forEach((point) => {
|
|
240
|
+
const distance = Math.sqrt(Math.pow(point.x - centerX, 2) + Math.pow(point.y - centerY, 2))
|
|
241
|
+
expect(distance).toBeCloseTo(radius, 0)
|
|
242
|
+
})
|
|
243
|
+
})
|
|
244
|
+
})
|
|
245
|
+
|
|
246
|
+
describe('child clipping behavior', () => {
|
|
247
|
+
it('should clip children when clipping is enabled', () => {
|
|
248
|
+
editor.createShape<CircleClipShape>({
|
|
249
|
+
id: ids.circleClip1,
|
|
250
|
+
type: 'circle-clip',
|
|
251
|
+
x: 100,
|
|
252
|
+
y: 100,
|
|
253
|
+
props: {
|
|
254
|
+
w: 200,
|
|
255
|
+
h: 200,
|
|
256
|
+
},
|
|
257
|
+
})
|
|
258
|
+
|
|
259
|
+
editor.createShape<TLTextShape>({
|
|
260
|
+
id: ids.text1,
|
|
261
|
+
type: 'text',
|
|
262
|
+
x: 0,
|
|
263
|
+
y: 0,
|
|
264
|
+
parentId: ids.circleClip1,
|
|
265
|
+
props: {
|
|
266
|
+
richText: toRichText('Test text'),
|
|
267
|
+
},
|
|
268
|
+
})
|
|
269
|
+
|
|
270
|
+
const util = editor.getShapeUtil<CircleClipShape>('circle-clip')
|
|
271
|
+
const textShape = editor.getShape<TLTextShape>(ids.text1)
|
|
272
|
+
|
|
273
|
+
// Clipping should be enabled by default
|
|
274
|
+
expect(isClippingEnabled$.get()).toBe(true)
|
|
275
|
+
expect(util.shouldClipChild?.(textShape!)).toBe(true)
|
|
276
|
+
expect(editor.getShapeClipPath(ids.text1)).toBeDefined()
|
|
277
|
+
})
|
|
278
|
+
|
|
279
|
+
it('should not clip children when clipping is disabled', () => {
|
|
280
|
+
isClippingEnabled$.set(false)
|
|
281
|
+
|
|
282
|
+
editor.createShape<CircleClipShape>({
|
|
283
|
+
id: ids.circleClip1,
|
|
284
|
+
type: 'circle-clip',
|
|
285
|
+
x: 100,
|
|
286
|
+
y: 100,
|
|
287
|
+
props: {
|
|
288
|
+
w: 200,
|
|
289
|
+
h: 200,
|
|
290
|
+
},
|
|
291
|
+
})
|
|
292
|
+
|
|
293
|
+
editor.createShape<TLTextShape>({
|
|
294
|
+
id: ids.text1,
|
|
295
|
+
type: 'text',
|
|
296
|
+
x: 0,
|
|
297
|
+
y: 0,
|
|
298
|
+
parentId: ids.circleClip1,
|
|
299
|
+
props: {
|
|
300
|
+
richText: toRichText('Test text'),
|
|
301
|
+
},
|
|
302
|
+
})
|
|
303
|
+
|
|
304
|
+
const util = editor.getShapeUtil<CircleClipShape>('circle-clip')
|
|
305
|
+
const textShape = editor.getShape<TLTextShape>(ids.text1)
|
|
306
|
+
|
|
307
|
+
expect(isClippingEnabled$.get()).toBe(false)
|
|
308
|
+
expect(util.shouldClipChild?.(textShape!)).toBe(false)
|
|
309
|
+
expect(editor.getShapeClipPath(ids.text1)).toBeUndefined()
|
|
310
|
+
})
|
|
311
|
+
})
|
|
312
|
+
})
|
|
313
|
+
|
|
314
|
+
describe('Integration tests', () => {
|
|
315
|
+
it('should create and manage circle clip shapes with children', () => {
|
|
316
|
+
// Create circle clip shape
|
|
317
|
+
editor.createShape<CircleClipShape>({
|
|
318
|
+
id: ids.circleClip1,
|
|
319
|
+
type: 'circle-clip',
|
|
320
|
+
x: 100,
|
|
321
|
+
y: 100,
|
|
322
|
+
props: {
|
|
323
|
+
w: 200,
|
|
324
|
+
h: 200,
|
|
325
|
+
},
|
|
326
|
+
})
|
|
327
|
+
|
|
328
|
+
// Add text child
|
|
329
|
+
editor.createShape<TLTextShape>({
|
|
330
|
+
id: ids.text1,
|
|
331
|
+
type: 'text',
|
|
332
|
+
x: 50,
|
|
333
|
+
y: 50,
|
|
334
|
+
parentId: ids.circleClip1,
|
|
335
|
+
props: {
|
|
336
|
+
richText: toRichText('Clipped text'),
|
|
337
|
+
},
|
|
338
|
+
})
|
|
339
|
+
|
|
340
|
+
// Add geo child
|
|
341
|
+
editor.createShape<TLGeoShape>({
|
|
342
|
+
id: ids.geo1,
|
|
343
|
+
type: 'geo',
|
|
344
|
+
x: 150,
|
|
345
|
+
y: 150,
|
|
346
|
+
parentId: ids.circleClip1,
|
|
347
|
+
props: {
|
|
348
|
+
w: 50,
|
|
349
|
+
h: 50,
|
|
350
|
+
},
|
|
351
|
+
})
|
|
352
|
+
|
|
353
|
+
const circleClipShape = editor.getShape<CircleClipShape>(ids.circleClip1)
|
|
354
|
+
const textShape = editor.getShape<TLTextShape>(ids.text1)
|
|
355
|
+
const geoShape = editor.getShape<TLGeoShape>(ids.geo1)
|
|
356
|
+
|
|
357
|
+
expect(circleClipShape).toBeDefined()
|
|
358
|
+
expect(textShape!.parentId).toBe(ids.circleClip1)
|
|
359
|
+
expect(geoShape!.parentId).toBe(ids.circleClip1)
|
|
360
|
+
|
|
361
|
+
// Verify clipping behavior
|
|
362
|
+
const util = editor.getShapeUtil<CircleClipShape>('circle-clip')
|
|
363
|
+
expect(util.shouldClipChild?.(textShape!)).toBe(true)
|
|
364
|
+
expect(util.shouldClipChild?.(geoShape!)).toBe(true)
|
|
365
|
+
expect(editor.getShapeClipPath(ids.text1)).toBeDefined()
|
|
366
|
+
expect(editor.getShapeClipPath(ids.geo1)).toBeDefined()
|
|
367
|
+
|
|
368
|
+
// Test clipping toggle
|
|
369
|
+
isClippingEnabled$.set(false)
|
|
370
|
+
expect(util.shouldClipChild?.(textShape!)).toBe(false)
|
|
371
|
+
expect(util.shouldClipChild?.(geoShape!)).toBe(false)
|
|
372
|
+
expect(editor.getShapeClipPath(ids.text1)).toBeUndefined()
|
|
373
|
+
expect(editor.getShapeClipPath(ids.geo1)).toBeUndefined()
|
|
374
|
+
})
|
|
375
|
+
|
|
376
|
+
it('should handle multiple circle clip shapes independently', () => {
|
|
377
|
+
// Create two circle clip shapes
|
|
378
|
+
editor.createShape<CircleClipShape>({
|
|
379
|
+
id: ids.circleClip1,
|
|
380
|
+
type: 'circle-clip',
|
|
381
|
+
x: 100,
|
|
382
|
+
y: 100,
|
|
383
|
+
props: {
|
|
384
|
+
w: 200,
|
|
385
|
+
h: 200,
|
|
386
|
+
},
|
|
387
|
+
})
|
|
388
|
+
|
|
389
|
+
editor.createShape<CircleClipShape>({
|
|
390
|
+
id: ids.circleClip2,
|
|
391
|
+
type: 'circle-clip',
|
|
392
|
+
x: 400,
|
|
393
|
+
y: 100,
|
|
394
|
+
props: {
|
|
395
|
+
w: 150,
|
|
396
|
+
h: 150,
|
|
397
|
+
},
|
|
398
|
+
})
|
|
399
|
+
|
|
400
|
+
// Add children to both
|
|
401
|
+
editor.createShape<TLTextShape>({
|
|
402
|
+
id: ids.text1,
|
|
403
|
+
type: 'text',
|
|
404
|
+
x: 0,
|
|
405
|
+
y: 0,
|
|
406
|
+
parentId: ids.circleClip1,
|
|
407
|
+
props: {
|
|
408
|
+
richText: toRichText('First clip'),
|
|
409
|
+
},
|
|
410
|
+
})
|
|
411
|
+
|
|
412
|
+
editor.createShape<TLTextShape>({
|
|
413
|
+
id: ids.geo1,
|
|
414
|
+
type: 'text',
|
|
415
|
+
x: 0,
|
|
416
|
+
y: 0,
|
|
417
|
+
parentId: ids.circleClip2,
|
|
418
|
+
props: {
|
|
419
|
+
richText: toRichText('Second clip'),
|
|
420
|
+
},
|
|
421
|
+
})
|
|
422
|
+
|
|
423
|
+
const util = editor.getShapeUtil<CircleClipShape>('circle-clip')
|
|
424
|
+
const text1 = editor.getShape<TLTextShape>(ids.text1)
|
|
425
|
+
const text2 = editor.getShape<TLTextShape>(ids.geo1)
|
|
426
|
+
|
|
427
|
+
// Both should be clipped when enabled
|
|
428
|
+
expect(util.shouldClipChild?.(text1!)).toBe(true)
|
|
429
|
+
expect(util.shouldClipChild?.(text2!)).toBe(true)
|
|
430
|
+
|
|
431
|
+
// Both should not be clipped when disabled
|
|
432
|
+
isClippingEnabled$.set(false)
|
|
433
|
+
expect(util.shouldClipChild?.(text1!)).toBe(false)
|
|
434
|
+
expect(util.shouldClipChild?.(text2!)).toBe(false)
|
|
435
|
+
})
|
|
436
|
+
})
|
package/src/test/drawing.test.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { TLDrawShape, TLHighlightShape, last } from '@tldraw/editor'
|
|
2
|
+
import { vi } from 'vitest'
|
|
2
3
|
import { TestEditor } from './TestEditor'
|
|
3
4
|
import { TEST_DRAW_SHAPE_SCREEN_POINTS } from './drawing.data'
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
vi.useFakeTimers()
|
|
6
7
|
|
|
7
8
|
let editor: TestEditor
|
|
8
9
|
|
|
@@ -10,12 +10,13 @@ import {
|
|
|
10
10
|
createBindingId,
|
|
11
11
|
createShapeId,
|
|
12
12
|
} from '@tldraw/editor'
|
|
13
|
+
import { vi } from 'vitest'
|
|
13
14
|
import { getArrowBindings } from '../lib/shapes/arrow/shared'
|
|
14
15
|
import { TestEditor } from './TestEditor'
|
|
15
16
|
|
|
16
17
|
let editor: TestEditor
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
vi.useFakeTimers()
|
|
19
20
|
|
|
20
21
|
const ids = {
|
|
21
22
|
boxA: createShapeId('boxA'),
|
|
@@ -297,7 +298,7 @@ describe('When one shape is selected', () => {
|
|
|
297
298
|
})
|
|
298
299
|
|
|
299
300
|
it('Flips the direct child shape positions if the shape is a group', async () => {
|
|
300
|
-
const fn =
|
|
301
|
+
const fn = vi.fn()
|
|
301
302
|
|
|
302
303
|
editor.selectAll()
|
|
303
304
|
editor.groupShapes(editor.getSelectedShapeIds()) // this will also select the new group
|
|
@@ -306,7 +307,7 @@ describe('When one shape is selected', () => {
|
|
|
306
307
|
editor.flipShapes(editor.getSelectedShapeIds(), 'horizontal')
|
|
307
308
|
|
|
308
309
|
// The change event should have been called
|
|
309
|
-
|
|
310
|
+
vi.runOnlyPendingTimers()
|
|
310
311
|
expect(fn).toHaveBeenCalled()
|
|
311
312
|
|
|
312
313
|
editor.expectShapeToMatch(
|
package/src/test/frames.test.ts
CHANGED
|
@@ -8,13 +8,14 @@ import {
|
|
|
8
8
|
createShapeId,
|
|
9
9
|
toRichText,
|
|
10
10
|
} from '@tldraw/editor'
|
|
11
|
+
import { vi } from 'vitest'
|
|
11
12
|
import { getArrowBindings } from '../lib/shapes/arrow/shared'
|
|
12
13
|
import { DEFAULT_FRAME_PADDING, fitFrameToContent, removeFrame } from '../lib/utils/frames/frames'
|
|
13
14
|
import { TestEditor } from './TestEditor'
|
|
14
15
|
|
|
15
16
|
let editor: TestEditor
|
|
16
17
|
|
|
17
|
-
|
|
18
|
+
vi.useFakeTimers()
|
|
18
19
|
|
|
19
20
|
beforeEach(() => {
|
|
20
21
|
editor = new TestEditor()
|
|
@@ -335,7 +336,7 @@ describe('frame shapes', () => {
|
|
|
335
336
|
// move to the center of the frame
|
|
336
337
|
editor.pointerMove(100, 100)
|
|
337
338
|
|
|
338
|
-
|
|
339
|
+
vi.advanceTimersByTime(300)
|
|
339
340
|
|
|
340
341
|
// Expect the shape to be inside the frame
|
|
341
342
|
expect(editor.getOnlySelectedShape()!.id).toBe(ids.boxA)
|
|
@@ -343,13 +344,13 @@ describe('frame shapes', () => {
|
|
|
343
344
|
|
|
344
345
|
// Move out of the frame
|
|
345
346
|
editor.pointerMove(275, 275)
|
|
346
|
-
|
|
347
|
+
vi.advanceTimersByTime(250)
|
|
347
348
|
|
|
348
349
|
expect(editor.getOnlySelectedShape()!.parentId).toBe(editor.getCurrentPageId())
|
|
349
350
|
|
|
350
351
|
// Move back into the frame
|
|
351
352
|
editor.pointerMove(150, 150)
|
|
352
|
-
|
|
353
|
+
vi.advanceTimersByTime(250)
|
|
353
354
|
|
|
354
355
|
// Expect the shape to be inside the frame again
|
|
355
356
|
expect(editor.getOnlySelectedShape()!.parentId).toBe(frameId)
|
|
@@ -384,7 +385,7 @@ describe('frame shapes', () => {
|
|
|
384
385
|
|
|
385
386
|
editor.setCurrentTool('select').select(box1.id).pointerDown(127, 127).pointerMove(132, 127)
|
|
386
387
|
|
|
387
|
-
|
|
388
|
+
vi.advanceTimersByTime(250)
|
|
388
389
|
|
|
389
390
|
expect(editor.getOnlySelectedShape()!.id).toBe(box1.id)
|
|
390
391
|
if (editor.getShape(box1)?.parentId !== frame.id) {
|
|
@@ -403,14 +404,14 @@ describe('frame shapes', () => {
|
|
|
403
404
|
editor.pointerMove(175, 175)
|
|
404
405
|
expect(editor.getOnlySelectedShape()!.parentId).toBe(frame.id)
|
|
405
406
|
|
|
406
|
-
|
|
407
|
+
vi.advanceTimersByTime(250)
|
|
407
408
|
expect(editor.getOnlySelectedShape()!.parentId).toBe(frame.id)
|
|
408
409
|
|
|
409
410
|
// Let's try that
|
|
410
411
|
editor.pointerMove(1750, 1750)
|
|
411
|
-
|
|
412
|
+
vi.advanceTimersByTime(200)
|
|
412
413
|
editor.pointerMove(175, 175)
|
|
413
|
-
|
|
414
|
+
vi.advanceTimersByTime(200)
|
|
414
415
|
|
|
415
416
|
// yay
|
|
416
417
|
expect(editor.getHintingShapeIds()).toHaveLength(1)
|
|
@@ -958,7 +959,7 @@ describe('When dragging a shape inside a group inside a frame', () => {
|
|
|
958
959
|
editor.pointerMove(150, 150).pointerDown(150, 150).pointerMove(140, 140)
|
|
959
960
|
|
|
960
961
|
expect(editor.getOnlySelectedShapeId()).toBe(ids.box1)
|
|
961
|
-
|
|
962
|
+
vi.advanceTimersByTime(300)
|
|
962
963
|
|
|
963
964
|
expect(editor.getShape(ids.box1)!.parentId).toBe(ids.group1)
|
|
964
965
|
})
|
|
@@ -973,7 +974,7 @@ it('Drags into a frame', () => {
|
|
|
973
974
|
editor.pointerDown(550, 550)
|
|
974
975
|
editor.pointerMove(250, 250)
|
|
975
976
|
|
|
976
|
-
|
|
977
|
+
vi.advanceTimersByTime(200)
|
|
977
978
|
|
|
978
979
|
expect(editor.getShape(box1)!.parentId).toBe(frame.id)
|
|
979
980
|
})
|
|
@@ -992,7 +993,7 @@ it('Allows dragging grouped shapes into frames if every shape in the group is in
|
|
|
992
993
|
editor.pointerDown(1100, 1100)
|
|
993
994
|
editor.pointerMove(250, 250)
|
|
994
995
|
|
|
995
|
-
|
|
996
|
+
vi.advanceTimersByTime(250)
|
|
996
997
|
|
|
997
998
|
expect(editor.getHintingShapeIds()).toMatchObject([frame.id])
|
|
998
999
|
|
|
@@ -1068,7 +1069,7 @@ describe('When dragging a shape', () => {
|
|
|
1068
1069
|
editor.pointerMove(30, 50)
|
|
1069
1070
|
editor.pointerUp(30, 50)
|
|
1070
1071
|
const parent = editor.getShape(rectId)?.parentId
|
|
1071
|
-
|
|
1072
|
+
vi.advanceTimersByTime(200)
|
|
1072
1073
|
expect(parent).toBe(frameId)
|
|
1073
1074
|
})
|
|
1074
1075
|
|
|
@@ -1185,7 +1186,7 @@ describe('Unparenting behavior', () => {
|
|
|
1185
1186
|
// expect(editor.getShape(rect.id)!.parentId).toBe(frame.id)
|
|
1186
1187
|
// editor.pointerDown(90, 50)
|
|
1187
1188
|
// editor.pointerMove(110, 50)
|
|
1188
|
-
//
|
|
1189
|
+
// vi.advanceTimersByTime(200)
|
|
1189
1190
|
// expect(editor.getShape(rect.id)!.parentId).toBe(editor.getCurrentPageId())
|
|
1190
1191
|
// editor.pointerUp(110, 50)
|
|
1191
1192
|
// expect(editor.getShape(rect.id)!.parentId).toBe(editor.getCurrentPageId())
|
|
@@ -1199,7 +1200,7 @@ describe('Unparenting behavior', () => {
|
|
|
1199
1200
|
expect(editor.getShape(rect.id)!.parentId).toBe(frame.id)
|
|
1200
1201
|
editor.pointerDown(90, 50)
|
|
1201
1202
|
editor.pointerMove(110, 50)
|
|
1202
|
-
|
|
1203
|
+
vi.advanceTimersByTime(200)
|
|
1203
1204
|
expect(editor.getShape(rect.id)!.parentId).toBe(editor.getCurrentPageId())
|
|
1204
1205
|
editor.pointerUp(110, 50)
|
|
1205
1206
|
expect(editor.getShape(rect.id)!.parentId).toBe(editor.getCurrentPageId())
|
|
@@ -1299,7 +1300,7 @@ describe('Unparenting behavior', () => {
|
|
|
1299
1300
|
expect(editor.getShape(triangle.id)!.parentId).toBe(frame.id)
|
|
1300
1301
|
|
|
1301
1302
|
// But after a delay, the triangle is reparented because it's not overlapping
|
|
1302
|
-
|
|
1303
|
+
vi.advanceTimersByTime(200)
|
|
1303
1304
|
expect(editor.getShape(triangle.id)!.parentId).toBe(editor.getCurrentPageId())
|
|
1304
1305
|
|
|
1305
1306
|
editor.pointerMove(50, 50)
|
|
@@ -1308,7 +1309,7 @@ describe('Unparenting behavior', () => {
|
|
|
1308
1309
|
expect(editor.getShape(triangle.id)!.parentId).toBe(editor.getCurrentPageId())
|
|
1309
1310
|
|
|
1310
1311
|
// But after a delay, the triangle is reparented because it's overlapping
|
|
1311
|
-
|
|
1312
|
+
vi.advanceTimersByTime(200)
|
|
1312
1313
|
expect(editor.getShape(triangle.id)!.parentId).toBe(frame.id)
|
|
1313
1314
|
})
|
|
1314
1315
|
|
|
@@ -1348,12 +1349,12 @@ describe('Unparenting behavior', () => {
|
|
|
1348
1349
|
expect(editor.isIn('select.translating')).toBe(true)
|
|
1349
1350
|
|
|
1350
1351
|
// Wait for reparenting to happen
|
|
1351
|
-
|
|
1352
|
+
vi.advanceTimersByTime(250)
|
|
1352
1353
|
expect(editor.getShape(largeRect.id)!.parentId).toBe(frameId)
|
|
1353
1354
|
|
|
1354
1355
|
// The large rectangle should now be reparented to the frame, even though the frame covers it
|
|
1355
1356
|
editor.pointerUp(250, 250)
|
|
1356
|
-
|
|
1357
|
+
vi.advanceTimersByTime(250)
|
|
1357
1358
|
}
|
|
1358
1359
|
|
|
1359
1360
|
// When the shape has no fill and an empty label, it should fall out of the frame
|
|
@@ -1503,7 +1504,7 @@ describe('When dragging groups or shapes within a group', () => {
|
|
|
1503
1504
|
editor.pointerDown(1100, 1100)
|
|
1504
1505
|
editor.pointerMove(250, 250)
|
|
1505
1506
|
|
|
1506
|
-
|
|
1507
|
+
vi.advanceTimersByTime(200)
|
|
1507
1508
|
|
|
1508
1509
|
expect(editor.getShape(group)!.parentId).toBe(frame.id)
|
|
1509
1510
|
})
|
|
@@ -1526,14 +1527,14 @@ describe('When dragging groups or shapes within a group', () => {
|
|
|
1526
1527
|
editor.select(rect1ID)
|
|
1527
1528
|
editor.pointerDown(15, 15)
|
|
1528
1529
|
editor.pointerMove(100, 100)
|
|
1529
|
-
|
|
1530
|
+
vi.advanceTimersByTime(200)
|
|
1530
1531
|
|
|
1531
1532
|
expect(editor.getShape(rect1ID)?.parentId).toBe(group.id)
|
|
1532
1533
|
expect(editor.getShape(rect2ID)?.parentId).toBe(group.id)
|
|
1533
1534
|
expect(group.parentId).toBe(frame.id)
|
|
1534
1535
|
|
|
1535
1536
|
editor.pointerUp(100, 100)
|
|
1536
|
-
|
|
1537
|
+
vi.advanceTimersByTime(200)
|
|
1537
1538
|
|
|
1538
1539
|
expect(editor.getShape(rect1ID)?.parentId).toBe(group.id)
|
|
1539
1540
|
expect(editor.getShape(rect2ID)?.parentId).toBe(group.id)
|
|
@@ -1558,7 +1559,7 @@ describe('When dragging groups or shapes within a group', () => {
|
|
|
1558
1559
|
editor.pointerDown(15, 15)
|
|
1559
1560
|
editor.pointerMove(200, 200)
|
|
1560
1561
|
|
|
1561
|
-
|
|
1562
|
+
vi.advanceTimersByTime(200)
|
|
1562
1563
|
expect(editor.getShape(rect1ID)?.parentId).toBe(group.id)
|
|
1563
1564
|
expect(editor.getShape(rect2ID)?.parentId).toBe(group.id)
|
|
1564
1565
|
expect(editor.getShape(group.id)?.parentId).toBe(editor.getCurrentPageId())
|
|
@@ -1587,7 +1588,7 @@ describe('When dragging groups or shapes within a group', () => {
|
|
|
1587
1588
|
editor.pointerDown(15, 15)
|
|
1588
1589
|
editor.pointerMove(200, 200)
|
|
1589
1590
|
|
|
1590
|
-
|
|
1591
|
+
vi.advanceTimersByTime(200)
|
|
1591
1592
|
expect(editor.getShape(rect1ID)?.parentId).toBe(group.id)
|
|
1592
1593
|
expect(editor.getShape(rect2ID)?.parentId).toBe(group.id)
|
|
1593
1594
|
expect(editor.getShape(group.id)?.parentId).toBe(editor.getCurrentPageId())
|
|
@@ -1638,7 +1639,7 @@ describe('When dragging groups or shapes within a group', () => {
|
|
|
1638
1639
|
editor.pointerDown(215, 215)
|
|
1639
1640
|
editor.pointerMove(15, 15)
|
|
1640
1641
|
|
|
1641
|
-
|
|
1642
|
+
vi.advanceTimersByTime(200)
|
|
1642
1643
|
expect(editor.getShape(rect1ID)?.parentId).toBe(group.id)
|
|
1643
1644
|
expect(editor.getShape(rect2ID)?.parentId).toBe(group.id)
|
|
1644
1645
|
expect(editor.getShape(group.id)?.parentId).toBe(frameID)
|