@tldraw/editor 4.3.0-canary.da35795ba8e2 → 4.3.0-canary.e52fa5385f86
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 +70 -35
- package/dist-cjs/index.js +2 -1
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
- package/dist-cjs/lib/editor/Editor.js +24 -12
- package/dist-cjs/lib/editor/Editor.js.map +2 -2
- package/dist-cjs/lib/editor/bindings/BindingUtil.js.map +2 -2
- package/dist-cjs/lib/editor/derivations/bindingsIndex.js.map +2 -2
- package/dist-cjs/lib/editor/managers/SnapManager/SnapManager.js.map +2 -2
- package/dist-cjs/lib/editor/shapes/BaseBoxShapeUtil.js.map +1 -1
- package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
- package/dist-cjs/lib/editor/shapes/group/GroupShapeUtil.js.map +2 -2
- package/dist-cjs/lib/editor/tools/BaseBoxShapeTool/BaseBoxShapeTool.js.map +2 -2
- package/dist-cjs/lib/editor/tools/BaseBoxShapeTool/children/Pointing.js.map +2 -2
- package/dist-cjs/lib/editor/types/emit-types.js.map +1 -1
- package/dist-cjs/lib/exports/getSvgJsx.js.map +2 -2
- package/dist-cjs/lib/globals/environment.js +45 -9
- package/dist-cjs/lib/globals/environment.js.map +2 -2
- package/dist-cjs/lib/globals/menus.js +1 -1
- package/dist-cjs/lib/globals/menus.js.map +2 -2
- package/dist-cjs/lib/hooks/useCoarsePointer.js +14 -29
- package/dist-cjs/lib/hooks/useCoarsePointer.js.map +2 -2
- package/dist-cjs/lib/utils/reparenting.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 +70 -35
- package/dist-esm/index.mjs +3 -2
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
- package/dist-esm/lib/editor/Editor.mjs +24 -12
- package/dist-esm/lib/editor/Editor.mjs.map +2 -2
- package/dist-esm/lib/editor/bindings/BindingUtil.mjs.map +2 -2
- package/dist-esm/lib/editor/derivations/bindingsIndex.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/SnapManager/SnapManager.mjs.map +2 -2
- package/dist-esm/lib/editor/shapes/BaseBoxShapeUtil.mjs.map +1 -1
- package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/editor/shapes/group/GroupShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/editor/tools/BaseBoxShapeTool/BaseBoxShapeTool.mjs.map +2 -2
- package/dist-esm/lib/editor/tools/BaseBoxShapeTool/children/Pointing.mjs.map +2 -2
- package/dist-esm/lib/exports/getSvgJsx.mjs.map +2 -2
- package/dist-esm/lib/globals/environment.mjs +45 -9
- package/dist-esm/lib/globals/environment.mjs.map +2 -2
- package/dist-esm/lib/globals/menus.mjs +1 -1
- package/dist-esm/lib/globals/menus.mjs.map +2 -2
- package/dist-esm/lib/hooks/useCoarsePointer.mjs +15 -30
- package/dist-esm/lib/hooks/useCoarsePointer.mjs.map +2 -2
- package/dist-esm/lib/utils/reparenting.mjs.map +2 -2
- package/dist-esm/version.mjs +3 -3
- package/dist-esm/version.mjs.map +1 -1
- package/package.json +10 -10
- package/src/index.ts +1 -1
- package/src/lib/components/default-components/DefaultCanvas.tsx +1 -0
- package/src/lib/editor/Editor.test.ts +10 -10
- package/src/lib/editor/Editor.ts +110 -59
- package/src/lib/editor/bindings/BindingUtil.ts +15 -9
- package/src/lib/editor/derivations/bindingsIndex.ts +2 -2
- package/src/lib/editor/managers/FontManager/FontManager.test.ts +14 -4
- package/src/lib/editor/managers/SnapManager/SnapManager.ts +3 -3
- package/src/lib/editor/shapes/BaseBoxShapeUtil.tsx +2 -2
- package/src/lib/editor/shapes/ShapeUtil.ts +5 -8
- package/src/lib/editor/shapes/group/GroupShapeUtil.tsx +1 -3
- package/src/lib/editor/tools/BaseBoxShapeTool/BaseBoxShapeTool.ts +2 -1
- package/src/lib/editor/tools/BaseBoxShapeTool/children/Pointing.ts +3 -3
- package/src/lib/editor/types/emit-types.ts +3 -1
- package/src/lib/exports/getSvgJsx.test.ts +10 -19
- package/src/lib/exports/getSvgJsx.tsx +2 -5
- package/src/lib/globals/environment.ts +65 -10
- package/src/lib/globals/menus.ts +1 -1
- package/src/lib/hooks/useCoarsePointer.ts +16 -59
- package/src/lib/utils/reparenting.ts +5 -5
- package/src/version.ts +3 -3
package/src/lib/editor/Editor.ts
CHANGED
|
@@ -21,7 +21,6 @@ import {
|
|
|
21
21
|
PageRecordType,
|
|
22
22
|
StyleProp,
|
|
23
23
|
StylePropValue,
|
|
24
|
-
TLArrowShape,
|
|
25
24
|
TLAsset,
|
|
26
25
|
TLAssetId,
|
|
27
26
|
TLAssetPartial,
|
|
@@ -30,12 +29,12 @@ import {
|
|
|
30
29
|
TLBindingId,
|
|
31
30
|
TLBindingUpdate,
|
|
32
31
|
TLCamera,
|
|
32
|
+
TLCreateShapePartial,
|
|
33
33
|
TLCursor,
|
|
34
34
|
TLCursorType,
|
|
35
35
|
TLDOCUMENT_ID,
|
|
36
36
|
TLDocument,
|
|
37
37
|
TLFrameShape,
|
|
38
|
-
TLGeoShape,
|
|
39
38
|
TLGroupShape,
|
|
40
39
|
TLHandle,
|
|
41
40
|
TLINSTANCE_ID,
|
|
@@ -43,7 +42,6 @@ import {
|
|
|
43
42
|
TLInstance,
|
|
44
43
|
TLInstancePageState,
|
|
45
44
|
TLInstancePresence,
|
|
46
|
-
TLNoteShape,
|
|
47
45
|
TLPOINTER_ID,
|
|
48
46
|
TLPage,
|
|
49
47
|
TLPageId,
|
|
@@ -54,8 +52,6 @@ import {
|
|
|
54
52
|
TLShapePartial,
|
|
55
53
|
TLStore,
|
|
56
54
|
TLStoreSnapshot,
|
|
57
|
-
TLUnknownBinding,
|
|
58
|
-
TLUnknownShape,
|
|
59
55
|
TLVideoAsset,
|
|
60
56
|
createBindingId,
|
|
61
57
|
createShapeId,
|
|
@@ -447,7 +443,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
447
443
|
let deletedBindings = new Map<TLBindingId, BindingOnDeleteOptions<any>>()
|
|
448
444
|
const deletedShapeIds = new Set<TLShapeId>()
|
|
449
445
|
const invalidParents = new Set<TLShapeId>()
|
|
450
|
-
let invalidBindingTypes = new Set<
|
|
446
|
+
let invalidBindingTypes = new Set<TLBinding['type']>()
|
|
451
447
|
this.disposables.add(
|
|
452
448
|
this.sideEffects.registerOperationCompleteHandler(() => {
|
|
453
449
|
// this needs to be cleared here because further effects may delete more shapes
|
|
@@ -710,7 +706,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
710
706
|
if (filtered.length > 0) {
|
|
711
707
|
const commonGroupAncestor = this.findCommonAncestor(
|
|
712
708
|
compact(filtered.map((id) => this.getShape(id))),
|
|
713
|
-
(shape) => this.isShapeOfType
|
|
709
|
+
(shape) => this.isShapeOfType(shape, 'group')
|
|
714
710
|
)
|
|
715
711
|
|
|
716
712
|
if (commonGroupAncestor) {
|
|
@@ -973,6 +969,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
973
969
|
this.disposables.clear()
|
|
974
970
|
this.store.dispose()
|
|
975
971
|
this.isDisposed = true
|
|
972
|
+
this.emit('dispose')
|
|
976
973
|
}
|
|
977
974
|
|
|
978
975
|
/* ------------------- Shape Utils ------------------ */
|
|
@@ -982,7 +979,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
982
979
|
*
|
|
983
980
|
* @public
|
|
984
981
|
*/
|
|
985
|
-
shapeUtils: { readonly [K in string]?: ShapeUtil<
|
|
982
|
+
shapeUtils: { readonly [K in string]?: ShapeUtil<TLShape> }
|
|
986
983
|
|
|
987
984
|
styleProps: { [key: string]: Map<StyleProp<any>, string> }
|
|
988
985
|
|
|
@@ -1001,8 +998,8 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
1001
998
|
*
|
|
1002
999
|
* @public
|
|
1003
1000
|
*/
|
|
1004
|
-
getShapeUtil<
|
|
1005
|
-
getShapeUtil<S extends
|
|
1001
|
+
getShapeUtil<K extends TLShape['type']>(type: K): ShapeUtil<Extract<TLShape, { type: K }>>
|
|
1002
|
+
getShapeUtil<S extends TLShape>(shape: S | TLShapePartial<S> | S['type']): ShapeUtil<S>
|
|
1006
1003
|
getShapeUtil<T extends ShapeUtil>(type: T extends ShapeUtil<infer R> ? R['type'] : string): T
|
|
1007
1004
|
getShapeUtil(arg: string | { type: string }) {
|
|
1008
1005
|
const type = typeof arg === 'string' ? arg : arg.type
|
|
@@ -1016,8 +1013,8 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
1016
1013
|
*
|
|
1017
1014
|
* @param shape - A shape, shape partial, or shape type.
|
|
1018
1015
|
*/
|
|
1019
|
-
hasShapeUtil
|
|
1020
|
-
hasShapeUtil
|
|
1016
|
+
hasShapeUtil(shape: TLShape | TLShapePartial<TLShape>): boolean
|
|
1017
|
+
hasShapeUtil(type: TLShape['type']): boolean
|
|
1021
1018
|
hasShapeUtil<T extends ShapeUtil>(
|
|
1022
1019
|
type: T extends ShapeUtil<infer R> ? R['type'] : string
|
|
1023
1020
|
): boolean
|
|
@@ -1032,7 +1029,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
1032
1029
|
*
|
|
1033
1030
|
* @public
|
|
1034
1031
|
*/
|
|
1035
|
-
bindingUtils: { readonly [K in string]?: BindingUtil<
|
|
1032
|
+
bindingUtils: { readonly [K in string]?: BindingUtil<TLBinding> }
|
|
1036
1033
|
|
|
1037
1034
|
/**
|
|
1038
1035
|
* Get a binding util from a binding itself.
|
|
@@ -1049,8 +1046,8 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
1049
1046
|
*
|
|
1050
1047
|
* @public
|
|
1051
1048
|
*/
|
|
1052
|
-
getBindingUtil<
|
|
1053
|
-
getBindingUtil<S extends
|
|
1049
|
+
getBindingUtil<K extends TLBinding['type']>(type: K): BindingUtil<Extract<TLBinding, { type: K }>>
|
|
1050
|
+
getBindingUtil<S extends TLBinding>(binding: S | { type: S['type'] }): BindingUtil<S>
|
|
1054
1051
|
getBindingUtil<T extends BindingUtil>(
|
|
1055
1052
|
type: T extends BindingUtil<infer R> ? R['type'] : string
|
|
1056
1053
|
): T
|
|
@@ -2220,7 +2217,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
2220
2217
|
throw Error(`Editor.setFocusedGroup: Shape with id ${id} does not exist`)
|
|
2221
2218
|
}
|
|
2222
2219
|
|
|
2223
|
-
if (!this.isShapeOfType
|
|
2220
|
+
if (!this.isShapeOfType(shape, 'group')) {
|
|
2224
2221
|
throw Error(
|
|
2225
2222
|
`Editor.setFocusedGroup: Cannot set focused group to shape of type ${shape.type}`
|
|
2226
2223
|
)
|
|
@@ -2248,7 +2245,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
2248
2245
|
if (focusedGroup) {
|
|
2249
2246
|
// If we have a focused layer, look for an ancestor of the focused shape that is a group
|
|
2250
2247
|
const match = this.findShapeAncestor(focusedGroup, (shape) =>
|
|
2251
|
-
this.isShapeOfType
|
|
2248
|
+
this.isShapeOfType(shape, 'group')
|
|
2252
2249
|
)
|
|
2253
2250
|
// If we have an ancestor that can become a focused layer, set it as the focused layer
|
|
2254
2251
|
this.setFocusedGroup(match?.id ?? null)
|
|
@@ -3635,16 +3632,19 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
3635
3632
|
if (_willSetInitialBounds) {
|
|
3636
3633
|
// If we have just received the initial bounds, don't center the camera.
|
|
3637
3634
|
this.updateInstanceState({ screenBounds: screenBounds.toJson(), insets })
|
|
3635
|
+
this.emit('resize', screenBounds.toJson())
|
|
3638
3636
|
this.setCamera(this.getCamera())
|
|
3639
3637
|
} else {
|
|
3640
3638
|
if (center && !this.getInstanceState().followingUserId) {
|
|
3641
3639
|
// Get the page center before the change, make the change, and restore it
|
|
3642
3640
|
const before = this.getViewportPageBounds().center
|
|
3643
3641
|
this.updateInstanceState({ screenBounds: screenBounds.toJson(), insets })
|
|
3642
|
+
this.emit('resize', screenBounds.toJson())
|
|
3644
3643
|
this.centerOnPoint(before)
|
|
3645
3644
|
} else {
|
|
3646
3645
|
// Otherwise,
|
|
3647
3646
|
this.updateInstanceState({ screenBounds: screenBounds.toJson(), insets })
|
|
3647
|
+
this.emit('resize', screenBounds.toJson())
|
|
3648
3648
|
this._setCamera(Vec.From({ ...this.getCamera() }))
|
|
3649
3649
|
}
|
|
3650
3650
|
}
|
|
@@ -5127,10 +5127,10 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
5127
5127
|
|
|
5128
5128
|
// Check labels first
|
|
5129
5129
|
if (
|
|
5130
|
-
this.isShapeOfType
|
|
5131
|
-
((this.isShapeOfType
|
|
5132
|
-
this.isShapeOfType
|
|
5133
|
-
(this.isShapeOfType
|
|
5130
|
+
this.isShapeOfType(shape, 'frame') ||
|
|
5131
|
+
((this.isShapeOfType(shape, 'note') ||
|
|
5132
|
+
this.isShapeOfType(shape, 'arrow') ||
|
|
5133
|
+
(this.isShapeOfType(shape, 'geo') && shape.props.fill === 'none')) &&
|
|
5134
5134
|
this.getShapeUtil(shape).getText(shape)?.trim())
|
|
5135
5135
|
) {
|
|
5136
5136
|
for (const childGeometry of (geometry as Group2d).children) {
|
|
@@ -5140,7 +5140,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
5140
5140
|
}
|
|
5141
5141
|
}
|
|
5142
5142
|
|
|
5143
|
-
if (this.isShapeOfType
|
|
5143
|
+
if (this.isShapeOfType(shape, 'frame')) {
|
|
5144
5144
|
// On the rare case that we've hit a frame (not its label), test again hitInside to be forced true;
|
|
5145
5145
|
// this prevents clicks from passing through the body of a frame to shapes behind it.
|
|
5146
5146
|
|
|
@@ -5421,7 +5421,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
5421
5421
|
*
|
|
5422
5422
|
* @example
|
|
5423
5423
|
* ```ts
|
|
5424
|
-
* const isArrowShape = isShapeOfType
|
|
5424
|
+
* const isArrowShape = isShapeOfType(someShape, 'arrow')
|
|
5425
5425
|
* ```
|
|
5426
5426
|
*
|
|
5427
5427
|
* @param util - the TLShapeUtil constructor to test against
|
|
@@ -5429,15 +5429,16 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
5429
5429
|
*
|
|
5430
5430
|
* @public
|
|
5431
5431
|
*/
|
|
5432
|
-
isShapeOfType<
|
|
5433
|
-
|
|
5434
|
-
|
|
5435
|
-
|
|
5436
|
-
|
|
5437
|
-
|
|
5438
|
-
arg: TLUnknownShape | TLUnknownShape['id'],
|
|
5432
|
+
isShapeOfType<K extends TLShape['type']>(
|
|
5433
|
+
shape: TLShape,
|
|
5434
|
+
type: K
|
|
5435
|
+
): shape is Extract<TLShape, { type: K }>
|
|
5436
|
+
isShapeOfType<T extends TLShape>(
|
|
5437
|
+
shape: TLShape,
|
|
5439
5438
|
type: T['type']
|
|
5440
|
-
) {
|
|
5439
|
+
): shape is Extract<TLShape, { type: T['type'] }>
|
|
5440
|
+
isShapeOfType<T extends TLShape = TLShape>(shapeId: TLShapeId, type: T['type']): boolean
|
|
5441
|
+
isShapeOfType(arg: TLShape | TLShapeId, type: TLShape['type']) {
|
|
5441
5442
|
const shape = typeof arg === 'string' ? this.getShape(arg) : arg
|
|
5442
5443
|
if (!shape) return false
|
|
5443
5444
|
return shape.type === type
|
|
@@ -5833,7 +5834,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
5833
5834
|
|
|
5834
5835
|
while (node) {
|
|
5835
5836
|
if (
|
|
5836
|
-
this.isShapeOfType
|
|
5837
|
+
this.isShapeOfType(node, 'group') &&
|
|
5837
5838
|
focusedGroup?.id !== node.id &&
|
|
5838
5839
|
!this.hasAncestor(focusedGroup, node.id) &&
|
|
5839
5840
|
(filter?.(node) ?? true)
|
|
@@ -5875,7 +5876,15 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
5875
5876
|
* Get all bindings of a certain type _from_ a particular shape. These are the bindings whose
|
|
5876
5877
|
* `fromId` matched the shape's ID.
|
|
5877
5878
|
*/
|
|
5878
|
-
getBindingsFromShape<
|
|
5879
|
+
getBindingsFromShape<K extends TLBinding['type']>(
|
|
5880
|
+
shape: TLShape | TLShapeId,
|
|
5881
|
+
type: K
|
|
5882
|
+
): Extract<TLBinding, { type: K }>[]
|
|
5883
|
+
getBindingsFromShape<Binding extends TLBinding = TLBinding>(
|
|
5884
|
+
shape: TLShape | TLShapeId,
|
|
5885
|
+
type: Binding['type']
|
|
5886
|
+
): Binding[]
|
|
5887
|
+
getBindingsFromShape<Binding extends TLBinding = TLBinding>(
|
|
5879
5888
|
shape: TLShape | TLShapeId,
|
|
5880
5889
|
type: Binding['type']
|
|
5881
5890
|
): Binding[] {
|
|
@@ -5889,7 +5898,15 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
5889
5898
|
* Get all bindings of a certain type _to_ a particular shape. These are the bindings whose
|
|
5890
5899
|
* `toId` matches the shape's ID.
|
|
5891
5900
|
*/
|
|
5892
|
-
getBindingsToShape<
|
|
5901
|
+
getBindingsToShape<K extends TLBinding['type']>(
|
|
5902
|
+
shape: TLShape | TLShapeId,
|
|
5903
|
+
type: K
|
|
5904
|
+
): Extract<TLBinding, { type: K }>[]
|
|
5905
|
+
getBindingsToShape<Binding extends TLBinding = TLBinding>(
|
|
5906
|
+
shape: TLShape | TLShapeId,
|
|
5907
|
+
type: Binding['type']
|
|
5908
|
+
): Binding[]
|
|
5909
|
+
getBindingsToShape<Binding extends TLBinding = TLBinding>(
|
|
5893
5910
|
shape: TLShape | TLShapeId,
|
|
5894
5911
|
type: Binding['type']
|
|
5895
5912
|
): Binding[] {
|
|
@@ -5903,7 +5920,15 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
5903
5920
|
* Get all bindings involving a particular shape. This includes bindings where the shape is the
|
|
5904
5921
|
* `fromId` or `toId`. If a type is provided, only bindings of that type are returned.
|
|
5905
5922
|
*/
|
|
5906
|
-
getBindingsInvolvingShape<
|
|
5923
|
+
getBindingsInvolvingShape<K extends TLBinding['type']>(
|
|
5924
|
+
shape: TLShape | TLShapeId,
|
|
5925
|
+
type: K
|
|
5926
|
+
): Extract<TLBinding, { type: K }>[]
|
|
5927
|
+
getBindingsInvolvingShape<Binding extends TLBinding = TLBinding>(
|
|
5928
|
+
shape: TLShape | TLShapeId,
|
|
5929
|
+
type?: Binding['type']
|
|
5930
|
+
): Binding[]
|
|
5931
|
+
getBindingsInvolvingShape<Binding extends TLBinding = TLBinding>(
|
|
5907
5932
|
shape: TLShape | TLShapeId,
|
|
5908
5933
|
type?: Binding['type']
|
|
5909
5934
|
): Binding[] {
|
|
@@ -5925,7 +5950,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
5925
5950
|
if (!fromShape || !toShape) continue
|
|
5926
5951
|
if (!this.canBindShapes({ fromShape, toShape, binding: partial })) continue
|
|
5927
5952
|
|
|
5928
|
-
const util = this.getBindingUtil
|
|
5953
|
+
const util = this.getBindingUtil(partial.type)
|
|
5929
5954
|
const defaultProps = util.getDefaultProps()
|
|
5930
5955
|
const binding = this.store.schema.types.binding.create({
|
|
5931
5956
|
...partial,
|
|
@@ -6030,7 +6055,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
6030
6055
|
const toShapeType = typeof toShape === 'string' ? toShape : toShape.type
|
|
6031
6056
|
const bindingType = typeof binding === 'string' ? binding : binding.type
|
|
6032
6057
|
|
|
6033
|
-
const canBindOpts = { fromShapeType, toShapeType, bindingType }
|
|
6058
|
+
const canBindOpts = { fromShapeType, toShapeType, bindingType } as const
|
|
6034
6059
|
|
|
6035
6060
|
if (fromShapeType === toShapeType) {
|
|
6036
6061
|
return this.getShapeUtil(fromShapeType).canBind(canBindOpts)
|
|
@@ -6571,7 +6596,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
6571
6596
|
const shapesToFlipFirstPass = compact(ids.map((id) => this.getShape(id)))
|
|
6572
6597
|
|
|
6573
6598
|
for (const shape of shapesToFlipFirstPass) {
|
|
6574
|
-
if (this.isShapeOfType
|
|
6599
|
+
if (this.isShapeOfType(shape, 'group')) {
|
|
6575
6600
|
const childrenOfGroups = compact(
|
|
6576
6601
|
this.getSortedChildIdsForParent(shape.id).map((id) => this.getShape(id))
|
|
6577
6602
|
)
|
|
@@ -7692,9 +7717,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
7692
7717
|
*
|
|
7693
7718
|
* @public
|
|
7694
7719
|
*/
|
|
7695
|
-
canCreateShape<
|
|
7696
|
-
shape: OptionalKeys<TLShapePartial<T>, 'id'> | T['id']
|
|
7697
|
-
): boolean {
|
|
7720
|
+
canCreateShape(shape: OptionalKeys<TLShapePartial<TLShape>, 'id'> | TLShape['id']): boolean {
|
|
7698
7721
|
return this.canCreateShapes([shape])
|
|
7699
7722
|
}
|
|
7700
7723
|
|
|
@@ -7705,8 +7728,8 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
7705
7728
|
*
|
|
7706
7729
|
* @public
|
|
7707
7730
|
*/
|
|
7708
|
-
canCreateShapes
|
|
7709
|
-
shapes: (
|
|
7731
|
+
canCreateShapes(
|
|
7732
|
+
shapes: (TLShape['id'] | OptionalKeys<TLShapePartial<TLShape>, 'id'>)[]
|
|
7710
7733
|
): boolean {
|
|
7711
7734
|
return shapes.length + this.getCurrentPageShapeIds().size <= this.options.maxShapesPerPage
|
|
7712
7735
|
}
|
|
@@ -7724,7 +7747,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
7724
7747
|
*
|
|
7725
7748
|
* @public
|
|
7726
7749
|
*/
|
|
7727
|
-
createShape<
|
|
7750
|
+
createShape<TShape extends TLShape>(shape: TLCreateShapePartial<TShape>): this {
|
|
7728
7751
|
this.createShapes([shape])
|
|
7729
7752
|
return this
|
|
7730
7753
|
}
|
|
@@ -7742,7 +7765,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
7742
7765
|
*
|
|
7743
7766
|
* @public
|
|
7744
7767
|
*/
|
|
7745
|
-
createShapes<
|
|
7768
|
+
createShapes<TShape extends TLShape = TLShape>(shapes: TLCreateShapePartial<TShape>[]): this {
|
|
7746
7769
|
if (!Array.isArray(shapes)) {
|
|
7747
7770
|
throw Error('Editor.createShapes: must provide an array of shapes or shape partials')
|
|
7748
7771
|
}
|
|
@@ -8123,7 +8146,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8123
8146
|
const highestIndex = shapesWithRootParent[shapesWithRootParent.length - 1]?.index
|
|
8124
8147
|
|
|
8125
8148
|
this.run(() => {
|
|
8126
|
-
this.createShapes
|
|
8149
|
+
this.createShapes([
|
|
8127
8150
|
{
|
|
8128
8151
|
id: groupId,
|
|
8129
8152
|
type: 'group',
|
|
@@ -8193,7 +8216,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8193
8216
|
const groups: TLGroupShape[] = []
|
|
8194
8217
|
|
|
8195
8218
|
shapesToUngroup.forEach((shape) => {
|
|
8196
|
-
if (this.isShapeOfType
|
|
8219
|
+
if (this.isShapeOfType(shape, 'group')) {
|
|
8197
8220
|
groups.push(shape)
|
|
8198
8221
|
} else {
|
|
8199
8222
|
idsToSelect.add(shape.id)
|
|
@@ -8239,7 +8262,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8239
8262
|
*
|
|
8240
8263
|
* @public
|
|
8241
8264
|
*/
|
|
8242
|
-
updateShape<T extends
|
|
8265
|
+
updateShape<T extends TLShape = TLShape>(partial: TLShapePartial<T> | null | undefined) {
|
|
8243
8266
|
this.updateShapes([partial])
|
|
8244
8267
|
return this
|
|
8245
8268
|
}
|
|
@@ -8256,7 +8279,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8256
8279
|
*
|
|
8257
8280
|
* @public
|
|
8258
8281
|
*/
|
|
8259
|
-
updateShapes<T extends
|
|
8282
|
+
updateShapes<T extends TLShape>(partials: (TLShapePartial<T> | null | undefined)[]) {
|
|
8260
8283
|
const compactedPartials: TLShapePartial<T>[] = Array(partials.length)
|
|
8261
8284
|
|
|
8262
8285
|
for (let i = 0, n = partials.length; i < n; i++) {
|
|
@@ -8408,7 +8431,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8408
8431
|
* @internal
|
|
8409
8432
|
*/
|
|
8410
8433
|
private _extractSharedStyles(shape: TLShape, sharedStyleMap: SharedStyleMap) {
|
|
8411
|
-
if (this.isShapeOfType
|
|
8434
|
+
if (this.isShapeOfType(shape, 'group')) {
|
|
8412
8435
|
// For groups, ignore the styles of the group shape and instead include the styles of the
|
|
8413
8436
|
// group's children. These are the shapes that would have their styles changed if the
|
|
8414
8437
|
// user called `setStyle` on the current selection.
|
|
@@ -8528,7 +8551,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8528
8551
|
// For groups, ignore the opacity of the group shape and instead include
|
|
8529
8552
|
// the opacity of the group's children. These are the shapes that would have
|
|
8530
8553
|
// their opacity changed if the user called `setOpacity` on the current selection.
|
|
8531
|
-
if (this.isShapeOfType
|
|
8554
|
+
if (this.isShapeOfType(shape, 'group')) {
|
|
8532
8555
|
for (const childId of this.getSortedChildIdsForParent(shape.id)) {
|
|
8533
8556
|
addShape(childId)
|
|
8534
8557
|
}
|
|
@@ -8589,7 +8612,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8589
8612
|
// We can have many deep levels of grouped shape
|
|
8590
8613
|
// Making a recursive function to look through all the levels
|
|
8591
8614
|
const addShapeById = (shape: TLShape) => {
|
|
8592
|
-
if (this.isShapeOfType
|
|
8615
|
+
if (this.isShapeOfType(shape, 'group')) {
|
|
8593
8616
|
const childIds = this.getSortedChildIdsForParent(shape)
|
|
8594
8617
|
for (const childId of childIds) {
|
|
8595
8618
|
addShapeById(this.getShape(childId)!)
|
|
@@ -8673,7 +8696,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8673
8696
|
// We can have many deep levels of grouped shape
|
|
8674
8697
|
// Making a recursive function to look through all the levels
|
|
8675
8698
|
const addShapeById = (shape: TLShape) => {
|
|
8676
|
-
if (this.isShapeOfType
|
|
8699
|
+
if (this.isShapeOfType(shape, 'group')) {
|
|
8677
8700
|
const childIds = this.getSortedChildIdsForParent(shape.id)
|
|
8678
8701
|
for (const childId of childIds) {
|
|
8679
8702
|
addShapeById(this.getShape(childId)!)
|
|
@@ -9098,7 +9121,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
9098
9121
|
for (const shape of this.getSelectedShapes()) {
|
|
9099
9122
|
if (lowestDepth === 0) break
|
|
9100
9123
|
|
|
9101
|
-
const isFrame = this.isShapeOfType
|
|
9124
|
+
const isFrame = this.isShapeOfType(shape, 'frame')
|
|
9102
9125
|
const ancestors = this.getShapeAncestors(shape)
|
|
9103
9126
|
if (isFrame) ancestors.push(shape)
|
|
9104
9127
|
|
|
@@ -9126,6 +9149,30 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
9126
9149
|
}
|
|
9127
9150
|
}
|
|
9128
9151
|
|
|
9152
|
+
if (point) {
|
|
9153
|
+
const shapesById = new Map<TLShapeId, TLShape>(shapes.map((shape) => [shape.id, shape]))
|
|
9154
|
+
const rootShapesFromContent = compact(rootShapeIds.map((id) => shapesById.get(id)))
|
|
9155
|
+
if (rootShapesFromContent.length > 0) {
|
|
9156
|
+
const targetParent = this.getShapeAtPoint(point, {
|
|
9157
|
+
hitInside: true,
|
|
9158
|
+
hitFrameInside: true,
|
|
9159
|
+
hitLocked: true,
|
|
9160
|
+
filter: (shape) => {
|
|
9161
|
+
const util = this.getShapeUtil(shape)
|
|
9162
|
+
if (!util.canReceiveNewChildrenOfType) return false
|
|
9163
|
+
return rootShapesFromContent.every((rootShape) =>
|
|
9164
|
+
util.canReceiveNewChildrenOfType!(shape, rootShape.type)
|
|
9165
|
+
)
|
|
9166
|
+
},
|
|
9167
|
+
})
|
|
9168
|
+
|
|
9169
|
+
// When pasting at a specific point (e.g. paste-at-cursor) prefer the
|
|
9170
|
+
// parent under the pointer so that we don't keep using the original
|
|
9171
|
+
// selection's parent (which can keep shapes clipped inside frames).
|
|
9172
|
+
pasteParentId = targetParent ? targetParent.id : currentPageId
|
|
9173
|
+
}
|
|
9174
|
+
}
|
|
9175
|
+
|
|
9129
9176
|
let isDuplicating = false
|
|
9130
9177
|
|
|
9131
9178
|
if (!isPageId(pasteParentId)) {
|
|
@@ -9137,8 +9184,8 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
9137
9184
|
if (rootShapeIds.length === 1) {
|
|
9138
9185
|
const rootShape = shapes.find((s) => s.id === rootShapeIds[0])!
|
|
9139
9186
|
if (
|
|
9140
|
-
this.isShapeOfType
|
|
9141
|
-
this.isShapeOfType
|
|
9187
|
+
this.isShapeOfType(parent, 'frame') &&
|
|
9188
|
+
this.isShapeOfType(rootShape, 'frame') &&
|
|
9142
9189
|
rootShape.props.w === parent?.props.w &&
|
|
9143
9190
|
rootShape.props.h === parent?.props.h
|
|
9144
9191
|
) {
|
|
@@ -9313,11 +9360,11 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
9313
9360
|
const onlyRoot = rootShapes[0] as TLFrameShape
|
|
9314
9361
|
// If the old bounds are in the viewport...
|
|
9315
9362
|
// todo: replace frame references with shapes that can accept children
|
|
9316
|
-
if (this.isShapeOfType
|
|
9363
|
+
if (this.isShapeOfType(onlyRoot, 'frame')) {
|
|
9317
9364
|
while (
|
|
9318
9365
|
this.getShapesAtPoint(point).some(
|
|
9319
9366
|
(shape) =>
|
|
9320
|
-
this.isShapeOfType
|
|
9367
|
+
this.isShapeOfType(shape, 'frame') &&
|
|
9321
9368
|
shape.props.w === onlyRoot.props.w &&
|
|
9322
9369
|
shape.props.h === onlyRoot.props.h
|
|
9323
9370
|
)
|
|
@@ -10233,6 +10280,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
10233
10280
|
}
|
|
10234
10281
|
|
|
10235
10282
|
this.root.handleEvent(info)
|
|
10283
|
+
this.emit('event', info)
|
|
10236
10284
|
return
|
|
10237
10285
|
}
|
|
10238
10286
|
|
|
@@ -10730,7 +10778,10 @@ function alertMaxShapes(editor: Editor, pageId = editor.getCurrentPageId()) {
|
|
|
10730
10778
|
|
|
10731
10779
|
function applyPartialToRecordWithProps<
|
|
10732
10780
|
T extends UnknownRecord & { type: string; props: object; meta: object },
|
|
10733
|
-
>(
|
|
10781
|
+
>(
|
|
10782
|
+
prev: T,
|
|
10783
|
+
partial?: T extends T ? Omit<Partial<T>, 'props'> & { props?: Partial<T['props']> } : never
|
|
10784
|
+
): T {
|
|
10734
10785
|
if (!partial) return prev
|
|
10735
10786
|
let next = null as null | T
|
|
10736
10787
|
const entries = Object.entries(partial)
|
|
@@ -1,9 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
RecordProps,
|
|
3
|
+
TLBinding,
|
|
4
|
+
TLPropsMigrations,
|
|
5
|
+
TLShape,
|
|
6
|
+
TLUnknownBinding,
|
|
7
|
+
} from '@tldraw/tlschema'
|
|
2
8
|
import { Editor } from '../Editor'
|
|
3
9
|
|
|
4
10
|
/** @public */
|
|
5
11
|
export interface TLBindingUtilConstructor<
|
|
6
|
-
T extends
|
|
12
|
+
T extends TLBinding,
|
|
7
13
|
U extends BindingUtil<T> = BindingUtil<T>,
|
|
8
14
|
> {
|
|
9
15
|
new (editor: Editor): U
|
|
@@ -20,7 +26,7 @@ export interface TLBindingUtilConstructor<
|
|
|
20
26
|
*
|
|
21
27
|
* @public
|
|
22
28
|
*/
|
|
23
|
-
export interface BindingOnCreateOptions<Binding extends
|
|
29
|
+
export interface BindingOnCreateOptions<Binding extends TLBinding = TLBinding> {
|
|
24
30
|
/** The binding being created. */
|
|
25
31
|
binding: Binding
|
|
26
32
|
}
|
|
@@ -31,7 +37,7 @@ export interface BindingOnCreateOptions<Binding extends TLUnknownBinding> {
|
|
|
31
37
|
*
|
|
32
38
|
* @public
|
|
33
39
|
*/
|
|
34
|
-
export interface BindingOnChangeOptions<Binding extends
|
|
40
|
+
export interface BindingOnChangeOptions<Binding extends TLBinding = TLBinding> {
|
|
35
41
|
/** The binding record before the change is made. */
|
|
36
42
|
bindingBefore: Binding
|
|
37
43
|
/** The binding record after the change is made. */
|
|
@@ -44,7 +50,7 @@ export interface BindingOnChangeOptions<Binding extends TLUnknownBinding> {
|
|
|
44
50
|
*
|
|
45
51
|
* @public
|
|
46
52
|
*/
|
|
47
|
-
export interface BindingOnDeleteOptions<Binding extends
|
|
53
|
+
export interface BindingOnDeleteOptions<Binding extends TLBinding = TLBinding> {
|
|
48
54
|
/** The binding being deleted. */
|
|
49
55
|
binding: Binding
|
|
50
56
|
}
|
|
@@ -55,7 +61,7 @@ export interface BindingOnDeleteOptions<Binding extends TLUnknownBinding> {
|
|
|
55
61
|
*
|
|
56
62
|
* @public
|
|
57
63
|
*/
|
|
58
|
-
export interface BindingOnShapeChangeOptions<Binding extends
|
|
64
|
+
export interface BindingOnShapeChangeOptions<Binding extends TLBinding = TLBinding> {
|
|
59
65
|
/** The binding record linking these two shapes. */
|
|
60
66
|
binding: Binding
|
|
61
67
|
/** The shape record before the change is made. */
|
|
@@ -95,7 +101,7 @@ export interface BindingOnShapeChangeOptions<Binding extends TLUnknownBinding> {
|
|
|
95
101
|
*
|
|
96
102
|
* @public
|
|
97
103
|
*/
|
|
98
|
-
export interface BindingOnShapeIsolateOptions<Binding extends
|
|
104
|
+
export interface BindingOnShapeIsolateOptions<Binding extends TLBinding = TLBinding> {
|
|
99
105
|
/** The binding record that refers to the shape in question. */
|
|
100
106
|
binding: Binding
|
|
101
107
|
/**
|
|
@@ -114,7 +120,7 @@ export interface BindingOnShapeIsolateOptions<Binding extends TLUnknownBinding>
|
|
|
114
120
|
*
|
|
115
121
|
* @public
|
|
116
122
|
*/
|
|
117
|
-
export interface BindingOnShapeDeleteOptions<Binding extends
|
|
123
|
+
export interface BindingOnShapeDeleteOptions<Binding extends TLBinding = TLBinding> {
|
|
118
124
|
/** The binding record that refers to the shape in question. */
|
|
119
125
|
binding: Binding
|
|
120
126
|
/** The shape that is about to be deleted. */
|
|
@@ -122,7 +128,7 @@ export interface BindingOnShapeDeleteOptions<Binding extends TLUnknownBinding> {
|
|
|
122
128
|
}
|
|
123
129
|
|
|
124
130
|
/** @public */
|
|
125
|
-
export abstract class BindingUtil<Binding extends
|
|
131
|
+
export abstract class BindingUtil<Binding extends TLBinding = TLBinding> {
|
|
126
132
|
constructor(public editor: Editor) {}
|
|
127
133
|
static props?: RecordProps<TLUnknownBinding>
|
|
128
134
|
static migrations?: TLPropsMigrations
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { Computed, RESET_VALUE, computed, isUninitialized } from '@tldraw/state'
|
|
2
|
-
import {
|
|
2
|
+
import { TLBinding, TLShapeId } from '@tldraw/tlschema'
|
|
3
3
|
import { objectMapValues } from '@tldraw/utils'
|
|
4
4
|
import { Editor } from '../Editor'
|
|
5
5
|
|
|
6
6
|
type TLBindingsIndex = Map<TLShapeId, TLBinding[]>
|
|
7
7
|
|
|
8
|
-
function fromScratch(bindingsQuery: Computed<
|
|
8
|
+
function fromScratch(bindingsQuery: Computed<TLBinding[], unknown>) {
|
|
9
9
|
const allBindings = bindingsQuery.get() as TLBinding[]
|
|
10
10
|
|
|
11
11
|
const shapesToBindings: TLBindingsIndex = new Map()
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { TLShape, TLShapeId, createShapeId } from '@tldraw/tlschema'
|
|
1
|
+
import { TLParentId, TLShape, TLShapeId, createShapeId, toRichText } from '@tldraw/tlschema'
|
|
2
|
+
import { IndexKey } from '@tldraw/utils'
|
|
2
3
|
import { Mock, Mocked, vi } from 'vitest'
|
|
3
4
|
import { Editor } from '../../Editor'
|
|
4
5
|
import { FontManager, TLFontFace } from './FontManager'
|
|
@@ -41,12 +42,21 @@ describe('FontManager', () => {
|
|
|
41
42
|
x: 0,
|
|
42
43
|
y: 0,
|
|
43
44
|
rotation: 0,
|
|
44
|
-
index: 'a1' as
|
|
45
|
-
parentId: 'page:page' as
|
|
45
|
+
index: 'a1' as IndexKey,
|
|
46
|
+
parentId: 'page:page' as TLParentId,
|
|
46
47
|
opacity: 1,
|
|
47
48
|
isLocked: false,
|
|
48
49
|
meta: {},
|
|
49
|
-
props: {
|
|
50
|
+
props: {
|
|
51
|
+
color: 'black',
|
|
52
|
+
size: 'xl',
|
|
53
|
+
font: 'serif',
|
|
54
|
+
textAlign: 'middle',
|
|
55
|
+
w: 100,
|
|
56
|
+
richText: toRichText('❤️'),
|
|
57
|
+
scale: 2,
|
|
58
|
+
autoSize: true,
|
|
59
|
+
},
|
|
50
60
|
typeName: 'shape' as const,
|
|
51
61
|
})
|
|
52
62
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { EMPTY_ARRAY, atom, computed } from '@tldraw/state'
|
|
2
|
-
import {
|
|
2
|
+
import { TLParentId, TLShapeId, isShapeId } from '@tldraw/tlschema'
|
|
3
3
|
import { Vec, VecLike } from '../../../primitives/Vec'
|
|
4
4
|
import type { Editor } from '../../Editor'
|
|
5
5
|
import { BoundsSnaps } from './BoundsSnaps'
|
|
@@ -72,7 +72,7 @@ export class SnapManager {
|
|
|
72
72
|
const collectSnappableShapesFromParent = (parentId: TLParentId) => {
|
|
73
73
|
if (isShapeId(parentId)) {
|
|
74
74
|
const parent = editor.getShape(parentId)
|
|
75
|
-
if (parent && editor.isShapeOfType
|
|
75
|
+
if (parent && editor.isShapeOfType(parent, 'frame')) {
|
|
76
76
|
snappableShapes.add(parentId)
|
|
77
77
|
}
|
|
78
78
|
}
|
|
@@ -89,7 +89,7 @@ export class SnapManager {
|
|
|
89
89
|
const pageBounds = editor.getShapePageBounds(childId)
|
|
90
90
|
if (!(pageBounds && renderingBounds.includes(pageBounds))) continue
|
|
91
91
|
// Snap to children of groups but not group itself
|
|
92
|
-
if (editor.isShapeOfType
|
|
92
|
+
if (editor.isShapeOfType(childShape, 'group')) {
|
|
93
93
|
collectSnappableShapesFromParent(childId)
|
|
94
94
|
continue
|
|
95
95
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ExtractShapeByProps } from '@tldraw/tlschema'
|
|
2
2
|
import { lerp } from '@tldraw/utils'
|
|
3
3
|
import { Geometry2d } from '../../primitives/geometry/Geometry2d'
|
|
4
4
|
import { Rectangle2d } from '../../primitives/geometry/Rectangle2d'
|
|
@@ -7,7 +7,7 @@ import { ShapeUtil, TLResizeInfo } from './ShapeUtil'
|
|
|
7
7
|
import { resizeBox } from './shared/resizeBox'
|
|
8
8
|
|
|
9
9
|
/** @public */
|
|
10
|
-
export type TLBaseBoxShape =
|
|
10
|
+
export type TLBaseBoxShape = ExtractShapeByProps<{ w: number; h: number }>
|
|
11
11
|
|
|
12
12
|
/** @public */
|
|
13
13
|
export abstract class BaseBoxShapeUtil<Shape extends TLBaseBoxShape> extends ShapeUtil<Shape> {
|