@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.
Files changed (207) hide show
  1. package/dist-cjs/index.d.ts +412 -179
  2. package/dist-cjs/index.js +12 -23
  3. package/dist-cjs/index.js.map +2 -2
  4. package/dist-cjs/lib/TldrawEditor.js +3 -0
  5. package/dist-cjs/lib/TldrawEditor.js.map +2 -2
  6. package/dist-cjs/lib/components/default-components/CanvasOverlays.js +180 -0
  7. package/dist-cjs/lib/components/default-components/CanvasOverlays.js.map +7 -0
  8. package/dist-cjs/lib/components/default-components/DefaultCanvas.js +44 -249
  9. package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +3 -3
  10. package/dist-cjs/lib/editor/Editor.js +78 -28
  11. package/dist-cjs/lib/editor/Editor.js.map +2 -2
  12. package/dist-cjs/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.js +98 -0
  13. package/dist-cjs/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.js.map +7 -0
  14. package/dist-cjs/lib/editor/managers/ThemeManager/defaultThemes.js +14 -0
  15. package/dist-cjs/lib/editor/managers/ThemeManager/defaultThemes.js.map +2 -2
  16. package/dist-cjs/lib/editor/overlays/OverlayManager.js +154 -0
  17. package/dist-cjs/lib/editor/overlays/OverlayManager.js.map +7 -0
  18. package/dist-cjs/lib/editor/overlays/OverlayUtil.js +92 -0
  19. package/dist-cjs/lib/editor/overlays/OverlayUtil.js.map +7 -0
  20. package/dist-cjs/lib/editor/overlays/ShapeIndicatorOverlayUtil.js +161 -0
  21. package/dist-cjs/lib/editor/overlays/ShapeIndicatorOverlayUtil.js.map +7 -0
  22. package/dist-cjs/lib/editor/overlays/getOverlayDisplayValues.js +39 -0
  23. package/dist-cjs/lib/editor/overlays/getOverlayDisplayValues.js.map +7 -0
  24. package/dist-cjs/lib/editor/shapes/BaseFrameLikeShapeUtil.js +3 -0
  25. package/dist-cjs/lib/editor/shapes/BaseFrameLikeShapeUtil.js.map +2 -2
  26. package/dist-cjs/lib/editor/shapes/ShapeUtil.js +25 -23
  27. package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
  28. package/dist-cjs/lib/editor/shapes/group/GroupShapeUtil.js +32 -2
  29. package/dist-cjs/lib/editor/shapes/group/GroupShapeUtil.js.map +2 -2
  30. package/dist-cjs/lib/editor/types/event-types.js.map +2 -2
  31. package/dist-cjs/lib/exports/fetchCache.js +1 -1
  32. package/dist-cjs/lib/exports/fetchCache.js.map +2 -2
  33. package/dist-cjs/lib/hooks/EditorComponentsContext.js.map +2 -2
  34. package/dist-cjs/lib/hooks/useCanvasEvents.js +3 -3
  35. package/dist-cjs/lib/hooks/useCanvasEvents.js.map +2 -2
  36. package/dist-cjs/lib/hooks/useEditorComponents.js +0 -28
  37. package/dist-cjs/lib/hooks/useEditorComponents.js.map +2 -2
  38. package/dist-cjs/lib/hooks/usePeerIds.js +1 -36
  39. package/dist-cjs/lib/hooks/usePeerIds.js.map +2 -2
  40. package/dist-cjs/lib/hooks/useShapeCulling.js +2 -1
  41. package/dist-cjs/lib/hooks/useShapeCulling.js.map +2 -2
  42. package/dist-cjs/lib/options.js +0 -1
  43. package/dist-cjs/lib/options.js.map +2 -2
  44. package/dist-cjs/lib/utils/reparenting.js +20 -7
  45. package/dist-cjs/lib/utils/reparenting.js.map +2 -2
  46. package/dist-cjs/lib/utils/sync/TLLocalSyncClient.js +3 -0
  47. package/dist-cjs/lib/utils/sync/TLLocalSyncClient.js.map +2 -2
  48. package/dist-cjs/version.js +4 -4
  49. package/dist-cjs/version.js.map +1 -1
  50. package/dist-esm/index.d.mts +412 -179
  51. package/dist-esm/index.mjs +19 -41
  52. package/dist-esm/index.mjs.map +2 -2
  53. package/dist-esm/lib/TldrawEditor.mjs +3 -0
  54. package/dist-esm/lib/TldrawEditor.mjs.map +2 -2
  55. package/dist-esm/lib/components/default-components/CanvasOverlays.mjs +160 -0
  56. package/dist-esm/lib/components/default-components/CanvasOverlays.mjs.map +7 -0
  57. package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +45 -250
  58. package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +3 -3
  59. package/dist-esm/lib/editor/Editor.mjs +78 -29
  60. package/dist-esm/lib/editor/Editor.mjs.map +2 -2
  61. package/dist-esm/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.mjs +83 -0
  62. package/dist-esm/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.mjs.map +7 -0
  63. package/dist-esm/lib/editor/managers/ThemeManager/defaultThemes.mjs +14 -0
  64. package/dist-esm/lib/editor/managers/ThemeManager/defaultThemes.mjs.map +2 -2
  65. package/dist-esm/lib/editor/overlays/OverlayManager.mjs +136 -0
  66. package/dist-esm/lib/editor/overlays/OverlayManager.mjs.map +7 -0
  67. package/dist-esm/lib/editor/overlays/OverlayUtil.mjs +72 -0
  68. package/dist-esm/lib/editor/overlays/OverlayUtil.mjs.map +7 -0
  69. package/dist-esm/lib/editor/overlays/ShapeIndicatorOverlayUtil.mjs +141 -0
  70. package/dist-esm/lib/editor/overlays/ShapeIndicatorOverlayUtil.mjs.map +7 -0
  71. package/dist-esm/lib/editor/overlays/getOverlayDisplayValues.mjs +19 -0
  72. package/dist-esm/lib/editor/overlays/getOverlayDisplayValues.mjs.map +7 -0
  73. package/dist-esm/lib/editor/shapes/BaseFrameLikeShapeUtil.mjs +3 -0
  74. package/dist-esm/lib/editor/shapes/BaseFrameLikeShapeUtil.mjs.map +2 -2
  75. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs +25 -23
  76. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
  77. package/dist-esm/lib/editor/shapes/group/GroupShapeUtil.mjs +32 -2
  78. package/dist-esm/lib/editor/shapes/group/GroupShapeUtil.mjs.map +2 -2
  79. package/dist-esm/lib/editor/types/event-types.mjs.map +2 -2
  80. package/dist-esm/lib/exports/fetchCache.mjs +2 -2
  81. package/dist-esm/lib/exports/fetchCache.mjs.map +2 -2
  82. package/dist-esm/lib/hooks/EditorComponentsContext.mjs.map +2 -2
  83. package/dist-esm/lib/hooks/useCanvasEvents.mjs +3 -3
  84. package/dist-esm/lib/hooks/useCanvasEvents.mjs.map +2 -2
  85. package/dist-esm/lib/hooks/useEditorComponents.mjs +0 -28
  86. package/dist-esm/lib/hooks/useEditorComponents.mjs.map +2 -2
  87. package/dist-esm/lib/hooks/usePeerIds.mjs +2 -40
  88. package/dist-esm/lib/hooks/usePeerIds.mjs.map +2 -2
  89. package/dist-esm/lib/hooks/useShapeCulling.mjs +2 -1
  90. package/dist-esm/lib/hooks/useShapeCulling.mjs.map +2 -2
  91. package/dist-esm/lib/options.mjs +0 -1
  92. package/dist-esm/lib/options.mjs.map +2 -2
  93. package/dist-esm/lib/utils/reparenting.mjs +20 -7
  94. package/dist-esm/lib/utils/reparenting.mjs.map +2 -2
  95. package/dist-esm/lib/utils/sync/TLLocalSyncClient.mjs +3 -0
  96. package/dist-esm/lib/utils/sync/TLLocalSyncClient.mjs.map +2 -2
  97. package/dist-esm/version.mjs +4 -4
  98. package/dist-esm/version.mjs.map +1 -1
  99. package/editor.css +4 -239
  100. package/package.json +7 -7
  101. package/src/index.ts +17 -39
  102. package/src/lib/TldrawEditor.tsx +9 -0
  103. package/src/lib/components/default-components/CanvasOverlays.tsx +208 -0
  104. package/src/lib/components/default-components/DefaultCanvas.tsx +49 -324
  105. package/src/lib/editor/Editor.test.ts +3 -1
  106. package/src/lib/editor/Editor.ts +80 -24
  107. package/src/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.ts +98 -0
  108. package/src/lib/editor/managers/ThemeManager/defaultThemes.ts +14 -0
  109. package/src/lib/editor/overlays/OverlayManager.ts +183 -0
  110. package/src/lib/editor/overlays/OverlayUtil.ts +143 -0
  111. package/src/lib/editor/overlays/ShapeIndicatorOverlayUtil.ts +216 -0
  112. package/src/lib/editor/overlays/getOverlayDisplayValues.ts +51 -0
  113. package/src/lib/editor/shapes/BaseFrameLikeShapeUtil.tsx +9 -2
  114. package/src/lib/editor/shapes/ShapeUtil.ts +34 -26
  115. package/src/lib/editor/shapes/group/GroupShapeUtil.tsx +40 -3
  116. package/src/lib/editor/types/event-types.ts +2 -0
  117. package/src/lib/exports/fetchCache.ts +2 -4
  118. package/src/lib/exports/getSvgJsx.test.ts +3 -1
  119. package/src/lib/hooks/EditorComponentsContext.tsx +0 -27
  120. package/src/lib/hooks/useCanvasEvents.ts +13 -8
  121. package/src/lib/hooks/useEditorComponents.tsx +0 -28
  122. package/src/lib/hooks/usePeerIds.ts +6 -55
  123. package/src/lib/hooks/useShapeCulling.tsx +3 -1
  124. package/src/lib/options.ts +0 -7
  125. package/src/lib/utils/reparenting.ts +22 -9
  126. package/src/lib/utils/sync/TLLocalSyncClient.ts +3 -0
  127. package/src/version.ts +4 -4
  128. package/dist-cjs/lib/components/GeometryDebuggingView.js +0 -115
  129. package/dist-cjs/lib/components/GeometryDebuggingView.js.map +0 -7
  130. package/dist-cjs/lib/components/LiveCollaborators.js +0 -152
  131. package/dist-cjs/lib/components/LiveCollaborators.js.map +0 -7
  132. package/dist-cjs/lib/components/default-components/CanvasShapeIndicators.js +0 -234
  133. package/dist-cjs/lib/components/default-components/CanvasShapeIndicators.js.map +0 -7
  134. package/dist-cjs/lib/components/default-components/DefaultBrush.js +0 -38
  135. package/dist-cjs/lib/components/default-components/DefaultBrush.js.map +0 -7
  136. package/dist-cjs/lib/components/default-components/DefaultCollaboratorHint.js +0 -71
  137. package/dist-cjs/lib/components/default-components/DefaultCollaboratorHint.js.map +0 -7
  138. package/dist-cjs/lib/components/default-components/DefaultCursor.js +0 -59
  139. package/dist-cjs/lib/components/default-components/DefaultCursor.js.map +0 -7
  140. package/dist-cjs/lib/components/default-components/DefaultHandle.js +0 -56
  141. package/dist-cjs/lib/components/default-components/DefaultHandle.js.map +0 -7
  142. package/dist-cjs/lib/components/default-components/DefaultHandles.js +0 -28
  143. package/dist-cjs/lib/components/default-components/DefaultHandles.js.map +0 -7
  144. package/dist-cjs/lib/components/default-components/DefaultScribble.js +0 -51
  145. package/dist-cjs/lib/components/default-components/DefaultScribble.js.map +0 -7
  146. package/dist-cjs/lib/components/default-components/DefaultSelectionForeground.js +0 -69
  147. package/dist-cjs/lib/components/default-components/DefaultSelectionForeground.js.map +0 -7
  148. package/dist-cjs/lib/components/default-components/DefaultShapeIndicator.js +0 -107
  149. package/dist-cjs/lib/components/default-components/DefaultShapeIndicator.js.map +0 -7
  150. package/dist-cjs/lib/components/default-components/DefaultShapeIndicatorErrorFallback.js +0 -28
  151. package/dist-cjs/lib/components/default-components/DefaultShapeIndicatorErrorFallback.js.map +0 -7
  152. package/dist-cjs/lib/components/default-components/DefaultShapeIndicators.js +0 -102
  153. package/dist-cjs/lib/components/default-components/DefaultShapeIndicators.js.map +0 -7
  154. package/dist-cjs/lib/components/default-components/DefaultSnapIndictor.js +0 -170
  155. package/dist-cjs/lib/components/default-components/DefaultSnapIndictor.js.map +0 -7
  156. package/dist-cjs/lib/hooks/useHandleEvents.js +0 -100
  157. package/dist-cjs/lib/hooks/useHandleEvents.js.map +0 -7
  158. package/dist-cjs/lib/hooks/useSelectionEvents.js +0 -98
  159. package/dist-cjs/lib/hooks/useSelectionEvents.js.map +0 -7
  160. package/dist-esm/lib/components/GeometryDebuggingView.mjs +0 -95
  161. package/dist-esm/lib/components/GeometryDebuggingView.mjs.map +0 -7
  162. package/dist-esm/lib/components/LiveCollaborators.mjs +0 -135
  163. package/dist-esm/lib/components/LiveCollaborators.mjs.map +0 -7
  164. package/dist-esm/lib/components/default-components/CanvasShapeIndicators.mjs +0 -214
  165. package/dist-esm/lib/components/default-components/CanvasShapeIndicators.mjs.map +0 -7
  166. package/dist-esm/lib/components/default-components/DefaultBrush.mjs +0 -18
  167. package/dist-esm/lib/components/default-components/DefaultBrush.mjs.map +0 -7
  168. package/dist-esm/lib/components/default-components/DefaultCollaboratorHint.mjs +0 -41
  169. package/dist-esm/lib/components/default-components/DefaultCollaboratorHint.mjs.map +0 -7
  170. package/dist-esm/lib/components/default-components/DefaultCursor.mjs +0 -29
  171. package/dist-esm/lib/components/default-components/DefaultCursor.mjs.map +0 -7
  172. package/dist-esm/lib/components/default-components/DefaultHandle.mjs +0 -26
  173. package/dist-esm/lib/components/default-components/DefaultHandle.mjs.map +0 -7
  174. package/dist-esm/lib/components/default-components/DefaultHandles.mjs +0 -8
  175. package/dist-esm/lib/components/default-components/DefaultHandles.mjs.map +0 -7
  176. package/dist-esm/lib/components/default-components/DefaultScribble.mjs +0 -21
  177. package/dist-esm/lib/components/default-components/DefaultScribble.mjs.map +0 -7
  178. package/dist-esm/lib/components/default-components/DefaultSelectionForeground.mjs +0 -39
  179. package/dist-esm/lib/components/default-components/DefaultSelectionForeground.mjs.map +0 -7
  180. package/dist-esm/lib/components/default-components/DefaultShapeIndicator.mjs +0 -77
  181. package/dist-esm/lib/components/default-components/DefaultShapeIndicator.mjs.map +0 -7
  182. package/dist-esm/lib/components/default-components/DefaultShapeIndicatorErrorFallback.mjs +0 -8
  183. package/dist-esm/lib/components/default-components/DefaultShapeIndicatorErrorFallback.mjs.map +0 -7
  184. package/dist-esm/lib/components/default-components/DefaultShapeIndicators.mjs +0 -82
  185. package/dist-esm/lib/components/default-components/DefaultShapeIndicators.mjs.map +0 -7
  186. package/dist-esm/lib/components/default-components/DefaultSnapIndictor.mjs +0 -142
  187. package/dist-esm/lib/components/default-components/DefaultSnapIndictor.mjs.map +0 -7
  188. package/dist-esm/lib/hooks/useHandleEvents.mjs +0 -70
  189. package/dist-esm/lib/hooks/useHandleEvents.mjs.map +0 -7
  190. package/dist-esm/lib/hooks/useSelectionEvents.mjs +0 -78
  191. package/dist-esm/lib/hooks/useSelectionEvents.mjs.map +0 -7
  192. package/src/lib/components/GeometryDebuggingView.tsx +0 -108
  193. package/src/lib/components/LiveCollaborators.tsx +0 -180
  194. package/src/lib/components/default-components/CanvasShapeIndicators.tsx +0 -300
  195. package/src/lib/components/default-components/DefaultBrush.tsx +0 -35
  196. package/src/lib/components/default-components/DefaultCollaboratorHint.tsx +0 -52
  197. package/src/lib/components/default-components/DefaultCursor.tsx +0 -59
  198. package/src/lib/components/default-components/DefaultHandle.tsx +0 -42
  199. package/src/lib/components/default-components/DefaultHandles.tsx +0 -15
  200. package/src/lib/components/default-components/DefaultScribble.tsx +0 -31
  201. package/src/lib/components/default-components/DefaultSelectionForeground.tsx +0 -50
  202. package/src/lib/components/default-components/DefaultShapeIndicator.tsx +0 -104
  203. package/src/lib/components/default-components/DefaultShapeIndicatorErrorFallback.tsx +0 -9
  204. package/src/lib/components/default-components/DefaultShapeIndicators.tsx +0 -118
  205. package/src/lib/components/default-components/DefaultSnapIndictor.tsx +0 -174
  206. package/src/lib/hooks/useHandleEvents.ts +0 -88
  207. package/src/lib/hooks/useSelectionEvents.ts +0 -97
