@tldraw/editor 4.2.2 → 4.2.3
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 +155 -498
- package/dist-cjs/index.js +1 -6
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/components/ErrorBoundary.js.map +1 -1
- package/dist-cjs/lib/components/GeometryDebuggingView.js +17 -1
- package/dist-cjs/lib/components/GeometryDebuggingView.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js +3 -3
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
- package/dist-cjs/lib/constants.js +3 -1
- package/dist-cjs/lib/constants.js.map +2 -2
- package/dist-cjs/lib/editor/Editor.js +286 -292
- package/dist-cjs/lib/editor/Editor.js.map +2 -2
- package/dist-cjs/lib/editor/bindings/BindingUtil.js.map +2 -2
- package/dist-cjs/lib/editor/derivations/bindingsIndex.js.map +2 -2
- package/dist-cjs/lib/editor/derivations/notVisibleShapes.js +17 -18
- package/dist-cjs/lib/editor/derivations/notVisibleShapes.js.map +3 -3
- package/dist-cjs/lib/editor/derivations/parentsToChildren.js +3 -12
- package/dist-cjs/lib/editor/derivations/parentsToChildren.js.map +2 -2
- package/dist-cjs/lib/editor/managers/ClickManager/ClickManager.js +1 -1
- package/dist-cjs/lib/editor/managers/ClickManager/ClickManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.js +6 -5
- package/dist-cjs/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/SnapManager/SnapManager.js +1 -1
- package/dist-cjs/lib/editor/managers/SnapManager/SnapManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/TickManager/TickManager.js +22 -1
- package/dist-cjs/lib/editor/managers/TickManager/TickManager.js.map +2 -2
- package/dist-cjs/lib/editor/shapes/BaseBoxShapeUtil.js.map +1 -1
- package/dist-cjs/lib/editor/shapes/ShapeUtil.js +23 -31
- package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
- package/dist-cjs/lib/editor/shapes/group/DashedOutlineBox.js +1 -1
- package/dist-cjs/lib/editor/shapes/group/DashedOutlineBox.js.map +2 -2
- package/dist-cjs/lib/editor/shapes/group/GroupShapeUtil.js.map +2 -2
- package/dist-cjs/lib/editor/tools/BaseBoxShapeTool/BaseBoxShapeTool.js.map +2 -2
- package/dist-cjs/lib/editor/tools/BaseBoxShapeTool/children/Pointing.js +3 -3
- package/dist-cjs/lib/editor/tools/BaseBoxShapeTool/children/Pointing.js.map +2 -2
- package/dist-cjs/lib/editor/types/emit-types.js.map +1 -1
- package/dist-cjs/lib/exports/getSvgJsx.js.map +2 -2
- package/dist-cjs/lib/exports/parseCss.js +1 -1
- package/dist-cjs/lib/exports/parseCss.js.map +2 -2
- package/dist-cjs/lib/globals/environment.js +9 -45
- package/dist-cjs/lib/globals/environment.js.map +2 -2
- package/dist-cjs/lib/globals/menus.js +1 -1
- package/dist-cjs/lib/globals/menus.js.map +2 -2
- package/dist-cjs/lib/hooks/useCanvasEvents.js +3 -4
- package/dist-cjs/lib/hooks/useCanvasEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/useCoarsePointer.js +29 -14
- package/dist-cjs/lib/hooks/useCoarsePointer.js.map +2 -2
- package/dist-cjs/lib/hooks/useEvent.js +1 -1
- package/dist-cjs/lib/hooks/useEvent.js.map +2 -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/usePassThroughMouseOverEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/usePassThroughWheelEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/useScreenBounds.js.map +2 -2
- package/dist-cjs/lib/hooks/useStateAttribute.js +1 -4
- package/dist-cjs/lib/hooks/useStateAttribute.js.map +2 -2
- package/dist-cjs/lib/hooks/useTransform.js.map +1 -1
- package/dist-cjs/lib/hooks/useZoomCss.js +8 -4
- package/dist-cjs/lib/hooks/useZoomCss.js.map +2 -2
- package/dist-cjs/lib/options.js +1 -6
- package/dist-cjs/lib/options.js.map +2 -2
- package/dist-cjs/lib/primitives/Box.js +0 -3
- package/dist-cjs/lib/primitives/Box.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Geometry2d.js +0 -1
- package/dist-cjs/lib/primitives/geometry/Geometry2d.js.map +2 -2
- package/dist-cjs/lib/utils/reparenting.js.map +2 -2
- package/dist-cjs/lib/utils/rotation.js +1 -1
- package/dist-cjs/lib/utils/rotation.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 +155 -498
- package/dist-esm/index.mjs +2 -7
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/components/ErrorBoundary.mjs.map +1 -1
- package/dist-esm/lib/components/GeometryDebuggingView.mjs +17 -1
- package/dist-esm/lib/components/GeometryDebuggingView.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +3 -3
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
- package/dist-esm/lib/constants.mjs +3 -1
- package/dist-esm/lib/constants.mjs.map +2 -2
- package/dist-esm/lib/editor/Editor.mjs +289 -293
- package/dist-esm/lib/editor/Editor.mjs.map +2 -2
- package/dist-esm/lib/editor/bindings/BindingUtil.mjs.map +2 -2
- package/dist-esm/lib/editor/derivations/bindingsIndex.mjs.map +2 -2
- package/dist-esm/lib/editor/derivations/notVisibleShapes.mjs +17 -18
- package/dist-esm/lib/editor/derivations/notVisibleShapes.mjs.map +3 -3
- package/dist-esm/lib/editor/derivations/parentsToChildren.mjs +4 -13
- package/dist-esm/lib/editor/derivations/parentsToChildren.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/ClickManager/ClickManager.mjs +1 -1
- package/dist-esm/lib/editor/managers/ClickManager/ClickManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.mjs +6 -5
- package/dist-esm/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/SnapManager/SnapManager.mjs +1 -1
- package/dist-esm/lib/editor/managers/SnapManager/SnapManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/TickManager/TickManager.mjs +22 -1
- package/dist-esm/lib/editor/managers/TickManager/TickManager.mjs.map +2 -2
- package/dist-esm/lib/editor/shapes/BaseBoxShapeUtil.mjs.map +1 -1
- package/dist-esm/lib/editor/shapes/ShapeUtil.mjs +23 -31
- package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/editor/shapes/group/DashedOutlineBox.mjs +1 -1
- package/dist-esm/lib/editor/shapes/group/DashedOutlineBox.mjs.map +2 -2
- package/dist-esm/lib/editor/shapes/group/GroupShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/editor/tools/BaseBoxShapeTool/BaseBoxShapeTool.mjs.map +2 -2
- package/dist-esm/lib/editor/tools/BaseBoxShapeTool/children/Pointing.mjs +3 -3
- package/dist-esm/lib/editor/tools/BaseBoxShapeTool/children/Pointing.mjs.map +2 -2
- package/dist-esm/lib/exports/getSvgJsx.mjs.map +2 -2
- package/dist-esm/lib/exports/parseCss.mjs +1 -1
- package/dist-esm/lib/exports/parseCss.mjs.map +2 -2
- package/dist-esm/lib/globals/environment.mjs +9 -45
- package/dist-esm/lib/globals/environment.mjs.map +2 -2
- package/dist-esm/lib/globals/menus.mjs +1 -1
- package/dist-esm/lib/globals/menus.mjs.map +2 -2
- package/dist-esm/lib/hooks/useCanvasEvents.mjs +3 -4
- package/dist-esm/lib/hooks/useCanvasEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useCoarsePointer.mjs +30 -15
- package/dist-esm/lib/hooks/useCoarsePointer.mjs.map +2 -2
- package/dist-esm/lib/hooks/useEvent.mjs +1 -1
- package/dist-esm/lib/hooks/useEvent.mjs.map +2 -2
- package/dist-esm/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useGestureEvents.mjs +1 -1
- package/dist-esm/lib/hooks/useGestureEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/usePassThroughMouseOverEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/usePassThroughWheelEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useScreenBounds.mjs.map +2 -2
- package/dist-esm/lib/hooks/useStateAttribute.mjs +1 -4
- package/dist-esm/lib/hooks/useStateAttribute.mjs.map +2 -2
- package/dist-esm/lib/hooks/useTransform.mjs.map +1 -1
- package/dist-esm/lib/hooks/useZoomCss.mjs +8 -4
- package/dist-esm/lib/hooks/useZoomCss.mjs.map +2 -2
- package/dist-esm/lib/options.mjs +1 -6
- package/dist-esm/lib/options.mjs.map +2 -2
- package/dist-esm/lib/primitives/Box.mjs +0 -3
- package/dist-esm/lib/primitives/Box.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Geometry2d.mjs +0 -1
- package/dist-esm/lib/primitives/geometry/Geometry2d.mjs.map +2 -2
- package/dist-esm/lib/utils/reparenting.mjs.map +2 -2
- package/dist-esm/lib/utils/rotation.mjs +1 -1
- package/dist-esm/lib/utils/rotation.mjs.map +2 -2
- package/dist-esm/version.mjs +3 -3
- package/dist-esm/version.mjs.map +1 -1
- package/editor.css +12 -14
- package/package.json +16 -18
- package/src/index.ts +1 -4
- package/src/lib/components/ErrorBoundary.tsx +1 -1
- package/src/lib/components/GeometryDebuggingView.tsx +19 -1
- package/src/lib/components/default-components/DefaultCanvas.tsx +3 -4
- package/src/lib/constants.ts +2 -0
- package/src/lib/editor/Editor.test.ts +10 -150
- package/src/lib/editor/Editor.ts +379 -459
- package/src/lib/editor/bindings/BindingUtil.ts +9 -15
- package/src/lib/editor/derivations/bindingsIndex.ts +2 -2
- package/src/lib/editor/derivations/notVisibleShapes.ts +23 -37
- package/src/lib/editor/derivations/parentsToChildren.ts +7 -18
- package/src/lib/editor/managers/ClickManager/ClickManager.test.ts +31 -17
- package/src/lib/editor/managers/ClickManager/ClickManager.ts +1 -1
- package/src/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.test.ts +79 -129
- package/src/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.ts +6 -10
- package/src/lib/editor/managers/FontManager/FontManager.test.ts +4 -14
- package/src/lib/editor/managers/ScribbleManager/ScribbleManager.test.ts +4 -0
- package/src/lib/editor/managers/SnapManager/SnapManager.test.ts +0 -12
- package/src/lib/editor/managers/SnapManager/SnapManager.ts +4 -4
- package/src/lib/editor/managers/TickManager/TickManager.test.ts +107 -40
- package/src/lib/editor/managers/TickManager/TickManager.ts +32 -2
- package/src/lib/editor/shapes/BaseBoxShapeUtil.tsx +2 -2
- package/src/lib/editor/shapes/ShapeUtil.ts +32 -72
- package/src/lib/editor/shapes/group/DashedOutlineBox.tsx +1 -1
- package/src/lib/editor/shapes/group/GroupShapeUtil.tsx +3 -1
- package/src/lib/editor/tools/BaseBoxShapeTool/BaseBoxShapeTool.ts +1 -2
- package/src/lib/editor/tools/BaseBoxShapeTool/children/Pointing.ts +6 -6
- package/src/lib/editor/types/emit-types.ts +1 -3
- package/src/lib/exports/getSvgJsx.test.ts +19 -10
- package/src/lib/exports/getSvgJsx.tsx +5 -2
- package/src/lib/exports/parseCss.test.ts +0 -1
- package/src/lib/exports/parseCss.ts +1 -1
- package/src/lib/globals/environment.ts +10 -65
- package/src/lib/globals/menus.ts +1 -1
- package/src/lib/hooks/useCanvasEvents.ts +3 -4
- package/src/lib/hooks/useCoarsePointer.ts +59 -16
- package/src/lib/hooks/useEvent.tsx +1 -1
- package/src/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.ts +1 -1
- package/src/lib/hooks/useGestureEvents.ts +2 -2
- package/src/lib/hooks/usePassThroughMouseOverEvents.ts +1 -1
- package/src/lib/hooks/usePassThroughWheelEvents.ts +1 -1
- package/src/lib/hooks/useScreenBounds.ts +1 -1
- package/src/lib/hooks/useStateAttribute.ts +1 -4
- package/src/lib/hooks/useTransform.ts +1 -1
- package/src/lib/hooks/useZoomCss.ts +8 -3
- package/src/lib/options.ts +0 -32
- package/src/lib/primitives/Box.ts +0 -9
- package/src/lib/primitives/geometry/Geometry2d.ts +0 -1
- package/src/lib/utils/reparenting.ts +5 -5
- package/src/lib/utils/rotation.ts +1 -1
- package/src/version.ts +3 -3
- package/dist-cjs/lib/editor/managers/InputsManager/InputsManager.js +0 -591
- package/dist-cjs/lib/editor/managers/InputsManager/InputsManager.js.map +0 -7
- package/dist-esm/lib/editor/managers/InputsManager/InputsManager.mjs +0 -573
- package/dist-esm/lib/editor/managers/InputsManager/InputsManager.mjs.map +0 -7
- package/src/lib/config/TLUserPreferences.test.ts +0 -40
- package/src/lib/editor/managers/InputsManager/InputsManager.ts +0 -566
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useAtom, useValue } from '@tldraw/state-react'
|
|
2
2
|
import {
|
|
3
3
|
TLFrameShape,
|
|
4
|
+
TLGroupShape,
|
|
4
5
|
TLShape,
|
|
5
6
|
TLShapeId,
|
|
6
7
|
getColorValue,
|
|
@@ -57,7 +58,9 @@ export function getSvgJsx(editor: Editor, ids: TLShapeId[], opts: TLImageExportO
|
|
|
57
58
|
|
|
58
59
|
// --- Common bounding box of all shapes
|
|
59
60
|
const singleFrameShapeId =
|
|
60
|
-
ids.length === 1 && editor.isShapeOfType(editor.getShape(ids[0])!, 'frame')
|
|
61
|
+
ids.length === 1 && editor.isShapeOfType<TLFrameShape>(editor.getShape(ids[0])!, 'frame')
|
|
62
|
+
? ids[0]
|
|
63
|
+
: null
|
|
61
64
|
|
|
62
65
|
let bbox: null | Box = null
|
|
63
66
|
if (opts.bounds) {
|
|
@@ -269,7 +272,7 @@ function SvgExport({
|
|
|
269
272
|
|
|
270
273
|
const shape = editor.getShape(id)!
|
|
271
274
|
|
|
272
|
-
if (editor.isShapeOfType(shape, 'group')) return []
|
|
275
|
+
if (editor.isShapeOfType<TLGroupShape>(shape, 'group')) return []
|
|
273
276
|
|
|
274
277
|
const elements = []
|
|
275
278
|
const util = editor.getShapeUtil(shape)
|
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
import { atom } from '@tldraw/state'
|
|
2
|
-
|
|
3
1
|
/**
|
|
4
2
|
* An object that contains information about the current device and environment.
|
|
5
|
-
* This object is not reactive and will not update automatically when the environment changes,
|
|
6
|
-
* so only include values that are fixed, such as the user's browser and operating system.
|
|
7
3
|
*
|
|
8
4
|
* @public
|
|
9
5
|
*/
|
|
@@ -18,66 +14,15 @@ const tlenv = {
|
|
|
18
14
|
hasCanvasSupport: false,
|
|
19
15
|
}
|
|
20
16
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
tlenv.isDarwin = window.navigator.userAgent.toLowerCase().indexOf('mac') > -1
|
|
31
|
-
}
|
|
32
|
-
tlenv.hasCanvasSupport = 'Promise' in window && 'HTMLCanvasElement' in window
|
|
33
|
-
isForcedFinePointer = tlenv.isFirefox && !tlenv.isAndroid && !tlenv.isIos
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* An atom that contains information about the current device and environment.
|
|
38
|
-
* This object is reactive and will update automatically when the environment changes.
|
|
39
|
-
* Use it for values that may change over time, such as the pointer type.
|
|
40
|
-
*
|
|
41
|
-
* @public
|
|
42
|
-
*/
|
|
43
|
-
const tlenvReactive = atom('tlenvReactive', {
|
|
44
|
-
// Whether the user's device has a coarse pointer. This is dynamic on many systems, especially
|
|
45
|
-
// on touch-screen laptops, which will become "coarse" if the user touches the screen.
|
|
46
|
-
// See https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/@media/pointer#coarse
|
|
47
|
-
isCoarsePointer: false,
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
if (typeof window !== 'undefined' && !isForcedFinePointer) {
|
|
51
|
-
const mql = window.matchMedia && window.matchMedia('(any-pointer: coarse)')
|
|
52
|
-
|
|
53
|
-
const isCurrentCoarsePointer = () => tlenvReactive.__unsafe__getWithoutCapture().isCoarsePointer
|
|
54
|
-
|
|
55
|
-
if (mql) {
|
|
56
|
-
// 1. Update the coarse pointer automatically when the media query changes
|
|
57
|
-
const updateIsCoarsePointer = () => {
|
|
58
|
-
const isCoarsePointer = mql.matches
|
|
59
|
-
if (isCoarsePointer !== isCurrentCoarsePointer()) {
|
|
60
|
-
tlenvReactive.update((prev) => ({ ...prev, isCoarsePointer: isCoarsePointer }))
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
updateIsCoarsePointer()
|
|
64
|
-
mql.addEventListener('change', updateIsCoarsePointer)
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// 2. Also update the coarse pointer state when a pointer down event occurs. We need `capture: true`
|
|
68
|
-
// here because the tldraw component itself stops propagation on pointer events it receives.
|
|
69
|
-
window.addEventListener(
|
|
70
|
-
'pointerdown',
|
|
71
|
-
(e: PointerEvent) => {
|
|
72
|
-
// when the user interacts with a mouse, we assume they have a fine pointer.
|
|
73
|
-
// otherwise, we assume they have a coarse pointer.
|
|
74
|
-
const isCoarseEvent = e.pointerType !== 'mouse'
|
|
75
|
-
if (isCoarseEvent !== isCurrentCoarsePointer()) {
|
|
76
|
-
tlenvReactive.update((prev) => ({ ...prev, isCoarsePointer: isCoarseEvent }))
|
|
77
|
-
}
|
|
78
|
-
},
|
|
79
|
-
{ capture: true }
|
|
80
|
-
)
|
|
17
|
+
if (typeof window !== 'undefined' && 'navigator' in window) {
|
|
18
|
+
tlenv.isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent)
|
|
19
|
+
tlenv.isIos = !!navigator.userAgent.match(/iPad/i) || !!navigator.userAgent.match(/iPhone/i)
|
|
20
|
+
tlenv.isChromeForIos = /crios.*safari/i.test(navigator.userAgent)
|
|
21
|
+
tlenv.isFirefox = /firefox/i.test(navigator.userAgent)
|
|
22
|
+
tlenv.isAndroid = /android/i.test(navigator.userAgent)
|
|
23
|
+
tlenv.isDarwin = window.navigator.userAgent.toLowerCase().indexOf('mac') > -1
|
|
24
|
+
tlenv.hasCanvasSupport =
|
|
25
|
+
typeof window !== 'undefined' && 'Promise' in window && 'HTMLCanvasElement' in window
|
|
81
26
|
}
|
|
82
27
|
|
|
83
|
-
export { tlenv
|
|
28
|
+
export { tlenv }
|
package/src/lib/globals/menus.ts
CHANGED
|
@@ -8,7 +8,6 @@ import { useEditor } from './useEditor'
|
|
|
8
8
|
|
|
9
9
|
export function useCanvasEvents() {
|
|
10
10
|
const editor = useEditor()
|
|
11
|
-
const ownerDocument = editor.getContainer().ownerDocument
|
|
12
11
|
const currentTool = useValue('current tool', () => editor.getCurrentTool(), [editor])
|
|
13
12
|
|
|
14
13
|
const events = useMemo(
|
|
@@ -181,11 +180,11 @@ export function useCanvasEvents() {
|
|
|
181
180
|
}
|
|
182
181
|
}
|
|
183
182
|
|
|
184
|
-
|
|
183
|
+
document.body.addEventListener('pointermove', onPointerMove)
|
|
185
184
|
return () => {
|
|
186
|
-
|
|
185
|
+
document.body.removeEventListener('pointermove', onPointerMove)
|
|
187
186
|
}
|
|
188
|
-
}, [editor, currentTool
|
|
187
|
+
}, [editor, currentTool])
|
|
189
188
|
|
|
190
189
|
return events
|
|
191
190
|
}
|
|
@@ -1,23 +1,66 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { tlenvReactive } from '../globals/environment'
|
|
1
|
+
import { useEffect } from 'react'
|
|
2
|
+
import { tlenv } from '../globals/environment'
|
|
4
3
|
import { useEditor } from './useEditor'
|
|
5
4
|
|
|
6
5
|
/** @internal */
|
|
7
6
|
export function useCoarsePointer() {
|
|
8
7
|
const editor = useEditor()
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
// We'll track our own state for the pointer type
|
|
11
|
+
let isCoarse = editor.getInstanceState().isCoarsePointer
|
|
12
|
+
|
|
13
|
+
// 1.
|
|
14
|
+
// We'll use pointer events to detect coarse pointer.
|
|
15
|
+
|
|
16
|
+
const handlePointerDown = (e: PointerEvent) => {
|
|
17
|
+
// when the user interacts with a mouse, we assume they have a fine pointer.
|
|
18
|
+
// otherwise, we assume they have a coarse pointer.
|
|
19
|
+
const isCoarseEvent = e.pointerType !== 'mouse'
|
|
20
|
+
if (isCoarse === isCoarseEvent) return
|
|
21
|
+
isCoarse = isCoarseEvent
|
|
22
|
+
editor.updateInstanceState({ isCoarsePointer: isCoarseEvent })
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// we need `capture: true` here because the tldraw component itself stops propagation on
|
|
26
|
+
// pointer events it receives.
|
|
27
|
+
window.addEventListener('pointerdown', handlePointerDown, { capture: true })
|
|
28
|
+
|
|
29
|
+
// 2.
|
|
30
|
+
// We can also use the media query to detect / set the initial pointer type
|
|
31
|
+
// and update the state if the pointer type changes.
|
|
32
|
+
|
|
33
|
+
// We want the touch / mouse events to run even if the browser does not
|
|
34
|
+
// support matchMedia. We'll have to handle the media query changes
|
|
35
|
+
// conditionally in the code below.
|
|
36
|
+
const mql = window.matchMedia && window.matchMedia('(any-pointer: coarse)')
|
|
37
|
+
|
|
38
|
+
// This is a workaround for a Firefox bug where we don't correctly
|
|
39
|
+
// detect coarse VS fine pointer. For now, let's assume that you have a fine
|
|
40
|
+
// pointer if you're on Firefox on desktop.
|
|
41
|
+
const isForcedFinePointer = tlenv.isFirefox && !tlenv.isAndroid && !tlenv.isIos
|
|
42
|
+
|
|
43
|
+
const handleMediaQueryChange = () => {
|
|
44
|
+
const next = isForcedFinePointer ? false : mql.matches // get the value from the media query
|
|
45
|
+
if (isCoarse !== next) return // bail if the value hasn't changed
|
|
46
|
+
isCoarse = next // update the local value
|
|
47
|
+
editor.updateInstanceState({ isCoarsePointer: next }) // update the value in state
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (mql) {
|
|
51
|
+
// set up the listener
|
|
52
|
+
mql.addEventListener('change', handleMediaQueryChange)
|
|
53
|
+
|
|
54
|
+
// and run the handler once to set the initial value
|
|
55
|
+
handleMediaQueryChange()
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return () => {
|
|
59
|
+
window.removeEventListener('pointerdown', handlePointerDown, { capture: true })
|
|
60
|
+
|
|
61
|
+
if (mql) {
|
|
62
|
+
mql.removeEventListener('change', handleMediaQueryChange)
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}, [editor])
|
|
23
66
|
}
|
|
@@ -27,7 +27,7 @@ import { useCallback, useDebugValue, useLayoutEffect, useRef } from 'react'
|
|
|
27
27
|
export function useEvent<Args extends Array<unknown>, Result>(
|
|
28
28
|
handler: (...args: Args) => Result
|
|
29
29
|
): (...args: Args) => Result {
|
|
30
|
-
const handlerRef = useRef<(
|
|
30
|
+
const handlerRef = useRef<(...args: Args) => Result>()
|
|
31
31
|
|
|
32
32
|
// In a real implementation, this would run before layout effects
|
|
33
33
|
useLayoutEffect(() => {
|
|
@@ -9,7 +9,7 @@ const IGNORED_TAGS = ['textarea', 'input']
|
|
|
9
9
|
* want this for drawing operations and can disable it by setting 'disableDoubleTapZoom' in the main
|
|
10
10
|
* editor.
|
|
11
11
|
*/
|
|
12
|
-
export function useFixSafariDoubleTapZoomPencilEvents(ref: React.RefObject<HTMLElement
|
|
12
|
+
export function useFixSafariDoubleTapZoomPencilEvents(ref: React.RefObject<HTMLElement>) {
|
|
13
13
|
const editor = useEditor()
|
|
14
14
|
|
|
15
15
|
useEffect(() => {
|
|
@@ -75,7 +75,7 @@ const isWheelEndEvent = (time: number) => {
|
|
|
75
75
|
return false
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
export function useGestureEvents(ref: React.RefObject<HTMLDivElement
|
|
78
|
+
export function useGestureEvents(ref: React.RefObject<HTMLDivElement>) {
|
|
79
79
|
const editor = useEditor()
|
|
80
80
|
|
|
81
81
|
const events = React.useMemo(() => {
|
|
@@ -105,7 +105,7 @@ export function useGestureEvents(ref: React.RefObject<HTMLDivElement | null>) {
|
|
|
105
105
|
const util = editor.getShapeUtil(shape)
|
|
106
106
|
if (util.canScroll(shape)) {
|
|
107
107
|
const bounds = editor.getShapePageBounds(editingShapeId)
|
|
108
|
-
if (bounds?.containsPoint(editor.inputs.
|
|
108
|
+
if (bounds?.containsPoint(editor.inputs.currentPagePoint)) {
|
|
109
109
|
return
|
|
110
110
|
}
|
|
111
111
|
}
|
|
@@ -4,7 +4,7 @@ import { useContainer } from './useContainer'
|
|
|
4
4
|
import { useMaybeEditor } from './useEditor'
|
|
5
5
|
|
|
6
6
|
/** @public */
|
|
7
|
-
export function usePassThroughMouseOverEvents(ref: RefObject<HTMLElement
|
|
7
|
+
export function usePassThroughMouseOverEvents(ref: RefObject<HTMLElement>) {
|
|
8
8
|
if (!ref) throw Error('usePassThroughWheelEvents must be passed a ref')
|
|
9
9
|
const container = useContainer()
|
|
10
10
|
const editor = useMaybeEditor()
|
|
@@ -4,7 +4,7 @@ import { useContainer } from './useContainer'
|
|
|
4
4
|
import { useMaybeEditor } from './useEditor'
|
|
5
5
|
|
|
6
6
|
/** @public */
|
|
7
|
-
export function usePassThroughWheelEvents(ref: RefObject<HTMLElement
|
|
7
|
+
export function usePassThroughWheelEvents(ref: RefObject<HTMLElement>) {
|
|
8
8
|
if (!ref) throw Error('usePassThroughWheelEvents must be passed a ref')
|
|
9
9
|
const container = useContainer()
|
|
10
10
|
const editor = useMaybeEditor()
|
|
@@ -2,7 +2,7 @@ import { throttle } from '@tldraw/utils'
|
|
|
2
2
|
import { useLayoutEffect } from 'react'
|
|
3
3
|
import { useEditor } from './useEditor'
|
|
4
4
|
|
|
5
|
-
export function useScreenBounds(ref: React.RefObject<HTMLElement
|
|
5
|
+
export function useScreenBounds(ref: React.RefObject<HTMLElement>) {
|
|
6
6
|
const editor = useEditor()
|
|
7
7
|
|
|
8
8
|
useLayoutEffect(() => {
|
|
@@ -9,10 +9,7 @@ export function useStateAttribute() {
|
|
|
9
9
|
// editor mounting and this attribute being applied, because styles may depend on it:
|
|
10
10
|
useLayoutEffect(() => {
|
|
11
11
|
return react('stateAttribute', () => {
|
|
12
|
-
|
|
13
|
-
const instanceState = editor.getInstanceState()
|
|
14
|
-
container.setAttribute('data-state', editor.getPath())
|
|
15
|
-
container.setAttribute('data-coarse', String(instanceState.isCoarsePointer))
|
|
12
|
+
editor.getContainer().setAttribute('data-state', editor.getPath())
|
|
16
13
|
})
|
|
17
14
|
}, [editor])
|
|
18
15
|
}
|
|
@@ -12,9 +12,14 @@ export function useZoomCss() {
|
|
|
12
12
|
const setScale = (s: number) => container.style.setProperty('--tl-zoom', s.toString())
|
|
13
13
|
const setScaleDebounced = debounce(setScale, 100)
|
|
14
14
|
|
|
15
|
-
const scheduler = new EffectScheduler('useZoomCss', () =>
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
const scheduler = new EffectScheduler('useZoomCss', () => {
|
|
16
|
+
const numShapes = editor.getCurrentPageShapeIds().size
|
|
17
|
+
if (numShapes < 300) {
|
|
18
|
+
setScale(editor.getZoomLevel())
|
|
19
|
+
} else {
|
|
20
|
+
setScaleDebounced(editor.getZoomLevel())
|
|
21
|
+
}
|
|
22
|
+
})
|
|
18
23
|
|
|
19
24
|
scheduler.attach()
|
|
20
25
|
scheduler.execute()
|
package/src/lib/options.ts
CHANGED
|
@@ -87,33 +87,6 @@ export interface TldrawOptions {
|
|
|
87
87
|
* Branding name of the app, currently only used for adding aria-label for the application.
|
|
88
88
|
*/
|
|
89
89
|
readonly branding?: string
|
|
90
|
-
/**
|
|
91
|
-
* Whether to use debounced zoom level for certain rendering optimizations. When true,
|
|
92
|
-
* `editor.getDebouncedZoomLevel()` returns a cached zoom value while the camera is moving,
|
|
93
|
-
* reducing re-renders. When false, it always returns the current zoom level.
|
|
94
|
-
*/
|
|
95
|
-
readonly debouncedZoom: boolean
|
|
96
|
-
/**
|
|
97
|
-
* The number of shapes that must be on the page for the debounced zoom level to be used.
|
|
98
|
-
* Defaults to 300 shapes.
|
|
99
|
-
*/
|
|
100
|
-
readonly debouncedZoomThreshold: number
|
|
101
|
-
/**
|
|
102
|
-
* Whether to allow spacebar panning. When true, the spacebar will pan the camera when held down.
|
|
103
|
-
* When false, the spacebar will not pan the camera.
|
|
104
|
-
*/
|
|
105
|
-
readonly spacebarPanning: boolean
|
|
106
|
-
/**
|
|
107
|
-
* The default padding (in pixels) used when zooming to fit content in the viewport.
|
|
108
|
-
* This affects methods like `zoomToFit()`, `zoomToSelection()`, and `zoomToBounds()`.
|
|
109
|
-
* The actual padding used is the minimum of this value and 28% of the viewport width.
|
|
110
|
-
* Defaults to 128 pixels.
|
|
111
|
-
*/
|
|
112
|
-
readonly zoomToFitPadding: number
|
|
113
|
-
/**
|
|
114
|
-
* The distance (in screen pixels) at which shapes snap to guides and other shapes.
|
|
115
|
-
*/
|
|
116
|
-
readonly snapThreshold: number
|
|
117
90
|
}
|
|
118
91
|
|
|
119
92
|
/** @public */
|
|
@@ -166,9 +139,4 @@ export const defaultTldrawOptions = {
|
|
|
166
139
|
enableToolbarKeyboardShortcuts: true,
|
|
167
140
|
maxFontsToLoadBeforeRender: Infinity,
|
|
168
141
|
nonce: undefined,
|
|
169
|
-
debouncedZoom: true,
|
|
170
|
-
debouncedZoomThreshold: 500,
|
|
171
|
-
spacebarPanning: true,
|
|
172
|
-
zoomToFitPadding: 128,
|
|
173
|
-
snapThreshold: 8,
|
|
174
142
|
} as const satisfies TldrawOptions
|
|
@@ -180,15 +180,6 @@ export class Box {
|
|
|
180
180
|
return new Vec(this.w, this.h)
|
|
181
181
|
}
|
|
182
182
|
|
|
183
|
-
isValid() {
|
|
184
|
-
return (
|
|
185
|
-
Number.isFinite(this.x) &&
|
|
186
|
-
Number.isFinite(this.y) &&
|
|
187
|
-
Number.isFinite(this.w) &&
|
|
188
|
-
Number.isFinite(this.h)
|
|
189
|
-
)
|
|
190
|
-
}
|
|
191
|
-
|
|
192
183
|
toFixed() {
|
|
193
184
|
this.x = toPrecision(this.x)
|
|
194
185
|
this.y = toPrecision(this.y)
|
|
@@ -140,7 +140,6 @@ export abstract class Geometry2d {
|
|
|
140
140
|
}
|
|
141
141
|
}
|
|
142
142
|
if (!nearest) throw Error('nearest point not found')
|
|
143
|
-
dist = Math.sqrt(dist) // return the actual distance, not the squared distance
|
|
144
143
|
return this.isClosed && this.isFilled && pointInPolygon(nearest, this.vertices) ? -dist : dist
|
|
145
144
|
}
|
|
146
145
|
|
|
@@ -95,8 +95,8 @@ export function kickoutOccludedShapes(
|
|
|
95
95
|
if (remainingShapesToReparent.size > 0) {
|
|
96
96
|
// The remaining shapes are going to be reparented to the old parent's containing group, if there was one, or else to the page
|
|
97
97
|
const newParentId =
|
|
98
|
-
editor.findShapeAncestor(prevParent, (s) => editor.isShapeOfType(s, 'group'))
|
|
99
|
-
|
|
98
|
+
editor.findShapeAncestor(prevParent, (s) => editor.isShapeOfType<TLGroupShape>(s, 'group'))
|
|
99
|
+
?.id ?? editor.getCurrentPageId()
|
|
100
100
|
|
|
101
101
|
remainingShapesToReparent.forEach((shape) => {
|
|
102
102
|
if (!parentsToNewChildren[newParentId]) {
|
|
@@ -211,7 +211,7 @@ export function getDroppedShapesToNewParents(
|
|
|
211
211
|
|
|
212
212
|
for (const shape of shapes) {
|
|
213
213
|
const parent = editor.getShapeParent(shape)
|
|
214
|
-
if (parent && editor.isShapeOfType(parent, 'group')) {
|
|
214
|
+
if (parent && editor.isShapeOfType<TLGroupShape>(parent, 'group')) {
|
|
215
215
|
if (!movingGroups.has(parent)) {
|
|
216
216
|
movingGroups.add(parent)
|
|
217
217
|
}
|
|
@@ -248,7 +248,7 @@ export function getDroppedShapesToNewParents(
|
|
|
248
248
|
parentCheck: for (let i = potentialParentShapes.length - 1; i >= 0; i--) {
|
|
249
249
|
const parentShape = potentialParentShapes[i]
|
|
250
250
|
const parentShapeContainingGroupId = editor.findShapeAncestor(parentShape, (s) =>
|
|
251
|
-
editor.isShapeOfType(s, 'group')
|
|
251
|
+
editor.isShapeOfType<TLGroupShape>(s, 'group')
|
|
252
252
|
)?.id
|
|
253
253
|
|
|
254
254
|
const parentGeometry = editor.getShapeGeometry(parentShape)
|
|
@@ -274,7 +274,7 @@ export function getDroppedShapesToNewParents(
|
|
|
274
274
|
if (!shapeGroupIds.has(shape.id)) {
|
|
275
275
|
shapeGroupIds.set(
|
|
276
276
|
shape.id,
|
|
277
|
-
editor.findShapeAncestor(shape, (s) => editor.isShapeOfType(s, 'group'))?.id
|
|
277
|
+
editor.findShapeAncestor(shape, (s) => editor.isShapeOfType<TLGroupShape>(s, 'group'))?.id
|
|
278
278
|
)
|
|
279
279
|
}
|
|
280
280
|
|
|
@@ -32,7 +32,7 @@ export function getRotationSnapshot({
|
|
|
32
32
|
|
|
33
33
|
return {
|
|
34
34
|
initialPageCenter,
|
|
35
|
-
initialCursorAngle: initialPageCenter.angle(editor.inputs.
|
|
35
|
+
initialCursorAngle: initialPageCenter.angle(editor.inputs.originPagePoint),
|
|
36
36
|
initialShapesRotation: rotation,
|
|
37
37
|
shapeSnapshots: shapes.map((shape) => ({
|
|
38
38
|
shape,
|
package/src/version.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// This file is automatically generated by internal/scripts/refresh-assets.ts.
|
|
2
2
|
// Do not edit manually. Or do, I'm a comment, not a cop.
|
|
3
3
|
|
|
4
|
-
export const version = '4.2.
|
|
4
|
+
export const version = '4.2.3'
|
|
5
5
|
export const publishDates = {
|
|
6
6
|
major: '2025-09-18T14:39:22.803Z',
|
|
7
|
-
minor: '2025-11-19T11:
|
|
8
|
-
patch: '2026-01-
|
|
7
|
+
minor: '2025-11-19T11:47:45.748Z',
|
|
8
|
+
patch: '2026-01-08T10:11:20.530Z',
|
|
9
9
|
}
|