@tldraw/editor 3.13.0-canary.c0afd1f5aa1e → 3.13.0-canary.c3ce2eeb1729

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.
Files changed (116) hide show
  1. package/dist-cjs/index.d.ts +99 -97
  2. package/dist-cjs/index.js +22 -7
  3. package/dist-cjs/index.js.map +2 -2
  4. package/dist-cjs/lib/components/default-components/DefaultCanvas.js +6 -10
  5. package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
  6. package/dist-cjs/lib/editor/Editor.js +16 -64
  7. package/dist-cjs/lib/editor/Editor.js.map +2 -2
  8. package/dist-cjs/lib/editor/managers/SnapManager/HandleSnaps.js.map +2 -2
  9. package/dist-cjs/lib/editor/shapes/ShapeUtil.js +1 -1
  10. package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
  11. package/dist-cjs/lib/editor/shapes/group/GroupShapeUtil.js +3 -0
  12. package/dist-cjs/lib/editor/shapes/group/GroupShapeUtil.js.map +2 -2
  13. package/dist-cjs/lib/editor/shapes/shared/getPerfectDashProps.js.map +2 -2
  14. package/dist-cjs/lib/hooks/useEditorComponents.js +2 -1
  15. package/dist-cjs/lib/hooks/useEditorComponents.js.map +2 -2
  16. package/dist-cjs/lib/primitives/Box.js +0 -16
  17. package/dist-cjs/lib/primitives/Box.js.map +2 -2
  18. package/dist-cjs/lib/primitives/Mat.js +1 -1
  19. package/dist-cjs/lib/primitives/Mat.js.map +2 -2
  20. package/dist-cjs/lib/primitives/Vec.js +0 -20
  21. package/dist-cjs/lib/primitives/Vec.js.map +2 -2
  22. package/dist-cjs/lib/primitives/geometry/Arc2d.js +2 -2
  23. package/dist-cjs/lib/primitives/geometry/Arc2d.js.map +2 -2
  24. package/dist-cjs/lib/primitives/geometry/Circle2d.js +1 -1
  25. package/dist-cjs/lib/primitives/geometry/Circle2d.js.map +2 -2
  26. package/dist-cjs/lib/primitives/geometry/CubicBezier2d.js +1 -1
  27. package/dist-cjs/lib/primitives/geometry/CubicBezier2d.js.map +2 -2
  28. package/dist-cjs/lib/primitives/geometry/CubicSpline2d.js.map +2 -2
  29. package/dist-cjs/lib/primitives/geometry/Edge2d.js +1 -1
  30. package/dist-cjs/lib/primitives/geometry/Edge2d.js.map +2 -2
  31. package/dist-cjs/lib/primitives/geometry/Ellipse2d.js.map +2 -2
  32. package/dist-cjs/lib/primitives/geometry/Geometry2d.js +20 -91
  33. package/dist-cjs/lib/primitives/geometry/Geometry2d.js.map +2 -2
  34. package/dist-cjs/lib/primitives/geometry/Group2d.js +2 -55
  35. package/dist-cjs/lib/primitives/geometry/Group2d.js.map +2 -2
  36. package/dist-cjs/lib/primitives/geometry/Point2d.js.map +2 -2
  37. package/dist-cjs/lib/primitives/geometry/Polyline2d.js.map +2 -2
  38. package/dist-cjs/lib/primitives/geometry/Stadium2d.js.map +2 -2
  39. package/dist-cjs/lib/utils/debug-flags.js +2 -5
  40. package/dist-cjs/lib/utils/debug-flags.js.map +2 -2
  41. package/dist-cjs/version.js +3 -3
  42. package/dist-cjs/version.js.map +1 -1
  43. package/dist-esm/index.d.mts +99 -97
  44. package/dist-esm/index.mjs +41 -9
  45. package/dist-esm/index.mjs.map +2 -2
  46. package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +6 -10
  47. package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
  48. package/dist-esm/lib/editor/Editor.mjs +16 -64
  49. package/dist-esm/lib/editor/Editor.mjs.map +2 -2
  50. package/dist-esm/lib/editor/managers/SnapManager/HandleSnaps.mjs.map +2 -2
  51. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs +1 -1
  52. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
  53. package/dist-esm/lib/editor/shapes/group/GroupShapeUtil.mjs +3 -0
  54. package/dist-esm/lib/editor/shapes/group/GroupShapeUtil.mjs.map +2 -2
  55. package/dist-esm/lib/editor/shapes/shared/getPerfectDashProps.mjs.map +2 -2
  56. package/dist-esm/lib/hooks/useEditorComponents.mjs +4 -1
  57. package/dist-esm/lib/hooks/useEditorComponents.mjs.map +2 -2
  58. package/dist-esm/lib/primitives/Box.mjs +0 -16
  59. package/dist-esm/lib/primitives/Box.mjs.map +2 -2
  60. package/dist-esm/lib/primitives/Mat.mjs +1 -1
  61. package/dist-esm/lib/primitives/Mat.mjs.map +2 -2
  62. package/dist-esm/lib/primitives/Vec.mjs +0 -20
  63. package/dist-esm/lib/primitives/Vec.mjs.map +2 -2
  64. package/dist-esm/lib/primitives/geometry/Arc2d.mjs +2 -2
  65. package/dist-esm/lib/primitives/geometry/Arc2d.mjs.map +2 -2
  66. package/dist-esm/lib/primitives/geometry/Circle2d.mjs +1 -1
  67. package/dist-esm/lib/primitives/geometry/Circle2d.mjs.map +2 -2
  68. package/dist-esm/lib/primitives/geometry/CubicBezier2d.mjs +1 -1
  69. package/dist-esm/lib/primitives/geometry/CubicBezier2d.mjs.map +2 -2
  70. package/dist-esm/lib/primitives/geometry/CubicSpline2d.mjs.map +2 -2
  71. package/dist-esm/lib/primitives/geometry/Edge2d.mjs +1 -1
  72. package/dist-esm/lib/primitives/geometry/Edge2d.mjs.map +2 -2
  73. package/dist-esm/lib/primitives/geometry/Ellipse2d.mjs.map +2 -2
  74. package/dist-esm/lib/primitives/geometry/Geometry2d.mjs +21 -92
  75. package/dist-esm/lib/primitives/geometry/Geometry2d.mjs.map +2 -2
  76. package/dist-esm/lib/primitives/geometry/Group2d.mjs +2 -55
  77. package/dist-esm/lib/primitives/geometry/Group2d.mjs.map +2 -2
  78. package/dist-esm/lib/primitives/geometry/Point2d.mjs.map +2 -2
  79. package/dist-esm/lib/primitives/geometry/Polyline2d.mjs.map +2 -2
  80. package/dist-esm/lib/primitives/geometry/Stadium2d.mjs.map +2 -2
  81. package/dist-esm/lib/utils/debug-flags.mjs +2 -5
  82. package/dist-esm/lib/utils/debug-flags.mjs.map +2 -2
  83. package/dist-esm/version.mjs +3 -3
  84. package/dist-esm/version.mjs.map +1 -1
  85. package/editor.css +4 -32
  86. package/package.json +7 -7
  87. package/src/index.ts +31 -16
  88. package/src/lib/components/default-components/DefaultCanvas.tsx +6 -11
  89. package/src/lib/editor/Editor.test.ts +1 -1
  90. package/src/lib/editor/Editor.ts +16 -75
  91. package/src/lib/editor/managers/SnapManager/HandleSnaps.ts +1 -0
  92. package/src/lib/editor/shapes/ShapeUtil.ts +2 -10
  93. package/src/lib/editor/shapes/group/GroupShapeUtil.tsx +4 -0
  94. package/src/lib/editor/shapes/shared/getPerfectDashProps.ts +9 -9
  95. package/src/lib/hooks/useEditorComponents.tsx +5 -2
  96. package/src/lib/primitives/Box.ts +0 -20
  97. package/src/lib/primitives/Mat.ts +4 -5
  98. package/src/lib/primitives/Vec.ts +0 -23
  99. package/src/lib/primitives/geometry/Arc2d.ts +5 -5
  100. package/src/lib/primitives/geometry/Circle2d.ts +4 -4
  101. package/src/lib/primitives/geometry/CubicBezier2d.ts +4 -4
  102. package/src/lib/primitives/geometry/CubicSpline2d.ts +3 -3
  103. package/src/lib/primitives/geometry/Edge2d.ts +3 -3
  104. package/src/lib/primitives/geometry/Ellipse2d.ts +3 -3
  105. package/src/lib/primitives/geometry/Geometry2d.ts +35 -123
  106. package/src/lib/primitives/geometry/Group2d.ts +7 -70
  107. package/src/lib/primitives/geometry/Point2d.ts +2 -2
  108. package/src/lib/primitives/geometry/Polyline2d.ts +3 -3
  109. package/src/lib/primitives/geometry/Stadium2d.ts +3 -3
  110. package/src/lib/test/currentToolIdMask.test.ts +1 -1
  111. package/src/lib/test/user.test.ts +1 -1
  112. package/src/lib/utils/debug-flags.ts +2 -7
  113. package/src/lib/utils/sync/LocalIndexedDb.test.ts +1 -1
  114. package/src/lib/utils/sync/TLLocalSyncClient.test.ts +1 -1
  115. package/src/version.ts +3 -3
  116. package/src/lib/primitives/geometry/Geometry2d.test.ts +0 -42
