tldraw 3.16.0-next.6611943ca24a → 3.16.0-next.8eb6d5c2d8f4
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 +251 -114
- package/dist-cjs/index.js +34 -15
- 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/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/TldrawUi.js +13 -12
- package/dist-cjs/lib/ui/TldrawUi.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/{FollowingIndicator.js → DefaultFollowingIndicator.js} +6 -6
- package/dist-cjs/lib/ui/components/DefaultFollowingIndicator.js.map +7 -0
- 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/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.js +5 -5
- 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/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 +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 +63 -14
- 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/components.js +2 -0
- package/dist-cjs/lib/ui/context/components.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 +13 -3
- 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 +251 -114
- package/dist-esm/index.mjs +67 -31
- 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/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/TldrawUi.mjs +13 -12
- package/dist-esm/lib/ui/TldrawUi.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/{FollowingIndicator.mjs → DefaultFollowingIndicator.mjs} +3 -3
- package/dist-esm/lib/ui/components/DefaultFollowingIndicator.mjs.map +7 -0
- 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/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.mjs +5 -5
- 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/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 +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 +64 -14
- 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/components.mjs +2 -0
- package/dist-esm/lib/ui/context/components.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 +13 -3
- 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 +3 -3
- package/src/index.ts +49 -23
- package/src/lib/Tldraw.tsx +15 -2
- package/src/lib/defaultExternalContentHandlers.ts +26 -4
- 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 +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/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/TldrawUi.tsx +16 -10
- package/src/lib/ui/components/A11y.tsx +1 -2
- package/src/lib/ui/components/AccessibilityMenu.tsx +2 -2
- package/src/lib/ui/components/{FollowingIndicator.tsx → DefaultFollowingIndicator.tsx} +2 -1
- package/src/lib/ui/components/InputModeMenu.tsx +65 -0
- package/src/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.tsx +5 -5
- 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 +52 -32
- package/src/lib/ui/components/primitives/TldrawUiToolbar.tsx +5 -1
- package/src/lib/ui/components/primitives/TldrawUiTooltip.tsx +88 -29
- 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/components.tsx +3 -0
- 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 +12 -2
- package/src/lib/ui/hooks/useTranslation/defaultTranslation.ts +13 -3
- package/src/lib/ui/kbd-utils.ts +10 -3
- package/src/lib/ui/version.ts +3 -3
- 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 +57 -7
- 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/frames.test.ts
CHANGED
|
@@ -1680,3 +1680,18 @@ it('drops into the top-most frame, if there is one', () => {
|
|
|
1680
1680
|
|
|
1681
1681
|
expect(editor.getShape(rect)?.parentId).toBe(editor.getCurrentPageId())
|
|
1682
1682
|
})
|
|
1683
|
+
|
|
1684
|
+
it('does not get drop children of nested frame if they are occluded from the outer frame', () => {
|
|
1685
|
+
const frame1Id = dragCreateFrame({ down: [100, 100], move: [300, 300], up: [300, 300] })
|
|
1686
|
+
const frame2Id = dragCreateFrame({ down: [150, 150], move: [290, 290], up: [290, 290] })
|
|
1687
|
+
|
|
1688
|
+
const rect1 = createRect({ pos: [280, 160], size: [10, 30] })
|
|
1689
|
+
|
|
1690
|
+
expect(editor.getShape(rect1)?.parentId).toBe(frame2Id)
|
|
1691
|
+
expect(editor.getShape(frame2Id)?.parentId).toBe(frame1Id)
|
|
1692
|
+
|
|
1693
|
+
editor.select(frame2Id)
|
|
1694
|
+
editor.translateSelection(30, 0)
|
|
1695
|
+
|
|
1696
|
+
expect(editor.getShape(rect1)?.parentId).toBe(frame2Id)
|
|
1697
|
+
})
|
|
@@ -1,12 +1,50 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
BaseBoxShapeUtil,
|
|
3
|
+
Box,
|
|
4
|
+
RecordProps,
|
|
5
|
+
T,
|
|
6
|
+
TLBaseShape,
|
|
7
|
+
TLShapeId,
|
|
8
|
+
createShapeId,
|
|
9
|
+
} from '@tldraw/editor'
|
|
2
10
|
import { vi } from 'vitest'
|
|
3
11
|
import { TestEditor } from './TestEditor'
|
|
4
12
|
import { TL } from './test-jsx'
|
|
5
13
|
|
|
14
|
+
// Custom uncullable shape type for testing canCull override
|
|
15
|
+
type UncullableShape = TLBaseShape<'uncullable', { w: number; h: number }>
|
|
16
|
+
|
|
17
|
+
class UncullableShapeUtil extends BaseBoxShapeUtil<UncullableShape> {
|
|
18
|
+
static override type = 'uncullable' as const
|
|
19
|
+
static override props: RecordProps<UncullableShape> = {
|
|
20
|
+
w: T.number,
|
|
21
|
+
h: T.number,
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
override canCull() {
|
|
25
|
+
return false
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
override getDefaultProps(): UncullableShape['props'] {
|
|
29
|
+
return {
|
|
30
|
+
w: 100,
|
|
31
|
+
h: 100,
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
override component() {
|
|
36
|
+
return <div>Uncullable shape</div>
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
override indicator() {
|
|
40
|
+
return <div>Uncullable shape</div>
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
6
44
|
let editor: TestEditor
|
|
7
45
|
|
|
8
46
|
beforeEach(() => {
|
|
9
|
-
editor = new TestEditor()
|
|
47
|
+
editor = new TestEditor({ shapeUtils: [UncullableShapeUtil] })
|
|
10
48
|
editor.setScreenBounds({ x: 0, y: 0, w: 1800, h: 900 })
|
|
11
49
|
})
|
|
12
50
|
|
|
@@ -203,3 +241,34 @@ it('works for shapes that are outside of the viewport, but are then moved inside
|
|
|
203
241
|
// Arrow should also not be culled
|
|
204
242
|
expect(editor.getCulledShapes()).toEqual(new Set())
|
|
205
243
|
})
|
|
244
|
+
|
|
245
|
+
it('respects canCull override - shapes that cannot be culled are never culled', () => {
|
|
246
|
+
const cullableShapeId = createShapeId()
|
|
247
|
+
const uncullableShapeId = createShapeId()
|
|
248
|
+
|
|
249
|
+
// Create both shapes outside the viewport
|
|
250
|
+
editor.createShapes([
|
|
251
|
+
{
|
|
252
|
+
id: cullableShapeId,
|
|
253
|
+
type: 'geo',
|
|
254
|
+
x: -2000, // Way outside viewport
|
|
255
|
+
y: -2000,
|
|
256
|
+
props: { w: 100, h: 100 },
|
|
257
|
+
},
|
|
258
|
+
{
|
|
259
|
+
id: uncullableShapeId,
|
|
260
|
+
type: 'uncullable',
|
|
261
|
+
x: -2000, // Way outside viewport
|
|
262
|
+
y: -2000,
|
|
263
|
+
props: { w: 100, h: 100 },
|
|
264
|
+
},
|
|
265
|
+
])
|
|
266
|
+
|
|
267
|
+
const culledShapes = editor.getCulledShapes()
|
|
268
|
+
|
|
269
|
+
// The regular geo shape should be culled since it's outside the viewport
|
|
270
|
+
expect(culledShapes).toContain(cullableShapeId)
|
|
271
|
+
|
|
272
|
+
// The uncullable shape should NOT be culled even though it's outside the viewport
|
|
273
|
+
expect(culledShapes).not.toContain(uncullableShapeId)
|
|
274
|
+
})
|
package/tldraw.css
CHANGED
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
--tl-layer-watermark: 200;
|
|
34
34
|
--tl-layer-canvas-shapes: 300;
|
|
35
35
|
--tl-layer-canvas-overlays: 500;
|
|
36
|
+
--tl-layer-canvas-in-front: 600;
|
|
36
37
|
--tl-layer-canvas-blocker: 10000;
|
|
37
38
|
|
|
38
39
|
/* Canvas overlays z-index */
|
|
@@ -301,6 +302,13 @@ input,
|
|
|
301
302
|
contain: strict;
|
|
302
303
|
}
|
|
303
304
|
|
|
305
|
+
.tl-canvas__in-front {
|
|
306
|
+
position: absolute;
|
|
307
|
+
inset: 0;
|
|
308
|
+
pointer-events: none;
|
|
309
|
+
z-index: var(--tl-layer-canvas-in-front);
|
|
310
|
+
}
|
|
311
|
+
|
|
304
312
|
.tl-shapes {
|
|
305
313
|
position: relative;
|
|
306
314
|
z-index: var(--tl-layer-canvas-shapes);
|
|
@@ -685,11 +693,17 @@ input,
|
|
|
685
693
|
}
|
|
686
694
|
|
|
687
695
|
.tl-text-measure {
|
|
688
|
-
position: absolute;
|
|
689
696
|
z-index: var(--tl-layer-canvas-hidden);
|
|
697
|
+
opacity: 0;
|
|
698
|
+
visibility: hidden;
|
|
699
|
+
|
|
700
|
+
/* pointer-events: all; */
|
|
701
|
+
/* opacity: 1; */
|
|
702
|
+
/* z-index: 99999; */
|
|
703
|
+
|
|
704
|
+
position: absolute;
|
|
690
705
|
top: 0px;
|
|
691
706
|
left: 0px;
|
|
692
|
-
opacity: 0;
|
|
693
707
|
width: max-content;
|
|
694
708
|
box-sizing: border-box;
|
|
695
709
|
pointer-events: none;
|
|
@@ -700,7 +714,6 @@ input,
|
|
|
700
714
|
border: none;
|
|
701
715
|
user-select: none;
|
|
702
716
|
contain: style paint;
|
|
703
|
-
visibility: hidden;
|
|
704
717
|
/* N.B. This property, while discouraged ("intended for Document Type Definition (DTD) designers") is necessary for ensuring correct mixed RTL/LTR behavior when exporting SVGs. */
|
|
705
718
|
unicode-bidi: plaintext;
|
|
706
719
|
-webkit-user-select: none;
|
|
@@ -1951,7 +1964,7 @@ it from receiving any pointer events or affecting the cursor. */
|
|
|
1951
1964
|
min-height: 40px;
|
|
1952
1965
|
width: 100%;
|
|
1953
1966
|
gap: 8px;
|
|
1954
|
-
margin: -4px
|
|
1967
|
+
margin-top: -4px;
|
|
1955
1968
|
}
|
|
1956
1969
|
|
|
1957
1970
|
.tlui-button__menu::after {
|
|
@@ -2277,6 +2290,10 @@ it from receiving any pointer events or affecting the cursor. */
|
|
|
2277
2290
|
-webkit-user-select: auto !important;
|
|
2278
2291
|
}
|
|
2279
2292
|
|
|
2293
|
+
.tlui-input::placeholder {
|
|
2294
|
+
color: var(--tl-color-text-3);
|
|
2295
|
+
}
|
|
2296
|
+
|
|
2280
2297
|
.tlui-input__wrapper {
|
|
2281
2298
|
width: 100%;
|
|
2282
2299
|
height: 44px;
|
|
@@ -2361,6 +2378,12 @@ it from receiving any pointer events or affecting the cursor. */
|
|
|
2361
2378
|
box-shadow: var(--tl-shadow-3);
|
|
2362
2379
|
}
|
|
2363
2380
|
|
|
2381
|
+
@media (max-height: 600px) {
|
|
2382
|
+
.tlui-menu {
|
|
2383
|
+
max-height: 70vh;
|
|
2384
|
+
}
|
|
2385
|
+
}
|
|
2386
|
+
|
|
2364
2387
|
.tlui-menu::-webkit-scrollbar {
|
|
2365
2388
|
display: none;
|
|
2366
2389
|
}
|
|
@@ -2770,7 +2793,7 @@ it from receiving any pointer events or affecting the cursor. */
|
|
|
2770
2793
|
max-width: 148px;
|
|
2771
2794
|
}
|
|
2772
2795
|
|
|
2773
|
-
.tlui-style-panel[data-
|
|
2796
|
+
.tlui-style-panel[data-enhanced-a11y-mode='true'] .tlui-button[data-isactive='true'] {
|
|
2774
2797
|
border-radius: 10px;
|
|
2775
2798
|
outline: 2px solid var(--tl-color-text);
|
|
2776
2799
|
outline-offset: -5px;
|
|
@@ -2790,21 +2813,48 @@ it from receiving any pointer events or affecting the cursor. */
|
|
|
2790
2813
|
flex-direction: column;
|
|
2791
2814
|
}
|
|
2792
2815
|
|
|
2793
|
-
|
|
2816
|
+
/*
|
|
2817
|
+
add a border to the bottom of all but the last section. we have to handle empty sections too, which
|
|
2818
|
+
are hidden and shouldn't be counted
|
|
2819
|
+
*/
|
|
2820
|
+
.tlui-style-panel__section:not(:nth-last-child(-n + 1 of .tlui-style-panel__section:not(:empty))) {
|
|
2794
2821
|
border-bottom: 1px solid var(--tl-color-divider);
|
|
2795
2822
|
}
|
|
2823
|
+
/*
|
|
2824
|
+
if a section ends with a slider and we're adding a border, we need some extra space for visual
|
|
2825
|
+
balance. we need to handle empty sections as above. is this the most complex css selector in all of
|
|
2826
|
+
tldraw? probably.
|
|
2827
|
+
*/
|
|
2828
|
+
.tlui-style-panel__section:has(.tlui-slider__container:last-child):not(
|
|
2829
|
+
:nth-last-child(-n + 1 of .tlui-style-panel__section:not(:empty))
|
|
2830
|
+
) {
|
|
2831
|
+
margin-bottom: 7px;
|
|
2832
|
+
}
|
|
2796
2833
|
|
|
2797
2834
|
.tlui-style-panel__section:empty {
|
|
2798
2835
|
display: none;
|
|
2799
2836
|
}
|
|
2800
2837
|
|
|
2838
|
+
/*
|
|
2839
|
+
* This is used in a couple places, like Align and Vertical Align.
|
|
2840
|
+
* It's because we have a toolbar with a Toggle Group but then an adjacent button
|
|
2841
|
+
* next to it that opens a popup.
|
|
2842
|
+
*/
|
|
2843
|
+
.tlui-style-panel__section .tlui-toolbar:has(.tlui-toolbar) {
|
|
2844
|
+
flex-wrap: wrap;
|
|
2845
|
+
}
|
|
2846
|
+
|
|
2847
|
+
.tlui-style-panel__section .tlui-toolbar:has(.tlui-toolbar) .tlui-style-panel__subheading {
|
|
2848
|
+
margin-left: -2px;
|
|
2849
|
+
}
|
|
2850
|
+
|
|
2801
2851
|
.tlui-style-panel__section__common:not(:only-child) {
|
|
2802
2852
|
margin-bottom: 7px;
|
|
2803
2853
|
border-bottom: 1px solid var(--tl-color-divider);
|
|
2804
2854
|
}
|
|
2805
2855
|
|
|
2806
2856
|
.tlui-style-panel__dropdown-picker:only-child {
|
|
2807
|
-
|
|
2857
|
+
flex: 1;
|
|
2808
2858
|
}
|
|
2809
2859
|
|
|
2810
2860
|
.tlui-style-panel__double-select-picker {
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../../src/lib/ui/components/FollowingIndicator.tsx"],
|
|
4
|
-
"sourcesContent": ["import { useEditor, usePresence, useValue } from '@tldraw/editor'\n\nexport function FollowingIndicator() {\n\tconst editor = useEditor()\n\tconst followingUserId = useValue('follow', () => editor.getInstanceState().followingUserId, [\n\t\teditor,\n\t])\n\tif (!followingUserId) return null\n\treturn <FollowingIndicatorInner userId={followingUserId} />\n}\n\nfunction FollowingIndicatorInner({ userId }: { userId: string }) {\n\tconst presence = usePresence(userId)\n\tif (!presence) return null\n\treturn <div className=\"tlui-following-indicator\" style={{ borderColor: presence.color }} />\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAQQ;AARR,oBAAiD;AAE1C,SAAS,qBAAqB;AACpC,QAAM,aAAS,yBAAU;AACzB,QAAM,sBAAkB,wBAAS,UAAU,MAAM,OAAO,iBAAiB,EAAE,iBAAiB;AAAA,IAC3F;AAAA,EACD,CAAC;AACD,MAAI,CAAC,gBAAiB,QAAO;AAC7B,SAAO,4CAAC,2BAAwB,QAAQ,iBAAiB;AAC1D;AAEA,SAAS,wBAAwB,EAAE,OAAO,GAAuB;AAChE,QAAM,eAAW,2BAAY,MAAM;AACnC,MAAI,CAAC,SAAU,QAAO;AACtB,SAAO,4CAAC,SAAI,WAAU,4BAA2B,OAAO,EAAE,aAAa,SAAS,MAAM,GAAG;AAC1F;",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|