@tldraw/editor 5.5.0-next.f9308d324e1c → 5.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-cjs/index.d.ts +49 -23
- package/dist-cjs/index.js +1 -1
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/TldrawEditor.js +16 -12
- package/dist-cjs/lib/TldrawEditor.js.map +2 -2
- package/dist-cjs/lib/components/MenuClickCapture.js +42 -3
- package/dist-cjs/lib/components/MenuClickCapture.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js +5 -1
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultErrorFallback.js +2 -5
- package/dist-cjs/lib/components/default-components/DefaultErrorFallback.js.map +3 -3
- package/dist-cjs/lib/components/default-components/DefaultSpinner.js.map +2 -2
- package/dist-cjs/lib/editor/Editor.js +168 -181
- package/dist-cjs/lib/editor/Editor.js.map +3 -3
- package/dist-cjs/lib/editor/derivations/bindingsIndex.js +2 -0
- package/dist-cjs/lib/editor/derivations/bindingsIndex.js.map +2 -2
- package/dist-cjs/lib/editor/managers/ClickManager/ClickManager.js +3 -2
- package/dist-cjs/lib/editor/managers/ClickManager/ClickManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/EditorManager.js +11 -2
- package/dist-cjs/lib/editor/managers/EditorManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/PerformanceManager/PerformanceManager.js +49 -63
- package/dist-cjs/lib/editor/managers/PerformanceManager/PerformanceManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/ScribbleManager/ScribbleManager.js +1 -1
- package/dist-cjs/lib/editor/managers/ScribbleManager/ScribbleManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/SnapManager/BoundsSnaps.js +24 -24
- package/dist-cjs/lib/editor/managers/SnapManager/BoundsSnaps.js.map +2 -2
- package/dist-cjs/lib/editor/managers/SnapManager/HandleSnaps.js +7 -1
- package/dist-cjs/lib/editor/managers/SnapManager/HandleSnaps.js.map +2 -2
- package/dist-cjs/lib/editor/managers/SnapManager/SnapManager.js +4 -3
- package/dist-cjs/lib/editor/managers/SnapManager/SnapManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/TextManager/TextManager.js +4 -4
- package/dist-cjs/lib/editor/managers/TextManager/TextManager.js.map +2 -2
- package/dist-cjs/lib/editor/shapes/group/GroupShapeUtil.js +14 -6
- package/dist-cjs/lib/editor/shapes/group/GroupShapeUtil.js.map +3 -3
- package/dist-cjs/lib/editor/types/external-content.js.map +1 -1
- package/dist-cjs/lib/exports/ExportDelay.js +10 -2
- package/dist-cjs/lib/exports/ExportDelay.js.map +2 -2
- package/dist-cjs/lib/exports/FontEmbedder.js +25 -11
- package/dist-cjs/lib/exports/FontEmbedder.js.map +2 -2
- package/dist-cjs/lib/exports/StyleEmbedder.js +9 -4
- package/dist-cjs/lib/exports/StyleEmbedder.js.map +2 -2
- package/dist-cjs/lib/exports/fetchCache.js +3 -0
- package/dist-cjs/lib/exports/fetchCache.js.map +2 -2
- package/dist-cjs/lib/exports/getSvgAsImage.js +10 -4
- package/dist-cjs/lib/exports/getSvgAsImage.js.map +2 -2
- package/dist-cjs/lib/exports/getSvgJsx.js +18 -9
- 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 +1 -1
- package/dist-cjs/lib/hooks/EditorComponentsContext.js.map +2 -2
- package/dist-cjs/lib/hooks/useCanvasEvents.js +24 -0
- package/dist-cjs/lib/hooks/useCanvasEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/useIdentity.js +6 -2
- package/dist-cjs/lib/hooks/useIdentity.js.map +3 -3
- package/dist-cjs/lib/license/LicenseManager.js +9 -1
- package/dist-cjs/lib/license/LicenseManager.js.map +2 -2
- package/dist-cjs/lib/license/LicenseProvider.js +12 -4
- package/dist-cjs/lib/license/LicenseProvider.js.map +2 -2
- package/dist-cjs/lib/utils/debug-flags.js +0 -6
- package/dist-cjs/lib/utils/debug-flags.js.map +2 -2
- package/dist-cjs/lib/utils/deepLinks.js +2 -1
- package/dist-cjs/lib/utils/deepLinks.js.map +2 -2
- package/dist-cjs/lib/utils/sync/LocalIndexedDb.js +32 -25
- package/dist-cjs/lib/utils/sync/LocalIndexedDb.js.map +2 -2
- package/dist-cjs/lib/utils/sync/TLLocalSyncClient.js +81 -40
- 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 +49 -23
- package/dist-esm/index.mjs +4 -2
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/TldrawEditor.mjs +17 -13
- package/dist-esm/lib/TldrawEditor.mjs.map +2 -2
- package/dist-esm/lib/components/MenuClickCapture.mjs +42 -3
- package/dist-esm/lib/components/MenuClickCapture.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +5 -1
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultErrorFallback.mjs +2 -5
- package/dist-esm/lib/components/default-components/DefaultErrorFallback.mjs.map +3 -3
- package/dist-esm/lib/components/default-components/DefaultSpinner.mjs.map +2 -2
- package/dist-esm/lib/editor/Editor.mjs +168 -181
- package/dist-esm/lib/editor/Editor.mjs.map +3 -3
- package/dist-esm/lib/editor/derivations/bindingsIndex.mjs +2 -0
- package/dist-esm/lib/editor/derivations/bindingsIndex.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/ClickManager/ClickManager.mjs +3 -2
- package/dist-esm/lib/editor/managers/ClickManager/ClickManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/EditorManager.mjs +11 -2
- package/dist-esm/lib/editor/managers/EditorManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/PerformanceManager/PerformanceManager.mjs +49 -63
- package/dist-esm/lib/editor/managers/PerformanceManager/PerformanceManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/ScribbleManager/ScribbleManager.mjs +1 -1
- package/dist-esm/lib/editor/managers/ScribbleManager/ScribbleManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/SnapManager/BoundsSnaps.mjs +24 -24
- package/dist-esm/lib/editor/managers/SnapManager/BoundsSnaps.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/SnapManager/HandleSnaps.mjs +7 -1
- package/dist-esm/lib/editor/managers/SnapManager/HandleSnaps.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/SnapManager/SnapManager.mjs +4 -3
- package/dist-esm/lib/editor/managers/SnapManager/SnapManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs +4 -4
- package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs.map +2 -2
- package/dist-esm/lib/editor/shapes/group/GroupShapeUtil.mjs +14 -6
- package/dist-esm/lib/editor/shapes/group/GroupShapeUtil.mjs.map +3 -3
- package/dist-esm/lib/exports/ExportDelay.mjs +11 -3
- package/dist-esm/lib/exports/ExportDelay.mjs.map +2 -2
- package/dist-esm/lib/exports/FontEmbedder.mjs +25 -11
- package/dist-esm/lib/exports/FontEmbedder.mjs.map +2 -2
- package/dist-esm/lib/exports/StyleEmbedder.mjs +9 -4
- package/dist-esm/lib/exports/StyleEmbedder.mjs.map +2 -2
- package/dist-esm/lib/exports/fetchCache.mjs +3 -0
- package/dist-esm/lib/exports/fetchCache.mjs.map +2 -2
- package/dist-esm/lib/exports/getSvgAsImage.mjs +10 -4
- package/dist-esm/lib/exports/getSvgAsImage.mjs.map +2 -2
- package/dist-esm/lib/exports/getSvgJsx.mjs +18 -9
- 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 +1 -1
- package/dist-esm/lib/hooks/EditorComponentsContext.mjs.map +2 -2
- package/dist-esm/lib/hooks/useCanvasEvents.mjs +24 -0
- package/dist-esm/lib/hooks/useCanvasEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useIdentity.mjs +7 -3
- package/dist-esm/lib/hooks/useIdentity.mjs.map +3 -3
- package/dist-esm/lib/license/LicenseManager.mjs +9 -1
- package/dist-esm/lib/license/LicenseManager.mjs.map +2 -2
- package/dist-esm/lib/license/LicenseProvider.mjs +13 -5
- package/dist-esm/lib/license/LicenseProvider.mjs.map +2 -2
- package/dist-esm/lib/utils/debug-flags.mjs +0 -6
- package/dist-esm/lib/utils/debug-flags.mjs.map +2 -2
- package/dist-esm/lib/utils/deepLinks.mjs +2 -1
- package/dist-esm/lib/utils/deepLinks.mjs.map +2 -2
- package/dist-esm/lib/utils/sync/LocalIndexedDb.mjs +32 -25
- package/dist-esm/lib/utils/sync/LocalIndexedDb.mjs.map +2 -2
- package/dist-esm/lib/utils/sync/TLLocalSyncClient.mjs +81 -40
- 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 +9 -1
- package/package.json +8 -11
- package/src/index.ts +5 -1
- package/src/lib/TldrawEditor.tsx +35 -21
- package/src/lib/components/MenuClickCapture.tsx +55 -4
- package/src/lib/components/default-components/DefaultCanvas.tsx +7 -1
- package/src/lib/components/default-components/DefaultErrorFallback.tsx +13 -5
- package/src/lib/components/default-components/DefaultSpinner.tsx +4 -1
- package/src/lib/editor/Editor.test.ts +65 -0
- package/src/lib/editor/Editor.ts +261 -294
- package/src/lib/editor/derivations/bindingsIndex.ts +3 -0
- package/src/lib/editor/managers/ClickManager/ClickManager.test.ts +1 -0
- package/src/lib/editor/managers/ClickManager/ClickManager.ts +3 -2
- package/src/lib/editor/managers/EditorManager.test.ts +32 -1
- package/src/lib/editor/managers/EditorManager.ts +15 -3
- package/src/lib/editor/managers/PerformanceManager/PerformanceManager.test.ts +80 -0
- package/src/lib/editor/managers/PerformanceManager/PerformanceManager.ts +54 -81
- package/src/lib/editor/managers/ScribbleManager/ScribbleManager.ts +1 -1
- package/src/lib/editor/managers/SnapManager/BoundsSnaps.ts +32 -36
- package/src/lib/editor/managers/SnapManager/HandleSnaps.ts +13 -2
- package/src/lib/editor/managers/SnapManager/SnapManager.test.ts +13 -0
- package/src/lib/editor/managers/SnapManager/SnapManager.ts +6 -4
- package/src/lib/editor/managers/TextManager/TextManager.test.ts +74 -0
- package/src/lib/editor/managers/TextManager/TextManager.ts +6 -5
- package/src/lib/editor/shapes/group/GroupShapeUtil.tsx +23 -8
- package/src/lib/editor/types/external-content.ts +5 -0
- package/src/lib/exports/ExportDelay.tsx +16 -4
- package/src/lib/exports/FontEmbedder.test.ts +99 -0
- package/src/lib/exports/FontEmbedder.ts +32 -11
- package/src/lib/exports/StyleEmbedder.ts +13 -4
- package/src/lib/exports/fetchCache.test.ts +22 -0
- package/src/lib/exports/fetchCache.ts +4 -0
- package/src/lib/exports/getSvgAsImage.ts +13 -5
- package/src/lib/exports/getSvgJsx.test.ts +43 -1
- package/src/lib/exports/getSvgJsx.tsx +28 -16
- package/src/lib/exports/parseCss.test.ts +4 -0
- package/src/lib/exports/parseCss.ts +2 -2
- package/src/lib/hooks/EditorComponentsContext.tsx +2 -1
- package/src/lib/hooks/useCanvasEvents.ts +42 -0
- package/src/lib/hooks/useIdentity.tsx +12 -1
- package/src/lib/license/LicenseManager.ts +13 -1
- package/src/lib/license/LicenseProvider.test.tsx +76 -0
- package/src/lib/license/LicenseProvider.tsx +19 -5
- package/src/lib/test/preserveFocus.test.tsx +81 -0
- package/src/lib/utils/debug-flags.ts +0 -6
- package/src/lib/utils/deepLinks.test.ts +15 -0
- package/src/lib/utils/deepLinks.ts +8 -3
- package/src/lib/utils/sync/LocalIndexedDb.test.ts +121 -1
- package/src/lib/utils/sync/LocalIndexedDb.ts +41 -28
- package/src/lib/utils/sync/TLLocalSyncClient.test.ts +257 -1
- package/src/lib/utils/sync/TLLocalSyncClient.ts +112 -54
- package/src/version.ts +3 -3
- package/dist-cjs/lib/primitives/geometry/geometry.bench.js +0 -133
- package/dist-cjs/lib/primitives/geometry/geometry.bench.js.map +0 -7
- package/dist-esm/lib/primitives/geometry/geometry.bench.mjs +0 -132
- package/dist-esm/lib/primitives/geometry/geometry.bench.mjs.map +0 -7
- package/src/lib/primitives/geometry/geometry.bench.ts +0 -179
package/src/index.ts
CHANGED
|
@@ -25,6 +25,7 @@ export {
|
|
|
25
25
|
export {
|
|
26
26
|
DefaultErrorFallback,
|
|
27
27
|
type TLErrorFallbackComponent,
|
|
28
|
+
type TLErrorFallbackProps,
|
|
28
29
|
} from './lib/components/default-components/DefaultErrorFallback'
|
|
29
30
|
export { DefaultGrid, type TLGridProps } from './lib/components/default-components/DefaultGrid'
|
|
30
31
|
export { type TLShapeErrorFallbackComponent } from './lib/components/default-components/DefaultShapeErrorFallback'
|
|
@@ -32,7 +33,10 @@ export {
|
|
|
32
33
|
DefaultShapeWrapper,
|
|
33
34
|
type TLShapeWrapperProps,
|
|
34
35
|
} from './lib/components/default-components/DefaultShapeWrapper'
|
|
35
|
-
export {
|
|
36
|
+
export {
|
|
37
|
+
DefaultSpinner,
|
|
38
|
+
type TLSpinnerProps,
|
|
39
|
+
} from './lib/components/default-components/DefaultSpinner'
|
|
36
40
|
export { DefaultSvgDefs } from './lib/components/default-components/DefaultSvgDefs'
|
|
37
41
|
export {
|
|
38
42
|
EditorPortal,
|
package/src/lib/TldrawEditor.tsx
CHANGED
|
@@ -46,7 +46,7 @@ import { EditorProvider, useEditor } from './hooks/useEditor'
|
|
|
46
46
|
import { EditorComponentsProvider } from './hooks/useEditorComponents'
|
|
47
47
|
import { useEvent } from './hooks/useEvent'
|
|
48
48
|
import { useForceUpdate } from './hooks/useForceUpdate'
|
|
49
|
-
import { useShallowObjectIdentity } from './hooks/useIdentity'
|
|
49
|
+
import { useDeepObjectIdentity, useShallowObjectIdentity } from './hooks/useIdentity'
|
|
50
50
|
import { useLocalStore } from './hooks/useLocalStore'
|
|
51
51
|
import { useRefState } from './hooks/useRefState'
|
|
52
52
|
import { useStateAttribute } from './hooks/useStateAttribute'
|
|
@@ -106,11 +106,7 @@ export interface TldrawEditorWithoutStoreProps extends TLStoreBaseOptions {
|
|
|
106
106
|
/** @public */
|
|
107
107
|
export type TldrawEditorStoreProps = TldrawEditorWithStoreProps | TldrawEditorWithoutStoreProps
|
|
108
108
|
|
|
109
|
-
/**
|
|
110
|
-
* Props for the {@link tldraw#Tldraw} and {@link TldrawEditor} components.
|
|
111
|
-
*
|
|
112
|
-
* @public
|
|
113
|
-
**/
|
|
109
|
+
/** @public */
|
|
114
110
|
export type TldrawEditorProps = TldrawEditorBaseProps & TldrawEditorStoreProps
|
|
115
111
|
|
|
116
112
|
/**
|
|
@@ -284,7 +280,13 @@ const EMPTY_TOOLS_ARRAY = [] as const
|
|
|
284
280
|
/** @internal */
|
|
285
281
|
export const TL_CONTAINER_CLASS = 'tl-container'
|
|
286
282
|
|
|
287
|
-
/**
|
|
283
|
+
/**
|
|
284
|
+
* The editor component without any of the default shapes, tools, or UI. It renders the canvas, or
|
|
285
|
+
* your own children in its place, with the shape utils, binding utils, tools, and components you
|
|
286
|
+
* pass in; the `Tldraw` component in the `tldraw` package wraps it with those defaults.
|
|
287
|
+
*
|
|
288
|
+
* @public @react
|
|
289
|
+
*/
|
|
288
290
|
export const TldrawEditor = memo(function TldrawEditor({
|
|
289
291
|
store,
|
|
290
292
|
components,
|
|
@@ -311,18 +313,24 @@ export const TldrawEditor = memo(function TldrawEditor({
|
|
|
311
313
|
const ErrorFallback =
|
|
312
314
|
components?.ErrorFallback === undefined ? DefaultErrorFallback : components?.ErrorFallback
|
|
313
315
|
|
|
314
|
-
// Merge deprecated props with options
|
|
315
|
-
//
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
316
|
+
// Merge deprecated props with options (options win). `options` is a dependency of the
|
|
317
|
+
// editor-creating effect, so it's shallow-stabilised below; the nested objects are
|
|
318
|
+
// deep-stabilised here first, or an inline `options={{ camera: { ... } }}` would still
|
|
319
|
+
// recreate the editor on every render. `text` needs the deep comparison as well: `<Tldraw>`
|
|
320
|
+
// builds a fresh `tipTapConfig` inside it whenever its own `options.text` is a new identity.
|
|
321
|
+
const camera = useDeepObjectIdentity(_options?.camera)
|
|
322
|
+
const gridSteps = useDeepObjectIdentity(_options?.gridSteps)
|
|
323
|
+
const text = useDeepObjectIdentity(_options?.text ?? _textOptions)
|
|
324
|
+
const mergedDeepLinks = _options?.deepLinks ?? _deepLinks
|
|
325
|
+
const deepLinkOptions = useDeepObjectIdentity(
|
|
326
|
+
mergedDeepLinks === true ? undefined : mergedDeepLinks
|
|
327
|
+
)
|
|
328
|
+
const deepLinks = mergedDeepLinks === true ? true : deepLinkOptions
|
|
329
|
+
let mergedOptions = _options
|
|
330
|
+
if (camera !== undefined) mergedOptions = { ...mergedOptions, camera }
|
|
331
|
+
if (gridSteps !== undefined) mergedOptions = { ...mergedOptions, gridSteps }
|
|
332
|
+
if (text !== undefined) mergedOptions = { ...mergedOptions, text }
|
|
333
|
+
if (deepLinks !== undefined) mergedOptions = { ...mergedOptions, deepLinks }
|
|
326
334
|
|
|
327
335
|
// apply defaults. if you're using the bare @tldraw/editor package, we
|
|
328
336
|
// default these to the "tldraw zero" configuration. We have different
|
|
@@ -669,19 +677,25 @@ function TldrawEditorWithReadyStore({
|
|
|
669
677
|
useEffect(
|
|
670
678
|
function handleFocusOnPointerDownForPreserveFocusMode() {
|
|
671
679
|
if (!editor) return
|
|
680
|
+
const container = editor.getContainer()
|
|
672
681
|
|
|
673
682
|
function handleFocusOnPointerDown() {
|
|
674
683
|
if (!editor) return
|
|
675
684
|
editor.focus()
|
|
676
685
|
}
|
|
677
686
|
|
|
678
|
-
function handleBlurOnPointerDown() {
|
|
687
|
+
function handleBlurOnPointerDown(e: PointerEvent) {
|
|
679
688
|
if (!editor) return
|
|
689
|
+
// The same pointerdown bubbles from the container to the body; blurring here would
|
|
690
|
+
// cancel the interaction the container listener just focused for. Check the composed
|
|
691
|
+
// path rather than `e.target`: when the editor lives in an open shadow root the target
|
|
692
|
+
// is retargeted to the shadow host by the time the event reaches the body. (A closed
|
|
693
|
+
// shadow root truncates the path at the host, so those still blur.)
|
|
694
|
+
if (e.composedPath().includes(container)) return
|
|
680
695
|
editor.blur()
|
|
681
696
|
}
|
|
682
697
|
|
|
683
698
|
if (autoFocus && noAutoFocus()) {
|
|
684
|
-
const container = editor.getContainer()
|
|
685
699
|
container.addEventListener('pointerdown', handleFocusOnPointerDown)
|
|
686
700
|
container.ownerDocument.body.addEventListener('pointerdown', handleBlurOnPointerDown)
|
|
687
701
|
|
|
@@ -29,6 +29,7 @@ export function MenuClickCapture() {
|
|
|
29
29
|
isDown: false,
|
|
30
30
|
isDragging: false,
|
|
31
31
|
button: 0,
|
|
32
|
+
pointerId: -1,
|
|
32
33
|
start: new Vec(),
|
|
33
34
|
})
|
|
34
35
|
|
|
@@ -69,6 +70,11 @@ export function MenuClickCapture() {
|
|
|
69
70
|
|
|
70
71
|
const handlePointerDown = useCallback(
|
|
71
72
|
(e: PointerEvent) => {
|
|
73
|
+
// This overlay tracks a single press. A second pointer landing while one is active —
|
|
74
|
+
// a palm resting on the glass beside a pen — must not take over the gesture, or its
|
|
75
|
+
// own cancel would end the press it stole.
|
|
76
|
+
if (rPointerState.current.isDown) return
|
|
77
|
+
|
|
72
78
|
const button = getPointerEventButton(e)
|
|
73
79
|
if (button !== 0 && button !== 2) return
|
|
74
80
|
|
|
@@ -94,6 +100,7 @@ export function MenuClickCapture() {
|
|
|
94
100
|
isDown: true,
|
|
95
101
|
isDragging: false,
|
|
96
102
|
button,
|
|
103
|
+
pointerId: e.pointerId,
|
|
97
104
|
start: new Vec(e.clientX, e.clientY),
|
|
98
105
|
}
|
|
99
106
|
|
|
@@ -111,7 +118,7 @@ export function MenuClickCapture() {
|
|
|
111
118
|
const handlePointerMove = useCallback(
|
|
112
119
|
(e: PointerEvent) => {
|
|
113
120
|
const state = rPointerState.current
|
|
114
|
-
if (!state.isDown) return
|
|
121
|
+
if (!state.isDown || state.pointerId !== e.pointerId) return
|
|
115
122
|
|
|
116
123
|
// Left-click: wait for the drag threshold before forwarding anything, then
|
|
117
124
|
// replay pointerdown at the original start so the editor records the
|
|
@@ -144,15 +151,17 @@ export function MenuClickCapture() {
|
|
|
144
151
|
|
|
145
152
|
const handlePointerUp = useCallback(
|
|
146
153
|
(e: PointerEvent) => {
|
|
147
|
-
const
|
|
148
|
-
|
|
154
|
+
const state = rPointerState.current
|
|
155
|
+
if (!state.isDown || state.pointerId !== e.pointerId) return
|
|
156
|
+
|
|
157
|
+
const isStaticRightClick = state.button === 2 && !state.isDragging
|
|
149
158
|
|
|
150
159
|
editor.dispatch({
|
|
151
160
|
type: 'pointer',
|
|
152
161
|
target: 'canvas',
|
|
153
162
|
name: 'pointer_up',
|
|
154
163
|
...getPointerInfo(editor, e),
|
|
155
|
-
button:
|
|
164
|
+
button: state.button === 2 ? 2 : getPointerEventButton(e),
|
|
156
165
|
})
|
|
157
166
|
|
|
158
167
|
if (isStaticRightClick && editor.options.rightClickPanning) {
|
|
@@ -183,12 +192,53 @@ export function MenuClickCapture() {
|
|
|
183
192
|
isDown: false,
|
|
184
193
|
isDragging: false,
|
|
185
194
|
button: 0,
|
|
195
|
+
pointerId: -1,
|
|
186
196
|
start: new Vec(e.clientX, e.clientY),
|
|
187
197
|
}
|
|
188
198
|
},
|
|
189
199
|
[editor]
|
|
190
200
|
)
|
|
191
201
|
|
|
202
|
+
const handlePointerCancel = useCallback(
|
|
203
|
+
(e: PointerEvent) => {
|
|
204
|
+
const state = rPointerState.current
|
|
205
|
+
if (!state.isDown || state.pointerId !== e.pointerId) {
|
|
206
|
+
// Either a right-click press that was forwarded to the canvas, or a pointer this
|
|
207
|
+
// overlay never tracked. Neither is ours to end, so let the canvas handler decide.
|
|
208
|
+
canvasEvents.onPointerCancel?.(e)
|
|
209
|
+
return
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// The canvas's own cancel handler doesn't know about this element's pointer
|
|
213
|
+
// state, so without this the overlay stays mounted over the canvas and
|
|
214
|
+
// swallows the next interaction after the browser cancels a press.
|
|
215
|
+
if (editor.inputs.getIsPointing()) {
|
|
216
|
+
editor.interrupt()
|
|
217
|
+
editor.dispatch({
|
|
218
|
+
type: 'pointer',
|
|
219
|
+
target: 'canvas',
|
|
220
|
+
name: 'pointer_up',
|
|
221
|
+
...getPointerInfo(editor, e),
|
|
222
|
+
// pointercancel reports button -1
|
|
223
|
+
button: state.button,
|
|
224
|
+
})
|
|
225
|
+
} else {
|
|
226
|
+
editor.markEventAsHandled(e)
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
releasePointerCapture(e.currentTarget, e)
|
|
230
|
+
setIsPointing(false)
|
|
231
|
+
rPointerState.current = {
|
|
232
|
+
isDown: false,
|
|
233
|
+
isDragging: false,
|
|
234
|
+
button: 0,
|
|
235
|
+
pointerId: -1,
|
|
236
|
+
start: new Vec(e.clientX, e.clientY),
|
|
237
|
+
}
|
|
238
|
+
},
|
|
239
|
+
[canvasEvents, editor]
|
|
240
|
+
)
|
|
241
|
+
|
|
192
242
|
return (
|
|
193
243
|
showElement && (
|
|
194
244
|
<div
|
|
@@ -198,6 +248,7 @@ export function MenuClickCapture() {
|
|
|
198
248
|
onPointerDown={handlePointerDown}
|
|
199
249
|
onPointerMove={handlePointerMove}
|
|
200
250
|
onPointerUp={handlePointerUp}
|
|
251
|
+
onPointerCancel={handlePointerCancel}
|
|
201
252
|
onContextMenu={(e) => {
|
|
202
253
|
e.preventDefault()
|
|
203
254
|
e.stopPropagation()
|
|
@@ -119,7 +119,13 @@ export function DefaultCanvas({ className }: TLCanvasComponentProps) {
|
|
|
119
119
|
[editor]
|
|
120
120
|
)
|
|
121
121
|
|
|
122
|
-
|
|
122
|
+
// Gated on debug mode so a flag left on can't strand the user on a blank canvas with no
|
|
123
|
+
// debug menu to turn it back off.
|
|
124
|
+
const hideShapes = useValue(
|
|
125
|
+
'debug_shapes',
|
|
126
|
+
() => debugFlags.hideShapes.get() && editor.getInstanceState().isDebugMode,
|
|
127
|
+
[editor]
|
|
128
|
+
)
|
|
123
129
|
|
|
124
130
|
const isGridMode = useValue('isGridMode', () => editor.getInstanceState().isGridMode, [editor])
|
|
125
131
|
const { Grid } = useEditorComponents()
|
|
@@ -13,13 +13,21 @@ import { ErrorBoundary } from '../ErrorBoundary'
|
|
|
13
13
|
const BASE_ERROR_URL = 'https://github.com/tldraw/tldraw/issues/new'
|
|
14
14
|
|
|
15
15
|
/** @public */
|
|
16
|
-
export
|
|
16
|
+
export interface TLErrorFallbackProps {
|
|
17
|
+
/** The error that was caught. */
|
|
18
|
+
error: unknown
|
|
19
|
+
/**
|
|
20
|
+
* Only set when the caller renders the fallback with an editor; the editor's own error
|
|
21
|
+
* boundaries pass just `error`.
|
|
22
|
+
*/
|
|
23
|
+
editor?: Editor
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** @public */
|
|
27
|
+
export type TLErrorFallbackComponent = ComponentType<TLErrorFallbackProps>
|
|
17
28
|
|
|
18
29
|
/** @public @react */
|
|
19
|
-
export
|
|
20
|
-
error,
|
|
21
|
-
editor,
|
|
22
|
-
}) {
|
|
30
|
+
export function DefaultErrorFallback({ error, editor }: TLErrorFallbackProps) {
|
|
23
31
|
const containerRef = useRef<HTMLDivElement>(null)
|
|
24
32
|
const [shouldShowError, setShouldShowError] = useState(process.env.NODE_ENV === 'development')
|
|
25
33
|
const [didCopy, setDidCopy] = useState(false)
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import classNames from 'classnames'
|
|
2
2
|
|
|
3
|
+
/** @public */
|
|
4
|
+
export type TLSpinnerProps = React.SVGProps<SVGSVGElement>
|
|
5
|
+
|
|
3
6
|
/** @public @react */
|
|
4
|
-
export function DefaultSpinner(props:
|
|
7
|
+
export function DefaultSpinner(props: TLSpinnerProps) {
|
|
5
8
|
return (
|
|
6
9
|
<svg
|
|
7
10
|
width={16}
|
|
@@ -96,6 +96,26 @@ describe('updateShape', () => {
|
|
|
96
96
|
})
|
|
97
97
|
})
|
|
98
98
|
|
|
99
|
+
describe('setErasingShapes', () => {
|
|
100
|
+
it('sorts a copy of the ids rather than the array the caller passed in', () => {
|
|
101
|
+
const a = createShapeId('a')
|
|
102
|
+
const b = createShapeId('b')
|
|
103
|
+
editor.createShapes([
|
|
104
|
+
{ id: a, type: 'my-custom-shape', props: { w: 100, h: 100, text: undefined } },
|
|
105
|
+
{ id: b, type: 'my-custom-shape', props: { w: 100, h: 100, text: undefined } },
|
|
106
|
+
])
|
|
107
|
+
|
|
108
|
+
// the store freezes the arrays it owns, so sorting one in place throws
|
|
109
|
+
const ids = [b, a]
|
|
110
|
+
Object.freeze(ids)
|
|
111
|
+
|
|
112
|
+
editor.setErasingShapes(ids)
|
|
113
|
+
|
|
114
|
+
expect(ids).toEqual([b, a])
|
|
115
|
+
expect(editor.getErasingShapeIds()).toEqual([a, b])
|
|
116
|
+
})
|
|
117
|
+
})
|
|
118
|
+
|
|
99
119
|
describe('updateViewportScreenBounds', () => {
|
|
100
120
|
it('bails without crashing or updating bounds when the container document has no body', () => {
|
|
101
121
|
const documentSpy = vi
|
|
@@ -1101,6 +1121,51 @@ describe('dispatch event emission', () => {
|
|
|
1101
1121
|
|
|
1102
1122
|
expect(eventHandler).toHaveBeenCalledWith(pinchEndEvent)
|
|
1103
1123
|
})
|
|
1124
|
+
|
|
1125
|
+
it('still ends a pinch when the camera is locked mid-gesture', () => {
|
|
1126
|
+
const pinchStartEvent = {
|
|
1127
|
+
type: 'pinch' as const,
|
|
1128
|
+
name: 'pinch_start' as const,
|
|
1129
|
+
point: { x: 100, y: 100, z: 1 },
|
|
1130
|
+
delta: { x: 0, y: 0, z: 0 },
|
|
1131
|
+
shiftKey: false,
|
|
1132
|
+
altKey: false,
|
|
1133
|
+
ctrlKey: false,
|
|
1134
|
+
metaKey: false,
|
|
1135
|
+
accelKey: false,
|
|
1136
|
+
}
|
|
1137
|
+
testEditor.dispatch(pinchStartEvent)
|
|
1138
|
+
testEditor.emit('tick', 16)
|
|
1139
|
+
expect(testEditor.inputs.getIsPinching()).toBe(true)
|
|
1140
|
+
|
|
1141
|
+
// Locking only stops the camera: pinch_end must still clear isPinching, otherwise
|
|
1142
|
+
// every pointer event is ignored from here on.
|
|
1143
|
+
testEditor.setCameraOptions({ isLocked: true })
|
|
1144
|
+
testEditor.dispatch({ ...pinchStartEvent, name: 'pinch_end' })
|
|
1145
|
+
testEditor.emit('tick', 16)
|
|
1146
|
+
expect(testEditor.inputs.getIsPinching()).toBe(false)
|
|
1147
|
+
})
|
|
1148
|
+
|
|
1149
|
+
it('ignores the stylus eraser button when no eraser tool is registered', () => {
|
|
1150
|
+
const pointerDown = {
|
|
1151
|
+
type: 'pointer' as const,
|
|
1152
|
+
name: 'pointer_down' as const,
|
|
1153
|
+
target: 'canvas' as const,
|
|
1154
|
+
point: { x: 100, y: 100, z: 0.5 },
|
|
1155
|
+
pointerId: 1,
|
|
1156
|
+
button: 5,
|
|
1157
|
+
isPen: true,
|
|
1158
|
+
shiftKey: false,
|
|
1159
|
+
altKey: false,
|
|
1160
|
+
ctrlKey: false,
|
|
1161
|
+
metaKey: false,
|
|
1162
|
+
accelKey: false,
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
expect(() => testEditor.dispatch(pointerDown)).not.toThrow()
|
|
1166
|
+
expect(() => testEditor.dispatch({ ...pointerDown, name: 'pointer_up' })).not.toThrow()
|
|
1167
|
+
expect(testEditor.getCrashingError()).toBeNull()
|
|
1168
|
+
})
|
|
1104
1169
|
})
|
|
1105
1170
|
|
|
1106
1171
|
describe('setTool', () => {
|