From 9ec43d2626bd42aa93cfc940e6f5af38bd57f3b3 Mon Sep 17 00:00:00 2001 From: Kostas Bariotis Date: Tue, 12 May 2020 20:10:11 +0100 Subject: [PATCH] Add free draw mode (#1570) --- package-lock.json | 6 +- package.json | 2 +- src/actions/actionFinalize.tsx | 47 ++-- src/components/Actions.tsx | 10 +- src/components/App.tsx | 20 +- src/components/HintViewer.tsx | 4 + src/components/ShortcutsDialog.tsx | 3 +- src/data/restore.ts | 2 +- src/element/bounds.ts | 1 - src/element/collision.ts | 2 +- src/element/handlerRectangles.ts | 6 +- src/element/sizeHelpers.ts | 6 +- src/element/typeChecks.ts | 6 +- src/element/types.ts | 2 +- src/locales/en.json | 2 + src/renderer/renderElement.ts | 14 +- src/scene/comparisons.ts | 2 + src/shapes.tsx | 26 +- .../regressionTests.test.tsx.snap | 225 +++++++++++++++++- src/tests/queries/toolQueries.ts | 1 + src/tests/regressionTests.test.tsx | 6 + 21 files changed, 344 insertions(+), 49 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9f8ccb74..c65cd85a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16394,9 +16394,9 @@ } }, "roughjs": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/roughjs/-/roughjs-4.3.0.tgz", - "integrity": "sha512-aHEBK0dn50v9HP5hMghQmjpkvPD3He9+pm6UbbcmniFJlIbnvWhw72xFVYR44TorhmwpwtKZj6USniiT0Mq98w==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/roughjs/-/roughjs-4.3.1.tgz", + "integrity": "sha512-m42+OBaBR7x5UhIKyjBCnWqqkaEkBKLkXvHv4pOWJXPofvMnQY4ZcFEQlqf3coKKyZN2lfWMyx7QXSg2GD7SGA==", "requires": { "path-data-parser": "^0.1.0", "points-on-curve": "^0.2.0", diff --git a/package.json b/package.json index fc7f18cd..bc243772 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "react": "16.13.1", "react-dom": "16.13.1", "react-scripts": "3.4.1", - "roughjs": "4.3.0", + "roughjs": "4.3.1", "socket.io-client": "2.3.0", "typescript": "3.8.3" }, diff --git a/src/actions/actionFinalize.tsx b/src/actions/actionFinalize.tsx index 54e3ebe5..429731cd 100644 --- a/src/actions/actionFinalize.tsx +++ b/src/actions/actionFinalize.tsx @@ -16,31 +16,44 @@ export const actionFinalize = register({ if (window.document.activeElement instanceof HTMLElement) { window.document.activeElement.blur(); } - if (appState.multiElement) { + + const multiPointElement = appState.multiElement + ? appState.multiElement + : appState.editingElement?.type === "draw" + ? appState.editingElement + : null; + + if (multiPointElement) { // pen and mouse have hover - if (appState.lastPointerDownWith !== "touch") { - const { points, lastCommittedPoint } = appState.multiElement; + if ( + multiPointElement.type !== "draw" && + appState.lastPointerDownWith !== "touch" + ) { + const { points, lastCommittedPoint } = multiPointElement; if ( !lastCommittedPoint || points[points.length - 1] !== lastCommittedPoint ) { - mutateElement(appState.multiElement, { - points: appState.multiElement.points.slice(0, -1), + mutateElement(multiPointElement, { + points: multiPointElement.points.slice(0, -1), }); } } - if (isInvisiblySmallElement(appState.multiElement)) { + if (isInvisiblySmallElement(multiPointElement)) { newElements = newElements.slice(0, -1); } // If the multi point line closes the loop, // set the last point to first point. // This ensures that loop remains closed at different scales. - if (appState.multiElement.type === "line") { - if (isPathALoop(appState.multiElement.points)) { - const linePoints = appState.multiElement.points; + if ( + multiPointElement.type === "line" || + multiPointElement.type === "draw" + ) { + if (isPathALoop(multiPointElement.points)) { + const linePoints = multiPointElement.points; const firstPoint = linePoints[0]; - mutateElement(appState.multiElement, { + mutateElement(multiPointElement, { points: linePoints.map((point, i) => i === linePoints.length - 1 ? ([firstPoint[0], firstPoint[1]] as const) @@ -51,10 +64,10 @@ export const actionFinalize = register({ } if (!appState.elementLocked) { - appState.selectedElementIds[appState.multiElement.id] = true; + appState.selectedElementIds[multiPointElement.id] = true; } } - if (!appState.elementLocked || !appState.multiElement) { + if (!appState.elementLocked || !multiPointElement) { resetCursor(); } return { @@ -62,13 +75,19 @@ export const actionFinalize = register({ appState: { ...appState, elementType: - appState.elementLocked && appState.multiElement + appState.elementLocked && multiPointElement ? appState.elementType : "selection", draggingElement: null, multiElement: null, editingElement: null, - selectedElementIds: {}, + selectedElementIds: + multiPointElement && !appState.elementLocked + ? { + ...appState.selectedElementIds, + [multiPointElement.id]: true, + } + : appState.selectedElementIds, }, commitToHistory: false, }; diff --git a/src/components/Actions.tsx b/src/components/Actions.tsx index ac043d90..b492161f 100644 --- a/src/components/Actions.tsx +++ b/src/components/Actions.tsx @@ -94,11 +94,11 @@ export function ShapesSwitcher({ }) { return ( <> - {SHAPES.map(({ value, icon }, index) => { + {SHAPES.map(({ value, icon, key }, index) => { const label = t(`toolBar.${value}`); - const shortcut = `${capitalizeString(value)[0]} ${t( - "shortcutsDialog.or", - )} ${index + 1}`; + const shortcut = `${capitalizeString(key)} ${t("shortcutsDialog.or")} ${ + index + 1 + }`; return ( { setAppState({ diff --git a/src/components/App.tsx b/src/components/App.tsx index 49724983..bc1aa50d 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -3,6 +3,7 @@ import React from "react"; import socketIOClient from "socket.io-client"; import rough from "roughjs/bin/rough"; import { RoughCanvas } from "roughjs/bin/canvas"; +import { simplify, Point } from "points-on-curve"; import { FlooredNumber, SocketUpdateData } from "../types"; import { @@ -1981,6 +1982,7 @@ class App extends React.Component { return; } else if ( this.state.elementType === "arrow" || + this.state.elementType === "draw" || this.state.elementType === "line" ) { if (this.state.multiElement) { @@ -2122,7 +2124,7 @@ class App extends React.Component { window.devicePixelRatio, ); - // for arrows, don't start dragging until a given threshold + // for arrows/lines, don't start dragging until a given threshold // to ensure we don't create a 2-point arrow by mistake when // user clicks mouse in a way that it moves a tiny bit (thus // triggering pointermove) @@ -2249,9 +2251,15 @@ class App extends React.Component { if (points.length === 1) { mutateElement(draggingElement, { points: [...points, [dx, dy]] }); } else if (points.length > 1) { - mutateElement(draggingElement, { - points: [...points.slice(0, -1), [dx, dy]], - }); + if (draggingElement.type === "draw") { + mutateElement(draggingElement, { + points: simplify([...(points as Point[]), [dx, dy]], 0.7), + }); + } else { + mutateElement(draggingElement, { + points: [...points.slice(0, -1), [dx, dy]], + }); + } } } else { if (getResizeWithSidesSameLengthKey(event)) { @@ -2330,6 +2338,10 @@ class App extends React.Component { window.removeEventListener(EVENT.POINTER_MOVE, onPointerMove); window.removeEventListener(EVENT.POINTER_UP, onPointerUp); + if (draggingElement?.type === "draw") { + this.actionManager.executeAction(actionFinalize); + return; + } if (isLinearElement(draggingElement)) { if (draggingElement!.points.length > 1) { history.resumeRecording(); diff --git a/src/components/HintViewer.tsx b/src/components/HintViewer.tsx index 4e3e398f..80a25349 100644 --- a/src/components/HintViewer.tsx +++ b/src/components/HintViewer.tsx @@ -22,6 +22,10 @@ const getHints = ({ appState, elements }: Hint) => { return t("hints.linearElementMulti"); } + if (elementType === "draw") { + return t("hints.freeDraw"); + } + const selectedElements = getSelectedElements(elements, appState); if ( isResizing && diff --git a/src/components/ShortcutsDialog.tsx b/src/components/ShortcutsDialog.tsx index bb4cf72a..6f99945a 100644 --- a/src/components/ShortcutsDialog.tsx +++ b/src/components/ShortcutsDialog.tsx @@ -184,7 +184,8 @@ export const ShortcutsDialog = ({ onClose }: { onClose?: () => void }) => { - + + [number, number], ): [number, number, number, number] => { let currentP: Point = [0, 0]; - const { minX, minY, maxX, maxY } = ops.reduce( (limits, { op, data }) => { // There are only four operation types: diff --git a/src/element/collision.ts b/src/element/collision.ts index 917c9a46..b49a5188 100644 --- a/src/element/collision.ts +++ b/src/element/collision.ts @@ -26,7 +26,7 @@ function isElementDraggableFromInside( const dragFromInside = element.backgroundColor !== "transparent" || appState.selectedElementIds[element.id]; - if (element.type === "line") { + if (element.type === "line" || element.type === "draw") { return dragFromInside && isPathALoop(element.points); } return dragFromInside; diff --git a/src/element/handlerRectangles.ts b/src/element/handlerRectangles.ts index ea0a924b..2b222ab9 100644 --- a/src/element/handlerRectangles.ts +++ b/src/element/handlerRectangles.ts @@ -187,7 +187,11 @@ export function handlerRectangles( pointerType, ); - if (element.type === "arrow" || element.type === "line") { + if ( + element.type === "arrow" || + element.type === "line" || + element.type === "draw" + ) { if (element.points.length === 2) { // only check the last point because starting point is always (0,0) const [, p1] = element.points; diff --git a/src/element/sizeHelpers.ts b/src/element/sizeHelpers.ts index 0ed8cad6..b8f10a45 100644 --- a/src/element/sizeHelpers.ts +++ b/src/element/sizeHelpers.ts @@ -21,7 +21,11 @@ export function getPerfectElementSize( const absWidth = Math.abs(width); const absHeight = Math.abs(height); - if (elementType === "line" || elementType === "arrow") { + if ( + elementType === "line" || + elementType === "arrow" || + elementType === "draw" + ) { const lockedAngle = Math.round(Math.atan(absHeight / absWidth) / SHIFT_LOCKING_ANGLE) * SHIFT_LOCKING_ANGLE; diff --git a/src/element/typeChecks.ts b/src/element/typeChecks.ts index 3809849a..8d1fdce3 100644 --- a/src/element/typeChecks.ts +++ b/src/element/typeChecks.ts @@ -14,7 +14,10 @@ export function isLinearElement( element?: ExcalidrawElement | null, ): element is ExcalidrawLinearElement { return ( - element != null && (element.type === "arrow" || element.type === "line") + element != null && + (element.type === "arrow" || + element.type === "line" || + element.type === "draw") ); } @@ -25,6 +28,7 @@ export function isExcalidrawElement(element: any): boolean { element?.type === "rectangle" || element?.type === "ellipse" || element?.type === "arrow" || + element?.type === "draw" || element?.type === "line" ); } diff --git a/src/element/types.ts b/src/element/types.ts index b21c16c8..75c19975 100644 --- a/src/element/types.ts +++ b/src/element/types.ts @@ -50,7 +50,7 @@ export type ExcalidrawTextElement = _ExcalidrawElementBase & export type ExcalidrawLinearElement = _ExcalidrawElementBase & Readonly<{ - type: "arrow" | "line"; + type: "arrow" | "line" | "draw"; points: Point[]; lastCommittedPoint?: Point | null; }>; diff --git a/src/locales/en.json b/src/locales/en.json index 21151a45..305d7865 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -96,6 +96,7 @@ }, "toolBar": { "selection": "Selection", + "draw": "Free draw", "rectangle": "Rectangle", "diamond": "Diamond", "ellipse": "Ellipse", @@ -111,6 +112,7 @@ }, "hints": { "linearElement": "Click to start multiple points, drag for single line", + "freeDraw": "Click and drag, release when you're finished", "linearElementMulti": "Click on last point or press Escape or Enter to finish", "resize": "You can constrain proportions by holding SHIFT while resizing,\nhold ALT to resize from the center", "rotate": "You can constrain angles by holding SHIFT while rotating" diff --git a/src/renderer/renderElement.ts b/src/renderer/renderElement.ts index 627262c4..a4507b06 100644 --- a/src/renderer/renderElement.ts +++ b/src/renderer/renderElement.ts @@ -3,7 +3,7 @@ import { ExcalidrawTextElement, NonDeletedExcalidrawElement, } from "../element/types"; -import { isTextElement } from "../element/typeChecks"; +import { isTextElement, isLinearElement } from "../element/typeChecks"; import { getDiamondPoints, getArrowPoints, @@ -35,12 +35,10 @@ function generateElementCanvas( const canvas = document.createElement("canvas"); const context = canvas.getContext("2d")!; - const isLinear = /\b(arrow|line)\b/.test(element.type); - let canvasOffsetX = 0; let canvasOffsetY = 0; - if (isLinear) { + if (isLinearElement(element)) { const [x1, y1, x2, y2] = getElementAbsoluteCoords(element); canvas.width = distance(x1, x2) * window.devicePixelRatio * zoom + CANVAS_PADDING * 2; @@ -90,6 +88,7 @@ function drawElementOnCanvas( break; } case "arrow": + case "draw": case "line": { (getShapeForElement(element) as Drawable[]).forEach((shape) => rc.draw(shape), @@ -226,6 +225,7 @@ function generateElement( ); break; case "line": + case "draw": case "arrow": { const options: Options = { stroke: element.strokeColor, @@ -240,7 +240,7 @@ function generateElement( // If shape is a line and is a closed shape, // fill the shape if a color is set. - if (element.type === "line") { + if (element.type === "line" || element.type === "draw") { if (isPathALoop(element.points)) { options.fillStyle = element.fillStyle; options.fill = @@ -343,6 +343,7 @@ export function renderElement( case "diamond": case "ellipse": case "line": + case "draw": case "arrow": case "text": { const elementWithCanvas = generateElement(element, generator, sceneState); @@ -410,6 +411,7 @@ export function renderElementToSvg( break; } case "line": + case "draw": case "arrow": { generateElement(element, generator); const group = svgRoot.ownerDocument!.createElementNS(SVG_NS, "g"); @@ -427,7 +429,7 @@ export function renderElementToSvg( }) rotate(${degree} ${cx} ${cy})`, ); if ( - element.type === "line" && + (element.type === "line" || element.type === "draw") && isPathALoop(element.points) && element.backgroundColor !== "transparent" ) { diff --git a/src/scene/comparisons.ts b/src/scene/comparisons.ts index a914e6cf..2f221693 100644 --- a/src/scene/comparisons.ts +++ b/src/scene/comparisons.ts @@ -10,6 +10,7 @@ export const hasBackground = (type: string) => type === "rectangle" || type === "ellipse" || type === "diamond" || + type === "draw" || type === "line"; export const hasStroke = (type: string) => @@ -17,6 +18,7 @@ export const hasStroke = (type: string) => type === "ellipse" || type === "diamond" || type === "arrow" || + type === "draw" || type === "line"; export const hasText = (type: string) => type === "text"; diff --git a/src/shapes.tsx b/src/shapes.tsx index 0b166090..0941d01d 100644 --- a/src/shapes.tsx +++ b/src/shapes.tsx @@ -11,6 +11,7 @@ export const SHAPES = [ ), value: "selection", + key: "s", }, { icon: ( @@ -20,6 +21,7 @@ export const SHAPES = [ ), value: "rectangle", + key: "r", }, { icon: ( @@ -29,6 +31,7 @@ export const SHAPES = [ ), value: "diamond", + key: "d", }, { icon: ( @@ -38,6 +41,7 @@ export const SHAPES = [ ), value: "ellipse", + key: "e", }, { icon: ( @@ -47,6 +51,7 @@ export const SHAPES = [ ), value: "arrow", + key: "a", }, { icon: ( @@ -63,6 +68,20 @@ export const SHAPES = [ ), value: "line", + key: "l", + }, + { + icon: ( + // fa-pencil + + + + ), + value: "draw", + key: "x", }, { icon: ( @@ -72,20 +91,19 @@ export const SHAPES = [ ), value: "text", + key: "t", }, ] as const; export const shapesShortcutKeys = SHAPES.map((shape, index) => [ - shape.value[0], + shape.key, (index + 1).toString(), ]).flat(1); export function findShapeByKey(key: string) { return ( SHAPES.find((shape, index) => { - return ( - shape.value[0] === key.toLowerCase() || key === (index + 1).toString() - ); + return shape.key === key.toLowerCase() || key === (index + 1).toString(); })?.value || "selection" ); } diff --git a/src/tests/__snapshots__/regressionTests.test.tsx.snap b/src/tests/__snapshots__/regressionTests.test.tsx.snap index 34d4bbd3..7cbe0c81 100644 --- a/src/tests/__snapshots__/regressionTests.test.tsx.snap +++ b/src/tests/__snapshots__/regressionTests.test.tsx.snap @@ -1633,7 +1633,7 @@ Object { "currentItemStrokeColor": "#000000", "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", - "cursorButton": "up", + "cursorButton": "down", "cursorX": 0, "cursorY": 0, "draggingElement": null, @@ -1654,7 +1654,9 @@ Object { "scrollX": 0, "scrollY": 0, "scrolledOutside": false, - "selectedElementIds": Object {}, + "selectedElementIds": Object { + "id7": true, + }, "selectionElement": null, "shouldAddWatermark": false, "shouldCacheIgnoreZoom": false, @@ -1798,6 +1800,39 @@ Object { } `; +exports[`regression tests draw every type of shape: [end of test] element 5 1`] = ` +Object { + "angle": 0, + "backgroundColor": "transparent", + "fillStyle": "hachure", + "height": 10, + "id": "id7", + "isDeleted": false, + "lastCommittedPoint": null, + "opacity": 100, + "points": Array [ + Array [ + 0, + 0, + ], + Array [ + 10, + 10, + ], + ], + "roughness": 1, + "seed": 1051383431, + "strokeColor": "#000000", + "strokeWidth": 1, + "type": "draw", + "version": 3, + "versionNonce": 1279028647, + "width": 10, + "x": 30, + "y": 10, +} +`; + exports[`regression tests draw every type of shape: [end of test] history 1`] = ` Object { "recording": false, @@ -2248,9 +2283,9 @@ Object { } `; -exports[`regression tests draw every type of shape: [end of test] number of elements 1`] = `5`; +exports[`regression tests draw every type of shape: [end of test] number of elements 1`] = `6`; -exports[`regression tests draw every type of shape: [end of test] number of renders 1`] = `34`; +exports[`regression tests draw every type of shape: [end of test] number of renders 1`] = `38`; exports[`regression tests hotkey 2 selects rectangle tool: [end of test] appState 1`] = ` Object { @@ -2901,6 +2936,97 @@ exports[`regression tests hotkey 6 selects line tool: [end of test] number of el exports[`regression tests hotkey 6 selects line tool: [end of test] number of renders 1`] = `6`; +exports[`regression tests hotkey 7 selects draw tool: [end of test] appState 1`] = ` +Object { + "collaborators": Map {}, + "currentItemBackgroundColor": "transparent", + "currentItemFillStyle": "hachure", + "currentItemFont": "20px Virgil", + "currentItemOpacity": 100, + "currentItemRoughness": 1, + "currentItemStrokeColor": "#000000", + "currentItemStrokeWidth": 1, + "currentItemTextAlign": "left", + "cursorButton": "down", + "cursorX": 0, + "cursorY": 0, + "draggingElement": null, + "editingElement": null, + "elementLocked": false, + "elementType": "selection", + "errorMessage": null, + "exportBackground": true, + "isCollaborating": false, + "isLoading": false, + "isResizing": false, + "isRotating": false, + "lastPointerDownWith": "mouse", + "multiElement": null, + "name": "Untitled-201933152653", + "openMenu": null, + "resizingElement": null, + "scrollX": 0, + "scrollY": 0, + "scrolledOutside": false, + "selectedElementIds": Object { + "id0": true, + }, + "selectionElement": null, + "shouldAddWatermark": false, + "shouldCacheIgnoreZoom": false, + "showShortcutsDialog": false, + "username": "", + "viewBackgroundColor": "#ffffff", + "zenModeEnabled": false, + "zoom": 1, +} +`; + +exports[`regression tests hotkey 7 selects draw tool: [end of test] element 0 1`] = ` +Object { + "angle": 0, + "backgroundColor": "transparent", + "fillStyle": "hachure", + "height": 10, + "id": "id0", + "isDeleted": false, + "lastCommittedPoint": null, + "opacity": 100, + "points": Array [ + Array [ + 0, + 0, + ], + Array [ + 10, + 10, + ], + ], + "roughness": 1, + "seed": 337897, + "strokeColor": "#000000", + "strokeWidth": 1, + "type": "draw", + "version": 3, + "versionNonce": 449462985, + "width": 10, + "x": 10, + "y": 10, +} +`; + +exports[`regression tests hotkey 7 selects draw tool: [end of test] history 1`] = ` +Object { + "recording": false, + "redoStack": Array [], + "stateHistory": Array [], +} +`; + +exports[`regression tests hotkey 7 selects draw tool: [end of test] number of elements 1`] = `1`; + +exports[`regression tests hotkey 7 selects draw tool: [end of test] number of renders 1`] = `6`; + exports[`regression tests hotkey a selects arrow tool: [end of test] appState 1`] = ` Object { "collaborators": Map {}, @@ -3550,6 +3676,97 @@ exports[`regression tests hotkey r selects rectangle tool: [end of test] number exports[`regression tests hotkey r selects rectangle tool: [end of test] number of renders 1`] = `6`; +exports[`regression tests hotkey x selects draw tool: [end of test] appState 1`] = ` +Object { + "collaborators": Map {}, + "currentItemBackgroundColor": "transparent", + "currentItemFillStyle": "hachure", + "currentItemFont": "20px Virgil", + "currentItemOpacity": 100, + "currentItemRoughness": 1, + "currentItemStrokeColor": "#000000", + "currentItemStrokeWidth": 1, + "currentItemTextAlign": "left", + "cursorButton": "down", + "cursorX": 0, + "cursorY": 0, + "draggingElement": null, + "editingElement": null, + "elementLocked": false, + "elementType": "selection", + "errorMessage": null, + "exportBackground": true, + "isCollaborating": false, + "isLoading": false, + "isResizing": false, + "isRotating": false, + "lastPointerDownWith": "mouse", + "multiElement": null, + "name": "Untitled-201933152653", + "openMenu": null, + "resizingElement": null, + "scrollX": 0, + "scrollY": 0, + "scrolledOutside": false, + "selectedElementIds": Object { + "id0": true, + }, + "selectionElement": null, + "shouldAddWatermark": false, + "shouldCacheIgnoreZoom": false, + "showShortcutsDialog": false, + "username": "", + "viewBackgroundColor": "#ffffff", + "zenModeEnabled": false, + "zoom": 1, +} +`; + +exports[`regression tests hotkey x selects draw tool: [end of test] element 0 1`] = ` +Object { + "angle": 0, + "backgroundColor": "transparent", + "fillStyle": "hachure", + "height": 10, + "id": "id0", + "isDeleted": false, + "lastCommittedPoint": null, + "opacity": 100, + "points": Array [ + Array [ + 0, + 0, + ], + Array [ + 10, + 10, + ], + ], + "roughness": 1, + "seed": 337897, + "strokeColor": "#000000", + "strokeWidth": 1, + "type": "draw", + "version": 3, + "versionNonce": 449462985, + "width": 10, + "x": 10, + "y": 10, +} +`; + +exports[`regression tests hotkey x selects draw tool: [end of test] history 1`] = ` +Object { + "recording": false, + "redoStack": Array [], + "stateHistory": Array [], +} +`; + +exports[`regression tests hotkey x selects draw tool: [end of test] number of elements 1`] = `1`; + +exports[`regression tests hotkey x selects draw tool: [end of test] number of renders 1`] = `6`; + exports[`regression tests pinch-to-zoom works: [end of test] appState 1`] = ` Object { "collaborators": Map {}, diff --git a/src/tests/queries/toolQueries.ts b/src/tests/queries/toolQueries.ts index df1eb12b..a106e573 100644 --- a/src/tests/queries/toolQueries.ts +++ b/src/tests/queries/toolQueries.ts @@ -7,6 +7,7 @@ const toolMap = { ellipse: "ellipse", arrow: "arrow", line: "line", + draw: "draw", }; export type ToolName = keyof typeof toolMap; diff --git a/src/tests/regressionTests.test.tsx b/src/tests/regressionTests.test.tsx index 0fb13098..0ae487d5 100644 --- a/src/tests/regressionTests.test.tsx +++ b/src/tests/regressionTests.test.tsx @@ -265,6 +265,11 @@ describe("regression tests", () => { pointerMove(30, 50); pointerUp(); hotkeyPress("ENTER"); + + clickTool("draw"); + pointerDown(30, 10); + pointerMove(40, 20); + pointerUp(); }); it("click to select a shape", () => { @@ -290,6 +295,7 @@ describe("regression tests", () => { ["4e", "ellipse"], ["5a", "arrow"], ["6l", "line"], + ["7x", "draw"], ] as [string, ExcalidrawElement["type"]][]) { for (const key of keys) { it(`hotkey ${key} selects ${shape} tool`, () => {