@tldraw/editor 5.2.0-next.b91d4a4551c9 → 5.2.0-next.cd4a35fc06d5
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/README.md +1 -1
- package/dist-cjs/index.d.ts +7 -43
- package/dist-cjs/index.js +3 -4
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/editor/Editor.js +55 -16
- package/dist-cjs/lib/editor/Editor.js.map +3 -3
- package/dist-cjs/lib/editor/managers/ClickManager/ClickManager.js +8 -58
- package/dist-cjs/lib/editor/managers/ClickManager/ClickManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.js +1 -1
- package/dist-cjs/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/FocusManager/FocusManager.js +1 -2
- package/dist-cjs/lib/editor/managers/FocusManager/FocusManager.js.map +2 -2
- package/dist-cjs/lib/editor/overlays/strokeShapeIndicators.js +79 -0
- package/dist-cjs/lib/editor/overlays/strokeShapeIndicators.js.map +7 -0
- package/dist-cjs/lib/editor/tools/StateNode.js.map +2 -2
- package/dist-cjs/lib/editor/types/event-types.js +0 -2
- package/dist-cjs/lib/editor/types/event-types.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 +7 -43
- package/dist-esm/index.mjs +2 -6
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/editor/Editor.mjs +55 -16
- package/dist-esm/lib/editor/Editor.mjs.map +3 -3
- package/dist-esm/lib/editor/managers/ClickManager/ClickManager.mjs +8 -58
- package/dist-esm/lib/editor/managers/ClickManager/ClickManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.mjs +1 -1
- package/dist-esm/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/FocusManager/FocusManager.mjs +1 -2
- package/dist-esm/lib/editor/managers/FocusManager/FocusManager.mjs.map +2 -2
- package/dist-esm/lib/editor/overlays/strokeShapeIndicators.mjs +59 -0
- package/dist-esm/lib/editor/overlays/strokeShapeIndicators.mjs.map +7 -0
- package/dist-esm/lib/editor/tools/StateNode.mjs.map +2 -2
- package/dist-esm/lib/editor/types/event-types.mjs +0 -2
- package/dist-esm/lib/editor/types/event-types.mjs.map +2 -2
- package/dist-esm/version.mjs +3 -3
- package/dist-esm/version.mjs.map +1 -1
- package/editor.css +2 -0
- package/package.json +8 -8
- package/src/index.ts +1 -5
- package/src/lib/editor/Editor.ts +87 -24
- package/src/lib/editor/managers/ClickManager/ClickManager.test.ts +54 -74
- package/src/lib/editor/managers/ClickManager/ClickManager.ts +15 -65
- package/src/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.test.ts +14 -0
- package/src/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.ts +6 -3
- package/src/lib/editor/managers/FocusManager/FocusManager.test.ts +4 -4
- package/src/lib/editor/managers/FocusManager/FocusManager.ts +1 -2
- package/src/lib/editor/managers/FontManager/FontManager.test.ts +13 -9
- package/src/lib/editor/managers/TextManager/TextManager.test.ts +16 -14
- package/src/lib/editor/overlays/strokeShapeIndicators.ts +86 -0
- package/src/lib/editor/tools/StateNode.ts +0 -2
- package/src/lib/editor/types/event-types.ts +2 -6
- package/src/version.ts +3 -3
- package/dist-cjs/lib/editor/overlays/ShapeIndicatorOverlayUtil.js +0 -161
- package/dist-cjs/lib/editor/overlays/ShapeIndicatorOverlayUtil.js.map +0 -7
- package/dist-esm/lib/editor/overlays/ShapeIndicatorOverlayUtil.mjs +0 -141
- package/dist-esm/lib/editor/overlays/ShapeIndicatorOverlayUtil.mjs.map +0 -7
- package/src/lib/editor/overlays/ShapeIndicatorOverlayUtil.ts +0 -216
|
@@ -1,216 +0,0 @@
|
|
|
1
|
-
import { computed } from '@tldraw/state'
|
|
2
|
-
import { createComputedCache } from '@tldraw/store'
|
|
3
|
-
import { TLShape, TLShapeId } from '@tldraw/tlschema'
|
|
4
|
-
import type { Editor } from '../Editor'
|
|
5
|
-
import { OverlayUtil, TLOverlay } from './OverlayUtil'
|
|
6
|
-
|
|
7
|
-
interface RelevantInstanceFlags {
|
|
8
|
-
isChangingStyle: boolean
|
|
9
|
-
isHoveringCanvas: boolean | null
|
|
10
|
-
isCoarsePointer: boolean
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
/** @public */
|
|
14
|
-
export interface TLShapeIndicatorOverlay extends TLOverlay {
|
|
15
|
-
props: {
|
|
16
|
-
idsToDisplay: TLShapeId[]
|
|
17
|
-
hintingShapeIds: TLShapeId[]
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const indicatorPathCache = createComputedCache(
|
|
22
|
-
'shapeIndicatorPath',
|
|
23
|
-
(editor: Editor, shape: TLShape) => {
|
|
24
|
-
const util = editor.getShapeUtil(shape)
|
|
25
|
-
return util.getIndicatorPath(shape)
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
areRecordsEqual(a, b) {
|
|
29
|
-
return a.props === b.props
|
|
30
|
-
},
|
|
31
|
-
}
|
|
32
|
-
)
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Combine every batchable shape indicator into a single page-space `Path2D` and
|
|
36
|
-
* emit one stroke call. Shapes whose indicator needs an evenodd clip (e.g.
|
|
37
|
-
* arrows with labels or complex arrowheads) can't be batched — they still
|
|
38
|
-
* stroke individually inside a save/restore with `ctx.clip` applied.
|
|
39
|
-
*
|
|
40
|
-
* Shared by {@link ShapeIndicatorOverlayUtil} and any overlay util that paints
|
|
41
|
-
* shape indicators (e.g. collaborator selections).
|
|
42
|
-
*
|
|
43
|
-
* @public
|
|
44
|
-
*/
|
|
45
|
-
export function strokeShapeIndicators(
|
|
46
|
-
editor: Editor,
|
|
47
|
-
ctx: CanvasRenderingContext2D,
|
|
48
|
-
shapeIds: TLShapeId[]
|
|
49
|
-
): void {
|
|
50
|
-
if (shapeIds.length === 0) return
|
|
51
|
-
|
|
52
|
-
const batched = new Path2D()
|
|
53
|
-
|
|
54
|
-
for (const shapeId of shapeIds) {
|
|
55
|
-
const shape = editor.getShape(shapeId)
|
|
56
|
-
if (!shape || shape.isLocked) continue
|
|
57
|
-
|
|
58
|
-
const pageTransform = editor.getShapePageTransform(shape)
|
|
59
|
-
if (!pageTransform) continue
|
|
60
|
-
|
|
61
|
-
const indicatorPath = indicatorPathCache.get(editor, shape.id)
|
|
62
|
-
if (!indicatorPath) continue
|
|
63
|
-
|
|
64
|
-
if (indicatorPath instanceof Path2D) {
|
|
65
|
-
batched.addPath(indicatorPath, pageTransform)
|
|
66
|
-
continue
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const { path, clipPath, additionalPaths } = indicatorPath
|
|
70
|
-
|
|
71
|
-
if (!clipPath) {
|
|
72
|
-
batched.addPath(path, pageTransform)
|
|
73
|
-
if (additionalPaths) {
|
|
74
|
-
for (const p of additionalPaths) batched.addPath(p, pageTransform)
|
|
75
|
-
}
|
|
76
|
-
continue
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// Clipped case: fall back to an individual stroke. Rare (arrows with
|
|
80
|
-
// labels / complex arrowheads), so the extra save/restore/stroke
|
|
81
|
-
// pair per such shape isn't worth batching away.
|
|
82
|
-
ctx.save()
|
|
83
|
-
ctx.transform(
|
|
84
|
-
pageTransform.a,
|
|
85
|
-
pageTransform.b,
|
|
86
|
-
pageTransform.c,
|
|
87
|
-
pageTransform.d,
|
|
88
|
-
pageTransform.e,
|
|
89
|
-
pageTransform.f
|
|
90
|
-
)
|
|
91
|
-
ctx.save()
|
|
92
|
-
ctx.clip(clipPath, 'evenodd')
|
|
93
|
-
ctx.stroke(path)
|
|
94
|
-
ctx.restore()
|
|
95
|
-
if (additionalPaths) {
|
|
96
|
-
for (const p of additionalPaths) ctx.stroke(p)
|
|
97
|
-
}
|
|
98
|
-
ctx.restore()
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
ctx.stroke(batched)
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Overlay util for shape indicators — the selection / hover / hint outlines drawn
|
|
106
|
-
* under the selection foreground. Paints local indicators in the theme's
|
|
107
|
-
* selection color.
|
|
108
|
-
*
|
|
109
|
-
* Remote collaborator selection indicators are drawn by a separate overlay util
|
|
110
|
-
* (e.g. `CollaboratorShapeIndicatorOverlayUtil` from `tldraw`) that runs at a
|
|
111
|
-
* lower z-index so peer selections appear under the local indicators.
|
|
112
|
-
*
|
|
113
|
-
* Non-interactive: contributes no hit-test geometry.
|
|
114
|
-
*
|
|
115
|
-
* @public
|
|
116
|
-
*/
|
|
117
|
-
export class ShapeIndicatorOverlayUtil extends OverlayUtil<TLShapeIndicatorOverlay> {
|
|
118
|
-
static override type = 'shape_indicator'
|
|
119
|
-
override options = { zIndex: 50, lineWidth: 1.5, hintedLineWidth: 2.5 }
|
|
120
|
-
|
|
121
|
-
// Narrow projection of instance state. Reading the full record would
|
|
122
|
-
// re-fire getOverlays on every cursor move / brush update; gating on these
|
|
123
|
-
// three booleans means we only re-fire when one of them actually flips.
|
|
124
|
-
private _instanceFlags$ = computed<RelevantInstanceFlags>(
|
|
125
|
-
'shape indicator instance flags',
|
|
126
|
-
() => {
|
|
127
|
-
const i = this.editor.getInstanceState()
|
|
128
|
-
return {
|
|
129
|
-
isChangingStyle: i.isChangingStyle,
|
|
130
|
-
isHoveringCanvas: i.isHoveringCanvas,
|
|
131
|
-
isCoarsePointer: i.isCoarsePointer,
|
|
132
|
-
}
|
|
133
|
-
},
|
|
134
|
-
{
|
|
135
|
-
isEqual: (a, b) =>
|
|
136
|
-
a.isChangingStyle === b.isChangingStyle &&
|
|
137
|
-
a.isHoveringCanvas === b.isHoveringCanvas &&
|
|
138
|
-
a.isCoarsePointer === b.isCoarsePointer,
|
|
139
|
-
}
|
|
140
|
-
)
|
|
141
|
-
|
|
142
|
-
override isActive(): boolean {
|
|
143
|
-
return true
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
override getOverlays(): TLShapeIndicatorOverlay[] {
|
|
147
|
-
const editor = this.editor
|
|
148
|
-
const renderingShapeIds = new Set(editor.getRenderingShapes().map((s) => s.id))
|
|
149
|
-
|
|
150
|
-
// Local selected / hovered indicators.
|
|
151
|
-
const idsToDisplay: TLShapeId[] = []
|
|
152
|
-
const { isChangingStyle, isHoveringCanvas, isCoarsePointer } = this._instanceFlags$.get()
|
|
153
|
-
const isIdleOrEditing = editor.isInAny('select.idle', 'select.editing_shape')
|
|
154
|
-
const isInSelectState = editor.isInAny(
|
|
155
|
-
'select.brushing',
|
|
156
|
-
'select.scribble_brushing',
|
|
157
|
-
'select.pointing_shape',
|
|
158
|
-
'select.pointing_selection',
|
|
159
|
-
'select.pointing_handle'
|
|
160
|
-
)
|
|
161
|
-
|
|
162
|
-
if (!isChangingStyle && (isIdleOrEditing || isInSelectState)) {
|
|
163
|
-
for (const id of editor.getSelectedShapeIds()) {
|
|
164
|
-
if (renderingShapeIds.has(id)) idsToDisplay.push(id)
|
|
165
|
-
}
|
|
166
|
-
if (isIdleOrEditing && isHoveringCanvas && !isCoarsePointer) {
|
|
167
|
-
const hovered = editor.getHoveredShapeId()
|
|
168
|
-
if (hovered && renderingShapeIds.has(hovered) && !idsToDisplay.includes(hovered)) {
|
|
169
|
-
idsToDisplay.push(hovered)
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
// Hinted shapes (drawn thicker). Already deduped at write time in
|
|
175
|
-
// `updateHintingShapeIds`, so no need to dedupe again here.
|
|
176
|
-
const hintingShapeIds: TLShapeId[] = []
|
|
177
|
-
for (const id of editor.getHintingShapeIds()) {
|
|
178
|
-
if (renderingShapeIds.has(id)) hintingShapeIds.push(id)
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
if (idsToDisplay.length === 0 && hintingShapeIds.length === 0) {
|
|
182
|
-
return []
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
return [
|
|
186
|
-
{
|
|
187
|
-
id: 'shape_indicator',
|
|
188
|
-
type: 'shape_indicator',
|
|
189
|
-
props: { idsToDisplay, hintingShapeIds },
|
|
190
|
-
},
|
|
191
|
-
]
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
override render(ctx: CanvasRenderingContext2D, overlays: TLShapeIndicatorOverlay[]): void {
|
|
195
|
-
const overlay = overlays[0]
|
|
196
|
-
if (!overlay) return
|
|
197
|
-
|
|
198
|
-
const editor = this.editor
|
|
199
|
-
const zoom = editor.getZoomLevel()
|
|
200
|
-
const { idsToDisplay, hintingShapeIds } = overlay.props
|
|
201
|
-
|
|
202
|
-
ctx.lineCap = 'round'
|
|
203
|
-
ctx.lineJoin = 'round'
|
|
204
|
-
|
|
205
|
-
// Local selected / hovered indicators — one stroke call for the whole batch.
|
|
206
|
-
ctx.strokeStyle = editor.getCurrentTheme().colors[editor.getColorMode()].selectionStroke
|
|
207
|
-
ctx.lineWidth = this.options.lineWidth / zoom
|
|
208
|
-
strokeShapeIndicators(editor, ctx, idsToDisplay)
|
|
209
|
-
|
|
210
|
-
// Hinted shapes — thicker stroke, one call for the whole batch.
|
|
211
|
-
if (hintingShapeIds.length > 0) {
|
|
212
|
-
ctx.lineWidth = this.options.hintedLineWidth / zoom
|
|
213
|
-
strokeShapeIndicators(editor, ctx, hintingShapeIds)
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
}
|