gitmaps 1.1.0 → 1.1.2
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/README.md +267 -118
- package/app/[...slug]/page.client.tsx +1 -0
- package/app/[...slug]/page.tsx +6 -0
- package/app/analytics.db +0 -0
- package/app/api/analytics/route.ts +64 -0
- package/app/api/auth/positions/route.ts +95 -33
- package/app/api/build-info/route.ts +19 -0
- package/app/api/chat/route.ts +13 -2
- package/app/api/og-image/route.ts +14 -0
- package/app/api/repo/file-content/route.ts +73 -20
- package/app/api/repo/load/route.test.ts +62 -0
- package/app/api/repo/load/route.ts +41 -1
- package/app/api/repo/pdf-thumb/route.ts +127 -0
- package/app/api/repo/resolve-slug/route.ts +51 -0
- package/app/api/repo/tree/route.ts +188 -104
- package/app/api/version/route.ts +26 -0
- package/app/globals.css +5706 -4938
- package/app/layout.tsx +1279 -490
- package/app/lib/auto-arrange.test.ts +158 -0
- package/app/lib/auto-arrange.ts +147 -0
- package/app/lib/canvas-export.ts +358 -358
- package/app/lib/canvas.ts +625 -564
- package/app/lib/cards.tsx +1361 -916
- package/app/lib/chat.tsx +65 -9
- package/app/lib/code-editor.ts +86 -2
- package/app/lib/context.test.ts +32 -0
- package/app/lib/context.ts +19 -3
- package/app/lib/cursor-sharing.ts +34 -0
- package/app/lib/events.tsx +71 -93
- package/app/lib/export-canvas.ts +287 -0
- package/app/lib/file-card-plugin.ts +148 -148
- package/app/lib/file-modal.tsx +49 -0
- package/app/lib/file-preview.ts +486 -427
- package/app/lib/github-import.test.ts +424 -0
- package/app/lib/initial-route-hydration.test.ts +283 -0
- package/app/lib/initial-route-hydration.ts +202 -0
- package/app/lib/landing-reset.test.ts +99 -0
- package/app/lib/landing-reset.ts +106 -0
- package/app/lib/landing-shell.test.ts +75 -0
- package/app/lib/large-repo-optimization.ts +37 -0
- package/app/lib/layout-snapshots.ts +320 -0
- package/app/lib/loading.test.ts +69 -0
- package/app/lib/loading.tsx +160 -45
- package/app/lib/mount-cleanup.test.ts +52 -0
- package/app/lib/mount-cleanup.ts +34 -0
- package/app/lib/mount-init.test.ts +123 -0
- package/app/lib/mount-init.ts +107 -0
- package/app/lib/mount-lifecycle.test.ts +39 -0
- package/app/lib/mount-lifecycle.ts +12 -0
- package/app/lib/mount-route-wiring.test.ts +87 -0
- package/app/lib/mount-route-wiring.ts +84 -0
- package/app/lib/multi-repo.ts +14 -0
- package/app/lib/onboarding-tutorial.ts +278 -0
- package/app/lib/positions.ts +190 -121
- package/app/lib/recent-commits.test.ts +947 -0
- package/app/lib/recent-commits.ts +227 -0
- package/app/lib/repo-handoff.test.ts +23 -0
- package/app/lib/repo-handoff.ts +16 -0
- package/app/lib/repo-progressive.ts +119 -0
- package/app/lib/repo-select.test.ts +61 -0
- package/app/lib/repo-select.ts +74 -0
- package/app/lib/repo.tsx +1383 -987
- package/app/lib/role.ts +228 -0
- package/app/lib/route-catchall.test.ts +27 -0
- package/app/lib/route-repo-entry.test.ts +95 -0
- package/app/lib/route-repo-entry.ts +36 -0
- package/app/lib/router-contract.test.ts +22 -0
- package/app/lib/router-contract.ts +19 -0
- package/app/lib/shared-layout.test.ts +86 -0
- package/app/lib/shared-layout.ts +82 -0
- package/app/lib/status-bar.test.ts +118 -0
- package/app/lib/status-bar.ts +365 -128
- package/app/lib/sync-controls.test.ts +43 -0
- package/app/lib/sync-controls.tsx +303 -0
- package/app/lib/test-dom.ts +145 -0
- package/app/lib/test-fixtures/router-contract/[...slug]/page.tsx +3 -0
- package/app/lib/test-fixtures/router-contract/api/health/route.ts +3 -0
- package/app/lib/test-fixtures/router-contract/api/version/route.ts +3 -0
- package/app/lib/test-fixtures/router-contract/galaxy-canvas/page.tsx +3 -0
- package/app/lib/test-fixtures/router-contract/page.tsx +3 -0
- package/app/lib/transclusion-smoke.test.ts +163 -0
- package/app/lib/tutorial.ts +301 -0
- package/app/lib/version.ts +93 -0
- package/app/lib/viewport-culling.ts +740 -735
- package/app/lib/virtual-files.ts +456 -0
- package/app/lib/webgl-text.ts +189 -0
- package/app/lib/{galaxydraw-bridge.ts → xydraw-bridge.ts} +485 -482
- package/app/lib/{galaxydraw.test.ts → xydraw.test.ts} +228 -229
- package/app/og-image.png +0 -0
- package/app/page.client.tsx +70 -269
- package/app/page.tsx +15 -16
- package/app/state/machine.js +13 -0
- package/package.json +84 -75
- package/server.ts +10 -0
- package/app/[owner]/[repo]/page.tsx +0 -6
- package/app/[slug]/page.tsx +0 -6
- package/packages/galaxydraw/README.md +0 -296
- package/packages/galaxydraw/banner.png +0 -0
- package/packages/galaxydraw/demo/build-static.ts +0 -100
- package/packages/galaxydraw/demo/client.ts +0 -154
- package/packages/galaxydraw/demo/dist/client.js +0 -8
- package/packages/galaxydraw/demo/index.html +0 -256
- package/packages/galaxydraw/demo/server.ts +0 -96
- package/packages/galaxydraw/dist/index.js +0 -984
- package/packages/galaxydraw/dist/index.js.map +0 -16
- package/packages/galaxydraw/node_modules/.bin/tsc.bunx +0 -0
- package/packages/galaxydraw/node_modules/.bin/tsc.exe +0 -0
- package/packages/galaxydraw/node_modules/.bin/tsserver.bunx +0 -0
- package/packages/galaxydraw/node_modules/.bin/tsserver.exe +0 -0
- package/packages/galaxydraw/package.json +0 -49
- package/packages/galaxydraw/perf.test.ts +0 -284
- package/packages/galaxydraw/src/core/cards.ts +0 -435
- package/packages/galaxydraw/src/core/engine.ts +0 -339
- package/packages/galaxydraw/src/core/events.ts +0 -81
- package/packages/galaxydraw/src/core/layout.ts +0 -136
- package/packages/galaxydraw/src/core/minimap.ts +0 -216
- package/packages/galaxydraw/src/core/state.ts +0 -177
- package/packages/galaxydraw/src/core/viewport.ts +0 -106
- package/packages/galaxydraw/src/galaxydraw.css +0 -166
- package/packages/galaxydraw/src/index.ts +0 -40
- package/packages/galaxydraw/tsconfig.json +0 -30
|
@@ -1,229 +1,228 @@
|
|
|
1
|
-
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* Pure logic tests (no DOM). Validates coordinate conversion,
|
|
5
|
-
* zoom clamping, snapshot/subscribe, and pub/sub.
|
|
6
|
-
*
|
|
7
|
-
* Run: bun test app/lib/
|
|
8
|
-
*/
|
|
9
|
-
import { describe, expect, test } from 'bun:test'
|
|
10
|
-
import { CanvasState } from 'galaxydraw'
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
expect(s.
|
|
19
|
-
expect(s.
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
s.
|
|
36
|
-
expect(s.
|
|
37
|
-
expect(s.
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
s.
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
s.
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
s.
|
|
56
|
-
expect(s.
|
|
57
|
-
|
|
58
|
-
s.
|
|
59
|
-
expect(s.
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
s.
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
s.
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
//
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
expect(p.
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
s.
|
|
102
|
-
|
|
103
|
-
expect(p.
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
s.
|
|
110
|
-
|
|
111
|
-
expect(p.
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
expect(p.
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
s.
|
|
125
|
-
|
|
126
|
-
expect(p.
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
s.
|
|
133
|
-
const
|
|
134
|
-
|
|
135
|
-
expect(screen.
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
bus.
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
bus.on('canvas:zoom', () => { count++ })
|
|
155
|
-
bus.
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
bus.
|
|
175
|
-
bus.emit('card:create', { id: '
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
bus.on('canvas:pan', () => { count++ })
|
|
184
|
-
bus.
|
|
185
|
-
bus.
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
let
|
|
193
|
-
|
|
194
|
-
const
|
|
195
|
-
|
|
196
|
-
bus.on('canvas:pan',
|
|
197
|
-
bus.
|
|
198
|
-
bus.
|
|
199
|
-
|
|
200
|
-
expect(
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
bus.on('canvas:
|
|
208
|
-
bus.
|
|
209
|
-
bus.
|
|
210
|
-
bus.emit('canvas:
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
bus.on('canvas:pan', () => {
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
})
|
|
1
|
+
/**
|
|
2
|
+
* xydraw core unit tests — CanvasState & EventBus
|
|
3
|
+
*
|
|
4
|
+
* Pure logic tests (no DOM). Validates coordinate conversion,
|
|
5
|
+
* zoom clamping, snapshot/subscribe, and pub/sub.
|
|
6
|
+
*
|
|
7
|
+
* Run: bun test app/lib/xydraw.test.ts
|
|
8
|
+
*/
|
|
9
|
+
import { describe, expect, test } from 'bun:test'
|
|
10
|
+
import { CanvasState, EventBus } from '../../packages/galaxydraw/src/index'
|
|
11
|
+
|
|
12
|
+
// ─── CanvasState ────────────────────────────────────────
|
|
13
|
+
|
|
14
|
+
describe('CanvasState', () => {
|
|
15
|
+
test('initial state is zoom=1, offset=0,0', () => {
|
|
16
|
+
const s = new CanvasState()
|
|
17
|
+
expect(s.zoom).toBe(1)
|
|
18
|
+
expect(s.offsetX).toBe(0)
|
|
19
|
+
expect(s.offsetY).toBe(0)
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
test('snapshot returns a copy', () => {
|
|
23
|
+
const s = new CanvasState()
|
|
24
|
+
const snap = s.snapshot()
|
|
25
|
+
expect(snap).toEqual({ zoom: 1, offsetX: 0, offsetY: 0 })
|
|
26
|
+
|
|
27
|
+
// Mutation doesn't affect original
|
|
28
|
+
snap.zoom = 999
|
|
29
|
+
expect(s.zoom).toBe(1)
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
test('set() updates zoom and offset', () => {
|
|
33
|
+
const s = new CanvasState()
|
|
34
|
+
s.set(2, 100, 200)
|
|
35
|
+
expect(s.zoom).toBe(2)
|
|
36
|
+
expect(s.offsetX).toBe(100)
|
|
37
|
+
expect(s.offsetY).toBe(200)
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
test('set() clamps zoom to MIN_ZOOM', () => {
|
|
41
|
+
const s = new CanvasState()
|
|
42
|
+
s.set(0.001, 0, 0)
|
|
43
|
+
expect(s.zoom).toBe(s.MIN_ZOOM)
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
test('set() clamps zoom to MAX_ZOOM', () => {
|
|
47
|
+
const s = new CanvasState()
|
|
48
|
+
s.set(100, 0, 0)
|
|
49
|
+
expect(s.zoom).toBe(s.MAX_ZOOM)
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
test('pan() accumulates delta', () => {
|
|
53
|
+
const s = new CanvasState()
|
|
54
|
+
s.pan(10, 20)
|
|
55
|
+
expect(s.offsetX).toBe(10)
|
|
56
|
+
expect(s.offsetY).toBe(20)
|
|
57
|
+
s.pan(5, -10)
|
|
58
|
+
expect(s.offsetX).toBe(15)
|
|
59
|
+
expect(s.offsetY).toBe(10)
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
test('subscribe() is called on set()', () => {
|
|
63
|
+
const s = new CanvasState()
|
|
64
|
+
let callCount = 0
|
|
65
|
+
s.subscribe(() => { callCount++ })
|
|
66
|
+
s.set(2, 0, 0)
|
|
67
|
+
expect(callCount).toBe(1)
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
test('unsubscribe works', () => {
|
|
71
|
+
const s = new CanvasState()
|
|
72
|
+
let callCount = 0
|
|
73
|
+
const unsub = s.subscribe(() => { callCount++ })
|
|
74
|
+
s.set(2, 0, 0)
|
|
75
|
+
expect(callCount).toBe(1)
|
|
76
|
+
unsub()
|
|
77
|
+
s.set(3, 0, 0)
|
|
78
|
+
expect(callCount).toBe(1) // No additional call
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
test('subscribe() is called on pan()', () => {
|
|
82
|
+
const s = new CanvasState()
|
|
83
|
+
let called = false
|
|
84
|
+
s.subscribe(() => { called = true })
|
|
85
|
+
s.pan(10, 20)
|
|
86
|
+
expect(called).toBe(true)
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
test('screenToWorld identity at zoom=1 offset=0 (no viewport)', () => {
|
|
90
|
+
const s = new CanvasState()
|
|
91
|
+
// Without a viewport, rect defaults are 0, so screenToWorld
|
|
92
|
+
// just divides by zoom and subtracts offset
|
|
93
|
+
const p = s.screenToWorld(100, 200)
|
|
94
|
+
expect(p.x).toBe(100)
|
|
95
|
+
expect(p.y).toBe(200)
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
test('screenToWorld with zoom=2', () => {
|
|
99
|
+
const s = new CanvasState()
|
|
100
|
+
s.set(2, 0, 0)
|
|
101
|
+
const p = s.screenToWorld(200, 400)
|
|
102
|
+
expect(p.x).toBe(100)
|
|
103
|
+
expect(p.y).toBe(200)
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
test('screenToWorld with offset', () => {
|
|
107
|
+
const s = new CanvasState()
|
|
108
|
+
s.set(1, 50, 100)
|
|
109
|
+
const p = s.screenToWorld(150, 200)
|
|
110
|
+
expect(p.x).toBe(100)
|
|
111
|
+
expect(p.y).toBe(100)
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
test('worldToScreen identity at zoom=1 offset=0 (no viewport)', () => {
|
|
115
|
+
const s = new CanvasState()
|
|
116
|
+
const p = s.worldToScreen(100, 200)
|
|
117
|
+
expect(p.x).toBe(100)
|
|
118
|
+
expect(p.y).toBe(200)
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
test('worldToScreen with zoom=2', () => {
|
|
122
|
+
const s = new CanvasState()
|
|
123
|
+
s.set(2, 0, 0)
|
|
124
|
+
const p = s.worldToScreen(100, 200)
|
|
125
|
+
expect(p.x).toBe(200)
|
|
126
|
+
expect(p.y).toBe(400)
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
test('screenToWorld/worldToScreen roundtrip', () => {
|
|
130
|
+
const s = new CanvasState()
|
|
131
|
+
s.set(1.5, 30, -40)
|
|
132
|
+
const world = s.screenToWorld(300, 250)
|
|
133
|
+
const screen = s.worldToScreen(world.x, world.y)
|
|
134
|
+
expect(screen.x).toBeCloseTo(300, 5)
|
|
135
|
+
expect(screen.y).toBeCloseTo(250, 5)
|
|
136
|
+
})
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
// ─── EventBus ───────────────────────────────────────────
|
|
140
|
+
|
|
141
|
+
describe('EventBus', () => {
|
|
142
|
+
test('on() receives emitted events', () => {
|
|
143
|
+
const bus = new EventBus()
|
|
144
|
+
let received: any = null
|
|
145
|
+
bus.on('canvas:pan', (data) => { received = data })
|
|
146
|
+
bus.emit('canvas:pan', { offsetX: 10, offsetY: 20 })
|
|
147
|
+
expect(received).toEqual({ offsetX: 10, offsetY: 20 })
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
test('multiple handlers receive same event', () => {
|
|
151
|
+
const bus = new EventBus()
|
|
152
|
+
let count = 0
|
|
153
|
+
bus.on('canvas:zoom', () => { count++ })
|
|
154
|
+
bus.on('canvas:zoom', () => { count++ })
|
|
155
|
+
bus.emit('canvas:zoom', { zoom: 2, centerX: 0, centerY: 0 })
|
|
156
|
+
expect(count).toBe(2)
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
test('unsubscribe via returned function', () => {
|
|
160
|
+
const bus = new EventBus()
|
|
161
|
+
let count = 0
|
|
162
|
+
const unsub = bus.on('canvas:pan', () => { count++ })
|
|
163
|
+
bus.emit('canvas:pan', { offsetX: 0, offsetY: 0 })
|
|
164
|
+
expect(count).toBe(1)
|
|
165
|
+
unsub()
|
|
166
|
+
bus.emit('canvas:pan', { offsetX: 0, offsetY: 0 })
|
|
167
|
+
expect(count).toBe(1)
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
test('once() fires only once', () => {
|
|
171
|
+
const bus = new EventBus()
|
|
172
|
+
let count = 0
|
|
173
|
+
bus.once('card:create', () => { count++ })
|
|
174
|
+
bus.emit('card:create', { id: '1', x: 0, y: 0 })
|
|
175
|
+
bus.emit('card:create', { id: '2', x: 0, y: 0 })
|
|
176
|
+
expect(count).toBe(1)
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
test('off() without handler removes all handlers for event', () => {
|
|
180
|
+
const bus = new EventBus()
|
|
181
|
+
let count = 0
|
|
182
|
+
bus.on('canvas:pan', () => { count++ })
|
|
183
|
+
bus.on('canvas:pan', () => { count++ })
|
|
184
|
+
bus.off('canvas:pan')
|
|
185
|
+
bus.emit('canvas:pan', { offsetX: 0, offsetY: 0 })
|
|
186
|
+
expect(count).toBe(0)
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
test('off() with handler removes only that handler', () => {
|
|
190
|
+
const bus = new EventBus()
|
|
191
|
+
let aCount = 0
|
|
192
|
+
let bCount = 0
|
|
193
|
+
const handlerA = () => { aCount++ }
|
|
194
|
+
const handlerB = () => { bCount++ }
|
|
195
|
+
bus.on('canvas:pan', handlerA)
|
|
196
|
+
bus.on('canvas:pan', handlerB)
|
|
197
|
+
bus.off('canvas:pan', handlerA)
|
|
198
|
+
bus.emit('canvas:pan', { offsetX: 0, offsetY: 0 })
|
|
199
|
+
expect(aCount).toBe(0)
|
|
200
|
+
expect(bCount).toBe(1)
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
test('clear() removes all event handlers', () => {
|
|
204
|
+
const bus = new EventBus()
|
|
205
|
+
let count = 0
|
|
206
|
+
bus.on('canvas:pan', () => { count++ })
|
|
207
|
+
bus.on('canvas:zoom', () => { count++ })
|
|
208
|
+
bus.clear()
|
|
209
|
+
bus.emit('canvas:pan', { offsetX: 0, offsetY: 0 })
|
|
210
|
+
bus.emit('canvas:zoom', { zoom: 1, centerX: 0, centerY: 0 })
|
|
211
|
+
expect(count).toBe(0)
|
|
212
|
+
})
|
|
213
|
+
|
|
214
|
+
test('emit with no handlers does not throw', () => {
|
|
215
|
+
const bus = new EventBus()
|
|
216
|
+
expect(() => bus.emit('canvas:pan', { offsetX: 0, offsetY: 0 })).not.toThrow()
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
test('handler error does not break other handlers', () => {
|
|
220
|
+
const bus = new EventBus()
|
|
221
|
+
let secondCalled = false
|
|
222
|
+
bus.on('canvas:pan', () => { throw new Error('boom') })
|
|
223
|
+
bus.on('canvas:pan', () => { secondCalled = true })
|
|
224
|
+
// Should not throw, errors are caught internally
|
|
225
|
+
bus.emit('canvas:pan', { offsetX: 0, offsetY: 0 })
|
|
226
|
+
expect(secondCalled).toBe(true)
|
|
227
|
+
})
|
|
228
|
+
})
|
package/app/og-image.png
ADDED
|
Binary file
|