@@ -1,31 +0,0 @@
1
- import { TLScribble } from '@tldraw/tlschema'
2
- import classNames from 'classnames'
3
- import { getSvgPathFromPoints } from '../../utils/getSvgPathFromPoints'
4
-
5
- /** @public */
6
- export interface TLScribbleProps {
7
- userId?: string
8
- scribble: TLScribble
9
- zoom: number
10
- color?: string
11
- opacity?: number
12
- className?: string
13
- }
14
-
15
- /** @public @react */
16
- export function DefaultScribble({ scribble, zoom, color, opacity, className }: TLScribbleProps) {
17
- if (!scribble.points.length) return null
18
-
19
- return (
20
- <svg className={className ? classNames('tl-overlays__item', className) : className}>
21
- <path
22
- className="tl-scribble"
23
- d={getSvgPathFromPoints(scribble.points, false)}
24
- stroke={color ?? `var(--tl-color-${scribble.color})`}
25
- fill="none"
26
- strokeWidth={8 / zoom}
27
- opacity={opacity ?? scribble.opacity}
28
- />
29
- </svg>
30
- )
31
- }
@@ -1,50 +0,0 @@
1
- import { useValue } from '@tldraw/state-react'
2
- import classNames from 'classnames'
3
- import { useRef } from 'react'
4
- import { useEditor } from '../../hooks/useEditor'
5
- import { useTransform } from '../../hooks/useTransform'
6
- import { Box } from '../../primitives/Box'
7
- import { toDomPrecision } from '../../primitives/utils'
8
-
9
- /** @public */
10
- export interface TLSelectionForegroundProps {
11
- bounds: Box
12
- rotation: number
13
- }
14
-
15
- /** @public @react */
16
- export function DefaultSelectionForeground({ bounds, rotation }: TLSelectionForegroundProps) {
17
- const editor = useEditor()
18
- const rSvg = useRef<SVGSVGElement>(null)
19
-
20
- const onlyShape = useValue('only selected shape', () => editor.getOnlySelectedShape(), [editor])
21
-
22
- // if all shapes have an expandBy for the selection outline, we can expand by the l
23
- const expandOutlineBy = onlyShape
24
- ? editor.getShapeUtil(onlyShape).expandSelectionOutlinePx(onlyShape)
25
- : 0
26
-
27
- useTransform(rSvg, bounds?.x, bounds?.y, 1, rotation, {
28
- x: -expandOutlineBy,
29
- y: -expandOutlineBy,
30
- })
31
-
32
- bounds =
33
- expandOutlineBy instanceof Box
34
- ? bounds.clone().expand(expandOutlineBy).zeroFix()
35
- : bounds.clone().expandBy(expandOutlineBy).zeroFix()
36
-
37
- return (
38
- <svg
39
- ref={rSvg}
40
- className="tl-overlays__item tl-selection__fg"
41
- data-testid="selection-foreground"
42
- >
43
- <rect
44
- className={classNames('tl-selection__fg__outline')}
45
- width={toDomPrecision(bounds.width)}
46
- height={toDomPrecision(bounds.height)}
47
- />
48
- </svg>
49
- )
50
- }
@@ -1,104 +0,0 @@
1
- import { useQuickReactor, useStateTracking, useValue } from '@tldraw/state-react'
2
- import { TLShape, TLShapeId } from '@tldraw/tlschema'
3
- import classNames from 'classnames'
4
- import { memo, useLayoutEffect, useRef } from 'react'
5
- import type { Editor } from '../../editor/Editor'
6
- import { ShapeUtil } from '../../editor/shapes/ShapeUtil'
7
- import { useEditorComponents } from '../../hooks/EditorComponentsContext'
8
- import { useEditor } from '../../hooks/useEditor'
9
- import { OptionalErrorBoundary } from '../ErrorBoundary'
10
-
11
- // need an extra layer of indirection here to allow hooks to be used inside the indicator render
12
- const EvenInnererIndicator = memo(
13
- ({ shape, util }: { shape: TLShape; util: ShapeUtil<any> }) => {
14
- return useStateTracking('Indicator: ' + shape.type, () =>
15
- // always fetch the latest shape from the store even if the props/meta have not changed, to avoid
16
- // calling the render method with stale data.
17
- util.indicator(util.editor.store.unsafeGetWithoutCapture(shape.id) as TLShape)
18
- )
19
- },
20
- (prevProps, nextProps) => {
21
- return (
22
- prevProps.shape.props === nextProps.shape.props &&
23
- prevProps.shape.meta === nextProps.shape.meta
24
- )
25
- }
26
- )
27
-
28
- const InnerIndicator = memo(({ editor, id }: { editor: Editor; id: TLShapeId }) => {
29
- const shape = useValue('shape for indicator', () => editor.store.get(id), [editor, id])
30
-
31
- const { ShapeIndicatorErrorFallback } = useEditorComponents()
32
-
33
- if (!shape || shape.isLocked) return null
34
-
35
- const util = editor.getShapeUtil(shape)
36
-
37
- // If canvas indicators are enabled and the shape uses them, it will be rendered by CanvasShapeIndicators
38
- if (editor.options.useCanvasIndicators && !util.useLegacyIndicator()) return null
39
-
40
- return (
41
- <OptionalErrorBoundary
42
- fallback={ShapeIndicatorErrorFallback}
43
- onError={(error) =>
44
- editor.annotateError(error, { origin: 'react.shapeIndicator', willCrashApp: false })
45
- }
46
- >
47
- <EvenInnererIndicator key={shape.id} shape={shape} util={util} />
48
- </OptionalErrorBoundary>
49
- )
50
- })
51
-
52
- /** @public */
53
- export interface TLShapeIndicatorProps {
54
- userId?: string
55
- shapeId: TLShapeId
56
- color?: string | undefined
57
- opacity?: number
58
- className?: string
59
- hidden?: boolean
60
- }
61
-
62
- /** @public @react */
63
- export const DefaultShapeIndicator = memo(function DefaultShapeIndicator({
64
- shapeId,
65
- className,
66
- color,
67
- hidden,
68
- opacity,
69
- }: TLShapeIndicatorProps) {
70
- const editor = useEditor()
71
-
72
- const rIndicator = useRef<SVGSVGElement>(null)
73
-
74
- useQuickReactor(
75
- 'indicator transform',
76
- () => {
77
- if (hidden) return
78
- const elm = rIndicator.current
79
- if (!elm) return
80
- const pageTransform = editor.getShapePageTransform(shapeId)
81
- if (!pageTransform) return
82
- elm.style.setProperty('transform', pageTransform.toCssString())
83
- },
84
- [editor, shapeId, hidden]
85
- )
86
-
87
- useLayoutEffect(() => {
88
- const elm = rIndicator.current
89
- if (!elm) return
90
- elm.style.setProperty('display', hidden ? 'none' : 'block')
91
- }, [hidden])
92
-
93
- return (
94
- <svg ref={rIndicator} className={classNames('tl-overlays__item', className)} aria-hidden="true">
95
- <g
96
- className="tl-shape-indicator"
97
- stroke={color ?? 'var(--tl-color-selected)'}
98
- opacity={opacity}
99
- >
100
- <InnerIndicator editor={editor} id={shapeId} />
101
- </g>
102
- </svg>
103
- )
104
- })
@@ -1,9 +0,0 @@
1
- import { ComponentType } from 'react'
2
-
3
- /** @public */
4
- export type TLShapeIndicatorErrorFallbackComponent = ComponentType<{ error: unknown }>
5
-
6
- /** @internal */
7
- export const DefaultShapeIndicatorErrorFallback: TLShapeIndicatorErrorFallbackComponent = () => {
8
- return <circle cx={4} cy={4} r={8} strokeWidth="1" stroke="red" />
9
- }
@@ -1,118 +0,0 @@
1
- import { useValue } from '@tldraw/state-react'
2
- import { TLShapeId } from '@tldraw/tlschema'
3
- import { memo, useRef } from 'react'
4
- import { useEditorComponents } from '../../hooks/EditorComponentsContext'
5
- import { useEditor } from '../../hooks/useEditor'
6
-
7
- /** @public */
8
- export interface TLShapeIndicatorsProps {
9
- /** Whether to hide all of the indicators */
10
- hideAll?: boolean
11
- /** Whether to show all of the indicators */
12
- showAll?: boolean
13
- }
14
-
15
- /** @public @react */
16
- export const DefaultShapeIndicators = memo(function DefaultShapeIndicators({
17
- hideAll,
18
- showAll,
19
- }: TLShapeIndicatorsProps) {
20
- const editor = useEditor()
21
-
22
- if (hideAll && showAll)
23
- throw Error('You cannot set both hideAll and showAll props to true, cmon now')
24
-
25
- const rPreviousSelectedShapeIds = useRef<Set<TLShapeId>>(new Set())
26
-
27
- const idsToDisplay = useValue(
28
- 'should display selected ids',
29
- () => {
30
- const prev = rPreviousSelectedShapeIds.current
31
- const next = new Set<TLShapeId>()
32
-
33
- const instanceState = editor.getInstanceState()
34
-
35
- const isChangingStyle = instanceState.isChangingStyle
36
-
37
- // todo: this is tldraw specific and is duplicated at the tldraw layer. What should we do here instead?
38
-
39
- const isIdleOrEditing = editor.isInAny('select.idle', 'select.editing_shape')
40
-
41
- const isInSelectState = editor.isInAny(
42
- 'select.brushing',
43
- 'select.scribble_brushing',
44
- 'select.pointing_shape',
45
- 'select.pointing_selection',
46
- 'select.pointing_handle'
47
- )
48
-
49
- // We hide all indicators if we're changing style or in certain interactions
50
- // todo: move this to some kind of Tool.hideIndicators property
51
- if (isChangingStyle || !(isIdleOrEditing || isInSelectState)) {
52
- rPreviousSelectedShapeIds.current = next
53
- return next
54
- }
55
-
56
- // We always want to show indicators for the selected shapes, if any
57
- for (const id of editor.getSelectedShapeIds()) {
58
- next.add(id)
59
- }
60
-
61
- // If we're idle or editing a shape, we want to also show an indicator for the hovered shape, if any
62
- if (isIdleOrEditing && instanceState.isHoveringCanvas && !instanceState.isCoarsePointer) {
63
- const hovered = editor.getHoveredShapeId()
64
- if (hovered) next.add(hovered)
65
- }
66
-
67
- // Ok, has anything changed?
68
-
69
- // If the number of items in the set is different, then the selection has changed. This catches most changes.
70
- if (prev.size !== next.size) {
71
- rPreviousSelectedShapeIds.current = next
72
- return next
73
- }
74
-
75
- // Set difference check
76
- for (const id of next) {
77
- if (!prev.has(id)) {
78
- rPreviousSelectedShapeIds.current = next
79
- return next
80
- }
81
- }
82
-
83
- return prev
84
- },
85
- [editor]
86
- )
87
-
88
- // Show indicators only for the shapes that are currently being rendered (ie that are on screen)
89
- const renderingShapes = useValue('rendering shapes', () => editor.getRenderingShapes(), [editor])
90
-
91
- const { ShapeIndicator } = useEditorComponents()
92
-
93
- // Filter out shapes that have canvas indicator support - only render shapes that use legacy SVG indicators
94
- // When useCanvasIndicators is disabled, render all shapes via SVG
95
- const shapesToRender = useValue(
96
- 'shapes to render for svg indicators',
97
- () => {
98
- if (!editor.options.useCanvasIndicators) return renderingShapes
99
- return renderingShapes.filter(({ id }) => {
100
- const shape = editor.getShape(id)
101
- if (!shape) return false
102
- const util = editor.getShapeUtil(shape)
103
- return util.useLegacyIndicator()
104
- })
105
- },
106
- [editor, renderingShapes]
107
- )
108
-
109
- if (!ShapeIndicator) return null
110
-
111
- return shapesToRender.map(({ id }) => (
112
- <ShapeIndicator
113
- key={id + '_indicator'}
114
- shapeId={id}
115
- hidden={!showAll && (hideAll || !idsToDisplay.has(id))}
116
- />
117
- ))
118
- })
@@ -1,174 +0,0 @@
1
- import classNames from 'classnames'
2
- import * as React from 'react'
3
- import {
4
- type GapsSnapIndicator,
5
- type PointsSnapIndicator,
6
- type SnapIndicator,
7
- } from '../../editor/managers/SnapManager/SnapManager'
8
- import { rangeIntersection } from '../../primitives/utils'
9
-
10
- function PointsSnapIndicator({ points, zoom }: { zoom: number } & PointsSnapIndicator) {
11
- const l = 2.5 / zoom
12
-
13
- const minX = points.reduce((acc, p) => Math.min(acc, p.x), Infinity)
14
- const maxX = points.reduce((acc, p) => Math.max(acc, p.x), -Infinity)
15
- const minY = points.reduce((acc, p) => Math.min(acc, p.y), Infinity)
16
- const maxY = points.reduce((acc, p) => Math.max(acc, p.y), -Infinity)
17
-
18
- const useNWtoSEdireciton = points.some((p) => p.x === minX && p.y === minY)
19
- let firstX: number, firstY: number, secondX: number, secondY: number
20
- if (useNWtoSEdireciton) {
21
- firstX = minX
22
- firstY = minY
23
- secondX = maxX
24
- secondY = maxY
25
- } else {
26
- firstX = minX
27
- firstY = maxY
28
- secondX = maxX
29
- secondY = minY
30
- }
31
-
32
- return (
33
- <g className="tl-snap-indicator" stroke="lime">
34
- <line x1={firstX} y1={firstY} x2={secondX} y2={secondY} />
35
- {points.map((p, i) => (
36
- <g transform={`translate(${p.x},${p.y})`} key={i}>
37
- <path
38
- className="tl-snap-point"
39
- d={`M ${-l},${-l} L ${l},${l} M ${-l},${l} L ${l},${-l}`}
40
- />
41
- </g>
42
- ))}
43
- </g>
44
- )
45
- }
46
-
47
- function GapsSnapIndicator({ gaps, direction, zoom }: { zoom: number } & GapsSnapIndicator) {
48
- const l = 3.5 / zoom
49
-
50
- let edgeIntersection: number[] | null = [-Infinity, +Infinity]
51
- let nextEdgeIntersection: number[] | null = null
52
-
53
- const horizontal = direction === 'horizontal'
54
-
55
- // find intersection of all gaps so we can render a straight line through it;
56
- // some range intersections may return null, in which case we skip that gap.
57
- for (const gap of gaps) {
58
- nextEdgeIntersection = rangeIntersection(
59
- edgeIntersection[0],
60
- edgeIntersection[1],
61
- horizontal ? gap.startEdge[0].y : gap.startEdge[0].x,
62
- horizontal ? gap.startEdge[1].y : gap.startEdge[1].x
63
- )
64
-
65
- if (nextEdgeIntersection) {
66
- edgeIntersection = nextEdgeIntersection
67
- } else {
68
- continue
69
- }
70
-
71
- nextEdgeIntersection = rangeIntersection(
72
- edgeIntersection[0],
73
- edgeIntersection[1],
74
- horizontal ? gap.endEdge[0].y : gap.endEdge[0].x,
75
- horizontal ? gap.endEdge[1].y : gap.endEdge[1].x
76
- )
77
-
78
- if (nextEdgeIntersection) {
79
- edgeIntersection = nextEdgeIntersection
80
- } else {
81
- continue
82
- }
83
- }
84
-
85
- if (edgeIntersection === null) {
86
- return null
87
- }
88
-
89
- const midPoint = (edgeIntersection[0] + edgeIntersection[1]) / 2
90
-
91
- return (
92
- <g className="tl-snap-indicator" stroke="cyan">
93
- {gaps.map(({ startEdge, endEdge }, i) => (
94
- <React.Fragment key={i}>
95
- {horizontal ? (
96
- // horizontal gap
97
- <>
98
- {/* start edge */}
99
- <line
100
- x1={startEdge[0].x}
101
- y1={midPoint - 2 * l}
102
- x2={startEdge[1].x}
103
- y2={midPoint + 2 * l}
104
- />
105
- {/* end edge */}
106
- <line
107
- x1={endEdge[0].x}
108
- y1={midPoint - 2 * l}
109
- x2={endEdge[1].x}
110
- y2={midPoint + 2 * l}
111
- />
112
- {/* joining line */}
113
- <line x1={startEdge[0].x} y1={midPoint} x2={endEdge[0].x} y2={midPoint} />
114
- {/* center point marker */}
115
- <line
116
- x1={(startEdge[0].x + endEdge[0].x) / 2}
117
- y1={midPoint - l}
118
- x2={(startEdge[0].x + endEdge[0].x) / 2}
119
- y2={midPoint + l}
120
- />
121
- </>
122
- ) : (
123
- // vertical gap
124
- <>
125
- {/* start edge */}
126
- <line
127
- x1={midPoint - 2 * l}
128
- y1={startEdge[0].y}
129
- x2={midPoint + 2 * l}
130
- y2={startEdge[1].y}
131
- />
132
- {/* end edge */}
133
- <line
134
- x1={midPoint - 2 * l}
135
- y1={endEdge[0].y}
136
- x2={midPoint + 2 * l}
137
- y2={endEdge[1].y}
138
- />
139
- {/* joining line */}
140
- <line x1={midPoint} y1={startEdge[0].y} x2={midPoint} y2={endEdge[0].y} />
141
- {/* center point marker */}
142
- <line
143
- x1={midPoint - l}
144
- y1={(startEdge[0].y + endEdge[0].y) / 2}
145
- x2={midPoint + l}
146
- y2={(startEdge[0].y + endEdge[0].y) / 2}
147
- />
148
- </>
149
- )}
150
- </React.Fragment>
151
- ))}
152
- </g>
153
- )
154
- }
155
-
156
- /** @public */
157
- export interface TLSnapIndicatorProps {
158
- className?: string
159
- line: SnapIndicator
160
- zoom: number
161
- }
162
-
163
- /** @public @react */
164
- export function DefaultSnapIndicator({ className, line, zoom }: TLSnapIndicatorProps) {
165
- return (
166
- <svg className={classNames('tl-overlays__item', className)} aria-hidden="true">
167
- {line.type === 'points' ? (
168
- <PointsSnapIndicator {...line} zoom={zoom} />
169
- ) : line.type === 'gaps' ? (
170
- <GapsSnapIndicator {...line} zoom={zoom} />
171
- ) : null}
172
- </svg>
173
- )
174
- }
@@ -1,88 +0,0 @@
1
- import { TLArrowShape, TLLineShape, TLShapeId } from '@tldraw/tlschema'
2
- import * as React from 'react'
3
- import { Editor } from '../editor/Editor'
4
- import { loopToHtmlElement, releasePointerCapture, setPointerCapture } from '../utils/dom'
5
- import { getPointerInfo } from '../utils/getPointerInfo'
6
- import { useEditor } from './useEditor'
7
-
8
- function getHandle(editor: Editor, id: TLShapeId, handleId: string) {
9
- const shape = editor.getShape<TLArrowShape | TLLineShape>(id)!
10
- const handles = editor.getShapeHandles(shape)!
11
- return { shape, handle: handles.find((h) => h.id === handleId) }
12
- }
13
-
14
- export function useHandleEvents(id: TLShapeId, handleId: string) {
15
- const editor = useEditor()
16
-
17
- return React.useMemo(() => {
18
- const onPointerDown = (e: React.PointerEvent) => {
19
- if (editor.wasEventAlreadyHandled(e)) return
20
-
21
- // Must set pointer capture on an HTML element!
22
- const target = loopToHtmlElement(e.currentTarget)
23
- setPointerCapture(target, e)
24
-
25
- const { shape, handle } = getHandle(editor, id, handleId)
26
-
27
- if (!handle) return
28
-
29
- editor.dispatch({
30
- type: 'pointer',
31
- target: 'handle',
32
- handle,
33
- shape,
34
- name: 'pointer_down',
35
- ...getPointerInfo(editor, e),
36
- })
37
- }
38
-
39
- // Track the last screen point
40
- let lastX: number, lastY: number
41
-
42
- const onPointerMove = (e: React.PointerEvent) => {
43
- if (editor.wasEventAlreadyHandled(e)) return
44
- if (e.clientX === lastX && e.clientY === lastY) return
45
- lastX = e.clientX
46
- lastY = e.clientY
47
-
48
- const { shape, handle } = getHandle(editor, id, handleId)
49
-
50
- if (!handle) return
51
-
52
- editor.dispatch({
53
- type: 'pointer',
54
- target: 'handle',
55
- handle,
56
- shape,
57
- name: 'pointer_move',
58
- ...getPointerInfo(editor, e),
59
- })
60
- }
61
-
62
- const onPointerUp = (e: React.PointerEvent) => {
63
- if (editor.wasEventAlreadyHandled(e)) return
64
-
65
- const target = loopToHtmlElement(e.currentTarget)
66
- releasePointerCapture(target, e)
67
-
68
- const { shape, handle } = getHandle(editor, id, handleId)
69
-
70
- if (!handle) return
71
-
72
- editor.dispatch({
73
- type: 'pointer',
74
- target: 'handle',
75
- handle,
76
- shape,
77
- name: 'pointer_up',
78
- ...getPointerInfo(editor, e),
79
- })
80
- }
81
-
82
- return {
83
- onPointerDown,
84
- onPointerMove,
85
- onPointerUp,
86
- }
87
- }, [editor, id, handleId])
88
- }
@@ -1,97 +0,0 @@
1
- import { useMemo } from 'react'
2
- import { RIGHT_MOUSE_BUTTON } from '../constants'
3
- import { TLSelectionHandle } from '../editor/types/selection-types'
4
- import { loopToHtmlElement, releasePointerCapture, setPointerCapture } from '../utils/dom'
5
- import { getPointerInfo } from '../utils/getPointerInfo'
6
- import { useEditor } from './useEditor'
7
-
8
- /** @public */
9
- export function useSelectionEvents(handle: TLSelectionHandle) {
10
- const editor = useEditor()
11
-
12
- const events = useMemo(
13
- function selectionEvents() {
14
- const onPointerDown: React.PointerEventHandler = (e) => {
15
- if (editor.wasEventAlreadyHandled(e)) return
16
-
17
- if (e.button === RIGHT_MOUSE_BUTTON) {
18
- editor.dispatch({
19
- type: 'pointer',
20
- target: 'selection',
21
- handle,
22
- name: 'right_click',
23
- ...getPointerInfo(editor, e),
24
- })
25
- return
26
- }
27
-
28
- if (e.button !== 0) return
29
-
30
- // Because the events are probably set on SVG elements,
31
- // we need to instead place pointer capture on the first HTML
32
- // element above the event's target; and set a listener to
33
- // remove pointer capture when the pointer is released.
34
-
35
- const elm = loopToHtmlElement(e.currentTarget)
36
-
37
- function releaseCapture() {
38
- elm.removeEventListener('pointerup', releaseCapture)
39
- releasePointerCapture(elm, e)
40
- }
41
-
42
- setPointerCapture(elm, e)
43
- elm.addEventListener('pointerup', releaseCapture)
44
-
45
- editor.dispatch({
46
- name: 'pointer_down',
47
- type: 'pointer',
48
- target: 'selection',
49
- handle,
50
- ...getPointerInfo(editor, e),
51
- })
52
- editor.markEventAsHandled(e)
53
- }
54
-
55
- // Track the last screen point
56
- let lastX: number, lastY: number
57
-
58
- function onPointerMove(e: React.PointerEvent) {
59
- if (editor.wasEventAlreadyHandled(e)) return
60
- if (e.button !== 0) return
61
- if (e.clientX === lastX && e.clientY === lastY) return
62
- lastX = e.clientX
63
- lastY = e.clientY
64
-
65
- editor.dispatch({
66
- name: 'pointer_move',
67
- type: 'pointer',
68
- target: 'selection',
69
- handle,
70
- ...getPointerInfo(editor, e),
71
- })
72
- }
73
-
74
- const onPointerUp: React.PointerEventHandler = (e) => {
75
- if (editor.wasEventAlreadyHandled(e)) return
76
- if (e.button !== 0) return
77
-
78
- editor.dispatch({
79
- name: 'pointer_up',
80
- type: 'pointer',
81
- target: 'selection',
82
- handle,
83
- ...getPointerInfo(editor, e),
84
- })
85
- }
86
-
87
- return {
88
- onPointerDown,
89
- onPointerMove,
90
- onPointerUp,
91
- }
92
- },
93
- [editor, handle]
94
- )
95
-
96
- return events
97
- }