@tldraw/editor 4.4.0-next.55b4db2171bd → 4.4.0-next.f181afb0ab39

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.
Files changed (87) hide show
  1. package/dist-cjs/index.d.ts +175 -11
  2. package/dist-cjs/index.js +1 -1
  3. package/dist-cjs/index.js.map +2 -2
  4. package/dist-cjs/lib/components/LiveCollaborators.js +14 -24
  5. package/dist-cjs/lib/components/LiveCollaborators.js.map +2 -2
  6. package/dist-cjs/lib/components/default-components/CanvasShapeIndicators.js +201 -0
  7. package/dist-cjs/lib/components/default-components/CanvasShapeIndicators.js.map +7 -0
  8. package/dist-cjs/lib/components/default-components/DefaultCanvas.js +29 -14
  9. package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
  10. package/dist-cjs/lib/components/default-components/DefaultShapeIndicator.js +3 -1
  11. package/dist-cjs/lib/components/default-components/DefaultShapeIndicator.js.map +2 -2
  12. package/dist-cjs/lib/components/default-components/DefaultShapeIndicators.js +13 -1
  13. package/dist-cjs/lib/components/default-components/DefaultShapeIndicators.js.map +2 -2
  14. package/dist-cjs/lib/config/TLUserPreferences.js +9 -3
  15. package/dist-cjs/lib/config/TLUserPreferences.js.map +2 -2
  16. package/dist-cjs/lib/editor/Editor.js +4 -1
  17. package/dist-cjs/lib/editor/Editor.js.map +2 -2
  18. package/dist-cjs/lib/editor/managers/ScribbleManager/ScribbleManager.js +378 -89
  19. package/dist-cjs/lib/editor/managers/ScribbleManager/ScribbleManager.js.map +2 -2
  20. package/dist-cjs/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.js +2 -3
  21. package/dist-cjs/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.js.map +2 -2
  22. package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js +8 -3
  23. package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js.map +2 -2
  24. package/dist-cjs/lib/editor/shapes/ShapeUtil.js +29 -0
  25. package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
  26. package/dist-cjs/lib/hooks/usePeerIds.js +29 -0
  27. package/dist-cjs/lib/hooks/usePeerIds.js.map +2 -2
  28. package/dist-cjs/lib/options.js +1 -0
  29. package/dist-cjs/lib/options.js.map +2 -2
  30. package/dist-cjs/lib/utils/collaboratorState.js +42 -0
  31. package/dist-cjs/lib/utils/collaboratorState.js.map +7 -0
  32. package/dist-cjs/version.js +3 -3
  33. package/dist-cjs/version.js.map +1 -1
  34. package/dist-esm/index.d.mts +175 -11
  35. package/dist-esm/index.mjs +1 -1
  36. package/dist-esm/index.mjs.map +2 -2
  37. package/dist-esm/lib/components/LiveCollaborators.mjs +17 -24
  38. package/dist-esm/lib/components/LiveCollaborators.mjs.map +2 -2
  39. package/dist-esm/lib/components/default-components/CanvasShapeIndicators.mjs +181 -0
  40. package/dist-esm/lib/components/default-components/CanvasShapeIndicators.mjs.map +7 -0
  41. package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +29 -14
  42. package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
  43. package/dist-esm/lib/components/default-components/DefaultShapeIndicator.mjs +3 -1
  44. package/dist-esm/lib/components/default-components/DefaultShapeIndicator.mjs.map +2 -2
  45. package/dist-esm/lib/components/default-components/DefaultShapeIndicators.mjs +13 -1
  46. package/dist-esm/lib/components/default-components/DefaultShapeIndicators.mjs.map +2 -2
  47. package/dist-esm/lib/config/TLUserPreferences.mjs +9 -3
  48. package/dist-esm/lib/config/TLUserPreferences.mjs.map +2 -2
  49. package/dist-esm/lib/editor/Editor.mjs +4 -1
  50. package/dist-esm/lib/editor/Editor.mjs.map +2 -2
  51. package/dist-esm/lib/editor/managers/ScribbleManager/ScribbleManager.mjs +378 -89
  52. package/dist-esm/lib/editor/managers/ScribbleManager/ScribbleManager.mjs.map +2 -2
  53. package/dist-esm/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.mjs +2 -3
  54. package/dist-esm/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.mjs.map +2 -2
  55. package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs +8 -3
  56. package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs.map +2 -2
  57. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs +29 -0
  58. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
  59. package/dist-esm/lib/hooks/usePeerIds.mjs +33 -1
  60. package/dist-esm/lib/hooks/usePeerIds.mjs.map +2 -2
  61. package/dist-esm/lib/options.mjs +1 -0
  62. package/dist-esm/lib/options.mjs.map +2 -2
  63. package/dist-esm/lib/utils/collaboratorState.mjs +22 -0
  64. package/dist-esm/lib/utils/collaboratorState.mjs.map +7 -0
  65. package/dist-esm/version.mjs +3 -3
  66. package/dist-esm/version.mjs.map +1 -1
  67. package/editor.css +6 -0
  68. package/package.json +7 -7
  69. package/src/index.ts +2 -0
  70. package/src/lib/components/LiveCollaborators.tsx +26 -37
  71. package/src/lib/components/default-components/CanvasShapeIndicators.tsx +244 -0
  72. package/src/lib/components/default-components/DefaultCanvas.tsx +15 -1
  73. package/src/lib/components/default-components/DefaultShapeIndicator.tsx +6 -1
  74. package/src/lib/components/default-components/DefaultShapeIndicators.tsx +16 -1
  75. package/src/lib/config/TLUserPreferences.test.ts +1 -0
  76. package/src/lib/config/TLUserPreferences.ts +8 -0
  77. package/src/lib/editor/Editor.ts +10 -1
  78. package/src/lib/editor/managers/ScribbleManager/ScribbleManager.ts +491 -106
  79. package/src/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.ts +2 -3
  80. package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.test.ts +24 -0
  81. package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.ts +8 -0
  82. package/src/lib/editor/shapes/ShapeUtil.ts +44 -0
  83. package/src/lib/hooks/usePeerIds.ts +46 -1
  84. package/src/lib/options.ts +7 -0
  85. package/src/lib/utils/collaboratorState.ts +54 -0
  86. package/src/version.ts +3 -3
  87. package/src/lib/editor/managers/ScribbleManager/ScribbleManager.test.ts +0 -621
