@tldraw/editor 3.14.0-canary.ba221e7baf33 → 3.14.0-canary.ba997e465fde
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 +62 -67
- package/dist-cjs/index.js +10 -8
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/editor/Editor.js +43 -71
- package/dist-cjs/lib/editor/Editor.js.map +2 -2
- package/dist-cjs/lib/editor/derivations/bindingsIndex.js +22 -22
- package/dist-cjs/lib/editor/derivations/bindingsIndex.js.map +2 -2
- package/dist-cjs/lib/editor/derivations/parentsToChildren.js +16 -16
- package/dist-cjs/lib/editor/derivations/parentsToChildren.js.map +2 -2
- package/dist-cjs/lib/editor/managers/{ClickManager.js → ClickManager/ClickManager.js} +1 -1
- package/dist-cjs/lib/editor/managers/ClickManager/ClickManager.js.map +7 -0
- package/dist-cjs/lib/editor/managers/{EdgeScrollManager.js → EdgeScrollManager/EdgeScrollManager.js} +2 -2
- package/dist-cjs/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.js.map +7 -0
- package/dist-cjs/lib/editor/managers/FocusManager/FocusManager.js.map +7 -0
- package/dist-cjs/lib/editor/managers/{FontManager.js → FontManager/FontManager.js} +5 -1
- package/dist-cjs/lib/editor/managers/FontManager/FontManager.js.map +7 -0
- package/dist-cjs/lib/editor/managers/{HistoryManager.js → HistoryManager/HistoryManager.js} +64 -6
- package/dist-cjs/lib/editor/managers/HistoryManager/HistoryManager.js.map +7 -0
- package/dist-cjs/lib/editor/managers/{ScribbleManager.js → ScribbleManager/ScribbleManager.js} +1 -1
- package/dist-cjs/lib/editor/managers/ScribbleManager/ScribbleManager.js.map +7 -0
- package/dist-cjs/lib/editor/managers/TextManager/TextManager.js.map +7 -0
- package/dist-cjs/lib/editor/managers/{TickManager.js → TickManager/TickManager.js} +1 -1
- package/dist-cjs/lib/editor/managers/TickManager/TickManager.js.map +7 -0
- package/dist-cjs/lib/editor/managers/{UserPreferencesManager.js → UserPreferencesManager/UserPreferencesManager.js} +1 -1
- package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js.map +7 -0
- package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +1 -1
- package/dist-cjs/lib/exports/getSvgJsx.js.map +1 -1
- package/dist-cjs/lib/primitives/Box.js +39 -33
- package/dist-cjs/lib/primitives/Box.js.map +2 -2
- package/dist-cjs/lib/primitives/Vec.js +13 -8
- package/dist-cjs/lib/primitives/Vec.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Arc2d.js +41 -21
- package/dist-cjs/lib/primitives/geometry/Arc2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Circle2d.js +11 -11
- package/dist-cjs/lib/primitives/geometry/Circle2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/CubicBezier2d.js +13 -16
- package/dist-cjs/lib/primitives/geometry/CubicBezier2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/CubicSpline2d.js +4 -4
- package/dist-cjs/lib/primitives/geometry/CubicSpline2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Edge2d.js +14 -17
- package/dist-cjs/lib/primitives/geometry/Edge2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Ellipse2d.js +10 -10
- package/dist-cjs/lib/primitives/geometry/Ellipse2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Point2d.js +6 -6
- package/dist-cjs/lib/primitives/geometry/Point2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Polygon2d.js +3 -0
- package/dist-cjs/lib/primitives/geometry/Polygon2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Polyline2d.js +8 -5
- package/dist-cjs/lib/primitives/geometry/Polyline2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Rectangle2d.js +22 -11
- package/dist-cjs/lib/primitives/geometry/Rectangle2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Stadium2d.js +22 -22
- package/dist-cjs/lib/primitives/geometry/Stadium2d.js.map +2 -2
- package/dist-cjs/lib/utils/areShapesContentEqual.js +1 -1
- package/dist-cjs/lib/utils/areShapesContentEqual.js.map +2 -2
- package/dist-cjs/lib/utils/reorderShapes.js +11 -10
- package/dist-cjs/lib/utils/reorderShapes.js.map +2 -2
- package/dist-cjs/lib/utils/richText.js.map +1 -1
- package/dist-cjs/version.js +3 -3
- package/dist-cjs/version.js.map +1 -1
- package/dist-esm/index.d.mts +62 -67
- package/dist-esm/index.mjs +14 -8
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/editor/Editor.mjs +43 -71
- package/dist-esm/lib/editor/Editor.mjs.map +2 -2
- package/dist-esm/lib/editor/derivations/bindingsIndex.mjs +22 -22
- package/dist-esm/lib/editor/derivations/bindingsIndex.mjs.map +2 -2
- package/dist-esm/lib/editor/derivations/parentsToChildren.mjs +16 -16
- package/dist-esm/lib/editor/derivations/parentsToChildren.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/{ClickManager.mjs → ClickManager/ClickManager.mjs} +1 -1
- package/dist-esm/lib/editor/managers/ClickManager/ClickManager.mjs.map +7 -0
- package/dist-esm/lib/editor/managers/{EdgeScrollManager.mjs → EdgeScrollManager/EdgeScrollManager.mjs} +2 -2
- package/dist-esm/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.mjs.map +7 -0
- package/dist-esm/lib/editor/managers/FocusManager/FocusManager.mjs.map +7 -0
- package/dist-esm/lib/editor/managers/{FontManager.mjs → FontManager/FontManager.mjs} +5 -1
- package/dist-esm/lib/editor/managers/FontManager/FontManager.mjs.map +7 -0
- package/dist-esm/lib/editor/managers/{HistoryManager.mjs → HistoryManager/HistoryManager.mjs} +60 -2
- package/dist-esm/lib/editor/managers/HistoryManager/HistoryManager.mjs.map +7 -0
- package/dist-esm/lib/editor/managers/{ScribbleManager.mjs → ScribbleManager/ScribbleManager.mjs} +1 -1
- package/dist-esm/lib/editor/managers/ScribbleManager/ScribbleManager.mjs.map +7 -0
- package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs.map +7 -0
- package/dist-esm/lib/editor/managers/{TickManager.mjs → TickManager/TickManager.mjs} +1 -1
- package/dist-esm/lib/editor/managers/TickManager/TickManager.mjs.map +7 -0
- package/dist-esm/lib/editor/managers/{UserPreferencesManager.mjs → UserPreferencesManager/UserPreferencesManager.mjs} +1 -1
- package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs.map +7 -0
- package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +1 -1
- package/dist-esm/lib/exports/getSvgJsx.mjs.map +1 -1
- package/dist-esm/lib/primitives/Box.mjs +39 -33
- package/dist-esm/lib/primitives/Box.mjs.map +2 -2
- package/dist-esm/lib/primitives/Vec.mjs +13 -8
- package/dist-esm/lib/primitives/Vec.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Arc2d.mjs +41 -21
- package/dist-esm/lib/primitives/geometry/Arc2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Circle2d.mjs +11 -11
- package/dist-esm/lib/primitives/geometry/Circle2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/CubicBezier2d.mjs +13 -16
- package/dist-esm/lib/primitives/geometry/CubicBezier2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/CubicSpline2d.mjs +4 -4
- package/dist-esm/lib/primitives/geometry/CubicSpline2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Edge2d.mjs +14 -17
- package/dist-esm/lib/primitives/geometry/Edge2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Ellipse2d.mjs +11 -11
- package/dist-esm/lib/primitives/geometry/Ellipse2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Point2d.mjs +6 -6
- package/dist-esm/lib/primitives/geometry/Point2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Polygon2d.mjs +3 -0
- package/dist-esm/lib/primitives/geometry/Polygon2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Polyline2d.mjs +8 -5
- package/dist-esm/lib/primitives/geometry/Polyline2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Rectangle2d.mjs +22 -11
- package/dist-esm/lib/primitives/geometry/Rectangle2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Stadium2d.mjs +22 -22
- package/dist-esm/lib/primitives/geometry/Stadium2d.mjs.map +2 -2
- package/dist-esm/lib/utils/areShapesContentEqual.mjs +1 -1
- package/dist-esm/lib/utils/areShapesContentEqual.mjs.map +2 -2
- package/dist-esm/lib/utils/reorderShapes.mjs +11 -10
- package/dist-esm/lib/utils/reorderShapes.mjs.map +2 -2
- package/dist-esm/lib/utils/richText.mjs.map +1 -1
- package/dist-esm/version.mjs +3 -3
- package/dist-esm/version.mjs.map +1 -1
- package/package.json +7 -7
- package/src/index.ts +14 -7
- package/src/lib/editor/Editor.test.ts +252 -3
- package/src/lib/editor/Editor.ts +46 -73
- package/src/lib/editor/derivations/bindingsIndex.ts +27 -26
- package/src/lib/editor/derivations/parentsToChildren.ts +28 -25
- package/src/lib/editor/managers/ClickManager/ClickManager.test.ts +442 -0
- package/src/lib/editor/managers/{ClickManager.ts → ClickManager/ClickManager.ts} +3 -3
- package/src/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.test.ts +374 -0
- package/src/lib/editor/managers/{EdgeScrollManager.ts → EdgeScrollManager/EdgeScrollManager.ts} +3 -3
- package/src/lib/editor/managers/FocusManager/FocusManager.test.ts +455 -0
- package/src/lib/editor/managers/{FocusManager.ts → FocusManager/FocusManager.ts} +1 -1
- package/src/lib/editor/managers/FontManager/FontManager.test.ts +263 -0
- package/src/lib/editor/managers/{FontManager.ts → FontManager/FontManager.ts} +6 -2
- package/src/lib/editor/managers/{HistoryManager.test.ts → HistoryManager/HistoryManager.test.ts} +388 -1
- package/src/lib/editor/managers/{HistoryManager.ts → HistoryManager/HistoryManager.ts} +73 -2
- package/src/lib/editor/managers/ScribbleManager/ScribbleManager.test.ts +624 -0
- package/src/lib/editor/managers/{ScribbleManager.ts → ScribbleManager/ScribbleManager.ts} +2 -2
- package/src/lib/editor/managers/SnapManager/SnapManager.test.ts +485 -0
- package/src/lib/editor/managers/TextManager/TextManager.test.ts +411 -0
- package/src/lib/editor/managers/{TextManager.ts → TextManager/TextManager.ts} +1 -1
- package/src/lib/editor/managers/TickManager/TickManager.test.ts +314 -0
- package/src/lib/editor/managers/{TickManager.ts → TickManager/TickManager.ts} +2 -2
- package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.test.ts +591 -0
- package/src/lib/editor/managers/{UserPreferencesManager.ts → UserPreferencesManager/UserPreferencesManager.ts} +2 -2
- package/src/lib/editor/shapes/ShapeUtil.ts +1 -1
- package/src/lib/exports/getSvgJsx.tsx +1 -1
- package/src/lib/primitives/Box.test.ts +588 -7
- package/src/lib/primitives/Box.ts +41 -33
- package/src/lib/primitives/Vec.test.ts +2 -2
- package/src/lib/primitives/Vec.ts +13 -8
- package/src/lib/primitives/geometry/Arc2d.ts +42 -23
- package/src/lib/primitives/geometry/Circle2d.ts +12 -12
- package/src/lib/primitives/geometry/CubicBezier2d.test.ts +5 -0
- package/src/lib/primitives/geometry/CubicBezier2d.ts +13 -17
- package/src/lib/primitives/geometry/CubicSpline2d.ts +5 -5
- package/src/lib/primitives/geometry/Edge2d.ts +14 -18
- package/src/lib/primitives/geometry/Ellipse2d.ts +12 -13
- package/src/lib/primitives/geometry/Point2d.ts +6 -6
- package/src/lib/primitives/geometry/Polygon2d.ts +4 -0
- package/src/lib/primitives/geometry/Polyline2d.ts +10 -7
- package/src/lib/primitives/geometry/Rectangle2d.ts +24 -11
- package/src/lib/primitives/geometry/Stadium2d.ts +22 -23
- package/src/lib/utils/areShapesContentEqual.ts +2 -1
- package/src/lib/utils/reorderShapes.ts +10 -13
- package/src/lib/utils/richText.ts +1 -1
- package/src/version.ts +3 -3
- package/dist-cjs/lib/editor/managers/ClickManager.js.map +0 -7
- package/dist-cjs/lib/editor/managers/EdgeScrollManager.js.map +0 -7
- package/dist-cjs/lib/editor/managers/FocusManager.js.map +0 -7
- package/dist-cjs/lib/editor/managers/FontManager.js.map +0 -7
- package/dist-cjs/lib/editor/managers/HistoryManager.js.map +0 -7
- package/dist-cjs/lib/editor/managers/ScribbleManager.js.map +0 -7
- package/dist-cjs/lib/editor/managers/Stack.js +0 -82
- package/dist-cjs/lib/editor/managers/Stack.js.map +0 -7
- package/dist-cjs/lib/editor/managers/TextManager.js.map +0 -7
- package/dist-cjs/lib/editor/managers/TickManager.js.map +0 -7
- package/dist-cjs/lib/editor/managers/UserPreferencesManager.js.map +0 -7
- package/dist-esm/lib/editor/managers/ClickManager.mjs.map +0 -7
- package/dist-esm/lib/editor/managers/EdgeScrollManager.mjs.map +0 -7
- package/dist-esm/lib/editor/managers/FocusManager.mjs.map +0 -7
- package/dist-esm/lib/editor/managers/FontManager.mjs.map +0 -7
- package/dist-esm/lib/editor/managers/HistoryManager.mjs.map +0 -7
- package/dist-esm/lib/editor/managers/ScribbleManager.mjs.map +0 -7
- package/dist-esm/lib/editor/managers/Stack.mjs +0 -62
- package/dist-esm/lib/editor/managers/Stack.mjs.map +0 -7
- package/dist-esm/lib/editor/managers/TextManager.mjs.map +0 -7
- package/dist-esm/lib/editor/managers/TickManager.mjs.map +0 -7
- package/dist-esm/lib/editor/managers/UserPreferencesManager.mjs.map +0 -7
- package/src/lib/editor/managers/ScribbleManager.test.ts +0 -32
- package/src/lib/editor/managers/Stack.ts +0 -71
- /package/dist-cjs/lib/editor/managers/{FocusManager.js → FocusManager/FocusManager.js} +0 -0
- /package/dist-cjs/lib/editor/managers/{TextManager.js → TextManager/TextManager.js} +0 -0
- /package/dist-esm/lib/editor/managers/{FocusManager.mjs → FocusManager/FocusManager.mjs} +0 -0
- /package/dist-esm/lib/editor/managers/{TextManager.mjs → TextManager/TextManager.mjs} +0 -0
package/dist-esm/version.mjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/version.ts"],
|
|
4
|
-
"sourcesContent": ["// This file is automatically generated by internal/scripts/refresh-assets.ts.\n// Do not edit manually. Or do, I'm a comment, not a cop.\n\nexport const version = '3.14.0-canary.
|
|
4
|
+
"sourcesContent": ["// This file is automatically generated by internal/scripts/refresh-assets.ts.\n// Do not edit manually. Or do, I'm a comment, not a cop.\n\nexport const version = '3.14.0-canary.ba997e465fde'\nexport const publishDates = {\n\tmajor: '2024-09-13T14:36:29.063Z',\n\tminor: '2025-06-10T15:07:57.016Z',\n\tpatch: '2025-06-10T15:07:57.016Z',\n}\n"],
|
|
5
5
|
"mappings": "AAGO,MAAM,UAAU;AAChB,MAAM,eAAe;AAAA,EAC3B,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AACR;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
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.ba997e465fde",
|
|
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.ba997e465fde",
|
|
52
|
+
"@tldraw/state-react": "3.14.0-canary.ba997e465fde",
|
|
53
|
+
"@tldraw/store": "3.14.0-canary.ba997e465fde",
|
|
54
|
+
"@tldraw/tlschema": "3.14.0-canary.ba997e465fde",
|
|
55
|
+
"@tldraw/utils": "3.14.0-canary.ba997e465fde",
|
|
56
|
+
"@tldraw/validate": "3.14.0-canary.ba997e465fde",
|
|
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,6 +4,7 @@ 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
|
+
export { areShapesContentEqual } from './lib/utils/areShapesContentEqual'
|
|
7
8
|
|
|
8
9
|
// eslint-disable-next-line local/no-export-star
|
|
9
10
|
export * from '@tldraw/state'
|
|
@@ -147,15 +148,18 @@ export {
|
|
|
147
148
|
type BindingOnShapeIsolateOptions,
|
|
148
149
|
type TLBindingUtilConstructor,
|
|
149
150
|
} from './lib/editor/bindings/BindingUtil'
|
|
150
|
-
export { ClickManager, type TLClickState } from './lib/editor/managers/ClickManager'
|
|
151
|
-
export { EdgeScrollManager } from './lib/editor/managers/EdgeScrollManager'
|
|
151
|
+
export { ClickManager, type TLClickState } from './lib/editor/managers/ClickManager/ClickManager'
|
|
152
|
+
export { EdgeScrollManager } from './lib/editor/managers/EdgeScrollManager/EdgeScrollManager'
|
|
152
153
|
export {
|
|
153
154
|
FontManager,
|
|
154
155
|
type TLFontFace,
|
|
155
156
|
type TLFontFaceSource,
|
|
156
|
-
} from './lib/editor/managers/FontManager'
|
|
157
|
-
export { HistoryManager } from './lib/editor/managers/HistoryManager'
|
|
158
|
-
export {
|
|
157
|
+
} from './lib/editor/managers/FontManager/FontManager'
|
|
158
|
+
export { HistoryManager } from './lib/editor/managers/HistoryManager/HistoryManager'
|
|
159
|
+
export {
|
|
160
|
+
ScribbleManager,
|
|
161
|
+
type ScribbleItem,
|
|
162
|
+
} from './lib/editor/managers/ScribbleManager/ScribbleManager'
|
|
159
163
|
export {
|
|
160
164
|
BoundsSnaps,
|
|
161
165
|
type BoundsSnapGeometry,
|
|
@@ -169,8 +173,11 @@ export {
|
|
|
169
173
|
type SnapData,
|
|
170
174
|
type SnapIndicator,
|
|
171
175
|
} from './lib/editor/managers/SnapManager/SnapManager'
|
|
172
|
-
export {
|
|
173
|
-
|
|
176
|
+
export {
|
|
177
|
+
TextManager,
|
|
178
|
+
type TLMeasureTextSpanOpts,
|
|
179
|
+
} from './lib/editor/managers/TextManager/TextManager'
|
|
180
|
+
export { UserPreferencesManager } from './lib/editor/managers/UserPreferencesManager/UserPreferencesManager'
|
|
174
181
|
export { BaseBoxShapeUtil, type TLBaseBoxShape } from './lib/editor/shapes/BaseBoxShapeUtil'
|
|
175
182
|
export {
|
|
176
183
|
ShapeUtil,
|
|
@@ -17,6 +17,7 @@ type ICustomShape = TLBaseShape<
|
|
|
17
17
|
w: number
|
|
18
18
|
h: number
|
|
19
19
|
text: string | undefined
|
|
20
|
+
isFilled: boolean
|
|
20
21
|
}
|
|
21
22
|
>
|
|
22
23
|
|
|
@@ -26,19 +27,21 @@ class CustomShape extends ShapeUtil<ICustomShape> {
|
|
|
26
27
|
w: T.number,
|
|
27
28
|
h: T.number,
|
|
28
29
|
text: T.string.optional(),
|
|
30
|
+
isFilled: T.boolean,
|
|
29
31
|
}
|
|
30
32
|
getDefaultProps(): ICustomShape['props'] {
|
|
31
33
|
return {
|
|
32
34
|
w: 200,
|
|
33
35
|
h: 200,
|
|
34
36
|
text: '',
|
|
37
|
+
isFilled: false,
|
|
35
38
|
}
|
|
36
39
|
}
|
|
37
40
|
getGeometry(shape: ICustomShape): Geometry2d {
|
|
38
41
|
return new Rectangle2d({
|
|
39
42
|
width: shape.props.w,
|
|
40
43
|
height: shape.props.h,
|
|
41
|
-
isFilled:
|
|
44
|
+
isFilled: shape.props.isFilled,
|
|
42
45
|
})
|
|
43
46
|
}
|
|
44
47
|
indicator() {}
|
|
@@ -81,11 +84,11 @@ describe('updateShape', () => {
|
|
|
81
84
|
props: { w: 100, h: 100, text: 'Hello' },
|
|
82
85
|
})
|
|
83
86
|
const shape = editor.getShape(id) as ICustomShape
|
|
84
|
-
expect(shape.props).toEqual({ w: 100, h: 100, text: 'Hello' })
|
|
87
|
+
expect(shape.props).toEqual({ w: 100, h: 100, text: 'Hello', isFilled: false })
|
|
85
88
|
|
|
86
89
|
editor.updateShape({ ...shape, props: { ...shape.props, text: undefined } })
|
|
87
90
|
const updatedShape = editor.getShape(id) as ICustomShape
|
|
88
|
-
expect(updatedShape.props).toEqual({ w: 100, h: 100, text: undefined })
|
|
91
|
+
expect(updatedShape.props).toEqual({ w: 100, h: 100, text: undefined, isFilled: false })
|
|
89
92
|
})
|
|
90
93
|
})
|
|
91
94
|
|
|
@@ -176,3 +179,249 @@ describe('zoomToBounds', () => {
|
|
|
176
179
|
expect(editor.setCamera).toHaveBeenCalled()
|
|
177
180
|
})
|
|
178
181
|
})
|
|
182
|
+
|
|
183
|
+
describe('getShapesAtPoint', () => {
|
|
184
|
+
const ids = {
|
|
185
|
+
shape1: createShapeId('shape1'),
|
|
186
|
+
shape2: createShapeId('shape2'),
|
|
187
|
+
shape3: createShapeId('shape3'),
|
|
188
|
+
shape4: createShapeId('shape4'),
|
|
189
|
+
shape5: createShapeId('shape5'),
|
|
190
|
+
overlap1: createShapeId('overlap1'),
|
|
191
|
+
overlap2: createShapeId('overlap2'),
|
|
192
|
+
filledShape: createShapeId('filledShape'),
|
|
193
|
+
hollowShape: createShapeId('hollowShape'),
|
|
194
|
+
hiddenShape: createShapeId('hiddenShape'),
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
beforeEach(() => {
|
|
198
|
+
// Create test shapes with different z-index positions
|
|
199
|
+
// Shape 1: Bottom layer, large square
|
|
200
|
+
editor.createShape({
|
|
201
|
+
id: ids.shape1,
|
|
202
|
+
type: 'my-custom-shape',
|
|
203
|
+
x: 0,
|
|
204
|
+
y: 0,
|
|
205
|
+
props: { w: 200, h: 200, text: 'Bottom' },
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
// Shape 2: Middle layer, overlapping square
|
|
209
|
+
editor.createShape({
|
|
210
|
+
id: ids.shape2,
|
|
211
|
+
type: 'my-custom-shape',
|
|
212
|
+
x: 100,
|
|
213
|
+
y: 0,
|
|
214
|
+
props: { w: 200, h: 200, text: 'Middle' },
|
|
215
|
+
})
|
|
216
|
+
|
|
217
|
+
// Shape 3: Top layer, small square
|
|
218
|
+
editor.createShape({
|
|
219
|
+
id: ids.shape3,
|
|
220
|
+
type: 'my-custom-shape',
|
|
221
|
+
x: 50,
|
|
222
|
+
y: 50,
|
|
223
|
+
props: { w: 100, h: 100, text: 'Top' },
|
|
224
|
+
})
|
|
225
|
+
|
|
226
|
+
// Shape 4: Separate area, no overlap
|
|
227
|
+
editor.createShape({
|
|
228
|
+
id: ids.shape4,
|
|
229
|
+
type: 'my-custom-shape',
|
|
230
|
+
x: 50,
|
|
231
|
+
y: 100,
|
|
232
|
+
props: { w: 100, h: 100, text: 'Separate' },
|
|
233
|
+
})
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
it('returns shapes at a point in reverse z-index order', () => {
|
|
237
|
+
// Point at (50, 50) should hit shape3's edge (since it's at 50,50 with size 100x100)
|
|
238
|
+
// This point is exactly at the top-left corner of shape3
|
|
239
|
+
const shapes = editor.getShapesAtPoint({ x: 50, y: 50 })
|
|
240
|
+
const shapeIds = shapes.map((s) => s.id)
|
|
241
|
+
|
|
242
|
+
expect(shapeIds).toEqual([ids.shape3])
|
|
243
|
+
expect(shapes).toHaveLength(1)
|
|
244
|
+
})
|
|
245
|
+
|
|
246
|
+
it('returns empty array when no shapes at point', () => {
|
|
247
|
+
const shapes = editor.getShapesAtPoint({ x: 1000, y: 1000 })
|
|
248
|
+
expect(shapes).toEqual([])
|
|
249
|
+
})
|
|
250
|
+
|
|
251
|
+
it('returns single shape when point hits only one shape', () => {
|
|
252
|
+
// Point at right edge of shape2 where it doesn't overlap with other shapes
|
|
253
|
+
// Shape2 is at (100,0) with size 200x200, so right edge is at x=300
|
|
254
|
+
const shapes = editor.getShapesAtPoint({ x: 300, y: 100 })
|
|
255
|
+
expect(shapes).toHaveLength(1)
|
|
256
|
+
expect(shapes[0].id).toBe(ids.shape2)
|
|
257
|
+
})
|
|
258
|
+
|
|
259
|
+
it('returns shapes on edge when point is exactly on boundary', () => {
|
|
260
|
+
// Point at exact edge of shape1
|
|
261
|
+
const shapes = editor.getShapesAtPoint({ x: 0, y: 0 })
|
|
262
|
+
expect(shapes).toHaveLength(1)
|
|
263
|
+
expect(shapes[0].id).toBe(ids.shape1)
|
|
264
|
+
})
|
|
265
|
+
|
|
266
|
+
it('respects hitInside option when false (default)', () => {
|
|
267
|
+
// Point inside shape1 (at 0,0 with size 200x200) but with hitInside false should not hit
|
|
268
|
+
const shapes = editor.getShapesAtPoint({ x: 25, y: 25 }, { hitInside: false })
|
|
269
|
+
expect(shapes).toEqual([])
|
|
270
|
+
})
|
|
271
|
+
|
|
272
|
+
it('respects hitInside option when true', () => {
|
|
273
|
+
// Point inside shape1 (at 0,0 with size 200x200) with hitInside true should hit
|
|
274
|
+
const shapes = editor.getShapesAtPoint({ x: 25, y: 25 }, { hitInside: true })
|
|
275
|
+
expect(shapes).toHaveLength(1)
|
|
276
|
+
expect(shapes[0].id).toBe(ids.shape1)
|
|
277
|
+
})
|
|
278
|
+
|
|
279
|
+
it('respects margin option', () => {
|
|
280
|
+
// Point slightly outside shape1 at bottom edge but within margin should hit only shape1
|
|
281
|
+
// Shape1 is at (0,0) with size 200x200, shape2 goes to (300,200) so avoid overlap at (200,200)
|
|
282
|
+
const shapes = editor.getShapesAtPoint({ x: 205, y: 100 }, { margin: 10 })
|
|
283
|
+
expect(shapes).toHaveLength(1)
|
|
284
|
+
expect(shapes[0].id).toBe(ids.shape1)
|
|
285
|
+
})
|
|
286
|
+
|
|
287
|
+
it('filters out hidden shapes', () => {
|
|
288
|
+
// Create a spy to mock isShapeHidden
|
|
289
|
+
const isShapeHiddenSpy = jest.spyOn(editor, 'isShapeHidden')
|
|
290
|
+
isShapeHiddenSpy.mockImplementation((shape) => {
|
|
291
|
+
return typeof shape === 'string' ? shape === ids.shape3 : shape.id === ids.shape3
|
|
292
|
+
})
|
|
293
|
+
|
|
294
|
+
const shapes = editor.getShapesAtPoint({ x: 50, y: 50 })
|
|
295
|
+
const shapeIds = shapes.map((s) => s.id)
|
|
296
|
+
|
|
297
|
+
// Should not include shape3 since it's hidden, and no other shapes are at this point
|
|
298
|
+
expect(shapeIds).toEqual([])
|
|
299
|
+
expect(shapes).toHaveLength(0)
|
|
300
|
+
|
|
301
|
+
isShapeHiddenSpy.mockRestore()
|
|
302
|
+
})
|
|
303
|
+
|
|
304
|
+
it('handles point exactly at shape corner', () => {
|
|
305
|
+
// Point at bottom-left corner of shape1 where it doesn't overlap with other shapes
|
|
306
|
+
const shapes = editor.getShapesAtPoint({ x: 0, y: 200 })
|
|
307
|
+
expect(shapes).toHaveLength(1)
|
|
308
|
+
expect(shapes[0].id).toBe(ids.shape1)
|
|
309
|
+
})
|
|
310
|
+
|
|
311
|
+
it('handles overlapping shapes with different hit areas', () => {
|
|
312
|
+
// Point that hits both shape1 and shape2 edges (they overlap at x=100,y=0)
|
|
313
|
+
const shapes = editor.getShapesAtPoint({ x: 100, y: 0 })
|
|
314
|
+
const shapeIds = shapes.map((s) => s.id)
|
|
315
|
+
|
|
316
|
+
// Both shapes should be detected at this overlapping point (reversed order - top-most first)
|
|
317
|
+
expect(shapeIds).toEqual([ids.shape2, ids.shape1])
|
|
318
|
+
expect(shapes).toHaveLength(2)
|
|
319
|
+
})
|
|
320
|
+
|
|
321
|
+
it('maintains reverse shape order and responds to z-index changes', () => {
|
|
322
|
+
// Create filled shape that overlaps with shape2
|
|
323
|
+
editor.createShape({
|
|
324
|
+
id: ids.shape5,
|
|
325
|
+
type: 'my-custom-shape',
|
|
326
|
+
x: 110,
|
|
327
|
+
y: 110,
|
|
328
|
+
props: { w: 200, h: 200, isFilled: true, text: 'Shape5' },
|
|
329
|
+
})
|
|
330
|
+
|
|
331
|
+
// Test with hitInside to detect multiple shapes
|
|
332
|
+
// Point (120,120) will hit shape1, shape2, shape3, shape4, and shape5 with hitInside: true
|
|
333
|
+
const shapes = editor.getShapesAtPoint({ x: 120, y: 120 }, { hitInside: true })
|
|
334
|
+
const shapeIds = shapes.map((s) => s.id)
|
|
335
|
+
|
|
336
|
+
// All shapes that contain this point should be returned in reverse z-index order (top-most first)
|
|
337
|
+
expect(shapeIds).toEqual([ids.shape5, ids.shape4, ids.shape3, ids.shape2, ids.shape1])
|
|
338
|
+
|
|
339
|
+
// After bringing shape2 to front, order should change (shape2 becomes top-most)
|
|
340
|
+
editor.bringToFront([ids.shape2])
|
|
341
|
+
const shapes2 = editor.getShapesAtPoint({ x: 120, y: 120 }, { hitInside: true })
|
|
342
|
+
const shapeIds2 = shapes2.map((s) => s.id)
|
|
343
|
+
expect(shapeIds2).toEqual([ids.shape2, ids.shape5, ids.shape4, ids.shape3, ids.shape1])
|
|
344
|
+
})
|
|
345
|
+
|
|
346
|
+
it('combines hitInside and margin options', () => {
|
|
347
|
+
// Point inside shape1 (at 0,0 with size 200x200) with hitInside and margin
|
|
348
|
+
const shapes = editor.getShapesAtPoint({ x: 25, y: 25 }, { hitInside: true, margin: 5 })
|
|
349
|
+
expect(shapes).toHaveLength(1)
|
|
350
|
+
expect(shapes[0].id).toBe(ids.shape1)
|
|
351
|
+
})
|
|
352
|
+
|
|
353
|
+
it('returns empty array when all shapes are hidden', () => {
|
|
354
|
+
// Mock all shapes as hidden
|
|
355
|
+
const isShapeHiddenSpy = jest.spyOn(editor, 'isShapeHidden')
|
|
356
|
+
isShapeHiddenSpy.mockReturnValue(true)
|
|
357
|
+
|
|
358
|
+
const shapes = editor.getShapesAtPoint({ x: 50, y: 50 })
|
|
359
|
+
expect(shapes).toEqual([])
|
|
360
|
+
|
|
361
|
+
isShapeHiddenSpy.mockRestore()
|
|
362
|
+
})
|
|
363
|
+
|
|
364
|
+
it('returns multiple shapes at same point in reverse z-index order', () => {
|
|
365
|
+
// Create two shapes at exactly the same position (away from existing shapes)
|
|
366
|
+
editor.createShape({
|
|
367
|
+
id: ids.overlap1,
|
|
368
|
+
type: 'my-custom-shape',
|
|
369
|
+
x: 600,
|
|
370
|
+
y: 600,
|
|
371
|
+
props: { w: 100, h: 100, text: 'First' },
|
|
372
|
+
})
|
|
373
|
+
|
|
374
|
+
editor.createShape({
|
|
375
|
+
id: ids.overlap2,
|
|
376
|
+
type: 'my-custom-shape',
|
|
377
|
+
x: 600,
|
|
378
|
+
y: 600,
|
|
379
|
+
props: { w: 100, h: 100, text: 'Second' },
|
|
380
|
+
})
|
|
381
|
+
|
|
382
|
+
// Test at corner where both shapes' edges meet
|
|
383
|
+
const shapes = editor.getShapesAtPoint({ x: 600, y: 600 })
|
|
384
|
+
const shapeIds = shapes.map((s) => s.id)
|
|
385
|
+
|
|
386
|
+
// Should return both shapes in reverse z-index order (top-most first)
|
|
387
|
+
expect(shapeIds).toEqual([ids.overlap2, ids.overlap1])
|
|
388
|
+
expect(shapes).toHaveLength(2)
|
|
389
|
+
})
|
|
390
|
+
|
|
391
|
+
it('respects isFilled property for hit detection', () => {
|
|
392
|
+
// Create a filled shape
|
|
393
|
+
editor.createShape({
|
|
394
|
+
id: ids.filledShape,
|
|
395
|
+
type: 'my-custom-shape',
|
|
396
|
+
x: 300,
|
|
397
|
+
y: 300,
|
|
398
|
+
props: { w: 100, h: 100, isFilled: true, text: 'Filled' },
|
|
399
|
+
})
|
|
400
|
+
|
|
401
|
+
// Create a hollow shape at the same position
|
|
402
|
+
editor.createShape({
|
|
403
|
+
id: ids.hollowShape,
|
|
404
|
+
type: 'my-custom-shape',
|
|
405
|
+
x: 400,
|
|
406
|
+
y: 300,
|
|
407
|
+
props: { w: 100, h: 100, isFilled: false, text: 'Hollow' },
|
|
408
|
+
})
|
|
409
|
+
|
|
410
|
+
// Test point inside filled shape - should hit without hitInside option
|
|
411
|
+
const filledShapes = editor.getShapesAtPoint({ x: 350, y: 350 })
|
|
412
|
+
expect(filledShapes).toHaveLength(1)
|
|
413
|
+
expect(filledShapes[0].id).toBe(ids.filledShape)
|
|
414
|
+
|
|
415
|
+
// Test point inside hollow shape - should not hit without hitInside option
|
|
416
|
+
const hollowShapes = editor.getShapesAtPoint({ x: 450, y: 350 })
|
|
417
|
+
expect(hollowShapes).toHaveLength(0)
|
|
418
|
+
|
|
419
|
+
// Test point inside hollow shape with hitInside - should hit
|
|
420
|
+
const hollowShapesWithHitInside = editor.getShapesAtPoint(
|
|
421
|
+
{ x: 450, y: 350 },
|
|
422
|
+
{ hitInside: true }
|
|
423
|
+
)
|
|
424
|
+
expect(hollowShapesWithHitInside).toHaveLength(1)
|
|
425
|
+
expect(hollowShapesWithHitInside[0].id).toBe(ids.hollowShape)
|
|
426
|
+
})
|
|
427
|
+
})
|
package/src/lib/editor/Editor.ts
CHANGED
|
@@ -148,16 +148,16 @@ import { bindingsIndex } from './derivations/bindingsIndex'
|
|
|
148
148
|
import { notVisibleShapes } from './derivations/notVisibleShapes'
|
|
149
149
|
import { parentsToChildren } from './derivations/parentsToChildren'
|
|
150
150
|
import { deriveShapeIdsInCurrentPage } from './derivations/shapeIdsInCurrentPage'
|
|
151
|
-
import { ClickManager } from './managers/ClickManager'
|
|
152
|
-
import { EdgeScrollManager } from './managers/EdgeScrollManager'
|
|
153
|
-
import { FocusManager } from './managers/FocusManager'
|
|
154
|
-
import { FontManager } from './managers/FontManager'
|
|
155
|
-
import { HistoryManager } from './managers/HistoryManager'
|
|
156
|
-
import { ScribbleManager } from './managers/ScribbleManager'
|
|
151
|
+
import { ClickManager } from './managers/ClickManager/ClickManager'
|
|
152
|
+
import { EdgeScrollManager } from './managers/EdgeScrollManager/EdgeScrollManager'
|
|
153
|
+
import { FocusManager } from './managers/FocusManager/FocusManager'
|
|
154
|
+
import { FontManager } from './managers/FontManager/FontManager'
|
|
155
|
+
import { HistoryManager } from './managers/HistoryManager/HistoryManager'
|
|
156
|
+
import { ScribbleManager } from './managers/ScribbleManager/ScribbleManager'
|
|
157
157
|
import { SnapManager } from './managers/SnapManager/SnapManager'
|
|
158
|
-
import { TextManager } from './managers/TextManager'
|
|
159
|
-
import { TickManager } from './managers/TickManager'
|
|
160
|
-
import { UserPreferencesManager } from './managers/UserPreferencesManager'
|
|
158
|
+
import { TextManager } from './managers/TextManager/TextManager'
|
|
159
|
+
import { TickManager } from './managers/TickManager/TickManager'
|
|
160
|
+
import { UserPreferencesManager } from './managers/UserPreferencesManager/UserPreferencesManager'
|
|
161
161
|
import { ShapeUtil, TLGeometryOpts, TLResizeMode } from './shapes/ShapeUtil'
|
|
162
162
|
import { RootState } from './tools/RootState'
|
|
163
163
|
import { StateNode, TLStateNodeConstructor } from './tools/StateNode'
|
|
@@ -328,7 +328,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
328
328
|
this.store = store
|
|
329
329
|
this.history = new HistoryManager<TLRecord>({
|
|
330
330
|
store,
|
|
331
|
-
annotateError: (error) => {
|
|
331
|
+
annotateError: (error: any) => {
|
|
332
332
|
this.annotateError(error, { origin: 'history.batch', willCrashApp: true })
|
|
333
333
|
this.crash(error)
|
|
334
334
|
},
|
|
@@ -506,6 +506,8 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
506
506
|
shape: {
|
|
507
507
|
afterChange: (shapeBefore, shapeAfter) => {
|
|
508
508
|
for (const binding of this.getBindingsInvolvingShape(shapeAfter)) {
|
|
509
|
+
if (areShapesContentEqual(shapeBefore, shapeAfter)) continue
|
|
510
|
+
|
|
509
511
|
invalidBindingTypes.add(binding.type)
|
|
510
512
|
if (binding.fromId === shapeAfter.id) {
|
|
511
513
|
this.getBindingUtil(binding).onAfterChangeFromShape?.({
|
|
@@ -3715,10 +3717,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
3715
3717
|
*/
|
|
3716
3718
|
@computed getViewportScreenCenter() {
|
|
3717
3719
|
const viewportScreenBounds = this.getViewportScreenBounds()
|
|
3718
|
-
return new Vec(
|
|
3719
|
-
viewportScreenBounds.midX - viewportScreenBounds.minX,
|
|
3720
|
-
viewportScreenBounds.midY - viewportScreenBounds.minY
|
|
3721
|
-
)
|
|
3720
|
+
return new Vec(viewportScreenBounds.w / 2, viewportScreenBounds.h / 2)
|
|
3722
3721
|
}
|
|
3723
3722
|
|
|
3724
3723
|
/**
|
|
@@ -4644,44 +4643,6 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
4644
4643
|
)! as T
|
|
4645
4644
|
}
|
|
4646
4645
|
|
|
4647
|
-
private _shapePageGeometryCaches: Record<string, ComputedCache<Geometry2d, TLShape>> = {}
|
|
4648
|
-
|
|
4649
|
-
/**
|
|
4650
|
-
* Get the geometry of a shape in page-space.
|
|
4651
|
-
*
|
|
4652
|
-
* @example
|
|
4653
|
-
* ```ts
|
|
4654
|
-
* editor.getShapePageGeometry(myShape)
|
|
4655
|
-
* editor.getShapePageGeometry(myShapeId)
|
|
4656
|
-
* editor.getShapePageGeometry(myShapeId, { context: "arrow" })
|
|
4657
|
-
* ```
|
|
4658
|
-
*
|
|
4659
|
-
* @param shape - The shape (or shape id) to get the geometry for.
|
|
4660
|
-
* @param opts - Additional options about the request for geometry. Passed to {@link ShapeUtil.getGeometry}.
|
|
4661
|
-
*
|
|
4662
|
-
* @public
|
|
4663
|
-
*/
|
|
4664
|
-
getShapePageGeometry<T extends Geometry2d>(shape: TLShape | TLShapeId, opts?: TLGeometryOpts): T {
|
|
4665
|
-
const context = opts?.context ?? 'none'
|
|
4666
|
-
if (!this._shapePageGeometryCaches[context]) {
|
|
4667
|
-
this._shapePageGeometryCaches[context] = this.store.createComputedCache(
|
|
4668
|
-
'bounds',
|
|
4669
|
-
(shape) => {
|
|
4670
|
-
const geometry = this.getShapeGeometry(shape.id, opts)
|
|
4671
|
-
const pageTransform = this.getShapePageTransform(shape.id)
|
|
4672
|
-
return geometry.transform(pageTransform)
|
|
4673
|
-
},
|
|
4674
|
-
{
|
|
4675
|
-
// we only depend directly on the shape id, and changing geometry/transform will update us anyway
|
|
4676
|
-
areRecordsEqual: () => true,
|
|
4677
|
-
}
|
|
4678
|
-
)
|
|
4679
|
-
}
|
|
4680
|
-
return this._shapePageGeometryCaches[context].get(
|
|
4681
|
-
typeof shape === 'string' ? shape : shape.id
|
|
4682
|
-
)! as T
|
|
4683
|
-
}
|
|
4684
|
-
|
|
4685
4646
|
/** @internal */
|
|
4686
4647
|
@computed private _getShapeHandlesCache(): ComputedCache<TLHandle[] | undefined, TLShape> {
|
|
4687
4648
|
return this.store.createComputedCache(
|
|
@@ -4794,7 +4755,10 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
4794
4755
|
/** @internal */
|
|
4795
4756
|
@computed private _getShapePageBoundsCache(): ComputedCache<Box, TLShape> {
|
|
4796
4757
|
return this.store.createComputedCache<Box, TLShape>('pageBoundsCache', (shape) => {
|
|
4797
|
-
|
|
4758
|
+
const pageTransform = this.getShapePageTransform(shape)
|
|
4759
|
+
if (!pageTransform) return undefined
|
|
4760
|
+
const geometry = this.getShapeGeometry(shape)
|
|
4761
|
+
return Box.FromPoints(pageTransform.applyToPoints(geometry.vertices))
|
|
4798
4762
|
})
|
|
4799
4763
|
}
|
|
4800
4764
|
|
|
@@ -4868,11 +4832,12 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
4868
4832
|
if (frameAncestors.length === 0) return undefined
|
|
4869
4833
|
|
|
4870
4834
|
const pageMask = frameAncestors
|
|
4871
|
-
.map<Vec[] | undefined>(
|
|
4872
|
-
|
|
4873
|
-
|
|
4874
|
-
|
|
4875
|
-
|
|
4835
|
+
.map<Vec[] | undefined>((s) => {
|
|
4836
|
+
// Apply the frame transform to the frame outline to get the frame outline in the current page space
|
|
4837
|
+
const geometry = this.getShapeGeometry(s.id)
|
|
4838
|
+
const pageTransform = this.getShapePageTransform(s.id)
|
|
4839
|
+
return pageTransform.applyToPoints(geometry.vertices)
|
|
4840
|
+
})
|
|
4876
4841
|
.reduce((acc, b) => {
|
|
4877
4842
|
if (!(b && acc)) return undefined
|
|
4878
4843
|
const intersection = intersectPolygonPolygon(acc, b)
|
|
@@ -5070,28 +5035,33 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
5070
5035
|
*
|
|
5071
5036
|
* @public
|
|
5072
5037
|
*/
|
|
5073
|
-
isShapeOrAncestorLocked(shape?: TLShape): boolean
|
|
5074
|
-
|
|
5075
|
-
|
|
5076
|
-
|
|
5077
|
-
|
|
5078
|
-
if (shape.isLocked) return true
|
|
5079
|
-
return this.isShapeOrAncestorLocked(this.getShapeParent(shape))
|
|
5038
|
+
isShapeOrAncestorLocked(shape?: TLShape | TLShapeId): boolean {
|
|
5039
|
+
const _shape = shape && this.getShape(shape)
|
|
5040
|
+
if (_shape === undefined) return false
|
|
5041
|
+
if (_shape.isLocked) return true
|
|
5042
|
+
return this.isShapeOrAncestorLocked(this.getShapeParent(_shape))
|
|
5080
5043
|
}
|
|
5081
5044
|
|
|
5045
|
+
/**
|
|
5046
|
+
* Get shapes that are outside of the viewport.
|
|
5047
|
+
*
|
|
5048
|
+
* @public
|
|
5049
|
+
*/
|
|
5082
5050
|
@computed
|
|
5083
|
-
|
|
5084
|
-
return
|
|
5051
|
+
getNotVisibleShapes() {
|
|
5052
|
+
return this._notVisibleShapes.get()
|
|
5085
5053
|
}
|
|
5086
5054
|
|
|
5055
|
+
private _notVisibleShapes = notVisibleShapes(this)
|
|
5056
|
+
|
|
5087
5057
|
/**
|
|
5088
|
-
* Get culled shapes.
|
|
5058
|
+
* Get culled shapes (those that should not render), taking into account which shapes are selected or editing.
|
|
5089
5059
|
*
|
|
5090
5060
|
* @public
|
|
5091
5061
|
*/
|
|
5092
5062
|
@computed
|
|
5093
5063
|
getCulledShapes() {
|
|
5094
|
-
const notVisibleShapes = this.
|
|
5064
|
+
const notVisibleShapes = this.getNotVisibleShapes()
|
|
5095
5065
|
const selectedShapeIds = this.getSelectedShapeIds()
|
|
5096
5066
|
const editingId = this.getEditingShapeId()
|
|
5097
5067
|
const culledShapes = new Set<TLShapeId>(notVisibleShapes)
|
|
@@ -5340,21 +5310,23 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
5340
5310
|
* @example
|
|
5341
5311
|
* ```ts
|
|
5342
5312
|
* editor.getShapesAtPoint({ x: 100, y: 100 })
|
|
5343
|
-
* editor.getShapesAtPoint({ x: 100, y: 100 }, { hitInside: true,
|
|
5313
|
+
* editor.getShapesAtPoint({ x: 100, y: 100 }, { hitInside: true, margin: 8 })
|
|
5344
5314
|
* ```
|
|
5345
5315
|
*
|
|
5346
5316
|
* @param point - The page point to test.
|
|
5347
5317
|
* @param opts - The options for the hit point testing.
|
|
5348
5318
|
*
|
|
5319
|
+
* @returns An array of shapes at the given point, sorted in reverse order of their absolute z-index (top-most shape first).
|
|
5320
|
+
*
|
|
5349
5321
|
* @public
|
|
5350
5322
|
*/
|
|
5351
5323
|
getShapesAtPoint(
|
|
5352
5324
|
point: VecLike,
|
|
5353
5325
|
opts = {} as { margin?: number; hitInside?: boolean }
|
|
5354
5326
|
): TLShape[] {
|
|
5355
|
-
return this.
|
|
5356
|
-
(shape) => !this.isShapeHidden(shape) && this.isPointInShape(shape, point, opts)
|
|
5357
|
-
|
|
5327
|
+
return this.getCurrentPageShapesSorted()
|
|
5328
|
+
.filter((shape) => !this.isShapeHidden(shape) && this.isPointInShape(shape, point, opts))
|
|
5329
|
+
.reverse()
|
|
5358
5330
|
}
|
|
5359
5331
|
|
|
5360
5332
|
/**
|
|
@@ -9303,6 +9275,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
9303
9275
|
if (rootShapes.length === 1) {
|
|
9304
9276
|
const onlyRoot = rootShapes[0] as TLFrameShape
|
|
9305
9277
|
// If the old bounds are in the viewport...
|
|
9278
|
+
// todo: replace frame references with shapes that can accept children
|
|
9306
9279
|
if (this.isShapeOfType<TLFrameShape>(onlyRoot, 'frame')) {
|
|
9307
9280
|
while (
|
|
9308
9281
|
this.getShapesAtPoint(point).some(
|
|
@@ -1,41 +1,42 @@
|
|
|
1
1
|
import { Computed, RESET_VALUE, computed, isUninitialized } from '@tldraw/state'
|
|
2
|
-
import { TLBinding, TLShapeId } from '@tldraw/tlschema'
|
|
2
|
+
import { TLArrowBinding, TLBinding, TLShapeId, TLUnknownBinding } 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
|
-
|
|
9
|
-
const
|
|
10
|
-
const bindingsHistory = store.query.filterHistory('binding')
|
|
11
|
-
const bindingsQuery = store.query.records('binding')
|
|
12
|
-
function fromScratch() {
|
|
13
|
-
const allBindings = bindingsQuery.get() as TLBinding[]
|
|
8
|
+
function fromScratch(bindingsQuery: Computed<(TLArrowBinding | TLUnknownBinding)[], unknown>) {
|
|
9
|
+
const allBindings = bindingsQuery.get() as TLBinding[]
|
|
14
10
|
|
|
15
|
-
|
|
11
|
+
const shapesToBindings: TLBindingsIndex = new Map()
|
|
16
12
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
13
|
+
for (const binding of allBindings) {
|
|
14
|
+
const { fromId, toId } = binding
|
|
15
|
+
const bindingsForFromShape = shapesToBindings.get(fromId)
|
|
16
|
+
if (!bindingsForFromShape) {
|
|
17
|
+
shapesToBindings.set(fromId, [binding])
|
|
18
|
+
} else {
|
|
19
|
+
bindingsForFromShape.push(binding)
|
|
20
|
+
}
|
|
21
|
+
const bindingsForToShape = shapesToBindings.get(toId)
|
|
22
|
+
if (!bindingsForToShape) {
|
|
23
|
+
shapesToBindings.set(toId, [binding])
|
|
24
|
+
} else {
|
|
25
|
+
bindingsForToShape.push(binding)
|
|
31
26
|
}
|
|
32
|
-
|
|
33
|
-
return shape2Binding
|
|
34
27
|
}
|
|
35
28
|
|
|
29
|
+
return shapesToBindings
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export const bindingsIndex = (editor: Editor): Computed<TLBindingsIndex> => {
|
|
33
|
+
const { store } = editor
|
|
34
|
+
const bindingsHistory = store.query.filterHistory('binding')
|
|
35
|
+
const bindingsQuery = store.query.records('binding')
|
|
36
|
+
|
|
36
37
|
return computed<TLBindingsIndex>('arrowBindingsIndex', (_lastValue, lastComputedEpoch) => {
|
|
37
38
|
if (isUninitialized(_lastValue)) {
|
|
38
|
-
return fromScratch()
|
|
39
|
+
return fromScratch(bindingsQuery)
|
|
39
40
|
}
|
|
40
41
|
|
|
41
42
|
const lastValue = _lastValue
|
|
@@ -43,7 +44,7 @@ export const bindingsIndex = (editor: Editor): Computed<TLBindingsIndex> => {
|
|
|
43
44
|
const diff = bindingsHistory.getDiffSince(lastComputedEpoch)
|
|
44
45
|
|
|
45
46
|
if (diff === RESET_VALUE) {
|
|
46
|
-
return fromScratch()
|
|
47
|
+
return fromScratch(bindingsQuery)
|
|
47
48
|
}
|
|
48
49
|
|
|
49
50
|
let nextValue: TLBindingsIndex | undefined = undefined
|