@tldraw/editor 4.4.0-next.f181afb0ab39 → 4.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-cjs/index.d.ts +102 -19
- package/dist-cjs/index.js +1 -6
- package/dist-cjs/index.js.map +3 -3
- package/dist-cjs/lib/TldrawEditor.js +20 -8
- package/dist-cjs/lib/TldrawEditor.js.map +2 -2
- package/dist-cjs/lib/components/Shape.js +12 -17
- package/dist-cjs/lib/components/Shape.js.map +2 -2
- package/dist-cjs/lib/components/default-components/CanvasShapeIndicators.js +26 -1
- package/dist-cjs/lib/components/default-components/CanvasShapeIndicators.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js +16 -1
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
- package/dist-cjs/lib/config/createTLStore.js.map +1 -1
- package/dist-cjs/lib/editor/Editor.js +35 -17
- package/dist-cjs/lib/editor/Editor.js.map +2 -2
- package/dist-cjs/lib/editor/derivations/notVisibleShapes.js +32 -13
- package/dist-cjs/lib/editor/derivations/notVisibleShapes.js.map +2 -2
- package/dist-cjs/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.js +2 -3
- package/dist-cjs/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/HistoryManager/HistoryManager.js +13 -38
- package/dist-cjs/lib/editor/managers/HistoryManager/HistoryManager.js.map +3 -3
- package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
- package/dist-cjs/lib/editor/tools/RootState.js +0 -13
- package/dist-cjs/lib/editor/tools/RootState.js.map +2 -2
- package/dist-cjs/lib/hooks/usePeerIds.js +8 -2
- package/dist-cjs/lib/hooks/usePeerIds.js.map +2 -2
- package/dist-cjs/lib/hooks/useShapeCulling.js +75 -0
- package/dist-cjs/lib/hooks/useShapeCulling.js.map +7 -0
- package/dist-cjs/lib/license/LicenseManager.js +6 -6
- package/dist-cjs/lib/license/LicenseManager.js.map +2 -2
- package/dist-cjs/lib/options.js +6 -1
- package/dist-cjs/lib/options.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 +102 -19
- package/dist-esm/index.mjs +1 -6
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/TldrawEditor.mjs +20 -8
- package/dist-esm/lib/TldrawEditor.mjs.map +2 -2
- package/dist-esm/lib/components/Shape.mjs +12 -17
- package/dist-esm/lib/components/Shape.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/CanvasShapeIndicators.mjs +27 -2
- package/dist-esm/lib/components/default-components/CanvasShapeIndicators.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +16 -1
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
- package/dist-esm/lib/config/createTLStore.mjs.map +1 -1
- package/dist-esm/lib/editor/Editor.mjs +35 -17
- package/dist-esm/lib/editor/Editor.mjs.map +2 -2
- package/dist-esm/lib/editor/derivations/notVisibleShapes.mjs +32 -13
- package/dist-esm/lib/editor/derivations/notVisibleShapes.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.mjs +2 -3
- package/dist-esm/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/HistoryManager/HistoryManager.mjs +14 -39
- package/dist-esm/lib/editor/managers/HistoryManager/HistoryManager.mjs.map +2 -2
- package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/editor/tools/RootState.mjs +0 -13
- package/dist-esm/lib/editor/tools/RootState.mjs.map +2 -2
- package/dist-esm/lib/hooks/usePeerIds.mjs +8 -2
- package/dist-esm/lib/hooks/usePeerIds.mjs.map +2 -2
- package/dist-esm/lib/hooks/useShapeCulling.mjs +55 -0
- package/dist-esm/lib/hooks/useShapeCulling.mjs.map +7 -0
- package/dist-esm/lib/license/LicenseManager.mjs +6 -6
- package/dist-esm/lib/license/LicenseManager.mjs.map +2 -2
- package/dist-esm/lib/options.mjs +6 -1
- package/dist-esm/lib/options.mjs.map +2 -2
- package/dist-esm/version.mjs +3 -3
- package/dist-esm/version.mjs.map +1 -1
- package/editor.css +22 -11
- package/package.json +10 -13
- package/src/index.ts +0 -5
- package/src/lib/TldrawEditor.tsx +35 -13
- package/src/lib/components/Shape.tsx +15 -16
- package/src/lib/components/default-components/CanvasShapeIndicators.tsx +46 -2
- package/src/lib/components/default-components/DefaultCanvas.tsx +24 -2
- package/src/lib/config/createTLStore.ts +1 -1
- package/src/lib/editor/Editor.ts +62 -19
- package/src/lib/editor/derivations/notVisibleShapes.ts +39 -17
- package/src/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.test.ts +0 -35
- package/src/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.ts +4 -8
- package/src/lib/editor/managers/HistoryManager/HistoryManager.ts +19 -47
- package/src/lib/editor/shapes/ShapeUtil.ts +19 -5
- package/src/lib/editor/tools/RootState.ts +0 -16
- package/src/lib/hooks/usePeerIds.ts +9 -2
- package/src/lib/hooks/useShapeCulling.tsx +98 -0
- package/src/lib/license/LicenseManager.ts +6 -6
- package/src/lib/options.ts +41 -2
- package/src/version.ts +3 -3
|
@@ -35,17 +35,31 @@ export interface TLShapeUtilConstructor<T extends TLShape, U extends ShapeUtil<T
|
|
|
35
35
|
|
|
36
36
|
/**
|
|
37
37
|
* Options passed to {@link ShapeUtil.canBind}. A binding that could be made. At least one of
|
|
38
|
-
* `
|
|
38
|
+
* `fromShape` or `toShape` will belong to this shape util.
|
|
39
|
+
*
|
|
40
|
+
* The shapes may be full {@link @tldraw/tlschema#TLShape} objects when available, or just
|
|
41
|
+
* `{ type }` stubs when the shape hasn't been created yet (e.g. during arrow creation). Use
|
|
42
|
+
* `'id' in shape` to check whether the full shape is available.
|
|
39
43
|
*
|
|
40
44
|
* @public
|
|
41
45
|
*/
|
|
42
46
|
export interface TLShapeUtilCanBindOpts<Shape extends TLShape = TLShape> {
|
|
43
|
-
/** The
|
|
44
|
-
|
|
45
|
-
/** The
|
|
46
|
-
|
|
47
|
+
/** The shape referenced by the `fromId` of the binding, or a `{ type }` stub if unavailable. */
|
|
48
|
+
fromShape: TLShape | { type: TLShape['type'] }
|
|
49
|
+
/** The shape referenced by the `toId` of the binding, or a `{ type }` stub if unavailable. */
|
|
50
|
+
toShape: TLShape | { type: TLShape['type'] }
|
|
47
51
|
/** The type of binding. */
|
|
48
52
|
bindingType: string
|
|
53
|
+
/**
|
|
54
|
+
* The type of shape referenced by the `fromId` of the binding.
|
|
55
|
+
* @deprecated Use `fromShape.type` instead.
|
|
56
|
+
*/
|
|
57
|
+
fromShapeType: TLShape['type']
|
|
58
|
+
/**
|
|
59
|
+
* The type of shape referenced by the `toId` of the binding.
|
|
60
|
+
* @deprecated Use `toShape.type` instead.
|
|
61
|
+
*/
|
|
62
|
+
toShapeType: TLShape['type']
|
|
49
63
|
}
|
|
50
64
|
|
|
51
65
|
/**
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { TLKeyboardEventInfo } from '../types/event-types'
|
|
2
1
|
import { StateNode } from './StateNode'
|
|
3
2
|
|
|
4
3
|
export class RootState extends StateNode {
|
|
@@ -7,19 +6,4 @@ export class RootState extends StateNode {
|
|
|
7
6
|
static override children() {
|
|
8
7
|
return []
|
|
9
8
|
}
|
|
10
|
-
|
|
11
|
-
override onKeyDown(info: TLKeyboardEventInfo) {
|
|
12
|
-
// todo: move this logic up to the tldraw library, as the "zoom" tool only exists there
|
|
13
|
-
switch (info.code) {
|
|
14
|
-
case 'KeyZ': {
|
|
15
|
-
if (!(info.shiftKey || info.ctrlKey)) {
|
|
16
|
-
const currentTool = this.getCurrent()
|
|
17
|
-
if (currentTool && currentTool.getCurrent()?.id === 'idle' && this.children!['zoom']) {
|
|
18
|
-
this.editor.setCurrentTool('zoom', { ...info, onInteractionEnd: currentTool.id })
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
break
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
9
|
}
|
|
@@ -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:
|
|
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:
|
|
452
|
+
`color: white; background: ${bgColor}; padding: 2px; border-radius: 3px;`
|
|
453
453
|
)
|
|
454
454
|
}
|
|
455
455
|
|
package/src/lib/options.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import { ComponentType, Fragment } from 'react'
|
|
2
|
+
import { DEFAULT_CAMERA_OPTIONS } from './constants'
|
|
3
|
+
import { TLCameraOptions } from './editor/types/misc-types'
|
|
4
|
+
import { TLDeepLinkOptions } from './utils/deepLinks'
|
|
5
|
+
import { TLTextOptions } from './utils/richText'
|
|
2
6
|
|
|
3
7
|
/**
|
|
4
8
|
* Options for configuring tldraw. For defaults, see {@link defaultTldrawOptions}.
|
|
@@ -95,13 +99,13 @@ export interface TldrawOptions {
|
|
|
95
99
|
readonly branding?: string
|
|
96
100
|
/**
|
|
97
101
|
* Whether to use debounced zoom level for certain rendering optimizations. When true,
|
|
98
|
-
* `editor.
|
|
102
|
+
* `editor.getEfficientZoomLevel()` returns a cached zoom value while the camera is moving,
|
|
99
103
|
* reducing re-renders. When false, it always returns the current zoom level.
|
|
100
104
|
*/
|
|
101
105
|
readonly debouncedZoom: boolean
|
|
102
106
|
/**
|
|
103
107
|
* The number of shapes that must be on the page for the debounced zoom level to be used.
|
|
104
|
-
* Defaults to
|
|
108
|
+
* Defaults to 500 shapes.
|
|
105
109
|
*/
|
|
106
110
|
readonly debouncedZoomThreshold: number
|
|
107
111
|
/**
|
|
@@ -120,6 +124,37 @@ export interface TldrawOptions {
|
|
|
120
124
|
* The distance (in screen pixels) at which shapes snap to guides and other shapes.
|
|
121
125
|
*/
|
|
122
126
|
readonly snapThreshold: number
|
|
127
|
+
/**
|
|
128
|
+
* Options for the editor's camera. These are the initial camera options.
|
|
129
|
+
* Use {@link Editor.setCameraOptions} to update camera options at runtime.
|
|
130
|
+
*/
|
|
131
|
+
readonly camera: Partial<TLCameraOptions>
|
|
132
|
+
/**
|
|
133
|
+
* Options for the editor's text rendering. These include TipTap configuration and
|
|
134
|
+
* font handling. These are the initial text options and cannot be changed at runtime.
|
|
135
|
+
*/
|
|
136
|
+
readonly text: TLTextOptions
|
|
137
|
+
/**
|
|
138
|
+
* Options for syncing the editor's camera state with the URL. Set to `true` to enable
|
|
139
|
+
* with default options, or pass an options object to customize behavior.
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* ```tsx
|
|
143
|
+
* // Enable with defaults
|
|
144
|
+
* <Tldraw options={{ deepLinks: true }} />
|
|
145
|
+
*
|
|
146
|
+
* // Enable with custom options
|
|
147
|
+
* <Tldraw options={{ deepLinks: { param: 'd', debounceMs: 500 } }} />
|
|
148
|
+
* ```
|
|
149
|
+
*/
|
|
150
|
+
readonly deepLinks: true | TLDeepLinkOptions | undefined
|
|
151
|
+
/**
|
|
152
|
+
* Whether the quick-zoom brush preserves its screen-pixel size when the user
|
|
153
|
+
* zooms the overview. When true, zooming in shrinks the target viewport (higher
|
|
154
|
+
* return zoom); zooming out expands it. When false, the brush keeps the original
|
|
155
|
+
* viewport's page dimensions regardless of overview zoom changes.
|
|
156
|
+
*/
|
|
157
|
+
readonly quickZoomPreservesScreenBounds: boolean
|
|
123
158
|
}
|
|
124
159
|
|
|
125
160
|
/** @public */
|
|
@@ -178,4 +213,8 @@ export const defaultTldrawOptions = {
|
|
|
178
213
|
spacebarPanning: true,
|
|
179
214
|
zoomToFitPadding: 128,
|
|
180
215
|
snapThreshold: 8,
|
|
216
|
+
camera: DEFAULT_CAMERA_OPTIONS,
|
|
217
|
+
text: {},
|
|
218
|
+
deepLinks: undefined,
|
|
219
|
+
quickZoomPreservesScreenBounds: true,
|
|
181
220
|
} 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
|
|
4
|
+
export const version = '4.4.0'
|
|
5
5
|
export const publishDates = {
|
|
6
6
|
major: '2025-09-18T14:39:22.803Z',
|
|
7
|
-
minor: '2026-
|
|
8
|
-
patch: '2026-
|
|
7
|
+
minor: '2026-02-18T12:03:50.380Z',
|
|
8
|
+
patch: '2026-02-18T12:03:50.380Z',
|
|
9
9
|
}
|