tldraw 5.4.0-next.ef99ab47e5ce → 5.4.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 +2826 -3226
- package/RELEASE_NOTES.md +190 -2
- package/dist-cjs/index.d.ts +264 -275
- package/dist-cjs/index.js +1 -1
- package/dist-cjs/lib/defaultExternalContentHandlers.js +32 -16
- package/dist-cjs/lib/defaultExternalContentHandlers.js.map +2 -2
- package/dist-cjs/lib/shapes/arrow/curved-arrow.js +2 -2
- package/dist-cjs/lib/shapes/arrow/curved-arrow.js.map +2 -2
- package/dist-cjs/lib/shapes/arrow/elbow/getElbowArrowInfo.js +2 -2
- package/dist-cjs/lib/shapes/arrow/elbow/getElbowArrowInfo.js.map +2 -2
- package/dist-cjs/lib/shapes/arrow/getArrowInfo.js +1 -1
- package/dist-cjs/lib/shapes/arrow/getArrowInfo.js.map +2 -2
- package/dist-cjs/lib/shapes/arrow/straight-arrow.js +2 -2
- package/dist-cjs/lib/shapes/arrow/straight-arrow.js.map +2 -2
- package/dist-cjs/lib/shapes/arrow/toolStates/Idle.js +2 -3
- package/dist-cjs/lib/shapes/arrow/toolStates/Idle.js.map +2 -2
- package/dist-cjs/lib/shapes/arrow/toolStates/Pointing.js +7 -5
- package/dist-cjs/lib/shapes/arrow/toolStates/Pointing.js.map +2 -2
- package/dist-cjs/lib/shapes/draw/toolStates/Drawing.js +8 -6
- package/dist-cjs/lib/shapes/draw/toolStates/Drawing.js.map +2 -2
- package/dist-cjs/lib/shapes/geo/getGeoShapePath.js +3 -1
- package/dist-cjs/lib/shapes/geo/getGeoShapePath.js.map +2 -2
- package/dist-cjs/lib/shapes/geo/toolStates/Idle.js +2 -3
- package/dist-cjs/lib/shapes/geo/toolStates/Idle.js.map +2 -2
- package/dist-cjs/lib/shapes/geo/toolStates/Pointing.js +1 -1
- package/dist-cjs/lib/shapes/geo/toolStates/Pointing.js.map +2 -2
- package/dist-cjs/lib/shapes/line/toolStates/Pointing.js +2 -6
- package/dist-cjs/lib/shapes/line/toolStates/Pointing.js.map +2 -2
- package/dist-cjs/lib/shapes/note/NoteShapeUtil.js +4 -4
- package/dist-cjs/lib/shapes/note/NoteShapeUtil.js.map +2 -2
- package/dist-cjs/lib/shapes/note/noteHelpers.js +6 -5
- package/dist-cjs/lib/shapes/note/noteHelpers.js.map +2 -2
- package/dist-cjs/lib/shapes/note/toolStates/Pointing.js +1 -1
- package/dist-cjs/lib/shapes/note/toolStates/Pointing.js.map +2 -2
- package/dist-cjs/lib/shapes/shared/crop.js +1 -1
- package/dist-cjs/lib/shapes/shared/crop.js.map +2 -2
- package/dist-cjs/lib/shapes/text/toolStates/Idle.js +1 -1
- package/dist-cjs/lib/shapes/text/toolStates/Idle.js.map +2 -2
- package/dist-cjs/lib/shapes/text/toolStates/Pointing.js +1 -0
- package/dist-cjs/lib/shapes/text/toolStates/Pointing.js.map +2 -2
- package/dist-cjs/lib/shapes/video/VideoShapeUtil.js +3 -2
- package/dist-cjs/lib/shapes/video/VideoShapeUtil.js.map +2 -2
- package/dist-cjs/lib/tools/EraserTool/childStates/Erasing.js +2 -0
- package/dist-cjs/lib/tools/EraserTool/childStates/Erasing.js.map +2 -2
- package/dist-cjs/lib/tools/HandTool/childStates/OneFingerZooming.js +6 -0
- package/dist-cjs/lib/tools/HandTool/childStates/OneFingerZooming.js.map +2 -2
- package/dist-cjs/lib/tools/SelectTool/SelectTool.js +3 -0
- package/dist-cjs/lib/tools/SelectTool/SelectTool.js.map +2 -2
- package/dist-cjs/lib/tools/SelectTool/childStates/Brushing.js +1 -0
- package/dist-cjs/lib/tools/SelectTool/childStates/Brushing.js.map +2 -2
- package/dist-cjs/lib/tools/SelectTool/childStates/Crop/Crop.js +1 -0
- package/dist-cjs/lib/tools/SelectTool/childStates/Crop/Crop.js.map +2 -2
- package/dist-cjs/lib/tools/SelectTool/childStates/DraggingHandle.js +1 -3
- package/dist-cjs/lib/tools/SelectTool/childStates/DraggingHandle.js.map +2 -2
- package/dist-cjs/lib/tools/SelectTool/childStates/Idle.js +6 -3
- package/dist-cjs/lib/tools/SelectTool/childStates/Idle.js.map +2 -2
- package/dist-cjs/lib/tools/SelectTool/childStates/PointingArrowLabel.js +1 -1
- package/dist-cjs/lib/tools/SelectTool/childStates/PointingArrowLabel.js.map +2 -2
- package/dist-cjs/lib/tools/SelectTool/childStates/PointingCanvas.js +3 -0
- package/dist-cjs/lib/tools/SelectTool/childStates/PointingCanvas.js.map +2 -2
- package/dist-cjs/lib/tools/SelectTool/childStates/PointingHandle.js +1 -0
- package/dist-cjs/lib/tools/SelectTool/childStates/PointingHandle.js.map +2 -2
- package/dist-cjs/lib/tools/SelectTool/childStates/PointingShape.js +1 -1
- package/dist-cjs/lib/tools/SelectTool/childStates/PointingShape.js.map +2 -2
- package/dist-cjs/lib/tools/SelectTool/childStates/Resizing.js +22 -30
- package/dist-cjs/lib/tools/SelectTool/childStates/Resizing.js.map +2 -2
- package/dist-cjs/lib/tools/SelectTool/childStates/ScribbleBrushing.js +1 -3
- package/dist-cjs/lib/tools/SelectTool/childStates/ScribbleBrushing.js.map +2 -2
- package/dist-cjs/lib/tools/SelectTool/childStates/Translating.js +4 -1
- package/dist-cjs/lib/tools/SelectTool/childStates/Translating.js.map +2 -2
- package/dist-cjs/lib/tools/SelectTool/selectHelpers.js +10 -0
- package/dist-cjs/lib/tools/SelectTool/selectHelpers.js.map +2 -2
- package/dist-cjs/lib/ui/TldrawUi.js +2 -3
- package/dist-cjs/lib/ui/TldrawUi.js.map +2 -2
- package/dist-cjs/lib/ui/components/ActionsMenu/DefaultActionsMenu.js +1 -11
- package/dist-cjs/lib/ui/components/ActionsMenu/DefaultActionsMenu.js.map +2 -2
- package/dist-cjs/lib/ui/components/ContextMenu/DefaultContextMenu.js +6 -1
- package/dist-cjs/lib/ui/components/ContextMenu/DefaultContextMenu.js.map +2 -2
- package/dist-cjs/lib/ui/components/ContextMenu/DefaultContextMenuContent.js +1 -1
- package/dist-cjs/lib/ui/components/ContextMenu/DefaultContextMenuContent.js.map +2 -2
- package/dist-cjs/lib/ui/components/Dialogs.js +8 -0
- package/dist-cjs/lib/ui/components/Dialogs.js.map +2 -2
- package/dist-cjs/lib/ui/components/EditLinkDialog.js +5 -5
- package/dist-cjs/lib/ui/components/EditLinkDialog.js.map +2 -2
- package/dist-cjs/lib/ui/components/Minimap/DefaultMinimap.js +4 -20
- package/dist-cjs/lib/ui/components/Minimap/DefaultMinimap.js.map +2 -2
- package/dist-cjs/lib/ui/components/SharePanel/DefaultPeopleMenuItem.js +1 -2
- package/dist-cjs/lib/ui/components/SharePanel/DefaultPeopleMenuItem.js.map +2 -2
- package/dist-cjs/lib/ui/components/StylePanel/StylePanelDoubleDropdownPicker.js +2 -0
- package/dist-cjs/lib/ui/components/StylePanel/StylePanelDoubleDropdownPicker.js.map +2 -2
- package/dist-cjs/lib/ui/components/Toolbar/AltTextEditor.js +1 -0
- package/dist-cjs/lib/ui/components/Toolbar/AltTextEditor.js.map +2 -2
- package/dist-cjs/lib/ui/components/Toolbar/DefaultImageToolbarContent.js +10 -8
- package/dist-cjs/lib/ui/components/Toolbar/DefaultImageToolbarContent.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/TldrawUiSlider.js +20 -1
- package/dist-cjs/lib/ui/components/primitives/TldrawUiSlider.js.map +2 -2
- package/dist-cjs/lib/ui/context/actions.js +8 -8
- package/dist-cjs/lib/ui/context/actions.js.map +2 -2
- package/dist-cjs/lib/ui/hooks/useClipboardEvents.js +2 -0
- package/dist-cjs/lib/ui/hooks/useClipboardEvents.js.map +2 -2
- package/dist-cjs/lib/ui/hooks/useCommentingEnabled.js +1 -1
- package/dist-cjs/lib/ui/hooks/useCommentingEnabled.js.map +2 -2
- package/dist-cjs/lib/ui/hooks/useFlatten.js +42 -23
- package/dist-cjs/lib/ui/hooks/useFlatten.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-esm/index.d.mts +264 -275
- package/dist-esm/index.mjs +1 -1
- package/dist-esm/lib/defaultExternalContentHandlers.mjs +32 -16
- package/dist-esm/lib/defaultExternalContentHandlers.mjs.map +2 -2
- package/dist-esm/lib/shapes/arrow/curved-arrow.mjs +2 -2
- package/dist-esm/lib/shapes/arrow/curved-arrow.mjs.map +2 -2
- package/dist-esm/lib/shapes/arrow/elbow/getElbowArrowInfo.mjs +2 -2
- package/dist-esm/lib/shapes/arrow/elbow/getElbowArrowInfo.mjs.map +2 -2
- package/dist-esm/lib/shapes/arrow/getArrowInfo.mjs +1 -1
- package/dist-esm/lib/shapes/arrow/getArrowInfo.mjs.map +2 -2
- package/dist-esm/lib/shapes/arrow/straight-arrow.mjs +2 -2
- package/dist-esm/lib/shapes/arrow/straight-arrow.mjs.map +2 -2
- package/dist-esm/lib/shapes/arrow/toolStates/Idle.mjs +3 -4
- package/dist-esm/lib/shapes/arrow/toolStates/Idle.mjs.map +2 -2
- package/dist-esm/lib/shapes/arrow/toolStates/Pointing.mjs +7 -5
- package/dist-esm/lib/shapes/arrow/toolStates/Pointing.mjs.map +2 -2
- package/dist-esm/lib/shapes/draw/toolStates/Drawing.mjs +8 -6
- package/dist-esm/lib/shapes/draw/toolStates/Drawing.mjs.map +2 -2
- package/dist-esm/lib/shapes/geo/getGeoShapePath.mjs +3 -1
- package/dist-esm/lib/shapes/geo/getGeoShapePath.mjs.map +2 -2
- package/dist-esm/lib/shapes/geo/toolStates/Idle.mjs +3 -4
- package/dist-esm/lib/shapes/geo/toolStates/Idle.mjs.map +2 -2
- package/dist-esm/lib/shapes/geo/toolStates/Pointing.mjs +1 -1
- package/dist-esm/lib/shapes/geo/toolStates/Pointing.mjs.map +2 -2
- package/dist-esm/lib/shapes/line/toolStates/Pointing.mjs +2 -7
- package/dist-esm/lib/shapes/line/toolStates/Pointing.mjs.map +2 -2
- package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs +4 -4
- package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/shapes/note/noteHelpers.mjs +6 -5
- package/dist-esm/lib/shapes/note/noteHelpers.mjs.map +2 -2
- package/dist-esm/lib/shapes/note/toolStates/Pointing.mjs +1 -1
- package/dist-esm/lib/shapes/note/toolStates/Pointing.mjs.map +2 -2
- package/dist-esm/lib/shapes/shared/crop.mjs +1 -1
- package/dist-esm/lib/shapes/shared/crop.mjs.map +2 -2
- package/dist-esm/lib/shapes/text/toolStates/Idle.mjs +2 -2
- package/dist-esm/lib/shapes/text/toolStates/Idle.mjs.map +2 -2
- package/dist-esm/lib/shapes/text/toolStates/Pointing.mjs +1 -0
- package/dist-esm/lib/shapes/text/toolStates/Pointing.mjs.map +2 -2
- package/dist-esm/lib/shapes/video/VideoShapeUtil.mjs +3 -2
- package/dist-esm/lib/shapes/video/VideoShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/tools/EraserTool/childStates/Erasing.mjs +2 -0
- package/dist-esm/lib/tools/EraserTool/childStates/Erasing.mjs.map +2 -2
- package/dist-esm/lib/tools/HandTool/childStates/OneFingerZooming.mjs +6 -0
- package/dist-esm/lib/tools/HandTool/childStates/OneFingerZooming.mjs.map +2 -2
- package/dist-esm/lib/tools/SelectTool/SelectTool.mjs +3 -0
- package/dist-esm/lib/tools/SelectTool/SelectTool.mjs.map +2 -2
- package/dist-esm/lib/tools/SelectTool/childStates/Brushing.mjs +1 -0
- package/dist-esm/lib/tools/SelectTool/childStates/Brushing.mjs.map +2 -2
- package/dist-esm/lib/tools/SelectTool/childStates/Crop/Crop.mjs +1 -0
- package/dist-esm/lib/tools/SelectTool/childStates/Crop/Crop.mjs.map +2 -2
- package/dist-esm/lib/tools/SelectTool/childStates/DraggingHandle.mjs +1 -3
- package/dist-esm/lib/tools/SelectTool/childStates/DraggingHandle.mjs.map +2 -2
- package/dist-esm/lib/tools/SelectTool/childStates/Idle.mjs +6 -3
- package/dist-esm/lib/tools/SelectTool/childStates/Idle.mjs.map +2 -2
- package/dist-esm/lib/tools/SelectTool/childStates/PointingArrowLabel.mjs +1 -1
- package/dist-esm/lib/tools/SelectTool/childStates/PointingArrowLabel.mjs.map +2 -2
- package/dist-esm/lib/tools/SelectTool/childStates/PointingCanvas.mjs +3 -0
- package/dist-esm/lib/tools/SelectTool/childStates/PointingCanvas.mjs.map +2 -2
- package/dist-esm/lib/tools/SelectTool/childStates/PointingHandle.mjs +5 -1
- package/dist-esm/lib/tools/SelectTool/childStates/PointingHandle.mjs.map +2 -2
- package/dist-esm/lib/tools/SelectTool/childStates/PointingShape.mjs +1 -1
- package/dist-esm/lib/tools/SelectTool/childStates/PointingShape.mjs.map +2 -2
- package/dist-esm/lib/tools/SelectTool/childStates/Resizing.mjs +22 -31
- package/dist-esm/lib/tools/SelectTool/childStates/Resizing.mjs.map +2 -2
- package/dist-esm/lib/tools/SelectTool/childStates/ScribbleBrushing.mjs +1 -3
- package/dist-esm/lib/tools/SelectTool/childStates/ScribbleBrushing.mjs.map +2 -2
- package/dist-esm/lib/tools/SelectTool/childStates/Translating.mjs +4 -1
- package/dist-esm/lib/tools/SelectTool/childStates/Translating.mjs.map +2 -2
- package/dist-esm/lib/tools/SelectTool/selectHelpers.mjs +10 -0
- package/dist-esm/lib/tools/SelectTool/selectHelpers.mjs.map +2 -2
- package/dist-esm/lib/ui/TldrawUi.mjs +2 -3
- package/dist-esm/lib/ui/TldrawUi.mjs.map +2 -2
- package/dist-esm/lib/ui/components/ActionsMenu/DefaultActionsMenu.mjs +2 -12
- package/dist-esm/lib/ui/components/ActionsMenu/DefaultActionsMenu.mjs.map +2 -2
- package/dist-esm/lib/ui/components/ContextMenu/DefaultContextMenu.mjs +7 -2
- package/dist-esm/lib/ui/components/ContextMenu/DefaultContextMenu.mjs.map +2 -2
- package/dist-esm/lib/ui/components/ContextMenu/DefaultContextMenuContent.mjs +1 -1
- package/dist-esm/lib/ui/components/ContextMenu/DefaultContextMenuContent.mjs.map +2 -2
- package/dist-esm/lib/ui/components/Dialogs.mjs +9 -1
- package/dist-esm/lib/ui/components/Dialogs.mjs.map +2 -2
- package/dist-esm/lib/ui/components/EditLinkDialog.mjs +5 -5
- package/dist-esm/lib/ui/components/EditLinkDialog.mjs.map +2 -2
- package/dist-esm/lib/ui/components/Minimap/DefaultMinimap.mjs +5 -22
- package/dist-esm/lib/ui/components/Minimap/DefaultMinimap.mjs.map +2 -2
- package/dist-esm/lib/ui/components/SharePanel/DefaultPeopleMenuItem.mjs +1 -2
- package/dist-esm/lib/ui/components/SharePanel/DefaultPeopleMenuItem.mjs.map +2 -2
- package/dist-esm/lib/ui/components/StylePanel/StylePanelDoubleDropdownPicker.mjs +2 -0
- package/dist-esm/lib/ui/components/StylePanel/StylePanelDoubleDropdownPicker.mjs.map +2 -2
- package/dist-esm/lib/ui/components/Toolbar/AltTextEditor.mjs +1 -0
- package/dist-esm/lib/ui/components/Toolbar/AltTextEditor.mjs.map +2 -2
- package/dist-esm/lib/ui/components/Toolbar/DefaultImageToolbarContent.mjs +10 -8
- package/dist-esm/lib/ui/components/Toolbar/DefaultImageToolbarContent.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/TldrawUiSlider.mjs +20 -1
- package/dist-esm/lib/ui/components/primitives/TldrawUiSlider.mjs.map +2 -2
- package/dist-esm/lib/ui/context/actions.mjs +8 -8
- package/dist-esm/lib/ui/context/actions.mjs.map +2 -2
- package/dist-esm/lib/ui/hooks/useClipboardEvents.mjs +2 -0
- package/dist-esm/lib/ui/hooks/useClipboardEvents.mjs.map +2 -2
- package/dist-esm/lib/ui/hooks/useCommentingEnabled.mjs +2 -2
- package/dist-esm/lib/ui/hooks/useCommentingEnabled.mjs.map +2 -2
- package/dist-esm/lib/ui/hooks/useFlatten.mjs +42 -23
- package/dist-esm/lib/ui/hooks/useFlatten.mjs.map +2 -2
- package/dist-esm/lib/ui/version.mjs +3 -3
- package/dist-esm/lib/ui/version.mjs.map +1 -1
- package/package.json +12 -6
- package/src/lib/defaultExternalContentHandlers.test.ts +43 -0
- package/src/lib/defaultExternalContentHandlers.ts +40 -18
- package/src/lib/shapes/arrow/ArrowShapeTool.test.ts +17 -0
- package/src/lib/shapes/arrow/curved-arrow.ts +2 -2
- package/src/lib/shapes/arrow/elbow/getElbowArrowInfo.tsx +5 -3
- package/src/lib/shapes/arrow/getArrowInfo.ts +2 -1
- package/src/lib/shapes/arrow/straight-arrow.ts +2 -2
- package/src/lib/shapes/arrow/toolStates/Idle.tsx +3 -4
- package/src/lib/shapes/arrow/toolStates/Pointing.tsx +10 -6
- package/src/lib/shapes/draw/DrawShapeTool.test.ts +19 -0
- package/src/lib/shapes/draw/toolStates/Drawing.ts +12 -6
- package/src/lib/shapes/frame/FrameShapeTool.test.ts +17 -0
- package/src/lib/shapes/geo/GeoShapeTool.test.ts +28 -0
- package/src/lib/shapes/geo/getGeoShapePath.ts +3 -1
- package/src/lib/shapes/geo/toolStates/Idle.ts +3 -4
- package/src/lib/shapes/geo/toolStates/Pointing.ts +2 -1
- package/src/lib/shapes/line/LineShapeTool.test.ts +30 -1
- package/src/lib/shapes/line/toolStates/Pointing.ts +6 -7
- package/src/lib/shapes/note/NoteShapeTool.test.ts +45 -0
- package/src/lib/shapes/note/NoteShapeUtil.tsx +7 -4
- package/src/lib/shapes/note/noteHelpers.ts +18 -8
- package/src/lib/shapes/note/toolStates/Pointing.ts +2 -1
- package/src/lib/shapes/shared/crop.ts +7 -1
- package/src/lib/shapes/text/TextShapeTool.test.ts +33 -0
- package/src/lib/shapes/text/toolStates/Idle.ts +2 -2
- package/src/lib/shapes/text/toolStates/Pointing.ts +3 -0
- package/src/lib/shapes/video/VideoShapeUtil.tsx +4 -2
- package/src/lib/tools/EraserTool/childStates/Erasing.ts +5 -0
- package/src/lib/tools/HandTool/childStates/OneFingerZooming.ts +10 -0
- package/src/lib/tools/SelectTool/SelectTool.ts +4 -0
- package/src/lib/tools/SelectTool/childStates/Brushing.ts +4 -0
- package/src/lib/tools/SelectTool/childStates/Crop/Crop.ts +4 -0
- package/src/lib/tools/SelectTool/childStates/DraggingHandle.tsx +3 -4
- package/src/lib/tools/SelectTool/childStates/Idle.ts +10 -3
- package/src/lib/tools/SelectTool/childStates/PointingArrowLabel.ts +1 -1
- package/src/lib/tools/SelectTool/childStates/PointingCanvas.ts +4 -0
- package/src/lib/tools/SelectTool/childStates/PointingHandle.ts +6 -1
- package/src/lib/tools/SelectTool/childStates/PointingShape.ts +4 -1
- package/src/lib/tools/SelectTool/childStates/Resizing.ts +30 -33
- package/src/lib/tools/SelectTool/childStates/ScribbleBrushing.ts +3 -3
- package/src/lib/tools/SelectTool/childStates/Translating.ts +6 -0
- package/src/lib/tools/SelectTool/selectHelpers.ts +21 -0
- package/src/lib/ui/TldrawUi.tsx +1 -2
- package/src/lib/ui/components/ActionsMenu/DefaultActionsMenu.tsx +4 -14
- package/src/lib/ui/components/ContextMenu/DefaultContextMenu.tsx +8 -2
- package/src/lib/ui/components/ContextMenu/DefaultContextMenuContent.tsx +5 -1
- package/src/lib/ui/components/Dialogs.tsx +17 -1
- package/src/lib/ui/components/EditLinkDialog.tsx +8 -7
- package/src/lib/ui/components/Minimap/DefaultMinimap.tsx +5 -23
- package/src/lib/ui/components/SharePanel/DefaultPeopleMenuItem.tsx +2 -3
- package/src/lib/ui/components/StylePanel/StylePanelDoubleDropdownPicker.tsx +2 -0
- package/src/lib/ui/components/Toolbar/AltTextEditor.tsx +1 -0
- package/src/lib/ui/components/Toolbar/DefaultImageToolbarContent.tsx +13 -8
- package/src/lib/ui/components/primitives/TldrawUiSlider.test.tsx +92 -0
- package/src/lib/ui/components/primitives/TldrawUiSlider.tsx +25 -1
- package/src/lib/ui/context/actions.tsx +25 -8
- package/src/lib/ui/hooks/useClipboardEvents.ts +2 -0
- package/src/lib/ui/hooks/useCommentingEnabled.ts +5 -3
- package/src/lib/ui/hooks/useFlatten.ts +56 -23
- package/src/lib/ui/version.ts +3 -3
- package/src/lib/ui.css +7 -16
- package/src/test/ClickManager.test.ts +18 -0
- package/src/test/Editor.test.tsx +3 -0
- package/src/test/EraserTool.test.ts +18 -2
- package/src/test/HandTool.test.ts +21 -0
- package/src/test/LaserTool.test.ts +46 -0
- package/src/test/ScribbleManager.test.ts +19 -0
- package/src/test/SelectTool.test.ts +110 -0
- package/src/test/TldrawEditor.test.tsx +18 -0
- package/src/test/VideoShapeUtil.test.tsx +126 -0
- package/src/test/actions-menu-readonly.test.tsx +37 -0
- package/src/test/bookmark-shapes.test.ts +110 -0
- package/src/test/commands/__snapshots__/packShapes.test.ts.snap +6 -6
- package/src/test/commands/clipboard.test.ts +36 -1
- package/src/test/commands/lockShapes.test.ts +11 -0
- package/src/test/commands/packShapes.test.ts +20 -0
- package/src/test/commands/putContent.test.ts +35 -1
- package/src/test/commands/setCamera.test.ts +69 -0
- package/src/test/commands/stackShapes.test.ts +12 -0
- package/src/test/commands/updateViewportPageBounds.test.ts +8 -0
- package/src/test/cropping.test.ts +162 -0
- package/src/test/customSnapping.test.tsx +32 -0
- package/src/test/defaultHandleExternalFileContent.test.ts +86 -0
- package/src/test/drawing.test.ts +60 -1
- package/src/test/duplicate.test.ts +22 -0
- package/src/test/flatten.test.ts +135 -0
- package/src/test/frames.test.ts +51 -0
- package/src/test/getShapeAtPoint.test.ts +44 -1
- package/src/test/handleDeepLink.test.tsx +15 -0
- package/src/test/minimap-wheel.test.tsx +48 -0
- package/src/test/resizing.test.ts +46 -0
- package/src/test/selection-omnibus.test.ts +50 -0
- package/src/test/spacebarPanning.test.ts +58 -0
- package/src/test/translating.test.ts +42 -0
- package/src/test/ui/AltTextEditor.test.tsx +51 -0
- package/src/test/ui/ContextMenu.test.tsx +61 -2
- package/src/test/ui/EditLinkDialog.test.tsx +77 -0
- package/src/test/ui/ImageToolbar.test.tsx +58 -0
- package/src/test/ui/StylePanel.test.tsx +33 -2
- package/src/test/ui/keyboardShortcuts.test.tsx +27 -0
- package/src/test/ui/presenceActivity.test.tsx +44 -0
- package/src/test/ui/unlockAll.test.tsx +55 -0
- package/src/test/ui-outside-editor.test.tsx +74 -0
- package/src/test/viewport-following.test.ts +29 -1
- package/tldraw.css +7 -16
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/lib/shapes/note/NoteShapeUtil.tsx"],
|
|
4
|
-
"sourcesContent": ["/* eslint-disable react-hooks/rules-of-hooks */\nimport {\n\tBox,\n\tEMPTY_ARRAY,\n\tGroup2d,\n\tIndexKey,\n\tRectangle2d,\n\tSafeId,\n\tShapeUtil,\n\tSvgExportContext,\n\tTLHandle,\n\tTLNoteShape,\n\tTLNoteShapeProps,\n\tTLResizeInfo,\n\tTLShape,\n\tTLShapeId,\n\tVec,\n\tWeakCache,\n\texhaustiveSwitchError,\n\tgetColorValue,\n\tgetFontsFromRichText,\n\tisEqual,\n\tlerp,\n\tnoteShapeMigrations,\n\tnoteShapeProps,\n\tresizeScaled,\n\tresolveLineHeightPx,\n\trng,\n\ttoRichText,\n\tuseColorMode,\n\tuseEditor,\n\tuseValue,\n} from '@tldraw/editor'\nimport { useCallback, useContext } from 'react'\nimport { startEditingShapeWithRichText } from '../../tools/SelectTool/selectHelpers'\nimport { TldrawUiTooltip } from '../../ui/components/primitives/TldrawUiTooltip'\nimport { TranslationsContext } from '../../ui/hooks/useTranslation/useTranslation'\nimport {\n\tisEditingRichTextList,\n\tisEmptyRichText,\n\trenderHtmlFromRichTextForMeasurement,\n\trenderPlaintextFromRichText,\n} from '../../utils/text/richText'\nimport { isRightToLeftLanguage } from '../../utils/text/text'\nimport {\n\tLABEL_FONT_SIZES,\n\tLABEL_PADDING,\n\tTEXT_PROPS,\n\tgetFontFamily,\n} from '../shared/default-shape-constants'\nimport { DefaultFontFaces, getThemeFontFaces } from '../shared/defaultFonts'\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 { CLONE_HANDLE_MARGIN, getNoteShapeForAdjacentPosition } from './noteHelpers'\n\nconst NOTE_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 NOTE_SHAPE_VERTICAL_ALIGNS = Object.freeze({\n\tstart: 'start',\n\tmiddle: 'middle',\n\tend: 'end',\n} as const)\n\n/** @public */\nexport interface NoteShapeUtilDisplayValues {\n\tnoteWidth: number\n\tnoteHeight: number\n\tnoteBackgroundColor: string\n\tborderColor: string\n\tborderWidth: number\n\tlabelColor: string\n\tlabelFontFamily: string\n\tlabelFontSize: number\n\tlabelLineHeight: number\n\tlabelFontWeight: string\n\tlabelFontVariant: string\n\tlabelFontStyle: string\n\tlabelPadding: number\n\tlabelHorizontalAlign: 'start' | 'center' | 'end'\n\tlabelVerticalAlign: 'start' | 'middle' | 'end'\n}\n\n/** @public */\nexport interface NoteShapeOptions extends ShapeOptionsWithDisplayValues<\n\tTLNoteShape,\n\tNoteShapeUtilDisplayValues\n> {\n\t/**\n\t * How should the note shape resize? By default it does not resize (except automatically based on its text content),\n\t * but you can set it to be user-resizable using scale.\n\t */\n\tresizeMode: 'none' | 'scale'\n}\n\n/** @public */\nexport class NoteShapeUtil extends ShapeUtil<TLNoteShape> {\n\tstatic override type = 'note' as const\n\tstatic override props = noteShapeProps\n\tstatic override migrations = noteShapeMigrations\n\n\toverride options: NoteShapeOptions = {\n\t\tresizeMode: 'none',\n\t\tgetDefaultDisplayValues(_editor, shape, theme, colorMode): NoteShapeUtilDisplayValues {\n\t\t\tconst { color, labelColor, font, size, align, verticalAlign } = shape.props\n\t\t\tconst colors = theme.colors[colorMode]\n\t\t\treturn {\n\t\t\t\tnoteWidth: 200,\n\t\t\t\tnoteHeight: 200,\n\t\t\t\tnoteBackgroundColor: getColorValue(colors, color, 'noteFill'),\n\t\t\t\tborderColor: colors.noteBorder,\n\t\t\t\tborderWidth: 2,\n\t\t\t\tlabelColor:\n\t\t\t\t\tlabelColor === 'black'\n\t\t\t\t\t\t? getColorValue(colors, color, 'noteText')\n\t\t\t\t\t\t: getColorValue(colors, labelColor, 'fill'),\n\t\t\t\tlabelFontFamily: getFontFamily(theme, font),\n\t\t\t\tlabelFontSize: theme.fontSize * LABEL_FONT_SIZES[size],\n\t\t\t\tlabelLineHeight: theme.lineHeight,\n\t\t\t\tlabelFontWeight: TEXT_PROPS.fontWeight,\n\t\t\t\tlabelFontVariant: TEXT_PROPS.fontVariant,\n\t\t\t\tlabelFontStyle: TEXT_PROPS.fontStyle,\n\t\t\t\tlabelPadding: LABEL_PADDING,\n\t\t\t\tlabelHorizontalAlign: NOTE_SHAPE_HORIZONTAL_ALIGNS[align],\n\t\t\t\tlabelVerticalAlign: NOTE_SHAPE_VERTICAL_ALIGNS[verticalAlign],\n\t\t\t}\n\t\t},\n\t\tgetCustomDisplayValues(): Partial<NoteShapeUtilDisplayValues> {\n\t\t\treturn {}\n\t\t},\n\t}\n\n\toverride canEdit(shape: TLNoteShape) {\n\t\treturn true\n\t}\n\toverride hideResizeHandles(shape: TLNoteShape) {\n\t\tconst { resizeMode } = this.options\n\t\tswitch (resizeMode) {\n\t\t\tcase 'none': {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\tcase 'scale': {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tdefault: {\n\t\t\t\tthrow exhaustiveSwitchError(resizeMode)\n\t\t\t}\n\t\t}\n\t}\n\n\toverride isAspectRatioLocked(shape: TLNoteShape) {\n\t\treturn this.options.resizeMode === 'scale'\n\t}\n\n\toverride hideSelectionBoundsFg(shape: TLNoteShape) {\n\t\treturn false\n\t}\n\n\tgetDefaultProps(): TLNoteShape['props'] {\n\t\treturn {\n\t\t\tcolor: 'black',\n\t\t\trichText: toRichText(''),\n\t\t\tsize: 'm',\n\t\t\tfont: 'draw',\n\t\t\talign: 'middle',\n\t\t\tverticalAlign: 'middle',\n\t\t\tlabelColor: 'black',\n\t\t\tgrowY: 0,\n\t\t\tfontSizeAdjustment: 1,\n\t\t\turl: '',\n\t\t\tscale: 1,\n\t\t\ttextLastEditedBy: null,\n\t\t}\n\t}\n\n\tgetGeometry(shape: TLNoteShape) {\n\t\tconst { labelHeight, labelWidth } = this.getLabelSize(shape)\n\t\tconst { scale } = shape.props\n\n\t\tconst dv = getDisplayValues(this, shape)\n\n\t\tconst lh = labelHeight * scale\n\t\tconst lw = labelWidth * scale\n\t\tconst nw = dv.noteWidth * scale\n\t\tconst nh = getNoteHeight(shape, dv.noteHeight)\n\n\t\treturn new Group2d({\n\t\t\tchildren: [\n\t\t\t\tnew Rectangle2d({ width: nw, height: nh, isFilled: true }),\n\t\t\t\tnew Rectangle2d({\n\t\t\t\t\tx:\n\t\t\t\t\t\tdv.labelHorizontalAlign === 'start'\n\t\t\t\t\t\t\t? 0\n\t\t\t\t\t\t\t: dv.labelHorizontalAlign === 'end'\n\t\t\t\t\t\t\t\t? nw - lw\n\t\t\t\t\t\t\t\t: (nw - lw) / 2,\n\t\t\t\t\ty:\n\t\t\t\t\t\tdv.labelVerticalAlign === 'start'\n\t\t\t\t\t\t\t? 0\n\t\t\t\t\t\t\t: dv.labelVerticalAlign === 'end'\n\t\t\t\t\t\t\t\t? nh - lh\n\t\t\t\t\t\t\t\t: (nh - lh) / 2,\n\t\t\t\t\twidth: lw,\n\t\t\t\t\theight: lh,\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}),\n\t\t\t],\n\t\t})\n\t}\n\n\toverride getHandles(shape: TLNoteShape): TLHandle[] {\n\t\tconst { scale } = shape.props\n\t\tconst isCoarsePointer = this.editor.getInstanceState().isCoarsePointer\n\t\tif (isCoarsePointer) return []\n\n\t\tconst zoom = this.editor.getEfficientZoomLevel()\n\t\tif (zoom * scale < 0.25) return []\n\n\t\tconst dv = getDisplayValues(this, shape)\n\t\tconst nh = getNoteHeight(shape, dv.noteHeight)\n\t\tconst nw = dv.noteWidth * scale\n\t\tconst offset = (CLONE_HANDLE_MARGIN / zoom) * scale\n\n\t\tif (zoom * scale < 0.5) {\n\t\t\treturn [\n\t\t\t\t{\n\t\t\t\t\tid: 'bottom',\n\t\t\t\t\tindex: 'a3' as IndexKey,\n\t\t\t\t\ttype: 'clone',\n\t\t\t\t\tx: nw / 2,\n\t\t\t\t\ty: nh + offset,\n\t\t\t\t},\n\t\t\t]\n\t\t}\n\n\t\treturn [\n\t\t\t{\n\t\t\t\tid: 'top',\n\t\t\t\tindex: 'a1' as IndexKey,\n\t\t\t\ttype: 'clone',\n\t\t\t\tx: nw / 2,\n\t\t\t\ty: -offset,\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'right',\n\t\t\t\tindex: 'a2' as IndexKey,\n\t\t\t\ttype: 'clone',\n\t\t\t\tx: nw + offset,\n\t\t\t\ty: nh / 2,\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'bottom',\n\t\t\t\tindex: 'a3' as IndexKey,\n\t\t\t\ttype: 'clone',\n\t\t\t\tx: nw / 2,\n\t\t\t\ty: nh + offset,\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'left',\n\t\t\t\tindex: 'a4' as IndexKey,\n\t\t\t\ttype: 'clone',\n\t\t\t\tx: -offset,\n\t\t\t\ty: nh / 2,\n\t\t\t},\n\t\t]\n\t}\n\n\toverride onResize(shape: any, info: TLResizeInfo<any>) {\n\t\tconst { resizeMode } = this.options\n\t\tswitch (resizeMode) {\n\t\t\tcase 'none': {\n\t\t\t\treturn undefined\n\t\t\t}\n\t\t\tcase 'scale': {\n\t\t\t\treturn resizeScaled(shape, info)\n\t\t\t}\n\t\t\tdefault: {\n\t\t\t\tthrow exhaustiveSwitchError(resizeMode)\n\t\t\t}\n\t\t}\n\t}\n\n\toverride getText(shape: TLNoteShape) {\n\t\treturn renderPlaintextFromRichText(this.editor, shape.props.richText)\n\t}\n\n\toverride getReferencedUserIds(shape: TLNoteShape) {\n\t\treturn shape.props.textLastEditedBy ? [shape.props.textLastEditedBy] : []\n\t}\n\n\toverride getFontFaces(shape: TLNoteShape) {\n\t\tconst fonts = isEmptyRichText(shape.props.richText)\n\t\t\t? []\n\t\t\t: getFontsFromRichText(this.editor, shape.props.richText, {\n\t\t\t\t\tfamily: `tldraw_${shape.props.font}`,\n\t\t\t\t\tweight: 'normal',\n\t\t\t\t\tstyle: 'normal',\n\t\t\t\t})\n\n\t\tif (shape.props.textLastEditedBy && !isEmptyRichText(shape.props.richText)) {\n\t\t\treturn [...fonts, DefaultFontFaces.tldraw_sans.normal.normal]\n\t\t}\n\t\tconst themeFaces = getThemeFontFaces(this.editor.getCurrentTheme(), shape.props.font)\n\t\tif (themeFaces) return [...themeFaces, ...fonts]\n\n\t\treturn fonts.length ? fonts : EMPTY_ARRAY\n\t}\n\n\tcomponent(shape: TLNoteShape) {\n\t\tconst { id, type, props } = shape\n\t\tconst { scale, richText, fontSizeAdjustment, textLastEditedBy } = props\n\n\t\tconst handleKeyDown = useNoteKeydownHandler(id)\n\n\t\tconst rotation = useValue(\n\t\t\t'shape rotation',\n\t\t\t() => this.editor.getShapePageTransform(id)?.rotation() ?? 0,\n\t\t\t[this.editor]\n\t\t)\n\n\t\tconst colorMode = useColorMode()\n\t\tconst dv = getDisplayValues(this, shape, colorMode)\n\n\t\tconst nw = dv.noteWidth * scale\n\t\tconst nh = getNoteHeight(shape, dv.noteHeight)\n\n\t\t// Shadows are hidden when zoomed out far enough; the cheap borderBottom takes over.\n\t\tconst hideShadows = useEfficientZoomThreshold(0.25 / scale)\n\n\t\tconst isSelected = shape.id === this.editor.getOnlySelectedShapeId()\n\n\t\tconst isReadyForEditing = useIsReadyForEditing(this.editor, shape.id)\n\t\tconst isEmpty = isEmptyRichText(richText)\n\n\t\tconst attribution = useValue(\n\t\t\t'attribution',\n\t\t\t() => {\n\t\t\t\tif (!textLastEditedBy || isEmpty) return null\n\t\t\t\tconst name = this.editor.getAttributionDisplayName(textLastEditedBy)\n\t\t\t\tif (!name) return null\n\t\t\t\treturn { short: name.split(' ')[0], full: name }\n\t\t\t},\n\t\t\t[textLastEditedBy, isEmpty, this.editor]\n\t\t)\n\n\t\treturn (\n\t\t\t<>\n\t\t\t\t<div\n\t\t\t\t\tid={id}\n\t\t\t\t\tclassName=\"tl-note__container\"\n\t\t\t\t\tstyle={{\n\t\t\t\t\t\twidth: nw,\n\t\t\t\t\t\theight: nh,\n\t\t\t\t\t\tbackgroundColor: dv.noteBackgroundColor,\n\t\t\t\t\t\tborderBottom: hideShadows\n\t\t\t\t\t\t\t? `${dv.borderWidth * scale}px solid ${dv.borderColor}`\n\t\t\t\t\t\t\t: 'none',\n\t\t\t\t\t\tboxShadow: hideShadows ? 'none' : getNoteShadow(shape.id, rotation, scale),\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t{attribution && (\n\t\t\t\t\t\t<TldrawUiTooltip content={attribution.full} side=\"bottom\">\n\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\tclassName=\"tl-note__attribution\"\n\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\t['--note-attribution-scale' as string]: scale,\n\t\t\t\t\t\t\t\t\tfontSize: 11 * scale,\n\t\t\t\t\t\t\t\t\tcolor: dv.labelColor,\n\t\t\t\t\t\t\t\t\topacity: 0.6,\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{attribution.short}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</TldrawUiTooltip>\n\t\t\t\t\t)}\n\t\t\t\t\t{(isSelected || isReadyForEditing || !isEmpty) && (\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={(fontSizeAdjustment ?? 1) * dv.labelFontSize}\n\t\t\t\t\t\t\tlineHeight={dv.labelLineHeight}\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={isSelected}\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\tpadding={dv.labelPadding}\n\t\t\t\t\t\t\thasCustomTabBehavior\n\t\t\t\t\t\t\tshowTextOutline={false}\n\t\t\t\t\t\t\tonKeyDown={handleKeyDown}\n\t\t\t\t\t\t\tstyle={\n\t\t\t\t\t\t\t\tscale !== 1\n\t\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\t\ttransform: `scale(${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: dv.noteWidth,\n\t\t\t\t\t\t\t\t\t\t\theight: dv.noteHeight + shape.props.growY,\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)}\n\t\t\t\t</div>\n\t\t\t\t{'url' in shape.props && shape.props.url && <HyperlinkButton url={shape.props.url} />}\n\t\t\t</>\n\t\t)\n\t}\n\n\toverride getIndicatorPath(shape: TLNoteShape): Path2D {\n\t\tconst { scale } = shape.props\n\t\tconst dv = getDisplayValues(this, shape)\n\t\tconst path = new Path2D()\n\t\tpath.rect(0, 0, dv.noteWidth * scale, getNoteHeight(shape, dv.noteHeight))\n\t\treturn path\n\t}\n\n\toverride toSvg(shape: TLNoteShape, ctx: SvgExportContext) {\n\t\tconst dv = getDisplayValues(this, shape, ctx.colorMode)\n\t\tconst bounds = new Box(0, 0, dv.noteWidth, dv.noteHeight + shape.props.growY)\n\n\t\tconst filterId = `note-shadow-${shape.id.replace(/:/g, '_')}` as SafeId\n\n\t\tctx.addExportDef({\n\t\t\tkey: filterId,\n\t\t\tgetElement: () => (\n\t\t\t\t<filter id={filterId} x=\"-10%\" y=\"-10%\" width=\"130%\" height=\"150%\">\n\t\t\t\t\t<feMorphology in=\"SourceAlpha\" operator=\"erode\" radius=\"3\" result=\"erode1\" />\n\t\t\t\t\t<feGaussianBlur in=\"erode1\" stdDeviation=\"3\" result=\"blur1\" />\n\t\t\t\t\t<feOffset in=\"blur1\" dy=\"3\" result=\"offsetBlur1\" />\n\t\t\t\t\t<feComponentTransfer in=\"offsetBlur1\" result=\"shadow1\">\n\t\t\t\t\t\t<feFuncA type=\"linear\" slope=\"0.5\" />\n\t\t\t\t\t</feComponentTransfer>\n\t\t\t\t\t<feMorphology in=\"SourceAlpha\" operator=\"erode\" radius=\"10\" result=\"erode2\" />\n\t\t\t\t\t<feGaussianBlur in=\"erode2\" stdDeviation=\"6\" result=\"blur2\" />\n\t\t\t\t\t<feOffset in=\"blur2\" dy=\"6\" result=\"offsetBlur2\" />\n\t\t\t\t\t<feComponentTransfer in=\"offsetBlur2\" result=\"shadow2\">\n\t\t\t\t\t\t<feFuncA type=\"linear\" slope=\"0.5\" />\n\t\t\t\t\t</feComponentTransfer>\n\t\t\t\t\t<feMerge>\n\t\t\t\t\t\t<feMergeNode in=\"shadow1\" />\n\t\t\t\t\t\t<feMergeNode in=\"shadow2\" />\n\t\t\t\t\t\t<feMergeNode in=\"SourceGraphic\" />\n\t\t\t\t\t</feMerge>\n\t\t\t\t</filter>\n\t\t\t),\n\t\t})\n\n\t\tconst { textLastEditedBy } = shape.props\n\t\tconst attributionName =\n\t\t\ttextLastEditedBy && !isEmptyRichText(shape.props.richText)\n\t\t\t\t? (this.editor.getAttributionDisplayName(textLastEditedBy)?.split(' ')[0] ?? null)\n\t\t\t\t: null\n\n\t\treturn (\n\t\t\t<>\n\t\t\t\t{ctx.isDarkMode ? null : (\n\t\t\t\t\t<rect\n\t\t\t\t\t\trx={1}\n\t\t\t\t\t\twidth={dv.noteWidth}\n\t\t\t\t\t\theight={bounds.h}\n\t\t\t\t\t\tfill={dv.noteBackgroundColor}\n\t\t\t\t\t\tfilter={`url(#${filterId})`}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t\t<rect rx={1} width={dv.noteWidth} height={bounds.h} fill={dv.noteBackgroundColor} />\n\t\t\t\t<RichTextSVG\n\t\t\t\t\tfontSize={(shape.props.fontSizeAdjustment ?? 1) * 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\trichText={shape.props.richText}\n\t\t\t\t\tlabelColor={dv.labelColor}\n\t\t\t\t\tbounds={bounds}\n\t\t\t\t\tpadding={dv.labelPadding}\n\t\t\t\t\tshowTextOutline={false}\n\t\t\t\t/>\n\t\t\t\t{attributionName && (\n\t\t\t\t\t<foreignObject\n\t\t\t\t\t\tx={0}\n\t\t\t\t\t\ty={0}\n\t\t\t\t\t\twidth={dv.noteWidth}\n\t\t\t\t\t\theight={bounds.h}\n\t\t\t\t\t\tclassName=\"tl-export-embed-styles\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<div style={{ position: 'relative', width: '100%', height: '100%' }}>\n\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\tclassName=\"tl-note__attribution\"\n\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\tfontSize: 11,\n\t\t\t\t\t\t\t\t\tcolor: dv.labelColor,\n\t\t\t\t\t\t\t\t\topacity: 0.6,\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{attributionName}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</foreignObject>\n\t\t\t\t)}\n\t\t\t</>\n\t\t)\n\t}\n\n\toverride onBeforeCreate(next: TLNoteShape) {\n\t\treturn this.getNoteSizeAdjustments(next)\n\t}\n\n\toverride onBeforeDuplicate(\n\t\t_source: TLNoteShape,\n\t\tduplicate: TLNoteShape\n\t): TLNoteShape | undefined {\n\t\t// Attribution follows the last person to produce the note's text. Duplicating (or pasting)\n\t\t// a note with text is a new act of authorship by the current user, so re-stamp the copy to\n\t\t// them rather than carrying over the original author's identity. Empty notes have no\n\t\t// attribution to begin with, so leave them alone.\n\t\tif (isEmptyRichText(duplicate.props.richText)) return\n\t\treturn {\n\t\t\t...duplicate,\n\t\t\tprops: { ...duplicate.props, textLastEditedBy: this.editor.getAttributionUserId() },\n\t\t}\n\t}\n\n\toverride onBeforeUpdate(prev: TLNoteShape, next: TLNoteShape) {\n\t\tconst richTextChanged = !isEqual(prev.props.richText, next.props.richText)\n\n\t\tif (\n\t\t\t!richTextChanged &&\n\t\t\tprev.props.font === next.props.font &&\n\t\t\tprev.props.size === next.props.size\n\t\t) {\n\t\t\treturn\n\t\t}\n\n\t\tlet shape = next\n\t\tif (richTextChanged) {\n\t\t\tif (isEmptyRichText(next.props.richText)) {\n\t\t\t\tshape = {\n\t\t\t\t\t...shape,\n\t\t\t\t\tprops: { ...shape.props, textLastEditedBy: null },\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tshape = {\n\t\t\t\t\t...shape,\n\t\t\t\t\tprops: { ...shape.props, textLastEditedBy: this.editor.getAttributionUserId() },\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this.getNoteSizeAdjustments(shape) ?? (richTextChanged ? shape : undefined)\n\t}\n\n\toverride getInterpolatedProps(\n\t\tstartShape: TLNoteShape,\n\t\tendShape: TLNoteShape,\n\t\tt: number\n\t): TLNoteShapeProps {\n\t\treturn {\n\t\t\t...(t > 0.5 ? endShape.props : startShape.props),\n\t\t\tscale: lerp(startShape.props.scale, endShape.props.scale, t),\n\t\t}\n\t}\n\n\t/**\n\t * Get the growY and fontSizeAdjustment for a shape.\n\t */\n\tprivate getNoteSizeAdjustments(shape: TLNoteShape) {\n\t\tconst dv = getDisplayValues(this, shape)\n\t\tconst { labelHeight, fontSizeAdjustment } = this.getLabelSize(shape)\n\t\t// When the label height is more than the height of the shape, we add extra height to it\n\t\tconst growY = Math.max(0, labelHeight - dv.noteHeight)\n\n\t\tif (growY !== shape.props.growY || fontSizeAdjustment !== shape.props.fontSizeAdjustment) {\n\t\t\treturn {\n\t\t\t\t...shape,\n\t\t\t\tprops: {\n\t\t\t\t\t...shape.props,\n\t\t\t\t\tgrowY,\n\t\t\t\t\tfontSizeAdjustment,\n\t\t\t\t},\n\t\t\t}\n\t\t}\n\n\t\treturn undefined\n\t}\n\n\tprivate _labelSizesForNoteCache = new WeakCache<\n\t\tTLShape,\n\t\t{ labelHeight: number; labelWidth: number; fontSizeAdjustment: number }\n\t>()\n\n\t/**\n\t * Get the cached label size for the shape.\n\t */\n\tprivate getLabelSize(shape: TLNoteShape) {\n\t\treturn this._labelSizesForNoteCache.get(shape, () => this.measureNoteLabelSize(shape))\n\t}\n\n\t/**\n\t * Expensively measure the label size for a note shape.\n\t */\n\tprivate measureNoteLabelSize(shape: TLNoteShape) {\n\t\tconst dv = getDisplayValues(this, shape)\n\t\tconst { richText } = shape.props\n\n\t\tif (isEmptyRichText(richText)) {\n\t\t\tconst minHeight =\n\t\t\t\tresolveLineHeightPx(dv.labelFontSize, dv.labelLineHeight) + dv.labelPadding * 2\n\t\t\treturn { labelHeight: minHeight, labelWidth: 100, fontSizeAdjustment: 1 }\n\t\t}\n\n\t\tconst unadjustedFontSize = dv.labelFontSize\n\n\t\tlet fontSizeAdjustment = unadjustedFontSize\n\t\tlet iterations = 0\n\t\tlet labelHeight = dv.noteHeight\n\t\tlet labelWidth = dv.noteWidth\n\n\t\t// N.B. For some note shapes with text like 'hjhjhjhjhjhjhjhj', you'll run into\n\t\t// some text measurement fuzziness where the browser swears there's no overflow (scrollWidth === width)\n\t\t// but really there is when you enable overflow-wrap again. This helps account for that little bit\n\t\t// of give.\n\t\tconst FUZZ = 1\n\n\t\t// We slightly make the font smaller if the text is too big for the note, width-wise.\n\t\tdo {\n\t\t\tfontSizeAdjustment = Math.min(unadjustedFontSize, unadjustedFontSize - iterations)\n\t\t\tconst html = renderHtmlFromRichTextForMeasurement(this.editor, richText)\n\t\t\tconst nextTextSize = this.editor.textMeasure.measureHtml(html, {\n\t\t\t\t...TEXT_PROPS,\n\t\t\t\tlineHeight: dv.labelLineHeight,\n\t\t\t\tfontFamily: dv.labelFontFamily,\n\t\t\t\tfontSize: fontSizeAdjustment,\n\t\t\t\tmaxWidth: dv.noteWidth - dv.labelPadding * 2 - FUZZ,\n\t\t\t\tdisableOverflowWrapBreaking: true,\n\t\t\t\tmeasureScrollWidth: true,\n\t\t\t})\n\n\t\t\tlabelHeight = nextTextSize.h + dv.labelPadding * 2\n\t\t\tlabelWidth = nextTextSize.w + dv.labelPadding * 2\n\n\t\t\tif (fontSizeAdjustment <= 14) {\n\t\t\t\t// Too small, just rely now on CSS `overflow-wrap: break-word`\n\t\t\t\t// We need to recalculate the text measurement here with break-word enabled.\n\t\t\t\tconst html = renderHtmlFromRichTextForMeasurement(this.editor, richText)\n\t\t\t\tconst nextTextSizeWithOverflowBreak = this.editor.textMeasure.measureHtml(html, {\n\t\t\t\t\t...TEXT_PROPS,\n\t\t\t\t\tlineHeight: dv.labelLineHeight,\n\t\t\t\t\tfontFamily: dv.labelFontFamily,\n\t\t\t\t\tfontSize: fontSizeAdjustment,\n\t\t\t\t\tmaxWidth: dv.noteWidth - dv.labelPadding * 2 - FUZZ,\n\t\t\t\t})\n\t\t\t\tlabelHeight = nextTextSizeWithOverflowBreak.h + dv.labelPadding * 2\n\t\t\t\tlabelWidth = nextTextSizeWithOverflowBreak.w + dv.labelPadding * 2\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tif (nextTextSize.scrollWidth.toFixed(0) === nextTextSize.w.toFixed(0)) {\n\t\t\t\tbreak\n\t\t\t}\n\t\t} while (iterations++ < 50)\n\n\t\treturn {\n\t\t\tlabelHeight: labelHeight,\n\t\t\tlabelWidth: labelWidth,\n\t\t\tfontSizeAdjustment:\n\t\t\t\tfontSizeAdjustment === unadjustedFontSize ? 1 : fontSizeAdjustment / unadjustedFontSize,\n\t\t}\n\t}\n}\n\nfunction useNoteKeydownHandler(id: TLShapeId) {\n\tconst editor = useEditor()\n\t// Try to get the translation context, but fallback to ltr if it doesn't exist\n\tconst translation = useContext(TranslationsContext)\n\n\treturn useCallback(\n\t\t(e: KeyboardEvent) => {\n\t\t\tconst shape = editor.getShape<TLNoteShape>(id)\n\t\t\tif (!shape) return\n\n\t\t\tconst isTab = e.key === 'Tab'\n\t\t\tconst isCmdEnter = (e.metaKey || e.ctrlKey) && e.key === 'Enter'\n\n\t\t\tif (isTab && isEditingRichTextList(editor)) {\n\t\t\t\t// In a list, let the rich text editor indent the item instead of\n\t\t\t\t// creating a new note. Prevent default so Tab doesn't move focus out\n\t\t\t\t// of the editor when the item can't be indented (e.g. the first item).\n\t\t\t\te.preventDefault()\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif (isTab || isCmdEnter) {\n\t\t\t\te.preventDefault()\n\n\t\t\t\tconst pageTransform = editor.getShapePageTransform(id)\n\t\t\t\tconst pageRotation = pageTransform.rotation()\n\n\t\t\t\t// Based on the inputs, calculate the offset to the next note\n\t\t\t\t// tab controls x axis (shift inverts direction set by RTL)\n\t\t\t\t// cmd enter is the y axis (shift inverts direction)\n\t\t\t\tconst isRTL = !!(\n\t\t\t\t\ttranslation?.dir === 'rtl' ||\n\t\t\t\t\t// todo: can we check a partial of the text, so that we don't have to render the whole thing?\n\t\t\t\t\tisRightToLeftLanguage(renderPlaintextFromRichText(editor, shape.props.richText))\n\t\t\t\t)\n\n\t\t\t\tconst noteUtil = editor.getShapeUtil(shape) as NoteShapeUtil\n\t\t\t\tconst dv = getDisplayValues(noteUtil, shape)\n\n\t\t\t\tconst noteOffset = isTab\n\t\t\t\t\t? dv.noteWidth + editor.options.adjacentShapeMargin\n\t\t\t\t\t: dv.noteHeight +\n\t\t\t\t\t\teditor.options.adjacentShapeMargin +\n\t\t\t\t\t\t// If we're growing down, we need to account for the current shape's growY\n\t\t\t\t\t\t(isCmdEnter && !e.shiftKey ? shape.props.growY : 0)\n\t\t\t\tconst offsetLength = noteOffset * shape.props.scale\n\n\t\t\t\tconst adjacentCenter = new Vec(\n\t\t\t\t\tisTab ? (e.shiftKey != isRTL ? -1 : 1) : 0,\n\t\t\t\t\tisCmdEnter ? (e.shiftKey ? -1 : 1) : 0\n\t\t\t\t)\n\t\t\t\t\t.mul(offsetLength)\n\t\t\t\t\t.add(new Vec(dv.noteWidth / 2, dv.noteHeight / 2).mul(shape.props.scale))\n\t\t\t\t\t.rot(pageRotation)\n\t\t\t\t\t.add(pageTransform.point())\n\n\t\t\t\tconst newNote = getNoteShapeForAdjacentPosition(editor, {\n\t\t\t\t\tshape,\n\t\t\t\t\tcenter: adjacentCenter,\n\t\t\t\t\tpageRotation,\n\t\t\t\t\tnoteWidth: dv.noteWidth,\n\t\t\t\t\tnoteHeight: dv.noteHeight,\n\t\t\t\t})\n\n\t\t\t\tif (newNote) {\n\t\t\t\t\tstartEditingShapeWithRichText(editor, newNote, { selectAll: true })\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t[id, editor, translation?.dir]\n\t)\n}\n\nfunction getNoteHeight(shape: TLNoteShape, noteHeight: number) {\n\treturn (noteHeight + shape.props.growY) * shape.props.scale\n}\n\nfunction getNoteShadow(id: string, rotation: number, scale: number) {\n\tconst random = rng(id) // seeded based on id\n\tconst lift = Math.abs(random()) + 0.5 // 0 to 1.5\n\tconst oy = Math.cos(rotation)\n\tconst a = 5 * scale\n\tconst b = 4 * scale\n\tconst c = 6 * scale\n\tconst d = 7 * scale\n\t// Clamped so shadow never goes above the note at small scales (e.g. dynamic size mode at high zoom)\n\treturn `0px ${Math.max(0, a - lift)}px ${a}px -${a}px rgba(15, 23, 31, .6),\n\t0px ${(b + lift * d) * Math.max(0, oy)}px ${c + lift * d}px -${b + lift * c}px rgba(15, 23, 31, ${(0.3 + lift * 0.1).toFixed(2)}),\n\t0px ${48 * scale}px ${10 * scale}px -${10 * scale}px inset rgba(15, 23, 44, ${((0.022 + random() * 0.005) * ((1 + oy) / 2)).toFixed(2)})`\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["/* eslint-disable react-hooks/rules-of-hooks */\nimport {\n\tBox,\n\tEMPTY_ARRAY,\n\tGroup2d,\n\tIndexKey,\n\tRectangle2d,\n\tSafeId,\n\tShapeUtil,\n\tSvgExportContext,\n\tTLHandle,\n\tTLNoteShape,\n\tTLNoteShapeProps,\n\tTLResizeInfo,\n\tTLShape,\n\tTLShapeId,\n\tVec,\n\tWeakCache,\n\texhaustiveSwitchError,\n\tgetColorValue,\n\tgetFontsFromRichText,\n\tisEqual,\n\tlerp,\n\tnoteShapeMigrations,\n\tnoteShapeProps,\n\tresizeScaled,\n\tresolveLineHeightPx,\n\trng,\n\ttoRichText,\n\tuseColorMode,\n\tuseEditor,\n\tuseValue,\n} from '@tldraw/editor'\nimport { useCallback, useContext } from 'react'\nimport { startEditingShapeWithRichText } from '../../tools/SelectTool/selectHelpers'\nimport { TldrawUiTooltip } from '../../ui/components/primitives/TldrawUiTooltip'\nimport { TranslationsContext } from '../../ui/hooks/useTranslation/useTranslation'\nimport {\n\tisEditingRichTextList,\n\tisEmptyRichText,\n\trenderHtmlFromRichTextForMeasurement,\n\trenderPlaintextFromRichText,\n} from '../../utils/text/richText'\nimport { isRightToLeftLanguage } from '../../utils/text/text'\nimport {\n\tLABEL_FONT_SIZES,\n\tLABEL_PADDING,\n\tTEXT_PROPS,\n\tgetFontFamily,\n} from '../shared/default-shape-constants'\nimport { DefaultFontFaces, getThemeFontFaces } from '../shared/defaultFonts'\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 { CLONE_HANDLE_MARGIN, getNoteShapeForAdjacentPosition } from './noteHelpers'\n\nconst NOTE_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 NOTE_SHAPE_VERTICAL_ALIGNS = Object.freeze({\n\tstart: 'start',\n\tmiddle: 'middle',\n\tend: 'end',\n} as const)\n\n/** @public */\nexport interface NoteShapeUtilDisplayValues {\n\tnoteWidth: number\n\tnoteHeight: number\n\tnoteBackgroundColor: string\n\tborderColor: string\n\tborderWidth: number\n\tlabelColor: string\n\tlabelFontFamily: string\n\tlabelFontSize: number\n\tlabelLineHeight: number\n\tlabelFontWeight: string\n\tlabelFontVariant: string\n\tlabelFontStyle: string\n\tlabelPadding: number\n\tlabelHorizontalAlign: 'start' | 'center' | 'end'\n\tlabelVerticalAlign: 'start' | 'middle' | 'end'\n}\n\n/** @public */\nexport interface NoteShapeOptions extends ShapeOptionsWithDisplayValues<\n\tTLNoteShape,\n\tNoteShapeUtilDisplayValues\n> {\n\t/**\n\t * How should the note shape resize? By default it does not resize (except automatically based on its text content),\n\t * but you can set it to be user-resizable using scale.\n\t */\n\tresizeMode: 'none' | 'scale'\n}\n\n/** @public */\nexport class NoteShapeUtil extends ShapeUtil<TLNoteShape> {\n\tstatic override type = 'note' as const\n\tstatic override props = noteShapeProps\n\tstatic override migrations = noteShapeMigrations\n\n\toverride options: NoteShapeOptions = {\n\t\tresizeMode: 'none',\n\t\tgetDefaultDisplayValues(_editor, shape, theme, colorMode): NoteShapeUtilDisplayValues {\n\t\t\tconst { color, labelColor, font, size, align, verticalAlign } = shape.props\n\t\t\tconst colors = theme.colors[colorMode]\n\t\t\treturn {\n\t\t\t\tnoteWidth: 200,\n\t\t\t\tnoteHeight: 200,\n\t\t\t\tnoteBackgroundColor: getColorValue(colors, color, 'noteFill'),\n\t\t\t\tborderColor: colors.noteBorder,\n\t\t\t\tborderWidth: 2,\n\t\t\t\tlabelColor:\n\t\t\t\t\tlabelColor === 'black'\n\t\t\t\t\t\t? getColorValue(colors, color, 'noteText')\n\t\t\t\t\t\t: getColorValue(colors, labelColor, 'fill'),\n\t\t\t\tlabelFontFamily: getFontFamily(theme, font),\n\t\t\t\tlabelFontSize: theme.fontSize * LABEL_FONT_SIZES[size],\n\t\t\t\tlabelLineHeight: theme.lineHeight,\n\t\t\t\tlabelFontWeight: TEXT_PROPS.fontWeight,\n\t\t\t\tlabelFontVariant: TEXT_PROPS.fontVariant,\n\t\t\t\tlabelFontStyle: TEXT_PROPS.fontStyle,\n\t\t\t\tlabelPadding: LABEL_PADDING,\n\t\t\t\tlabelHorizontalAlign: NOTE_SHAPE_HORIZONTAL_ALIGNS[align],\n\t\t\t\tlabelVerticalAlign: NOTE_SHAPE_VERTICAL_ALIGNS[verticalAlign],\n\t\t\t}\n\t\t},\n\t\tgetCustomDisplayValues(): Partial<NoteShapeUtilDisplayValues> {\n\t\t\treturn {}\n\t\t},\n\t}\n\n\toverride canEdit(shape: TLNoteShape) {\n\t\treturn true\n\t}\n\toverride hideResizeHandles(shape: TLNoteShape) {\n\t\tconst { resizeMode } = this.options\n\t\tswitch (resizeMode) {\n\t\t\tcase 'none': {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\tcase 'scale': {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tdefault: {\n\t\t\t\tthrow exhaustiveSwitchError(resizeMode)\n\t\t\t}\n\t\t}\n\t}\n\n\toverride isAspectRatioLocked(shape: TLNoteShape) {\n\t\treturn this.options.resizeMode === 'scale'\n\t}\n\n\toverride hideSelectionBoundsFg(shape: TLNoteShape) {\n\t\treturn false\n\t}\n\n\tgetDefaultProps(): TLNoteShape['props'] {\n\t\treturn {\n\t\t\tcolor: 'black',\n\t\t\trichText: toRichText(''),\n\t\t\tsize: 'm',\n\t\t\tfont: 'draw',\n\t\t\talign: 'middle',\n\t\t\tverticalAlign: 'middle',\n\t\t\tlabelColor: 'black',\n\t\t\tgrowY: 0,\n\t\t\tfontSizeAdjustment: 1,\n\t\t\turl: '',\n\t\t\tscale: 1,\n\t\t\ttextLastEditedBy: null,\n\t\t}\n\t}\n\n\tgetGeometry(shape: TLNoteShape) {\n\t\tconst { labelHeight, labelWidth } = this.getLabelSize(shape)\n\t\tconst { scale } = shape.props\n\n\t\tconst dv = getDisplayValues(this, shape)\n\n\t\tconst lh = labelHeight * scale\n\t\tconst lw = labelWidth * scale\n\t\tconst nw = dv.noteWidth * scale\n\t\tconst nh = getNoteHeight(shape, dv.noteHeight)\n\n\t\treturn new Group2d({\n\t\t\tchildren: [\n\t\t\t\tnew Rectangle2d({ width: nw, height: nh, isFilled: true }),\n\t\t\t\tnew Rectangle2d({\n\t\t\t\t\tx:\n\t\t\t\t\t\tdv.labelHorizontalAlign === 'start'\n\t\t\t\t\t\t\t? 0\n\t\t\t\t\t\t\t: dv.labelHorizontalAlign === 'end'\n\t\t\t\t\t\t\t\t? nw - lw\n\t\t\t\t\t\t\t\t: (nw - lw) / 2,\n\t\t\t\t\ty:\n\t\t\t\t\t\tdv.labelVerticalAlign === 'start'\n\t\t\t\t\t\t\t? 0\n\t\t\t\t\t\t\t: dv.labelVerticalAlign === 'end'\n\t\t\t\t\t\t\t\t? nh - lh\n\t\t\t\t\t\t\t\t: (nh - lh) / 2,\n\t\t\t\t\twidth: lw,\n\t\t\t\t\theight: lh,\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}),\n\t\t\t],\n\t\t})\n\t}\n\n\toverride getHandles(shape: TLNoteShape): TLHandle[] {\n\t\tconst { scale } = shape.props\n\t\tconst isCoarsePointer = this.editor.getInstanceState().isCoarsePointer\n\t\tif (isCoarsePointer) return []\n\n\t\tconst zoom = this.editor.getEfficientZoomLevel()\n\t\tif (zoom * scale < 0.25) return []\n\n\t\tconst dv = getDisplayValues(this, shape)\n\t\tconst nh = getNoteHeight(shape, dv.noteHeight)\n\t\tconst nw = dv.noteWidth * scale\n\t\tconst offset = (CLONE_HANDLE_MARGIN / zoom) * scale\n\n\t\tif (zoom * scale < 0.5) {\n\t\t\treturn [\n\t\t\t\t{\n\t\t\t\t\tid: 'bottom',\n\t\t\t\t\tindex: 'a3' as IndexKey,\n\t\t\t\t\ttype: 'clone',\n\t\t\t\t\tx: nw / 2,\n\t\t\t\t\ty: nh + offset,\n\t\t\t\t},\n\t\t\t]\n\t\t}\n\n\t\treturn [\n\t\t\t{\n\t\t\t\tid: 'top',\n\t\t\t\tindex: 'a1' as IndexKey,\n\t\t\t\ttype: 'clone',\n\t\t\t\tx: nw / 2,\n\t\t\t\ty: -offset,\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'right',\n\t\t\t\tindex: 'a2' as IndexKey,\n\t\t\t\ttype: 'clone',\n\t\t\t\tx: nw + offset,\n\t\t\t\ty: nh / 2,\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'bottom',\n\t\t\t\tindex: 'a3' as IndexKey,\n\t\t\t\ttype: 'clone',\n\t\t\t\tx: nw / 2,\n\t\t\t\ty: nh + offset,\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'left',\n\t\t\t\tindex: 'a4' as IndexKey,\n\t\t\t\ttype: 'clone',\n\t\t\t\tx: -offset,\n\t\t\t\ty: nh / 2,\n\t\t\t},\n\t\t]\n\t}\n\n\toverride onResize(shape: any, info: TLResizeInfo<any>) {\n\t\tconst { resizeMode } = this.options\n\t\tswitch (resizeMode) {\n\t\t\tcase 'none': {\n\t\t\t\treturn undefined\n\t\t\t}\n\t\t\tcase 'scale': {\n\t\t\t\treturn resizeScaled(shape, info)\n\t\t\t}\n\t\t\tdefault: {\n\t\t\t\tthrow exhaustiveSwitchError(resizeMode)\n\t\t\t}\n\t\t}\n\t}\n\n\toverride getText(shape: TLNoteShape) {\n\t\treturn renderPlaintextFromRichText(this.editor, shape.props.richText)\n\t}\n\n\toverride getReferencedUserIds(shape: TLNoteShape) {\n\t\treturn shape.props.textLastEditedBy ? [shape.props.textLastEditedBy] : []\n\t}\n\n\toverride getFontFaces(shape: TLNoteShape) {\n\t\tconst fonts = isEmptyRichText(shape.props.richText)\n\t\t\t? []\n\t\t\t: getFontsFromRichText(this.editor, shape.props.richText, {\n\t\t\t\t\tfamily: `tldraw_${shape.props.font}`,\n\t\t\t\t\tweight: 'normal',\n\t\t\t\t\tstyle: 'normal',\n\t\t\t\t})\n\n\t\tconst themeFaces = getThemeFontFaces(this.editor.getCurrentTheme(), shape.props.font)\n\t\tconst textFaces = themeFaces ? [...themeFaces, ...fonts] : fonts\n\n\t\t// The attribution line renders in the default sans face regardless of the note's font.\n\t\t// Theme faces come first so an attributed note keeps its custom font (export included).\n\t\tif (shape.props.textLastEditedBy && !isEmptyRichText(shape.props.richText)) {\n\t\t\treturn [...textFaces, DefaultFontFaces.tldraw_sans.normal.normal]\n\t\t}\n\n\t\treturn textFaces.length ? textFaces : EMPTY_ARRAY\n\t}\n\n\tcomponent(shape: TLNoteShape) {\n\t\tconst { id, type, props } = shape\n\t\tconst { scale, richText, fontSizeAdjustment, textLastEditedBy } = props\n\n\t\tconst handleKeyDown = useNoteKeydownHandler(id)\n\n\t\tconst rotation = useValue(\n\t\t\t'shape rotation',\n\t\t\t() => this.editor.getShapePageTransform(id)?.rotation() ?? 0,\n\t\t\t[this.editor]\n\t\t)\n\n\t\tconst colorMode = useColorMode()\n\t\tconst dv = getDisplayValues(this, shape, colorMode)\n\n\t\tconst nw = dv.noteWidth * scale\n\t\tconst nh = getNoteHeight(shape, dv.noteHeight)\n\n\t\t// Shadows are hidden when zoomed out far enough; the cheap borderBottom takes over.\n\t\tconst hideShadows = useEfficientZoomThreshold(0.25 / scale)\n\n\t\tconst isSelected = shape.id === this.editor.getOnlySelectedShapeId()\n\n\t\tconst isReadyForEditing = useIsReadyForEditing(this.editor, shape.id)\n\t\tconst isEmpty = isEmptyRichText(richText)\n\n\t\tconst attribution = useValue(\n\t\t\t'attribution',\n\t\t\t() => {\n\t\t\t\tif (!textLastEditedBy || isEmpty) return null\n\t\t\t\tconst name = this.editor.getAttributionDisplayName(textLastEditedBy)\n\t\t\t\tif (!name) return null\n\t\t\t\treturn { short: name.split(' ')[0], full: name }\n\t\t\t},\n\t\t\t[textLastEditedBy, isEmpty, this.editor]\n\t\t)\n\n\t\treturn (\n\t\t\t<>\n\t\t\t\t<div\n\t\t\t\t\tid={id}\n\t\t\t\t\tclassName=\"tl-note__container\"\n\t\t\t\t\tstyle={{\n\t\t\t\t\t\twidth: nw,\n\t\t\t\t\t\theight: nh,\n\t\t\t\t\t\tbackgroundColor: dv.noteBackgroundColor,\n\t\t\t\t\t\tborderBottom: hideShadows\n\t\t\t\t\t\t\t? `${dv.borderWidth * scale}px solid ${dv.borderColor}`\n\t\t\t\t\t\t\t: 'none',\n\t\t\t\t\t\tboxShadow: hideShadows ? 'none' : getNoteShadow(shape.id, rotation, scale),\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t{attribution && (\n\t\t\t\t\t\t<TldrawUiTooltip content={attribution.full} side=\"bottom\">\n\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\tclassName=\"tl-note__attribution\"\n\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\t['--note-attribution-scale' as string]: scale,\n\t\t\t\t\t\t\t\t\tfontSize: 11 * scale,\n\t\t\t\t\t\t\t\t\tcolor: dv.labelColor,\n\t\t\t\t\t\t\t\t\topacity: 0.6,\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{attribution.short}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</TldrawUiTooltip>\n\t\t\t\t\t)}\n\t\t\t\t\t{(isSelected || isReadyForEditing || !isEmpty) && (\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={(fontSizeAdjustment ?? 1) * dv.labelFontSize}\n\t\t\t\t\t\t\tlineHeight={dv.labelLineHeight}\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={isSelected}\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\tpadding={dv.labelPadding}\n\t\t\t\t\t\t\thasCustomTabBehavior\n\t\t\t\t\t\t\tshowTextOutline={false}\n\t\t\t\t\t\t\tonKeyDown={handleKeyDown}\n\t\t\t\t\t\t\tstyle={\n\t\t\t\t\t\t\t\tscale !== 1\n\t\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\t\ttransform: `scale(${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: dv.noteWidth,\n\t\t\t\t\t\t\t\t\t\t\theight: dv.noteHeight + shape.props.growY,\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)}\n\t\t\t\t</div>\n\t\t\t\t{'url' in shape.props && shape.props.url && <HyperlinkButton url={shape.props.url} />}\n\t\t\t</>\n\t\t)\n\t}\n\n\toverride getIndicatorPath(shape: TLNoteShape): Path2D {\n\t\tconst { scale } = shape.props\n\t\tconst dv = getDisplayValues(this, shape)\n\t\tconst path = new Path2D()\n\t\tpath.rect(0, 0, dv.noteWidth * scale, getNoteHeight(shape, dv.noteHeight))\n\t\treturn path\n\t}\n\n\toverride toSvg(shape: TLNoteShape, ctx: SvgExportContext) {\n\t\tconst dv = getDisplayValues(this, shape, ctx.colorMode)\n\t\tconst bounds = new Box(0, 0, dv.noteWidth, dv.noteHeight + shape.props.growY)\n\n\t\tconst filterId = `note-shadow-${shape.id.replace(/:/g, '_')}` as SafeId\n\n\t\tctx.addExportDef({\n\t\t\tkey: filterId,\n\t\t\tgetElement: () => (\n\t\t\t\t<filter id={filterId} x=\"-10%\" y=\"-10%\" width=\"130%\" height=\"150%\">\n\t\t\t\t\t<feMorphology in=\"SourceAlpha\" operator=\"erode\" radius=\"3\" result=\"erode1\" />\n\t\t\t\t\t<feGaussianBlur in=\"erode1\" stdDeviation=\"3\" result=\"blur1\" />\n\t\t\t\t\t<feOffset in=\"blur1\" dy=\"3\" result=\"offsetBlur1\" />\n\t\t\t\t\t<feComponentTransfer in=\"offsetBlur1\" result=\"shadow1\">\n\t\t\t\t\t\t<feFuncA type=\"linear\" slope=\"0.5\" />\n\t\t\t\t\t</feComponentTransfer>\n\t\t\t\t\t<feMorphology in=\"SourceAlpha\" operator=\"erode\" radius=\"10\" result=\"erode2\" />\n\t\t\t\t\t<feGaussianBlur in=\"erode2\" stdDeviation=\"6\" result=\"blur2\" />\n\t\t\t\t\t<feOffset in=\"blur2\" dy=\"6\" result=\"offsetBlur2\" />\n\t\t\t\t\t<feComponentTransfer in=\"offsetBlur2\" result=\"shadow2\">\n\t\t\t\t\t\t<feFuncA type=\"linear\" slope=\"0.5\" />\n\t\t\t\t\t</feComponentTransfer>\n\t\t\t\t\t<feMerge>\n\t\t\t\t\t\t<feMergeNode in=\"shadow1\" />\n\t\t\t\t\t\t<feMergeNode in=\"shadow2\" />\n\t\t\t\t\t\t<feMergeNode in=\"SourceGraphic\" />\n\t\t\t\t\t</feMerge>\n\t\t\t\t</filter>\n\t\t\t),\n\t\t})\n\n\t\tconst { textLastEditedBy } = shape.props\n\t\tconst attributionName =\n\t\t\ttextLastEditedBy && !isEmptyRichText(shape.props.richText)\n\t\t\t\t? (this.editor.getAttributionDisplayName(textLastEditedBy)?.split(' ')[0] ?? null)\n\t\t\t\t: null\n\n\t\treturn (\n\t\t\t<>\n\t\t\t\t{ctx.isDarkMode ? null : (\n\t\t\t\t\t<rect\n\t\t\t\t\t\trx={1}\n\t\t\t\t\t\twidth={dv.noteWidth}\n\t\t\t\t\t\theight={bounds.h}\n\t\t\t\t\t\tfill={dv.noteBackgroundColor}\n\t\t\t\t\t\tfilter={`url(#${filterId})`}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t\t<rect rx={1} width={dv.noteWidth} height={bounds.h} fill={dv.noteBackgroundColor} />\n\t\t\t\t<RichTextSVG\n\t\t\t\t\tfontSize={(shape.props.fontSizeAdjustment ?? 1) * 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\trichText={shape.props.richText}\n\t\t\t\t\tlabelColor={dv.labelColor}\n\t\t\t\t\tbounds={bounds}\n\t\t\t\t\tpadding={dv.labelPadding}\n\t\t\t\t\tshowTextOutline={false}\n\t\t\t\t/>\n\t\t\t\t{attributionName && (\n\t\t\t\t\t<foreignObject\n\t\t\t\t\t\tx={0}\n\t\t\t\t\t\ty={0}\n\t\t\t\t\t\twidth={dv.noteWidth}\n\t\t\t\t\t\theight={bounds.h}\n\t\t\t\t\t\tclassName=\"tl-export-embed-styles\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<div style={{ position: 'relative', width: '100%', height: '100%' }}>\n\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\tclassName=\"tl-note__attribution\"\n\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\tfontSize: 11,\n\t\t\t\t\t\t\t\t\tcolor: dv.labelColor,\n\t\t\t\t\t\t\t\t\topacity: 0.6,\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{attributionName}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</foreignObject>\n\t\t\t\t)}\n\t\t\t</>\n\t\t)\n\t}\n\n\toverride onBeforeCreate(next: TLNoteShape) {\n\t\treturn this.getNoteSizeAdjustments(next)\n\t}\n\n\toverride onBeforeDuplicate(\n\t\t_source: TLNoteShape,\n\t\tduplicate: TLNoteShape\n\t): TLNoteShape | undefined {\n\t\t// Attribution follows the last person to produce the note's text. Duplicating (or pasting)\n\t\t// a note with text is a new act of authorship by the current user, so re-stamp the copy to\n\t\t// them rather than carrying over the original author's identity. Empty notes have no\n\t\t// attribution to begin with, so leave them alone.\n\t\tif (isEmptyRichText(duplicate.props.richText)) return\n\t\treturn {\n\t\t\t...duplicate,\n\t\t\tprops: { ...duplicate.props, textLastEditedBy: this.editor.getAttributionUserId() },\n\t\t}\n\t}\n\n\toverride onBeforeUpdate(prev: TLNoteShape, next: TLNoteShape) {\n\t\tconst richTextChanged = !isEqual(prev.props.richText, next.props.richText)\n\n\t\tif (\n\t\t\t!richTextChanged &&\n\t\t\tprev.props.font === next.props.font &&\n\t\t\tprev.props.size === next.props.size\n\t\t) {\n\t\t\treturn\n\t\t}\n\n\t\tlet shape = next\n\t\tif (richTextChanged) {\n\t\t\tif (isEmptyRichText(next.props.richText)) {\n\t\t\t\tshape = {\n\t\t\t\t\t...shape,\n\t\t\t\t\tprops: { ...shape.props, textLastEditedBy: null },\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tshape = {\n\t\t\t\t\t...shape,\n\t\t\t\t\tprops: { ...shape.props, textLastEditedBy: this.editor.getAttributionUserId() },\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this.getNoteSizeAdjustments(shape) ?? (richTextChanged ? shape : undefined)\n\t}\n\n\toverride getInterpolatedProps(\n\t\tstartShape: TLNoteShape,\n\t\tendShape: TLNoteShape,\n\t\tt: number\n\t): TLNoteShapeProps {\n\t\treturn {\n\t\t\t...(t > 0.5 ? endShape.props : startShape.props),\n\t\t\tscale: lerp(startShape.props.scale, endShape.props.scale, t),\n\t\t}\n\t}\n\n\t/**\n\t * Get the growY and fontSizeAdjustment for a shape.\n\t */\n\tprivate getNoteSizeAdjustments(shape: TLNoteShape) {\n\t\tconst dv = getDisplayValues(this, shape)\n\t\tconst { labelHeight, fontSizeAdjustment } = this.getLabelSize(shape)\n\t\t// When the label height is more than the height of the shape, we add extra height to it\n\t\tconst growY = Math.max(0, labelHeight - dv.noteHeight)\n\n\t\tif (growY !== shape.props.growY || fontSizeAdjustment !== shape.props.fontSizeAdjustment) {\n\t\t\treturn {\n\t\t\t\t...shape,\n\t\t\t\tprops: {\n\t\t\t\t\t...shape.props,\n\t\t\t\t\tgrowY,\n\t\t\t\t\tfontSizeAdjustment,\n\t\t\t\t},\n\t\t\t}\n\t\t}\n\n\t\treturn undefined\n\t}\n\n\tprivate _labelSizesForNoteCache = new WeakCache<\n\t\tTLShape,\n\t\t{ labelHeight: number; labelWidth: number; fontSizeAdjustment: number }\n\t>()\n\n\t/**\n\t * Get the cached label size for the shape.\n\t */\n\tprivate getLabelSize(shape: TLNoteShape) {\n\t\treturn this._labelSizesForNoteCache.get(shape, () => this.measureNoteLabelSize(shape))\n\t}\n\n\t/**\n\t * Expensively measure the label size for a note shape.\n\t */\n\tprivate measureNoteLabelSize(shape: TLNoteShape) {\n\t\tconst dv = getDisplayValues(this, shape)\n\t\tconst { richText } = shape.props\n\n\t\tif (isEmptyRichText(richText)) {\n\t\t\tconst minHeight =\n\t\t\t\tresolveLineHeightPx(dv.labelFontSize, dv.labelLineHeight) + dv.labelPadding * 2\n\t\t\treturn { labelHeight: minHeight, labelWidth: 100, fontSizeAdjustment: 1 }\n\t\t}\n\n\t\tconst unadjustedFontSize = dv.labelFontSize\n\n\t\tlet fontSizeAdjustment = unadjustedFontSize\n\t\tlet iterations = 0\n\t\tlet labelHeight = dv.noteHeight\n\t\tlet labelWidth = dv.noteWidth\n\n\t\t// N.B. For some note shapes with text like 'hjhjhjhjhjhjhjhj', you'll run into\n\t\t// some text measurement fuzziness where the browser swears there's no overflow (scrollWidth === width)\n\t\t// but really there is when you enable overflow-wrap again. This helps account for that little bit\n\t\t// of give.\n\t\tconst FUZZ = 1\n\n\t\t// We slightly make the font smaller if the text is too big for the note, width-wise.\n\t\tdo {\n\t\t\tfontSizeAdjustment = Math.min(unadjustedFontSize, unadjustedFontSize - iterations)\n\t\t\tconst html = renderHtmlFromRichTextForMeasurement(this.editor, richText)\n\t\t\tconst nextTextSize = this.editor.textMeasure.measureHtml(html, {\n\t\t\t\t...TEXT_PROPS,\n\t\t\t\tlineHeight: dv.labelLineHeight,\n\t\t\t\tfontFamily: dv.labelFontFamily,\n\t\t\t\tfontSize: fontSizeAdjustment,\n\t\t\t\tmaxWidth: dv.noteWidth - dv.labelPadding * 2 - FUZZ,\n\t\t\t\tdisableOverflowWrapBreaking: true,\n\t\t\t\tmeasureScrollWidth: true,\n\t\t\t})\n\n\t\t\tlabelHeight = nextTextSize.h + dv.labelPadding * 2\n\t\t\tlabelWidth = nextTextSize.w + dv.labelPadding * 2\n\n\t\t\tif (fontSizeAdjustment <= 14) {\n\t\t\t\t// Too small, just rely now on CSS `overflow-wrap: break-word`\n\t\t\t\t// We need to recalculate the text measurement here with break-word enabled.\n\t\t\t\tconst html = renderHtmlFromRichTextForMeasurement(this.editor, richText)\n\t\t\t\tconst nextTextSizeWithOverflowBreak = this.editor.textMeasure.measureHtml(html, {\n\t\t\t\t\t...TEXT_PROPS,\n\t\t\t\t\tlineHeight: dv.labelLineHeight,\n\t\t\t\t\tfontFamily: dv.labelFontFamily,\n\t\t\t\t\tfontSize: fontSizeAdjustment,\n\t\t\t\t\tmaxWidth: dv.noteWidth - dv.labelPadding * 2 - FUZZ,\n\t\t\t\t})\n\t\t\t\tlabelHeight = nextTextSizeWithOverflowBreak.h + dv.labelPadding * 2\n\t\t\t\tlabelWidth = nextTextSizeWithOverflowBreak.w + dv.labelPadding * 2\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tif (nextTextSize.scrollWidth.toFixed(0) === nextTextSize.w.toFixed(0)) {\n\t\t\t\tbreak\n\t\t\t}\n\t\t} while (iterations++ < 50)\n\n\t\treturn {\n\t\t\tlabelHeight: labelHeight,\n\t\t\tlabelWidth: labelWidth,\n\t\t\tfontSizeAdjustment:\n\t\t\t\tfontSizeAdjustment === unadjustedFontSize ? 1 : fontSizeAdjustment / unadjustedFontSize,\n\t\t}\n\t}\n}\n\nfunction useNoteKeydownHandler(id: TLShapeId) {\n\tconst editor = useEditor()\n\t// Try to get the translation context, but fallback to ltr if it doesn't exist\n\tconst translation = useContext(TranslationsContext)\n\n\treturn useCallback(\n\t\t(e: KeyboardEvent) => {\n\t\t\tconst shape = editor.getShape<TLNoteShape>(id)\n\t\t\tif (!shape) return\n\n\t\t\tconst isTab = e.key === 'Tab'\n\t\t\tconst isCmdEnter = (e.metaKey || e.ctrlKey) && e.key === 'Enter'\n\n\t\t\tif (isTab && isEditingRichTextList(editor)) {\n\t\t\t\t// In a list, let the rich text editor indent the item instead of\n\t\t\t\t// creating a new note. Prevent default so Tab doesn't move focus out\n\t\t\t\t// of the editor when the item can't be indented (e.g. the first item).\n\t\t\t\te.preventDefault()\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif (isTab || isCmdEnter) {\n\t\t\t\te.preventDefault()\n\n\t\t\t\tconst pageTransform = editor.getShapePageTransform(id)\n\t\t\t\tconst pageRotation = pageTransform.rotation()\n\n\t\t\t\t// Based on the inputs, calculate the offset to the next note\n\t\t\t\t// tab controls x axis (shift inverts direction set by RTL)\n\t\t\t\t// cmd enter is the y axis (shift inverts direction)\n\t\t\t\tconst isRTL = !!(\n\t\t\t\t\ttranslation?.dir === 'rtl' ||\n\t\t\t\t\t// todo: can we check a partial of the text, so that we don't have to render the whole thing?\n\t\t\t\t\tisRightToLeftLanguage(renderPlaintextFromRichText(editor, shape.props.richText))\n\t\t\t\t)\n\n\t\t\t\tconst noteUtil = editor.getShapeUtil(shape) as NoteShapeUtil\n\t\t\t\tconst dv = getDisplayValues(noteUtil, shape)\n\n\t\t\t\tconst noteOffset = isTab\n\t\t\t\t\t? dv.noteWidth + editor.options.adjacentShapeMargin\n\t\t\t\t\t: dv.noteHeight +\n\t\t\t\t\t\teditor.options.adjacentShapeMargin +\n\t\t\t\t\t\t// If we're growing down, we need to account for the current shape's growY\n\t\t\t\t\t\t(isCmdEnter && !e.shiftKey ? shape.props.growY : 0)\n\t\t\t\tconst offsetLength = noteOffset * shape.props.scale\n\n\t\t\t\tconst adjacentCenter = new Vec(\n\t\t\t\t\tisTab ? (e.shiftKey != isRTL ? -1 : 1) : 0,\n\t\t\t\t\tisCmdEnter ? (e.shiftKey ? -1 : 1) : 0\n\t\t\t\t)\n\t\t\t\t\t.mul(offsetLength)\n\t\t\t\t\t.add(new Vec(dv.noteWidth / 2, dv.noteHeight / 2).mul(shape.props.scale))\n\t\t\t\t\t.rot(pageRotation)\n\t\t\t\t\t.add(pageTransform.point())\n\n\t\t\t\tconst newNote = getNoteShapeForAdjacentPosition(editor, {\n\t\t\t\t\tshape,\n\t\t\t\t\tcenter: adjacentCenter,\n\t\t\t\t\tpageRotation,\n\t\t\t\t\tnoteWidth: dv.noteWidth,\n\t\t\t\t\tnoteHeight: dv.noteHeight,\n\t\t\t\t})\n\n\t\t\t\tif (newNote) {\n\t\t\t\t\tstartEditingShapeWithRichText(editor, newNote, { selectAll: true })\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t[id, editor, translation?.dir]\n\t)\n}\n\nfunction getNoteHeight(shape: TLNoteShape, noteHeight: number) {\n\treturn (noteHeight + shape.props.growY) * shape.props.scale\n}\n\nfunction getNoteShadow(id: string, rotation: number, scale: number) {\n\tconst random = rng(id) // seeded based on id\n\tconst lift = Math.abs(random()) + 0.5 // 0 to 1.5\n\tconst oy = Math.cos(rotation)\n\tconst a = 5 * scale\n\tconst b = 4 * scale\n\tconst c = 6 * scale\n\tconst d = 7 * scale\n\t// Clamped so shadow never goes above the note at small scales (e.g. dynamic size mode at high zoom)\n\treturn `0px ${Math.max(0, a - lift)}px ${a}px -${a}px rgba(15, 23, 31, .6),\n\t0px ${(b + lift * d) * Math.max(0, oy)}px ${c + lift * d}px -${b + lift * c}px rgba(15, 23, 31, ${(0.3 + lift * 0.1).toFixed(2)}),\n\t0px ${48 * scale}px ${10 * scale}px -${10 * scale}px inset rgba(15, 23, 44, ${((0.022 + random() * 0.005) * ((1 + oy) / 2)).toFixed(2)})`\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["html"]
|
|
7
7
|
}
|
|
@@ -81,13 +81,13 @@ function getNoteAdjacentPositions(editor, opts) {
|
|
|
81
81
|
);
|
|
82
82
|
}
|
|
83
83
|
function getAvailableNoteAdjacentPositions(editor, opts) {
|
|
84
|
-
const { rotation, scale, extraHeight, noteWidth, noteHeight } = opts;
|
|
85
|
-
const
|
|
84
|
+
const { rotation, scale, extraHeight, noteWidth, noteHeight, excludeShapeIds = [] } = opts;
|
|
85
|
+
const excludedShapeIds = new Set(excludeShapeIds);
|
|
86
86
|
const minSize = (Math.max(noteWidth, noteHeight) + editor.options.adjacentShapeMargin + extraHeight) ** 2;
|
|
87
87
|
const allCenters = /* @__PURE__ */ new Map();
|
|
88
88
|
const positions = [];
|
|
89
89
|
for (const shape of editor.getCurrentPageShapes()) {
|
|
90
|
-
if (!editor.isShapeOfType(shape, "note") || scale !== shape.props.scale ||
|
|
90
|
+
if (!editor.isShapeOfType(shape, "note") || scale !== shape.props.scale || excludedShapeIds.has(shape.id)) {
|
|
91
91
|
continue;
|
|
92
92
|
}
|
|
93
93
|
const transform = editor.getShapePageTransform(shape.id);
|
|
@@ -98,7 +98,8 @@ function getAvailableNoteAdjacentPositions(editor, opts) {
|
|
|
98
98
|
getNoteAdjacentPositions(editor, {
|
|
99
99
|
pagePoint: transform.point(),
|
|
100
100
|
pageRotation: rotation,
|
|
101
|
-
|
|
101
|
+
// page units, like the base positions (see PointingHandle)
|
|
102
|
+
growY: shape.props.growY * shape.props.scale,
|
|
102
103
|
extraHeight,
|
|
103
104
|
scale,
|
|
104
105
|
noteWidth,
|
|
@@ -125,7 +126,7 @@ function getNoteShapeForAdjacentPosition(editor, opts) {
|
|
|
125
126
|
const { shape, center, pageRotation, noteWidth, noteHeight, forceNew = false } = opts;
|
|
126
127
|
let nextNote;
|
|
127
128
|
const allShapesOnPage = editor.getCurrentPageShapesSorted();
|
|
128
|
-
const minDistance = (Math.max(noteWidth, noteHeight) + editor.options.adjacentShapeMargin
|
|
129
|
+
const minDistance = ((Math.max(noteWidth, noteHeight) + editor.options.adjacentShapeMargin) * shape.props.scale) ** 2;
|
|
129
130
|
for (let i = allShapesOnPage.length - 1; i >= 0; i--) {
|
|
130
131
|
const otherNote = allShapesOnPage[i];
|
|
131
132
|
if (otherNote.type === "note" && otherNote.id !== shape.id) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/lib/shapes/note/noteHelpers.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n\tEditor,\n\tIndexKey,\n\tTLNoteShape,\n\tTLShape,\n\tVec,\n\tcompact,\n\tcreateShapeId,\n\ttoRichText,\n} from '@tldraw/editor'\n\n/** @internal */\nexport const CLONE_HANDLE_MARGIN = 0\n/** @internal */\nexport const NOTE_ADJACENT_POSITION_SNAP_RADIUS = 10\n\nconst BASE_NOTE_POSITIONS = (editor: Editor, noteWidth: number, noteHeight: number) =>\n\t[\n\t\t[\n\t\t\t['a1' as IndexKey],\n\t\t\tnew Vec(noteWidth * 0.5, noteHeight * -0.5 - editor.options.adjacentShapeMargin),\n\t\t], // t\n\t\t[\n\t\t\t['a2' as IndexKey],\n\t\t\tnew Vec(noteWidth * 1.5 + editor.options.adjacentShapeMargin, noteHeight * 0.5),\n\t\t], // r\n\t\t[\n\t\t\t['a3' as IndexKey],\n\t\t\tnew Vec(noteWidth * 0.5, noteHeight * 1.5 + editor.options.adjacentShapeMargin),\n\t\t], // b\n\t\t[\n\t\t\t['a4' as IndexKey],\n\t\t\tnew Vec(noteWidth * -0.5 - editor.options.adjacentShapeMargin, noteHeight * 0.5),\n\t\t], // l\n\t] as const\n\nfunction getBaseAdjacentNotePositions(\n\teditor: Editor,\n\tscale: number,\n\tnoteWidth: number,\n\tnoteHeight: number\n) {\n\tif (scale === 1) return BASE_NOTE_POSITIONS(editor, noteWidth, noteHeight)\n\tconst w = noteWidth * scale\n\tconst h = noteHeight * scale\n\tconst m = editor.options.adjacentShapeMargin * scale\n\treturn [\n\t\t[['a1' as IndexKey], new Vec(w * 0.5, h * -0.5 - m)], // t\n\t\t[['a2' as IndexKey], new Vec(w * 1.5 + m, h * 0.5)], // r\n\t\t[['a3' as IndexKey], new Vec(w * 0.5, h * 1.5 + m)], // b\n\t\t[['a4' as IndexKey], new Vec(w * -0.5 - m, h * 0.5)], // l\n\t] as const\n}\n\n/** @internal */\nexport interface NoteAdjacentPositionsOpts {\n\tpagePoint: Vec\n\tpageRotation: number\n\tgrowY: number\n\textraHeight: number\n\tscale: number\n\tnoteWidth: number\n\tnoteHeight: number\n}\n\n/**\n * Get the adjacent positions for a particular note shape.\n *\n * @internal */\nexport function getNoteAdjacentPositions(\n\teditor: Editor,\n\topts: NoteAdjacentPositionsOpts\n): Record<IndexKey, Vec> {\n\tconst { pagePoint, pageRotation, growY, extraHeight, scale, noteWidth, noteHeight } = opts\n\treturn Object.fromEntries(\n\t\tgetBaseAdjacentNotePositions(editor, scale, noteWidth, noteHeight).map(([id, v], i) => {\n\t\t\tconst point = v.clone()\n\t\t\tif (i === 0 && extraHeight) {\n\t\t\t\t// apply top margin (the growY of the moving note shape)\n\t\t\t\tpoint.y -= extraHeight\n\t\t\t} else if (i === 2 && growY) {\n\t\t\t\t// apply bottom margin (the growY of this note shape)\n\t\t\t\tpoint.y += growY\n\t\t\t}\n\t\t\treturn [id, point.rot(pageRotation).add(pagePoint)]\n\t\t})\n\t)\n}\n\n/** @internal */\nexport interface AvailableNoteAdjacentPositionsOpts {\n\trotation: number\n\tscale: number\n\textraHeight: number\n\tnoteWidth: number\n\tnoteHeight: number\n}\n\n/**\n * Get all of the available note adjacent positions, excluding
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,
|
|
4
|
+
"sourcesContent": ["import {\n\tEditor,\n\tIndexKey,\n\tTLNoteShape,\n\tTLShape,\n\tTLShapeId,\n\tVec,\n\tcompact,\n\tcreateShapeId,\n\ttoRichText,\n} from '@tldraw/editor'\n\n/** @internal */\nexport const CLONE_HANDLE_MARGIN = 0\n/** @internal */\nexport const NOTE_ADJACENT_POSITION_SNAP_RADIUS = 10\n\nconst BASE_NOTE_POSITIONS = (editor: Editor, noteWidth: number, noteHeight: number) =>\n\t[\n\t\t[\n\t\t\t['a1' as IndexKey],\n\t\t\tnew Vec(noteWidth * 0.5, noteHeight * -0.5 - editor.options.adjacentShapeMargin),\n\t\t], // t\n\t\t[\n\t\t\t['a2' as IndexKey],\n\t\t\tnew Vec(noteWidth * 1.5 + editor.options.adjacentShapeMargin, noteHeight * 0.5),\n\t\t], // r\n\t\t[\n\t\t\t['a3' as IndexKey],\n\t\t\tnew Vec(noteWidth * 0.5, noteHeight * 1.5 + editor.options.adjacentShapeMargin),\n\t\t], // b\n\t\t[\n\t\t\t['a4' as IndexKey],\n\t\t\tnew Vec(noteWidth * -0.5 - editor.options.adjacentShapeMargin, noteHeight * 0.5),\n\t\t], // l\n\t] as const\n\nfunction getBaseAdjacentNotePositions(\n\teditor: Editor,\n\tscale: number,\n\tnoteWidth: number,\n\tnoteHeight: number\n) {\n\tif (scale === 1) return BASE_NOTE_POSITIONS(editor, noteWidth, noteHeight)\n\tconst w = noteWidth * scale\n\tconst h = noteHeight * scale\n\tconst m = editor.options.adjacentShapeMargin * scale\n\treturn [\n\t\t[['a1' as IndexKey], new Vec(w * 0.5, h * -0.5 - m)], // t\n\t\t[['a2' as IndexKey], new Vec(w * 1.5 + m, h * 0.5)], // r\n\t\t[['a3' as IndexKey], new Vec(w * 0.5, h * 1.5 + m)], // b\n\t\t[['a4' as IndexKey], new Vec(w * -0.5 - m, h * 0.5)], // l\n\t] as const\n}\n\n/** @internal */\nexport interface NoteAdjacentPositionsOpts {\n\tpagePoint: Vec\n\tpageRotation: number\n\tgrowY: number\n\textraHeight: number\n\tscale: number\n\tnoteWidth: number\n\tnoteHeight: number\n}\n\n/**\n * Get the adjacent positions for a particular note shape.\n *\n * @internal */\nexport function getNoteAdjacentPositions(\n\teditor: Editor,\n\topts: NoteAdjacentPositionsOpts\n): Record<IndexKey, Vec> {\n\tconst { pagePoint, pageRotation, growY, extraHeight, scale, noteWidth, noteHeight } = opts\n\treturn Object.fromEntries(\n\t\tgetBaseAdjacentNotePositions(editor, scale, noteWidth, noteHeight).map(([id, v], i) => {\n\t\t\tconst point = v.clone()\n\t\t\tif (i === 0 && extraHeight) {\n\t\t\t\t// apply top margin (the growY of the moving note shape)\n\t\t\t\tpoint.y -= extraHeight\n\t\t\t} else if (i === 2 && growY) {\n\t\t\t\t// apply bottom margin (the growY of this note shape)\n\t\t\t\tpoint.y += growY\n\t\t\t}\n\t\t\treturn [id, point.rot(pageRotation).add(pagePoint)]\n\t\t})\n\t)\n}\n\n/** @internal */\nexport interface AvailableNoteAdjacentPositionsOpts {\n\trotation: number\n\tscale: number\n\textraHeight: number\n\tnoteWidth: number\n\tnoteHeight: number\n\t/**\n\t * Notes whose adjacent positions should not be offered, e.g. the notes being dragged,\n\t * which would otherwise snap to their own slots.\n\t */\n\texcludeShapeIds?: TLShapeId[]\n}\n\n/**\n * Get all of the available note adjacent positions, excluding those around `excludeShapeIds`.\n *\n * @internal */\nexport function getAvailableNoteAdjacentPositions(\n\teditor: Editor,\n\topts: AvailableNoteAdjacentPositionsOpts\n) {\n\tconst { rotation, scale, extraHeight, noteWidth, noteHeight, excludeShapeIds = [] } = opts\n\tconst excludedShapeIds = new Set(excludeShapeIds)\n\tconst minSize =\n\t\t(Math.max(noteWidth, noteHeight) + editor.options.adjacentShapeMargin + extraHeight) ** 2\n\tconst allCenters = new Map<TLNoteShape, Vec>()\n\tconst positions: (Vec | undefined)[] = []\n\n\t// Get all the positions that are adjacent to the candidate note shapes\n\tfor (const shape of editor.getCurrentPageShapes()) {\n\t\tif (\n\t\t\t!editor.isShapeOfType(shape, 'note') ||\n\t\t\tscale !== shape.props.scale ||\n\t\t\texcludedShapeIds.has(shape.id)\n\t\t) {\n\t\t\tcontinue\n\t\t}\n\n\t\tconst transform = editor.getShapePageTransform(shape.id)!\n\n\t\t// If the note has a different rotation, we can't use its adjacent positions\n\t\tif (rotation !== transform.rotation()) continue\n\n\t\t// Save the candidate note shape's center\n\t\tallCenters.set(shape, editor.getShapePageBounds(shape)!.center)\n\n\t\t// And push its position to the positions array\n\t\tpositions.push(\n\t\t\t...Object.values(\n\t\t\t\tgetNoteAdjacentPositions(editor, {\n\t\t\t\t\tpagePoint: transform.point(),\n\t\t\t\t\tpageRotation: rotation,\n\t\t\t\t\t// page units, like the base positions (see PointingHandle)\n\t\t\t\t\tgrowY: shape.props.growY * shape.props.scale,\n\t\t\t\t\textraHeight,\n\t\t\t\t\tscale,\n\t\t\t\t\tnoteWidth,\n\t\t\t\t\tnoteHeight,\n\t\t\t\t})\n\t\t\t)\n\t\t)\n\t}\n\n\t// Remove positions that are inside of another note shape\n\tconst len = positions.length\n\tlet position: Vec | undefined\n\tfor (const [shape, center] of allCenters) {\n\t\tfor (let i = 0; i < len; i++) {\n\t\t\tposition = positions[i]\n\t\t\tif (!position) continue\n\t\t\tif (Vec.Dist2(center, position) > minSize) continue\n\t\t\tif (editor.isPointInShape(shape, position)) {\n\t\t\t\tpositions[i] = undefined\n\t\t\t}\n\t\t}\n\t}\n\n\treturn compact(positions)\n}\n\n/** @internal */\nexport interface NoteShapeForAdjacentPositionOpts {\n\tshape: TLNoteShape\n\tcenter: Vec\n\tpageRotation: number\n\tnoteWidth: number\n\tnoteHeight: number\n\tforceNew?: boolean\n}\n\n/**\n * For a particular adjacent note position, get the shape in that position or create a new one.\n *\n * @internal */\nexport function getNoteShapeForAdjacentPosition(\n\teditor: Editor,\n\topts: NoteShapeForAdjacentPositionOpts\n) {\n\tconst { shape, center, pageRotation, noteWidth, noteHeight, forceNew = false } = opts\n\t// There might already be a note in that position! If there is, we'll\n\t// select the next note and switch focus to it. If there's not, then\n\t// we'll create a new note in that position.\n\n\tlet nextNote: TLShape | undefined\n\n\t// Check the center of where a new note would be\n\t// Start from the top of the stack, and work our way down\n\tconst allShapesOnPage = editor.getCurrentPageShapesSorted()\n\n\t// Squared, in page units, to compare against Dist2 below. A neighbour that has grown\n\t// (growY) sits further from the ideal slot centre, so the radius is a full note plus margin.\n\tconst minDistance =\n\t\t((Math.max(noteWidth, noteHeight) + editor.options.adjacentShapeMargin) * shape.props.scale) **\n\t\t2\n\n\tfor (let i = allShapesOnPage.length - 1; i >= 0; i--) {\n\t\tconst otherNote = allShapesOnPage[i]\n\t\tif (otherNote.type === 'note' && otherNote.id !== shape.id) {\n\t\t\tconst otherBounds = editor.getShapePageBounds(otherNote)\n\t\t\tif (\n\t\t\t\totherBounds &&\n\t\t\t\tVec.Dist2(otherBounds.center, center) < minDistance &&\n\t\t\t\teditor.isPointInShape(otherNote, center)\n\t\t\t) {\n\t\t\t\tnextNote = otherNote\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\teditor.complete()\n\n\t// If we didn't find any in that position, then create a new one\n\tif (!nextNote || forceNew) {\n\t\teditor.markHistoryStoppingPoint('creating note shape')\n\t\tconst id = createShapeId()\n\n\t\t// We create it at the center first, so that it becomes\n\t\t// the child of whatever parent was at that center\n\t\teditor.createShape({\n\t\t\tid,\n\t\t\ttype: 'note',\n\t\t\tx: center.x,\n\t\t\ty: center.y,\n\t\t\trotation: pageRotation,\n\t\t\topacity: shape.opacity,\n\t\t\tprops: {\n\t\t\t\t// Use the props of the shape we're cloning\n\t\t\t\t...shape.props,\n\t\t\t\trichText: toRichText(''),\n\t\t\t\tgrowY: 0,\n\t\t\t\tfontSizeAdjustment: 1,\n\t\t\t\turl: '',\n\t\t\t\ttextLastEditedBy: null,\n\t\t\t},\n\t\t})\n\n\t\t// Now we need to correct its location within its new parent\n\n\t\tconst createdShape = editor.getShape<TLNoteShape>(id)!\n\t\tif (!createdShape) return // may have hit max shapes\n\n\t\t// We need to put the page point in the same coordinate space as the newly created shape (i.e its parent's space)\n\t\tconst topLeft = editor.getPointInParentSpace(\n\t\t\tcreatedShape,\n\t\t\tVec.Sub(\n\t\t\t\tcenter,\n\t\t\t\tVec.Rot(new Vec(noteWidth / 2, noteHeight / 2).mul(createdShape.props.scale), pageRotation)\n\t\t\t)\n\t\t)\n\n\t\teditor.updateShape({\n\t\t\tid,\n\t\t\ttype: 'note',\n\t\t\tx: topLeft.x,\n\t\t\ty: topLeft.y,\n\t\t})\n\n\t\tnextNote = editor.getShape(id)!\n\t}\n\n\teditor.zoomToSelectionIfOffscreen(16, {\n\t\tanimation: {\n\t\t\tduration: editor.options.animationMediumMs,\n\t\t},\n\t\tinset: 0,\n\t})\n\treturn nextNote\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/lib/shapes/note/toolStates/Pointing.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n\tEditor,\n\tStateNode,\n\tTLNoteShape,\n\tTLPointerEventInfo,\n\tTLShapeId,\n\tVec,\n\tcreateShapeId,\n\tmaybeSnapToGrid,\n} from '@tldraw/editor'\nimport { startEditingShapeWithRichText } from '../../../tools/SelectTool/selectHelpers'\nimport { getDisplayValues } from '../../shared/getDisplayValues'\nimport {\n\tNOTE_ADJACENT_POSITION_SNAP_RADIUS,\n\tgetAvailableNoteAdjacentPositions,\n} from '../noteHelpers'\nimport type { NoteShapeUtil } from '../NoteShapeUtil'\n\nexport class Pointing extends StateNode {\n\tstatic override id = 'pointing'\n\n\tdragged = false\n\n\tinfo = {} as TLPointerEventInfo\n\n\tmarkId = ''\n\n\tshape = {} as TLNoteShape\n\n\tprivate shapeId!: TLShapeId\n\n\tprivate shapeCenter = new Vec()\n\n\tprivate hasCreatedShape = false\n\n\toverride onEnter() {\n\t\tconst { editor } = this\n\n\t\tthis.hasCreatedShape = false\n\t\tthis.shapeId = createShapeId()\n\t\tthis.markId = editor.markHistoryStoppingPoint(`creating_note:${this.shapeId}`)\n\n\t\t// Resolve note dimensions from the util's defaults\n\t\tconst noteUtil = editor.getShapeUtil('note') as NoteShapeUtil\n\t\tconst dv = getDisplayValues(noteUtil, { props: noteUtil.getDefaultProps() } as TLNoteShape)\n\n\t\t// Check for note pits; if the pointer is close to one, place the note centered on the pit\n\t\tconst center = editor.inputs.getOriginPagePoint().clone()\n\t\tconst offset = getNoteShapeAdjacentPositionOffset(\n\t\t\teditor,\n\t\t\tcenter,\n\t\t\teditor.getResizeScaleFactor(),\n\t\t\tdv.noteWidth,\n\t\t\tdv.noteHeight\n\t\t)\n\t\tif (offset) {\n\t\t\tcenter.sub(offset)\n\t\t}\n\t\tthis.shapeCenter = center\n\n\t\t// On a coarse pointer, defer creating the note until the gesture commits (a\n\t\t// drag or a release). The note is created on press, and a long-press cancels\n\t\t// the pending creation, so without deferral the note appears on press and\n\t\t// vanishes at the long-press mark \u2014 a visible flash. On a fine pointer there\n\t\t// is no long-press cancel, so create immediately to keep the press-and-drag feel.\n\t\tif (!editor.getInstanceState().isCoarsePointer) {\n\t\t\tthis.ensureShapeCreated()\n\t\t}\n\t}\n\n\t// Create the note now if it hasn't been created yet (idempotent). The deferred\n\t// drag and release paths route through here; a max-shapes failure cancels the\n\t// gesture, matching the original onEnter behaviour.\n\tprivate ensureShapeCreated() {\n\t\tif (this.hasCreatedShape) return\n\n\t\tconst shape = createNoteShape(this.editor, this.shapeId, this.shapeCenter)\n\t\tif (shape) {\n\t\t\tthis.shape = shape\n\t\t\tthis.hasCreatedShape = true\n\t\t} else {\n\t\t\tthis.cancel()\n\t\t}\n\t}\n\n\toverride onPointerMove(info: TLPointerEventInfo) {\n\t\tif (this.editor.inputs.getIsDragging()) {\n\t\t\tthis.ensureShapeCreated()\n\t\t\tif (!this.hasCreatedShape) return\n\t\t\tthis.editor.setCurrentTool('select.translating', {\n\t\t\t\t...info,\n\t\t\t\ttarget: 'shape',\n\t\t\t\tshape: this.shape,\n\t\t\t\tonInteractionEnd: 'note',\n\t\t\t\tisCreating: true,\n\t\t\t\tcreatingMarkId: this.markId,\n\t\t\t\tonCreate: () => {\n\t\t\t\t\tstartEditingShapeWithRichText(this.editor, this.shape.id)\n\t\t\t\t},\n\t\t\t})\n\t\t}\n\t}\n\n\toverride onPointerUp() {\n\t\tthis.complete()\n\t}\n\n\toverride onLongPress() {\n\t\t// On a touch (coarse pointer) long-press, cancel the pending shape so it leaves nothing behind.\n\t\tif (this.editor.getInstanceState().isCoarsePointer) this.cancel()\n\t}\n\n\toverride onInterrupt() {\n\t\tthis.cancel()\n\t}\n\n\toverride onComplete() {\n\t\tthis.
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBASO;AACP,2BAA8C;AAC9C,8BAAiC;AACjC,yBAGO;AAGA,MAAM,iBAAiB,wBAAU;AAAA,EACvC,OAAgB,KAAK;AAAA,EAErB,UAAU;AAAA,EAEV,OAAO,CAAC;AAAA,EAER,SAAS;AAAA,EAET,QAAQ,CAAC;AAAA,EAED;AAAA,EAEA,cAAc,IAAI,kBAAI;AAAA,EAEtB,kBAAkB;AAAA,EAEjB,UAAU;AAClB,UAAM,EAAE,OAAO,IAAI;AAEnB,SAAK,kBAAkB;AACvB,SAAK,cAAU,6BAAc;AAC7B,SAAK,SAAS,OAAO,yBAAyB,iBAAiB,KAAK,OAAO,EAAE;AAG7E,UAAM,WAAW,OAAO,aAAa,MAAM;AAC3C,UAAM,SAAK,0CAAiB,UAAU,EAAE,OAAO,SAAS,gBAAgB,EAAE,CAAgB;AAG1F,UAAM,SAAS,OAAO,OAAO,mBAAmB,EAAE,MAAM;AACxD,UAAM,SAAS;AAAA,MACd;AAAA,MACA;AAAA,MACA,OAAO,qBAAqB;AAAA,MAC5B,GAAG;AAAA,MACH,GAAG;AAAA,IACJ;AACA,QAAI,QAAQ;AACX,aAAO,IAAI,MAAM;AAAA,IAClB;AACA,SAAK,cAAc;AAOnB,QAAI,CAAC,OAAO,iBAAiB,EAAE,iBAAiB;AAC/C,WAAK,mBAAmB;AAAA,IACzB;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKQ,qBAAqB;AAC5B,QAAI,KAAK,gBAAiB;AAE1B,UAAM,QAAQ,gBAAgB,KAAK,QAAQ,KAAK,SAAS,KAAK,WAAW;AACzE,QAAI,OAAO;AACV,WAAK,QAAQ;AACb,WAAK,kBAAkB;AAAA,IACxB,OAAO;AACN,WAAK,OAAO;AAAA,IACb;AAAA,EACD;AAAA,EAES,cAAc,MAA0B;AAChD,QAAI,KAAK,OAAO,OAAO,cAAc,GAAG;AACvC,WAAK,mBAAmB;AACxB,UAAI,CAAC,KAAK,gBAAiB;AAC3B,WAAK,OAAO,eAAe,sBAAsB;AAAA,QAChD,GAAG;AAAA,QACH,QAAQ;AAAA,QACR,OAAO,KAAK;AAAA,QACZ,kBAAkB;AAAA,QAClB,YAAY;AAAA,QACZ,gBAAgB,KAAK;AAAA,QACrB,UAAU,MAAM;AACf,kEAA8B,KAAK,QAAQ,KAAK,MAAM,EAAE;AAAA,QACzD;AAAA,MACD,CAAC;AAAA,IACF;AAAA,EACD;AAAA,EAES,cAAc;AACtB,SAAK,SAAS;AAAA,EACf;AAAA,EAES,cAAc;AAEtB,QAAI,KAAK,OAAO,iBAAiB,EAAE,gBAAiB,MAAK,OAAO;AAAA,EACjE;AAAA,EAES,cAAc;AACtB,SAAK,OAAO;AAAA,EACb;AAAA,EAES,aAAa;
|
|
4
|
+
"sourcesContent": ["import {\n\tEditor,\n\tStateNode,\n\tTLNoteShape,\n\tTLPointerEventInfo,\n\tTLShapeId,\n\tVec,\n\tcreateShapeId,\n\tmaybeSnapToGrid,\n} from '@tldraw/editor'\nimport { startEditingShapeWithRichText } from '../../../tools/SelectTool/selectHelpers'\nimport { getDisplayValues } from '../../shared/getDisplayValues'\nimport {\n\tNOTE_ADJACENT_POSITION_SNAP_RADIUS,\n\tgetAvailableNoteAdjacentPositions,\n} from '../noteHelpers'\nimport type { NoteShapeUtil } from '../NoteShapeUtil'\n\nexport class Pointing extends StateNode {\n\tstatic override id = 'pointing'\n\n\tdragged = false\n\n\tinfo = {} as TLPointerEventInfo\n\n\tmarkId = ''\n\n\tshape = {} as TLNoteShape\n\n\tprivate shapeId!: TLShapeId\n\n\tprivate shapeCenter = new Vec()\n\n\tprivate hasCreatedShape = false\n\n\toverride onEnter() {\n\t\tconst { editor } = this\n\n\t\tthis.hasCreatedShape = false\n\t\tthis.shapeId = createShapeId()\n\t\tthis.markId = editor.markHistoryStoppingPoint(`creating_note:${this.shapeId}`)\n\n\t\t// Resolve note dimensions from the util's defaults\n\t\tconst noteUtil = editor.getShapeUtil('note') as NoteShapeUtil\n\t\tconst dv = getDisplayValues(noteUtil, { props: noteUtil.getDefaultProps() } as TLNoteShape)\n\n\t\t// Check for note pits; if the pointer is close to one, place the note centered on the pit\n\t\tconst center = editor.inputs.getOriginPagePoint().clone()\n\t\tconst offset = getNoteShapeAdjacentPositionOffset(\n\t\t\teditor,\n\t\t\tcenter,\n\t\t\teditor.getResizeScaleFactor(),\n\t\t\tdv.noteWidth,\n\t\t\tdv.noteHeight\n\t\t)\n\t\tif (offset) {\n\t\t\tcenter.sub(offset)\n\t\t}\n\t\tthis.shapeCenter = center\n\n\t\t// On a coarse pointer, defer creating the note until the gesture commits (a\n\t\t// drag or a release). The note is created on press, and a long-press cancels\n\t\t// the pending creation, so without deferral the note appears on press and\n\t\t// vanishes at the long-press mark \u2014 a visible flash. On a fine pointer there\n\t\t// is no long-press cancel, so create immediately to keep the press-and-drag feel.\n\t\tif (!editor.getInstanceState().isCoarsePointer) {\n\t\t\tthis.ensureShapeCreated()\n\t\t}\n\t}\n\n\t// Create the note now if it hasn't been created yet (idempotent). The deferred\n\t// drag and release paths route through here; a max-shapes failure cancels the\n\t// gesture, matching the original onEnter behaviour.\n\tprivate ensureShapeCreated() {\n\t\tif (this.hasCreatedShape) return\n\n\t\tconst shape = createNoteShape(this.editor, this.shapeId, this.shapeCenter)\n\t\tif (shape) {\n\t\t\tthis.shape = shape\n\t\t\tthis.hasCreatedShape = true\n\t\t} else {\n\t\t\tthis.cancel()\n\t\t}\n\t}\n\n\toverride onPointerMove(info: TLPointerEventInfo) {\n\t\tif (this.editor.inputs.getIsDragging()) {\n\t\t\tthis.ensureShapeCreated()\n\t\t\tif (!this.hasCreatedShape) return\n\t\t\tthis.editor.setCurrentTool('select.translating', {\n\t\t\t\t...info,\n\t\t\t\ttarget: 'shape',\n\t\t\t\tshape: this.shape,\n\t\t\t\tonInteractionEnd: 'note',\n\t\t\t\tisCreating: true,\n\t\t\t\tcreatingMarkId: this.markId,\n\t\t\t\tonCreate: () => {\n\t\t\t\t\tstartEditingShapeWithRichText(this.editor, this.shape.id)\n\t\t\t\t},\n\t\t\t})\n\t\t}\n\t}\n\n\toverride onPointerUp() {\n\t\tthis.complete()\n\t}\n\n\toverride onLongPress() {\n\t\t// On a touch (coarse pointer) long-press, cancel the pending shape so it leaves nothing behind.\n\t\tif (this.editor.getInstanceState().isCoarsePointer) this.cancel()\n\t}\n\n\toverride onInterrupt() {\n\t\tthis.cancel()\n\t}\n\n\toverride onComplete() {\n\t\t// Not a release: see BaseBoxShapeTool's Pointing state for why this cancels.\n\t\tthis.cancel()\n\t}\n\n\toverride onCancel() {\n\t\tthis.cancel()\n\t}\n\n\tprivate complete() {\n\t\tthis.ensureShapeCreated()\n\t\tif (!this.hasCreatedShape) return\n\t\tif (this.editor.getInstanceState().isToolLocked) {\n\t\t\tthis.parent.transition('idle')\n\t\t} else {\n\t\t\tstartEditingShapeWithRichText(this.editor, this.shape.id, { info: this.info })\n\t\t}\n\t}\n\n\tprivate cancel() {\n\t\tthis.editor.bailToMark(this.markId)\n\t\tthis.parent.transition('idle', this.info)\n\t}\n}\n\nexport function getNoteShapeAdjacentPositionOffset(\n\teditor: Editor,\n\tcenter: Vec,\n\tscale: number,\n\tnoteWidth: number,\n\tnoteHeight: number\n) {\n\tlet min = NOTE_ADJACENT_POSITION_SNAP_RADIUS / editor.getZoomLevel() // in screen space\n\tlet offset: Vec | undefined\n\tfor (const pit of getAvailableNoteAdjacentPositions(editor, {\n\t\trotation: 0,\n\t\tscale,\n\t\textraHeight: 0,\n\t\tnoteWidth,\n\t\tnoteHeight,\n\t})) {\n\t\t// only check page rotations of zero\n\t\tconst deltaToPit = Vec.Sub(center, pit)\n\t\tconst dist = deltaToPit.len()\n\t\tif (dist < min) {\n\t\t\tmin = dist\n\t\t\toffset = deltaToPit\n\t\t}\n\t}\n\treturn offset\n}\n\nexport function createNoteShape(editor: Editor, id: TLShapeId, center: Vec) {\n\teditor.createShape({\n\t\tid,\n\t\ttype: 'note',\n\t\tx: center.x,\n\t\ty: center.y,\n\t\tprops: {\n\t\t\tscale: editor.getResizeScaleFactor(),\n\t\t},\n\t})\n\n\tconst shape = editor.getShape<TLNoteShape>(id)\n\t// Should never happen since we just checked, but just in case\n\tif (!shape) return\n\n\teditor.select(id)\n\tconst bounds = editor.getShapeGeometry(shape).bounds\n\tconst newPoint = maybeSnapToGrid(\n\t\tnew Vec(shape.x - bounds.width / 2, shape.y - bounds.height / 2),\n\t\teditor\n\t)\n\n\t// Center the text around the created point\n\teditor.updateShapes([\n\t\t{\n\t\t\tid,\n\t\t\ttype: 'note',\n\t\t\tx: newPoint.x,\n\t\t\ty: newPoint.y,\n\t\t},\n\t])\n\n\treturn editor.getShape<TLNoteShape>(id)\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBASO;AACP,2BAA8C;AAC9C,8BAAiC;AACjC,yBAGO;AAGA,MAAM,iBAAiB,wBAAU;AAAA,EACvC,OAAgB,KAAK;AAAA,EAErB,UAAU;AAAA,EAEV,OAAO,CAAC;AAAA,EAER,SAAS;AAAA,EAET,QAAQ,CAAC;AAAA,EAED;AAAA,EAEA,cAAc,IAAI,kBAAI;AAAA,EAEtB,kBAAkB;AAAA,EAEjB,UAAU;AAClB,UAAM,EAAE,OAAO,IAAI;AAEnB,SAAK,kBAAkB;AACvB,SAAK,cAAU,6BAAc;AAC7B,SAAK,SAAS,OAAO,yBAAyB,iBAAiB,KAAK,OAAO,EAAE;AAG7E,UAAM,WAAW,OAAO,aAAa,MAAM;AAC3C,UAAM,SAAK,0CAAiB,UAAU,EAAE,OAAO,SAAS,gBAAgB,EAAE,CAAgB;AAG1F,UAAM,SAAS,OAAO,OAAO,mBAAmB,EAAE,MAAM;AACxD,UAAM,SAAS;AAAA,MACd;AAAA,MACA;AAAA,MACA,OAAO,qBAAqB;AAAA,MAC5B,GAAG;AAAA,MACH,GAAG;AAAA,IACJ;AACA,QAAI,QAAQ;AACX,aAAO,IAAI,MAAM;AAAA,IAClB;AACA,SAAK,cAAc;AAOnB,QAAI,CAAC,OAAO,iBAAiB,EAAE,iBAAiB;AAC/C,WAAK,mBAAmB;AAAA,IACzB;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKQ,qBAAqB;AAC5B,QAAI,KAAK,gBAAiB;AAE1B,UAAM,QAAQ,gBAAgB,KAAK,QAAQ,KAAK,SAAS,KAAK,WAAW;AACzE,QAAI,OAAO;AACV,WAAK,QAAQ;AACb,WAAK,kBAAkB;AAAA,IACxB,OAAO;AACN,WAAK,OAAO;AAAA,IACb;AAAA,EACD;AAAA,EAES,cAAc,MAA0B;AAChD,QAAI,KAAK,OAAO,OAAO,cAAc,GAAG;AACvC,WAAK,mBAAmB;AACxB,UAAI,CAAC,KAAK,gBAAiB;AAC3B,WAAK,OAAO,eAAe,sBAAsB;AAAA,QAChD,GAAG;AAAA,QACH,QAAQ;AAAA,QACR,OAAO,KAAK;AAAA,QACZ,kBAAkB;AAAA,QAClB,YAAY;AAAA,QACZ,gBAAgB,KAAK;AAAA,QACrB,UAAU,MAAM;AACf,kEAA8B,KAAK,QAAQ,KAAK,MAAM,EAAE;AAAA,QACzD;AAAA,MACD,CAAC;AAAA,IACF;AAAA,EACD;AAAA,EAES,cAAc;AACtB,SAAK,SAAS;AAAA,EACf;AAAA,EAES,cAAc;AAEtB,QAAI,KAAK,OAAO,iBAAiB,EAAE,gBAAiB,MAAK,OAAO;AAAA,EACjE;AAAA,EAES,cAAc;AACtB,SAAK,OAAO;AAAA,EACb;AAAA,EAES,aAAa;AAErB,SAAK,OAAO;AAAA,EACb;AAAA,EAES,WAAW;AACnB,SAAK,OAAO;AAAA,EACb;AAAA,EAEQ,WAAW;AAClB,SAAK,mBAAmB;AACxB,QAAI,CAAC,KAAK,gBAAiB;AAC3B,QAAI,KAAK,OAAO,iBAAiB,EAAE,cAAc;AAChD,WAAK,OAAO,WAAW,MAAM;AAAA,IAC9B,OAAO;AACN,8DAA8B,KAAK,QAAQ,KAAK,MAAM,IAAI,EAAE,MAAM,KAAK,KAAK,CAAC;AAAA,IAC9E;AAAA,EACD;AAAA,EAEQ,SAAS;AAChB,SAAK,OAAO,WAAW,KAAK,MAAM;AAClC,SAAK,OAAO,WAAW,QAAQ,KAAK,IAAI;AAAA,EACzC;AACD;AAEO,SAAS,mCACf,QACA,QACA,OACA,WACA,YACC;AACD,MAAI,MAAM,wDAAqC,OAAO,aAAa;AACnE,MAAI;AACJ,aAAW,WAAO,sDAAkC,QAAQ;AAAA,IAC3D,UAAU;AAAA,IACV;AAAA,IACA,aAAa;AAAA,IACb;AAAA,IACA;AAAA,EACD,CAAC,GAAG;AAEH,UAAM,aAAa,kBAAI,IAAI,QAAQ,GAAG;AACtC,UAAM,OAAO,WAAW,IAAI;AAC5B,QAAI,OAAO,KAAK;AACf,YAAM;AACN,eAAS;AAAA,IACV;AAAA,EACD;AACA,SAAO;AACR;AAEO,SAAS,gBAAgB,QAAgB,IAAe,QAAa;AAC3E,SAAO,YAAY;AAAA,IAClB;AAAA,IACA,MAAM;AAAA,IACN,GAAG,OAAO;AAAA,IACV,GAAG,OAAO;AAAA,IACV,OAAO;AAAA,MACN,OAAO,OAAO,qBAAqB;AAAA,IACpC;AAAA,EACD,CAAC;AAED,QAAM,QAAQ,OAAO,SAAsB,EAAE;AAE7C,MAAI,CAAC,MAAO;AAEZ,SAAO,OAAO,EAAE;AAChB,QAAM,SAAS,OAAO,iBAAiB,KAAK,EAAE;AAC9C,QAAM,eAAW;AAAA,IAChB,IAAI,kBAAI,MAAM,IAAI,OAAO,QAAQ,GAAG,MAAM,IAAI,OAAO,SAAS,CAAC;AAAA,IAC/D;AAAA,EACD;AAGA,SAAO,aAAa;AAAA,IACnB;AAAA,MACC;AAAA,MACA,MAAM;AAAA,MACN,GAAG,SAAS;AAAA,MACZ,GAAG,SAAS;AAAA,IACb;AAAA,EACD,CAAC;AAED,SAAO,OAAO,SAAsB,EAAE;AACvC;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -390,7 +390,7 @@ function getCroppedImageDataForReplacedImage(imageShape, newImageWidth, newImage
|
|
|
390
390
|
let crop = defaultCrop;
|
|
391
391
|
let newDisplayW = origDisplayW;
|
|
392
392
|
let newDisplayH = origDisplayH;
|
|
393
|
-
const isOriginalCrop = (0, import_editor.isEqual)(imageShape.props.crop, defaultCrop);
|
|
393
|
+
const isOriginalCrop = !!imageShape.props.crop && (0, import_editor.isEqual)(imageShape.props.crop.topLeft, defaultCrop.topLeft) && (0, import_editor.isEqual)(imageShape.props.crop.bottomRight, defaultCrop.bottomRight) && !imageShape.props.crop.isCircle;
|
|
394
394
|
if (isOriginalCrop) {
|
|
395
395
|
newDisplayW = origDisplayW;
|
|
396
396
|
newDisplayH = origDisplayW * newImageHeight / newImageWidth;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/lib/shapes/shared/crop.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n\tBox,\n\tShapeWithCrop,\n\tTLCropInfo,\n\tTLImageShape,\n\tTLShapeCrop,\n\tTLShapeId,\n\tVec,\n\tclamp,\n\tisEqual,\n} from '@tldraw/editor'\n\n/** @internal */\nexport const MIN_CROP_SIZE = 8\n\n/** @public */\nexport interface CropBoxOptions {\n\tminWidth?: number\n\tminHeight?: number\n}\n\n/** @public */\nexport function getDefaultCrop(): TLShapeCrop {\n\treturn {\n\t\ttopLeft: { x: 0, y: 0 },\n\t\tbottomRight: { x: 1, y: 1 },\n\t}\n}\n\n/** @public */\nexport type ASPECT_RATIO_OPTION =\n\t| 'original'\n\t| 'square'\n\t| 'circle'\n\t| 'landscape'\n\t| 'portrait'\n\t| 'wide'\n\n/** @public */\nexport const ASPECT_RATIO_OPTIONS: ASPECT_RATIO_OPTION[] = [\n\t'original',\n\t'square',\n\t'circle',\n\t'landscape',\n\t'portrait',\n\t'wide',\n]\n\n/** @public */\nexport const ASPECT_RATIO_TO_VALUE: Record<ASPECT_RATIO_OPTION, number> = {\n\toriginal: 0,\n\tsquare: 1,\n\tcircle: 1,\n\tlandscape: 4 / 3,\n\tportrait: 3 / 4,\n\twide: 16 / 9,\n}\n\n/**\n * Original (uncropped) width and height of shape.\n *\n * @public\n */\nexport function getUncroppedSize(\n\tshapeSize: { w: number; h: number },\n\tcrop: TLShapeCrop | null\n): { w: number; h: number } {\n\tif (!crop) return { w: shapeSize.w, h: shapeSize.h }\n\tconst w = shapeSize.w / (crop.bottomRight.x - crop.topLeft.x)\n\tconst h = shapeSize.h / (crop.bottomRight.y - crop.topLeft.y)\n\treturn { w, h }\n}\n\n// Utility function to get crop dimensions\nfunction getCropDimensions(crop: TLShapeCrop) {\n\treturn {\n\t\twidth: crop.bottomRight.x - crop.topLeft.x,\n\t\theight: crop.bottomRight.y - crop.topLeft.y,\n\t}\n}\n\n// Utility function to get crop center\nfunction getCropCenter(crop: TLShapeCrop) {\n\tconst { width, height } = getCropDimensions(crop)\n\treturn {\n\t\tx: crop.topLeft.x + width / 2,\n\t\ty: crop.topLeft.y + height / 2,\n\t}\n}\n\n// Utility function to create crop with specified dimensions centered on given point\nfunction createCropAroundCenter(\n\tcenterX: number,\n\tcenterY: number,\n\twidth: number,\n\theight: number,\n\tisCircle?: boolean\n) {\n\tconst topLeftX = Math.max(0, Math.min(1 - width, centerX - width / 2))\n\tconst topLeftY = Math.max(0, Math.min(1 - height, centerY - height / 2))\n\n\treturn {\n\t\ttopLeft: { x: topLeftX, y: topLeftY },\n\t\tbottomRight: { x: topLeftX + width, y: topLeftY + height },\n\t\tisCircle,\n\t}\n}\n\n/** @public */\nexport function getCropBox<T extends ShapeWithCrop>(\n\tshape: T,\n\tinfo: TLCropInfo<T>,\n\topts = {} as CropBoxOptions\n):\n\t| {\n\t\t\tid: TLShapeId\n\t\t\ttype: T['type']\n\t\t\tx: number\n\t\t\ty: number\n\t\t\tprops: ShapeWithCrop['props']\n\t }\n\t| undefined {\n\tconst { handle, change, crop, aspectRatioLocked, isResizingFromCenter } = info\n\tconst { w, h } = info.uncroppedSize\n\tconst { minWidth = MIN_CROP_SIZE, minHeight = MIN_CROP_SIZE } = opts\n\n\tif (w < minWidth || h < minHeight || (change.x === 0 && change.y === 0)) {\n\t\treturn\n\t}\n\n\t// Lets get a box here in pixel space. For simplicity, we'll do all the math in\n\t// pixel space, then convert to normalized space at the end.\n\tconst prevCropBox = new Box(\n\t\tcrop.topLeft.x * w,\n\t\tcrop.topLeft.y * h,\n\t\t(crop.bottomRight.x - crop.topLeft.x) * w,\n\t\t(crop.bottomRight.y - crop.topLeft.y) * h\n\t)\n\n\tconst targetRatio = prevCropBox.aspectRatio\n\tconst tempBox = prevCropBox.clone()\n\n\t// Which axes does the dragged handle move?\n\tconst movesLeft = handle === 'top_left' || handle === 'bottom_left' || handle === 'left'\n\tconst movesRight = handle === 'top_right' || handle === 'bottom_right' || handle === 'right'\n\tconst movesTop = handle === 'top_left' || handle === 'top_right' || handle === 'top'\n\tconst movesBottom = handle === 'bottom_left' || handle === 'bottom_right' || handle === 'bottom'\n\n\tif (isResizingFromCenter) {\n\t\t// Resizing from the center (alt/option): the crop center stays fixed and the\n\t\t// opposite edge mirrors the dragged edge, so the crop grows/shrinks symmetrically.\n\t\tconst cx = prevCropBox.midX\n\t\tconst cy = prevCropBox.midY\n\n\t\t// Desired half-extents from the dragged edge. Undragged axes keep their size.\n\t\tlet halfW = prevCropBox.w / 2\n\t\tlet halfH = prevCropBox.h / 2\n\t\tif (movesLeft) halfW = cx - (prevCropBox.x + change.x)\n\t\telse if (movesRight) halfW = prevCropBox.maxX + change.x - cx\n\t\tif (movesTop) halfH = cy - (prevCropBox.y + change.y)\n\t\telse if (movesBottom) halfH = prevCropBox.maxY + change.y - cy\n\n\t\tif (aspectRatioLocked) {\n\t\t\t// Keep the aspect ratio while staying centered. Pick the driving dimension,\n\t\t\t// derive the other from the ratio, then clamp both at once so the ratio holds.\n\t\t\tconst isCorner = (movesLeft || movesRight) && (movesTop || movesBottom)\n\t\t\tlet drivingHalfW: number\n\t\t\tif (isCorner) {\n\t\t\t\tdrivingHalfW = halfW / halfH > targetRatio ? halfW : halfH * targetRatio\n\t\t\t} else if (movesLeft || movesRight) {\n\t\t\t\tdrivingHalfW = halfW\n\t\t\t} else {\n\t\t\t\tdrivingHalfW = halfH * targetRatio\n\t\t\t}\n\n\t\t\tconst minHalfW = Math.max(minWidth / 2, (minHeight / 2) * targetRatio)\n\t\t\tconst maxHalfW = Math.min(cx, w - cx, cy * targetRatio, (h - cy) * targetRatio)\n\t\t\tif (maxHalfW < minHalfW) return\n\n\t\t\thalfW = clamp(drivingHalfW, minHalfW, maxHalfW)\n\t\t\thalfH = halfW / targetRatio\n\t\t} else {\n\t\t\t// Clamp each dragged axis independently against the image bounds and min size.\n\t\t\tif (movesLeft || movesRight) {\n\t\t\t\tconst maxHalfW = Math.min(cx, w - cx)\n\t\t\t\tif (maxHalfW < minWidth / 2) return\n\t\t\t\thalfW = clamp(halfW, minWidth / 2, maxHalfW)\n\t\t\t}\n\t\t\tif (movesTop || movesBottom) {\n\t\t\t\tconst maxHalfH = Math.min(cy, h - cy)\n\t\t\t\tif (maxHalfH < minHeight / 2) return\n\t\t\t\thalfH = clamp(halfH, minHeight / 2, maxHalfH)\n\t\t\t}\n\t\t}\n\n\t\ttempBox.x = cx - halfW\n\t\ttempBox.y = cy - halfH\n\t\ttempBox.w = halfW * 2\n\t\ttempBox.h = halfH * 2\n\t} else {\n\t\t// Basic resizing logic based on the handles\n\n\t\tif (movesLeft) {\n\t\t\ttempBox.x = clamp(tempBox.x + change.x, 0, prevCropBox.maxX - minWidth)\n\t\t\ttempBox.w = prevCropBox.maxX - tempBox.x\n\t\t} else if (movesRight) {\n\t\t\tconst tempRight = clamp(tempBox.maxX + change.x, prevCropBox.x + minWidth, w)\n\t\t\ttempBox.w = tempRight - tempBox.x\n\t\t}\n\n\t\tif (movesTop) {\n\t\t\ttempBox.y = clamp(tempBox.y + change.y, 0, prevCropBox.maxY - minHeight)\n\t\t\ttempBox.h = prevCropBox.maxY - tempBox.y\n\t\t} else if (movesBottom) {\n\t\t\tconst tempBottom = clamp(tempBox.maxY + change.y, prevCropBox.y + minHeight, h)\n\t\t\ttempBox.h = tempBottom - tempBox.y\n\t\t}\n\t}\n\n\t// Aspect ratio locked resizing logic\n\n\tif (aspectRatioLocked && !isResizingFromCenter) {\n\t\tconst isXLimiting = tempBox.aspectRatio > targetRatio\n\n\t\tif (isXLimiting) {\n\t\t\ttempBox.h = tempBox.w / targetRatio\n\t\t} else {\n\t\t\ttempBox.w = tempBox.h * targetRatio\n\t\t}\n\n\t\tswitch (handle) {\n\t\t\tcase 'top_left': {\n\t\t\t\t// preserve the bottom right corner\n\t\t\t\ttempBox.x = prevCropBox.maxX - tempBox.w\n\t\t\t\ttempBox.y = prevCropBox.maxY - tempBox.h\n\n\t\t\t\tif (tempBox.x <= 0) {\n\t\t\t\t\ttempBox.x = 0\n\t\t\t\t\ttempBox.w = prevCropBox.maxX - tempBox.x\n\t\t\t\t\ttempBox.h = tempBox.w / targetRatio\n\t\t\t\t\ttempBox.y = prevCropBox.maxY - tempBox.h\n\t\t\t\t}\n\n\t\t\t\tif (tempBox.y <= 0) {\n\t\t\t\t\ttempBox.y = 0\n\t\t\t\t\ttempBox.h = prevCropBox.maxY - tempBox.y\n\t\t\t\t\ttempBox.w = tempBox.h * targetRatio\n\t\t\t\t\ttempBox.x = prevCropBox.maxX - tempBox.w\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'top_right': {\n\t\t\t\t// preserve the bottom left corner\n\t\t\t\ttempBox.x = prevCropBox.x\n\t\t\t\ttempBox.y = prevCropBox.maxY - tempBox.h\n\n\t\t\t\tif (tempBox.maxX >= w) {\n\t\t\t\t\ttempBox.w = w - prevCropBox.x\n\t\t\t\t\ttempBox.h = tempBox.w / targetRatio\n\t\t\t\t\ttempBox.y = prevCropBox.maxY - tempBox.h\n\t\t\t\t}\n\n\t\t\t\tif (tempBox.y <= 0) {\n\t\t\t\t\ttempBox.y = 0\n\t\t\t\t\ttempBox.h = prevCropBox.maxY - tempBox.y\n\t\t\t\t\ttempBox.w = tempBox.h * targetRatio\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'bottom_left': {\n\t\t\t\t// preserve the top right corner\n\t\t\t\ttempBox.x = prevCropBox.maxX - tempBox.w\n\t\t\t\ttempBox.y = prevCropBox.y\n\n\t\t\t\tif (tempBox.x <= 0) {\n\t\t\t\t\ttempBox.x = 0\n\t\t\t\t\ttempBox.w = prevCropBox.maxX - tempBox.x\n\t\t\t\t\ttempBox.h = tempBox.w / targetRatio\n\t\t\t\t}\n\n\t\t\t\tif (tempBox.maxY >= h) {\n\t\t\t\t\ttempBox.h = h - prevCropBox.y\n\t\t\t\t\ttempBox.w = tempBox.h * targetRatio\n\t\t\t\t\ttempBox.x = prevCropBox.maxX - tempBox.w\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'bottom_right': {\n\t\t\t\t// preserve the top left corner\n\t\t\t\ttempBox.x = prevCropBox.x\n\t\t\t\ttempBox.y = prevCropBox.y\n\n\t\t\t\tif (tempBox.maxX >= w) {\n\t\t\t\t\ttempBox.w = w - prevCropBox.x\n\t\t\t\t\ttempBox.h = tempBox.w / targetRatio\n\t\t\t\t}\n\n\t\t\t\tif (tempBox.maxY >= h) {\n\t\t\t\t\ttempBox.h = h - prevCropBox.y\n\t\t\t\t\ttempBox.w = tempBox.h * targetRatio\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'top': {\n\t\t\t\t// preserve the bottom edge center\n\t\t\t\ttempBox.h = prevCropBox.maxY - tempBox.y\n\t\t\t\ttempBox.w = tempBox.h * targetRatio\n\t\t\t\ttempBox.x -= (tempBox.w - prevCropBox.w) / 2\n\n\t\t\t\tif (tempBox.x <= 0) {\n\t\t\t\t\tconst leftSide = prevCropBox.midX\n\t\t\t\t\ttempBox.w = leftSide * 2\n\t\t\t\t\ttempBox.h = tempBox.w / targetRatio\n\t\t\t\t\ttempBox.x = 0\n\t\t\t\t}\n\n\t\t\t\tif (tempBox.maxX >= w) {\n\t\t\t\t\tconst rightSide = w - prevCropBox.midX\n\t\t\t\t\ttempBox.w = rightSide * 2\n\t\t\t\t\ttempBox.h = tempBox.w / targetRatio\n\t\t\t\t\ttempBox.x = w - tempBox.w\n\t\t\t\t}\n\n\t\t\t\ttempBox.y = prevCropBox.maxY - tempBox.h\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'right': {\n\t\t\t\t// preserve the left edge center\n\t\t\t\ttempBox.w = tempBox.maxX - prevCropBox.x\n\t\t\t\ttempBox.h = tempBox.w / targetRatio\n\t\t\t\ttempBox.y -= (tempBox.h - prevCropBox.h) / 2\n\n\t\t\t\tif (tempBox.y <= 0) {\n\t\t\t\t\tconst topSide = prevCropBox.midY\n\t\t\t\t\ttempBox.h = topSide * 2\n\t\t\t\t\ttempBox.w = tempBox.h * targetRatio\n\t\t\t\t\ttempBox.y = 0\n\t\t\t\t}\n\n\t\t\t\tif (tempBox.maxY >= h) {\n\t\t\t\t\tconst bottomSide = h - prevCropBox.midY\n\t\t\t\t\ttempBox.h = bottomSide * 2\n\t\t\t\t\ttempBox.w = tempBox.h * targetRatio\n\t\t\t\t\ttempBox.y = h - tempBox.h\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'bottom': {\n\t\t\t\t// preserve the top edge center\n\t\t\t\ttempBox.h = tempBox.maxY - prevCropBox.y\n\t\t\t\ttempBox.w = tempBox.h * targetRatio\n\t\t\t\ttempBox.x -= (tempBox.w - prevCropBox.w) / 2\n\n\t\t\t\tif (tempBox.x <= 0) {\n\t\t\t\t\tconst leftSide = prevCropBox.midX\n\t\t\t\t\ttempBox.w = leftSide * 2\n\t\t\t\t\ttempBox.h = tempBox.w / targetRatio\n\t\t\t\t\ttempBox.x = 0\n\t\t\t\t}\n\n\t\t\t\tif (tempBox.maxX >= w) {\n\t\t\t\t\tconst rightSide = w - prevCropBox.midX\n\t\t\t\t\ttempBox.w = rightSide * 2\n\t\t\t\t\ttempBox.h = tempBox.w / targetRatio\n\t\t\t\t\ttempBox.x = w - tempBox.w\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'left': {\n\t\t\t\t// preserve the right edge center\n\t\t\t\ttempBox.w = prevCropBox.maxX - tempBox.x\n\t\t\t\ttempBox.h = tempBox.w / targetRatio\n\t\t\t\ttempBox.y -= (tempBox.h - prevCropBox.h) / 2\n\n\t\t\t\tif (tempBox.y <= 0) {\n\t\t\t\t\tconst topSide = prevCropBox.midY\n\t\t\t\t\ttempBox.h = topSide * 2\n\t\t\t\t\ttempBox.w = tempBox.h * targetRatio\n\t\t\t\t\ttempBox.y = 0\n\t\t\t\t}\n\n\t\t\t\tif (tempBox.maxY >= h) {\n\t\t\t\t\tconst bottomSide = h - prevCropBox.midY\n\t\t\t\t\ttempBox.h = bottomSide * 2\n\t\t\t\t\ttempBox.w = tempBox.h * targetRatio\n\t\t\t\t\ttempBox.y = h - tempBox.h\n\t\t\t\t}\n\n\t\t\t\ttempBox.x = prevCropBox.maxX - tempBox.w\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\t// Convert the box back to normalized space\n\tconst newCrop: TLShapeCrop = {\n\t\ttopLeft: { x: tempBox.x / w, y: tempBox.y / h },\n\t\tbottomRight: { x: tempBox.maxX / w, y: tempBox.maxY / h },\n\t}\n\tif (crop.isCircle != null) {\n\t\tnewCrop.isCircle = crop.isCircle\n\t}\n\n\t// If the crop hasn't changed, we can return early\n\tif (\n\t\tnewCrop.topLeft.x === crop.topLeft.x &&\n\t\tnewCrop.topLeft.y === crop.topLeft.y &&\n\t\tnewCrop.bottomRight.x === crop.bottomRight.x &&\n\t\tnewCrop.bottomRight.y === crop.bottomRight.y\n\t) {\n\t\treturn\n\t}\n\n\t// Adjust the shape's position to keep the crop's absolute coordinates correct\n\tconst newPoint = new Vec(tempBox.x - crop.topLeft.x * w, tempBox.y - crop.topLeft.y * h)\n\t\t.rot(shape.rotation)\n\t\t.add(shape)\n\n\treturn {\n\t\tid: shape.id,\n\t\ttype: shape.type,\n\t\tx: newPoint.x,\n\t\ty: newPoint.y,\n\t\tprops: {\n\t\t\t...shape.props,\n\t\t\tw: tempBox.w,\n\t\t\th: tempBox.h,\n\t\t\tcrop: newCrop,\n\t\t},\n\t}\n}\n\ninterface CropChange {\n\tcrop: {\n\t\ttopLeft: { x: number; y: number }\n\t\tbottomRight: { x: number; y: number }\n\t\tisCircle?: boolean\n\t}\n\tw: number\n\th: number\n\tx: number\n\ty: number\n}\n\n// Base function for calculating crop changes\nfunction calculateCropChange(\n\timageShape: TLImageShape,\n\tnewCropWidth: number,\n\tnewCropHeight: number,\n\tcenterOnCurrentCrop: boolean = true,\n\tisCircle: boolean = false\n): CropChange {\n\tconst { w, h } = getUncroppedSize(imageShape.props, imageShape.props.crop ?? getDefaultCrop())\n\tconst currentCrop = imageShape.props.crop || getDefaultCrop()\n\n\t// Calculate image and crop centers\n\tconst imageCenterX = imageShape.x + imageShape.props.w / 2\n\tconst imageCenterY = imageShape.y + imageShape.props.h / 2\n\n\tlet cropCenterX, cropCenterY\n\tif (centerOnCurrentCrop) {\n\t\tconst { x, y } = getCropCenter(currentCrop)\n\t\tcropCenterX = x\n\t\tcropCenterY = y\n\t} else {\n\t\tcropCenterX = 0.5\n\t\tcropCenterY = 0.5\n\t}\n\n\t// Create new crop\n\tconst newCrop = createCropAroundCenter(\n\t\tcropCenterX,\n\t\tcropCenterY,\n\t\tnewCropWidth,\n\t\tnewCropHeight,\n\t\tisCircle\n\t)\n\n\t// Calculate new dimensions\n\tconst croppedW = newCropWidth * w\n\tconst croppedH = newCropHeight * h\n\n\treturn {\n\t\tcrop: newCrop,\n\t\tw: croppedW,\n\t\th: croppedH,\n\t\tx: imageCenterX - croppedW / 2,\n\t\ty: imageCenterY - croppedH / 2,\n\t}\n}\n\n/** @internal */\nexport const MAX_ZOOM = 3\n\n/**\n * Calculate new crop dimensions and position when zooming\n */\nexport function getCroppedImageDataWhenZooming(\n\tzoom: number,\n\timageShape: TLImageShape,\n\tmaxZoom?: number\n): CropChange {\n\tconst oldCrop = imageShape.props.crop || getDefaultCrop()\n\tconst { width: oldWidth, height: oldHeight } = getCropDimensions(oldCrop)\n\tconst aspectRatio = oldWidth / oldHeight\n\n\t// Calculate new crop size with zoom scale\n\tconst derivedMaxZoom = maxZoom ? 1 / (1 - maxZoom) : MAX_ZOOM\n\tconst zoomScale = 1 + zoom * (derivedMaxZoom - 1)\n\tlet newWidth, newHeight\n\n\tif (aspectRatio > 1) {\n\t\tnewWidth = Math.min(1, 1 / zoomScale)\n\t\tnewHeight = newWidth / aspectRatio\n\t} else {\n\t\tnewHeight = Math.min(1, 1 / zoomScale)\n\t\tnewWidth = newHeight * aspectRatio\n\t}\n\n\t// Calculate result with base function\n\tconst result = calculateCropChange(imageShape, newWidth, newHeight, true, oldCrop.isCircle)\n\n\t// Apply zoom factor to display dimensions\n\tconst scaleFactor = Math.min(MAX_ZOOM, oldWidth / newWidth)\n\tresult.w *= scaleFactor\n\tresult.h *= scaleFactor\n\n\t// Recenter\n\tconst imageCenterX = imageShape.x + imageShape.props.w / 2\n\tconst imageCenterY = imageShape.y + imageShape.props.h / 2\n\tresult.x = imageCenterX - result.w / 2\n\tresult.y = imageCenterY - result.h / 2\n\n\treturn result\n}\n\n/**\n * Calculate new crop dimensions and position when replacing an image\n */\nexport function getCroppedImageDataForReplacedImage(\n\timageShape: TLImageShape,\n\tnewImageWidth: number,\n\tnewImageHeight: number\n): CropChange {\n\tconst defaultCrop = getDefaultCrop()\n\tconst currentCrop = imageShape.props.crop || defaultCrop\n\tconst origDisplayW = imageShape.props.w\n\tconst origDisplayH = imageShape.props.h\n\tconst newImageAspectRatio = newImageWidth / newImageHeight\n\n\tlet crop = defaultCrop\n\tlet newDisplayW = origDisplayW\n\tlet newDisplayH = origDisplayH\n\tconst isOriginalCrop = isEqual(imageShape.props.crop, defaultCrop)\n\n\tif (isOriginalCrop) {\n\t\tnewDisplayW = origDisplayW\n\t\tnewDisplayH = (origDisplayW * newImageHeight) / newImageWidth\n\t} else {\n\t\tconst { w: uncroppedW, h: uncroppedH } = getUncroppedSize(\n\t\t\timageShape.props,\n\t\t\timageShape.props.crop || getDefaultCrop() // Use the ACTUAL current crop to correctly infer uncropped size\n\t\t)\n\t\tconst { width: cropW, height: cropH } = getCropDimensions(currentCrop)\n\t\tconst targetRatio = cropW / cropH\n\t\tconst oldImageAspectRatio = uncroppedW / uncroppedH\n\t\tlet newRelativeWidth: number\n\t\tlet newRelativeHeight: number\n\n\t\tconst currentCropCenter = getCropCenter(currentCrop)\n\n\t\t// Adjust the new crop dimensions to match the current crop zoom\n\t\tnewRelativeWidth = cropW\n\t\tconst ratioConversion = newImageAspectRatio / oldImageAspectRatio / targetRatio\n\t\tnewRelativeHeight = newRelativeWidth * ratioConversion\n\n\t\t// Check that our new crop dimensions are within the MAX_ZOOM bounds\n\t\tconst maxRatioConversion = MAX_ZOOM / (MAX_ZOOM - 1)\n\t\tif (ratioConversion > maxRatioConversion) {\n\t\t\tconst minDimension = 1 / MAX_ZOOM\n\t\t\tif (1 / newRelativeHeight < 1 / newRelativeWidth) {\n\t\t\t\tconst scale = newRelativeHeight / minDimension\n\t\t\t\tnewRelativeHeight = newRelativeHeight / scale\n\t\t\t\tnewRelativeWidth = newRelativeWidth / scale\n\t\t\t} else {\n\t\t\t\tconst scale = newRelativeWidth / minDimension\n\t\t\t\tnewRelativeWidth = newRelativeWidth / scale\n\t\t\t\tnewRelativeHeight = newRelativeHeight / scale\n\t\t\t}\n\t\t}\n\n\t\t// Ensure dimensions are within [0, 1] bounds after adjustment\n\t\tnewRelativeWidth = Math.max(0, Math.min(1, newRelativeWidth))\n\t\tnewRelativeHeight = Math.max(0, Math.min(1, newRelativeHeight))\n\n\t\t// Create the new crop object, centered around the CURRENT crop's center\n\t\tcrop = createCropAroundCenter(\n\t\t\tcurrentCropCenter.x,\n\t\t\tcurrentCropCenter.y,\n\t\t\tnewRelativeWidth,\n\t\t\tnewRelativeHeight,\n\t\t\tcurrentCrop.isCircle\n\t\t)\n\t}\n\n\t// Position so visual center stays put\n\tconst pageCenterX = imageShape.x + origDisplayW / 2\n\tconst pageCenterY = imageShape.y + origDisplayH / 2\n\n\tconst newX = pageCenterX - newDisplayW / 2\n\tconst newY = pageCenterY - newDisplayH / 2\n\n\treturn {\n\t\tcrop,\n\t\tw: newDisplayW,\n\t\th: newDisplayH,\n\t\tx: newX,\n\t\ty: newY,\n\t}\n}\n\n/**\n * Calculate new crop dimensions and position when changing aspect ratio\n */\nexport function getCroppedImageDataForAspectRatio(\n\taspectRatioOption: ASPECT_RATIO_OPTION,\n\timageShape: TLImageShape\n): CropChange {\n\t// If original aspect ratio is requested, use default crop\n\tif (aspectRatioOption === 'original') {\n\t\tconst { w, h } = getUncroppedSize(imageShape.props, imageShape.props.crop ?? getDefaultCrop())\n\t\tconst imageCenterX = imageShape.x + imageShape.props.w / 2\n\t\tconst imageCenterY = imageShape.y + imageShape.props.h / 2\n\n\t\treturn {\n\t\t\tcrop: getDefaultCrop(),\n\t\t\tw,\n\t\t\th,\n\t\t\tx: imageCenterX - w / 2,\n\t\t\ty: imageCenterY - h / 2,\n\t\t}\n\t}\n\n\t// Get target ratio and uncropped image properties\n\tconst targetRatio = ASPECT_RATIO_TO_VALUE[aspectRatioOption] // Assume valid option\n\tconst isCircle = aspectRatioOption === 'circle'\n\t// Use default crop to get uncropped size relative to the *original* image bounds\n\tconst { w: uncroppedW, h: uncroppedH } = getUncroppedSize(\n\t\timageShape.props,\n\t\timageShape.props.crop || getDefaultCrop() // Use the ACTUAL current crop to correctly infer uncropped size\n\t)\n\t// Calculate the original image aspect ratio\n\tconst imageAspectRatio = uncroppedW / uncroppedH\n\n\t// Get the current crop and its relative dimensions\n\tconst currentCrop = imageShape.props.crop || getDefaultCrop()\n\tconst { width: cropW, height: cropH } = getCropDimensions(currentCrop)\n\tconst currentCropCenter = getCropCenter(currentCrop)\n\n\t// Calculate the current crop zoom level\n\tconst currentCropZoom = Math.min(1 / cropW, 1 / cropH)\n\n\t// Calculate the relative width and height of the crop rectangle (0-1 scale)\n\t// Try to preserve the longest dimension of the current crop when changing aspect ratios\n\tlet newRelativeWidth: number\n\tlet newRelativeHeight: number\n\n\tif (imageAspectRatio === 0 || !Number.isFinite(imageAspectRatio) || targetRatio === 0) {\n\t\t// Avoid division by zero or NaN issues if image dimensions are invalid or target ratio is 0\n\t\tnewRelativeWidth = 1\n\t\tnewRelativeHeight = 1\n\t} else {\n\t\t// Get current crop dimensions in absolute units\n\t\tconst currentAbsoluteWidth = cropW * uncroppedW\n\t\tconst currentAbsoluteHeight = cropH * uncroppedH\n\n\t\t// Find the longest current dimension to preserve\n\t\tconst longestCurrentDimension = Math.max(currentAbsoluteWidth, currentAbsoluteHeight)\n\t\tconst isWidthLongest = currentAbsoluteWidth >= currentAbsoluteHeight\n\n\t\t// Calculate new dimensions preserving the longest dimension\n\t\tlet newAbsoluteWidth: number\n\t\tlet newAbsoluteHeight: number\n\n\t\tif (isWidthLongest) {\n\t\t\t// Preserve width, calculate height based on target ratio\n\t\t\tnewAbsoluteWidth = longestCurrentDimension\n\t\t\tnewAbsoluteHeight = newAbsoluteWidth / targetRatio\n\t\t} else {\n\t\t\t// Preserve height, calculate width based on target ratio\n\t\t\tnewAbsoluteHeight = longestCurrentDimension\n\t\t\tnewAbsoluteWidth = newAbsoluteHeight * targetRatio\n\t\t}\n\n\t\t// Convert back to relative coordinates\n\t\tnewRelativeWidth = newAbsoluteWidth / uncroppedW\n\t\tnewRelativeHeight = newAbsoluteHeight / uncroppedH\n\n\t\t// Clamp to image bounds and adjust if necessary\n\t\tif (newRelativeWidth > 1) {\n\t\t\t// Width exceeds bounds, clamp and recalculate height\n\t\t\tnewRelativeWidth = 1\n\t\t\tnewRelativeHeight = imageAspectRatio / targetRatio\n\t\t}\n\t\tif (newRelativeHeight > 1) {\n\t\t\t// Height exceeds bounds, clamp and recalculate width\n\t\t\tnewRelativeHeight = 1\n\t\t\tnewRelativeWidth = targetRatio / imageAspectRatio\n\t\t}\n\n\t\t// Final clamp to ensure we stay within bounds\n\t\tnewRelativeWidth = Math.max(0, Math.min(1, newRelativeWidth))\n\t\tnewRelativeHeight = Math.max(0, Math.min(1, newRelativeHeight))\n\t}\n\n\tconst newCropZoom = Math.min(1 / newRelativeWidth, 1 / newRelativeHeight)\n\t// Adjust the new crop dimensions to match the current crop zoom\n\tnewRelativeWidth *= newCropZoom / currentCropZoom\n\tnewRelativeHeight *= newCropZoom / currentCropZoom\n\n\t// Ensure dimensions are within [0, 1] bounds after adjustment\n\tnewRelativeWidth = Math.max(0, Math.min(1, newRelativeWidth))\n\tnewRelativeHeight = Math.max(0, Math.min(1, newRelativeHeight))\n\n\t// Create the new crop object, centered around the CURRENT crop's center\n\tconst newCrop = createCropAroundCenter(\n\t\tcurrentCropCenter.x,\n\t\tcurrentCropCenter.y,\n\t\tnewRelativeWidth,\n\t\tnewRelativeHeight,\n\t\tisCircle\n\t)\n\n\t// Get the actual relative dimensions from the new crop (after potential clamping)\n\tconst finalRelativeWidth = newCrop.bottomRight.x - newCrop.topLeft.x\n\tconst finalRelativeHeight = newCrop.bottomRight.y - newCrop.topLeft.y\n\n\t// Calculate the base dimensions (as if applying the new crop to the uncropped image at scale 1)\n\tconst baseW = finalRelativeWidth * uncroppedW\n\tconst baseH = finalRelativeHeight * uncroppedH\n\n\t// Determine the current effective scale of the shape\n\t// This preserves the visual size when the crop changes\n\tlet currentScale = 1.0\n\tif (cropW > 0) {\n\t\tcurrentScale = imageShape.props.w / (cropW * uncroppedW)\n\t} else if (cropH > 0) {\n\t\t// Fallback to height if width relative dimension is zero\n\t\tcurrentScale = imageShape.props.h / (cropH * uncroppedH)\n\t}\n\n\t// Apply the current scale to the base dimensions to get the final dimensions\n\tconst newW = baseW * currentScale\n\tconst newH = baseH * currentScale\n\n\t// Calculate the new top-left position (x, y) for the shape\n\t// to keep the visual center of the cropped area fixed on the page.\n\tconst currentCenterXPage = imageShape.x + imageShape.props.w / 2\n\tconst currentCenterYPage = imageShape.y + imageShape.props.h / 2\n\tconst newX = currentCenterXPage - newW / 2\n\tconst newY = currentCenterYPage - newH / 2\n\n\treturn {\n\t\tcrop: newCrop,\n\t\tw: newW,\n\t\th: newH,\n\t\tx: newX,\n\t\ty: newY,\n\t}\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import {\n\tBox,\n\tShapeWithCrop,\n\tTLCropInfo,\n\tTLImageShape,\n\tTLShapeCrop,\n\tTLShapeId,\n\tVec,\n\tclamp,\n\tisEqual,\n} from '@tldraw/editor'\n\n/** @internal */\nexport const MIN_CROP_SIZE = 8\n\n/** @public */\nexport interface CropBoxOptions {\n\tminWidth?: number\n\tminHeight?: number\n}\n\n/** @public */\nexport function getDefaultCrop(): TLShapeCrop {\n\treturn {\n\t\ttopLeft: { x: 0, y: 0 },\n\t\tbottomRight: { x: 1, y: 1 },\n\t}\n}\n\n/** @public */\nexport type ASPECT_RATIO_OPTION =\n\t| 'original'\n\t| 'square'\n\t| 'circle'\n\t| 'landscape'\n\t| 'portrait'\n\t| 'wide'\n\n/** @public */\nexport const ASPECT_RATIO_OPTIONS: ASPECT_RATIO_OPTION[] = [\n\t'original',\n\t'square',\n\t'circle',\n\t'landscape',\n\t'portrait',\n\t'wide',\n]\n\n/** @public */\nexport const ASPECT_RATIO_TO_VALUE: Record<ASPECT_RATIO_OPTION, number> = {\n\toriginal: 0,\n\tsquare: 1,\n\tcircle: 1,\n\tlandscape: 4 / 3,\n\tportrait: 3 / 4,\n\twide: 16 / 9,\n}\n\n/**\n * Original (uncropped) width and height of shape.\n *\n * @public\n */\nexport function getUncroppedSize(\n\tshapeSize: { w: number; h: number },\n\tcrop: TLShapeCrop | null\n): { w: number; h: number } {\n\tif (!crop) return { w: shapeSize.w, h: shapeSize.h }\n\tconst w = shapeSize.w / (crop.bottomRight.x - crop.topLeft.x)\n\tconst h = shapeSize.h / (crop.bottomRight.y - crop.topLeft.y)\n\treturn { w, h }\n}\n\n// Utility function to get crop dimensions\nfunction getCropDimensions(crop: TLShapeCrop) {\n\treturn {\n\t\twidth: crop.bottomRight.x - crop.topLeft.x,\n\t\theight: crop.bottomRight.y - crop.topLeft.y,\n\t}\n}\n\n// Utility function to get crop center\nfunction getCropCenter(crop: TLShapeCrop) {\n\tconst { width, height } = getCropDimensions(crop)\n\treturn {\n\t\tx: crop.topLeft.x + width / 2,\n\t\ty: crop.topLeft.y + height / 2,\n\t}\n}\n\n// Utility function to create crop with specified dimensions centered on given point\nfunction createCropAroundCenter(\n\tcenterX: number,\n\tcenterY: number,\n\twidth: number,\n\theight: number,\n\tisCircle?: boolean\n) {\n\tconst topLeftX = Math.max(0, Math.min(1 - width, centerX - width / 2))\n\tconst topLeftY = Math.max(0, Math.min(1 - height, centerY - height / 2))\n\n\treturn {\n\t\ttopLeft: { x: topLeftX, y: topLeftY },\n\t\tbottomRight: { x: topLeftX + width, y: topLeftY + height },\n\t\tisCircle,\n\t}\n}\n\n/** @public */\nexport function getCropBox<T extends ShapeWithCrop>(\n\tshape: T,\n\tinfo: TLCropInfo<T>,\n\topts = {} as CropBoxOptions\n):\n\t| {\n\t\t\tid: TLShapeId\n\t\t\ttype: T['type']\n\t\t\tx: number\n\t\t\ty: number\n\t\t\tprops: ShapeWithCrop['props']\n\t }\n\t| undefined {\n\tconst { handle, change, crop, aspectRatioLocked, isResizingFromCenter } = info\n\tconst { w, h } = info.uncroppedSize\n\tconst { minWidth = MIN_CROP_SIZE, minHeight = MIN_CROP_SIZE } = opts\n\n\tif (w < minWidth || h < minHeight || (change.x === 0 && change.y === 0)) {\n\t\treturn\n\t}\n\n\t// Lets get a box here in pixel space. For simplicity, we'll do all the math in\n\t// pixel space, then convert to normalized space at the end.\n\tconst prevCropBox = new Box(\n\t\tcrop.topLeft.x * w,\n\t\tcrop.topLeft.y * h,\n\t\t(crop.bottomRight.x - crop.topLeft.x) * w,\n\t\t(crop.bottomRight.y - crop.topLeft.y) * h\n\t)\n\n\tconst targetRatio = prevCropBox.aspectRatio\n\tconst tempBox = prevCropBox.clone()\n\n\t// Which axes does the dragged handle move?\n\tconst movesLeft = handle === 'top_left' || handle === 'bottom_left' || handle === 'left'\n\tconst movesRight = handle === 'top_right' || handle === 'bottom_right' || handle === 'right'\n\tconst movesTop = handle === 'top_left' || handle === 'top_right' || handle === 'top'\n\tconst movesBottom = handle === 'bottom_left' || handle === 'bottom_right' || handle === 'bottom'\n\n\tif (isResizingFromCenter) {\n\t\t// Resizing from the center (alt/option): the crop center stays fixed and the\n\t\t// opposite edge mirrors the dragged edge, so the crop grows/shrinks symmetrically.\n\t\tconst cx = prevCropBox.midX\n\t\tconst cy = prevCropBox.midY\n\n\t\t// Desired half-extents from the dragged edge. Undragged axes keep their size.\n\t\tlet halfW = prevCropBox.w / 2\n\t\tlet halfH = prevCropBox.h / 2\n\t\tif (movesLeft) halfW = cx - (prevCropBox.x + change.x)\n\t\telse if (movesRight) halfW = prevCropBox.maxX + change.x - cx\n\t\tif (movesTop) halfH = cy - (prevCropBox.y + change.y)\n\t\telse if (movesBottom) halfH = prevCropBox.maxY + change.y - cy\n\n\t\tif (aspectRatioLocked) {\n\t\t\t// Keep the aspect ratio while staying centered. Pick the driving dimension,\n\t\t\t// derive the other from the ratio, then clamp both at once so the ratio holds.\n\t\t\tconst isCorner = (movesLeft || movesRight) && (movesTop || movesBottom)\n\t\t\tlet drivingHalfW: number\n\t\t\tif (isCorner) {\n\t\t\t\tdrivingHalfW = halfW / halfH > targetRatio ? halfW : halfH * targetRatio\n\t\t\t} else if (movesLeft || movesRight) {\n\t\t\t\tdrivingHalfW = halfW\n\t\t\t} else {\n\t\t\t\tdrivingHalfW = halfH * targetRatio\n\t\t\t}\n\n\t\t\tconst minHalfW = Math.max(minWidth / 2, (minHeight / 2) * targetRatio)\n\t\t\tconst maxHalfW = Math.min(cx, w - cx, cy * targetRatio, (h - cy) * targetRatio)\n\t\t\tif (maxHalfW < minHalfW) return\n\n\t\t\thalfW = clamp(drivingHalfW, minHalfW, maxHalfW)\n\t\t\thalfH = halfW / targetRatio\n\t\t} else {\n\t\t\t// Clamp each dragged axis independently against the image bounds and min size.\n\t\t\tif (movesLeft || movesRight) {\n\t\t\t\tconst maxHalfW = Math.min(cx, w - cx)\n\t\t\t\tif (maxHalfW < minWidth / 2) return\n\t\t\t\thalfW = clamp(halfW, minWidth / 2, maxHalfW)\n\t\t\t}\n\t\t\tif (movesTop || movesBottom) {\n\t\t\t\tconst maxHalfH = Math.min(cy, h - cy)\n\t\t\t\tif (maxHalfH < minHeight / 2) return\n\t\t\t\thalfH = clamp(halfH, minHeight / 2, maxHalfH)\n\t\t\t}\n\t\t}\n\n\t\ttempBox.x = cx - halfW\n\t\ttempBox.y = cy - halfH\n\t\ttempBox.w = halfW * 2\n\t\ttempBox.h = halfH * 2\n\t} else {\n\t\t// Basic resizing logic based on the handles\n\n\t\tif (movesLeft) {\n\t\t\ttempBox.x = clamp(tempBox.x + change.x, 0, prevCropBox.maxX - minWidth)\n\t\t\ttempBox.w = prevCropBox.maxX - tempBox.x\n\t\t} else if (movesRight) {\n\t\t\tconst tempRight = clamp(tempBox.maxX + change.x, prevCropBox.x + minWidth, w)\n\t\t\ttempBox.w = tempRight - tempBox.x\n\t\t}\n\n\t\tif (movesTop) {\n\t\t\ttempBox.y = clamp(tempBox.y + change.y, 0, prevCropBox.maxY - minHeight)\n\t\t\ttempBox.h = prevCropBox.maxY - tempBox.y\n\t\t} else if (movesBottom) {\n\t\t\tconst tempBottom = clamp(tempBox.maxY + change.y, prevCropBox.y + minHeight, h)\n\t\t\ttempBox.h = tempBottom - tempBox.y\n\t\t}\n\t}\n\n\t// Aspect ratio locked resizing logic\n\n\tif (aspectRatioLocked && !isResizingFromCenter) {\n\t\tconst isXLimiting = tempBox.aspectRatio > targetRatio\n\n\t\tif (isXLimiting) {\n\t\t\ttempBox.h = tempBox.w / targetRatio\n\t\t} else {\n\t\t\ttempBox.w = tempBox.h * targetRatio\n\t\t}\n\n\t\tswitch (handle) {\n\t\t\tcase 'top_left': {\n\t\t\t\t// preserve the bottom right corner\n\t\t\t\ttempBox.x = prevCropBox.maxX - tempBox.w\n\t\t\t\ttempBox.y = prevCropBox.maxY - tempBox.h\n\n\t\t\t\tif (tempBox.x <= 0) {\n\t\t\t\t\ttempBox.x = 0\n\t\t\t\t\ttempBox.w = prevCropBox.maxX - tempBox.x\n\t\t\t\t\ttempBox.h = tempBox.w / targetRatio\n\t\t\t\t\ttempBox.y = prevCropBox.maxY - tempBox.h\n\t\t\t\t}\n\n\t\t\t\tif (tempBox.y <= 0) {\n\t\t\t\t\ttempBox.y = 0\n\t\t\t\t\ttempBox.h = prevCropBox.maxY - tempBox.y\n\t\t\t\t\ttempBox.w = tempBox.h * targetRatio\n\t\t\t\t\ttempBox.x = prevCropBox.maxX - tempBox.w\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'top_right': {\n\t\t\t\t// preserve the bottom left corner\n\t\t\t\ttempBox.x = prevCropBox.x\n\t\t\t\ttempBox.y = prevCropBox.maxY - tempBox.h\n\n\t\t\t\tif (tempBox.maxX >= w) {\n\t\t\t\t\ttempBox.w = w - prevCropBox.x\n\t\t\t\t\ttempBox.h = tempBox.w / targetRatio\n\t\t\t\t\ttempBox.y = prevCropBox.maxY - tempBox.h\n\t\t\t\t}\n\n\t\t\t\tif (tempBox.y <= 0) {\n\t\t\t\t\ttempBox.y = 0\n\t\t\t\t\ttempBox.h = prevCropBox.maxY - tempBox.y\n\t\t\t\t\ttempBox.w = tempBox.h * targetRatio\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'bottom_left': {\n\t\t\t\t// preserve the top right corner\n\t\t\t\ttempBox.x = prevCropBox.maxX - tempBox.w\n\t\t\t\ttempBox.y = prevCropBox.y\n\n\t\t\t\tif (tempBox.x <= 0) {\n\t\t\t\t\ttempBox.x = 0\n\t\t\t\t\ttempBox.w = prevCropBox.maxX - tempBox.x\n\t\t\t\t\ttempBox.h = tempBox.w / targetRatio\n\t\t\t\t}\n\n\t\t\t\tif (tempBox.maxY >= h) {\n\t\t\t\t\ttempBox.h = h - prevCropBox.y\n\t\t\t\t\ttempBox.w = tempBox.h * targetRatio\n\t\t\t\t\ttempBox.x = prevCropBox.maxX - tempBox.w\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'bottom_right': {\n\t\t\t\t// preserve the top left corner\n\t\t\t\ttempBox.x = prevCropBox.x\n\t\t\t\ttempBox.y = prevCropBox.y\n\n\t\t\t\tif (tempBox.maxX >= w) {\n\t\t\t\t\ttempBox.w = w - prevCropBox.x\n\t\t\t\t\ttempBox.h = tempBox.w / targetRatio\n\t\t\t\t}\n\n\t\t\t\tif (tempBox.maxY >= h) {\n\t\t\t\t\ttempBox.h = h - prevCropBox.y\n\t\t\t\t\ttempBox.w = tempBox.h * targetRatio\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'top': {\n\t\t\t\t// preserve the bottom edge center\n\t\t\t\ttempBox.h = prevCropBox.maxY - tempBox.y\n\t\t\t\ttempBox.w = tempBox.h * targetRatio\n\t\t\t\ttempBox.x -= (tempBox.w - prevCropBox.w) / 2\n\n\t\t\t\tif (tempBox.x <= 0) {\n\t\t\t\t\tconst leftSide = prevCropBox.midX\n\t\t\t\t\ttempBox.w = leftSide * 2\n\t\t\t\t\ttempBox.h = tempBox.w / targetRatio\n\t\t\t\t\ttempBox.x = 0\n\t\t\t\t}\n\n\t\t\t\tif (tempBox.maxX >= w) {\n\t\t\t\t\tconst rightSide = w - prevCropBox.midX\n\t\t\t\t\ttempBox.w = rightSide * 2\n\t\t\t\t\ttempBox.h = tempBox.w / targetRatio\n\t\t\t\t\ttempBox.x = w - tempBox.w\n\t\t\t\t}\n\n\t\t\t\ttempBox.y = prevCropBox.maxY - tempBox.h\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'right': {\n\t\t\t\t// preserve the left edge center\n\t\t\t\ttempBox.w = tempBox.maxX - prevCropBox.x\n\t\t\t\ttempBox.h = tempBox.w / targetRatio\n\t\t\t\ttempBox.y -= (tempBox.h - prevCropBox.h) / 2\n\n\t\t\t\tif (tempBox.y <= 0) {\n\t\t\t\t\tconst topSide = prevCropBox.midY\n\t\t\t\t\ttempBox.h = topSide * 2\n\t\t\t\t\ttempBox.w = tempBox.h * targetRatio\n\t\t\t\t\ttempBox.y = 0\n\t\t\t\t}\n\n\t\t\t\tif (tempBox.maxY >= h) {\n\t\t\t\t\tconst bottomSide = h - prevCropBox.midY\n\t\t\t\t\ttempBox.h = bottomSide * 2\n\t\t\t\t\ttempBox.w = tempBox.h * targetRatio\n\t\t\t\t\ttempBox.y = h - tempBox.h\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'bottom': {\n\t\t\t\t// preserve the top edge center\n\t\t\t\ttempBox.h = tempBox.maxY - prevCropBox.y\n\t\t\t\ttempBox.w = tempBox.h * targetRatio\n\t\t\t\ttempBox.x -= (tempBox.w - prevCropBox.w) / 2\n\n\t\t\t\tif (tempBox.x <= 0) {\n\t\t\t\t\tconst leftSide = prevCropBox.midX\n\t\t\t\t\ttempBox.w = leftSide * 2\n\t\t\t\t\ttempBox.h = tempBox.w / targetRatio\n\t\t\t\t\ttempBox.x = 0\n\t\t\t\t}\n\n\t\t\t\tif (tempBox.maxX >= w) {\n\t\t\t\t\tconst rightSide = w - prevCropBox.midX\n\t\t\t\t\ttempBox.w = rightSide * 2\n\t\t\t\t\ttempBox.h = tempBox.w / targetRatio\n\t\t\t\t\ttempBox.x = w - tempBox.w\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'left': {\n\t\t\t\t// preserve the right edge center\n\t\t\t\ttempBox.w = prevCropBox.maxX - tempBox.x\n\t\t\t\ttempBox.h = tempBox.w / targetRatio\n\t\t\t\ttempBox.y -= (tempBox.h - prevCropBox.h) / 2\n\n\t\t\t\tif (tempBox.y <= 0) {\n\t\t\t\t\tconst topSide = prevCropBox.midY\n\t\t\t\t\ttempBox.h = topSide * 2\n\t\t\t\t\ttempBox.w = tempBox.h * targetRatio\n\t\t\t\t\ttempBox.y = 0\n\t\t\t\t}\n\n\t\t\t\tif (tempBox.maxY >= h) {\n\t\t\t\t\tconst bottomSide = h - prevCropBox.midY\n\t\t\t\t\ttempBox.h = bottomSide * 2\n\t\t\t\t\ttempBox.w = tempBox.h * targetRatio\n\t\t\t\t\ttempBox.y = h - tempBox.h\n\t\t\t\t}\n\n\t\t\t\ttempBox.x = prevCropBox.maxX - tempBox.w\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\t// Convert the box back to normalized space\n\tconst newCrop: TLShapeCrop = {\n\t\ttopLeft: { x: tempBox.x / w, y: tempBox.y / h },\n\t\tbottomRight: { x: tempBox.maxX / w, y: tempBox.maxY / h },\n\t}\n\tif (crop.isCircle != null) {\n\t\tnewCrop.isCircle = crop.isCircle\n\t}\n\n\t// If the crop hasn't changed, we can return early\n\tif (\n\t\tnewCrop.topLeft.x === crop.topLeft.x &&\n\t\tnewCrop.topLeft.y === crop.topLeft.y &&\n\t\tnewCrop.bottomRight.x === crop.bottomRight.x &&\n\t\tnewCrop.bottomRight.y === crop.bottomRight.y\n\t) {\n\t\treturn\n\t}\n\n\t// Adjust the shape's position to keep the crop's absolute coordinates correct\n\tconst newPoint = new Vec(tempBox.x - crop.topLeft.x * w, tempBox.y - crop.topLeft.y * h)\n\t\t.rot(shape.rotation)\n\t\t.add(shape)\n\n\treturn {\n\t\tid: shape.id,\n\t\ttype: shape.type,\n\t\tx: newPoint.x,\n\t\ty: newPoint.y,\n\t\tprops: {\n\t\t\t...shape.props,\n\t\t\tw: tempBox.w,\n\t\t\th: tempBox.h,\n\t\t\tcrop: newCrop,\n\t\t},\n\t}\n}\n\ninterface CropChange {\n\tcrop: {\n\t\ttopLeft: { x: number; y: number }\n\t\tbottomRight: { x: number; y: number }\n\t\tisCircle?: boolean\n\t}\n\tw: number\n\th: number\n\tx: number\n\ty: number\n}\n\n// Base function for calculating crop changes\nfunction calculateCropChange(\n\timageShape: TLImageShape,\n\tnewCropWidth: number,\n\tnewCropHeight: number,\n\tcenterOnCurrentCrop: boolean = true,\n\tisCircle: boolean = false\n): CropChange {\n\tconst { w, h } = getUncroppedSize(imageShape.props, imageShape.props.crop ?? getDefaultCrop())\n\tconst currentCrop = imageShape.props.crop || getDefaultCrop()\n\n\t// Calculate image and crop centers\n\tconst imageCenterX = imageShape.x + imageShape.props.w / 2\n\tconst imageCenterY = imageShape.y + imageShape.props.h / 2\n\n\tlet cropCenterX, cropCenterY\n\tif (centerOnCurrentCrop) {\n\t\tconst { x, y } = getCropCenter(currentCrop)\n\t\tcropCenterX = x\n\t\tcropCenterY = y\n\t} else {\n\t\tcropCenterX = 0.5\n\t\tcropCenterY = 0.5\n\t}\n\n\t// Create new crop\n\tconst newCrop = createCropAroundCenter(\n\t\tcropCenterX,\n\t\tcropCenterY,\n\t\tnewCropWidth,\n\t\tnewCropHeight,\n\t\tisCircle\n\t)\n\n\t// Calculate new dimensions\n\tconst croppedW = newCropWidth * w\n\tconst croppedH = newCropHeight * h\n\n\treturn {\n\t\tcrop: newCrop,\n\t\tw: croppedW,\n\t\th: croppedH,\n\t\tx: imageCenterX - croppedW / 2,\n\t\ty: imageCenterY - croppedH / 2,\n\t}\n}\n\n/** @internal */\nexport const MAX_ZOOM = 3\n\n/**\n * Calculate new crop dimensions and position when zooming\n */\nexport function getCroppedImageDataWhenZooming(\n\tzoom: number,\n\timageShape: TLImageShape,\n\tmaxZoom?: number\n): CropChange {\n\tconst oldCrop = imageShape.props.crop || getDefaultCrop()\n\tconst { width: oldWidth, height: oldHeight } = getCropDimensions(oldCrop)\n\tconst aspectRatio = oldWidth / oldHeight\n\n\t// Calculate new crop size with zoom scale\n\tconst derivedMaxZoom = maxZoom ? 1 / (1 - maxZoom) : MAX_ZOOM\n\tconst zoomScale = 1 + zoom * (derivedMaxZoom - 1)\n\tlet newWidth, newHeight\n\n\tif (aspectRatio > 1) {\n\t\tnewWidth = Math.min(1, 1 / zoomScale)\n\t\tnewHeight = newWidth / aspectRatio\n\t} else {\n\t\tnewHeight = Math.min(1, 1 / zoomScale)\n\t\tnewWidth = newHeight * aspectRatio\n\t}\n\n\t// Calculate result with base function\n\tconst result = calculateCropChange(imageShape, newWidth, newHeight, true, oldCrop.isCircle)\n\n\t// Apply zoom factor to display dimensions\n\tconst scaleFactor = Math.min(MAX_ZOOM, oldWidth / newWidth)\n\tresult.w *= scaleFactor\n\tresult.h *= scaleFactor\n\n\t// Recenter\n\tconst imageCenterX = imageShape.x + imageShape.props.w / 2\n\tconst imageCenterY = imageShape.y + imageShape.props.h / 2\n\tresult.x = imageCenterX - result.w / 2\n\tresult.y = imageCenterY - result.h / 2\n\n\treturn result\n}\n\n/**\n * Calculate new crop dimensions and position when replacing an image\n */\nexport function getCroppedImageDataForReplacedImage(\n\timageShape: TLImageShape,\n\tnewImageWidth: number,\n\tnewImageHeight: number\n): CropChange {\n\tconst defaultCrop = getDefaultCrop()\n\tconst currentCrop = imageShape.props.crop || defaultCrop\n\tconst origDisplayW = imageShape.props.w\n\tconst origDisplayH = imageShape.props.h\n\tconst newImageAspectRatio = newImageWidth / newImageHeight\n\n\tlet crop = defaultCrop\n\tlet newDisplayW = origDisplayW\n\tlet newDisplayH = origDisplayH\n\t// Compare the bounds, not the whole object: an explicit `isCircle: false` must still count\n\t// as the original crop.\n\tconst isOriginalCrop =\n\t\t!!imageShape.props.crop &&\n\t\tisEqual(imageShape.props.crop.topLeft, defaultCrop.topLeft) &&\n\t\tisEqual(imageShape.props.crop.bottomRight, defaultCrop.bottomRight) &&\n\t\t!imageShape.props.crop.isCircle\n\n\tif (isOriginalCrop) {\n\t\tnewDisplayW = origDisplayW\n\t\tnewDisplayH = (origDisplayW * newImageHeight) / newImageWidth\n\t} else {\n\t\tconst { w: uncroppedW, h: uncroppedH } = getUncroppedSize(\n\t\t\timageShape.props,\n\t\t\timageShape.props.crop || getDefaultCrop() // Use the ACTUAL current crop to correctly infer uncropped size\n\t\t)\n\t\tconst { width: cropW, height: cropH } = getCropDimensions(currentCrop)\n\t\tconst targetRatio = cropW / cropH\n\t\tconst oldImageAspectRatio = uncroppedW / uncroppedH\n\t\tlet newRelativeWidth: number\n\t\tlet newRelativeHeight: number\n\n\t\tconst currentCropCenter = getCropCenter(currentCrop)\n\n\t\t// Adjust the new crop dimensions to match the current crop zoom\n\t\tnewRelativeWidth = cropW\n\t\tconst ratioConversion = newImageAspectRatio / oldImageAspectRatio / targetRatio\n\t\tnewRelativeHeight = newRelativeWidth * ratioConversion\n\n\t\t// Check that our new crop dimensions are within the MAX_ZOOM bounds\n\t\tconst maxRatioConversion = MAX_ZOOM / (MAX_ZOOM - 1)\n\t\tif (ratioConversion > maxRatioConversion) {\n\t\t\tconst minDimension = 1 / MAX_ZOOM\n\t\t\tif (1 / newRelativeHeight < 1 / newRelativeWidth) {\n\t\t\t\tconst scale = newRelativeHeight / minDimension\n\t\t\t\tnewRelativeHeight = newRelativeHeight / scale\n\t\t\t\tnewRelativeWidth = newRelativeWidth / scale\n\t\t\t} else {\n\t\t\t\tconst scale = newRelativeWidth / minDimension\n\t\t\t\tnewRelativeWidth = newRelativeWidth / scale\n\t\t\t\tnewRelativeHeight = newRelativeHeight / scale\n\t\t\t}\n\t\t}\n\n\t\t// Ensure dimensions are within [0, 1] bounds after adjustment\n\t\tnewRelativeWidth = Math.max(0, Math.min(1, newRelativeWidth))\n\t\tnewRelativeHeight = Math.max(0, Math.min(1, newRelativeHeight))\n\n\t\t// Create the new crop object, centered around the CURRENT crop's center\n\t\tcrop = createCropAroundCenter(\n\t\t\tcurrentCropCenter.x,\n\t\t\tcurrentCropCenter.y,\n\t\t\tnewRelativeWidth,\n\t\t\tnewRelativeHeight,\n\t\t\tcurrentCrop.isCircle\n\t\t)\n\t}\n\n\t// Position so visual center stays put\n\tconst pageCenterX = imageShape.x + origDisplayW / 2\n\tconst pageCenterY = imageShape.y + origDisplayH / 2\n\n\tconst newX = pageCenterX - newDisplayW / 2\n\tconst newY = pageCenterY - newDisplayH / 2\n\n\treturn {\n\t\tcrop,\n\t\tw: newDisplayW,\n\t\th: newDisplayH,\n\t\tx: newX,\n\t\ty: newY,\n\t}\n}\n\n/**\n * Calculate new crop dimensions and position when changing aspect ratio\n */\nexport function getCroppedImageDataForAspectRatio(\n\taspectRatioOption: ASPECT_RATIO_OPTION,\n\timageShape: TLImageShape\n): CropChange {\n\t// If original aspect ratio is requested, use default crop\n\tif (aspectRatioOption === 'original') {\n\t\tconst { w, h } = getUncroppedSize(imageShape.props, imageShape.props.crop ?? getDefaultCrop())\n\t\tconst imageCenterX = imageShape.x + imageShape.props.w / 2\n\t\tconst imageCenterY = imageShape.y + imageShape.props.h / 2\n\n\t\treturn {\n\t\t\tcrop: getDefaultCrop(),\n\t\t\tw,\n\t\t\th,\n\t\t\tx: imageCenterX - w / 2,\n\t\t\ty: imageCenterY - h / 2,\n\t\t}\n\t}\n\n\t// Get target ratio and uncropped image properties\n\tconst targetRatio = ASPECT_RATIO_TO_VALUE[aspectRatioOption] // Assume valid option\n\tconst isCircle = aspectRatioOption === 'circle'\n\t// Use default crop to get uncropped size relative to the *original* image bounds\n\tconst { w: uncroppedW, h: uncroppedH } = getUncroppedSize(\n\t\timageShape.props,\n\t\timageShape.props.crop || getDefaultCrop() // Use the ACTUAL current crop to correctly infer uncropped size\n\t)\n\t// Calculate the original image aspect ratio\n\tconst imageAspectRatio = uncroppedW / uncroppedH\n\n\t// Get the current crop and its relative dimensions\n\tconst currentCrop = imageShape.props.crop || getDefaultCrop()\n\tconst { width: cropW, height: cropH } = getCropDimensions(currentCrop)\n\tconst currentCropCenter = getCropCenter(currentCrop)\n\n\t// Calculate the current crop zoom level\n\tconst currentCropZoom = Math.min(1 / cropW, 1 / cropH)\n\n\t// Calculate the relative width and height of the crop rectangle (0-1 scale)\n\t// Try to preserve the longest dimension of the current crop when changing aspect ratios\n\tlet newRelativeWidth: number\n\tlet newRelativeHeight: number\n\n\tif (imageAspectRatio === 0 || !Number.isFinite(imageAspectRatio) || targetRatio === 0) {\n\t\t// Avoid division by zero or NaN issues if image dimensions are invalid or target ratio is 0\n\t\tnewRelativeWidth = 1\n\t\tnewRelativeHeight = 1\n\t} else {\n\t\t// Get current crop dimensions in absolute units\n\t\tconst currentAbsoluteWidth = cropW * uncroppedW\n\t\tconst currentAbsoluteHeight = cropH * uncroppedH\n\n\t\t// Find the longest current dimension to preserve\n\t\tconst longestCurrentDimension = Math.max(currentAbsoluteWidth, currentAbsoluteHeight)\n\t\tconst isWidthLongest = currentAbsoluteWidth >= currentAbsoluteHeight\n\n\t\t// Calculate new dimensions preserving the longest dimension\n\t\tlet newAbsoluteWidth: number\n\t\tlet newAbsoluteHeight: number\n\n\t\tif (isWidthLongest) {\n\t\t\t// Preserve width, calculate height based on target ratio\n\t\t\tnewAbsoluteWidth = longestCurrentDimension\n\t\t\tnewAbsoluteHeight = newAbsoluteWidth / targetRatio\n\t\t} else {\n\t\t\t// Preserve height, calculate width based on target ratio\n\t\t\tnewAbsoluteHeight = longestCurrentDimension\n\t\t\tnewAbsoluteWidth = newAbsoluteHeight * targetRatio\n\t\t}\n\n\t\t// Convert back to relative coordinates\n\t\tnewRelativeWidth = newAbsoluteWidth / uncroppedW\n\t\tnewRelativeHeight = newAbsoluteHeight / uncroppedH\n\n\t\t// Clamp to image bounds and adjust if necessary\n\t\tif (newRelativeWidth > 1) {\n\t\t\t// Width exceeds bounds, clamp and recalculate height\n\t\t\tnewRelativeWidth = 1\n\t\t\tnewRelativeHeight = imageAspectRatio / targetRatio\n\t\t}\n\t\tif (newRelativeHeight > 1) {\n\t\t\t// Height exceeds bounds, clamp and recalculate width\n\t\t\tnewRelativeHeight = 1\n\t\t\tnewRelativeWidth = targetRatio / imageAspectRatio\n\t\t}\n\n\t\t// Final clamp to ensure we stay within bounds\n\t\tnewRelativeWidth = Math.max(0, Math.min(1, newRelativeWidth))\n\t\tnewRelativeHeight = Math.max(0, Math.min(1, newRelativeHeight))\n\t}\n\n\tconst newCropZoom = Math.min(1 / newRelativeWidth, 1 / newRelativeHeight)\n\t// Adjust the new crop dimensions to match the current crop zoom\n\tnewRelativeWidth *= newCropZoom / currentCropZoom\n\tnewRelativeHeight *= newCropZoom / currentCropZoom\n\n\t// Ensure dimensions are within [0, 1] bounds after adjustment\n\tnewRelativeWidth = Math.max(0, Math.min(1, newRelativeWidth))\n\tnewRelativeHeight = Math.max(0, Math.min(1, newRelativeHeight))\n\n\t// Create the new crop object, centered around the CURRENT crop's center\n\tconst newCrop = createCropAroundCenter(\n\t\tcurrentCropCenter.x,\n\t\tcurrentCropCenter.y,\n\t\tnewRelativeWidth,\n\t\tnewRelativeHeight,\n\t\tisCircle\n\t)\n\n\t// Get the actual relative dimensions from the new crop (after potential clamping)\n\tconst finalRelativeWidth = newCrop.bottomRight.x - newCrop.topLeft.x\n\tconst finalRelativeHeight = newCrop.bottomRight.y - newCrop.topLeft.y\n\n\t// Calculate the base dimensions (as if applying the new crop to the uncropped image at scale 1)\n\tconst baseW = finalRelativeWidth * uncroppedW\n\tconst baseH = finalRelativeHeight * uncroppedH\n\n\t// Determine the current effective scale of the shape\n\t// This preserves the visual size when the crop changes\n\tlet currentScale = 1.0\n\tif (cropW > 0) {\n\t\tcurrentScale = imageShape.props.w / (cropW * uncroppedW)\n\t} else if (cropH > 0) {\n\t\t// Fallback to height if width relative dimension is zero\n\t\tcurrentScale = imageShape.props.h / (cropH * uncroppedH)\n\t}\n\n\t// Apply the current scale to the base dimensions to get the final dimensions\n\tconst newW = baseW * currentScale\n\tconst newH = baseH * currentScale\n\n\t// Calculate the new top-left position (x, y) for the shape\n\t// to keep the visual center of the cropped area fixed on the page.\n\tconst currentCenterXPage = imageShape.x + imageShape.props.w / 2\n\tconst currentCenterYPage = imageShape.y + imageShape.props.h / 2\n\tconst newX = currentCenterXPage - newW / 2\n\tconst newY = currentCenterYPage - newH / 2\n\n\treturn {\n\t\tcrop: newCrop,\n\t\tw: newW,\n\t\th: newH,\n\t\tx: newX,\n\t\ty: newY,\n\t}\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -48,7 +48,7 @@ class Idle extends import_editor.StateNode {
|
|
|
48
48
|
const onlySelectedShape = this.editor.getOnlySelectedShape();
|
|
49
49
|
if (!this.editor.canEditShape(onlySelectedShape)) return;
|
|
50
50
|
this.editor.setCurrentTool("select");
|
|
51
|
-
(0, import_selectHelpers.
|
|
51
|
+
(0, import_selectHelpers.startEditingShape)(this.editor, onlySelectedShape, { info });
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
54
|
onCancel() {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/lib/shapes/text/toolStates/Idle.ts"],
|
|
4
|
-
"sourcesContent": ["import { StateNode, TLKeyboardEventInfo, TLPointerEventInfo } from '@tldraw/editor'\nimport {\n\tcancelUpdateHoveredShapeId,\n\tupdateHoveredShapeId,\n} from '../../../tools/selection-logic/updateHoveredShapeId'\nimport {
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAAmE;AACnE,kCAGO;AACP,
|
|
4
|
+
"sourcesContent": ["import { StateNode, TLKeyboardEventInfo, TLPointerEventInfo } from '@tldraw/editor'\nimport {\n\tcancelUpdateHoveredShapeId,\n\tupdateHoveredShapeId,\n} from '../../../tools/selection-logic/updateHoveredShapeId'\nimport { startEditingShape } from '../../../tools/SelectTool/selectHelpers'\n\nexport class Idle extends StateNode {\n\tstatic override id = 'idle'\n\n\toverride onPointerMove(info: TLPointerEventInfo) {\n\t\tswitch (info.target) {\n\t\t\tcase 'shape':\n\t\t\tcase 'canvas': {\n\t\t\t\tupdateHoveredShapeId(this.editor)\n\t\t\t}\n\t\t}\n\t}\n\n\toverride onPointerDown(info: TLPointerEventInfo) {\n\t\tthis.parent.transition('pointing', info)\n\t}\n\n\toverride onEnter() {\n\t\tthis.editor.setCursor({ type: 'cross', rotation: 0 })\n\t}\n\n\toverride onExit() {\n\t\tcancelUpdateHoveredShapeId(this.editor)\n\t}\n\n\toverride onKeyDown(info: TLKeyboardEventInfo) {\n\t\tif (info.key === 'Enter') {\n\t\t\tconst onlySelectedShape = this.editor.getOnlySelectedShape()\n\t\t\tif (!this.editor.canEditShape(onlySelectedShape)) return\n\t\t\tthis.editor.setCurrentTool('select')\n\t\t\tstartEditingShape(this.editor, onlySelectedShape, { info })\n\t\t}\n\t}\n\n\toverride onCancel() {\n\t\tthis.editor.setCurrentTool('select')\n\t}\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAAmE;AACnE,kCAGO;AACP,2BAAkC;AAE3B,MAAM,aAAa,wBAAU;AAAA,EACnC,OAAgB,KAAK;AAAA,EAEZ,cAAc,MAA0B;AAChD,YAAQ,KAAK,QAAQ;AAAA,MACpB,KAAK;AAAA,MACL,KAAK,UAAU;AACd,8DAAqB,KAAK,MAAM;AAAA,MACjC;AAAA,IACD;AAAA,EACD;AAAA,EAES,cAAc,MAA0B;AAChD,SAAK,OAAO,WAAW,YAAY,IAAI;AAAA,EACxC;AAAA,EAES,UAAU;AAClB,SAAK,OAAO,UAAU,EAAE,MAAM,SAAS,UAAU,EAAE,CAAC;AAAA,EACrD;AAAA,EAES,SAAS;AACjB,gEAA2B,KAAK,MAAM;AAAA,EACvC;AAAA,EAES,UAAU,MAA2B;AAC7C,QAAI,KAAK,QAAQ,SAAS;AACzB,YAAM,oBAAoB,KAAK,OAAO,qBAAqB;AAC3D,UAAI,CAAC,KAAK,OAAO,aAAa,iBAAiB,EAAG;AAClD,WAAK,OAAO,eAAe,QAAQ;AACnC,kDAAkB,KAAK,QAAQ,mBAAmB,EAAE,KAAK,CAAC;AAAA,IAC3D;AAAA,EACD;AAAA,EAES,WAAW;AACnB,SAAK,OAAO,eAAe,QAAQ;AAAA,EACpC;AACD;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|