@tldraw/editor 4.6.0-next.fecc64eee134 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-cjs/index.d.ts +493 -170
- package/dist-cjs/index.js +14 -23
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/TldrawEditor.js +3 -0
- package/dist-cjs/lib/TldrawEditor.js.map +2 -2
- package/dist-cjs/lib/components/MenuClickCapture.js +93 -47
- package/dist-cjs/lib/components/MenuClickCapture.js.map +2 -2
- package/dist-cjs/lib/components/default-components/CanvasOverlays.js +180 -0
- package/dist-cjs/lib/components/default-components/CanvasOverlays.js.map +7 -0
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js +46 -248
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +3 -3
- package/dist-cjs/lib/editor/Editor.js +142 -33
- package/dist-cjs/lib/editor/Editor.js.map +2 -2
- package/dist-cjs/lib/editor/assets/AssetUtil.js +1 -0
- package/dist-cjs/lib/editor/assets/AssetUtil.js.map +1 -1
- package/dist-cjs/lib/editor/bindings/BindingUtil.js +1 -0
- package/dist-cjs/lib/editor/bindings/BindingUtil.js.map +1 -1
- package/dist-cjs/lib/editor/managers/ClickManager/ClickManager.js +1 -0
- package/dist-cjs/lib/editor/managers/ClickManager/ClickManager.js.map +1 -1
- package/dist-cjs/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.js +98 -0
- package/dist-cjs/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.js.map +7 -0
- package/dist-cjs/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.js +1 -0
- package/dist-cjs/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.js.map +1 -1
- package/dist-cjs/lib/editor/managers/FocusManager/FocusManager.js +1 -0
- package/dist-cjs/lib/editor/managers/FocusManager/FocusManager.js.map +1 -1
- package/dist-cjs/lib/editor/managers/FontManager/FontManager.js +2 -0
- package/dist-cjs/lib/editor/managers/FontManager/FontManager.js.map +1 -1
- package/dist-cjs/lib/editor/managers/HistoryManager/HistoryManager.js +2 -0
- package/dist-cjs/lib/editor/managers/HistoryManager/HistoryManager.js.map +1 -1
- package/dist-cjs/lib/editor/managers/InputsManager/InputsManager.js +12 -0
- package/dist-cjs/lib/editor/managers/InputsManager/InputsManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/ScribbleManager/ScribbleManager.js +1 -0
- package/dist-cjs/lib/editor/managers/ScribbleManager/ScribbleManager.js.map +1 -1
- package/dist-cjs/lib/editor/managers/SnapManager/BoundsSnaps.js +1 -0
- package/dist-cjs/lib/editor/managers/SnapManager/BoundsSnaps.js.map +1 -1
- package/dist-cjs/lib/editor/managers/SnapManager/HandleSnaps.js +1 -0
- package/dist-cjs/lib/editor/managers/SnapManager/HandleSnaps.js.map +1 -1
- package/dist-cjs/lib/editor/managers/SnapManager/SnapManager.js +2 -1
- package/dist-cjs/lib/editor/managers/SnapManager/SnapManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.js +1 -0
- package/dist-cjs/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.js.map +1 -1
- package/dist-cjs/lib/editor/managers/TextManager/TextManager.js +1 -0
- package/dist-cjs/lib/editor/managers/TextManager/TextManager.js.map +1 -1
- package/dist-cjs/lib/editor/managers/ThemeManager/ThemeManager.js +1 -0
- package/dist-cjs/lib/editor/managers/ThemeManager/ThemeManager.js.map +1 -1
- package/dist-cjs/lib/editor/managers/ThemeManager/defaultThemes.js +14 -0
- package/dist-cjs/lib/editor/managers/ThemeManager/defaultThemes.js.map +2 -2
- package/dist-cjs/lib/editor/managers/TickManager/TickManager.js +1 -0
- package/dist-cjs/lib/editor/managers/TickManager/TickManager.js.map +1 -1
- package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js +2 -0
- package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js.map +1 -1
- package/dist-cjs/lib/editor/overlays/OverlayManager.js +154 -0
- package/dist-cjs/lib/editor/overlays/OverlayManager.js.map +7 -0
- package/dist-cjs/lib/editor/overlays/OverlayUtil.js +92 -0
- package/dist-cjs/lib/editor/overlays/OverlayUtil.js.map +7 -0
- package/dist-cjs/lib/editor/overlays/ShapeIndicatorOverlayUtil.js +161 -0
- package/dist-cjs/lib/editor/overlays/ShapeIndicatorOverlayUtil.js.map +7 -0
- package/dist-cjs/lib/editor/overlays/getOverlayDisplayValues.js +39 -0
- package/dist-cjs/lib/editor/overlays/getOverlayDisplayValues.js.map +7 -0
- package/dist-cjs/lib/editor/shapes/BaseFrameLikeShapeUtil.js +79 -0
- package/dist-cjs/lib/editor/shapes/BaseFrameLikeShapeUtil.js.map +7 -0
- package/dist-cjs/lib/editor/shapes/ShapeUtil.js +36 -23
- package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
- package/dist-cjs/lib/editor/shapes/group/GroupShapeUtil.js +32 -2
- package/dist-cjs/lib/editor/shapes/group/GroupShapeUtil.js.map +2 -2
- package/dist-cjs/lib/editor/tools/StateNode.js +1 -0
- package/dist-cjs/lib/editor/tools/StateNode.js.map +1 -1
- package/dist-cjs/lib/editor/types/event-types.js.map +2 -2
- package/dist-cjs/lib/exports/ExportDelay.js +1 -0
- package/dist-cjs/lib/exports/ExportDelay.js.map +1 -1
- package/dist-cjs/lib/exports/StyleEmbedder.js +1 -0
- package/dist-cjs/lib/exports/StyleEmbedder.js.map +1 -1
- package/dist-cjs/lib/exports/fetchCache.js +1 -1
- package/dist-cjs/lib/exports/fetchCache.js.map +2 -2
- package/dist-cjs/lib/exports/getSvgJsx.js +2 -1
- package/dist-cjs/lib/exports/getSvgJsx.js.map +2 -2
- package/dist-cjs/lib/hooks/EditorComponentsContext.js.map +2 -2
- package/dist-cjs/lib/hooks/useCanvasEvents.js +25 -4
- package/dist-cjs/lib/hooks/useCanvasEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/useEditorComponents.js +0 -28
- package/dist-cjs/lib/hooks/useEditorComponents.js.map +2 -2
- package/dist-cjs/lib/hooks/usePeerIds.js +1 -36
- package/dist-cjs/lib/hooks/usePeerIds.js.map +2 -2
- package/dist-cjs/lib/hooks/useShapeCulling.js +2 -1
- package/dist-cjs/lib/hooks/useShapeCulling.js.map +2 -2
- package/dist-cjs/lib/options.js +1 -0
- package/dist-cjs/lib/options.js.map +2 -2
- package/dist-cjs/lib/primitives/Vec.js +3 -0
- package/dist-cjs/lib/primitives/Vec.js.map +1 -1
- package/dist-cjs/lib/primitives/geometry/Circle2d.js +1 -0
- package/dist-cjs/lib/primitives/geometry/Circle2d.js.map +1 -1
- package/dist-cjs/lib/primitives/geometry/Ellipse2d.js +1 -0
- package/dist-cjs/lib/primitives/geometry/Ellipse2d.js.map +1 -1
- package/dist-cjs/lib/primitives/geometry/Geometry2d.js +2 -0
- package/dist-cjs/lib/primitives/geometry/Geometry2d.js.map +1 -1
- package/dist-cjs/lib/primitives/geometry/Stadium2d.js +1 -0
- package/dist-cjs/lib/primitives/geometry/Stadium2d.js.map +1 -1
- package/dist-cjs/lib/utils/EditorAtom.js +2 -0
- package/dist-cjs/lib/utils/EditorAtom.js.map +1 -1
- package/dist-cjs/lib/utils/reparenting.js +20 -7
- package/dist-cjs/lib/utils/reparenting.js.map +2 -2
- package/dist-cjs/lib/utils/sync/TLLocalSyncClient.js +5 -0
- package/dist-cjs/lib/utils/sync/TLLocalSyncClient.js.map +2 -2
- package/dist-cjs/version.js +4 -4
- package/dist-cjs/version.js.map +1 -1
- package/dist-esm/index.d.mts +493 -170
- package/dist-esm/index.mjs +21 -41
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/TldrawEditor.mjs +3 -0
- package/dist-esm/lib/TldrawEditor.mjs.map +2 -2
- package/dist-esm/lib/components/MenuClickCapture.mjs +94 -48
- package/dist-esm/lib/components/MenuClickCapture.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/CanvasOverlays.mjs +160 -0
- package/dist-esm/lib/components/default-components/CanvasOverlays.mjs.map +7 -0
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +47 -249
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +3 -3
- package/dist-esm/lib/editor/Editor.mjs +143 -35
- package/dist-esm/lib/editor/Editor.mjs.map +2 -2
- package/dist-esm/lib/editor/assets/AssetUtil.mjs +1 -0
- package/dist-esm/lib/editor/assets/AssetUtil.mjs.map +1 -1
- package/dist-esm/lib/editor/bindings/BindingUtil.mjs +1 -0
- package/dist-esm/lib/editor/bindings/BindingUtil.mjs.map +1 -1
- package/dist-esm/lib/editor/managers/ClickManager/ClickManager.mjs +1 -0
- package/dist-esm/lib/editor/managers/ClickManager/ClickManager.mjs.map +1 -1
- package/dist-esm/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.mjs +83 -0
- package/dist-esm/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.mjs.map +7 -0
- package/dist-esm/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.mjs +1 -0
- package/dist-esm/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.mjs.map +1 -1
- package/dist-esm/lib/editor/managers/FocusManager/FocusManager.mjs +1 -0
- package/dist-esm/lib/editor/managers/FocusManager/FocusManager.mjs.map +1 -1
- package/dist-esm/lib/editor/managers/FontManager/FontManager.mjs +2 -0
- package/dist-esm/lib/editor/managers/FontManager/FontManager.mjs.map +1 -1
- package/dist-esm/lib/editor/managers/HistoryManager/HistoryManager.mjs +2 -0
- package/dist-esm/lib/editor/managers/HistoryManager/HistoryManager.mjs.map +1 -1
- package/dist-esm/lib/editor/managers/InputsManager/InputsManager.mjs +12 -0
- package/dist-esm/lib/editor/managers/InputsManager/InputsManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/ScribbleManager/ScribbleManager.mjs +1 -0
- package/dist-esm/lib/editor/managers/ScribbleManager/ScribbleManager.mjs.map +1 -1
- package/dist-esm/lib/editor/managers/SnapManager/BoundsSnaps.mjs +1 -0
- package/dist-esm/lib/editor/managers/SnapManager/BoundsSnaps.mjs.map +1 -1
- package/dist-esm/lib/editor/managers/SnapManager/HandleSnaps.mjs +1 -0
- package/dist-esm/lib/editor/managers/SnapManager/HandleSnaps.mjs.map +1 -1
- package/dist-esm/lib/editor/managers/SnapManager/SnapManager.mjs +2 -1
- package/dist-esm/lib/editor/managers/SnapManager/SnapManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.mjs +1 -0
- package/dist-esm/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.mjs.map +1 -1
- package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs +1 -0
- package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs.map +1 -1
- package/dist-esm/lib/editor/managers/ThemeManager/ThemeManager.mjs +1 -0
- package/dist-esm/lib/editor/managers/ThemeManager/ThemeManager.mjs.map +1 -1
- package/dist-esm/lib/editor/managers/ThemeManager/defaultThemes.mjs +14 -0
- package/dist-esm/lib/editor/managers/ThemeManager/defaultThemes.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/TickManager/TickManager.mjs +1 -0
- package/dist-esm/lib/editor/managers/TickManager/TickManager.mjs.map +1 -1
- package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs +2 -0
- package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs.map +1 -1
- package/dist-esm/lib/editor/overlays/OverlayManager.mjs +136 -0
- package/dist-esm/lib/editor/overlays/OverlayManager.mjs.map +7 -0
- package/dist-esm/lib/editor/overlays/OverlayUtil.mjs +72 -0
- package/dist-esm/lib/editor/overlays/OverlayUtil.mjs.map +7 -0
- package/dist-esm/lib/editor/overlays/ShapeIndicatorOverlayUtil.mjs +141 -0
- package/dist-esm/lib/editor/overlays/ShapeIndicatorOverlayUtil.mjs.map +7 -0
- package/dist-esm/lib/editor/overlays/getOverlayDisplayValues.mjs +19 -0
- package/dist-esm/lib/editor/overlays/getOverlayDisplayValues.mjs.map +7 -0
- package/dist-esm/lib/editor/shapes/BaseFrameLikeShapeUtil.mjs +59 -0
- package/dist-esm/lib/editor/shapes/BaseFrameLikeShapeUtil.mjs.map +7 -0
- package/dist-esm/lib/editor/shapes/ShapeUtil.mjs +36 -23
- package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/editor/shapes/group/GroupShapeUtil.mjs +32 -2
- package/dist-esm/lib/editor/shapes/group/GroupShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/editor/tools/StateNode.mjs +1 -0
- package/dist-esm/lib/editor/tools/StateNode.mjs.map +1 -1
- package/dist-esm/lib/editor/types/event-types.mjs.map +2 -2
- package/dist-esm/lib/exports/ExportDelay.mjs +1 -0
- package/dist-esm/lib/exports/ExportDelay.mjs.map +1 -1
- package/dist-esm/lib/exports/StyleEmbedder.mjs +1 -0
- package/dist-esm/lib/exports/StyleEmbedder.mjs.map +1 -1
- package/dist-esm/lib/exports/fetchCache.mjs +2 -2
- package/dist-esm/lib/exports/fetchCache.mjs.map +2 -2
- package/dist-esm/lib/exports/getSvgJsx.mjs +2 -1
- package/dist-esm/lib/exports/getSvgJsx.mjs.map +2 -2
- package/dist-esm/lib/hooks/EditorComponentsContext.mjs.map +2 -2
- package/dist-esm/lib/hooks/useCanvasEvents.mjs +25 -4
- package/dist-esm/lib/hooks/useCanvasEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useEditorComponents.mjs +0 -28
- package/dist-esm/lib/hooks/useEditorComponents.mjs.map +2 -2
- package/dist-esm/lib/hooks/usePeerIds.mjs +2 -40
- package/dist-esm/lib/hooks/usePeerIds.mjs.map +2 -2
- package/dist-esm/lib/hooks/useShapeCulling.mjs +2 -1
- package/dist-esm/lib/hooks/useShapeCulling.mjs.map +2 -2
- package/dist-esm/lib/options.mjs +1 -0
- package/dist-esm/lib/options.mjs.map +2 -2
- package/dist-esm/lib/primitives/Vec.mjs +3 -0
- package/dist-esm/lib/primitives/Vec.mjs.map +1 -1
- package/dist-esm/lib/primitives/geometry/Circle2d.mjs +1 -0
- package/dist-esm/lib/primitives/geometry/Circle2d.mjs.map +1 -1
- package/dist-esm/lib/primitives/geometry/Ellipse2d.mjs +1 -0
- package/dist-esm/lib/primitives/geometry/Ellipse2d.mjs.map +1 -1
- package/dist-esm/lib/primitives/geometry/Geometry2d.mjs +2 -0
- package/dist-esm/lib/primitives/geometry/Geometry2d.mjs.map +1 -1
- package/dist-esm/lib/primitives/geometry/Stadium2d.mjs +1 -0
- package/dist-esm/lib/primitives/geometry/Stadium2d.mjs.map +1 -1
- package/dist-esm/lib/utils/EditorAtom.mjs +2 -0
- package/dist-esm/lib/utils/EditorAtom.mjs.map +1 -1
- package/dist-esm/lib/utils/reparenting.mjs +20 -7
- package/dist-esm/lib/utils/reparenting.mjs.map +2 -2
- package/dist-esm/lib/utils/sync/TLLocalSyncClient.mjs +5 -0
- package/dist-esm/lib/utils/sync/TLLocalSyncClient.mjs.map +2 -2
- package/dist-esm/version.mjs +4 -4
- package/dist-esm/version.mjs.map +1 -1
- package/editor.css +4 -243
- package/package.json +7 -7
- package/src/index.ts +18 -39
- package/src/lib/TldrawEditor.tsx +9 -0
- package/src/lib/components/MenuClickCapture.tsx +124 -64
- package/src/lib/components/default-components/CanvasOverlays.tsx +208 -0
- package/src/lib/components/default-components/DefaultCanvas.tsx +51 -322
- package/src/lib/editor/Editor.test.ts +3 -1
- package/src/lib/editor/Editor.ts +167 -38
- package/src/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.ts +98 -0
- package/src/lib/editor/managers/InputsManager/InputsManager.ts +12 -0
- package/src/lib/editor/managers/SnapManager/SnapManager.test.ts +13 -2
- package/src/lib/editor/managers/SnapManager/SnapManager.ts +1 -1
- package/src/lib/editor/managers/ThemeManager/defaultThemes.ts +14 -0
- package/src/lib/editor/overlays/OverlayManager.ts +183 -0
- package/src/lib/editor/overlays/OverlayUtil.ts +143 -0
- package/src/lib/editor/overlays/ShapeIndicatorOverlayUtil.ts +216 -0
- package/src/lib/editor/overlays/getOverlayDisplayValues.ts +51 -0
- package/src/lib/editor/shapes/BaseFrameLikeShapeUtil.tsx +128 -0
- package/src/lib/editor/shapes/ShapeUtil.ts +45 -26
- package/src/lib/editor/shapes/group/GroupShapeUtil.tsx +40 -3
- package/src/lib/editor/types/event-types.ts +2 -0
- package/src/lib/exports/fetchCache.ts +2 -4
- package/src/lib/exports/getSvgJsx.test.ts +3 -1
- package/src/lib/exports/getSvgJsx.tsx +2 -1
- package/src/lib/hooks/EditorComponentsContext.tsx +0 -27
- package/src/lib/hooks/useCanvasEvents.ts +45 -3
- package/src/lib/hooks/useEditorComponents.tsx +0 -28
- package/src/lib/hooks/usePeerIds.ts +6 -55
- package/src/lib/hooks/useShapeCulling.tsx +3 -1
- package/src/lib/options.ts +7 -0
- package/src/lib/utils/reparenting.ts +22 -9
- package/src/lib/utils/sync/TLLocalSyncClient.ts +3 -0
- package/src/version.ts +4 -4
- package/dist-cjs/lib/components/GeometryDebuggingView.js +0 -115
- package/dist-cjs/lib/components/GeometryDebuggingView.js.map +0 -7
- package/dist-cjs/lib/components/LiveCollaborators.js +0 -151
- package/dist-cjs/lib/components/LiveCollaborators.js.map +0 -7
- package/dist-cjs/lib/components/default-components/CanvasShapeIndicators.js +0 -227
- package/dist-cjs/lib/components/default-components/CanvasShapeIndicators.js.map +0 -7
- package/dist-cjs/lib/components/default-components/DefaultBrush.js +0 -38
- package/dist-cjs/lib/components/default-components/DefaultBrush.js.map +0 -7
- package/dist-cjs/lib/components/default-components/DefaultCollaboratorHint.js +0 -71
- package/dist-cjs/lib/components/default-components/DefaultCollaboratorHint.js.map +0 -7
- package/dist-cjs/lib/components/default-components/DefaultCursor.js +0 -59
- package/dist-cjs/lib/components/default-components/DefaultCursor.js.map +0 -7
- package/dist-cjs/lib/components/default-components/DefaultHandle.js +0 -56
- package/dist-cjs/lib/components/default-components/DefaultHandle.js.map +0 -7
- package/dist-cjs/lib/components/default-components/DefaultHandles.js +0 -28
- package/dist-cjs/lib/components/default-components/DefaultHandles.js.map +0 -7
- package/dist-cjs/lib/components/default-components/DefaultScribble.js +0 -51
- package/dist-cjs/lib/components/default-components/DefaultScribble.js.map +0 -7
- package/dist-cjs/lib/components/default-components/DefaultSelectionForeground.js +0 -69
- package/dist-cjs/lib/components/default-components/DefaultSelectionForeground.js.map +0 -7
- package/dist-cjs/lib/components/default-components/DefaultShapeIndicator.js +0 -107
- package/dist-cjs/lib/components/default-components/DefaultShapeIndicator.js.map +0 -7
- package/dist-cjs/lib/components/default-components/DefaultShapeIndicatorErrorFallback.js +0 -28
- package/dist-cjs/lib/components/default-components/DefaultShapeIndicatorErrorFallback.js.map +0 -7
- package/dist-cjs/lib/components/default-components/DefaultShapeIndicators.js +0 -101
- package/dist-cjs/lib/components/default-components/DefaultShapeIndicators.js.map +0 -7
- package/dist-cjs/lib/components/default-components/DefaultSnapIndictor.js +0 -170
- package/dist-cjs/lib/components/default-components/DefaultSnapIndictor.js.map +0 -7
- package/dist-cjs/lib/hooks/useHandleEvents.js +0 -100
- package/dist-cjs/lib/hooks/useHandleEvents.js.map +0 -7
- package/dist-cjs/lib/hooks/useSelectionEvents.js +0 -98
- package/dist-cjs/lib/hooks/useSelectionEvents.js.map +0 -7
- package/dist-esm/lib/components/GeometryDebuggingView.mjs +0 -95
- package/dist-esm/lib/components/GeometryDebuggingView.mjs.map +0 -7
- package/dist-esm/lib/components/LiveCollaborators.mjs +0 -134
- package/dist-esm/lib/components/LiveCollaborators.mjs.map +0 -7
- package/dist-esm/lib/components/default-components/CanvasShapeIndicators.mjs +0 -207
- package/dist-esm/lib/components/default-components/CanvasShapeIndicators.mjs.map +0 -7
- package/dist-esm/lib/components/default-components/DefaultBrush.mjs +0 -18
- package/dist-esm/lib/components/default-components/DefaultBrush.mjs.map +0 -7
- package/dist-esm/lib/components/default-components/DefaultCollaboratorHint.mjs +0 -41
- package/dist-esm/lib/components/default-components/DefaultCollaboratorHint.mjs.map +0 -7
- package/dist-esm/lib/components/default-components/DefaultCursor.mjs +0 -29
- package/dist-esm/lib/components/default-components/DefaultCursor.mjs.map +0 -7
- package/dist-esm/lib/components/default-components/DefaultHandle.mjs +0 -26
- package/dist-esm/lib/components/default-components/DefaultHandle.mjs.map +0 -7
- package/dist-esm/lib/components/default-components/DefaultHandles.mjs +0 -8
- package/dist-esm/lib/components/default-components/DefaultHandles.mjs.map +0 -7
- package/dist-esm/lib/components/default-components/DefaultScribble.mjs +0 -21
- package/dist-esm/lib/components/default-components/DefaultScribble.mjs.map +0 -7
- package/dist-esm/lib/components/default-components/DefaultSelectionForeground.mjs +0 -39
- package/dist-esm/lib/components/default-components/DefaultSelectionForeground.mjs.map +0 -7
- package/dist-esm/lib/components/default-components/DefaultShapeIndicator.mjs +0 -77
- package/dist-esm/lib/components/default-components/DefaultShapeIndicator.mjs.map +0 -7
- package/dist-esm/lib/components/default-components/DefaultShapeIndicatorErrorFallback.mjs +0 -8
- package/dist-esm/lib/components/default-components/DefaultShapeIndicatorErrorFallback.mjs.map +0 -7
- package/dist-esm/lib/components/default-components/DefaultShapeIndicators.mjs +0 -81
- package/dist-esm/lib/components/default-components/DefaultShapeIndicators.mjs.map +0 -7
- package/dist-esm/lib/components/default-components/DefaultSnapIndictor.mjs +0 -142
- package/dist-esm/lib/components/default-components/DefaultSnapIndictor.mjs.map +0 -7
- package/dist-esm/lib/hooks/useHandleEvents.mjs +0 -70
- package/dist-esm/lib/hooks/useHandleEvents.mjs.map +0 -7
- package/dist-esm/lib/hooks/useSelectionEvents.mjs +0 -78
- package/dist-esm/lib/hooks/useSelectionEvents.mjs.map +0 -7
- package/src/lib/components/GeometryDebuggingView.tsx +0 -108
- package/src/lib/components/LiveCollaborators.tsx +0 -174
- package/src/lib/components/default-components/CanvasShapeIndicators.tsx +0 -289
- package/src/lib/components/default-components/DefaultBrush.tsx +0 -35
- package/src/lib/components/default-components/DefaultCollaboratorHint.tsx +0 -52
- package/src/lib/components/default-components/DefaultCursor.tsx +0 -59
- package/src/lib/components/default-components/DefaultHandle.tsx +0 -42
- package/src/lib/components/default-components/DefaultHandles.tsx +0 -15
- package/src/lib/components/default-components/DefaultScribble.tsx +0 -31
- package/src/lib/components/default-components/DefaultSelectionForeground.tsx +0 -50
- package/src/lib/components/default-components/DefaultShapeIndicator.tsx +0 -104
- package/src/lib/components/default-components/DefaultShapeIndicatorErrorFallback.tsx +0 -9
- package/src/lib/components/default-components/DefaultShapeIndicators.tsx +0 -116
- package/src/lib/components/default-components/DefaultSnapIndictor.tsx +0 -174
- package/src/lib/hooks/useHandleEvents.ts +0 -88
- package/src/lib/hooks/useSelectionEvents.ts +0 -97
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { atom, computed } from '@tldraw/state'
|
|
2
|
+
import { Geometry2d } from '../../primitives/geometry/Geometry2d'
|
|
3
|
+
import { VecLike } from '../../primitives/Vec'
|
|
4
|
+
import type { Editor } from '../Editor'
|
|
5
|
+
import { OverlayUtil, TLOverlay } from './OverlayUtil'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* An active overlay util paired with the overlays it produced for the current
|
|
9
|
+
* editor state. Returned by {@link OverlayManager.getActiveOverlayEntries} so
|
|
10
|
+
* hit-test, render, and debug paths share a single scan per reactive tick.
|
|
11
|
+
*
|
|
12
|
+
* @public
|
|
13
|
+
*/
|
|
14
|
+
export interface TLOverlayEntry {
|
|
15
|
+
util: OverlayUtil
|
|
16
|
+
overlays: TLOverlay[]
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** @public */
|
|
20
|
+
export class OverlayManager {
|
|
21
|
+
constructor(public readonly editor: Editor) {}
|
|
22
|
+
|
|
23
|
+
/** @internal */
|
|
24
|
+
readonly _overlayUtils = new Map<string, OverlayUtil>()
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Register an overlay util instance. Called during editor construction.
|
|
28
|
+
* @internal
|
|
29
|
+
*/
|
|
30
|
+
registerUtil(util: OverlayUtil) {
|
|
31
|
+
const type = (util.constructor as typeof OverlayUtil).type
|
|
32
|
+
if (!type) {
|
|
33
|
+
throw new Error(`Overlay util ${util.constructor.name} is missing a static 'type' property.`)
|
|
34
|
+
}
|
|
35
|
+
if (this._overlayUtils.has(type)) {
|
|
36
|
+
throw new Error(`Duplicate overlay util type: "${type}"`)
|
|
37
|
+
}
|
|
38
|
+
this._overlayUtils.set(type, util)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Get an overlay util by type string, overlay instance, or by passing
|
|
43
|
+
* a util class as a generic parameter for type-safe lookup.
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```ts
|
|
47
|
+
* const util = editor.overlays.getOverlayUtil('brush')
|
|
48
|
+
* const util = editor.overlays.getOverlayUtil<BrushOverlayUtil>('brush')
|
|
49
|
+
* const util = editor.overlays.getOverlayUtil(myOverlay)
|
|
50
|
+
* ```
|
|
51
|
+
*
|
|
52
|
+
* @public
|
|
53
|
+
*/
|
|
54
|
+
getOverlayUtil<T extends OverlayUtil>(
|
|
55
|
+
type: T extends OverlayUtil<infer O> ? O['type'] : string
|
|
56
|
+
): T
|
|
57
|
+
getOverlayUtil<O extends TLOverlay>(overlay: O): OverlayUtil<O>
|
|
58
|
+
getOverlayUtil(arg: string | TLOverlay): OverlayUtil {
|
|
59
|
+
const type = typeof arg === 'string' ? arg : arg.type
|
|
60
|
+
const util = this._overlayUtils.get(type)
|
|
61
|
+
if (!util) throw new Error(`No overlay util found for type: "${type}"`)
|
|
62
|
+
return util
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Returns all registered overlay utils in paint order (ascending zIndex).
|
|
67
|
+
* Utils with the same zIndex preserve their registration order.
|
|
68
|
+
*
|
|
69
|
+
* @public
|
|
70
|
+
*/
|
|
71
|
+
@computed getOverlayUtilsInZOrder(): OverlayUtil[] {
|
|
72
|
+
const utils = Array.from(this._overlayUtils.values())
|
|
73
|
+
// Stable sort by zIndex (registration order breaks ties).
|
|
74
|
+
return utils
|
|
75
|
+
.map((util, i) => ({ util, i, z: util.options.zIndex ?? 0 }))
|
|
76
|
+
.sort((a, b) => a.z - b.z || a.i - b.i)
|
|
77
|
+
.map((entry) => entry.util)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Reactive list of active overlay utils paired with the overlays they
|
|
82
|
+
* produced for the current editor state, in paint order (ascending
|
|
83
|
+
* zIndex). Both the hit-test and render paths read from this single
|
|
84
|
+
* cached scan instead of each re-deriving the active set. Active utils
|
|
85
|
+
* are included even when their `getOverlays()` returns an empty array,
|
|
86
|
+
* since `render()` may still draw non-interactive UI (e.g. the selection
|
|
87
|
+
* bounding box during brushing).
|
|
88
|
+
*
|
|
89
|
+
* @public
|
|
90
|
+
*/
|
|
91
|
+
@computed getActiveOverlayEntries(): TLOverlayEntry[] {
|
|
92
|
+
const entries: TLOverlayEntry[] = []
|
|
93
|
+
for (const util of this.getOverlayUtilsInZOrder()) {
|
|
94
|
+
if (!util.isActive()) continue
|
|
95
|
+
entries.push({ util, overlays: util.getOverlays() })
|
|
96
|
+
}
|
|
97
|
+
return entries
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Reactively computed list of all currently active overlays, in paint order.
|
|
102
|
+
* @public
|
|
103
|
+
*/
|
|
104
|
+
@computed getCurrentOverlays(): TLOverlay[] {
|
|
105
|
+
const all: TLOverlay[] = []
|
|
106
|
+
for (const { overlays } of this.getActiveOverlayEntries()) {
|
|
107
|
+
all.push(...overlays)
|
|
108
|
+
}
|
|
109
|
+
return all
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Hit-test geometry cache keyed by overlay identity. Entries remain valid
|
|
113
|
+
// while getActiveOverlayEntries() keeps returning the same overlay
|
|
114
|
+
// instances; when its reactive deps change, getOverlays() emits fresh
|
|
115
|
+
// objects and stale entries fall out by GC.
|
|
116
|
+
private _geometryCache = new WeakMap<TLOverlay, Geometry2d | null>()
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Get hit-test geometry for an overlay, cached by overlay identity. Lets
|
|
120
|
+
* hit-testing on a pointermove storm skip the per-overlay geometry
|
|
121
|
+
* allocation that {@link OverlayUtil.getGeometry} would otherwise do on
|
|
122
|
+
* every call.
|
|
123
|
+
*
|
|
124
|
+
* @public
|
|
125
|
+
*/
|
|
126
|
+
getOverlayGeometry(overlay: TLOverlay): Geometry2d | null {
|
|
127
|
+
const cached = this._geometryCache.get(overlay)
|
|
128
|
+
if (cached !== undefined) return cached
|
|
129
|
+
const util = this.getOverlayUtil(overlay)
|
|
130
|
+
const geometry = util.getGeometry(overlay)
|
|
131
|
+
this._geometryCache.set(overlay, geometry)
|
|
132
|
+
return geometry
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* The currently hovered overlay id.
|
|
137
|
+
* @public
|
|
138
|
+
*/
|
|
139
|
+
private _hoveredOverlayId = atom<string | null>('hoveredOverlayId', null)
|
|
140
|
+
|
|
141
|
+
getHoveredOverlayId(): string | null {
|
|
142
|
+
return this._hoveredOverlayId.get()
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
getHoveredOverlay(): TLOverlay | null {
|
|
146
|
+
const id = this._hoveredOverlayId.get()
|
|
147
|
+
if (!id) return null
|
|
148
|
+
return this.getCurrentOverlays().find((o) => o.id === id) ?? null
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
setHoveredOverlay(id: string | null) {
|
|
152
|
+
if (id === this._hoveredOverlayId.get()) return
|
|
153
|
+
this._hoveredOverlayId.set(id)
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Hit test all active overlays at a given page point.
|
|
158
|
+
* Returns the topmost overlay whose geometry contains the point, or null.
|
|
159
|
+
* Utils are walked from highest zIndex to lowest so the overlay painted on
|
|
160
|
+
* top also wins the hit test. Within a util, overlays are walked in
|
|
161
|
+
* array order: the first overlay whose geometry contains the point wins,
|
|
162
|
+
* so utils should place highest-priority overlays first in `getOverlays`.
|
|
163
|
+
* Interactive overlays (those with geometry) are checked; non-interactive are skipped.
|
|
164
|
+
*
|
|
165
|
+
* @param point - Point in page coordinates
|
|
166
|
+
* @param margin - Hit test margin
|
|
167
|
+
* @public
|
|
168
|
+
*/
|
|
169
|
+
getOverlayAtPoint(point: VecLike, margin = 0): TLOverlay | null {
|
|
170
|
+
const entries = this.getActiveOverlayEntries()
|
|
171
|
+
for (let i = entries.length - 1; i >= 0; i--) {
|
|
172
|
+
const { overlays } = entries[i]
|
|
173
|
+
for (const overlay of overlays) {
|
|
174
|
+
const geometry = this.getOverlayGeometry(overlay)
|
|
175
|
+
if (!geometry) continue
|
|
176
|
+
if (geometry.hitTestPoint(point, geometry.isFilled ? 0 : margin, true)) {
|
|
177
|
+
return overlay
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return null
|
|
182
|
+
}
|
|
183
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { TLCursorType } from '@tldraw/tlschema'
|
|
2
|
+
import { Geometry2d } from '../../primitives/geometry/Geometry2d'
|
|
3
|
+
import type { Editor } from '../Editor'
|
|
4
|
+
import { TLPointerEventInfo } from '../types/event-types'
|
|
5
|
+
|
|
6
|
+
/** @public */
|
|
7
|
+
export interface TLOverlay<Props = Record<string, unknown>> {
|
|
8
|
+
/**
|
|
9
|
+
* Globally unique id for this overlay instance across all overlay utils.
|
|
10
|
+
* Hit-test and hover lookup key on `id` alone, so utils must namespace their
|
|
11
|
+
* ids (e.g. `'selection_fg:top_left'`, `'handle:<shapeId>:<handleId>'`) to
|
|
12
|
+
* avoid colliding with overlays from other utils.
|
|
13
|
+
*/
|
|
14
|
+
id: string
|
|
15
|
+
/** The overlay util type that owns this instance */
|
|
16
|
+
type: string
|
|
17
|
+
/** Arbitrary props for the overlay (handle id, corner name, etc.) */
|
|
18
|
+
props: Props
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** @public */
|
|
22
|
+
export interface TLOverlayUtilConstructor<U extends OverlayUtil = OverlayUtil> {
|
|
23
|
+
new (editor: Editor): U
|
|
24
|
+
type: string
|
|
25
|
+
configure<T extends TLOverlayUtilConstructor<any>>(
|
|
26
|
+
this: T,
|
|
27
|
+
options: T extends new (...args: any[]) => { options: infer Options } ? Partial<Options> : never
|
|
28
|
+
): T
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** @public */
|
|
32
|
+
export type TLAnyOverlayUtilConstructor = TLOverlayUtilConstructor<any>
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Base class for overlay utilities. Overlays are ephemeral UI elements rendered
|
|
36
|
+
* on top of the canvas (selection handles, rotation corners, shape handles, etc.).
|
|
37
|
+
*
|
|
38
|
+
* Each OverlayUtil defines a type of overlay and knows how to:
|
|
39
|
+
* - Determine when its overlays should be active (predicate)
|
|
40
|
+
* - Produce overlay instances from current editor state
|
|
41
|
+
* - Provide hit-test geometry for interactive overlays
|
|
42
|
+
* - Provide cursor style on hover
|
|
43
|
+
* - Render into a canvas 2D context
|
|
44
|
+
*
|
|
45
|
+
* @public
|
|
46
|
+
*/
|
|
47
|
+
export abstract class OverlayUtil<T extends TLOverlay = TLOverlay> {
|
|
48
|
+
constructor(public editor: Editor) {}
|
|
49
|
+
static type: string
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Options for this overlay util. Override this to provide customization options.
|
|
53
|
+
* Use {@link OverlayUtil.configure} to customize existing overlay utils.
|
|
54
|
+
*
|
|
55
|
+
* `zIndex` controls paint and hit-test order across utils — higher numbers
|
|
56
|
+
* paint on top and are hit-tested first. Ties resolve by registration order.
|
|
57
|
+
* Defaults to `0`; built-in utils use larger integers (100, 200, …) with
|
|
58
|
+
* gaps so custom utils can slot between.
|
|
59
|
+
*
|
|
60
|
+
* @public
|
|
61
|
+
*/
|
|
62
|
+
options: { zIndex?: number } = {}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Create a new overlay util class with the given options merged in.
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```ts
|
|
69
|
+
* const MyBrush = BrushOverlayUtil.configure({ fill: 'rgba(0,0,255,0.1)' })
|
|
70
|
+
* ```
|
|
71
|
+
*
|
|
72
|
+
* @public
|
|
73
|
+
*/
|
|
74
|
+
static configure<T extends TLOverlayUtilConstructor<any>>(
|
|
75
|
+
this: T,
|
|
76
|
+
options: T extends new (...args: any[]) => { options: infer Options } ? Partial<Options> : never
|
|
77
|
+
): T {
|
|
78
|
+
// @ts-expect-error -- typescript has no idea what's going on here but it's fine
|
|
79
|
+
return class extends this {
|
|
80
|
+
// @ts-expect-error
|
|
81
|
+
options = { ...this.options, ...options }
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Whether this overlay util's overlays should currently be active.
|
|
87
|
+
* Checked reactively to determine which overlays exist at any given time.
|
|
88
|
+
*/
|
|
89
|
+
abstract isActive(): boolean
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Returns the overlay instances that currently exist.
|
|
93
|
+
* Called only when `isActive()` returns true.
|
|
94
|
+
*/
|
|
95
|
+
abstract getOverlays(): T[]
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Returns hit-test geometry for an overlay instance, in page coordinates.
|
|
99
|
+
* Return null for non-interactive overlays (e.g. snap indicators, scribbles).
|
|
100
|
+
*/
|
|
101
|
+
getGeometry(_overlay: T): Geometry2d | null {
|
|
102
|
+
return null
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Returns the cursor type to show when hovering this overlay.
|
|
107
|
+
*/
|
|
108
|
+
getCursor(_overlay: T): TLCursorType | undefined {
|
|
109
|
+
return undefined
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Called when the user points down on this overlay, before the default
|
|
114
|
+
* routing runs. Acts as an interrupt: define it to take over the event.
|
|
115
|
+
*
|
|
116
|
+
* Return `false` to continue with the default behavior (e.g. the
|
|
117
|
+
* built-in rotate/resize handle transitions or shape-handle dispatch).
|
|
118
|
+
* Return `true` — or nothing at all — to skip the default. In other
|
|
119
|
+
* words, once you override this method you own the event unless you
|
|
120
|
+
* explicitly opt back in by returning `false`.
|
|
121
|
+
*/
|
|
122
|
+
onPointerDown?(overlay: T, info: TLPointerEventInfo): boolean | void
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Render all active overlays into the canvas context.
|
|
126
|
+
* The context is already transformed to page space (camera transform applied).
|
|
127
|
+
* Called reactively when overlays or editor state changes.
|
|
128
|
+
*/
|
|
129
|
+
render(_ctx: CanvasRenderingContext2D, _overlays: T[]): void {}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Optional: render all active overlays into the minimap canvas.
|
|
133
|
+
* The context is already transformed to page space (minimap camera applied),
|
|
134
|
+
* so overlays can use the same page-space coordinates as in {@link OverlayUtil.render}.
|
|
135
|
+
*
|
|
136
|
+
* `zoom` is the minimap's screen-pixels-per-page-unit, analogous to
|
|
137
|
+
* `editor.getCamera().z`; use `1 / zoom` for one-minimap-pixel line widths.
|
|
138
|
+
*
|
|
139
|
+
* Most overlays should leave this blank — only overlays that are meaningful
|
|
140
|
+
* at minimap scale (e.g. brushes, collaborator cursors) should opt in.
|
|
141
|
+
*/
|
|
142
|
+
renderMinimap(_ctx: CanvasRenderingContext2D, _overlays: T[], _zoom: number): void {}
|
|
143
|
+
}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import { computed } from '@tldraw/state'
|
|
2
|
+
import { createComputedCache } from '@tldraw/store'
|
|
3
|
+
import { TLShape, TLShapeId } from '@tldraw/tlschema'
|
|
4
|
+
import type { Editor } from '../Editor'
|
|
5
|
+
import { OverlayUtil, TLOverlay } from './OverlayUtil'
|
|
6
|
+
|
|
7
|
+
interface RelevantInstanceFlags {
|
|
8
|
+
isChangingStyle: boolean
|
|
9
|
+
isHoveringCanvas: boolean | null
|
|
10
|
+
isCoarsePointer: boolean
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** @public */
|
|
14
|
+
export interface TLShapeIndicatorOverlay extends TLOverlay {
|
|
15
|
+
props: {
|
|
16
|
+
idsToDisplay: TLShapeId[]
|
|
17
|
+
hintingShapeIds: TLShapeId[]
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const indicatorPathCache = createComputedCache(
|
|
22
|
+
'shapeIndicatorPath',
|
|
23
|
+
(editor: Editor, shape: TLShape) => {
|
|
24
|
+
const util = editor.getShapeUtil(shape)
|
|
25
|
+
return util.getIndicatorPath(shape)
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
areRecordsEqual(a, b) {
|
|
29
|
+
return a.props === b.props
|
|
30
|
+
},
|
|
31
|
+
}
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Combine every batchable shape indicator into a single page-space `Path2D` and
|
|
36
|
+
* emit one stroke call. Shapes whose indicator needs an evenodd clip (e.g.
|
|
37
|
+
* arrows with labels or complex arrowheads) can't be batched — they still
|
|
38
|
+
* stroke individually inside a save/restore with `ctx.clip` applied.
|
|
39
|
+
*
|
|
40
|
+
* Shared by {@link ShapeIndicatorOverlayUtil} and any overlay util that paints
|
|
41
|
+
* shape indicators (e.g. collaborator selections).
|
|
42
|
+
*
|
|
43
|
+
* @public
|
|
44
|
+
*/
|
|
45
|
+
export function strokeShapeIndicators(
|
|
46
|
+
editor: Editor,
|
|
47
|
+
ctx: CanvasRenderingContext2D,
|
|
48
|
+
shapeIds: TLShapeId[]
|
|
49
|
+
): void {
|
|
50
|
+
if (shapeIds.length === 0) return
|
|
51
|
+
|
|
52
|
+
const batched = new Path2D()
|
|
53
|
+
|
|
54
|
+
for (const shapeId of shapeIds) {
|
|
55
|
+
const shape = editor.getShape(shapeId)
|
|
56
|
+
if (!shape || shape.isLocked) continue
|
|
57
|
+
|
|
58
|
+
const pageTransform = editor.getShapePageTransform(shape)
|
|
59
|
+
if (!pageTransform) continue
|
|
60
|
+
|
|
61
|
+
const indicatorPath = indicatorPathCache.get(editor, shape.id)
|
|
62
|
+
if (!indicatorPath) continue
|
|
63
|
+
|
|
64
|
+
if (indicatorPath instanceof Path2D) {
|
|
65
|
+
batched.addPath(indicatorPath, pageTransform)
|
|
66
|
+
continue
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const { path, clipPath, additionalPaths } = indicatorPath
|
|
70
|
+
|
|
71
|
+
if (!clipPath) {
|
|
72
|
+
batched.addPath(path, pageTransform)
|
|
73
|
+
if (additionalPaths) {
|
|
74
|
+
for (const p of additionalPaths) batched.addPath(p, pageTransform)
|
|
75
|
+
}
|
|
76
|
+
continue
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Clipped case: fall back to an individual stroke. Rare (arrows with
|
|
80
|
+
// labels / complex arrowheads), so the extra save/restore/stroke
|
|
81
|
+
// pair per such shape isn't worth batching away.
|
|
82
|
+
ctx.save()
|
|
83
|
+
ctx.transform(
|
|
84
|
+
pageTransform.a,
|
|
85
|
+
pageTransform.b,
|
|
86
|
+
pageTransform.c,
|
|
87
|
+
pageTransform.d,
|
|
88
|
+
pageTransform.e,
|
|
89
|
+
pageTransform.f
|
|
90
|
+
)
|
|
91
|
+
ctx.save()
|
|
92
|
+
ctx.clip(clipPath, 'evenodd')
|
|
93
|
+
ctx.stroke(path)
|
|
94
|
+
ctx.restore()
|
|
95
|
+
if (additionalPaths) {
|
|
96
|
+
for (const p of additionalPaths) ctx.stroke(p)
|
|
97
|
+
}
|
|
98
|
+
ctx.restore()
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
ctx.stroke(batched)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Overlay util for shape indicators — the selection / hover / hint outlines drawn
|
|
106
|
+
* under the selection foreground. Paints local indicators in the theme's
|
|
107
|
+
* selection color.
|
|
108
|
+
*
|
|
109
|
+
* Remote collaborator selection indicators are drawn by a separate overlay util
|
|
110
|
+
* (e.g. `CollaboratorShapeIndicatorOverlayUtil` from `tldraw`) that runs at a
|
|
111
|
+
* lower z-index so peer selections appear under the local indicators.
|
|
112
|
+
*
|
|
113
|
+
* Non-interactive: contributes no hit-test geometry.
|
|
114
|
+
*
|
|
115
|
+
* @public
|
|
116
|
+
*/
|
|
117
|
+
export class ShapeIndicatorOverlayUtil extends OverlayUtil<TLShapeIndicatorOverlay> {
|
|
118
|
+
static override type = 'shape_indicator'
|
|
119
|
+
override options = { zIndex: 50, lineWidth: 1.5, hintedLineWidth: 2.5 }
|
|
120
|
+
|
|
121
|
+
// Narrow projection of instance state. Reading the full record would
|
|
122
|
+
// re-fire getOverlays on every cursor move / brush update; gating on these
|
|
123
|
+
// three booleans means we only re-fire when one of them actually flips.
|
|
124
|
+
private _instanceFlags$ = computed<RelevantInstanceFlags>(
|
|
125
|
+
'shape indicator instance flags',
|
|
126
|
+
() => {
|
|
127
|
+
const i = this.editor.getInstanceState()
|
|
128
|
+
return {
|
|
129
|
+
isChangingStyle: i.isChangingStyle,
|
|
130
|
+
isHoveringCanvas: i.isHoveringCanvas,
|
|
131
|
+
isCoarsePointer: i.isCoarsePointer,
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
isEqual: (a, b) =>
|
|
136
|
+
a.isChangingStyle === b.isChangingStyle &&
|
|
137
|
+
a.isHoveringCanvas === b.isHoveringCanvas &&
|
|
138
|
+
a.isCoarsePointer === b.isCoarsePointer,
|
|
139
|
+
}
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
override isActive(): boolean {
|
|
143
|
+
return true
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
override getOverlays(): TLShapeIndicatorOverlay[] {
|
|
147
|
+
const editor = this.editor
|
|
148
|
+
const renderingShapeIds = new Set(editor.getRenderingShapes().map((s) => s.id))
|
|
149
|
+
|
|
150
|
+
// Local selected / hovered indicators.
|
|
151
|
+
const idsToDisplay: TLShapeId[] = []
|
|
152
|
+
const { isChangingStyle, isHoveringCanvas, isCoarsePointer } = this._instanceFlags$.get()
|
|
153
|
+
const isIdleOrEditing = editor.isInAny('select.idle', 'select.editing_shape')
|
|
154
|
+
const isInSelectState = editor.isInAny(
|
|
155
|
+
'select.brushing',
|
|
156
|
+
'select.scribble_brushing',
|
|
157
|
+
'select.pointing_shape',
|
|
158
|
+
'select.pointing_selection',
|
|
159
|
+
'select.pointing_handle'
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
if (!isChangingStyle && (isIdleOrEditing || isInSelectState)) {
|
|
163
|
+
for (const id of editor.getSelectedShapeIds()) {
|
|
164
|
+
if (renderingShapeIds.has(id)) idsToDisplay.push(id)
|
|
165
|
+
}
|
|
166
|
+
if (isIdleOrEditing && isHoveringCanvas && !isCoarsePointer) {
|
|
167
|
+
const hovered = editor.getHoveredShapeId()
|
|
168
|
+
if (hovered && renderingShapeIds.has(hovered) && !idsToDisplay.includes(hovered)) {
|
|
169
|
+
idsToDisplay.push(hovered)
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Hinted shapes (drawn thicker). Already deduped at write time in
|
|
175
|
+
// `updateHintingShapeIds`, so no need to dedupe again here.
|
|
176
|
+
const hintingShapeIds: TLShapeId[] = []
|
|
177
|
+
for (const id of editor.getHintingShapeIds()) {
|
|
178
|
+
if (renderingShapeIds.has(id)) hintingShapeIds.push(id)
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (idsToDisplay.length === 0 && hintingShapeIds.length === 0) {
|
|
182
|
+
return []
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return [
|
|
186
|
+
{
|
|
187
|
+
id: 'shape_indicator',
|
|
188
|
+
type: 'shape_indicator',
|
|
189
|
+
props: { idsToDisplay, hintingShapeIds },
|
|
190
|
+
},
|
|
191
|
+
]
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
override render(ctx: CanvasRenderingContext2D, overlays: TLShapeIndicatorOverlay[]): void {
|
|
195
|
+
const overlay = overlays[0]
|
|
196
|
+
if (!overlay) return
|
|
197
|
+
|
|
198
|
+
const editor = this.editor
|
|
199
|
+
const zoom = editor.getZoomLevel()
|
|
200
|
+
const { idsToDisplay, hintingShapeIds } = overlay.props
|
|
201
|
+
|
|
202
|
+
ctx.lineCap = 'round'
|
|
203
|
+
ctx.lineJoin = 'round'
|
|
204
|
+
|
|
205
|
+
// Local selected / hovered indicators — one stroke call for the whole batch.
|
|
206
|
+
ctx.strokeStyle = editor.getCurrentTheme().colors[editor.getColorMode()].selectionStroke
|
|
207
|
+
ctx.lineWidth = this.options.lineWidth / zoom
|
|
208
|
+
strokeShapeIndicators(editor, ctx, idsToDisplay)
|
|
209
|
+
|
|
210
|
+
// Hinted shapes — thicker stroke, one call for the whole batch.
|
|
211
|
+
if (hintingShapeIds.length > 0) {
|
|
212
|
+
ctx.lineWidth = this.options.hintedLineWidth / zoom
|
|
213
|
+
strokeShapeIndicators(editor, ctx, hintingShapeIds)
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { TLTheme } from '@tldraw/tlschema'
|
|
2
|
+
import type { Editor } from '../Editor'
|
|
3
|
+
import { TLOverlay } from './OverlayUtil'
|
|
4
|
+
|
|
5
|
+
/** @public */
|
|
6
|
+
export interface OverlayOptionsWithDisplayValues<
|
|
7
|
+
Overlay extends TLOverlay,
|
|
8
|
+
DisplayValues extends object,
|
|
9
|
+
> {
|
|
10
|
+
getDefaultDisplayValues(
|
|
11
|
+
editor: Editor,
|
|
12
|
+
overlay: Overlay,
|
|
13
|
+
theme: TLTheme,
|
|
14
|
+
colorMode: 'light' | 'dark'
|
|
15
|
+
): DisplayValues
|
|
16
|
+
getCustomDisplayValues(
|
|
17
|
+
editor: Editor,
|
|
18
|
+
overlay: Overlay,
|
|
19
|
+
theme: TLTheme,
|
|
20
|
+
colorMode: 'light' | 'dark'
|
|
21
|
+
): Partial<DisplayValues>
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const dvCache = new WeakMap<
|
|
25
|
+
TLOverlay,
|
|
26
|
+
{ theme: TLTheme; colorMode: 'light' | 'dark'; values: object }
|
|
27
|
+
>()
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Get the resolved display values for an overlay, merging the base values with any overrides.
|
|
31
|
+
*
|
|
32
|
+
* @public
|
|
33
|
+
*/
|
|
34
|
+
export function getOverlayDisplayValues<Overlay extends TLOverlay, DisplayValues extends object>(
|
|
35
|
+
util: { editor: Editor; options: OverlayOptionsWithDisplayValues<Overlay, DisplayValues> },
|
|
36
|
+
overlay: Overlay,
|
|
37
|
+
colorMode?: 'light' | 'dark'
|
|
38
|
+
): DisplayValues {
|
|
39
|
+
const theme = util.editor.getCurrentTheme()
|
|
40
|
+
const resolvedColorMode = colorMode ?? util.editor.getColorMode()
|
|
41
|
+
const cached = dvCache.get(overlay)
|
|
42
|
+
if (cached && cached.theme === theme && cached.colorMode === resolvedColorMode) {
|
|
43
|
+
return cached.values as DisplayValues
|
|
44
|
+
}
|
|
45
|
+
const values = {
|
|
46
|
+
...util.options.getDefaultDisplayValues(util.editor, overlay, theme, resolvedColorMode),
|
|
47
|
+
...util.options.getCustomDisplayValues(util.editor, overlay, theme, resolvedColorMode),
|
|
48
|
+
}
|
|
49
|
+
dvCache.set(overlay, { theme, colorMode: resolvedColorMode, values })
|
|
50
|
+
return values
|
|
51
|
+
}
|