tldraw 3.16.0-canary.614a556981b7 → 3.16.0-canary.654b4007a087
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 +74 -1
- package/dist-cjs/index.js +5 -1
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/shapes/frame/FrameShapeUtil.js +4 -4
- package/dist-cjs/lib/shapes/frame/FrameShapeUtil.js.map +2 -2
- package/dist-cjs/lib/shapes/shared/ShapeFill.js +1 -1
- package/dist-cjs/lib/shapes/shared/ShapeFill.js.map +2 -2
- package/dist-cjs/lib/shapes/shared/freehand/svg.js.map +2 -2
- package/dist-cjs/lib/tools/EraserTool/childStates/Erasing.js +25 -1
- package/dist-cjs/lib/tools/EraserTool/childStates/Erasing.js.map +2 -2
- package/dist-cjs/lib/tools/EraserTool/childStates/Pointing.js +12 -0
- package/dist-cjs/lib/tools/EraserTool/childStates/Pointing.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js +68 -91
- package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuContext.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuGroup.js +0 -10
- package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuGroup.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js +3 -19
- package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js.map +2 -2
- package/dist-cjs/lib/ui/hooks/useTools.js +21 -3
- package/dist-cjs/lib/ui/hooks/useTools.js.map +2 -2
- package/dist-cjs/lib/ui/version.js +3 -3
- package/dist-cjs/lib/ui/version.js.map +1 -1
- package/dist-esm/index.d.mts +74 -1
- package/dist-esm/index.mjs +5 -1
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/shapes/frame/FrameShapeUtil.mjs +4 -4
- package/dist-esm/lib/shapes/frame/FrameShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/shapes/shared/ShapeFill.mjs +1 -1
- package/dist-esm/lib/shapes/shared/ShapeFill.mjs.map +2 -2
- package/dist-esm/lib/shapes/shared/freehand/svg.mjs.map +2 -2
- package/dist-esm/lib/tools/EraserTool/childStates/Erasing.mjs +26 -1
- package/dist-esm/lib/tools/EraserTool/childStates/Erasing.mjs.map +2 -2
- package/dist-esm/lib/tools/EraserTool/childStates/Pointing.mjs +13 -0
- package/dist-esm/lib/tools/EraserTool/childStates/Pointing.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs +77 -93
- package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuContext.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuGroup.mjs +0 -10
- package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuGroup.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs +3 -19
- package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs.map +2 -2
- package/dist-esm/lib/ui/hooks/useTools.mjs +22 -3
- package/dist-esm/lib/ui/hooks/useTools.mjs.map +2 -2
- package/dist-esm/lib/ui/version.mjs +3 -3
- package/dist-esm/lib/ui/version.mjs.map +1 -1
- package/package.json +9 -33
- package/src/index.ts +3 -0
- package/src/lib/shapes/arrow/ArrowShapeOptions.test.ts +2 -1
- package/src/lib/shapes/arrow/ArrowShapeTool.test.ts +4 -3
- package/src/lib/shapes/arrow/ArrowShapeUtil.test.ts +7 -6
- package/src/lib/shapes/draw/DrawShapeTool.test.ts +0 -5
- package/src/lib/shapes/frame/FrameShapeUtil.tsx +12 -4
- package/src/lib/shapes/line/LineShapeUtil.test.tsx +4 -3
- package/src/lib/shapes/line/__snapshots__/LineShapeUtil.test.tsx.snap +2 -2
- package/src/lib/shapes/shared/ShapeFill.tsx +1 -1
- package/src/lib/shapes/shared/freehand/svg.ts +2 -0
- package/src/lib/shapes/text/TextShapeTool.test.ts +6 -5
- package/src/lib/tools/EraserTool/childStates/Erasing.ts +34 -1
- package/src/lib/tools/EraserTool/childStates/Pointing.ts +20 -0
- package/src/lib/ui/components/primitives/TldrawUiTooltip.tsx +98 -114
- package/src/lib/ui/components/primitives/menus/TldrawUiMenuContext.tsx +0 -1
- package/src/lib/ui/components/primitives/menus/TldrawUiMenuGroup.tsx +0 -10
- package/src/lib/ui/components/primitives/menus/TldrawUiMenuItem.tsx +5 -18
- package/src/lib/ui/hooks/useTools.tsx +25 -3
- package/src/lib/ui/version.ts +3 -3
- package/src/lib/ui.css +5 -6
- package/src/lib/utils/excalidraw/__snapshots__/putExcalidrawContent.test.tsx.snap +5 -5
- package/src/lib/utils/tldr/__snapshots__/buildFromV1Document.test.ts.snap +4 -4
- package/src/test/A11y.test.tsx +3 -2
- package/src/test/ClickManager.test.ts +7 -6
- package/src/test/Editor.test.tsx +20 -19
- package/src/test/EraserTool.test.ts +184 -13
- package/src/test/HandTool.test.ts +10 -9
- package/src/test/HighlightShape.test.ts +2 -1
- package/src/test/SelectTool.test.ts +3 -2
- package/src/test/TLUserPreferences.test.ts +4 -3
- package/src/test/TestEditor.ts +13 -15
- package/src/test/TldrawEditor.test.tsx +11 -10
- package/src/test/ZoomTool.test.ts +7 -6
- package/src/test/__snapshots__/drawing.test.ts.snap +2 -2
- package/src/test/__snapshots__/groups.test.tsx.snap +6 -6
- package/src/test/__snapshots__/resizing.test.ts.snap +2 -2
- package/src/test/arrows-megabus.test.tsx +5 -4
- package/src/test/bindings.test.tsx +24 -37
- package/src/test/bookmark-shapes.test.ts +1 -8
- package/src/test/commands/__snapshots__/getSvgString.test.ts.snap +23 -7
- package/src/test/commands/__snapshots__/packShapes.test.ts.snap +8 -8
- package/src/test/commands/__snapshots__/zoomToFit.test.ts.snap +2 -2
- package/src/test/commands/alignShapes.test.tsx +25 -24
- package/src/test/commands/animationSpeed.test.ts +2 -1
- package/src/test/commands/centerOnPoint.test.ts +3 -2
- package/src/test/commands/clipboard.test.ts +3 -2
- package/src/test/commands/createShapes.test.ts +2 -1
- package/src/test/commands/deleteShapes.test.ts +2 -1
- package/src/test/commands/distributeShapes.test.tsx +11 -10
- package/src/test/commands/getSvgString.test.ts +2 -1
- package/src/test/commands/packShapes.test.ts +5 -4
- package/src/test/commands/resizeShape.test.ts +2 -1
- package/src/test/commands/rotateShapes.test.ts +7 -6
- package/src/test/commands/setCamera.test.ts +4 -3
- package/src/test/commands/setCurrentPage.test.ts +3 -2
- package/src/test/commands/stackShapes.test.ts +11 -10
- package/src/test/commands/stretch.test.tsx +13 -12
- package/src/test/createDeepLink.test.tsx +2 -1
- package/src/test/cropping.test.ts +3 -2
- package/src/test/drawing.test.ts +2 -1
- package/src/test/flipShapes.test.ts +4 -3
- package/src/test/frames.test.ts +25 -24
- package/src/test/getCulledShapes.test.tsx +3 -2
- package/src/test/groups.test.tsx +1 -1
- package/src/test/handleDeepLink.test.tsx +2 -1
- package/src/test/maxShapes.test.ts +3 -2
- package/src/test/modifiers.test.ts +5 -4
- package/src/test/navigation.test.ts +12 -11
- package/src/test/panning.test.ts +2 -1
- package/src/test/perf/perf.test.ts +2 -1
- package/src/test/registerDeepLinkListener.test.tsx +10 -9
- package/src/test/resizing.test.ts +39 -38
- package/src/test/select.test.tsx +4 -3
- package/src/test/selection-omnibus.test.ts +11 -10
- package/src/test/shapeutils.test.ts +4 -3
- package/src/test/translating.test.ts +9 -8
- package/tldraw.css +5 -6
|
@@ -24,7 +24,9 @@ module.exports = __toCommonJS(Pointing_exports);
|
|
|
24
24
|
var import_editor = require("@tldraw/editor");
|
|
25
25
|
class Pointing extends import_editor.StateNode {
|
|
26
26
|
static id = "pointing";
|
|
27
|
+
_isHoldingAccelKey = false;
|
|
27
28
|
onEnter() {
|
|
29
|
+
this._isHoldingAccelKey = (0, import_editor.isAccelKey)(this.editor.inputs);
|
|
28
30
|
const zoomLevel = this.editor.getZoomLevel();
|
|
29
31
|
const currentPageShapesSorted = this.editor.getCurrentPageRenderingShapesSorted();
|
|
30
32
|
const {
|
|
@@ -46,10 +48,19 @@ class Pointing extends import_editor.StateNode {
|
|
|
46
48
|
break;
|
|
47
49
|
}
|
|
48
50
|
erasing.add(hitShape.id);
|
|
51
|
+
if (this._isHoldingAccelKey) {
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
49
54
|
}
|
|
50
55
|
}
|
|
51
56
|
this.editor.setErasingShapes([...erasing]);
|
|
52
57
|
}
|
|
58
|
+
onKeyUp() {
|
|
59
|
+
this._isHoldingAccelKey = (0, import_editor.isAccelKey)(this.editor.inputs);
|
|
60
|
+
}
|
|
61
|
+
onKeyDown() {
|
|
62
|
+
this._isHoldingAccelKey = (0, import_editor.isAccelKey)(this.editor.inputs);
|
|
63
|
+
}
|
|
53
64
|
onLongPress(info) {
|
|
54
65
|
this.startErasing(info);
|
|
55
66
|
}
|
|
@@ -59,6 +70,7 @@ class Pointing extends import_editor.StateNode {
|
|
|
59
70
|
}
|
|
60
71
|
}
|
|
61
72
|
onPointerMove(info) {
|
|
73
|
+
if (this._isHoldingAccelKey) return;
|
|
62
74
|
if (this.editor.inputs.isDragging) {
|
|
63
75
|
this.startErasing(info);
|
|
64
76
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/lib/tools/EraserTool/childStates/Pointing.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n\tStateNode,\n\tTLFrameShape,\n\tTLGroupShape,\n\tTLPointerEventInfo,\n\tTLShapeId,\n} from '@tldraw/editor'\n\nexport class Pointing extends StateNode {\n\tstatic override id = 'pointing'\n\n\toverride onEnter() {\n\t\tconst zoomLevel = this.editor.getZoomLevel()\n\t\tconst currentPageShapesSorted = this.editor.getCurrentPageRenderingShapesSorted()\n\t\tconst {\n\t\t\tinputs: { currentPagePoint },\n\t\t} = this.editor\n\n\t\tconst erasing = new Set<TLShapeId>()\n\n\t\tconst initialSize = erasing.size\n\n\t\tfor (let n = currentPageShapesSorted.length, i = n - 1; i >= 0; i--) {\n\t\t\tconst shape = currentPageShapesSorted[i]\n\t\t\tif (\n\t\t\t\tthis.editor.isShapeOrAncestorLocked(shape) ||\n\t\t\t\tthis.editor.isShapeOfType<TLGroupShape>(shape, 'group')\n\t\t\t) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\tthis.editor.isPointInShape(shape, currentPagePoint, {\n\t\t\t\t\thitInside: false,\n\t\t\t\t\tmargin: this.editor.options.hitTestMargin / zoomLevel,\n\t\t\t\t})\n\t\t\t) {\n\t\t\t\tconst hitShape = this.editor.getOutermostSelectableShape(shape)\n\t\t\t\t// If we've hit a frame after hitting any other shape, stop here\n\t\t\t\tif (\n\t\t\t\t\tthis.editor.isShapeOfType<TLFrameShape>(hitShape, 'frame') &&\n\t\t\t\t\terasing.size > initialSize\n\t\t\t\t) {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\terasing.add(hitShape.id)\n\t\t\t}\n\t\t}\n\n\t\tthis.editor.setErasingShapes([...erasing])\n\t}\n\n\toverride onLongPress(info: TLPointerEventInfo) {\n\t\tthis.startErasing(info)\n\t}\n\n\toverride onExit(_info: any, to: string) {\n\t\tif (to !== 'erasing') {\n\t\t\tthis.editor.setErasingShapes([])\n\t\t}\n\t}\n\n\toverride onPointerMove(info: TLPointerEventInfo) {\n\t\tif (this.editor.inputs.isDragging) {\n\t\t\tthis.startErasing(info)\n\t\t}\n\t}\n\n\toverride onPointerUp() {\n\t\tthis.complete()\n\t}\n\n\toverride onCancel() {\n\t\tthis.cancel()\n\t}\n\n\toverride onComplete() {\n\t\tthis.complete()\n\t}\n\n\toverride onInterrupt() {\n\t\tthis.cancel()\n\t}\n\n\tprivate startErasing(info: TLPointerEventInfo) {\n\t\tthis.parent.transition('erasing', info)\n\t}\n\n\tcomplete() {\n\t\tconst erasingShapeIds = this.editor.getErasingShapeIds()\n\n\t\tif (erasingShapeIds.length) {\n\t\t\tthis.editor.markHistoryStoppingPoint('erase end')\n\t\t\tthis.editor.deleteShapes(erasingShapeIds)\n\t\t}\n\n\t\tthis.parent.transition('idle')\n\t}\n\n\tcancel() {\n\t\tthis.parent.transition('idle')\n\t}\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,
|
|
4
|
+
"sourcesContent": ["import {\n\tisAccelKey,\n\tStateNode,\n\tTLFrameShape,\n\tTLGroupShape,\n\tTLPointerEventInfo,\n\tTLShapeId,\n} from '@tldraw/editor'\n\nexport class Pointing extends StateNode {\n\tstatic override id = 'pointing'\n\n\t_isHoldingAccelKey = false\n\n\toverride onEnter() {\n\t\tthis._isHoldingAccelKey = isAccelKey(this.editor.inputs)\n\n\t\tconst zoomLevel = this.editor.getZoomLevel()\n\t\tconst currentPageShapesSorted = this.editor.getCurrentPageRenderingShapesSorted()\n\t\tconst {\n\t\t\tinputs: { currentPagePoint },\n\t\t} = this.editor\n\n\t\tconst erasing = new Set<TLShapeId>()\n\n\t\tconst initialSize = erasing.size\n\n\t\tfor (let n = currentPageShapesSorted.length, i = n - 1; i >= 0; i--) {\n\t\t\tconst shape = currentPageShapesSorted[i]\n\t\t\tif (\n\t\t\t\tthis.editor.isShapeOrAncestorLocked(shape) ||\n\t\t\t\tthis.editor.isShapeOfType<TLGroupShape>(shape, 'group')\n\t\t\t) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\tthis.editor.isPointInShape(shape, currentPagePoint, {\n\t\t\t\t\thitInside: false,\n\t\t\t\t\tmargin: this.editor.options.hitTestMargin / zoomLevel,\n\t\t\t\t})\n\t\t\t) {\n\t\t\t\tconst hitShape = this.editor.getOutermostSelectableShape(shape)\n\t\t\t\t// If we've hit a frame after hitting any other shape, stop here\n\t\t\t\tif (\n\t\t\t\t\tthis.editor.isShapeOfType<TLFrameShape>(hitShape, 'frame') &&\n\t\t\t\t\terasing.size > initialSize\n\t\t\t\t) {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\terasing.add(hitShape.id)\n\n\t\t\t\t// If the user is holding the meta / ctrl key, stop after the first shape\n\t\t\t\tif (this._isHoldingAccelKey) {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthis.editor.setErasingShapes([...erasing])\n\t}\n\n\toverride onKeyUp() {\n\t\tthis._isHoldingAccelKey = isAccelKey(this.editor.inputs)\n\t}\n\n\toverride onKeyDown() {\n\t\tthis._isHoldingAccelKey = isAccelKey(this.editor.inputs)\n\t}\n\n\toverride onLongPress(info: TLPointerEventInfo) {\n\t\tthis.startErasing(info)\n\t}\n\n\toverride onExit(_info: any, to: string) {\n\t\tif (to !== 'erasing') {\n\t\t\tthis.editor.setErasingShapes([])\n\t\t}\n\t}\n\n\toverride onPointerMove(info: TLPointerEventInfo) {\n\t\tif (this._isHoldingAccelKey) return\n\n\t\tif (this.editor.inputs.isDragging) {\n\t\t\tthis.startErasing(info)\n\t\t}\n\t}\n\n\toverride onPointerUp() {\n\t\tthis.complete()\n\t}\n\n\toverride onCancel() {\n\t\tthis.cancel()\n\t}\n\n\toverride onComplete() {\n\t\tthis.complete()\n\t}\n\n\toverride onInterrupt() {\n\t\tthis.cancel()\n\t}\n\n\tprivate startErasing(info: TLPointerEventInfo) {\n\t\tthis.parent.transition('erasing', info)\n\t}\n\n\tcomplete() {\n\t\tconst erasingShapeIds = this.editor.getErasingShapeIds()\n\n\t\tif (erasingShapeIds.length) {\n\t\t\tthis.editor.markHistoryStoppingPoint('erase end')\n\t\t\tthis.editor.deleteShapes(erasingShapeIds)\n\t\t}\n\n\t\tthis.parent.transition('idle')\n\t}\n\n\tcancel() {\n\t\tthis.parent.transition('idle')\n\t}\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAOO;AAEA,MAAM,iBAAiB,wBAAU;AAAA,EACvC,OAAgB,KAAK;AAAA,EAErB,qBAAqB;AAAA,EAEZ,UAAU;AAClB,SAAK,yBAAqB,0BAAW,KAAK,OAAO,MAAM;AAEvD,UAAM,YAAY,KAAK,OAAO,aAAa;AAC3C,UAAM,0BAA0B,KAAK,OAAO,oCAAoC;AAChF,UAAM;AAAA,MACL,QAAQ,EAAE,iBAAiB;AAAA,IAC5B,IAAI,KAAK;AAET,UAAM,UAAU,oBAAI,IAAe;AAEnC,UAAM,cAAc,QAAQ;AAE5B,aAAS,IAAI,wBAAwB,QAAQ,IAAI,IAAI,GAAG,KAAK,GAAG,KAAK;AACpE,YAAM,QAAQ,wBAAwB,CAAC;AACvC,UACC,KAAK,OAAO,wBAAwB,KAAK,KACzC,KAAK,OAAO,cAA4B,OAAO,OAAO,GACrD;AACD;AAAA,MACD;AAEA,UACC,KAAK,OAAO,eAAe,OAAO,kBAAkB;AAAA,QACnD,WAAW;AAAA,QACX,QAAQ,KAAK,OAAO,QAAQ,gBAAgB;AAAA,MAC7C,CAAC,GACA;AACD,cAAM,WAAW,KAAK,OAAO,4BAA4B,KAAK;AAE9D,YACC,KAAK,OAAO,cAA4B,UAAU,OAAO,KACzD,QAAQ,OAAO,aACd;AACD;AAAA,QACD;AAEA,gBAAQ,IAAI,SAAS,EAAE;AAGvB,YAAI,KAAK,oBAAoB;AAC5B;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAEA,SAAK,OAAO,iBAAiB,CAAC,GAAG,OAAO,CAAC;AAAA,EAC1C;AAAA,EAES,UAAU;AAClB,SAAK,yBAAqB,0BAAW,KAAK,OAAO,MAAM;AAAA,EACxD;AAAA,EAES,YAAY;AACpB,SAAK,yBAAqB,0BAAW,KAAK,OAAO,MAAM;AAAA,EACxD;AAAA,EAES,YAAY,MAA0B;AAC9C,SAAK,aAAa,IAAI;AAAA,EACvB;AAAA,EAES,OAAO,OAAY,IAAY;AACvC,QAAI,OAAO,WAAW;AACrB,WAAK,OAAO,iBAAiB,CAAC,CAAC;AAAA,IAChC;AAAA,EACD;AAAA,EAES,cAAc,MAA0B;AAChD,QAAI,KAAK,mBAAoB;AAE7B,QAAI,KAAK,OAAO,OAAO,YAAY;AAClC,WAAK,aAAa,IAAI;AAAA,IACvB;AAAA,EACD;AAAA,EAES,cAAc;AACtB,SAAK,SAAS;AAAA,EACf;AAAA,EAES,WAAW;AACnB,SAAK,OAAO;AAAA,EACb;AAAA,EAES,aAAa;AACrB,SAAK,SAAS;AAAA,EACf;AAAA,EAES,cAAc;AACtB,SAAK,OAAO;AAAA,EACb;AAAA,EAEQ,aAAa,MAA0B;AAC9C,SAAK,OAAO,WAAW,WAAW,IAAI;AAAA,EACvC;AAAA,EAEA,WAAW;AACV,UAAM,kBAAkB,KAAK,OAAO,mBAAmB;AAEvD,QAAI,gBAAgB,QAAQ;AAC3B,WAAK,OAAO,yBAAyB,WAAW;AAChD,WAAK,OAAO,aAAa,eAAe;AAAA,IACzC;AAEA,SAAK,OAAO,WAAW,MAAM;AAAA,EAC9B;AAAA,EAEA,SAAS;AACR,SAAK,OAAO,WAAW,MAAM;AAAA,EAC9B;AACD;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -37,78 +37,67 @@ var import_jsx_runtime = require("react/jsx-runtime");
|
|
|
37
37
|
var import_editor = require("@tldraw/editor");
|
|
38
38
|
var import_radix_ui = require("radix-ui");
|
|
39
39
|
var import_react = __toESM(require("react"));
|
|
40
|
-
var import_usePrefersReducedMotion = require("../../../shapes/shared/usePrefersReducedMotion");
|
|
41
40
|
var import_layout = require("./layout");
|
|
42
41
|
const DEFAULT_TOOLTIP_DELAY_MS = 700;
|
|
43
42
|
class TooltipManager {
|
|
44
43
|
static instance = null;
|
|
45
|
-
|
|
46
|
-
currentContent = "";
|
|
47
|
-
currentSide = "bottom";
|
|
48
|
-
currentSideOffset = 5;
|
|
44
|
+
currentTooltip = (0, import_editor.atom)("current tooltip", null);
|
|
49
45
|
destroyTimeoutId = null;
|
|
50
|
-
subscribers = /* @__PURE__ */ new Set();
|
|
51
|
-
activeElement = null;
|
|
52
|
-
editor = null;
|
|
53
46
|
static getInstance() {
|
|
54
47
|
if (!TooltipManager.instance) {
|
|
55
48
|
TooltipManager.instance = new TooltipManager();
|
|
56
49
|
}
|
|
57
50
|
return TooltipManager.instance;
|
|
58
51
|
}
|
|
59
|
-
|
|
60
|
-
this.editor = editor;
|
|
61
|
-
}
|
|
62
|
-
subscribe(callback) {
|
|
63
|
-
this.subscribers.add(callback);
|
|
64
|
-
return () => this.subscribers.delete(callback);
|
|
65
|
-
}
|
|
66
|
-
notify() {
|
|
67
|
-
this.subscribers.forEach((callback) => callback());
|
|
68
|
-
}
|
|
69
|
-
showTooltip(tooltipId, content, element, side = "bottom", sideOffset = 5) {
|
|
52
|
+
showTooltip(tooltipId, content, targetElement, side, sideOffset, showOnMobile, delayDuration) {
|
|
70
53
|
if (this.destroyTimeoutId) {
|
|
71
54
|
clearTimeout(this.destroyTimeoutId);
|
|
72
55
|
this.destroyTimeoutId = null;
|
|
73
56
|
}
|
|
74
|
-
this.
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
57
|
+
this.currentTooltip.set({
|
|
58
|
+
id: tooltipId,
|
|
59
|
+
content,
|
|
60
|
+
side,
|
|
61
|
+
sideOffset,
|
|
62
|
+
showOnMobile,
|
|
63
|
+
targetElement,
|
|
64
|
+
delayDuration
|
|
65
|
+
});
|
|
80
66
|
}
|
|
81
|
-
hideTooltip(tooltipId, instant = false) {
|
|
67
|
+
hideTooltip(editor, tooltipId, instant = false) {
|
|
82
68
|
const hide = () => {
|
|
83
|
-
if (this.
|
|
84
|
-
this.
|
|
85
|
-
this.currentContent = "";
|
|
86
|
-
this.activeElement = null;
|
|
69
|
+
if (this.currentTooltip.get()?.id === tooltipId) {
|
|
70
|
+
this.currentTooltip.set(null);
|
|
87
71
|
this.destroyTimeoutId = null;
|
|
88
|
-
this.notify();
|
|
89
72
|
}
|
|
90
73
|
};
|
|
91
|
-
if (instant) {
|
|
74
|
+
if (editor && !instant) {
|
|
75
|
+
this.destroyTimeoutId = editor.timers.setTimeout(hide, 300);
|
|
76
|
+
} else {
|
|
92
77
|
hide();
|
|
93
|
-
} else if (this.editor) {
|
|
94
|
-
this.destroyTimeoutId = this.editor.timers.setTimeout(hide, 300);
|
|
95
78
|
}
|
|
96
79
|
}
|
|
97
80
|
hideAllTooltips() {
|
|
98
|
-
this.
|
|
99
|
-
this.currentContent = "";
|
|
100
|
-
this.activeElement = null;
|
|
81
|
+
this.currentTooltip.set(null);
|
|
101
82
|
this.destroyTimeoutId = null;
|
|
102
|
-
this.notify();
|
|
103
83
|
}
|
|
104
84
|
getCurrentTooltipData() {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
85
|
+
const currentTooltip = this.currentTooltip.get();
|
|
86
|
+
if (!currentTooltip) return null;
|
|
87
|
+
if (!this.supportsHover() && !currentTooltip.showOnMobile) return null;
|
|
88
|
+
return currentTooltip;
|
|
89
|
+
}
|
|
90
|
+
supportsHoverAtom = null;
|
|
91
|
+
supportsHover() {
|
|
92
|
+
if (!this.supportsHoverAtom) {
|
|
93
|
+
const mediaQuery = window.matchMedia("(hover: hover)");
|
|
94
|
+
const supportsHover = (0, import_editor.atom)("has hover", mediaQuery.matches);
|
|
95
|
+
this.supportsHoverAtom = supportsHover;
|
|
96
|
+
mediaQuery.addEventListener("change", (e) => {
|
|
97
|
+
supportsHover.set(e.matches);
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
return this.supportsHoverAtom.get();
|
|
112
101
|
}
|
|
113
102
|
}
|
|
114
103
|
const tooltipManager = TooltipManager.getInstance();
|
|
@@ -121,44 +110,23 @@ function TldrawUiTooltipProvider({ children }) {
|
|
|
121
110
|
}
|
|
122
111
|
function TooltipSingleton() {
|
|
123
112
|
const editor = (0, import_editor.useMaybeEditor)();
|
|
124
|
-
const [, forceUpdate] = (0, import_react.useState)({});
|
|
125
113
|
const [isOpen, setIsOpen] = (0, import_react.useState)(false);
|
|
126
114
|
const triggerRef = (0, import_react.useRef)(null);
|
|
127
|
-
const previousPositionRef = (0, import_react.useRef)(null);
|
|
128
|
-
const prefersReducedMotion = (0, import_usePrefersReducedMotion.usePrefersReducedMotion)();
|
|
129
|
-
const [shouldAnimate, setShouldAnimate] = (0, import_react.useState)(false);
|
|
130
115
|
const isFirstShowRef = (0, import_react.useRef)(true);
|
|
131
116
|
const showTimeoutRef = (0, import_react.useRef)(null);
|
|
117
|
+
const currentTooltip = (0, import_editor.useValue)(
|
|
118
|
+
"current tooltip",
|
|
119
|
+
() => tooltipManager.getCurrentTooltipData(),
|
|
120
|
+
[]
|
|
121
|
+
);
|
|
132
122
|
(0, import_react.useEffect)(() => {
|
|
133
|
-
tooltipManager.setEditor(editor);
|
|
134
|
-
}, [editor]);
|
|
135
|
-
(0, import_react.useEffect)(() => {
|
|
136
|
-
const unsubscribe = tooltipManager.subscribe(() => {
|
|
137
|
-
forceUpdate({});
|
|
138
|
-
});
|
|
139
|
-
return unsubscribe;
|
|
140
|
-
}, []);
|
|
141
|
-
const tooltipData = tooltipManager.getCurrentTooltipData();
|
|
142
|
-
(0, import_react.useEffect)(() => {
|
|
143
|
-
const shouldBeOpen = Boolean(tooltipData.id && tooltipData.element);
|
|
144
123
|
if (showTimeoutRef.current) {
|
|
145
124
|
clearTimeout(showTimeoutRef.current);
|
|
146
125
|
showTimeoutRef.current = null;
|
|
147
126
|
}
|
|
148
|
-
if (
|
|
149
|
-
const activeRect =
|
|
127
|
+
if (currentTooltip && triggerRef.current) {
|
|
128
|
+
const activeRect = currentTooltip.targetElement.getBoundingClientRect();
|
|
150
129
|
const trigger = triggerRef.current;
|
|
151
|
-
const newPosition = {
|
|
152
|
-
x: activeRect.left + activeRect.width / 2,
|
|
153
|
-
y: activeRect.top + activeRect.height / 2
|
|
154
|
-
};
|
|
155
|
-
let shouldAnimateCheck = false;
|
|
156
|
-
if (previousPositionRef.current) {
|
|
157
|
-
const isNearPrevious = import_editor.Vec.DistMin(previousPositionRef.current, newPosition, 200);
|
|
158
|
-
shouldAnimateCheck = !prefersReducedMotion && isNearPrevious && Math.abs(newPosition.y - previousPositionRef.current.y) < 50;
|
|
159
|
-
}
|
|
160
|
-
setShouldAnimate(isFirstShowRef.current ? false : shouldAnimateCheck);
|
|
161
|
-
previousPositionRef.current = newPosition;
|
|
162
130
|
trigger.style.position = "fixed";
|
|
163
131
|
trigger.style.left = `${activeRect.left}px`;
|
|
164
132
|
trigger.style.top = `${activeRect.top}px`;
|
|
@@ -170,18 +138,16 @@ function TooltipSingleton() {
|
|
|
170
138
|
showTimeoutRef.current = editor.timers.setTimeout(() => {
|
|
171
139
|
setIsOpen(true);
|
|
172
140
|
isFirstShowRef.current = false;
|
|
173
|
-
}, editor.options.tooltipDelayMs);
|
|
141
|
+
}, currentTooltip.delayDuration ?? editor.options.tooltipDelayMs);
|
|
174
142
|
} else {
|
|
175
143
|
setIsOpen(true);
|
|
176
144
|
}
|
|
177
|
-
} else
|
|
145
|
+
} else {
|
|
178
146
|
setIsOpen(false);
|
|
179
|
-
previousPositionRef.current = null;
|
|
180
|
-
setShouldAnimate(false);
|
|
181
147
|
isFirstShowRef.current = true;
|
|
182
148
|
}
|
|
183
|
-
}, [
|
|
184
|
-
if (!
|
|
149
|
+
}, [editor, currentTooltip]);
|
|
150
|
+
if (!currentTooltip) {
|
|
185
151
|
return null;
|
|
186
152
|
}
|
|
187
153
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_radix_ui.Tooltip.Root, { open: isOpen, delayDuration: 0, children: [
|
|
@@ -190,14 +156,13 @@ function TooltipSingleton() {
|
|
|
190
156
|
import_radix_ui.Tooltip.Content,
|
|
191
157
|
{
|
|
192
158
|
className: "tlui-tooltip",
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
sideOffset: tooltipData.sideOffset,
|
|
159
|
+
side: currentTooltip.side,
|
|
160
|
+
sideOffset: currentTooltip.sideOffset,
|
|
196
161
|
avoidCollisions: true,
|
|
197
162
|
collisionPadding: 8,
|
|
198
163
|
dir: "ltr",
|
|
199
164
|
children: [
|
|
200
|
-
|
|
165
|
+
currentTooltip.content,
|
|
201
166
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_radix_ui.Tooltip.Arrow, { className: "tlui-tooltip__arrow" })
|
|
202
167
|
]
|
|
203
168
|
}
|
|
@@ -205,7 +170,15 @@ function TooltipSingleton() {
|
|
|
205
170
|
] });
|
|
206
171
|
}
|
|
207
172
|
const TldrawUiTooltip = (0, import_react.forwardRef)(
|
|
208
|
-
({
|
|
173
|
+
({
|
|
174
|
+
children,
|
|
175
|
+
content,
|
|
176
|
+
side,
|
|
177
|
+
sideOffset = 5,
|
|
178
|
+
disabled = false,
|
|
179
|
+
showOnMobile = false,
|
|
180
|
+
delayDuration
|
|
181
|
+
}, ref) => {
|
|
209
182
|
const editor = (0, import_editor.useMaybeEditor)();
|
|
210
183
|
const tooltipId = (0, import_react.useRef)((0, import_editor.uniqueId)());
|
|
211
184
|
const hasProvider = (0, import_react.useContext)(TooltipSingletonContext);
|
|
@@ -215,10 +188,10 @@ const TldrawUiTooltip = (0, import_react.forwardRef)(
|
|
|
215
188
|
const currentTooltipId = tooltipId.current;
|
|
216
189
|
return () => {
|
|
217
190
|
if (hasProvider) {
|
|
218
|
-
tooltipManager.hideTooltip(currentTooltipId, true);
|
|
191
|
+
tooltipManager.hideTooltip(editor, currentTooltipId, true);
|
|
219
192
|
}
|
|
220
193
|
};
|
|
221
|
-
}, [hasProvider]);
|
|
194
|
+
}, [editor, hasProvider]);
|
|
222
195
|
if (disabled || !content) {
|
|
223
196
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children });
|
|
224
197
|
}
|
|
@@ -226,7 +199,7 @@ const TldrawUiTooltip = (0, import_react.forwardRef)(
|
|
|
226
199
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
227
200
|
import_radix_ui.Tooltip.Root,
|
|
228
201
|
{
|
|
229
|
-
delayDuration: editor?.options.tooltipDelayMs || DEFAULT_TOOLTIP_DELAY_MS,
|
|
202
|
+
delayDuration: delayDuration ?? (editor?.options.tooltipDelayMs || DEFAULT_TOOLTIP_DELAY_MS),
|
|
230
203
|
disableHoverableContent: true,
|
|
231
204
|
children: [
|
|
232
205
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_radix_ui.Tooltip.Trigger, { asChild: true, ref, children }),
|
|
@@ -258,12 +231,14 @@ const TldrawUiTooltip = (0, import_react.forwardRef)(
|
|
|
258
231
|
content,
|
|
259
232
|
event.currentTarget,
|
|
260
233
|
sideToUse,
|
|
261
|
-
sideOffset
|
|
234
|
+
sideOffset,
|
|
235
|
+
showOnMobile,
|
|
236
|
+
delayDuration
|
|
262
237
|
);
|
|
263
238
|
};
|
|
264
239
|
const handleMouseLeave = (event) => {
|
|
265
240
|
child.props.onMouseLeave?.(event);
|
|
266
|
-
tooltipManager.hideTooltip(tooltipId.current);
|
|
241
|
+
tooltipManager.hideTooltip(editor, tooltipId.current);
|
|
267
242
|
};
|
|
268
243
|
const handleFocus = (event) => {
|
|
269
244
|
child.props.onFocus?.(event);
|
|
@@ -272,12 +247,14 @@ const TldrawUiTooltip = (0, import_react.forwardRef)(
|
|
|
272
247
|
content,
|
|
273
248
|
event.currentTarget,
|
|
274
249
|
sideToUse,
|
|
275
|
-
sideOffset
|
|
250
|
+
sideOffset,
|
|
251
|
+
showOnMobile,
|
|
252
|
+
delayDuration
|
|
276
253
|
);
|
|
277
254
|
};
|
|
278
255
|
const handleBlur = (event) => {
|
|
279
256
|
child.props.onBlur?.(event);
|
|
280
|
-
tooltipManager.hideTooltip(tooltipId.current);
|
|
257
|
+
tooltipManager.hideTooltip(editor, tooltipId.current);
|
|
281
258
|
};
|
|
282
259
|
const childrenWithHandlers = import_react.default.cloneElement(children, {
|
|
283
260
|
onMouseEnter: handleMouseEnter,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/lib/ui/components/primitives/TldrawUiTooltip.tsx"],
|
|
4
|
-
"sourcesContent": ["import { assert, Editor, uniqueId, useMaybeEditor, Vec } from '@tldraw/editor'\nimport { Tooltip as _Tooltip } from 'radix-ui'\nimport React, { createContext, forwardRef, useContext, useEffect, useRef, useState } from 'react'\nimport { usePrefersReducedMotion } from '../../../shapes/shared/usePrefersReducedMotion'\nimport { useTldrawUiOrientation } from './layout'\n\nconst DEFAULT_TOOLTIP_DELAY_MS = 700\n\n/** @public */\nexport interface TldrawUiTooltipProps {\n\tchildren: React.ReactNode\n\tcontent?: string | React.ReactNode\n\tside?: 'top' | 'right' | 'bottom' | 'left'\n\tsideOffset?: number\n\tdisabled?: boolean\n}\n\n// Singleton tooltip manager\nclass TooltipManager {\n\tprivate static instance: TooltipManager | null = null\n\tprivate currentTooltipId: string | null = null\n\tprivate currentContent: string | React.ReactNode = ''\n\tprivate currentSide: 'top' | 'right' | 'bottom' | 'left' = 'bottom'\n\tprivate currentSideOffset: number = 5\n\tprivate destroyTimeoutId: number | null = null\n\tprivate subscribers: Set<() => void> = new Set()\n\tprivate activeElement: HTMLElement | null = null\n\tprivate editor: Editor | null = null\n\n\tstatic getInstance(): TooltipManager {\n\t\tif (!TooltipManager.instance) {\n\t\t\tTooltipManager.instance = new TooltipManager()\n\t\t}\n\t\treturn TooltipManager.instance\n\t}\n\n\tsetEditor(editor: Editor | null) {\n\t\tthis.editor = editor\n\t}\n\n\tsubscribe(callback: () => void): () => void {\n\t\tthis.subscribers.add(callback)\n\t\treturn () => this.subscribers.delete(callback)\n\t}\n\n\tprivate notify() {\n\t\tthis.subscribers.forEach((callback) => callback())\n\t}\n\n\tshowTooltip(\n\t\ttooltipId: string,\n\t\tcontent: string | React.ReactNode,\n\t\telement: HTMLElement,\n\t\tside: 'top' | 'right' | 'bottom' | 'left' = 'bottom',\n\t\tsideOffset: number = 5\n\t) {\n\t\t// Clear any existing destroy timeout\n\t\tif (this.destroyTimeoutId) {\n\t\t\tclearTimeout(this.destroyTimeoutId)\n\t\t\tthis.destroyTimeoutId = null\n\t\t}\n\n\t\t// Update current tooltip\n\t\tthis.currentTooltipId = tooltipId\n\t\tthis.currentContent = content\n\t\tthis.currentSide = side\n\t\tthis.currentSideOffset = sideOffset\n\t\tthis.activeElement = element\n\n\t\tthis.notify()\n\t}\n\n\thideTooltip(tooltipId: string, instant: boolean = false) {\n\t\tconst hide = () => {\n\t\t\t// Only hide if this is the current tooltip\n\t\t\tif (this.currentTooltipId === tooltipId) {\n\t\t\t\tthis.currentTooltipId = null\n\t\t\t\tthis.currentContent = ''\n\t\t\t\tthis.activeElement = null\n\t\t\t\tthis.destroyTimeoutId = null\n\t\t\t\tthis.notify()\n\t\t\t}\n\t\t}\n\n\t\tif (instant) {\n\t\t\thide()\n\t\t} else if (this.editor) {\n\t\t\t// Start destroy timeout (1 second)\n\t\t\tthis.destroyTimeoutId = this.editor.timers.setTimeout(hide, 300)\n\t\t}\n\t}\n\n\thideAllTooltips() {\n\t\tthis.currentTooltipId = null\n\t\tthis.currentContent = ''\n\t\tthis.activeElement = null\n\t\tthis.destroyTimeoutId = null\n\t\tthis.notify()\n\t}\n\n\tgetCurrentTooltipData() {\n\t\treturn {\n\t\t\tid: this.currentTooltipId,\n\t\t\tcontent: this.currentContent,\n\t\t\tside: this.currentSide,\n\t\t\tsideOffset: this.currentSideOffset,\n\t\t\telement: this.activeElement,\n\t\t}\n\t}\n}\n\nexport const tooltipManager = TooltipManager.getInstance()\n\n// Context for the tooltip singleton\nconst TooltipSingletonContext = createContext<boolean>(false)\n\n/** @public */\nexport interface TldrawUiTooltipProviderProps {\n\tchildren: React.ReactNode\n}\n\n/** @public @react */\nexport function TldrawUiTooltipProvider({ children }: TldrawUiTooltipProviderProps) {\n\treturn (\n\t\t<_Tooltip.Provider skipDelayDuration={700}>\n\t\t\t<TooltipSingletonContext.Provider value={true}>\n\t\t\t\t{children}\n\t\t\t\t<TooltipSingleton />\n\t\t\t</TooltipSingletonContext.Provider>\n\t\t</_Tooltip.Provider>\n\t)\n}\n\n// The singleton tooltip component that renders once\nfunction TooltipSingleton() {\n\tconst editor = useMaybeEditor()\n\tconst [, forceUpdate] = useState({})\n\tconst [isOpen, setIsOpen] = useState(false)\n\tconst triggerRef = useRef<HTMLDivElement>(null)\n\tconst previousPositionRef = useRef<{ x: number; y: number } | null>(null)\n\tconst prefersReducedMotion = usePrefersReducedMotion()\n\tconst [shouldAnimate, setShouldAnimate] = useState(false)\n\tconst isFirstShowRef = useRef(true)\n\tconst showTimeoutRef = useRef<number | null>(null)\n\n\t// Set editor in tooltip manager\n\tuseEffect(() => {\n\t\ttooltipManager.setEditor(editor)\n\t}, [editor])\n\n\t// Subscribe to tooltip manager updates\n\tuseEffect(() => {\n\t\tconst unsubscribe = tooltipManager.subscribe(() => {\n\t\t\tforceUpdate({})\n\t\t})\n\t\treturn unsubscribe\n\t}, [])\n\n\tconst tooltipData = tooltipManager.getCurrentTooltipData()\n\n\t// Update open state and trigger position\n\tuseEffect(() => {\n\t\tconst shouldBeOpen = Boolean(tooltipData.id && tooltipData.element)\n\n\t\t// Clear any existing show timeout\n\t\tif (showTimeoutRef.current) {\n\t\t\tclearTimeout(showTimeoutRef.current)\n\t\t\tshowTimeoutRef.current = null\n\t\t}\n\n\t\tif (shouldBeOpen && tooltipData.element && triggerRef.current) {\n\t\t\t// Position the invisible trigger element over the active element\n\t\t\tconst activeRect = tooltipData.element.getBoundingClientRect()\n\t\t\tconst trigger = triggerRef.current\n\n\t\t\tconst newPosition = {\n\t\t\t\tx: activeRect.left + activeRect.width / 2,\n\t\t\t\ty: activeRect.top + activeRect.height / 2,\n\t\t\t}\n\n\t\t\t// Determine if we should animate\n\t\t\tlet shouldAnimateCheck = false\n\t\t\tif (previousPositionRef.current) {\n\t\t\t\tconst isNearPrevious = Vec.DistMin(previousPositionRef.current, newPosition, 200)\n\t\t\t\t// Only animate if the distance is less than 200px (nearby tooltips)\n\t\t\t\tshouldAnimateCheck =\n\t\t\t\t\t!prefersReducedMotion &&\n\t\t\t\t\tisNearPrevious &&\n\t\t\t\t\tMath.abs(newPosition.y - previousPositionRef.current.y) < 50\n\t\t\t}\n\t\t\t// Don't animate on initial show (previousPositionRef.current is null)\n\n\t\t\tsetShouldAnimate(isFirstShowRef.current ? false : shouldAnimateCheck)\n\t\t\tpreviousPositionRef.current = newPosition\n\n\t\t\ttrigger.style.position = 'fixed'\n\t\t\ttrigger.style.left = `${activeRect.left}px`\n\t\t\ttrigger.style.top = `${activeRect.top}px`\n\t\t\ttrigger.style.width = `${activeRect.width}px`\n\t\t\ttrigger.style.height = `${activeRect.height}px`\n\t\t\ttrigger.style.pointerEvents = 'none'\n\t\t\ttrigger.style.zIndex = '9999'\n\n\t\t\t// Handle delay for first show\n\t\t\tif (isFirstShowRef.current && editor) {\n\t\t\t\tshowTimeoutRef.current = editor.timers.setTimeout(() => {\n\t\t\t\t\tsetIsOpen(true)\n\t\t\t\t\tisFirstShowRef.current = false\n\t\t\t\t}, editor.options.tooltipDelayMs)\n\t\t\t} else {\n\t\t\t\t// Subsequent tooltips show immediately\n\t\t\t\tsetIsOpen(true)\n\t\t\t}\n\t\t} else if (!shouldBeOpen) {\n\t\t\t// Hide tooltip immediately\n\t\t\tsetIsOpen(false)\n\t\t\t// Reset position tracking when tooltip closes\n\t\t\tpreviousPositionRef.current = null\n\t\t\tsetShouldAnimate(false)\n\t\t\t// Reset first show state after tooltip is hidden\n\t\t\tisFirstShowRef.current = true\n\t\t}\n\t}, [tooltipData.id, tooltipData.element, editor, prefersReducedMotion])\n\n\tif (!tooltipData.id) {\n\t\treturn null\n\t}\n\n\treturn (\n\t\t<_Tooltip.Root open={isOpen} delayDuration={0}>\n\t\t\t<_Tooltip.Trigger asChild>\n\t\t\t\t<div ref={triggerRef} />\n\t\t\t</_Tooltip.Trigger>\n\t\t\t<_Tooltip.Content\n\t\t\t\tclassName=\"tlui-tooltip\"\n\t\t\t\tdata-should-animate={shouldAnimate}\n\t\t\t\tside={tooltipData.side}\n\t\t\t\tsideOffset={tooltipData.sideOffset}\n\t\t\t\tavoidCollisions\n\t\t\t\tcollisionPadding={8}\n\t\t\t\tdir=\"ltr\"\n\t\t\t>\n\t\t\t\t{tooltipData.content}\n\t\t\t\t<_Tooltip.Arrow className=\"tlui-tooltip__arrow\" />\n\t\t\t</_Tooltip.Content>\n\t\t</_Tooltip.Root>\n\t)\n}\n\n/** @public @react */\nexport const TldrawUiTooltip = forwardRef<HTMLButtonElement, TldrawUiTooltipProps>(\n\t({ children, content, side, sideOffset = 5, disabled = false }, ref) => {\n\t\tconst editor = useMaybeEditor()\n\t\tconst tooltipId = useRef<string>(uniqueId())\n\t\tconst hasProvider = useContext(TooltipSingletonContext)\n\n\t\tconst orientationCtx = useTldrawUiOrientation()\n\t\tconst sideToUse = side ?? orientationCtx.tooltipSide\n\n\t\tuseEffect(() => {\n\t\t\tconst currentTooltipId = tooltipId.current\n\t\t\treturn () => {\n\t\t\t\tif (hasProvider) {\n\t\t\t\t\ttooltipManager.hideTooltip(currentTooltipId, true)\n\t\t\t\t}\n\t\t\t}\n\t\t}, [hasProvider])\n\n\t\t// Don't show tooltip if disabled, no content, or UI labels are disabled\n\t\tif (disabled || !content) {\n\t\t\treturn <>{children}</>\n\t\t}\n\n\t\t// Fallback to old behavior if no provider\n\t\tif (!hasProvider) {\n\t\t\treturn (\n\t\t\t\t<_Tooltip.Root\n\t\t\t\t\tdelayDuration={editor?.options.tooltipDelayMs || DEFAULT_TOOLTIP_DELAY_MS}\n\t\t\t\t\tdisableHoverableContent\n\t\t\t\t>\n\t\t\t\t\t<_Tooltip.Trigger asChild ref={ref}>\n\t\t\t\t\t\t{children}\n\t\t\t\t\t</_Tooltip.Trigger>\n\t\t\t\t\t<_Tooltip.Content\n\t\t\t\t\t\tclassName=\"tlui-tooltip\"\n\t\t\t\t\t\tside={sideToUse}\n\t\t\t\t\t\tsideOffset={sideOffset}\n\t\t\t\t\t\tavoidCollisions\n\t\t\t\t\t\tcollisionPadding={8}\n\t\t\t\t\t\tdir=\"ltr\"\n\t\t\t\t\t>\n\t\t\t\t\t\t{content}\n\t\t\t\t\t\t<_Tooltip.Arrow className=\"tlui-tooltip__arrow\" />\n\t\t\t\t\t</_Tooltip.Content>\n\t\t\t\t</_Tooltip.Root>\n\t\t\t)\n\t\t}\n\n\t\tconst child = React.Children.only(children)\n\t\tassert(React.isValidElement(child), 'TldrawUiTooltip children must be a single element')\n\n\t\tconst handleMouseEnter = (event: React.MouseEvent<HTMLElement>) => {\n\t\t\tchild.props.onMouseEnter?.(event)\n\t\t\ttooltipManager.showTooltip(\n\t\t\t\ttooltipId.current,\n\t\t\t\tcontent,\n\t\t\t\tevent.currentTarget as HTMLElement,\n\t\t\t\tsideToUse,\n\t\t\t\tsideOffset\n\t\t\t)\n\t\t}\n\n\t\tconst handleMouseLeave = (event: React.MouseEvent<HTMLElement>) => {\n\t\t\tchild.props.onMouseLeave?.(event)\n\t\t\ttooltipManager.hideTooltip(tooltipId.current)\n\t\t}\n\n\t\tconst handleFocus = (event: React.FocusEvent<HTMLElement>) => {\n\t\t\tchild.props.onFocus?.(event)\n\t\t\ttooltipManager.showTooltip(\n\t\t\t\ttooltipId.current,\n\t\t\t\tcontent,\n\t\t\t\tevent.currentTarget as HTMLElement,\n\t\t\t\tsideToUse,\n\t\t\t\tsideOffset\n\t\t\t)\n\t\t}\n\n\t\tconst handleBlur = (event: React.FocusEvent<HTMLElement>) => {\n\t\t\tchild.props.onBlur?.(event)\n\t\t\ttooltipManager.hideTooltip(tooltipId.current)\n\t\t}\n\n\t\tconst childrenWithHandlers = React.cloneElement(children as React.ReactElement, {\n\t\t\tonMouseEnter: handleMouseEnter,\n\t\t\tonMouseLeave: handleMouseLeave,\n\t\t\tonFocus: handleFocus,\n\t\t\tonBlur: handleBlur,\n\t\t})\n\n\t\treturn childrenWithHandlers\n\t}\n)\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;
|
|
4
|
+
"sourcesContent": ["import { assert, Atom, atom, Editor, uniqueId, useMaybeEditor, useValue } from '@tldraw/editor'\nimport { Tooltip as _Tooltip } from 'radix-ui'\nimport React, {\n\tcreateContext,\n\tforwardRef,\n\tReactNode,\n\tuseContext,\n\tuseEffect,\n\tuseRef,\n\tuseState,\n} from 'react'\nimport { useTldrawUiOrientation } from './layout'\n\nconst DEFAULT_TOOLTIP_DELAY_MS = 700\n\n/** @public */\nexport interface TldrawUiTooltipProps {\n\tchildren: React.ReactNode\n\tcontent?: string | React.ReactNode\n\tside?: 'top' | 'right' | 'bottom' | 'left'\n\tsideOffset?: number\n\tdisabled?: boolean\n\tshowOnMobile?: boolean\n\tdelayDuration?: number\n}\n\n// Singleton tooltip manager\nclass TooltipManager {\n\tprivate static instance: TooltipManager | null = null\n\tprivate currentTooltip = atom<{\n\t\tid: string\n\t\tcontent: ReactNode\n\t\tside: 'top' | 'right' | 'bottom' | 'left'\n\t\tsideOffset: number\n\t\tshowOnMobile: boolean\n\t\ttargetElement: HTMLElement\n\t\tdelayDuration: number | undefined\n\t} | null>('current tooltip', null)\n\tprivate destroyTimeoutId: number | null = null\n\n\tstatic getInstance(): TooltipManager {\n\t\tif (!TooltipManager.instance) {\n\t\t\tTooltipManager.instance = new TooltipManager()\n\t\t}\n\t\treturn TooltipManager.instance\n\t}\n\n\tshowTooltip(\n\t\ttooltipId: string,\n\t\tcontent: string | React.ReactNode,\n\t\ttargetElement: HTMLElement,\n\t\tside: 'top' | 'right' | 'bottom' | 'left',\n\t\tsideOffset: number,\n\t\tshowOnMobile: boolean,\n\t\tdelayDuration: number | undefined\n\t) {\n\t\t// Clear any existing destroy timeout\n\t\tif (this.destroyTimeoutId) {\n\t\t\tclearTimeout(this.destroyTimeoutId)\n\t\t\tthis.destroyTimeoutId = null\n\t\t}\n\n\t\t// Update current tooltip\n\t\tthis.currentTooltip.set({\n\t\t\tid: tooltipId,\n\t\t\tcontent,\n\t\t\tside,\n\t\t\tsideOffset,\n\t\t\tshowOnMobile,\n\t\t\ttargetElement,\n\t\t\tdelayDuration,\n\t\t})\n\t}\n\n\thideTooltip(editor: Editor | null, tooltipId: string, instant: boolean = false) {\n\t\tconst hide = () => {\n\t\t\t// Only hide if this is the current tooltip\n\t\t\tif (this.currentTooltip.get()?.id === tooltipId) {\n\t\t\t\tthis.currentTooltip.set(null)\n\t\t\t\tthis.destroyTimeoutId = null\n\t\t\t}\n\t\t}\n\n\t\tif (editor && !instant) {\n\t\t\t// Start destroy timeout (1 second)\n\t\t\tthis.destroyTimeoutId = editor.timers.setTimeout(hide, 300)\n\t\t} else {\n\t\t\thide()\n\t\t}\n\t}\n\n\thideAllTooltips() {\n\t\tthis.currentTooltip.set(null)\n\t\tthis.destroyTimeoutId = null\n\t}\n\n\tgetCurrentTooltipData() {\n\t\tconst currentTooltip = this.currentTooltip.get()\n\t\tif (!currentTooltip) return null\n\t\tif (!this.supportsHover() && !currentTooltip.showOnMobile) return null\n\t\treturn currentTooltip\n\t}\n\n\tprivate supportsHoverAtom: Atom<boolean> | null = null\n\tsupportsHover() {\n\t\tif (!this.supportsHoverAtom) {\n\t\t\tconst mediaQuery = window.matchMedia('(hover: hover)')\n\t\t\tconst supportsHover = atom('has hover', mediaQuery.matches)\n\t\t\tthis.supportsHoverAtom = supportsHover\n\t\t\tmediaQuery.addEventListener('change', (e) => {\n\t\t\t\tsupportsHover.set(e.matches)\n\t\t\t})\n\t\t}\n\t\treturn this.supportsHoverAtom.get()\n\t}\n}\n\nexport const tooltipManager = TooltipManager.getInstance()\n\n// Context for the tooltip singleton\nconst TooltipSingletonContext = createContext<boolean>(false)\n\n/** @public */\nexport interface TldrawUiTooltipProviderProps {\n\tchildren: React.ReactNode\n}\n\n/** @public @react */\nexport function TldrawUiTooltipProvider({ children }: TldrawUiTooltipProviderProps) {\n\treturn (\n\t\t<_Tooltip.Provider skipDelayDuration={700}>\n\t\t\t<TooltipSingletonContext.Provider value={true}>\n\t\t\t\t{children}\n\t\t\t\t<TooltipSingleton />\n\t\t\t</TooltipSingletonContext.Provider>\n\t\t</_Tooltip.Provider>\n\t)\n}\n\n// The singleton tooltip component that renders once\nfunction TooltipSingleton() {\n\tconst editor = useMaybeEditor()\n\tconst [isOpen, setIsOpen] = useState(false)\n\tconst triggerRef = useRef<HTMLDivElement>(null)\n\tconst isFirstShowRef = useRef(true)\n\tconst showTimeoutRef = useRef<number | null>(null)\n\n\tconst currentTooltip = useValue(\n\t\t'current tooltip',\n\t\t() => tooltipManager.getCurrentTooltipData(),\n\t\t[]\n\t)\n\n\t// Update open state and trigger position\n\tuseEffect(() => {\n\t\t// Clear any existing show timeout\n\t\tif (showTimeoutRef.current) {\n\t\t\tclearTimeout(showTimeoutRef.current)\n\t\t\tshowTimeoutRef.current = null\n\t\t}\n\n\t\tif (currentTooltip && triggerRef.current) {\n\t\t\t// Position the invisible trigger element over the active element\n\t\t\tconst activeRect = currentTooltip.targetElement.getBoundingClientRect()\n\t\t\tconst trigger = triggerRef.current\n\n\t\t\ttrigger.style.position = 'fixed'\n\t\t\ttrigger.style.left = `${activeRect.left}px`\n\t\t\ttrigger.style.top = `${activeRect.top}px`\n\t\t\ttrigger.style.width = `${activeRect.width}px`\n\t\t\ttrigger.style.height = `${activeRect.height}px`\n\t\t\ttrigger.style.pointerEvents = 'none'\n\t\t\ttrigger.style.zIndex = '9999'\n\n\t\t\t// Handle delay for first show\n\t\t\tif (isFirstShowRef.current && editor) {\n\t\t\t\tshowTimeoutRef.current = editor.timers.setTimeout(() => {\n\t\t\t\t\tsetIsOpen(true)\n\t\t\t\t\tisFirstShowRef.current = false\n\t\t\t\t}, currentTooltip.delayDuration ?? editor.options.tooltipDelayMs)\n\t\t\t} else {\n\t\t\t\t// Subsequent tooltips show immediately\n\t\t\t\tsetIsOpen(true)\n\t\t\t}\n\t\t} else {\n\t\t\t// Hide tooltip immediately\n\t\t\tsetIsOpen(false)\n\t\t\t// Reset first show state after tooltip is hidden\n\t\t\tisFirstShowRef.current = true\n\t\t}\n\t}, [editor, currentTooltip])\n\n\tif (!currentTooltip) {\n\t\treturn null\n\t}\n\n\treturn (\n\t\t<_Tooltip.Root open={isOpen} delayDuration={0}>\n\t\t\t<_Tooltip.Trigger asChild>\n\t\t\t\t<div ref={triggerRef} />\n\t\t\t</_Tooltip.Trigger>\n\t\t\t<_Tooltip.Content\n\t\t\t\tclassName=\"tlui-tooltip\"\n\t\t\t\tside={currentTooltip.side}\n\t\t\t\tsideOffset={currentTooltip.sideOffset}\n\t\t\t\tavoidCollisions\n\t\t\t\tcollisionPadding={8}\n\t\t\t\tdir=\"ltr\"\n\t\t\t>\n\t\t\t\t{currentTooltip.content}\n\t\t\t\t<_Tooltip.Arrow className=\"tlui-tooltip__arrow\" />\n\t\t\t</_Tooltip.Content>\n\t\t</_Tooltip.Root>\n\t)\n}\n\n/** @public @react */\nexport const TldrawUiTooltip = forwardRef<HTMLButtonElement, TldrawUiTooltipProps>(\n\t(\n\t\t{\n\t\t\tchildren,\n\t\t\tcontent,\n\t\t\tside,\n\t\t\tsideOffset = 5,\n\t\t\tdisabled = false,\n\t\t\tshowOnMobile = false,\n\t\t\tdelayDuration,\n\t\t},\n\t\tref\n\t) => {\n\t\tconst editor = useMaybeEditor()\n\t\tconst tooltipId = useRef<string>(uniqueId())\n\t\tconst hasProvider = useContext(TooltipSingletonContext)\n\n\t\tconst orientationCtx = useTldrawUiOrientation()\n\t\tconst sideToUse = side ?? orientationCtx.tooltipSide\n\n\t\tuseEffect(() => {\n\t\t\tconst currentTooltipId = tooltipId.current\n\t\t\treturn () => {\n\t\t\t\tif (hasProvider) {\n\t\t\t\t\ttooltipManager.hideTooltip(editor, currentTooltipId, true)\n\t\t\t\t}\n\t\t\t}\n\t\t}, [editor, hasProvider])\n\n\t\t// Don't show tooltip if disabled, no content, or UI labels are disabled\n\t\tif (disabled || !content) {\n\t\t\treturn <>{children}</>\n\t\t}\n\n\t\t// Fallback to old behavior if no provider\n\t\tif (!hasProvider) {\n\t\t\treturn (\n\t\t\t\t<_Tooltip.Root\n\t\t\t\t\tdelayDuration={\n\t\t\t\t\t\tdelayDuration ?? (editor?.options.tooltipDelayMs || DEFAULT_TOOLTIP_DELAY_MS)\n\t\t\t\t\t}\n\t\t\t\t\tdisableHoverableContent\n\t\t\t\t>\n\t\t\t\t\t<_Tooltip.Trigger asChild ref={ref}>\n\t\t\t\t\t\t{children}\n\t\t\t\t\t</_Tooltip.Trigger>\n\t\t\t\t\t<_Tooltip.Content\n\t\t\t\t\t\tclassName=\"tlui-tooltip\"\n\t\t\t\t\t\tside={sideToUse}\n\t\t\t\t\t\tsideOffset={sideOffset}\n\t\t\t\t\t\tavoidCollisions\n\t\t\t\t\t\tcollisionPadding={8}\n\t\t\t\t\t\tdir=\"ltr\"\n\t\t\t\t\t>\n\t\t\t\t\t\t{content}\n\t\t\t\t\t\t<_Tooltip.Arrow className=\"tlui-tooltip__arrow\" />\n\t\t\t\t\t</_Tooltip.Content>\n\t\t\t\t</_Tooltip.Root>\n\t\t\t)\n\t\t}\n\n\t\tconst child = React.Children.only(children)\n\t\tassert(React.isValidElement(child), 'TldrawUiTooltip children must be a single element')\n\n\t\tconst handleMouseEnter = (event: React.MouseEvent<HTMLElement>) => {\n\t\t\tchild.props.onMouseEnter?.(event)\n\t\t\ttooltipManager.showTooltip(\n\t\t\t\ttooltipId.current,\n\t\t\t\tcontent,\n\t\t\t\tevent.currentTarget as HTMLElement,\n\t\t\t\tsideToUse,\n\t\t\t\tsideOffset,\n\t\t\t\tshowOnMobile,\n\t\t\t\tdelayDuration\n\t\t\t)\n\t\t}\n\n\t\tconst handleMouseLeave = (event: React.MouseEvent<HTMLElement>) => {\n\t\t\tchild.props.onMouseLeave?.(event)\n\t\t\ttooltipManager.hideTooltip(editor, tooltipId.current)\n\t\t}\n\n\t\tconst handleFocus = (event: React.FocusEvent<HTMLElement>) => {\n\t\t\tchild.props.onFocus?.(event)\n\t\t\ttooltipManager.showTooltip(\n\t\t\t\ttooltipId.current,\n\t\t\t\tcontent,\n\t\t\t\tevent.currentTarget as HTMLElement,\n\t\t\t\tsideToUse,\n\t\t\t\tsideOffset,\n\t\t\t\tshowOnMobile,\n\t\t\t\tdelayDuration\n\t\t\t)\n\t\t}\n\n\t\tconst handleBlur = (event: React.FocusEvent<HTMLElement>) => {\n\t\t\tchild.props.onBlur?.(event)\n\t\t\ttooltipManager.hideTooltip(editor, tooltipId.current)\n\t\t}\n\n\t\tconst childrenWithHandlers = React.cloneElement(children as React.ReactElement, {\n\t\t\tonMouseEnter: handleMouseEnter,\n\t\t\tonMouseLeave: handleMouseLeave,\n\t\t\tonFocus: handleFocus,\n\t\t\tonBlur: handleBlur,\n\t\t})\n\n\t\treturn childrenWithHandlers\n\t}\n)\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["_Tooltip", "React"]
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../src/lib/ui/components/primitives/menus/TldrawUiMenuContext.tsx"],
|
|
4
|
-
"sourcesContent": ["import { createContext, useContext } from 'react'\nimport { TLUiEventSource } from '../../../context/events'\n\n/** @public */\nexport type TLUiMenuContextType =\n\t| '
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;
|
|
4
|
+
"sourcesContent": ["import { createContext, useContext } from 'react'\nimport { TLUiEventSource } from '../../../context/events'\n\n/** @public */\nexport type TLUiMenuContextType =\n\t| 'menu'\n\t| 'small-icons'\n\t| 'context-menu'\n\t| 'icons'\n\t| 'keyboard-shortcuts'\n\t| 'helper-buttons'\n\t| 'toolbar'\n\t| 'toolbar-overflow'\n\nconst menuContext = createContext<{\n\ttype: TLUiMenuContextType\n\tsourceId: TLUiEventSource\n} | null>(null)\n\n/** @public */\nexport function useTldrawUiMenuContext() {\n\tconst context = useContext(menuContext)\n\tif (!context) {\n\t\tthrow new Error('useTldrawUiMenuContext must be used within a TldrawUiMenuContextProvider')\n\t}\n\treturn context\n}\n\n/** @public */\nexport interface TLUiMenuContextProviderProps {\n\ttype: TLUiMenuContextType\n\tsourceId: TLUiEventSource\n\tchildren: React.ReactNode\n}\n\n/** @public @react */\nexport function TldrawUiMenuContextProvider({\n\ttype,\n\tsourceId,\n\tchildren,\n}: TLUiMenuContextProviderProps) {\n\treturn <menuContext.Provider value={{ type, sourceId }}>{children}</menuContext.Provider>\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAyCQ;AAzCR,mBAA0C;AAc1C,MAAM,kBAAc,4BAGV,IAAI;AAGP,SAAS,yBAAyB;AACxC,QAAM,cAAU,yBAAW,WAAW;AACtC,MAAI,CAAC,SAAS;AACb,UAAM,IAAI,MAAM,0EAA0E;AAAA,EAC3F;AACA,SAAO;AACR;AAUO,SAAS,4BAA4B;AAAA,EAC3C;AAAA,EACA;AAAA,EACA;AACD,GAAiC;AAChC,SAAO,4CAAC,YAAY,UAAZ,EAAqB,OAAO,EAAE,MAAM,SAAS,GAAI,UAAS;AACnE;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -45,16 +45,6 @@ function TldrawUiMenuGroup({ id, label, className, children }) {
|
|
|
45
45
|
const labelToUse = (0, import_actions.unwrapLabel)(label, menu.type);
|
|
46
46
|
const labelStr = labelToUse ? msg(labelToUse) : void 0;
|
|
47
47
|
switch (menu.type) {
|
|
48
|
-
case "panel": {
|
|
49
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
50
|
-
"div",
|
|
51
|
-
{
|
|
52
|
-
className: (0, import_classnames.default)("tlui-menu__group", className),
|
|
53
|
-
"data-testid": `${menu.sourceId}-group.${id}`,
|
|
54
|
-
children
|
|
55
|
-
}
|
|
56
|
-
);
|
|
57
|
-
}
|
|
58
48
|
case "menu": {
|
|
59
49
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
60
50
|
import_TldrawUiDropdownMenu.TldrawUiDropdownMenuGroup,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../src/lib/ui/components/primitives/menus/TldrawUiMenuGroup.tsx"],
|
|
4
|
-
"sourcesContent": ["import classNames from 'classnames'\nimport { ReactNode } from 'react'\nimport { unwrapLabel } from '../../../context/actions'\nimport { TLUiTranslationKey } from '../../../hooks/useTranslation/TLUiTranslationKey'\nimport { useTranslation } from '../../../hooks/useTranslation/useTranslation'\nimport { TldrawUiColumn, TldrawUiGrid, TldrawUiRow, useTldrawUiOrientation } from '../layout'\nimport { TldrawUiDropdownMenuGroup } from '../TldrawUiDropdownMenu'\nimport { useTldrawUiMenuContext } from './TldrawUiMenuContext'\n\n/** @public */\nexport interface TLUiMenuGroupProps<TranslationKey extends string = string> {\n\tid: string\n\t/**\n\t * The label to display on the item. If it's a string, it will be translated. If it's an object, the keys will be used as the language keys and the values will be translated.\n\t */\n\tlabel?: TranslationKey | { [key: string]: TranslationKey }\n\tclassName?: string\n\tchildren?: ReactNode\n}\n\n/** @public @react */\nexport function TldrawUiMenuGroup({ id, label, className, children }: TLUiMenuGroupProps) {\n\tconst menu = useTldrawUiMenuContext()\n\tconst { orientation } = useTldrawUiOrientation()\n\tconst msg = useTranslation()\n\tconst labelToUse = unwrapLabel(label, menu.type)\n\tconst labelStr = labelToUse ? msg(labelToUse as TLUiTranslationKey) : undefined\n\n\tswitch (menu.type) {\n\t\tcase '
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA+BI;AA/BJ,wBAAuB;AAEvB,qBAA4B;AAE5B,4BAA+B;AAC/B,oBAAkF;AAClF,kCAA0C;AAC1C,iCAAuC;AAchC,SAAS,kBAAkB,EAAE,IAAI,OAAO,WAAW,SAAS,GAAuB;AACzF,QAAM,WAAO,mDAAuB;AACpC,QAAM,EAAE,YAAY,QAAI,sCAAuB;AAC/C,QAAM,UAAM,sCAAe;AAC3B,QAAM,iBAAa,4BAAY,OAAO,KAAK,IAAI;AAC/C,QAAM,WAAW,aAAa,IAAI,UAAgC,IAAI;AAEtE,UAAQ,KAAK,MAAM;AAAA,IAClB,KAAK,
|
|
4
|
+
"sourcesContent": ["import classNames from 'classnames'\nimport { ReactNode } from 'react'\nimport { unwrapLabel } from '../../../context/actions'\nimport { TLUiTranslationKey } from '../../../hooks/useTranslation/TLUiTranslationKey'\nimport { useTranslation } from '../../../hooks/useTranslation/useTranslation'\nimport { TldrawUiColumn, TldrawUiGrid, TldrawUiRow, useTldrawUiOrientation } from '../layout'\nimport { TldrawUiDropdownMenuGroup } from '../TldrawUiDropdownMenu'\nimport { useTldrawUiMenuContext } from './TldrawUiMenuContext'\n\n/** @public */\nexport interface TLUiMenuGroupProps<TranslationKey extends string = string> {\n\tid: string\n\t/**\n\t * The label to display on the item. If it's a string, it will be translated. If it's an object, the keys will be used as the language keys and the values will be translated.\n\t */\n\tlabel?: TranslationKey | { [key: string]: TranslationKey }\n\tclassName?: string\n\tchildren?: ReactNode\n}\n\n/** @public @react */\nexport function TldrawUiMenuGroup({ id, label, className, children }: TLUiMenuGroupProps) {\n\tconst menu = useTldrawUiMenuContext()\n\tconst { orientation } = useTldrawUiOrientation()\n\tconst msg = useTranslation()\n\tconst labelToUse = unwrapLabel(label, menu.type)\n\tconst labelStr = labelToUse ? msg(labelToUse as TLUiTranslationKey) : undefined\n\n\tswitch (menu.type) {\n\t\tcase 'menu': {\n\t\t\treturn (\n\t\t\t\t<TldrawUiDropdownMenuGroup\n\t\t\t\t\tclassName={className}\n\t\t\t\t\tdata-testid={`${menu.sourceId}-group.${id}`}\n\t\t\t\t>\n\t\t\t\t\t{children}\n\t\t\t\t</TldrawUiDropdownMenuGroup>\n\t\t\t)\n\t\t}\n\t\tcase 'context-menu': {\n\t\t\treturn (\n\t\t\t\t<div\n\t\t\t\t\tdir=\"ltr\"\n\t\t\t\t\tclassName={classNames('tlui-menu__group', className)}\n\t\t\t\t\tdata-testid={`${menu.sourceId}-group.${id}`}\n\t\t\t\t>\n\t\t\t\t\t{children}\n\t\t\t\t</div>\n\t\t\t)\n\t\t}\n\t\tcase 'keyboard-shortcuts': {\n\t\t\t// todo: if groups need a label, let's give em a label\n\t\t\treturn (\n\t\t\t\t<div className=\"tlui-shortcuts-dialog__group\" data-testid={`${menu.sourceId}-group.${id}`}>\n\t\t\t\t\t<h2 className=\"tlui-shortcuts-dialog__group__title\">{labelStr}</h2>\n\t\t\t\t\t<div className=\"tlui-shortcuts-dialog__group__content\">{children}</div>\n\t\t\t\t</div>\n\t\t\t)\n\t\t}\n\t\tcase 'toolbar': {\n\t\t\tconst Layout = orientation === 'horizontal' ? TldrawUiRow : TldrawUiColumn\n\t\t\treturn (\n\t\t\t\t<Layout className=\"tlui-main-toolbar__group\" data-testid={`${menu.sourceId}-group.${id}`}>\n\t\t\t\t\t{children}\n\t\t\t\t</Layout>\n\t\t\t)\n\t\t}\n\t\tcase 'toolbar-overflow': {\n\t\t\treturn (\n\t\t\t\t<TldrawUiGrid\n\t\t\t\t\tclassName=\"tlui-main-toolbar__group\"\n\t\t\t\t\tdata-testid={`${menu.sourceId}-group.${id}`}\n\t\t\t\t>\n\t\t\t\t\t{children}\n\t\t\t\t</TldrawUiGrid>\n\t\t\t)\n\t\t}\n\t\tdefault: {\n\t\t\treturn children\n\t\t}\n\t}\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA+BI;AA/BJ,wBAAuB;AAEvB,qBAA4B;AAE5B,4BAA+B;AAC/B,oBAAkF;AAClF,kCAA0C;AAC1C,iCAAuC;AAchC,SAAS,kBAAkB,EAAE,IAAI,OAAO,WAAW,SAAS,GAAuB;AACzF,QAAM,WAAO,mDAAuB;AACpC,QAAM,EAAE,YAAY,QAAI,sCAAuB;AAC/C,QAAM,UAAM,sCAAe;AAC3B,QAAM,iBAAa,4BAAY,OAAO,KAAK,IAAI;AAC/C,QAAM,WAAW,aAAa,IAAI,UAAgC,IAAI;AAEtE,UAAQ,KAAK,MAAM;AAAA,IAClB,KAAK,QAAQ;AACZ,aACC;AAAA,QAAC;AAAA;AAAA,UACA;AAAA,UACA,eAAa,GAAG,KAAK,QAAQ,UAAU,EAAE;AAAA,UAExC;AAAA;AAAA,MACF;AAAA,IAEF;AAAA,IACA,KAAK,gBAAgB;AACpB,aACC;AAAA,QAAC;AAAA;AAAA,UACA,KAAI;AAAA,UACJ,eAAW,kBAAAA,SAAW,oBAAoB,SAAS;AAAA,UACnD,eAAa,GAAG,KAAK,QAAQ,UAAU,EAAE;AAAA,UAExC;AAAA;AAAA,MACF;AAAA,IAEF;AAAA,IACA,KAAK,sBAAsB;AAE1B,aACC,6CAAC,SAAI,WAAU,gCAA+B,eAAa,GAAG,KAAK,QAAQ,UAAU,EAAE,IACtF;AAAA,oDAAC,QAAG,WAAU,uCAAuC,oBAAS;AAAA,QAC9D,4CAAC,SAAI,WAAU,yCAAyC,UAAS;AAAA,SAClE;AAAA,IAEF;AAAA,IACA,KAAK,WAAW;AACf,YAAM,SAAS,gBAAgB,eAAe,4BAAc;AAC5D,aACC,4CAAC,UAAO,WAAU,4BAA2B,eAAa,GAAG,KAAK,QAAQ,UAAU,EAAE,IACpF,UACF;AAAA,IAEF;AAAA,IACA,KAAK,oBAAoB;AACxB,aACC;AAAA,QAAC;AAAA;AAAA,UACA,WAAU;AAAA,UACV,eAAa,GAAG,KAAK,QAAQ,UAAU,EAAE;AAAA,UAExC;AAAA;AAAA,MACF;AAAA,IAEF;AAAA,IACA,SAAS;AACR,aAAO;AAAA,IACR;AAAA,EACD;AACD;",
|
|
6
6
|
"names": ["classNames"]
|
|
7
7
|
}
|
|
@@ -69,7 +69,6 @@ function TldrawUiMenuItem({
|
|
|
69
69
|
type: "menu",
|
|
70
70
|
"data-testid": `${sourceId}.${id}`,
|
|
71
71
|
disabled,
|
|
72
|
-
title: titleStr,
|
|
73
72
|
onClick: (e) => {
|
|
74
73
|
if (noClose) {
|
|
75
74
|
(0, import_editor.preventDefault)(e);
|
|
@@ -94,7 +93,6 @@ function TldrawUiMenuItem({
|
|
|
94
93
|
import_radix_ui.ContextMenu.Item,
|
|
95
94
|
{
|
|
96
95
|
dir: "ltr",
|
|
97
|
-
title: titleStr,
|
|
98
96
|
draggable: false,
|
|
99
97
|
className: "tlui-button tlui-button__menu",
|
|
100
98
|
"data-testid": `${sourceId}.${id}`,
|
|
@@ -115,22 +113,6 @@ function TldrawUiMenuItem({
|
|
|
115
113
|
}
|
|
116
114
|
);
|
|
117
115
|
}
|
|
118
|
-
case "panel": {
|
|
119
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
120
|
-
import_TldrawUiButton.TldrawUiButton,
|
|
121
|
-
{
|
|
122
|
-
"data-testid": `${sourceId}.${id}`,
|
|
123
|
-
type: "menu",
|
|
124
|
-
title: titleStr,
|
|
125
|
-
disabled,
|
|
126
|
-
onClick: () => onSelect(sourceId),
|
|
127
|
-
children: [
|
|
128
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_TldrawUiButtonLabel.TldrawUiButtonLabel, { children: labelStr }),
|
|
129
|
-
spinner ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_Spinner.Spinner, {}) : icon && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_TldrawUiButtonIcon.TldrawUiButtonIcon, { icon })
|
|
130
|
-
]
|
|
131
|
-
}
|
|
132
|
-
);
|
|
133
|
-
}
|
|
134
116
|
case "small-icons":
|
|
135
117
|
case "icons": {
|
|
136
118
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
@@ -251,13 +233,14 @@ function useDraggableEvents(onDragStart, onSelect) {
|
|
|
251
233
|
if (e.isSpecialRedispatchedEvent) return;
|
|
252
234
|
if (state.name === "pointing") {
|
|
253
235
|
const distanceSq = import_editor.Vec.Dist2(state.screenSpaceStart, { x: e.clientX, y: e.clientY });
|
|
254
|
-
if (distanceSq > (editor.getInstanceState().isCoarsePointer ? editor.options.
|
|
236
|
+
if (distanceSq > (editor.getInstanceState().isCoarsePointer ? editor.options.uiCoarseDragDistanceSquared : editor.options.uiDragDistanceSquared)) {
|
|
255
237
|
const screenSpaceStart = state.screenSpaceStart;
|
|
256
238
|
state = {
|
|
257
239
|
name: "dragging",
|
|
258
240
|
screenSpaceStart
|
|
259
241
|
};
|
|
260
242
|
editor.run(() => {
|
|
243
|
+
editor.setCurrentTool("select");
|
|
261
244
|
editor.dispatch({
|
|
262
245
|
type: "pointer",
|
|
263
246
|
target: "canvas",
|
|
@@ -274,6 +257,7 @@ function useDraggableEvents(onDragStart, onSelect) {
|
|
|
274
257
|
point: screenSpaceStart
|
|
275
258
|
});
|
|
276
259
|
import_TldrawUiTooltip.tooltipManager.hideAllTooltips();
|
|
260
|
+
editor.getContainer().focus();
|
|
277
261
|
});
|
|
278
262
|
}
|
|
279
263
|
}
|