tldraw 3.16.0-canary.ed8bd30c0f28 → 3.16.0-canary.fa3749606e52
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 +32 -1
- package/dist-cjs/index.js +2 -1
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/tools/SelectTool/childStates/Translating.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js +149 -1
- package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js.map +2 -2
- package/dist-cjs/lib/ui/context/events.js.map +2 -2
- package/dist-cjs/lib/ui/hooks/useTools.js +76 -9
- 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 +32 -1
- package/dist-esm/index.mjs +3 -1
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/tools/SelectTool/childStates/Translating.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs +157 -3
- package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs.map +2 -2
- package/dist-esm/lib/ui/context/events.mjs.map +2 -2
- package/dist-esm/lib/ui/hooks/useTools.mjs +83 -10
- 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 +3 -3
- package/src/index.ts +2 -0
- package/src/lib/tools/SelectTool/childStates/Translating.ts +0 -1
- package/src/lib/ui/components/primitives/menus/TldrawUiMenuItem.tsx +213 -2
- package/src/lib/ui/context/events.tsx +1 -0
- package/src/lib/ui/hooks/useTools.tsx +118 -10
- package/src/lib/ui/version.ts +3 -3
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/lib/tools/SelectTool/childStates/Translating.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n\tBoundsSnapPoint,\n\tEditor,\n\tMat,\n\tMatModel,\n\tPageRecordType,\n\tStateNode,\n\tTLNoteShape,\n\tTLPointerEventInfo,\n\tTLShape,\n\tTLShapePartial,\n\tTLTickEventInfo,\n\tVec,\n\tbind,\n\tcompact,\n\tisPageId,\n\tkickoutOccludedShapes,\n} from '@tldraw/editor'\nimport {\n\tNOTE_ADJACENT_POSITION_SNAP_RADIUS,\n\tNOTE_CENTER_OFFSET,\n\tgetAvailableNoteAdjacentPositions,\n} from '../../../shapes/note/noteHelpers'\nimport { DragAndDropManager } from '../DragAndDropManager'\n\nexport type TranslatingInfo = TLPointerEventInfo & {\n\ttarget: 'shape'\n\tisCreating?: boolean\n\tcreatingMarkId?: string\n\tonCreate?(): void\n\tdidStartInPit?: boolean\n\tonInteractionEnd?: string\n}\n\nexport class Translating extends StateNode {\n\tstatic override id = 'translating'\n\n\tinfo = {} as TranslatingInfo\n\n\tselectionSnapshot: TranslatingSnapshot = {} as any\n\n\tsnapshot: TranslatingSnapshot = {} as any\n\n\tmarkId = ''\n\n\tisCloning = false\n\tisCreating = false\n\tonCreate(_shape: TLShape | null): void {\n\t\treturn\n\t}\n\n\tdragAndDropManager = new DragAndDropManager(this.editor)\n\n\toverride onEnter(info: TranslatingInfo) {\n\t\tconst { isCreating = false, creatingMarkId, onCreate = () => void null } = info\n\n\t\tif (!this.editor.getSelectedShapeIds()?.length) {\n\t\t\tthis.parent.transition('idle')\n\t\t\treturn\n\t\t}\n\n\t\tthis.info = info\n\t\tthis.parent.setCurrentToolIdMask(info.onInteractionEnd)\n\t\tthis.isCreating = isCreating\n\n\t\tthis.markId = ''\n\n\t\tif (isCreating) {\n\t\t\tif (creatingMarkId) {\n\t\t\t\tthis.markId = creatingMarkId\n\t\t\t} else {\n\t\t\t\t// handle legacy implicit `creating:{shapeId}` marks\n\t\t\t\tconst markId = this.editor.getMarkIdMatching(\n\t\t\t\t\t`creating:${this.editor.getOnlySelectedShapeId()}`\n\t\t\t\t)\n\t\t\t\tif (markId) {\n\t\t\t\t\tthis.markId = markId\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tthis.markId = this.editor.markHistoryStoppingPoint('translating')\n\t\t}\n\n\t\tthis.onCreate = onCreate\n\n\t\tthis.isCloning = false\n\t\tthis.info = info\n\n\t\tthis.editor.setCursor({ type: 'move', rotation: 0 })\n\t\tthis.selectionSnapshot = getTranslatingSnapshot(this.editor)\n\n\t\t// Don't clone on create; otherwise clone on altKey\n\t\tif (!this.isCreating) {\n\t\t\tif (this.editor.inputs.altKey) {\n\t\t\t\tthis.startCloning()\n\t\t\t\tif (this.isCloning) return\n\t\t\t}\n\t\t}\n\n\t\tthis.snapshot = this.selectionSnapshot\n\t\tthis.handleStart()\n\t\tthis.updateShapes()\n\t}\n\n\toverride onExit() {\n\t\tthis.parent.setCurrentToolIdMask(undefined)\n\t\tthis.selectionSnapshot = {} as any\n\t\tthis.snapshot = {} as any\n\t\tthis.editor.snaps.clearIndicators()\n\t\tthis.editor.setCursor({ type: 'default', rotation: 0 })\n\t\tthis.dragAndDropManager.clear()\n\t}\n\n\toverride onTick({ elapsed }: TLTickEventInfo) {\n\t\tconst { editor } = this\n\t\teditor.edgeScrollManager.updateEdgeScrolling(elapsed)\n\t}\n\n\toverride onPointerMove() {\n\t\tthis.updateShapes()\n\t}\n\n\toverride onKeyDown() {\n\t\tif (this.editor.inputs.altKey && !this.isCloning) {\n\t\t\tthis.startCloning()\n\t\t\tif (this.isCloning) return\n\t\t}\n\n\t\t// need to update in case user pressed a different modifier key\n\t\tthis.updateShapes()\n\t}\n\n\toverride onKeyUp() {\n\t\tif (!this.editor.inputs.altKey && this.isCloning) {\n\t\t\tthis.stopCloning()\n\t\t\treturn\n\t\t}\n\n\t\t// need to update in case user pressed a different modifier key\n\t\tthis.updateShapes()\n\t}\n\n\toverride onPointerUp() {\n\t\tthis.complete()\n\t}\n\n\toverride onComplete() {\n\t\tthis.complete()\n\t}\n\n\toverride onCancel() {\n\t\tthis.cancel()\n\t}\n\n\tprotected startCloning() {\n\t\tif (this.isCreating) return\n\t\tconst shapeIds = Array.from(this.editor.getSelectedShapeIds())\n\n\t\t// If we can't create the shapes, don't even start cloning\n\t\tif (!this.editor.canCreateShapes(shapeIds)) return\n\n\t\tthis.isCloning = true\n\t\tthis.reset()\n\t\tthis.markId = this.editor.markHistoryStoppingPoint('translate cloning')\n\n\t\tthis.editor.duplicateShapes(Array.from(this.editor.getSelectedShapeIds()))\n\n\t\tthis.snapshot = getTranslatingSnapshot(this.editor)\n\t\tthis.handleStart()\n\t\tthis.updateShapes()\n\t}\n\n\tprotected stopCloning() {\n\t\tthis.isCloning = false\n\t\tthis.snapshot = this.selectionSnapshot\n\t\tthis.reset()\n\t\tthis.markId = this.editor.markHistoryStoppingPoint('translate')\n\t\tthis.updateShapes()\n\t}\n\n\treset() {\n\t\tthis.editor.bailToMark(this.markId)\n\t}\n\n\tprotected complete() {\n\t\tthis.updateShapes()\n\t\tthis.dragAndDropManager.dropShapes(this.snapshot.movingShapes)\n\t\tthis.handleEnd()\n\t\tkickoutOccludedShapes(\n\t\t\tthis.editor,\n\t\t\tthis.snapshot.movingShapes.map((s) => s.id)\n\t\t)\n\n\t\tif (this.editor.getInstanceState().isToolLocked && this.info.onInteractionEnd) {\n\t\t\tthis.editor.setCurrentTool(this.info.onInteractionEnd)\n\t\t} else {\n\t\t\tif (this.isCreating) {\n\t\t\t\tthis.onCreate?.(this.editor.getOnlySelectedShape())\n\t\t\t} else {\n\t\t\t\tthis.parent.transition('idle')\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate cancel() {\n\t\t// Call onTranslateCancel callback before resetting\n\t\tconst { movingShapes } = this.snapshot\n\n\t\tmovingShapes.forEach((shape) => {\n\t\t\tconst current = this.editor.getShape(shape.id)\n\t\t\tif (current) {\n\t\t\t\tconst util = this.editor.getShapeUtil(shape)\n\t\t\t\tutil.onTranslateCancel?.(shape, current)\n\t\t\t}\n\t\t})\n\n\t\tthis.reset()\n\t\tif (this.info.onInteractionEnd) {\n\t\t\tthis.editor.setCurrentTool(this.info.onInteractionEnd)\n\t\t} else {\n\t\t\tthis.parent.transition('idle', this.info)\n\t\t}\n\t}\n\n\tprotected handleStart() {\n\t\tconst { movingShapes } = this.snapshot\n\n\t\tconst changes: TLShapePartial[] = []\n\n\t\tmovingShapes.forEach((shape) => {\n\t\t\tconst util = this.editor.getShapeUtil(shape)\n\t\t\tconst change = util.onTranslateStart?.(shape)\n\t\t\tif (change) {\n\t\t\t\tchanges.push(change)\n\t\t\t}\n\t\t})\n\n\t\tif (changes.length > 0) {\n\t\t\tthis.editor.updateShapes(changes)\n\t\t}\n\n\t\tthis.dragAndDropManager.startDraggingShapes(\n\t\t\t// Get fresh shapes from the snapshot, in case onTranslateStart mutates the shape\n\t\t\tcompact(this.snapshot.movingShapes.map((s) => this.editor.getShape(s.id))),\n\t\t\t// Start from the place where the user started dragging\n\t\t\tthis.editor.inputs.originPagePoint,\n\t\t\tthis.updateParentTransforms\n\t\t)\n\n\t\tthis.editor.setHoveredShape(null)\n\t}\n\n\tprotected handleEnd() {\n\t\tconst { movingShapes } = this.snapshot\n\n\t\tif (this.isCloning && movingShapes.length > 0) {\n\t\t\tconst currentAveragePagePoint = Vec.Average(\n\t\t\t\tmovingShapes.map((s) => this.editor.getShapePageTransform(s.id)!.point())\n\t\t\t)\n\t\t\tconst offset = Vec.Sub(currentAveragePagePoint, this.selectionSnapshot.averagePagePoint)\n\t\t\tif (!Vec.IsNaN(offset)) {\n\t\t\t\tthis.editor.updateInstanceState({\n\t\t\t\t\tduplicateProps: {\n\t\t\t\t\t\tshapeIds: movingShapes.map((s) => s.id),\n\t\t\t\t\t\toffset: { x: offset.x, y: offset.y },\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\t\tconst changes: TLShapePartial[] = []\n\n\t\tmovingShapes.forEach((shape) => {\n\t\t\tconst current = this.editor.getShape(shape.id)!\n\t\t\tconst util = this.editor.getShapeUtil(shape)\n\t\t\tconst change = util.onTranslateEnd?.(shape, current)\n\t\t\tif (change) {\n\t\t\t\tchanges.push(change)\n\t\t\t}\n\t\t})\n\n\t\tif (changes.length > 0) {\n\t\t\tthis.editor.updateShapes(changes)\n\t\t}\n\t}\n\n\tprotected updateShapes() {\n\t\tconst { snapshot } = this\n\n\t\t// We should have started already, but hey\n\t\tthis.dragAndDropManager.startDraggingShapes(\n\t\t\tsnapshot.movingShapes,\n\t\t\tthis.editor.inputs.originPagePoint,\n\t\t\tthis.updateParentTransforms\n\t\t)\n\n\t\tmoveShapesToPoint({\n\t\t\teditor: this.editor,\n\t\t\tsnapshot,\n\t\t})\n\n\t\tconst { movingShapes } = snapshot\n\n\t\tconst changes: TLShapePartial[] = []\n\n\t\tmovingShapes.forEach((shape) => {\n\t\t\tconst current = this.editor.getShape(shape.id)!\n\t\t\tconst util = this.editor.getShapeUtil(shape)\n\t\t\tconst change = util.onTranslate?.(shape, current)\n\t\t\tif (change) {\n\t\t\t\tchanges.push(change)\n\t\t\t}\n\t\t})\n\n\t\tif (changes.length > 0) {\n\t\t\tthis.editor.updateShapes(changes)\n\t\t}\n\t}\n\n\t@bind\n\tprotected updateParentTransforms() {\n\t\tconst {\n\t\t\teditor,\n\t\t\tsnapshot: { shapeSnapshots },\n\t\t} = this\n\t\tconst movingShapes: TLShape[] = []\n\n\t\tshapeSnapshots.forEach((shapeSnapshot) => {\n\t\t\tconst shape = editor.getShape(shapeSnapshot.shape.id)\n\t\t\tif (!shape) return null\n\t\t\tmovingShapes.push(shape)\n\n\t\t\tconst parentTransform = isPageId(shape.parentId)\n\t\t\t\t? null\n\t\t\t\t: Mat.Inverse(editor.getShapePageTransform(shape.parentId)!)\n\n\t\t\tshapeSnapshot.parentTransform = parentTransform\n\t\t})\n\t}\n}\n\nfunction getTranslatingSnapshot(editor: Editor) {\n\tconst movingShapes: TLShape[] = []\n\tconst pagePoints: Vec[] = []\n\n\tconst selectedShapeIds = editor.getSelectedShapeIds()\n\tconst shapeSnapshots = compact(\n\t\tselectedShapeIds.map((id): null | MovingShapeSnapshot => {\n\t\t\tconst shape = editor.getShape(id)\n\t\t\tif (!shape) return null\n\t\t\tmovingShapes.push(shape)\n\n\t\t\tconst pageTransform = editor.getShapePageTransform(id)\n\t\t\tconst pagePoint = pageTransform.point()\n\t\t\tconst pageRotation = pageTransform.rotation()\n\n\t\t\tpagePoints.push(pagePoint)\n\n\t\t\tconst parentTransform = PageRecordType.isId(shape.parentId)\n\t\t\t\t? null\n\t\t\t\t: Mat.Inverse(editor.getShapePageTransform(shape.parentId)!)\n\n\t\t\treturn {\n\t\t\t\tshape,\n\t\t\t\tpagePoint,\n\t\t\t\tpageRotation,\n\t\t\t\tparentTransform,\n\t\t\t}\n\t\t})\n\t)\n\n\tconst onlySelectedShape = editor.getOnlySelectedShape()\n\n\tlet initialSnapPoints: BoundsSnapPoint[] = []\n\n\tif (onlySelectedShape) {\n\t\tinitialSnapPoints = editor.snaps.shapeBounds.getSnapPoints(onlySelectedShape.id)!\n\t} else {\n\t\tconst selectionPageBounds = editor.getSelectionPageBounds()\n\t\tif (selectionPageBounds) {\n\t\t\tinitialSnapPoints = selectionPageBounds.cornersAndCenter.map((p, i) => ({\n\t\t\t\tid: 'selection:' + i,\n\t\t\t\tx: p.x,\n\t\t\t\ty: p.y,\n\t\t\t}))\n\t\t}\n\t}\n\n\tlet noteAdjacentPositions: Vec[] | undefined\n\tlet noteSnapshot: (MovingShapeSnapshot & { shape: TLNoteShape }) | undefined\n\n\tconst { originPagePoint } = editor.inputs\n\n\tconst allHoveredNotes = shapeSnapshots.filter(\n\t\t(s) =>\n\t\t\teditor.isShapeOfType<TLNoteShape>(s.shape, 'note') &&\n\t\t\teditor.isPointInShape(s.shape, originPagePoint)\n\t) as (MovingShapeSnapshot & { shape: TLNoteShape })[]\n\n\tif (allHoveredNotes.length === 0) {\n\t\t// noop\n\t} else if (allHoveredNotes.length === 1) {\n\t\t// just one, easy\n\t\tnoteSnapshot = allHoveredNotes[0]\n\t} else {\n\t\t// More than one under the cursor, so we need to find the highest shape in z-order\n\t\tconst allShapesSorted = editor.getCurrentPageShapesSorted()\n\t\tnoteSnapshot = allHoveredNotes\n\t\t\t.map((s) => ({\n\t\t\t\tsnapshot: s,\n\t\t\t\tindex: allShapesSorted.findIndex((shape) => shape.id === s.shape.id),\n\t\t\t}))\n\t\t\t.sort((a, b) => b.index - a.index)[0]?.snapshot // highest up first\n\t}\n\n\tif (noteSnapshot) {\n\t\tnoteAdjacentPositions = getAvailableNoteAdjacentPositions(\n\t\t\teditor,\n\t\t\tnoteSnapshot.pageRotation,\n\t\t\tnoteSnapshot.shape.props.scale,\n\t\t\tnoteSnapshot.shape.props.growY ?? 0\n\t\t)\n\t}\n\n\treturn {\n\t\taveragePagePoint: Vec.Average(pagePoints),\n\t\tmovingShapes,\n\t\tshapeSnapshots,\n\t\tinitialPageBounds: editor.getSelectionPageBounds()!,\n\t\tinitialSnapPoints,\n\t\tnoteAdjacentPositions,\n\t\tnoteSnapshot,\n\t}\n}\n\nexport type TranslatingSnapshot = ReturnType<typeof getTranslatingSnapshot>\n\nexport interface MovingShapeSnapshot {\n\tshape: TLShape\n\tpagePoint: Vec\n\tpageRotation: number\n\tparentTransform: MatModel | null\n}\n\nexport function moveShapesToPoint({\n\teditor,\n\tsnapshot,\n}: {\n\teditor: Editor\n\tsnapshot: TranslatingSnapshot\n}) {\n\tconst { inputs } = editor\n\n\tconst {\n\t\tnoteSnapshot,\n\t\tnoteAdjacentPositions,\n\t\tinitialPageBounds,\n\t\tinitialSnapPoints,\n\t\tshapeSnapshots,\n\t\taveragePagePoint,\n\t} = snapshot\n\n\tconst isGridMode = editor.getInstanceState().isGridMode\n\n\tconst gridSize = editor.getDocumentSettings().gridSize\n\n\tconst delta = Vec.Sub(inputs.currentPagePoint, inputs.originPagePoint)\n\n\tconst flatten: 'x' | 'y' | null = editor.inputs.shiftKey\n\t\t? Math.abs(delta.x) < Math.abs(delta.y)\n\t\t\t? 'x'\n\t\t\t: 'y'\n\t\t: null\n\n\tif (flatten === 'x') {\n\t\tdelta.x = 0\n\t} else if (flatten === 'y') {\n\t\tdelta.y = 0\n\t}\n\n\t// Provisional snapping\n\teditor.snaps.clearIndicators()\n\n\t// If the user isn't moving super quick\n\tconst isSnapping = editor.user.getIsSnapMode() ? !inputs.ctrlKey : inputs.ctrlKey\n\tlet snappedToPit = false\n\tif (isSnapping && editor.inputs.pointerVelocity.len() < 0.5) {\n\t\t// snapping\n\t\tconst { nudge } = editor.snaps.shapeBounds.snapTranslateShapes({\n\t\t\tdragDelta: delta,\n\t\t\tinitialSelectionPageBounds: initialPageBounds,\n\t\t\tlockedAxis: flatten,\n\t\t\tinitialSelectionSnapPoints: initialSnapPoints,\n\t\t})\n\n\t\tdelta.add(nudge)\n\t} else {\n\t\t// for sticky notes, snap to grid position next to other notes\n\t\tif (noteSnapshot && noteAdjacentPositions) {\n\t\t\tconst { scale } = noteSnapshot.shape.props\n\t\t\tconst pageCenter = noteSnapshot.pagePoint\n\t\t\t\t.clone()\n\t\t\t\t.add(delta)\n\t\t\t\t// use the middle of the note, disregarding extra height\n\t\t\t\t.add(NOTE_CENTER_OFFSET.clone().mul(scale).rot(noteSnapshot.pageRotation))\n\n\t\t\t// Find the pit with the center closest to the put center\n\t\t\tlet min = NOTE_ADJACENT_POSITION_SNAP_RADIUS / editor.getZoomLevel() // in screen space\n\t\t\tlet offset = new Vec(0, 0)\n\t\t\tfor (const pit of noteAdjacentPositions) {\n\t\t\t\t// We've already filtered pits with the same page rotation\n\t\t\t\tconst deltaToPit = Vec.Sub(pageCenter, pit)\n\t\t\t\tconst dist = deltaToPit.len()\n\t\t\t\tif (dist < min) {\n\t\t\t\t\tsnappedToPit = true\n\t\t\t\t\tmin = dist\n\t\t\t\t\toffset = deltaToPit\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tdelta.sub(offset)\n\t\t}\n\t}\n\n\tconst averageSnappedPoint = Vec.Add(averagePagePoint, delta)\n\n\t// we don't want to snap to the grid if we're holding the ctrl key, if we've already snapped into a pit, or if we're showing snapping indicators\n\tconst snapIndicators = editor.snaps.getIndicators()\n\tif (isGridMode && !inputs.ctrlKey && !snappedToPit && snapIndicators.length === 0) {\n\t\taverageSnappedPoint.snapToGrid(gridSize)\n\t}\n\n\tconst averageSnap = Vec.Sub(averageSnappedPoint, averagePagePoint)\n\n\teditor.updateShapes(\n\t\tcompact(\n\t\t\tshapeSnapshots.map(({ shape, pagePoint, parentTransform }): TLShapePartial | null => {\n\t\t\t\tconst newPagePoint = Vec.Add(pagePoint, averageSnap)\n\n\t\t\t\tconst newLocalPoint = parentTransform\n\t\t\t\t\t? Mat.applyToPoint(parentTransform, newPagePoint)\n\t\t\t\t\t: newPagePoint\n\n\t\t\t\treturn {\n\t\t\t\t\tid: shape.id,\n\t\t\t\t\ttype: shape.type,\n\t\t\t\t\tx: newLocalPoint.x,\n\t\t\t\t\ty: newLocalPoint.y,\n\t\t\t\t}\n\t\t\t})\n\t\t)\n\t)\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA,EAGC;AAAA,EAEA;AAAA,EACA;AAAA,EAMA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AACP;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,OACM;AACP,SAAS,0BAA0B;
|
|
4
|
+
"sourcesContent": ["import {\n\tBoundsSnapPoint,\n\tEditor,\n\tMat,\n\tMatModel,\n\tPageRecordType,\n\tStateNode,\n\tTLNoteShape,\n\tTLPointerEventInfo,\n\tTLShape,\n\tTLShapePartial,\n\tTLTickEventInfo,\n\tVec,\n\tbind,\n\tcompact,\n\tisPageId,\n\tkickoutOccludedShapes,\n} from '@tldraw/editor'\nimport {\n\tNOTE_ADJACENT_POSITION_SNAP_RADIUS,\n\tNOTE_CENTER_OFFSET,\n\tgetAvailableNoteAdjacentPositions,\n} from '../../../shapes/note/noteHelpers'\nimport { DragAndDropManager } from '../DragAndDropManager'\n\nexport type TranslatingInfo = TLPointerEventInfo & {\n\ttarget: 'shape'\n\tisCreating?: boolean\n\tcreatingMarkId?: string\n\tonCreate?(): void\n\tonInteractionEnd?: string\n}\n\nexport class Translating extends StateNode {\n\tstatic override id = 'translating'\n\n\tinfo = {} as TranslatingInfo\n\n\tselectionSnapshot: TranslatingSnapshot = {} as any\n\n\tsnapshot: TranslatingSnapshot = {} as any\n\n\tmarkId = ''\n\n\tisCloning = false\n\tisCreating = false\n\tonCreate(_shape: TLShape | null): void {\n\t\treturn\n\t}\n\n\tdragAndDropManager = new DragAndDropManager(this.editor)\n\n\toverride onEnter(info: TranslatingInfo) {\n\t\tconst { isCreating = false, creatingMarkId, onCreate = () => void null } = info\n\n\t\tif (!this.editor.getSelectedShapeIds()?.length) {\n\t\t\tthis.parent.transition('idle')\n\t\t\treturn\n\t\t}\n\n\t\tthis.info = info\n\t\tthis.parent.setCurrentToolIdMask(info.onInteractionEnd)\n\t\tthis.isCreating = isCreating\n\n\t\tthis.markId = ''\n\n\t\tif (isCreating) {\n\t\t\tif (creatingMarkId) {\n\t\t\t\tthis.markId = creatingMarkId\n\t\t\t} else {\n\t\t\t\t// handle legacy implicit `creating:{shapeId}` marks\n\t\t\t\tconst markId = this.editor.getMarkIdMatching(\n\t\t\t\t\t`creating:${this.editor.getOnlySelectedShapeId()}`\n\t\t\t\t)\n\t\t\t\tif (markId) {\n\t\t\t\t\tthis.markId = markId\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tthis.markId = this.editor.markHistoryStoppingPoint('translating')\n\t\t}\n\n\t\tthis.onCreate = onCreate\n\n\t\tthis.isCloning = false\n\t\tthis.info = info\n\n\t\tthis.editor.setCursor({ type: 'move', rotation: 0 })\n\t\tthis.selectionSnapshot = getTranslatingSnapshot(this.editor)\n\n\t\t// Don't clone on create; otherwise clone on altKey\n\t\tif (!this.isCreating) {\n\t\t\tif (this.editor.inputs.altKey) {\n\t\t\t\tthis.startCloning()\n\t\t\t\tif (this.isCloning) return\n\t\t\t}\n\t\t}\n\n\t\tthis.snapshot = this.selectionSnapshot\n\t\tthis.handleStart()\n\t\tthis.updateShapes()\n\t}\n\n\toverride onExit() {\n\t\tthis.parent.setCurrentToolIdMask(undefined)\n\t\tthis.selectionSnapshot = {} as any\n\t\tthis.snapshot = {} as any\n\t\tthis.editor.snaps.clearIndicators()\n\t\tthis.editor.setCursor({ type: 'default', rotation: 0 })\n\t\tthis.dragAndDropManager.clear()\n\t}\n\n\toverride onTick({ elapsed }: TLTickEventInfo) {\n\t\tconst { editor } = this\n\t\teditor.edgeScrollManager.updateEdgeScrolling(elapsed)\n\t}\n\n\toverride onPointerMove() {\n\t\tthis.updateShapes()\n\t}\n\n\toverride onKeyDown() {\n\t\tif (this.editor.inputs.altKey && !this.isCloning) {\n\t\t\tthis.startCloning()\n\t\t\tif (this.isCloning) return\n\t\t}\n\n\t\t// need to update in case user pressed a different modifier key\n\t\tthis.updateShapes()\n\t}\n\n\toverride onKeyUp() {\n\t\tif (!this.editor.inputs.altKey && this.isCloning) {\n\t\t\tthis.stopCloning()\n\t\t\treturn\n\t\t}\n\n\t\t// need to update in case user pressed a different modifier key\n\t\tthis.updateShapes()\n\t}\n\n\toverride onPointerUp() {\n\t\tthis.complete()\n\t}\n\n\toverride onComplete() {\n\t\tthis.complete()\n\t}\n\n\toverride onCancel() {\n\t\tthis.cancel()\n\t}\n\n\tprotected startCloning() {\n\t\tif (this.isCreating) return\n\t\tconst shapeIds = Array.from(this.editor.getSelectedShapeIds())\n\n\t\t// If we can't create the shapes, don't even start cloning\n\t\tif (!this.editor.canCreateShapes(shapeIds)) return\n\n\t\tthis.isCloning = true\n\t\tthis.reset()\n\t\tthis.markId = this.editor.markHistoryStoppingPoint('translate cloning')\n\n\t\tthis.editor.duplicateShapes(Array.from(this.editor.getSelectedShapeIds()))\n\n\t\tthis.snapshot = getTranslatingSnapshot(this.editor)\n\t\tthis.handleStart()\n\t\tthis.updateShapes()\n\t}\n\n\tprotected stopCloning() {\n\t\tthis.isCloning = false\n\t\tthis.snapshot = this.selectionSnapshot\n\t\tthis.reset()\n\t\tthis.markId = this.editor.markHistoryStoppingPoint('translate')\n\t\tthis.updateShapes()\n\t}\n\n\treset() {\n\t\tthis.editor.bailToMark(this.markId)\n\t}\n\n\tprotected complete() {\n\t\tthis.updateShapes()\n\t\tthis.dragAndDropManager.dropShapes(this.snapshot.movingShapes)\n\t\tthis.handleEnd()\n\t\tkickoutOccludedShapes(\n\t\t\tthis.editor,\n\t\t\tthis.snapshot.movingShapes.map((s) => s.id)\n\t\t)\n\n\t\tif (this.editor.getInstanceState().isToolLocked && this.info.onInteractionEnd) {\n\t\t\tthis.editor.setCurrentTool(this.info.onInteractionEnd)\n\t\t} else {\n\t\t\tif (this.isCreating) {\n\t\t\t\tthis.onCreate?.(this.editor.getOnlySelectedShape())\n\t\t\t} else {\n\t\t\t\tthis.parent.transition('idle')\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate cancel() {\n\t\t// Call onTranslateCancel callback before resetting\n\t\tconst { movingShapes } = this.snapshot\n\n\t\tmovingShapes.forEach((shape) => {\n\t\t\tconst current = this.editor.getShape(shape.id)\n\t\t\tif (current) {\n\t\t\t\tconst util = this.editor.getShapeUtil(shape)\n\t\t\t\tutil.onTranslateCancel?.(shape, current)\n\t\t\t}\n\t\t})\n\n\t\tthis.reset()\n\t\tif (this.info.onInteractionEnd) {\n\t\t\tthis.editor.setCurrentTool(this.info.onInteractionEnd)\n\t\t} else {\n\t\t\tthis.parent.transition('idle', this.info)\n\t\t}\n\t}\n\n\tprotected handleStart() {\n\t\tconst { movingShapes } = this.snapshot\n\n\t\tconst changes: TLShapePartial[] = []\n\n\t\tmovingShapes.forEach((shape) => {\n\t\t\tconst util = this.editor.getShapeUtil(shape)\n\t\t\tconst change = util.onTranslateStart?.(shape)\n\t\t\tif (change) {\n\t\t\t\tchanges.push(change)\n\t\t\t}\n\t\t})\n\n\t\tif (changes.length > 0) {\n\t\t\tthis.editor.updateShapes(changes)\n\t\t}\n\n\t\tthis.dragAndDropManager.startDraggingShapes(\n\t\t\t// Get fresh shapes from the snapshot, in case onTranslateStart mutates the shape\n\t\t\tcompact(this.snapshot.movingShapes.map((s) => this.editor.getShape(s.id))),\n\t\t\t// Start from the place where the user started dragging\n\t\t\tthis.editor.inputs.originPagePoint,\n\t\t\tthis.updateParentTransforms\n\t\t)\n\n\t\tthis.editor.setHoveredShape(null)\n\t}\n\n\tprotected handleEnd() {\n\t\tconst { movingShapes } = this.snapshot\n\n\t\tif (this.isCloning && movingShapes.length > 0) {\n\t\t\tconst currentAveragePagePoint = Vec.Average(\n\t\t\t\tmovingShapes.map((s) => this.editor.getShapePageTransform(s.id)!.point())\n\t\t\t)\n\t\t\tconst offset = Vec.Sub(currentAveragePagePoint, this.selectionSnapshot.averagePagePoint)\n\t\t\tif (!Vec.IsNaN(offset)) {\n\t\t\t\tthis.editor.updateInstanceState({\n\t\t\t\t\tduplicateProps: {\n\t\t\t\t\t\tshapeIds: movingShapes.map((s) => s.id),\n\t\t\t\t\t\toffset: { x: offset.x, y: offset.y },\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\t\tconst changes: TLShapePartial[] = []\n\n\t\tmovingShapes.forEach((shape) => {\n\t\t\tconst current = this.editor.getShape(shape.id)!\n\t\t\tconst util = this.editor.getShapeUtil(shape)\n\t\t\tconst change = util.onTranslateEnd?.(shape, current)\n\t\t\tif (change) {\n\t\t\t\tchanges.push(change)\n\t\t\t}\n\t\t})\n\n\t\tif (changes.length > 0) {\n\t\t\tthis.editor.updateShapes(changes)\n\t\t}\n\t}\n\n\tprotected updateShapes() {\n\t\tconst { snapshot } = this\n\n\t\t// We should have started already, but hey\n\t\tthis.dragAndDropManager.startDraggingShapes(\n\t\t\tsnapshot.movingShapes,\n\t\t\tthis.editor.inputs.originPagePoint,\n\t\t\tthis.updateParentTransforms\n\t\t)\n\n\t\tmoveShapesToPoint({\n\t\t\teditor: this.editor,\n\t\t\tsnapshot,\n\t\t})\n\n\t\tconst { movingShapes } = snapshot\n\n\t\tconst changes: TLShapePartial[] = []\n\n\t\tmovingShapes.forEach((shape) => {\n\t\t\tconst current = this.editor.getShape(shape.id)!\n\t\t\tconst util = this.editor.getShapeUtil(shape)\n\t\t\tconst change = util.onTranslate?.(shape, current)\n\t\t\tif (change) {\n\t\t\t\tchanges.push(change)\n\t\t\t}\n\t\t})\n\n\t\tif (changes.length > 0) {\n\t\t\tthis.editor.updateShapes(changes)\n\t\t}\n\t}\n\n\t@bind\n\tprotected updateParentTransforms() {\n\t\tconst {\n\t\t\teditor,\n\t\t\tsnapshot: { shapeSnapshots },\n\t\t} = this\n\t\tconst movingShapes: TLShape[] = []\n\n\t\tshapeSnapshots.forEach((shapeSnapshot) => {\n\t\t\tconst shape = editor.getShape(shapeSnapshot.shape.id)\n\t\t\tif (!shape) return null\n\t\t\tmovingShapes.push(shape)\n\n\t\t\tconst parentTransform = isPageId(shape.parentId)\n\t\t\t\t? null\n\t\t\t\t: Mat.Inverse(editor.getShapePageTransform(shape.parentId)!)\n\n\t\t\tshapeSnapshot.parentTransform = parentTransform\n\t\t})\n\t}\n}\n\nfunction getTranslatingSnapshot(editor: Editor) {\n\tconst movingShapes: TLShape[] = []\n\tconst pagePoints: Vec[] = []\n\n\tconst selectedShapeIds = editor.getSelectedShapeIds()\n\tconst shapeSnapshots = compact(\n\t\tselectedShapeIds.map((id): null | MovingShapeSnapshot => {\n\t\t\tconst shape = editor.getShape(id)\n\t\t\tif (!shape) return null\n\t\t\tmovingShapes.push(shape)\n\n\t\t\tconst pageTransform = editor.getShapePageTransform(id)\n\t\t\tconst pagePoint = pageTransform.point()\n\t\t\tconst pageRotation = pageTransform.rotation()\n\n\t\t\tpagePoints.push(pagePoint)\n\n\t\t\tconst parentTransform = PageRecordType.isId(shape.parentId)\n\t\t\t\t? null\n\t\t\t\t: Mat.Inverse(editor.getShapePageTransform(shape.parentId)!)\n\n\t\t\treturn {\n\t\t\t\tshape,\n\t\t\t\tpagePoint,\n\t\t\t\tpageRotation,\n\t\t\t\tparentTransform,\n\t\t\t}\n\t\t})\n\t)\n\n\tconst onlySelectedShape = editor.getOnlySelectedShape()\n\n\tlet initialSnapPoints: BoundsSnapPoint[] = []\n\n\tif (onlySelectedShape) {\n\t\tinitialSnapPoints = editor.snaps.shapeBounds.getSnapPoints(onlySelectedShape.id)!\n\t} else {\n\t\tconst selectionPageBounds = editor.getSelectionPageBounds()\n\t\tif (selectionPageBounds) {\n\t\t\tinitialSnapPoints = selectionPageBounds.cornersAndCenter.map((p, i) => ({\n\t\t\t\tid: 'selection:' + i,\n\t\t\t\tx: p.x,\n\t\t\t\ty: p.y,\n\t\t\t}))\n\t\t}\n\t}\n\n\tlet noteAdjacentPositions: Vec[] | undefined\n\tlet noteSnapshot: (MovingShapeSnapshot & { shape: TLNoteShape }) | undefined\n\n\tconst { originPagePoint } = editor.inputs\n\n\tconst allHoveredNotes = shapeSnapshots.filter(\n\t\t(s) =>\n\t\t\teditor.isShapeOfType<TLNoteShape>(s.shape, 'note') &&\n\t\t\teditor.isPointInShape(s.shape, originPagePoint)\n\t) as (MovingShapeSnapshot & { shape: TLNoteShape })[]\n\n\tif (allHoveredNotes.length === 0) {\n\t\t// noop\n\t} else if (allHoveredNotes.length === 1) {\n\t\t// just one, easy\n\t\tnoteSnapshot = allHoveredNotes[0]\n\t} else {\n\t\t// More than one under the cursor, so we need to find the highest shape in z-order\n\t\tconst allShapesSorted = editor.getCurrentPageShapesSorted()\n\t\tnoteSnapshot = allHoveredNotes\n\t\t\t.map((s) => ({\n\t\t\t\tsnapshot: s,\n\t\t\t\tindex: allShapesSorted.findIndex((shape) => shape.id === s.shape.id),\n\t\t\t}))\n\t\t\t.sort((a, b) => b.index - a.index)[0]?.snapshot // highest up first\n\t}\n\n\tif (noteSnapshot) {\n\t\tnoteAdjacentPositions = getAvailableNoteAdjacentPositions(\n\t\t\teditor,\n\t\t\tnoteSnapshot.pageRotation,\n\t\t\tnoteSnapshot.shape.props.scale,\n\t\t\tnoteSnapshot.shape.props.growY ?? 0\n\t\t)\n\t}\n\n\treturn {\n\t\taveragePagePoint: Vec.Average(pagePoints),\n\t\tmovingShapes,\n\t\tshapeSnapshots,\n\t\tinitialPageBounds: editor.getSelectionPageBounds()!,\n\t\tinitialSnapPoints,\n\t\tnoteAdjacentPositions,\n\t\tnoteSnapshot,\n\t}\n}\n\nexport type TranslatingSnapshot = ReturnType<typeof getTranslatingSnapshot>\n\nexport interface MovingShapeSnapshot {\n\tshape: TLShape\n\tpagePoint: Vec\n\tpageRotation: number\n\tparentTransform: MatModel | null\n}\n\nexport function moveShapesToPoint({\n\teditor,\n\tsnapshot,\n}: {\n\teditor: Editor\n\tsnapshot: TranslatingSnapshot\n}) {\n\tconst { inputs } = editor\n\n\tconst {\n\t\tnoteSnapshot,\n\t\tnoteAdjacentPositions,\n\t\tinitialPageBounds,\n\t\tinitialSnapPoints,\n\t\tshapeSnapshots,\n\t\taveragePagePoint,\n\t} = snapshot\n\n\tconst isGridMode = editor.getInstanceState().isGridMode\n\n\tconst gridSize = editor.getDocumentSettings().gridSize\n\n\tconst delta = Vec.Sub(inputs.currentPagePoint, inputs.originPagePoint)\n\n\tconst flatten: 'x' | 'y' | null = editor.inputs.shiftKey\n\t\t? Math.abs(delta.x) < Math.abs(delta.y)\n\t\t\t? 'x'\n\t\t\t: 'y'\n\t\t: null\n\n\tif (flatten === 'x') {\n\t\tdelta.x = 0\n\t} else if (flatten === 'y') {\n\t\tdelta.y = 0\n\t}\n\n\t// Provisional snapping\n\teditor.snaps.clearIndicators()\n\n\t// If the user isn't moving super quick\n\tconst isSnapping = editor.user.getIsSnapMode() ? !inputs.ctrlKey : inputs.ctrlKey\n\tlet snappedToPit = false\n\tif (isSnapping && editor.inputs.pointerVelocity.len() < 0.5) {\n\t\t// snapping\n\t\tconst { nudge } = editor.snaps.shapeBounds.snapTranslateShapes({\n\t\t\tdragDelta: delta,\n\t\t\tinitialSelectionPageBounds: initialPageBounds,\n\t\t\tlockedAxis: flatten,\n\t\t\tinitialSelectionSnapPoints: initialSnapPoints,\n\t\t})\n\n\t\tdelta.add(nudge)\n\t} else {\n\t\t// for sticky notes, snap to grid position next to other notes\n\t\tif (noteSnapshot && noteAdjacentPositions) {\n\t\t\tconst { scale } = noteSnapshot.shape.props\n\t\t\tconst pageCenter = noteSnapshot.pagePoint\n\t\t\t\t.clone()\n\t\t\t\t.add(delta)\n\t\t\t\t// use the middle of the note, disregarding extra height\n\t\t\t\t.add(NOTE_CENTER_OFFSET.clone().mul(scale).rot(noteSnapshot.pageRotation))\n\n\t\t\t// Find the pit with the center closest to the put center\n\t\t\tlet min = NOTE_ADJACENT_POSITION_SNAP_RADIUS / editor.getZoomLevel() // in screen space\n\t\t\tlet offset = new Vec(0, 0)\n\t\t\tfor (const pit of noteAdjacentPositions) {\n\t\t\t\t// We've already filtered pits with the same page rotation\n\t\t\t\tconst deltaToPit = Vec.Sub(pageCenter, pit)\n\t\t\t\tconst dist = deltaToPit.len()\n\t\t\t\tif (dist < min) {\n\t\t\t\t\tsnappedToPit = true\n\t\t\t\t\tmin = dist\n\t\t\t\t\toffset = deltaToPit\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tdelta.sub(offset)\n\t\t}\n\t}\n\n\tconst averageSnappedPoint = Vec.Add(averagePagePoint, delta)\n\n\t// we don't want to snap to the grid if we're holding the ctrl key, if we've already snapped into a pit, or if we're showing snapping indicators\n\tconst snapIndicators = editor.snaps.getIndicators()\n\tif (isGridMode && !inputs.ctrlKey && !snappedToPit && snapIndicators.length === 0) {\n\t\taverageSnappedPoint.snapToGrid(gridSize)\n\t}\n\n\tconst averageSnap = Vec.Sub(averageSnappedPoint, averagePagePoint)\n\n\teditor.updateShapes(\n\t\tcompact(\n\t\t\tshapeSnapshots.map(({ shape, pagePoint, parentTransform }): TLShapePartial | null => {\n\t\t\t\tconst newPagePoint = Vec.Add(pagePoint, averageSnap)\n\n\t\t\t\tconst newLocalPoint = parentTransform\n\t\t\t\t\t? Mat.applyToPoint(parentTransform, newPagePoint)\n\t\t\t\t\t: newPagePoint\n\n\t\t\t\treturn {\n\t\t\t\t\tid: shape.id,\n\t\t\t\t\ttype: shape.type,\n\t\t\t\t\tx: newLocalPoint.x,\n\t\t\t\t\ty: newLocalPoint.y,\n\t\t\t\t}\n\t\t\t})\n\t\t)\n\t)\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
exhaustiveSwitchError,
|
|
4
|
+
getPointerInfo,
|
|
5
|
+
preventDefault,
|
|
6
|
+
useEditor,
|
|
7
|
+
Vec
|
|
8
|
+
} from "@tldraw/editor";
|
|
3
9
|
import { ContextMenu as _ContextMenu } from "radix-ui";
|
|
4
|
-
import { useState } from "react";
|
|
10
|
+
import { useMemo, useState } from "react";
|
|
5
11
|
import { unwrapLabel } from "../../../context/actions.mjs";
|
|
6
12
|
import { useReadonly } from "../../../hooks/useReadonly.mjs";
|
|
7
13
|
import { useTranslation } from "../../../hooks/useTranslation/useTranslation.mjs";
|
|
@@ -25,7 +31,8 @@ function TldrawUiMenuItem({
|
|
|
25
31
|
iconLeft,
|
|
26
32
|
onSelect,
|
|
27
33
|
noClose,
|
|
28
|
-
isSelected
|
|
34
|
+
isSelected,
|
|
35
|
+
onDragStart
|
|
29
36
|
}) {
|
|
30
37
|
const { type: menuType, sourceId } = useTldrawUiMenuContext();
|
|
31
38
|
const msg = useTranslation();
|
|
@@ -139,6 +146,21 @@ function TldrawUiMenuItem({
|
|
|
139
146
|
] });
|
|
140
147
|
}
|
|
141
148
|
case "toolbar": {
|
|
149
|
+
if (onDragStart) {
|
|
150
|
+
return /* @__PURE__ */ jsx(
|
|
151
|
+
DraggableToolbarButton,
|
|
152
|
+
{
|
|
153
|
+
id,
|
|
154
|
+
icon,
|
|
155
|
+
onSelect,
|
|
156
|
+
onDragStart,
|
|
157
|
+
labelToUse,
|
|
158
|
+
titleStr,
|
|
159
|
+
disabled,
|
|
160
|
+
isSelected
|
|
161
|
+
}
|
|
162
|
+
);
|
|
163
|
+
}
|
|
142
164
|
return /* @__PURE__ */ jsx(
|
|
143
165
|
TldrawUiToolbarButton,
|
|
144
166
|
{
|
|
@@ -159,6 +181,22 @@ function TldrawUiMenuItem({
|
|
|
159
181
|
);
|
|
160
182
|
}
|
|
161
183
|
case "toolbar-overflow": {
|
|
184
|
+
if (onDragStart) {
|
|
185
|
+
return /* @__PURE__ */ jsx(
|
|
186
|
+
DraggableToolbarButton,
|
|
187
|
+
{
|
|
188
|
+
id,
|
|
189
|
+
icon,
|
|
190
|
+
onSelect,
|
|
191
|
+
onDragStart,
|
|
192
|
+
labelToUse,
|
|
193
|
+
titleStr,
|
|
194
|
+
disabled,
|
|
195
|
+
isSelected,
|
|
196
|
+
overflow: true
|
|
197
|
+
}
|
|
198
|
+
);
|
|
199
|
+
}
|
|
162
200
|
return /* @__PURE__ */ jsx(
|
|
163
201
|
TldrawUiToolbarButton,
|
|
164
202
|
{
|
|
@@ -181,6 +219,122 @@ function TldrawUiMenuItem({
|
|
|
181
219
|
}
|
|
182
220
|
}
|
|
183
221
|
}
|
|
222
|
+
function useDraggableEvents(onDragStart, onSelect) {
|
|
223
|
+
const editor = useEditor();
|
|
224
|
+
const events = useMemo(() => {
|
|
225
|
+
let state = { name: "idle" };
|
|
226
|
+
function handlePointerDown(e) {
|
|
227
|
+
state = {
|
|
228
|
+
name: "pointing",
|
|
229
|
+
start: editor.inputs.currentPagePoint.clone()
|
|
230
|
+
};
|
|
231
|
+
e.currentTarget.setPointerCapture(e.pointerId);
|
|
232
|
+
}
|
|
233
|
+
function handlePointerMove(e) {
|
|
234
|
+
if (e.isSpecialRedispatchedEvent) return;
|
|
235
|
+
if (state.name === "pointing") {
|
|
236
|
+
const distance = Vec.Dist2(state.start, editor.inputs.currentPagePoint);
|
|
237
|
+
if (distance > (editor.getInstanceState().isCoarsePointer ? editor.options.coarseDragDistanceSquared : editor.options.dragDistanceSquared)) {
|
|
238
|
+
const start = state.start;
|
|
239
|
+
state = {
|
|
240
|
+
name: "dragging",
|
|
241
|
+
start
|
|
242
|
+
};
|
|
243
|
+
editor.run(() => {
|
|
244
|
+
editor.dispatch({
|
|
245
|
+
type: "pointer",
|
|
246
|
+
target: "canvas",
|
|
247
|
+
name: "pointer_down",
|
|
248
|
+
...getPointerInfo(e),
|
|
249
|
+
point: start
|
|
250
|
+
});
|
|
251
|
+
editor.selectNone();
|
|
252
|
+
onDragStart?.("toolbar", {
|
|
253
|
+
type: "pointer",
|
|
254
|
+
target: "canvas",
|
|
255
|
+
name: "pointer_move",
|
|
256
|
+
...getPointerInfo(e)
|
|
257
|
+
});
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
function handlePointerUp(e) {
|
|
263
|
+
if (e.isSpecialRedispatchedEvent) return;
|
|
264
|
+
e.currentTarget.releasePointerCapture(e.pointerId);
|
|
265
|
+
editor.dispatch({
|
|
266
|
+
type: "pointer",
|
|
267
|
+
target: "canvas",
|
|
268
|
+
name: "pointer_up",
|
|
269
|
+
...getPointerInfo(e)
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
function handleClick() {
|
|
273
|
+
if (state.name === "dragging" || state.name === "dragged") {
|
|
274
|
+
state = { name: "idle" };
|
|
275
|
+
return true;
|
|
276
|
+
}
|
|
277
|
+
state = { name: "idle" };
|
|
278
|
+
onSelect?.("toolbar");
|
|
279
|
+
}
|
|
280
|
+
return {
|
|
281
|
+
onPointerDown: handlePointerDown,
|
|
282
|
+
onPointerMove: handlePointerMove,
|
|
283
|
+
onPointerUp: handlePointerUp,
|
|
284
|
+
onClick: handleClick
|
|
285
|
+
};
|
|
286
|
+
}, [onDragStart, editor, onSelect]);
|
|
287
|
+
return events;
|
|
288
|
+
}
|
|
289
|
+
function DraggableToolbarButton({
|
|
290
|
+
id,
|
|
291
|
+
labelToUse,
|
|
292
|
+
titleStr,
|
|
293
|
+
disabled,
|
|
294
|
+
isSelected,
|
|
295
|
+
icon,
|
|
296
|
+
onSelect,
|
|
297
|
+
onDragStart,
|
|
298
|
+
overflow
|
|
299
|
+
}) {
|
|
300
|
+
const events = useDraggableEvents(onDragStart, onSelect);
|
|
301
|
+
if (overflow) {
|
|
302
|
+
return /* @__PURE__ */ jsx(
|
|
303
|
+
TldrawUiToolbarButton,
|
|
304
|
+
{
|
|
305
|
+
"aria-label": labelToUse,
|
|
306
|
+
"aria-pressed": isSelected ? "true" : "false",
|
|
307
|
+
isActive: isSelected,
|
|
308
|
+
className: "tlui-button-grid__button",
|
|
309
|
+
"data-testid": `tools.more.${id}`,
|
|
310
|
+
"data-value": id,
|
|
311
|
+
disabled,
|
|
312
|
+
title: titleStr,
|
|
313
|
+
type: "icon",
|
|
314
|
+
...events,
|
|
315
|
+
children: /* @__PURE__ */ jsx(TldrawUiButtonIcon, { icon })
|
|
316
|
+
}
|
|
317
|
+
);
|
|
318
|
+
}
|
|
319
|
+
return /* @__PURE__ */ jsx(
|
|
320
|
+
TldrawUiToolbarButton,
|
|
321
|
+
{
|
|
322
|
+
"aria-label": labelToUse,
|
|
323
|
+
"aria-pressed": isSelected ? "true" : "false",
|
|
324
|
+
"data-testid": `tools.${id}`,
|
|
325
|
+
"data-value": id,
|
|
326
|
+
disabled,
|
|
327
|
+
onTouchStart: (e) => {
|
|
328
|
+
preventDefault(e);
|
|
329
|
+
onSelect("toolbar");
|
|
330
|
+
},
|
|
331
|
+
title: titleStr,
|
|
332
|
+
type: "tool",
|
|
333
|
+
...events,
|
|
334
|
+
children: /* @__PURE__ */ jsx(TldrawUiButtonIcon, { icon })
|
|
335
|
+
}
|
|
336
|
+
);
|
|
337
|
+
}
|
|
184
338
|
export {
|
|
185
339
|
TldrawUiMenuItem
|
|
186
340
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../src/lib/ui/components/primitives/menus/TldrawUiMenuItem.tsx"],
|
|
4
|
-
"sourcesContent": ["import { exhaustiveSwitchError, preventDefault } from '@tldraw/editor'\nimport { ContextMenu as _ContextMenu } from 'radix-ui'\nimport { useState } from 'react'\nimport { unwrapLabel } from '../../../context/actions'\nimport { TLUiEventSource } from '../../../context/events'\nimport { useReadonly } from '../../../hooks/useReadonly'\nimport { TLUiTranslationKey } from '../../../hooks/useTranslation/TLUiTranslationKey'\nimport { useTranslation } from '../../../hooks/useTranslation/useTranslation'\nimport { kbdStr } from '../../../kbd-utils'\nimport { Spinner } from '../../Spinner'\nimport { TldrawUiButton } from '../Button/TldrawUiButton'\nimport { TldrawUiButtonIcon } from '../Button/TldrawUiButtonIcon'\nimport { TldrawUiButtonLabel } from '../Button/TldrawUiButtonLabel'\nimport { TldrawUiDropdownMenuItem } from '../TldrawUiDropdownMenu'\nimport { TLUiIconJsx } from '../TldrawUiIcon'\nimport { TldrawUiKbd } from '../TldrawUiKbd'\nimport { TldrawUiToolbarButton } from '../TldrawUiToolbar'\nimport { useTldrawUiMenuContext } from './TldrawUiMenuContext'\n\n/** @public */\nexport interface TLUiMenuItemProps<\n\tTranslationKey extends string = string,\n\tIconType extends string = string,\n> {\n\tid: string\n\t/**\n\t * The icon to display on the item. Icons are only shown in certain menu types.\n\t */\n\ticon?: IconType | TLUiIconJsx\n\t/**\n\t * An icon to display to the left of the menu item.\n\t */\n\ticonLeft?: IconType | TLUiIconJsx\n\t/**\n\t * The keyboard shortcut to display on the item.\n\t */\n\tkbd?: 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\t/**\n\t * If the editor is in readonly mode and the item is not marked as readonlyok, it will not be rendered.\n\t */\n\treadonlyOk?: boolean\n\t/**\n\t * The function to call when the item is clicked.\n\t */\n\tonSelect(source: TLUiEventSource): Promise<void> | void\n\t/**\n\t * Whether this item should be disabled.\n\t */\n\tdisabled?: boolean\n\t/**\n\t * Prevent the menu from closing when the item is clicked\n\t */\n\tnoClose?: boolean\n\t/**\n\t * Whether to show a spinner on the item.\n\t */\n\tspinner?: boolean\n\t/**\n\t * Whether the item is selected.\n\t */\n\tisSelected?: boolean\n}\n\n/** @public @react */\nexport function TldrawUiMenuItem<\n\tTranslationKey extends string = string,\n\tIconType extends string = string,\n>({\n\tdisabled = false,\n\tspinner = false,\n\treadonlyOk = false,\n\tid,\n\tkbd,\n\tlabel,\n\ticon,\n\ticonLeft,\n\tonSelect,\n\tnoClose,\n\tisSelected,\n}: TLUiMenuItemProps<TranslationKey, IconType>) {\n\tconst { type: menuType, sourceId } = useTldrawUiMenuContext()\n\n\tconst msg = useTranslation()\n\n\tconst [disableClicks, setDisableClicks] = useState(false)\n\n\tconst isReadonlyMode = useReadonly()\n\tif (isReadonlyMode && !readonlyOk) return null\n\n\tconst labelToUse = unwrapLabel(label, menuType)\n\tconst kbdToUse = kbd ? kbdStr(kbd) : undefined\n\n\tconst labelStr = labelToUse ? msg(labelToUse as TLUiTranslationKey) : undefined\n\tconst titleStr = labelStr && kbdToUse ? `${labelStr} ${kbdToUse}` : labelStr\n\n\tswitch (menuType) {\n\t\tcase 'menu': {\n\t\t\treturn (\n\t\t\t\t<TldrawUiDropdownMenuItem>\n\t\t\t\t\t<TldrawUiButton\n\t\t\t\t\t\ttype=\"menu\"\n\t\t\t\t\t\tdata-testid={`${sourceId}.${id}`}\n\t\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\t\ttitle={titleStr}\n\t\t\t\t\t\tonClick={(e) => {\n\t\t\t\t\t\t\tif (noClose) {\n\t\t\t\t\t\t\t\tpreventDefault(e)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (disableClicks) {\n\t\t\t\t\t\t\t\tsetDisableClicks(false)\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tonSelect(sourceId)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t{iconLeft && <TldrawUiButtonIcon icon={iconLeft} small />}\n\t\t\t\t\t\t<TldrawUiButtonLabel>{labelStr}</TldrawUiButtonLabel>\n\t\t\t\t\t\t{kbd && <TldrawUiKbd>{kbd}</TldrawUiKbd>}\n\t\t\t\t\t</TldrawUiButton>\n\t\t\t\t</TldrawUiDropdownMenuItem>\n\t\t\t)\n\t\t}\n\t\tcase 'context-menu': {\n\t\t\t// Hide disabled context menu items\n\t\t\tif (disabled) return null\n\n\t\t\treturn (\n\t\t\t\t<_ContextMenu.Item\n\t\t\t\t\tdir=\"ltr\"\n\t\t\t\t\ttitle={titleStr}\n\t\t\t\t\tdraggable={false}\n\t\t\t\t\tclassName=\"tlui-button tlui-button__menu\"\n\t\t\t\t\tdata-testid={`${sourceId}.${id}`}\n\t\t\t\t\tonSelect={(e) => {\n\t\t\t\t\t\tif (noClose) preventDefault(e)\n\t\t\t\t\t\tif (disableClicks) {\n\t\t\t\t\t\t\tsetDisableClicks(false)\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tonSelect(sourceId)\n\t\t\t\t\t\t}\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t<span className=\"tlui-button__label\" draggable={false}>\n\t\t\t\t\t\t{labelStr}\n\t\t\t\t\t</span>\n\t\t\t\t\t{iconLeft && <TldrawUiButtonIcon icon={iconLeft} small />}\n\t\t\t\t\t{kbd && <TldrawUiKbd>{kbd}</TldrawUiKbd>}\n\t\t\t\t\t{spinner && <Spinner />}\n\t\t\t\t</_ContextMenu.Item>\n\t\t\t)\n\t\t}\n\t\tcase 'panel': {\n\t\t\treturn (\n\t\t\t\t<TldrawUiButton\n\t\t\t\t\tdata-testid={`${sourceId}.${id}`}\n\t\t\t\t\ttype=\"menu\"\n\t\t\t\t\ttitle={titleStr}\n\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\tonClick={() => onSelect(sourceId)}\n\t\t\t\t>\n\t\t\t\t\t<TldrawUiButtonLabel>{labelStr}</TldrawUiButtonLabel>\n\t\t\t\t\t{spinner ? <Spinner /> : icon && <TldrawUiButtonIcon icon={icon} />}\n\t\t\t\t</TldrawUiButton>\n\t\t\t)\n\t\t}\n\t\tcase 'small-icons':\n\t\tcase 'icons': {\n\t\t\treturn (\n\t\t\t\t<TldrawUiToolbarButton\n\t\t\t\t\tdata-testid={`${sourceId}.${id}`}\n\t\t\t\t\ttype=\"icon\"\n\t\t\t\t\ttitle={titleStr}\n\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\tonClick={() => onSelect(sourceId)}\n\t\t\t\t>\n\t\t\t\t\t<TldrawUiButtonIcon icon={icon!} small />\n\t\t\t\t</TldrawUiToolbarButton>\n\t\t\t)\n\t\t}\n\t\tcase 'keyboard-shortcuts': {\n\t\t\tif (!kbd) {\n\t\t\t\tconsole.warn(\n\t\t\t\t\t`Menu item '${label}' isn't shown in the keyboard shortcuts dialog because it doesn't have a keyboard shortcut.`\n\t\t\t\t)\n\t\t\t\treturn null\n\t\t\t}\n\n\t\t\treturn (\n\t\t\t\t<div className=\"tlui-shortcuts-dialog__key-pair\" data-testid={`${sourceId}.${id}`}>\n\t\t\t\t\t<div className=\"tlui-shortcuts-dialog__key-pair__key\">{labelStr}</div>\n\t\t\t\t\t<div className=\"tlui-shortcuts-dialog__key-pair__value\">\n\t\t\t\t\t\t<TldrawUiKbd visibleOnMobileLayout>{kbd}</TldrawUiKbd>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t)\n\t\t}\n\t\tcase 'helper-buttons': {\n\t\t\treturn (\n\t\t\t\t<TldrawUiButton type=\"low\" onClick={() => onSelect(sourceId)}>\n\t\t\t\t\t<TldrawUiButtonIcon icon={icon!} />\n\t\t\t\t\t<TldrawUiButtonLabel>{labelStr}</TldrawUiButtonLabel>\n\t\t\t\t</TldrawUiButton>\n\t\t\t)\n\t\t}\n\t\tcase 'toolbar': {\n\t\t\treturn (\n\t\t\t\t<TldrawUiToolbarButton\n\t\t\t\t\taria-label={labelStr}\n\t\t\t\t\taria-pressed={isSelected ? 'true' : 'false'}\n\t\t\t\t\tdata-testid={`tools.${id}`}\n\t\t\t\t\tdata-value={id}\n\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\tonClick={() => onSelect('toolbar')}\n\t\t\t\t\tonTouchStart={(e) => {\n\t\t\t\t\t\tpreventDefault(e)\n\t\t\t\t\t\tonSelect('toolbar')\n\t\t\t\t\t}}\n\t\t\t\t\ttitle={titleStr}\n\t\t\t\t\ttype=\"tool\"\n\t\t\t\t>\n\t\t\t\t\t<TldrawUiButtonIcon icon={icon!} />\n\t\t\t\t</TldrawUiToolbarButton>\n\t\t\t)\n\t\t}\n\t\tcase 'toolbar-overflow': {\n\t\t\treturn (\n\t\t\t\t<TldrawUiToolbarButton\n\t\t\t\t\taria-label={labelStr}\n\t\t\t\t\taria-pressed={isSelected ? 'true' : 'false'}\n\t\t\t\t\tisActive={isSelected}\n\t\t\t\t\tclassName=\"tlui-button-grid__button\"\n\t\t\t\t\tdata-testid={`tools.more.${id}`}\n\t\t\t\t\tdata-value={id}\n\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\tonClick={() => onSelect('toolbar')}\n\t\t\t\t\ttitle={titleStr}\n\t\t\t\t\ttype=\"icon\"\n\t\t\t\t>\n\t\t\t\t\t<TldrawUiButtonIcon icon={icon!} />\n\t\t\t\t</TldrawUiToolbarButton>\n\t\t\t)\n\t\t}\n\t\tdefault: {\n\t\t\tthrow exhaustiveSwitchError(menuType)\n\t\t}\n\t}\n}\n"],
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["import {\n\texhaustiveSwitchError,\n\tgetPointerInfo,\n\tpreventDefault,\n\tTLPointerEventInfo,\n\tuseEditor,\n\tVec,\n} from '@tldraw/editor'\nimport { ContextMenu as _ContextMenu } from 'radix-ui'\nimport { useMemo, useState } from 'react'\nimport { unwrapLabel } from '../../../context/actions'\nimport { TLUiEventSource } from '../../../context/events'\nimport { useReadonly } from '../../../hooks/useReadonly'\nimport { TLUiToolItem } from '../../../hooks/useTools'\nimport { TLUiTranslationKey } from '../../../hooks/useTranslation/TLUiTranslationKey'\nimport { useTranslation } from '../../../hooks/useTranslation/useTranslation'\nimport { kbdStr } from '../../../kbd-utils'\nimport { Spinner } from '../../Spinner'\nimport { TldrawUiButton } from '../Button/TldrawUiButton'\nimport { TldrawUiButtonIcon } from '../Button/TldrawUiButtonIcon'\nimport { TldrawUiButtonLabel } from '../Button/TldrawUiButtonLabel'\nimport { TldrawUiDropdownMenuItem } from '../TldrawUiDropdownMenu'\nimport { TLUiIconJsx } from '../TldrawUiIcon'\nimport { TldrawUiKbd } from '../TldrawUiKbd'\nimport { TldrawUiToolbarButton } from '../TldrawUiToolbar'\nimport { useTldrawUiMenuContext } from './TldrawUiMenuContext'\n\n/** @public */\nexport interface TLUiMenuItemProps<\n\tTranslationKey extends string = string,\n\tIconType extends string = string,\n> {\n\tid: string\n\t/**\n\t * The icon to display on the item. Icons are only shown in certain menu types.\n\t */\n\ticon?: IconType | TLUiIconJsx\n\t/**\n\t * An icon to display to the left of the menu item.\n\t */\n\ticonLeft?: IconType | TLUiIconJsx\n\t/**\n\t * The keyboard shortcut to display on the item.\n\t */\n\tkbd?: 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\t/**\n\t * If the editor is in readonly mode and the item is not marked as readonlyok, it will not be rendered.\n\t */\n\treadonlyOk?: boolean\n\t/**\n\t * The function to call when the item is clicked.\n\t */\n\tonSelect(source: TLUiEventSource): Promise<void> | void\n\t/**\n\t * Whether this item should be disabled.\n\t */\n\tdisabled?: boolean\n\t/**\n\t * Prevent the menu from closing when the item is clicked\n\t */\n\tnoClose?: boolean\n\t/**\n\t * Whether to show a spinner on the item.\n\t */\n\tspinner?: boolean\n\t/**\n\t * Whether the item is selected.\n\t */\n\tisSelected?: boolean\n\t/**\n\t * The function to call when the item is dragged. If this is provided, the item will be draggable.\n\t */\n\tonDragStart?(source: TLUiEventSource, info: TLPointerEventInfo): void\n}\n\n/** @public @react */\nexport function TldrawUiMenuItem<\n\tTranslationKey extends string = string,\n\tIconType extends string = string,\n>({\n\tdisabled = false,\n\tspinner = false,\n\treadonlyOk = false,\n\tid,\n\tkbd,\n\tlabel,\n\ticon,\n\ticonLeft,\n\tonSelect,\n\tnoClose,\n\tisSelected,\n\tonDragStart,\n}: TLUiMenuItemProps<TranslationKey, IconType>) {\n\tconst { type: menuType, sourceId } = useTldrawUiMenuContext()\n\n\tconst msg = useTranslation()\n\n\tconst [disableClicks, setDisableClicks] = useState(false)\n\n\tconst isReadonlyMode = useReadonly()\n\tif (isReadonlyMode && !readonlyOk) return null\n\n\tconst labelToUse = unwrapLabel(label, menuType)\n\tconst kbdToUse = kbd ? kbdStr(kbd) : undefined\n\n\tconst labelStr = labelToUse ? msg(labelToUse as TLUiTranslationKey) : undefined\n\tconst titleStr = labelStr && kbdToUse ? `${labelStr} ${kbdToUse}` : labelStr\n\n\tswitch (menuType) {\n\t\tcase 'menu': {\n\t\t\treturn (\n\t\t\t\t<TldrawUiDropdownMenuItem>\n\t\t\t\t\t<TldrawUiButton\n\t\t\t\t\t\ttype=\"menu\"\n\t\t\t\t\t\tdata-testid={`${sourceId}.${id}`}\n\t\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\t\ttitle={titleStr}\n\t\t\t\t\t\tonClick={(e) => {\n\t\t\t\t\t\t\tif (noClose) {\n\t\t\t\t\t\t\t\tpreventDefault(e)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (disableClicks) {\n\t\t\t\t\t\t\t\tsetDisableClicks(false)\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tonSelect(sourceId)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t{iconLeft && <TldrawUiButtonIcon icon={iconLeft} small />}\n\t\t\t\t\t\t<TldrawUiButtonLabel>{labelStr}</TldrawUiButtonLabel>\n\t\t\t\t\t\t{kbd && <TldrawUiKbd>{kbd}</TldrawUiKbd>}\n\t\t\t\t\t</TldrawUiButton>\n\t\t\t\t</TldrawUiDropdownMenuItem>\n\t\t\t)\n\t\t}\n\t\tcase 'context-menu': {\n\t\t\t// Hide disabled context menu items\n\t\t\tif (disabled) return null\n\n\t\t\treturn (\n\t\t\t\t<_ContextMenu.Item\n\t\t\t\t\tdir=\"ltr\"\n\t\t\t\t\ttitle={titleStr}\n\t\t\t\t\tdraggable={false}\n\t\t\t\t\tclassName=\"tlui-button tlui-button__menu\"\n\t\t\t\t\tdata-testid={`${sourceId}.${id}`}\n\t\t\t\t\tonSelect={(e) => {\n\t\t\t\t\t\tif (noClose) preventDefault(e)\n\t\t\t\t\t\tif (disableClicks) {\n\t\t\t\t\t\t\tsetDisableClicks(false)\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tonSelect(sourceId)\n\t\t\t\t\t\t}\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t<span className=\"tlui-button__label\" draggable={false}>\n\t\t\t\t\t\t{labelStr}\n\t\t\t\t\t</span>\n\t\t\t\t\t{iconLeft && <TldrawUiButtonIcon icon={iconLeft} small />}\n\t\t\t\t\t{kbd && <TldrawUiKbd>{kbd}</TldrawUiKbd>}\n\t\t\t\t\t{spinner && <Spinner />}\n\t\t\t\t</_ContextMenu.Item>\n\t\t\t)\n\t\t}\n\t\tcase 'panel': {\n\t\t\treturn (\n\t\t\t\t<TldrawUiButton\n\t\t\t\t\tdata-testid={`${sourceId}.${id}`}\n\t\t\t\t\ttype=\"menu\"\n\t\t\t\t\ttitle={titleStr}\n\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\tonClick={() => onSelect(sourceId)}\n\t\t\t\t>\n\t\t\t\t\t<TldrawUiButtonLabel>{labelStr}</TldrawUiButtonLabel>\n\t\t\t\t\t{spinner ? <Spinner /> : icon && <TldrawUiButtonIcon icon={icon} />}\n\t\t\t\t</TldrawUiButton>\n\t\t\t)\n\t\t}\n\t\tcase 'small-icons':\n\t\tcase 'icons': {\n\t\t\treturn (\n\t\t\t\t<TldrawUiToolbarButton\n\t\t\t\t\tdata-testid={`${sourceId}.${id}`}\n\t\t\t\t\ttype=\"icon\"\n\t\t\t\t\ttitle={titleStr}\n\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\tonClick={() => onSelect(sourceId)}\n\t\t\t\t>\n\t\t\t\t\t<TldrawUiButtonIcon icon={icon!} small />\n\t\t\t\t</TldrawUiToolbarButton>\n\t\t\t)\n\t\t}\n\t\tcase 'keyboard-shortcuts': {\n\t\t\tif (!kbd) {\n\t\t\t\tconsole.warn(\n\t\t\t\t\t`Menu item '${label}' isn't shown in the keyboard shortcuts dialog because it doesn't have a keyboard shortcut.`\n\t\t\t\t)\n\t\t\t\treturn null\n\t\t\t}\n\n\t\t\treturn (\n\t\t\t\t<div className=\"tlui-shortcuts-dialog__key-pair\" data-testid={`${sourceId}.${id}`}>\n\t\t\t\t\t<div className=\"tlui-shortcuts-dialog__key-pair__key\">{labelStr}</div>\n\t\t\t\t\t<div className=\"tlui-shortcuts-dialog__key-pair__value\">\n\t\t\t\t\t\t<TldrawUiKbd visibleOnMobileLayout>{kbd}</TldrawUiKbd>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t)\n\t\t}\n\t\tcase 'helper-buttons': {\n\t\t\treturn (\n\t\t\t\t<TldrawUiButton type=\"low\" onClick={() => onSelect(sourceId)}>\n\t\t\t\t\t<TldrawUiButtonIcon icon={icon!} />\n\t\t\t\t\t<TldrawUiButtonLabel>{labelStr}</TldrawUiButtonLabel>\n\t\t\t\t</TldrawUiButton>\n\t\t\t)\n\t\t}\n\t\tcase 'toolbar': {\n\t\t\tif (onDragStart) {\n\t\t\t\treturn (\n\t\t\t\t\t<DraggableToolbarButton\n\t\t\t\t\t\tid={id}\n\t\t\t\t\t\ticon={icon}\n\t\t\t\t\t\tonSelect={onSelect}\n\t\t\t\t\t\tonDragStart={onDragStart}\n\t\t\t\t\t\tlabelToUse={labelToUse}\n\t\t\t\t\t\ttitleStr={titleStr}\n\t\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\t\tisSelected={isSelected}\n\t\t\t\t\t/>\n\t\t\t\t)\n\t\t\t}\n\t\t\treturn (\n\t\t\t\t<TldrawUiToolbarButton\n\t\t\t\t\taria-label={labelStr}\n\t\t\t\t\taria-pressed={isSelected ? 'true' : 'false'}\n\t\t\t\t\tdata-testid={`tools.${id}`}\n\t\t\t\t\tdata-value={id}\n\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\tonClick={() => onSelect('toolbar')}\n\t\t\t\t\tonTouchStart={(e) => {\n\t\t\t\t\t\tpreventDefault(e)\n\t\t\t\t\t\tonSelect('toolbar')\n\t\t\t\t\t}}\n\t\t\t\t\ttitle={titleStr}\n\t\t\t\t\ttype=\"tool\"\n\t\t\t\t>\n\t\t\t\t\t<TldrawUiButtonIcon icon={icon!} />\n\t\t\t\t</TldrawUiToolbarButton>\n\t\t\t)\n\t\t}\n\t\tcase 'toolbar-overflow': {\n\t\t\tif (onDragStart) {\n\t\t\t\treturn (\n\t\t\t\t\t<DraggableToolbarButton\n\t\t\t\t\t\tid={id}\n\t\t\t\t\t\ticon={icon}\n\t\t\t\t\t\tonSelect={onSelect}\n\t\t\t\t\t\tonDragStart={onDragStart}\n\t\t\t\t\t\tlabelToUse={labelToUse}\n\t\t\t\t\t\ttitleStr={titleStr}\n\t\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\t\tisSelected={isSelected}\n\t\t\t\t\t\toverflow\n\t\t\t\t\t/>\n\t\t\t\t)\n\t\t\t}\n\t\t\treturn (\n\t\t\t\t<TldrawUiToolbarButton\n\t\t\t\t\taria-label={labelStr}\n\t\t\t\t\taria-pressed={isSelected ? 'true' : 'false'}\n\t\t\t\t\tisActive={isSelected}\n\t\t\t\t\tclassName=\"tlui-button-grid__button\"\n\t\t\t\t\tdata-testid={`tools.more.${id}`}\n\t\t\t\t\tdata-value={id}\n\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\tonClick={() => onSelect('toolbar')}\n\t\t\t\t\ttitle={titleStr}\n\t\t\t\t\ttype=\"icon\"\n\t\t\t\t>\n\t\t\t\t\t<TldrawUiButtonIcon icon={icon!} />\n\t\t\t\t</TldrawUiToolbarButton>\n\t\t\t)\n\t\t}\n\t\tdefault: {\n\t\t\tthrow exhaustiveSwitchError(menuType)\n\t\t}\n\t}\n}\n\nfunction useDraggableEvents(\n\tonDragStart: TLUiToolItem['onDragStart'],\n\tonSelect: TLUiToolItem['onSelect']\n) {\n\tconst editor = useEditor()\n\tconst events = useMemo(() => {\n\t\tlet state = { name: 'idle' } as\n\t\t\t| {\n\t\t\t\t\tname: 'idle'\n\t\t\t }\n\t\t\t| {\n\t\t\t\t\tname: 'pointing'\n\t\t\t\t\tstart: Vec\n\t\t\t }\n\t\t\t| {\n\t\t\t\t\tname: 'dragging'\n\t\t\t\t\tstart: Vec\n\t\t\t }\n\t\t\t| {\n\t\t\t\t\tname: 'dragged'\n\t\t\t }\n\n\t\tfunction handlePointerDown(e: React.PointerEvent<HTMLButtonElement>) {\n\t\t\tstate = {\n\t\t\t\tname: 'pointing',\n\t\t\t\tstart: editor.inputs.currentPagePoint.clone(),\n\t\t\t}\n\n\t\t\te.currentTarget.setPointerCapture(e.pointerId)\n\t\t}\n\n\t\tfunction handlePointerMove(e: React.PointerEvent<HTMLButtonElement>) {\n\t\t\tif ((e as any).isSpecialRedispatchedEvent) return\n\n\t\t\tif (state.name === 'pointing') {\n\t\t\t\tconst distance = Vec.Dist2(state.start, editor.inputs.currentPagePoint)\n\t\t\t\tif (\n\t\t\t\t\tdistance >\n\t\t\t\t\t(editor.getInstanceState().isCoarsePointer\n\t\t\t\t\t\t? editor.options.coarseDragDistanceSquared\n\t\t\t\t\t\t: editor.options.dragDistanceSquared)\n\t\t\t\t) {\n\t\t\t\t\tconst start = state.start\n\t\t\t\t\tstate = {\n\t\t\t\t\t\tname: 'dragging',\n\t\t\t\t\t\tstart,\n\t\t\t\t\t}\n\n\t\t\t\t\teditor.run(() => {\n\t\t\t\t\t\t// Set origin point\n\t\t\t\t\t\teditor.dispatch({\n\t\t\t\t\t\t\ttype: 'pointer',\n\t\t\t\t\t\t\ttarget: 'canvas',\n\t\t\t\t\t\t\tname: 'pointer_down',\n\t\t\t\t\t\t\t...getPointerInfo(e),\n\t\t\t\t\t\t\tpoint: start,\n\t\t\t\t\t\t})\n\n\t\t\t\t\t\t// Pointer down potentially selects shapes, so we need to deselect them.\n\t\t\t\t\t\teditor.selectNone()\n\n\t\t\t\t\t\t// start drag\n\t\t\t\t\t\tonDragStart?.('toolbar', {\n\t\t\t\t\t\t\ttype: 'pointer',\n\t\t\t\t\t\t\ttarget: 'canvas',\n\t\t\t\t\t\t\tname: 'pointer_move',\n\t\t\t\t\t\t\t...getPointerInfo(e),\n\t\t\t\t\t\t})\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfunction handlePointerUp(e: React.PointerEvent<HTMLButtonElement>) {\n\t\t\tif ((e as any).isSpecialRedispatchedEvent) return\n\n\t\t\te.currentTarget.releasePointerCapture(e.pointerId)\n\n\t\t\teditor.dispatch({\n\t\t\t\ttype: 'pointer',\n\t\t\t\ttarget: 'canvas',\n\t\t\t\tname: 'pointer_up',\n\t\t\t\t...getPointerInfo(e),\n\t\t\t})\n\t\t}\n\n\t\tfunction handleClick() {\n\t\t\tif (state.name === 'dragging' || state.name === 'dragged') {\n\t\t\t\tstate = { name: 'idle' }\n\t\t\t\treturn true\n\t\t\t}\n\n\t\t\tstate = { name: 'idle' }\n\t\t\tonSelect?.('toolbar')\n\t\t}\n\n\t\treturn {\n\t\t\tonPointerDown: handlePointerDown,\n\t\t\tonPointerMove: handlePointerMove,\n\t\t\tonPointerUp: handlePointerUp,\n\t\t\tonClick: handleClick,\n\t\t}\n\t}, [onDragStart, editor, onSelect])\n\n\treturn events\n}\n\nfunction DraggableToolbarButton({\n\tid,\n\tlabelToUse,\n\ttitleStr,\n\tdisabled,\n\tisSelected,\n\ticon,\n\tonSelect,\n\tonDragStart,\n\toverflow,\n}: {\n\tid: string\n\tdisabled: boolean\n\tlabelToUse?: string\n\ttitleStr?: string\n\tisSelected?: boolean\n\ticon: TLUiMenuItemProps['icon']\n\tonSelect: TLUiMenuItemProps['onSelect']\n\tonDragStart: TLUiMenuItemProps['onDragStart']\n\toverflow?: boolean\n}) {\n\tconst events = useDraggableEvents(onDragStart, onSelect)\n\n\tif (overflow) {\n\t\treturn (\n\t\t\t<TldrawUiToolbarButton\n\t\t\t\taria-label={labelToUse}\n\t\t\t\taria-pressed={isSelected ? 'true' : 'false'}\n\t\t\t\tisActive={isSelected}\n\t\t\t\tclassName=\"tlui-button-grid__button\"\n\t\t\t\tdata-testid={`tools.more.${id}`}\n\t\t\t\tdata-value={id}\n\t\t\t\tdisabled={disabled}\n\t\t\t\ttitle={titleStr}\n\t\t\t\ttype=\"icon\"\n\t\t\t\t{...events}\n\t\t\t>\n\t\t\t\t<TldrawUiButtonIcon icon={icon!} />\n\t\t\t</TldrawUiToolbarButton>\n\t\t)\n\t}\n\n\treturn (\n\t\t<TldrawUiToolbarButton\n\t\t\taria-label={labelToUse}\n\t\t\taria-pressed={isSelected ? 'true' : 'false'}\n\t\t\tdata-testid={`tools.${id}`}\n\t\t\tdata-value={id}\n\t\t\tdisabled={disabled}\n\t\t\tonTouchStart={(e) => {\n\t\t\t\tpreventDefault(e)\n\t\t\t\tonSelect('toolbar')\n\t\t\t}}\n\t\t\ttitle={titleStr}\n\t\t\ttype=\"tool\"\n\t\t\t{...events}\n\t\t>\n\t\t\t<TldrawUiButtonIcon icon={icon!} />\n\t\t</TldrawUiToolbarButton>\n\t)\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/lib/ui/context/events.tsx"],
|
|
4
|
-
"sourcesContent": ["import * as React from 'react'\n\n/** @public */\nexport type TLUiEventSource =\n\t| 'menu'\n\t| 'main-menu'\n\t| 'context-menu'\n\t| 'zoom-menu'\n\t| 'document-name'\n\t| 'navigation-zone'\n\t| 'quick-actions'\n\t| 'actions-menu'\n\t| 'kbd'\n\t| 'debug-panel'\n\t| 'page-menu'\n\t| 'share-menu'\n\t| 'export-menu'\n\t| 'toolbar'\n\t| 'people-menu'\n\t| 'dialog'\n\t| 'help-menu'\n\t| 'helper-buttons'\n\t| 'style-panel'\n\t| 'rich-text-menu'\n\t| 'image-toolbar'\n\t| 'video-toolbar'\n\t| 'unknown'\n\n/** @public */\nexport interface TLUiEventMap {\n\t// Actions\n\tundo: null\n\tredo: null\n\t'change-language': { locale: string }\n\t'change-page': { direction?: 'prev' | 'next' }\n\t'select-adjacent-shape': { direction: 'prev' | 'next' | 'left' | 'right' | 'up' | 'down' }\n\t'delete-page': null\n\t'duplicate-page': null\n\t'move-page': null\n\t'new-page': null\n\t'rename-page': null\n\t'move-to-page': null\n\t'move-to-new-page': null\n\t'rename-document': null\n\t'group-shapes': null\n\t'ungroup-shapes': null\n\t'remove-frame': null\n\t'fit-frame-to-content': null\n\t'convert-to-embed': null\n\t'convert-to-bookmark': null\n\t'open-embed-link': null\n\t'toggle-auto-size': null\n\t'copy-as': { format: 'svg' | 'png' | 'json' }\n\t'export-as': { format: 'svg' | 'png' | 'json' }\n\t'export-all-as': { format: 'svg' | 'png' | 'json' }\n\t'download-original': null\n\t'edit-link': null\n\t'insert-embed': null\n\t'insert-media': null\n\t'replace-media': null\n\t'image-manipulate': null\n\t'alt-text-start': null\n\t'set-alt-text': null\n\t'align-shapes': {\n\t\toperation: 'left' | 'center-horizontal' | 'right' | 'top' | 'center-vertical' | 'bottom'\n\t}\n\t'duplicate-shapes': null\n\t'pack-shapes': null\n\t'stack-shapes': { operation: 'horizontal' | 'vertical' }\n\t'flip-shapes': { operation: 'horizontal' | 'vertical' }\n\t'distribute-shapes': { operation: 'horizontal' | 'vertical' }\n\t'stretch-shapes': { operation: 'horizontal' | 'vertical' }\n\t'reorder-shapes': {\n\t\toperation: 'toBack' | 'toFront' | 'forward' | 'backward'\n\t}\n\t'delete-shapes': null\n\t'select-all-shapes': null\n\t'select-none-shapes': null\n\t'rotate-ccw': { fine: boolean }\n\t'rotate-cw': { fine: boolean }\n\t'zoom-in': { towardsCursor: boolean }\n\t'zoom-out': { towardsCursor: boolean }\n\t'zoom-to-fit': null\n\t'zoom-to-selection': null\n\t'reset-zoom': null\n\t'zoom-into-view': null\n\t'zoom-to-content': null\n\t'open-menu': { id: string }\n\t'close-menu': { id: string }\n\t'create-new-project': null\n\t'save-project-to-file': null\n\t'open-file': null\n\t'select-tool': { id: string }\n\tprint: null\n\tcopy: null\n\tpaste: null\n\tcut: null\n\t'set-style': { id: string; value: string | number }\n\t'toggle-transparent': null\n\t'toggle-snap-mode': null\n\t'toggle-tool-lock': null\n\t'toggle-grid-mode': null\n\t'toggle-wrap-mode': null\n\t'toggle-focus-mode': null\n\t'toggle-debug-mode': null\n\t'toggle-dynamic-size-mode': null\n\t'toggle-paste-at-cursor': null\n\t'toggle-lock': null\n\t'toggle-reduce-motion': null\n\t'toggle-keyboard-shortcuts': null\n\t'toggle-edge-scrolling': null\n\t'color-scheme': { value: string }\n\t'exit-pen-mode': null\n\t'start-following': null\n\t'stop-following': null\n\t'set-color': null\n\t'change-user-name': null\n\t'open-cursor-chat': null\n\t'zoom-tool': null\n\t'unlock-all': null\n\t'enlarge-shapes': null\n\t'shrink-shapes': null\n\t'flatten-to-image': null\n\t'a11y-repeat-shape-announce': null\n\t'open-url': { url: string }\n\t'open-context-menu': null\n\t'adjust-shape-styles': null\n\t'copy-link': null\n\t'image-replace': null\n\t'video-replace': null\n\t'open-kbd-shortcuts': null\n\t'rich-text': {\n\t\toperation:\n\t\t\t| 'bold'\n\t\t\t| 'strike'\n\t\t\t| 'link'\n\t\t\t| 'link-edit'\n\t\t\t| 'link-visit'\n\t\t\t| 'link-remove'\n\t\t\t| 'heading'\n\t\t\t| 'bulletList'\n\t}\n\tedit: null\n}\n\n/** @public */\nexport type TLUiEventData<K> = K extends null\n\t? { source: TLUiEventSource }\n\t: { source: TLUiEventSource } & K\n\n/** @public */\nexport type TLUiEventHandler = <T extends keyof TLUiEventMap>(\n\tname: T,\n\tdata: TLUiEventData<TLUiEventMap[T]>\n) => void\n\n/** @public */\nexport type TLUiEventContextType = TLUiEventHandler\n\n/** @internal */\nconst defaultEventHandler: TLUiEventContextType = () => void null\n\n/** @internal */\nexport const EventsContext = React.createContext<TLUiEventContextType | null>(null)\n\n/** @public */\nexport interface EventsProviderProps {\n\tonEvent?: TLUiEventHandler\n\tchildren: React.ReactNode\n}\n\n/** @public @react */\nexport function TldrawUiEventsProvider({ onEvent, children }: EventsProviderProps) {\n\treturn (\n\t\t<EventsContext.Provider value={onEvent ?? defaultEventHandler}>\n\t\t\t{children}\n\t\t</EventsContext.Provider>\n\t)\n}\n\n/** @public */\nexport function useUiEvents(): TLUiEventContextType {\n\tconst eventHandler = React.useContext(EventsContext)\n\treturn eventHandler ?? defaultEventHandler\n}\n"],
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["import * as React from 'react'\n\n/** @public */\nexport type TLUiEventSource =\n\t| 'menu'\n\t| 'main-menu'\n\t| 'context-menu'\n\t| 'zoom-menu'\n\t| 'document-name'\n\t| 'navigation-zone'\n\t| 'quick-actions'\n\t| 'actions-menu'\n\t| 'kbd'\n\t| 'debug-panel'\n\t| 'page-menu'\n\t| 'share-menu'\n\t| 'export-menu'\n\t| 'toolbar'\n\t| 'people-menu'\n\t| 'dialog'\n\t| 'help-menu'\n\t| 'helper-buttons'\n\t| 'style-panel'\n\t| 'rich-text-menu'\n\t| 'image-toolbar'\n\t| 'video-toolbar'\n\t| 'unknown'\n\n/** @public */\nexport interface TLUiEventMap {\n\t// Actions\n\tundo: null\n\tredo: null\n\t'change-language': { locale: string }\n\t'change-page': { direction?: 'prev' | 'next' }\n\t'select-adjacent-shape': { direction: 'prev' | 'next' | 'left' | 'right' | 'up' | 'down' }\n\t'delete-page': null\n\t'duplicate-page': null\n\t'move-page': null\n\t'new-page': null\n\t'rename-page': null\n\t'move-to-page': null\n\t'move-to-new-page': null\n\t'rename-document': null\n\t'group-shapes': null\n\t'ungroup-shapes': null\n\t'remove-frame': null\n\t'fit-frame-to-content': null\n\t'convert-to-embed': null\n\t'convert-to-bookmark': null\n\t'open-embed-link': null\n\t'toggle-auto-size': null\n\t'copy-as': { format: 'svg' | 'png' | 'json' }\n\t'export-as': { format: 'svg' | 'png' | 'json' }\n\t'export-all-as': { format: 'svg' | 'png' | 'json' }\n\t'download-original': null\n\t'edit-link': null\n\t'insert-embed': null\n\t'insert-media': null\n\t'replace-media': null\n\t'image-manipulate': null\n\t'alt-text-start': null\n\t'set-alt-text': null\n\t'align-shapes': {\n\t\toperation: 'left' | 'center-horizontal' | 'right' | 'top' | 'center-vertical' | 'bottom'\n\t}\n\t'duplicate-shapes': null\n\t'pack-shapes': null\n\t'stack-shapes': { operation: 'horizontal' | 'vertical' }\n\t'flip-shapes': { operation: 'horizontal' | 'vertical' }\n\t'distribute-shapes': { operation: 'horizontal' | 'vertical' }\n\t'stretch-shapes': { operation: 'horizontal' | 'vertical' }\n\t'reorder-shapes': {\n\t\toperation: 'toBack' | 'toFront' | 'forward' | 'backward'\n\t}\n\t'delete-shapes': null\n\t'select-all-shapes': null\n\t'select-none-shapes': null\n\t'rotate-ccw': { fine: boolean }\n\t'rotate-cw': { fine: boolean }\n\t'zoom-in': { towardsCursor: boolean }\n\t'zoom-out': { towardsCursor: boolean }\n\t'zoom-to-fit': null\n\t'zoom-to-selection': null\n\t'reset-zoom': null\n\t'zoom-into-view': null\n\t'zoom-to-content': null\n\t'open-menu': { id: string }\n\t'close-menu': { id: string }\n\t'create-new-project': null\n\t'save-project-to-file': null\n\t'open-file': null\n\t'select-tool': { id: string }\n\tprint: null\n\tcopy: null\n\tpaste: null\n\tcut: null\n\t'set-style': { id: string; value: string | number }\n\t'toggle-transparent': null\n\t'toggle-snap-mode': null\n\t'toggle-tool-lock': null\n\t'toggle-grid-mode': null\n\t'toggle-wrap-mode': null\n\t'toggle-focus-mode': null\n\t'toggle-debug-mode': null\n\t'toggle-dynamic-size-mode': null\n\t'toggle-paste-at-cursor': null\n\t'toggle-lock': null\n\t'toggle-reduce-motion': null\n\t'toggle-keyboard-shortcuts': null\n\t'toggle-edge-scrolling': null\n\t'color-scheme': { value: string }\n\t'exit-pen-mode': null\n\t'start-following': null\n\t'stop-following': null\n\t'set-color': null\n\t'change-user-name': null\n\t'open-cursor-chat': null\n\t'zoom-tool': null\n\t'unlock-all': null\n\t'enlarge-shapes': null\n\t'shrink-shapes': null\n\t'flatten-to-image': null\n\t'a11y-repeat-shape-announce': null\n\t'open-url': { url: string }\n\t'open-context-menu': null\n\t'adjust-shape-styles': null\n\t'copy-link': null\n\t'drag-tool': { id: string }\n\t'image-replace': null\n\t'video-replace': null\n\t'open-kbd-shortcuts': null\n\t'rich-text': {\n\t\toperation:\n\t\t\t| 'bold'\n\t\t\t| 'strike'\n\t\t\t| 'link'\n\t\t\t| 'link-edit'\n\t\t\t| 'link-visit'\n\t\t\t| 'link-remove'\n\t\t\t| 'heading'\n\t\t\t| 'bulletList'\n\t}\n\tedit: null\n}\n\n/** @public */\nexport type TLUiEventData<K> = K extends null\n\t? { source: TLUiEventSource }\n\t: { source: TLUiEventSource } & K\n\n/** @public */\nexport type TLUiEventHandler = <T extends keyof TLUiEventMap>(\n\tname: T,\n\tdata: TLUiEventData<TLUiEventMap[T]>\n) => void\n\n/** @public */\nexport type TLUiEventContextType = TLUiEventHandler\n\n/** @internal */\nconst defaultEventHandler: TLUiEventContextType = () => void null\n\n/** @internal */\nexport const EventsContext = React.createContext<TLUiEventContextType | null>(null)\n\n/** @public */\nexport interface EventsProviderProps {\n\tonEvent?: TLUiEventHandler\n\tchildren: React.ReactNode\n}\n\n/** @public @react */\nexport function TldrawUiEventsProvider({ onEvent, children }: EventsProviderProps) {\n\treturn (\n\t\t<EventsContext.Provider value={onEvent ?? defaultEventHandler}>\n\t\t\t{children}\n\t\t</EventsContext.Provider>\n\t)\n}\n\n/** @public */\nexport function useUiEvents(): TLUiEventContextType {\n\tconst eventHandler = React.useContext(EventsContext)\n\treturn eventHandler ?? defaultEventHandler\n}\n"],
|
|
5
|
+
"mappings": "AA+KE;AA/KF,YAAY,WAAW;AAiKvB,MAAM,sBAA4C,MAAM;AAGjD,MAAM,gBAAgB,MAAM,cAA2C,IAAI;AAS3E,SAAS,uBAAuB,EAAE,SAAS,SAAS,GAAwB;AAClF,SACC,oBAAC,cAAc,UAAd,EAAuB,OAAO,WAAW,qBACxC,UACF;AAEF;AAGO,SAAS,cAAoC;AACnD,QAAM,eAAe,MAAM,WAAW,aAAa;AACnD,SAAO,gBAAgB;AACxB;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import { jsx } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
assertExists,
|
|
4
|
+
createShapeId,
|
|
5
|
+
GeoShapeGeoStyle,
|
|
6
|
+
toRichText,
|
|
7
|
+
useMaybeEditor
|
|
8
|
+
} from "@tldraw/editor";
|
|
3
9
|
import * as React from "react";
|
|
4
10
|
import { EmbedDialog } from "../components/EmbedDialog.mjs";
|
|
5
11
|
import { useA11y } from "../context/a11y.mjs";
|
|
@@ -70,20 +76,26 @@ function ToolsProvider({ overrides, children }) {
|
|
|
70
76
|
onToolSelect(source, this);
|
|
71
77
|
}
|
|
72
78
|
},
|
|
73
|
-
...[...GeoShapeGeoStyle.values].map((
|
|
74
|
-
id,
|
|
75
|
-
label: `tool.${
|
|
79
|
+
...[...GeoShapeGeoStyle.values].map((geo) => ({
|
|
80
|
+
id: geo,
|
|
81
|
+
label: `tool.${geo}`,
|
|
76
82
|
meta: {
|
|
77
|
-
geo
|
|
83
|
+
geo
|
|
78
84
|
},
|
|
79
|
-
kbd:
|
|
80
|
-
icon: "geo-" +
|
|
85
|
+
kbd: geo === "rectangle" ? "r" : geo === "ellipse" ? "o" : void 0,
|
|
86
|
+
icon: "geo-" + geo,
|
|
81
87
|
onSelect(source) {
|
|
82
88
|
editor.run(() => {
|
|
83
|
-
editor.setStyleForNextShapes(GeoShapeGeoStyle,
|
|
89
|
+
editor.setStyleForNextShapes(GeoShapeGeoStyle, geo);
|
|
84
90
|
editor.setCurrentTool("geo");
|
|
85
|
-
onToolSelect(source, this, `geo-${
|
|
91
|
+
onToolSelect(source, this, `geo-${geo}`);
|
|
86
92
|
});
|
|
93
|
+
},
|
|
94
|
+
onDragStart(source, info) {
|
|
95
|
+
onDragFromToolbarToCreateShape(editor, info, {
|
|
96
|
+
createShape: (id) => editor.createShape({ id, type: "geo", props: { geo } })
|
|
97
|
+
});
|
|
98
|
+
trackEvent("drag-tool", { source, id: "geo" });
|
|
87
99
|
}
|
|
88
100
|
})),
|
|
89
101
|
{
|
|
@@ -94,6 +106,16 @@ function ToolsProvider({ overrides, children }) {
|
|
|
94
106
|
onSelect(source) {
|
|
95
107
|
editor.setCurrentTool("arrow");
|
|
96
108
|
onToolSelect(source, this);
|
|
109
|
+
},
|
|
110
|
+
onDragStart(source, info) {
|
|
111
|
+
onDragFromToolbarToCreateShape(editor, info, {
|
|
112
|
+
createShape: (id) => editor.createShape({
|
|
113
|
+
id,
|
|
114
|
+
type: "arrow",
|
|
115
|
+
props: { start: { x: 0, y: 0 }, end: { x: 200, y: 0 } }
|
|
116
|
+
})
|
|
117
|
+
});
|
|
118
|
+
trackEvent("drag-tool", { source, id: "arrow" });
|
|
97
119
|
}
|
|
98
120
|
},
|
|
99
121
|
{
|
|
@@ -114,6 +136,12 @@ function ToolsProvider({ overrides, children }) {
|
|
|
114
136
|
onSelect(source) {
|
|
115
137
|
editor.setCurrentTool("frame");
|
|
116
138
|
onToolSelect(source, this);
|
|
139
|
+
},
|
|
140
|
+
onDragStart(source, info) {
|
|
141
|
+
onDragFromToolbarToCreateShape(editor, info, {
|
|
142
|
+
createShape: (id) => editor.createShape({ id, type: "frame" })
|
|
143
|
+
});
|
|
144
|
+
trackEvent("drag-tool", { source, id: "frame" });
|
|
117
145
|
}
|
|
118
146
|
},
|
|
119
147
|
{
|
|
@@ -124,6 +152,16 @@ function ToolsProvider({ overrides, children }) {
|
|
|
124
152
|
onSelect(source) {
|
|
125
153
|
editor.setCurrentTool("text");
|
|
126
154
|
onToolSelect(source, this);
|
|
155
|
+
},
|
|
156
|
+
onDragStart(source, info) {
|
|
157
|
+
onDragFromToolbarToCreateShape(editor, info, {
|
|
158
|
+
createShape: (id) => editor.createShape({ id, type: "text", props: { richText: toRichText("Text") } }),
|
|
159
|
+
onDragEnd: (id) => {
|
|
160
|
+
editor.emit("select-all-text", { shapeId: id });
|
|
161
|
+
editor.setEditingShape(id);
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
trackEvent("drag-tool", { source, id: "text" });
|
|
127
165
|
}
|
|
128
166
|
},
|
|
129
167
|
{
|
|
@@ -144,6 +182,16 @@ function ToolsProvider({ overrides, children }) {
|
|
|
144
182
|
onSelect(source) {
|
|
145
183
|
editor.setCurrentTool("note");
|
|
146
184
|
onToolSelect(source, this);
|
|
185
|
+
},
|
|
186
|
+
onDragStart(source, info) {
|
|
187
|
+
onDragFromToolbarToCreateShape(editor, info, {
|
|
188
|
+
createShape: (id) => editor.createShape({ id, type: "note" }),
|
|
189
|
+
onDragEnd: (id) => {
|
|
190
|
+
editor.emit("select-all-text", { shapeId: id });
|
|
191
|
+
editor.setEditingShape(id);
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
trackEvent("drag-tool", { source, id: "note" });
|
|
147
195
|
}
|
|
148
196
|
},
|
|
149
197
|
{
|
|
@@ -184,7 +232,7 @@ function ToolsProvider({ overrides, children }) {
|
|
|
184
232
|
return overrides(editor, tools2, helpers);
|
|
185
233
|
}
|
|
186
234
|
return tools2;
|
|
187
|
-
}, [overrides, editor, helpers, onToolSelect]);
|
|
235
|
+
}, [overrides, editor, helpers, onToolSelect, trackEvent]);
|
|
188
236
|
return /* @__PURE__ */ jsx(ToolsContext.Provider, { value: tools, children });
|
|
189
237
|
}
|
|
190
238
|
function useTools() {
|
|
@@ -194,9 +242,34 @@ function useTools() {
|
|
|
194
242
|
}
|
|
195
243
|
return ctx;
|
|
196
244
|
}
|
|
245
|
+
function onDragFromToolbarToCreateShape(editor, info, opts) {
|
|
246
|
+
const { x, y } = editor.inputs.currentPagePoint;
|
|
247
|
+
const stoppingPoint = editor.markHistoryStoppingPoint("drag shape tool");
|
|
248
|
+
editor.setCurrentTool("select.translating");
|
|
249
|
+
const id = createShapeId();
|
|
250
|
+
opts.createShape(id);
|
|
251
|
+
const shape = assertExists(editor.getShape(id), "Shape not found");
|
|
252
|
+
const { w, h } = editor.getShapePageBounds(id);
|
|
253
|
+
editor.updateShape({ id, type: shape.type, x: x - w / 2, y: y - h / 2 });
|
|
254
|
+
editor.select(id);
|
|
255
|
+
editor.setCurrentTool("select.translating", {
|
|
256
|
+
...info,
|
|
257
|
+
target: "shape",
|
|
258
|
+
shape: editor.getShape(id),
|
|
259
|
+
isCreating: true,
|
|
260
|
+
creatingMarkId: stoppingPoint,
|
|
261
|
+
onCreate() {
|
|
262
|
+
editor.setCurrentTool("select.idle");
|
|
263
|
+
editor.select(id);
|
|
264
|
+
opts.onDragEnd?.(id);
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
editor.getCurrentTool().setCurrentToolIdMask(shape.type);
|
|
268
|
+
}
|
|
197
269
|
export {
|
|
198
270
|
ToolsContext,
|
|
199
271
|
ToolsProvider,
|
|
272
|
+
onDragFromToolbarToCreateShape,
|
|
200
273
|
useTools
|
|
201
274
|
};
|
|
202
275
|
//# sourceMappingURL=useTools.mjs.map
|