package/editor.css CHANGED
@@ -157,7 +157,6 @@
157
157
  --color-panel-contrast: hsl(0, 0%, 100%);
158
158
  --color-panel-overlay: hsl(0, 0%, 100%, 82%);
159
159
  --color-panel: hsl(0, 0%, 99%);
160
- --color-panel-transparent: hsla(0, 0%, 99%, 0%);
161
160
  --color-focus: hsl(219, 65%, 50%);
162
161
  --color-selected: hsl(214, 84%, 56%);
163
162
  --color-selected-contrast: hsl(0, 0%, 100%);
@@ -209,7 +208,6 @@
209
208
  --color-panel-contrast: hsl(245, 12%, 23%);
210
209
  --color-panel: hsl(235, 6.8%, 13.5%);
211
210
  --color-panel-overlay: hsl(210, 10%, 24%, 82%);
212
- --color-panel-transparent: hsla(235, 6.8%, 13.5%, 0%);
213
211
  --color-focus: hsl(217, 76%, 80%);
214
212
  --color-selected: hsl(217, 89%, 61%);
215
213
  --color-selected-contrast: hsl(0, 0%, 100%);
@@ -602,36 +600,6 @@ input,
602
600
  }
603
601
  }
604
602
 
605
- .tl-rotate-corner:not(:hover),
606
- .tl-resize-handle:not(:hover) {
607
- cursor: none;
608
- }
609
-
610
- /* --------------------- Arrow Hints -------------------- */
611
-
612
- .tl-arrow-hint-handle {
613
- fill: var(--color-selected-contrast);
614
- stroke: var(--color-selection-stroke);
615
- stroke-width: calc(1.5px * var(--tl-scale));
616
- r: calc(4px * var(--tl-scale));
617
- }
618
-
619
- .tl-arrow-hint-snap {
620
- stroke: transparent;
621
- fill: var(--color-selection-fill);
622
- r: calc(12px * var(--tl-scale));
623
- }
624
-
625
- .tl-arrow-hint-snap__none,
626
- .tl-arrow-hint-snap__center,
627
- .tl-arrow-hint-snap__axis {
628
- display: none;
629
- }
630
-
631
- .tl-arrow-hint-snap__edge {
632
- r: calc(8px * var(--tl-scale));
633
- }
634
-
635
603
  /* ------------------ Bounds Detail ----------------- */
