@tldraw/editor 3.16.0-internal.a478398270c6 → 3.16.0-internal.f8b97f0c414f
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 +350 -142
- package/dist-cjs/index.js +13 -6
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/TldrawEditor.js +10 -8
- package/dist-cjs/lib/TldrawEditor.js.map +2 -2
- package/dist-cjs/lib/components/MenuClickCapture.js +0 -5
- package/dist-cjs/lib/components/MenuClickCapture.js.map +2 -2
- package/dist-cjs/lib/components/SVGContainer.js +1 -1
- package/dist-cjs/lib/components/SVGContainer.js.map +2 -2
- package/dist-cjs/lib/components/Shape.js +11 -36
- package/dist-cjs/lib/components/Shape.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultBrush.js +1 -1
- package/dist-cjs/lib/components/default-components/DefaultBrush.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js +15 -24
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultCollaboratorHint.js +2 -2
- package/dist-cjs/lib/components/default-components/DefaultCollaboratorHint.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultCursor.js +1 -1
- package/dist-cjs/lib/components/default-components/DefaultCursor.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultErrorFallback.js +1 -1
- package/dist-cjs/lib/components/default-components/DefaultErrorFallback.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultGrid.js +1 -1
- package/dist-cjs/lib/components/default-components/DefaultGrid.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultHandles.js +1 -1
- package/dist-cjs/lib/components/default-components/DefaultHandles.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultScribble.js +1 -1
- package/dist-cjs/lib/components/default-components/DefaultScribble.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultShapeIndicator.js +9 -1
- package/dist-cjs/lib/components/default-components/DefaultShapeIndicator.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultShapeWrapper.js +53 -0
- package/dist-cjs/lib/components/default-components/DefaultShapeWrapper.js.map +7 -0
- package/dist-cjs/lib/components/default-components/DefaultSnapIndictor.js +1 -1
- package/dist-cjs/lib/components/default-components/DefaultSnapIndictor.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultSpinner.js +27 -15
- package/dist-cjs/lib/components/default-components/DefaultSpinner.js.map +3 -3
- package/dist-cjs/lib/config/TLUserPreferences.js +15 -3
- package/dist-cjs/lib/config/TLUserPreferences.js.map +2 -2
- package/dist-cjs/lib/editor/Editor.js +174 -180
- package/dist-cjs/lib/editor/Editor.js.map +2 -2
- package/dist-cjs/lib/editor/derivations/notVisibleShapes.js +4 -0
- package/dist-cjs/lib/editor/derivations/notVisibleShapes.js.map +2 -2
- package/dist-cjs/lib/editor/derivations/parentsToChildren.js.map +2 -2
- package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js +14 -4
- package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js.map +2 -2
- package/dist-cjs/lib/editor/shapes/BaseBoxShapeUtil.js.map +1 -1
- package/dist-cjs/lib/editor/shapes/ShapeUtil.js +23 -0
- package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
- package/dist-cjs/lib/editor/tools/BaseBoxShapeTool/BaseBoxShapeTool.js.map +2 -2
- package/dist-cjs/lib/editor/tools/StateNode.js +20 -1
- package/dist-cjs/lib/editor/tools/StateNode.js.map +2 -2
- package/dist-cjs/lib/editor/types/misc-types.js.map +1 -1
- package/dist-cjs/lib/exports/getSvgJsx.js +35 -16
- package/dist-cjs/lib/exports/getSvgJsx.js.map +2 -2
- package/dist-cjs/lib/hooks/useCanvasEvents.js +44 -35
- package/dist-cjs/lib/hooks/useCanvasEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/useDocumentEvents.js +5 -5
- package/dist-cjs/lib/hooks/useDocumentEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/useEditor.js +1 -4
- package/dist-cjs/lib/hooks/useEditor.js.map +2 -2
- package/dist-cjs/lib/hooks/useEditorComponents.js +2 -0
- package/dist-cjs/lib/hooks/useEditorComponents.js.map +2 -2
- package/dist-cjs/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.js +1 -2
- package/dist-cjs/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/useGestureEvents.js +1 -1
- package/dist-cjs/lib/hooks/useGestureEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/useHandleEvents.js +3 -3
- package/dist-cjs/lib/hooks/useHandleEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/usePassThroughMouseOverEvents.js +4 -1
- package/dist-cjs/lib/hooks/usePassThroughMouseOverEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/usePassThroughWheelEvents.js +4 -1
- package/dist-cjs/lib/hooks/usePassThroughWheelEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/useSelectionEvents.js +4 -4
- package/dist-cjs/lib/hooks/useSelectionEvents.js.map +2 -2
- package/dist-cjs/lib/{utils/nearestMultiple.js → hooks/useStateAttribute.js} +15 -14
- package/dist-cjs/lib/hooks/useStateAttribute.js.map +7 -0
- package/dist-cjs/lib/license/LicenseManager.js +140 -53
- package/dist-cjs/lib/license/LicenseManager.js.map +2 -2
- package/dist-cjs/lib/license/LicenseProvider.js +39 -1
- package/dist-cjs/lib/license/LicenseProvider.js.map +2 -2
- package/dist-cjs/lib/license/Watermark.js +75 -13
- package/dist-cjs/lib/license/Watermark.js.map +3 -3
- package/dist-cjs/lib/license/useLicenseManagerState.js.map +2 -2
- package/dist-cjs/lib/options.js +7 -0
- package/dist-cjs/lib/options.js.map +2 -2
- package/dist-cjs/lib/primitives/Box.js +3 -0
- package/dist-cjs/lib/primitives/Box.js.map +2 -2
- package/dist-cjs/lib/primitives/Vec.js +0 -4
- package/dist-cjs/lib/primitives/Vec.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Arc2d.js +1 -1
- package/dist-cjs/lib/primitives/geometry/Arc2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Circle2d.js +1 -1
- package/dist-cjs/lib/primitives/geometry/Circle2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/CubicBezier2d.js +3 -1
- package/dist-cjs/lib/primitives/geometry/CubicBezier2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Ellipse2d.js +1 -1
- package/dist-cjs/lib/primitives/geometry/Ellipse2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Geometry2d.js +50 -20
- package/dist-cjs/lib/primitives/geometry/Geometry2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Group2d.js +8 -1
- package/dist-cjs/lib/primitives/geometry/Group2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/geometry-constants.js +2 -2
- package/dist-cjs/lib/primitives/geometry/geometry-constants.js.map +2 -2
- package/dist-cjs/lib/primitives/intersect.js +4 -4
- package/dist-cjs/lib/primitives/intersect.js.map +2 -2
- package/dist-cjs/lib/primitives/utils.js +4 -0
- package/dist-cjs/lib/primitives/utils.js.map +2 -2
- package/dist-cjs/lib/utils/EditorAtom.js +45 -0
- package/dist-cjs/lib/utils/EditorAtom.js.map +7 -0
- package/dist-cjs/lib/utils/dom.js +12 -1
- package/dist-cjs/lib/utils/dom.js.map +2 -2
- package/dist-cjs/lib/utils/getPointerInfo.js +2 -2
- package/dist-cjs/lib/utils/getPointerInfo.js.map +2 -2
- package/dist-cjs/lib/utils/reparenting.js +2 -35
- package/dist-cjs/lib/utils/reparenting.js.map +3 -3
- package/dist-cjs/lib/utils/sync/TLLocalSyncClient.js +0 -1
- package/dist-cjs/lib/utils/sync/TLLocalSyncClient.js.map +2 -2
- package/dist-cjs/version.js +3 -3
- package/dist-cjs/version.js.map +1 -1
- package/dist-esm/index.d.mts +350 -142
- package/dist-esm/index.mjs +24 -8
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/TldrawEditor.mjs +11 -9
- package/dist-esm/lib/TldrawEditor.mjs.map +2 -2
- package/dist-esm/lib/components/MenuClickCapture.mjs +0 -5
- package/dist-esm/lib/components/MenuClickCapture.mjs.map +2 -2
- package/dist-esm/lib/components/SVGContainer.mjs +1 -1
- package/dist-esm/lib/components/SVGContainer.mjs.map +2 -2
- package/dist-esm/lib/components/Shape.mjs +11 -36
- package/dist-esm/lib/components/Shape.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultBrush.mjs +1 -1
- package/dist-esm/lib/components/default-components/DefaultBrush.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +16 -25
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultCollaboratorHint.mjs +2 -2
- package/dist-esm/lib/components/default-components/DefaultCollaboratorHint.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultCursor.mjs +1 -1
- package/dist-esm/lib/components/default-components/DefaultCursor.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultErrorFallback.mjs +1 -1
- package/dist-esm/lib/components/default-components/DefaultErrorFallback.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultGrid.mjs +1 -1
- package/dist-esm/lib/components/default-components/DefaultGrid.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultHandles.mjs +1 -1
- package/dist-esm/lib/components/default-components/DefaultHandles.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultScribble.mjs +1 -1
- package/dist-esm/lib/components/default-components/DefaultScribble.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultShapeIndicator.mjs +9 -1
- package/dist-esm/lib/components/default-components/DefaultShapeIndicator.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultShapeWrapper.mjs +23 -0
- package/dist-esm/lib/components/default-components/DefaultShapeWrapper.mjs.map +7 -0
- package/dist-esm/lib/components/default-components/DefaultSnapIndictor.mjs +1 -1
- package/dist-esm/lib/components/default-components/DefaultSnapIndictor.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultSpinner.mjs +17 -15
- package/dist-esm/lib/components/default-components/DefaultSpinner.mjs.map +2 -2
- package/dist-esm/lib/config/TLUserPreferences.mjs +15 -3
- package/dist-esm/lib/config/TLUserPreferences.mjs.map +2 -2
- package/dist-esm/lib/editor/Editor.mjs +174 -180
- package/dist-esm/lib/editor/Editor.mjs.map +2 -2
- package/dist-esm/lib/editor/derivations/notVisibleShapes.mjs +4 -0
- package/dist-esm/lib/editor/derivations/notVisibleShapes.mjs.map +2 -2
- package/dist-esm/lib/editor/derivations/parentsToChildren.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs +14 -4
- package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs.map +2 -2
- package/dist-esm/lib/editor/shapes/BaseBoxShapeUtil.mjs.map +1 -1
- package/dist-esm/lib/editor/shapes/ShapeUtil.mjs +23 -0
- package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/editor/tools/BaseBoxShapeTool/BaseBoxShapeTool.mjs.map +2 -2
- package/dist-esm/lib/editor/tools/StateNode.mjs +20 -1
- package/dist-esm/lib/editor/tools/StateNode.mjs.map +2 -2
- package/dist-esm/lib/exports/getSvgJsx.mjs +36 -16
- package/dist-esm/lib/exports/getSvgJsx.mjs.map +2 -2
- package/dist-esm/lib/hooks/useCanvasEvents.mjs +47 -37
- package/dist-esm/lib/hooks/useCanvasEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useDocumentEvents.mjs +11 -6
- package/dist-esm/lib/hooks/useDocumentEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useEditor.mjs +1 -4
- package/dist-esm/lib/hooks/useEditor.mjs.map +2 -2
- package/dist-esm/lib/hooks/useEditorComponents.mjs +4 -0
- package/dist-esm/lib/hooks/useEditorComponents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.mjs +2 -3
- package/dist-esm/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useGestureEvents.mjs +2 -2
- package/dist-esm/lib/hooks/useGestureEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useHandleEvents.mjs +9 -4
- package/dist-esm/lib/hooks/useHandleEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/usePassThroughMouseOverEvents.mjs +4 -1
- package/dist-esm/lib/hooks/usePassThroughMouseOverEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/usePassThroughWheelEvents.mjs +4 -1
- package/dist-esm/lib/hooks/usePassThroughWheelEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useSelectionEvents.mjs +6 -5
- package/dist-esm/lib/hooks/useSelectionEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useStateAttribute.mjs +15 -0
- package/dist-esm/lib/hooks/useStateAttribute.mjs.map +7 -0
- package/dist-esm/lib/license/LicenseManager.mjs +141 -54
- package/dist-esm/lib/license/LicenseManager.mjs.map +2 -2
- package/dist-esm/lib/license/LicenseProvider.mjs +39 -2
- package/dist-esm/lib/license/LicenseProvider.mjs.map +2 -2
- package/dist-esm/lib/license/Watermark.mjs +76 -14
- package/dist-esm/lib/license/Watermark.mjs.map +3 -3
- package/dist-esm/lib/license/useLicenseManagerState.mjs.map +2 -2
- package/dist-esm/lib/options.mjs +7 -0
- package/dist-esm/lib/options.mjs.map +2 -2
- package/dist-esm/lib/primitives/Box.mjs +4 -1
- package/dist-esm/lib/primitives/Box.mjs.map +2 -2
- package/dist-esm/lib/primitives/Vec.mjs +0 -4
- package/dist-esm/lib/primitives/Vec.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Arc2d.mjs +2 -2
- package/dist-esm/lib/primitives/geometry/Arc2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Circle2d.mjs +2 -2
- package/dist-esm/lib/primitives/geometry/Circle2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/CubicBezier2d.mjs +3 -1
- package/dist-esm/lib/primitives/geometry/CubicBezier2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Ellipse2d.mjs +2 -2
- package/dist-esm/lib/primitives/geometry/Ellipse2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Geometry2d.mjs +53 -21
- package/dist-esm/lib/primitives/geometry/Geometry2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Group2d.mjs +8 -1
- package/dist-esm/lib/primitives/geometry/Group2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/geometry-constants.mjs +2 -2
- package/dist-esm/lib/primitives/geometry/geometry-constants.mjs.map +2 -2
- package/dist-esm/lib/primitives/intersect.mjs +5 -5
- package/dist-esm/lib/primitives/intersect.mjs.map +2 -2
- package/dist-esm/lib/primitives/utils.mjs +4 -0
- package/dist-esm/lib/primitives/utils.mjs.map +2 -2
- package/dist-esm/lib/utils/EditorAtom.mjs +25 -0
- package/dist-esm/lib/utils/EditorAtom.mjs.map +7 -0
- package/dist-esm/lib/utils/dom.mjs +12 -1
- package/dist-esm/lib/utils/dom.mjs.map +2 -2
- package/dist-esm/lib/utils/getPointerInfo.mjs +2 -2
- package/dist-esm/lib/utils/getPointerInfo.mjs.map +2 -2
- package/dist-esm/lib/utils/reparenting.mjs +3 -40
- package/dist-esm/lib/utils/reparenting.mjs.map +2 -2
- package/dist-esm/lib/utils/sync/TLLocalSyncClient.mjs +0 -1
- package/dist-esm/lib/utils/sync/TLLocalSyncClient.mjs.map +2 -2
- package/dist-esm/version.mjs +3 -3
- package/dist-esm/version.mjs.map +1 -1
- package/editor.css +327 -315
- package/package.json +16 -38
- package/src/index.ts +19 -10
- package/src/lib/TldrawEditor.tsx +16 -21
- package/src/lib/components/MenuClickCapture.tsx +0 -8
- package/src/lib/components/SVGContainer.tsx +1 -1
- package/src/lib/components/Shape.tsx +12 -33
- package/src/lib/components/default-components/DefaultBrush.tsx +1 -1
- package/src/lib/components/default-components/DefaultCanvas.tsx +13 -24
- package/src/lib/components/default-components/DefaultCollaboratorHint.tsx +2 -2
- package/src/lib/components/default-components/DefaultCursor.tsx +1 -1
- package/src/lib/components/default-components/DefaultErrorFallback.tsx +1 -1
- package/src/lib/components/default-components/DefaultGrid.tsx +1 -1
- package/src/lib/components/default-components/DefaultHandles.tsx +5 -1
- package/src/lib/components/default-components/DefaultScribble.tsx +1 -1
- package/src/lib/components/default-components/DefaultShapeIndicator.tsx +6 -2
- package/src/lib/components/default-components/DefaultShapeWrapper.tsx +35 -0
- package/src/lib/components/default-components/DefaultSnapIndictor.tsx +1 -1
- package/src/lib/components/default-components/DefaultSpinner.tsx +12 -12
- package/src/lib/config/TLUserPreferences.ts +15 -1
- package/src/lib/editor/Editor.test.ts +512 -8
- package/src/lib/editor/Editor.ts +252 -267
- package/src/lib/editor/derivations/notVisibleShapes.ts +6 -0
- package/src/lib/editor/derivations/parentsToChildren.ts +1 -1
- package/src/lib/editor/managers/ClickManager/ClickManager.test.ts +15 -14
- package/src/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.test.ts +16 -15
- package/src/lib/editor/managers/FocusManager/FocusManager.test.ts +49 -48
- package/src/lib/editor/managers/FontManager/FontManager.test.ts +38 -27
- package/src/lib/editor/managers/HistoryManager/HistoryManager.test.ts +7 -6
- package/src/lib/editor/managers/ScribbleManager/ScribbleManager.test.ts +12 -11
- package/src/lib/editor/managers/SnapManager/SnapManager.test.ts +57 -50
- package/src/lib/editor/managers/TextManager/TextManager.test.ts +51 -26
- package/src/lib/editor/managers/TickManager/TickManager.test.ts +14 -13
- package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.test.ts +55 -26
- package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.ts +14 -1
- package/src/lib/editor/shapes/BaseBoxShapeUtil.tsx +2 -2
- package/src/lib/editor/shapes/ShapeUtil.ts +108 -8
- package/src/lib/editor/tools/BaseBoxShapeTool/BaseBoxShapeTool.ts +2 -1
- package/src/lib/editor/tools/StateNode.test.ts +285 -0
- package/src/lib/editor/tools/StateNode.ts +27 -1
- package/src/lib/editor/types/misc-types.ts +73 -7
- package/src/lib/exports/getSvgJsx.test.ts +874 -0
- package/src/lib/exports/getSvgJsx.tsx +78 -21
- package/src/lib/hooks/useCanvasEvents.ts +60 -47
- package/src/lib/hooks/useDocumentEvents.ts +11 -6
- package/src/lib/hooks/useEditor.tsx +6 -5
- package/src/lib/hooks/useEditorComponents.tsx +8 -2
- package/src/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.ts +2 -2
- package/src/lib/hooks/useGestureEvents.ts +2 -2
- package/src/lib/hooks/useHandleEvents.ts +9 -4
- package/src/lib/hooks/usePassThroughMouseOverEvents.ts +4 -1
- package/src/lib/hooks/usePassThroughWheelEvents.ts +6 -1
- package/src/lib/hooks/useSelectionEvents.ts +6 -5
- package/src/lib/hooks/useStateAttribute.ts +15 -0
- package/src/lib/license/LicenseManager.test.ts +724 -383
- package/src/lib/license/LicenseManager.ts +201 -58
- package/src/lib/license/LicenseProvider.tsx +74 -2
- package/src/lib/license/Watermark.test.tsx +2 -1
- package/src/lib/license/Watermark.tsx +81 -14
- package/src/lib/license/useLicenseManagerState.ts +2 -2
- package/src/lib/options.ts +8 -0
- package/src/lib/primitives/Box.test.ts +126 -0
- package/src/lib/primitives/Box.ts +10 -1
- package/src/lib/primitives/Vec.ts +0 -5
- package/src/lib/primitives/geometry/Arc2d.ts +2 -2
- package/src/lib/primitives/geometry/Circle2d.ts +2 -2
- package/src/lib/primitives/geometry/CubicBezier2d.ts +4 -1
- package/src/lib/primitives/geometry/Ellipse2d.ts +2 -2
- package/src/lib/primitives/geometry/Geometry2d.test.ts +420 -0
- package/src/lib/primitives/geometry/Geometry2d.ts +78 -21
- package/src/lib/primitives/geometry/Group2d.ts +10 -1
- package/src/lib/primitives/geometry/geometry-constants.ts +2 -1
- package/src/lib/primitives/intersect.test.ts +946 -0
- package/src/lib/primitives/intersect.ts +12 -5
- package/src/lib/primitives/utils.ts +11 -0
- package/src/lib/test/InFrontOfTheCanvas.test.tsx +187 -0
- package/src/lib/utils/EditorAtom.ts +37 -0
- package/src/lib/utils/dom.test.ts +94 -0
- package/src/lib/utils/dom.ts +38 -1
- package/src/lib/utils/getPointerInfo.ts +2 -1
- package/src/lib/utils/reparenting.ts +3 -69
- package/src/lib/utils/sync/LocalIndexedDb.test.ts +2 -1
- package/src/lib/utils/sync/TLLocalSyncClient.test.ts +15 -15
- package/src/lib/utils/sync/TLLocalSyncClient.ts +0 -1
- package/src/version.ts +3 -3
- package/dist-cjs/lib/utils/nearestMultiple.js.map +0 -7
- package/dist-esm/lib/utils/nearestMultiple.mjs +0 -14
- package/dist-esm/lib/utils/nearestMultiple.mjs.map +0 -7
- package/src/lib/test/currentToolIdMask.test.ts +0 -49
- package/src/lib/utils/nearestMultiple.ts +0 -13
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/exports/getSvgJsx.tsx"],
|
|
4
|
-
"sourcesContent": ["import { useAtom, useValue } from '@tldraw/state-react'\nimport {\n\tTLFrameShape,\n\tTLGroupShape,\n\tTLShape,\n\tTLShapeId,\n\tgetDefaultColorTheme,\n} from '@tldraw/tlschema'\nimport { hasOwnProperty, promiseWithResolve, uniqueId } from '@tldraw/utils'\nimport {\n\tComponentType,\n\tFragment,\n\tReactElement,\n\tReactNode,\n\tuseEffect,\n\tuseLayoutEffect,\n\tuseMemo,\n\tuseRef,\n} from 'react'\nimport { flushSync } from 'react-dom'\nimport { ErrorBoundary } from '../components/ErrorBoundary'\nimport { InnerShape, InnerShapeBackground } from '../components/Shape'\nimport { Editor, TLRenderingShape } from '../editor/Editor'\nimport { TLFontFace } from '../editor/managers/FontManager/FontManager'\nimport { ShapeUtil } from '../editor/shapes/ShapeUtil'\nimport {\n\tSvgExportContext,\n\tSvgExportContextProvider,\n\tSvgExportDef,\n} from '../editor/types/SvgExportContext'\nimport { TLImageExportOptions } from '../editor/types/misc-types'\nimport { useEditor } from '../hooks/useEditor'\nimport { useEvent } from '../hooks/useEvent'\nimport { suffixSafeId, useUniqueSafeId } from '../hooks/useSafeId'\nimport { Box } from '../primitives/Box'\nimport { Mat } from '../primitives/Mat'\nimport { ExportDelay } from './ExportDelay'\n\nexport function getSvgJsx(editor: Editor, ids: TLShapeId[], opts: TLImageExportOptions = {}) {\n\tif (!window.document) throw Error('No document')\n\n\tconst {\n\t\tscale = 1,\n\t\t// should we include the background in the export? or is it transparent?\n\t\tbackground = editor.getInstanceState().exportBackground,\n\t\tpadding = editor.options.defaultSvgPadding,\n\t\tpreserveAspectRatio,\n\t} = opts\n\n\tconst isDarkMode = opts.darkMode ?? editor.user.getIsDarkMode()\n\n\t// ---Figure out which shapes we need to include\n\tconst shapeIdsToInclude = editor.getShapeAndDescendantIds(ids)\n\tconst renderingShapes = editor\n\t\t.getUnorderedRenderingShapes(false)\n\t\t.filter(({ id }) => shapeIdsToInclude.has(id))\n\n\t// --- Common bounding box of all shapes\n\tlet bbox: null | Box = null\n\tif (opts.bounds) {\n\t\tbbox = opts.bounds\n\t} else {\n\t\tfor (const { id } of renderingShapes) {\n\t\t\tconst maskedPageBounds = editor.getShapeMaskedPageBounds(id)\n\t\t\tif (!maskedPageBounds) continue\n\t\t\tif (bbox) {\n\t\t\t\tbbox.union(maskedPageBounds)\n\t\t\t} else {\n\t\t\t\tbbox = maskedPageBounds.clone()\n\t\t\t}\n\t\t}\n\t}\n\n\t// no unmasked shapes to export\n\tif (!bbox) return\n\n\tconst singleFrameShapeId =\n\t\tids.length === 1 && editor.isShapeOfType<TLFrameShape>(editor.getShape(ids[0])!, 'frame')\n\t\t\t? ids[0]\n\t\t\t: null\n\tif (!singleFrameShapeId) {\n\t\t// Expand by an extra 32 pixels\n\t\tbbox.expandBy(padding)\n\t}\n\n\t// We want the svg image to be BIGGER THAN USUAL to account for image quality\n\tconst w = bbox.width * scale\n\tconst h = bbox.height * scale\n\n\ttry {\n\t\tdocument.body.focus?.() // weird but necessary\n\t} catch {\n\t\t// not implemented\n\t}\n\n\tconst exportDelay = new ExportDelay(editor.options.maxExportDelayMs)\n\n\tconst initialEffectPromise = promiseWithResolve<void>()\n\texportDelay.waitUntil(initialEffectPromise)\n\n\tconst svg = (\n\t\t<SvgExport\n\t\t\teditor={editor}\n\t\t\tpreserveAspectRatio={preserveAspectRatio}\n\t\t\tscale={scale}\n\t\t\tpixelRatio={opts.pixelRatio ?? null}\n\t\t\tbbox={bbox}\n\t\t\tbackground={background}\n\t\t\tsingleFrameShapeId={singleFrameShapeId}\n\t\t\tisDarkMode={isDarkMode}\n\t\t\trenderingShapes={renderingShapes}\n\t\t\tonMount={initialEffectPromise.resolve}\n\t\t\twaitUntil={exportDelay.waitUntil}\n\t\t>\n\t\t\t{}\n\t\t</SvgExport>\n\t)\n\n\treturn { jsx: svg, width: w, height: h, exportDelay }\n}\n\nfunction SvgExport({\n\teditor,\n\tpreserveAspectRatio,\n\tscale,\n\tpixelRatio,\n\tbbox,\n\tbackground,\n\tsingleFrameShapeId,\n\tisDarkMode,\n\trenderingShapes,\n\tonMount,\n\twaitUntil,\n}: {\n\teditor: Editor\n\tpreserveAspectRatio?: string\n\tscale: number\n\tpixelRatio: number | null\n\tbbox: Box\n\tbackground: boolean\n\tsingleFrameShapeId: TLShapeId | null\n\tisDarkMode: boolean\n\trenderingShapes: TLRenderingShape[]\n\tonMount(): void\n\twaitUntil(promise: Promise<void>): void\n}) {\n\tconst masksId = useUniqueSafeId()\n\tconst theme = getDefaultColorTheme({ isDarkMode })\n\n\tconst stateAtom = useAtom<{\n\t\tdefsById: Record<\n\t\t\tstring,\n\t\t\t{ pending: false; element: ReactNode } | { pending: true; element: Promise<ReactNode> }\n\t\t>\n\t\tshapeElements: ReactElement[] | null\n\t}>('export state', { defsById: {}, shapeElements: null })\n\tconst { defsById, shapeElements } = useValue(stateAtom)\n\n\tconst addExportDef = useEvent((def: SvgExportDef) => {\n\t\tstateAtom.update((state) => {\n\t\t\tif (hasOwnProperty(state.defsById, def.key)) return state\n\n\t\t\tconst promise = Promise.resolve(def.getElement())\n\t\t\twaitUntil(\n\t\t\t\tpromise.then((result) => {\n\t\t\t\t\tstateAtom.update((state) => ({\n\t\t\t\t\t\t...state,\n\t\t\t\t\t\tdefsById: { ...state.defsById, [def.key]: { pending: false, element: result } },\n\t\t\t\t\t}))\n\t\t\t\t})\n\t\t\t)\n\t\t\treturn {\n\t\t\t\t...state,\n\t\t\t\tdefsById: { ...state.defsById, [def.key]: { pending: true, element: promise } },\n\t\t\t}\n\t\t})\n\t})\n\n\tconst exportContext = useMemo(\n\t\t(): SvgExportContext => ({\n\t\t\tisDarkMode,\n\t\t\twaitUntil,\n\t\t\taddExportDef,\n\t\t\tscale,\n\t\t\tpixelRatio,\n\t\t\tasync resolveAssetUrl(assetId, width) {\n\t\t\t\tconst asset = editor.getAsset(assetId)\n\t\t\t\tif (!asset || (asset.type !== 'image' && asset.type !== 'video')) return null\n\n\t\t\t\treturn await editor.resolveAssetUrl(assetId, {\n\t\t\t\t\tscreenScale: scale * (width / asset.props.w),\n\t\t\t\t\tshouldResolveToOriginal: pixelRatio === null,\n\t\t\t\t\tdpr: pixelRatio ?? undefined,\n\t\t\t\t})\n\t\t\t},\n\t\t}),\n\t\t[isDarkMode, waitUntil, addExportDef, scale, pixelRatio, editor]\n\t)\n\n\tconst didRenderRef = useRef(false)\n\tuseLayoutEffect(() => {\n\t\tif (didRenderRef.current) {\n\t\t\tthrow new Error('SvgExport should only render once - do not use with react strict mode')\n\t\t}\n\t\tdidRenderRef.current = true\n\t\t;(async () => {\n\t\t\tconst shapeDefs: Record<string, { pending: false; element: ReactElement }> = {}\n\n\t\t\t// Then render everything. The shapes with assets should all hit the cache\n\t\t\tconst unorderedShapeElementPromises = renderingShapes.map(\n\t\t\t\tasync ({ id, opacity, index, backgroundIndex }) => {\n\t\t\t\t\t// Don't render the frame if we're only exporting a single frame and it's children\n\t\t\t\t\tif (id === singleFrameShapeId) return []\n\n\t\t\t\t\tconst shape = editor.getShape(id)!\n\n\t\t\t\t\tif (editor.isShapeOfType<TLGroupShape>(shape, 'group')) return []\n\n\t\t\t\t\tconst elements = []\n\t\t\t\t\tconst util = editor.getShapeUtil(shape)\n\n\t\t\t\t\tif (util.toSvg || util.toBackgroundSvg) {\n\t\t\t\t\t\t// If the shape has any sort of custom svg export, let's use that.\n\t\t\t\t\t\tconst [toSvgResult, toBackgroundSvgResult] = await Promise.all([\n\t\t\t\t\t\t\tutil.toSvg?.(shape, exportContext),\n\t\t\t\t\t\t\tutil.toBackgroundSvg?.(shape, exportContext),\n\t\t\t\t\t\t])\n\n\t\t\t\t\t\tconst pageTransform = editor.getShapePageTransform(shape)\n\t\t\t\t\t\tlet pageTransformString = pageTransform!.toCssString()\n\t\t\t\t\t\tlet scale = 1\n\t\t\t\t\t\tif ('scale' in shape.props) {\n\t\t\t\t\t\t\tif (shape.props.scale !== 1) {\n\t\t\t\t\t\t\t\tscale = shape.props.scale\n\t\t\t\t\t\t\t\tpageTransformString = `${pageTransformString} scale(${shape.props.scale}, ${shape.props.scale})`\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Create svg mask if shape has a frame as parent\n\t\t\t\t\t\tconst pageMask = editor.getShapeMask(shape.id)\n\t\t\t\t\t\tconst shapeMask = pageMask\n\t\t\t\t\t\t\t? Mat.From(Mat.Inverse(pageTransform)).applyToPoints(pageMask)\n\t\t\t\t\t\t\t: null\n\t\t\t\t\t\tconst shapeMaskId = suffixSafeId(masksId, shape.id)\n\t\t\t\t\t\tif (shapeMask) {\n\t\t\t\t\t\t\t// Create a clip path and add it to defs\n\t\t\t\t\t\t\tshapeDefs[shapeMaskId] = {\n\t\t\t\t\t\t\t\tpending: false,\n\t\t\t\t\t\t\t\telement: (\n\t\t\t\t\t\t\t\t\t<clipPath id={shapeMaskId}>\n\t\t\t\t\t\t\t\t\t\t{/* Create a polyline mask that does the clipping */}\n\t\t\t\t\t\t\t\t\t\t<path\n\t\t\t\t\t\t\t\t\t\t\td={`M${shapeMask.map(({ x, y }) => `${x / scale},${y / scale}`).join('L')}Z`}\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t</clipPath>\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (toSvgResult) {\n\t\t\t\t\t\t\telements.push({\n\t\t\t\t\t\t\t\tzIndex: index,\n\t\t\t\t\t\t\t\telement: (\n\t\t\t\t\t\t\t\t\t<g\n\t\t\t\t\t\t\t\t\t\tkey={`fg_${shape.id}`}\n\t\t\t\t\t\t\t\t\t\ttransform={pageTransformString}\n\t\t\t\t\t\t\t\t\t\topacity={opacity}\n\t\t\t\t\t\t\t\t\t\tclipPath={pageMask ? `url(#${shapeMaskId})` : undefined}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{toSvgResult}\n\t\t\t\t\t\t\t\t\t</g>\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (toBackgroundSvgResult) {\n\t\t\t\t\t\t\telements.push({\n\t\t\t\t\t\t\t\tzIndex: backgroundIndex,\n\t\t\t\t\t\t\t\telement: (\n\t\t\t\t\t\t\t\t\t<g\n\t\t\t\t\t\t\t\t\t\tkey={`bg_${shape.id}`}\n\t\t\t\t\t\t\t\t\t\ttransform={pageTransformString}\n\t\t\t\t\t\t\t\t\t\topacity={opacity}\n\t\t\t\t\t\t\t\t\t\tclipPath={pageMask ? `url(#${shapeMaskId})` : undefined}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{toBackgroundSvgResult}\n\t\t\t\t\t\t\t\t\t</g>\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// If the shape doesn't have a custom svg export, we'll use its normal HTML\n\t\t\t\t\t\t// renderer in a foreignObject.\n\t\t\t\t\t\telements.push({\n\t\t\t\t\t\t\tzIndex: index,\n\t\t\t\t\t\t\telement: (\n\t\t\t\t\t\t\t\t<ForeignObjectShape\n\t\t\t\t\t\t\t\t\tkey={`fg_${shape.id}`}\n\t\t\t\t\t\t\t\t\tshape={shape}\n\t\t\t\t\t\t\t\t\tutil={util}\n\t\t\t\t\t\t\t\t\tcomponent={InnerShape}\n\t\t\t\t\t\t\t\t\tclassName=\"tl-shape\"\n\t\t\t\t\t\t\t\t\tbbox={bbox}\n\t\t\t\t\t\t\t\t\topacity={opacity}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t})\n\n\t\t\t\t\t\tif (util.backgroundComponent) {\n\t\t\t\t\t\t\telements.push({\n\t\t\t\t\t\t\t\tzIndex: backgroundIndex,\n\t\t\t\t\t\t\t\telement: (\n\t\t\t\t\t\t\t\t\t<ForeignObjectShape\n\t\t\t\t\t\t\t\t\t\tkey={`bg_${shape.id}`}\n\t\t\t\t\t\t\t\t\t\tshape={shape}\n\t\t\t\t\t\t\t\t\t\tutil={util}\n\t\t\t\t\t\t\t\t\t\tcomponent={InnerShapeBackground}\n\t\t\t\t\t\t\t\t\t\tclassName=\"tl-shape tl-shape-background\"\n\t\t\t\t\t\t\t\t\t\tbbox={bbox}\n\t\t\t\t\t\t\t\t\t\topacity={opacity}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn elements\n\t\t\t\t}\n\t\t\t)\n\n\t\t\tconst unorderedShapeElements = (await Promise.all(unorderedShapeElementPromises)).flat()\n\n\t\t\tflushSync(() => {\n\t\t\t\tstateAtom.update((state) => ({\n\t\t\t\t\t...state,\n\t\t\t\t\tshapeElements: unorderedShapeElements\n\t\t\t\t\t\t.sort((a, b) => a.zIndex - b.zIndex)\n\t\t\t\t\t\t.map(({ element }) => element),\n\t\t\t\t\tdefsById: { ...state.defsById, ...shapeDefs },\n\t\t\t\t}))\n\t\t\t})\n\t\t})()\n\t}, [bbox, editor, exportContext, masksId, renderingShapes, singleFrameShapeId, stateAtom])\n\n\tuseEffect(() => {\n\t\tconst fontsInUse = new Set<TLFontFace>()\n\t\tfor (const { id } of renderingShapes) {\n\t\t\tfor (const font of editor.fonts.getShapeFontFaces(id)) {\n\t\t\t\tfontsInUse.add(font)\n\t\t\t}\n\t\t}\n\n\t\tfor (const font of fontsInUse) {\n\t\t\taddExportDef({\n\t\t\t\tkey: uniqueId(),\n\t\t\t\tgetElement: async () => {\n\t\t\t\t\tconst declaration = await editor.fonts.toEmbeddedCssDeclaration(font)\n\t\t\t\t\treturn <style nonce={editor.options.nonce}>{declaration}</style>\n\t\t\t\t},\n\t\t\t})\n\t\t}\n\t}, [editor, renderingShapes, addExportDef])\n\n\tuseEffect(() => {\n\t\tif (shapeElements === null) return\n\t\tonMount()\n\t}, [onMount, shapeElements])\n\n\tlet backgroundColor = background ? theme.background : 'transparent'\n\n\tif (singleFrameShapeId && background) {\n\t\tconst frameShapeUtil = editor.getShapeUtil('frame') as any as\n\t\t\t| undefined\n\t\t\t| { options: { showColors: boolean } }\n\t\tif (frameShapeUtil?.options.showColors) {\n\t\t\tconst shape = editor.getShape(singleFrameShapeId)! as TLFrameShape\n\t\t\tconst color = theme[shape.props.color]\n\t\t\tbackgroundColor = color.frame.fill\n\t\t} else {\n\t\t\tbackgroundColor = theme.solid\n\t\t}\n\t}\n\n\treturn (\n\t\t<SvgExportContextProvider editor={editor} context={exportContext}>\n\t\t\t<svg\n\t\t\t\tpreserveAspectRatio={preserveAspectRatio}\n\t\t\t\tdirection=\"ltr\"\n\t\t\t\twidth={bbox.width * scale}\n\t\t\t\theight={bbox.height * scale}\n\t\t\t\tviewBox={`${bbox.minX} ${bbox.minY} ${bbox.width} ${bbox.height}`}\n\t\t\t\tstrokeLinecap=\"round\"\n\t\t\t\tstrokeLinejoin=\"round\"\n\t\t\t\tstyle={{ backgroundColor }}\n\t\t\t\tdata-color-mode={isDarkMode ? 'dark' : 'light'}\n\t\t\t\tclassName={`tl-container tl-theme__force-sRGB ${isDarkMode ? 'tl-theme__dark' : 'tl-theme__light'}`}\n\t\t\t>\n\t\t\t\t<defs>\n\t\t\t\t\t{Object.entries(defsById).map(([key, def]) =>\n\t\t\t\t\t\tdef.pending ? null : <Fragment key={key}>{def.element}</Fragment>\n\t\t\t\t\t)}\n\t\t\t\t</defs>\n\t\t\t\t{shapeElements}\n\t\t\t</svg>\n\t\t</SvgExportContextProvider>\n\t)\n}\n\nfunction ForeignObjectShape({\n\tshape,\n\tutil,\n\tclassName,\n\tcomponent: Component,\n\tbbox,\n\topacity,\n}: {\n\tshape: TLShape\n\tutil: ShapeUtil\n\tclassName?: string\n\tcomponent: ComponentType<{ shape: TLShape; util: ShapeUtil }>\n\tbbox: Box\n\topacity: number\n}) {\n\tconst editor = useEditor()\n\n\tconst transform = Mat.Translate(-bbox.minX, -bbox.minY).multiply(\n\t\teditor.getShapePageTransform(shape.id)!\n\t)\n\n\tconst bounds = editor.getShapeGeometry(shape.id).bounds\n\tconst width = Math.max(bounds.width, 1)\n\tconst height = Math.max(bounds.height, 1)\n\n\treturn (\n\t\t<ErrorBoundary fallback={() => null}>\n\t\t\t<foreignObject\n\t\t\t\tx={bbox.minX}\n\t\t\t\ty={bbox.minY}\n\t\t\t\twidth={bbox.w}\n\t\t\t\theight={bbox.h}\n\t\t\t\tclassName=\"tl-shape-foreign-object tl-export-embed-styles\"\n\t\t\t>\n\t\t\t\t<div\n\t\t\t\t\tclassName={className}\n\t\t\t\t\tdata-shape-type={shape.type}\n\t\t\t\t\tstyle={{\n\t\t\t\t\t\tclipPath: editor.getShapeClipPath(shape.id),\n\t\t\t\t\t\ttransform: transform.toCssString(),\n\t\t\t\t\t\twidth,\n\t\t\t\t\t\theight,\n\t\t\t\t\t\topacity,\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t<Component shape={shape} util={util} />\n\t\t\t\t</div>\n\t\t\t</foreignObject>\n\t\t</ErrorBoundary>\n\t)\n}\n"],
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["import { useAtom, useValue } from '@tldraw/state-react'\nimport {\n\tTLFrameShape,\n\tTLGroupShape,\n\tTLShape,\n\tTLShapeId,\n\tgetColorValue,\n\tgetDefaultColorTheme,\n} from '@tldraw/tlschema'\nimport { hasOwnProperty, promiseWithResolve, uniqueId } from '@tldraw/utils'\nimport {\n\tComponentType,\n\tFragment,\n\tReactElement,\n\tReactNode,\n\tuseEffect,\n\tuseLayoutEffect,\n\tuseMemo,\n\tuseRef,\n} from 'react'\nimport { flushSync } from 'react-dom'\nimport { ErrorBoundary } from '../components/ErrorBoundary'\nimport { InnerShape, InnerShapeBackground } from '../components/Shape'\nimport { Editor, TLRenderingShape } from '../editor/Editor'\nimport { TLFontFace } from '../editor/managers/FontManager/FontManager'\nimport { ShapeUtil } from '../editor/shapes/ShapeUtil'\nimport {\n\tSvgExportContext,\n\tSvgExportContextProvider,\n\tSvgExportDef,\n} from '../editor/types/SvgExportContext'\nimport { TLImageExportOptions } from '../editor/types/misc-types'\nimport { useEditor } from '../hooks/useEditor'\nimport { useEvent } from '../hooks/useEvent'\nimport { suffixSafeId, useUniqueSafeId } from '../hooks/useSafeId'\nimport { Box } from '../primitives/Box'\nimport { Mat } from '../primitives/Mat'\nimport { ExportDelay } from './ExportDelay'\n\nexport function getSvgJsx(editor: Editor, ids: TLShapeId[], opts: TLImageExportOptions = {}) {\n\tif (!window.document) throw Error('No document')\n\n\tconst {\n\t\tscale = 1,\n\t\t// should we include the background in the export? or is it transparent?\n\t\tbackground = editor.getInstanceState().exportBackground,\n\t\tpadding = editor.options.defaultSvgPadding,\n\t\tpreserveAspectRatio,\n\t} = opts\n\n\tconst isDarkMode = opts.darkMode ?? editor.user.getIsDarkMode()\n\n\t// ---Figure out which shapes we need to include\n\tconst shapeIdsToInclude = editor.getShapeAndDescendantIds(ids)\n\tconst renderingShapes = editor\n\t\t.getUnorderedRenderingShapes(false)\n\t\t.filter(({ id }) => shapeIdsToInclude.has(id))\n\n\t// --- Common bounding box of all shapes\n\tconst singleFrameShapeId =\n\t\tids.length === 1 && editor.isShapeOfType<TLFrameShape>(editor.getShape(ids[0])!, 'frame')\n\t\t\t? ids[0]\n\t\t\t: null\n\n\tlet bbox: null | Box = null\n\tif (opts.bounds) {\n\t\tbbox = opts.bounds.clone().expandBy(padding)\n\t} else {\n\t\tbbox = getExportDefaultBounds(editor, renderingShapes, padding, singleFrameShapeId)\n\t}\n\n\t// no unmasked shapes to export\n\tif (!bbox) return\n\n\t// We want the svg image to be BIGGER THAN USUAL to account for image quality\n\tconst w = bbox.width * scale\n\tconst h = bbox.height * scale\n\n\ttry {\n\t\tdocument.body.focus?.() // weird but necessary\n\t} catch {\n\t\t// not implemented\n\t}\n\n\tconst exportDelay = new ExportDelay(editor.options.maxExportDelayMs)\n\n\tconst initialEffectPromise = promiseWithResolve<void>()\n\texportDelay.waitUntil(initialEffectPromise)\n\n\tconst svg = (\n\t\t<SvgExport\n\t\t\teditor={editor}\n\t\t\tpreserveAspectRatio={preserveAspectRatio}\n\t\t\tscale={scale}\n\t\t\tpixelRatio={opts.pixelRatio ?? null}\n\t\t\tbbox={bbox}\n\t\t\tbackground={background}\n\t\t\tsingleFrameShapeId={singleFrameShapeId}\n\t\t\tisDarkMode={isDarkMode}\n\t\t\trenderingShapes={renderingShapes}\n\t\t\tonMount={initialEffectPromise.resolve}\n\t\t\twaitUntil={exportDelay.waitUntil}\n\t\t>\n\t\t\t{}\n\t\t</SvgExport>\n\t)\n\n\treturn { jsx: svg, width: w, height: h, exportDelay }\n}\n\n/**\n * Calculates the default bounds for an SVG export. This function handles:\n * 1. Computing masked page bounds for each shape\n * 2. Container logic: if a shape is marked as an export bounds container and it\n * contains all other shapes, use its bounds and skip padding\n * 3. Otherwise, create a union of all shape bounds and apply padding\n *\n * The container logic is useful for cases like annotating on an image - if the image\n * contains all annotations, we want to export exactly the image bounds without extra padding.\n *\n * @param editor - The editor instance\n * @param renderingShapes - The shapes to include in the export\n * @param padding - Padding to add around the bounds (only applied if no container bounds)\n * @param singleFrameShapeId - If exporting a single frame, this is its ID (skips padding)\n * @returns The calculated bounds box, or null if no shapes to export\n */\nexport function getExportDefaultBounds(\n\teditor: Editor,\n\trenderingShapes: TLRenderingShape[],\n\tpadding: number,\n\tsingleFrameShapeId: TLShapeId | null\n) {\n\tlet isBoundedByContainer = false\n\tlet bbox: null | Box = null\n\n\tfor (const { id } of renderingShapes) {\n\t\tconst maskedPageBounds = editor.getShapeMaskedPageBounds(id)\n\t\tif (!maskedPageBounds) continue\n\n\t\t// Check if this shape is an export bounds container (e.g., an image being annotated)\n\t\tconst shape = editor.getShape(id)!\n\t\tconst isContainer = editor.getShapeUtil(shape).isExportBoundsContainer(shape)\n\n\t\tif (bbox) {\n\t\t\t// Container logic: if this is a container and it contains all shapes processed so far,\n\t\t\t// use the container's bounds instead of the union. This prevents extra padding around\n\t\t\t// things like annotated images.\n\t\t\tif (isContainer && Box.ContainsApproximately(maskedPageBounds, bbox)) {\n\t\t\t\tisBoundedByContainer = true\n\t\t\t\tbbox = maskedPageBounds.clone()\n\t\t\t} else {\n\t\t\t\t// If we were previously bounded by a container but this shape extends outside it,\n\t\t\t\t// we're no longer bounded by a container\n\t\t\t\tif (isBoundedByContainer && !Box.ContainsApproximately(bbox, maskedPageBounds)) {\n\t\t\t\t\tisBoundedByContainer = false\n\t\t\t\t}\n\t\t\t\t// Expand the bounding box to include this shape\n\t\t\t\tbbox.union(maskedPageBounds)\n\t\t\t}\n\t\t} else {\n\t\t\t// First shape sets the initial bounds\n\t\t\tisBoundedByContainer = isContainer\n\t\t\tbbox = maskedPageBounds.clone()\n\t\t}\n\t}\n\n\t// No unmasked shapes to export\n\tif (!bbox) return null\n\n\t// Only apply padding if:\n\t// - Not exporting a single frame (frames have their own padding rules)\n\t// - Not bounded by a container (containers define their own bounds precisely)\n\tif (!singleFrameShapeId && !isBoundedByContainer) {\n\t\tbbox.expandBy(padding)\n\t}\n\n\treturn bbox\n}\n\nfunction SvgExport({\n\teditor,\n\tpreserveAspectRatio,\n\tscale,\n\tpixelRatio,\n\tbbox,\n\tbackground,\n\tsingleFrameShapeId,\n\tisDarkMode,\n\trenderingShapes,\n\tonMount,\n\twaitUntil,\n}: {\n\teditor: Editor\n\tpreserveAspectRatio?: string\n\tscale: number\n\tpixelRatio: number | null\n\tbbox: Box\n\tbackground: boolean\n\tsingleFrameShapeId: TLShapeId | null\n\tisDarkMode: boolean\n\trenderingShapes: TLRenderingShape[]\n\tonMount(): void\n\twaitUntil(promise: Promise<void>): void\n}) {\n\tconst masksId = useUniqueSafeId()\n\tconst theme = getDefaultColorTheme({ isDarkMode })\n\n\tconst stateAtom = useAtom<{\n\t\tdefsById: Record<\n\t\t\tstring,\n\t\t\t{ pending: false; element: ReactNode } | { pending: true; element: Promise<ReactNode> }\n\t\t>\n\t\tshapeElements: ReactElement[] | null\n\t}>('export state', { defsById: {}, shapeElements: null })\n\tconst { defsById, shapeElements } = useValue(stateAtom)\n\n\tconst addExportDef = useEvent((def: SvgExportDef) => {\n\t\tstateAtom.update((state) => {\n\t\t\tif (hasOwnProperty(state.defsById, def.key)) return state\n\n\t\t\tconst promise = Promise.resolve(def.getElement())\n\t\t\twaitUntil(\n\t\t\t\tpromise.then((result) => {\n\t\t\t\t\tstateAtom.update((state) => ({\n\t\t\t\t\t\t...state,\n\t\t\t\t\t\tdefsById: { ...state.defsById, [def.key]: { pending: false, element: result } },\n\t\t\t\t\t}))\n\t\t\t\t})\n\t\t\t)\n\t\t\treturn {\n\t\t\t\t...state,\n\t\t\t\tdefsById: { ...state.defsById, [def.key]: { pending: true, element: promise } },\n\t\t\t}\n\t\t})\n\t})\n\n\tconst exportContext = useMemo(\n\t\t(): SvgExportContext => ({\n\t\t\tisDarkMode,\n\t\t\twaitUntil,\n\t\t\taddExportDef,\n\t\t\tscale,\n\t\t\tpixelRatio,\n\t\t\tasync resolveAssetUrl(assetId, width) {\n\t\t\t\tconst asset = editor.getAsset(assetId)\n\t\t\t\tif (!asset || (asset.type !== 'image' && asset.type !== 'video')) return null\n\n\t\t\t\treturn await editor.resolveAssetUrl(assetId, {\n\t\t\t\t\tscreenScale: scale * (width / asset.props.w),\n\t\t\t\t\tshouldResolveToOriginal: pixelRatio === null,\n\t\t\t\t\tdpr: pixelRatio ?? undefined,\n\t\t\t\t})\n\t\t\t},\n\t\t}),\n\t\t[isDarkMode, waitUntil, addExportDef, scale, pixelRatio, editor]\n\t)\n\n\tconst didRenderRef = useRef(false)\n\tuseLayoutEffect(() => {\n\t\tif (didRenderRef.current) {\n\t\t\tthrow new Error('SvgExport should only render once - do not use with react strict mode')\n\t\t}\n\t\tdidRenderRef.current = true\n\t\t;(async () => {\n\t\t\tconst shapeDefs: Record<string, { pending: false; element: ReactElement }> = {}\n\n\t\t\t// Then render everything. The shapes with assets should all hit the cache\n\t\t\tconst unorderedShapeElementPromises = renderingShapes.map(\n\t\t\t\tasync ({ id, opacity, index, backgroundIndex }) => {\n\t\t\t\t\t// Don't render the frame if we're only exporting a single frame and it's children\n\t\t\t\t\tif (id === singleFrameShapeId) return []\n\n\t\t\t\t\tconst shape = editor.getShape(id)!\n\n\t\t\t\t\tif (editor.isShapeOfType<TLGroupShape>(shape, 'group')) return []\n\n\t\t\t\t\tconst elements = []\n\t\t\t\t\tconst util = editor.getShapeUtil(shape)\n\n\t\t\t\t\tif (util.toSvg || util.toBackgroundSvg) {\n\t\t\t\t\t\t// If the shape has any sort of custom svg export, let's use that.\n\t\t\t\t\t\tconst [toSvgResult, toBackgroundSvgResult] = await Promise.all([\n\t\t\t\t\t\t\tutil.toSvg?.(shape, exportContext),\n\t\t\t\t\t\t\tutil.toBackgroundSvg?.(shape, exportContext),\n\t\t\t\t\t\t])\n\n\t\t\t\t\t\tconst pageTransform = editor.getShapePageTransform(shape)\n\t\t\t\t\t\tlet pageTransformString = pageTransform!.toCssString()\n\t\t\t\t\t\tlet scale = 1\n\t\t\t\t\t\tif ('scale' in shape.props) {\n\t\t\t\t\t\t\tif (shape.props.scale !== 1) {\n\t\t\t\t\t\t\t\tscale = shape.props.scale\n\t\t\t\t\t\t\t\tpageTransformString = `${pageTransformString} scale(${shape.props.scale}, ${shape.props.scale})`\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Create svg mask if shape has a frame as parent\n\t\t\t\t\t\tconst pageMask = editor.getShapeMask(shape.id)\n\t\t\t\t\t\tconst shapeMask = pageMask\n\t\t\t\t\t\t\t? Mat.From(Mat.Inverse(pageTransform)).applyToPoints(pageMask)\n\t\t\t\t\t\t\t: null\n\t\t\t\t\t\tconst shapeMaskId = suffixSafeId(masksId, shape.id)\n\t\t\t\t\t\tif (shapeMask) {\n\t\t\t\t\t\t\t// Create a clip path and add it to defs\n\t\t\t\t\t\t\tshapeDefs[shapeMaskId] = {\n\t\t\t\t\t\t\t\tpending: false,\n\t\t\t\t\t\t\t\telement: (\n\t\t\t\t\t\t\t\t\t<clipPath id={shapeMaskId}>\n\t\t\t\t\t\t\t\t\t\t{/* Create a polyline mask that does the clipping */}\n\t\t\t\t\t\t\t\t\t\t<path\n\t\t\t\t\t\t\t\t\t\t\td={`M${shapeMask.map(({ x, y }) => `${x / scale},${y / scale}`).join('L')}Z`}\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t</clipPath>\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (toSvgResult) {\n\t\t\t\t\t\t\telements.push({\n\t\t\t\t\t\t\t\tzIndex: index,\n\t\t\t\t\t\t\t\telement: (\n\t\t\t\t\t\t\t\t\t<g\n\t\t\t\t\t\t\t\t\t\tkey={`fg_${shape.id}`}\n\t\t\t\t\t\t\t\t\t\ttransform={pageTransformString}\n\t\t\t\t\t\t\t\t\t\topacity={opacity}\n\t\t\t\t\t\t\t\t\t\tclipPath={pageMask ? `url(#${shapeMaskId})` : undefined}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{toSvgResult}\n\t\t\t\t\t\t\t\t\t</g>\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (toBackgroundSvgResult) {\n\t\t\t\t\t\t\telements.push({\n\t\t\t\t\t\t\t\tzIndex: backgroundIndex,\n\t\t\t\t\t\t\t\telement: (\n\t\t\t\t\t\t\t\t\t<g\n\t\t\t\t\t\t\t\t\t\tkey={`bg_${shape.id}`}\n\t\t\t\t\t\t\t\t\t\ttransform={pageTransformString}\n\t\t\t\t\t\t\t\t\t\topacity={opacity}\n\t\t\t\t\t\t\t\t\t\tclipPath={pageMask ? `url(#${shapeMaskId})` : undefined}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{toBackgroundSvgResult}\n\t\t\t\t\t\t\t\t\t</g>\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// If the shape doesn't have a custom svg export, we'll use its normal HTML\n\t\t\t\t\t\t// renderer in a foreignObject.\n\t\t\t\t\t\telements.push({\n\t\t\t\t\t\t\tzIndex: index,\n\t\t\t\t\t\t\telement: (\n\t\t\t\t\t\t\t\t<ForeignObjectShape\n\t\t\t\t\t\t\t\t\tkey={`fg_${shape.id}`}\n\t\t\t\t\t\t\t\t\tshape={shape}\n\t\t\t\t\t\t\t\t\tutil={util}\n\t\t\t\t\t\t\t\t\tcomponent={InnerShape}\n\t\t\t\t\t\t\t\t\tclassName=\"tl-shape\"\n\t\t\t\t\t\t\t\t\tbbox={bbox}\n\t\t\t\t\t\t\t\t\topacity={opacity}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t})\n\n\t\t\t\t\t\tif (util.backgroundComponent) {\n\t\t\t\t\t\t\telements.push({\n\t\t\t\t\t\t\t\tzIndex: backgroundIndex,\n\t\t\t\t\t\t\t\telement: (\n\t\t\t\t\t\t\t\t\t<ForeignObjectShape\n\t\t\t\t\t\t\t\t\t\tkey={`bg_${shape.id}`}\n\t\t\t\t\t\t\t\t\t\tshape={shape}\n\t\t\t\t\t\t\t\t\t\tutil={util}\n\t\t\t\t\t\t\t\t\t\tcomponent={InnerShapeBackground}\n\t\t\t\t\t\t\t\t\t\tclassName=\"tl-shape tl-shape-background\"\n\t\t\t\t\t\t\t\t\t\tbbox={bbox}\n\t\t\t\t\t\t\t\t\t\topacity={opacity}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn elements\n\t\t\t\t}\n\t\t\t)\n\n\t\t\tconst unorderedShapeElements = (await Promise.all(unorderedShapeElementPromises)).flat()\n\n\t\t\tflushSync(() => {\n\t\t\t\tstateAtom.update((state) => ({\n\t\t\t\t\t...state,\n\t\t\t\t\tshapeElements: unorderedShapeElements\n\t\t\t\t\t\t.sort((a, b) => a.zIndex - b.zIndex)\n\t\t\t\t\t\t.map(({ element }) => element),\n\t\t\t\t\tdefsById: { ...state.defsById, ...shapeDefs },\n\t\t\t\t}))\n\t\t\t})\n\t\t})()\n\t}, [bbox, editor, exportContext, masksId, renderingShapes, singleFrameShapeId, stateAtom])\n\n\tuseEffect(() => {\n\t\tconst fontsInUse = new Set<TLFontFace>()\n\t\tfor (const { id } of renderingShapes) {\n\t\t\tfor (const font of editor.fonts.getShapeFontFaces(id)) {\n\t\t\t\tfontsInUse.add(font)\n\t\t\t}\n\t\t}\n\n\t\tfor (const font of fontsInUse) {\n\t\t\taddExportDef({\n\t\t\t\tkey: uniqueId(),\n\t\t\t\tgetElement: async () => {\n\t\t\t\t\tconst declaration = await editor.fonts.toEmbeddedCssDeclaration(font)\n\t\t\t\t\treturn <style nonce={editor.options.nonce}>{declaration}</style>\n\t\t\t\t},\n\t\t\t})\n\t\t}\n\t}, [editor, renderingShapes, addExportDef])\n\n\tuseEffect(() => {\n\t\tif (shapeElements === null) return\n\t\tonMount()\n\t}, [onMount, shapeElements])\n\n\tlet backgroundColor = background ? theme.background : 'transparent'\n\n\tif (singleFrameShapeId && background) {\n\t\tconst frameShapeUtil = editor.getShapeUtil('frame') as any as\n\t\t\t| undefined\n\t\t\t| { options: { showColors: boolean } }\n\t\tif (frameShapeUtil?.options.showColors) {\n\t\t\tconst shape = editor.getShape(singleFrameShapeId)! as TLFrameShape\n\t\t\tbackgroundColor = getColorValue(theme, shape.props.color, 'frameFill')\n\t\t} else {\n\t\t\tbackgroundColor = theme.solid\n\t\t}\n\t}\n\n\treturn (\n\t\t<SvgExportContextProvider editor={editor} context={exportContext}>\n\t\t\t<svg\n\t\t\t\tpreserveAspectRatio={preserveAspectRatio}\n\t\t\t\tdirection=\"ltr\"\n\t\t\t\twidth={bbox.width * scale}\n\t\t\t\theight={bbox.height * scale}\n\t\t\t\tviewBox={`${bbox.minX} ${bbox.minY} ${bbox.width} ${bbox.height}`}\n\t\t\t\tstrokeLinecap=\"round\"\n\t\t\t\tstrokeLinejoin=\"round\"\n\t\t\t\tstyle={{ backgroundColor }}\n\t\t\t\tdata-color-mode={isDarkMode ? 'dark' : 'light'}\n\t\t\t\tclassName={`tl-container tl-theme__force-sRGB ${isDarkMode ? 'tl-theme__dark' : 'tl-theme__light'}`}\n\t\t\t>\n\t\t\t\t<defs>\n\t\t\t\t\t{Object.entries(defsById).map(([key, def]) =>\n\t\t\t\t\t\tdef.pending ? null : <Fragment key={key}>{def.element}</Fragment>\n\t\t\t\t\t)}\n\t\t\t\t</defs>\n\t\t\t\t{shapeElements}\n\t\t\t</svg>\n\t\t</SvgExportContextProvider>\n\t)\n}\n\nfunction ForeignObjectShape({\n\tshape,\n\tutil,\n\tclassName,\n\tcomponent: Component,\n\tbbox,\n\topacity,\n}: {\n\tshape: TLShape\n\tutil: ShapeUtil\n\tclassName?: string\n\tcomponent: ComponentType<{ shape: TLShape; util: ShapeUtil }>\n\tbbox: Box\n\topacity: number\n}) {\n\tconst editor = useEditor()\n\n\tconst transform = Mat.Translate(-bbox.minX, -bbox.minY).multiply(\n\t\teditor.getShapePageTransform(shape.id)!\n\t)\n\n\tconst bounds = editor.getShapeGeometry(shape.id).bounds\n\tconst width = Math.max(bounds.width, 1)\n\tconst height = Math.max(bounds.height, 1)\n\n\treturn (\n\t\t<ErrorBoundary fallback={() => null}>\n\t\t\t<foreignObject\n\t\t\t\tx={bbox.minX}\n\t\t\t\ty={bbox.minY}\n\t\t\t\twidth={bbox.w}\n\t\t\t\theight={bbox.h}\n\t\t\t\tclassName=\"tl-shape-foreign-object tl-export-embed-styles\"\n\t\t\t>\n\t\t\t\t<div\n\t\t\t\t\tclassName={className}\n\t\t\t\t\tdata-shape-type={shape.type}\n\t\t\t\t\tstyle={{\n\t\t\t\t\t\tclipPath: editor.getShapeClipPath(shape.id),\n\t\t\t\t\t\ttransform: transform.toCssString(),\n\t\t\t\t\t\twidth,\n\t\t\t\t\t\theight,\n\t\t\t\t\t\topacity,\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t<Component shape={shape} util={util} />\n\t\t\t\t</div>\n\t\t\t</foreignObject>\n\t\t</ErrorBoundary>\n\t)\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["state", "scale"]
|
|
7
7
|
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { useValue } from "@tldraw/state-react";
|
|
2
|
-
import { useMemo } from "react";
|
|
2
|
+
import { useEffect, useMemo } from "react";
|
|
3
3
|
import { RIGHT_MOUSE_BUTTON } from "../constants.mjs";
|
|
4
4
|
import {
|
|
5
|
+
markEventAsHandled,
|
|
5
6
|
preventDefault,
|
|
6
7
|
releasePointerCapture,
|
|
7
8
|
setPointerCapture,
|
|
8
|
-
|
|
9
|
+
wasEventAlreadyHandled
|
|
9
10
|
} from "../utils/dom.mjs";
|
|
10
11
|
import { getPointerInfo } from "../utils/getPointerInfo.mjs";
|
|
11
12
|
import { useEditor } from "./useEditor.mjs";
|
|
@@ -14,9 +15,8 @@ function useCanvasEvents() {
|
|
|
14
15
|
const currentTool = useValue("current tool", () => editor.getCurrentTool(), [editor]);
|
|
15
16
|
const events = useMemo(
|
|
16
17
|
function canvasEvents() {
|
|
17
|
-
let lastX, lastY;
|
|
18
18
|
function onPointerDown(e) {
|
|
19
|
-
if (e
|
|
19
|
+
if (wasEventAlreadyHandled(e)) return;
|
|
20
20
|
if (e.button === RIGHT_MOUSE_BUTTON) {
|
|
21
21
|
editor.dispatch({
|
|
22
22
|
type: "pointer",
|
|
@@ -35,26 +35,9 @@ function useCanvasEvents() {
|
|
|
35
35
|
...getPointerInfo(e)
|
|
36
36
|
});
|
|
37
37
|
}
|
|
38
|
-
function onPointerMove(e) {
|
|
39
|
-
if (e.isKilled) return;
|
|
40
|
-
if (e.clientX === lastX && e.clientY === lastY) return;
|
|
41
|
-
lastX = e.clientX;
|
|
42
|
-
lastY = e.clientY;
|
|
43
|
-
const events2 = currentTool.useCoalescedEvents && e.nativeEvent.getCoalescedEvents ? e.nativeEvent.getCoalescedEvents() : [e];
|
|
44
|
-
for (const singleEvent of events2) {
|
|
45
|
-
editor.dispatch({
|
|
46
|
-
type: "pointer",
|
|
47
|
-
target: "canvas",
|
|
48
|
-
name: "pointer_move",
|
|
49
|
-
...getPointerInfo(singleEvent)
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
38
|
function onPointerUp(e) {
|
|
54
|
-
if (e
|
|
39
|
+
if (wasEventAlreadyHandled(e)) return;
|
|
55
40
|
if (e.button !== 0 && e.button !== 1 && e.button !== 2 && e.button !== 5) return;
|
|
56
|
-
lastX = e.clientX;
|
|
57
|
-
lastY = e.clientY;
|
|
58
41
|
releasePointerCapture(e.currentTarget, e);
|
|
59
42
|
editor.dispatch({
|
|
60
43
|
type: "pointer",
|
|
@@ -64,40 +47,44 @@ function useCanvasEvents() {
|
|
|
64
47
|
});
|
|
65
48
|
}
|
|
66
49
|
function onPointerEnter(e) {
|
|
67
|
-
if (e
|
|
50
|
+
if (wasEventAlreadyHandled(e)) return;
|
|
68
51
|
if (editor.getInstanceState().isPenMode && e.pointerType !== "pen") return;
|
|
69
52
|
const canHover = e.pointerType === "mouse" || e.pointerType === "pen";
|
|
70
53
|
editor.updateInstanceState({ isHoveringCanvas: canHover ? true : null });
|
|
71
54
|
}
|
|
72
55
|
function onPointerLeave(e) {
|
|
73
|
-
if (e
|
|
56
|
+
if (wasEventAlreadyHandled(e)) return;
|
|
74
57
|
if (editor.getInstanceState().isPenMode && e.pointerType !== "pen") return;
|
|
75
58
|
const canHover = e.pointerType === "mouse" || e.pointerType === "pen";
|
|
76
59
|
editor.updateInstanceState({ isHoveringCanvas: canHover ? false : null });
|
|
77
60
|
}
|
|
78
61
|
function onTouchStart(e) {
|
|
79
|
-
;
|
|
80
|
-
e
|
|
62
|
+
if (wasEventAlreadyHandled(e)) return;
|
|
63
|
+
markEventAsHandled(e);
|
|
81
64
|
preventDefault(e);
|
|
82
65
|
}
|
|
83
66
|
function onTouchEnd(e) {
|
|
84
|
-
;
|
|
85
|
-
e
|
|
67
|
+
if (wasEventAlreadyHandled(e)) return;
|
|
68
|
+
markEventAsHandled(e);
|
|
86
69
|
if (!(e.target instanceof HTMLElement)) return;
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
70
|
+
const editingShapeId = editor.getEditingShape()?.id;
|
|
71
|
+
if (
|
|
72
|
+
// if the target is not inside the editing shape
|
|
73
|
+
!(editingShapeId && e.target.closest(`[data-shape-id="${editingShapeId}"]`)) && // and the target is not an clickable element
|
|
74
|
+
e.target.tagName !== "A" && // or a TextArea.tsx ?
|
|
75
|
+
e.target.tagName !== "TEXTAREA" && !e.target.isContentEditable
|
|
76
|
+
) {
|
|
92
77
|
preventDefault(e);
|
|
93
78
|
}
|
|
94
79
|
}
|
|
95
80
|
function onDragOver(e) {
|
|
81
|
+
if (wasEventAlreadyHandled(e)) return;
|
|
96
82
|
preventDefault(e);
|
|
97
83
|
}
|
|
98
84
|
async function onDrop(e) {
|
|
85
|
+
if (wasEventAlreadyHandled(e)) return;
|
|
99
86
|
preventDefault(e);
|
|
100
|
-
|
|
87
|
+
e.stopPropagation();
|
|
101
88
|
if (e.dataTransfer?.files?.length) {
|
|
102
89
|
const files = Array.from(e.dataTransfer.files);
|
|
103
90
|
await editor.putExternalContent({
|
|
@@ -118,11 +105,11 @@ function useCanvasEvents() {
|
|
|
118
105
|
}
|
|
119
106
|
}
|
|
120
107
|
function onClick(e) {
|
|
121
|
-
|
|
108
|
+
if (wasEventAlreadyHandled(e)) return;
|
|
109
|
+
e.stopPropagation();
|
|
122
110
|
}
|
|
123
111
|
return {
|
|
124
112
|
onPointerDown,
|
|
125
|
-
onPointerMove,
|
|
126
113
|
onPointerUp,
|
|
127
114
|
onPointerEnter,
|
|
128
115
|
onPointerLeave,
|
|
@@ -133,8 +120,31 @@ function useCanvasEvents() {
|
|
|
133
120
|
onClick
|
|
134
121
|
};
|
|
135
122
|
},
|
|
136
|
-
[editor
|
|
123
|
+
[editor]
|
|
137
124
|
);
|
|
125
|
+
useEffect(() => {
|
|
126
|
+
let lastX, lastY;
|
|
127
|
+
function onPointerMove(e) {
|
|
128
|
+
if (wasEventAlreadyHandled(e)) return;
|
|
129
|
+
markEventAsHandled(e);
|
|
130
|
+
if (e.clientX === lastX && e.clientY === lastY) return;
|
|
131
|
+
lastX = e.clientX;
|
|
132
|
+
lastY = e.clientY;
|
|
133
|
+
const events2 = currentTool.useCoalescedEvents && e.getCoalescedEvents ? e.getCoalescedEvents() : [e];
|
|
134
|
+
for (const singleEvent of events2) {
|
|
135
|
+
editor.dispatch({
|
|
136
|
+
type: "pointer",
|
|
137
|
+
target: "canvas",
|
|
138
|
+
name: "pointer_move",
|
|
139
|
+
...getPointerInfo(singleEvent)
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
document.body.addEventListener("pointermove", onPointerMove);
|
|
144
|
+
return () => {
|
|
145
|
+
document.body.removeEventListener("pointermove", onPointerMove);
|
|
146
|
+
};
|
|
147
|
+
}, [editor, currentTool]);
|
|
138
148
|
return events;
|
|
139
149
|
}
|
|
140
150
|
export {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/hooks/useCanvasEvents.ts"],
|
|
4
|
-
"sourcesContent": ["import { useValue } from '@tldraw/state-react'\nimport React, { useMemo } from 'react'\nimport { RIGHT_MOUSE_BUTTON } from '../constants'\nimport {\n\tpreventDefault,\n\treleasePointerCapture,\n\tsetPointerCapture,\n\
|
|
5
|
-
"mappings": "AAAA,SAAS,gBAAgB;AACzB,SAAgB,eAAe;
|
|
4
|
+
"sourcesContent": ["import { useValue } from '@tldraw/state-react'\nimport React, { useEffect, useMemo } from 'react'\nimport { RIGHT_MOUSE_BUTTON } from '../constants'\nimport {\n\tmarkEventAsHandled,\n\tpreventDefault,\n\treleasePointerCapture,\n\tsetPointerCapture,\n\twasEventAlreadyHandled,\n} from '../utils/dom'\nimport { getPointerInfo } from '../utils/getPointerInfo'\nimport { useEditor } from './useEditor'\n\nexport function useCanvasEvents() {\n\tconst editor = useEditor()\n\tconst currentTool = useValue('current tool', () => editor.getCurrentTool(), [editor])\n\n\tconst events = useMemo(\n\t\tfunction canvasEvents() {\n\t\t\tfunction onPointerDown(e: React.PointerEvent) {\n\t\t\t\tif (wasEventAlreadyHandled(e)) return\n\n\t\t\t\tif (e.button === RIGHT_MOUSE_BUTTON) {\n\t\t\t\t\teditor.dispatch({\n\t\t\t\t\t\ttype: 'pointer',\n\t\t\t\t\t\ttarget: 'canvas',\n\t\t\t\t\t\tname: 'right_click',\n\t\t\t\t\t\t...getPointerInfo(e),\n\t\t\t\t\t})\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tif (e.button !== 0 && e.button !== 1 && e.button !== 5) return\n\n\t\t\t\tsetPointerCapture(e.currentTarget, e)\n\n\t\t\t\teditor.dispatch({\n\t\t\t\t\ttype: 'pointer',\n\t\t\t\t\ttarget: 'canvas',\n\t\t\t\t\tname: 'pointer_down',\n\t\t\t\t\t...getPointerInfo(e),\n\t\t\t\t})\n\t\t\t}\n\n\t\t\tfunction onPointerUp(e: React.PointerEvent) {\n\t\t\t\tif (wasEventAlreadyHandled(e)) return\n\t\t\t\tif (e.button !== 0 && e.button !== 1 && e.button !== 2 && e.button !== 5) return\n\n\t\t\t\treleasePointerCapture(e.currentTarget, e)\n\n\t\t\t\teditor.dispatch({\n\t\t\t\t\ttype: 'pointer',\n\t\t\t\t\ttarget: 'canvas',\n\t\t\t\t\tname: 'pointer_up',\n\t\t\t\t\t...getPointerInfo(e),\n\t\t\t\t})\n\t\t\t}\n\n\t\t\tfunction onPointerEnter(e: React.PointerEvent) {\n\t\t\t\tif (wasEventAlreadyHandled(e)) return\n\t\t\t\tif (editor.getInstanceState().isPenMode && e.pointerType !== 'pen') return\n\t\t\t\tconst canHover = e.pointerType === 'mouse' || e.pointerType === 'pen'\n\t\t\t\teditor.updateInstanceState({ isHoveringCanvas: canHover ? true : null })\n\t\t\t}\n\n\t\t\tfunction onPointerLeave(e: React.PointerEvent) {\n\t\t\t\tif (wasEventAlreadyHandled(e)) return\n\t\t\t\tif (editor.getInstanceState().isPenMode && e.pointerType !== 'pen') return\n\t\t\t\tconst canHover = e.pointerType === 'mouse' || e.pointerType === 'pen'\n\t\t\t\teditor.updateInstanceState({ isHoveringCanvas: canHover ? false : null })\n\t\t\t}\n\n\t\t\tfunction onTouchStart(e: React.TouchEvent) {\n\t\t\t\tif (wasEventAlreadyHandled(e)) return\n\t\t\t\tmarkEventAsHandled(e)\n\t\t\t\tpreventDefault(e)\n\t\t\t}\n\n\t\t\tfunction onTouchEnd(e: React.TouchEvent) {\n\t\t\t\tif (wasEventAlreadyHandled(e)) return\n\t\t\t\tmarkEventAsHandled(e)\n\t\t\t\t// check that e.target is an HTMLElement\n\t\t\t\tif (!(e.target instanceof HTMLElement)) return\n\n\t\t\t\tconst editingShapeId = editor.getEditingShape()?.id\n\t\t\t\tif (\n\t\t\t\t\t// if the target is not inside the editing shape\n\t\t\t\t\t!(editingShapeId && e.target.closest(`[data-shape-id=\"${editingShapeId}\"]`)) &&\n\t\t\t\t\t// and the target is not an clickable element\n\t\t\t\t\te.target.tagName !== 'A' &&\n\t\t\t\t\t// or a TextArea.tsx ?\n\t\t\t\t\te.target.tagName !== 'TEXTAREA' &&\n\t\t\t\t\t!e.target.isContentEditable\n\t\t\t\t) {\n\t\t\t\t\tpreventDefault(e)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfunction onDragOver(e: React.DragEvent<Element>) {\n\t\t\t\tif (wasEventAlreadyHandled(e)) return\n\t\t\t\tpreventDefault(e)\n\t\t\t}\n\n\t\t\tasync function onDrop(e: React.DragEvent<Element>) {\n\t\t\t\tif (wasEventAlreadyHandled(e)) return\n\t\t\t\tpreventDefault(e)\n\t\t\t\te.stopPropagation()\n\n\t\t\t\tif (e.dataTransfer?.files?.length) {\n\t\t\t\t\tconst files = Array.from(e.dataTransfer.files)\n\n\t\t\t\t\tawait editor.putExternalContent({\n\t\t\t\t\t\ttype: 'files',\n\t\t\t\t\t\tfiles,\n\t\t\t\t\t\tpoint: editor.screenToPage({ x: e.clientX, y: e.clientY }),\n\t\t\t\t\t})\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tconst url = e.dataTransfer.getData('url')\n\t\t\t\tif (url) {\n\t\t\t\t\tawait editor.putExternalContent({\n\t\t\t\t\t\ttype: 'url',\n\t\t\t\t\t\turl,\n\t\t\t\t\t\tpoint: editor.screenToPage({ x: e.clientX, y: e.clientY }),\n\t\t\t\t\t})\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfunction onClick(e: React.MouseEvent) {\n\t\t\t\tif (wasEventAlreadyHandled(e)) return\n\t\t\t\te.stopPropagation()\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tonPointerDown,\n\t\t\t\tonPointerUp,\n\t\t\t\tonPointerEnter,\n\t\t\t\tonPointerLeave,\n\t\t\t\tonDragOver,\n\t\t\t\tonDrop,\n\t\t\t\tonTouchStart,\n\t\t\t\tonTouchEnd,\n\t\t\t\tonClick,\n\t\t\t}\n\t\t},\n\t\t[editor]\n\t)\n\n\t// onPointerMove is special: where we're only interested in the other events when they're\n\t// happening _on_ the canvas (as opposed to outside of it, or on UI floating over it), we want\n\t// the pointer position to be up to date regardless of whether it's over the tldraw canvas or\n\t// not. So instead of returning a listener to be attached to the canvas, we directly attach a\n\t// listener to the whole document instead.\n\tuseEffect(() => {\n\t\tlet lastX: number, lastY: number\n\n\t\tfunction onPointerMove(e: PointerEvent) {\n\t\t\tif (wasEventAlreadyHandled(e)) return\n\t\t\tmarkEventAsHandled(e)\n\n\t\t\tif (e.clientX === lastX && e.clientY === lastY) return\n\t\t\tlastX = e.clientX\n\t\t\tlastY = e.clientY\n\n\t\t\t// For tools that benefit from a higher fidelity of events,\n\t\t\t// we dispatch the coalesced events.\n\t\t\t// N.B. Sometimes getCoalescedEvents isn't present on iOS, ugh.\n\t\t\tconst events =\n\t\t\t\tcurrentTool.useCoalescedEvents && e.getCoalescedEvents ? e.getCoalescedEvents() : [e]\n\t\t\tfor (const singleEvent of events) {\n\t\t\t\teditor.dispatch({\n\t\t\t\t\ttype: 'pointer',\n\t\t\t\t\ttarget: 'canvas',\n\t\t\t\t\tname: 'pointer_move',\n\t\t\t\t\t...getPointerInfo(singleEvent),\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\t\tdocument.body.addEventListener('pointermove', onPointerMove)\n\t\treturn () => {\n\t\t\tdocument.body.removeEventListener('pointermove', onPointerMove)\n\t\t}\n\t}, [editor, currentTool])\n\n\treturn events\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["events"]
|
|
7
7
|
}
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { useValue } from "@tldraw/state-react";
|
|
2
2
|
import { useEffect } from "react";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
activeElementShouldCaptureKeys,
|
|
5
|
+
markEventAsHandled,
|
|
6
|
+
preventDefault,
|
|
7
|
+
wasEventAlreadyHandled
|
|
8
|
+
} from "../utils/dom.mjs";
|
|
4
9
|
import { isAccelKey } from "../utils/keyboard.mjs";
|
|
5
10
|
import { useContainer } from "./useContainer.mjs";
|
|
6
11
|
import { useEditor } from "./useEditor.mjs";
|
|
@@ -14,7 +19,7 @@ function useDocumentEvents() {
|
|
|
14
19
|
function onDrop(e) {
|
|
15
20
|
if (e.isSpecialRedispatchedEvent) return;
|
|
16
21
|
preventDefault(e);
|
|
17
|
-
|
|
22
|
+
e.stopPropagation();
|
|
18
23
|
const cvs = container.querySelector(".tl-canvas");
|
|
19
24
|
if (!cvs) return;
|
|
20
25
|
const newEvent = new DragEvent(e.type, e);
|
|
@@ -68,8 +73,8 @@ function useDocumentEvents() {
|
|
|
68
73
|
(editor.isIn("zoom") || !editor.getPath().endsWith(".idle")) && !areShortcutsDisabled(editor)) {
|
|
69
74
|
preventDefault(e);
|
|
70
75
|
}
|
|
71
|
-
if (e
|
|
72
|
-
e
|
|
76
|
+
if (wasEventAlreadyHandled(e)) return;
|
|
77
|
+
markEventAsHandled(e);
|
|
73
78
|
const hasSelectedShapes = !!editor.getSelectedShapeIds().length;
|
|
74
79
|
switch (e.key) {
|
|
75
80
|
case "=":
|
|
@@ -138,8 +143,8 @@ function useDocumentEvents() {
|
|
|
138
143
|
editor.dispatch(info);
|
|
139
144
|
};
|
|
140
145
|
const handleKeyUp = (e) => {
|
|
141
|
-
if (e
|
|
142
|
-
e
|
|
146
|
+
if (wasEventAlreadyHandled(e)) return;
|
|
147
|
+
markEventAsHandled(e);
|
|
143
148
|
if (areShortcutsDisabled(editor)) {
|
|
144
149
|
return;
|
|
145
150
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/hooks/useDocumentEvents.ts"],
|
|
4
|
-
"sourcesContent": ["import { useValue } from '@tldraw/state-react'\nimport { useEffect } from 'react'\nimport { Editor } from '../editor/Editor'\nimport { TLKeyboardEventInfo } from '../editor/types/event-types'\nimport { activeElementShouldCaptureKeys, preventDefault, stopEventPropagation } from '../utils/dom'\nimport { isAccelKey } from '../utils/keyboard'\nimport { useContainer } from './useContainer'\nimport { useEditor } from './useEditor'\n\nexport function useDocumentEvents() {\n\tconst editor = useEditor()\n\tconst container = useContainer()\n\n\tconst isEditing = useValue('isEditing', () => editor.getEditingShapeId(), [editor])\n\tconst isAppFocused = useValue('isFocused', () => editor.getIsFocused(), [editor])\n\n\t// Prevent the browser's default drag and drop behavior on our container (UI, etc)\n\tuseEffect(() => {\n\t\tif (!container) return\n\n\t\tfunction onDrop(e: DragEvent) {\n\t\t\t// this is tricky: we don't want the event to do anything\n\t\t\t// here, but we do want it to make its way to the canvas,\n\t\t\t// even if the drop is over some other element (like a toolbar),\n\t\t\t// so we're going to flag the event and then dispatch\n\t\t\t// it to the canvas; the canvas will handle it and try to\n\t\t\t// stop it from propagating back, but in case we do see it again,\n\t\t\t// we'll look for the flag so we know to stop it from being\n\t\t\t// re-dispatched, which would lead to an infinite loop.\n\t\t\tif ((e as any).isSpecialRedispatchedEvent) return\n\t\t\tpreventDefault(e)\n\t\t\tstopEventPropagation(e)\n\t\t\tconst cvs = container.querySelector('.tl-canvas')\n\t\t\tif (!cvs) return\n\t\t\tconst newEvent = new DragEvent(e.type, e)\n\t\t\t;(newEvent as any).isSpecialRedispatchedEvent = true\n\t\t\tcvs.dispatchEvent(newEvent)\n\t\t}\n\n\t\tcontainer.addEventListener('dragover', onDrop)\n\t\tcontainer.addEventListener('drop', onDrop)\n\t\treturn () => {\n\t\t\tcontainer.removeEventListener('dragover', onDrop)\n\t\t\tcontainer.removeEventListener('drop', onDrop)\n\t\t}\n\t}, [container])\n\n\tuseEffect(() => {\n\t\tif (typeof window === 'undefined' || !('matchMedia' in window)) return\n\n\t\t// https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio#monitoring_screen_resolution_or_zoom_level_changes\n\t\tlet remove: (() => void) | null = null\n\t\tconst updatePixelRatio = () => {\n\t\t\tif (remove != null) {\n\t\t\t\tremove()\n\t\t\t}\n\t\t\tconst mqString = `(resolution: ${window.devicePixelRatio}dppx)`\n\t\t\tconst media = matchMedia(mqString)\n\t\t\t// Safari only started supporting `addEventListener('change',...) in version 14\n\t\t\t// https://developer.mozilla.org/en-US/docs/Web/API/MediaQueryList/change_event\n\t\t\tconst safariCb = (ev: any) => {\n\t\t\t\tif (ev.type === 'change') {\n\t\t\t\t\tupdatePixelRatio()\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (media.addEventListener) {\n\t\t\t\tmedia.addEventListener('change', updatePixelRatio)\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\t\t\t} else if (media.addListener) {\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\t\t\t\tmedia.addListener(safariCb)\n\t\t\t}\n\t\t\tremove = () => {\n\t\t\t\tif (media.removeEventListener) {\n\t\t\t\t\tmedia.removeEventListener('change', updatePixelRatio)\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\t\t\t\t} else if (media.removeListener) {\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\t\t\t\t\tmedia.removeListener(safariCb)\n\t\t\t\t}\n\t\t\t}\n\t\t\teditor.updateInstanceState({ devicePixelRatio: window.devicePixelRatio })\n\t\t}\n\t\tupdatePixelRatio()\n\t\treturn () => {\n\t\t\tremove?.()\n\t\t}\n\t}, [editor])\n\n\tuseEffect(() => {\n\t\tif (!isAppFocused) return\n\n\t\tconst handleKeyDown = (e: KeyboardEvent) => {\n\t\t\tif (\n\t\t\t\te.altKey &&\n\t\t\t\t// todo: When should we allow the alt key to be used? Perhaps states should declare which keys matter to them?\n\t\t\t\t(editor.isIn('zoom') || !editor.getPath().endsWith('.idle')) &&\n\t\t\t\t!areShortcutsDisabled(editor)\n\t\t\t) {\n\t\t\t\t// On windows the alt key opens the menu bar.\n\t\t\t\t// We want to prevent that if the user is doing something else,\n\t\t\t\t// e.g. resizing a shape\n\t\t\t\tpreventDefault(e)\n\t\t\t}\n\n\t\t\tif ((e as any).isKilled) return\n\t\t\t;(e as any).isKilled = true\n\t\t\tconst hasSelectedShapes = !!editor.getSelectedShapeIds().length\n\n\t\t\tswitch (e.key) {\n\t\t\t\tcase '=':\n\t\t\t\tcase '-':\n\t\t\t\tcase '0': {\n\t\t\t\t\t// These keys are used for zooming. Technically we only use\n\t\t\t\t\t// the + - and 0 keys, however it's common for them to be\n\t\t\t\t\t// paired with modifier keys (command / control) so we need\n\t\t\t\t\t// to prevent the browser's regular actions (i.e. zooming\n\t\t\t\t\t// the page). A user can zoom by unfocusing the editor.\n\t\t\t\t\tif (e.metaKey || e.ctrlKey) {\n\t\t\t\t\t\tpreventDefault(e)\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tcase 'Tab': {\n\t\t\t\t\tif (areShortcutsDisabled(editor)) {\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\t// isEditing here sounds like it's about text editing\n\t\t\t\t\t// but more specifically, this is so you can tab into an\n\t\t\t\t\t// embed that's being 'edited'. In our world,\n\t\t\t\t\t// editing an embed, means it's interactive.\n\t\t\t\t\tif (hasSelectedShapes && !isEditing) {\n\t\t\t\t\t\t// This is used in tandem with shape navigation.\n\t\t\t\t\t\tpreventDefault(e)\n\t\t\t\t\t}\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tcase 'ArrowLeft':\n\t\t\t\tcase 'ArrowRight':\n\t\t\t\tcase 'ArrowUp':\n\t\t\t\tcase 'ArrowDown': {\n\t\t\t\t\tif (areShortcutsDisabled(editor)) {\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tif (hasSelectedShapes && (e.metaKey || e.ctrlKey)) {\n\t\t\t\t\t\t// This is used in tandem with shape navigation.\n\t\t\t\t\t\tpreventDefault(e)\n\t\t\t\t\t}\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tcase ',': {\n\t\t\t\t\t// this was moved to useKeyBoardShortcuts; it's possible\n\t\t\t\t\t// that the comma key is pressed when the container is not\n\t\t\t\t\t// focused, for example when the user has just interacted\n\t\t\t\t\t// with the toolbar. We need to handle it on the window\n\t\t\t\t\t// (ofc ensuring it's a correct time for a shortcut)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tcase 'Escape': {\n\t\t\t\t\t// In certain browsers, pressing escape while in full screen mode\n\t\t\t\t\t// will exit full screen mode. We want to allow that, but not when\n\t\t\t\t\t// escape is being handled by the editor. When a user has an editing\n\t\t\t\t\t// shape, escape stops editing. When a user is using a tool, escape\n\t\t\t\t\t// returns to the select tool. When the user has selected shapes,\n\t\t\t\t\t// escape de-selects them. Only when the user's selection is empty\n\t\t\t\t\t// should we allow escape to do its normal thing.\n\n\t\t\t\t\tif (editor.getEditingShape() || editor.getSelectedShapeIds().length > 0) {\n\t\t\t\t\t\tpreventDefault(e)\n\t\t\t\t\t}\n\n\t\t\t\t\t// Don't do anything if we open menus open\n\t\t\t\t\tif (editor.menus.getOpenMenus().length > 0) return\n\n\t\t\t\t\tif (editor.inputs.keys.has('Escape')) {\n\t\t\t\t\t\t// noop\n\t\t\t\t\t} else {\n\t\t\t\t\t\teditor.inputs.keys.add('Escape')\n\n\t\t\t\t\t\teditor.cancel()\n\t\t\t\t\t\t// Pressing escape will focus the document.body,\n\t\t\t\t\t\t// which will cause the app to lose focus, which\n\t\t\t\t\t\t// will break additional shortcuts. We need to\n\t\t\t\t\t\t// refocus the container in order to keep these\n\t\t\t\t\t\t// shortcuts working.\n\t\t\t\t\t\tcontainer.focus()\n\t\t\t\t\t}\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tdefault: {\n\t\t\t\t\tif (areShortcutsDisabled(editor)) {\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst info: TLKeyboardEventInfo = {\n\t\t\t\ttype: 'keyboard',\n\t\t\t\tname: e.repeat ? 'key_repeat' : 'key_down',\n\t\t\t\tkey: e.key,\n\t\t\t\tcode: e.code,\n\t\t\t\tshiftKey: e.shiftKey,\n\t\t\t\taltKey: e.altKey,\n\t\t\t\tctrlKey: e.metaKey || e.ctrlKey,\n\t\t\t\tmetaKey: e.metaKey,\n\t\t\t\taccelKey: isAccelKey(e),\n\t\t\t}\n\n\t\t\teditor.dispatch(info)\n\t\t}\n\n\t\tconst handleKeyUp = (e: KeyboardEvent) => {\n\t\t\tif ((e as any).isKilled) return\n\t\t\t;(e as any).isKilled = true\n\n\t\t\tif (areShortcutsDisabled(editor)) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif (e.key === ',') {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tconst info: TLKeyboardEventInfo = {\n\t\t\t\ttype: 'keyboard',\n\t\t\t\tname: 'key_up',\n\t\t\t\tkey: e.key,\n\t\t\t\tcode: e.code,\n\t\t\t\tshiftKey: e.shiftKey,\n\t\t\t\taltKey: e.altKey,\n\t\t\t\tctrlKey: e.metaKey || e.ctrlKey,\n\t\t\t\tmetaKey: e.metaKey,\n\t\t\t\taccelKey: isAccelKey(e),\n\t\t\t}\n\n\t\t\teditor.dispatch(info)\n\t\t}\n\n\t\tfunction handleTouchStart(e: TouchEvent) {\n\t\t\tif (container.contains(e.target as Node)) {\n\t\t\t\t// Center point of the touch area\n\t\t\t\tconst touchXPosition = e.touches[0].pageX\n\t\t\t\t// Size of the touch area\n\t\t\t\tconst touchXRadius = e.touches[0].radiusX || 0\n\n\t\t\t\t// We set a threshold (10px) on both sizes of the screen,\n\t\t\t\t// if the touch area overlaps with the screen edges\n\t\t\t\t// it's likely to trigger the navigation. We prevent the\n\t\t\t\t// touchstart event in that case.\n\t\t\t\t// todo: make this relative to the actual window, not the editor's screen bounds\n\t\t\t\tif (\n\t\t\t\t\ttouchXPosition - touchXRadius < 10 ||\n\t\t\t\t\ttouchXPosition + touchXRadius > editor.getViewportScreenBounds().width - 10\n\t\t\t\t) {\n\t\t\t\t\tif ((e.target as HTMLElement)?.tagName === 'BUTTON') {\n\t\t\t\t\t\t// Force a click before bailing\n\t\t\t\t\t\t;(e.target as HTMLButtonElement)?.click()\n\t\t\t\t\t}\n\n\t\t\t\t\tpreventDefault(e)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Prevent wheel events that occur inside of the container\n\t\tconst handleWheel = (e: WheelEvent) => {\n\t\t\t// Ctrl/Meta key indicates a pinch event (funny, eh?)\n\t\t\tif (container.contains(e.target as Node) && (e.ctrlKey || e.metaKey)) {\n\t\t\t\tpreventDefault(e)\n\t\t\t}\n\t\t}\n\n\t\tcontainer.addEventListener('touchstart', handleTouchStart, { passive: false })\n\n\t\tcontainer.addEventListener('wheel', handleWheel, { passive: false })\n\n\t\tdocument.addEventListener('gesturestart', preventDefault)\n\t\tdocument.addEventListener('gesturechange', preventDefault)\n\t\tdocument.addEventListener('gestureend', preventDefault)\n\n\t\tcontainer.addEventListener('keydown', handleKeyDown)\n\t\tcontainer.addEventListener('keyup', handleKeyUp)\n\n\t\treturn () => {\n\t\t\tcontainer.removeEventListener('touchstart', handleTouchStart)\n\n\t\t\tcontainer.removeEventListener('wheel', handleWheel)\n\n\t\t\tdocument.removeEventListener('gesturestart', preventDefault)\n\t\t\tdocument.removeEventListener('gesturechange', preventDefault)\n\t\t\tdocument.removeEventListener('gestureend', preventDefault)\n\n\t\t\tcontainer.removeEventListener('keydown', handleKeyDown)\n\t\t\tcontainer.removeEventListener('keyup', handleKeyUp)\n\t\t}\n\t}, [editor, container, isAppFocused, isEditing])\n}\n\nfunction areShortcutsDisabled(editor: Editor) {\n\treturn editor.menus.hasOpenMenus() || activeElementShouldCaptureKeys()\n}\n"],
|
|
5
|
-
"mappings": "AAAA,SAAS,gBAAgB;AACzB,SAAS,iBAAiB;AAG1B,
|
|
4
|
+
"sourcesContent": ["import { useValue } from '@tldraw/state-react'\nimport { useEffect } from 'react'\nimport { Editor } from '../editor/Editor'\nimport { TLKeyboardEventInfo } from '../editor/types/event-types'\nimport {\n\tactiveElementShouldCaptureKeys,\n\tmarkEventAsHandled,\n\tpreventDefault,\n\twasEventAlreadyHandled,\n} from '../utils/dom'\nimport { isAccelKey } from '../utils/keyboard'\nimport { useContainer } from './useContainer'\nimport { useEditor } from './useEditor'\n\nexport function useDocumentEvents() {\n\tconst editor = useEditor()\n\tconst container = useContainer()\n\n\tconst isEditing = useValue('isEditing', () => editor.getEditingShapeId(), [editor])\n\tconst isAppFocused = useValue('isFocused', () => editor.getIsFocused(), [editor])\n\n\t// Prevent the browser's default drag and drop behavior on our container (UI, etc)\n\tuseEffect(() => {\n\t\tif (!container) return\n\n\t\tfunction onDrop(e: DragEvent) {\n\t\t\t// this is tricky: we don't want the event to do anything\n\t\t\t// here, but we do want it to make its way to the canvas,\n\t\t\t// even if the drop is over some other element (like a toolbar),\n\t\t\t// so we're going to flag the event and then dispatch\n\t\t\t// it to the canvas; the canvas will handle it and try to\n\t\t\t// stop it from propagating back, but in case we do see it again,\n\t\t\t// we'll look for the flag so we know to stop it from being\n\t\t\t// re-dispatched, which would lead to an infinite loop.\n\t\t\tif ((e as any).isSpecialRedispatchedEvent) return\n\t\t\tpreventDefault(e)\n\t\t\te.stopPropagation()\n\t\t\tconst cvs = container.querySelector('.tl-canvas')\n\t\t\tif (!cvs) return\n\t\t\tconst newEvent = new DragEvent(e.type, e)\n\t\t\t;(newEvent as any).isSpecialRedispatchedEvent = true\n\t\t\tcvs.dispatchEvent(newEvent)\n\t\t}\n\n\t\tcontainer.addEventListener('dragover', onDrop)\n\t\tcontainer.addEventListener('drop', onDrop)\n\t\treturn () => {\n\t\t\tcontainer.removeEventListener('dragover', onDrop)\n\t\t\tcontainer.removeEventListener('drop', onDrop)\n\t\t}\n\t}, [container])\n\n\tuseEffect(() => {\n\t\tif (typeof window === 'undefined' || !('matchMedia' in window)) return\n\n\t\t// https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio#monitoring_screen_resolution_or_zoom_level_changes\n\t\tlet remove: (() => void) | null = null\n\t\tconst updatePixelRatio = () => {\n\t\t\tif (remove != null) {\n\t\t\t\tremove()\n\t\t\t}\n\t\t\tconst mqString = `(resolution: ${window.devicePixelRatio}dppx)`\n\t\t\tconst media = matchMedia(mqString)\n\t\t\t// Safari only started supporting `addEventListener('change',...) in version 14\n\t\t\t// https://developer.mozilla.org/en-US/docs/Web/API/MediaQueryList/change_event\n\t\t\tconst safariCb = (ev: any) => {\n\t\t\t\tif (ev.type === 'change') {\n\t\t\t\t\tupdatePixelRatio()\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (media.addEventListener) {\n\t\t\t\tmedia.addEventListener('change', updatePixelRatio)\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\t\t\t} else if (media.addListener) {\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\t\t\t\tmedia.addListener(safariCb)\n\t\t\t}\n\t\t\tremove = () => {\n\t\t\t\tif (media.removeEventListener) {\n\t\t\t\t\tmedia.removeEventListener('change', updatePixelRatio)\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\t\t\t\t} else if (media.removeListener) {\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\t\t\t\t\tmedia.removeListener(safariCb)\n\t\t\t\t}\n\t\t\t}\n\t\t\teditor.updateInstanceState({ devicePixelRatio: window.devicePixelRatio })\n\t\t}\n\t\tupdatePixelRatio()\n\t\treturn () => {\n\t\t\tremove?.()\n\t\t}\n\t}, [editor])\n\n\tuseEffect(() => {\n\t\tif (!isAppFocused) return\n\n\t\tconst handleKeyDown = (e: KeyboardEvent) => {\n\t\t\tif (\n\t\t\t\te.altKey &&\n\t\t\t\t// todo: When should we allow the alt key to be used? Perhaps states should declare which keys matter to them?\n\t\t\t\t(editor.isIn('zoom') || !editor.getPath().endsWith('.idle')) &&\n\t\t\t\t!areShortcutsDisabled(editor)\n\t\t\t) {\n\t\t\t\t// On windows the alt key opens the menu bar.\n\t\t\t\t// We want to prevent that if the user is doing something else,\n\t\t\t\t// e.g. resizing a shape\n\t\t\t\tpreventDefault(e)\n\t\t\t}\n\n\t\t\tif (wasEventAlreadyHandled(e)) return\n\t\t\tmarkEventAsHandled(e)\n\t\t\tconst hasSelectedShapes = !!editor.getSelectedShapeIds().length\n\n\t\t\tswitch (e.key) {\n\t\t\t\tcase '=':\n\t\t\t\tcase '-':\n\t\t\t\tcase '0': {\n\t\t\t\t\t// These keys are used for zooming. Technically we only use\n\t\t\t\t\t// the + - and 0 keys, however it's common for them to be\n\t\t\t\t\t// paired with modifier keys (command / control) so we need\n\t\t\t\t\t// to prevent the browser's regular actions (i.e. zooming\n\t\t\t\t\t// the page). A user can zoom by unfocusing the editor.\n\t\t\t\t\tif (e.metaKey || e.ctrlKey) {\n\t\t\t\t\t\tpreventDefault(e)\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tcase 'Tab': {\n\t\t\t\t\tif (areShortcutsDisabled(editor)) {\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\t// isEditing here sounds like it's about text editing\n\t\t\t\t\t// but more specifically, this is so you can tab into an\n\t\t\t\t\t// embed that's being 'edited'. In our world,\n\t\t\t\t\t// editing an embed, means it's interactive.\n\t\t\t\t\tif (hasSelectedShapes && !isEditing) {\n\t\t\t\t\t\t// This is used in tandem with shape navigation.\n\t\t\t\t\t\tpreventDefault(e)\n\t\t\t\t\t}\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tcase 'ArrowLeft':\n\t\t\t\tcase 'ArrowRight':\n\t\t\t\tcase 'ArrowUp':\n\t\t\t\tcase 'ArrowDown': {\n\t\t\t\t\tif (areShortcutsDisabled(editor)) {\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tif (hasSelectedShapes && (e.metaKey || e.ctrlKey)) {\n\t\t\t\t\t\t// This is used in tandem with shape navigation.\n\t\t\t\t\t\tpreventDefault(e)\n\t\t\t\t\t}\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tcase ',': {\n\t\t\t\t\t// this was moved to useKeyBoardShortcuts; it's possible\n\t\t\t\t\t// that the comma key is pressed when the container is not\n\t\t\t\t\t// focused, for example when the user has just interacted\n\t\t\t\t\t// with the toolbar. We need to handle it on the window\n\t\t\t\t\t// (ofc ensuring it's a correct time for a shortcut)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tcase 'Escape': {\n\t\t\t\t\t// In certain browsers, pressing escape while in full screen mode\n\t\t\t\t\t// will exit full screen mode. We want to allow that, but not when\n\t\t\t\t\t// escape is being handled by the editor. When a user has an editing\n\t\t\t\t\t// shape, escape stops editing. When a user is using a tool, escape\n\t\t\t\t\t// returns to the select tool. When the user has selected shapes,\n\t\t\t\t\t// escape de-selects them. Only when the user's selection is empty\n\t\t\t\t\t// should we allow escape to do its normal thing.\n\n\t\t\t\t\tif (editor.getEditingShape() || editor.getSelectedShapeIds().length > 0) {\n\t\t\t\t\t\tpreventDefault(e)\n\t\t\t\t\t}\n\n\t\t\t\t\t// Don't do anything if we open menus open\n\t\t\t\t\tif (editor.menus.getOpenMenus().length > 0) return\n\n\t\t\t\t\tif (editor.inputs.keys.has('Escape')) {\n\t\t\t\t\t\t// noop\n\t\t\t\t\t} else {\n\t\t\t\t\t\teditor.inputs.keys.add('Escape')\n\n\t\t\t\t\t\teditor.cancel()\n\t\t\t\t\t\t// Pressing escape will focus the document.body,\n\t\t\t\t\t\t// which will cause the app to lose focus, which\n\t\t\t\t\t\t// will break additional shortcuts. We need to\n\t\t\t\t\t\t// refocus the container in order to keep these\n\t\t\t\t\t\t// shortcuts working.\n\t\t\t\t\t\tcontainer.focus()\n\t\t\t\t\t}\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tdefault: {\n\t\t\t\t\tif (areShortcutsDisabled(editor)) {\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst info: TLKeyboardEventInfo = {\n\t\t\t\ttype: 'keyboard',\n\t\t\t\tname: e.repeat ? 'key_repeat' : 'key_down',\n\t\t\t\tkey: e.key,\n\t\t\t\tcode: e.code,\n\t\t\t\tshiftKey: e.shiftKey,\n\t\t\t\taltKey: e.altKey,\n\t\t\t\tctrlKey: e.metaKey || e.ctrlKey,\n\t\t\t\tmetaKey: e.metaKey,\n\t\t\t\taccelKey: isAccelKey(e),\n\t\t\t}\n\n\t\t\teditor.dispatch(info)\n\t\t}\n\n\t\tconst handleKeyUp = (e: KeyboardEvent) => {\n\t\t\tif (wasEventAlreadyHandled(e)) return\n\t\t\tmarkEventAsHandled(e)\n\n\t\t\tif (areShortcutsDisabled(editor)) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif (e.key === ',') {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tconst info: TLKeyboardEventInfo = {\n\t\t\t\ttype: 'keyboard',\n\t\t\t\tname: 'key_up',\n\t\t\t\tkey: e.key,\n\t\t\t\tcode: e.code,\n\t\t\t\tshiftKey: e.shiftKey,\n\t\t\t\taltKey: e.altKey,\n\t\t\t\tctrlKey: e.metaKey || e.ctrlKey,\n\t\t\t\tmetaKey: e.metaKey,\n\t\t\t\taccelKey: isAccelKey(e),\n\t\t\t}\n\n\t\t\teditor.dispatch(info)\n\t\t}\n\n\t\tfunction handleTouchStart(e: TouchEvent) {\n\t\t\tif (container.contains(e.target as Node)) {\n\t\t\t\t// Center point of the touch area\n\t\t\t\tconst touchXPosition = e.touches[0].pageX\n\t\t\t\t// Size of the touch area\n\t\t\t\tconst touchXRadius = e.touches[0].radiusX || 0\n\n\t\t\t\t// We set a threshold (10px) on both sizes of the screen,\n\t\t\t\t// if the touch area overlaps with the screen edges\n\t\t\t\t// it's likely to trigger the navigation. We prevent the\n\t\t\t\t// touchstart event in that case.\n\t\t\t\t// todo: make this relative to the actual window, not the editor's screen bounds\n\t\t\t\tif (\n\t\t\t\t\ttouchXPosition - touchXRadius < 10 ||\n\t\t\t\t\ttouchXPosition + touchXRadius > editor.getViewportScreenBounds().width - 10\n\t\t\t\t) {\n\t\t\t\t\tif ((e.target as HTMLElement)?.tagName === 'BUTTON') {\n\t\t\t\t\t\t// Force a click before bailing\n\t\t\t\t\t\t;(e.target as HTMLButtonElement)?.click()\n\t\t\t\t\t}\n\n\t\t\t\t\tpreventDefault(e)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Prevent wheel events that occur inside of the container\n\t\tconst handleWheel = (e: WheelEvent) => {\n\t\t\t// Ctrl/Meta key indicates a pinch event (funny, eh?)\n\t\t\tif (container.contains(e.target as Node) && (e.ctrlKey || e.metaKey)) {\n\t\t\t\tpreventDefault(e)\n\t\t\t}\n\t\t}\n\n\t\tcontainer.addEventListener('touchstart', handleTouchStart, { passive: false })\n\n\t\tcontainer.addEventListener('wheel', handleWheel, { passive: false })\n\n\t\tdocument.addEventListener('gesturestart', preventDefault)\n\t\tdocument.addEventListener('gesturechange', preventDefault)\n\t\tdocument.addEventListener('gestureend', preventDefault)\n\n\t\tcontainer.addEventListener('keydown', handleKeyDown)\n\t\tcontainer.addEventListener('keyup', handleKeyUp)\n\n\t\treturn () => {\n\t\t\tcontainer.removeEventListener('touchstart', handleTouchStart)\n\n\t\t\tcontainer.removeEventListener('wheel', handleWheel)\n\n\t\t\tdocument.removeEventListener('gesturestart', preventDefault)\n\t\t\tdocument.removeEventListener('gesturechange', preventDefault)\n\t\t\tdocument.removeEventListener('gestureend', preventDefault)\n\n\t\t\tcontainer.removeEventListener('keydown', handleKeyDown)\n\t\t\tcontainer.removeEventListener('keyup', handleKeyUp)\n\t\t}\n\t}, [editor, container, isAppFocused, isEditing])\n}\n\nfunction areShortcutsDisabled(editor: Editor) {\n\treturn editor.menus.hasOpenMenus() || activeElementShouldCaptureKeys()\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -14,10 +14,7 @@ function useEditor() {
|
|
|
14
14
|
function useMaybeEditor() {
|
|
15
15
|
return React.useContext(EditorContext);
|
|
16
16
|
}
|
|
17
|
-
function EditorProvider({
|
|
18
|
-
editor,
|
|
19
|
-
children
|
|
20
|
-
}) {
|
|
17
|
+
function EditorProvider({ editor, children }) {
|
|
21
18
|
return /* @__PURE__ */ jsx(EditorContext.Provider, { value: editor, children: /* @__PURE__ */ jsx(IdProvider, { children }) });
|
|
22
19
|
}
|
|
23
20
|
export {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/hooks/useEditor.tsx"],
|
|
4
|
-
"sourcesContent": ["import React, { createContext } from 'react'\nimport { Editor } from '../editor/Editor'\nimport { IdProvider } from './useSafeId'\n\n/** @public */\nexport const EditorContext = createContext<Editor | null>(null)\n\n/** @public */\nexport function useEditor(): Editor {\n\tconst editor = React.useContext(EditorContext)\n\tif (!editor) {\n\t\tthrow new Error(\n\t\t\t'useEditor must be used inside of the <Tldraw /> or <TldrawEditor /> components'\n\t\t)\n\t}\n\treturn editor\n}\n\n/** @public */\nexport function useMaybeEditor(): Editor | null {\n\treturn React.useContext(EditorContext)\n}\n\nexport
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["import React, { createContext } from 'react'\nimport { Editor } from '../editor/Editor'\nimport { IdProvider } from './useSafeId'\n\n/** @public */\nexport const EditorContext = createContext<Editor | null>(null)\n\n/** @public */\nexport function useEditor(): Editor {\n\tconst editor = React.useContext(EditorContext)\n\tif (!editor) {\n\t\tthrow new Error(\n\t\t\t'useEditor must be used inside of the <Tldraw /> or <TldrawEditor /> components'\n\t\t)\n\t}\n\treturn editor\n}\n\n/** @public */\nexport function useMaybeEditor(): Editor | null {\n\treturn React.useContext(EditorContext)\n}\n\n/** @public */\nexport interface EditorProviderProps {\n\teditor: Editor\n\tchildren: React.ReactNode\n}\n\n/** @public @react */\nexport function EditorProvider({ editor, children }: EditorProviderProps) {\n\treturn (\n\t\t<EditorContext.Provider value={editor}>\n\t\t\t<IdProvider>{children}</IdProvider>\n\t\t</EditorContext.Provider>\n\t)\n}\n"],
|
|
5
|
+
"mappings": "AAiCG;AAjCH,OAAO,SAAS,qBAAqB;AAErC,SAAS,kBAAkB;AAGpB,MAAM,gBAAgB,cAA6B,IAAI;AAGvD,SAAS,YAAoB;AACnC,QAAM,SAAS,MAAM,WAAW,aAAa;AAC7C,MAAI,CAAC,QAAQ;AACZ,UAAM,IAAI;AAAA,MACT;AAAA,IACD;AAAA,EACD;AACA,SAAO;AACR;AAGO,SAAS,iBAAgC;AAC/C,SAAO,MAAM,WAAW,aAAa;AACtC;AASO,SAAS,eAAe,EAAE,QAAQ,SAAS,GAAwB;AACzE,SACC,oBAAC,cAAc,UAAd,EAAuB,OAAO,QAC9B,8BAAC,cAAY,UAAS,GACvB;AAEF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -30,6 +30,9 @@ import {
|
|
|
30
30
|
DefaultShapeIndicatorErrorFallback
|
|
31
31
|
} from "../components/default-components/DefaultShapeIndicatorErrorFallback.mjs";
|
|
32
32
|
import { DefaultShapeIndicators } from "../components/default-components/DefaultShapeIndicators.mjs";
|
|
33
|
+
import {
|
|
34
|
+
DefaultShapeWrapper
|
|
35
|
+
} from "../components/default-components/DefaultShapeWrapper.mjs";
|
|
33
36
|
import {
|
|
34
37
|
DefaultSnapIndicator
|
|
35
38
|
} from "../components/default-components/DefaultSnapIndictor.mjs";
|
|
@@ -65,6 +68,7 @@ function EditorComponentsProvider({
|
|
|
65
68
|
SelectionForeground: DefaultSelectionForeground,
|
|
66
69
|
ShapeIndicator: DefaultShapeIndicator,
|
|
67
70
|
ShapeIndicators: DefaultShapeIndicators,
|
|
71
|
+
ShapeWrapper: DefaultShapeWrapper,
|
|
68
72
|
SnapIndicator: DefaultSnapIndicator,
|
|
69
73
|
Spinner: DefaultSpinner,
|
|
70
74
|
SvgDefs: DefaultSvgDefs,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/hooks/useEditorComponents.tsx"],
|
|
4
|
-
"sourcesContent": ["import { ComponentType, ReactNode, createContext, useContext, useMemo } from 'react'\nimport { DefaultBackground } from '../components/default-components/DefaultBackground'\nimport { DefaultBrush, TLBrushProps } from '../components/default-components/DefaultBrush'\nimport {\n\tDefaultCanvas,\n\tTLCanvasComponentProps,\n} from '../components/default-components/DefaultCanvas'\nimport {\n\tDefaultCollaboratorHint,\n\tTLCollaboratorHintProps,\n} from '../components/default-components/DefaultCollaboratorHint'\nimport { DefaultCursor, TLCursorProps } from '../components/default-components/DefaultCursor'\nimport {\n\tDefaultErrorFallback,\n\tTLErrorFallbackComponent,\n} from '../components/default-components/DefaultErrorFallback'\nimport { DefaultGrid, TLGridProps } from '../components/default-components/DefaultGrid'\nimport { DefaultHandle, TLHandleProps } from '../components/default-components/DefaultHandle'\nimport { DefaultHandles, TLHandlesProps } from '../components/default-components/DefaultHandles'\nimport { DefaultLoadingScreen } from '../components/default-components/DefaultLoadingScreen'\nimport { DefaultScribble, TLScribbleProps } from '../components/default-components/DefaultScribble'\nimport { TLSelectionBackgroundProps } from '../components/default-components/DefaultSelectionBackground'\nimport {\n\tDefaultSelectionForeground,\n\tTLSelectionForegroundProps,\n} from '../components/default-components/DefaultSelectionForeground'\nimport {\n\tDefaultShapeErrorFallback,\n\tTLShapeErrorFallbackComponent,\n} from '../components/default-components/DefaultShapeErrorFallback'\nimport {\n\tDefaultShapeIndicator,\n\tTLShapeIndicatorProps,\n} from '../components/default-components/DefaultShapeIndicator'\nimport {\n\tDefaultShapeIndicatorErrorFallback,\n\tTLShapeIndicatorErrorFallbackComponent,\n} from '../components/default-components/DefaultShapeIndicatorErrorFallback'\nimport { DefaultShapeIndicators } from '../components/default-components/DefaultShapeIndicators'\nimport {\n\tDefaultSnapIndicator,\n\tTLSnapIndicatorProps,\n} from '../components/default-components/DefaultSnapIndictor'\nimport { DefaultSpinner } from '../components/default-components/DefaultSpinner'\nimport { DefaultSvgDefs } from '../components/default-components/DefaultSvgDefs'\nimport { useShallowObjectIdentity } from './useIdentity'\n\n/** @public */\nexport interface TLEditorComponents {\n\tBackground?: ComponentType | null\n\tBrush?: ComponentType<TLBrushProps> | null\n\tCanvas?: ComponentType<TLCanvasComponentProps> | null\n\tCollaboratorBrush?: ComponentType<TLBrushProps> | null\n\tCollaboratorCursor?: ComponentType<TLCursorProps> | null\n\tCollaboratorHint?: ComponentType<TLCollaboratorHintProps> | null\n\tCollaboratorScribble?: ComponentType<TLScribbleProps> | null\n\tCollaboratorShapeIndicator?: ComponentType<TLShapeIndicatorProps> | null\n\tCursor?: ComponentType<TLCursorProps> | null\n\tGrid?: ComponentType<TLGridProps> | null\n\tHandle?: ComponentType<TLHandleProps> | null\n\tHandles?: ComponentType<TLHandlesProps> | null\n\tInFrontOfTheCanvas?: ComponentType | null\n\tLoadingScreen?: ComponentType | null\n\tOnTheCanvas?: ComponentType | null\n\tOverlays?: ComponentType | null\n\tScribble?: ComponentType<TLScribbleProps> | null\n\tSelectionBackground?: ComponentType<TLSelectionBackgroundProps> | null\n\tSelectionForeground?: ComponentType<TLSelectionForegroundProps> | null\n\tShapeIndicator?: ComponentType<TLShapeIndicatorProps> | null\n\tShapeIndicators?: ComponentType | null\n\tSnapIndicator?: ComponentType<TLSnapIndicatorProps> | null\n\tSpinner?: ComponentType | null\n\tSvgDefs?: ComponentType | null\n\tZoomBrush?: ComponentType<TLBrushProps> | null\n\n\t// These will always have defaults\n\tErrorFallback?: TLErrorFallbackComponent\n\tShapeErrorFallback?: TLShapeErrorFallbackComponent\n\tShapeIndicatorErrorFallback?: TLShapeIndicatorErrorFallbackComponent\n}\n\nconst EditorComponentsContext = createContext<null | Required<TLEditorComponents>>(null)\n\ninterface ComponentsContextProviderProps {\n\toverrides?: TLEditorComponents\n\tchildren: ReactNode\n}\n\nexport function EditorComponentsProvider({\n\toverrides = {},\n\tchildren,\n}: ComponentsContextProviderProps) {\n\tconst _overrides = useShallowObjectIdentity(overrides)\n\tconst value = useMemo(\n\t\t(): Required<TLEditorComponents> => ({\n\t\t\tBackground: DefaultBackground,\n\t\t\tBrush: DefaultBrush,\n\t\t\tCanvas: DefaultCanvas,\n\t\t\tCollaboratorBrush: DefaultBrush,\n\t\t\tCollaboratorCursor: DefaultCursor,\n\t\t\tCollaboratorHint: DefaultCollaboratorHint,\n\t\t\tCollaboratorScribble: DefaultScribble,\n\t\t\tCollaboratorShapeIndicator: DefaultShapeIndicator,\n\t\t\tCursor: DefaultCursor,\n\t\t\tGrid: DefaultGrid,\n\t\t\tHandle: DefaultHandle,\n\t\t\tHandles: DefaultHandles,\n\t\t\tInFrontOfTheCanvas: null,\n\t\t\tLoadingScreen: DefaultLoadingScreen,\n\t\t\tOnTheCanvas: null,\n\t\t\tOverlays: null,\n\t\t\tScribble: DefaultScribble,\n\t\t\tSelectionBackground: null,\n\t\t\tSelectionForeground: DefaultSelectionForeground,\n\t\t\tShapeIndicator: DefaultShapeIndicator,\n\t\t\tShapeIndicators: DefaultShapeIndicators,\n\t\t\tSnapIndicator: DefaultSnapIndicator,\n\t\t\tSpinner: DefaultSpinner,\n\t\t\tSvgDefs: DefaultSvgDefs,\n\t\t\tZoomBrush: DefaultBrush,\n\n\t\t\tErrorFallback: DefaultErrorFallback,\n\t\t\tShapeErrorFallback: DefaultShapeErrorFallback,\n\t\t\tShapeIndicatorErrorFallback: DefaultShapeIndicatorErrorFallback,\n\n\t\t\t..._overrides,\n\t\t}),\n\t\t[_overrides]\n\t)\n\n\treturn (\n\t\t<EditorComponentsContext.Provider value={value}>{children}</EditorComponentsContext.Provider>\n\t)\n}\n\n/** @public */\nexport function useEditorComponents() {\n\tconst components = useContext(EditorComponentsContext)\n\tif (!components) {\n\t\tthrow new Error('useEditorComponents must be used inside of <EditorComponentsProvider />')\n\t}\n\treturn components\n}\n"],
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["import { ComponentType, ReactNode, RefAttributes, createContext, useContext, useMemo } from 'react'\nimport { DefaultBackground } from '../components/default-components/DefaultBackground'\nimport { DefaultBrush, TLBrushProps } from '../components/default-components/DefaultBrush'\nimport {\n\tDefaultCanvas,\n\tTLCanvasComponentProps,\n} from '../components/default-components/DefaultCanvas'\nimport {\n\tDefaultCollaboratorHint,\n\tTLCollaboratorHintProps,\n} from '../components/default-components/DefaultCollaboratorHint'\nimport { DefaultCursor, TLCursorProps } from '../components/default-components/DefaultCursor'\nimport {\n\tDefaultErrorFallback,\n\tTLErrorFallbackComponent,\n} from '../components/default-components/DefaultErrorFallback'\nimport { DefaultGrid, TLGridProps } from '../components/default-components/DefaultGrid'\nimport { DefaultHandle, TLHandleProps } from '../components/default-components/DefaultHandle'\nimport { DefaultHandles, TLHandlesProps } from '../components/default-components/DefaultHandles'\nimport { DefaultLoadingScreen } from '../components/default-components/DefaultLoadingScreen'\nimport { DefaultScribble, TLScribbleProps } from '../components/default-components/DefaultScribble'\nimport { TLSelectionBackgroundProps } from '../components/default-components/DefaultSelectionBackground'\nimport {\n\tDefaultSelectionForeground,\n\tTLSelectionForegroundProps,\n} from '../components/default-components/DefaultSelectionForeground'\nimport {\n\tDefaultShapeErrorFallback,\n\tTLShapeErrorFallbackComponent,\n} from '../components/default-components/DefaultShapeErrorFallback'\nimport {\n\tDefaultShapeIndicator,\n\tTLShapeIndicatorProps,\n} from '../components/default-components/DefaultShapeIndicator'\nimport {\n\tDefaultShapeIndicatorErrorFallback,\n\tTLShapeIndicatorErrorFallbackComponent,\n} from '../components/default-components/DefaultShapeIndicatorErrorFallback'\nimport { DefaultShapeIndicators } from '../components/default-components/DefaultShapeIndicators'\nimport {\n\tDefaultShapeWrapper,\n\tTLShapeWrapperProps,\n} from '../components/default-components/DefaultShapeWrapper'\nimport {\n\tDefaultSnapIndicator,\n\tTLSnapIndicatorProps,\n} from '../components/default-components/DefaultSnapIndictor'\nimport { DefaultSpinner } from '../components/default-components/DefaultSpinner'\nimport { DefaultSvgDefs } from '../components/default-components/DefaultSvgDefs'\nimport { useShallowObjectIdentity } from './useIdentity'\n\n/** @public */\nexport interface TLEditorComponents {\n\tBackground?: ComponentType | null\n\tBrush?: ComponentType<TLBrushProps> | null\n\tCanvas?: ComponentType<TLCanvasComponentProps> | null\n\tCollaboratorBrush?: ComponentType<TLBrushProps> | null\n\tCollaboratorCursor?: ComponentType<TLCursorProps> | null\n\tCollaboratorHint?: ComponentType<TLCollaboratorHintProps> | null\n\tCollaboratorScribble?: ComponentType<TLScribbleProps> | null\n\tCollaboratorShapeIndicator?: ComponentType<TLShapeIndicatorProps> | null\n\tCursor?: ComponentType<TLCursorProps> | null\n\tGrid?: ComponentType<TLGridProps> | null\n\tHandle?: ComponentType<TLHandleProps> | null\n\tHandles?: ComponentType<TLHandlesProps> | null\n\tInFrontOfTheCanvas?: ComponentType | null\n\tLoadingScreen?: ComponentType | null\n\tOnTheCanvas?: ComponentType | null\n\tOverlays?: ComponentType | null\n\tScribble?: ComponentType<TLScribbleProps> | null\n\tSelectionBackground?: ComponentType<TLSelectionBackgroundProps> | null\n\tSelectionForeground?: ComponentType<TLSelectionForegroundProps> | null\n\tShapeIndicator?: ComponentType<TLShapeIndicatorProps> | null\n\tShapeIndicators?: ComponentType | null\n\tShapeWrapper?: ComponentType<TLShapeWrapperProps & RefAttributes<HTMLDivElement>> | null\n\tSnapIndicator?: ComponentType<TLSnapIndicatorProps> | null\n\tSpinner?: ComponentType<React.SVGProps<SVGSVGElement>> | null\n\tSvgDefs?: ComponentType | null\n\tZoomBrush?: ComponentType<TLBrushProps> | null\n\n\t// These will always have defaults\n\tErrorFallback?: TLErrorFallbackComponent\n\tShapeErrorFallback?: TLShapeErrorFallbackComponent\n\tShapeIndicatorErrorFallback?: TLShapeIndicatorErrorFallbackComponent\n}\n\nconst EditorComponentsContext = createContext<null | Required<TLEditorComponents>>(null)\n\ninterface ComponentsContextProviderProps {\n\toverrides?: TLEditorComponents\n\tchildren: ReactNode\n}\n\nexport function EditorComponentsProvider({\n\toverrides = {},\n\tchildren,\n}: ComponentsContextProviderProps) {\n\tconst _overrides = useShallowObjectIdentity(overrides)\n\tconst value = useMemo(\n\t\t(): Required<TLEditorComponents> => ({\n\t\t\tBackground: DefaultBackground,\n\t\t\tBrush: DefaultBrush,\n\t\t\tCanvas: DefaultCanvas,\n\t\t\tCollaboratorBrush: DefaultBrush,\n\t\t\tCollaboratorCursor: DefaultCursor,\n\t\t\tCollaboratorHint: DefaultCollaboratorHint,\n\t\t\tCollaboratorScribble: DefaultScribble,\n\t\t\tCollaboratorShapeIndicator: DefaultShapeIndicator,\n\t\t\tCursor: DefaultCursor,\n\t\t\tGrid: DefaultGrid,\n\t\t\tHandle: DefaultHandle,\n\t\t\tHandles: DefaultHandles,\n\t\t\tInFrontOfTheCanvas: null,\n\t\t\tLoadingScreen: DefaultLoadingScreen,\n\t\t\tOnTheCanvas: null,\n\t\t\tOverlays: null,\n\t\t\tScribble: DefaultScribble,\n\t\t\tSelectionBackground: null,\n\t\t\tSelectionForeground: DefaultSelectionForeground,\n\t\t\tShapeIndicator: DefaultShapeIndicator,\n\t\t\tShapeIndicators: DefaultShapeIndicators,\n\t\t\tShapeWrapper: DefaultShapeWrapper,\n\t\t\tSnapIndicator: DefaultSnapIndicator,\n\t\t\tSpinner: DefaultSpinner,\n\t\t\tSvgDefs: DefaultSvgDefs,\n\t\t\tZoomBrush: DefaultBrush,\n\n\t\t\tErrorFallback: DefaultErrorFallback,\n\t\t\tShapeErrorFallback: DefaultShapeErrorFallback,\n\t\t\tShapeIndicatorErrorFallback: DefaultShapeIndicatorErrorFallback,\n\n\t\t\t..._overrides,\n\t\t}),\n\t\t[_overrides]\n\t)\n\n\treturn (\n\t\t<EditorComponentsContext.Provider value={value}>{children}</EditorComponentsContext.Provider>\n\t)\n}\n\n/** @public */\nexport function useEditorComponents() {\n\tconst components = useContext(EditorComponentsContext)\n\tif (!components) {\n\t\tthrow new Error('useEditorComponents must be used inside of <EditorComponentsProvider />')\n\t}\n\treturn components\n}\n"],
|
|
5
|
+
"mappings": "AAyIE;AAzIF,SAAkD,eAAe,YAAY,eAAe;AAC5F,SAAS,yBAAyB;AAClC,SAAS,oBAAkC;AAC3C;AAAA,EACC;AAAA,OAEM;AACP;AAAA,EACC;AAAA,OAEM;AACP,SAAS,qBAAoC;AAC7C;AAAA,EACC;AAAA,OAEM;AACP,SAAS,mBAAgC;AACzC,SAAS,qBAAoC;AAC7C,SAAS,sBAAsC;AAC/C,SAAS,4BAA4B;AACrC,SAAS,uBAAwC;AAEjD;AAAA,EACC;AAAA,OAEM;AACP;AAAA,EACC;AAAA,OAEM;AACP;AAAA,EACC;AAAA,OAEM;AACP;AAAA,EACC;AAAA,OAEM;AACP,SAAS,8BAA8B;AACvC;AAAA,EACC;AAAA,OAEM;AACP;AAAA,EACC;AAAA,OAEM;AACP,SAAS,sBAAsB;AAC/B,SAAS,sBAAsB;AAC/B,SAAS,gCAAgC;AAqCzC,MAAM,0BAA0B,cAAmD,IAAI;AAOhF,SAAS,yBAAyB;AAAA,EACxC,YAAY,CAAC;AAAA,EACb;AACD,GAAmC;AAClC,QAAM,aAAa,yBAAyB,SAAS;AACrD,QAAM,QAAQ;AAAA,IACb,OAAqC;AAAA,MACpC,YAAY;AAAA,MACZ,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,mBAAmB;AAAA,MACnB,oBAAoB;AAAA,MACpB,kBAAkB;AAAA,MAClB,sBAAsB;AAAA,MACtB,4BAA4B;AAAA,MAC5B,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,oBAAoB;AAAA,MACpB,eAAe;AAAA,MACf,aAAa;AAAA,MACb,UAAU;AAAA,MACV,UAAU;AAAA,MACV,qBAAqB;AAAA,MACrB,qBAAqB;AAAA,MACrB,gBAAgB;AAAA,MAChB,iBAAiB;AAAA,MACjB,cAAc;AAAA,MACd,eAAe;AAAA,MACf,SAAS;AAAA,MACT,SAAS;AAAA,MACT,WAAW;AAAA,MAEX,eAAe;AAAA,MACf,oBAAoB;AAAA,MACpB,6BAA6B;AAAA,MAE7B,GAAG;AAAA,IACJ;AAAA,IACA,CAAC,UAAU;AAAA,EACZ;AAEA,SACC,oBAAC,wBAAwB,UAAxB,EAAiC,OAAe,UAAS;AAE5D;AAGO,SAAS,sBAAsB;AACrC,QAAM,aAAa,WAAW,uBAAuB;AACrD,MAAI,CAAC,YAAY;AAChB,UAAM,IAAI,MAAM,yEAAyE;AAAA,EAC1F;AACA,SAAO;AACR;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useEffect } from "react";
|
|
2
|
-
import { preventDefault } from "../utils/dom.mjs";
|
|
2
|
+
import { markEventAsHandled, preventDefault } from "../utils/dom.mjs";
|
|
3
3
|
import { useEditor } from "./useEditor.mjs";
|
|
4
4
|
const IGNORED_TAGS = ["textarea", "input"];
|
|
5
5
|
function useFixSafariDoubleTapZoomPencilEvents(ref) {
|
|
@@ -9,8 +9,7 @@ function useFixSafariDoubleTapZoomPencilEvents(ref) {
|
|
|
9
9
|
if (!elm) return;
|
|
10
10
|
const handleEvent = (e) => {
|
|
11
11
|
if (e instanceof PointerEvent && e.pointerType === "pen") {
|
|
12
|
-
;
|
|
13
|
-
e.isKilled = true;
|
|
12
|
+
markEventAsHandled(e);
|
|
14
13
|
const { target } = e;
|
|
15
14
|
if (IGNORED_TAGS.includes(target.tagName?.toLocaleLowerCase()) || target.isContentEditable || editor.isIn("select.editing_shape")) {
|
|
16
15
|
return;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.ts"],
|
|
4
|
-
"sourcesContent": ["import { useEffect } from 'react'\nimport { preventDefault } from '../utils/dom'\nimport { useEditor } from './useEditor'\n\nconst IGNORED_TAGS = ['textarea', 'input']\n\n/**\n * When double tapping with the pencil in iOS, it enables a little zoom window in the UI. We don't\n * want this for drawing operations and can disable it by setting 'disableDoubleTapZoom' in the main\n * editor.\n */\nexport function useFixSafariDoubleTapZoomPencilEvents(ref: React.RefObject<HTMLElement>) {\n\tconst editor = useEditor()\n\n\tuseEffect(() => {\n\t\tconst elm = ref.current\n\n\t\tif (!elm) return\n\n\t\tconst handleEvent = (e: PointerEvent | TouchEvent) => {\n\t\t\tif (e instanceof PointerEvent && e.pointerType === 'pen') {\n\t\t\t\
|
|
5
|
-
"mappings": "AAAA,SAAS,iBAAiB;AAC1B,SAAS,sBAAsB;
|
|
4
|
+
"sourcesContent": ["import { useEffect } from 'react'\nimport { markEventAsHandled, preventDefault } from '../utils/dom'\nimport { useEditor } from './useEditor'\n\nconst IGNORED_TAGS = ['textarea', 'input']\n\n/**\n * When double tapping with the pencil in iOS, it enables a little zoom window in the UI. We don't\n * want this for drawing operations and can disable it by setting 'disableDoubleTapZoom' in the main\n * editor.\n */\nexport function useFixSafariDoubleTapZoomPencilEvents(ref: React.RefObject<HTMLElement>) {\n\tconst editor = useEditor()\n\n\tuseEffect(() => {\n\t\tconst elm = ref.current\n\n\t\tif (!elm) return\n\n\t\tconst handleEvent = (e: PointerEvent | TouchEvent) => {\n\t\t\tif (e instanceof PointerEvent && e.pointerType === 'pen') {\n\t\t\t\tmarkEventAsHandled(e)\n\t\t\t\tconst { target } = e\n\n\t\t\t\t// Allow events to propagate if the app is editing a shape, or if the event is occurring in a text area or input\n\t\t\t\tif (\n\t\t\t\t\tIGNORED_TAGS.includes((target as Element).tagName?.toLocaleLowerCase()) ||\n\t\t\t\t\t(target as HTMLElement).isContentEditable ||\n\t\t\t\t\teditor.isIn('select.editing_shape')\n\t\t\t\t) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tpreventDefault(e)\n\t\t\t}\n\t\t}\n\n\t\telm.addEventListener('touchstart', handleEvent)\n\t\telm.addEventListener('touchend', handleEvent)\n\t\treturn () => {\n\t\t\telm.removeEventListener('touchstart', handleEvent)\n\t\t\telm.removeEventListener('touchend', handleEvent)\n\t\t}\n\t}, [editor, ref])\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,iBAAiB;AAC1B,SAAS,oBAAoB,sBAAsB;AACnD,SAAS,iBAAiB;AAE1B,MAAM,eAAe,CAAC,YAAY,OAAO;AAOlC,SAAS,sCAAsC,KAAmC;AACxF,QAAM,SAAS,UAAU;AAEzB,YAAU,MAAM;AACf,UAAM,MAAM,IAAI;AAEhB,QAAI,CAAC,IAAK;AAEV,UAAM,cAAc,CAAC,MAAiC;AACrD,UAAI,aAAa,gBAAgB,EAAE,gBAAgB,OAAO;AACzD,2BAAmB,CAAC;AACpB,cAAM,EAAE,OAAO,IAAI;AAGnB,YACC,aAAa,SAAU,OAAmB,SAAS,kBAAkB,CAAC,KACrE,OAAuB,qBACxB,OAAO,KAAK,sBAAsB,GACjC;AACD;AAAA,QACD;AAEA,uBAAe,CAAC;AAAA,MACjB;AAAA,IACD;AAEA,QAAI,iBAAiB,cAAc,WAAW;AAC9C,QAAI,iBAAiB,YAAY,WAAW;AAC5C,WAAO,MAAM;AACZ,UAAI,oBAAoB,cAAc,WAAW;AACjD,UAAI,oBAAoB,YAAY,WAAW;AAAA,IAChD;AAAA,EACD,GAAG,CAAC,QAAQ,GAAG,CAAC;AACjB;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|