@tldraw/editor 4.4.0-canary.afdcafe834b3 → 4.4.0-canary.b5c642789999

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 (65) hide show
  1. package/dist-cjs/index.d.ts +52 -9
  2. package/dist-cjs/index.js +1 -1
  3. package/dist-cjs/lib/components/Shape.js +12 -17
  4. package/dist-cjs/lib/components/Shape.js.map +2 -2
  5. package/dist-cjs/lib/components/default-components/CanvasShapeIndicators.js +26 -1
  6. package/dist-cjs/lib/components/default-components/CanvasShapeIndicators.js.map +2 -2
  7. package/dist-cjs/lib/components/default-components/DefaultCanvas.js +16 -1
  8. package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
  9. package/dist-cjs/lib/editor/Editor.js +19 -11
  10. package/dist-cjs/lib/editor/Editor.js.map +2 -2
  11. package/dist-cjs/lib/editor/derivations/notVisibleShapes.js +32 -13
  12. package/dist-cjs/lib/editor/derivations/notVisibleShapes.js.map +2 -2
  13. package/dist-cjs/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.js +2 -3
  14. package/dist-cjs/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.js.map +2 -2
  15. package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
  16. package/dist-cjs/lib/hooks/usePeerIds.js +8 -2
  17. package/dist-cjs/lib/hooks/usePeerIds.js.map +2 -2
  18. package/dist-cjs/lib/hooks/useShapeCulling.js +75 -0
  19. package/dist-cjs/lib/hooks/useShapeCulling.js.map +7 -0
  20. package/dist-cjs/lib/license/LicenseManager.js +6 -6
  21. package/dist-cjs/lib/license/LicenseManager.js.map +2 -2
  22. package/dist-cjs/lib/options.js +2 -1
  23. package/dist-cjs/lib/options.js.map +2 -2
  24. package/dist-cjs/version.js +3 -3
  25. package/dist-cjs/version.js.map +1 -1
  26. package/dist-esm/index.d.mts +52 -9
  27. package/dist-esm/index.mjs +1 -1
  28. package/dist-esm/lib/components/Shape.mjs +12 -17
  29. package/dist-esm/lib/components/Shape.mjs.map +2 -2
  30. package/dist-esm/lib/components/default-components/CanvasShapeIndicators.mjs +27 -2
  31. package/dist-esm/lib/components/default-components/CanvasShapeIndicators.mjs.map +2 -2
  32. package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +16 -1
  33. package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
  34. package/dist-esm/lib/editor/Editor.mjs +19 -11
  35. package/dist-esm/lib/editor/Editor.mjs.map +2 -2
  36. package/dist-esm/lib/editor/derivations/notVisibleShapes.mjs +32 -13
  37. package/dist-esm/lib/editor/derivations/notVisibleShapes.mjs.map +2 -2
  38. package/dist-esm/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.mjs +2 -3
  39. package/dist-esm/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.mjs.map +2 -2
  40. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
  41. package/dist-esm/lib/hooks/usePeerIds.mjs +8 -2
  42. package/dist-esm/lib/hooks/usePeerIds.mjs.map +2 -2
  43. package/dist-esm/lib/hooks/useShapeCulling.mjs +55 -0
  44. package/dist-esm/lib/hooks/useShapeCulling.mjs.map +7 -0
  45. package/dist-esm/lib/license/LicenseManager.mjs +6 -6
  46. package/dist-esm/lib/license/LicenseManager.mjs.map +2 -2
  47. package/dist-esm/lib/options.mjs +2 -1
  48. package/dist-esm/lib/options.mjs.map +2 -2
  49. package/dist-esm/version.mjs +3 -3
  50. package/dist-esm/version.mjs.map +1 -1
  51. package/editor.css +22 -2
  52. package/package.json +8 -9
  53. package/src/lib/components/Shape.tsx +15 -16
  54. package/src/lib/components/default-components/CanvasShapeIndicators.tsx +46 -2
  55. package/src/lib/components/default-components/DefaultCanvas.tsx +24 -2
  56. package/src/lib/editor/Editor.ts +33 -11
  57. package/src/lib/editor/derivations/notVisibleShapes.ts +39 -17
  58. package/src/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.test.ts +0 -35
  59. package/src/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.ts +4 -8
  60. package/src/lib/editor/shapes/ShapeUtil.ts +19 -5
  61. package/src/lib/hooks/usePeerIds.ts +9 -2
  62. package/src/lib/hooks/useShapeCulling.tsx +98 -0
  63. package/src/lib/license/LicenseManager.ts +6 -6
  64. package/src/lib/options.ts +10 -2
  65. package/src/version.ts +3 -3