636
604
 
637
605
  .tl-image,
@@ -1389,6 +1357,10 @@ input,
1389
1357
  opacity: 0;
1390
1358
  }
1391
1359
 
1360
+ .tl-arrow-label[data-isediting='true'] > .tl-arrow-label__inner {
1361
+ background-color: var(--color-background);
1362
+ }
1363
+
1392
1364
  .tl-arrow-label__inner {
1393
1365
  border-radius: var(--radius-1);
1394
1366
  box-sizing: content-box;
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.13.0-canary.c0afd1f5aa1e",
4
+ "version": "3.13.0-canary.c3ce2eeb1729",
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.13.0-canary.c0afd1f5aa1e",
52
- "@tldraw/state-react": "3.13.0-canary.c0afd1f5aa1e",
53
- "@tldraw/store": "3.13.0-canary.c0afd1f5aa1e",
54
- "@tldraw/tlschema": "3.13.0-canary.c0afd1f5aa1e",
55
- "@tldraw/utils": "3.13.0-canary.c0afd1f5aa1e",
56
- "@tldraw/validate": "3.13.0-canary.c0afd1f5aa1e",
51
+ "@tldraw/state": "3.13.0-canary.c3ce2eeb1729",
52
+ "@tldraw/state-react": "3.13.0-canary.c3ce2eeb1729",
53
+ "@tldraw/store": "3.13.0-canary.c3ce2eeb1729",
54
+ "@tldraw/tlschema": "3.13.0-canary.c3ce2eeb1729",
55
+ "@tldraw/utils": "3.13.0-canary.c3ce2eeb1729",
56
+ "@tldraw/validate": "3.13.0-canary.c3ce2eeb1729",
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
@@ -4,11 +4,37 @@ import 'core-js/stable/array/flat-map.js'
4
4
  import 'core-js/stable/array/flat.js'
5
5
  import 'core-js/stable/string/at.js'
6
6
  import 'core-js/stable/string/replace-all.js'
7
-
8
- // eslint-disable-next-line local/no-export-star
9
- export * from '@tldraw/state'
10
- // eslint-disable-next-line local/no-export-star
11
- export * from '@tldraw/state-react'
7
+ export {
8
+ EMPTY_ARRAY,
9
+ EffectScheduler,
10
+ atom,
11
+ computed,
12
+ react,
13
+ transact,
14
+ transaction,
15
+ whyAmIRunning,
16
+ type Atom,
17
+ type Signal,
18
+ } from '@tldraw/state'
19
+ export {
20
+ track,
21
+ useAtom,
22
+ useComputed,
23
+ useQuickReactor,
24
+ useReactor,
25
+ useStateTracking,
26
+ useValue,
27
+ } from '@tldraw/state-react'
28
+ export { resizeScaled } from './lib/editor/shapes/shared/resizeScaled'
29
+ export {
30
+ getFontsFromRichText,
31
+ type RichTextFontVisitor,
32
+ type RichTextFontVisitorState,
33
+ type TLTextOptions,
34
+ type TiptapEditor,
35
+ type TiptapNode,
36
+ } from './lib/utils/richText'
37
+ export { LocalIndexedDb, Table, type StoreName } from './lib/utils/sync/LocalIndexedDb'
12
38
  // eslint-disable-next-line local/no-export-star
13
39
  export * from '@tldraw/store'
14
40
  // eslint-disable-next-line local/no-export-star
@@ -17,7 +43,6 @@ export * from '@tldraw/tlschema'
17
43
  export * from '@tldraw/utils'
18
44
  // eslint-disable-next-line local/no-export-star
19
45
  export * from '@tldraw/validate'
20
-
21
46
  export {
22
47
  ErrorScreen,
23
48
  LoadingScreen,
@@ -187,7 +212,6 @@ export {
187
212
  export { GroupShapeUtil } from './lib/editor/shapes/group/GroupShapeUtil'
188
213
  export { getPerfectDashProps } from './lib/editor/shapes/shared/getPerfectDashProps'
189
214
  export { resizeBox, type ResizeBoxOptions } from './lib/editor/shapes/shared/resizeBox'
190
- export { resizeScaled } from './lib/editor/shapes/shared/resizeScaled'
191
215
  export { BaseBoxShapeTool } from './lib/editor/tools/BaseBoxShapeTool/BaseBoxShapeTool'
192
216
  export { maybeSnapToGrid } from './lib/editor/tools/BaseBoxShapeTool/children/Pointing'
193
217
  export { StateNode, type TLStateNodeConstructor } from './lib/editor/tools/StateNode'
@@ -435,21 +459,12 @@ export { hardResetEditor } from './lib/utils/hardResetEditor'
435
459
  export { isAccelKey } from './lib/utils/keyboard'
436
460
  export { normalizeWheel } from './lib/utils/normalizeWheel'
437
461
  export { refreshPage } from './lib/utils/refreshPage'
438
- export {
439
- getFontsFromRichText,
440
- type RichTextFontVisitor,
441
- type RichTextFontVisitorState,
442
- type TLTextOptions,
443
- type TiptapEditor,
444
- type TiptapNode,
445
- } from './lib/utils/richText'
446
462
  export {
447
463
  applyRotationToSnapshotShapes,
448
464
  getRotationSnapshot,
449
465
  type TLRotationSnapshot,
450
466
  } from './lib/utils/rotation'
451
467
  export { runtime, setRuntimeOverrides } from './lib/utils/runtime'
452
- export { LocalIndexedDb, Table, type StoreName } from './lib/utils/sync/LocalIndexedDb'
453
468
  export { type TLStoreWithStatus } from './lib/utils/sync/StoreWithStatus'
454
469
  export { hardReset } from './lib/utils/sync/hardReset'
455
470
  export { uniq } from './lib/utils/uniq'
@@ -37,7 +37,7 @@ export interface TLCanvasComponentProps {
37
37
  export function DefaultCanvas({ className }: TLCanvasComponentProps) {
38
38
  const editor = useEditor()
39
39
 
40
- const { SelectionBackground, Background, SvgDefs, ShapeIndicators } = useEditorComponents()
40
+ const { Background, SvgDefs, ShapeIndicators } = useEditorComponents()
41
41
 
42
42
  const rCanvas = useRef<HTMLDivElement>(null)
43
43
  const rHtmlLayer = useRef<HTMLDivElement>(null)
@@ -155,7 +155,7 @@ export function DefaultCanvas({ className }: TLCanvasComponentProps) {
155
155
  <GridWrapper />
156
156
  <div ref={rHtmlLayer} className="tl-html-layer tl-shapes" draggable={false}>
157
157
  <OnTheCanvasWrapper />
158
- {SelectionBackground && <SelectionBackgroundWrapper />}
158
+ <SelectionBackgroundWrapper />
159
159
  {hideShapes ? null : debugSvg ? <ShapesWithSVGs /> : <ShapesToDisplay />}
160
160
  </div>
161
161
  <div className="tl-overlays">
@@ -365,8 +365,7 @@ function HandleWrapper({
365
365
  return (
366
366
  <g
367
367
  role="button"
368
- // TODO(mime): handle.label needs to be required in the future.
369
- aria-label={handle.label || 'handle'}
368
+ aria-label="handle"
370
369
  transform={`translate(${handle.x}, ${handle.y})`}
371
370
  {...events}
372
371
  >
@@ -576,13 +575,9 @@ function DebugSvgCopy({ id, mode }: { id: TLShapeId; mode: 'img' | 'iframe' }) {
576
575
 
577
576
  function SelectionForegroundWrapper() {
578
577
  const editor = useEditor()
579
- const selectionRotation = useValue(
580
- 'selection rotation',
581
- function getSelectionRotation() {
582
- return editor.getSelectionRotation()
583
- },
584
- [editor]
585
- )
578
+ const selectionRotation = useValue('selection rotation', () => editor.getSelectionRotation(), [
579
+ editor,
580
+ ])
586
581
  const selectionBounds = useValue(
587
582
  'selection bounds',
588
583
  () => editor.getSelectionRotatedPageBounds(),
@@ -52,7 +52,7 @@ beforeEach(() => {
52
52
  shapeUtils: [CustomShape],
53
53
  bindingUtils: [],
54
54
  tools: [],
55
- store: createTLStore({ shapeUtils: [CustomShape], bindingUtils: [] }),
55
+ store: createTLStore({ shapeUtils: [CustomShape] }),
56
56
  getContainer: () => document.body,
57
57
  })
58
58
  editor.setCameraOptions({ isLocked: true })
@@ -326,6 +326,7 @@ export class Editor extends EventEmitter<TLEventMap> {
326
326
  this.options = { ...defaultTldrawOptions, ...options }
327
327
 
328
328
  this.store = store
329
+ this.disposables.add(this.store.dispose.bind(this.store))
329
330
  this.history = new HistoryManager<TLRecord>({
330
331
  store,
331
332
  annotateError: (error) => {
@@ -955,7 +956,6 @@ export class Editor extends EventEmitter<TLEventMap> {
955
956
  dispose() {
956
957
  this.disposables.forEach((dispose) => dispose())
957
958
  this.disposables.clear()
958
- this.store.dispose()
959
959
  this.isDisposed = true
960
960
  }
961
961
 
@@ -1815,28 +1815,9 @@ export class Editor extends EventEmitter<TLEventMap> {
1815
1815
  return this
1816
1816
  }
1817
1817
 
1818
- /**
1819
- * Select the next shape in the reading order or in cardinal order.
1820
- *
1821
- * @example
1822
- * ```ts
1823
- * editor.selectAdjacentShape('next')
1824
- * ```
1825
- *
1826
- * @public
1827
- */
1828
1818
  selectAdjacentShape(direction: TLAdjacentDirection) {
1819
+ const readingOrderShapes = this.getCurrentPageShapesInReadingOrder()
1829
1820
  const selectedShapeIds = this.getSelectedShapeIds()
1830
- const firstParentId = selectedShapeIds[0] ? this.getShape(selectedShapeIds[0])?.parentId : null
1831
- const isSelectedWithinContainer =
1832
- firstParentId &&
1833
- selectedShapeIds.every((shapeId) => this.getShape(shapeId)?.parentId === firstParentId) &&
1834
- !isPageId(firstParentId)
1835
- const readingOrderShapes = isSelectedWithinContainer
1836
- ? this._getShapesInReadingOrder(
1837
- this.getCurrentPageShapes().filter((shape) => shape.parentId === firstParentId)
1838
- )
1839
- : this.getCurrentPageShapesInReadingOrder()
1840
1821
  const currentShapeId: TLShapeId | undefined =
1841
1822
  selectedShapeIds.length === 1
1842
1823
  ? selectedShapeIds[0]
@@ -1858,7 +1839,13 @@ export class Editor extends EventEmitter<TLEventMap> {
1858
1839
  const shape = this.getShape(adjacentShapeId)
1859
1840
  if (!shape) return
1860
1841
 
1861
- this._selectShapesAndZoom([shape.id])
1842
+ this.setSelectedShapes([shape.id])
1843
+ this.zoomToSelectionIfOffscreen(256, {
1844
+ animation: {
1845
+ duration: this.options.animationMediumMs,
1846
+ },
1847
+ inset: 0,
1848
+ })
1862
1849
  }
1863
1850
 
1864
1851
  /**
@@ -1868,14 +1855,10 @@ export class Editor extends EventEmitter<TLEventMap> {
1868
1855
  * @public
1869
1856
  */
1870
1857
  @computed getCurrentPageShapesInReadingOrder(): TLShape[] {
1871
- const shapes = this.getCurrentPageShapes().filter((shape) => isPageId(shape.parentId))
1872
- return this._getShapesInReadingOrder(shapes)
1873
- }
1874
-
1875
- private _getShapesInReadingOrder(shapes: TLShape[]): TLShape[] {
1876
1858
  const SHALLOW_ANGLE = 20
1877
1859
  const ROW_THRESHOLD = 100
1878
1860
 
1861
+ const shapes = this.getCurrentPageShapes()
1879
1862
  const tabbableShapes = shapes.filter((shape) => this.getShapeUtil(shape).canTabTo(shape))
1880
1863
 
1881
1864
  if (tabbableShapes.length <= 1) return tabbableShapes
@@ -2021,36 +2004,6 @@ export class Editor extends EventEmitter<TLEventMap> {
2021
2004
  return lowestScoringShape!.shape.id
2022
2005
  }
2023
2006
 
2024
- selectParentShape() {
2025
- const selectedShape = this.getOnlySelectedShape()
2026
- if (!selectedShape) return
2027
- const parentShape = this.getShape(selectedShape.parentId)
2028
- if (!parentShape) return
2029
- this._selectShapesAndZoom([parentShape.id])
2030
- }
2031
-
2032
- selectFirstChildShape() {
2033
- const selectedShapes = this.getSelectedShapes()
2034
- if (!selectedShapes.length) return
2035
- const selectedShape = selectedShapes[0]
2036
- const children = this.getSortedChildIdsForParent(selectedShape.id)
2037
- .map((id) => this.getShape(id))
2038
- .filter((i) => i) as TLShape[]
2039
- const sortedChildren = this._getShapesInReadingOrder(children)
2040
- if (sortedChildren.length === 0) return
2041
- this._selectShapesAndZoom([sortedChildren[0].id])
2042
- }
2043
-
2044
- private _selectShapesAndZoom(ids: TLShapeId[]) {
2045
- this.setSelectedShapes(ids)
2046
- this.zoomToSelectionIfOffscreen(256, {
2047
- animation: {
2048
- duration: this.options.animationMediumMs,
2049
- },
2050
- inset: 0,
2051
- })
2052
- }
2053
-
2054
2007
  /**
2055
2008
  * Clear the selection.
2056
2009
  *
@@ -2323,21 +2276,13 @@ export class Editor extends EventEmitter<TLEventMap> {
2323
2276
  setEditingShape(shape: TLShapeId | TLShape | null): this {
2324
2277
  const id = typeof shape === 'string' ? shape : (shape?.id ?? null)
2325
2278
  this.setRichTextEditor(null)
2326
- const prevEditingShapeId = this.getEditingShapeId()
2327
- if (id !== prevEditingShapeId) {
2279
+ if (id !== this.getEditingShapeId()) {
2328
2280
  if (id) {
2329
2281
  const shape = this.getShape(id)
2330
2282
  if (shape && this.getShapeUtil(shape).canEdit(shape)) {
2331
2283
  this.run(
2332
2284
  () => {
2333
2285
  this._updateCurrentPageState({ editingShapeId: id })
2334
- if (prevEditingShapeId) {
2335
- const prevEditingShape = this.getShape(prevEditingShapeId)
2336
- if (prevEditingShape) {
2337
- this.getShapeUtil(prevEditingShape).onEditEnd?.(prevEditingShape)
2338
- }
2339
- }
2340
- this.getShapeUtil(shape).onEditStart?.(shape)
2341
2286
  },
2342
2287
  { history: 'ignore' }
2343
2288
  )
@@ -2350,12 +2295,6 @@ export class Editor extends EventEmitter<TLEventMap> {
2350
2295
  () => {
2351
2296
  this._updateCurrentPageState({ editingShapeId: null })
2352
2297
  this._currentRichTextEditor.set(null)
2353
- if (prevEditingShapeId) {
2354
- const prevEditingShape = this.getShape(prevEditingShapeId)
2355
- if (prevEditingShape) {
2356
- this.getShapeUtil(prevEditingShape).onEditEnd?.(prevEditingShape)
2357
- }
2358
- }
2359
2298
  },
2360
2299
  { history: 'ignore' }
2361
2300
  )
@@ -10404,10 +10343,12 @@ export class Editor extends EventEmitter<TLEventMap> {
10404
10343
  if (this.inputs.isPanning && this.inputs.isPointing) {
10405
10344
  // Handle spacebar / middle mouse button panning
10406
10345
  const { currentScreenPoint, previousScreenPoint } = this.inputs
10346
+ const { panSpeed } = cameraOptions
10407
10347
  const offset = Vec.Sub(currentScreenPoint, previousScreenPoint)
10408
- this.setCamera(new Vec(cx + offset.x / cz, cy + offset.y / cz, cz), {
10409
- immediate: true,
10410
- })
10348
+ this.setCamera(
10349
+ new Vec(cx + (offset.x * panSpeed) / cz, cy + (offset.y * panSpeed) / cz, cz),
10350
+ { immediate: true }
10351
+ )
10411
10352
  this.maybeTrackPerformance('Panning')
10412
10353
  return
10413
10354
  }
@@ -45,6 +45,7 @@ export interface HandleSnapGeometry {
45
45
 
46
46
  const defaultGetSelfSnapOutline = () => null
47
47
  const defaultGetSelfSnapPoints = () => []
48
+
48
49
  /** @public */
49
50
  export class HandleSnaps {
50
51
  readonly editor: Editor
@@ -245,7 +245,7 @@ export abstract class ShapeUtil<Shape extends TLUnknownShape = TLUnknownShape> {
245
245
  *
246
246
  * @public
247
247
  */
248
- canEditInReadonly(_shape: Shape): boolean {
248
+ canEditInReadOnly(_shape: Shape): boolean {
249
249
  return false
250
250
  }
251
251
 
@@ -707,15 +707,7 @@ export abstract class ShapeUtil<Shape extends TLUnknownShape = TLUnknownShape> {
707
707
  onClick?(shape: Shape): TLShapePartial<Shape> | void
708
708
 
709
709
  /**
710
- * A callback called when a shape starts being edited.
711
- *
712
- * @param shape - The shape.
713
- * @public
714
- */
715
- onEditStart?(shape: Shape): void
716
-
717
- /**
718
- * A callback called when a shape finishes being edited.
710
+ * A callback called when a shape finishes being editing.
719
711
  *
720
712
  * @param shape - The shape.
721
713
  * @public
@@ -12,6 +12,10 @@ export class GroupShapeUtil extends ShapeUtil<TLGroupShape> {
12
12
  static override props = groupShapeProps
13
13
  static override migrations = groupShapeMigrations
14
14
 
15
+ override canTabTo() {
16
+ return false
17
+ }
18
+
15
19
  override hideSelectionBoundsFg() {
16
20
  return true
17
21
  }
@@ -4,15 +4,15 @@ import { TLDefaultDashStyle } from '@tldraw/tlschema'
4
4
  export function getPerfectDashProps(
5
5
  totalLength: number,
6
6
  strokeWidth: number,
7
- opts: {
8
- style?: TLDefaultDashStyle
9
- snap?: number
10
- end?: 'skip' | 'outset' | 'none'
11
- start?: 'skip' | 'outset' | 'none'
12
- lengthRatio?: number
13
- closed?: boolean
14
- forceSolid?: boolean
15
- } = {}
7
+ opts = {} as Partial<{
8
+ style: TLDefaultDashStyle
9
+ snap: number
10
+ end: 'skip' | 'outset' | 'none'
11
+ start: 'skip' | 'outset' | 'none'
12
+ lengthRatio: number
13
+ closed: boolean
14
+ forceSolid: boolean
15
+ }>
16
16
  ): {
17
17
  strokeDasharray: string
18
18
  strokeDashoffset: string
@@ -19,7 +19,10 @@ import { DefaultHandle, TLHandleProps } from '../components/default-components/D
19
19
  import { DefaultHandles, TLHandlesProps } from '../components/default-components/DefaultHandles'
20
20
  import { DefaultLoadingScreen } from '../components/default-components/DefaultLoadingScreen'
21
21
  import { DefaultScribble, TLScribbleProps } from '../components/default-components/DefaultScribble'
22
- import { TLSelectionBackgroundProps } from '../components/default-components/DefaultSelectionBackground'
22
+ import {
23
+ DefaultSelectionBackground,
24
+ TLSelectionBackgroundProps,
25
+ } from '../components/default-components/DefaultSelectionBackground'
23
26
  import {
24
27
  DefaultSelectionForeground,
25
28
  TLSelectionForegroundProps,
@@ -110,7 +113,7 @@ export function EditorComponentsProvider({
110
113
  OnTheCanvas: null,
111
114
  Overlays: null,
112
115
  Scribble: DefaultScribble,
113
- SelectionBackground: null,
116
+ SelectionBackground: DefaultSelectionBackground,
114
117
  SelectionForeground: DefaultSelectionForeground,
115
118
  ShapeIndicator: DefaultShapeIndicator,
116
119
  ShapeIndicators: DefaultShapeIndicators,
@@ -57,11 +57,6 @@ export class Box {
57
57
  this.x = n
58
58
  }
59
59
 
60
- // eslint-disable-next-line no-restricted-syntax
61
- get left() {
62
- return this.x
63
- }
64
-
65
60
  // eslint-disable-next-line no-restricted-syntax
66
61
  get midX() {
67
62
  return this.x + this.w / 2
@@ -72,11 +67,6 @@ export class Box {
72
67
  return this.x + this.w
73
68
  }
74
69
 
75
- // eslint-disable-next-line no-restricted-syntax
76
- get right() {
77
- return this.x + this.w
78
- }
79
-
80
70
  // eslint-disable-next-line no-restricted-syntax
81
71
  get minY() {
82
72
  return this.y
@@ -87,11 +77,6 @@ export class Box {
87
77
  this.y = n
88
78
  }
89
79
 
90
- // eslint-disable-next-line no-restricted-syntax
91
- get top() {
92
- return this.y
93
- }
94
-
95
80
  // eslint-disable-next-line no-restricted-syntax
96
81
  get midY() {
97
82
  return this.y + this.h / 2
@@ -102,11 +87,6 @@ export class Box {
102
87
  return this.y + this.h
103
88
  }
104
89
 
105
- // eslint-disable-next-line no-restricted-syntax
106
- get bottom() {
107
- return this.y + this.h
108
- }
109
-
110
90
  // eslint-disable-next-line no-restricted-syntax
111
91
  get width() {
112
92
  return this.w
@@ -157,13 +157,12 @@ export class Mat {
157
157
  return Mat.Compose(Mat.Translate(cx, cy!), rotationMatrix, Mat.Translate(-cx, -cy!))
158
158
  }
159
159
 
160
- static Scale(x: number, y: number): Mat
161
- static Scale(x: number, y: number, cx: number, cy: number): Mat
162
- static Scale(x: number, y: number, cx?: number, cy?: number): Mat {
160
+ static Scale(x: number, y: number): MatModel
161
+ static Scale(x: number, y: number, cx: number, cy: number): MatModel
162
+ static Scale(x: number, y: number, cx?: number, cy?: number): MatModel {
163
163
  const scaleMatrix = new Mat(x, 0, 0, y, 0, 0)
164
164
  if (cx === undefined) return scaleMatrix
165
-
166
- return Mat.Translate(cx, cy!).multiply(scaleMatrix).translate(-cx, -cy!)
165
+ return Mat.Compose(Mat.Translate(cx, cy!), scaleMatrix, Mat.Translate(-cx, -cy!))
167
166
  }
168
167
  static Multiply(m1: MatModel, m2: MatModel): MatModel {
169
168
  return {
@@ -319,11 +319,6 @@ export class Vec {
319
319
  return ((A.y - B.y) ** 2 + (A.x - B.x) ** 2) ** 0.5
320
320
  }
321
321
 
322
- // Get the Manhattan distance between two points.
323
- static ManhattanDist(A: VecLike, B: VecLike): number {
324
- return Math.abs(A.x - B.x) + Math.abs(A.y - B.y)
325
- }
326
-
327
322
  // Get whether a distance between two points is less than a number. This is faster to calulate than using `Vec.Dist(a, b) < n`.
328
323
  static DistMin(A: VecLike, B: VecLike, n: number): boolean {
329
324
  return (A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y) < n ** 2
@@ -470,28 +465,10 @@ export class Vec {
470
465
  return isNaN(A.x) || isNaN(A.y)
471
466
  }
472
467
 
473
- /**
474
- * Get the angle from position A to position B.
475
- */
476
468
  static Angle(A: VecLike, B: VecLike): number {
477
469
  return Math.atan2(B.y - A.y, B.x - A.x)
478
470
  }
479
471
 
480
- /**
481
- * Get the angle between vector A and vector B. This will return the smallest angle between the
482
- * two vectors, between -π and π. The sign indicates direction of angle.
483
- */
484
- static AngleBetween(A: VecLike, B: VecLike): number {
485
- const p = A.x * B.x + A.y * B.y
486
- const n = Math.sqrt(
487
- (Math.pow(A.x, 2) + Math.pow(A.y, 2)) * (Math.pow(B.x, 2) + Math.pow(B.y, 2))
488
- )
489
- const sign = A.x * B.y - A.y * B.x < 0 ? -1 : 1
490
- const angle = sign * Math.acos(p / n)
491
-
492
- return angle
493
- }
494
-
495
472
  /**
496
473
  * Linearly interpolate between two points.
497
474
  * @param A - The first point.
@@ -1,4 +1,4 @@
1
- import { Vec, VecLike } from '../Vec'
1
+ import { Vec } from '../Vec'
2
2
  import { intersectLineSegmentCircle } from '../intersect'
3
3
  import { getArcMeasure, getPointInArcT, getPointOnCircle } from '../utils'
4
4
  import { Geometry2d, Geometry2dOptions } from './Geometry2d'
@@ -44,14 +44,14 @@ export class Arc2d extends Geometry2d {
44
44
  this._center = center
45
45
  }
46
46
 
47
- nearestPoint(point: VecLike): Vec {
47
+ nearestPoint(point: Vec): Vec {
48
48
  const { _center, measure, radius, angleEnd, angleStart, start: A, end: B } = this
49
49
  const t = getPointInArcT(measure, angleStart, angleEnd, _center.angle(point))
50
50
  if (t <= 0) return A
51
51
  if (t >= 1) return B
52
52
 
53
53
  // Get the point (P) on the arc, then pick the nearest of A, B, and P
54
- const P = Vec.Sub(point, _center).uni().mul(radius).add(_center)
54
+ const P = _center.clone().add(point.clone().sub(_center).uni().mul(radius))
55
55
 
56
56
  let nearest: Vec | undefined
57
57
  let dist = Infinity
@@ -67,7 +67,7 @@ export class Arc2d extends Geometry2d {
67
67
  return nearest
68
68
  }
69
69
 
70
- hitTestLineSegment(A: VecLike, B: VecLike): boolean {
70
+ hitTestLineSegment(A: Vec, B: Vec): boolean {
71
71
  const { _center, radius, measure, angleStart, angleEnd } = this
72
72
  const intersection = intersectLineSegmentCircle(A, B, _center, radius)
73
73
  if (intersection === null) return false
@@ -95,6 +95,6 @@ export class Arc2d extends Geometry2d {
95
95
  }
96
96
 
97
97
  override getLength() {
98
- return Math.abs(this.measure * this.radius)
98
+ return this.measure * this.radius
99
99
  }
100
100
  }
@@ -1,5 +1,5 @@
1
1
  import { Box } from '../Box'
2
- import { Vec, VecLike } from '../Vec'
2
+ import { Vec } from '../Vec'
3
3
  import { intersectLineSegmentCircle } from '../intersect'
4
4
  import { PI2, getPointOnCircle } from '../utils'
5
5
  import { Geometry2d, Geometry2dOptions } from './Geometry2d'
@@ -43,13 +43,13 @@ export class Circle2d extends Geometry2d {
43
43
  return vertices
44
44
  }
45
45
 
46
- nearestPoint(point: VecLike): Vec {
46
+ nearestPoint(point: Vec): Vec {
47
47
  const { _center, radius } = this
48
48
  if (_center.equals(point)) return Vec.AddXY(_center, radius, 0)
49
- return Vec.Sub(point, _center).uni().mul(radius).add(_center)
49
+ return _center.clone().add(point.clone().sub(_center).uni().mul(radius))
50
50
  }
51
51
 
52
- hitTestLineSegment(A: VecLike, B: VecLike, distance = 0): boolean {
52
+ hitTestLineSegment(A: Vec, B: Vec, distance = 0): boolean {
53
53
  const { _center, radius } = this
54
54
  return intersectLineSegmentCircle(A, B, _center, radius + distance) !== null
55
55
  }