tldraw 5.2.0-next.e2b8d10bf10e → 5.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/DOCS.md +20294 -0
- package/README.md +13 -1
- package/RELEASE_NOTES.md +2908 -0
- package/dist-cjs/index.d.ts +110 -23
- package/dist-cjs/index.js +3 -3
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/TldrawImage.js +0 -1
- package/dist-cjs/lib/TldrawImage.js.map +2 -2
- package/dist-cjs/lib/bindings/arrow/ArrowBindingUtil.js +2 -1
- package/dist-cjs/lib/bindings/arrow/ArrowBindingUtil.js.map +2 -2
- package/dist-cjs/lib/defaultEmbedDefinitions.js +3 -2
- package/dist-cjs/lib/defaultEmbedDefinitions.js.map +2 -2
- package/dist-cjs/lib/defaultOverlayUtils.js +11 -11
- package/dist-cjs/lib/defaultOverlayUtils.js.map +2 -2
- package/dist-cjs/lib/overlays/SelectionForegroundOverlayUtil.js +76 -64
- package/dist-cjs/lib/overlays/SelectionForegroundOverlayUtil.js.map +2 -2
- package/dist-cjs/lib/overlays/ShapeHandleOverlayUtil.js +1 -1
- package/dist-cjs/lib/overlays/ShapeHandleOverlayUtil.js.map +2 -2
- package/dist-cjs/lib/overlays/ShapeIndicatorOverlayUtil.js +107 -0
- package/dist-cjs/lib/overlays/ShapeIndicatorOverlayUtil.js.map +7 -0
- package/dist-cjs/lib/shapes/arrow/toolStates/Pointing.js +3 -0
- package/dist-cjs/lib/shapes/arrow/toolStates/Pointing.js.map +2 -2
- package/dist-cjs/lib/shapes/bookmark/BookmarkShapeUtil.js +12 -3
- package/dist-cjs/lib/shapes/bookmark/BookmarkShapeUtil.js.map +2 -2
- package/dist-cjs/lib/shapes/bookmark/bookmarks.js +54 -6
- package/dist-cjs/lib/shapes/bookmark/bookmarks.js.map +2 -2
- package/dist-cjs/lib/shapes/draw/DrawShapeUtil.js +2 -1
- package/dist-cjs/lib/shapes/draw/DrawShapeUtil.js.map +2 -2
- package/dist-cjs/lib/shapes/draw/getPath.js +1 -1
- package/dist-cjs/lib/shapes/draw/getPath.js.map +2 -2
- package/dist-cjs/lib/shapes/draw/toolStates/Drawing.js +45 -47
- package/dist-cjs/lib/shapes/draw/toolStates/Drawing.js.map +2 -2
- package/dist-cjs/lib/shapes/embed/EmbedShapeUtil.js +2 -1
- package/dist-cjs/lib/shapes/embed/EmbedShapeUtil.js.map +2 -2
- package/dist-cjs/lib/shapes/frame/FrameShapeTool.js +23 -18
- package/dist-cjs/lib/shapes/frame/FrameShapeTool.js.map +2 -2
- package/dist-cjs/lib/shapes/geo/GeoShapeUtil.js +1 -1
- package/dist-cjs/lib/shapes/geo/GeoShapeUtil.js.map +2 -2
- package/dist-cjs/lib/shapes/geo/toolStates/Pointing.js +3 -0
- package/dist-cjs/lib/shapes/geo/toolStates/Pointing.js.map +2 -2
- package/dist-cjs/lib/shapes/highlight/HighlightShapeUtil.js +11 -7
- package/dist-cjs/lib/shapes/highlight/HighlightShapeUtil.js.map +2 -2
- package/dist-cjs/lib/shapes/image/ImageShapeUtil.js +3 -11
- package/dist-cjs/lib/shapes/image/ImageShapeUtil.js.map +2 -2
- package/dist-cjs/lib/shapes/line/toolStates/Pointing.js +5 -1
- package/dist-cjs/lib/shapes/line/toolStates/Pointing.js.map +2 -2
- package/dist-cjs/lib/shapes/note/NoteShapeUtil.js +31 -41
- package/dist-cjs/lib/shapes/note/NoteShapeUtil.js.map +2 -2
- package/dist-cjs/lib/shapes/note/noteHelpers.js +1 -1
- package/dist-cjs/lib/shapes/note/noteHelpers.js.map +2 -2
- package/dist-cjs/lib/shapes/note/toolStates/Pointing.js +28 -6
- package/dist-cjs/lib/shapes/note/toolStates/Pointing.js.map +2 -2
- package/dist-cjs/lib/shapes/shared/PlainTextLabel.js +3 -2
- package/dist-cjs/lib/shapes/shared/PlainTextLabel.js.map +2 -2
- package/dist-cjs/lib/shapes/shared/RichTextLabel.js +3 -3
- package/dist-cjs/lib/shapes/shared/RichTextLabel.js.map +2 -2
- package/dist-cjs/lib/shapes/shared/defaultStyleDefs.js +17 -3
- package/dist-cjs/lib/shapes/shared/defaultStyleDefs.js.map +2 -2
- package/dist-cjs/lib/shapes/shared/freehand/core.js +424 -0
- package/dist-cjs/lib/shapes/shared/freehand/core.js.map +7 -0
- package/dist-cjs/lib/shapes/shared/freehand/fmt.js +106 -0
- package/dist-cjs/lib/shapes/shared/freehand/fmt.js.map +7 -0
- package/dist-cjs/lib/shapes/shared/freehand/getStroke.js +6 -6
- package/dist-cjs/lib/shapes/shared/freehand/getStroke.js.map +2 -2
- package/dist-cjs/lib/shapes/shared/freehand/getStrokeOutlinePoints.js +320 -86
- package/dist-cjs/lib/shapes/shared/freehand/getStrokeOutlinePoints.js.map +3 -3
- package/dist-cjs/lib/shapes/shared/freehand/getStrokePoints.js +20 -96
- package/dist-cjs/lib/shapes/shared/freehand/getStrokePoints.js.map +3 -3
- package/dist-cjs/lib/shapes/shared/freehand/svg.js +55 -19
- package/dist-cjs/lib/shapes/shared/freehand/svg.js.map +2 -2
- package/dist-cjs/lib/shapes/shared/freehand/svgInk.js +189 -97
- package/dist-cjs/lib/shapes/shared/freehand/svgInk.js.map +3 -3
- package/dist-cjs/lib/shapes/shared/freehand/types.js.map +1 -1
- package/dist-cjs/lib/shapes/shared/interpolate-props.js +6 -2
- package/dist-cjs/lib/shapes/shared/interpolate-props.js.map +2 -2
- package/dist-cjs/lib/shapes/text/toolStates/Pointing.js +3 -0
- package/dist-cjs/lib/shapes/text/toolStates/Pointing.js.map +2 -2
- package/dist-cjs/lib/tools/HandTool/HandTool.js +16 -6
- package/dist-cjs/lib/tools/HandTool/HandTool.js.map +2 -2
- package/dist-cjs/lib/tools/HandTool/childStates/Dragging.js +10 -1
- package/dist-cjs/lib/tools/HandTool/childStates/Dragging.js.map +2 -2
- package/dist-cjs/lib/tools/HandTool/childStates/OneFingerZooming.js +84 -0
- package/dist-cjs/lib/tools/HandTool/childStates/OneFingerZooming.js.map +7 -0
- package/dist-cjs/lib/tools/SelectTool/childStates/Idle.js +12 -0
- package/dist-cjs/lib/tools/SelectTool/childStates/Idle.js.map +2 -2
- package/dist-cjs/lib/tools/SelectTool/childStates/PointingShape.js +4 -0
- package/dist-cjs/lib/tools/SelectTool/childStates/PointingShape.js.map +2 -2
- package/dist-cjs/lib/tools/SelectTool/childStates/Resizing.js +107 -46
- package/dist-cjs/lib/tools/SelectTool/childStates/Resizing.js.map +2 -2
- package/dist-cjs/lib/ui/TldrawUi.js +4 -3
- package/dist-cjs/lib/ui/TldrawUi.js.map +2 -2
- package/dist-cjs/lib/ui/components/A11y.js +2 -0
- package/dist-cjs/lib/ui/components/A11y.js.map +2 -2
- package/dist-cjs/lib/ui/components/ContextMenu/DefaultContextMenu.js +14 -1
- package/dist-cjs/lib/ui/components/ContextMenu/DefaultContextMenu.js.map +2 -2
- package/dist-cjs/lib/ui/components/ContextMenu/DefaultContextMenuContent.js +0 -6
- package/dist-cjs/lib/ui/components/ContextMenu/DefaultContextMenuContent.js.map +2 -2
- package/dist-cjs/lib/ui/components/DefaultFollowingIndicator.js.map +2 -2
- package/dist-cjs/lib/ui/components/Dialogs.js +17 -37
- package/dist-cjs/lib/ui/components/Dialogs.js.map +2 -2
- package/dist-cjs/lib/ui/components/HelperButtons/BackToContent.js +19 -4
- package/dist-cjs/lib/ui/components/HelperButtons/BackToContent.js.map +2 -2
- package/dist-cjs/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.js +12 -2
- package/dist-cjs/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.js.map +2 -2
- package/dist-cjs/lib/ui/components/Minimap/DefaultMinimap.js +47 -70
- package/dist-cjs/lib/ui/components/Minimap/DefaultMinimap.js.map +2 -2
- package/dist-cjs/lib/ui/components/Minimap/MinimapManager.js +25 -46
- package/dist-cjs/lib/ui/components/Minimap/MinimapManager.js.map +2 -2
- package/dist-cjs/lib/ui/components/SharePanel/DefaultPeopleMenuAvatar.js.map +2 -2
- package/dist-cjs/lib/ui/components/SharePanel/DefaultPeopleMenuContent.js.map +2 -2
- package/dist-cjs/lib/ui/components/SharePanel/DefaultPeopleMenuFacePile.js.map +2 -2
- package/dist-cjs/lib/ui/components/SharePanel/DefaultPeopleMenuItem.js +1 -1
- package/dist-cjs/lib/ui/components/SharePanel/DefaultPeopleMenuItem.js.map +2 -2
- package/dist-cjs/lib/ui/components/StylePanel/StylePanelButtonPicker.js +1 -0
- package/dist-cjs/lib/ui/components/StylePanel/StylePanelButtonPicker.js.map +2 -2
- package/dist-cjs/lib/ui/components/menu-items.js +7 -0
- package/dist-cjs/lib/ui/components/menu-items.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/TldrawUiDropdownMenu.js +2 -1
- package/dist-cjs/lib/ui/components/primitives/TldrawUiDropdownMenu.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/TldrawUiIcon.js +14 -3
- package/dist-cjs/lib/ui/components/primitives/TldrawUiIcon.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/TldrawUiInput.js +2 -0
- package/dist-cjs/lib/ui/components/primitives/TldrawUiInput.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/TldrawUiPopover.js +2 -0
- package/dist-cjs/lib/ui/components/primitives/TldrawUiPopover.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.js +0 -2
- package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuSubmenu.js +1 -2
- package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuSubmenu.js.map +2 -2
- package/dist-cjs/lib/ui/context/actions.js +70 -1
- package/dist-cjs/lib/ui/context/actions.js.map +2 -2
- package/dist-cjs/lib/ui/context/asset-urls.js +5 -8
- package/dist-cjs/lib/ui/context/asset-urls.js.map +2 -2
- package/dist-cjs/lib/ui/context/events.js.map +2 -2
- package/dist-cjs/lib/ui/hooks/useKeyboardShortcuts.js +13 -0
- package/dist-cjs/lib/ui/hooks/useKeyboardShortcuts.js.map +2 -2
- package/dist-cjs/lib/ui/hooks/useTools.js +1 -1
- package/dist-cjs/lib/ui/hooks/useTools.js.map +2 -2
- package/dist-cjs/lib/ui/hooks/useTranslation/TLUiTranslationKey.js.map +1 -1
- package/dist-cjs/lib/ui/hooks/useTranslation/defaultTranslation.js +2 -0
- package/dist-cjs/lib/ui/hooks/useTranslation/defaultTranslation.js.map +2 -2
- package/dist-cjs/lib/ui/version.js +3 -3
- package/dist-cjs/lib/ui/version.js.map +1 -1
- package/dist-cjs/lib/utils/embeds/embeds.js +4 -4
- package/dist-cjs/lib/utils/embeds/embeds.js.map +2 -2
- package/dist-cjs/lib/utils/test-helpers.js +2 -2
- package/dist-cjs/lib/utils/test-helpers.js.map +2 -2
- package/dist-cjs/lib/utils/text/richText.js +3 -1
- package/dist-cjs/lib/utils/text/richText.js.map +2 -2
- package/dist-esm/index.d.mts +110 -23
- package/dist-esm/index.mjs +5 -3
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/TldrawImage.mjs +0 -1
- package/dist-esm/lib/TldrawImage.mjs.map +2 -2
- package/dist-esm/lib/bindings/arrow/ArrowBindingUtil.mjs +2 -1
- package/dist-esm/lib/bindings/arrow/ArrowBindingUtil.mjs.map +2 -2
- package/dist-esm/lib/defaultEmbedDefinitions.mjs +3 -2
- package/dist-esm/lib/defaultEmbedDefinitions.mjs.map +2 -2
- package/dist-esm/lib/defaultOverlayUtils.mjs +11 -11
- package/dist-esm/lib/defaultOverlayUtils.mjs.map +2 -2
- package/dist-esm/lib/overlays/SelectionForegroundOverlayUtil.mjs +77 -65
- package/dist-esm/lib/overlays/SelectionForegroundOverlayUtil.mjs.map +2 -2
- package/dist-esm/lib/overlays/ShapeHandleOverlayUtil.mjs +1 -1
- package/dist-esm/lib/overlays/ShapeHandleOverlayUtil.mjs.map +2 -2
- package/dist-esm/lib/overlays/ShapeIndicatorOverlayUtil.mjs +87 -0
- package/dist-esm/lib/overlays/ShapeIndicatorOverlayUtil.mjs.map +7 -0
- package/dist-esm/lib/shapes/arrow/toolStates/Pointing.mjs +9 -1
- package/dist-esm/lib/shapes/arrow/toolStates/Pointing.mjs.map +2 -2
- package/dist-esm/lib/shapes/bookmark/BookmarkShapeUtil.mjs +15 -3
- package/dist-esm/lib/shapes/bookmark/BookmarkShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/shapes/bookmark/bookmarks.mjs +54 -6
- package/dist-esm/lib/shapes/bookmark/bookmarks.mjs.map +2 -2
- package/dist-esm/lib/shapes/draw/DrawShapeUtil.mjs +3 -1
- package/dist-esm/lib/shapes/draw/DrawShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/shapes/draw/getPath.mjs +1 -1
- package/dist-esm/lib/shapes/draw/getPath.mjs.map +2 -2
- package/dist-esm/lib/shapes/draw/toolStates/Drawing.mjs +46 -47
- package/dist-esm/lib/shapes/draw/toolStates/Drawing.mjs.map +2 -2
- package/dist-esm/lib/shapes/embed/EmbedShapeUtil.mjs +2 -1
- package/dist-esm/lib/shapes/embed/EmbedShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/shapes/frame/FrameShapeTool.mjs +23 -18
- package/dist-esm/lib/shapes/frame/FrameShapeTool.mjs.map +2 -2
- package/dist-esm/lib/shapes/geo/GeoShapeUtil.mjs +2 -1
- package/dist-esm/lib/shapes/geo/GeoShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/shapes/geo/toolStates/Pointing.mjs +4 -0
- package/dist-esm/lib/shapes/geo/toolStates/Pointing.mjs.map +2 -2
- package/dist-esm/lib/shapes/highlight/HighlightShapeUtil.mjs +12 -7
- package/dist-esm/lib/shapes/highlight/HighlightShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/shapes/image/ImageShapeUtil.mjs +3 -11
- package/dist-esm/lib/shapes/image/ImageShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/shapes/line/toolStates/Pointing.mjs +6 -1
- package/dist-esm/lib/shapes/line/toolStates/Pointing.mjs.map +2 -2
- package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs +32 -42
- package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/shapes/note/noteHelpers.mjs +1 -1
- package/dist-esm/lib/shapes/note/noteHelpers.mjs.map +2 -2
- package/dist-esm/lib/shapes/note/toolStates/Pointing.mjs +29 -6
- package/dist-esm/lib/shapes/note/toolStates/Pointing.mjs.map +2 -2
- package/dist-esm/lib/shapes/shared/PlainTextLabel.mjs +3 -2
- package/dist-esm/lib/shapes/shared/PlainTextLabel.mjs.map +2 -2
- package/dist-esm/lib/shapes/shared/RichTextLabel.mjs +4 -3
- package/dist-esm/lib/shapes/shared/RichTextLabel.mjs.map +2 -2
- package/dist-esm/lib/shapes/shared/defaultStyleDefs.mjs +17 -3
- package/dist-esm/lib/shapes/shared/defaultStyleDefs.mjs.map +2 -2
- package/dist-esm/lib/shapes/shared/freehand/core.mjs +404 -0
- package/dist-esm/lib/shapes/shared/freehand/core.mjs.map +7 -0
- package/dist-esm/lib/shapes/shared/freehand/fmt.mjs +86 -0
- package/dist-esm/lib/shapes/shared/freehand/fmt.mjs.map +7 -0
- package/dist-esm/lib/shapes/shared/freehand/getStroke.mjs +7 -7
- package/dist-esm/lib/shapes/shared/freehand/getStroke.mjs.map +2 -2
- package/dist-esm/lib/shapes/shared/freehand/getStrokeOutlinePoints.mjs +332 -86
- package/dist-esm/lib/shapes/shared/freehand/getStrokeOutlinePoints.mjs.map +3 -3
- package/dist-esm/lib/shapes/shared/freehand/getStrokePoints.mjs +31 -96
- package/dist-esm/lib/shapes/shared/freehand/getStrokePoints.mjs.map +3 -3
- package/dist-esm/lib/shapes/shared/freehand/svg.mjs +55 -19
- package/dist-esm/lib/shapes/shared/freehand/svg.mjs.map +2 -2
- package/dist-esm/lib/shapes/shared/freehand/svgInk.mjs +214 -99
- package/dist-esm/lib/shapes/shared/freehand/svgInk.mjs.map +3 -3
- package/dist-esm/lib/shapes/shared/interpolate-props.mjs +6 -2
- package/dist-esm/lib/shapes/shared/interpolate-props.mjs.map +2 -2
- package/dist-esm/lib/shapes/text/toolStates/Pointing.mjs +4 -0
- package/dist-esm/lib/shapes/text/toolStates/Pointing.mjs.map +2 -2
- package/dist-esm/lib/tools/HandTool/HandTool.mjs +16 -6
- package/dist-esm/lib/tools/HandTool/HandTool.mjs.map +2 -2
- package/dist-esm/lib/tools/HandTool/childStates/Dragging.mjs +10 -1
- package/dist-esm/lib/tools/HandTool/childStates/Dragging.mjs.map +2 -2
- package/dist-esm/lib/tools/HandTool/childStates/OneFingerZooming.mjs +64 -0
- package/dist-esm/lib/tools/HandTool/childStates/OneFingerZooming.mjs.map +7 -0
- package/dist-esm/lib/tools/SelectTool/childStates/Idle.mjs +12 -0
- package/dist-esm/lib/tools/SelectTool/childStates/Idle.mjs.map +2 -2
- package/dist-esm/lib/tools/SelectTool/childStates/PointingShape.mjs +4 -0
- package/dist-esm/lib/tools/SelectTool/childStates/PointingShape.mjs.map +2 -2
- package/dist-esm/lib/tools/SelectTool/childStates/Resizing.mjs +108 -46
- package/dist-esm/lib/tools/SelectTool/childStates/Resizing.mjs.map +2 -2
- package/dist-esm/lib/ui/TldrawUi.mjs +4 -3
- package/dist-esm/lib/ui/TldrawUi.mjs.map +2 -2
- package/dist-esm/lib/ui/components/A11y.mjs +2 -0
- package/dist-esm/lib/ui/components/A11y.mjs.map +2 -2
- package/dist-esm/lib/ui/components/ContextMenu/DefaultContextMenu.mjs +21 -2
- package/dist-esm/lib/ui/components/ContextMenu/DefaultContextMenu.mjs.map +2 -2
- package/dist-esm/lib/ui/components/ContextMenu/DefaultContextMenuContent.mjs +0 -6
- package/dist-esm/lib/ui/components/ContextMenu/DefaultContextMenuContent.mjs.map +2 -2
- package/dist-esm/lib/ui/components/DefaultFollowingIndicator.mjs.map +2 -2
- package/dist-esm/lib/ui/components/Dialogs.mjs +19 -39
- package/dist-esm/lib/ui/components/Dialogs.mjs.map +2 -2
- package/dist-esm/lib/ui/components/HelperButtons/BackToContent.mjs +20 -5
- package/dist-esm/lib/ui/components/HelperButtons/BackToContent.mjs.map +2 -2
- package/dist-esm/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.mjs +12 -2
- package/dist-esm/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.mjs.map +2 -2
- package/dist-esm/lib/ui/components/Minimap/DefaultMinimap.mjs +47 -70
- package/dist-esm/lib/ui/components/Minimap/DefaultMinimap.mjs.map +2 -2
- package/dist-esm/lib/ui/components/Minimap/MinimapManager.mjs +25 -46
- package/dist-esm/lib/ui/components/Minimap/MinimapManager.mjs.map +2 -2
- package/dist-esm/lib/ui/components/SharePanel/DefaultPeopleMenuAvatar.mjs.map +2 -2
- package/dist-esm/lib/ui/components/SharePanel/DefaultPeopleMenuContent.mjs.map +2 -2
- package/dist-esm/lib/ui/components/SharePanel/DefaultPeopleMenuFacePile.mjs.map +2 -2
- package/dist-esm/lib/ui/components/SharePanel/DefaultPeopleMenuItem.mjs +1 -1
- package/dist-esm/lib/ui/components/SharePanel/DefaultPeopleMenuItem.mjs.map +2 -2
- package/dist-esm/lib/ui/components/StylePanel/StylePanelButtonPicker.mjs +1 -0
- package/dist-esm/lib/ui/components/StylePanel/StylePanelButtonPicker.mjs.map +2 -2
- package/dist-esm/lib/ui/components/menu-items.mjs +7 -0
- package/dist-esm/lib/ui/components/menu-items.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/TldrawUiDropdownMenu.mjs +2 -1
- package/dist-esm/lib/ui/components/primitives/TldrawUiDropdownMenu.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/TldrawUiIcon.mjs +14 -3
- package/dist-esm/lib/ui/components/primitives/TldrawUiIcon.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/TldrawUiInput.mjs +2 -0
- package/dist-esm/lib/ui/components/primitives/TldrawUiInput.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/TldrawUiPopover.mjs +2 -0
- package/dist-esm/lib/ui/components/primitives/TldrawUiPopover.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.mjs +0 -2
- package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuSubmenu.mjs +1 -2
- package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuSubmenu.mjs.map +2 -2
- package/dist-esm/lib/ui/context/actions.mjs +71 -1
- package/dist-esm/lib/ui/context/actions.mjs.map +2 -2
- package/dist-esm/lib/ui/context/asset-urls.mjs +5 -8
- package/dist-esm/lib/ui/context/asset-urls.mjs.map +2 -2
- package/dist-esm/lib/ui/context/events.mjs.map +2 -2
- package/dist-esm/lib/ui/hooks/useKeyboardShortcuts.mjs +13 -0
- package/dist-esm/lib/ui/hooks/useKeyboardShortcuts.mjs.map +2 -2
- package/dist-esm/lib/ui/hooks/useTools.mjs +1 -1
- package/dist-esm/lib/ui/hooks/useTools.mjs.map +2 -2
- package/dist-esm/lib/ui/hooks/useTranslation/defaultTranslation.mjs +2 -0
- package/dist-esm/lib/ui/hooks/useTranslation/defaultTranslation.mjs.map +2 -2
- package/dist-esm/lib/ui/version.mjs +3 -3
- package/dist-esm/lib/ui/version.mjs.map +1 -1
- package/dist-esm/lib/utils/embeds/embeds.mjs +4 -4
- package/dist-esm/lib/utils/embeds/embeds.mjs.map +2 -2
- package/dist-esm/lib/utils/test-helpers.mjs +2 -2
- package/dist-esm/lib/utils/test-helpers.mjs.map +2 -2
- package/dist-esm/lib/utils/text/richText.mjs +3 -1
- package/dist-esm/lib/utils/text/richText.mjs.map +2 -2
- package/package.json +11 -6
- package/src/index.ts +6 -1
- package/src/lib/TldrawImage.tsx +2 -2
- package/src/lib/bindings/arrow/ArrowBindingUtil.ts +5 -1
- package/src/lib/defaultEmbedDefinitions.ts +28 -6
- package/src/lib/defaultOverlayUtils.ts +11 -11
- package/src/lib/overlays/SelectionForegroundOverlayUtil.ts +91 -72
- package/src/lib/overlays/ShapeHandleOverlayUtil.ts +3 -1
- package/src/lib/overlays/ShapeIndicatorOverlayUtil.ts +133 -0
- package/src/lib/shapes/arrow/toolStates/Pointing.tsx +11 -1
- package/src/lib/shapes/bookmark/BookmarkShapeUtil.tsx +16 -3
- package/src/lib/shapes/bookmark/bookmarks.ts +105 -15
- package/src/lib/shapes/draw/DrawShapeUtil.tsx +7 -5
- package/src/lib/shapes/draw/getPath.ts +1 -1
- package/src/lib/shapes/draw/toolStates/Drawing.ts +55 -48
- package/src/lib/shapes/embed/EmbedShapeUtil.tsx +14 -4
- package/src/lib/shapes/frame/FrameShapeTool.ts +35 -24
- package/src/lib/shapes/geo/GeoShapeUtil.test.tsx +46 -0
- package/src/lib/shapes/geo/GeoShapeUtil.tsx +2 -1
- package/src/lib/shapes/geo/toolStates/Pointing.ts +5 -0
- package/src/lib/shapes/highlight/HighlightShapeUtil.tsx +14 -11
- package/src/lib/shapes/image/ImageShapeUtil.tsx +7 -11
- package/src/lib/shapes/line/LineShapeTool.test.ts +41 -0
- package/src/lib/shapes/line/toolStates/Pointing.ts +12 -2
- package/src/lib/shapes/note/NoteShapeUtil.tsx +36 -51
- package/src/lib/shapes/note/noteCloning.test.ts +5 -5
- package/src/lib/shapes/note/noteHelpers.ts +1 -1
- package/src/lib/shapes/note/toolStates/Pointing.ts +40 -7
- package/src/lib/shapes/shared/PlainTextLabel.tsx +3 -3
- package/src/lib/shapes/shared/RichTextLabel.tsx +4 -3
- package/src/lib/shapes/shared/defaultStyleDefs.tsx +25 -3
- package/src/lib/shapes/shared/freehand/core.ts +547 -0
- package/src/lib/shapes/shared/freehand/fmt.ts +106 -0
- package/src/lib/shapes/shared/freehand/getStroke.ts +7 -7
- package/src/lib/shapes/shared/freehand/getStrokeOutlinePoints.ts +451 -139
- package/src/lib/shapes/shared/freehand/getStrokePoints.ts +33 -153
- package/src/lib/shapes/shared/freehand/svg.ts +72 -23
- package/src/lib/shapes/shared/freehand/svgInk.ts +281 -136
- package/src/lib/shapes/shared/freehand/types.ts +0 -1
- package/src/lib/shapes/shared/interpolate-props.ts +6 -2
- package/src/lib/shapes/text/toolStates/Pointing.ts +5 -0
- package/src/lib/tools/HandTool/HandTool.ts +19 -6
- package/src/lib/tools/HandTool/childStates/Dragging.ts +17 -1
- package/src/lib/tools/HandTool/childStates/OneFingerZooming.ts +79 -0
- package/src/lib/tools/SelectTool/childStates/Idle.ts +16 -2
- package/src/lib/tools/SelectTool/childStates/PointingShape.ts +8 -0
- package/src/lib/tools/SelectTool/childStates/Resizing.ts +137 -49
- package/src/lib/ui/TldrawUi.tsx +3 -3
- package/src/lib/ui/components/A11y.tsx +2 -0
- package/src/lib/ui/components/ContextMenu/DefaultContextMenu.tsx +32 -2
- package/src/lib/ui/components/ContextMenu/DefaultContextMenuContent.tsx +5 -6
- package/src/lib/ui/components/DefaultFollowingIndicator.tsx +2 -2
- package/src/lib/ui/components/Dialogs.tsx +20 -23
- package/src/lib/ui/components/HelperButtons/BackToContent.tsx +32 -4
- package/src/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.tsx +10 -0
- package/src/lib/ui/components/Minimap/DefaultMinimap.tsx +60 -74
- package/src/lib/ui/components/Minimap/MinimapManager.ts +35 -57
- package/src/lib/ui/components/SharePanel/DefaultPeopleMenuAvatar.tsx +2 -2
- package/src/lib/ui/components/SharePanel/DefaultPeopleMenuContent.tsx +2 -1
- package/src/lib/ui/components/SharePanel/DefaultPeopleMenuFacePile.tsx +2 -1
- package/src/lib/ui/components/SharePanel/DefaultPeopleMenuItem.tsx +3 -3
- package/src/lib/ui/components/StylePanel/StylePanelButtonPicker.tsx +5 -0
- package/src/lib/ui/components/menu-items.tsx +9 -0
- package/src/lib/ui/components/primitives/TldrawUiDropdownMenu.tsx +3 -1
- package/src/lib/ui/components/primitives/TldrawUiIcon.tsx +15 -3
- package/src/lib/ui/components/primitives/TldrawUiInput.tsx +4 -0
- package/src/lib/ui/components/primitives/TldrawUiPopover.tsx +7 -0
- package/src/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.tsx +0 -2
- package/src/lib/ui/components/primitives/menus/TldrawUiMenuSubmenu.tsx +0 -1
- package/src/lib/ui/context/actions.tsx +88 -1
- package/src/lib/ui/context/asset-urls.tsx +9 -8
- package/src/lib/ui/context/events.tsx +2 -0
- package/src/lib/ui/hooks/useKeyboardShortcuts.ts +45 -7
- package/src/lib/ui/hooks/useTools.tsx +7 -1
- package/src/lib/ui/hooks/useTranslation/TLUiTranslationKey.ts +2 -0
- package/src/lib/ui/hooks/useTranslation/defaultTranslation.ts +2 -0
- package/src/lib/ui/version.ts +3 -3
- package/src/lib/ui.css +20 -9
- package/src/lib/utils/embeds/embeds.test.ts +14 -12
- package/src/lib/utils/embeds/embeds.ts +10 -4
- package/src/lib/utils/test-helpers.ts +3 -3
- package/src/lib/utils/text/richText.test.ts +36 -0
- package/src/lib/utils/text/richText.ts +9 -1
- package/src/test/HandTool.test.ts +93 -0
- package/src/test/ImageShapeUtil.test.ts +88 -0
- package/src/test/SelectTool.test.ts +102 -1
- package/src/test/__snapshots__/drawing.test.ts.snap +2 -1
- package/src/test/attribution.test.ts +40 -29
- package/src/test/bookmark-shapes.test.ts +256 -28
- package/src/test/commands/__snapshots__/getSvgString.test.ts.snap +2 -2
- package/src/test/commands/clipboardCallbacks.test.ts +3 -1
- package/src/test/commands/getSvgString.test.ts +30 -0
- package/src/test/commands/penmode.test.ts +97 -1
- package/src/test/commands/setCamera.test.ts +12 -0
- package/src/test/dragFromToolbar.test.ts +67 -0
- package/src/test/drawing.test.ts +48 -7
- package/src/test/frames.test.ts +72 -0
- package/src/test/freehand/corpus/presets.ts +71 -0
- package/src/test/freehand/corpus/real.ts +370 -0
- package/src/test/freehand/corpus/strokes.ts +50 -0
- package/src/test/freehand/svg.test.ts +20 -0
- package/src/test/freehand/wellformed.test.ts +30 -0
- package/src/test/long-press-create.test.ts +102 -0
- package/src/test/overlays/CollaboratorBrushOverlayUtil.test.ts +4 -4
- package/src/test/overlays/CollaboratorCursorOverlayUtil.test.ts +18 -18
- package/src/test/overlays/CollaboratorHintOverlayUtil.test.ts +7 -7
- package/src/test/overlays/CollaboratorScribbleOverlayUtil.test.ts +3 -3
- package/src/test/overlays/OverlayManager.test.ts +1 -1
- package/src/test/overlays/SelectionForegroundOverlayUtil.test.ts +58 -0
- package/src/test/overlays/ShapeHandleOverlayUtil.test.ts +2 -2
- package/src/test/overlays/ShapeIndicatorOverlayUtil.test.ts +36 -0
- package/src/test/resizing.test.ts +250 -0
- package/src/test/right-click-context-menu.test.ts +90 -0
- package/src/test/rightClickPanning.test.ts +11 -0
- package/src/test/selection-omnibus.test.ts +15 -2
- package/src/test/spatialIndex.test.ts +132 -0
- package/src/test/translating.test.ts +0 -6
- package/src/test/ui/ContextMenu.test.tsx +146 -3
- package/src/test/ui/Dialogs.test.tsx +256 -0
- package/src/test/ui/copyHoveredStyles.test.tsx +154 -0
- package/src/test/ui/keyboardShortcuts.test.tsx +266 -0
- package/tldraw.css +35 -12
- package/dist-cjs/lib/shapes/shared/freehand/setStrokePointRadii.js +0 -100
- package/dist-cjs/lib/shapes/shared/freehand/setStrokePointRadii.js.map +0 -7
- package/dist-esm/lib/shapes/shared/freehand/setStrokePointRadii.mjs +0 -80
- package/dist-esm/lib/shapes/shared/freehand/setStrokePointRadii.mjs.map +0 -7
- package/src/lib/shapes/shared/freehand/setStrokePointRadii.ts +0 -127
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/lib/shapes/geo/GeoShapeUtil.tsx"],
|
|
4
|
-
"sourcesContent": ["/* eslint-disable react-hooks/rules-of-hooks */\nimport {\n\tBaseBoxShapeUtil,\n\tBox,\n\tEMPTY_ARRAY,\n\tEditor,\n\tGeoShapeGeoStyle,\n\tGroup2d,\n\tHTMLContainer,\n\tHandleSnapGeometry,\n\tRectangle2d,\n\tSVGContainer,\n\tSvgExportContext,\n\tTLGeoShape,\n\tTLGeoShapeProps,\n\tTLMeasureTextOpts,\n\tTLResizeInfo,\n\tTLShape,\n\tTLShapeId,\n\tTLShapeUtilCanvasSvgDef,\n\tTLShapeUtilConstructor,\n\tVec,\n\tVecLike,\n\tWeakCache,\n\tapproximately,\n\tareAnglesCompatible,\n\tgeoShapeMigrations,\n\tgeoShapeProps,\n\tgetColorValue,\n\tgetFontsFromRichText,\n\tisEqual,\n\tlerp,\n\ttoRichText,\n\tuseColorMode,\n\tuseValue,\n} from '@tldraw/editor'\nimport {\n\tisEmptyRichText,\n\trenderHtmlFromRichTextForMeasurement,\n\trenderPlaintextFromRichText,\n} from '../../utils/text/richText'\nimport {\n\tLABEL_FONT_SIZES,\n\tLABEL_PADDING,\n\tSTROKE_SIZES,\n\tTEXT_PROPS,\n\tgetFontFamily,\n} from '../shared/default-shape-constants'\nimport { DEFAULT_FILL_COLOR_NAMES } from '../shared/defaultFills'\nimport { getThemeFontFaces } from '../shared/defaultFonts'\nimport { getFillDefForCanvas, getFillDefForExport } from '../shared/defaultStyleDefs'\nimport { ShapeOptionsWithDisplayValues, getDisplayValues } from '../shared/getDisplayValues'\nimport { HyperlinkButton } from '../shared/HyperlinkButton'\nimport { RichTextLabel, RichTextSVG } from '../shared/RichTextLabel'\nimport { useIsReadyForEditing } from '../shared/useEditablePlainText'\nimport { useEfficientZoomThreshold } from '../shared/useEfficientZoomThreshold'\nimport { GeoShapeBody } from './GeoShapeBody'\nimport {\n\tdefaultGeoTypeDefinitions,\n\ttype GeoTypeDefinition,\n\tgetGeoShapePath,\n\tgetGeoTypeDefinition,\n} from './getGeoShapePath'\n\n// imperfect but good enough, should be the width of the W in the font / size combo\nconst GEO_SHAPE_MIN_WIDTHS = Object.freeze({\n\ts: 12,\n\tm: 14,\n\tl: 16,\n\txl: 20,\n})\n\n// Extra padding for geo shape labels matches the stroke width\n// Computed dynamically in getDisplayValues via theme.strokeWidth * STROKE_SIZES[size]\n\nconst GEO_SHAPE_HORIZONTAL_ALIGNS = Object.freeze({\n\tstart: 'start',\n\tmiddle: 'center',\n\tend: 'end',\n\t'start-legacy': 'start',\n\t'end-legacy': 'end',\n\t'middle-legacy': 'center',\n} as const)\n\nconst GEO_SHAPE_VERTICAL_ALIGNS = Object.freeze({\n\tstart: 'start',\n\tmiddle: 'middle',\n\tend: 'end',\n} as const)\n\nconst GEO_SHAPE_EMPTY_LABEL_SIZE = Object.freeze({ w: 0, h: 0 })\n\n// Snapshot the built-in geo types at module init so that collision detection\n// in `configure()` only fires against the built-ins, not against keys added\n// by previous `configure()` calls. This lets repeat `configure()` calls reuse\n// the same custom key (e.g. when wrapping/extending the util) without having\n// the entry stripped from `options.customGeoTypes`.\nconst BUILTIN_GEO_TYPES: ReadonlySet<string> = new Set(Object.keys(defaultGeoTypeDefinitions))\n\n/** @public */\nexport interface GeoShapeUtilDisplayValues {\n\tstrokeColor: string\n\tstrokeRoundness: number\n\tstrokeWidth: number\n\tfillColor: string\n\tpatternFillFallbackColor: string\n\tlabelColor: string\n\tlabelFontFamily: string\n\tlabelFontSize: number\n\tlabelMinWidth: number\n\tlabelExtraPadding: number\n\tlabelLineHeight: number\n\tlabelFontWeight: string\n\tlabelFontVariant: string\n\tlabelFontStyle: string\n\tlabelHorizontalAlign: 'start' | 'center' | 'end'\n\tlabelVerticalAlign: 'start' | 'middle' | 'end'\n\tlabelPadding: number\n\tlabelEdgeMargin: number\n\tminSizeWithLabel: number\n}\n\n/** @public */\nexport interface GeoShapeOptions extends ShapeOptionsWithDisplayValues<\n\tTLGeoShape,\n\tGeoShapeUtilDisplayValues\n> {\n\tshowTextOutline: boolean\n\t/**\n\t * A map of custom geo type definitions. Each key becomes a new value for\n\t * {@link @tldraw/editor#GeoShapeGeoStyle} that can be used in the style panel\n\t * and on shapes. Custom geo types inherit all standard geo shape behavior\n\t * (labels, resizing, styling, etc.).\n\t *\n\t * @example\n\t * ```ts\n\t * const MyGeoShapeUtil = GeoShapeUtil.configure({\n\t * customGeoTypes: {\n\t * 'my-shape': {\n\t * getPath: (w, h) => new PathBuilder().moveTo(0, 0).lineTo(w, 0).lineTo(w, h).lineTo(0, h).close(),\n\t * snapType: 'polygon',\n\t * icon: 'geo-rectangle',\n\t * },\n\t * },\n\t * })\n\t * ```\n\t */\n\tcustomGeoTypes?: Record<string, GeoTypeDefinition>\n}\n\n/** @public */\nexport class GeoShapeUtil extends BaseBoxShapeUtil<TLGeoShape> {\n\tstatic override type = 'geo' as const\n\tstatic override props = geoShapeProps\n\tstatic override migrations = geoShapeMigrations\n\n\tstatic override configure<T extends TLShapeUtilConstructor<any, any>>(\n\t\tthis: T,\n\t\toptions: T extends new (...args: any[]) => { options: infer Options } ? Partial<Options> : never\n\t): T {\n\t\tconst opts = options as Partial<GeoShapeOptions>\n\t\tif (opts.customGeoTypes) {\n\t\t\tconst validEntries: Array<[string, GeoTypeDefinition]> = []\n\t\t\tfor (const [key, def] of Object.entries(opts.customGeoTypes)) {\n\t\t\t\tif (BUILTIN_GEO_TYPES.has(key)) {\n\t\t\t\t\tif (process.env.NODE_ENV !== 'production') {\n\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t`[GeoShapeUtil.configure] customGeoTypes key \"${key}\" collides with a built-in geo type and will be ignored. Please use a unique name.`\n\t\t\t\t\t\t)\n\t\t\t\t\t}\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tvalidEntries.push([key, def])\n\t\t\t}\n\t\t\tif (validEntries.length > 0) {\n\t\t\t\tGeoShapeGeoStyle.addValues(\n\t\t\t\t\t...(validEntries.map(([k]) => k) as Parameters<typeof GeoShapeGeoStyle.addValues>)\n\t\t\t\t)\n\t\t\t}\n\t\t\t// Strip colliding entries from the options so runtime lookups (tool\n\t\t\t// defaultSize, style panel icons, double-click handlers) don't see them.\n\t\t\tconst filtered = { ...opts, customGeoTypes: Object.fromEntries(validEntries) }\n\t\t\treturn super.configure(filtered as unknown as typeof options) as T\n\t\t}\n\t\treturn super.configure(options) as T\n\t}\n\n\toverride options: GeoShapeOptions = {\n\t\tshowTextOutline: true,\n\t\tgetDefaultDisplayValues(_editor, shape, theme, colorMode): GeoShapeUtilDisplayValues {\n\t\t\tconst { color, size, labelColor, fill, align, verticalAlign, font } = shape.props\n\t\t\tconst colors = theme.colors[colorMode]\n\n\t\t\treturn {\n\t\t\t\tstrokeColor: getColorValue(colors, color, 'solid'),\n\t\t\t\tstrokeRoundness: theme.strokeWidth * STROKE_SIZES[size] * 2,\n\t\t\t\tstrokeWidth: theme.strokeWidth * STROKE_SIZES[size],\n\t\t\t\tfillColor:\n\t\t\t\t\tfill === 'none'\n\t\t\t\t\t\t? 'transparent'\n\t\t\t\t\t\t: fill === 'semi'\n\t\t\t\t\t\t\t? colors.solid\n\t\t\t\t\t\t\t: getColorValue(colors, color, DEFAULT_FILL_COLOR_NAMES[fill]),\n\t\t\t\tpatternFillFallbackColor: getColorValue(colors, color, 'semi'),\n\t\t\t\tlabelColor: getColorValue(colors, labelColor, 'solid'), // todo: separate from the solid color (or create more named colors in the palette so that these could be configured separately)\n\t\t\t\tlabelFontFamily: getFontFamily(theme, font),\n\t\t\t\tlabelFontSize: theme.fontSize * LABEL_FONT_SIZES[size],\n\t\t\t\tlabelMinWidth: GEO_SHAPE_MIN_WIDTHS[size],\n\t\t\t\tlabelExtraPadding: theme.strokeWidth * STROKE_SIZES[size],\n\t\t\t\tlabelLineHeight: theme.lineHeight,\n\t\t\t\tlabelFontWeight: 'normal',\n\t\t\t\tlabelFontVariant: 'normal',\n\t\t\t\tlabelFontStyle: 'normal',\n\t\t\t\tlabelHorizontalAlign: GEO_SHAPE_HORIZONTAL_ALIGNS[align],\n\t\t\t\tlabelVerticalAlign: GEO_SHAPE_VERTICAL_ALIGNS[verticalAlign],\n\t\t\t\tlabelPadding: LABEL_PADDING,\n\t\t\t\t// Margin between label edge and shape edge (in unscaled units)\n\t\t\t\tlabelEdgeMargin: 8,\n\t\t\t\t// Minimum size of the shape to fit a label, based on font size and padding (in unscaled units)\n\t\t\t\tminSizeWithLabel: (LABEL_PADDING + 1) * 3,\n\t\t\t}\n\t\t},\n\t\tgetCustomDisplayValues(_editor, _shape): Partial<GeoShapeUtilDisplayValues> {\n\t\t\treturn {}\n\t\t},\n\t}\n\n\toverride canEdit(shape: TLGeoShape) {\n\t\treturn true\n\t}\n\n\toverride getDefaultProps(): TLGeoShape['props'] {\n\t\treturn {\n\t\t\tw: 100,\n\t\t\th: 100,\n\t\t\tgeo: 'rectangle',\n\t\t\tdash: 'draw',\n\t\t\tgrowY: 0,\n\t\t\turl: '',\n\t\t\tscale: 1,\n\n\t\t\t// Text properties\n\t\t\tcolor: 'black',\n\t\t\tlabelColor: 'black',\n\t\t\tfill: 'none',\n\t\t\tsize: 'm',\n\t\t\tfont: 'draw',\n\t\t\talign: 'middle',\n\t\t\tverticalAlign: 'middle',\n\t\t\trichText: toRichText(''),\n\t\t}\n\t}\n\n\toverride getGeometry(shape: TLGeoShape) {\n\t\tconst { props } = shape\n\t\tconst { scale } = props\n\t\tconst dv = getDisplayValues(this, shape)\n\t\tconst path = getGeoShapePath(shape, dv.strokeWidth, this.options.customGeoTypes)\n\t\tconst pathGeometry = path.toGeometry()\n\n\t\tconst scaledW = Math.max(1, props.w)\n\t\tconst scaledH = Math.max(1, props.h + props.growY)\n\t\tconst unscaledShapeW = scaledW / scale\n\t\tconst unscaledShapeH = scaledH / scale\n\n\t\tconst isEmptyLabel = isEmptyRichText(props.richText)\n\t\tconst unscaledLabelSize = isEmptyLabel\n\t\t\t? GEO_SHAPE_EMPTY_LABEL_SIZE\n\t\t\t: this.getUnscaledLabelSize(shape)\n\n\t\t// Calculate minimum label dimensions based on font size and shape size\n\t\tconst unscaledMinWidth = Math.min(100, unscaledShapeW / 2)\n\t\tconst unscaledMinHeight = Math.min(\n\t\t\tdv.labelFontSize * dv.labelLineHeight + dv.labelPadding * 2,\n\t\t\tunscaledShapeH / 2\n\t\t)\n\n\t\t// Label dimensions: at least the measured size, but constrained to shape bounds\n\t\tconst unscaledLabelW = Math.min(\n\t\t\tunscaledShapeW,\n\t\t\tMath.max(\n\t\t\t\tunscaledLabelSize.w,\n\t\t\t\tMath.min(unscaledMinWidth, Math.max(1, unscaledShapeW - dv.labelEdgeMargin))\n\t\t\t)\n\t\t)\n\t\tconst unscaledLabelH = Math.min(\n\t\t\tunscaledShapeH,\n\t\t\tMath.max(\n\t\t\t\tunscaledLabelSize.h,\n\t\t\t\tMath.min(unscaledMinHeight, Math.max(1, unscaledShapeH - dv.labelEdgeMargin))\n\t\t\t)\n\t\t)\n\n\t\t// Calculate position based on alignment\n\t\tconst unscaledX =\n\t\t\tdv.labelHorizontalAlign === 'start'\n\t\t\t\t? 0\n\t\t\t\t: dv.labelHorizontalAlign === 'end'\n\t\t\t\t\t? unscaledShapeW - unscaledLabelW\n\t\t\t\t\t: (unscaledShapeW - unscaledLabelW) / 2\n\n\t\tconst unscaledY =\n\t\t\tdv.labelVerticalAlign === 'start'\n\t\t\t\t? 0\n\t\t\t\t: dv.labelVerticalAlign === 'end'\n\t\t\t\t\t? unscaledShapeH - unscaledLabelH\n\t\t\t\t\t: (unscaledShapeH - unscaledLabelH) / 2\n\n\t\tconst labelBounds = {\n\t\t\tx: unscaledX * scale,\n\t\t\ty: unscaledY * scale,\n\t\t\twidth: unscaledLabelW * scale,\n\t\t\theight: unscaledLabelH * scale,\n\t\t}\n\n\t\treturn new Group2d({\n\t\t\tchildren: [\n\t\t\t\tpathGeometry,\n\t\t\t\tnew Rectangle2d({\n\t\t\t\t\t...labelBounds,\n\t\t\t\t\tisFilled: true,\n\t\t\t\t\tisLabel: true,\n\t\t\t\t\texcludeFromShapeBounds: true,\n\t\t\t\t\tisEmptyLabel: isEmptyLabel,\n\t\t\t\t}),\n\t\t\t],\n\t\t})\n\t}\n\n\toverride getHandleSnapGeometry(shape: TLGeoShape): HandleSnapGeometry {\n\t\tconst geometry = this.getGeometry(shape)\n\t\t// we only want to snap handles to the outline of the shape - not to its label etc.\n\t\tconst outline = geometry.children[0]\n\t\tconst def = getGeoTypeDefinition(shape.props.geo, this.options.customGeoTypes)\n\t\tif (!def) {\n\t\t\tthrow new Error(`Unknown geo type: ${shape.props.geo}`)\n\t\t}\n\t\t// blobby shapes only snap to the center; polygon shapes snap to vertices + center.\n\t\tif (def.snapType === 'blobby') {\n\t\t\treturn { outline: outline, points: [geometry.bounds.center] }\n\t\t}\n\t\treturn { outline: outline, points: [...outline.vertices, geometry.bounds.center] }\n\t}\n\n\toverride getText(shape: TLGeoShape) {\n\t\treturn renderPlaintextFromRichText(this.editor, shape.props.richText)\n\t}\n\n\toverride getFontFaces(shape: TLGeoShape) {\n\t\tif (isEmptyRichText(shape.props.richText)) {\n\t\t\treturn EMPTY_ARRAY\n\t\t}\n\t\tconst themeFaces = getThemeFontFaces(this.editor.getCurrentTheme(), shape.props.font)\n\t\tif (themeFaces) return themeFaces\n\t\treturn getFontsFromRichText(this.editor, shape.props.richText, {\n\t\t\tfamily: `tldraw_${shape.props.font}`,\n\t\t\tweight: 'normal',\n\t\t\tstyle: 'normal',\n\t\t})\n\t}\n\n\tcomponent(shape: TLGeoShape) {\n\t\tconst { id, type, props } = shape\n\t\tconst { editor } = this\n\t\tconst isOnlySelected = useValue(\n\t\t\t'isGeoOnlySelected',\n\t\t\t() => shape.id === editor.getOnlySelectedShapeId(),\n\t\t\t[editor]\n\t\t)\n\t\tconst isReadyForEditing = useIsReadyForEditing(editor, shape.id)\n\t\tconst isForceSolid = useEfficientZoomThreshold(0.25 / shape.props.scale)\n\t\tconst colorMode = useColorMode()\n\t\tconst dv = getDisplayValues(this, shape, colorMode)\n\n\t\tconst { w, h, richText, url } = props\n\n\t\tconst isEmpty = isEmptyRichText(richText)\n\t\tconst showHtmlContainer = isReadyForEditing || !isEmpty\n\n\t\treturn (\n\t\t\t<>\n\t\t\t\t<SVGContainer>\n\t\t\t\t\t<GeoShapeBody\n\t\t\t\t\t\tshape={shape}\n\t\t\t\t\t\tshouldScale={true}\n\t\t\t\t\t\tforceSolid={isForceSolid}\n\t\t\t\t\t\tstrokeColor={dv.strokeColor}\n\t\t\t\t\t\tstrokeWidth={dv.strokeWidth}\n\t\t\t\t\t\tfillColor={dv.fillColor}\n\t\t\t\t\t\tpatternFillFallbackColor={dv.patternFillFallbackColor}\n\t\t\t\t\t\tcustomGeoTypes={this.options.customGeoTypes}\n\t\t\t\t\t/>\n\t\t\t\t</SVGContainer>\n\t\t\t\t{showHtmlContainer && (\n\t\t\t\t\t<HTMLContainer\n\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\toverflow: 'hidden',\n\t\t\t\t\t\t\twidth: w,\n\t\t\t\t\t\t\theight: h + props.growY,\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t<RichTextLabel\n\t\t\t\t\t\t\tshapeId={id}\n\t\t\t\t\t\t\ttype={type}\n\t\t\t\t\t\t\tfontFamily={dv.labelFontFamily}\n\t\t\t\t\t\t\tfontSize={dv.labelFontSize}\n\t\t\t\t\t\t\tlineHeight={dv.labelLineHeight}\n\t\t\t\t\t\t\tpadding={dv.labelPadding}\n\t\t\t\t\t\t\ttextAlign={dv.labelHorizontalAlign}\n\t\t\t\t\t\t\tverticalAlign={dv.labelVerticalAlign}\n\t\t\t\t\t\t\trichText={richText}\n\t\t\t\t\t\t\tisSelected={isOnlySelected}\n\t\t\t\t\t\t\tlabelColor={dv.labelColor}\n\t\t\t\t\t\t\twrap\n\t\t\t\t\t\t\tshowTextOutline={this.options.showTextOutline}\n\t\t\t\t\t\t\tstyle={\n\t\t\t\t\t\t\t\tshape.props.scale !== 1\n\t\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\t\ttransform: `scale(${shape.props.scale})`,\n\t\t\t\t\t\t\t\t\t\t\ttransformOrigin: 'top left',\n\t\t\t\t\t\t\t\t\t\t\twidth: shape.props.w / shape.props.scale,\n\t\t\t\t\t\t\t\t\t\t\theight: (shape.props.h + props.growY) / shape.props.scale,\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t: undefined\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</HTMLContainer>\n\t\t\t\t)}\n\t\t\t\t{url && <HyperlinkButton url={url} />}\n\t\t\t</>\n\t\t)\n\t}\n\n\toverride getIndicatorPath(shape: TLGeoShape): Path2D | undefined {\n\t\tconst isForceSolid = this.editor.getEfficientZoomLevel() < 0.25 / shape.props.scale\n\n\t\tconst { dash, scale } = shape.props\n\t\tconst dv = getDisplayValues(this, shape)\n\n\t\tconst path = getGeoShapePath(shape, dv.strokeWidth, this.options.customGeoTypes)\n\n\t\treturn path.toPath2D({\n\t\t\tstyle: dash === 'draw' ? 'draw' : 'solid',\n\t\t\tstrokeWidth: 1,\n\t\t\tpasses: 1,\n\t\t\trandomSeed: shape.id,\n\t\t\toffset: 0,\n\t\t\troundness: dv.strokeRoundness * scale,\n\t\t\tforceSolid: isForceSolid,\n\t\t})\n\t}\n\n\toverride toSvg(shape: TLGeoShape, ctx: SvgExportContext) {\n\t\tconst dv = getDisplayValues(this, shape, ctx.colorMode)\n\t\tconst { richText, fill, scale, growY, w, h } = shape.props\n\t\t// We need to scale the shape to 1x for export\n\t\tconst newShape = {\n\t\t\t...shape,\n\t\t\tprops: {\n\t\t\t\t...shape.props,\n\t\t\t\tw: w / scale,\n\t\t\t\th: (h + growY) / scale,\n\t\t\t\tgrowY: 0, // growY throws off the path calculations, so we set it to 0\n\t\t\t},\n\t\t}\n\t\tctx.addExportDef(getFillDefForExport(fill))\n\n\t\tlet textEl\n\t\tif (!isEmptyRichText(richText)) {\n\t\t\tconst bounds = new Box(0, 0, newShape.props.w, (h + growY) / scale)\n\t\t\ttextEl = (\n\t\t\t\t<RichTextSVG\n\t\t\t\t\tfontSize={dv.labelFontSize}\n\t\t\t\t\tfontFamily={dv.labelFontFamily}\n\t\t\t\t\tlineHeight={dv.labelLineHeight}\n\t\t\t\t\ttextAlign={dv.labelHorizontalAlign}\n\t\t\t\t\tverticalAlign={dv.labelVerticalAlign}\n\t\t\t\t\tlabelColor={dv.labelColor}\n\t\t\t\t\tpadding={dv.labelPadding}\n\t\t\t\t\tshowTextOutline={this.options.showTextOutline}\n\t\t\t\t\tbounds={bounds}\n\t\t\t\t\trichText={richText}\n\t\t\t\t/>\n\t\t\t)\n\t\t}\n\n\t\treturn (\n\t\t\t<>\n\t\t\t\t<GeoShapeBody\n\t\t\t\t\tshouldScale={false}\n\t\t\t\t\tshape={newShape}\n\t\t\t\t\tforceSolid={false}\n\t\t\t\t\tstrokeColor={dv.strokeColor}\n\t\t\t\t\tstrokeWidth={dv.strokeWidth}\n\t\t\t\t\tfillColor={dv.fillColor}\n\t\t\t\t\tpatternFillFallbackColor={dv.patternFillFallbackColor}\n\t\t\t\t\tcustomGeoTypes={this.options.customGeoTypes}\n\t\t\t\t/>\n\t\t\t\t{textEl}\n\t\t\t</>\n\t\t)\n\t}\n\n\toverride getCanvasSvgDefs(): TLShapeUtilCanvasSvgDef[] {\n\t\treturn [getFillDefForCanvas()]\n\t}\n\n\toverride onResize(\n\t\tshape: TLGeoShape,\n\t\t{ handle, newPoint, scaleX, scaleY, initialShape }: TLResizeInfo<TLGeoShape>\n\t) {\n\t\tconst unscaledInitial = this.getUnscaledGeoProps(initialShape.props)\n\t\t// use the w/h from props here instead of the initialBounds here,\n\t\t// since cloud shapes calculated bounds can differ from the props w/h.\n\t\tlet unscaledW = unscaledInitial.w * scaleX\n\t\tlet unscaledH = (unscaledInitial.h + unscaledInitial.growY) * scaleY\n\t\tlet overShrinkX = 0\n\t\tlet overShrinkY = 0\n\n\t\tconst dv = getDisplayValues(this, shape)\n\n\t\tif (!isEmptyRichText(shape.props.richText)) {\n\t\t\tconst absUnscaledW = Math.abs(unscaledW)\n\t\t\tconst absUnscaledH = Math.abs(unscaledH)\n\t\t\t// Check the batch cache first (set by Resizing.ts during multi-shape resize).\n\t\t\t// If not cached, measure the label at the constrained target dimensions so text\n\t\t\t// wrapping is accounted for. We call measureUnscaledLabelSize directly (bypassing\n\t\t\t// WeakCache) since temp shapes with resize dimensions change every frame.\n\t\t\tconst cached = getBatchLabelSizeCache(this.editor)?.get(shape.id)\n\t\t\tlet unscaledLabelSize: { w: number; h: number }\n\t\t\tif (cached) {\n\t\t\t\tunscaledLabelSize = cached\n\t\t\t} else {\n\t\t\t\tconst measureW = Math.max(absUnscaledW, dv.minSizeWithLabel)\n\t\t\t\tconst measureH = Math.max(absUnscaledH, dv.minSizeWithLabel)\n\t\t\t\tunscaledLabelSize = this.measureUnscaledLabelSize({\n\t\t\t\t\t...shape,\n\t\t\t\t\tprops: {\n\t\t\t\t\t\t...shape.props,\n\t\t\t\t\t\tw: measureW * shape.props.scale,\n\t\t\t\t\t\th: measureH * shape.props.scale,\n\t\t\t\t\t},\n\t\t\t\t} as TLGeoShape)\n\t\t\t}\n\n\t\t\tconst constrainedW = Math.max(absUnscaledW, unscaledLabelSize.w)\n\t\t\tconst constrainedH = Math.max(absUnscaledH, unscaledLabelSize.h)\n\n\t\t\toverShrinkX = constrainedW - absUnscaledW\n\t\t\toverShrinkY = constrainedH - absUnscaledH\n\n\t\t\tunscaledW = constrainedW * Math.sign(unscaledW || 1)\n\t\t\tunscaledH = constrainedH * Math.sign(unscaledH || 1)\n\t\t}\n\n\t\tconst scaledW = unscaledW * shape.props.scale\n\t\tconst scaledH = unscaledH * shape.props.scale\n\n\t\tconst offset = new Vec(0, 0)\n\n\t\t// x offsets\n\n\t\tif (scaleX < 0) {\n\t\t\toffset.x += scaledW\n\t\t}\n\n\t\tif (handle === 'left' || handle === 'top_left' || handle === 'bottom_left') {\n\t\t\toffset.x += scaleX < 0 ? overShrinkX : -overShrinkX\n\t\t}\n\n\t\t// y offsets\n\n\t\tif (scaleY < 0) {\n\t\t\toffset.y += scaledH\n\t\t}\n\n\t\tif (handle === 'top' || handle === 'top_left' || handle === 'top_right') {\n\t\t\toffset.y += scaleY < 0 ? overShrinkY : -overShrinkY\n\t\t}\n\n\t\tconst { x, y } = offset.rot(shape.rotation).add(newPoint)\n\n\t\treturn {\n\t\t\tx,\n\t\t\ty,\n\t\t\tprops: {\n\t\t\t\tw: Math.max(Math.abs(scaledW), 1),\n\t\t\t\th: Math.max(Math.abs(scaledH), 1),\n\t\t\t\tgrowY: 0,\n\t\t\t},\n\t\t}\n\t}\n\n\toverride onBeforeCreate(shape: TLGeoShape) {\n\t\tconst { props } = shape\n\n\t\t// No text - ensure growY is 0\n\t\tif (isEmptyRichText(props.richText)) {\n\t\t\treturn props.growY !== 0 ? { ...shape, props: { ...props, growY: 0 } } : undefined\n\t\t}\n\n\t\t// Has text - calculate growY needed to fit label\n\t\tconst unscaledShapeH = props.h / props.scale\n\t\tconst unscaledLabelH = this.getUnscaledLabelSize(shape).h\n\t\tconst unscaledGrowY = this.calculateGrowY(\n\t\t\tunscaledShapeH,\n\t\t\tunscaledLabelH,\n\t\t\tprops.growY / props.scale\n\t\t)\n\n\t\tif (unscaledGrowY !== null) {\n\t\t\treturn {\n\t\t\t\t...shape,\n\t\t\t\tprops: { ...props, growY: unscaledGrowY * props.scale },\n\t\t\t}\n\t\t}\n\n\t\treturn undefined\n\t}\n\n\toverride onBeforeUpdate(prev: TLGeoShape, next: TLGeoShape) {\n\t\tconst { props: prevProps } = prev\n\t\tconst { props: nextProps } = next\n\n\t\t// No change to text, font, or size - no update needed\n\t\tif (\n\t\t\tisEqual(prevProps.richText, nextProps.richText) &&\n\t\t\tprevProps.font === nextProps.font &&\n\t\t\tprevProps.size === nextProps.size\n\t\t) {\n\t\t\treturn undefined\n\t\t}\n\n\t\tconst wasEmpty = isEmptyRichText(prevProps.richText)\n\t\tconst isEmpty = isEmptyRichText(nextProps.richText)\n\n\t\t// If label is empty and used to be empty, skip label measurement and dimension adjustment\n\t\tif (wasEmpty && isEmpty) {\n\t\t\treturn undefined\n\t\t}\n\n\t\t// Text was removed - reset growY\n\t\tif (isEmpty) {\n\t\t\treturn nextProps.growY !== 0 ? { ...next, props: { ...nextProps, growY: 0 } } : undefined\n\t\t}\n\n\t\tconst unscaledPrev = this.getUnscaledGeoProps(prevProps)\n\t\tconst unscaledLabelSize = this.getUnscaledLabelSize(next)\n\t\tconst { scale } = nextProps\n\n\t\t// Text was added for the first time - expand shape to fit (if wasEmpty and now there's text...\n\t\t// It might be just whitespace but it is faster to assume that it is NOT just whitespace and expand\n\t\t// the shape in either case (a label with just spaces text will be less performant but that's acceptable)\n\t\tif (wasEmpty && !isEmpty) {\n\t\t\tconst expanded = this.expandShapeForFirstLabel(\n\t\t\t\tnext,\n\t\t\t\tunscaledPrev.w,\n\t\t\t\tunscaledPrev.h,\n\t\t\t\tunscaledLabelSize\n\t\t\t)\n\t\t\treturn {\n\t\t\t\t...next,\n\t\t\t\tprops: {\n\t\t\t\t\t...nextProps,\n\t\t\t\t\tw: expanded.w * scale,\n\t\t\t\t\th: expanded.h * scale,\n\t\t\t\t\tgrowY: 0,\n\t\t\t\t},\n\t\t\t}\n\t\t}\n\n\t\t// Text was modified - adjust dimensions to fit new label\n\t\tconst unscaledNextW = next.props.w / scale\n\t\tconst needsWidthExpand = unscaledLabelSize.w > unscaledNextW\n\t\tconst unscaledGrowY = this.calculateGrowY(\n\t\t\tunscaledPrev.h,\n\t\t\tunscaledLabelSize.h,\n\t\t\tunscaledPrev.growY\n\t\t)\n\n\t\tif (unscaledGrowY !== null || needsWidthExpand) {\n\t\t\treturn {\n\t\t\t\t...next,\n\t\t\t\tprops: {\n\t\t\t\t\t...nextProps,\n\t\t\t\t\tgrowY: (unscaledGrowY ?? unscaledPrev.growY) * scale,\n\t\t\t\t\tw: Math.max(unscaledNextW, unscaledLabelSize.w) * scale,\n\t\t\t\t},\n\t\t\t}\n\t\t}\n\n\t\treturn undefined\n\t}\n\n\toverride onDoubleClick(shape: TLGeoShape) {\n\t\t// Little easter egg: double-clicking a rectangle / checkbox while\n\t\t// holding alt will toggle between check-box and rectangle\n\t\tif (this.editor.inputs.getAltKey()) {\n\t\t\tswitch (shape.props.geo) {\n\t\t\t\tcase 'rectangle': {\n\t\t\t\t\treturn {\n\t\t\t\t\t\t...shape,\n\t\t\t\t\t\tprops: {\n\t\t\t\t\t\t\tgeo: 'check-box' as const,\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcase 'check-box': {\n\t\t\t\t\treturn {\n\t\t\t\t\t\t...shape,\n\t\t\t\t\t\tprops: {\n\t\t\t\t\t\t\tgeo: 'rectangle' as const,\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst def = getGeoTypeDefinition(shape.props.geo, this.options.customGeoTypes)\n\t\tif (def?.onDoubleClick) {\n\t\t\tconst result = def.onDoubleClick(shape)\n\t\t\tif (result) {\n\t\t\t\treturn { ...shape, props: { ...shape.props, ...result.props } }\n\t\t\t}\n\t\t}\n\n\t\treturn\n\t}\n\n\toverride getInterpolatedProps(\n\t\tstartShape: TLGeoShape,\n\t\tendShape: TLGeoShape,\n\t\tt: number\n\t): TLGeoShapeProps {\n\t\treturn {\n\t\t\t...(t > 0.5 ? endShape.props : startShape.props),\n\t\t\tw: lerp(startShape.props.w, endShape.props.w, t),\n\t\t\th: lerp(startShape.props.h, endShape.props.h, t),\n\t\t\tscale: lerp(startShape.props.scale, endShape.props.scale, t),\n\t\t}\n\t}\n\n\t/**\n\t * Get the unscaled dimensions from a geo shape's props\n\t */\n\tprivate getUnscaledGeoProps(props: TLGeoShapeProps) {\n\t\tconst { w, h, growY, scale } = props\n\t\treturn {\n\t\t\tw: w / scale,\n\t\t\th: h / scale,\n\t\t\tgrowY: growY / scale,\n\t\t}\n\t}\n\n\t/**\n\t * Calculate the growY needed to fit a label within a shape.\n\t * Returns null if no change is needed, otherwise returns the new unscaled growY value.\n\t */\n\tprivate calculateGrowY(\n\t\tunscaledShapeH: number,\n\t\tunscaledLabelH: number,\n\t\tunscaledCurrentGrowY: number\n\t): number | null {\n\t\tif (unscaledLabelH > unscaledShapeH) {\n\t\t\t// Label is taller than shape - need to grow\n\t\t\treturn unscaledLabelH - unscaledShapeH\n\t\t}\n\t\tif (unscaledCurrentGrowY > 0) {\n\t\t\t// Label fits and we have existing growY - reset it\n\t\t\treturn 0\n\t\t}\n\t\t// No change needed\n\t\treturn null\n\t}\n\n\t/**\n\t * Calculate expanded dimensions when adding a label to a shape for the first time.\n\t * Ensures the shape meets minimum size requirements and is square if originally small.\n\t */\n\tprivate expandShapeForFirstLabel(\n\t\tshape: TLGeoShape,\n\t\tunscaledW: number,\n\t\tunscaledH: number,\n\t\tunscaledLabelSize: { w: number; h: number }\n\t): { w: number; h: number } {\n\t\tlet w = Math.max(unscaledW, unscaledLabelSize.w)\n\t\tlet h = Math.max(unscaledH, unscaledLabelSize.h)\n\n\t\tconst dv = getDisplayValues(this, shape)\n\n\t\t// If shape was smaller than min size in both dimensions, make it square\n\t\tif (unscaledW < dv.minSizeWithLabel && unscaledH < dv.minSizeWithLabel) {\n\t\t\tw = Math.max(w, dv.minSizeWithLabel)\n\t\t\th = Math.max(h, dv.minSizeWithLabel)\n\t\t\t// Make square by using the larger dimension\n\t\t\tconst maxDim = Math.max(w, h)\n\t\t\tw = maxDim\n\t\t\th = maxDim\n\t\t}\n\n\t\treturn { w, h }\n\t}\n\n\tprivate _labelSizesForGeoCache = new WeakCache<TLGeoShape, { w: number; h: number }>()\n\n\t/**\n\t * Get the cached label size for the shape. Don't call with empty rich text.\n\t */\n\tprivate getUnscaledLabelSize(shape: TLGeoShape) {\n\t\tconst batchCached = getBatchLabelSizeCache(this.editor)?.get(shape.id)\n\t\tif (batchCached) return batchCached\n\n\t\treturn this._labelSizesForGeoCache.get(shape, () => {\n\t\t\treturn this.measureUnscaledLabelSize(shape)\n\t\t})\n\t}\n\n\t/**\n\t * Expensively measure the unscaled label size for the shape. Avoid using it if we can.\n\t */\n\tprivate measureUnscaledLabelSize(shape: TLGeoShape) {\n\t\tconst dv = getDisplayValues(this, shape)\n\n\t\tconst html = renderHtmlFromRichTextForMeasurement(this.editor, shape.props.richText)\n\n\t\tconst textSize = this.editor.textMeasure.measureHtml(html, {\n\t\t\t...TEXT_PROPS,\n\t\t\tfontFamily: dv.labelFontFamily,\n\t\t\tfontSize: dv.labelFontSize,\n\t\t\tlineHeight: dv.labelLineHeight,\n\t\t\tminWidth: dv.labelMinWidth,\n\t\t\tmaxWidth: Math.max(\n\t\t\t\t// Guard because a DOM nodes can't be less 0\n\t\t\t\t0,\n\t\t\t\t// A 'w' width that we're setting as the min-width\n\t\t\t\tMath.ceil(dv.labelMinWidth + dv.labelExtraPadding),\n\t\t\t\t// The actual text size\n\t\t\t\tMath.ceil(shape.props.w / shape.props.scale - dv.labelPadding * 2)\n\t\t\t),\n\t\t})\n\n\t\treturn {\n\t\t\tw: textSize.w + dv.labelPadding * 2,\n\t\t\th: textSize.h + dv.labelPadding * 2,\n\t\t}\n\t}\n}\n\nconst MIN_SIZE_WITH_LABEL = (LABEL_PADDING + 1) * 3\nconst MIN_WIDTHS = GEO_SHAPE_MIN_WIDTHS\n\n// Per-editor batch cache, set by batchMeasureGeoLabels before the resize loop and cleared after.\n// When set, onResize will use pre-computed label sizes instead of measuring individually.\n// Uses a WeakMap keyed by editor to avoid issues with multiple editors on the same page.\nconst _batchLabelSizeCaches = new WeakMap<Editor, Map<TLShapeId, { w: number; h: number }>>()\n\n/** @internal */\nexport function setBatchLabelSizeCache(\n\teditor: Editor,\n\tcache: Map<TLShapeId, { w: number; h: number }> | null\n) {\n\tif (cache) {\n\t\t_batchLabelSizeCaches.set(editor, cache)\n\t} else {\n\t\t_batchLabelSizeCaches.delete(editor)\n\t}\n}\n\nfunction getBatchLabelSizeCache(editor: Editor) {\n\treturn _batchLabelSizeCaches.get(editor)\n}\n\n/**\n * Build the measurement request params (html + opts) for a geo shape's label\n * without actually performing the measurement. Used by batch measurement.\n */\nfunction getGeoLabelMeasurementRequest(\n\teditor: Editor,\n\tshape: TLGeoShape\n): { html: string; opts: TLMeasureTextOpts } {\n\tconst { richText, font, size, w } = shape.props\n\tconst theme = editor.getCurrentTheme()\n\tconst minWidth = MIN_WIDTHS[size]\n\tconst html = renderHtmlFromRichTextForMeasurement(editor, richText)\n\tconst opts: TLMeasureTextOpts = {\n\t\t...TEXT_PROPS,\n\t\tfontFamily: getFontFamily(theme, font),\n\t\tfontSize: theme.fontSize * LABEL_FONT_SIZES[size],\n\t\tlineHeight: theme.lineHeight,\n\t\tminWidth: minWidth,\n\t\tmaxWidth: Math.max(\n\t\t\t// Guard because a DOM node can't be less than 0\n\t\t\t0,\n\t\t\t// A 'w' width that we're setting as the min-width\n\t\t\tMath.ceil(minWidth + theme.strokeWidth * STROKE_SIZES[size]),\n\t\t\t// The actual text size\n\t\t\tMath.ceil(w / shape.props.scale - LABEL_PADDING * 2)\n\t\t),\n\t}\n\treturn { html, opts }\n}\n\n/**\n * Compute the target unscaled width for label measurement during resize.\n * This replicates the measureW computation from onResize so batch measurement can\n * build measurement requests without duplicating GeoShapeUtil internals.\n */\nfunction getGeoResizeTargetWidth(initialProps: TLGeoShapeProps, scaleX: number): number {\n\tconst unscaledInitialW = initialProps.w / initialProps.scale\n\tconst absUnscaledW = Math.abs(unscaledInitialW * scaleX)\n\treturn Math.max(absUnscaledW, MIN_SIZE_WITH_LABEL)\n}\n\n/**\n * Batch-measure all geo shape labels before the resize loop to avoid layout thrashing.\n * For each geo shape with a non-empty label that has compatible rotation, compute the\n * measurement request and batch all measurements in a single DOM pass.\n * Sets the per-editor batch cache so onResize and getGeometry can use pre-computed sizes.\n * @internal\n */\nexport function batchMeasureGeoLabels(\n\teditor: Editor,\n\tshapeSnapshots: Map<\n\t\tTLShapeId,\n\t\t{\n\t\t\tshape: TLShape\n\t\t\tpageRotation: number\n\t\t\tisAspectRatioLocked: boolean\n\t\t}\n\t>,\n\tscale: VecLike,\n\tselectionRotation: number,\n\tisAspectRatioLocked: boolean\n) {\n\tconst requests: Array<{ id: TLShapeId; html: string; opts: TLMeasureTextOpts }> = []\n\n\tfor (const [id, snapshot] of shapeSnapshots) {\n\t\t// Only process geo shapes with non-empty text labels\n\t\tif (!editor.isShapeOfType<TLGeoShape>(snapshot.shape, 'geo')) continue\n\t\tconst geoShape = snapshot.shape as TLGeoShape\n\t\tif (isEmptyRichText(geoShape.props.richText)) continue\n\n\t\t// Skip unaligned shapes \u2014 they take a different resize path (_resizeUnalignedShape)\n\t\t// and won't use the standard onResize, so caching wouldn't help.\n\t\tif (!areAnglesCompatible(snapshot.pageRotation, selectionRotation)) continue\n\n\t\t// Compute the effective scaleX for this shape, replicating Editor.resizeShape logic.\n\t\t// Shapes rotated 90\u00B0 from the selection axis have their x/y scale swapped.\n\t\tconst areWidthAndHeightAlignedWithCorrectAxis = approximately(\n\t\t\t(snapshot.pageRotation - selectionRotation) % Math.PI,\n\t\t\t0\n\t\t)\n\n\t\tlet effectiveScaleX: number\n\t\tif (isAspectRatioLocked || snapshot.isAspectRatioLocked) {\n\t\t\t// When aspect ratio is locked, both axes get the same absolute scale\n\t\t\tconst uniformScale = Math.max(Math.abs(scale.x), Math.abs(scale.y))\n\t\t\teffectiveScaleX = uniformScale\n\t\t} else {\n\t\t\teffectiveScaleX = Math.abs(areWidthAndHeightAlignedWithCorrectAxis ? scale.x : scale.y)\n\t\t}\n\n\t\t// Compute the target width for measurement (same logic as onResize)\n\t\tconst targetW = getGeoResizeTargetWidth(geoShape.props, effectiveScaleX)\n\n\t\t// Build a temporary shape with the target width for measurement\n\t\tconst tempShape = {\n\t\t\t...geoShape,\n\t\t\tprops: {\n\t\t\t\t...geoShape.props,\n\t\t\t\tw: targetW * geoShape.props.scale,\n\t\t\t},\n\t\t} as TLGeoShape\n\n\t\tconst { html, opts } = getGeoLabelMeasurementRequest(editor, tempShape)\n\t\trequests.push({ id, html, opts })\n\t}\n\n\tif (requests.length === 0) return\n\n\t// Batch measure all labels in one DOM pass\n\tconst results = editor.textMeasure.measureHtmlBatch(\n\t\trequests.map(({ html, opts }) => ({ html, opts }))\n\t)\n\n\t// Build the cache map with label sizes (adding padding)\n\tconst cache = new Map<TLShapeId, { w: number; h: number }>()\n\tfor (let i = 0; i < requests.length; i++) {\n\t\tcache.set(requests[i].id, {\n\t\t\tw: results[i].w + LABEL_PADDING * 2,\n\t\t\th: results[i].h + LABEL_PADDING * 2,\n\t\t})\n\t}\n\n\tsetBatchLabelSizeCache(editor, cache)\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["/* eslint-disable react-hooks/rules-of-hooks */\nimport {\n\tBaseBoxShapeUtil,\n\tBox,\n\tEMPTY_ARRAY,\n\tEditor,\n\tGeoShapeGeoStyle,\n\tGroup2d,\n\tHTMLContainer,\n\tHandleSnapGeometry,\n\tRectangle2d,\n\tSVGContainer,\n\tSvgExportContext,\n\tTLGeoShape,\n\tTLGeoShapeProps,\n\tTLMeasureTextOpts,\n\tTLResizeInfo,\n\tTLShape,\n\tTLShapeId,\n\tTLShapeUtilCanvasSvgDef,\n\tTLShapeUtilConstructor,\n\tVec,\n\tVecLike,\n\tWeakCache,\n\tapproximately,\n\tareAnglesCompatible,\n\tgeoShapeMigrations,\n\tgeoShapeProps,\n\tgetColorValue,\n\tgetFontsFromRichText,\n\tisEqual,\n\tlerp,\n\tresolveLineHeightPx,\n\ttoRichText,\n\tuseColorMode,\n\tuseValue,\n} from '@tldraw/editor'\nimport {\n\tisEmptyRichText,\n\trenderHtmlFromRichTextForMeasurement,\n\trenderPlaintextFromRichText,\n} from '../../utils/text/richText'\nimport {\n\tLABEL_FONT_SIZES,\n\tLABEL_PADDING,\n\tSTROKE_SIZES,\n\tTEXT_PROPS,\n\tgetFontFamily,\n} from '../shared/default-shape-constants'\nimport { DEFAULT_FILL_COLOR_NAMES } from '../shared/defaultFills'\nimport { getThemeFontFaces } from '../shared/defaultFonts'\nimport { getFillDefForCanvas, getFillDefForExport } from '../shared/defaultStyleDefs'\nimport { ShapeOptionsWithDisplayValues, getDisplayValues } from '../shared/getDisplayValues'\nimport { HyperlinkButton } from '../shared/HyperlinkButton'\nimport { RichTextLabel, RichTextSVG } from '../shared/RichTextLabel'\nimport { useIsReadyForEditing } from '../shared/useEditablePlainText'\nimport { useEfficientZoomThreshold } from '../shared/useEfficientZoomThreshold'\nimport { GeoShapeBody } from './GeoShapeBody'\nimport {\n\tdefaultGeoTypeDefinitions,\n\ttype GeoTypeDefinition,\n\tgetGeoShapePath,\n\tgetGeoTypeDefinition,\n} from './getGeoShapePath'\n\n// imperfect but good enough, should be the width of the W in the font / size combo\nconst GEO_SHAPE_MIN_WIDTHS = Object.freeze({\n\ts: 12,\n\tm: 14,\n\tl: 16,\n\txl: 20,\n})\n\n// Extra padding for geo shape labels matches the stroke width\n// Computed dynamically in getDisplayValues via theme.strokeWidth * STROKE_SIZES[size]\n\nconst GEO_SHAPE_HORIZONTAL_ALIGNS = Object.freeze({\n\tstart: 'start',\n\tmiddle: 'center',\n\tend: 'end',\n\t'start-legacy': 'start',\n\t'end-legacy': 'end',\n\t'middle-legacy': 'center',\n} as const)\n\nconst GEO_SHAPE_VERTICAL_ALIGNS = Object.freeze({\n\tstart: 'start',\n\tmiddle: 'middle',\n\tend: 'end',\n} as const)\n\nconst GEO_SHAPE_EMPTY_LABEL_SIZE = Object.freeze({ w: 0, h: 0 })\n\n// Snapshot the built-in geo types at module init so that collision detection\n// in `configure()` only fires against the built-ins, not against keys added\n// by previous `configure()` calls. This lets repeat `configure()` calls reuse\n// the same custom key (e.g. when wrapping/extending the util) without having\n// the entry stripped from `options.customGeoTypes`.\nconst BUILTIN_GEO_TYPES: ReadonlySet<string> = new Set(Object.keys(defaultGeoTypeDefinitions))\n\n/** @public */\nexport interface GeoShapeUtilDisplayValues {\n\tstrokeColor: string\n\tstrokeRoundness: number\n\tstrokeWidth: number\n\tfillColor: string\n\tpatternFillFallbackColor: string\n\tlabelColor: string\n\tlabelFontFamily: string\n\tlabelFontSize: number\n\tlabelMinWidth: number\n\tlabelExtraPadding: number\n\tlabelLineHeight: number\n\tlabelFontWeight: string\n\tlabelFontVariant: string\n\tlabelFontStyle: string\n\tlabelHorizontalAlign: 'start' | 'center' | 'end'\n\tlabelVerticalAlign: 'start' | 'middle' | 'end'\n\tlabelPadding: number\n\tlabelEdgeMargin: number\n\tminSizeWithLabel: number\n}\n\n/** @public */\nexport interface GeoShapeOptions extends ShapeOptionsWithDisplayValues<\n\tTLGeoShape,\n\tGeoShapeUtilDisplayValues\n> {\n\tshowTextOutline: boolean\n\t/**\n\t * A map of custom geo type definitions. Each key becomes a new value for\n\t * {@link @tldraw/editor#GeoShapeGeoStyle} that can be used in the style panel\n\t * and on shapes. Custom geo types inherit all standard geo shape behavior\n\t * (labels, resizing, styling, etc.).\n\t *\n\t * @example\n\t * ```ts\n\t * const MyGeoShapeUtil = GeoShapeUtil.configure({\n\t * customGeoTypes: {\n\t * 'my-shape': {\n\t * getPath: (w, h) => new PathBuilder().moveTo(0, 0).lineTo(w, 0).lineTo(w, h).lineTo(0, h).close(),\n\t * snapType: 'polygon',\n\t * icon: 'geo-rectangle',\n\t * },\n\t * },\n\t * })\n\t * ```\n\t */\n\tcustomGeoTypes?: Record<string, GeoTypeDefinition>\n}\n\n/** @public */\nexport class GeoShapeUtil extends BaseBoxShapeUtil<TLGeoShape> {\n\tstatic override type = 'geo' as const\n\tstatic override props = geoShapeProps\n\tstatic override migrations = geoShapeMigrations\n\n\tstatic override configure<T extends TLShapeUtilConstructor<any, any>>(\n\t\tthis: T,\n\t\toptions: T extends new (...args: any[]) => { options: infer Options } ? Partial<Options> : never\n\t): T {\n\t\tconst opts = options as Partial<GeoShapeOptions>\n\t\tif (opts.customGeoTypes) {\n\t\t\tconst validEntries: Array<[string, GeoTypeDefinition]> = []\n\t\t\tfor (const [key, def] of Object.entries(opts.customGeoTypes)) {\n\t\t\t\tif (BUILTIN_GEO_TYPES.has(key)) {\n\t\t\t\t\tif (process.env.NODE_ENV !== 'production') {\n\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t`[GeoShapeUtil.configure] customGeoTypes key \"${key}\" collides with a built-in geo type and will be ignored. Please use a unique name.`\n\t\t\t\t\t\t)\n\t\t\t\t\t}\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tvalidEntries.push([key, def])\n\t\t\t}\n\t\t\tif (validEntries.length > 0) {\n\t\t\t\tGeoShapeGeoStyle.addValues(\n\t\t\t\t\t...(validEntries.map(([k]) => k) as Parameters<typeof GeoShapeGeoStyle.addValues>)\n\t\t\t\t)\n\t\t\t}\n\t\t\t// Strip colliding entries from the options so runtime lookups (tool\n\t\t\t// defaultSize, style panel icons, double-click handlers) don't see them.\n\t\t\tconst filtered = { ...opts, customGeoTypes: Object.fromEntries(validEntries) }\n\t\t\treturn super.configure(filtered as unknown as typeof options) as T\n\t\t}\n\t\treturn super.configure(options) as T\n\t}\n\n\toverride options: GeoShapeOptions = {\n\t\tshowTextOutline: true,\n\t\tgetDefaultDisplayValues(_editor, shape, theme, colorMode): GeoShapeUtilDisplayValues {\n\t\t\tconst { color, size, labelColor, fill, align, verticalAlign, font } = shape.props\n\t\t\tconst colors = theme.colors[colorMode]\n\n\t\t\treturn {\n\t\t\t\tstrokeColor: getColorValue(colors, color, 'solid'),\n\t\t\t\tstrokeRoundness: theme.strokeWidth * STROKE_SIZES[size] * 2,\n\t\t\t\tstrokeWidth: theme.strokeWidth * STROKE_SIZES[size],\n\t\t\t\tfillColor:\n\t\t\t\t\tfill === 'none'\n\t\t\t\t\t\t? 'transparent'\n\t\t\t\t\t\t: fill === 'semi'\n\t\t\t\t\t\t\t? colors.solid\n\t\t\t\t\t\t\t: getColorValue(colors, color, DEFAULT_FILL_COLOR_NAMES[fill]),\n\t\t\t\tpatternFillFallbackColor: getColorValue(colors, color, 'semi'),\n\t\t\t\tlabelColor: getColorValue(colors, labelColor, 'solid'), // todo: separate from the solid color (or create more named colors in the palette so that these could be configured separately)\n\t\t\t\tlabelFontFamily: getFontFamily(theme, font),\n\t\t\t\tlabelFontSize: theme.fontSize * LABEL_FONT_SIZES[size],\n\t\t\t\tlabelMinWidth: GEO_SHAPE_MIN_WIDTHS[size],\n\t\t\t\tlabelExtraPadding: theme.strokeWidth * STROKE_SIZES[size],\n\t\t\t\tlabelLineHeight: theme.lineHeight,\n\t\t\t\tlabelFontWeight: 'normal',\n\t\t\t\tlabelFontVariant: 'normal',\n\t\t\t\tlabelFontStyle: 'normal',\n\t\t\t\tlabelHorizontalAlign: GEO_SHAPE_HORIZONTAL_ALIGNS[align],\n\t\t\t\tlabelVerticalAlign: GEO_SHAPE_VERTICAL_ALIGNS[verticalAlign],\n\t\t\t\tlabelPadding: LABEL_PADDING,\n\t\t\t\t// Margin between label edge and shape edge (in unscaled units)\n\t\t\t\tlabelEdgeMargin: 8,\n\t\t\t\t// Minimum size of the shape to fit a label, based on font size and padding (in unscaled units)\n\t\t\t\tminSizeWithLabel: (LABEL_PADDING + 1) * 3,\n\t\t\t}\n\t\t},\n\t\tgetCustomDisplayValues(_editor, _shape): Partial<GeoShapeUtilDisplayValues> {\n\t\t\treturn {}\n\t\t},\n\t}\n\n\toverride canEdit(shape: TLGeoShape) {\n\t\treturn true\n\t}\n\n\toverride getDefaultProps(): TLGeoShape['props'] {\n\t\treturn {\n\t\t\tw: 100,\n\t\t\th: 100,\n\t\t\tgeo: 'rectangle',\n\t\t\tdash: 'draw',\n\t\t\tgrowY: 0,\n\t\t\turl: '',\n\t\t\tscale: 1,\n\n\t\t\t// Text properties\n\t\t\tcolor: 'black',\n\t\t\tlabelColor: 'black',\n\t\t\tfill: 'none',\n\t\t\tsize: 'm',\n\t\t\tfont: 'draw',\n\t\t\talign: 'middle',\n\t\t\tverticalAlign: 'middle',\n\t\t\trichText: toRichText(''),\n\t\t}\n\t}\n\n\toverride getGeometry(shape: TLGeoShape) {\n\t\tconst { props } = shape\n\t\tconst { scale } = props\n\t\tconst dv = getDisplayValues(this, shape)\n\t\tconst path = getGeoShapePath(shape, dv.strokeWidth, this.options.customGeoTypes)\n\t\tconst pathGeometry = path.toGeometry()\n\n\t\tconst scaledW = Math.max(1, props.w)\n\t\tconst scaledH = Math.max(1, props.h + props.growY)\n\t\tconst unscaledShapeW = scaledW / scale\n\t\tconst unscaledShapeH = scaledH / scale\n\n\t\tconst isEmptyLabel = isEmptyRichText(props.richText)\n\t\tconst unscaledLabelSize = isEmptyLabel\n\t\t\t? GEO_SHAPE_EMPTY_LABEL_SIZE\n\t\t\t: this.getUnscaledLabelSize(shape)\n\n\t\t// Calculate minimum label dimensions based on font size and shape size\n\t\tconst unscaledMinWidth = Math.min(100, unscaledShapeW / 2)\n\t\tconst unscaledMinHeight = Math.min(\n\t\t\tresolveLineHeightPx(dv.labelFontSize, dv.labelLineHeight) + dv.labelPadding * 2,\n\t\t\tunscaledShapeH / 2\n\t\t)\n\n\t\t// Label dimensions: at least the measured size, but constrained to shape bounds\n\t\tconst unscaledLabelW = Math.min(\n\t\t\tunscaledShapeW,\n\t\t\tMath.max(\n\t\t\t\tunscaledLabelSize.w,\n\t\t\t\tMath.min(unscaledMinWidth, Math.max(1, unscaledShapeW - dv.labelEdgeMargin))\n\t\t\t)\n\t\t)\n\t\tconst unscaledLabelH = Math.min(\n\t\t\tunscaledShapeH,\n\t\t\tMath.max(\n\t\t\t\tunscaledLabelSize.h,\n\t\t\t\tMath.min(unscaledMinHeight, Math.max(1, unscaledShapeH - dv.labelEdgeMargin))\n\t\t\t)\n\t\t)\n\n\t\t// Calculate position based on alignment\n\t\tconst unscaledX =\n\t\t\tdv.labelHorizontalAlign === 'start'\n\t\t\t\t? 0\n\t\t\t\t: dv.labelHorizontalAlign === 'end'\n\t\t\t\t\t? unscaledShapeW - unscaledLabelW\n\t\t\t\t\t: (unscaledShapeW - unscaledLabelW) / 2\n\n\t\tconst unscaledY =\n\t\t\tdv.labelVerticalAlign === 'start'\n\t\t\t\t? 0\n\t\t\t\t: dv.labelVerticalAlign === 'end'\n\t\t\t\t\t? unscaledShapeH - unscaledLabelH\n\t\t\t\t\t: (unscaledShapeH - unscaledLabelH) / 2\n\n\t\tconst labelBounds = {\n\t\t\tx: unscaledX * scale,\n\t\t\ty: unscaledY * scale,\n\t\t\twidth: unscaledLabelW * scale,\n\t\t\theight: unscaledLabelH * scale,\n\t\t}\n\n\t\treturn new Group2d({\n\t\t\tchildren: [\n\t\t\t\tpathGeometry,\n\t\t\t\tnew Rectangle2d({\n\t\t\t\t\t...labelBounds,\n\t\t\t\t\tisFilled: true,\n\t\t\t\t\tisLabel: true,\n\t\t\t\t\texcludeFromShapeBounds: true,\n\t\t\t\t\tisEmptyLabel: isEmptyLabel,\n\t\t\t\t}),\n\t\t\t],\n\t\t})\n\t}\n\n\toverride getHandleSnapGeometry(shape: TLGeoShape): HandleSnapGeometry {\n\t\tconst geometry = this.getGeometry(shape)\n\t\t// we only want to snap handles to the outline of the shape - not to its label etc.\n\t\tconst outline = geometry.children[0]\n\t\tconst def = getGeoTypeDefinition(shape.props.geo, this.options.customGeoTypes)\n\t\tif (!def) {\n\t\t\tthrow new Error(`Unknown geo type: ${shape.props.geo}`)\n\t\t}\n\t\t// blobby shapes only snap to the center; polygon shapes snap to vertices + center.\n\t\tif (def.snapType === 'blobby') {\n\t\t\treturn { outline: outline, points: [geometry.bounds.center] }\n\t\t}\n\t\treturn { outline: outline, points: [...outline.vertices, geometry.bounds.center] }\n\t}\n\n\toverride getText(shape: TLGeoShape) {\n\t\treturn renderPlaintextFromRichText(this.editor, shape.props.richText)\n\t}\n\n\toverride getFontFaces(shape: TLGeoShape) {\n\t\tif (isEmptyRichText(shape.props.richText)) {\n\t\t\treturn EMPTY_ARRAY\n\t\t}\n\t\tconst themeFaces = getThemeFontFaces(this.editor.getCurrentTheme(), shape.props.font)\n\t\tif (themeFaces) return themeFaces\n\t\treturn getFontsFromRichText(this.editor, shape.props.richText, {\n\t\t\tfamily: `tldraw_${shape.props.font}`,\n\t\t\tweight: 'normal',\n\t\t\tstyle: 'normal',\n\t\t})\n\t}\n\n\tcomponent(shape: TLGeoShape) {\n\t\tconst { id, type, props } = shape\n\t\tconst { editor } = this\n\t\tconst isOnlySelected = useValue(\n\t\t\t'isGeoOnlySelected',\n\t\t\t() => shape.id === editor.getOnlySelectedShapeId(),\n\t\t\t[editor]\n\t\t)\n\t\tconst isReadyForEditing = useIsReadyForEditing(editor, shape.id)\n\t\tconst isForceSolid = useEfficientZoomThreshold(0.25 / shape.props.scale)\n\t\tconst colorMode = useColorMode()\n\t\tconst dv = getDisplayValues(this, shape, colorMode)\n\n\t\tconst { w, h, richText, url } = props\n\n\t\tconst isEmpty = isEmptyRichText(richText)\n\t\tconst showHtmlContainer = isReadyForEditing || !isEmpty\n\n\t\treturn (\n\t\t\t<>\n\t\t\t\t<SVGContainer>\n\t\t\t\t\t<GeoShapeBody\n\t\t\t\t\t\tshape={shape}\n\t\t\t\t\t\tshouldScale={true}\n\t\t\t\t\t\tforceSolid={isForceSolid}\n\t\t\t\t\t\tstrokeColor={dv.strokeColor}\n\t\t\t\t\t\tstrokeWidth={dv.strokeWidth}\n\t\t\t\t\t\tfillColor={dv.fillColor}\n\t\t\t\t\t\tpatternFillFallbackColor={dv.patternFillFallbackColor}\n\t\t\t\t\t\tcustomGeoTypes={this.options.customGeoTypes}\n\t\t\t\t\t/>\n\t\t\t\t</SVGContainer>\n\t\t\t\t{showHtmlContainer && (\n\t\t\t\t\t<HTMLContainer\n\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\toverflow: 'hidden',\n\t\t\t\t\t\t\twidth: w,\n\t\t\t\t\t\t\theight: h + props.growY,\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t<RichTextLabel\n\t\t\t\t\t\t\tshapeId={id}\n\t\t\t\t\t\t\ttype={type}\n\t\t\t\t\t\t\tfontFamily={dv.labelFontFamily}\n\t\t\t\t\t\t\tfontSize={dv.labelFontSize}\n\t\t\t\t\t\t\tlineHeight={dv.labelLineHeight}\n\t\t\t\t\t\t\tpadding={dv.labelPadding}\n\t\t\t\t\t\t\ttextAlign={dv.labelHorizontalAlign}\n\t\t\t\t\t\t\tverticalAlign={dv.labelVerticalAlign}\n\t\t\t\t\t\t\trichText={richText}\n\t\t\t\t\t\t\tisSelected={isOnlySelected}\n\t\t\t\t\t\t\tlabelColor={dv.labelColor}\n\t\t\t\t\t\t\twrap\n\t\t\t\t\t\t\tshowTextOutline={this.options.showTextOutline}\n\t\t\t\t\t\t\tstyle={\n\t\t\t\t\t\t\t\tshape.props.scale !== 1\n\t\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\t\ttransform: `scale(${shape.props.scale})`,\n\t\t\t\t\t\t\t\t\t\t\ttransformOrigin: 'top left',\n\t\t\t\t\t\t\t\t\t\t\twidth: shape.props.w / shape.props.scale,\n\t\t\t\t\t\t\t\t\t\t\theight: (shape.props.h + props.growY) / shape.props.scale,\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t: undefined\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</HTMLContainer>\n\t\t\t\t)}\n\t\t\t\t{url && <HyperlinkButton url={url} />}\n\t\t\t</>\n\t\t)\n\t}\n\n\toverride getIndicatorPath(shape: TLGeoShape): Path2D | undefined {\n\t\tconst isForceSolid = this.editor.getEfficientZoomLevel() < 0.25 / shape.props.scale\n\n\t\tconst { dash, scale } = shape.props\n\t\tconst dv = getDisplayValues(this, shape)\n\n\t\tconst path = getGeoShapePath(shape, dv.strokeWidth, this.options.customGeoTypes)\n\n\t\treturn path.toPath2D({\n\t\t\tstyle: dash === 'draw' ? 'draw' : 'solid',\n\t\t\tstrokeWidth: 1,\n\t\t\tpasses: 1,\n\t\t\trandomSeed: shape.id,\n\t\t\toffset: 0,\n\t\t\troundness: dv.strokeRoundness * scale,\n\t\t\tforceSolid: isForceSolid,\n\t\t})\n\t}\n\n\toverride toSvg(shape: TLGeoShape, ctx: SvgExportContext) {\n\t\tconst dv = getDisplayValues(this, shape, ctx.colorMode)\n\t\tconst { richText, fill, scale, growY, w, h } = shape.props\n\t\t// We need to scale the shape to 1x for export\n\t\tconst newShape = {\n\t\t\t...shape,\n\t\t\tprops: {\n\t\t\t\t...shape.props,\n\t\t\t\tw: w / scale,\n\t\t\t\th: (h + growY) / scale,\n\t\t\t\tgrowY: 0, // growY throws off the path calculations, so we set it to 0\n\t\t\t},\n\t\t}\n\t\tctx.addExportDef(getFillDefForExport(fill))\n\n\t\tlet textEl\n\t\tif (!isEmptyRichText(richText)) {\n\t\t\tconst bounds = new Box(0, 0, newShape.props.w, (h + growY) / scale)\n\t\t\ttextEl = (\n\t\t\t\t<RichTextSVG\n\t\t\t\t\tfontSize={dv.labelFontSize}\n\t\t\t\t\tfontFamily={dv.labelFontFamily}\n\t\t\t\t\tlineHeight={dv.labelLineHeight}\n\t\t\t\t\ttextAlign={dv.labelHorizontalAlign}\n\t\t\t\t\tverticalAlign={dv.labelVerticalAlign}\n\t\t\t\t\tlabelColor={dv.labelColor}\n\t\t\t\t\tpadding={dv.labelPadding}\n\t\t\t\t\tshowTextOutline={this.options.showTextOutline}\n\t\t\t\t\tbounds={bounds}\n\t\t\t\t\trichText={richText}\n\t\t\t\t/>\n\t\t\t)\n\t\t}\n\n\t\treturn (\n\t\t\t<>\n\t\t\t\t<GeoShapeBody\n\t\t\t\t\tshouldScale={false}\n\t\t\t\t\tshape={newShape}\n\t\t\t\t\tforceSolid={false}\n\t\t\t\t\tstrokeColor={dv.strokeColor}\n\t\t\t\t\tstrokeWidth={dv.strokeWidth}\n\t\t\t\t\tfillColor={dv.fillColor}\n\t\t\t\t\tpatternFillFallbackColor={dv.patternFillFallbackColor}\n\t\t\t\t\tcustomGeoTypes={this.options.customGeoTypes}\n\t\t\t\t/>\n\t\t\t\t{textEl}\n\t\t\t</>\n\t\t)\n\t}\n\n\toverride getCanvasSvgDefs(): TLShapeUtilCanvasSvgDef[] {\n\t\treturn [getFillDefForCanvas()]\n\t}\n\n\toverride onResize(\n\t\tshape: TLGeoShape,\n\t\t{ handle, newPoint, scaleX, scaleY, initialShape }: TLResizeInfo<TLGeoShape>\n\t) {\n\t\tconst unscaledInitial = this.getUnscaledGeoProps(initialShape.props)\n\t\t// use the w/h from props here instead of the initialBounds here,\n\t\t// since cloud shapes calculated bounds can differ from the props w/h.\n\t\tlet unscaledW = unscaledInitial.w * scaleX\n\t\tlet unscaledH = (unscaledInitial.h + unscaledInitial.growY) * scaleY\n\t\tlet overShrinkX = 0\n\t\tlet overShrinkY = 0\n\n\t\tconst dv = getDisplayValues(this, shape)\n\n\t\tif (!isEmptyRichText(shape.props.richText)) {\n\t\t\tconst absUnscaledW = Math.abs(unscaledW)\n\t\t\tconst absUnscaledH = Math.abs(unscaledH)\n\t\t\t// Check the batch cache first (set by Resizing.ts during multi-shape resize).\n\t\t\t// If not cached, measure the label at the constrained target dimensions so text\n\t\t\t// wrapping is accounted for. We call measureUnscaledLabelSize directly (bypassing\n\t\t\t// WeakCache) since temp shapes with resize dimensions change every frame.\n\t\t\tconst cached = getBatchLabelSizeCache(this.editor)?.get(shape.id)\n\t\t\tlet unscaledLabelSize: { w: number; h: number }\n\t\t\tif (cached) {\n\t\t\t\tunscaledLabelSize = cached\n\t\t\t} else {\n\t\t\t\tconst measureW = Math.max(absUnscaledW, dv.minSizeWithLabel)\n\t\t\t\tconst measureH = Math.max(absUnscaledH, dv.minSizeWithLabel)\n\t\t\t\tunscaledLabelSize = this.measureUnscaledLabelSize({\n\t\t\t\t\t...shape,\n\t\t\t\t\tprops: {\n\t\t\t\t\t\t...shape.props,\n\t\t\t\t\t\tw: measureW * shape.props.scale,\n\t\t\t\t\t\th: measureH * shape.props.scale,\n\t\t\t\t\t},\n\t\t\t\t} as TLGeoShape)\n\t\t\t}\n\n\t\t\tconst constrainedW = Math.max(absUnscaledW, unscaledLabelSize.w)\n\t\t\tconst constrainedH = Math.max(absUnscaledH, unscaledLabelSize.h)\n\n\t\t\toverShrinkX = constrainedW - absUnscaledW\n\t\t\toverShrinkY = constrainedH - absUnscaledH\n\n\t\t\tunscaledW = constrainedW * Math.sign(unscaledW || 1)\n\t\t\tunscaledH = constrainedH * Math.sign(unscaledH || 1)\n\t\t}\n\n\t\tconst scaledW = unscaledW * shape.props.scale\n\t\tconst scaledH = unscaledH * shape.props.scale\n\n\t\tconst offset = new Vec(0, 0)\n\n\t\t// x offsets\n\n\t\tif (scaleX < 0) {\n\t\t\toffset.x += scaledW\n\t\t}\n\n\t\tif (handle === 'left' || handle === 'top_left' || handle === 'bottom_left') {\n\t\t\toffset.x += scaleX < 0 ? overShrinkX : -overShrinkX\n\t\t}\n\n\t\t// y offsets\n\n\t\tif (scaleY < 0) {\n\t\t\toffset.y += scaledH\n\t\t}\n\n\t\tif (handle === 'top' || handle === 'top_left' || handle === 'top_right') {\n\t\t\toffset.y += scaleY < 0 ? overShrinkY : -overShrinkY\n\t\t}\n\n\t\tconst { x, y } = offset.rot(shape.rotation).add(newPoint)\n\n\t\treturn {\n\t\t\tx,\n\t\t\ty,\n\t\t\tprops: {\n\t\t\t\tw: Math.max(Math.abs(scaledW), 1),\n\t\t\t\th: Math.max(Math.abs(scaledH), 1),\n\t\t\t\tgrowY: 0,\n\t\t\t},\n\t\t}\n\t}\n\n\toverride onBeforeCreate(shape: TLGeoShape) {\n\t\tconst { props } = shape\n\n\t\t// No text - ensure growY is 0\n\t\tif (isEmptyRichText(props.richText)) {\n\t\t\treturn props.growY !== 0 ? { ...shape, props: { ...props, growY: 0 } } : undefined\n\t\t}\n\n\t\t// Has text - calculate growY needed to fit label\n\t\tconst unscaledShapeH = props.h / props.scale\n\t\tconst unscaledLabelH = this.getUnscaledLabelSize(shape).h\n\t\tconst unscaledGrowY = this.calculateGrowY(\n\t\t\tunscaledShapeH,\n\t\t\tunscaledLabelH,\n\t\t\tprops.growY / props.scale\n\t\t)\n\n\t\tif (unscaledGrowY !== null) {\n\t\t\treturn {\n\t\t\t\t...shape,\n\t\t\t\tprops: { ...props, growY: unscaledGrowY * props.scale },\n\t\t\t}\n\t\t}\n\n\t\treturn undefined\n\t}\n\n\toverride onBeforeUpdate(prev: TLGeoShape, next: TLGeoShape) {\n\t\tconst { props: prevProps } = prev\n\t\tconst { props: nextProps } = next\n\n\t\t// No change to text, font, or size - no update needed\n\t\tif (\n\t\t\tisEqual(prevProps.richText, nextProps.richText) &&\n\t\t\tprevProps.font === nextProps.font &&\n\t\t\tprevProps.size === nextProps.size\n\t\t) {\n\t\t\treturn undefined\n\t\t}\n\n\t\tconst wasEmpty = isEmptyRichText(prevProps.richText)\n\t\tconst isEmpty = isEmptyRichText(nextProps.richText)\n\n\t\t// If label is empty and used to be empty, skip label measurement and dimension adjustment\n\t\tif (wasEmpty && isEmpty) {\n\t\t\treturn undefined\n\t\t}\n\n\t\t// Text was removed - reset growY\n\t\tif (isEmpty) {\n\t\t\treturn nextProps.growY !== 0 ? { ...next, props: { ...nextProps, growY: 0 } } : undefined\n\t\t}\n\n\t\tconst unscaledPrev = this.getUnscaledGeoProps(prevProps)\n\t\tconst unscaledLabelSize = this.getUnscaledLabelSize(next)\n\t\tconst { scale } = nextProps\n\n\t\t// Text was added for the first time - expand shape to fit (if wasEmpty and now there's text...\n\t\t// It might be just whitespace but it is faster to assume that it is NOT just whitespace and expand\n\t\t// the shape in either case (a label with just spaces text will be less performant but that's acceptable)\n\t\tif (wasEmpty && !isEmpty) {\n\t\t\tconst expanded = this.expandShapeForFirstLabel(\n\t\t\t\tnext,\n\t\t\t\tunscaledPrev.w,\n\t\t\t\tunscaledPrev.h,\n\t\t\t\tunscaledLabelSize\n\t\t\t)\n\t\t\treturn {\n\t\t\t\t...next,\n\t\t\t\tprops: {\n\t\t\t\t\t...nextProps,\n\t\t\t\t\tw: expanded.w * scale,\n\t\t\t\t\th: expanded.h * scale,\n\t\t\t\t\tgrowY: 0,\n\t\t\t\t},\n\t\t\t}\n\t\t}\n\n\t\t// Text was modified - adjust dimensions to fit new label\n\t\tconst unscaledNextW = next.props.w / scale\n\t\tconst needsWidthExpand = unscaledLabelSize.w > unscaledNextW\n\t\tconst unscaledGrowY = this.calculateGrowY(\n\t\t\tunscaledPrev.h,\n\t\t\tunscaledLabelSize.h,\n\t\t\tunscaledPrev.growY\n\t\t)\n\n\t\tif (unscaledGrowY !== null || needsWidthExpand) {\n\t\t\treturn {\n\t\t\t\t...next,\n\t\t\t\tprops: {\n\t\t\t\t\t...nextProps,\n\t\t\t\t\tgrowY: (unscaledGrowY ?? unscaledPrev.growY) * scale,\n\t\t\t\t\tw: Math.max(unscaledNextW, unscaledLabelSize.w) * scale,\n\t\t\t\t},\n\t\t\t}\n\t\t}\n\n\t\treturn undefined\n\t}\n\n\toverride onDoubleClick(shape: TLGeoShape) {\n\t\t// Little easter egg: double-clicking a rectangle / checkbox while\n\t\t// holding alt will toggle between check-box and rectangle\n\t\tif (this.editor.inputs.getAltKey()) {\n\t\t\tswitch (shape.props.geo) {\n\t\t\t\tcase 'rectangle': {\n\t\t\t\t\treturn {\n\t\t\t\t\t\t...shape,\n\t\t\t\t\t\tprops: {\n\t\t\t\t\t\t\tgeo: 'check-box' as const,\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcase 'check-box': {\n\t\t\t\t\treturn {\n\t\t\t\t\t\t...shape,\n\t\t\t\t\t\tprops: {\n\t\t\t\t\t\t\tgeo: 'rectangle' as const,\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst def = getGeoTypeDefinition(shape.props.geo, this.options.customGeoTypes)\n\t\tif (def?.onDoubleClick) {\n\t\t\tconst result = def.onDoubleClick(shape)\n\t\t\tif (result) {\n\t\t\t\treturn { ...shape, props: { ...shape.props, ...result.props } }\n\t\t\t}\n\t\t}\n\n\t\treturn\n\t}\n\n\toverride getInterpolatedProps(\n\t\tstartShape: TLGeoShape,\n\t\tendShape: TLGeoShape,\n\t\tt: number\n\t): TLGeoShapeProps {\n\t\treturn {\n\t\t\t...(t > 0.5 ? endShape.props : startShape.props),\n\t\t\tw: lerp(startShape.props.w, endShape.props.w, t),\n\t\t\th: lerp(startShape.props.h, endShape.props.h, t),\n\t\t\tscale: lerp(startShape.props.scale, endShape.props.scale, t),\n\t\t}\n\t}\n\n\t/**\n\t * Get the unscaled dimensions from a geo shape's props\n\t */\n\tprivate getUnscaledGeoProps(props: TLGeoShapeProps) {\n\t\tconst { w, h, growY, scale } = props\n\t\treturn {\n\t\t\tw: w / scale,\n\t\t\th: h / scale,\n\t\t\tgrowY: growY / scale,\n\t\t}\n\t}\n\n\t/**\n\t * Calculate the growY needed to fit a label within a shape.\n\t * Returns null if no change is needed, otherwise returns the new unscaled growY value.\n\t */\n\tprivate calculateGrowY(\n\t\tunscaledShapeH: number,\n\t\tunscaledLabelH: number,\n\t\tunscaledCurrentGrowY: number\n\t): number | null {\n\t\tif (unscaledLabelH > unscaledShapeH) {\n\t\t\t// Label is taller than shape - need to grow\n\t\t\treturn unscaledLabelH - unscaledShapeH\n\t\t}\n\t\tif (unscaledCurrentGrowY > 0) {\n\t\t\t// Label fits and we have existing growY - reset it\n\t\t\treturn 0\n\t\t}\n\t\t// No change needed\n\t\treturn null\n\t}\n\n\t/**\n\t * Calculate expanded dimensions when adding a label to a shape for the first time.\n\t * Ensures the shape meets minimum size requirements and is square if originally small.\n\t */\n\tprivate expandShapeForFirstLabel(\n\t\tshape: TLGeoShape,\n\t\tunscaledW: number,\n\t\tunscaledH: number,\n\t\tunscaledLabelSize: { w: number; h: number }\n\t): { w: number; h: number } {\n\t\tlet w = Math.max(unscaledW, unscaledLabelSize.w)\n\t\tlet h = Math.max(unscaledH, unscaledLabelSize.h)\n\n\t\tconst dv = getDisplayValues(this, shape)\n\n\t\t// If shape was smaller than min size in both dimensions, make it square\n\t\tif (unscaledW < dv.minSizeWithLabel && unscaledH < dv.minSizeWithLabel) {\n\t\t\tw = Math.max(w, dv.minSizeWithLabel)\n\t\t\th = Math.max(h, dv.minSizeWithLabel)\n\t\t\t// Make square by using the larger dimension\n\t\t\tconst maxDim = Math.max(w, h)\n\t\t\tw = maxDim\n\t\t\th = maxDim\n\t\t}\n\n\t\treturn { w, h }\n\t}\n\n\tprivate _labelSizesForGeoCache = new WeakCache<TLGeoShape, { w: number; h: number }>()\n\n\t/**\n\t * Get the cached label size for the shape. Don't call with empty rich text.\n\t */\n\tprivate getUnscaledLabelSize(shape: TLGeoShape) {\n\t\tconst batchCached = getBatchLabelSizeCache(this.editor)?.get(shape.id)\n\t\tif (batchCached) return batchCached\n\n\t\treturn this._labelSizesForGeoCache.get(shape, () => {\n\t\t\treturn this.measureUnscaledLabelSize(shape)\n\t\t})\n\t}\n\n\t/**\n\t * Expensively measure the unscaled label size for the shape. Avoid using it if we can.\n\t */\n\tprivate measureUnscaledLabelSize(shape: TLGeoShape) {\n\t\tconst dv = getDisplayValues(this, shape)\n\n\t\tconst html = renderHtmlFromRichTextForMeasurement(this.editor, shape.props.richText)\n\n\t\tconst textSize = this.editor.textMeasure.measureHtml(html, {\n\t\t\t...TEXT_PROPS,\n\t\t\tfontFamily: dv.labelFontFamily,\n\t\t\tfontSize: dv.labelFontSize,\n\t\t\tlineHeight: dv.labelLineHeight,\n\t\t\tminWidth: dv.labelMinWidth,\n\t\t\tmaxWidth: Math.max(\n\t\t\t\t// Guard because a DOM nodes can't be less 0\n\t\t\t\t0,\n\t\t\t\t// A 'w' width that we're setting as the min-width\n\t\t\t\tMath.ceil(dv.labelMinWidth + dv.labelExtraPadding),\n\t\t\t\t// The actual text size\n\t\t\t\tMath.ceil(shape.props.w / shape.props.scale - dv.labelPadding * 2)\n\t\t\t),\n\t\t})\n\n\t\treturn {\n\t\t\tw: textSize.w + dv.labelPadding * 2,\n\t\t\th: textSize.h + dv.labelPadding * 2,\n\t\t}\n\t}\n}\n\nconst MIN_SIZE_WITH_LABEL = (LABEL_PADDING + 1) * 3\nconst MIN_WIDTHS = GEO_SHAPE_MIN_WIDTHS\n\n// Per-editor batch cache, set by batchMeasureGeoLabels before the resize loop and cleared after.\n// When set, onResize will use pre-computed label sizes instead of measuring individually.\n// Uses a WeakMap keyed by editor to avoid issues with multiple editors on the same page.\nconst _batchLabelSizeCaches = new WeakMap<Editor, Map<TLShapeId, { w: number; h: number }>>()\n\n/** @internal */\nexport function setBatchLabelSizeCache(\n\teditor: Editor,\n\tcache: Map<TLShapeId, { w: number; h: number }> | null\n) {\n\tif (cache) {\n\t\t_batchLabelSizeCaches.set(editor, cache)\n\t} else {\n\t\t_batchLabelSizeCaches.delete(editor)\n\t}\n}\n\nfunction getBatchLabelSizeCache(editor: Editor) {\n\treturn _batchLabelSizeCaches.get(editor)\n}\n\n/**\n * Build the measurement request params (html + opts) for a geo shape's label\n * without actually performing the measurement. Used by batch measurement.\n */\nfunction getGeoLabelMeasurementRequest(\n\teditor: Editor,\n\tshape: TLGeoShape\n): { html: string; opts: TLMeasureTextOpts } {\n\tconst { richText, font, size, w } = shape.props\n\tconst theme = editor.getCurrentTheme()\n\tconst minWidth = MIN_WIDTHS[size]\n\tconst html = renderHtmlFromRichTextForMeasurement(editor, richText)\n\tconst opts: TLMeasureTextOpts = {\n\t\t...TEXT_PROPS,\n\t\tfontFamily: getFontFamily(theme, font),\n\t\tfontSize: theme.fontSize * LABEL_FONT_SIZES[size],\n\t\tlineHeight: theme.lineHeight,\n\t\tminWidth: minWidth,\n\t\tmaxWidth: Math.max(\n\t\t\t// Guard because a DOM node can't be less than 0\n\t\t\t0,\n\t\t\t// A 'w' width that we're setting as the min-width\n\t\t\tMath.ceil(minWidth + theme.strokeWidth * STROKE_SIZES[size]),\n\t\t\t// The actual text size\n\t\t\tMath.ceil(w / shape.props.scale - LABEL_PADDING * 2)\n\t\t),\n\t}\n\treturn { html, opts }\n}\n\n/**\n * Compute the target unscaled width for label measurement during resize.\n * This replicates the measureW computation from onResize so batch measurement can\n * build measurement requests without duplicating GeoShapeUtil internals.\n */\nfunction getGeoResizeTargetWidth(initialProps: TLGeoShapeProps, scaleX: number): number {\n\tconst unscaledInitialW = initialProps.w / initialProps.scale\n\tconst absUnscaledW = Math.abs(unscaledInitialW * scaleX)\n\treturn Math.max(absUnscaledW, MIN_SIZE_WITH_LABEL)\n}\n\n/**\n * Batch-measure all geo shape labels before the resize loop to avoid layout thrashing.\n * For each geo shape with a non-empty label that has compatible rotation, compute the\n * measurement request and batch all measurements in a single DOM pass.\n * Sets the per-editor batch cache so onResize and getGeometry can use pre-computed sizes.\n * @internal\n */\nexport function batchMeasureGeoLabels(\n\teditor: Editor,\n\tshapeSnapshots: Map<\n\t\tTLShapeId,\n\t\t{\n\t\t\tshape: TLShape\n\t\t\tpageRotation: number\n\t\t\tisAspectRatioLocked: boolean\n\t\t}\n\t>,\n\tscale: VecLike,\n\tselectionRotation: number,\n\tisAspectRatioLocked: boolean\n) {\n\tconst requests: Array<{ id: TLShapeId; html: string; opts: TLMeasureTextOpts }> = []\n\n\tfor (const [id, snapshot] of shapeSnapshots) {\n\t\t// Only process geo shapes with non-empty text labels\n\t\tif (!editor.isShapeOfType<TLGeoShape>(snapshot.shape, 'geo')) continue\n\t\tconst geoShape = snapshot.shape as TLGeoShape\n\t\tif (isEmptyRichText(geoShape.props.richText)) continue\n\n\t\t// Skip unaligned shapes \u2014 they take a different resize path (_resizeUnalignedShape)\n\t\t// and won't use the standard onResize, so caching wouldn't help.\n\t\tif (!areAnglesCompatible(snapshot.pageRotation, selectionRotation)) continue\n\n\t\t// Compute the effective scaleX for this shape, replicating Editor.resizeShape logic.\n\t\t// Shapes rotated 90\u00B0 from the selection axis have their x/y scale swapped.\n\t\tconst areWidthAndHeightAlignedWithCorrectAxis = approximately(\n\t\t\t(snapshot.pageRotation - selectionRotation) % Math.PI,\n\t\t\t0\n\t\t)\n\n\t\tlet effectiveScaleX: number\n\t\tif (isAspectRatioLocked || snapshot.isAspectRatioLocked) {\n\t\t\t// When aspect ratio is locked, both axes get the same absolute scale\n\t\t\tconst uniformScale = Math.max(Math.abs(scale.x), Math.abs(scale.y))\n\t\t\teffectiveScaleX = uniformScale\n\t\t} else {\n\t\t\teffectiveScaleX = Math.abs(areWidthAndHeightAlignedWithCorrectAxis ? scale.x : scale.y)\n\t\t}\n\n\t\t// Compute the target width for measurement (same logic as onResize)\n\t\tconst targetW = getGeoResizeTargetWidth(geoShape.props, effectiveScaleX)\n\n\t\t// Build a temporary shape with the target width for measurement\n\t\tconst tempShape = {\n\t\t\t...geoShape,\n\t\t\tprops: {\n\t\t\t\t...geoShape.props,\n\t\t\t\tw: targetW * geoShape.props.scale,\n\t\t\t},\n\t\t} as TLGeoShape\n\n\t\tconst { html, opts } = getGeoLabelMeasurementRequest(editor, tempShape)\n\t\trequests.push({ id, html, opts })\n\t}\n\n\tif (requests.length === 0) return\n\n\t// Batch measure all labels in one DOM pass\n\tconst results = editor.textMeasure.measureHtmlBatch(\n\t\trequests.map(({ html, opts }) => ({ html, opts }))\n\t)\n\n\t// Build the cache map with label sizes (adding padding)\n\tconst cache = new Map<TLShapeId, { w: number; h: number }>()\n\tfor (let i = 0; i < requests.length; i++) {\n\t\tcache.set(requests[i].id, {\n\t\t\tw: results[i].w + LABEL_PADDING * 2,\n\t\t\th: results[i].h + LABEL_PADDING * 2,\n\t\t})\n\t}\n\n\tsetBatchLabelSizeCache(editor, cache)\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
StateNode,
|
|
4
4
|
Vec,
|
|
5
5
|
createShapeId,
|
|
6
|
+
cancelShapeCreationOnLongPress,
|
|
6
7
|
maybeSnapToGrid
|
|
7
8
|
} from "@tldraw/editor";
|
|
8
9
|
import { getGeoTypeDefinition } from "../getGeoShapePath.mjs";
|
|
@@ -11,6 +12,9 @@ class Pointing extends StateNode {
|
|
|
11
12
|
onPointerUp() {
|
|
12
13
|
this.complete();
|
|
13
14
|
}
|
|
15
|
+
onLongPress() {
|
|
16
|
+
cancelShapeCreationOnLongPress(this.editor, () => this.cancel());
|
|
17
|
+
}
|
|
14
18
|
onPointerMove(info) {
|
|
15
19
|
if (this.editor.inputs.getIsDragging()) {
|
|
16
20
|
const originPagePoint = this.editor.inputs.getOriginPagePoint();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/lib/shapes/geo/toolStates/Pointing.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n\tGeoShapeGeoStyle,\n\tStateNode,\n\tTLGeoShape,\n\tTLPointerEventInfo,\n\tVec,\n\tcreateShapeId,\n\tmaybeSnapToGrid,\n} from '@tldraw/editor'\nimport { GeoShapeUtil } from '../GeoShapeUtil'\nimport { getGeoTypeDefinition } from '../getGeoShapePath'\n\nexport class Pointing extends StateNode {\n\tstatic override id = 'pointing'\n\n\toverride onPointerUp() {\n\t\tthis.complete()\n\t}\n\n\toverride onPointerMove(info: TLPointerEventInfo) {\n\t\tif (this.editor.inputs.getIsDragging()) {\n\t\t\tconst originPagePoint = this.editor.inputs.getOriginPagePoint()\n\n\t\t\tconst id = createShapeId()\n\n\t\t\tconst creatingMarkId = this.editor.markHistoryStoppingPoint(`creating_geo:${id}`)\n\t\t\tconst newPoint = maybeSnapToGrid(originPagePoint, this.editor)\n\t\t\tthis.editor\n\t\t\t\t.createShapes([\n\t\t\t\t\t{\n\t\t\t\t\t\tid,\n\t\t\t\t\t\ttype: 'geo',\n\t\t\t\t\t\tx: newPoint.x,\n\t\t\t\t\t\ty: newPoint.y,\n\t\t\t\t\t\tprops: {\n\t\t\t\t\t\t\tw: 1,\n\t\t\t\t\t\t\th: 1,\n\t\t\t\t\t\t\tgeo: this.editor.getStyleForNextShape(GeoShapeGeoStyle),\n\t\t\t\t\t\t\tscale: this.editor.getResizeScaleFactor(),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t])\n\t\t\t\t.select(id)\n\n\t\t\tconst shape = this.editor.getShape(id)\n\t\t\tif (!shape) {\n\t\t\t\tthis.cancel()\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tthis.editor.setCurrentTool('select.resizing', {\n\t\t\t\t...info,\n\t\t\t\ttarget: 'selection',\n\t\t\t\thandle: 'bottom_right',\n\t\t\t\tisCreating: true,\n\t\t\t\tcreatingMarkId,\n\t\t\t\tcreationCursorOffset: { x: 1, y: 1 },\n\t\t\t\tonInteractionEnd: 'geo',\n\t\t\t})\n\t\t}\n\t}\n\n\toverride onCancel() {\n\t\tthis.cancel()\n\t}\n\n\toverride onComplete() {\n\t\tthis.complete()\n\t}\n\n\toverride onInterrupt() {\n\t\tthis.cancel()\n\t}\n\n\tprivate complete() {\n\t\tconst originPagePoint = this.editor.inputs.getOriginPagePoint()\n\n\t\tconst id = createShapeId()\n\n\t\tthis.editor.markHistoryStoppingPoint(`creating_geo:${id}`)\n\n\t\tconst scale = this.editor.getResizeScaleFactor()\n\n\t\tconst geo = this.editor.getStyleForNextShape(GeoShapeGeoStyle)\n\t\tconst geoShapeUtil = this.editor.getShapeUtil<GeoShapeUtil>('geo')\n\n\t\tconst def = getGeoTypeDefinition(geo, geoShapeUtil.options.customGeoTypes)\n\t\tconst size = def?.defaultSize ?? { w: 200, h: 200 }\n\n\t\tthis.editor.createShapes([\n\t\t\t{\n\t\t\t\tid,\n\t\t\t\ttype: 'geo',\n\t\t\t\tx: originPagePoint.x,\n\t\t\t\ty: originPagePoint.y,\n\t\t\t\tprops: {\n\t\t\t\t\tgeo: this.editor.getStyleForNextShape(GeoShapeGeoStyle),\n\t\t\t\t\tscale,\n\t\t\t\t\t...size,\n\t\t\t\t},\n\t\t\t},\n\t\t])\n\n\t\tconst shape = this.editor.getShape<TLGeoShape>(id)!\n\t\tif (!shape) {\n\t\t\tthis.cancel()\n\t\t\treturn\n\t\t}\n\n\t\tconst { w, h } = shape.props\n\n\t\tconst delta = new Vec(w / 2, h / 2).mul(scale)\n\t\tconst parentTransform = this.editor.getShapeParentTransform(shape)\n\t\tif (parentTransform) delta.rot(-parentTransform.rotation())\n\t\tconst newPoint = maybeSnapToGrid(new Vec(shape.x - delta.x, shape.y - delta.y), this.editor)\n\t\tthis.editor.select(id)\n\t\tthis.editor.updateShape({\n\t\t\tid: shape.id,\n\t\t\ttype: 'geo',\n\t\t\tx: newPoint.x,\n\t\t\ty: newPoint.y,\n\t\t\tprops: {\n\t\t\t\tgeo: this.editor.getStyleForNextShape(GeoShapeGeoStyle),\n\t\t\t\tw: w * scale,\n\t\t\t\th: h * scale,\n\t\t\t},\n\t\t})\n\n\t\tif (this.editor.getInstanceState().isToolLocked) {\n\t\t\tthis.parent.transition('idle')\n\t\t} else {\n\t\t\tthis.editor.setCurrentTool('select', {})\n\t\t}\n\t}\n\n\tprivate cancel() {\n\t\t// we should not have created any shapes yet, so no need to bail\n\t\tthis.parent.transition('idle')\n\t}\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import {\n\tGeoShapeGeoStyle,\n\tStateNode,\n\tTLGeoShape,\n\tTLPointerEventInfo,\n\tVec,\n\tcreateShapeId,\n\tcancelShapeCreationOnLongPress,\n\tmaybeSnapToGrid,\n} from '@tldraw/editor'\nimport { GeoShapeUtil } from '../GeoShapeUtil'\nimport { getGeoTypeDefinition } from '../getGeoShapePath'\n\nexport class Pointing extends StateNode {\n\tstatic override id = 'pointing'\n\n\toverride onPointerUp() {\n\t\tthis.complete()\n\t}\n\n\toverride onLongPress() {\n\t\tcancelShapeCreationOnLongPress(this.editor, () => this.cancel())\n\t}\n\n\toverride onPointerMove(info: TLPointerEventInfo) {\n\t\tif (this.editor.inputs.getIsDragging()) {\n\t\t\tconst originPagePoint = this.editor.inputs.getOriginPagePoint()\n\n\t\t\tconst id = createShapeId()\n\n\t\t\tconst creatingMarkId = this.editor.markHistoryStoppingPoint(`creating_geo:${id}`)\n\t\t\tconst newPoint = maybeSnapToGrid(originPagePoint, this.editor)\n\t\t\tthis.editor\n\t\t\t\t.createShapes([\n\t\t\t\t\t{\n\t\t\t\t\t\tid,\n\t\t\t\t\t\ttype: 'geo',\n\t\t\t\t\t\tx: newPoint.x,\n\t\t\t\t\t\ty: newPoint.y,\n\t\t\t\t\t\tprops: {\n\t\t\t\t\t\t\tw: 1,\n\t\t\t\t\t\t\th: 1,\n\t\t\t\t\t\t\tgeo: this.editor.getStyleForNextShape(GeoShapeGeoStyle),\n\t\t\t\t\t\t\tscale: this.editor.getResizeScaleFactor(),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t])\n\t\t\t\t.select(id)\n\n\t\t\tconst shape = this.editor.getShape(id)\n\t\t\tif (!shape) {\n\t\t\t\tthis.cancel()\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tthis.editor.setCurrentTool('select.resizing', {\n\t\t\t\t...info,\n\t\t\t\ttarget: 'selection',\n\t\t\t\thandle: 'bottom_right',\n\t\t\t\tisCreating: true,\n\t\t\t\tcreatingMarkId,\n\t\t\t\tcreationCursorOffset: { x: 1, y: 1 },\n\t\t\t\tonInteractionEnd: 'geo',\n\t\t\t})\n\t\t}\n\t}\n\n\toverride onCancel() {\n\t\tthis.cancel()\n\t}\n\n\toverride onComplete() {\n\t\tthis.complete()\n\t}\n\n\toverride onInterrupt() {\n\t\tthis.cancel()\n\t}\n\n\tprivate complete() {\n\t\tconst originPagePoint = this.editor.inputs.getOriginPagePoint()\n\n\t\tconst id = createShapeId()\n\n\t\tthis.editor.markHistoryStoppingPoint(`creating_geo:${id}`)\n\n\t\tconst scale = this.editor.getResizeScaleFactor()\n\n\t\tconst geo = this.editor.getStyleForNextShape(GeoShapeGeoStyle)\n\t\tconst geoShapeUtil = this.editor.getShapeUtil<GeoShapeUtil>('geo')\n\n\t\tconst def = getGeoTypeDefinition(geo, geoShapeUtil.options.customGeoTypes)\n\t\tconst size = def?.defaultSize ?? { w: 200, h: 200 }\n\n\t\tthis.editor.createShapes([\n\t\t\t{\n\t\t\t\tid,\n\t\t\t\ttype: 'geo',\n\t\t\t\tx: originPagePoint.x,\n\t\t\t\ty: originPagePoint.y,\n\t\t\t\tprops: {\n\t\t\t\t\tgeo: this.editor.getStyleForNextShape(GeoShapeGeoStyle),\n\t\t\t\t\tscale,\n\t\t\t\t\t...size,\n\t\t\t\t},\n\t\t\t},\n\t\t])\n\n\t\tconst shape = this.editor.getShape<TLGeoShape>(id)!\n\t\tif (!shape) {\n\t\t\tthis.cancel()\n\t\t\treturn\n\t\t}\n\n\t\tconst { w, h } = shape.props\n\n\t\tconst delta = new Vec(w / 2, h / 2).mul(scale)\n\t\tconst parentTransform = this.editor.getShapeParentTransform(shape)\n\t\tif (parentTransform) delta.rot(-parentTransform.rotation())\n\t\tconst newPoint = maybeSnapToGrid(new Vec(shape.x - delta.x, shape.y - delta.y), this.editor)\n\t\tthis.editor.select(id)\n\t\tthis.editor.updateShape({\n\t\t\tid: shape.id,\n\t\t\ttype: 'geo',\n\t\t\tx: newPoint.x,\n\t\t\ty: newPoint.y,\n\t\t\tprops: {\n\t\t\t\tgeo: this.editor.getStyleForNextShape(GeoShapeGeoStyle),\n\t\t\t\tw: w * scale,\n\t\t\t\th: h * scale,\n\t\t\t},\n\t\t})\n\n\t\tif (this.editor.getInstanceState().isToolLocked) {\n\t\t\tthis.parent.transition('idle')\n\t\t} else {\n\t\t\tthis.editor.setCurrentTool('select', {})\n\t\t}\n\t}\n\n\tprivate cancel() {\n\t\t// we should not have created any shapes yet, so no need to bail\n\t\tthis.parent.transition('idle')\n\t}\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
Polygon2d,
|
|
5
5
|
SVGContainer,
|
|
6
6
|
ShapeUtil,
|
|
7
|
+
b64Vecs,
|
|
7
8
|
debugFlags,
|
|
8
9
|
getColorValue,
|
|
9
10
|
highlightShapeMigrations,
|
|
@@ -17,9 +18,8 @@ import {
|
|
|
17
18
|
} from "@tldraw/editor";
|
|
18
19
|
import { getHighlightFreehandSettings, getPointsFromDrawSegments } from "../draw/getPath.mjs";
|
|
19
20
|
import { FONT_SIZES } from "../shared/default-shape-constants.mjs";
|
|
20
|
-
import {
|
|
21
|
+
import { getStroke } from "../shared/freehand/getStroke.mjs";
|
|
21
22
|
import { getStrokePoints } from "../shared/freehand/getStrokePoints.mjs";
|
|
22
|
-
import { setStrokePointRadii } from "../shared/freehand/setStrokePointRadii.mjs";
|
|
23
23
|
import { getSvgPathFromStrokePoints } from "../shared/freehand/svg.mjs";
|
|
24
24
|
import { getDisplayValues } from "../shared/getDisplayValues.mjs";
|
|
25
25
|
import { interpolateSegments } from "../shared/interpolate-props.mjs";
|
|
@@ -77,11 +77,15 @@ class HighlightShapeUtil extends ShapeUtil {
|
|
|
77
77
|
isFilled: true
|
|
78
78
|
});
|
|
79
79
|
}
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
80
|
+
const allPointsFromSegments = getPointsFromDrawSegments(
|
|
81
|
+
shape.props.segments,
|
|
82
|
+
shape.props.scaleX,
|
|
83
|
+
shape.props.scaleY
|
|
84
|
+
);
|
|
85
|
+
const showAsComplete = shape.props.isComplete || last(shape.props.segments)?.type === "straight";
|
|
86
|
+
const opts = getHighlightFreehandSettings({ strokeWidth, showAsComplete });
|
|
83
87
|
return new Polygon2d({
|
|
84
|
-
points:
|
|
88
|
+
points: getStroke(allPointsFromSegments, opts),
|
|
85
89
|
isFilled: true
|
|
86
90
|
});
|
|
87
91
|
}
|
|
@@ -214,7 +218,8 @@ function getHighlightStrokePoints(shape, strokeWidth, forceSolid) {
|
|
|
214
218
|
return { strokePoints, sw };
|
|
215
219
|
}
|
|
216
220
|
function getIsDot(shape) {
|
|
217
|
-
|
|
221
|
+
const segment = shape.props.segments[0];
|
|
222
|
+
return shape.props.segments.length === 1 && b64Vecs.isSinglePoint(segment.path, segment.dim);
|
|
218
223
|
}
|
|
219
224
|
function HighlightRenderer({
|
|
220
225
|
strokeWidth,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/lib/shapes/highlight/HighlightShapeUtil.tsx"],
|
|
4
|
-
"sourcesContent": ["/* eslint-disable react-hooks/rules-of-hooks */\nimport {\n\tCircle2d,\n\tEditor,\n\tPolygon2d,\n\tSVGContainer,\n\tShapeUtil,\n\tSvgExportContext,\n\tTLHighlightShape,\n\tTLHighlightShapeProps,\n\tTLResizeInfo,\n\tVecLike,\n\tdebugFlags,\n\tgetColorValue,\n\thighlightShapeMigrations,\n\thighlightShapeProps,\n\tlast,\n\tlerp,\n\trng,\n\ttlenvReactive,\n\tuseColorMode,\n\tuseValue,\n} from '@tldraw/editor'\nimport { getHighlightFreehandSettings, getPointsFromDrawSegments } from '../draw/getPath'\nimport { FONT_SIZES } from '../shared/default-shape-constants'\nimport { getStrokeOutlinePoints } from '../shared/freehand/getStrokeOutlinePoints'\nimport { getStrokePoints } from '../shared/freehand/getStrokePoints'\nimport { setStrokePointRadii } from '../shared/freehand/setStrokePointRadii'\nimport { getSvgPathFromStrokePoints } from '../shared/freehand/svg'\nimport type { ShapeOptionsWithDisplayValues } from '../shared/getDisplayValues'\nimport { getDisplayValues } from '../shared/getDisplayValues'\nimport { interpolateSegments } from '../shared/interpolate-props'\n\n/** @public */\nexport interface HighlightShapeUtilDisplayValues {\n\tstrokeColor: string\n\tstrokeWidth: number\n\tunderlayOpacity: number\n\toverlayOpacity: number\n}\n\n/** @public */\nexport interface HighlightShapeOptions extends ShapeOptionsWithDisplayValues<\n\tTLHighlightShape,\n\tHighlightShapeUtilDisplayValues\n> {\n\t/**\n\t * The maximum number of points in a line before the draw tool will begin a new shape.\n\t * A higher number will lead to poor performance while drawing very long lines.\n\t */\n\treadonly maxPointsPerShape: number\n}\n\n/** @public */\nexport class HighlightShapeUtil extends ShapeUtil<TLHighlightShape> {\n\tstatic override type = 'highlight' as const\n\tstatic override props = highlightShapeProps\n\tstatic override migrations = highlightShapeMigrations\n\n\toverride options: HighlightShapeOptions = {\n\t\tmaxPointsPerShape: 600,\n\t\tgetDefaultDisplayValues(_editor, shape, theme, colorMode): HighlightShapeUtilDisplayValues {\n\t\t\tconst { color, size } = shape.props\n\t\t\tconst colors = theme.colors[colorMode]\n\t\t\tconst useP3 = !debugFlags.forceSrgb.get() && tlenvReactive.get().supportsP3ColorSpace\n\t\t\tconst strokeColor = useP3\n\t\t\t\t? getColorValue(colors, color, 'highlightP3')\n\t\t\t\t: getColorValue(colors, color, 'highlightSrgb')\n\t\t\treturn {\n\t\t\t\tstrokeColor,\n\t\t\t\tstrokeWidth: theme.fontSize * FONT_SIZES[size] * 1.12,\n\t\t\t\tunderlayOpacity: 0.82,\n\t\t\t\toverlayOpacity: 0.35,\n\t\t\t}\n\t\t},\n\t\tgetCustomDisplayValues(): Partial<HighlightShapeUtilDisplayValues> {\n\t\t\treturn {}\n\t\t},\n\t}\n\n\toverride hideResizeHandles(shape: TLHighlightShape) {\n\t\treturn getIsDot(shape)\n\t}\n\toverride hideRotateHandle(shape: TLHighlightShape) {\n\t\treturn getIsDot(shape)\n\t}\n\toverride hideSelectionBoundsFg(shape: TLHighlightShape) {\n\t\treturn getIsDot(shape)\n\t}\n\n\toverride getDefaultProps(): TLHighlightShape['props'] {\n\t\treturn {\n\t\t\tsegments: [],\n\t\t\tcolor: 'black',\n\t\t\tsize: 'm',\n\t\t\tisComplete: false,\n\t\t\tisPen: false,\n\t\t\tscale: 1,\n\t\t\tscaleX: 1,\n\t\t\tscaleY: 1,\n\t\t}\n\t}\n\n\tgetGeometry(shape: TLHighlightShape) {\n\t\tconst dv = getDisplayValues(this, shape)\n\t\tconst strokeWidth = dv.strokeWidth * shape.props.scale\n\t\tif (getIsDot(shape)) {\n\t\t\treturn new Circle2d({\n\t\t\t\tx: -strokeWidth / 2,\n\t\t\t\ty: -strokeWidth / 2,\n\t\t\t\tradius: strokeWidth / 2,\n\t\t\t\tisFilled: true,\n\t\t\t})\n\t\t}\n\n\t\tconst { strokePoints, sw } = getHighlightStrokePoints(shape, strokeWidth, true)\n\t\tconst opts = getHighlightFreehandSettings({ strokeWidth: sw, showAsComplete: true })\n\t\tsetStrokePointRadii(strokePoints, opts)\n\n\t\treturn new Polygon2d({\n\t\t\tpoints: getStrokeOutlinePoints(strokePoints, opts),\n\t\t\tisFilled: true,\n\t\t})\n\t}\n\n\tcomponent(shape: TLHighlightShape) {\n\t\tconst dv = getDisplayValues(this, shape)\n\t\tconst sw = dv.strokeWidth * shape.props.scale\n\t\tconst forceSolid = useHighlightForceSolid(this.editor, sw)\n\n\t\treturn (\n\t\t\t<SVGContainer>\n\t\t\t\t<HighlightRenderer\n\t\t\t\t\tshape={shape}\n\t\t\t\t\tforceSolid={forceSolid}\n\t\t\t\t\tstrokeWidth={sw}\n\t\t\t\t\topacity={dv.overlayOpacity}\n\t\t\t\t\tstrokeColor={dv.strokeColor}\n\t\t\t\t/>\n\t\t\t</SVGContainer>\n\t\t)\n\t}\n\n\toverride backgroundComponent(shape: TLHighlightShape) {\n\t\tconst colorMode = useColorMode()\n\t\tconst dv = getDisplayValues(this, shape, colorMode)\n\t\tconst sw = dv.strokeWidth * shape.props.scale\n\t\tconst forceSolid = useHighlightForceSolid(this.editor, sw)\n\t\treturn (\n\t\t\t<SVGContainer>\n\t\t\t\t<HighlightRenderer\n\t\t\t\t\tshape={shape}\n\t\t\t\t\tforceSolid={forceSolid}\n\t\t\t\t\tstrokeWidth={sw}\n\t\t\t\t\topacity={dv.underlayOpacity}\n\t\t\t\t\tstrokeColor={dv.strokeColor}\n\t\t\t\t/>\n\t\t\t</SVGContainer>\n\t\t)\n\t}\n\n\toverride getIndicatorPath(shape: TLHighlightShape): Path2D {\n\t\tconst dv = getDisplayValues(this, shape)\n\t\tconst strokeWidth = dv.strokeWidth * shape.props.scale\n\t\tconst zoomLevel = this.editor.getEfficientZoomLevel()\n\t\tconst forceSolid = strokeWidth / zoomLevel < 1.5\n\n\t\tconst { strokePoints, sw } = getHighlightStrokePoints(shape, strokeWidth, forceSolid)\n\t\tconst allPointsFromSegments = getPointsFromDrawSegments(\n\t\t\tshape.props.segments,\n\t\t\tshape.props.scaleX,\n\t\t\tshape.props.scaleY\n\t\t)\n\n\t\tlet strokePath\n\t\tif (strokePoints.length < 2) {\n\t\t\tstrokePath = getIndicatorDot(allPointsFromSegments[0], sw)\n\t\t} else {\n\t\t\tstrokePath = getSvgPathFromStrokePoints(strokePoints, false)\n\t\t}\n\n\t\treturn new Path2D(strokePath)\n\t}\n\n\toverride toSvg(shape: TLHighlightShape, ctx: SvgExportContext) {\n\t\tconst dv = getDisplayValues(this, shape, ctx.colorMode)\n\t\tconst strokeWidth = dv.strokeWidth * shape.props.scale\n\t\tconst forceSolid = strokeWidth < 1.5\n\t\tconst scaleFactor = 1 / shape.props.scale\n\t\treturn (\n\t\t\t<g transform={`scale(${scaleFactor})`}>\n\t\t\t\t<HighlightRenderer\n\t\t\t\t\tforceSolid={forceSolid}\n\t\t\t\t\tstrokeWidth={strokeWidth}\n\t\t\t\t\tshape={shape}\n\t\t\t\t\topacity={dv.overlayOpacity}\n\t\t\t\t\tstrokeColor={dv.strokeColor}\n\t\t\t\t/>\n\t\t\t</g>\n\t\t)\n\t}\n\n\toverride toBackgroundSvg(shape: TLHighlightShape, ctx: SvgExportContext) {\n\t\tconst dv = getDisplayValues(this, shape, ctx.colorMode)\n\t\tconst strokeWidth = dv.strokeWidth * shape.props.scale\n\t\tconst forceSolid = strokeWidth < 1.5\n\t\tconst scaleFactor = 1 / shape.props.scale\n\t\treturn (\n\t\t\t<g transform={`scale(${scaleFactor})`}>\n\t\t\t\t<HighlightRenderer\n\t\t\t\t\tforceSolid={forceSolid}\n\t\t\t\t\tstrokeWidth={strokeWidth}\n\t\t\t\t\tshape={shape}\n\t\t\t\t\topacity={dv.underlayOpacity}\n\t\t\t\t\tstrokeColor={dv.strokeColor}\n\t\t\t\t/>\n\t\t\t</g>\n\t\t)\n\t}\n\n\toverride onResize(shape: TLHighlightShape, info: TLResizeInfo<TLHighlightShape>) {\n\t\tconst newScaleX = info.scaleX * shape.props.scaleX\n\t\tconst newScaleY = info.scaleY * shape.props.scaleY\n\t\tif (newScaleX === 0 || newScaleY === 0) return\n\n\t\treturn {\n\t\t\tprops: {\n\t\t\t\tscaleX: newScaleX,\n\t\t\t\tscaleY: newScaleY,\n\t\t\t},\n\t\t}\n\t}\n\toverride getInterpolatedProps(\n\t\tstartShape: TLHighlightShape,\n\t\tendShape: TLHighlightShape,\n\t\tt: number\n\t): TLHighlightShapeProps {\n\t\treturn {\n\t\t\t...(t > 0.5 ? endShape.props : startShape.props),\n\t\t\t...endShape.props,\n\t\t\tsegments: interpolateSegments(startShape.props.segments, endShape.props.segments, t),\n\t\t\tscale: lerp(startShape.props.scale, endShape.props.scale, t),\n\t\t}\n\t}\n}\n\nfunction getShapeDot(point: VecLike) {\n\tconst r = 0.1\n\treturn `M ${point.x} ${point.y} m -${r}, 0 a ${r},${r} 0 1,0 ${r * 2},0 a ${r},${r} 0 1,0 -${\n\t\tr * 2\n\t},0`\n}\n\nfunction getIndicatorDot(point: VecLike, sw: number) {\n\tconst r = sw / 2\n\treturn `M ${point.x} ${point.y} m -${r}, 0 a ${r},${r} 0 1,0 ${r * 2},0 a ${r},${r} 0 1,0 -${\n\t\tr * 2\n\t},0`\n}\n\nfunction getHighlightStrokePoints(\n\tshape: TLHighlightShape,\n\tstrokeWidth: number,\n\tforceSolid: boolean\n) {\n\tconst allPointsFromSegments = getPointsFromDrawSegments(\n\t\tshape.props.segments,\n\t\tshape.props.scaleX,\n\t\tshape.props.scaleY\n\t)\n\tconst showAsComplete = shape.props.isComplete || last(shape.props.segments)?.type === 'straight'\n\n\tlet sw = strokeWidth\n\tif (!forceSolid && !shape.props.isPen && allPointsFromSegments.length === 1) {\n\t\tsw += rng(shape.id)() * (strokeWidth / 6)\n\t}\n\n\tconst options = getHighlightFreehandSettings({\n\t\tstrokeWidth: sw,\n\t\tshowAsComplete,\n\t})\n\n\tconst strokePoints = getStrokePoints(allPointsFromSegments, options)\n\n\treturn { strokePoints, sw }\n}\n\nfunction getIsDot(shape: TLHighlightShape) {\n\t// First point is 16 base64 chars (3 Float32s = 12 bytes)\n\t// Each delta point is 8 base64 chars (3 Float16s = 6 bytes)\n\t// 1 point = 16 chars, 2 points = 24 chars\n\t// Check if we have less than 2 points without decoding\n\treturn shape.props.segments.length === 1 && shape.props.segments[0].path.length < 24\n}\n\nfunction HighlightRenderer({\n\tstrokeWidth,\n\tforceSolid,\n\tshape,\n\topacity,\n\tstrokeColor,\n}: {\n\tstrokeWidth: number\n\tforceSolid: boolean\n\tshape: TLHighlightShape\n\topacity: number\n\tstrokeColor: string\n}) {\n\tconst allPointsFromSegments = getPointsFromDrawSegments(\n\t\tshape.props.segments,\n\t\tshape.props.scaleX,\n\t\tshape.props.scaleY\n\t)\n\n\tlet sw = strokeWidth\n\tif (!forceSolid && !shape.props.isPen && allPointsFromSegments.length === 1) {\n\t\tsw += rng(shape.id)() * (sw / 6)\n\t}\n\n\tconst options = getHighlightFreehandSettings({\n\t\tstrokeWidth: sw,\n\t\tshowAsComplete: shape.props.isComplete || last(shape.props.segments)?.type === 'straight',\n\t})\n\n\tconst strokePoints = getStrokePoints(allPointsFromSegments, options)\n\n\tconst solidStrokePath =\n\t\tstrokePoints.length > 1\n\t\t\t? getSvgPathFromStrokePoints(strokePoints, false)\n\t\t\t: getShapeDot(allPointsFromSegments[0])\n\n\treturn (\n\t\t<path\n\t\t\td={solidStrokePath}\n\t\t\tstrokeLinecap=\"round\"\n\t\t\tfill=\"none\"\n\t\t\tpointerEvents=\"all\"\n\t\t\tstroke={strokeColor}\n\t\t\tstrokeWidth={sw}\n\t\t\topacity={opacity}\n\t\t/>\n\t)\n}\n\nfunction useHighlightForceSolid(editor: Editor, scaledStrokeWidth: number) {\n\treturn useValue(\n\t\t'forceSolid',\n\t\t() => {\n\t\t\tconst zoomLevel = editor.getEfficientZoomLevel()\n\t\t\treturn scaledStrokeWidth / zoomLevel < 1.5\n\t\t},\n\t\t[editor, scaledStrokeWidth]\n\t)\n}\n"],
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["/* eslint-disable react-hooks/rules-of-hooks */\nimport {\n\tCircle2d,\n\tEditor,\n\tPolygon2d,\n\tSVGContainer,\n\tShapeUtil,\n\tSvgExportContext,\n\tTLHighlightShape,\n\tTLHighlightShapeProps,\n\tTLResizeInfo,\n\tVecLike,\n\tb64Vecs,\n\tdebugFlags,\n\tgetColorValue,\n\thighlightShapeMigrations,\n\thighlightShapeProps,\n\tlast,\n\tlerp,\n\trng,\n\ttlenvReactive,\n\tuseColorMode,\n\tuseValue,\n} from '@tldraw/editor'\nimport { getHighlightFreehandSettings, getPointsFromDrawSegments } from '../draw/getPath'\nimport { FONT_SIZES } from '../shared/default-shape-constants'\nimport { getStroke } from '../shared/freehand/getStroke'\nimport { getStrokePoints } from '../shared/freehand/getStrokePoints'\nimport { getSvgPathFromStrokePoints } from '../shared/freehand/svg'\nimport type { ShapeOptionsWithDisplayValues } from '../shared/getDisplayValues'\nimport { getDisplayValues } from '../shared/getDisplayValues'\nimport { interpolateSegments } from '../shared/interpolate-props'\n\n/** @public */\nexport interface HighlightShapeUtilDisplayValues {\n\tstrokeColor: string\n\tstrokeWidth: number\n\tunderlayOpacity: number\n\toverlayOpacity: number\n}\n\n/** @public */\nexport interface HighlightShapeOptions extends ShapeOptionsWithDisplayValues<\n\tTLHighlightShape,\n\tHighlightShapeUtilDisplayValues\n> {\n\t/**\n\t * The maximum number of points in a line before the draw tool will begin a new shape.\n\t * A higher number will lead to poor performance while drawing very long lines.\n\t */\n\treadonly maxPointsPerShape: number\n}\n\n/** @public */\nexport class HighlightShapeUtil extends ShapeUtil<TLHighlightShape> {\n\tstatic override type = 'highlight' as const\n\tstatic override props = highlightShapeProps\n\tstatic override migrations = highlightShapeMigrations\n\n\toverride options: HighlightShapeOptions = {\n\t\tmaxPointsPerShape: 600,\n\t\tgetDefaultDisplayValues(_editor, shape, theme, colorMode): HighlightShapeUtilDisplayValues {\n\t\t\tconst { color, size } = shape.props\n\t\t\tconst colors = theme.colors[colorMode]\n\t\t\tconst useP3 = !debugFlags.forceSrgb.get() && tlenvReactive.get().supportsP3ColorSpace\n\t\t\tconst strokeColor = useP3\n\t\t\t\t? getColorValue(colors, color, 'highlightP3')\n\t\t\t\t: getColorValue(colors, color, 'highlightSrgb')\n\t\t\treturn {\n\t\t\t\tstrokeColor,\n\t\t\t\tstrokeWidth: theme.fontSize * FONT_SIZES[size] * 1.12,\n\t\t\t\tunderlayOpacity: 0.82,\n\t\t\t\toverlayOpacity: 0.35,\n\t\t\t}\n\t\t},\n\t\tgetCustomDisplayValues(): Partial<HighlightShapeUtilDisplayValues> {\n\t\t\treturn {}\n\t\t},\n\t}\n\n\toverride hideResizeHandles(shape: TLHighlightShape) {\n\t\treturn getIsDot(shape)\n\t}\n\toverride hideRotateHandle(shape: TLHighlightShape) {\n\t\treturn getIsDot(shape)\n\t}\n\toverride hideSelectionBoundsFg(shape: TLHighlightShape) {\n\t\treturn getIsDot(shape)\n\t}\n\n\toverride getDefaultProps(): TLHighlightShape['props'] {\n\t\treturn {\n\t\t\tsegments: [],\n\t\t\tcolor: 'black',\n\t\t\tsize: 'm',\n\t\t\tisComplete: false,\n\t\t\tisPen: false,\n\t\t\tscale: 1,\n\t\t\tscaleX: 1,\n\t\t\tscaleY: 1,\n\t\t}\n\t}\n\n\tgetGeometry(shape: TLHighlightShape) {\n\t\tconst dv = getDisplayValues(this, shape)\n\t\tconst strokeWidth = dv.strokeWidth * shape.props.scale\n\t\tif (getIsDot(shape)) {\n\t\t\treturn new Circle2d({\n\t\t\t\tx: -strokeWidth / 2,\n\t\t\t\ty: -strokeWidth / 2,\n\t\t\t\tradius: strokeWidth / 2,\n\t\t\t\tisFilled: true,\n\t\t\t})\n\t\t}\n\n\t\tconst allPointsFromSegments = getPointsFromDrawSegments(\n\t\t\tshape.props.segments,\n\t\t\tshape.props.scaleX,\n\t\t\tshape.props.scaleY\n\t\t)\n\t\tconst showAsComplete = shape.props.isComplete || last(shape.props.segments)?.type === 'straight'\n\t\tconst opts = getHighlightFreehandSettings({ strokeWidth, showAsComplete })\n\n\t\treturn new Polygon2d({\n\t\t\tpoints: getStroke(allPointsFromSegments, opts),\n\t\t\tisFilled: true,\n\t\t})\n\t}\n\n\tcomponent(shape: TLHighlightShape) {\n\t\tconst dv = getDisplayValues(this, shape)\n\t\tconst sw = dv.strokeWidth * shape.props.scale\n\t\tconst forceSolid = useHighlightForceSolid(this.editor, sw)\n\n\t\treturn (\n\t\t\t<SVGContainer>\n\t\t\t\t<HighlightRenderer\n\t\t\t\t\tshape={shape}\n\t\t\t\t\tforceSolid={forceSolid}\n\t\t\t\t\tstrokeWidth={sw}\n\t\t\t\t\topacity={dv.overlayOpacity}\n\t\t\t\t\tstrokeColor={dv.strokeColor}\n\t\t\t\t/>\n\t\t\t</SVGContainer>\n\t\t)\n\t}\n\n\toverride backgroundComponent(shape: TLHighlightShape) {\n\t\tconst colorMode = useColorMode()\n\t\tconst dv = getDisplayValues(this, shape, colorMode)\n\t\tconst sw = dv.strokeWidth * shape.props.scale\n\t\tconst forceSolid = useHighlightForceSolid(this.editor, sw)\n\t\treturn (\n\t\t\t<SVGContainer>\n\t\t\t\t<HighlightRenderer\n\t\t\t\t\tshape={shape}\n\t\t\t\t\tforceSolid={forceSolid}\n\t\t\t\t\tstrokeWidth={sw}\n\t\t\t\t\topacity={dv.underlayOpacity}\n\t\t\t\t\tstrokeColor={dv.strokeColor}\n\t\t\t\t/>\n\t\t\t</SVGContainer>\n\t\t)\n\t}\n\n\toverride getIndicatorPath(shape: TLHighlightShape): Path2D {\n\t\tconst dv = getDisplayValues(this, shape)\n\t\tconst strokeWidth = dv.strokeWidth * shape.props.scale\n\t\tconst zoomLevel = this.editor.getEfficientZoomLevel()\n\t\tconst forceSolid = strokeWidth / zoomLevel < 1.5\n\n\t\tconst { strokePoints, sw } = getHighlightStrokePoints(shape, strokeWidth, forceSolid)\n\t\tconst allPointsFromSegments = getPointsFromDrawSegments(\n\t\t\tshape.props.segments,\n\t\t\tshape.props.scaleX,\n\t\t\tshape.props.scaleY\n\t\t)\n\n\t\tlet strokePath\n\t\tif (strokePoints.length < 2) {\n\t\t\tstrokePath = getIndicatorDot(allPointsFromSegments[0], sw)\n\t\t} else {\n\t\t\tstrokePath = getSvgPathFromStrokePoints(strokePoints, false)\n\t\t}\n\n\t\treturn new Path2D(strokePath)\n\t}\n\n\toverride toSvg(shape: TLHighlightShape, ctx: SvgExportContext) {\n\t\tconst dv = getDisplayValues(this, shape, ctx.colorMode)\n\t\tconst strokeWidth = dv.strokeWidth * shape.props.scale\n\t\tconst forceSolid = strokeWidth < 1.5\n\t\tconst scaleFactor = 1 / shape.props.scale\n\t\treturn (\n\t\t\t<g transform={`scale(${scaleFactor})`}>\n\t\t\t\t<HighlightRenderer\n\t\t\t\t\tforceSolid={forceSolid}\n\t\t\t\t\tstrokeWidth={strokeWidth}\n\t\t\t\t\tshape={shape}\n\t\t\t\t\topacity={dv.overlayOpacity}\n\t\t\t\t\tstrokeColor={dv.strokeColor}\n\t\t\t\t/>\n\t\t\t</g>\n\t\t)\n\t}\n\n\toverride toBackgroundSvg(shape: TLHighlightShape, ctx: SvgExportContext) {\n\t\tconst dv = getDisplayValues(this, shape, ctx.colorMode)\n\t\tconst strokeWidth = dv.strokeWidth * shape.props.scale\n\t\tconst forceSolid = strokeWidth < 1.5\n\t\tconst scaleFactor = 1 / shape.props.scale\n\t\treturn (\n\t\t\t<g transform={`scale(${scaleFactor})`}>\n\t\t\t\t<HighlightRenderer\n\t\t\t\t\tforceSolid={forceSolid}\n\t\t\t\t\tstrokeWidth={strokeWidth}\n\t\t\t\t\tshape={shape}\n\t\t\t\t\topacity={dv.underlayOpacity}\n\t\t\t\t\tstrokeColor={dv.strokeColor}\n\t\t\t\t/>\n\t\t\t</g>\n\t\t)\n\t}\n\n\toverride onResize(shape: TLHighlightShape, info: TLResizeInfo<TLHighlightShape>) {\n\t\tconst newScaleX = info.scaleX * shape.props.scaleX\n\t\tconst newScaleY = info.scaleY * shape.props.scaleY\n\t\tif (newScaleX === 0 || newScaleY === 0) return\n\n\t\treturn {\n\t\t\tprops: {\n\t\t\t\tscaleX: newScaleX,\n\t\t\t\tscaleY: newScaleY,\n\t\t\t},\n\t\t}\n\t}\n\toverride getInterpolatedProps(\n\t\tstartShape: TLHighlightShape,\n\t\tendShape: TLHighlightShape,\n\t\tt: number\n\t): TLHighlightShapeProps {\n\t\treturn {\n\t\t\t...(t > 0.5 ? endShape.props : startShape.props),\n\t\t\t...endShape.props,\n\t\t\tsegments: interpolateSegments(startShape.props.segments, endShape.props.segments, t),\n\t\t\tscale: lerp(startShape.props.scale, endShape.props.scale, t),\n\t\t}\n\t}\n}\n\nfunction getShapeDot(point: VecLike) {\n\tconst r = 0.1\n\treturn `M ${point.x} ${point.y} m -${r}, 0 a ${r},${r} 0 1,0 ${r * 2},0 a ${r},${r} 0 1,0 -${\n\t\tr * 2\n\t},0`\n}\n\nfunction getIndicatorDot(point: VecLike, sw: number) {\n\tconst r = sw / 2\n\treturn `M ${point.x} ${point.y} m -${r}, 0 a ${r},${r} 0 1,0 ${r * 2},0 a ${r},${r} 0 1,0 -${\n\t\tr * 2\n\t},0`\n}\n\nfunction getHighlightStrokePoints(\n\tshape: TLHighlightShape,\n\tstrokeWidth: number,\n\tforceSolid: boolean\n) {\n\tconst allPointsFromSegments = getPointsFromDrawSegments(\n\t\tshape.props.segments,\n\t\tshape.props.scaleX,\n\t\tshape.props.scaleY\n\t)\n\tconst showAsComplete = shape.props.isComplete || last(shape.props.segments)?.type === 'straight'\n\n\tlet sw = strokeWidth\n\tif (!forceSolid && !shape.props.isPen && allPointsFromSegments.length === 1) {\n\t\tsw += rng(shape.id)() * (strokeWidth / 6)\n\t}\n\n\tconst options = getHighlightFreehandSettings({\n\t\tstrokeWidth: sw,\n\t\tshowAsComplete,\n\t})\n\n\tconst strokePoints = getStrokePoints(allPointsFromSegments, options)\n\n\treturn { strokePoints, sw }\n}\n\nfunction getIsDot(shape: TLHighlightShape) {\n\t// A dot is a single-point segment. isSinglePoint knows the per-encoding length\n\t// (and takes the segment's dim), so this stays correct for both 2D and 3D paths.\n\tconst segment = shape.props.segments[0]\n\treturn shape.props.segments.length === 1 && b64Vecs.isSinglePoint(segment.path, segment.dim)\n}\n\nfunction HighlightRenderer({\n\tstrokeWidth,\n\tforceSolid,\n\tshape,\n\topacity,\n\tstrokeColor,\n}: {\n\tstrokeWidth: number\n\tforceSolid: boolean\n\tshape: TLHighlightShape\n\topacity: number\n\tstrokeColor: string\n}) {\n\tconst allPointsFromSegments = getPointsFromDrawSegments(\n\t\tshape.props.segments,\n\t\tshape.props.scaleX,\n\t\tshape.props.scaleY\n\t)\n\n\tlet sw = strokeWidth\n\tif (!forceSolid && !shape.props.isPen && allPointsFromSegments.length === 1) {\n\t\tsw += rng(shape.id)() * (sw / 6)\n\t}\n\n\tconst options = getHighlightFreehandSettings({\n\t\tstrokeWidth: sw,\n\t\tshowAsComplete: shape.props.isComplete || last(shape.props.segments)?.type === 'straight',\n\t})\n\n\tconst strokePoints = getStrokePoints(allPointsFromSegments, options)\n\n\tconst solidStrokePath =\n\t\tstrokePoints.length > 1\n\t\t\t? getSvgPathFromStrokePoints(strokePoints, false)\n\t\t\t: getShapeDot(allPointsFromSegments[0])\n\n\treturn (\n\t\t<path\n\t\t\td={solidStrokePath}\n\t\t\tstrokeLinecap=\"round\"\n\t\t\tfill=\"none\"\n\t\t\tpointerEvents=\"all\"\n\t\t\tstroke={strokeColor}\n\t\t\tstrokeWidth={sw}\n\t\t\topacity={opacity}\n\t\t/>\n\t)\n}\n\nfunction useHighlightForceSolid(editor: Editor, scaledStrokeWidth: number) {\n\treturn useValue(\n\t\t'forceSolid',\n\t\t() => {\n\t\t\tconst zoomLevel = editor.getEfficientZoomLevel()\n\t\t\treturn scaledStrokeWidth / zoomLevel < 1.5\n\t\t},\n\t\t[editor, scaledStrokeWidth]\n\t)\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -135,7 +135,7 @@ class ImageShapeUtil extends BaseBoxShapeUtil {
|
|
|
135
135
|
onResize(shape, info) {
|
|
136
136
|
let resized = resizeBox(shape, info);
|
|
137
137
|
const { flipX, flipY } = info.initialShape.props;
|
|
138
|
-
const { scaleX, scaleY
|
|
138
|
+
const { scaleX, scaleY } = info;
|
|
139
139
|
resized = {
|
|
140
140
|
...resized,
|
|
141
141
|
props: {
|
|
@@ -145,16 +145,8 @@ class ImageShapeUtil extends BaseBoxShapeUtil {
|
|
|
145
145
|
}
|
|
146
146
|
};
|
|
147
147
|
if (!shape.props.crop) return resized;
|
|
148
|
-
const flipCropHorizontally =
|
|
149
|
-
|
|
150
|
-
(// We resized the shape past it's bounds, so it flipped
|
|
151
|
-
mode === "scale_shape" && scaleX === -1 || mode === "resize_bounds" && flipX !== resized.props.flipX)
|
|
152
|
-
);
|
|
153
|
-
const flipCropVertically = (
|
|
154
|
-
// We used the flip vertically feature
|
|
155
|
-
(// We resized the shape past it's bounds, so it flipped
|
|
156
|
-
mode === "scale_shape" && scaleY === -1 || mode === "resize_bounds" && flipY !== resized.props.flipY)
|
|
157
|
-
);
|
|
148
|
+
const flipCropHorizontally = scaleX < 0;
|
|
149
|
+
const flipCropVertically = scaleY < 0;
|
|
158
150
|
const { topLeft, bottomRight } = shape.props.crop;
|
|
159
151
|
resized.props.crop = {
|
|
160
152
|
topLeft: {
|