@tldraw/editor 5.4.0-next.ef99ab47e5ce → 5.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-cjs/index.d.ts +114 -47
- package/dist-cjs/index.js +4 -1
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/TldrawEditor.js +7 -2
- package/dist-cjs/lib/TldrawEditor.js.map +2 -2
- package/dist-cjs/lib/components/MenuClickCapture.js +6 -8
- package/dist-cjs/lib/components/MenuClickCapture.js.map +2 -2
- package/dist-cjs/lib/components/default-components/CanvasOverlays.js +1 -3
- package/dist-cjs/lib/components/default-components/CanvasOverlays.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 +1 -1
- package/dist-cjs/lib/config/TLUserPreferences.js +6 -2
- package/dist-cjs/lib/config/TLUserPreferences.js.map +2 -2
- package/dist-cjs/lib/config/createTLStore.js +1 -1
- package/dist-cjs/lib/config/createTLStore.js.map +2 -2
- package/dist-cjs/lib/editor/Editor.js +181 -294
- package/dist-cjs/lib/editor/Editor.js.map +2 -2
- package/dist-cjs/lib/editor/derivations/shapeIdsInCurrentPage.js +7 -3
- package/dist-cjs/lib/editor/derivations/shapeIdsInCurrentPage.js.map +2 -2
- package/dist-cjs/lib/editor/managers/ClickManager/ClickManager.js +3 -3
- package/dist-cjs/lib/editor/managers/ClickManager/ClickManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.js +8 -8
- package/dist-cjs/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/FontManager/FontManager.js +2 -1
- package/dist-cjs/lib/editor/managers/FontManager/FontManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/InputsManager/InputsManager.js +79 -6
- package/dist-cjs/lib/editor/managers/InputsManager/InputsManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/ScribbleManager/ScribbleManager.js +7 -0
- package/dist-cjs/lib/editor/managers/ScribbleManager/ScribbleManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/SnapManager/BoundsSnaps.js +0 -2
- package/dist-cjs/lib/editor/managers/SnapManager/BoundsSnaps.js.map +2 -2
- package/dist-cjs/lib/editor/managers/TextManager/TextManager.js +1 -2
- package/dist-cjs/lib/editor/managers/TextManager/TextManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/TickManager/TickManager.js +6 -3
- package/dist-cjs/lib/editor/managers/TickManager/TickManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js +12 -1
- package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js.map +2 -2
- package/dist-cjs/lib/editor/overlays/OverlayManager.js +3 -7
- package/dist-cjs/lib/editor/overlays/OverlayManager.js.map +2 -2
- package/dist-cjs/lib/editor/overlays/strokeShapeIndicators.js +0 -1
- package/dist-cjs/lib/editor/overlays/strokeShapeIndicators.js.map +2 -2
- package/dist-cjs/lib/editor/shapes/BaseFrameLikeShapeUtil.js +3 -1
- package/dist-cjs/lib/editor/shapes/BaseFrameLikeShapeUtil.js.map +2 -2
- package/dist-cjs/lib/editor/shapes/shared/getPerfectDashProps.js +1 -0
- package/dist-cjs/lib/editor/shapes/shared/getPerfectDashProps.js.map +2 -2
- package/dist-cjs/lib/editor/tools/BaseBoxShapeTool/children/Pointing.js +1 -1
- package/dist-cjs/lib/editor/tools/BaseBoxShapeTool/children/Pointing.js.map +2 -2
- package/dist-cjs/lib/editor/tools/StateNode.js +3 -2
- package/dist-cjs/lib/editor/tools/StateNode.js.map +2 -2
- package/dist-cjs/lib/globals/editors.js +57 -0
- package/dist-cjs/lib/globals/editors.js.map +7 -0
- package/dist-cjs/lib/globals/menus.js +9 -4
- package/dist-cjs/lib/globals/menus.js.map +2 -2
- package/dist-cjs/lib/hooks/useCanvasEvents.js +2 -0
- package/dist-cjs/lib/hooks/useCanvasEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/useDocumentEvents.js +39 -9
- package/dist-cjs/lib/hooks/useDocumentEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/useLocalStore.js +10 -6
- package/dist-cjs/lib/hooks/useLocalStore.js.map +2 -2
- package/dist-cjs/lib/hooks/usePassThroughWheelEvents.js +1 -0
- package/dist-cjs/lib/hooks/usePassThroughWheelEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/usePeerIds.js +2 -1
- package/dist-cjs/lib/hooks/usePeerIds.js.map +2 -2
- package/dist-cjs/lib/license/LicenseManager.js +9 -2
- package/dist-cjs/lib/license/LicenseManager.js.map +2 -2
- package/dist-cjs/lib/license/LicenseProvider.js +16 -3
- package/dist-cjs/lib/license/LicenseProvider.js.map +2 -2
- package/dist-cjs/lib/license/useLicenseManagerState.js +5 -4
- package/dist-cjs/lib/license/useLicenseManagerState.js.map +2 -2
- package/dist-cjs/lib/primitives/Box.js +2 -1
- package/dist-cjs/lib/primitives/Box.js.map +2 -2
- package/dist-cjs/lib/primitives/Vec.js +4 -3
- package/dist-cjs/lib/primitives/Vec.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Group2d.js +63 -21
- package/dist-cjs/lib/primitives/geometry/Group2d.js.map +2 -2
- package/dist-cjs/lib/primitives/utils.js +2 -1
- package/dist-cjs/lib/primitives/utils.js.map +2 -2
- package/dist-cjs/lib/utils/deepLinks.js +5 -1
- package/dist-cjs/lib/utils/deepLinks.js.map +2 -2
- package/dist-cjs/lib/utils/normalizeWheel.js +2 -0
- package/dist-cjs/lib/utils/normalizeWheel.js.map +2 -2
- package/dist-cjs/lib/utils/rotation.js +1 -9
- package/dist-cjs/lib/utils/rotation.js.map +2 -2
- package/dist-cjs/lib/utils/sync/TLLocalSyncClient.js +17 -0
- package/dist-cjs/lib/utils/sync/TLLocalSyncClient.js.map +2 -2
- package/dist-cjs/lib/utils/sync/alerts.js +1 -1
- package/dist-cjs/lib/utils/sync/alerts.js.map +1 -1
- package/dist-cjs/version.js +3 -3
- package/dist-cjs/version.js.map +1 -1
- package/dist-esm/index.d.mts +114 -47
- package/dist-esm/index.mjs +9 -2
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/TldrawEditor.mjs +9 -4
- package/dist-esm/lib/TldrawEditor.mjs.map +2 -2
- package/dist-esm/lib/components/MenuClickCapture.mjs +6 -8
- package/dist-esm/lib/components/MenuClickCapture.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/CanvasOverlays.mjs +1 -3
- package/dist-esm/lib/components/default-components/CanvasOverlays.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 +1 -1
- package/dist-esm/lib/config/TLUserPreferences.mjs +6 -2
- package/dist-esm/lib/config/TLUserPreferences.mjs.map +2 -2
- package/dist-esm/lib/config/createTLStore.mjs +1 -1
- package/dist-esm/lib/config/createTLStore.mjs.map +2 -2
- package/dist-esm/lib/editor/Editor.mjs +189 -295
- package/dist-esm/lib/editor/Editor.mjs.map +2 -2
- package/dist-esm/lib/editor/derivations/shapeIdsInCurrentPage.mjs +7 -3
- package/dist-esm/lib/editor/derivations/shapeIdsInCurrentPage.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/ClickManager/ClickManager.mjs +3 -3
- package/dist-esm/lib/editor/managers/ClickManager/ClickManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.mjs +9 -9
- package/dist-esm/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/FontManager/FontManager.mjs +2 -1
- package/dist-esm/lib/editor/managers/FontManager/FontManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/InputsManager/InputsManager.mjs +81 -8
- package/dist-esm/lib/editor/managers/InputsManager/InputsManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/ScribbleManager/ScribbleManager.mjs +7 -0
- package/dist-esm/lib/editor/managers/ScribbleManager/ScribbleManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/SnapManager/BoundsSnaps.mjs +0 -2
- package/dist-esm/lib/editor/managers/SnapManager/BoundsSnaps.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs +2 -3
- package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/TickManager/TickManager.mjs +6 -3
- package/dist-esm/lib/editor/managers/TickManager/TickManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs +12 -1
- package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs.map +2 -2
- package/dist-esm/lib/editor/overlays/OverlayManager.mjs +3 -7
- package/dist-esm/lib/editor/overlays/OverlayManager.mjs.map +2 -2
- package/dist-esm/lib/editor/overlays/strokeShapeIndicators.mjs +0 -1
- package/dist-esm/lib/editor/overlays/strokeShapeIndicators.mjs.map +2 -2
- package/dist-esm/lib/editor/shapes/BaseFrameLikeShapeUtil.mjs +3 -1
- package/dist-esm/lib/editor/shapes/BaseFrameLikeShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/editor/shapes/shared/getPerfectDashProps.mjs +1 -0
- package/dist-esm/lib/editor/shapes/shared/getPerfectDashProps.mjs.map +2 -2
- package/dist-esm/lib/editor/tools/BaseBoxShapeTool/children/Pointing.mjs +1 -1
- package/dist-esm/lib/editor/tools/BaseBoxShapeTool/children/Pointing.mjs.map +2 -2
- package/dist-esm/lib/editor/tools/StateNode.mjs +3 -2
- package/dist-esm/lib/editor/tools/StateNode.mjs.map +2 -2
- package/dist-esm/lib/globals/editors.mjs +37 -0
- package/dist-esm/lib/globals/editors.mjs.map +7 -0
- package/dist-esm/lib/globals/menus.mjs +9 -4
- package/dist-esm/lib/globals/menus.mjs.map +2 -2
- package/dist-esm/lib/hooks/useCanvasEvents.mjs +2 -0
- package/dist-esm/lib/hooks/useCanvasEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useDocumentEvents.mjs +40 -10
- package/dist-esm/lib/hooks/useDocumentEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useLocalStore.mjs +11 -7
- package/dist-esm/lib/hooks/useLocalStore.mjs.map +2 -2
- package/dist-esm/lib/hooks/usePassThroughWheelEvents.mjs +1 -0
- package/dist-esm/lib/hooks/usePassThroughWheelEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/usePeerIds.mjs +2 -1
- package/dist-esm/lib/hooks/usePeerIds.mjs.map +2 -2
- package/dist-esm/lib/license/LicenseManager.mjs +9 -2
- package/dist-esm/lib/license/LicenseManager.mjs.map +2 -2
- package/dist-esm/lib/license/LicenseProvider.mjs +16 -3
- package/dist-esm/lib/license/LicenseProvider.mjs.map +2 -2
- package/dist-esm/lib/license/useLicenseManagerState.mjs +5 -4
- package/dist-esm/lib/license/useLicenseManagerState.mjs.map +2 -2
- package/dist-esm/lib/primitives/Box.mjs +2 -1
- package/dist-esm/lib/primitives/Box.mjs.map +2 -2
- package/dist-esm/lib/primitives/Vec.mjs +4 -3
- package/dist-esm/lib/primitives/Vec.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Group2d.mjs +63 -21
- package/dist-esm/lib/primitives/geometry/Group2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/utils.mjs +2 -1
- package/dist-esm/lib/primitives/utils.mjs.map +2 -2
- package/dist-esm/lib/utils/deepLinks.mjs +5 -1
- package/dist-esm/lib/utils/deepLinks.mjs.map +2 -2
- package/dist-esm/lib/utils/normalizeWheel.mjs +2 -0
- package/dist-esm/lib/utils/normalizeWheel.mjs.map +2 -2
- package/dist-esm/lib/utils/rotation.mjs +1 -9
- package/dist-esm/lib/utils/rotation.mjs.map +2 -2
- package/dist-esm/lib/utils/sync/TLLocalSyncClient.mjs +17 -0
- package/dist-esm/lib/utils/sync/TLLocalSyncClient.mjs.map +2 -2
- package/dist-esm/lib/utils/sync/alerts.mjs +1 -1
- package/dist-esm/lib/utils/sync/alerts.mjs.map +1 -1
- package/dist-esm/version.mjs +3 -3
- package/dist-esm/version.mjs.map +1 -1
- package/package.json +13 -7
- package/src/index.ts +6 -1
- package/src/lib/TldrawEditor.tsx +16 -4
- package/src/lib/components/MenuClickCapture.tsx +19 -18
- package/src/lib/components/default-components/CanvasOverlays.tsx +1 -3
- package/src/lib/components/default-components/DefaultErrorFallback.tsx +1 -1
- package/src/lib/config/TLUserPreferences.test.ts +18 -1
- package/src/lib/config/TLUserPreferences.ts +8 -4
- package/src/lib/config/createTLStore.ts +1 -1
- package/src/lib/editor/Editor.ts +266 -383
- package/src/lib/editor/derivations/shapeIdsInCurrentPage.ts +7 -3
- package/src/lib/editor/managers/ClickManager/ClickManager.ts +5 -3
- package/src/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.ts +9 -9
- package/src/lib/editor/managers/FontManager/FontManager.ts +2 -1
- package/src/lib/editor/managers/InputsManager/InputsManager.test.ts +199 -3
- package/src/lib/editor/managers/InputsManager/InputsManager.ts +128 -9
- package/src/lib/editor/managers/ScribbleManager/ScribbleManager.ts +12 -1
- package/src/lib/editor/managers/SnapManager/BoundsSnaps.ts +0 -2
- package/src/lib/editor/managers/TextManager/TextManager.ts +2 -6
- package/src/lib/editor/managers/TickManager/TickManager.test.ts +13 -0
- package/src/lib/editor/managers/TickManager/TickManager.ts +9 -3
- package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.test.ts +64 -3
- package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.ts +18 -1
- package/src/lib/editor/overlays/OverlayManager.ts +3 -7
- package/src/lib/editor/overlays/strokeShapeIndicators.ts +0 -1
- package/src/lib/editor/shapes/BaseFrameLikeShapeUtil.tsx +5 -1
- package/src/lib/editor/shapes/shared/getPerfectDashProps.ts +3 -0
- package/src/lib/editor/tools/BaseBoxShapeTool/children/Pointing.ts +4 -1
- package/src/lib/editor/tools/StateNode.test.ts +64 -0
- package/src/lib/editor/tools/StateNode.ts +12 -2
- package/src/lib/globals/editors.test.ts +76 -0
- package/src/lib/globals/editors.ts +53 -0
- package/src/lib/globals/menus.test.ts +33 -0
- package/src/lib/globals/menus.ts +11 -4
- package/src/lib/hooks/useCanvasEvents.ts +2 -0
- package/src/lib/hooks/useDocumentEvents.ts +60 -16
- package/src/lib/hooks/useLocalStore.ts +16 -8
- package/src/lib/hooks/usePassThroughWheelEvents.ts +3 -0
- package/src/lib/hooks/usePeerIds.ts +2 -1
- package/src/lib/license/LicenseManager.test.ts +160 -0
- package/src/lib/license/LicenseManager.ts +13 -4
- package/src/lib/license/LicenseProvider.tsx +24 -3
- package/src/lib/license/useLicenseManagerState.ts +8 -6
- package/src/lib/primitives/Box.test.ts +9 -1
- package/src/lib/primitives/Box.ts +3 -1
- package/src/lib/primitives/Vec.test.ts +10 -0
- package/src/lib/primitives/Vec.ts +4 -4
- package/src/lib/primitives/geometry/Arc2d.test.ts +226 -3
- package/src/lib/primitives/geometry/CubicBezier2d.test.ts +173 -3
- package/src/lib/primitives/geometry/CubicSpline2d.test.ts +160 -3
- package/src/lib/primitives/geometry/Ellipse2d.test.ts +243 -3
- package/src/lib/primitives/geometry/Geometry2d.test.ts +553 -1
- package/src/lib/primitives/geometry/Group2d.test.ts +398 -3
- package/src/lib/primitives/geometry/Group2d.ts +63 -27
- package/src/lib/primitives/geometry/Polyline2d.test.ts +207 -0
- package/src/lib/primitives/geometry/Stadium2d.test.ts +191 -3
- package/src/lib/primitives/utils.test.ts +10 -1
- package/src/lib/primitives/utils.ts +4 -1
- package/src/lib/test/useCanvasEvents.test.tsx +74 -0
- package/src/lib/test/useDocumentEvents.test.tsx +107 -0
- package/src/lib/test/usePassThroughWheelEvents.test.tsx +25 -2
- package/src/lib/utils/deepLinks.test.ts +15 -0
- package/src/lib/utils/deepLinks.ts +7 -1
- package/src/lib/utils/normalizeWheel.test.ts +39 -0
- package/src/lib/utils/normalizeWheel.ts +6 -0
- package/src/lib/utils/rotation.ts +4 -12
- package/src/lib/utils/sync/TLLocalSyncClient.test.ts +56 -0
- package/src/lib/utils/sync/TLLocalSyncClient.ts +24 -0
- package/src/lib/utils/sync/alerts.ts +1 -1
- package/src/version.ts +3 -3
- package/src/lib/primitives/geometry/Polyline.test.ts +0 -5
|
@@ -73,9 +73,15 @@ export function parseDeepLinkString(deepLinkString: string): TLDeepLink {
|
|
|
73
73
|
}
|
|
74
74
|
case 'v': {
|
|
75
75
|
const [x, y, w, h, pageId] = deepLinkString.slice(1).split('.')
|
|
76
|
+
const bounds = new Box(Number(x), Number(y), Number(w), Number(h))
|
|
77
|
+
// Number('abc') is NaN rather than an error, so without this check a malformed
|
|
78
|
+
// viewport link would bypass the caller's fallback and park the camera at the origin
|
|
79
|
+
if (![bounds.x, bounds.y, bounds.w, bounds.h].every(Number.isFinite)) {
|
|
80
|
+
throw Error('Invalid deep link string')
|
|
81
|
+
}
|
|
76
82
|
return {
|
|
77
83
|
type: 'viewport',
|
|
78
|
-
bounds
|
|
84
|
+
bounds,
|
|
79
85
|
pageId: pageId ? PageRecordType.createId(decodeURIComponent(pageId)) : undefined,
|
|
80
86
|
}
|
|
81
87
|
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { normalizeWheel } from './normalizeWheel'
|
|
2
|
+
|
|
3
|
+
function wheelEvent(props: Partial<WheelEvent>): WheelEvent {
|
|
4
|
+
return {
|
|
5
|
+
deltaX: 0,
|
|
6
|
+
deltaY: 0,
|
|
7
|
+
ctrlKey: false,
|
|
8
|
+
altKey: false,
|
|
9
|
+
metaKey: false,
|
|
10
|
+
shiftKey: false,
|
|
11
|
+
...props,
|
|
12
|
+
} as WheelEvent
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
describe('normalizeWheel', () => {
|
|
16
|
+
it('negates finite deltas for panning', () => {
|
|
17
|
+
const { x, y } = normalizeWheel(wheelEvent({ deltaX: 5, deltaY: 10 }))
|
|
18
|
+
expect(x).toBe(-5)
|
|
19
|
+
expect(y).toBe(-10)
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
it('coerces a non-finite deltaX to zero movement', () => {
|
|
23
|
+
const { x, y } = normalizeWheel(wheelEvent({ deltaX: NaN, deltaY: 10 }))
|
|
24
|
+
expect(x === 0).toBe(true)
|
|
25
|
+
expect(y).toBe(-10)
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
it('coerces a non-finite deltaY to zero movement', () => {
|
|
29
|
+
const { x, y } = normalizeWheel(wheelEvent({ deltaX: 5, deltaY: Infinity }))
|
|
30
|
+
expect(x).toBe(-5)
|
|
31
|
+
expect(y === 0).toBe(true)
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
it('does not produce a non-finite zoom delta when wheeling with a bad deltaY', () => {
|
|
35
|
+
const { z } = normalizeWheel(wheelEvent({ deltaY: NaN, ctrlKey: true }))
|
|
36
|
+
expect(Number.isFinite(z)).toBe(true)
|
|
37
|
+
expect(z === 0).toBe(true)
|
|
38
|
+
})
|
|
39
|
+
})
|
|
@@ -9,6 +9,12 @@ const MAX_ZOOM_STEP = 10
|
|
|
9
9
|
* @internal */
|
|
10
10
|
export function normalizeWheel(event: WheelEvent | React.WheelEvent<HTMLElement>) {
|
|
11
11
|
let { deltaY, deltaX } = event
|
|
12
|
+
|
|
13
|
+
// Coerce non-finite deltas to no movement so they can't propagate into the camera and
|
|
14
|
+
// crash validation. Also covers deltaZ below, which is derived from deltaY.
|
|
15
|
+
if (!Number.isFinite(deltaX)) deltaX = 0
|
|
16
|
+
if (!Number.isFinite(deltaY)) deltaY = 0
|
|
17
|
+
|
|
12
18
|
let deltaZ = 0
|
|
13
19
|
|
|
14
20
|
// wheeling
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { TLShape, TLShapeId, TLShapePartial } from '@tldraw/tlschema'
|
|
2
2
|
import { compact } from '@tldraw/utils'
|
|
3
3
|
import type { Editor } from '../editor/Editor'
|
|
4
|
-
import { Mat } from '../primitives/Mat'
|
|
5
4
|
import { canonicalizeRotation } from '../primitives/utils'
|
|
6
5
|
import { Vec, VecLike } from '../primitives/Vec'
|
|
7
6
|
|
|
@@ -75,18 +74,11 @@ export function applyRotationToSnapshotShapes({
|
|
|
75
74
|
// We need to both rotate each shape individually and rotate the shapes
|
|
76
75
|
// around the pivot point (the average center of all rotating shapes.)
|
|
77
76
|
|
|
78
|
-
const parentTransform = isShapeId(shape.parentId)
|
|
79
|
-
? editor.getShapePageTransform(shape.parentId)!
|
|
80
|
-
: Mat.Identity()
|
|
81
|
-
|
|
82
77
|
const newPagePoint = Vec.RotWith(initialPagePoint, centerOverride ?? initialPageCenter, delta)
|
|
83
78
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
Mat.Inverse(parentTransform),
|
|
88
|
-
newPagePoint
|
|
89
|
-
)
|
|
79
|
+
// uses the current parent transform in case it has moved/resized since the start
|
|
80
|
+
// (e.g. if rotating a shape at the edge of a group)
|
|
81
|
+
const newLocalPoint = editor.getPointInParentSpace(shape.id, newPagePoint)
|
|
90
82
|
const newRotation = canonicalizeRotation(shape.rotation + delta)
|
|
91
83
|
|
|
92
84
|
return {
|
|
@@ -172,3 +172,59 @@ test('writes that come in during a persist operation will get persisted afterwar
|
|
|
172
172
|
await tick()
|
|
173
173
|
expect(client.db.storeChanges).toHaveBeenCalledTimes(1)
|
|
174
174
|
})
|
|
175
|
+
|
|
176
|
+
test('pagehide flushes pending changes without waiting for the throttle', async () => {
|
|
177
|
+
const { client, tick } = testClient()
|
|
178
|
+
await tick()
|
|
179
|
+
client.store.put([PageRecordType.create({ name: 'test', index: 'a0' as IndexKey })])
|
|
180
|
+
await tick()
|
|
181
|
+
expect(client.db.storeSnapshot).toHaveBeenCalledTimes(1)
|
|
182
|
+
|
|
183
|
+
client.store.put([PageRecordType.create({ name: 'test2', index: 'a1' as IndexKey })])
|
|
184
|
+
expect(client.db.storeChanges).not.toHaveBeenCalled()
|
|
185
|
+
|
|
186
|
+
window.dispatchEvent(new Event('pagehide'))
|
|
187
|
+
expect(client.db.storeChanges).toHaveBeenCalledTimes(1)
|
|
188
|
+
})
|
|
189
|
+
|
|
190
|
+
test('hiding the tab flushes pending changes without waiting for the throttle', async () => {
|
|
191
|
+
const { client, tick } = testClient()
|
|
192
|
+
await tick()
|
|
193
|
+
client.store.put([PageRecordType.create({ name: 'test', index: 'a0' as IndexKey })])
|
|
194
|
+
await tick()
|
|
195
|
+
expect(client.db.storeSnapshot).toHaveBeenCalledTimes(1)
|
|
196
|
+
|
|
197
|
+
client.store.put([PageRecordType.create({ name: 'test2', index: 'a1' as IndexKey })])
|
|
198
|
+
expect(client.db.storeChanges).not.toHaveBeenCalled()
|
|
199
|
+
|
|
200
|
+
const visibilityState = vi.spyOn(document, 'visibilityState', 'get')
|
|
201
|
+
try {
|
|
202
|
+
visibilityState.mockReturnValue('hidden')
|
|
203
|
+
document.dispatchEvent(new Event('visibilitychange'))
|
|
204
|
+
expect(client.db.storeChanges).toHaveBeenCalledTimes(1)
|
|
205
|
+
} finally {
|
|
206
|
+
visibilityState.mockRestore()
|
|
207
|
+
}
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
test('pagehide does not write before the initial load has completed', async () => {
|
|
211
|
+
const { client } = testClient()
|
|
212
|
+
window.dispatchEvent(new Event('pagehide'))
|
|
213
|
+
expect(client.db.storeSnapshot).not.toHaveBeenCalled()
|
|
214
|
+
expect(client.db.storeChanges).not.toHaveBeenCalled()
|
|
215
|
+
})
|
|
216
|
+
|
|
217
|
+
test('pagehide and visibilitychange listeners are removed when the client closes', async () => {
|
|
218
|
+
const removeWindowListener = vi.spyOn(window, 'removeEventListener')
|
|
219
|
+
const removeDocumentListener = vi.spyOn(document, 'removeEventListener')
|
|
220
|
+
try {
|
|
221
|
+
const { client, tick } = testClient()
|
|
222
|
+
await tick()
|
|
223
|
+
client.close()
|
|
224
|
+
expect(removeWindowListener).toHaveBeenCalledWith('pagehide', expect.any(Function))
|
|
225
|
+
expect(removeDocumentListener).toHaveBeenCalledWith('visibilitychange', expect.any(Function))
|
|
226
|
+
} finally {
|
|
227
|
+
removeWindowListener.mockRestore()
|
|
228
|
+
removeDocumentListener.mockRestore()
|
|
229
|
+
}
|
|
230
|
+
})
|
|
@@ -68,6 +68,7 @@ export class TLLocalSyncClient {
|
|
|
68
68
|
private disposables = new Set<() => void>()
|
|
69
69
|
private diffQueue: Array<RecordsDiff<UnknownRecord> | typeof UPDATE_INSTANCE_STATE> = []
|
|
70
70
|
private didDispose = false
|
|
71
|
+
private didLoad = false
|
|
71
72
|
private shouldDoFullDBWrite = true
|
|
72
73
|
private isReloading = false
|
|
73
74
|
readonly persistenceKey: string
|
|
@@ -143,6 +144,28 @@ export class TLLocalSyncClient {
|
|
|
143
144
|
)
|
|
144
145
|
)
|
|
145
146
|
|
|
147
|
+
if (typeof window !== 'undefined') {
|
|
148
|
+
// Persists are throttled, so without this the last PERSIST_THROTTLE_MS of edits are lost
|
|
149
|
+
// whenever the tab is closed or reloaded. `pagehide` is the last reliable event before
|
|
150
|
+
// unload on desktop; on mobile the page can be discarded without it firing, so we also
|
|
151
|
+
// flush when the tab is hidden.
|
|
152
|
+
const flush = () => {
|
|
153
|
+
// Before the initial load completes a full write would overwrite the saved
|
|
154
|
+
// document with an empty store.
|
|
155
|
+
if (!this.didLoad) return
|
|
156
|
+
this.persistIfNeeded()
|
|
157
|
+
}
|
|
158
|
+
const onVisibilityChange = () => {
|
|
159
|
+
if (document.visibilityState === 'hidden') flush()
|
|
160
|
+
}
|
|
161
|
+
window.addEventListener('pagehide', flush)
|
|
162
|
+
document.addEventListener('visibilitychange', onVisibilityChange)
|
|
163
|
+
this.disposables.add(() => {
|
|
164
|
+
window.removeEventListener('pagehide', flush)
|
|
165
|
+
document.removeEventListener('visibilitychange', onVisibilityChange)
|
|
166
|
+
})
|
|
167
|
+
}
|
|
168
|
+
|
|
146
169
|
this.connect(onLoad, onLoadError)
|
|
147
170
|
|
|
148
171
|
this.documentTypes = new Set(
|
|
@@ -249,6 +272,7 @@ export class TLLocalSyncClient {
|
|
|
249
272
|
this.disposables.add(() => {
|
|
250
273
|
this.channel.close()
|
|
251
274
|
})
|
|
275
|
+
this.didLoad = true
|
|
252
276
|
onLoad(this)
|
|
253
277
|
} catch (e: any) {
|
|
254
278
|
this.debug('error loading data from store', e)
|
|
@@ -12,7 +12,7 @@ Keep seeing this message?
|
|
|
12
12
|
/** @internal */
|
|
13
13
|
export function showCantReadFromIndexDbAlert() {
|
|
14
14
|
window.alert(
|
|
15
|
-
`Oops! We could not access your browser's storage—and the app won't work correctly without that.
|
|
15
|
+
`Oops! We could not access your browser's storage—and the app won't work correctly without that. Reload the page to try again.
|
|
16
16
|
|
|
17
17
|
Keep seeing this message?
|
|
18
18
|
• If you're using tldraw in a private or "incognito" window, try loading tldraw in a regular window or in a different browser.`
|
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 = '5.4.0
|
|
4
|
+
export const version = '5.4.0'
|
|
5
5
|
export const publishDates = {
|
|
6
6
|
major: '2026-05-06T16:28:18.473Z',
|
|
7
|
-
minor: '2026-
|
|
8
|
-
patch: '2026-
|
|
7
|
+
minor: '2026-09-02T11:04:02.901Z',
|
|
8
|
+
patch: '2026-09-02T11:04:02.901Z',
|
|
9
9
|
}
|