@tldraw/editor 4.6.0-next.fe1474dc57d8 → 5.0.0
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 +412 -179
- package/dist-cjs/index.js +12 -23
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/TldrawEditor.js +3 -0
- package/dist-cjs/lib/TldrawEditor.js.map +2 -2
- package/dist-cjs/lib/components/default-components/CanvasOverlays.js +180 -0
- package/dist-cjs/lib/components/default-components/CanvasOverlays.js.map +7 -0
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js +44 -249
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +3 -3
- package/dist-cjs/lib/editor/Editor.js +78 -28
- package/dist-cjs/lib/editor/Editor.js.map +2 -2
- package/dist-cjs/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.js +98 -0
- package/dist-cjs/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.js.map +7 -0
- package/dist-cjs/lib/editor/managers/ThemeManager/defaultThemes.js +14 -0
- package/dist-cjs/lib/editor/managers/ThemeManager/defaultThemes.js.map +2 -2
- package/dist-cjs/lib/editor/overlays/OverlayManager.js +154 -0
- package/dist-cjs/lib/editor/overlays/OverlayManager.js.map +7 -0
- package/dist-cjs/lib/editor/overlays/OverlayUtil.js +92 -0
- package/dist-cjs/lib/editor/overlays/OverlayUtil.js.map +7 -0
- package/dist-cjs/lib/editor/overlays/ShapeIndicatorOverlayUtil.js +161 -0
- package/dist-cjs/lib/editor/overlays/ShapeIndicatorOverlayUtil.js.map +7 -0
- package/dist-cjs/lib/editor/overlays/getOverlayDisplayValues.js +39 -0
- package/dist-cjs/lib/editor/overlays/getOverlayDisplayValues.js.map +7 -0
- package/dist-cjs/lib/editor/shapes/BaseFrameLikeShapeUtil.js +3 -0
- package/dist-cjs/lib/editor/shapes/BaseFrameLikeShapeUtil.js.map +2 -2
- package/dist-cjs/lib/editor/shapes/ShapeUtil.js +25 -23
- package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
- package/dist-cjs/lib/editor/shapes/group/GroupShapeUtil.js +32 -2
- package/dist-cjs/lib/editor/shapes/group/GroupShapeUtil.js.map +2 -2
- package/dist-cjs/lib/editor/types/event-types.js.map +2 -2
- package/dist-cjs/lib/exports/fetchCache.js +1 -1
- package/dist-cjs/lib/exports/fetchCache.js.map +2 -2
- package/dist-cjs/lib/hooks/EditorComponentsContext.js.map +2 -2
- package/dist-cjs/lib/hooks/useCanvasEvents.js +3 -3
- package/dist-cjs/lib/hooks/useCanvasEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/useEditorComponents.js +0 -28
- package/dist-cjs/lib/hooks/useEditorComponents.js.map +2 -2
- package/dist-cjs/lib/hooks/usePeerIds.js +1 -36
- package/dist-cjs/lib/hooks/usePeerIds.js.map +2 -2
- package/dist-cjs/lib/hooks/useShapeCulling.js +2 -1
- package/dist-cjs/lib/hooks/useShapeCulling.js.map +2 -2
- package/dist-cjs/lib/options.js +0 -1
- package/dist-cjs/lib/options.js.map +2 -2
- package/dist-cjs/lib/utils/reparenting.js +20 -7
- package/dist-cjs/lib/utils/reparenting.js.map +2 -2
- package/dist-cjs/lib/utils/sync/TLLocalSyncClient.js +3 -0
- package/dist-cjs/lib/utils/sync/TLLocalSyncClient.js.map +2 -2
- package/dist-cjs/version.js +4 -4
- package/dist-cjs/version.js.map +1 -1
- package/dist-esm/index.d.mts +412 -179
- package/dist-esm/index.mjs +19 -41
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/TldrawEditor.mjs +3 -0
- package/dist-esm/lib/TldrawEditor.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/CanvasOverlays.mjs +160 -0
- package/dist-esm/lib/components/default-components/CanvasOverlays.mjs.map +7 -0
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +45 -250
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +3 -3
- package/dist-esm/lib/editor/Editor.mjs +78 -29
- package/dist-esm/lib/editor/Editor.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.mjs +83 -0
- package/dist-esm/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.mjs.map +7 -0
- package/dist-esm/lib/editor/managers/ThemeManager/defaultThemes.mjs +14 -0
- package/dist-esm/lib/editor/managers/ThemeManager/defaultThemes.mjs.map +2 -2
- package/dist-esm/lib/editor/overlays/OverlayManager.mjs +136 -0
- package/dist-esm/lib/editor/overlays/OverlayManager.mjs.map +7 -0
- package/dist-esm/lib/editor/overlays/OverlayUtil.mjs +72 -0
- package/dist-esm/lib/editor/overlays/OverlayUtil.mjs.map +7 -0
- package/dist-esm/lib/editor/overlays/ShapeIndicatorOverlayUtil.mjs +141 -0
- package/dist-esm/lib/editor/overlays/ShapeIndicatorOverlayUtil.mjs.map +7 -0
- package/dist-esm/lib/editor/overlays/getOverlayDisplayValues.mjs +19 -0
- package/dist-esm/lib/editor/overlays/getOverlayDisplayValues.mjs.map +7 -0
- package/dist-esm/lib/editor/shapes/BaseFrameLikeShapeUtil.mjs +3 -0
- package/dist-esm/lib/editor/shapes/BaseFrameLikeShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/editor/shapes/ShapeUtil.mjs +25 -23
- package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/editor/shapes/group/GroupShapeUtil.mjs +32 -2
- package/dist-esm/lib/editor/shapes/group/GroupShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/editor/types/event-types.mjs.map +2 -2
- package/dist-esm/lib/exports/fetchCache.mjs +2 -2
- package/dist-esm/lib/exports/fetchCache.mjs.map +2 -2
- package/dist-esm/lib/hooks/EditorComponentsContext.mjs.map +2 -2
- package/dist-esm/lib/hooks/useCanvasEvents.mjs +3 -3
- package/dist-esm/lib/hooks/useCanvasEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useEditorComponents.mjs +0 -28
- package/dist-esm/lib/hooks/useEditorComponents.mjs.map +2 -2
- package/dist-esm/lib/hooks/usePeerIds.mjs +2 -40
- package/dist-esm/lib/hooks/usePeerIds.mjs.map +2 -2
- package/dist-esm/lib/hooks/useShapeCulling.mjs +2 -1
- package/dist-esm/lib/hooks/useShapeCulling.mjs.map +2 -2
- package/dist-esm/lib/options.mjs +0 -1
- package/dist-esm/lib/options.mjs.map +2 -2
- package/dist-esm/lib/utils/reparenting.mjs +20 -7
- package/dist-esm/lib/utils/reparenting.mjs.map +2 -2
- package/dist-esm/lib/utils/sync/TLLocalSyncClient.mjs +3 -0
- package/dist-esm/lib/utils/sync/TLLocalSyncClient.mjs.map +2 -2
- package/dist-esm/version.mjs +4 -4
- package/dist-esm/version.mjs.map +1 -1
- package/editor.css +4 -239
- package/package.json +7 -7
- package/src/index.ts +17 -39
- package/src/lib/TldrawEditor.tsx +9 -0
- package/src/lib/components/default-components/CanvasOverlays.tsx +208 -0
- package/src/lib/components/default-components/DefaultCanvas.tsx +49 -324
- package/src/lib/editor/Editor.test.ts +3 -1
- package/src/lib/editor/Editor.ts +80 -24
- package/src/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.ts +98 -0
- package/src/lib/editor/managers/ThemeManager/defaultThemes.ts +14 -0
- package/src/lib/editor/overlays/OverlayManager.ts +183 -0
- package/src/lib/editor/overlays/OverlayUtil.ts +143 -0
- package/src/lib/editor/overlays/ShapeIndicatorOverlayUtil.ts +216 -0
- package/src/lib/editor/overlays/getOverlayDisplayValues.ts +51 -0
- package/src/lib/editor/shapes/BaseFrameLikeShapeUtil.tsx +9 -2
- package/src/lib/editor/shapes/ShapeUtil.ts +34 -26
- package/src/lib/editor/shapes/group/GroupShapeUtil.tsx +40 -3
- package/src/lib/editor/types/event-types.ts +2 -0
- package/src/lib/exports/fetchCache.ts +2 -4
- package/src/lib/exports/getSvgJsx.test.ts +3 -1
- package/src/lib/hooks/EditorComponentsContext.tsx +0 -27
- package/src/lib/hooks/useCanvasEvents.ts +13 -8
- package/src/lib/hooks/useEditorComponents.tsx +0 -28
- package/src/lib/hooks/usePeerIds.ts +6 -55
- package/src/lib/hooks/useShapeCulling.tsx +3 -1
- package/src/lib/options.ts +0 -7
- package/src/lib/utils/reparenting.ts +22 -9
- package/src/lib/utils/sync/TLLocalSyncClient.ts +3 -0
- package/src/version.ts +4 -4
- package/dist-cjs/lib/components/GeometryDebuggingView.js +0 -115
- package/dist-cjs/lib/components/GeometryDebuggingView.js.map +0 -7
- package/dist-cjs/lib/components/LiveCollaborators.js +0 -152
- package/dist-cjs/lib/components/LiveCollaborators.js.map +0 -7
- package/dist-cjs/lib/components/default-components/CanvasShapeIndicators.js +0 -234
- package/dist-cjs/lib/components/default-components/CanvasShapeIndicators.js.map +0 -7
- package/dist-cjs/lib/components/default-components/DefaultBrush.js +0 -38
- package/dist-cjs/lib/components/default-components/DefaultBrush.js.map +0 -7
- package/dist-cjs/lib/components/default-components/DefaultCollaboratorHint.js +0 -71
- package/dist-cjs/lib/components/default-components/DefaultCollaboratorHint.js.map +0 -7
- package/dist-cjs/lib/components/default-components/DefaultCursor.js +0 -59
- package/dist-cjs/lib/components/default-components/DefaultCursor.js.map +0 -7
- package/dist-cjs/lib/components/default-components/DefaultHandle.js +0 -56
- package/dist-cjs/lib/components/default-components/DefaultHandle.js.map +0 -7
- package/dist-cjs/lib/components/default-components/DefaultHandles.js +0 -28
- package/dist-cjs/lib/components/default-components/DefaultHandles.js.map +0 -7
- package/dist-cjs/lib/components/default-components/DefaultScribble.js +0 -51
- package/dist-cjs/lib/components/default-components/DefaultScribble.js.map +0 -7
- package/dist-cjs/lib/components/default-components/DefaultSelectionForeground.js +0 -69
- package/dist-cjs/lib/components/default-components/DefaultSelectionForeground.js.map +0 -7
- package/dist-cjs/lib/components/default-components/DefaultShapeIndicator.js +0 -107
- package/dist-cjs/lib/components/default-components/DefaultShapeIndicator.js.map +0 -7
- package/dist-cjs/lib/components/default-components/DefaultShapeIndicatorErrorFallback.js +0 -28
- package/dist-cjs/lib/components/default-components/DefaultShapeIndicatorErrorFallback.js.map +0 -7
- package/dist-cjs/lib/components/default-components/DefaultShapeIndicators.js +0 -102
- package/dist-cjs/lib/components/default-components/DefaultShapeIndicators.js.map +0 -7
- package/dist-cjs/lib/components/default-components/DefaultSnapIndictor.js +0 -170
- package/dist-cjs/lib/components/default-components/DefaultSnapIndictor.js.map +0 -7
- package/dist-cjs/lib/hooks/useHandleEvents.js +0 -100
- package/dist-cjs/lib/hooks/useHandleEvents.js.map +0 -7
- package/dist-cjs/lib/hooks/useSelectionEvents.js +0 -98
- package/dist-cjs/lib/hooks/useSelectionEvents.js.map +0 -7
- package/dist-esm/lib/components/GeometryDebuggingView.mjs +0 -95
- package/dist-esm/lib/components/GeometryDebuggingView.mjs.map +0 -7
- package/dist-esm/lib/components/LiveCollaborators.mjs +0 -135
- package/dist-esm/lib/components/LiveCollaborators.mjs.map +0 -7
- package/dist-esm/lib/components/default-components/CanvasShapeIndicators.mjs +0 -214
- package/dist-esm/lib/components/default-components/CanvasShapeIndicators.mjs.map +0 -7
- package/dist-esm/lib/components/default-components/DefaultBrush.mjs +0 -18
- package/dist-esm/lib/components/default-components/DefaultBrush.mjs.map +0 -7
- package/dist-esm/lib/components/default-components/DefaultCollaboratorHint.mjs +0 -41
- package/dist-esm/lib/components/default-components/DefaultCollaboratorHint.mjs.map +0 -7
- package/dist-esm/lib/components/default-components/DefaultCursor.mjs +0 -29
- package/dist-esm/lib/components/default-components/DefaultCursor.mjs.map +0 -7
- package/dist-esm/lib/components/default-components/DefaultHandle.mjs +0 -26
- package/dist-esm/lib/components/default-components/DefaultHandle.mjs.map +0 -7
- package/dist-esm/lib/components/default-components/DefaultHandles.mjs +0 -8
- package/dist-esm/lib/components/default-components/DefaultHandles.mjs.map +0 -7
- package/dist-esm/lib/components/default-components/DefaultScribble.mjs +0 -21
- package/dist-esm/lib/components/default-components/DefaultScribble.mjs.map +0 -7
- package/dist-esm/lib/components/default-components/DefaultSelectionForeground.mjs +0 -39
- package/dist-esm/lib/components/default-components/DefaultSelectionForeground.mjs.map +0 -7
- package/dist-esm/lib/components/default-components/DefaultShapeIndicator.mjs +0 -77
- package/dist-esm/lib/components/default-components/DefaultShapeIndicator.mjs.map +0 -7
- package/dist-esm/lib/components/default-components/DefaultShapeIndicatorErrorFallback.mjs +0 -8
- package/dist-esm/lib/components/default-components/DefaultShapeIndicatorErrorFallback.mjs.map +0 -7
- package/dist-esm/lib/components/default-components/DefaultShapeIndicators.mjs +0 -82
- package/dist-esm/lib/components/default-components/DefaultShapeIndicators.mjs.map +0 -7
- package/dist-esm/lib/components/default-components/DefaultSnapIndictor.mjs +0 -142
- package/dist-esm/lib/components/default-components/DefaultSnapIndictor.mjs.map +0 -7
- package/dist-esm/lib/hooks/useHandleEvents.mjs +0 -70
- package/dist-esm/lib/hooks/useHandleEvents.mjs.map +0 -7
- package/dist-esm/lib/hooks/useSelectionEvents.mjs +0 -78
- package/dist-esm/lib/hooks/useSelectionEvents.mjs.map +0 -7
- package/src/lib/components/GeometryDebuggingView.tsx +0 -108
- package/src/lib/components/LiveCollaborators.tsx +0 -180
- package/src/lib/components/default-components/CanvasShapeIndicators.tsx +0 -300
- package/src/lib/components/default-components/DefaultBrush.tsx +0 -35
- package/src/lib/components/default-components/DefaultCollaboratorHint.tsx +0 -52
- package/src/lib/components/default-components/DefaultCursor.tsx +0 -59
- package/src/lib/components/default-components/DefaultHandle.tsx +0 -42
- package/src/lib/components/default-components/DefaultHandles.tsx +0 -15
- package/src/lib/components/default-components/DefaultScribble.tsx +0 -31
- package/src/lib/components/default-components/DefaultSelectionForeground.tsx +0 -50
- package/src/lib/components/default-components/DefaultShapeIndicator.tsx +0 -104
- package/src/lib/components/default-components/DefaultShapeIndicatorErrorFallback.tsx +0 -9
- package/src/lib/components/default-components/DefaultShapeIndicators.tsx +0 -118
- package/src/lib/components/default-components/DefaultSnapIndictor.tsx +0 -174
- package/src/lib/hooks/useHandleEvents.ts +0 -88
- package/src/lib/hooks/useSelectionEvents.ts +0 -97
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
import { track } from '@tldraw/state-react'
|
|
2
|
-
import { TLInstancePresence } from '@tldraw/tlschema'
|
|
3
|
-
import { useEffect, useRef, useState } from 'react'
|
|
4
|
-
import { Editor } from '../editor/Editor'
|
|
5
|
-
import { useEditorComponents } from '../hooks/EditorComponentsContext'
|
|
6
|
-
import { useEditor } from '../hooks/useEditor'
|
|
7
|
-
import { usePeerIds } from '../hooks/usePeerIds'
|
|
8
|
-
import { usePresence } from '../hooks/usePresence'
|
|
9
|
-
import {
|
|
10
|
-
CollaboratorState,
|
|
11
|
-
getCollaboratorStateFromElapsedTime,
|
|
12
|
-
shouldShowCollaborator,
|
|
13
|
-
} from '../utils/collaboratorState'
|
|
14
|
-
|
|
15
|
-
export const LiveCollaborators = track(function Collaborators() {
|
|
16
|
-
const peerIds = usePeerIds()
|
|
17
|
-
return peerIds.map((id) => <CollaboratorGuard key={id} collaboratorId={id} />)
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
const CollaboratorGuard = track(function CollaboratorGuard({
|
|
21
|
-
collaboratorId,
|
|
22
|
-
}: {
|
|
23
|
-
collaboratorId: string
|
|
24
|
-
}) {
|
|
25
|
-
const editor = useEditor()
|
|
26
|
-
const presence = usePresence(collaboratorId)
|
|
27
|
-
const collaboratorState = useCollaboratorState(editor, presence)
|
|
28
|
-
|
|
29
|
-
if (!(presence && presence.currentPageId === editor.getCurrentPageId())) {
|
|
30
|
-
// No need to render if we don't have a presence or if they're on a different page
|
|
31
|
-
return null
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
if (!shouldShowCollaborator(editor, presence, collaboratorState)) {
|
|
35
|
-
return null
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
return <Collaborator latestPresence={presence} />
|
|
39
|
-
})
|
|
40
|
-
|
|
41
|
-
const Collaborator = track(function Collaborator({
|
|
42
|
-
latestPresence,
|
|
43
|
-
}: {
|
|
44
|
-
latestPresence: TLInstancePresence
|
|
45
|
-
}) {
|
|
46
|
-
const editor = useEditor()
|
|
47
|
-
|
|
48
|
-
const {
|
|
49
|
-
CollaboratorBrush,
|
|
50
|
-
CollaboratorScribble,
|
|
51
|
-
CollaboratorCursor,
|
|
52
|
-
CollaboratorHint,
|
|
53
|
-
CollaboratorShapeIndicator,
|
|
54
|
-
} = useEditorComponents()
|
|
55
|
-
|
|
56
|
-
const zoomLevel = editor.getZoomLevel()
|
|
57
|
-
const viewportPageBounds = editor.getViewportPageBounds()
|
|
58
|
-
const { userId, chatMessage, brush, scribbles, selectedShapeIds, userName, cursor, color } =
|
|
59
|
-
latestPresence
|
|
60
|
-
|
|
61
|
-
if (!cursor) return null
|
|
62
|
-
|
|
63
|
-
// Add a little padding to the top-left of the viewport
|
|
64
|
-
// so that the cursor doesn't get cut off
|
|
65
|
-
const isCursorInViewport = !(
|
|
66
|
-
cursor.x < viewportPageBounds.minX - 12 / zoomLevel ||
|
|
67
|
-
cursor.y < viewportPageBounds.minY - 16 / zoomLevel ||
|
|
68
|
-
cursor.x > viewportPageBounds.maxX - 12 / zoomLevel ||
|
|
69
|
-
cursor.y > viewportPageBounds.maxY - 16 / zoomLevel
|
|
70
|
-
)
|
|
71
|
-
|
|
72
|
-
return (
|
|
73
|
-
<>
|
|
74
|
-
{brush && CollaboratorBrush ? (
|
|
75
|
-
<CollaboratorBrush
|
|
76
|
-
className="tl-collaborator__brush"
|
|
77
|
-
key={userId + '_brush'}
|
|
78
|
-
userId={userId}
|
|
79
|
-
brush={brush}
|
|
80
|
-
color={color}
|
|
81
|
-
opacity={0.1}
|
|
82
|
-
/>
|
|
83
|
-
) : null}
|
|
84
|
-
{isCursorInViewport && CollaboratorCursor ? (
|
|
85
|
-
<CollaboratorCursor
|
|
86
|
-
className="tl-collaborator__cursor"
|
|
87
|
-
key={userId + '_cursor'}
|
|
88
|
-
userId={userId}
|
|
89
|
-
point={cursor}
|
|
90
|
-
color={color}
|
|
91
|
-
zoom={zoomLevel}
|
|
92
|
-
name={userName !== 'New User' ? userName : null}
|
|
93
|
-
chatMessage={chatMessage ?? ''}
|
|
94
|
-
/>
|
|
95
|
-
) : CollaboratorHint ? (
|
|
96
|
-
<CollaboratorHint
|
|
97
|
-
className="tl-collaborator__cursor-hint"
|
|
98
|
-
key={userId + '_cursor_hint'}
|
|
99
|
-
userId={userId}
|
|
100
|
-
point={cursor}
|
|
101
|
-
color={color}
|
|
102
|
-
zoom={zoomLevel}
|
|
103
|
-
viewport={viewportPageBounds}
|
|
104
|
-
/>
|
|
105
|
-
) : null}
|
|
106
|
-
{CollaboratorScribble && scribbles.length ? (
|
|
107
|
-
<>
|
|
108
|
-
{scribbles.map((scribble) => (
|
|
109
|
-
<CollaboratorScribble
|
|
110
|
-
key={userId + '_scribble_' + scribble.id}
|
|
111
|
-
className="tl-collaborator__scribble"
|
|
112
|
-
userId={userId}
|
|
113
|
-
scribble={scribble}
|
|
114
|
-
color={color}
|
|
115
|
-
zoom={zoomLevel}
|
|
116
|
-
opacity={scribble.color === 'laser' ? 0.5 : 0.1}
|
|
117
|
-
/>
|
|
118
|
-
))}
|
|
119
|
-
</>
|
|
120
|
-
) : null}
|
|
121
|
-
{CollaboratorShapeIndicator &&
|
|
122
|
-
selectedShapeIds
|
|
123
|
-
.filter((id) => {
|
|
124
|
-
// Skip hidden shapes
|
|
125
|
-
if (editor.isShapeHidden(id)) return false
|
|
126
|
-
// When canvas indicators are disabled, render SVG indicators for
|
|
127
|
-
// every selected shape. Otherwise shapes that opt into the canvas
|
|
128
|
-
// path via useLegacyIndicator() === false would never get a
|
|
129
|
-
// collaborator indicator drawn.
|
|
130
|
-
if (!editor.options.useCanvasIndicators) return true
|
|
131
|
-
// Otherwise, only render SVG indicators for shapes that opt in to
|
|
132
|
-
// the legacy path — canvas-based indicators are handled by
|
|
133
|
-
// CanvasShapeIndicators.
|
|
134
|
-
const shape = editor.getShape(id)
|
|
135
|
-
if (!shape) return false
|
|
136
|
-
const util = editor.getShapeUtil(shape)
|
|
137
|
-
return util.useLegacyIndicator()
|
|
138
|
-
})
|
|
139
|
-
.map((shapeId) => (
|
|
140
|
-
<CollaboratorShapeIndicator
|
|
141
|
-
className="tl-collaborator__shape-indicator"
|
|
142
|
-
key={userId + '_' + shapeId}
|
|
143
|
-
userId={userId}
|
|
144
|
-
shapeId={shapeId}
|
|
145
|
-
color={color}
|
|
146
|
-
opacity={0.5}
|
|
147
|
-
/>
|
|
148
|
-
))}
|
|
149
|
-
</>
|
|
150
|
-
)
|
|
151
|
-
})
|
|
152
|
-
|
|
153
|
-
function useCollaboratorState(
|
|
154
|
-
editor: Editor,
|
|
155
|
-
latestPresence: TLInstancePresence | null
|
|
156
|
-
): CollaboratorState {
|
|
157
|
-
const rLastActivityTimestamp = useRef(latestPresence?.lastActivityTimestamp ?? -1)
|
|
158
|
-
|
|
159
|
-
const [state, setState] = useState<CollaboratorState>(() =>
|
|
160
|
-
getCollaboratorStateFromElapsedTime(editor, Date.now() - rLastActivityTimestamp.current)
|
|
161
|
-
)
|
|
162
|
-
|
|
163
|
-
useEffect(() => {
|
|
164
|
-
const interval = editor.timers.setInterval(() => {
|
|
165
|
-
setState(
|
|
166
|
-
getCollaboratorStateFromElapsedTime(editor, Date.now() - rLastActivityTimestamp.current)
|
|
167
|
-
)
|
|
168
|
-
}, editor.options.collaboratorCheckIntervalMs)
|
|
169
|
-
|
|
170
|
-
return () => clearInterval(interval)
|
|
171
|
-
}, [editor])
|
|
172
|
-
|
|
173
|
-
if (latestPresence) {
|
|
174
|
-
// We can do this on every render, it's free and cheaper than an effect
|
|
175
|
-
// remember, there can be lots and lots of cursors moving around all the time
|
|
176
|
-
rLastActivityTimestamp.current = latestPresence.lastActivityTimestamp ?? Infinity
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
return state
|
|
180
|
-
}
|
|
@@ -1,300 +0,0 @@
|
|
|
1
|
-
import { useComputed, useQuickReactor } from '@tldraw/state-react'
|
|
2
|
-
import { createComputedCache } from '@tldraw/store'
|
|
3
|
-
import { TLShape, TLShapeId } from '@tldraw/tlschema'
|
|
4
|
-
import { dedupe } from '@tldraw/utils'
|
|
5
|
-
import { memo, useEffect, useRef } from 'react'
|
|
6
|
-
import { Editor } from '../../editor/Editor'
|
|
7
|
-
import { TLIndicatorPath } from '../../editor/shapes/ShapeUtil'
|
|
8
|
-
import { getComputedStyle } from '../../exports/domUtils'
|
|
9
|
-
import { useColorMode } from '../../hooks/useColorMode'
|
|
10
|
-
import { useEditor } from '../../hooks/useEditor'
|
|
11
|
-
import { useActivePeerIds$ } from '../../hooks/usePeerIds'
|
|
12
|
-
|
|
13
|
-
interface CollaboratorIndicatorData {
|
|
14
|
-
color: string
|
|
15
|
-
shapeIds: TLShapeId[]
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
interface RenderData {
|
|
19
|
-
idsToDisplay: Set<TLShapeId>
|
|
20
|
-
renderingShapeIds: Set<TLShapeId>
|
|
21
|
-
hintingShapeIds: TLShapeId[]
|
|
22
|
-
collaboratorIndicators: CollaboratorIndicatorData[]
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function setsEqual<T>(a: Set<T>, b: Set<T>): boolean {
|
|
26
|
-
if (a.size !== b.size) return false
|
|
27
|
-
for (const item of a) {
|
|
28
|
-
if (!b.has(item)) return false
|
|
29
|
-
}
|
|
30
|
-
return true
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function arraysEqual<T>(a: readonly T[], b: readonly T[]): boolean {
|
|
34
|
-
if (a.length !== b.length) return false
|
|
35
|
-
for (let i = 0; i < a.length; i++) {
|
|
36
|
-
if (a[i] !== b[i]) return false
|
|
37
|
-
}
|
|
38
|
-
return true
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function collaboratorIndicatorsEqual(
|
|
42
|
-
a: CollaboratorIndicatorData[],
|
|
43
|
-
b: CollaboratorIndicatorData[]
|
|
44
|
-
): boolean {
|
|
45
|
-
if (a.length !== b.length) return false
|
|
46
|
-
for (let i = 0; i < a.length; i++) {
|
|
47
|
-
if (a[i].color !== b[i].color) return false
|
|
48
|
-
if (!arraysEqual(a[i].shapeIds, b[i].shapeIds)) return false
|
|
49
|
-
}
|
|
50
|
-
return true
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function renderDataEqual(a: RenderData, b: RenderData): boolean {
|
|
54
|
-
return (
|
|
55
|
-
setsEqual(a.idsToDisplay, b.idsToDisplay) &&
|
|
56
|
-
setsEqual(a.renderingShapeIds, b.renderingShapeIds) &&
|
|
57
|
-
arraysEqual(a.hintingShapeIds, b.hintingShapeIds) &&
|
|
58
|
-
collaboratorIndicatorsEqual(a.collaboratorIndicators, b.collaboratorIndicators)
|
|
59
|
-
)
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const indicatorPathCache = createComputedCache(
|
|
63
|
-
'indicatorPath',
|
|
64
|
-
(editor: Editor, shape: TLShape) => {
|
|
65
|
-
const util = editor.getShapeUtil(shape)
|
|
66
|
-
return util.getIndicatorPath(shape)
|
|
67
|
-
}
|
|
68
|
-
)
|
|
69
|
-
|
|
70
|
-
const getIndicatorPath = (editor: Editor, shape: TLShape) => {
|
|
71
|
-
return indicatorPathCache.get(editor, shape.id)
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
function renderShapeIndicator(
|
|
75
|
-
ctx: CanvasRenderingContext2D,
|
|
76
|
-
editor: Editor,
|
|
77
|
-
shapeId: TLShapeId,
|
|
78
|
-
renderingShapeIds: Set<TLShapeId>
|
|
79
|
-
): boolean {
|
|
80
|
-
if (!renderingShapeIds.has(shapeId)) return false
|
|
81
|
-
|
|
82
|
-
const shape = editor.getShape(shapeId)
|
|
83
|
-
if (!shape || shape.isLocked) return false
|
|
84
|
-
|
|
85
|
-
const pageTransform = editor.getShapePageTransform(shape)
|
|
86
|
-
if (!pageTransform) return false
|
|
87
|
-
|
|
88
|
-
const indicatorPath = getIndicatorPath(editor, shape)
|
|
89
|
-
if (!indicatorPath) return false
|
|
90
|
-
|
|
91
|
-
ctx.save()
|
|
92
|
-
ctx.transform(
|
|
93
|
-
pageTransform.a,
|
|
94
|
-
pageTransform.b,
|
|
95
|
-
pageTransform.c,
|
|
96
|
-
pageTransform.d,
|
|
97
|
-
pageTransform.e,
|
|
98
|
-
pageTransform.f
|
|
99
|
-
)
|
|
100
|
-
renderIndicatorPath(ctx, indicatorPath)
|
|
101
|
-
ctx.restore()
|
|
102
|
-
|
|
103
|
-
return true
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
function renderIndicatorPath(ctx: CanvasRenderingContext2D, indicatorPath: TLIndicatorPath) {
|
|
107
|
-
if (indicatorPath instanceof Path2D) {
|
|
108
|
-
ctx.stroke(indicatorPath)
|
|
109
|
-
} else {
|
|
110
|
-
const { path, clipPath, additionalPaths } = indicatorPath
|
|
111
|
-
|
|
112
|
-
if (clipPath) {
|
|
113
|
-
ctx.save()
|
|
114
|
-
ctx.clip(clipPath, 'evenodd')
|
|
115
|
-
ctx.stroke(path)
|
|
116
|
-
ctx.restore()
|
|
117
|
-
} else {
|
|
118
|
-
ctx.stroke(path)
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
if (additionalPaths) {
|
|
122
|
-
for (const additionalPath of additionalPaths) {
|
|
123
|
-
ctx.stroke(additionalPath)
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
/** @internal @react */
|
|
130
|
-
export const CanvasShapeIndicators = memo(function CanvasShapeIndicators() {
|
|
131
|
-
const editor = useEditor()
|
|
132
|
-
|
|
133
|
-
// Skip canvas indicator rendering when the option is disabled (e.g. A/B test)
|
|
134
|
-
if (!editor.options.useCanvasIndicators) {
|
|
135
|
-
return null
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
return <CanvasShapeIndicatorsInner />
|
|
139
|
-
})
|
|
140
|
-
|
|
141
|
-
const CanvasShapeIndicatorsInner = memo(function CanvasShapeIndicatorsInner() {
|
|
142
|
-
const editor = useEditor()
|
|
143
|
-
const canvasRef = useRef<HTMLCanvasElement>(null)
|
|
144
|
-
|
|
145
|
-
// Cache the selected color to avoid getComputedStyle on every render
|
|
146
|
-
const rSelectedColor = useRef<string | null>(null)
|
|
147
|
-
const colorMode = useColorMode()
|
|
148
|
-
|
|
149
|
-
useEffect(() => {
|
|
150
|
-
const timer = editor.timers.setTimeout(() => {
|
|
151
|
-
rSelectedColor.current = null
|
|
152
|
-
}, 0)
|
|
153
|
-
return () => clearTimeout(timer)
|
|
154
|
-
}, [colorMode, editor])
|
|
155
|
-
|
|
156
|
-
// Get active peer IDs (already handles time-based state transitions)
|
|
157
|
-
const activePeerIds$ = useActivePeerIds$()
|
|
158
|
-
|
|
159
|
-
const $renderData = useComputed(
|
|
160
|
-
'indicator render data',
|
|
161
|
-
() => {
|
|
162
|
-
const renderingShapeIds = new Set(editor.getRenderingShapes().map((s) => s.id))
|
|
163
|
-
|
|
164
|
-
// Compute ids to display for selected/hovered shapes
|
|
165
|
-
const idsToDisplay = new Set<TLShapeId>()
|
|
166
|
-
const instanceState = editor.getInstanceState()
|
|
167
|
-
const isChangingStyle = instanceState.isChangingStyle
|
|
168
|
-
const isIdleOrEditing = editor.isInAny('select.idle', 'select.editing_shape')
|
|
169
|
-
const isInSelectState = editor.isInAny(
|
|
170
|
-
'select.brushing',
|
|
171
|
-
'select.scribble_brushing',
|
|
172
|
-
'select.pointing_shape',
|
|
173
|
-
'select.pointing_selection',
|
|
174
|
-
'select.pointing_handle'
|
|
175
|
-
)
|
|
176
|
-
|
|
177
|
-
if (!isChangingStyle && (isIdleOrEditing || isInSelectState)) {
|
|
178
|
-
for (const id of editor.getSelectedShapeIds()) {
|
|
179
|
-
idsToDisplay.add(id)
|
|
180
|
-
}
|
|
181
|
-
if (isIdleOrEditing && instanceState.isHoveringCanvas && !instanceState.isCoarsePointer) {
|
|
182
|
-
const hovered = editor.getHoveredShapeId()
|
|
183
|
-
if (hovered) idsToDisplay.add(hovered)
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
// Compute hinting shape ids
|
|
188
|
-
const hintingShapeIds = dedupe(editor.getHintingShapeIds())
|
|
189
|
-
|
|
190
|
-
// Compute collaborator indicators
|
|
191
|
-
const collaboratorIndicators: CollaboratorIndicatorData[] = []
|
|
192
|
-
const currentPageId = editor.getCurrentPageId()
|
|
193
|
-
const activePeerIds = activePeerIds$.get()
|
|
194
|
-
|
|
195
|
-
const collaborators = editor.getCollaborators()
|
|
196
|
-
for (const peerId of activePeerIds.values()) {
|
|
197
|
-
// Skip collaborators on different pages
|
|
198
|
-
const presence = collaborators.find((c) => c.userId === peerId)
|
|
199
|
-
if (!presence || presence.currentPageId !== currentPageId) continue
|
|
200
|
-
|
|
201
|
-
// Filter to shapes that are visible and on the current rendering set
|
|
202
|
-
const visibleShapeIds = presence.selectedShapeIds.filter(
|
|
203
|
-
(id) => renderingShapeIds.has(id) && !editor.isShapeHidden(id)
|
|
204
|
-
)
|
|
205
|
-
|
|
206
|
-
if (visibleShapeIds.length > 0) {
|
|
207
|
-
collaboratorIndicators.push({
|
|
208
|
-
color: presence.color,
|
|
209
|
-
shapeIds: visibleShapeIds,
|
|
210
|
-
})
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
return {
|
|
215
|
-
idsToDisplay,
|
|
216
|
-
renderingShapeIds,
|
|
217
|
-
hintingShapeIds,
|
|
218
|
-
collaboratorIndicators,
|
|
219
|
-
}
|
|
220
|
-
},
|
|
221
|
-
{ isEqual: renderDataEqual },
|
|
222
|
-
[editor, activePeerIds$]
|
|
223
|
-
)
|
|
224
|
-
|
|
225
|
-
useQuickReactor(
|
|
226
|
-
'canvas indicators render',
|
|
227
|
-
() => {
|
|
228
|
-
const canvas = canvasRef.current
|
|
229
|
-
if (!canvas) return
|
|
230
|
-
|
|
231
|
-
const ctx = canvas.getContext('2d')
|
|
232
|
-
if (!ctx) return
|
|
233
|
-
|
|
234
|
-
const { idsToDisplay, renderingShapeIds, hintingShapeIds, collaboratorIndicators } =
|
|
235
|
-
$renderData.get()
|
|
236
|
-
|
|
237
|
-
const { w, h } = editor.getViewportScreenBounds()
|
|
238
|
-
const dpr = editor.getInstanceState().devicePixelRatio
|
|
239
|
-
const { x: cx, y: cy, z: zoom } = editor.getCamera()
|
|
240
|
-
|
|
241
|
-
const canvasWidth = Math.ceil(w * dpr)
|
|
242
|
-
const canvasHeight = Math.ceil(h * dpr)
|
|
243
|
-
|
|
244
|
-
if (canvas.width !== canvasWidth || canvas.height !== canvasHeight) {
|
|
245
|
-
canvas.width = canvasWidth
|
|
246
|
-
canvas.height = canvasHeight
|
|
247
|
-
canvas.style.width = `${w}px`
|
|
248
|
-
canvas.style.height = `${h}px`
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
ctx.resetTransform()
|
|
252
|
-
ctx.clearRect(0, 0, canvas.width, canvas.height)
|
|
253
|
-
|
|
254
|
-
ctx.scale(dpr, dpr)
|
|
255
|
-
ctx.scale(zoom, zoom)
|
|
256
|
-
ctx.translate(cx, cy)
|
|
257
|
-
|
|
258
|
-
ctx.lineCap = 'round'
|
|
259
|
-
ctx.lineJoin = 'round'
|
|
260
|
-
|
|
261
|
-
// Draw collaborator indicators first (underneath local indicators)
|
|
262
|
-
// Use 0.5 opacity to match the original SVG-based collaborator indicators
|
|
263
|
-
ctx.lineWidth = 1.5 / zoom
|
|
264
|
-
for (const collaborator of collaboratorIndicators) {
|
|
265
|
-
ctx.strokeStyle = collaborator.color
|
|
266
|
-
ctx.globalAlpha = 0.7
|
|
267
|
-
for (const shapeId of collaborator.shapeIds) {
|
|
268
|
-
renderShapeIndicator(ctx, editor, shapeId, renderingShapeIds)
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
// Reset alpha for local indicators
|
|
273
|
-
ctx.globalAlpha = 1.0
|
|
274
|
-
|
|
275
|
-
// Use cached color, only call getComputedStyle when cache is empty
|
|
276
|
-
if (!rSelectedColor.current) {
|
|
277
|
-
rSelectedColor.current = getComputedStyle(canvas).getPropertyValue('--tl-color-selected')
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
ctx.strokeStyle = rSelectedColor.current
|
|
281
|
-
|
|
282
|
-
// Draw selected/hovered indicators (1.5px stroke)
|
|
283
|
-
ctx.lineWidth = 1.5 / zoom
|
|
284
|
-
for (const shapeId of idsToDisplay) {
|
|
285
|
-
renderShapeIndicator(ctx, editor, shapeId, renderingShapeIds)
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
// Draw hinted indicators with a thicker stroke (2.5px)
|
|
289
|
-
if (hintingShapeIds.length > 0) {
|
|
290
|
-
ctx.lineWidth = 2.5 / zoom
|
|
291
|
-
for (const shapeId of hintingShapeIds) {
|
|
292
|
-
renderShapeIndicator(ctx, editor, shapeId, renderingShapeIds)
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
},
|
|
296
|
-
[editor, $renderData]
|
|
297
|
-
)
|
|
298
|
-
|
|
299
|
-
return <canvas ref={canvasRef} className="tl-canvas-indicators" />
|
|
300
|
-
})
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { BoxModel } from '@tldraw/tlschema'
|
|
2
|
-
import { useRef } from 'react'
|
|
3
|
-
import { useTransform } from '../../hooks/useTransform'
|
|
4
|
-
import { toDomPrecision } from '../../primitives/utils'
|
|
5
|
-
|
|
6
|
-
/** @public */
|
|
7
|
-
export interface TLBrushProps {
|
|
8
|
-
userId?: string
|
|
9
|
-
brush: BoxModel
|
|
10
|
-
color?: string
|
|
11
|
-
opacity?: number
|
|
12
|
-
className?: string
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/** @public @react */
|
|
16
|
-
export const DefaultBrush = ({ brush, color, opacity, className }: TLBrushProps) => {
|
|
17
|
-
const rSvg = useRef<SVGSVGElement>(null)
|
|
18
|
-
useTransform(rSvg, brush.x, brush.y)
|
|
19
|
-
|
|
20
|
-
const w = toDomPrecision(Math.max(1, brush.w))
|
|
21
|
-
const h = toDomPrecision(Math.max(1, brush.h))
|
|
22
|
-
|
|
23
|
-
return (
|
|
24
|
-
<svg className="tl-overlays__item" ref={rSvg} aria-hidden="true">
|
|
25
|
-
{color ? (
|
|
26
|
-
<g className="tl-brush" opacity={opacity}>
|
|
27
|
-
<rect width={w} height={h} fill={color} opacity={0.75} />
|
|
28
|
-
<rect width={w} height={h} fill="none" stroke={color} opacity={0.1} />
|
|
29
|
-
</g>
|
|
30
|
-
) : (
|
|
31
|
-
<rect className={`tl-brush tl-brush__default ${className}`} width={w} height={h} />
|
|
32
|
-
)}
|
|
33
|
-
</svg>
|
|
34
|
-
)
|
|
35
|
-
}
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { VecModel } from '@tldraw/tlschema'
|
|
2
|
-
import classNames from 'classnames'
|
|
3
|
-
import { useRef } from 'react'
|
|
4
|
-
import { useSharedSafeId } from '../../hooks/useSafeId'
|
|
5
|
-
import { useTransform } from '../../hooks/useTransform'
|
|
6
|
-
import { Box } from '../../primitives/Box'
|
|
7
|
-
import { clamp } from '../../primitives/utils'
|
|
8
|
-
import { Vec } from '../../primitives/Vec'
|
|
9
|
-
|
|
10
|
-
/** @public */
|
|
11
|
-
export interface TLCollaboratorHintProps {
|
|
12
|
-
userId: string
|
|
13
|
-
className?: string
|
|
14
|
-
point: VecModel
|
|
15
|
-
viewport: Box
|
|
16
|
-
zoom: number
|
|
17
|
-
opacity?: number
|
|
18
|
-
color: string
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/** @public @react */
|
|
22
|
-
export function DefaultCollaboratorHint({
|
|
23
|
-
className,
|
|
24
|
-
zoom,
|
|
25
|
-
point,
|
|
26
|
-
color,
|
|
27
|
-
viewport,
|
|
28
|
-
opacity = 1,
|
|
29
|
-
}: TLCollaboratorHintProps) {
|
|
30
|
-
const rSvg = useRef<SVGSVGElement>(null)
|
|
31
|
-
|
|
32
|
-
useTransform(
|
|
33
|
-
rSvg,
|
|
34
|
-
clamp(point.x, viewport.minX + 5 / zoom, viewport.maxX - 5 / zoom),
|
|
35
|
-
clamp(point.y, viewport.minY + 5 / zoom, viewport.maxY - 5 / zoom),
|
|
36
|
-
1 / zoom,
|
|
37
|
-
Vec.Angle(viewport.center, point)
|
|
38
|
-
)
|
|
39
|
-
const cursorHintId = useSharedSafeId('cursor_hint')
|
|
40
|
-
|
|
41
|
-
return (
|
|
42
|
-
<svg ref={rSvg} className={classNames('tl-overlays__item', className)} aria-hidden="true">
|
|
43
|
-
<use
|
|
44
|
-
href={`#${cursorHintId}`}
|
|
45
|
-
color={color}
|
|
46
|
-
strokeWidth={3}
|
|
47
|
-
stroke="var(--tl-color-background)"
|
|
48
|
-
/>
|
|
49
|
-
<use href={`#${cursorHintId}`} color={color} opacity={opacity} />
|
|
50
|
-
</svg>
|
|
51
|
-
)
|
|
52
|
-
}
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { VecModel } from '@tldraw/tlschema'
|
|
2
|
-
import classNames from 'classnames'
|
|
3
|
-
import { memo, useRef } from 'react'
|
|
4
|
-
import { useSharedSafeId } from '../../hooks/useSafeId'
|
|
5
|
-
import { useTransform } from '../../hooks/useTransform'
|
|
6
|
-
|
|
7
|
-
/** @public */
|
|
8
|
-
export interface TLCursorProps {
|
|
9
|
-
userId: string
|
|
10
|
-
className?: string
|
|
11
|
-
point: VecModel | null
|
|
12
|
-
zoom: number
|
|
13
|
-
color?: string
|
|
14
|
-
name: string | null
|
|
15
|
-
chatMessage: string
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/** @public @react */
|
|
19
|
-
export const DefaultCursor = memo(function DefaultCursor({
|
|
20
|
-
className,
|
|
21
|
-
zoom,
|
|
22
|
-
point,
|
|
23
|
-
color,
|
|
24
|
-
name,
|
|
25
|
-
chatMessage,
|
|
26
|
-
}: TLCursorProps) {
|
|
27
|
-
const rCursor = useRef<HTMLDivElement>(null)
|
|
28
|
-
useTransform(rCursor, point?.x, point?.y, 1 / zoom)
|
|
29
|
-
|
|
30
|
-
const cursorId = useSharedSafeId('cursor')
|
|
31
|
-
|
|
32
|
-
if (!point) return null
|
|
33
|
-
|
|
34
|
-
return (
|
|
35
|
-
<div ref={rCursor} className={classNames('tl-overlays__item', className)}>
|
|
36
|
-
<svg className="tl-cursor" aria-hidden="true">
|
|
37
|
-
<use href={`#${cursorId}`} color={color} />
|
|
38
|
-
</svg>
|
|
39
|
-
{chatMessage ? (
|
|
40
|
-
<>
|
|
41
|
-
{name && (
|
|
42
|
-
<div className="tl-nametag-title" style={{ color }}>
|
|
43
|
-
{name}
|
|
44
|
-
</div>
|
|
45
|
-
)}
|
|
46
|
-
<div className="tl-nametag-chat" style={{ backgroundColor: color }}>
|
|
47
|
-
{chatMessage}
|
|
48
|
-
</div>
|
|
49
|
-
</>
|
|
50
|
-
) : (
|
|
51
|
-
name && (
|
|
52
|
-
<div className="tl-nametag" style={{ backgroundColor: color }}>
|
|
53
|
-
{name}
|
|
54
|
-
</div>
|
|
55
|
-
)
|
|
56
|
-
)}
|
|
57
|
-
</div>
|
|
58
|
-
)
|
|
59
|
-
})
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { TLHandle, TLShapeId } from '@tldraw/tlschema'
|
|
2
|
-
import classNames from 'classnames'
|
|
3
|
-
import { SIDES } from '../../constants'
|
|
4
|
-
import { useEditor } from '../../hooks/useEditor'
|
|
5
|
-
|
|
6
|
-
/** @public */
|
|
7
|
-
export interface TLHandleProps {
|
|
8
|
-
shapeId: TLShapeId
|
|
9
|
-
handle: TLHandle
|
|
10
|
-
zoom: number
|
|
11
|
-
isCoarse: boolean
|
|
12
|
-
className?: string
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/** @public @react */
|
|
16
|
-
export function DefaultHandle({ handle, isCoarse, className, zoom }: TLHandleProps) {
|
|
17
|
-
const editor = useEditor()
|
|
18
|
-
const br = (isCoarse ? editor.options.coarseHandleRadius : editor.options.handleRadius) / zoom
|
|
19
|
-
|
|
20
|
-
if (handle.type === 'clone') {
|
|
21
|
-
// bouba
|
|
22
|
-
const fr = 3 / zoom
|
|
23
|
-
const path = `M0,${-fr} A${fr},${fr} 0 0,1 0,${fr}`
|
|
24
|
-
|
|
25
|
-
const index = SIDES.indexOf(handle.id as (typeof SIDES)[number])
|
|
26
|
-
return (
|
|
27
|
-
<g className={classNames(`tl-handle tl-handle__${handle.type}`, className)}>
|
|
28
|
-
<circle className="tl-handle__bg" r={br} />
|
|
29
|
-
{/* Half circle */}
|
|
30
|
-
<path className="tl-handle__fg" d={path} transform={`rotate(${-90 + 90 * index})`} />
|
|
31
|
-
</g>
|
|
32
|
-
)
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const fr = (handle.type === 'create' && isCoarse ? 3 : 4) / Math.max(zoom, 0.25)
|
|
36
|
-
return (
|
|
37
|
-
<g className={classNames(`tl-handle tl-handle__${handle.type}`, className)}>
|
|
38
|
-
<circle className="tl-handle__bg" r={br} />
|
|
39
|
-
<circle className="tl-handle__fg" r={fr} />
|
|
40
|
-
</g>
|
|
41
|
-
)
|
|
42
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { ReactNode } from 'react'
|
|
2
|
-
|
|
3
|
-
/** @public */
|
|
4
|
-
export interface TLHandlesProps {
|
|
5
|
-
children: ReactNode
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
/** @public @react */
|
|
9
|
-
export const DefaultHandles = ({ children }: TLHandlesProps) => {
|
|
10
|
-
return (
|
|
11
|
-
<svg className="tl-user-handles tl-overlays__item" aria-hidden="true">
|
|
12
|
-
{children}
|
|
13
|
-
</svg>
|
|
14
|
-
)
|
|
15
|
-
}
|