@tldraw/editor 3.14.0-canary.6fbbca54ff57 → 3.14.0-canary.718fcc03811e
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 +14 -83
- package/dist-cjs/index.js +1 -4
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/editor/Editor.js +25 -45
- package/dist-cjs/lib/editor/Editor.js.map +2 -2
- package/dist-cjs/lib/editor/managers/TextManager/TextManager.js +2 -3
- package/dist-cjs/lib/editor/managers/TextManager/TextManager.js.map +2 -2
- package/dist-cjs/lib/editor/shapes/ShapeUtil.js +10 -0
- package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
- package/dist-cjs/lib/editor/tools/StateNode.js +3 -3
- package/dist-cjs/lib/editor/tools/StateNode.js.map +2 -2
- package/dist-cjs/lib/editor/types/emit-types.js.map +1 -1
- package/dist-cjs/lib/primitives/geometry/Geometry2d.js +2 -6
- package/dist-cjs/lib/primitives/geometry/Geometry2d.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 +14 -83
- package/dist-esm/index.mjs +1 -4
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/editor/Editor.mjs +25 -45
- package/dist-esm/lib/editor/Editor.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs +2 -3
- package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs.map +2 -2
- package/dist-esm/lib/editor/shapes/ShapeUtil.mjs +10 -0
- package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/editor/tools/StateNode.mjs +3 -3
- package/dist-esm/lib/editor/tools/StateNode.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Geometry2d.mjs +2 -6
- package/dist-esm/lib/primitives/geometry/Geometry2d.mjs.map +2 -2
- package/dist-esm/version.mjs +3 -3
- package/dist-esm/version.mjs.map +1 -1
- package/package.json +7 -7
- package/src/index.ts +0 -5
- package/src/lib/editor/Editor.ts +31 -48
- package/src/lib/editor/managers/TextManager/TextManager.ts +2 -4
- package/src/lib/editor/shapes/ShapeUtil.ts +15 -47
- package/src/lib/editor/tools/StateNode.ts +3 -3
- package/src/lib/editor/types/emit-types.ts +0 -4
- package/src/lib/primitives/geometry/Geometry2d.ts +2 -7
- package/src/version.ts +3 -3
- package/dist-cjs/lib/utils/reparenting.js +0 -232
- package/dist-cjs/lib/utils/reparenting.js.map +0 -7
- package/dist-esm/lib/utils/reparenting.mjs +0 -216
- package/dist-esm/lib/utils/reparenting.mjs.map +0 -7
- package/src/lib/utils/reparenting.ts +0 -383
package/src/lib/editor/Editor.ts
CHANGED
|
@@ -2128,7 +2128,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
2128
2128
|
* @readonly
|
|
2129
2129
|
* @public
|
|
2130
2130
|
*/
|
|
2131
|
-
getSelectionScreenBounds(): Box | undefined {
|
|
2131
|
+
@computed getSelectionScreenBounds(): Box | undefined {
|
|
2132
2132
|
const bounds = this.getSelectionPageBounds()
|
|
2133
2133
|
if (!bounds) return undefined
|
|
2134
2134
|
const { x, y } = this.pageToScreen(bounds.point)
|
|
@@ -5528,7 +5528,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
5528
5528
|
if (!id) return undefined
|
|
5529
5529
|
const freshShape = this.getShape(id)
|
|
5530
5530
|
if (freshShape === undefined || !isShapeId(freshShape.parentId)) return undefined
|
|
5531
|
-
return this.
|
|
5531
|
+
return this.store.get(freshShape.parentId)
|
|
5532
5532
|
}
|
|
5533
5533
|
|
|
5534
5534
|
/**
|
|
@@ -5711,10 +5711,6 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
5711
5711
|
const newPoint = invertedParentTransform.applyToPoint(pagePoint)
|
|
5712
5712
|
const newRotation = pageTransform.rotation() - parentPageRotation
|
|
5713
5713
|
|
|
5714
|
-
if (shape.id === parentId) {
|
|
5715
|
-
throw Error('Attempted to reparent a shape to itself!')
|
|
5716
|
-
}
|
|
5717
|
-
|
|
5718
5714
|
changes.push({
|
|
5719
5715
|
id: shape.id,
|
|
5720
5716
|
type: shape.type,
|
|
@@ -5818,11 +5814,6 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
5818
5814
|
return shapeIds
|
|
5819
5815
|
}
|
|
5820
5816
|
|
|
5821
|
-
/** @deprecated Use {@link Editor.getDraggingOverShape} instead */
|
|
5822
|
-
getDroppingOverShape(point: Vec, droppingShapes: TLShape[]): TLShape | undefined {
|
|
5823
|
-
return this.getDraggingOverShape(point, droppingShapes)
|
|
5824
|
-
}
|
|
5825
|
-
|
|
5826
5817
|
/**
|
|
5827
5818
|
* Get the shape that some shapes should be dropped on at a given point.
|
|
5828
5819
|
*
|
|
@@ -5833,33 +5824,35 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
5833
5824
|
*
|
|
5834
5825
|
* @public
|
|
5835
5826
|
*/
|
|
5836
|
-
|
|
5837
|
-
//
|
|
5838
|
-
const
|
|
5839
|
-
|
|
5840
|
-
|
|
5827
|
+
getDroppingOverShape(point: VecLike, droppingShapes: TLShape[] = []) {
|
|
5828
|
+
// starting from the top...
|
|
5829
|
+
const currentPageShapesSorted = this.getCurrentPageShapesSorted()
|
|
5830
|
+
for (let i = currentPageShapesSorted.length - 1; i >= 0; i--) {
|
|
5831
|
+
const shape = currentPageShapesSorted[i]
|
|
5841
5832
|
|
|
5842
|
-
|
|
5843
|
-
|
|
5844
|
-
|
|
5845
|
-
|
|
5846
|
-
|
|
5847
|
-
|
|
5848
|
-
!
|
|
5849
|
-
|
|
5850
|
-
|
|
5851
|
-
|
|
5833
|
+
if (
|
|
5834
|
+
// ignore hidden shapes
|
|
5835
|
+
this.isShapeHidden(shape) ||
|
|
5836
|
+
// don't allow dropping on selected shapes
|
|
5837
|
+
this.getSelectedShapeIds().includes(shape.id) ||
|
|
5838
|
+
// only allow shapes that can receive children
|
|
5839
|
+
!this.getShapeUtil(shape).canDropShapes(shape, droppingShapes) ||
|
|
5840
|
+
// don't allow dropping a shape on itself or one of it's children
|
|
5841
|
+
droppingShapes.find((s) => s.id === shape.id || this.hasAncestor(shape, s.id))
|
|
5842
|
+
) {
|
|
5843
|
+
continue
|
|
5844
|
+
}
|
|
5845
|
+
|
|
5846
|
+
// Only allow dropping into the masked page bounds of the shape, e.g. when a frame is
|
|
5847
|
+
// partially clipped by its own parent frame
|
|
5848
|
+
const maskedPageBounds = this.getShapeMaskedPageBounds(shape.id)
|
|
5852
5849
|
|
|
5853
|
-
for (const maybeDraggingOverShape of maybeDraggingOverShapes) {
|
|
5854
|
-
const shapeUtil = this.getShapeUtil(maybeDraggingOverShape)
|
|
5855
|
-
// Any shape that can handle any dragging interactions is a valid target
|
|
5856
5850
|
if (
|
|
5857
|
-
|
|
5858
|
-
|
|
5859
|
-
|
|
5860
|
-
shapeUtil.onDropShapesOver
|
|
5851
|
+
maskedPageBounds &&
|
|
5852
|
+
maskedPageBounds.containsPoint(point) &&
|
|
5853
|
+
this.getShapeGeometry(shape).hitTestPoint(this.getPointInShapeSpace(shape, point), 0, true)
|
|
5861
5854
|
) {
|
|
5862
|
-
return
|
|
5855
|
+
return shape
|
|
5863
5856
|
}
|
|
5864
5857
|
}
|
|
5865
5858
|
}
|
|
@@ -6218,12 +6211,11 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
6218
6211
|
*/
|
|
6219
6212
|
duplicateShapes(shapes: TLShapeId[] | TLShape[], offset?: VecLike): this {
|
|
6220
6213
|
this.run(() => {
|
|
6221
|
-
const
|
|
6214
|
+
const ids =
|
|
6222
6215
|
typeof shapes[0] === 'string'
|
|
6223
6216
|
? (shapes as TLShapeId[])
|
|
6224
6217
|
: (shapes as TLShape[]).map((s) => s.id)
|
|
6225
6218
|
|
|
6226
|
-
const ids = this._shouldIgnoreShapeLock ? _ids : this._getUnlockedShapeIds(_ids)
|
|
6227
6219
|
if (ids.length <= 0) return this
|
|
6228
6220
|
|
|
6229
6221
|
const initialIds = new Set(ids)
|
|
@@ -7813,10 +7805,9 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
7813
7805
|
|
|
7814
7806
|
for (let i = currentPageShapesSorted.length - 1; i >= 0; i--) {
|
|
7815
7807
|
const parent = currentPageShapesSorted[i]
|
|
7816
|
-
const util = this.getShapeUtil(parent)
|
|
7817
7808
|
if (
|
|
7818
|
-
util.canReceiveNewChildrenOfType(parent, partial.type) &&
|
|
7819
7809
|
!this.isShapeHidden(parent) &&
|
|
7810
|
+
this.getShapeUtil(parent).canReceiveNewChildrenOfType(parent, partial.type) &&
|
|
7820
7811
|
this.isPointInShape(
|
|
7821
7812
|
parent,
|
|
7822
7813
|
// If no parent is provided, then we can treat the
|
|
@@ -7945,8 +7936,6 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
7945
7936
|
}
|
|
7946
7937
|
})
|
|
7947
7938
|
|
|
7948
|
-
this.emit('created-shapes', shapeRecordsToCreate)
|
|
7949
|
-
this.emit('edit')
|
|
7950
7939
|
this.store.put(shapeRecordsToCreate)
|
|
7951
7940
|
})
|
|
7952
7941
|
|
|
@@ -8341,8 +8330,6 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8341
8330
|
updates.push(updated)
|
|
8342
8331
|
}
|
|
8343
8332
|
|
|
8344
|
-
this.emit('edited-shapes', updates)
|
|
8345
|
-
this.emit('edit')
|
|
8346
8333
|
this.store.put(updates)
|
|
8347
8334
|
})
|
|
8348
8335
|
}
|
|
@@ -8392,8 +8379,6 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8392
8379
|
})
|
|
8393
8380
|
}
|
|
8394
8381
|
|
|
8395
|
-
this.emit('deleted-shapes', [...allShapeIdsToDelete])
|
|
8396
|
-
this.emit('edit')
|
|
8397
8382
|
return this.run(() => this.store.remove([...allShapeIdsToDelete]))
|
|
8398
8383
|
}
|
|
8399
8384
|
|
|
@@ -9520,8 +9505,6 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
9520
9505
|
previousPagePoint,
|
|
9521
9506
|
currentScreenPoint,
|
|
9522
9507
|
currentPagePoint,
|
|
9523
|
-
originScreenPoint,
|
|
9524
|
-
originPagePoint,
|
|
9525
9508
|
} = this.inputs
|
|
9526
9509
|
|
|
9527
9510
|
const { screenBounds } = this.store.unsafeGetWithoutCapture(TLINSTANCE_ID)!
|
|
@@ -9550,8 +9533,8 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
9550
9533
|
// Reset velocity on pointer down, or when a pinch starts or ends
|
|
9551
9534
|
if (info.name === 'pointer_down' || this.inputs.isPinching) {
|
|
9552
9535
|
pointerVelocity.set(0, 0)
|
|
9553
|
-
originScreenPoint.setTo(currentScreenPoint)
|
|
9554
|
-
originPagePoint.setTo(currentPagePoint)
|
|
9536
|
+
this.inputs.originScreenPoint.setTo(currentScreenPoint)
|
|
9537
|
+
this.inputs.originPagePoint.setTo(currentPagePoint)
|
|
9555
9538
|
}
|
|
9556
9539
|
|
|
9557
9540
|
// todo: We only have to do this if there are multiple users in the document
|
|
@@ -26,7 +26,6 @@ export interface TLMeasureTextOpts {
|
|
|
26
26
|
fontWeight: string
|
|
27
27
|
fontFamily: string
|
|
28
28
|
fontSize: number
|
|
29
|
-
/** This must be a number, e.g. 1.35, not a pixel value. */
|
|
30
29
|
lineHeight: number
|
|
31
30
|
/**
|
|
32
31
|
* When maxWidth is a number, the text will be wrapped to that maxWidth. When maxWidth
|
|
@@ -76,7 +75,6 @@ export class TextManager {
|
|
|
76
75
|
// we need to save the default styles so that we can restore them when we're done
|
|
77
76
|
// these must be the css names, not the js names for the styles
|
|
78
77
|
this.defaultStyles = {
|
|
79
|
-
'overflow-wrap': 'break-word',
|
|
80
78
|
'word-break': 'auto',
|
|
81
79
|
width: null,
|
|
82
80
|
height: null,
|
|
@@ -125,7 +123,7 @@ export class TextManager {
|
|
|
125
123
|
elm.style.setProperty('font-style', opts.fontStyle)
|
|
126
124
|
elm.style.setProperty('font-weight', opts.fontWeight)
|
|
127
125
|
elm.style.setProperty('font-size', opts.fontSize + 'px')
|
|
128
|
-
elm.style.setProperty('line-height', opts.lineHeight.
|
|
126
|
+
elm.style.setProperty('line-height', opts.lineHeight * opts.fontSize + 'px')
|
|
129
127
|
elm.style.setProperty('padding', opts.padding)
|
|
130
128
|
|
|
131
129
|
if (opts.maxWidth) {
|
|
@@ -289,7 +287,7 @@ export class TextManager {
|
|
|
289
287
|
elm.style.setProperty('font-style', opts.fontStyle)
|
|
290
288
|
elm.style.setProperty('font-weight', opts.fontWeight)
|
|
291
289
|
elm.style.setProperty('font-size', opts.fontSize + 'px')
|
|
292
|
-
elm.style.setProperty('line-height', opts.lineHeight.
|
|
290
|
+
elm.style.setProperty('line-height', opts.lineHeight * opts.fontSize + 'px')
|
|
293
291
|
|
|
294
292
|
const elementWidth = Math.ceil(opts.width - opts.padding * 2)
|
|
295
293
|
elm.style.setProperty('width', `${elementWidth}px`)
|
|
@@ -4,15 +4,12 @@ import { LegacyMigrations, MigrationSequence } from '@tldraw/store'
|
|
|
4
4
|
import {
|
|
5
5
|
RecordProps,
|
|
6
6
|
TLHandle,
|
|
7
|
-
TLParentId,
|
|
8
7
|
TLPropsMigrations,
|
|
9
8
|
TLShape,
|
|
10
9
|
TLShapeCrop,
|
|
11
|
-
TLShapeId,
|
|
12
10
|
TLShapePartial,
|
|
13
11
|
TLUnknownShape,
|
|
14
12
|
} from '@tldraw/tlschema'
|
|
15
|
-
import { IndexKey } from '@tldraw/utils'
|
|
16
13
|
import { ReactElement } from 'react'
|
|
17
14
|
import { Box, SelectionHandle } from '../../primitives/Box'
|
|
18
15
|
import { Vec } from '../../primitives/Vec'
|
|
@@ -390,6 +387,17 @@ export abstract class ShapeUtil<Shape extends TLUnknownShape = TLUnknownShape> {
|
|
|
390
387
|
return false
|
|
391
388
|
}
|
|
392
389
|
|
|
390
|
+
/**
|
|
391
|
+
* Get whether the shape can receive children of a given type.
|
|
392
|
+
*
|
|
393
|
+
* @param shape - The shape type.
|
|
394
|
+
* @param shapes - The shapes that are being dropped.
|
|
395
|
+
* @public
|
|
396
|
+
*/
|
|
397
|
+
canDropShapes(_shape: Shape, _shapes: TLShape[]) {
|
|
398
|
+
return false
|
|
399
|
+
}
|
|
400
|
+
|
|
393
401
|
/**
|
|
394
402
|
* Get the shape as an SVG object.
|
|
395
403
|
*
|
|
@@ -509,16 +517,7 @@ export abstract class ShapeUtil<Shape extends TLUnknownShape = TLUnknownShape> {
|
|
|
509
517
|
): Omit<TLShapePartial<Shape>, 'id' | 'type'> | undefined | void
|
|
510
518
|
|
|
511
519
|
/**
|
|
512
|
-
* A callback called when some other shapes are dragged
|
|
513
|
-
*
|
|
514
|
-
* @param shape - The shape.
|
|
515
|
-
* @param shapes - The shapes that are being dragged in.
|
|
516
|
-
* @public
|
|
517
|
-
*/
|
|
518
|
-
onDragShapesIn?(shape: Shape, shapes: TLShape[], info: TLDragShapesInInfo): void
|
|
519
|
-
|
|
520
|
-
/**
|
|
521
|
-
* A callback called when some other shapes are dragged over this one. This fires when the shapes are dragged over the shape for the first time (after the onDragShapesIn callback), and again on every update while the shapes are being dragged.
|
|
520
|
+
* A callback called when some other shapes are dragged over this one.
|
|
522
521
|
*
|
|
523
522
|
* @example
|
|
524
523
|
*
|
|
@@ -532,7 +531,7 @@ export abstract class ShapeUtil<Shape extends TLUnknownShape = TLUnknownShape> {
|
|
|
532
531
|
* @param shapes - The shapes that are being dragged over this one.
|
|
533
532
|
* @public
|
|
534
533
|
*/
|
|
535
|
-
onDragShapesOver?(shape: Shape, shapes: TLShape[]
|
|
534
|
+
onDragShapesOver?(shape: Shape, shapes: TLShape[]): void
|
|
536
535
|
|
|
537
536
|
/**
|
|
538
537
|
* A callback called when some other shapes are dragged out of this one.
|
|
@@ -541,7 +540,7 @@ export abstract class ShapeUtil<Shape extends TLUnknownShape = TLUnknownShape> {
|
|
|
541
540
|
* @param shapes - The shapes that are being dragged out.
|
|
542
541
|
* @public
|
|
543
542
|
*/
|
|
544
|
-
onDragShapesOut?(shape: Shape, shapes: TLShape[]
|
|
543
|
+
onDragShapesOut?(shape: Shape, shapes: TLShape[]): void
|
|
545
544
|
|
|
546
545
|
/**
|
|
547
546
|
* A callback called when some other shapes are dropped over this one.
|
|
@@ -550,7 +549,7 @@ export abstract class ShapeUtil<Shape extends TLUnknownShape = TLUnknownShape> {
|
|
|
550
549
|
* @param shapes - The shapes that are being dropped over this one.
|
|
551
550
|
* @public
|
|
552
551
|
*/
|
|
553
|
-
onDropShapesOver?(shape: Shape, shapes: TLShape[]
|
|
552
|
+
onDropShapesOver?(shape: Shape, shapes: TLShape[]): void
|
|
554
553
|
|
|
555
554
|
/**
|
|
556
555
|
* A callback called when a shape starts being resized.
|
|
@@ -746,37 +745,6 @@ export interface TLCropInfo<T extends TLShape> {
|
|
|
746
745
|
crop: TLShapeCrop
|
|
747
746
|
uncroppedSize: { w: number; h: number }
|
|
748
747
|
initialShape: T
|
|
749
|
-
aspectRatioLocked?: boolean
|
|
750
|
-
}
|
|
751
|
-
|
|
752
|
-
/** @public */
|
|
753
|
-
export interface TLDragShapesInInfo {
|
|
754
|
-
initialDraggingOverShapeId: TLShapeId | null
|
|
755
|
-
prevDraggingOverShapeId: TLShapeId | null
|
|
756
|
-
initialParentIds: Map<TLShapeId, TLParentId>
|
|
757
|
-
initialIndices: Map<TLShapeId, IndexKey>
|
|
758
|
-
}
|
|
759
|
-
|
|
760
|
-
/** @public */
|
|
761
|
-
export interface TLDragShapesOverInfo {
|
|
762
|
-
initialDraggingOverShapeId: TLShapeId | null
|
|
763
|
-
initialParentIds: Map<TLShapeId, TLParentId>
|
|
764
|
-
initialIndices: Map<TLShapeId, IndexKey>
|
|
765
|
-
}
|
|
766
|
-
|
|
767
|
-
/** @public */
|
|
768
|
-
export interface TLDragShapesOutInfo {
|
|
769
|
-
nextDraggingOverShapeId: TLShapeId | null
|
|
770
|
-
initialDraggingOverShapeId: TLShapeId | null
|
|
771
|
-
initialParentIds: Map<TLShapeId, TLParentId>
|
|
772
|
-
initialIndices: Map<TLShapeId, IndexKey>
|
|
773
|
-
}
|
|
774
|
-
|
|
775
|
-
/** @public */
|
|
776
|
-
export interface TLDropShapesOverInfo {
|
|
777
|
-
initialDraggingOverShapeId: TLShapeId | null
|
|
778
|
-
initialParentIds: Map<TLShapeId, TLParentId>
|
|
779
|
-
initialIndices: Map<TLShapeId, IndexKey>
|
|
780
748
|
}
|
|
781
749
|
|
|
782
750
|
/**
|
|
@@ -206,15 +206,15 @@ export abstract class StateNode implements Partial<TLEventHandlers> {
|
|
|
206
206
|
}
|
|
207
207
|
|
|
208
208
|
// todo: move this logic into transition
|
|
209
|
-
exit(info: any,
|
|
209
|
+
exit(info: any, from: string) {
|
|
210
210
|
if (debugFlags.measurePerformance.get() && this.performanceTracker.isStarted()) {
|
|
211
211
|
this.performanceTracker.stop()
|
|
212
212
|
}
|
|
213
213
|
this._isActive.set(false)
|
|
214
|
-
this.onExit?.(info,
|
|
214
|
+
this.onExit?.(info, from)
|
|
215
215
|
|
|
216
216
|
if (!this.getIsActive()) {
|
|
217
|
-
this.getCurrent()?.exit(info,
|
|
217
|
+
this.getCurrent()?.exit(info, from)
|
|
218
218
|
}
|
|
219
219
|
}
|
|
220
220
|
|
|
@@ -18,10 +18,6 @@ export interface TLEventMap {
|
|
|
18
18
|
frame: [number]
|
|
19
19
|
'select-all-text': [{ shapeId: TLShapeId }]
|
|
20
20
|
'place-caret': [{ shapeId: TLShapeId; point: { x: number; y: number } }]
|
|
21
|
-
'created-shapes': [TLRecord[]]
|
|
22
|
-
'edited-shapes': [TLRecord[]]
|
|
23
|
-
'deleted-shapes': [TLShapeId[]]
|
|
24
|
-
edit: []
|
|
25
21
|
}
|
|
26
22
|
|
|
27
23
|
/** @public */
|
|
@@ -44,7 +44,6 @@ export const Geometry2dFilters: {
|
|
|
44
44
|
/** @public */
|
|
45
45
|
export interface TransformedGeometry2dOptions {
|
|
46
46
|
isLabel?: boolean
|
|
47
|
-
isEmptyLabel?: boolean
|
|
48
47
|
isInternal?: boolean
|
|
49
48
|
debugColor?: string
|
|
50
49
|
ignore?: boolean
|
|
@@ -58,24 +57,20 @@ export interface Geometry2dOptions extends TransformedGeometry2dOptions {
|
|
|
58
57
|
|
|
59
58
|
/** @public */
|
|
60
59
|
export abstract class Geometry2d {
|
|
61
|
-
// todo: consider making accessors for these too, so that they can be overridden in subclasses by geometries with more complex logic
|
|
62
60
|
isFilled = false
|
|
63
61
|
isClosed = true
|
|
64
62
|
isLabel = false
|
|
65
|
-
isEmptyLabel = false
|
|
66
63
|
isInternal = false
|
|
67
64
|
debugColor?: string
|
|
68
65
|
ignore?: boolean
|
|
69
66
|
|
|
70
67
|
constructor(opts: Geometry2dOptions) {
|
|
71
|
-
const { isLabel = false, isEmptyLabel = false, isInternal = false } = opts
|
|
72
68
|
this.isFilled = opts.isFilled
|
|
73
69
|
this.isClosed = opts.isClosed
|
|
70
|
+
this.isLabel = opts.isLabel ?? false
|
|
71
|
+
this.isInternal = opts.isInternal ?? false
|
|
74
72
|
this.debugColor = opts.debugColor
|
|
75
73
|
this.ignore = opts.ignore
|
|
76
|
-
this.isLabel = isLabel
|
|
77
|
-
this.isEmptyLabel = isEmptyLabel
|
|
78
|
-
this.isInternal = isInternal
|
|
79
74
|
}
|
|
80
75
|
|
|
81
76
|
isExcludedByFilter(filters?: Geometry2dFilters) {
|
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 = '3.14.0-canary.
|
|
4
|
+
export const version = '3.14.0-canary.718fcc03811e'
|
|
5
5
|
export const publishDates = {
|
|
6
6
|
major: '2024-09-13T14:36:29.063Z',
|
|
7
|
-
minor: '2025-06-
|
|
8
|
-
patch: '2025-06-
|
|
7
|
+
minor: '2025-06-18T12:23:40.139Z',
|
|
8
|
+
patch: '2025-06-18T12:23:40.139Z',
|
|
9
9
|
}
|
|
@@ -1,232 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
var __export = (target, all) => {
|
|
7
|
-
for (var name in all)
|
|
8
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
-
};
|
|
10
|
-
var __copyProps = (to, from, except, desc) => {
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
-
for (let key of __getOwnPropNames(from))
|
|
13
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
-
}
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
-
var reparenting_exports = {};
|
|
20
|
-
__export(reparenting_exports, {
|
|
21
|
-
doesGeometryOverlapPolygon: () => doesGeometryOverlapPolygon,
|
|
22
|
-
getDroppedShapesToNewParents: () => getDroppedShapesToNewParents,
|
|
23
|
-
kickoutOccludedShapes: () => kickoutOccludedShapes
|
|
24
|
-
});
|
|
25
|
-
module.exports = __toCommonJS(reparenting_exports);
|
|
26
|
-
var import_state = require("@tldraw/state");
|
|
27
|
-
var import_utils = require("@tldraw/utils");
|
|
28
|
-
var import_Group2d = require("../primitives/geometry/Group2d");
|
|
29
|
-
var import_intersect = require("../primitives/intersect");
|
|
30
|
-
var import_utils2 = require("../primitives/utils");
|
|
31
|
-
function kickoutOccludedShapes(editor, shapeIds, opts) {
|
|
32
|
-
const parentsToCheck = /* @__PURE__ */ new Set();
|
|
33
|
-
for (const id of shapeIds) {
|
|
34
|
-
const shape = editor.getShape(id);
|
|
35
|
-
if (!shape) continue;
|
|
36
|
-
parentsToCheck.add(shape);
|
|
37
|
-
const parent = editor.getShape(shape.parentId);
|
|
38
|
-
if (!parent) continue;
|
|
39
|
-
parentsToCheck.add(parent);
|
|
40
|
-
}
|
|
41
|
-
const parentsToLostChildren = /* @__PURE__ */ new Map();
|
|
42
|
-
for (const parent of parentsToCheck) {
|
|
43
|
-
const childIds = editor.getSortedChildIdsForParent(parent);
|
|
44
|
-
if (opts?.filter && !opts.filter(parent)) {
|
|
45
|
-
parentsToLostChildren.set(parent, childIds);
|
|
46
|
-
} else {
|
|
47
|
-
const overlappingChildren = getOverlappingShapes(editor, parent.id, childIds);
|
|
48
|
-
if (overlappingChildren.length < childIds.length) {
|
|
49
|
-
parentsToLostChildren.set(
|
|
50
|
-
parent,
|
|
51
|
-
childIds.filter((id) => !overlappingChildren.includes(id))
|
|
52
|
-
);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
const sortedShapeIds = editor.getCurrentPageShapesSorted().map((s) => s.id);
|
|
57
|
-
const parentsToNewChildren = {};
|
|
58
|
-
for (const [prevParent, lostChildrenIds] of parentsToLostChildren) {
|
|
59
|
-
const lostChildren = (0, import_utils.compact)(lostChildrenIds.map((id) => editor.getShape(id)));
|
|
60
|
-
const { reparenting, remainingShapesToReparent } = getDroppedShapesToNewParents(
|
|
61
|
-
editor,
|
|
62
|
-
lostChildren,
|
|
63
|
-
(shape, maybeNewParent) => {
|
|
64
|
-
if (opts?.filter && !opts.filter(maybeNewParent)) return false;
|
|
65
|
-
return maybeNewParent.id !== prevParent.id && sortedShapeIds.indexOf(maybeNewParent.id) < sortedShapeIds.indexOf(shape.id);
|
|
66
|
-
}
|
|
67
|
-
);
|
|
68
|
-
reparenting.forEach((childrenToReparent, newParentId) => {
|
|
69
|
-
if (childrenToReparent.length === 0) return;
|
|
70
|
-
if (!parentsToNewChildren[newParentId]) {
|
|
71
|
-
parentsToNewChildren[newParentId] = {
|
|
72
|
-
parentId: newParentId,
|
|
73
|
-
shapeIds: []
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
parentsToNewChildren[newParentId].shapeIds.push(...childrenToReparent.map((s) => s.id));
|
|
77
|
-
});
|
|
78
|
-
if (remainingShapesToReparent.size > 0) {
|
|
79
|
-
const newParentId = editor.findShapeAncestor(prevParent, (s) => editor.isShapeOfType(s, "group"))?.id ?? editor.getCurrentPageId();
|
|
80
|
-
remainingShapesToReparent.forEach((shape) => {
|
|
81
|
-
if (!parentsToNewChildren[newParentId]) {
|
|
82
|
-
let insertIndexKey;
|
|
83
|
-
const oldParentSiblingIds = editor.getSortedChildIdsForParent(newParentId);
|
|
84
|
-
const oldParentIndex = oldParentSiblingIds.indexOf(prevParent.id);
|
|
85
|
-
if (oldParentIndex > -1) {
|
|
86
|
-
const siblingsIndexAbove = oldParentSiblingIds[oldParentIndex + 1];
|
|
87
|
-
const indexKeyAbove = siblingsIndexAbove ? editor.getShape(siblingsIndexAbove).index : (0, import_utils.getIndexAbove)(prevParent.index);
|
|
88
|
-
insertIndexKey = (0, import_utils.getIndexBetween)(prevParent.index, indexKeyAbove);
|
|
89
|
-
} else {
|
|
90
|
-
}
|
|
91
|
-
parentsToNewChildren[newParentId] = {
|
|
92
|
-
parentId: newParentId,
|
|
93
|
-
shapeIds: [],
|
|
94
|
-
index: insertIndexKey
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
parentsToNewChildren[newParentId].shapeIds.push(shape.id);
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
editor.run(() => {
|
|
102
|
-
Object.values(parentsToNewChildren).forEach(({ parentId, shapeIds: shapeIds2, index }) => {
|
|
103
|
-
if (shapeIds2.length === 0) return;
|
|
104
|
-
shapeIds2.sort((a, b) => sortedShapeIds.indexOf(a) < sortedShapeIds.indexOf(b) ? -1 : 1);
|
|
105
|
-
editor.reparentShapes(shapeIds2, parentId, index);
|
|
106
|
-
});
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
function getOverlappingShapes(editor, shape, otherShapes) {
|
|
110
|
-
if (otherShapes.length === 0) {
|
|
111
|
-
return import_state.EMPTY_ARRAY;
|
|
112
|
-
}
|
|
113
|
-
const parentPageBounds = editor.getShapePageBounds(shape);
|
|
114
|
-
if (!parentPageBounds) return import_state.EMPTY_ARRAY;
|
|
115
|
-
const parentGeometry = editor.getShapeGeometry(shape);
|
|
116
|
-
const parentPageTransform = editor.getShapePageTransform(shape);
|
|
117
|
-
const parentPageCorners = parentPageTransform.applyToPoints(parentGeometry.vertices);
|
|
118
|
-
const parentPageMaskVertices = editor.getShapeMask(shape);
|
|
119
|
-
const parentPagePolygon = parentPageMaskVertices ? (0, import_intersect.intersectPolygonPolygon)(parentPageMaskVertices, parentPageCorners) : parentPageCorners;
|
|
120
|
-
if (!parentPagePolygon) return import_state.EMPTY_ARRAY;
|
|
121
|
-
return otherShapes.filter((childId) => {
|
|
122
|
-
const shapePageBounds = editor.getShapePageBounds(childId);
|
|
123
|
-
if (!shapePageBounds || !parentPageBounds.includes(shapePageBounds)) return false;
|
|
124
|
-
const parentPolygonInShapeShape = editor.getShapePageTransform(childId).clone().invert().applyToPoints(parentPagePolygon);
|
|
125
|
-
const geometry = editor.getShapeGeometry(childId);
|
|
126
|
-
return doesGeometryOverlapPolygon(geometry, parentPolygonInShapeShape);
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
function doesGeometryOverlapPolygon(geometry, parentCornersInShapeSpace) {
|
|
130
|
-
if (geometry instanceof import_Group2d.Group2d) {
|
|
131
|
-
return geometry.children.some(
|
|
132
|
-
(childGeometry) => doesGeometryOverlapPolygon(childGeometry, parentCornersInShapeSpace)
|
|
133
|
-
);
|
|
134
|
-
}
|
|
135
|
-
const { vertices, center, isFilled, isEmptyLabel, isClosed } = geometry;
|
|
136
|
-
if (isEmptyLabel) return false;
|
|
137
|
-
if (vertices.some((v) => (0, import_utils2.pointInPolygon)(v, parentCornersInShapeSpace))) {
|
|
138
|
-
return true;
|
|
139
|
-
}
|
|
140
|
-
if (isClosed) {
|
|
141
|
-
if (isFilled) {
|
|
142
|
-
if ((0, import_utils2.pointInPolygon)(center, parentCornersInShapeSpace)) {
|
|
143
|
-
return true;
|
|
144
|
-
}
|
|
145
|
-
if (parentCornersInShapeSpace.every((v) => (0, import_utils2.pointInPolygon)(v, vertices))) {
|
|
146
|
-
return true;
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
if ((0, import_intersect.polygonsIntersect)(parentCornersInShapeSpace, vertices)) {
|
|
150
|
-
return true;
|
|
151
|
-
}
|
|
152
|
-
} else {
|
|
153
|
-
if ((0, import_intersect.polygonIntersectsPolyline)(parentCornersInShapeSpace, vertices)) {
|
|
154
|
-
return true;
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
return false;
|
|
158
|
-
}
|
|
159
|
-
function getDroppedShapesToNewParents(editor, shapes, cb) {
|
|
160
|
-
const shapesToActuallyCheck = new Set(shapes);
|
|
161
|
-
const movingGroups = /* @__PURE__ */ new Set();
|
|
162
|
-
for (const shape of shapes) {
|
|
163
|
-
const parent = editor.getShapeParent(shape);
|
|
164
|
-
if (parent && editor.isShapeOfType(parent, "group")) {
|
|
165
|
-
if (!movingGroups.has(parent)) {
|
|
166
|
-
movingGroups.add(parent);
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
for (const movingGroup of movingGroups) {
|
|
171
|
-
const children = (0, import_utils.compact)(
|
|
172
|
-
editor.getSortedChildIdsForParent(movingGroup).map((id) => editor.getShape(id))
|
|
173
|
-
);
|
|
174
|
-
for (const child of children) {
|
|
175
|
-
shapesToActuallyCheck.delete(child);
|
|
176
|
-
}
|
|
177
|
-
shapesToActuallyCheck.add(movingGroup);
|
|
178
|
-
}
|
|
179
|
-
const shapeGroupIds = /* @__PURE__ */ new Map();
|
|
180
|
-
const reparenting = /* @__PURE__ */ new Map();
|
|
181
|
-
const remainingShapesToReparent = new Set(shapesToActuallyCheck);
|
|
182
|
-
const potentialParentShapes = editor.getCurrentPageShapesSorted().filter(
|
|
183
|
-
(s) => editor.getShapeUtil(s).canReceiveNewChildrenOfType?.(s, s.type) && !remainingShapesToReparent.has(s)
|
|
184
|
-
);
|
|
185
|
-
parentCheck: for (let i = potentialParentShapes.length - 1; i >= 0; i--) {
|
|
186
|
-
const parentShape = potentialParentShapes[i];
|
|
187
|
-
const parentShapeContainingGroupId = editor.findShapeAncestor(
|
|
188
|
-
parentShape,
|
|
189
|
-
(s) => editor.isShapeOfType(s, "group")
|
|
190
|
-
)?.id;
|
|
191
|
-
const parentGeometry = editor.getShapeGeometry(parentShape);
|
|
192
|
-
const parentPageTransform = editor.getShapePageTransform(parentShape);
|
|
193
|
-
const parentPageMaskVertices = editor.getShapeMask(parentShape);
|
|
194
|
-
const parentPageCorners = parentPageTransform.applyToPoints(parentGeometry.vertices);
|
|
195
|
-
const parentPagePolygon = parentPageMaskVertices ? (0, import_intersect.intersectPolygonPolygon)(parentPageMaskVertices, parentPageCorners) : parentPageCorners;
|
|
196
|
-
if (!parentPagePolygon) continue parentCheck;
|
|
197
|
-
const childrenToReparent = [];
|
|
198
|
-
shapeCheck: for (const shape of remainingShapesToReparent) {
|
|
199
|
-
if (parentShape.id === shape.id) continue shapeCheck;
|
|
200
|
-
if (cb && !cb(shape, parentShape)) continue shapeCheck;
|
|
201
|
-
if (!shapeGroupIds.has(shape.id)) {
|
|
202
|
-
shapeGroupIds.set(
|
|
203
|
-
shape.id,
|
|
204
|
-
editor.findShapeAncestor(shape, (s) => editor.isShapeOfType(s, "group"))?.id
|
|
205
|
-
);
|
|
206
|
-
}
|
|
207
|
-
const shapeGroupId = shapeGroupIds.get(shape.id);
|
|
208
|
-
if (shapeGroupId !== parentShapeContainingGroupId) continue shapeCheck;
|
|
209
|
-
if (editor.findShapeAncestor(parentShape, (s) => shape.id === s.id)) continue shapeCheck;
|
|
210
|
-
const parentPolygonInShapeSpace = editor.getShapePageTransform(shape).clone().invert().applyToPoints(parentPagePolygon);
|
|
211
|
-
if (doesGeometryOverlapPolygon(editor.getShapeGeometry(shape), parentPolygonInShapeSpace)) {
|
|
212
|
-
if (!editor.getShapeUtil(parentShape).canReceiveNewChildrenOfType?.(parentShape, shape.type))
|
|
213
|
-
continue shapeCheck;
|
|
214
|
-
if (shape.parentId !== parentShape.id) {
|
|
215
|
-
childrenToReparent.push(shape);
|
|
216
|
-
}
|
|
217
|
-
remainingShapesToReparent.delete(shape);
|
|
218
|
-
continue shapeCheck;
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
if (childrenToReparent.length) {
|
|
222
|
-
reparenting.set(parentShape.id, childrenToReparent);
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
return {
|
|
226
|
-
// these are the shapes that will be reparented to new parents
|
|
227
|
-
reparenting,
|
|
228
|
-
// these are the shapes that will be reparented to the page or their ancestral group
|
|
229
|
-
remainingShapesToReparent
|
|
230
|
-
};
|
|
231
|
-
}
|
|
232
|
-
//# sourceMappingURL=reparenting.js.map
|