@tldraw/editor 3.12.0-canary.3acee343372d → 3.12.0-canary.3e2ed74b5e86
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 +123 -17
- package/dist-cjs/index.js +3 -1
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/TldrawEditor.js +4 -0
- package/dist-cjs/lib/TldrawEditor.js.map +2 -2
- package/dist-cjs/lib/components/GeometryDebuggingView.js +2 -2
- package/dist-cjs/lib/components/GeometryDebuggingView.js.map +2 -2
- package/dist-cjs/lib/components/Shape.js +10 -14
- package/dist-cjs/lib/components/Shape.js.map +2 -2
- package/dist-cjs/lib/editor/Editor.js +79 -30
- package/dist-cjs/lib/editor/Editor.js.map +2 -2
- package/dist-cjs/lib/editor/derivations/notVisibleShapes.js +1 -1
- package/dist-cjs/lib/editor/derivations/notVisibleShapes.js.map +2 -2
- package/dist-cjs/lib/editor/managers/FontManager.js +1 -1
- package/dist-cjs/lib/editor/managers/FontManager.js.map +2 -2
- package/dist-cjs/lib/editor/shapes/group/GroupShapeUtil.js +1 -13
- package/dist-cjs/lib/editor/shapes/group/GroupShapeUtil.js.map +2 -2
- package/dist-cjs/lib/editor/tools/StateNode.js +4 -1
- package/dist-cjs/lib/editor/tools/StateNode.js.map +2 -2
- package/dist-cjs/lib/exports/StyleEmbedder.js +19 -5
- package/dist-cjs/lib/exports/StyleEmbedder.js.map +2 -2
- package/dist-cjs/lib/exports/cssRules.js +127 -0
- package/dist-cjs/lib/exports/cssRules.js.map +7 -0
- package/dist-cjs/lib/exports/parseCss.js +0 -69
- package/dist-cjs/lib/exports/parseCss.js.map +2 -2
- package/dist-cjs/lib/hooks/useCanvasEvents.js +12 -7
- package/dist-cjs/lib/hooks/useCanvasEvents.js.map +3 -3
- package/dist-cjs/lib/hooks/useGestureEvents.js +12 -6
- package/dist-cjs/lib/hooks/useGestureEvents.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Geometry2d.js +133 -16
- package/dist-cjs/lib/primitives/geometry/Geometry2d.js.map +3 -3
- package/dist-cjs/lib/primitives/geometry/Group2d.js +54 -11
- package/dist-cjs/lib/primitives/geometry/Group2d.js.map +2 -2
- package/dist-cjs/lib/primitives/intersect.js +20 -0
- package/dist-cjs/lib/primitives/intersect.js.map +2 -2
- package/dist-cjs/lib/utils/debug-flags.js +2 -1
- package/dist-cjs/lib/utils/debug-flags.js.map +2 -2
- package/dist-cjs/lib/utils/reorderShapes.js +2 -8
- package/dist-cjs/lib/utils/reorderShapes.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 +123 -17
- package/dist-esm/index.mjs +8 -2
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/TldrawEditor.mjs +4 -0
- package/dist-esm/lib/TldrawEditor.mjs.map +2 -2
- package/dist-esm/lib/components/GeometryDebuggingView.mjs +3 -3
- package/dist-esm/lib/components/GeometryDebuggingView.mjs.map +2 -2
- package/dist-esm/lib/components/Shape.mjs +11 -15
- package/dist-esm/lib/components/Shape.mjs.map +2 -2
- package/dist-esm/lib/editor/Editor.mjs +79 -30
- package/dist-esm/lib/editor/Editor.mjs.map +2 -2
- package/dist-esm/lib/editor/derivations/notVisibleShapes.mjs +1 -1
- package/dist-esm/lib/editor/derivations/notVisibleShapes.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/FontManager.mjs +1 -1
- package/dist-esm/lib/editor/managers/FontManager.mjs.map +2 -2
- package/dist-esm/lib/editor/shapes/group/GroupShapeUtil.mjs +1 -13
- package/dist-esm/lib/editor/shapes/group/GroupShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/editor/tools/StateNode.mjs +4 -1
- package/dist-esm/lib/editor/tools/StateNode.mjs.map +2 -2
- package/dist-esm/lib/exports/StyleEmbedder.mjs +21 -12
- package/dist-esm/lib/exports/StyleEmbedder.mjs.map +2 -2
- package/dist-esm/lib/exports/cssRules.mjs +107 -0
- package/dist-esm/lib/exports/cssRules.mjs.map +7 -0
- package/dist-esm/lib/exports/parseCss.mjs +0 -69
- package/dist-esm/lib/exports/parseCss.mjs.map +2 -2
- package/dist-esm/lib/hooks/useCanvasEvents.mjs +12 -7
- package/dist-esm/lib/hooks/useCanvasEvents.mjs.map +3 -3
- package/dist-esm/lib/hooks/useGestureEvents.mjs +12 -6
- package/dist-esm/lib/hooks/useGestureEvents.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Geometry2d.mjs +137 -14
- package/dist-esm/lib/primitives/geometry/Geometry2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Group2d.mjs +55 -12
- package/dist-esm/lib/primitives/geometry/Group2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/intersect.mjs +20 -0
- package/dist-esm/lib/primitives/intersect.mjs.map +2 -2
- package/dist-esm/lib/utils/debug-flags.mjs +2 -1
- package/dist-esm/lib/utils/debug-flags.mjs.map +2 -2
- package/dist-esm/lib/utils/reorderShapes.mjs +2 -8
- package/dist-esm/lib/utils/reorderShapes.mjs.map +2 -2
- package/dist-esm/version.mjs +3 -3
- package/dist-esm/version.mjs.map +1 -1
- package/editor.css +17 -11
- package/package.json +7 -7
- package/src/index.ts +6 -1
- package/src/lib/TldrawEditor.tsx +29 -3
- package/src/lib/components/GeometryDebuggingView.tsx +3 -3
- package/src/lib/components/Shape.tsx +15 -19
- package/src/lib/editor/Editor.ts +115 -38
- package/src/lib/editor/derivations/notVisibleShapes.ts +1 -1
- package/src/lib/editor/managers/FontManager.ts +1 -1
- package/src/lib/editor/shapes/group/GroupShapeUtil.tsx +3 -15
- package/src/lib/editor/tools/StateNode.ts +6 -1
- package/src/lib/exports/StyleEmbedder.ts +25 -15
- package/src/lib/exports/cssRules.ts +126 -0
- package/src/lib/exports/parseCss.ts +0 -79
- package/src/lib/hooks/useCanvasEvents.ts +14 -7
- package/src/lib/hooks/useGestureEvents.ts +12 -6
- package/src/lib/primitives/geometry/Geometry2d.ts +196 -16
- package/src/lib/primitives/geometry/Group2d.ts +76 -13
- package/src/lib/primitives/intersect.ts +41 -0
- package/src/lib/utils/debug-flags.ts +1 -0
- package/src/lib/utils/reorderShapes.ts +2 -9
- package/src/version.ts +3 -3
package/src/lib/TldrawEditor.tsx
CHANGED
|
@@ -50,7 +50,7 @@ import { TLStoreWithStatus } from './utils/sync/StoreWithStatus'
|
|
|
50
50
|
|
|
51
51
|
/**
|
|
52
52
|
* Props for the {@link tldraw#Tldraw} and {@link TldrawEditor} components, when passing in a
|
|
53
|
-
*
|
|
53
|
+
* `TLStore` directly. If you would like tldraw to create a store for you, use
|
|
54
54
|
* {@link TldrawEditorWithoutStoreProps}.
|
|
55
55
|
*
|
|
56
56
|
* @public
|
|
@@ -64,7 +64,7 @@ export interface TldrawEditorWithStoreProps {
|
|
|
64
64
|
|
|
65
65
|
/**
|
|
66
66
|
* Props for the {@link tldraw#Tldraw} and {@link TldrawEditor} components, when not passing in a
|
|
67
|
-
*
|
|
67
|
+
* `TLStore` directly. If you would like to pass in a store directly, use
|
|
68
68
|
* {@link TldrawEditorWithStoreProps}.
|
|
69
69
|
*
|
|
70
70
|
* @public
|
|
@@ -191,11 +191,33 @@ export interface TldrawEditorBaseProps {
|
|
|
191
191
|
/**
|
|
192
192
|
* Predicate for whether or not a shape should be hidden.
|
|
193
193
|
*
|
|
194
|
+
* @deprecated Use {@link TldrawEditorBaseProps#getShapeVisibility} instead.
|
|
195
|
+
*/
|
|
196
|
+
isShapeHidden?(shape: TLShape, editor: Editor): boolean
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Provides a way to hide shapes.
|
|
200
|
+
*
|
|
194
201
|
* Hidden shapes will not render in the editor, and they will not be eligible for hit test via
|
|
195
202
|
* {@link Editor#getShapeAtPoint} and {@link Editor#getShapesAtPoint}. But otherwise they will
|
|
196
203
|
* remain in the store and participate in all other operations.
|
|
204
|
+
*
|
|
205
|
+
* @example
|
|
206
|
+
* ```ts
|
|
207
|
+
* getShapeVisibility={(shape, editor) => shape.meta.hidden ? 'hidden' : 'inherit'}
|
|
208
|
+
* ```
|
|
209
|
+
*
|
|
210
|
+
* - `'inherit' | undefined` - (default) The shape will be visible unless its parent is hidden.
|
|
211
|
+
* - `'hidden'` - The shape will be hidden.
|
|
212
|
+
* - `'visible'` - The shape will be visible.
|
|
213
|
+
*
|
|
214
|
+
* @param shape - The shape to check.
|
|
215
|
+
* @param editor - The editor instance.
|
|
197
216
|
*/
|
|
198
|
-
|
|
217
|
+
getShapeVisibility?(
|
|
218
|
+
shape: TLShape,
|
|
219
|
+
editor: Editor
|
|
220
|
+
): 'visible' | 'hidden' | 'inherit' | null | undefined
|
|
199
221
|
|
|
200
222
|
/**
|
|
201
223
|
* The URLs for the fonts to use in the editor.
|
|
@@ -387,7 +409,9 @@ function TldrawEditorWithReadyStore({
|
|
|
387
409
|
options,
|
|
388
410
|
licenseKey,
|
|
389
411
|
deepLinks: _deepLinks,
|
|
412
|
+
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
|
390
413
|
isShapeHidden,
|
|
414
|
+
getShapeVisibility,
|
|
391
415
|
assetUrls,
|
|
392
416
|
}: Required<
|
|
393
417
|
TldrawEditorProps & {
|
|
@@ -447,6 +471,7 @@ function TldrawEditorWithReadyStore({
|
|
|
447
471
|
options,
|
|
448
472
|
licenseKey,
|
|
449
473
|
isShapeHidden,
|
|
474
|
+
getShapeVisibility,
|
|
450
475
|
fontAssetUrls: assetUrls?.fonts,
|
|
451
476
|
})
|
|
452
477
|
|
|
@@ -482,6 +507,7 @@ function TldrawEditorWithReadyStore({
|
|
|
482
507
|
setEditor,
|
|
483
508
|
licenseKey,
|
|
484
509
|
isShapeHidden,
|
|
510
|
+
getShapeVisibility,
|
|
485
511
|
textOptions,
|
|
486
512
|
assetUrls,
|
|
487
513
|
]
|
|
@@ -114,13 +114,13 @@ export const GeometryDebuggingView = track(function GeometryDebuggingView({
|
|
|
114
114
|
function GeometryStroke({ geometry }: { geometry: Geometry2d }) {
|
|
115
115
|
if (geometry instanceof Group2d) {
|
|
116
116
|
return (
|
|
117
|
-
|
|
117
|
+
<g stroke={geometry.debugColor}>
|
|
118
118
|
{[...geometry.children, ...geometry.ignoredChildren].map((child, i) => (
|
|
119
119
|
<GeometryStroke geometry={child} key={i} />
|
|
120
120
|
))}
|
|
121
|
-
|
|
121
|
+
</g>
|
|
122
122
|
)
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
-
return <path d={geometry.toSimpleSvgPath()} />
|
|
125
|
+
return <path d={geometry.toSimpleSvgPath()} stroke={geometry.debugColor} />
|
|
126
126
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { react } from '@tldraw/state'
|
|
2
2
|
import { useQuickReactor, useStateTracking } from '@tldraw/state-react'
|
|
3
3
|
import { TLShape, TLShapeId } from '@tldraw/tlschema'
|
|
4
|
-
import { memo, useCallback, useEffect, useRef } from 'react'
|
|
4
|
+
import { memo, useCallback, useEffect, useLayoutEffect, useRef } from 'react'
|
|
5
5
|
import { ShapeUtil } from '../editor/shapes/ShapeUtil'
|
|
6
6
|
import { useEditor } from '../hooks/useEditor'
|
|
7
7
|
import { useEditorComponents } from '../hooks/useEditorComponents'
|
|
@@ -44,10 +44,10 @@ export const Shape = memo(function Shape({
|
|
|
44
44
|
|
|
45
45
|
useEffect(() => {
|
|
46
46
|
return react('load fonts', () => {
|
|
47
|
-
const fonts = editor.fonts.getShapeFontFaces(
|
|
47
|
+
const fonts = editor.fonts.getShapeFontFaces(id)
|
|
48
48
|
editor.fonts.requestFonts(fonts)
|
|
49
49
|
})
|
|
50
|
-
}, [editor,
|
|
50
|
+
}, [editor, id])
|
|
51
51
|
|
|
52
52
|
const memoizedStuffRef = useRef({
|
|
53
53
|
transform: '',
|
|
@@ -104,22 +104,18 @@ export const Shape = memo(function Shape({
|
|
|
104
104
|
)
|
|
105
105
|
|
|
106
106
|
// This stuff changes pretty infrequently, so we can change them together
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
setStyleProperty(bgContainer, 'z-index', backgroundIndex)
|
|
120
|
-
},
|
|
121
|
-
[opacity, index, backgroundIndex]
|
|
122
|
-
)
|
|
107
|
+
useLayoutEffect(() => {
|
|
108
|
+
const container = containerRef.current
|
|
109
|
+
const bgContainer = bgContainerRef.current
|
|
110
|
+
|
|
111
|
+
// Opacity
|
|
112
|
+
setStyleProperty(container, 'opacity', opacity)
|
|
113
|
+
setStyleProperty(bgContainer, 'opacity', opacity)
|
|
114
|
+
|
|
115
|
+
// Z-Index
|
|
116
|
+
setStyleProperty(container, 'z-index', index)
|
|
117
|
+
setStyleProperty(bgContainer, 'z-index', backgroundIndex)
|
|
118
|
+
}, [opacity, index, backgroundIndex])
|
|
123
119
|
|
|
124
120
|
useQuickReactor(
|
|
125
121
|
'set display',
|
package/src/lib/editor/Editor.ts
CHANGED
|
@@ -241,10 +241,33 @@ export interface TLEditorOptions {
|
|
|
241
241
|
fontAssetUrls?: { [key: string]: string | undefined }
|
|
242
242
|
/**
|
|
243
243
|
* A predicate that should return true if the given shape should be hidden.
|
|
244
|
+
*
|
|
245
|
+
* @deprecated Use {@link Editor#getShapeVisibility} instead.
|
|
246
|
+
*
|
|
244
247
|
* @param shape - The shape to check.
|
|
245
248
|
* @param editor - The editor instance.
|
|
246
249
|
*/
|
|
247
250
|
isShapeHidden?(shape: TLShape, editor: Editor): boolean
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Provides a way to hide shapes.
|
|
254
|
+
*
|
|
255
|
+
* @example
|
|
256
|
+
* ```ts
|
|
257
|
+
* getShapeVisibility={(shape, editor) => shape.meta.hidden ? 'hidden' : 'inherit'}
|
|
258
|
+
* ```
|
|
259
|
+
*
|
|
260
|
+
* - `'inherit' | undefined` - (default) The shape will be visible unless its parent is hidden.
|
|
261
|
+
* - `'hidden'` - The shape will be hidden.
|
|
262
|
+
* - `'visible'` - The shape will be visible.
|
|
263
|
+
*
|
|
264
|
+
* @param shape - The shape to check.
|
|
265
|
+
* @param editor - The editor instance.
|
|
266
|
+
*/
|
|
267
|
+
getShapeVisibility?(
|
|
268
|
+
shape: TLShape,
|
|
269
|
+
editor: Editor
|
|
270
|
+
): 'visible' | 'hidden' | 'inherit' | null | undefined
|
|
248
271
|
}
|
|
249
272
|
|
|
250
273
|
/**
|
|
@@ -281,12 +304,21 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
281
304
|
autoFocus,
|
|
282
305
|
inferDarkMode,
|
|
283
306
|
options,
|
|
307
|
+
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
|
284
308
|
isShapeHidden,
|
|
309
|
+
getShapeVisibility,
|
|
285
310
|
fontAssetUrls,
|
|
286
311
|
}: TLEditorOptions) {
|
|
287
312
|
super()
|
|
313
|
+
assert(
|
|
314
|
+
!(isShapeHidden && getShapeVisibility),
|
|
315
|
+
'Cannot use both isShapeHidden and getShapeVisibility'
|
|
316
|
+
)
|
|
288
317
|
|
|
289
|
-
this.
|
|
318
|
+
this._getShapeVisibility = isShapeHidden
|
|
319
|
+
? // eslint-disable-next-line @typescript-eslint/no-deprecated
|
|
320
|
+
(shape: TLShape, editor: Editor) => (isShapeHidden(shape, editor) ? 'hidden' : 'inherit')
|
|
321
|
+
: getShapeVisibility
|
|
290
322
|
|
|
291
323
|
this.options = { ...defaultTldrawOptions, ...options }
|
|
292
324
|
|
|
@@ -773,18 +805,22 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
773
805
|
}
|
|
774
806
|
}
|
|
775
807
|
|
|
776
|
-
private readonly
|
|
808
|
+
private readonly _getShapeVisibility?: TLEditorOptions['getShapeVisibility']
|
|
777
809
|
@computed
|
|
778
810
|
private getIsShapeHiddenCache() {
|
|
779
|
-
if (!this.
|
|
811
|
+
if (!this._getShapeVisibility) return null
|
|
780
812
|
return this.store.createComputedCache<boolean, TLShape>('isShapeHidden', (shape: TLShape) => {
|
|
781
|
-
const
|
|
782
|
-
|
|
783
|
-
|
|
813
|
+
const visibility = this._getShapeVisibility!(shape, this)
|
|
814
|
+
const isParentHidden = PageRecordType.isId(shape.parentId)
|
|
815
|
+
? false
|
|
816
|
+
: this.isShapeHidden(shape.parentId)
|
|
817
|
+
|
|
818
|
+
if (isParentHidden) return visibility !== 'visible'
|
|
819
|
+
return visibility === 'hidden'
|
|
784
820
|
})
|
|
785
821
|
}
|
|
786
822
|
isShapeHidden(shapeOrId: TLShape | TLShapeId): boolean {
|
|
787
|
-
if (!this.
|
|
823
|
+
if (!this._getShapeVisibility) return false
|
|
788
824
|
return !!this.getIsShapeHiddenCache!()!.get(
|
|
789
825
|
typeof shapeOrId === 'string' ? shapeOrId : shapeOrId.id
|
|
790
826
|
)
|
|
@@ -1216,7 +1252,6 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
1216
1252
|
run(fn: () => void, opts?: TLEditorRunOptions): this {
|
|
1217
1253
|
const previousIgnoreShapeLock = this._shouldIgnoreShapeLock
|
|
1218
1254
|
this._shouldIgnoreShapeLock = opts?.ignoreShapeLock ?? previousIgnoreShapeLock
|
|
1219
|
-
|
|
1220
1255
|
try {
|
|
1221
1256
|
this.history.batch(fn, opts)
|
|
1222
1257
|
} finally {
|
|
@@ -3712,7 +3747,15 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
3712
3747
|
const addShapeById = (id: TLShapeId, opacity: number, isAncestorErasing: boolean) => {
|
|
3713
3748
|
const shape = this.getShape(id)
|
|
3714
3749
|
if (!shape) return
|
|
3715
|
-
|
|
3750
|
+
|
|
3751
|
+
if (this.isShapeHidden(shape)) {
|
|
3752
|
+
// process children just in case they are overriding the hidden state
|
|
3753
|
+
const isErasing = isAncestorErasing || erasingShapeIds.includes(id)
|
|
3754
|
+
for (const childId of this.getSortedChildIdsForParent(id)) {
|
|
3755
|
+
addShapeById(childId, opacity, isErasing)
|
|
3756
|
+
}
|
|
3757
|
+
return
|
|
3758
|
+
}
|
|
3716
3759
|
|
|
3717
3760
|
opacity *= shape.opacity
|
|
3718
3761
|
let isShapeErasing = false
|
|
@@ -4287,7 +4330,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
4287
4330
|
private _shapeGeometryCaches: Record<string, ComputedCache<Geometry2d, TLShape>> = {}
|
|
4288
4331
|
|
|
4289
4332
|
/**
|
|
4290
|
-
* Get the geometry of a shape.
|
|
4333
|
+
* Get the geometry of a shape in shape-space.
|
|
4291
4334
|
*
|
|
4292
4335
|
* @example
|
|
4293
4336
|
* ```ts
|
|
@@ -4318,6 +4361,44 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
4318
4361
|
)! as T
|
|
4319
4362
|
}
|
|
4320
4363
|
|
|
4364
|
+
private _shapePageGeometryCaches: Record<string, ComputedCache<Geometry2d, TLShape>> = {}
|
|
4365
|
+
|
|
4366
|
+
/**
|
|
4367
|
+
* Get the geometry of a shape in page-space.
|
|
4368
|
+
*
|
|
4369
|
+
* @example
|
|
4370
|
+
* ```ts
|
|
4371
|
+
* editor.getShapePageGeometry(myShape)
|
|
4372
|
+
* editor.getShapePageGeometry(myShapeId)
|
|
4373
|
+
* editor.getShapePageGeometry(myShapeId, { context: "arrow" })
|
|
4374
|
+
* ```
|
|
4375
|
+
*
|
|
4376
|
+
* @param shape - The shape (or shape id) to get the geometry for.
|
|
4377
|
+
* @param opts - Additional options about the request for geometry. Passed to {@link ShapeUtil.getGeometry}.
|
|
4378
|
+
*
|
|
4379
|
+
* @public
|
|
4380
|
+
*/
|
|
4381
|
+
getShapePageGeometry<T extends Geometry2d>(shape: TLShape | TLShapeId, opts?: TLGeometryOpts): T {
|
|
4382
|
+
const context = opts?.context ?? 'none'
|
|
4383
|
+
if (!this._shapePageGeometryCaches[context]) {
|
|
4384
|
+
this._shapePageGeometryCaches[context] = this.store.createComputedCache(
|
|
4385
|
+
'bounds',
|
|
4386
|
+
(shape) => {
|
|
4387
|
+
const geometry = this.getShapeGeometry(shape.id, opts)
|
|
4388
|
+
const pageTransform = this.getShapePageTransform(shape.id)
|
|
4389
|
+
return geometry.transform(pageTransform)
|
|
4390
|
+
},
|
|
4391
|
+
{
|
|
4392
|
+
// we only depend directly on the shape id, and changing geometry/transform will update us anyway
|
|
4393
|
+
areRecordsEqual: () => true,
|
|
4394
|
+
}
|
|
4395
|
+
)
|
|
4396
|
+
}
|
|
4397
|
+
return this._shapePageGeometryCaches[context].get(
|
|
4398
|
+
typeof shape === 'string' ? shape : shape.id
|
|
4399
|
+
)! as T
|
|
4400
|
+
}
|
|
4401
|
+
|
|
4321
4402
|
/** @internal */
|
|
4322
4403
|
@computed private _getShapeHandlesCache(): ComputedCache<TLHandle[] | undefined, TLShape> {
|
|
4323
4404
|
return this.store.createComputedCache('handles', (shape) => {
|
|
@@ -4424,15 +4505,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
4424
4505
|
/** @internal */
|
|
4425
4506
|
@computed private _getShapePageBoundsCache(): ComputedCache<Box, TLShape> {
|
|
4426
4507
|
return this.store.createComputedCache<Box, TLShape>('pageBoundsCache', (shape) => {
|
|
4427
|
-
|
|
4428
|
-
|
|
4429
|
-
if (!pageTransform) return new Box()
|
|
4430
|
-
|
|
4431
|
-
const result = Box.FromPoints(
|
|
4432
|
-
Mat.applyToPoints(pageTransform, this.getShapeGeometry(shape).vertices)
|
|
4433
|
-
)
|
|
4434
|
-
|
|
4435
|
-
return result
|
|
4508
|
+
return this.getShapePageGeometry(shape).bounds
|
|
4436
4509
|
})
|
|
4437
4510
|
}
|
|
4438
4511
|
|
|
@@ -4506,11 +4579,10 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
4506
4579
|
if (frameAncestors.length === 0) return undefined
|
|
4507
4580
|
|
|
4508
4581
|
const pageMask = frameAncestors
|
|
4509
|
-
.map<Vec[] | undefined>(
|
|
4510
|
-
|
|
4511
|
-
|
|
4512
|
-
.
|
|
4513
|
-
.applyToPoints(this.getShapeGeometry(s).vertices)
|
|
4582
|
+
.map<Vec[] | undefined>(
|
|
4583
|
+
(s) =>
|
|
4584
|
+
// Apply the frame transform to the frame outline to get the frame outline in the current page space
|
|
4585
|
+
this.getShapePageGeometry(s.id).vertices
|
|
4514
4586
|
)
|
|
4515
4587
|
.reduce((acc, b) => {
|
|
4516
4588
|
if (!(b && acc)) return undefined
|
|
@@ -8139,8 +8211,18 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8139
8211
|
if (!currentTool) return styles
|
|
8140
8212
|
|
|
8141
8213
|
if (currentTool.shapeType) {
|
|
8142
|
-
|
|
8143
|
-
|
|
8214
|
+
if (
|
|
8215
|
+
currentTool.shapeType === 'frame' &&
|
|
8216
|
+
!(this.getShapeUtil('frame')!.options as any).showColors
|
|
8217
|
+
) {
|
|
8218
|
+
for (const style of this.styleProps[currentTool.shapeType].keys()) {
|
|
8219
|
+
if (style.id === 'tldraw:color') continue
|
|
8220
|
+
styles.applyValue(style, this.getStyleForNextShape(style))
|
|
8221
|
+
}
|
|
8222
|
+
} else {
|
|
8223
|
+
for (const style of this.styleProps[currentTool.shapeType].keys()) {
|
|
8224
|
+
styles.applyValue(style, this.getStyleForNextShape(style))
|
|
8225
|
+
}
|
|
8144
8226
|
}
|
|
8145
8227
|
}
|
|
8146
8228
|
|
|
@@ -9849,12 +9931,12 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
9849
9931
|
|
|
9850
9932
|
const { x: cx, y: cy, z: cz } = unsafe__withoutCapture(() => this.getCamera())
|
|
9851
9933
|
|
|
9852
|
-
const { panSpeed
|
|
9934
|
+
const { panSpeed } = cameraOptions
|
|
9853
9935
|
this._setCamera(
|
|
9854
9936
|
new Vec(
|
|
9855
|
-
cx + (dx * panSpeed) / cz - x / cz + x /
|
|
9856
|
-
cy + (dy * panSpeed) / cz - y / cz + y /
|
|
9857
|
-
z
|
|
9937
|
+
cx + (dx * panSpeed) / cz - x / cz + x / z,
|
|
9938
|
+
cy + (dy * panSpeed) / cz - y / cz + y / z,
|
|
9939
|
+
z
|
|
9858
9940
|
),
|
|
9859
9941
|
{ immediate: true }
|
|
9860
9942
|
)
|
|
@@ -9929,14 +10011,9 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
9929
10011
|
}
|
|
9930
10012
|
|
|
9931
10013
|
const zoom = cz + (delta ?? 0) * zoomSpeed * cz
|
|
9932
|
-
this._setCamera(
|
|
9933
|
-
|
|
9934
|
-
|
|
9935
|
-
cy + (y / zoom - y) - (y / cz - y),
|
|
9936
|
-
zoom
|
|
9937
|
-
),
|
|
9938
|
-
{ immediate: true }
|
|
9939
|
-
)
|
|
10014
|
+
this._setCamera(new Vec(cx + x / zoom - x / cz, cy + y / zoom - y / cz, zoom), {
|
|
10015
|
+
immediate: true,
|
|
10016
|
+
})
|
|
9940
10017
|
this.maybeTrackPerformance('Zooming')
|
|
9941
10018
|
return
|
|
9942
10019
|
}
|
|
@@ -31,7 +31,7 @@ export const notVisibleShapes = (editor: Editor) => {
|
|
|
31
31
|
})
|
|
32
32
|
return notVisibleShapes
|
|
33
33
|
}
|
|
34
|
-
return computed<Set<TLShapeId>>('
|
|
34
|
+
return computed<Set<TLShapeId>>('notVisibleShapes', (prevValue) => {
|
|
35
35
|
if (isUninitialized(prevValue)) {
|
|
36
36
|
return fromScratch(editor)
|
|
37
37
|
}
|
|
@@ -94,7 +94,7 @@ export class FontManager {
|
|
|
94
94
|
const shapeUtil = this.editor.getShapeUtil(shape)
|
|
95
95
|
return shapeUtil.getFontFaces(shape)
|
|
96
96
|
},
|
|
97
|
-
{ areResultsEqual: areArraysShallowEqual }
|
|
97
|
+
{ areResultsEqual: areArraysShallowEqual, areRecordsEqual: (a, b) => a.props === b.props }
|
|
98
98
|
)
|
|
99
99
|
|
|
100
100
|
this.shapeFontLoadStateCache = editor.store.createCache<(FontState | null)[], TLShape>(
|
|
@@ -2,8 +2,6 @@ import { TLGroupShape, groupShapeMigrations, groupShapeProps } from '@tldraw/tls
|
|
|
2
2
|
import { SVGContainer } from '../../../components/SVGContainer'
|
|
3
3
|
import { Geometry2d } from '../../../primitives/geometry/Geometry2d'
|
|
4
4
|
import { Group2d } from '../../../primitives/geometry/Group2d'
|
|
5
|
-
import { Polygon2d } from '../../../primitives/geometry/Polygon2d'
|
|
6
|
-
import { Polyline2d } from '../../../primitives/geometry/Polyline2d'
|
|
7
5
|
import { Rectangle2d } from '../../../primitives/geometry/Rectangle2d'
|
|
8
6
|
import { ShapeUtil } from '../ShapeUtil'
|
|
9
7
|
import { DashedOutlineBox } from './DashedOutlineBox'
|
|
@@ -35,19 +33,9 @@ export class GroupShapeUtil extends ShapeUtil<TLGroupShape> {
|
|
|
35
33
|
return new Group2d({
|
|
36
34
|
children: children.map((childId) => {
|
|
37
35
|
const shape = this.editor.getShape(childId)!
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
if (geometry.isClosed) {
|
|
42
|
-
return new Polygon2d({
|
|
43
|
-
points,
|
|
44
|
-
isFilled: true,
|
|
45
|
-
})
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
return new Polyline2d({
|
|
49
|
-
points,
|
|
50
|
-
})
|
|
36
|
+
return this.editor
|
|
37
|
+
.getShapeGeometry(childId)
|
|
38
|
+
.transform(this.editor.getShapeLocalTransform(shape)!)
|
|
51
39
|
}),
|
|
52
40
|
})
|
|
53
41
|
}
|
|
@@ -38,6 +38,7 @@ export interface TLStateNodeConstructor {
|
|
|
38
38
|
initial?: string
|
|
39
39
|
children?(): TLStateNodeConstructor[]
|
|
40
40
|
isLockable: boolean
|
|
41
|
+
useCoalescedEvents: boolean
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
/** @public */
|
|
@@ -47,7 +48,8 @@ export abstract class StateNode implements Partial<TLEventHandlers> {
|
|
|
47
48
|
public editor: Editor,
|
|
48
49
|
parent?: StateNode
|
|
49
50
|
) {
|
|
50
|
-
const { id, children, initial, isLockable } = this
|
|
51
|
+
const { id, children, initial, isLockable, useCoalescedEvents } = this
|
|
52
|
+
.constructor as TLStateNodeConstructor
|
|
51
53
|
|
|
52
54
|
this.id = id
|
|
53
55
|
this._isActive = atom<boolean>('toolIsActive' + this.id, false)
|
|
@@ -83,6 +85,7 @@ export abstract class StateNode implements Partial<TLEventHandlers> {
|
|
|
83
85
|
}
|
|
84
86
|
}
|
|
85
87
|
this.isLockable = isLockable
|
|
88
|
+
this.useCoalescedEvents = useCoalescedEvents
|
|
86
89
|
this.performanceTracker = new PerformanceTracker()
|
|
87
90
|
}
|
|
88
91
|
|
|
@@ -90,6 +93,7 @@ export abstract class StateNode implements Partial<TLEventHandlers> {
|
|
|
90
93
|
static initial?: string
|
|
91
94
|
static children?: () => TLStateNodeConstructor[]
|
|
92
95
|
static isLockable = true
|
|
96
|
+
static useCoalescedEvents = false
|
|
93
97
|
|
|
94
98
|
id: string
|
|
95
99
|
type: 'branch' | 'leaf' | 'root'
|
|
@@ -97,6 +101,7 @@ export abstract class StateNode implements Partial<TLEventHandlers> {
|
|
|
97
101
|
initial?: string
|
|
98
102
|
children?: Record<string, StateNode>
|
|
99
103
|
isLockable: boolean
|
|
104
|
+
useCoalescedEvents: boolean
|
|
100
105
|
parent: StateNode
|
|
101
106
|
|
|
102
107
|
/**
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { assertExists, objectMapValues, uniqueId } from '@tldraw/utils'
|
|
1
|
+
import { assertExists, getOwnProperty, objectMapValues, uniqueId } from '@tldraw/utils'
|
|
2
2
|
import { FontEmbedder } from './FontEmbedder'
|
|
3
|
+
import { ReadonlyStyles, Styles, cssRules } from './cssRules'
|
|
3
4
|
import {
|
|
4
5
|
elementStyle,
|
|
5
6
|
getComputedStyle,
|
|
@@ -7,15 +8,8 @@ import {
|
|
|
7
8
|
getRenderedChildren,
|
|
8
9
|
} from './domUtils'
|
|
9
10
|
import { resourceToDataUrl } from './fetchCache'
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
isPropertyInherited,
|
|
13
|
-
parseCssValueUrls,
|
|
14
|
-
shouldIncludeCssProperty,
|
|
15
|
-
} from './parseCss'
|
|
16
|
-
|
|
17
|
-
type Styles = { [K in string]?: string }
|
|
18
|
-
type ReadonlyStyles = { readonly [K in string]?: string }
|
|
11
|
+
import { parseCssValueUrls, shouldIncludeCssProperty } from './parseCss'
|
|
12
|
+
|
|
19
13
|
const NO_STYLES = {} as const
|
|
20
14
|
|
|
21
15
|
interface ElementStyleInfo {
|
|
@@ -239,15 +233,22 @@ function styleFromComputedStyleMap(
|
|
|
239
233
|
{ defaultStyles, parentStyles }: ReadStyleOpts
|
|
240
234
|
) {
|
|
241
235
|
const styles: Record<string, string> = {}
|
|
236
|
+
const currentColor = style.get('color')?.toString() || ''
|
|
237
|
+
const ruleOptions = {
|
|
238
|
+
currentColor,
|
|
239
|
+
parentStyles,
|
|
240
|
+
defaultStyles,
|
|
241
|
+
getStyle: (property: string) => style.get(property)?.toString() ?? '',
|
|
242
|
+
}
|
|
242
243
|
for (const property of style.keys()) {
|
|
243
244
|
if (!shouldIncludeCssProperty(property)) continue
|
|
244
245
|
|
|
245
246
|
const value = style.get(property)!.toString()
|
|
246
247
|
|
|
247
248
|
if (defaultStyles[property] === value) continue
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
249
|
+
|
|
250
|
+
const rule = getOwnProperty(cssRules, property)
|
|
251
|
+
if (rule && rule(value, property, ruleOptions)) continue
|
|
251
252
|
|
|
252
253
|
styles[property] = value
|
|
253
254
|
}
|
|
@@ -260,14 +261,23 @@ function styleFromComputedStyle(
|
|
|
260
261
|
{ defaultStyles, parentStyles }: ReadStyleOpts
|
|
261
262
|
) {
|
|
262
263
|
const styles: Record<string, string> = {}
|
|
264
|
+
const currentColor = style.color
|
|
265
|
+
const ruleOptions = {
|
|
266
|
+
currentColor,
|
|
267
|
+
parentStyles,
|
|
268
|
+
defaultStyles,
|
|
269
|
+
getStyle: (property: string) => style.getPropertyValue(property),
|
|
270
|
+
}
|
|
271
|
+
|
|
263
272
|
for (const property in style) {
|
|
264
273
|
if (!shouldIncludeCssProperty(property)) continue
|
|
265
274
|
|
|
266
275
|
const value = style.getPropertyValue(property)
|
|
267
276
|
|
|
268
277
|
if (defaultStyles[property] === value) continue
|
|
269
|
-
|
|
270
|
-
|
|
278
|
+
|
|
279
|
+
const rule = getOwnProperty(cssRules, property)
|
|
280
|
+
if (rule && rule(value, property, ruleOptions)) continue
|
|
271
281
|
|
|
272
282
|
styles[property] = value
|
|
273
283
|
}
|