@@ -1,5 +1,4 @@
1
1
  import { useAtom, useComputed, useValue } from '@tldraw/state-react'
2
- import { isEqual } from '@tldraw/utils'
3
2
  import { useEffect } from 'react'
4
3
  import {
5
4
  getCollaboratorStateFromElapsedTime,
@@ -8,6 +7,14 @@ import {
8
7
  import { uniq } from '../utils/uniq'
9
8
  import { useEditor } from './useEditor'
10
9
 
10
+ function setsEqual<T>(a: Set<T>, b: Set<T>): boolean {
11
+ if (a.size !== b.size) return false
12
+ for (const item of a) {
13
+ if (!b.has(item)) return false
14
+ }
15
+ return true
16
+ }
17
+
11
18
  // TODO: maybe move this to a computed property on the App class?
12
19
  /**
13
20
  * @returns The list of peer UserIDs
@@ -60,7 +67,7 @@ export function useActivePeerIds$() {
60
67
  .map((p) => p.userId)
61
68
  )
62
69
  },
63
- { isEqual },
70
+ { isEqual: setsEqual },
64
71
  [editor]
65
72
  )
66
73
  }
@@ -0,0 +1,98 @@
1
+ import { TLShapeId } from '@tldraw/tlschema'
2
+ import { createContext, useCallback, useContext, useMemo, useRef } from 'react'
3
+ import { setStyleProperty } from '../utils/dom'
4
+
5
+ interface ShapeContainerEntry {
6
+ container: HTMLDivElement
7
+ bgContainer: HTMLDivElement | null
8
+ isCulled: boolean
9
+ }
10
+
11
+ interface ShapeCullingContextValue {
12
+ register(
13
+ id: TLShapeId,
14
+ container: HTMLDivElement,
15
+ bgContainer: HTMLDivElement | null,
16
+ isCulled: boolean
17
+ ): void
18
+ unregister(id: TLShapeId): void
19
+ updateCulling(culledShapes: Set<TLShapeId>): void
20
+ }
21
+
22
+ const ShapeCullingContext = createContext<ShapeCullingContextValue | null>(null)
23
+
24
+ /** @internal */
25
+ export interface ShapeCullingProviderProps {
26
+ children: React.ReactNode
27
+ }
28
+
29
+ /**
30
+ * Provides centralized culling management for shape containers.
31
+ * This allows a single reactor to update all shape display states
32
+ * instead of each shape having its own subscription.
33
+ *
34
+ * @internal
35
+ */
36
+ export function ShapeCullingProvider({ children }: ShapeCullingProviderProps) {
37
+ const containersRef = useRef(new Map<TLShapeId, ShapeContainerEntry>())
38
+
39
+ const register = useCallback(
40
+ (
41
+ id: TLShapeId,
42
+ container: HTMLDivElement,
43
+ bgContainer: HTMLDivElement | null,
44
+ isCulled: boolean
45
+ ) => {
46
+ const display = isCulled ? 'none' : 'block'
47
+ setStyleProperty(container, 'display', display)
48
+ setStyleProperty(bgContainer, 'display', display)
49
+
50
+ containersRef.current.set(id, {
51
+ container,
52
+ bgContainer,
53
+ isCulled,
54
+ })
55
+ },
56
+ []
57
+ )
58
+
59
+ const unregister = useCallback((id: TLShapeId) => {
60
+ containersRef.current.delete(id)
61
+ }, [])
62
+
63
+ const updateCulling = useCallback((culledShapes: Set<TLShapeId>) => {
64
+ for (const [id, entry] of containersRef.current) {
65
+ const shouldBeCulled = culledShapes.has(id)
66
+ if (shouldBeCulled !== entry.isCulled) {
67
+ const display = shouldBeCulled ? 'none' : 'block'
68
+ setStyleProperty(entry.container, 'display', display)
69
+ setStyleProperty(entry.bgContainer, 'display', display)
70
+ entry.isCulled = shouldBeCulled
71
+ }
72
+ }
73
+ }, [])
74
+
75
+ const value = useMemo(
76
+ () => ({
77
+ register,
78
+ unregister,
79
+ updateCulling,
80
+ }),
81
+ [register, unregister, updateCulling]
82
+ )
83
+
84
+ return <ShapeCullingContext.Provider value={value}>{children}</ShapeCullingContext.Provider>
85
+ }
86
+
87
+ /**
88
+ * Hook to access the shape culling context for container registration.
89
+ *
90
+ * @internal
91
+ */
92
+ export function useShapeCulling(): ShapeCullingContextValue {
93
+ const context = useContext(ShapeCullingContext)
94
+ if (!context) {
95
+ throw new Error('useShapeCulling must be used within ShapeCullingProvider')
96
+ }
97
+ return context
98
+ }
@@ -431,25 +431,25 @@ export class LicenseManager {
431
431
  private outputMessages(messages: string[], type: 'warning' | 'error' = 'error') {
432
432
  if (this.isTest) return
433
433
  if (this.verbose) {
434
- this.outputDelimiter()
434
+ this.outputDelimiter(type)
435
435
  for (const message of messages) {
436
- const color = type === 'warning' ? 'orange' : 'crimson'
437
436
  const bgColor = type === 'warning' ? 'orange' : 'crimson'
438
437
  // eslint-disable-next-line no-console
439
438
  console.log(
440
439
  `%c${message}`,
441
- `color: ${color}; background: ${bgColor}; padding: 2px; border-radius: 3px;`
440
+ `color: white; background: ${bgColor}; padding: 2px; border-radius: 3px;`
442
441
  )
443
442
  }
444
- this.outputDelimiter()
443
+ this.outputDelimiter(type)
445
444
  }
446
445
  }
447
446
 
448
- private outputDelimiter() {
447
+ private outputDelimiter(type: 'warning' | 'error' = 'error') {
448
+ const bgColor = type === 'warning' ? 'orange' : 'crimson'
449
449
  // eslint-disable-next-line no-console
450
450
  console.log(
451
451
  '%c-------------------------------------------------------------------',
452
- `color: white; background: crimson; padding: 2px; border-radius: 3px;`
452
+ `color: white; background: ${bgColor}; padding: 2px; border-radius: 3px;`
453
453
  )
454
454
  }
455
455
 
@@ -95,13 +95,13 @@ export interface TldrawOptions {
95
95
  readonly branding?: string
96
96
  /**
97
97
  * Whether to use debounced zoom level for certain rendering optimizations. When true,
98
- * `editor.getDebouncedZoomLevel()` returns a cached zoom value while the camera is moving,
98
+ * `editor.getEfficientZoomLevel()` returns a cached zoom value while the camera is moving,
99
99
  * reducing re-renders. When false, it always returns the current zoom level.
100
100
  */
101
101
  readonly debouncedZoom: boolean
102
102
  /**
103
103
  * The number of shapes that must be on the page for the debounced zoom level to be used.
104
- * Defaults to 300 shapes.
104
+ * Defaults to 500 shapes.
105
105
  */
106
106
  readonly debouncedZoomThreshold: number
107
107
  /**
@@ -120,6 +120,13 @@ export interface TldrawOptions {
120
120
  * The distance (in screen pixels) at which shapes snap to guides and other shapes.
121
121
  */
122
122
  readonly snapThreshold: number
123
+ /**
124
+ * Whether the quick-zoom brush preserves its screen-pixel size when the user
125
+ * zooms the overview. When true, zooming in shrinks the target viewport (higher
126
+ * return zoom); zooming out expands it. When false, the brush keeps the original
127
+ * viewport's page dimensions regardless of overview zoom changes.
128
+ */
129
+ readonly quickZoomPreservesScreenBounds: boolean
123
130
  }
124
131
 
125
132
  /** @public */
@@ -178,4 +185,5 @@ export const defaultTldrawOptions = {
178
185
  spacebarPanning: true,
179
186
  zoomToFitPadding: 128,
180
187
  snapThreshold: 8,
188
+ quickZoomPreservesScreenBounds: true,
181
189
  } as const satisfies TldrawOptions
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 = '4.4.0-canary.afdcafe834b3'
4
+ export const version = '4.4.0-canary.b5c642789999'
5
5
  export const publishDates = {
6
6
  major: '2025-09-18T14:39:22.803Z',
7
- minor: '2026-02-04T08:49:09.694Z',
8
- patch: '2026-02-04T08:49:09.694Z',
7
+ minor: '2026-02-11T11:56:14.353Z',
8
+ patch: '2026-02-11T11:56:14.353Z',
9
9
  }