@tldraw/editor 5.2.0-next.ee0fa4d6244f → 5.2.1
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 +7 -1
- package/dist-cjs/index.d.ts +117 -60
- package/dist-cjs/index.js +7 -8
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/components/MenuClickCapture.js +8 -5
- package/dist-cjs/lib/components/MenuClickCapture.js.map +2 -2
- package/dist-cjs/lib/components/Shape.js +47 -1
- package/dist-cjs/lib/components/Shape.js.map +3 -3
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js +1 -16
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
- package/dist-cjs/lib/editor/Editor.js +131 -57
- 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 +3 -3
- 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/managers/FontManager/FontManager.js +28 -4
- package/dist-cjs/lib/editor/managers/FontManager/FontManager.js.map +3 -3
- package/dist-cjs/lib/editor/managers/HistoryManager/HistoryManager.js +24 -2
- package/dist-cjs/lib/editor/managers/HistoryManager/HistoryManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/InputsManager/InputsManager.js +14 -3
- package/dist-cjs/lib/editor/managers/InputsManager/InputsManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.js +4 -2
- package/dist-cjs/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/TextManager/TextManager.js +7 -3
- package/dist-cjs/lib/editor/managers/TextManager/TextManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/TickManager/TickManager.js +0 -1
- package/dist-cjs/lib/editor/managers/TickManager/TickManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js +15 -2
- package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.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/shapes/ShapeUtil.js.map +2 -2
- package/dist-cjs/lib/editor/tools/BaseBoxShapeTool/children/Pointing.js +4 -0
- package/dist-cjs/lib/editor/tools/BaseBoxShapeTool/children/Pointing.js.map +2 -2
- package/dist-cjs/lib/editor/tools/StateNode.js.map +2 -2
- package/dist-cjs/lib/{hooks/useTransform.js → editor/tools/cancelShapeCreationOnLongPress.js} +8 -23
- package/dist-cjs/lib/editor/tools/cancelShapeCreationOnLongPress.js.map +7 -0
- 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/lib/globals/environment.js +6 -1
- package/dist-cjs/lib/globals/environment.js.map +2 -2
- package/dist-cjs/lib/hooks/EditorComponentsContext.js.map +2 -2
- package/dist-cjs/lib/hooks/useCanvasEvents.js +17 -8
- package/dist-cjs/lib/hooks/useCanvasEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/useEditorComponents.js +0 -1
- package/dist-cjs/lib/hooks/useEditorComponents.js.map +2 -2
- package/dist-cjs/lib/hooks/usePresence.js.map +2 -2
- package/dist-cjs/lib/hooks/useScreenBounds.js +1 -0
- package/dist-cjs/lib/hooks/useScreenBounds.js.map +2 -2
- package/dist-cjs/lib/license/LicenseManager.js +5 -1
- package/dist-cjs/lib/license/LicenseManager.js.map +2 -2
- package/dist-cjs/lib/primitives/Vec.js +3 -2
- package/dist-cjs/lib/primitives/Vec.js.map +2 -2
- package/dist-cjs/lib/utils/dom.js +12 -0
- package/dist-cjs/lib/utils/dom.js.map +2 -2
- package/dist-cjs/lib/utils/getPointerInfo.js +2 -1
- package/dist-cjs/lib/utils/getPointerInfo.js.map +2 -2
- package/dist-cjs/lib/utils/pointer.js +37 -0
- package/dist-cjs/lib/utils/pointer.js.map +7 -0
- package/dist-cjs/version.js +3 -3
- package/dist-cjs/version.js.map +1 -1
- package/dist-esm/index.d.mts +117 -60
- package/dist-esm/index.mjs +9 -13
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/components/MenuClickCapture.mjs +8 -5
- package/dist-esm/lib/components/MenuClickCapture.mjs.map +2 -2
- package/dist-esm/lib/components/Shape.mjs +48 -2
- package/dist-esm/lib/components/Shape.mjs.map +3 -3
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +1 -16
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
- package/dist-esm/lib/editor/Editor.mjs +131 -57
- 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 +3 -3
- 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/managers/FontManager/FontManager.mjs +28 -4
- package/dist-esm/lib/editor/managers/FontManager/FontManager.mjs.map +3 -3
- package/dist-esm/lib/editor/managers/HistoryManager/HistoryManager.mjs +24 -2
- package/dist-esm/lib/editor/managers/HistoryManager/HistoryManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/InputsManager/InputsManager.mjs +14 -3
- package/dist-esm/lib/editor/managers/InputsManager/InputsManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.mjs +4 -2
- package/dist-esm/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs +7 -3
- package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/TickManager/TickManager.mjs +0 -1
- package/dist-esm/lib/editor/managers/TickManager/TickManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs +15 -2
- package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.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/shapes/ShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/editor/tools/BaseBoxShapeTool/children/Pointing.mjs +4 -0
- package/dist-esm/lib/editor/tools/BaseBoxShapeTool/children/Pointing.mjs.map +2 -2
- package/dist-esm/lib/editor/tools/StateNode.mjs.map +2 -2
- package/dist-esm/lib/editor/tools/cancelShapeCreationOnLongPress.mjs +8 -0
- package/dist-esm/lib/editor/tools/cancelShapeCreationOnLongPress.mjs.map +7 -0
- 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/lib/globals/environment.mjs +6 -1
- package/dist-esm/lib/globals/environment.mjs.map +2 -2
- package/dist-esm/lib/hooks/EditorComponentsContext.mjs.map +2 -2
- package/dist-esm/lib/hooks/useCanvasEvents.mjs +17 -8
- package/dist-esm/lib/hooks/useCanvasEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useEditorComponents.mjs +0 -1
- package/dist-esm/lib/hooks/useEditorComponents.mjs.map +2 -2
- package/dist-esm/lib/hooks/usePresence.mjs.map +2 -2
- package/dist-esm/lib/hooks/useScreenBounds.mjs +1 -0
- package/dist-esm/lib/hooks/useScreenBounds.mjs.map +2 -2
- package/dist-esm/lib/license/LicenseManager.mjs +5 -1
- package/dist-esm/lib/license/LicenseManager.mjs.map +2 -2
- package/dist-esm/lib/primitives/Vec.mjs +3 -2
- package/dist-esm/lib/primitives/Vec.mjs.map +2 -2
- package/dist-esm/lib/utils/dom.mjs +12 -0
- package/dist-esm/lib/utils/dom.mjs.map +2 -2
- package/dist-esm/lib/utils/getPointerInfo.mjs +2 -1
- package/dist-esm/lib/utils/getPointerInfo.mjs.map +2 -2
- package/dist-esm/lib/utils/pointer.mjs +17 -0
- package/dist-esm/lib/utils/pointer.mjs.map +7 -0
- package/dist-esm/version.mjs +3 -3
- package/dist-esm/version.mjs.map +1 -1
- package/editor.css +15 -3
- package/package.json +11 -8
- package/src/index.ts +4 -10
- package/src/lib/components/MenuClickCapture.tsx +8 -4
- package/src/lib/components/Shape.tsx +88 -1
- package/src/lib/components/default-components/DefaultCanvas.tsx +1 -17
- package/src/lib/editor/Editor.test.ts +36 -0
- package/src/lib/editor/Editor.ts +204 -75
- 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 +43 -16
- package/src/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.ts +8 -5
- 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 +37 -10
- package/src/lib/editor/managers/FontManager/FontManager.ts +46 -1
- package/src/lib/editor/managers/HistoryManager/HistoryManager.test.ts +32 -0
- package/src/lib/editor/managers/HistoryManager/HistoryManager.ts +34 -4
- package/src/lib/editor/managers/InputsManager/InputsManager.test.ts +61 -0
- package/src/lib/editor/managers/InputsManager/InputsManager.ts +16 -4
- package/src/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.ts +9 -2
- package/src/lib/editor/managers/TextManager/TextManager.test.ts +16 -14
- package/src/lib/editor/managers/TextManager/TextManager.ts +17 -2
- package/src/lib/editor/managers/TickManager/TickManager.test.ts +0 -40
- package/src/lib/editor/managers/TickManager/TickManager.ts +0 -1
- package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.test.ts +12 -2
- package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.ts +27 -2
- package/src/lib/editor/overlays/strokeShapeIndicators.ts +86 -0
- package/src/lib/editor/shapes/ShapeUtil.ts +41 -0
- package/src/lib/editor/tools/BaseBoxShapeTool/children/Pointing.ts +5 -0
- package/src/lib/editor/tools/StateNode.ts +0 -2
- package/src/lib/editor/tools/cancelShapeCreationOnLongPress.ts +31 -0
- package/src/lib/editor/types/event-types.ts +9 -6
- package/src/lib/globals/environment.ts +7 -0
- package/src/lib/hooks/EditorComponentsContext.tsx +0 -2
- package/src/lib/hooks/useCanvasEvents.ts +24 -12
- package/src/lib/hooks/useEditorComponents.tsx +0 -1
- package/src/lib/hooks/usePresence.ts +2 -2
- package/src/lib/hooks/useScreenBounds.ts +3 -0
- package/src/lib/license/LicenseManager.test.ts +24 -16
- package/src/lib/license/LicenseManager.ts +8 -2
- package/src/lib/primitives/Vec.ts +5 -2
- package/src/lib/test/ContentElementSlot.test.tsx +201 -0
- package/src/lib/utils/dom.ts +34 -0
- package/src/lib/utils/getPointerInfo.ts +2 -1
- package/src/lib/utils/pointer.test.ts +76 -0
- package/src/lib/utils/pointer.ts +42 -0
- package/src/version.ts +3 -3
- package/dist-cjs/lib/components/default-components/DefaultSelectionBackground.js +0 -49
- package/dist-cjs/lib/components/default-components/DefaultSelectionBackground.js.map +0 -7
- package/dist-cjs/lib/editor/overlays/ShapeIndicatorOverlayUtil.js +0 -161
- package/dist-cjs/lib/editor/overlays/ShapeIndicatorOverlayUtil.js.map +0 -7
- package/dist-cjs/lib/hooks/useTransform.js.map +0 -7
- package/dist-esm/lib/components/default-components/DefaultSelectionBackground.mjs +0 -19
- package/dist-esm/lib/components/default-components/DefaultSelectionBackground.mjs.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/dist-esm/lib/hooks/useTransform.mjs +0 -23
- package/dist-esm/lib/hooks/useTransform.mjs.map +0 -7
- package/src/lib/components/default-components/DefaultSelectionBackground.tsx +0 -25
- package/src/lib/editor/overlays/ShapeIndicatorOverlayUtil.ts +0 -216
- package/src/lib/hooks/useTransform.ts +0 -30
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { tlenv } from "../globals/environment.mjs";
|
|
2
|
+
function isDirectDisplayPen(e) {
|
|
3
|
+
if (e.pointerType !== "pen") return false;
|
|
4
|
+
return tlenv.isTouchDevice;
|
|
5
|
+
}
|
|
6
|
+
function isSecondaryClickEvent(e) {
|
|
7
|
+
return e.button === 2 || tlenv.isDarwin && e.button === 0 && e.ctrlKey && !e.metaKey;
|
|
8
|
+
}
|
|
9
|
+
function getPointerEventButton(e) {
|
|
10
|
+
return isSecondaryClickEvent(e) ? 2 : e.button;
|
|
11
|
+
}
|
|
12
|
+
export {
|
|
13
|
+
getPointerEventButton,
|
|
14
|
+
isDirectDisplayPen,
|
|
15
|
+
isSecondaryClickEvent
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=pointer.mjs.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/lib/utils/pointer.ts"],
|
|
4
|
+
"sourcesContent": ["import type React from 'react'\nimport { tlenv } from '../globals/environment'\n\n/**\n * Decide whether a pen pointer event looks like direct manipulation on the display (e.g. Apple\n * Pencil on an iPad or a Surface Pen on a touchscreen) rather than indirect input from a desktop\n * graphics tablet (e.g. a Wacom Intuos).\n *\n * We can't tell the two apart from the pointer event itself: both report `pointerType: 'pen'`, and\n * implicit pointer capture \u2014 which in theory distinguishes direct-manipulation pointers \u2014 isn't\n * reliably observable across browsers (notably WebKit/iPad). Instead we key off the device: a\n * direct-display pen draws on a touch-capable screen, while an indirect graphics tablet is used on\n * a non-touch desktop alongside a mouse. A device with no touch input therefore can't host a\n * direct-display pen.\n *\n * Note this uses {@link tlenv.isTouchDevice} \u2014 the device's fixed touch capability \u2014 not the\n * editor's dynamic `isCoarsePointer` state, which a pen `pointerdown` flips to coarse regardless\n * of device.\n *\n * @internal\n */\nexport function isDirectDisplayPen(e: React.PointerEvent | PointerEvent): boolean {\n\tif (e.pointerType !== 'pen') return false\n\treturn tlenv.isTouchDevice\n}\n\n/** @internal */\ninterface PointerLike {\n\tbutton: number\n\tctrlKey: boolean\n\tmetaKey: boolean\n}\n\n/** @internal */\nexport function isSecondaryClickEvent(e: PointerLike) {\n\treturn e.button === 2 || (tlenv.isDarwin && e.button === 0 && e.ctrlKey && !e.metaKey)\n}\n\n/** @internal */\nexport function getPointerEventButton(e: PointerLike) {\n\treturn isSecondaryClickEvent(e) ? 2 : e.button\n}\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,aAAa;AAoBf,SAAS,mBAAmB,GAA+C;AACjF,MAAI,EAAE,gBAAgB,MAAO,QAAO;AACpC,SAAO,MAAM;AACd;AAUO,SAAS,sBAAsB,GAAgB;AACrD,SAAO,EAAE,WAAW,KAAM,MAAM,YAAY,EAAE,WAAW,KAAK,EAAE,WAAW,CAAC,EAAE;AAC/E;AAGO,SAAS,sBAAsB,GAAgB;AACrD,SAAO,sBAAsB,CAAC,IAAI,IAAI,EAAE;AACzC;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist-esm/version.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
const version = "5.2.
|
|
1
|
+
const version = "5.2.1";
|
|
2
2
|
const publishDates = {
|
|
3
3
|
major: "2026-05-06T16:28:18.473Z",
|
|
4
|
-
minor: "2026-
|
|
5
|
-
patch: "2026-
|
|
4
|
+
minor: "2026-07-01T09:20:01.735Z",
|
|
5
|
+
patch: "2026-07-01T10:28:54.350Z"
|
|
6
6
|
};
|
|
7
7
|
export {
|
|
8
8
|
publishDates,
|
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 = '5.2.
|
|
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 = '5.2.1'\nexport const publishDates = {\n\tmajor: '2026-05-06T16:28:18.473Z',\n\tminor: '2026-07-01T09:20:01.735Z',\n\tpatch: '2026-07-01T10:28:54.350Z',\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/editor.css
CHANGED
|
@@ -182,6 +182,7 @@
|
|
|
182
182
|
--tl-color-text-0: hsl(0, 0%, 11%);
|
|
183
183
|
--tl-color-text-1: hsl(0, 0%, 18%);
|
|
184
184
|
--tl-color-text-3: hsl(204, 4%, 45%);
|
|
185
|
+
--tl-color-text-disabled: hsl(204, 4%, 55%);
|
|
185
186
|
--tl-color-text-shadow: hsl(0, 0%, 100%);
|
|
186
187
|
--tl-color-text-highlight: hsl(52, 100%, 50%);
|
|
187
188
|
--tl-color-text-highlight-p3: color(display-p3 0.972 0.8205 0.05);
|
|
@@ -236,6 +237,7 @@
|
|
|
236
237
|
--tl-color-text-0: hsl(0, 9%, 94%);
|
|
237
238
|
--tl-color-text-1: hsl(0, 0%, 85%);
|
|
238
239
|
--tl-color-text-3: hsl(204, 4%, 75%);
|
|
240
|
+
--tl-color-text-disabled: hsl(204, 4%, 50%);
|
|
239
241
|
--tl-color-text-shadow: hsl(210, 13%, 18%);
|
|
240
242
|
--tl-color-text-highlight: hsl(52, 100%, 41%);
|
|
241
243
|
--tl-color-text-highlight-p3: color(display-p3 0.8078 0.6225 0.0312);
|
|
@@ -762,17 +764,17 @@ input,
|
|
|
762
764
|
.tl-rich-text ol {
|
|
763
765
|
text-align: left;
|
|
764
766
|
margin: 0;
|
|
765
|
-
padding-left:
|
|
767
|
+
padding-left: 1.625ch;
|
|
766
768
|
/* Some resets, like Tailwind, nix the list styling. */
|
|
767
769
|
list-style: revert;
|
|
768
770
|
}
|
|
769
771
|
|
|
770
772
|
.tl-rich-text ol:has(> li:nth-child(10)) {
|
|
771
|
-
padding-left:
|
|
773
|
+
padding-left: 2.625ch;
|
|
772
774
|
}
|
|
773
775
|
|
|
774
776
|
.tl-rich-text ol:has(> li:nth-child(100)) {
|
|
775
|
-
padding-left:
|
|
777
|
+
padding-left: 3.625ch;
|
|
776
778
|
}
|
|
777
779
|
|
|
778
780
|
.tl-rich-text h1,
|
|
@@ -811,6 +813,7 @@ input,
|
|
|
811
813
|
.tl-theme__dark .tl-rich-text mark {
|
|
812
814
|
background-color: var(--tl-color-text-highlight);
|
|
813
815
|
color: currentColor;
|
|
816
|
+
text-shadow: none;
|
|
814
817
|
}
|
|
815
818
|
|
|
816
819
|
@supports (color: color(display-p3 1 1 1)) {
|
|
@@ -983,6 +986,15 @@ input,
|
|
|
983
986
|
color: var(--tl-color-text-1);
|
|
984
987
|
}
|
|
985
988
|
|
|
989
|
+
.tl-content-slot {
|
|
990
|
+
position: absolute;
|
|
991
|
+
inset: 0px;
|
|
992
|
+
height: 100%;
|
|
993
|
+
width: 100%;
|
|
994
|
+
pointer-events: none;
|
|
995
|
+
transform-origin: top left;
|
|
996
|
+
}
|
|
997
|
+
|
|
986
998
|
/* -------------------- Group shape ------------------ */
|
|
987
999
|
|
|
988
1000
|
.tl-group {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tldraw/editor",
|
|
3
3
|
"description": "tldraw infinite canvas SDK (editor).",
|
|
4
|
-
"version": "5.2.
|
|
4
|
+
"version": "5.2.1",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "tldraw Inc.",
|
|
7
7
|
"email": "hello@tldraw.com"
|
|
@@ -49,12 +49,12 @@
|
|
|
49
49
|
"@tiptap/core": "^3.12.1",
|
|
50
50
|
"@tiptap/pm": "^3.12.1",
|
|
51
51
|
"@tiptap/react": "^3.12.1",
|
|
52
|
-
"@tldraw/state": "5.2.
|
|
53
|
-
"@tldraw/state-react": "5.2.
|
|
54
|
-
"@tldraw/store": "5.2.
|
|
55
|
-
"@tldraw/tlschema": "5.2.
|
|
56
|
-
"@tldraw/utils": "5.2.
|
|
57
|
-
"@tldraw/validate": "5.2.
|
|
52
|
+
"@tldraw/state": "5.2.1",
|
|
53
|
+
"@tldraw/state-react": "5.2.1",
|
|
54
|
+
"@tldraw/store": "5.2.1",
|
|
55
|
+
"@tldraw/tlschema": "5.2.1",
|
|
56
|
+
"@tldraw/utils": "5.2.1",
|
|
57
|
+
"@tldraw/validate": "5.2.1",
|
|
58
58
|
"classnames": "^2.5.1",
|
|
59
59
|
"eventemitter3": "^4.0.7",
|
|
60
60
|
"idb": "^7.1.1",
|
|
@@ -80,7 +80,10 @@
|
|
|
80
80
|
"react": "^19.2.1",
|
|
81
81
|
"react-dom": "^19.2.1",
|
|
82
82
|
"resize-observer-polyfill": "^1.5.1",
|
|
83
|
-
"vitest": "^
|
|
83
|
+
"vitest": "^4.1.7"
|
|
84
|
+
},
|
|
85
|
+
"engines": {
|
|
86
|
+
"node": ">=22.12.0"
|
|
84
87
|
},
|
|
85
88
|
"module": "dist-esm/index.mjs",
|
|
86
89
|
"source": "src/index.ts",
|
package/src/index.ts
CHANGED
|
@@ -23,10 +23,6 @@ export {
|
|
|
23
23
|
type TLErrorFallbackComponent,
|
|
24
24
|
} from './lib/components/default-components/DefaultErrorFallback'
|
|
25
25
|
export { DefaultGrid, type TLGridProps } from './lib/components/default-components/DefaultGrid'
|
|
26
|
-
export {
|
|
27
|
-
DefaultSelectionBackground,
|
|
28
|
-
type TLSelectionBackgroundProps,
|
|
29
|
-
} from './lib/components/default-components/DefaultSelectionBackground'
|
|
30
26
|
export { type TLShapeErrorFallbackComponent } from './lib/components/default-components/DefaultShapeErrorFallback'
|
|
31
27
|
export {
|
|
32
28
|
DefaultShapeWrapper,
|
|
@@ -128,6 +124,7 @@ export {
|
|
|
128
124
|
export { SpatialIndexManager } from './lib/editor/managers/SpatialIndexManager/SpatialIndexManager'
|
|
129
125
|
export {
|
|
130
126
|
TextManager,
|
|
127
|
+
resolveLineHeightPx,
|
|
131
128
|
type BatchMeasurementRequest,
|
|
132
129
|
type TLMeasuredTextSize,
|
|
133
130
|
type TLMeasureTextOpts,
|
|
@@ -185,11 +182,7 @@ export {
|
|
|
185
182
|
type TLOverlay,
|
|
186
183
|
type TLOverlayUtilConstructor,
|
|
187
184
|
} from './lib/editor/overlays/OverlayUtil'
|
|
188
|
-
export {
|
|
189
|
-
ShapeIndicatorOverlayUtil,
|
|
190
|
-
strokeShapeIndicators,
|
|
191
|
-
type TLShapeIndicatorOverlay,
|
|
192
|
-
} from './lib/editor/overlays/ShapeIndicatorOverlayUtil'
|
|
185
|
+
export { strokeShapeIndicators } from './lib/editor/overlays/strokeShapeIndicators'
|
|
193
186
|
export {
|
|
194
187
|
getPerfectDashProps,
|
|
195
188
|
type PerfectDashTerminal,
|
|
@@ -198,6 +191,7 @@ export { resizeBox, type ResizeBoxOptions } from './lib/editor/shapes/shared/res
|
|
|
198
191
|
export { resizeScaled } from './lib/editor/shapes/shared/resizeScaled'
|
|
199
192
|
export { BaseBoxShapeTool } from './lib/editor/tools/BaseBoxShapeTool/BaseBoxShapeTool'
|
|
200
193
|
export { maybeSnapToGrid } from './lib/editor/tools/BaseBoxShapeTool/children/Pointing'
|
|
194
|
+
export { cancelShapeCreationOnLongPress } from './lib/editor/tools/cancelShapeCreationOnLongPress'
|
|
201
195
|
export { StateNode, type TLStateNodeConstructor } from './lib/editor/tools/StateNode'
|
|
202
196
|
export { type TLContent } from './lib/editor/types/clipboard-types'
|
|
203
197
|
export { type TLEventMap, type TLEventMapHandler } from './lib/editor/types/emit-types'
|
|
@@ -325,7 +319,6 @@ export {
|
|
|
325
319
|
type SafeId,
|
|
326
320
|
} from './lib/hooks/useSafeId'
|
|
327
321
|
export { useTLSchemaFromUtils, useTLStore } from './lib/hooks/useTLStore'
|
|
328
|
-
export { useTransform } from './lib/hooks/useTransform'
|
|
329
322
|
export { useViewportHeight } from './lib/hooks/useViewportHeight'
|
|
330
323
|
export {
|
|
331
324
|
LicenseManager,
|
|
@@ -458,6 +451,7 @@ export {
|
|
|
458
451
|
getGlobalDocument,
|
|
459
452
|
getGlobalWindow,
|
|
460
453
|
loopToHtmlElement,
|
|
454
|
+
moveElementInto,
|
|
461
455
|
preventDefault,
|
|
462
456
|
releasePointerCapture,
|
|
463
457
|
setPointerCapture,
|
|
@@ -6,6 +6,7 @@ import { useEditor } from '../hooks/useEditor'
|
|
|
6
6
|
import { Vec } from '../primitives/Vec'
|
|
7
7
|
import { releasePointerCapture, setPointerCapture } from '../utils/dom'
|
|
8
8
|
import { getPointerInfo } from '../utils/getPointerInfo'
|
|
9
|
+
import { getPointerEventButton } from '../utils/pointer'
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* When a menu is open, this component prevents the user from interacting with the canvas.
|
|
@@ -68,18 +69,19 @@ export function MenuClickCapture() {
|
|
|
68
69
|
|
|
69
70
|
const handlePointerDown = useCallback(
|
|
70
71
|
(e: PointerEvent) => {
|
|
71
|
-
|
|
72
|
+
const button = getPointerEventButton(e)
|
|
73
|
+
if (button !== 0 && button !== 2) return
|
|
72
74
|
|
|
73
75
|
flushSync(() => setIsPointing(true))
|
|
74
76
|
setPointerCapture(e.currentTarget, e)
|
|
75
77
|
rPointerState.current = {
|
|
76
78
|
isDown: true,
|
|
77
79
|
isDragging: false,
|
|
78
|
-
button
|
|
80
|
+
button,
|
|
79
81
|
start: new Vec(e.clientX, e.clientY),
|
|
80
82
|
}
|
|
81
83
|
|
|
82
|
-
if (
|
|
84
|
+
if (button === 2) {
|
|
83
85
|
if (!editor.options.rightClickPanning) {
|
|
84
86
|
// Right-click panning off: close the open menu and swallow the native
|
|
85
87
|
// contextmenu that would otherwise briefly open a new one (causing a flash).
|
|
@@ -141,13 +143,15 @@ export function MenuClickCapture() {
|
|
|
141
143
|
|
|
142
144
|
const handlePointerUp = useCallback(
|
|
143
145
|
(e: PointerEvent) => {
|
|
144
|
-
const isStaticRightClick =
|
|
146
|
+
const isStaticRightClick =
|
|
147
|
+
rPointerState.current.button === 2 && !rPointerState.current.isDragging
|
|
145
148
|
|
|
146
149
|
editor.dispatch({
|
|
147
150
|
type: 'pointer',
|
|
148
151
|
target: 'canvas',
|
|
149
152
|
name: 'pointer_up',
|
|
150
153
|
...getPointerInfo(editor, e),
|
|
154
|
+
button: rPointerState.current.button === 2 ? 2 : getPointerEventButton(e),
|
|
151
155
|
})
|
|
152
156
|
|
|
153
157
|
if (isStaticRightClick && editor.options.rightClickPanning) {
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import { react } from '@tldraw/state'
|
|
2
2
|
import { useQuickReactor, useStateTracking } from '@tldraw/state-react'
|
|
3
3
|
import { TLShape, TLShapeId } from '@tldraw/tlschema'
|
|
4
|
+
import { warnOnce } from '@tldraw/utils'
|
|
4
5
|
import { memo, useCallback, useEffect, useLayoutEffect, useRef } from 'react'
|
|
6
|
+
import { Editor } from '../editor/Editor'
|
|
5
7
|
import { ShapeUtil } from '../editor/shapes/ShapeUtil'
|
|
6
8
|
import { useEditorComponents } from '../hooks/EditorComponentsContext'
|
|
7
9
|
import { useEditor } from '../hooks/useEditor'
|
|
8
10
|
import { useShapeCulling } from '../hooks/useShapeCulling'
|
|
9
11
|
import { Mat } from '../primitives/Mat'
|
|
10
12
|
import { areShapesContentEqual } from '../utils/areShapesContentEqual'
|
|
11
|
-
import { setStyleProperty } from '../utils/dom'
|
|
13
|
+
import { moveElementInto, setStyleProperty } from '../utils/dom'
|
|
12
14
|
import { OptionalErrorBoundary } from './ErrorBoundary'
|
|
13
15
|
|
|
14
16
|
/*
|
|
@@ -153,11 +155,96 @@ export const Shape = memo(function Shape({
|
|
|
153
155
|
<OptionalErrorBoundary fallback={ShapeErrorFallback as any} onError={annotateError}>
|
|
154
156
|
<InnerShape shape={shape} util={util} />
|
|
155
157
|
</OptionalErrorBoundary>
|
|
158
|
+
{util.getAppOwnedElement && <ContentElementSlot id={id} util={util} />}
|
|
156
159
|
</ShapeWrapper>
|
|
157
160
|
</>
|
|
158
161
|
)
|
|
159
162
|
})
|
|
160
163
|
|
|
164
|
+
/*
|
|
165
|
+
The content element slot hosts an app-owned element provided by the shape util's
|
|
166
|
+
getAppOwnedElement method. The contract: while the shape is mounted, tldraw never
|
|
167
|
+
unmounts, recreates, or relocates the element (the canvas renders shapes in stable
|
|
168
|
+
id-sorted DOM order, so reorders and reparenting never move DOM nodes), and before
|
|
169
|
+
the slot is destroyed — shape deletion, page change, error teardown, or the whole
|
|
170
|
+
editor unmounting — onReleaseAppOwnedElement is called while the slot is still
|
|
171
|
+
connected to the document, so the app can move the element to a new parent with
|
|
172
|
+
Node.moveBefore without resetting its state. That last guarantee relies on this
|
|
173
|
+
being a layout effect: React runs layout effect cleanups before it detaches the
|
|
174
|
+
host nodes of a deleted subtree, which is not true of passive effects.
|
|
175
|
+
*/
|
|
176
|
+
const ContentElementSlot = memo(function ContentElementSlot({
|
|
177
|
+
id,
|
|
178
|
+
util,
|
|
179
|
+
}: {
|
|
180
|
+
id: TLShapeId
|
|
181
|
+
util: ShapeUtil
|
|
182
|
+
}) {
|
|
183
|
+
const editor = useEditor()
|
|
184
|
+
const slotRef = useRef<HTMLDivElement>(null)
|
|
185
|
+
|
|
186
|
+
useLayoutEffect(() => {
|
|
187
|
+
const slot = slotRef.current
|
|
188
|
+
if (!slot) return
|
|
189
|
+
|
|
190
|
+
const shape = editor.getShape(id)
|
|
191
|
+
if (!shape) return
|
|
192
|
+
|
|
193
|
+
// getAppOwnedElement is called once per shape mount (the effect deps below are
|
|
194
|
+
// [editor, id, util], none of which change on a prop edit), so the adopted element is
|
|
195
|
+
// not refreshed when the shape's props change. A util whose element identity depends on
|
|
196
|
+
// props must mutate the existing element in place rather than return a new one. Likewise,
|
|
197
|
+
// if this returns null now and an element only later, the element is never adopted for
|
|
198
|
+
// this mount — return a stable element up front and populate it asynchronously instead.
|
|
199
|
+
const element = util.getAppOwnedElement?.(shape)
|
|
200
|
+
if (!element) return
|
|
201
|
+
|
|
202
|
+
// An element that was connected before adoption (e.g. parked off-canvas by the
|
|
203
|
+
// app between editor sessions) should survive the move without reloading.
|
|
204
|
+
const wasConnectedBeforeAdoption = element.isConnected
|
|
205
|
+
|
|
206
|
+
if (element.parentNode !== slot) {
|
|
207
|
+
moveElementInto(slot, element)
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if (process.env.NODE_ENV !== 'production' && wasConnectedBeforeAdoption) {
|
|
211
|
+
warnIfContentElementReloads(editor, slot, element)
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return () => {
|
|
215
|
+
// Note: under React StrictMode (dev only) this effect runs mount → cleanup → mount,
|
|
216
|
+
// so onReleaseAppOwnedElement fires once even though the shape was not removed, and on
|
|
217
|
+
// the appendChild fallback path the element is detached and re-adopted (reloading it).
|
|
218
|
+
// onReleaseAppOwnedElement must therefore be safe to call when the shape still exists;
|
|
219
|
+
// don't treat it as a definitive "shape removed" signal (check the store if you need
|
|
220
|
+
// to know). With Node.moveBefore the re-adoption preserves state, so this is benign.
|
|
221
|
+
const latestShape = editor.getShape(id) ?? shape
|
|
222
|
+
util.onReleaseAppOwnedElement?.(latestShape, element)
|
|
223
|
+
if (process.env.NODE_ENV !== 'production' && element.parentNode === slot) {
|
|
224
|
+
warnOnce(
|
|
225
|
+
`The content element for shape "${id}" was not reclaimed by onReleaseAppOwnedElement and will be destroyed along with its slot, losing any state it holds.`
|
|
226
|
+
)
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}, [editor, id, util])
|
|
230
|
+
|
|
231
|
+
return <div ref={slotRef} className="tl-content-slot" draggable={false} />
|
|
232
|
+
})
|
|
233
|
+
|
|
234
|
+
// Dev-mode assertion that adoption kept the platform's state-preservation promise: a
|
|
235
|
+
// load event firing on a previously-connected adopted element means the embed reloaded.
|
|
236
|
+
// load doesn't bubble, but capture-phase listeners on ancestors still observe it.
|
|
237
|
+
function warnIfContentElementReloads(editor: Editor, slot: HTMLElement, element: HTMLElement) {
|
|
238
|
+
const onLoad = (event: Event) => {
|
|
239
|
+
if (event.target !== element && !element.contains(event.target as Node)) return
|
|
240
|
+
warnOnce(
|
|
241
|
+
'A load event fired on an adopted content element. The element reloaded when it was moved into the shape, losing its state. State-preserving moves need Node.moveBefore (Chromium 133+, Firefox 144+) and a continuously connected element.'
|
|
242
|
+
)
|
|
243
|
+
}
|
|
244
|
+
slot.addEventListener('load', onLoad, { capture: true })
|
|
245
|
+
editor.timers.setTimeout(() => slot.removeEventListener('load', onLoad, { capture: true }), 1000)
|
|
246
|
+
}
|
|
247
|
+
|
|
161
248
|
export const InnerShape = memo(
|
|
162
249
|
function InnerShape<T extends TLShape>({ shape, util }: { shape: T; util: ShapeUtil<T> }) {
|
|
163
250
|
return useStateTracking(
|
|
@@ -32,7 +32,7 @@ export interface TLCanvasComponentProps {
|
|
|
32
32
|
export function DefaultCanvas({ className }: TLCanvasComponentProps) {
|
|
33
33
|
const editor = useEditor()
|
|
34
34
|
|
|
35
|
-
const {
|
|
35
|
+
const { Background, SvgDefs } = useEditorComponents()
|
|
36
36
|
|
|
37
37
|
const rCanvas = useRef<HTMLDivElement>(null)
|
|
38
38
|
const rHtmlLayer = useRef<HTMLDivElement>(null)
|
|
@@ -160,7 +160,6 @@ export function DefaultCanvas({ className }: TLCanvasComponentProps) {
|
|
|
160
160
|
{isGridMode && Grid && <GridWrapper />}
|
|
161
161
|
<div ref={rHtmlLayer} className="tl-html-layer tl-shapes" draggable={false}>
|
|
162
162
|
<OnTheCanvasWrapper />
|
|
163
|
-
{SelectionBackground && <SelectionBackgroundWrapper />}
|
|
164
163
|
{hideShapes ? null : <ShapesLayer canvasRef={rCanvas} />}
|
|
165
164
|
</div>
|
|
166
165
|
<CanvasOverlays />
|
|
@@ -345,21 +344,6 @@ function DebugSvgCopy({ id, mode }: { id: TLShapeId; mode: 'img' | 'iframe' }) {
|
|
|
345
344
|
)
|
|
346
345
|
}
|
|
347
346
|
|
|
348
|
-
function SelectionBackgroundWrapper() {
|
|
349
|
-
const editor = useEditor()
|
|
350
|
-
const selectionRotation = useValue('selection rotation', () => editor.getSelectionRotation(), [
|
|
351
|
-
editor,
|
|
352
|
-
])
|
|
353
|
-
const selectionBounds = useValue(
|
|
354
|
-
'selection bounds',
|
|
355
|
-
() => editor.getSelectionRotatedPageBounds(),
|
|
356
|
-
[editor]
|
|
357
|
-
)
|
|
358
|
-
const { SelectionBackground } = useEditorComponents()
|
|
359
|
-
if (!selectionBounds || !SelectionBackground) return null
|
|
360
|
-
return <SelectionBackground bounds={selectionBounds} rotation={selectionRotation} />
|
|
361
|
-
}
|
|
362
|
-
|
|
363
347
|
function OnTheCanvasWrapper() {
|
|
364
348
|
const { OnTheCanvas } = useEditorComponents()
|
|
365
349
|
if (!OnTheCanvas) return null
|
|
@@ -96,6 +96,42 @@ describe('updateShape', () => {
|
|
|
96
96
|
})
|
|
97
97
|
})
|
|
98
98
|
|
|
99
|
+
describe('updateViewportScreenBounds', () => {
|
|
100
|
+
it('bails without crashing or updating bounds when the container document has no body', () => {
|
|
101
|
+
const documentSpy = vi
|
|
102
|
+
.spyOn(editor, 'getContainerDocument')
|
|
103
|
+
.mockReturnValue({ body: null } as unknown as Document)
|
|
104
|
+
|
|
105
|
+
const prevScreenBounds = editor.getInstanceState().screenBounds
|
|
106
|
+
const prevInsets = editor.getInstanceState().insets
|
|
107
|
+
|
|
108
|
+
try {
|
|
109
|
+
expect(() => editor.updateViewportScreenBounds(new Box(10, 20, 100, 200))).not.toThrow()
|
|
110
|
+
// A torn-down document is not measurable, so the bounds are left untouched.
|
|
111
|
+
expect(editor.getInstanceState().screenBounds).toEqual(prevScreenBounds)
|
|
112
|
+
expect(editor.getInstanceState().insets).toEqual(prevInsets)
|
|
113
|
+
} finally {
|
|
114
|
+
documentSpy.mockRestore()
|
|
115
|
+
}
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
it('uses the container document body to calculate right and bottom insets', () => {
|
|
119
|
+
const documentSpy = vi.spyOn(editor, 'getContainerDocument').mockReturnValue({
|
|
120
|
+
body: {
|
|
121
|
+
scrollWidth: 500,
|
|
122
|
+
scrollHeight: 400,
|
|
123
|
+
},
|
|
124
|
+
} as unknown as Document)
|
|
125
|
+
|
|
126
|
+
try {
|
|
127
|
+
editor.updateViewportScreenBounds(new Box(10, 20, 100, 200))
|
|
128
|
+
expect(editor.getInstanceState().insets).toEqual([true, true, true, true])
|
|
129
|
+
} finally {
|
|
130
|
+
documentSpy.mockRestore()
|
|
131
|
+
}
|
|
132
|
+
})
|
|
133
|
+
})
|
|
134
|
+
|
|
99
135
|
describe('zoomToFit', () => {
|
|
100
136
|
it('no-op when isLocked is set', () => {
|
|
101
137
|
editor.getCurrentPageShapeIds = vi.fn(() => new Set([createShapeId('box1')]))
|