@tldraw/editor 3.16.0-next.eafb52d15064 → 3.16.0-next.fe14f1b4181f
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 +30 -0
- package/dist-cjs/index.js +1 -1
- package/dist-cjs/lib/TldrawEditor.js +6 -2
- 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/Shape.js +7 -10
- package/dist-cjs/lib/components/Shape.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js +4 -23
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultCollaboratorHint.js +1 -1
- package/dist-cjs/lib/components/default-components/DefaultCollaboratorHint.js.map +1 -1
- 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/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/config/TLUserPreferences.js +1 -1
- package/dist-cjs/lib/config/TLUserPreferences.js.map +2 -2
- package/dist-cjs/lib/editor/Editor.js +44 -15
- package/dist-cjs/lib/editor/Editor.js.map +2 -2
- package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js +1 -1
- package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js.map +2 -2
- package/dist-cjs/lib/editor/shapes/ShapeUtil.js +13 -0
- package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
- 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 +31 -25
- package/dist-cjs/lib/hooks/useCanvasEvents.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/license/Watermark.js +6 -6
- package/dist-cjs/lib/license/Watermark.js.map +1 -1
- package/dist-cjs/lib/options.js +6 -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/version.js +3 -3
- package/dist-cjs/version.js.map +1 -1
- package/dist-esm/index.d.mts +30 -0
- package/dist-esm/index.mjs +1 -1
- package/dist-esm/lib/TldrawEditor.mjs +6 -2
- 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/Shape.mjs +7 -10
- package/dist-esm/lib/components/Shape.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +4 -23
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultCollaboratorHint.mjs +1 -1
- package/dist-esm/lib/components/default-components/DefaultCollaboratorHint.mjs.map +1 -1
- 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/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/config/TLUserPreferences.mjs +1 -1
- package/dist-esm/lib/config/TLUserPreferences.mjs.map +2 -2
- package/dist-esm/lib/editor/Editor.mjs +44 -15
- package/dist-esm/lib/editor/Editor.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs +1 -1
- package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs.map +2 -2
- package/dist-esm/lib/editor/shapes/ShapeUtil.mjs +13 -0
- package/dist-esm/lib/editor/shapes/ShapeUtil.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 +32 -26
- package/dist-esm/lib/hooks/useCanvasEvents.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/license/Watermark.mjs +6 -6
- package/dist-esm/lib/license/Watermark.mjs.map +1 -1
- package/dist-esm/lib/options.mjs +6 -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/version.mjs +3 -3
- package/dist-esm/version.mjs.map +1 -1
- package/editor.css +301 -290
- package/package.json +14 -37
- package/src/lib/TldrawEditor.tsx +11 -6
- package/src/lib/components/MenuClickCapture.tsx +0 -8
- package/src/lib/components/Shape.tsx +6 -12
- package/src/lib/components/default-components/DefaultCanvas.tsx +5 -22
- package/src/lib/components/default-components/DefaultCollaboratorHint.tsx +1 -1
- package/src/lib/components/default-components/DefaultErrorFallback.tsx +1 -1
- package/src/lib/components/default-components/DefaultScribble.tsx +1 -1
- package/src/lib/components/default-components/DefaultShapeIndicator.tsx +5 -1
- package/src/lib/config/TLUserPreferences.ts +1 -1
- package/src/lib/editor/Editor.test.ts +12 -11
- package/src/lib/editor/Editor.ts +55 -20
- 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 +24 -23
- 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 +21 -26
- package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.ts +1 -1
- package/src/lib/editor/shapes/ShapeUtil.ts +14 -0
- package/src/lib/exports/getSvgJsx.test.ts +868 -0
- package/src/lib/exports/getSvgJsx.tsx +78 -21
- package/src/lib/hooks/useCanvasEvents.ts +45 -38
- package/src/lib/hooks/usePassThroughWheelEvents.ts +6 -1
- package/src/lib/license/LicenseManager.test.ts +3 -1
- package/src/lib/license/Watermark.test.tsx +2 -1
- package/src/lib/license/Watermark.tsx +6 -6
- package/src/lib/options.ts +6 -0
- package/src/lib/primitives/Box.test.ts +126 -0
- package/src/lib/primitives/Box.ts +10 -1
- package/src/lib/utils/sync/LocalIndexedDb.test.ts +2 -1
- package/src/lib/utils/sync/TLLocalSyncClient.test.ts +15 -15
- package/src/version.ts +3 -3
- package/dist-cjs/lib/utils/nearestMultiple.js +0 -34
- 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/utils/nearestMultiple.ts +0 -13
|
@@ -1,19 +1,20 @@
|
|
|
1
|
+
import { Mock, Mocked, vi } from 'vitest'
|
|
1
2
|
import { Box } from '../../../primitives/Box'
|
|
2
3
|
import { Vec } from '../../../primitives/Vec'
|
|
3
4
|
import { Editor } from '../../Editor'
|
|
4
5
|
import { EdgeScrollManager } from './EdgeScrollManager'
|
|
5
6
|
|
|
6
7
|
// Mock the Editor class
|
|
7
|
-
|
|
8
|
+
vi.mock('../../Editor')
|
|
8
9
|
|
|
9
10
|
describe('EdgeScrollManager', () => {
|
|
10
|
-
let editor:
|
|
11
|
+
let editor: Mocked<
|
|
11
12
|
Editor & {
|
|
12
|
-
user: { getEdgeScrollSpeed:
|
|
13
|
-
getCamera:
|
|
14
|
-
getCameraOptions:
|
|
15
|
-
getZoomLevel:
|
|
16
|
-
getViewportScreenBounds:
|
|
13
|
+
user: { getEdgeScrollSpeed: Mock }
|
|
14
|
+
getCamera: Mock
|
|
15
|
+
getCameraOptions: Mock
|
|
16
|
+
getZoomLevel: Mock
|
|
17
|
+
getViewportScreenBounds: Mock
|
|
17
18
|
}
|
|
18
19
|
>
|
|
19
20
|
let edgeScrollManager: EdgeScrollManager
|
|
@@ -33,33 +34,33 @@ describe('EdgeScrollManager', () => {
|
|
|
33
34
|
isPanning: false,
|
|
34
35
|
},
|
|
35
36
|
user: {
|
|
36
|
-
getEdgeScrollSpeed:
|
|
37
|
+
getEdgeScrollSpeed: vi.fn(() => 1),
|
|
37
38
|
},
|
|
38
|
-
getViewportScreenBounds:
|
|
39
|
-
getInstanceState:
|
|
39
|
+
getViewportScreenBounds: vi.fn(() => new Box(0, 0, 1000, 600)),
|
|
40
|
+
getInstanceState: vi.fn(
|
|
40
41
|
() =>
|
|
41
42
|
({
|
|
42
43
|
isCoarsePointer: false,
|
|
43
44
|
insets: [false, false, false, false], // [top, right, bottom, left]
|
|
44
45
|
}) as any
|
|
45
46
|
),
|
|
46
|
-
getCameraOptions:
|
|
47
|
+
getCameraOptions: vi.fn(() => ({
|
|
47
48
|
isLocked: false,
|
|
48
49
|
panSpeed: 1,
|
|
49
50
|
zoomSpeed: 1,
|
|
50
51
|
zoomSteps: [1],
|
|
51
52
|
wheelBehavior: 'pan' as const,
|
|
52
53
|
})),
|
|
53
|
-
getZoomLevel:
|
|
54
|
-
getCamera:
|
|
55
|
-
setCamera:
|
|
54
|
+
getZoomLevel: vi.fn(() => 1),
|
|
55
|
+
getCamera: vi.fn(() => new Vec(0, 0, 1)),
|
|
56
|
+
setCamera: vi.fn(),
|
|
56
57
|
} as any
|
|
57
58
|
|
|
58
59
|
edgeScrollManager = new EdgeScrollManager(editor as any)
|
|
59
60
|
})
|
|
60
61
|
|
|
61
62
|
afterEach(() => {
|
|
62
|
-
|
|
63
|
+
vi.clearAllMocks()
|
|
63
64
|
})
|
|
64
65
|
|
|
65
66
|
describe('constructor and initialization', () => {
|
|
@@ -1,58 +1,59 @@
|
|
|
1
|
+
import { Mock, Mocked, vi } from 'vitest'
|
|
1
2
|
import { Editor } from '../../Editor'
|
|
2
3
|
import { FocusManager } from './FocusManager'
|
|
3
4
|
|
|
4
5
|
// Mock the Editor class
|
|
5
|
-
|
|
6
|
+
vi.mock('../../Editor')
|
|
6
7
|
|
|
7
8
|
describe('FocusManager', () => {
|
|
8
|
-
let editor:
|
|
9
|
+
let editor: Mocked<
|
|
9
10
|
Editor & {
|
|
10
11
|
sideEffects: {
|
|
11
|
-
registerAfterChangeHandler:
|
|
12
|
+
registerAfterChangeHandler: Mock
|
|
12
13
|
}
|
|
13
|
-
getInstanceState:
|
|
14
|
-
updateInstanceState:
|
|
15
|
-
getContainer:
|
|
16
|
-
isIn:
|
|
17
|
-
getSelectedShapeIds:
|
|
18
|
-
complete:
|
|
14
|
+
getInstanceState: Mock
|
|
15
|
+
updateInstanceState: Mock
|
|
16
|
+
getContainer: Mock
|
|
17
|
+
isIn: Mock
|
|
18
|
+
getSelectedShapeIds: Mock
|
|
19
|
+
complete: Mock
|
|
19
20
|
}
|
|
20
21
|
>
|
|
21
22
|
let focusManager: FocusManager
|
|
22
23
|
let mockContainer: HTMLElement
|
|
23
|
-
let mockDispose:
|
|
24
|
+
let mockDispose: Mock
|
|
24
25
|
let originalAddEventListener: typeof document.body.addEventListener
|
|
25
26
|
let originalRemoveEventListener: typeof document.body.removeEventListener
|
|
26
27
|
|
|
27
28
|
beforeEach(() => {
|
|
28
29
|
// Create mock container element
|
|
29
30
|
mockContainer = document.createElement('div')
|
|
30
|
-
mockContainer.focus =
|
|
31
|
-
mockContainer.blur =
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
mockContainer.focus = vi.fn()
|
|
32
|
+
mockContainer.blur = vi.fn()
|
|
33
|
+
vi.spyOn(mockContainer.classList, 'add')
|
|
34
|
+
vi.spyOn(mockContainer.classList, 'remove')
|
|
34
35
|
|
|
35
36
|
// Create mock dispose function
|
|
36
|
-
mockDispose =
|
|
37
|
+
mockDispose = vi.fn()
|
|
37
38
|
|
|
38
39
|
// Mock editor
|
|
39
40
|
editor = {
|
|
40
41
|
sideEffects: {
|
|
41
|
-
registerAfterChangeHandler:
|
|
42
|
+
registerAfterChangeHandler: vi.fn(() => mockDispose),
|
|
42
43
|
},
|
|
43
|
-
getInstanceState:
|
|
44
|
-
updateInstanceState:
|
|
45
|
-
getContainer:
|
|
46
|
-
isIn:
|
|
47
|
-
getSelectedShapeIds:
|
|
48
|
-
complete:
|
|
44
|
+
getInstanceState: vi.fn(() => ({ isFocused: false })),
|
|
45
|
+
updateInstanceState: vi.fn(),
|
|
46
|
+
getContainer: vi.fn(() => mockContainer),
|
|
47
|
+
isIn: vi.fn(() => false),
|
|
48
|
+
getSelectedShapeIds: vi.fn(() => []),
|
|
49
|
+
complete: vi.fn(),
|
|
49
50
|
} as any
|
|
50
51
|
|
|
51
52
|
// Mock document.body event listeners
|
|
52
53
|
originalAddEventListener = document.body.addEventListener
|
|
53
54
|
originalRemoveEventListener = document.body.removeEventListener
|
|
54
|
-
document.body.addEventListener =
|
|
55
|
-
document.body.removeEventListener =
|
|
55
|
+
document.body.addEventListener = vi.fn()
|
|
56
|
+
document.body.removeEventListener = vi.fn()
|
|
56
57
|
})
|
|
57
58
|
|
|
58
59
|
afterEach(() => {
|
|
@@ -65,7 +66,7 @@ describe('FocusManager', () => {
|
|
|
65
66
|
focusManager.dispose()
|
|
66
67
|
}
|
|
67
68
|
|
|
68
|
-
|
|
69
|
+
vi.clearAllMocks()
|
|
69
70
|
})
|
|
70
71
|
|
|
71
72
|
describe('constructor', () => {
|
|
@@ -131,7 +132,7 @@ describe('FocusManager', () => {
|
|
|
131
132
|
const handler = handlerCall[1]
|
|
132
133
|
|
|
133
134
|
// Clear previous calls
|
|
134
|
-
|
|
135
|
+
vi.clearAllMocks()
|
|
135
136
|
|
|
136
137
|
// Simulate focus state change
|
|
137
138
|
const prev = { isFocused: false }
|
|
@@ -149,7 +150,7 @@ describe('FocusManager', () => {
|
|
|
149
150
|
const handlerCall = editor.sideEffects.registerAfterChangeHandler.mock.calls[0]
|
|
150
151
|
const handler = handlerCall[1]
|
|
151
152
|
|
|
152
|
-
|
|
153
|
+
vi.clearAllMocks()
|
|
153
154
|
|
|
154
155
|
// Simulate no focus state change
|
|
155
156
|
const prev = { isFocused: true }
|
|
@@ -170,7 +171,7 @@ describe('FocusManager', () => {
|
|
|
170
171
|
// Get the handler before clearing mocks
|
|
171
172
|
const handlerCall = editor.sideEffects.registerAfterChangeHandler.mock.calls[0]
|
|
172
173
|
handler = handlerCall[1]
|
|
173
|
-
|
|
174
|
+
vi.clearAllMocks()
|
|
174
175
|
})
|
|
175
176
|
|
|
176
177
|
it('should add focused class when editor is focused', () => {
|
|
@@ -205,11 +206,11 @@ describe('FocusManager', () => {
|
|
|
205
206
|
focusManager = new FocusManager(editor)
|
|
206
207
|
|
|
207
208
|
// Get the keydown handler that was registered
|
|
208
|
-
const addEventListenerCalls = (document.body.addEventListener as
|
|
209
|
-
const keydownCall = addEventListenerCalls.find((call) => call[0] === 'keydown')
|
|
210
|
-
keydownHandler = keydownCall[1]
|
|
209
|
+
const addEventListenerCalls = (document.body.addEventListener as Mock).mock.calls
|
|
210
|
+
const keydownCall = addEventListenerCalls.find((call: any) => call[0] === 'keydown')
|
|
211
|
+
keydownHandler = keydownCall![1]
|
|
211
212
|
|
|
212
|
-
|
|
213
|
+
vi.clearAllMocks()
|
|
213
214
|
})
|
|
214
215
|
|
|
215
216
|
it('should remove no-focus-ring class on Tab key', () => {
|
|
@@ -283,11 +284,11 @@ describe('FocusManager', () => {
|
|
|
283
284
|
focusManager = new FocusManager(editor)
|
|
284
285
|
|
|
285
286
|
// Get the mousedown handler that was registered
|
|
286
|
-
const addEventListenerCalls = (document.body.addEventListener as
|
|
287
|
-
const mousedownCall = addEventListenerCalls.find((call) => call[0] === 'mousedown')
|
|
288
|
-
mousedownHandler = mousedownCall[1]
|
|
287
|
+
const addEventListenerCalls = (document.body.addEventListener as Mock).mock.calls
|
|
288
|
+
const mousedownCall = addEventListenerCalls.find((call: any) => call[0] === 'mousedown')
|
|
289
|
+
mousedownHandler = mousedownCall![1]
|
|
289
290
|
|
|
290
|
-
|
|
291
|
+
vi.clearAllMocks()
|
|
291
292
|
})
|
|
292
293
|
|
|
293
294
|
it('should add no-focus-ring class on mouse down', () => {
|
|
@@ -326,7 +327,7 @@ describe('FocusManager', () => {
|
|
|
326
327
|
it('should complete before bluring', () => {
|
|
327
328
|
const callOrder: string[] = []
|
|
328
329
|
editor.complete.mockImplementation(() => callOrder.push('complete'))
|
|
329
|
-
mockContainer.blur =
|
|
330
|
+
mockContainer.blur = vi.fn(() => callOrder.push('blur'))
|
|
330
331
|
|
|
331
332
|
focusManager.blur()
|
|
332
333
|
|
|
@@ -337,7 +338,7 @@ describe('FocusManager', () => {
|
|
|
337
338
|
describe('dispose', () => {
|
|
338
339
|
beforeEach(() => {
|
|
339
340
|
focusManager = new FocusManager(editor)
|
|
340
|
-
|
|
341
|
+
vi.clearAllMocks()
|
|
341
342
|
})
|
|
342
343
|
|
|
343
344
|
it('should remove keyboard event listener', () => {
|
|
@@ -376,7 +377,7 @@ describe('FocusManager', () => {
|
|
|
376
377
|
const handlerCall = editor.sideEffects.registerAfterChangeHandler.mock.calls[0]
|
|
377
378
|
const handler = handlerCall[1]
|
|
378
379
|
|
|
379
|
-
|
|
380
|
+
vi.clearAllMocks()
|
|
380
381
|
|
|
381
382
|
// Rapid focus changes
|
|
382
383
|
editor.getInstanceState.mockReturnValue({ isFocused: true })
|
|
@@ -394,9 +395,9 @@ describe('FocusManager', () => {
|
|
|
394
395
|
|
|
395
396
|
it('should handle keyboard navigation while editing', () => {
|
|
396
397
|
focusManager = new FocusManager(editor)
|
|
397
|
-
const addEventListenerCalls = (document.body.addEventListener as
|
|
398
|
-
const keydownCall = addEventListenerCalls.find((call) => call[0] === 'keydown')
|
|
399
|
-
const keydownHandler = keydownCall[1]
|
|
398
|
+
const addEventListenerCalls = (document.body.addEventListener as Mock).mock.calls
|
|
399
|
+
const keydownCall = addEventListenerCalls.find((call: any) => call[0] === 'keydown')
|
|
400
|
+
const keydownHandler = keydownCall![1]
|
|
400
401
|
|
|
401
402
|
editor.isIn.mockReturnValue(true) // Editing mode
|
|
402
403
|
|
|
@@ -409,15 +410,15 @@ describe('FocusManager', () => {
|
|
|
409
410
|
|
|
410
411
|
it('should handle mouse and keyboard interaction sequence', () => {
|
|
411
412
|
focusManager = new FocusManager(editor)
|
|
412
|
-
const addEventListenerCalls = (document.body.addEventListener as
|
|
413
|
+
const addEventListenerCalls = (document.body.addEventListener as Mock).mock.calls
|
|
413
414
|
|
|
414
|
-
const mousedownCall = addEventListenerCalls.find((call) => call[0] === 'mousedown')
|
|
415
|
-
const keydownCall = addEventListenerCalls.find((call) => call[0] === 'keydown')
|
|
415
|
+
const mousedownCall = addEventListenerCalls.find((call: any) => call[0] === 'mousedown')
|
|
416
|
+
const keydownCall = addEventListenerCalls.find((call: any) => call[0] === 'keydown')
|
|
416
417
|
|
|
417
|
-
const mousedownHandler = mousedownCall[1]
|
|
418
|
-
const keydownHandler = keydownCall[1]
|
|
418
|
+
const mousedownHandler = mousedownCall![1]
|
|
419
|
+
const keydownHandler = keydownCall![1]
|
|
419
420
|
|
|
420
|
-
|
|
421
|
+
vi.clearAllMocks()
|
|
421
422
|
|
|
422
423
|
// Mouse down adds no-focus-ring
|
|
423
424
|
mousedownHandler()
|
|
@@ -1,30 +1,31 @@
|
|
|
1
1
|
import { TLShape, TLShapeId, createShapeId } from '@tldraw/tlschema'
|
|
2
|
+
import { Mock, Mocked, vi } from 'vitest'
|
|
2
3
|
import { Editor } from '../../Editor'
|
|
3
4
|
import { FontManager, TLFontFace } from './FontManager'
|
|
4
5
|
|
|
5
6
|
// Mock the Editor class
|
|
6
|
-
|
|
7
|
+
vi.mock('../../Editor')
|
|
7
8
|
|
|
8
9
|
// Mock globals
|
|
9
|
-
global.FontFace =
|
|
10
|
+
global.FontFace = vi.fn().mockImplementation((family, src, descriptors) => ({
|
|
10
11
|
family,
|
|
11
12
|
src,
|
|
12
13
|
...descriptors,
|
|
13
|
-
load:
|
|
14
|
+
load: vi.fn(() => Promise.resolve()),
|
|
14
15
|
}))
|
|
15
16
|
|
|
16
17
|
Object.defineProperty(global.document, 'fonts', {
|
|
17
18
|
value: {
|
|
18
|
-
add:
|
|
19
|
-
[Symbol.iterator]:
|
|
19
|
+
add: vi.fn(),
|
|
20
|
+
[Symbol.iterator]: vi.fn(() => [].values()),
|
|
20
21
|
},
|
|
21
22
|
configurable: true,
|
|
22
23
|
})
|
|
23
24
|
|
|
24
|
-
global.queueMicrotask =
|
|
25
|
+
global.queueMicrotask = vi.fn((fn) => Promise.resolve().then(fn))
|
|
25
26
|
|
|
26
27
|
describe('FontManager', () => {
|
|
27
|
-
let editor:
|
|
28
|
+
let editor: Mocked<Editor>
|
|
28
29
|
let fontManager: FontManager
|
|
29
30
|
let mockAssetUrls: { [key: string]: string }
|
|
30
31
|
|
|
@@ -50,30 +51,30 @@ describe('FontManager', () => {
|
|
|
50
51
|
})
|
|
51
52
|
|
|
52
53
|
beforeEach(() => {
|
|
53
|
-
|
|
54
|
+
vi.clearAllMocks()
|
|
54
55
|
|
|
55
56
|
mockAssetUrls = {
|
|
56
57
|
'test-font.woff2': 'https://example.com/fonts/test-font.woff2',
|
|
57
58
|
}
|
|
58
59
|
|
|
59
60
|
const mockShapeUtil = {
|
|
60
|
-
getFontFaces:
|
|
61
|
+
getFontFaces: vi.fn(() => []),
|
|
61
62
|
}
|
|
62
63
|
|
|
63
64
|
const mockStore = {
|
|
64
|
-
createComputedCache:
|
|
65
|
-
get:
|
|
65
|
+
createComputedCache: vi.fn(() => ({
|
|
66
|
+
get: vi.fn(() => []),
|
|
66
67
|
})),
|
|
67
|
-
createCache:
|
|
68
|
-
get:
|
|
68
|
+
createCache: vi.fn(() => ({
|
|
69
|
+
get: vi.fn(() => ({ get: vi.fn(() => []) })),
|
|
69
70
|
})),
|
|
70
71
|
}
|
|
71
72
|
|
|
72
73
|
editor = {
|
|
73
74
|
store: mockStore,
|
|
74
|
-
getShapeUtil:
|
|
75
|
-
getCurrentPageShapeIds:
|
|
76
|
-
getShape:
|
|
75
|
+
getShapeUtil: vi.fn(() => mockShapeUtil),
|
|
76
|
+
getCurrentPageShapeIds: vi.fn(() => new Set()),
|
|
77
|
+
getShape: vi.fn(),
|
|
77
78
|
isDisposed: false,
|
|
78
79
|
} as any
|
|
79
80
|
|
|
@@ -127,7 +128,7 @@ describe('FontManager', () => {
|
|
|
127
128
|
const shapes = shapeIds.map(createMockShape)
|
|
128
129
|
|
|
129
130
|
editor.getCurrentPageShapeIds.mockReturnValue(new Set(shapeIds))
|
|
130
|
-
editor.getShape.mockImplementation((id) => shapes.find((s) => s.id === id))
|
|
131
|
+
editor.getShape.mockImplementation((id: any) => shapes.find((s) => s.id === id))
|
|
131
132
|
|
|
132
133
|
await expect(fontManager.loadRequiredFontsForCurrentPage(3)).resolves.toBeUndefined()
|
|
133
134
|
})
|
|
@@ -150,12 +151,12 @@ describe('FontManager', () => {
|
|
|
150
151
|
const font = createMockFont()
|
|
151
152
|
const error = new Error('Font load failed')
|
|
152
153
|
|
|
153
|
-
;(global.FontFace as
|
|
154
|
+
;(global.FontFace as Mock).mockReturnValue({
|
|
154
155
|
family: font.family,
|
|
155
|
-
load:
|
|
156
|
+
load: vi.fn(() => Promise.reject(error)),
|
|
156
157
|
})
|
|
157
158
|
|
|
158
|
-
const consoleSpy =
|
|
159
|
+
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
|
|
159
160
|
|
|
160
161
|
await fontManager.ensureFontIsLoaded(font)
|
|
161
162
|
|
|
@@ -198,7 +199,7 @@ describe('FontManager', () => {
|
|
|
198
199
|
|
|
199
200
|
fontManager.requestFonts(fonts)
|
|
200
201
|
|
|
201
|
-
const callback = (queueMicrotask as
|
|
202
|
+
const callback = (queueMicrotask as Mock).mock.calls[0][0]
|
|
202
203
|
expect(() => callback()).not.toThrow()
|
|
203
204
|
})
|
|
204
205
|
})
|
|
@@ -213,7 +214,7 @@ describe('FontManager', () => {
|
|
|
213
214
|
src: url("mock-data-url");
|
|
214
215
|
}`
|
|
215
216
|
|
|
216
|
-
|
|
217
|
+
vi.spyOn(fontManager, 'toEmbeddedCssDeclaration').mockResolvedValue(mockCssDeclaration)
|
|
217
218
|
|
|
218
219
|
const result = await fontManager.toEmbeddedCssDeclaration(font)
|
|
219
220
|
|
|
@@ -227,7 +228,7 @@ describe('FontManager', () => {
|
|
|
227
228
|
const font = createMockFont()
|
|
228
229
|
|
|
229
230
|
// Simple spy to verify the method is called
|
|
230
|
-
const spy =
|
|
231
|
+
const spy = vi.spyOn(fontManager, 'toEmbeddedCssDeclaration').mockResolvedValue('mock-css')
|
|
231
232
|
|
|
232
233
|
await fontManager.toEmbeddedCssDeclaration(font)
|
|
233
234
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { BaseRecord, RecordId, Store, StoreSchema, createRecordType } from '@tldraw/store'
|
|
2
|
+
import { vi } from 'vitest'
|
|
2
3
|
import { TLHistoryBatchOptions } from '../../types/history-types'
|
|
3
4
|
import { HistoryManager } from './HistoryManager'
|
|
4
5
|
|
|
@@ -489,7 +490,7 @@ describe('HistoryManager constructor and lifecycle', () => {
|
|
|
489
490
|
})
|
|
490
491
|
|
|
491
492
|
it('should initialize with optional annotateError callback', () => {
|
|
492
|
-
const mockAnnotateError =
|
|
493
|
+
const mockAnnotateError = vi.fn()
|
|
493
494
|
const manager = new HistoryManager({ store, annotateError: mockAnnotateError })
|
|
494
495
|
expect(manager).toBeDefined()
|
|
495
496
|
})
|
|
@@ -503,7 +504,7 @@ describe('HistoryManager constructor and lifecycle', () => {
|
|
|
503
504
|
})
|
|
504
505
|
|
|
505
506
|
it('should handle errors in batch operations with annotateError', () => {
|
|
506
|
-
const mockAnnotateError =
|
|
507
|
+
const mockAnnotateError = vi.fn()
|
|
507
508
|
const manager = new HistoryManager({ store, annotateError: mockAnnotateError })
|
|
508
509
|
|
|
509
510
|
const errorFn = () => {
|
|
@@ -515,7 +516,7 @@ describe('HistoryManager constructor and lifecycle', () => {
|
|
|
515
516
|
})
|
|
516
517
|
|
|
517
518
|
it('should handle nested batch error scenarios', () => {
|
|
518
|
-
const mockAnnotateError =
|
|
519
|
+
const mockAnnotateError = vi.fn()
|
|
519
520
|
const manager = new HistoryManager({ store, annotateError: mockAnnotateError })
|
|
520
521
|
|
|
521
522
|
const nestedErrorFn = () => {
|
|
@@ -695,7 +696,7 @@ describe('HistoryManager error scenarios and edge cases', () => {
|
|
|
695
696
|
describe('squashToMark error handling', () => {
|
|
696
697
|
it('should handle non-existent mark gracefully', () => {
|
|
697
698
|
store.update(ids.a, (s) => ({ ...s, value: 1 }))
|
|
698
|
-
const consoleSpy =
|
|
699
|
+
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
|
|
699
700
|
|
|
700
701
|
manager.squashToMark('non-existent-mark')
|
|
701
702
|
|
|
@@ -707,7 +708,7 @@ describe('HistoryManager error scenarios and edge cases', () => {
|
|
|
707
708
|
})
|
|
708
709
|
|
|
709
710
|
it('should handle empty stack when squashing', () => {
|
|
710
|
-
const consoleSpy =
|
|
711
|
+
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
|
|
711
712
|
|
|
712
713
|
manager.squashToMark('non-existent')
|
|
713
714
|
|
|
@@ -780,7 +781,7 @@ describe('HistoryManager error scenarios and edge cases', () => {
|
|
|
780
781
|
})
|
|
781
782
|
|
|
782
783
|
it('should maintain batch state correctly during errors', () => {
|
|
783
|
-
const mockAnnotateError =
|
|
784
|
+
const mockAnnotateError = vi.fn()
|
|
784
785
|
const errorManager = new HistoryManager({ store, annotateError: mockAnnotateError })
|
|
785
786
|
|
|
786
787
|
try {
|
|
@@ -1,33 +1,34 @@
|
|
|
1
1
|
import { TLScribble } from '@tldraw/tlschema'
|
|
2
|
+
import { Mock, Mocked, vi } from 'vitest'
|
|
2
3
|
import { Editor } from '../../Editor'
|
|
3
4
|
import { ScribbleItem, ScribbleManager } from './ScribbleManager'
|
|
4
5
|
|
|
5
6
|
// Mock the Editor class
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
uniqueId:
|
|
7
|
+
vi.mock('../../Editor')
|
|
8
|
+
vi.mock('@tldraw/utils', () => ({
|
|
9
|
+
uniqueId: vi.fn(() => 'test-id'),
|
|
9
10
|
}))
|
|
10
11
|
|
|
11
12
|
describe('ScribbleManager', () => {
|
|
12
|
-
let editor:
|
|
13
|
+
let editor: Mocked<Editor>
|
|
13
14
|
let scribbleManager: ScribbleManager
|
|
14
|
-
let mockUniqueId:
|
|
15
|
+
let mockUniqueId: Mock
|
|
15
16
|
|
|
16
|
-
beforeEach(() => {
|
|
17
|
+
beforeEach(async () => {
|
|
17
18
|
editor = {
|
|
18
|
-
updateInstanceState:
|
|
19
|
-
run:
|
|
19
|
+
updateInstanceState: vi.fn(),
|
|
20
|
+
run: vi.fn((fn) => fn()),
|
|
20
21
|
} as any
|
|
21
22
|
|
|
22
|
-
const { uniqueId } =
|
|
23
|
-
mockUniqueId = uniqueId
|
|
23
|
+
const { uniqueId } = await vi.importMock('@tldraw/utils')
|
|
24
|
+
mockUniqueId = uniqueId as Mock
|
|
24
25
|
mockUniqueId.mockReturnValue('test-id')
|
|
25
26
|
|
|
26
27
|
scribbleManager = new ScribbleManager(editor)
|
|
27
28
|
})
|
|
28
29
|
|
|
29
30
|
afterEach(() => {
|
|
30
|
-
|
|
31
|
+
vi.clearAllMocks()
|
|
31
32
|
})
|
|
32
33
|
|
|
33
34
|
describe('constructor and initialization', () => {
|