@@ -27,13 +27,53 @@ class ScribbleManager {
27
27
  constructor(editor) {
28
28
  this.editor = editor;
29
29
  }
30
- scribbleItems = /* @__PURE__ */ new Map();
31
- state = "paused";
32
- addScribble(scribble, id = (0, import_utils.uniqueId)()) {
33
- const item = {
30
+ sessions = /* @__PURE__ */ new Map();
31
+ // ==================== SESSION API ====================
32
+ /**
33
+ * Start a new session for grouping scribbles.
34
+ * Returns a session ID that can be used with other session methods.
35
+ *
36
+ * @param options - Session configuration
37
+ * @returns Session ID
38
+ * @public
39
+ */
40
+ startSession(options = {}) {
41
+ const id = options.id ?? (0, import_utils.uniqueId)();
42
+ const session = {
34
43
  id,
44
+ items: [],
45
+ state: "active",
46
+ options: {
47
+ selfConsume: options.selfConsume ?? true,
48
+ idleTimeoutMs: options.idleTimeoutMs ?? 0,
49
+ fadeMode: options.fadeMode ?? "individual",
50
+ fadeEasing: options.fadeEasing ?? (options.fadeMode === "grouped" ? "ease-in" : "linear"),
51
+ fadeDurationMs: options.fadeDurationMs ?? this.editor.options.laserFadeoutMs
52
+ },
53
+ fadeElapsed: 0,
54
+ totalPointsAtFadeStart: 0
55
+ };
56
+ this.sessions.set(id, session);
57
+ if (session.options.idleTimeoutMs > 0) {
58
+ this.resetIdleTimeout(session);
59
+ }
60
+ return id;
61
+ }
62
+ /**
63
+ * Add a scribble to a session.
64
+ *
65
+ * @param sessionId - The session ID
66
+ * @param scribble - Partial scribble properties
67
+ * @param scribbleId - Optional scribble ID
68
+ * @public
69
+ */
70
+ addScribbleToSession(sessionId, scribble, scribbleId = (0, import_utils.uniqueId)()) {
71
+ const session = this.sessions.get(sessionId);
72
+ if (!session) throw Error(`Session ${sessionId} not found`);
73
+ const item = {
74
+ id: scribbleId,
35
75
  scribble: {
36
- id,
76
+ id: scribbleId,
37
77
  size: 20,
38
78
  color: "accent",
39
79
  opacity: 0.8,
@@ -49,43 +89,187 @@ class ScribbleManager {
49
89
  prev: null,
50
90
  next: null
51
91
  };
52
- this.scribbleItems.set(id, item);
92
+ session.items.push(item);
93
+ if (session.options.idleTimeoutMs > 0) {
94
+ this.resetIdleTimeout(session);
95
+ }
53
96
  return item;
54
97
  }
55
- reset() {
56
- this.editor.updateInstanceState({ scribbles: [] });
57
- this.scribbleItems.clear();
58
- }
59
98
  /**
60
- * Start stopping the scribble. The scribble won't be removed until its last point is cleared.
99
+ * Add a point to a scribble in a session.
61
100
  *
101
+ * @param sessionId - The session ID
102
+ * @param scribbleId - The scribble ID
103
+ * @param x - X coordinate
104
+ * @param y - Y coordinate
105
+ * @param z - Z coordinate (pressure)
62
106
  * @public
63
107
  */
64
- stop(id) {
65
- const item = this.scribbleItems.get(id);
66
- if (!item) throw Error(`Scribble with id ${id} not found`);
67
- item.delayRemaining = Math.min(item.delayRemaining, 200);
68
- item.scribble.state = "stopping";
108
+ addPointToSession(sessionId, scribbleId, x, y, z = 0.5) {
109
+ const session = this.sessions.get(sessionId);
110
+ if (!session) throw Error(`Session ${sessionId} not found`);
111
+ const item = session.items.find((i) => i.id === scribbleId);
112
+ if (!item) throw Error(`Scribble ${scribbleId} not found in session ${sessionId}`);
113
+ const point = { x, y, z };
114
+ if (!item.prev || import_Vec.Vec.Dist(item.prev, point) >= 1) {
115
+ item.next = point;
116
+ }
117
+ if (session.options.idleTimeoutMs > 0) {
118
+ this.resetIdleTimeout(session);
119
+ }
69
120
  return item;
70
121
  }
71
122
  /**
72
- * Set the scribble's next point.
123
+ * Extend a session, resetting its idle timeout.
73
124
  *
74
- * @param id - The id of the scribble to add a point to.
75
- * @param x - The x coordinate of the point.
76
- * @param y - The y coordinate of the point.
77
- * @param z - The z coordinate of the point.
125
+ * @param sessionId - The session ID
126
+ * @public
127
+ */
128
+ extendSession(sessionId) {
129
+ const session = this.sessions.get(sessionId);
130
+ if (!session) return;
131
+ if (session.options.idleTimeoutMs > 0) {
132
+ this.resetIdleTimeout(session);
133
+ }
134
+ }
135
+ /**
136
+ * Stop a session, triggering fade-out.
137
+ *
138
+ * @param sessionId - The session ID
139
+ * @public
140
+ */
141
+ stopSession(sessionId) {
142
+ const session = this.sessions.get(sessionId);
143
+ if (!session || session.state !== "active") return;
144
+ this.clearIdleTimeout(session);
145
+ session.state = "stopping";
146
+ if (session.options.fadeMode === "grouped") {
147
+ session.totalPointsAtFadeStart = session.items.reduce(
148
+ (sum, item) => sum + item.scribble.points.length,
149
+ 0
150
+ );
151
+ session.fadeElapsed = 0;
152
+ for (const item of session.items) {
153
+ item.scribble.state = "stopping";
154
+ }
155
+ } else {
156
+ for (const item of session.items) {
157
+ item.delayRemaining = Math.min(item.delayRemaining, 200);
158
+ item.scribble.state = "stopping";
159
+ }
160
+ }
161
+ }
162
+ /**
163
+ * Clear all scribbles in a session immediately.
164
+ *
165
+ * @param sessionId - The session ID
166
+ * @public
167
+ */
168
+ clearSession(sessionId) {
169
+ const session = this.sessions.get(sessionId);
170
+ if (!session) return;
171
+ this.clearIdleTimeout(session);
172
+ for (const item of session.items) {
173
+ item.scribble.points.length = 0;
174
+ }
175
+ session.state = "complete";
176
+ }
177
+ /**
178
+ * Check if a session is active.
179
+ *
180
+ * @param sessionId - The session ID
181
+ * @public
182
+ */
183
+ isSessionActive(sessionId) {
184
+ const session = this.sessions.get(sessionId);
185
+ return session?.state === "active";
186
+ }
187
+ // ==================== SIMPLE API (for eraser, select, etc.) ====================
188
+ /**
189
+ * Add a scribble using the default self-consuming behavior.
190
+ * Creates an implicit session for the scribble.
191
+ *
192
+ * @param scribble - Partial scribble properties
193
+ * @param id - Optional scribble id
194
+ * @returns The created scribble item
195
+ * @public
196
+ */
197
+ addScribble(scribble, id = (0, import_utils.uniqueId)()) {
198
+ const sessionId = this.startSession();
199
+ return this.addScribbleToSession(sessionId, scribble, id);
200
+ }
201
+ /**
202
+ * Add a point to a scribble. Searches all sessions.
203
+ *
204
+ * @param id - The scribble id
205
+ * @param x - X coordinate
206
+ * @param y - Y coordinate
207
+ * @param z - Z coordinate (pressure)
78
208
  * @public
79
209
  */
80
210
  addPoint(id, x, y, z = 0.5) {
81
- const item = this.scribbleItems.get(id);
82
- if (!item) throw Error(`Scribble with id ${id} not found`);
83
- const { prev } = item;
84
- const point = { x, y, z };
85
- if (!prev || import_Vec.Vec.Dist(prev, point) >= 1) {
86
- item.next = point;
211
+ for (const session of this.sessions.values()) {
212
+ const item = session.items.find((i) => i.id === id);
213
+ if (item) {
214
+ const point = { x, y, z };
215
+ if (!item.prev || import_Vec.Vec.Dist(item.prev, point) >= 1) {
216
+ item.next = point;
217
+ }
218
+ if (session.options.idleTimeoutMs > 0) {
219
+ this.resetIdleTimeout(session);
220
+ }
221
+ return item;
222
+ }
87
223
  }
88
- return item;
224
+ throw Error(`Scribble with id ${id} not found`);
225
+ }
226
+ /**
227
+ * Mark a scribble as complete (done being drawn but not yet fading).
228
+ * Searches all sessions.
229
+ *
230
+ * @param id - The scribble id
231
+ * @public
232
+ */
233
+ complete(id) {
234
+ for (const session of this.sessions.values()) {
235
+ const item = session.items.find((i) => i.id === id);
236
+ if (item) {
237
+ if (item.scribble.state === "starting" || item.scribble.state === "active") {
238
+ item.scribble.state = "complete";
239
+ }
240
+ return item;
241
+ }
242
+ }
243
+ throw Error(`Scribble with id ${id} not found`);
244
+ }
245
+ /**
246
+ * Stop a scribble. Searches all sessions.
247
+ *
248
+ * @param id - The scribble id
249
+ * @public
250
+ */
251
+ stop(id) {
252
+ for (const session of this.sessions.values()) {
253
+ const item = session.items.find((i) => i.id === id);
254
+ if (item) {
255
+ item.delayRemaining = Math.min(item.delayRemaining, 200);
256
+ item.scribble.state = "stopping";
257
+ return item;
258
+ }
259
+ }
260
+ throw Error(`Scribble with id ${id} not found`);
261
+ }
262
+ /**
263
+ * Stop and remove all sessions.
264
+ *
265
+ * @public
266
+ */
267
+ reset() {
268
+ for (const session of this.sessions.values()) {
269
+ this.clearIdleTimeout(session);
270
+ }
271
+ this.sessions.clear();
272
+ this.editor.updateInstanceState({ scribbles: [] });
89
273
  }
90
274
  /**
91
275
  * Update on each animation frame.
@@ -94,77 +278,182 @@ class ScribbleManager {
94
278
  * @public
95
279
  */
96
280
  tick(elapsed) {
97
- if (this.scribbleItems.size === 0) return;
281
+ const currentScribbles = this.editor.getInstanceState().scribbles;
282
+ if (this.sessions.size === 0 && currentScribbles.length === 0) return;
98
283
  this.editor.run(() => {
99
- this.scribbleItems.forEach((item) => {
100
- if (item.scribble.state === "starting") {
101
- const { next: next2, prev: prev2 } = item;
102
- if (next2 && next2 !== prev2) {
103
- item.prev = next2;
104
- item.scribble.points.push(next2);
105
- }
106
- if (item.scribble.points.length > 8) {
107
- item.scribble.state = "active";
108
- }
109
- return;
284
+ for (const session of this.sessions.values()) {
285
+ this.tickSession(session, elapsed);
286
+ }
287
+ for (const [id, session] of this.sessions) {
288
+ if (session.state === "complete") {
289
+ this.clearIdleTimeout(session);
290
+ this.sessions.delete(id);
110
291
  }
111
- if (item.delayRemaining > 0) {
112
- item.delayRemaining = Math.max(0, item.delayRemaining - elapsed);
292
+ }
293
+ const scribbles = [];
294
+ for (const session of this.sessions.values()) {
295
+ for (const item of session.items) {
296
+ if (item.scribble.points.length > 0) {
297
+ scribbles.push({
298
+ ...item.scribble,
299
+ points: [...item.scribble.points]
300
+ });
301
+ }
113
302
  }
114
- item.timeoutMs += elapsed;
115
- if (item.timeoutMs >= 16) {
116
- item.timeoutMs = 0;
303
+ }
304
+ this.editor.updateInstanceState({ scribbles });
305
+ });
306
+ }
307
+ // ==================== PRIVATE HELPERS ====================
308
+ resetIdleTimeout(session) {
309
+ this.clearIdleTimeout(session);
310
+ session.idleTimeoutHandle = this.editor.timers.setTimeout(() => {
311
+ this.stopSession(session.id);
312
+ }, session.options.idleTimeoutMs);
313
+ }
314
+ clearIdleTimeout(session) {
315
+ if (session.idleTimeoutHandle !== void 0) {
316
+ clearTimeout(session.idleTimeoutHandle);
317
+ session.idleTimeoutHandle = void 0;
318
+ }
319
+ }
320
+ tickSession(session, elapsed) {
321
+ if (session.state === "complete") return;
322
+ if (session.state === "stopping" && session.options.fadeMode === "grouped") {
323
+ this.tickGroupedFade(session, elapsed);
324
+ } else {
325
+ this.tickSessionItems(session, elapsed);
326
+ }
327
+ const hasContent = session.items.some((item) => item.scribble.points.length > 0);
328
+ if (!hasContent && (session.state === "stopping" || session.items.length === 0)) {
329
+ session.state = "complete";
330
+ }
331
+ }
332
+ tickSessionItems(session, elapsed) {
333
+ for (const item of session.items) {
334
+ const shouldSelfConsume = session.options.selfConsume || session.state === "stopping" || item.scribble.state === "stopping";
335
+ if (shouldSelfConsume) {
336
+ this.tickSelfConsumingItem(item, elapsed);
337
+ } else {
338
+ this.tickPersistentItem(item);
339
+ }
340
+ }
341
+ if (session.options.fadeMode === "individual") {
342
+ for (let i = session.items.length - 1; i >= 0; i--) {
343
+ if (session.items[i].scribble.points.length === 0) {
344
+ session.items.splice(i, 1);
117
345
  }
118
- const { delayRemaining, timeoutMs, prev, next, scribble } = item;
119
- switch (scribble.state) {
120
- case "active": {
121
- if (next && next !== prev) {
122
- item.prev = next;
123
- scribble.points.push(next);
124
- if (delayRemaining === 0) {
125
- if (scribble.points.length > 8) {
126
- scribble.points.shift();
127
- }
128
- }
346
+ }
347
+ }
348
+ }
349
+ tickPersistentItem(item) {
350
+ const { scribble } = item;
351
+ if (scribble.state === "starting") {
352
+ const { next, prev } = item;
353
+ if (next && next !== prev) {
354
+ item.prev = next;
355
+ scribble.points.push(next);
356
+ }
357
+ if (scribble.points.length > 8) {
358
+ scribble.state = "active";
359
+ }
360
+ return;
361
+ }
362
+ if (scribble.state === "active") {
363
+ const { next, prev } = item;
364
+ if (next && next !== prev) {
365
+ item.prev = next;
366
+ scribble.points.push(next);
367
+ }
368
+ }
369
+ }
370
+ tickSelfConsumingItem(item, elapsed) {
371
+ const { scribble } = item;
372
+ if (scribble.state === "starting") {
373
+ const { next: next2, prev: prev2 } = item;
374
+ if (next2 && next2 !== prev2) {
375
+ item.prev = next2;
376
+ scribble.points.push(next2);
377
+ }
378
+ if (scribble.points.length > 8) {
379
+ scribble.state = "active";
380
+ }
381
+ return;
382
+ }
383
+ if (item.delayRemaining > 0) {
384
+ item.delayRemaining = Math.max(0, item.delayRemaining - elapsed);
385
+ }
386
+ item.timeoutMs += elapsed;
387
+ if (item.timeoutMs >= 16) {
388
+ item.timeoutMs = 0;
389
+ }
390
+ const { delayRemaining, timeoutMs, prev, next } = item;
391
+ switch (scribble.state) {
392
+ case "active": {
393
+ if (next && next !== prev) {
394
+ item.prev = next;
395
+ scribble.points.push(next);
396
+ if (delayRemaining === 0 && scribble.points.length > 8) {
397
+ scribble.points.shift();
398
+ }
399
+ } else {
400
+ if (timeoutMs === 0) {
401
+ if (scribble.points.length > 1) {
402
+ scribble.points.shift();
129
403
  } else {
130
- if (timeoutMs === 0) {
131
- if (scribble.points.length > 1) {
132
- scribble.points.shift();
133
- } else {
134
- item.delayRemaining = scribble.delay;
135
- }
136
- }
404
+ item.delayRemaining = scribble.delay;
137
405
  }
138
- break;
139
406
  }
140
- case "stopping": {
141
- if (item.delayRemaining === 0) {
142
- if (timeoutMs === 0) {
143
- if (scribble.points.length === 1) {
144
- this.scribbleItems.delete(item.id);
145
- return;
146
- }
147
- if (scribble.shrink) {
148
- scribble.size = Math.max(1, scribble.size * (1 - scribble.shrink));
149
- }
150
- scribble.points.shift();
151
- }
152
- }
153
- break;
407
+ }
408
+ break;
409
+ }
410
+ case "stopping": {
411
+ if (delayRemaining === 0 && timeoutMs === 0) {
412
+ if (scribble.points.length <= 1) {
413
+ scribble.points.length = 0;
414
+ return;
154
415
  }
155
- case "paused": {
156
- break;
416
+ if (scribble.shrink) {
417
+ scribble.size = Math.max(1, scribble.size * (1 - scribble.shrink));
157
418
  }
419
+ scribble.points.shift();
158
420
  }
159
- });
160
- this.editor.updateInstanceState({
161
- scribbles: Array.from(this.scribbleItems.values()).map(({ scribble }) => ({
162
- ...scribble,
163
- points: [...scribble.points]
164
- })).slice(-5)
165
- // limit to three as a minor sanity check
166
- });
167
- });
421
+ break;
422
+ }
423
+ case "paused": {
424
+ break;
425
+ }
426
+ }
427
+ }
428
+ tickGroupedFade(session, elapsed) {
429
+ session.fadeElapsed += elapsed;
430
+ let remainingPoints = 0;
431
+ for (const item of session.items) {
432
+ remainingPoints += item.scribble.points.length;
433
+ }
434
+ if (remainingPoints === 0) return;
435
+ if (session.fadeElapsed >= session.options.fadeDurationMs) {
436
+ for (const item of session.items) {
437
+ item.scribble.points.length = 0;
438
+ }
439
+ return;
440
+ }
441
+ const progress = session.fadeElapsed / session.options.fadeDurationMs;
442
+ const easedProgress = session.options.fadeEasing === "ease-in" ? progress * progress : progress;
443
+ const targetRemoved = Math.floor(easedProgress * session.totalPointsAtFadeStart);
444
+ const actuallyRemoved = session.totalPointsAtFadeStart - remainingPoints;
445
+ const pointsToRemove = Math.max(1, targetRemoved - actuallyRemoved);
446
+ let removed = 0;
447
+ let itemIndex = 0;
448
+ while (removed < pointsToRemove && itemIndex < session.items.length) {
449
+ const item = session.items[itemIndex];
450
+ if (item.scribble.points.length > 0) {
451
+ item.scribble.points.shift();
452
+ removed++;
453
+ } else {
454
+ itemIndex++;
455
+ }
456
+ }
168
457
  }
169
458
  }
170
459
  //# sourceMappingURL=ScribbleManager.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/lib/editor/managers/ScribbleManager/ScribbleManager.ts"],
4
- "sourcesContent": ["import { TLScribble, VecModel } from '@tldraw/tlschema'\nimport { uniqueId } from '@tldraw/utils'\nimport { Vec } from '../../../primitives/Vec'\nimport { Editor } from '../../Editor'\n\n/** @public */\nexport interface ScribbleItem {\n\tid: string\n\tscribble: TLScribble\n\ttimeoutMs: number\n\tdelayRemaining: number\n\tprev: null | VecModel\n\tnext: null | VecModel\n}\n\n/** @public */\nexport class ScribbleManager {\n\tscribbleItems = new Map<string, ScribbleItem>()\n\tstate = 'paused' as 'paused' | 'running'\n\n\tconstructor(private editor: Editor) {}\n\n\taddScribble(scribble: Partial<TLScribble>, id = uniqueId()) {\n\t\tconst item: ScribbleItem = {\n\t\t\tid,\n\t\t\tscribble: {\n\t\t\t\tid,\n\t\t\t\tsize: 20,\n\t\t\t\tcolor: 'accent',\n\t\t\t\topacity: 0.8,\n\t\t\t\tdelay: 0,\n\t\t\t\tpoints: [],\n\t\t\t\tshrink: 0.1,\n\t\t\t\ttaper: true,\n\t\t\t\t...scribble,\n\t\t\t\tstate: 'starting',\n\t\t\t},\n\t\t\ttimeoutMs: 0,\n\t\t\tdelayRemaining: scribble.delay ?? 0,\n\t\t\tprev: null,\n\t\t\tnext: null,\n\t\t}\n\t\tthis.scribbleItems.set(id, item)\n\t\treturn item\n\t}\n\n\treset() {\n\t\tthis.editor.updateInstanceState({ scribbles: [] })\n\t\tthis.scribbleItems.clear()\n\t}\n\n\t/**\n\t * Start stopping the scribble. The scribble won't be removed until its last point is cleared.\n\t *\n\t * @public\n\t */\n\tstop(id: ScribbleItem['id']) {\n\t\tconst item = this.scribbleItems.get(id)\n\t\tif (!item) throw Error(`Scribble with id ${id} not found`)\n\t\titem.delayRemaining = Math.min(item.delayRemaining, 200)\n\t\titem.scribble.state = 'stopping'\n\t\treturn item\n\t}\n\n\t/**\n\t * Set the scribble's next point.\n\t *\n\t * @param id - The id of the scribble to add a point to.\n\t * @param x - The x coordinate of the point.\n\t * @param y - The y coordinate of the point.\n\t * @param z - The z coordinate of the point.\n\t * @public\n\t */\n\taddPoint(id: ScribbleItem['id'], x: number, y: number, z = 0.5) {\n\t\tconst item = this.scribbleItems.get(id)\n\t\tif (!item) throw Error(`Scribble with id ${id} not found`)\n\t\tconst { prev } = item\n\t\tconst point = { x, y, z }\n\t\tif (!prev || Vec.Dist(prev, point) >= 1) {\n\t\t\titem.next = point\n\t\t}\n\t\treturn item\n\t}\n\n\t/**\n\t * Update on each animation frame.\n\t *\n\t * @param elapsed - The number of milliseconds since the last tick.\n\t * @public\n\t */\n\ttick(elapsed: number) {\n\t\tif (this.scribbleItems.size === 0) return\n\t\tthis.editor.run(() => {\n\t\t\tthis.scribbleItems.forEach((item) => {\n\t\t\t\t// let the item get at least eight points before\n\t\t\t\t// switching from starting to active\n\t\t\t\tif (item.scribble.state === 'starting') {\n\t\t\t\t\tconst { next, prev } = item\n\t\t\t\t\tif (next && next !== prev) {\n\t\t\t\t\t\titem.prev = next\n\t\t\t\t\t\titem.scribble.points.push(next)\n\t\t\t\t\t}\n\n\t\t\t\t\tif (item.scribble.points.length > 8) {\n\t\t\t\t\t\titem.scribble.state = 'active'\n\t\t\t\t\t}\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tif (item.delayRemaining > 0) {\n\t\t\t\t\titem.delayRemaining = Math.max(0, item.delayRemaining - elapsed)\n\t\t\t\t}\n\n\t\t\t\titem.timeoutMs += elapsed\n\t\t\t\tif (item.timeoutMs >= 16) {\n\t\t\t\t\titem.timeoutMs = 0\n\t\t\t\t}\n\n\t\t\t\tconst { delayRemaining, timeoutMs, prev, next, scribble } = item\n\n\t\t\t\tswitch (scribble.state) {\n\t\t\t\t\tcase 'active': {\n\t\t\t\t\t\tif (next && next !== prev) {\n\t\t\t\t\t\t\titem.prev = next\n\t\t\t\t\t\t\tscribble.points.push(next)\n\n\t\t\t\t\t\t\t// If we've run out of delay, then shrink the scribble from the start\n\t\t\t\t\t\t\tif (delayRemaining === 0) {\n\t\t\t\t\t\t\t\tif (scribble.points.length > 8) {\n\t\t\t\t\t\t\t\t\tscribble.points.shift()\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// While not moving, shrink the scribble from the start\n\t\t\t\t\t\t\tif (timeoutMs === 0) {\n\t\t\t\t\t\t\t\tif (scribble.points.length > 1) {\n\t\t\t\t\t\t\t\t\tscribble.points.shift()\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t// Reset the item's delay\n\t\t\t\t\t\t\t\t\titem.delayRemaining = scribble.delay\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\tcase 'stopping': {\n\t\t\t\t\t\tif (item.delayRemaining === 0) {\n\t\t\t\t\t\t\tif (timeoutMs === 0) {\n\t\t\t\t\t\t\t\t// If the scribble is down to one point, we're done!\n\t\t\t\t\t\t\t\tif (scribble.points.length === 1) {\n\t\t\t\t\t\t\t\t\tthis.scribbleItems.delete(item.id) // Remove the scribble\n\t\t\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tif (scribble.shrink) {\n\t\t\t\t\t\t\t\t\t// Drop the scribble's size as it shrinks\n\t\t\t\t\t\t\t\t\tscribble.size = Math.max(1, scribble.size * (1 - scribble.shrink))\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// Drop the scribble's first point (its tail)\n\t\t\t\t\t\t\t\tscribble.points.shift()\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\tcase 'paused': {\n\t\t\t\t\t\t// Nothing to do while paused.\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t})\n\n\t\t\t// The object here will get frozen into the record, so we need to\n\t\t\t// create a copies of the parts that what we'll be mutating later.\n\t\t\tthis.editor.updateInstanceState({\n\t\t\t\tscribbles: Array.from(this.scribbleItems.values())\n\t\t\t\t\t.map(({ scribble }) => ({\n\t\t\t\t\t\t...scribble,\n\t\t\t\t\t\tpoints: [...scribble.points],\n\t\t\t\t\t}))\n\t\t\t\t\t.slice(-5), // limit to three as a minor sanity check\n\t\t\t})\n\t\t})\n\t}\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { TLScribble, VecModel } from '@tldraw/tlschema'\nimport { uniqueId } from '@tldraw/utils'\nimport { Vec } from '../../../primitives/Vec'\nimport { Editor } from '../../Editor'\n\n/** @public */\nexport interface ScribbleItem {\n\tid: string\n\tscribble: TLScribble\n\ttimeoutMs: number\n\tdelayRemaining: number\n\tprev: null | VecModel\n\tnext: null | VecModel\n}\n\n/** @public */\nexport interface ScribbleSessionOptions {\n\t/** Session id. Auto-generated if not provided. */\n\tid?: string\n\t/**\n\t * Whether scribbles self-consume (shrink from start) while drawing.\n\t * - true: scribbles eat their own tail as you draw (default, used for eraser/select)\n\t * - false: scribbles persist until session stops (used for laser)\n\t */\n\tselfConsume?: boolean\n\t/**\n\t * How long to wait after last activity before auto-stopping the session.\n\t * Only applies when selfConsume is false.\n\t */\n\tidleTimeoutMs?: number\n\t/**\n\t * How scribbles fade when stopping.\n\t * - 'individual': each scribble fades on its own (default)\n\t * - 'grouped': all scribbles fade together as one sequence\n\t */\n\tfadeMode?: 'individual' | 'grouped'\n\t/**\n\t * Easing for grouped fade.\n\t */\n\tfadeEasing?: 'linear' | 'ease-in'\n\t/**\n\t * Duration of the fade in milliseconds.\n\t */\n\tfadeDurationMs?: number\n}\n\n// Internal session state (not exported)\ninterface Session {\n\tid: string\n\titems: ScribbleItem[]\n\tstate: 'active' | 'stopping' | 'complete'\n\toptions: Required<Omit<ScribbleSessionOptions, 'id'>>\n\tidleTimeoutHandle?: number\n\tfadeElapsed: number\n\ttotalPointsAtFadeStart: number\n}\n\n/** @public */\nexport class ScribbleManager {\n\tprivate sessions = new Map<string, Session>()\n\n\tconstructor(private editor: Editor) {}\n\n\t// ==================== SESSION API ====================\n\n\t/**\n\t * Start a new session for grouping scribbles.\n\t * Returns a session ID that can be used with other session methods.\n\t *\n\t * @param options - Session configuration\n\t * @returns Session ID\n\t * @public\n\t */\n\tstartSession(options: ScribbleSessionOptions = {}): string {\n\t\tconst id = options.id ?? uniqueId()\n\t\tconst session: Session = {\n\t\t\tid,\n\t\t\titems: [],\n\t\t\tstate: 'active',\n\t\t\toptions: {\n\t\t\t\tselfConsume: options.selfConsume ?? true,\n\t\t\t\tidleTimeoutMs: options.idleTimeoutMs ?? 0,\n\t\t\t\tfadeMode: options.fadeMode ?? 'individual',\n\t\t\t\tfadeEasing: options.fadeEasing ?? (options.fadeMode === 'grouped' ? 'ease-in' : 'linear'),\n\t\t\t\tfadeDurationMs: options.fadeDurationMs ?? this.editor.options.laserFadeoutMs,\n\t\t\t},\n\t\t\tfadeElapsed: 0,\n\t\t\ttotalPointsAtFadeStart: 0,\n\t\t}\n\n\t\tthis.sessions.set(id, session)\n\n\t\t// Set up idle timeout if configured\n\t\tif (session.options.idleTimeoutMs > 0) {\n\t\t\tthis.resetIdleTimeout(session)\n\t\t}\n\n\t\treturn id\n\t}\n\n\t/**\n\t * Add a scribble to a session.\n\t *\n\t * @param sessionId - The session ID\n\t * @param scribble - Partial scribble properties\n\t * @param scribbleId - Optional scribble ID\n\t * @public\n\t */\n\taddScribbleToSession(\n\t\tsessionId: string,\n\t\tscribble: Partial<TLScribble>,\n\t\tscribbleId = uniqueId()\n\t): ScribbleItem {\n\t\tconst session = this.sessions.get(sessionId)\n\t\tif (!session) throw Error(`Session ${sessionId} not found`)\n\n\t\tconst item: ScribbleItem = {\n\t\t\tid: scribbleId,\n\t\t\tscribble: {\n\t\t\t\tid: scribbleId,\n\t\t\t\tsize: 20,\n\t\t\t\tcolor: 'accent',\n\t\t\t\topacity: 0.8,\n\t\t\t\tdelay: 0,\n\t\t\t\tpoints: [],\n\t\t\t\tshrink: 0.1,\n\t\t\t\ttaper: true,\n\t\t\t\t...scribble,\n\t\t\t\tstate: 'starting',\n\t\t\t},\n\t\t\ttimeoutMs: 0,\n\t\t\tdelayRemaining: scribble.delay ?? 0,\n\t\t\tprev: null,\n\t\t\tnext: null,\n\t\t}\n\n\t\tsession.items.push(item)\n\n\t\t// Reset idle timeout on activity\n\t\tif (session.options.idleTimeoutMs > 0) {\n\t\t\tthis.resetIdleTimeout(session)\n\t\t}\n\n\t\treturn item\n\t}\n\n\t/**\n\t * Add a point to a scribble in a session.\n\t *\n\t * @param sessionId - The session ID\n\t * @param scribbleId - The scribble ID\n\t * @param x - X coordinate\n\t * @param y - Y coordinate\n\t * @param z - Z coordinate (pressure)\n\t * @public\n\t */\n\taddPointToSession(\n\t\tsessionId: string,\n\t\tscribbleId: string,\n\t\tx: number,\n\t\ty: number,\n\t\tz = 0.5\n\t): ScribbleItem {\n\t\tconst session = this.sessions.get(sessionId)\n\t\tif (!session) throw Error(`Session ${sessionId} not found`)\n\n\t\tconst item = session.items.find((i) => i.id === scribbleId)\n\t\tif (!item) throw Error(`Scribble ${scribbleId} not found in session ${sessionId}`)\n\n\t\tconst point = { x, y, z }\n\t\tif (!item.prev || Vec.Dist(item.prev, point) >= 1) {\n\t\t\titem.next = point\n\t\t}\n\n\t\t// Reset idle timeout on activity\n\t\tif (session.options.idleTimeoutMs > 0) {\n\t\t\tthis.resetIdleTimeout(session)\n\t\t}\n\n\t\treturn item\n\t}\n\n\t/**\n\t * Extend a session, resetting its idle timeout.\n\t *\n\t * @param sessionId - The session ID\n\t * @public\n\t */\n\textendSession(sessionId: string): void {\n\t\tconst session = this.sessions.get(sessionId)\n\t\tif (!session) return\n\n\t\tif (session.options.idleTimeoutMs > 0) {\n\t\t\tthis.resetIdleTimeout(session)\n\t\t}\n\t}\n\n\t/**\n\t * Stop a session, triggering fade-out.\n\t *\n\t * @param sessionId - The session ID\n\t * @public\n\t */\n\tstopSession(sessionId: string): void {\n\t\tconst session = this.sessions.get(sessionId)\n\t\tif (!session || session.state !== 'active') return\n\n\t\tthis.clearIdleTimeout(session)\n\t\tsession.state = 'stopping'\n\n\t\tif (session.options.fadeMode === 'grouped') {\n\t\t\tsession.totalPointsAtFadeStart = session.items.reduce(\n\t\t\t\t(sum, item) => sum + item.scribble.points.length,\n\t\t\t\t0\n\t\t\t)\n\t\t\tsession.fadeElapsed = 0\n\t\t\tfor (const item of session.items) {\n\t\t\t\titem.scribble.state = 'stopping'\n\t\t\t}\n\t\t} else {\n\t\t\tfor (const item of session.items) {\n\t\t\t\titem.delayRemaining = Math.min(item.delayRemaining, 200)\n\t\t\t\titem.scribble.state = 'stopping'\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Clear all scribbles in a session immediately.\n\t *\n\t * @param sessionId - The session ID\n\t * @public\n\t */\n\tclearSession(sessionId: string): void {\n\t\tconst session = this.sessions.get(sessionId)\n\t\tif (!session) return\n\n\t\tthis.clearIdleTimeout(session)\n\t\tfor (const item of session.items) {\n\t\t\titem.scribble.points.length = 0\n\t\t}\n\t\tsession.state = 'complete'\n\t}\n\n\t/**\n\t * Check if a session is active.\n\t *\n\t * @param sessionId - The session ID\n\t * @public\n\t */\n\tisSessionActive(sessionId: string): boolean {\n\t\tconst session = this.sessions.get(sessionId)\n\t\treturn session?.state === 'active'\n\t}\n\n\t// ==================== SIMPLE API (for eraser, select, etc.) ====================\n\n\t/**\n\t * Add a scribble using the default self-consuming behavior.\n\t * Creates an implicit session for the scribble.\n\t *\n\t * @param scribble - Partial scribble properties\n\t * @param id - Optional scribble id\n\t * @returns The created scribble item\n\t * @public\n\t */\n\taddScribble(scribble: Partial<TLScribble>, id = uniqueId()): ScribbleItem {\n\t\tconst sessionId = this.startSession()\n\t\treturn this.addScribbleToSession(sessionId, scribble, id)\n\t}\n\n\t/**\n\t * Add a point to a scribble. Searches all sessions.\n\t *\n\t * @param id - The scribble id\n\t * @param x - X coordinate\n\t * @param y - Y coordinate\n\t * @param z - Z coordinate (pressure)\n\t * @public\n\t */\n\taddPoint(id: string, x: number, y: number, z = 0.5): ScribbleItem {\n\t\tfor (const session of this.sessions.values()) {\n\t\t\tconst item = session.items.find((i) => i.id === id)\n\t\t\tif (item) {\n\t\t\t\tconst point = { x, y, z }\n\t\t\t\tif (!item.prev || Vec.Dist(item.prev, point) >= 1) {\n\t\t\t\t\titem.next = point\n\t\t\t\t}\n\t\t\t\tif (session.options.idleTimeoutMs > 0) {\n\t\t\t\t\tthis.resetIdleTimeout(session)\n\t\t\t\t}\n\t\t\t\treturn item\n\t\t\t}\n\t\t}\n\t\tthrow Error(`Scribble with id ${id} not found`)\n\t}\n\n\t/**\n\t * Mark a scribble as complete (done being drawn but not yet fading).\n\t * Searches all sessions.\n\t *\n\t * @param id - The scribble id\n\t * @public\n\t */\n\tcomplete(id: string): ScribbleItem {\n\t\tfor (const session of this.sessions.values()) {\n\t\t\tconst item = session.items.find((i) => i.id === id)\n\t\t\tif (item) {\n\t\t\t\tif (item.scribble.state === 'starting' || item.scribble.state === 'active') {\n\t\t\t\t\titem.scribble.state = 'complete'\n\t\t\t\t}\n\t\t\t\treturn item\n\t\t\t}\n\t\t}\n\t\tthrow Error(`Scribble with id ${id} not found`)\n\t}\n\n\t/**\n\t * Stop a scribble. Searches all sessions.\n\t *\n\t * @param id - The scribble id\n\t * @public\n\t */\n\tstop(id: string): ScribbleItem {\n\t\tfor (const session of this.sessions.values()) {\n\t\t\tconst item = session.items.find((i) => i.id === id)\n\t\t\tif (item) {\n\t\t\t\titem.delayRemaining = Math.min(item.delayRemaining, 200)\n\t\t\t\titem.scribble.state = 'stopping'\n\t\t\t\treturn item\n\t\t\t}\n\t\t}\n\t\tthrow Error(`Scribble with id ${id} not found`)\n\t}\n\n\t/**\n\t * Stop and remove all sessions.\n\t *\n\t * @public\n\t */\n\treset(): void {\n\t\tfor (const session of this.sessions.values()) {\n\t\t\tthis.clearIdleTimeout(session)\n\t\t}\n\t\tthis.sessions.clear()\n\t\tthis.editor.updateInstanceState({ scribbles: [] })\n\t}\n\n\t/**\n\t * Update on each animation frame.\n\t *\n\t * @param elapsed - The number of milliseconds since the last tick.\n\t * @public\n\t */\n\ttick(elapsed: number): void {\n\t\tconst currentScribbles = this.editor.getInstanceState().scribbles\n\t\tif (this.sessions.size === 0 && currentScribbles.length === 0) return\n\n\t\tthis.editor.run(() => {\n\t\t\t// Tick all sessions\n\t\t\tfor (const session of this.sessions.values()) {\n\t\t\t\tthis.tickSession(session, elapsed)\n\t\t\t}\n\n\t\t\t// Remove completed sessions\n\t\t\tfor (const [id, session] of this.sessions) {\n\t\t\t\tif (session.state === 'complete') {\n\t\t\t\t\tthis.clearIdleTimeout(session)\n\t\t\t\t\tthis.sessions.delete(id)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Collect scribbles from all sessions\n\t\t\tconst scribbles: TLScribble[] = []\n\t\t\tfor (const session of this.sessions.values()) {\n\t\t\t\tfor (const item of session.items) {\n\t\t\t\t\tif (item.scribble.points.length > 0) {\n\t\t\t\t\t\tscribbles.push({\n\t\t\t\t\t\t\t...item.scribble,\n\t\t\t\t\t\t\tpoints: [...item.scribble.points],\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.editor.updateInstanceState({ scribbles })\n\t\t})\n\t}\n\n\t// ==================== PRIVATE HELPERS ====================\n\n\tprivate resetIdleTimeout(session: Session): void {\n\t\tthis.clearIdleTimeout(session)\n\t\tsession.idleTimeoutHandle = this.editor.timers.setTimeout(() => {\n\t\t\tthis.stopSession(session.id)\n\t\t}, session.options.idleTimeoutMs)\n\t}\n\n\tprivate clearIdleTimeout(session: Session): void {\n\t\tif (session.idleTimeoutHandle !== undefined) {\n\t\t\tclearTimeout(session.idleTimeoutHandle)\n\t\t\tsession.idleTimeoutHandle = undefined\n\t\t}\n\t}\n\n\tprivate tickSession(session: Session, elapsed: number): void {\n\t\tif (session.state === 'complete') return\n\n\t\tif (session.state === 'stopping' && session.options.fadeMode === 'grouped') {\n\t\t\tthis.tickGroupedFade(session, elapsed)\n\t\t} else {\n\t\t\tthis.tickSessionItems(session, elapsed)\n\t\t}\n\n\t\t// Check if session is complete\n\t\tconst hasContent = session.items.some((item) => item.scribble.points.length > 0)\n\t\tif (!hasContent && (session.state === 'stopping' || session.items.length === 0)) {\n\t\t\tsession.state = 'complete'\n\t\t}\n\t}\n\n\tprivate tickSessionItems(session: Session, elapsed: number): void {\n\t\tfor (const item of session.items) {\n\t\t\tconst shouldSelfConsume =\n\t\t\t\tsession.options.selfConsume ||\n\t\t\t\tsession.state === 'stopping' ||\n\t\t\t\titem.scribble.state === 'stopping'\n\n\t\t\tif (shouldSelfConsume) {\n\t\t\t\tthis.tickSelfConsumingItem(item, elapsed)\n\t\t\t} else {\n\t\t\t\tthis.tickPersistentItem(item)\n\t\t\t}\n\t\t}\n\n\t\t// Remove completed items in individual fade mode\n\t\tif (session.options.fadeMode === 'individual') {\n\t\t\tfor (let i = session.items.length - 1; i >= 0; i--) {\n\t\t\t\tif (session.items[i].scribble.points.length === 0) {\n\t\t\t\t\tsession.items.splice(i, 1)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate tickPersistentItem(item: ScribbleItem): void {\n\t\tconst { scribble } = item\n\n\t\tif (scribble.state === 'starting') {\n\t\t\tconst { next, prev } = item\n\t\t\tif (next && next !== prev) {\n\t\t\t\titem.prev = next\n\t\t\t\tscribble.points.push(next)\n\t\t\t}\n\t\t\tif (scribble.points.length > 8) {\n\t\t\t\tscribble.state = 'active'\n\t\t\t}\n\t\t\treturn\n\t\t}\n\n\t\tif (scribble.state === 'active') {\n\t\t\tconst { next, prev } = item\n\t\t\tif (next && next !== prev) {\n\t\t\t\titem.prev = next\n\t\t\t\tscribble.points.push(next)\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate tickSelfConsumingItem(item: ScribbleItem, elapsed: number): void {\n\t\tconst { scribble } = item\n\n\t\tif (scribble.state === 'starting') {\n\t\t\tconst { next, prev } = item\n\t\t\tif (next && next !== prev) {\n\t\t\t\titem.prev = next\n\t\t\t\tscribble.points.push(next)\n\t\t\t}\n\t\t\tif (scribble.points.length > 8) {\n\t\t\t\tscribble.state = 'active'\n\t\t\t}\n\t\t\treturn\n\t\t}\n\n\t\tif (item.delayRemaining > 0) {\n\t\t\titem.delayRemaining = Math.max(0, item.delayRemaining - elapsed)\n\t\t}\n\n\t\titem.timeoutMs += elapsed\n\t\tif (item.timeoutMs >= 16) {\n\t\t\titem.timeoutMs = 0\n\t\t}\n\n\t\tconst { delayRemaining, timeoutMs, prev, next } = item\n\n\t\tswitch (scribble.state) {\n\t\t\tcase 'active': {\n\t\t\t\tif (next && next !== prev) {\n\t\t\t\t\titem.prev = next\n\t\t\t\t\tscribble.points.push(next)\n\t\t\t\t\tif (delayRemaining === 0 && scribble.points.length > 8) {\n\t\t\t\t\t\tscribble.points.shift()\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif (timeoutMs === 0) {\n\t\t\t\t\t\tif (scribble.points.length > 1) {\n\t\t\t\t\t\t\tscribble.points.shift()\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\titem.delayRemaining = scribble.delay\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'stopping': {\n\t\t\t\tif (delayRemaining === 0 && timeoutMs === 0) {\n\t\t\t\t\tif (scribble.points.length <= 1) {\n\t\t\t\t\t\tscribble.points.length = 0\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tif (scribble.shrink) {\n\t\t\t\t\t\tscribble.size = Math.max(1, scribble.size * (1 - scribble.shrink))\n\t\t\t\t\t}\n\t\t\t\t\tscribble.points.shift()\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'paused': {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate tickGroupedFade(session: Session, elapsed: number): void {\n\t\tsession.fadeElapsed += elapsed\n\n\t\tlet remainingPoints = 0\n\t\tfor (const item of session.items) {\n\t\t\tremainingPoints += item.scribble.points.length\n\t\t}\n\n\t\tif (remainingPoints === 0) return\n\n\t\tif (session.fadeElapsed >= session.options.fadeDurationMs) {\n\t\t\tfor (const item of session.items) {\n\t\t\t\titem.scribble.points.length = 0\n\t\t\t}\n\t\t\treturn\n\t\t}\n\n\t\tconst progress = session.fadeElapsed / session.options.fadeDurationMs\n\t\tconst easedProgress = session.options.fadeEasing === 'ease-in' ? progress * progress : progress\n\n\t\tconst targetRemoved = Math.floor(easedProgress * session.totalPointsAtFadeStart)\n\t\tconst actuallyRemoved = session.totalPointsAtFadeStart - remainingPoints\n\t\tconst pointsToRemove = Math.max(1, targetRemoved - actuallyRemoved)\n\n\t\tlet removed = 0\n\t\tlet itemIndex = 0\n\t\twhile (removed < pointsToRemove && itemIndex < session.items.length) {\n\t\t\tconst item = session.items[itemIndex]\n\t\t\tif (item.scribble.points.length > 0) {\n\t\t\t\titem.scribble.points.shift()\n\t\t\t\tremoved++\n\t\t\t} else {\n\t\t\t\titemIndex++\n\t\t\t}\n\t\t}\n\t}\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["next", "prev"]
7
7
  }
@@ -94,17 +94,16 @@ class SpatialIndexManager {
94
94
  processedShapeIds.add(shape.id);
95
95
  }
96
96
  }
97
- for (const [from, to] of (0, import_utils.objectMapValues)(changes.updated)) {
97
+ for (const [, to] of (0, import_utils.objectMapValues)(changes.updated)) {
98
98
  if (!(0, import_tlschema.isShape)(to)) continue;
99
99
  processedShapeIds.add(to.id);
100
- const wasOnPage = this.editor.getAncestorPageId(from) === this.lastPageId;
101
100
  const isOnPage = this.editor.getAncestorPageId(to) === this.lastPageId;
102
101
  if (isOnPage) {
103
102
  const bounds = this.editor.getShapePageBounds(to.id);
104
103
  if (bounds) {
105
104
  this.rbush.upsert(to.id, bounds);
106
105
  }
107
- } else if (wasOnPage) {
106
+ } else {
108
107
  this.rbush.remove(to.id);
109
108
  }
110
109
  }