@tldraw/editor 3.14.0-canary.8141719daaf3 → 3.14.0-canary.8704233e0ed5
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 +133 -18
- package/dist-cjs/index.js +5 -1
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/editor/Editor.js +81 -25
- package/dist-cjs/lib/editor/Editor.js.map +2 -2
- package/dist-cjs/lib/editor/managers/HistoryManager/HistoryManager.js +3 -1
- package/dist-cjs/lib/editor/managers/HistoryManager/HistoryManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/TextManager/TextManager.js +3 -2
- package/dist-cjs/lib/editor/managers/TextManager/TextManager.js.map +2 -2
- package/dist-cjs/lib/editor/shapes/ShapeUtil.js +0 -10
- package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
- package/dist-cjs/lib/editor/tools/BaseBoxShapeTool/children/Pointing.js +13 -6
- package/dist-cjs/lib/editor/tools/BaseBoxShapeTool/children/Pointing.js.map +3 -3
- 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/editor/types/external-content.js.map +1 -1
- package/dist-cjs/lib/hooks/useCanvasEvents.js +1 -2
- package/dist-cjs/lib/hooks/useCanvasEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/useEditor.js +1 -4
- package/dist-cjs/lib/hooks/useEditor.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Geometry2d.js +6 -2
- package/dist-cjs/lib/primitives/geometry/Geometry2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Group2d.js +11 -6
- package/dist-cjs/lib/primitives/geometry/Group2d.js.map +2 -2
- package/dist-cjs/lib/utils/dom.js +1 -1
- package/dist-cjs/lib/utils/dom.js.map +2 -2
- package/dist-cjs/lib/utils/reparenting.js +232 -0
- package/dist-cjs/lib/utils/reparenting.js.map +7 -0
- package/dist-cjs/version.js +3 -3
- package/dist-cjs/version.js.map +1 -1
- package/dist-esm/index.d.mts +133 -18
- package/dist-esm/index.mjs +11 -2
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/editor/Editor.mjs +81 -25
- package/dist-esm/lib/editor/Editor.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/HistoryManager/HistoryManager.mjs +3 -1
- package/dist-esm/lib/editor/managers/HistoryManager/HistoryManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs +3 -2
- package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs.map +2 -2
- package/dist-esm/lib/editor/shapes/ShapeUtil.mjs +0 -10
- package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/editor/tools/BaseBoxShapeTool/children/Pointing.mjs +13 -6
- package/dist-esm/lib/editor/tools/BaseBoxShapeTool/children/Pointing.mjs.map +3 -3
- 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/hooks/useCanvasEvents.mjs +1 -2
- package/dist-esm/lib/hooks/useCanvasEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useEditor.mjs +1 -4
- package/dist-esm/lib/hooks/useEditor.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Geometry2d.mjs +6 -2
- package/dist-esm/lib/primitives/geometry/Geometry2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Group2d.mjs +11 -6
- package/dist-esm/lib/primitives/geometry/Group2d.mjs.map +2 -2
- package/dist-esm/lib/utils/dom.mjs +1 -1
- package/dist-esm/lib/utils/dom.mjs.map +2 -2
- package/dist-esm/lib/utils/reparenting.mjs +216 -0
- package/dist-esm/lib/utils/reparenting.mjs.map +7 -0
- package/dist-esm/version.mjs +3 -3
- package/dist-esm/version.mjs.map +1 -1
- package/editor.css +34 -12
- package/package.json +7 -7
- package/src/index.ts +13 -1
- package/src/lib/editor/Editor.ts +101 -36
- package/src/lib/editor/managers/HistoryManager/HistoryManager.ts +3 -1
- package/src/lib/editor/managers/TextManager/TextManager.ts +4 -2
- package/src/lib/editor/shapes/ShapeUtil.ts +47 -15
- package/src/lib/editor/tools/BaseBoxShapeTool/children/Pointing.ts +25 -17
- package/src/lib/editor/tools/StateNode.ts +3 -3
- package/src/lib/editor/types/emit-types.ts +4 -0
- package/src/lib/editor/types/external-content.ts +11 -2
- package/src/lib/hooks/useCanvasEvents.ts +0 -1
- package/src/lib/hooks/useEditor.tsx +6 -5
- package/src/lib/primitives/geometry/Geometry2d.ts +7 -2
- package/src/lib/primitives/geometry/Group2d.ts +11 -5
- package/src/lib/utils/dom.ts +1 -1
- package/src/lib/utils/reparenting.ts +383 -0
- package/src/version.ts +3 -3
- package/CHANGELOG.md +0 -4327
package/editor.css
CHANGED
|
@@ -176,8 +176,7 @@
|
|
|
176
176
|
--color-success: hsl(123, 46%, 34%);
|
|
177
177
|
--color-info: hsl(201, 98%, 41%);
|
|
178
178
|
--color-warning: hsl(27, 98%, 47%);
|
|
179
|
-
--color-
|
|
180
|
-
--color-warn: hsl(0, 90%, 43%);
|
|
179
|
+
--color-danger: hsl(0, 90%, 43%);
|
|
181
180
|
--color-laser: hsl(0, 100%, 50%);
|
|
182
181
|
/* Shadows */
|
|
183
182
|
--shadow-1: 0px 1px 2px hsl(0, 0%, 0%, 25%), 0px 1px 3px hsl(0, 0%, 0%, 9%);
|
|
@@ -232,8 +231,7 @@
|
|
|
232
231
|
--color-success: hsl(123, 38%, 57%);
|
|
233
232
|
--color-info: hsl(199, 92%, 56%);
|
|
234
233
|
--color-warning: hsl(36, 100%, 57%);
|
|
235
|
-
--color-
|
|
236
|
-
--color-warn: hsl(0, 81%, 66%);
|
|
234
|
+
--color-danger: hsl(0, 82%, 66%);
|
|
237
235
|
--color-laser: hsl(0, 100%, 50%);
|
|
238
236
|
/* Shadows */
|
|
239
237
|
--shadow-1:
|
|
@@ -247,6 +245,13 @@
|
|
|
247
245
|
inset 0px 0px 0px 1px var(--color-panel-contrast);
|
|
248
246
|
}
|
|
249
247
|
|
|
248
|
+
.tl-counter-scaled {
|
|
249
|
+
transform: scale(var(--tl-scale));
|
|
250
|
+
transform-origin: top left;
|
|
251
|
+
width: calc(100% * var(--tl-zoom));
|
|
252
|
+
height: calc(100% * var(--tl-zoom));
|
|
253
|
+
}
|
|
254
|
+
|
|
250
255
|
.tl-container,
|
|
251
256
|
.tl-container * {
|
|
252
257
|
-webkit-touch-callout: none;
|
|
@@ -575,6 +580,23 @@ input,
|
|
|
575
580
|
|
|
576
581
|
/* ---------------------- Text ---------------------- */
|
|
577
582
|
|
|
583
|
+
.tl-text-shape-label {
|
|
584
|
+
position: relative;
|
|
585
|
+
font-weight: normal;
|
|
586
|
+
min-width: 1px;
|
|
587
|
+
padding: 0px;
|
|
588
|
+
margin: 0px;
|
|
589
|
+
border: none;
|
|
590
|
+
width: fit-content;
|
|
591
|
+
height: fit-content;
|
|
592
|
+
font-variant: normal;
|
|
593
|
+
font-style: normal;
|
|
594
|
+
pointer-events: all;
|
|
595
|
+
white-space: pre-wrap;
|
|
596
|
+
overflow-wrap: break-word;
|
|
597
|
+
text-shadow: var(--tl-text-outline);
|
|
598
|
+
}
|
|
599
|
+
|
|
578
600
|
.tl-text-wrapper[data-font='draw'] {
|
|
579
601
|
font-family: var(--tl-font-draw);
|
|
580
602
|
}
|
|
@@ -1040,8 +1062,8 @@ input,
|
|
|
1040
1062
|
}
|
|
1041
1063
|
|
|
1042
1064
|
.tl-hyperlink__icon {
|
|
1043
|
-
width:
|
|
1044
|
-
height:
|
|
1065
|
+
width: 15px;
|
|
1066
|
+
height: 15px;
|
|
1045
1067
|
background-color: currentColor;
|
|
1046
1068
|
pointer-events: none;
|
|
1047
1069
|
}
|
|
@@ -1140,7 +1162,7 @@ input,
|
|
|
1140
1162
|
stroke-linejoin: round;
|
|
1141
1163
|
/* content-visibility: auto; */
|
|
1142
1164
|
transform-origin: top left;
|
|
1143
|
-
color:
|
|
1165
|
+
color: var(--color-text-1);
|
|
1144
1166
|
}
|
|
1145
1167
|
|
|
1146
1168
|
/* -------------------- Group shape ------------------ */
|
|
@@ -1255,6 +1277,7 @@ input,
|
|
|
1255
1277
|
display: flex;
|
|
1256
1278
|
justify-content: flex-end;
|
|
1257
1279
|
align-items: flex-start;
|
|
1280
|
+
box-shadow: inset 0px 0px 0px 1px var(--color-divider);
|
|
1258
1281
|
}
|
|
1259
1282
|
|
|
1260
1283
|
.tl-bookmark__image_container > .tl-hyperlink-button::after {
|
|
@@ -1277,7 +1300,7 @@ input,
|
|
|
1277
1300
|
}
|
|
1278
1301
|
|
|
1279
1302
|
.tl-bookmark__copy_container {
|
|
1280
|
-
background-color: var(--color-muted);
|
|
1303
|
+
background-color: var(--color-muted-0);
|
|
1281
1304
|
padding: var(--space-4);
|
|
1282
1305
|
pointer-events: all;
|
|
1283
1306
|
display: flex;
|
|
@@ -1296,11 +1319,11 @@ input,
|
|
|
1296
1319
|
|
|
1297
1320
|
.tl-bookmark__heading {
|
|
1298
1321
|
font-size: 16px;
|
|
1299
|
-
line-height: 1.
|
|
1322
|
+
line-height: 1.6;
|
|
1300
1323
|
font-weight: bold;
|
|
1301
1324
|
padding-bottom: var(--space-2);
|
|
1302
1325
|
overflow: hidden;
|
|
1303
|
-
max-height: calc((16px * 1.
|
|
1326
|
+
max-height: calc((16px * 1.6) * 2);
|
|
1304
1327
|
-webkit-box-orient: vertical;
|
|
1305
1328
|
-webkit-line-clamp: 2;
|
|
1306
1329
|
line-clamp: 2;
|
|
@@ -1381,7 +1404,6 @@ input,
|
|
|
1381
1404
|
|
|
1382
1405
|
.tl-image-container {
|
|
1383
1406
|
position: relative;
|
|
1384
|
-
overflow: hidden;
|
|
1385
1407
|
}
|
|
1386
1408
|
|
|
1387
1409
|
.tl-image {
|
|
@@ -1690,7 +1712,7 @@ it from receiving any pointer events or affecting the cursor. */
|
|
|
1690
1712
|
gap: var(--space-4);
|
|
1691
1713
|
}
|
|
1692
1714
|
.tl-error-boundary__content .tl-error-boundary__reset {
|
|
1693
|
-
color: var(--color-
|
|
1715
|
+
color: var(--color-danger);
|
|
1694
1716
|
}
|
|
1695
1717
|
.tl-error-boundary__content .tl-error-boundary__refresh {
|
|
1696
1718
|
background-color: var(--color-primary);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tldraw/editor",
|
|
3
3
|
"description": "A tiny little drawing app (editor).",
|
|
4
|
-
"version": "3.14.0-canary.
|
|
4
|
+
"version": "3.14.0-canary.8704233e0ed5",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "tldraw Inc.",
|
|
7
7
|
"email": "hello@tldraw.com"
|
|
@@ -48,12 +48,12 @@
|
|
|
48
48
|
"@tiptap/core": "^2.9.1",
|
|
49
49
|
"@tiptap/pm": "^2.9.1",
|
|
50
50
|
"@tiptap/react": "^2.9.1",
|
|
51
|
-
"@tldraw/state": "3.14.0-canary.
|
|
52
|
-
"@tldraw/state-react": "3.14.0-canary.
|
|
53
|
-
"@tldraw/store": "3.14.0-canary.
|
|
54
|
-
"@tldraw/tlschema": "3.14.0-canary.
|
|
55
|
-
"@tldraw/utils": "3.14.0-canary.
|
|
56
|
-
"@tldraw/validate": "3.14.0-canary.
|
|
51
|
+
"@tldraw/state": "3.14.0-canary.8704233e0ed5",
|
|
52
|
+
"@tldraw/state-react": "3.14.0-canary.8704233e0ed5",
|
|
53
|
+
"@tldraw/store": "3.14.0-canary.8704233e0ed5",
|
|
54
|
+
"@tldraw/tlschema": "3.14.0-canary.8704233e0ed5",
|
|
55
|
+
"@tldraw/utils": "3.14.0-canary.8704233e0ed5",
|
|
56
|
+
"@tldraw/validate": "3.14.0-canary.8704233e0ed5",
|
|
57
57
|
"@types/core-js": "^2.5.8",
|
|
58
58
|
"@use-gesture/react": "^10.3.1",
|
|
59
59
|
"classnames": "^2.5.1",
|
package/src/index.ts
CHANGED
|
@@ -182,6 +182,10 @@ export { BaseBoxShapeUtil, type TLBaseBoxShape } from './lib/editor/shapes/BaseB
|
|
|
182
182
|
export {
|
|
183
183
|
ShapeUtil,
|
|
184
184
|
type TLCropInfo,
|
|
185
|
+
type TLDragShapesInInfo,
|
|
186
|
+
type TLDragShapesOutInfo,
|
|
187
|
+
type TLDragShapesOverInfo,
|
|
188
|
+
type TLDropShapesOverInfo,
|
|
185
189
|
type TLGeometryOpts,
|
|
186
190
|
type TLHandleDragInfo,
|
|
187
191
|
type TLResizeInfo,
|
|
@@ -253,6 +257,7 @@ export {
|
|
|
253
257
|
type TLExternalContent,
|
|
254
258
|
type TLExternalContentSource,
|
|
255
259
|
type TLFileExternalAsset,
|
|
260
|
+
type TLFileReplaceExternalContent,
|
|
256
261
|
type TLFilesExternalContent,
|
|
257
262
|
type TLSvgTextExternalContent,
|
|
258
263
|
type TLTextExternalContent,
|
|
@@ -295,7 +300,13 @@ export {
|
|
|
295
300
|
type ContainerProviderProps,
|
|
296
301
|
} from './lib/hooks/useContainer'
|
|
297
302
|
export { getCursor } from './lib/hooks/useCursor'
|
|
298
|
-
export {
|
|
303
|
+
export {
|
|
304
|
+
EditorContext,
|
|
305
|
+
EditorProvider,
|
|
306
|
+
useEditor,
|
|
307
|
+
useMaybeEditor,
|
|
308
|
+
type EditorProviderProps,
|
|
309
|
+
} from './lib/hooks/useEditor'
|
|
299
310
|
export { useEditorComponents } from './lib/hooks/useEditorComponents'
|
|
300
311
|
export type { TLEditorComponents } from './lib/hooks/useEditorComponents'
|
|
301
312
|
export { useEvent, useReactiveEvent } from './lib/hooks/useEvent'
|
|
@@ -445,6 +456,7 @@ export { hardResetEditor } from './lib/utils/hardResetEditor'
|
|
|
445
456
|
export { isAccelKey } from './lib/utils/keyboard'
|
|
446
457
|
export { normalizeWheel } from './lib/utils/normalizeWheel'
|
|
447
458
|
export { refreshPage } from './lib/utils/refreshPage'
|
|
459
|
+
export { getDroppedShapesToNewParents, kickoutOccludedShapes } from './lib/utils/reparenting'
|
|
448
460
|
export {
|
|
449
461
|
getFontsFromRichText,
|
|
450
462
|
type RichTextFontVisitor,
|
package/src/lib/editor/Editor.ts
CHANGED
|
@@ -2122,6 +2122,20 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
2122
2122
|
return this.getShapesPageBounds(this.getSelectedShapeIds())
|
|
2123
2123
|
}
|
|
2124
2124
|
|
|
2125
|
+
/**
|
|
2126
|
+
* The bounds of the selection bounding box in the current page space.
|
|
2127
|
+
*
|
|
2128
|
+
* @readonly
|
|
2129
|
+
* @public
|
|
2130
|
+
*/
|
|
2131
|
+
getSelectionScreenBounds(): Box | undefined {
|
|
2132
|
+
const bounds = this.getSelectionPageBounds()
|
|
2133
|
+
if (!bounds) return undefined
|
|
2134
|
+
const { x, y } = this.pageToScreen(bounds.point)
|
|
2135
|
+
const zoom = this.getZoomLevel()
|
|
2136
|
+
return new Box(x, y, bounds.width * zoom, bounds.height * zoom)
|
|
2137
|
+
}
|
|
2138
|
+
|
|
2125
2139
|
/**
|
|
2126
2140
|
* @internal
|
|
2127
2141
|
*/
|
|
@@ -3648,7 +3662,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
3648
3662
|
* @public
|
|
3649
3663
|
*/
|
|
3650
3664
|
updateViewportScreenBounds(screenBounds: Box | HTMLElement, center = false): this {
|
|
3651
|
-
if (screenBounds instanceof
|
|
3665
|
+
if (!(screenBounds instanceof Box)) {
|
|
3652
3666
|
const rect = screenBounds.getBoundingClientRect()
|
|
3653
3667
|
screenBounds = new Box(
|
|
3654
3668
|
rect.left || rect.x,
|
|
@@ -5514,7 +5528,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
5514
5528
|
if (!id) return undefined
|
|
5515
5529
|
const freshShape = this.getShape(id)
|
|
5516
5530
|
if (freshShape === undefined || !isShapeId(freshShape.parentId)) return undefined
|
|
5517
|
-
return this.
|
|
5531
|
+
return this.getShape(freshShape.parentId)
|
|
5518
5532
|
}
|
|
5519
5533
|
|
|
5520
5534
|
/**
|
|
@@ -5697,6 +5711,10 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
5697
5711
|
const newPoint = invertedParentTransform.applyToPoint(pagePoint)
|
|
5698
5712
|
const newRotation = pageTransform.rotation() - parentPageRotation
|
|
5699
5713
|
|
|
5714
|
+
if (shape.id === parentId) {
|
|
5715
|
+
throw Error('Attempted to reparent a shape to itself!')
|
|
5716
|
+
}
|
|
5717
|
+
|
|
5700
5718
|
changes.push({
|
|
5701
5719
|
id: shape.id,
|
|
5702
5720
|
type: shape.type,
|
|
@@ -5800,6 +5818,11 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
5800
5818
|
return shapeIds
|
|
5801
5819
|
}
|
|
5802
5820
|
|
|
5821
|
+
/** @deprecated Use {@link Editor.getDraggingOverShape} instead */
|
|
5822
|
+
getDroppingOverShape(point: Vec, droppingShapes: TLShape[]): TLShape | undefined {
|
|
5823
|
+
return this.getDraggingOverShape(point, droppingShapes)
|
|
5824
|
+
}
|
|
5825
|
+
|
|
5803
5826
|
/**
|
|
5804
5827
|
* Get the shape that some shapes should be dropped on at a given point.
|
|
5805
5828
|
*
|
|
@@ -5810,35 +5833,33 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
5810
5833
|
*
|
|
5811
5834
|
* @public
|
|
5812
5835
|
*/
|
|
5813
|
-
|
|
5814
|
-
//
|
|
5815
|
-
const
|
|
5816
|
-
|
|
5817
|
-
|
|
5818
|
-
|
|
5819
|
-
if (
|
|
5820
|
-
// ignore hidden shapes
|
|
5821
|
-
this.isShapeHidden(shape) ||
|
|
5822
|
-
// don't allow dropping on selected shapes
|
|
5823
|
-
this.getSelectedShapeIds().includes(shape.id) ||
|
|
5824
|
-
// only allow shapes that can receive children
|
|
5825
|
-
!this.getShapeUtil(shape).canDropShapes(shape, droppingShapes) ||
|
|
5826
|
-
// don't allow dropping a shape on itself or one of it's children
|
|
5827
|
-
droppingShapes.find((s) => s.id === shape.id || this.hasAncestor(shape, s.id))
|
|
5828
|
-
) {
|
|
5829
|
-
continue
|
|
5830
|
-
}
|
|
5836
|
+
getDraggingOverShape(point: Vec, droppingShapes: TLShape[]): TLShape | undefined {
|
|
5837
|
+
// get fresh moving shapes
|
|
5838
|
+
const draggingShapes = compact(droppingShapes.map((s) => this.getShape(s))).filter(
|
|
5839
|
+
(s) => !s.isLocked && !this.isShapeHidden(s)
|
|
5840
|
+
)
|
|
5831
5841
|
|
|
5832
|
-
|
|
5833
|
-
|
|
5834
|
-
|
|
5842
|
+
const maybeDraggingOverShapes = this.getShapesAtPoint(point, {
|
|
5843
|
+
hitInside: true,
|
|
5844
|
+
margin: 0,
|
|
5845
|
+
}).filter(
|
|
5846
|
+
(s) =>
|
|
5847
|
+
!droppingShapes.includes(s) &&
|
|
5848
|
+
!s.isLocked &&
|
|
5849
|
+
!this.isShapeHidden(s) &&
|
|
5850
|
+
!draggingShapes.includes(s)
|
|
5851
|
+
)
|
|
5835
5852
|
|
|
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
|
|
5836
5856
|
if (
|
|
5837
|
-
|
|
5838
|
-
|
|
5839
|
-
|
|
5857
|
+
shapeUtil.onDragShapesOver ||
|
|
5858
|
+
shapeUtil.onDragShapesIn ||
|
|
5859
|
+
shapeUtil.onDragShapesOut ||
|
|
5860
|
+
shapeUtil.onDropShapesOver
|
|
5840
5861
|
) {
|
|
5841
|
-
return
|
|
5862
|
+
return maybeDraggingOverShape
|
|
5842
5863
|
}
|
|
5843
5864
|
}
|
|
5844
5865
|
}
|
|
@@ -6197,11 +6218,12 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
6197
6218
|
*/
|
|
6198
6219
|
duplicateShapes(shapes: TLShapeId[] | TLShape[], offset?: VecLike): this {
|
|
6199
6220
|
this.run(() => {
|
|
6200
|
-
const
|
|
6221
|
+
const _ids =
|
|
6201
6222
|
typeof shapes[0] === 'string'
|
|
6202
6223
|
? (shapes as TLShapeId[])
|
|
6203
6224
|
: (shapes as TLShape[]).map((s) => s.id)
|
|
6204
6225
|
|
|
6226
|
+
const ids = this._shouldIgnoreShapeLock ? _ids : this._getUnlockedShapeIds(_ids)
|
|
6205
6227
|
if (ids.length <= 0) return this
|
|
6206
6228
|
|
|
6207
6229
|
const initialIds = new Set(ids)
|
|
@@ -6281,10 +6303,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
6281
6303
|
})
|
|
6282
6304
|
const shapesToCreate = shapesToCreateWithOriginals.map(({ shape }) => shape)
|
|
6283
6305
|
|
|
6284
|
-
|
|
6285
|
-
shapesToCreate.length + this.getCurrentPageShapeIds().size > this.options.maxShapesPerPage
|
|
6286
|
-
|
|
6287
|
-
if (maxShapesReached) {
|
|
6306
|
+
if (!this.canCreateShapes(shapesToCreate)) {
|
|
6288
6307
|
alertMaxShapes(this)
|
|
6289
6308
|
return
|
|
6290
6309
|
}
|
|
@@ -7713,6 +7732,32 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
7713
7732
|
return {}
|
|
7714
7733
|
}
|
|
7715
7734
|
|
|
7735
|
+
/**
|
|
7736
|
+
* Get whether the provided shape can be created.
|
|
7737
|
+
*
|
|
7738
|
+
* @param shape - The shape or shape IDs to check.
|
|
7739
|
+
*
|
|
7740
|
+
* @public
|
|
7741
|
+
*/
|
|
7742
|
+
canCreateShape<T extends TLUnknownShape>(
|
|
7743
|
+
shape: OptionalKeys<TLShapePartial<T>, 'id'> | T['id']
|
|
7744
|
+
): boolean {
|
|
7745
|
+
return this.canCreateShapes([shape])
|
|
7746
|
+
}
|
|
7747
|
+
|
|
7748
|
+
/**
|
|
7749
|
+
* Get whether the provided shapes can be created.
|
|
7750
|
+
*
|
|
7751
|
+
* @param shapes - The shapes or shape IDs to create.
|
|
7752
|
+
*
|
|
7753
|
+
* @public
|
|
7754
|
+
*/
|
|
7755
|
+
canCreateShapes<T extends TLUnknownShape>(
|
|
7756
|
+
shapes: (T['id'] | OptionalKeys<TLShapePartial<T>, 'id'>)[]
|
|
7757
|
+
): boolean {
|
|
7758
|
+
return shapes.length + this.getCurrentPageShapeIds().size <= this.options.maxShapesPerPage
|
|
7759
|
+
}
|
|
7760
|
+
|
|
7716
7761
|
/**
|
|
7717
7762
|
* Create a single shape.
|
|
7718
7763
|
*
|
|
@@ -7759,6 +7804,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
7759
7804
|
if (maxShapesReached) {
|
|
7760
7805
|
// can't create more shapes than fit on the page
|
|
7761
7806
|
alertMaxShapes(this)
|
|
7807
|
+
// todo: throw an error here? Otherwise we'll need to check every time whether the shapes were actually created
|
|
7762
7808
|
return this
|
|
7763
7809
|
}
|
|
7764
7810
|
|
|
@@ -7791,9 +7837,10 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
7791
7837
|
|
|
7792
7838
|
for (let i = currentPageShapesSorted.length - 1; i >= 0; i--) {
|
|
7793
7839
|
const parent = currentPageShapesSorted[i]
|
|
7840
|
+
const util = this.getShapeUtil(parent)
|
|
7794
7841
|
if (
|
|
7842
|
+
util.canReceiveNewChildrenOfType(parent, partial.type) &&
|
|
7795
7843
|
!this.isShapeHidden(parent) &&
|
|
7796
|
-
this.getShapeUtil(parent).canReceiveNewChildrenOfType(parent, partial.type) &&
|
|
7797
7844
|
this.isPointInShape(
|
|
7798
7845
|
parent,
|
|
7799
7846
|
// If no parent is provided, then we can treat the
|
|
@@ -7812,7 +7859,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
7812
7859
|
|
|
7813
7860
|
const prevParentId = partial.parentId
|
|
7814
7861
|
|
|
7815
|
-
// a shape cannot be
|
|
7862
|
+
// a shape cannot be its own parent. This was a rare issue with frames/groups in the syncFuzz tests.
|
|
7816
7863
|
if (parentId === partial.id) {
|
|
7817
7864
|
parentId = focusedGroupId
|
|
7818
7865
|
}
|
|
@@ -7922,6 +7969,8 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
7922
7969
|
}
|
|
7923
7970
|
})
|
|
7924
7971
|
|
|
7972
|
+
this.emit('created-shapes', shapeRecordsToCreate)
|
|
7973
|
+
this.emit('edit')
|
|
7925
7974
|
this.store.put(shapeRecordsToCreate)
|
|
7926
7975
|
})
|
|
7927
7976
|
|
|
@@ -8316,6 +8365,8 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8316
8365
|
updates.push(updated)
|
|
8317
8366
|
}
|
|
8318
8367
|
|
|
8368
|
+
this.emit('edited-shapes', updates)
|
|
8369
|
+
this.emit('edit')
|
|
8319
8370
|
this.store.put(updates)
|
|
8320
8371
|
})
|
|
8321
8372
|
}
|
|
@@ -8365,6 +8416,8 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8365
8416
|
})
|
|
8366
8417
|
}
|
|
8367
8418
|
|
|
8419
|
+
this.emit('deleted-shapes', [...allShapeIdsToDelete])
|
|
8420
|
+
this.emit('edit')
|
|
8368
8421
|
return this.run(() => this.store.remove([...allShapeIdsToDelete]))
|
|
8369
8422
|
}
|
|
8370
8423
|
|
|
@@ -8813,6 +8866,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8813
8866
|
} = {
|
|
8814
8867
|
text: null,
|
|
8815
8868
|
files: null,
|
|
8869
|
+
'file-replace': null,
|
|
8816
8870
|
embed: null,
|
|
8817
8871
|
'svg-text': null,
|
|
8818
8872
|
url: null,
|
|
@@ -8862,6 +8916,15 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8862
8916
|
return this.externalContentHandlers[info.type]?.(info as any)
|
|
8863
8917
|
}
|
|
8864
8918
|
|
|
8919
|
+
/**
|
|
8920
|
+
* Handle replacing external content.
|
|
8921
|
+
*
|
|
8922
|
+
* @param info - Info about the external content.
|
|
8923
|
+
*/
|
|
8924
|
+
async replaceExternalContent<E>(info: TLExternalContent<E>): Promise<void> {
|
|
8925
|
+
return this.externalContentHandlers[info.type]?.(info as any)
|
|
8926
|
+
}
|
|
8927
|
+
|
|
8865
8928
|
/**
|
|
8866
8929
|
* Get content that can be exported for the given shape ids.
|
|
8867
8930
|
*
|
|
@@ -9481,6 +9544,8 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
9481
9544
|
previousPagePoint,
|
|
9482
9545
|
currentScreenPoint,
|
|
9483
9546
|
currentPagePoint,
|
|
9547
|
+
originScreenPoint,
|
|
9548
|
+
originPagePoint,
|
|
9484
9549
|
} = this.inputs
|
|
9485
9550
|
|
|
9486
9551
|
const { screenBounds } = this.store.unsafeGetWithoutCapture(TLINSTANCE_ID)!
|
|
@@ -9509,8 +9574,8 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
9509
9574
|
// Reset velocity on pointer down, or when a pinch starts or ends
|
|
9510
9575
|
if (info.name === 'pointer_down' || this.inputs.isPinching) {
|
|
9511
9576
|
pointerVelocity.set(0, 0)
|
|
9512
|
-
|
|
9513
|
-
|
|
9577
|
+
originScreenPoint.setTo(currentScreenPoint)
|
|
9578
|
+
originPagePoint.setTo(currentPagePoint)
|
|
9514
9579
|
}
|
|
9515
9580
|
|
|
9516
9581
|
// todo: We only have to do this if there are multiple users in the document
|
|
@@ -241,7 +241,9 @@ export class HistoryManager<R extends UnknownRecord> {
|
|
|
241
241
|
}
|
|
242
242
|
|
|
243
243
|
bailToMark(id: string) {
|
|
244
|
-
|
|
244
|
+
if (id) {
|
|
245
|
+
this._undo({ pushToRedoStack: false, toMark: id })
|
|
246
|
+
}
|
|
245
247
|
|
|
246
248
|
return this
|
|
247
249
|
}
|
|
@@ -26,6 +26,7 @@ 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. */
|
|
29
30
|
lineHeight: number
|
|
30
31
|
/**
|
|
31
32
|
* When maxWidth is a number, the text will be wrapped to that maxWidth. When maxWidth
|
|
@@ -75,6 +76,7 @@ export class TextManager {
|
|
|
75
76
|
// we need to save the default styles so that we can restore them when we're done
|
|
76
77
|
// these must be the css names, not the js names for the styles
|
|
77
78
|
this.defaultStyles = {
|
|
79
|
+
'overflow-wrap': 'break-word',
|
|
78
80
|
'word-break': 'auto',
|
|
79
81
|
width: null,
|
|
80
82
|
height: null,
|
|
@@ -123,7 +125,7 @@ export class TextManager {
|
|
|
123
125
|
elm.style.setProperty('font-style', opts.fontStyle)
|
|
124
126
|
elm.style.setProperty('font-weight', opts.fontWeight)
|
|
125
127
|
elm.style.setProperty('font-size', opts.fontSize + 'px')
|
|
126
|
-
elm.style.setProperty('line-height', opts.lineHeight
|
|
128
|
+
elm.style.setProperty('line-height', opts.lineHeight.toString())
|
|
127
129
|
elm.style.setProperty('padding', opts.padding)
|
|
128
130
|
|
|
129
131
|
if (opts.maxWidth) {
|
|
@@ -287,7 +289,7 @@ export class TextManager {
|
|
|
287
289
|
elm.style.setProperty('font-style', opts.fontStyle)
|
|
288
290
|
elm.style.setProperty('font-weight', opts.fontWeight)
|
|
289
291
|
elm.style.setProperty('font-size', opts.fontSize + 'px')
|
|
290
|
-
elm.style.setProperty('line-height', opts.lineHeight
|
|
292
|
+
elm.style.setProperty('line-height', opts.lineHeight.toString())
|
|
291
293
|
|
|
292
294
|
const elementWidth = Math.ceil(opts.width - opts.padding * 2)
|
|
293
295
|
elm.style.setProperty('width', `${elementWidth}px`)
|
|
@@ -4,12 +4,15 @@ import { LegacyMigrations, MigrationSequence } from '@tldraw/store'
|
|
|
4
4
|
import {
|
|
5
5
|
RecordProps,
|
|
6
6
|
TLHandle,
|
|
7
|
+
TLParentId,
|
|
7
8
|
TLPropsMigrations,
|
|
8
9
|
TLShape,
|
|
9
10
|
TLShapeCrop,
|
|
11
|
+
TLShapeId,
|
|
10
12
|
TLShapePartial,
|
|
11
13
|
TLUnknownShape,
|
|
12
14
|
} from '@tldraw/tlschema'
|
|
15
|
+
import { IndexKey } from '@tldraw/utils'
|
|
13
16
|
import { ReactElement } from 'react'
|
|
14
17
|
import { Box, SelectionHandle } from '../../primitives/Box'
|
|
15
18
|
import { Vec } from '../../primitives/Vec'
|
|
@@ -387,17 +390,6 @@ export abstract class ShapeUtil<Shape extends TLUnknownShape = TLUnknownShape> {
|
|
|
387
390
|
return false
|
|
388
391
|
}
|
|
389
392
|
|
|
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
|
-
|
|
401
393
|
/**
|
|
402
394
|
* Get the shape as an SVG object.
|
|
403
395
|
*
|
|
@@ -517,7 +509,16 @@ export abstract class ShapeUtil<Shape extends TLUnknownShape = TLUnknownShape> {
|
|
|
517
509
|
): Omit<TLShapePartial<Shape>, 'id' | 'type'> | undefined | void
|
|
518
510
|
|
|
519
511
|
/**
|
|
520
|
-
* A callback called when some other shapes are dragged
|
|
512
|
+
* A callback called when some other shapes are dragged into this one. This fires when the shapes are dragged over the shape for the first time.
|
|
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.
|
|
521
522
|
*
|
|
522
523
|
* @example
|
|
523
524
|
*
|
|
@@ -531,7 +532,7 @@ export abstract class ShapeUtil<Shape extends TLUnknownShape = TLUnknownShape> {
|
|
|
531
532
|
* @param shapes - The shapes that are being dragged over this one.
|
|
532
533
|
* @public
|
|
533
534
|
*/
|
|
534
|
-
onDragShapesOver?(shape: Shape, shapes: TLShape[]): void
|
|
535
|
+
onDragShapesOver?(shape: Shape, shapes: TLShape[], info: TLDragShapesOverInfo): void
|
|
535
536
|
|
|
536
537
|
/**
|
|
537
538
|
* A callback called when some other shapes are dragged out of this one.
|
|
@@ -540,7 +541,7 @@ export abstract class ShapeUtil<Shape extends TLUnknownShape = TLUnknownShape> {
|
|
|
540
541
|
* @param shapes - The shapes that are being dragged out.
|
|
541
542
|
* @public
|
|
542
543
|
*/
|
|
543
|
-
onDragShapesOut?(shape: Shape, shapes: TLShape[]): void
|
|
544
|
+
onDragShapesOut?(shape: Shape, shapes: TLShape[], info: TLDragShapesOutInfo): void
|
|
544
545
|
|
|
545
546
|
/**
|
|
546
547
|
* A callback called when some other shapes are dropped over this one.
|
|
@@ -549,7 +550,7 @@ export abstract class ShapeUtil<Shape extends TLUnknownShape = TLUnknownShape> {
|
|
|
549
550
|
* @param shapes - The shapes that are being dropped over this one.
|
|
550
551
|
* @public
|
|
551
552
|
*/
|
|
552
|
-
onDropShapesOver?(shape: Shape, shapes: TLShape[]): void
|
|
553
|
+
onDropShapesOver?(shape: Shape, shapes: TLShape[], info: TLDropShapesOverInfo): void
|
|
553
554
|
|
|
554
555
|
/**
|
|
555
556
|
* A callback called when a shape starts being resized.
|
|
@@ -745,6 +746,37 @@ export interface TLCropInfo<T extends TLShape> {
|
|
|
745
746
|
crop: TLShapeCrop
|
|
746
747
|
uncroppedSize: { w: number; h: number }
|
|
747
748
|
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>
|
|
748
780
|
}
|
|
749
781
|
|
|
750
782
|
/**
|
|
@@ -11,29 +11,36 @@ export class Pointing extends StateNode {
|
|
|
11
11
|
static override id = 'pointing'
|
|
12
12
|
|
|
13
13
|
override onPointerMove(info: TLPointerEventInfo) {
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
const { editor } = this
|
|
15
|
+
if (editor.inputs.isDragging) {
|
|
16
|
+
const { originPagePoint } = editor.inputs
|
|
16
17
|
|
|
17
18
|
const shapeType = (this.parent as BaseBoxShapeTool)!.shapeType
|
|
18
19
|
|
|
19
20
|
const id = createShapeId()
|
|
20
21
|
|
|
21
|
-
const creatingMarkId =
|
|
22
|
-
const newPoint = maybeSnapToGrid(originPagePoint,
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
22
|
+
const creatingMarkId = editor.markHistoryStoppingPoint(`creating_box:${id}`)
|
|
23
|
+
const newPoint = maybeSnapToGrid(originPagePoint, editor)
|
|
24
|
+
|
|
25
|
+
// Allow this to trigger the max shapes reached alert
|
|
26
|
+
this.editor.createShapes<TLBaseBoxShape>([
|
|
27
|
+
{
|
|
28
|
+
id,
|
|
29
|
+
type: shapeType,
|
|
30
|
+
x: newPoint.x,
|
|
31
|
+
y: newPoint.y,
|
|
32
|
+
props: {
|
|
33
|
+
w: 1,
|
|
34
|
+
h: 1,
|
|
34
35
|
},
|
|
35
|
-
|
|
36
|
-
|
|
36
|
+
},
|
|
37
|
+
])
|
|
38
|
+
const shape = editor.getShape(id)
|
|
39
|
+
if (!shape) {
|
|
40
|
+
this.cancel()
|
|
41
|
+
return
|
|
42
|
+
}
|
|
43
|
+
editor.select(id)
|
|
37
44
|
|
|
38
45
|
const parent = this.parent as BaseBoxShapeTool
|
|
39
46
|
this.editor.setCurrentTool(
|
|
@@ -79,6 +86,7 @@ export class Pointing extends StateNode {
|
|
|
79
86
|
|
|
80
87
|
this.editor.markHistoryStoppingPoint(`creating_box:${id}`)
|
|
81
88
|
|
|
89
|
+
// Allow this to trigger the max shapes reached alert
|
|
82
90
|
// todo: add scale here when dynamic size is enabled (is this still needed?)
|
|
83
91
|
this.editor.createShapes<TLBaseBoxShape>([
|
|
84
92
|
{
|