@tldraw/editor 3.14.2 → 3.15.0-canary.039c346f1d6f
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 +23 -4
- package/dist-cjs/index.js +4 -1
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/config/TLUserPreferences.js +7 -1
- package/dist-cjs/lib/config/TLUserPreferences.js.map +2 -2
- package/dist-cjs/lib/editor/Editor.js +20 -2
- package/dist-cjs/lib/editor/Editor.js.map +2 -2
- package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js +7 -2
- package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.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/Arc2d.js +1 -1
- package/dist-cjs/lib/primitives/geometry/Arc2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Circle2d.js +1 -1
- package/dist-cjs/lib/primitives/geometry/Circle2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/CubicBezier2d.js +3 -1
- package/dist-cjs/lib/primitives/geometry/CubicBezier2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Ellipse2d.js +1 -1
- package/dist-cjs/lib/primitives/geometry/Ellipse2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/geometry-constants.js +2 -2
- package/dist-cjs/lib/primitives/geometry/geometry-constants.js.map +2 -2
- package/dist-cjs/lib/primitives/intersect.js +4 -4
- package/dist-cjs/lib/primitives/intersect.js.map +2 -2
- package/dist-cjs/lib/primitives/utils.js +4 -0
- package/dist-cjs/lib/primitives/utils.js.map +2 -2
- package/dist-cjs/lib/utils/sync/TLLocalSyncClient.js +0 -1
- package/dist-cjs/lib/utils/sync/TLLocalSyncClient.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 +23 -4
- package/dist-esm/index.mjs +10 -2
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/config/TLUserPreferences.mjs +7 -1
- package/dist-esm/lib/config/TLUserPreferences.mjs.map +2 -2
- package/dist-esm/lib/editor/Editor.mjs +20 -2
- package/dist-esm/lib/editor/Editor.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs +7 -2
- package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.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/Arc2d.mjs +2 -2
- package/dist-esm/lib/primitives/geometry/Arc2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Circle2d.mjs +2 -2
- package/dist-esm/lib/primitives/geometry/Circle2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/CubicBezier2d.mjs +3 -1
- package/dist-esm/lib/primitives/geometry/CubicBezier2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Ellipse2d.mjs +2 -2
- package/dist-esm/lib/primitives/geometry/Ellipse2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/geometry-constants.mjs +2 -2
- package/dist-esm/lib/primitives/geometry/geometry-constants.mjs.map +2 -2
- package/dist-esm/lib/primitives/intersect.mjs +5 -5
- package/dist-esm/lib/primitives/intersect.mjs.map +2 -2
- package/dist-esm/lib/primitives/utils.mjs +4 -0
- package/dist-esm/lib/primitives/utils.mjs.map +2 -2
- package/dist-esm/lib/utils/sync/TLLocalSyncClient.mjs +0 -1
- package/dist-esm/lib/utils/sync/TLLocalSyncClient.mjs.map +2 -2
- package/dist-esm/version.mjs +3 -3
- package/dist-esm/version.mjs.map +1 -1
- package/package.json +7 -7
- package/src/index.ts +8 -1
- package/src/lib/config/TLUserPreferences.ts +7 -0
- package/src/lib/editor/Editor.test.ts +407 -0
- package/src/lib/editor/Editor.ts +30 -5
- package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.test.ts +21 -0
- package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.ts +8 -0
- package/src/lib/hooks/useEditor.tsx +6 -5
- package/src/lib/primitives/geometry/Arc2d.ts +2 -2
- package/src/lib/primitives/geometry/Circle2d.ts +2 -2
- package/src/lib/primitives/geometry/CubicBezier2d.ts +4 -1
- package/src/lib/primitives/geometry/Ellipse2d.ts +2 -2
- package/src/lib/primitives/geometry/geometry-constants.ts +2 -1
- package/src/lib/primitives/intersect.test.ts +946 -0
- package/src/lib/primitives/intersect.ts +12 -5
- package/src/lib/primitives/utils.ts +11 -0
- package/src/lib/utils/sync/TLLocalSyncClient.ts +0 -1
- package/src/version.ts +3 -3
package/src/lib/editor/Editor.ts
CHANGED
|
@@ -1803,7 +1803,9 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
1803
1803
|
}
|
|
1804
1804
|
|
|
1805
1805
|
/**
|
|
1806
|
-
* Select all
|
|
1806
|
+
* Select all shapes. If the user has selected shapes that share a parent,
|
|
1807
|
+
* select all shapes within that parent. If the user has not selected any shapes,
|
|
1808
|
+
* or if the shapes shapes are only on select all shapes on the current page.
|
|
1807
1809
|
*
|
|
1808
1810
|
* @example
|
|
1809
1811
|
* ```ts
|
|
@@ -1813,11 +1815,34 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
1813
1815
|
* @public
|
|
1814
1816
|
*/
|
|
1815
1817
|
selectAll(): this {
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
+
let parentToSelectWithinId: TLParentId | null = null
|
|
1819
|
+
|
|
1820
|
+
const selectedShapeIds = this.getSelectedShapeIds()
|
|
1821
|
+
|
|
1822
|
+
// If we have selected shapes, try to find a parent to select within
|
|
1823
|
+
if (selectedShapeIds.length > 0) {
|
|
1824
|
+
for (const id of selectedShapeIds) {
|
|
1825
|
+
const shape = this.getShape(id)
|
|
1826
|
+
if (!shape) continue
|
|
1827
|
+
if (parentToSelectWithinId === null) {
|
|
1828
|
+
// If we haven't found a parent yet, set this parent as the parent to select within
|
|
1829
|
+
parentToSelectWithinId = shape.parentId
|
|
1830
|
+
} else if (parentToSelectWithinId !== shape.parentId) {
|
|
1831
|
+
// If we've found two different parents, we can't select all, do nothing
|
|
1832
|
+
return this
|
|
1833
|
+
}
|
|
1834
|
+
}
|
|
1835
|
+
}
|
|
1836
|
+
|
|
1837
|
+
// If we haven't found a parent from our selected shapes, select the current page
|
|
1838
|
+
if (!parentToSelectWithinId) {
|
|
1839
|
+
parentToSelectWithinId = this.getCurrentPageId()
|
|
1840
|
+
}
|
|
1841
|
+
|
|
1842
|
+
// Select all the unlocked shapes within the parent
|
|
1843
|
+
const ids = this.getSortedChildIdsForParent(parentToSelectWithinId)
|
|
1818
1844
|
if (ids.length <= 0) return this
|
|
1819
1845
|
this.setSelectedShapes(this._getUnlockedShapeIds(ids))
|
|
1820
|
-
|
|
1821
1846
|
return this
|
|
1822
1847
|
}
|
|
1823
1848
|
|
|
@@ -7859,7 +7884,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
7859
7884
|
|
|
7860
7885
|
const prevParentId = partial.parentId
|
|
7861
7886
|
|
|
7862
|
-
// a shape cannot be
|
|
7887
|
+
// a shape cannot be its own parent. This was a rare issue with frames/groups in the syncFuzz tests.
|
|
7863
7888
|
if (parentId === partial.id) {
|
|
7864
7889
|
parentId = focusedGroupId
|
|
7865
7890
|
}
|
|
@@ -24,6 +24,7 @@ describe('UserPreferencesManager', () => {
|
|
|
24
24
|
color: '#FF802B',
|
|
25
25
|
locale: 'en',
|
|
26
26
|
animationSpeed: 1,
|
|
27
|
+
areKeyboardShortcutsEnabled: true,
|
|
27
28
|
edgeScrollSpeed: 1,
|
|
28
29
|
colorScheme: 'light',
|
|
29
30
|
isSnapMode: false,
|
|
@@ -229,6 +230,7 @@ describe('UserPreferencesManager', () => {
|
|
|
229
230
|
locale: mockUserPreferences.locale,
|
|
230
231
|
color: mockUserPreferences.color,
|
|
231
232
|
animationSpeed: mockUserPreferences.animationSpeed,
|
|
233
|
+
areKeyboardShortcutsEnabled: mockUserPreferences.areKeyboardShortcutsEnabled,
|
|
232
234
|
isSnapMode: mockUserPreferences.isSnapMode,
|
|
233
235
|
colorScheme: mockUserPreferences.colorScheme,
|
|
234
236
|
isDarkMode: false, // light mode
|
|
@@ -362,6 +364,21 @@ describe('UserPreferencesManager', () => {
|
|
|
362
364
|
})
|
|
363
365
|
})
|
|
364
366
|
|
|
367
|
+
describe('getAreKeyboardShortcutsEnabled', () => {
|
|
368
|
+
it('should return user keyboard shortcuts', () => {
|
|
369
|
+
expect(userPreferencesManager.getAreKeyboardShortcutsEnabled()).toBe(
|
|
370
|
+
mockUserPreferences.areKeyboardShortcutsEnabled
|
|
371
|
+
)
|
|
372
|
+
})
|
|
373
|
+
|
|
374
|
+
it('should return default keyboard shortcuts when null', () => {
|
|
375
|
+
userPreferencesAtom.set({ ...mockUserPreferences, areKeyboardShortcutsEnabled: null })
|
|
376
|
+
expect(userPreferencesManager.getAreKeyboardShortcutsEnabled()).toBe(
|
|
377
|
+
defaultUserPreferences.areKeyboardShortcutsEnabled
|
|
378
|
+
)
|
|
379
|
+
})
|
|
380
|
+
})
|
|
381
|
+
|
|
365
382
|
describe('getEdgeScrollSpeed', () => {
|
|
366
383
|
it('should return user edge scroll speed', () => {
|
|
367
384
|
expect(userPreferencesManager.getEdgeScrollSpeed()).toBe(
|
|
@@ -483,6 +500,7 @@ describe('UserPreferencesManager', () => {
|
|
|
483
500
|
color: null,
|
|
484
501
|
locale: null,
|
|
485
502
|
animationSpeed: null,
|
|
503
|
+
areKeyboardShortcutsEnabled: null,
|
|
486
504
|
edgeScrollSpeed: null,
|
|
487
505
|
isSnapMode: null,
|
|
488
506
|
isWrapMode: null,
|
|
@@ -496,6 +514,9 @@ describe('UserPreferencesManager', () => {
|
|
|
496
514
|
expect(userPreferencesManager.getColor()).toBe(defaultUserPreferences.color)
|
|
497
515
|
expect(userPreferencesManager.getLocale()).toBe(defaultUserPreferences.locale)
|
|
498
516
|
expect(userPreferencesManager.getAnimationSpeed()).toBe(defaultUserPreferences.animationSpeed)
|
|
517
|
+
expect(userPreferencesManager.getAreKeyboardShortcutsEnabled()).toBe(
|
|
518
|
+
defaultUserPreferences.areKeyboardShortcutsEnabled
|
|
519
|
+
)
|
|
499
520
|
expect(userPreferencesManager.getEdgeScrollSpeed()).toBe(
|
|
500
521
|
defaultUserPreferences.edgeScrollSpeed
|
|
501
522
|
)
|
|
@@ -43,6 +43,7 @@ export class UserPreferencesManager {
|
|
|
43
43
|
locale: this.getLocale(),
|
|
44
44
|
color: this.getColor(),
|
|
45
45
|
animationSpeed: this.getAnimationSpeed(),
|
|
46
|
+
areKeyboardShortcutsEnabled: this.getAreKeyboardShortcutsEnabled(),
|
|
46
47
|
isSnapMode: this.getIsSnapMode(),
|
|
47
48
|
colorScheme: this.user.userPreferences.get().colorScheme,
|
|
48
49
|
isDarkMode: this.getIsDarkMode(),
|
|
@@ -75,6 +76,13 @@ export class UserPreferencesManager {
|
|
|
75
76
|
return this.user.userPreferences.get().animationSpeed ?? defaultUserPreferences.animationSpeed
|
|
76
77
|
}
|
|
77
78
|
|
|
79
|
+
@computed getAreKeyboardShortcutsEnabled() {
|
|
80
|
+
return (
|
|
81
|
+
this.user.userPreferences.get().areKeyboardShortcutsEnabled ??
|
|
82
|
+
defaultUserPreferences.areKeyboardShortcutsEnabled
|
|
83
|
+
)
|
|
84
|
+
}
|
|
85
|
+
|
|
78
86
|
@computed getId() {
|
|
79
87
|
return this.user.userPreferences.get().id
|
|
80
88
|
}
|
|
@@ -21,13 +21,14 @@ export function useMaybeEditor(): Editor | null {
|
|
|
21
21
|
return React.useContext(EditorContext)
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
children,
|
|
27
|
-
}: {
|
|
24
|
+
/** @public */
|
|
25
|
+
export interface EditorProviderProps {
|
|
28
26
|
editor: Editor
|
|
29
27
|
children: React.ReactNode
|
|
30
|
-
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** @public @react */
|
|
31
|
+
export function EditorProvider({ editor, children }: EditorProviderProps) {
|
|
31
32
|
return (
|
|
32
33
|
<EditorContext.Provider value={editor}>
|
|
33
34
|
<IdProvider>{children}</IdProvider>
|
|
@@ -2,7 +2,7 @@ import { Vec, VecLike } from '../Vec'
|
|
|
2
2
|
import { intersectLineSegmentCircle } from '../intersect'
|
|
3
3
|
import { getArcMeasure, getPointInArcT, getPointOnCircle } from '../utils'
|
|
4
4
|
import { Geometry2d, Geometry2dOptions } from './Geometry2d'
|
|
5
|
-
import {
|
|
5
|
+
import { getVerticesCountForArcLength } from './geometry-constants'
|
|
6
6
|
|
|
7
7
|
/** @public */
|
|
8
8
|
export class Arc2d extends Geometry2d {
|
|
@@ -94,7 +94,7 @@ export class Arc2d extends Geometry2d {
|
|
|
94
94
|
getVertices(): Vec[] {
|
|
95
95
|
const { _center, _measure: measure, length, _radius: radius, _angleStart: angleStart } = this
|
|
96
96
|
const vertices: Vec[] = []
|
|
97
|
-
for (let i = 0, n =
|
|
97
|
+
for (let i = 0, n = getVerticesCountForArcLength(Math.abs(length)); i < n + 1; i++) {
|
|
98
98
|
const t = (i / n) * measure
|
|
99
99
|
const angle = angleStart + t
|
|
100
100
|
vertices.push(getPointOnCircle(_center, radius, angle))
|
|
@@ -3,7 +3,7 @@ import { Vec, VecLike } from '../Vec'
|
|
|
3
3
|
import { intersectLineSegmentCircle } from '../intersect'
|
|
4
4
|
import { PI2, getPointOnCircle } from '../utils'
|
|
5
5
|
import { Geometry2d, Geometry2dOptions } from './Geometry2d'
|
|
6
|
-
import {
|
|
6
|
+
import { getVerticesCountForArcLength } from './geometry-constants'
|
|
7
7
|
|
|
8
8
|
/** @public */
|
|
9
9
|
export class Circle2d extends Geometry2d {
|
|
@@ -36,7 +36,7 @@ export class Circle2d extends Geometry2d {
|
|
|
36
36
|
const { _center, _radius: radius } = this
|
|
37
37
|
const perimeter = PI2 * radius
|
|
38
38
|
const vertices: Vec[] = []
|
|
39
|
-
for (let i = 0, n =
|
|
39
|
+
for (let i = 0, n = getVerticesCountForArcLength(perimeter); i < n; i++) {
|
|
40
40
|
const angle = (i / n) * PI2
|
|
41
41
|
vertices.push(getPointOnCircle(_center, radius, angle))
|
|
42
42
|
}
|
|
@@ -8,6 +8,7 @@ export class CubicBezier2d extends Polyline2d {
|
|
|
8
8
|
private _b: Vec
|
|
9
9
|
private _c: Vec
|
|
10
10
|
private _d: Vec
|
|
11
|
+
private _resolution: number
|
|
11
12
|
|
|
12
13
|
constructor(
|
|
13
14
|
config: Omit<Geometry2dOptions, 'isFilled' | 'isClosed'> & {
|
|
@@ -15,6 +16,7 @@ export class CubicBezier2d extends Polyline2d {
|
|
|
15
16
|
cp1: Vec
|
|
16
17
|
cp2: Vec
|
|
17
18
|
end: Vec
|
|
19
|
+
resolution?: number
|
|
18
20
|
}
|
|
19
21
|
) {
|
|
20
22
|
const { start: a, cp1: b, cp2: c, end: d } = config
|
|
@@ -24,13 +26,14 @@ export class CubicBezier2d extends Polyline2d {
|
|
|
24
26
|
this._b = b
|
|
25
27
|
this._c = c
|
|
26
28
|
this._d = d
|
|
29
|
+
this._resolution = config.resolution ?? 10
|
|
27
30
|
}
|
|
28
31
|
|
|
29
32
|
override getVertices() {
|
|
30
33
|
const vertices = [] as Vec[]
|
|
31
34
|
const { _a: a, _b: b, _c: c, _d: d } = this
|
|
32
35
|
// we'll always use ten vertices for each bezier curve
|
|
33
|
-
for (let i = 0, n =
|
|
36
|
+
for (let i = 0, n = this._resolution; i <= n; i++) {
|
|
34
37
|
const t = i / n
|
|
35
38
|
vertices.push(
|
|
36
39
|
new Vec(
|
|
@@ -3,7 +3,7 @@ import { Vec, VecLike } from '../Vec'
|
|
|
3
3
|
import { PI, PI2, clamp, perimeterOfEllipse } from '../utils'
|
|
4
4
|
import { Edge2d } from './Edge2d'
|
|
5
5
|
import { Geometry2d, Geometry2dOptions } from './Geometry2d'
|
|
6
|
-
import {
|
|
6
|
+
import { getVerticesCountForArcLength } from './geometry-constants'
|
|
7
7
|
|
|
8
8
|
/** @public */
|
|
9
9
|
export class Ellipse2d extends Geometry2d {
|
|
@@ -47,7 +47,7 @@ export class Ellipse2d extends Geometry2d {
|
|
|
47
47
|
const q = Math.pow(cx - cy, 2) / Math.pow(cx + cy, 2)
|
|
48
48
|
const p = PI * (cx + cy) * (1 + (3 * q) / (10 + Math.sqrt(4 - 3 * q)))
|
|
49
49
|
// Number of points
|
|
50
|
-
const len =
|
|
50
|
+
const len = getVerticesCountForArcLength(p)
|
|
51
51
|
// Size of step
|
|
52
52
|
const step = PI2 / len
|
|
53
53
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const SPACING = 20
|
|
2
2
|
const MIN_COUNT = 8
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
/** @internal */
|
|
5
|
+
export function getVerticesCountForArcLength(length: number, spacing = SPACING) {
|
|
5
6
|
return Math.max(MIN_COUNT, Math.ceil(length / spacing))
|
|
6
7
|
}
|