diff --git a/.gitignore b/.gitignore index af578687..35d096aa 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,18 @@ -*.log .DS_Store +.env.development.local +.env.local +.env.production.local +.env.test.local .envrc -.now +.eslintcache +.idea +.vercel .vscode +*.log +*.tgz build -firebase/ +dist +firebase logs node_modules npm-debug.log* @@ -12,12 +20,3 @@ static yarn-debug.log* yarn-error.log* yarn.lock -.idea -dist/ -.eslintcache -*.tgz - -.env.local -.env.development.local -.env.test.local -.env.production.local diff --git a/src/actions/actionProperties.tsx b/src/actions/actionProperties.tsx index de2b48a5..5d025546 100644 --- a/src/actions/actionProperties.tsx +++ b/src/actions/actionProperties.tsx @@ -4,15 +4,19 @@ import { ExcalidrawTextElement, TextAlign, FontFamily, + ExcalidrawLinearElement, + Arrowhead, } from "../element/types"; import { getCommonAttributeOfSelectedElements, isSomeElementSelected, getTargetElements, canChangeSharpness, + canHaveArrowheads, } from "../scene"; import { ButtonSelect } from "../components/ButtonSelect"; import { ButtonIconSelect } from "../components/ButtonIconSelect"; +import { ButtonIconCycle } from "../components/ButtonIconCycle"; import { isTextElement, redrawTextBoundingBox, @@ -39,6 +43,7 @@ import { SloppinessArchitectIcon, SloppinessArtistIcon, SloppinessCartoonistIcon, + ArrowArrowheadIcon, } from "../components/icons"; import { EVENT_CHANGE, trackEvent } from "../analytics"; import colors from "../colors"; @@ -622,3 +627,110 @@ export const actionChangeSharpness = register({ ), }); + +export const actionChangeArrowhead = register({ + name: "changeArrowhead", + perform: ( + elements, + appState, + value: { position: "start" | "end"; type: Arrowhead }, + ) => { + return { + elements: changeProperty(elements, appState, (el) => { + if (isLinearElement(el)) { + trackEvent( + EVENT_CHANGE, + `arrowhead ${value.position}`, + value.type || "none", + ); + + const { position, type } = value; + + if (position === "start") { + const element: ExcalidrawLinearElement = newElementWith(el, { + startArrowhead: type, + }); + return element; + } else if (position === "end") { + const element: ExcalidrawLinearElement = newElementWith(el, { + endArrowhead: type, + }); + return element; + } + } + + return el; + }), + appState: { + ...appState, + currentItemArrowheads: { + ...appState.currentItemArrowheads, + [value.position]: value.type, + }, + }, + commitToHistory: true, + }; + }, + PanelComponent: ({ elements, appState, updateData }) => ( +
+ {t("labels.arrowheads")} +
+ , + }, + { + value: "arrow", + text: t("labels.arrowhead_arrow"), + icon: ( + + ), + }, + ]} + value={getFormValue( + elements, + appState, + (element) => + isLinearElement(element) && canHaveArrowheads(element.type) + ? element.startArrowhead + : appState.currentItemArrowheads.start, + appState.currentItemArrowheads.start, + )} + onChange={(value) => updateData({ position: "start", type: value })} + /> + , + }, + { + value: "arrow", + text: t("labels.arrowhead_arrow"), + icon: , + }, + ]} + value={getFormValue( + elements, + appState, + (element) => + isLinearElement(element) && canHaveArrowheads(element.type) + ? element.endArrowhead + : appState.currentItemArrowheads.end, + appState.currentItemArrowheads.end, + )} + onChange={(value) => updateData({ position: "end", type: value })} + /> +
+
+ ), +}); diff --git a/src/actions/types.ts b/src/actions/types.ts index c643a647..25108fd2 100644 --- a/src/actions/types.ts +++ b/src/actions/types.ts @@ -35,6 +35,7 @@ export type ActionName = | "changeStrokeWidth" | "changeSloppiness" | "changeStrokeStyle" + | "changeArrowhead" | "changeOpacity" | "changeFontSize" | "toggleCanvasMenu" @@ -99,9 +100,7 @@ export interface Action { } export interface ActionsManagerInterface { - actions: { - [actionName in ActionName]: Action; - }; + actions: Record; registerAction: (action: Action) => void; handleKeyDown: (event: KeyboardEvent) => boolean; getContextMenuItems: ( diff --git a/src/appState.ts b/src/appState.ts index 4a3853f8..0fd88208 100644 --- a/src/appState.ts +++ b/src/appState.ts @@ -39,6 +39,7 @@ export const getDefaultAppState = (): Omit< currentItemTextAlign: DEFAULT_TEXT_ALIGN, currentItemStrokeSharpness: "sharp", currentItemLinearStrokeSharpness: "round", + currentItemArrowheads: { start: null, end: "arrow" }, viewBackgroundColor: oc.white, scrollX: 0 as FlooredNumber, scrollY: 0 as FlooredNumber, @@ -103,6 +104,7 @@ const APP_STATE_STORAGE_CONF = (< currentItemTextAlign: { browser: true, export: false }, currentItemStrokeSharpness: { browser: true, export: false }, currentItemLinearStrokeSharpness: { browser: true, export: false }, + currentItemArrowheads: { browser: true, export: false }, cursorButton: { browser: true, export: false }, cursorX: { browser: true, export: false }, cursorY: { browser: true, export: false }, diff --git a/src/components/Actions.tsx b/src/components/Actions.tsx index f7f3b727..ad1a0a45 100644 --- a/src/components/Actions.tsx +++ b/src/components/Actions.tsx @@ -7,6 +7,7 @@ import { hasStroke, canChangeSharpness, hasText, + canHaveArrowheads, getTargetElements, } from "../scene"; import { t } from "../i18n"; @@ -46,6 +47,7 @@ export const SelectedShapeActions = ({ const showChangeBackgroundIcons = hasBackground(elementType) || targetElements.some((element) => hasBackground(element.type)); + return (
{renderAction("changeStrokeColor")} @@ -77,6 +79,11 @@ export const SelectedShapeActions = ({ )} + {(canHaveArrowheads(elementType) || + targetElements.some((element) => canHaveArrowheads(element.type))) && ( + <>{renderAction("changeArrowhead")} + )} + {renderAction("changeOpacity")}
diff --git a/src/components/App.tsx b/src/components/App.tsx index 28dc6b76..171d71b2 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -2576,6 +2576,14 @@ class App extends React.Component { pointerDownState.origin.y, elementType === "draw" ? null : this.state.gridSize, ); + + // If arrow is pre-arrowheads, it will have undefined for both start and end arrowheads. + // If so, we want it to be null/"arrow". If the linear item is not an arrow, we want it + // to be null/null. Otherwise, we want it to use the currentItemArrowheads values. + const { start, end } = this.state.currentItemArrowheads; + const [startArrowhead, endArrowhead] = + elementType === "arrow" ? [start, end] : [null, null]; + const element = newLinearElement({ type: elementType, x: gridX, @@ -2588,6 +2596,8 @@ class App extends React.Component { roughness: this.state.currentItemRoughness, opacity: this.state.currentItemOpacity, strokeSharpness: this.state.currentItemLinearStrokeSharpness, + startArrowhead, + endArrowhead, }); this.setState((prevState) => ({ selectedElementIds: { diff --git a/src/components/ButtonIconCycle.tsx b/src/components/ButtonIconCycle.tsx new file mode 100644 index 00000000..1159a1f4 --- /dev/null +++ b/src/components/ButtonIconCycle.tsx @@ -0,0 +1,29 @@ +import React from "react"; +import clsx from "clsx"; + +export const ButtonIconCycle = ({ + options, + value, + onChange, + group, +}: { + options: { value: T; text: string; icon: JSX.Element }[]; + value: T | null; + onChange: (value: T) => void; + group: string; +}) => { + const current = options.find((op) => op.value === value); + + function cycle() { + const index = options.indexOf(current!); + const next = (index + 1) % options.length; + onChange(options[next].value); + } + + return ( + + ); +}; diff --git a/src/components/icons.tsx b/src/components/icons.tsx index e6d23198..94fe0e2f 100644 --- a/src/components/icons.tsx +++ b/src/components/icons.tsx @@ -568,13 +568,12 @@ export const UngroupIcon = React.memo( export const FillHachureIcon = React.memo( ({ appearance }: { appearance: "light" | "dark" }) => createIcon( - - - - , + , { width: 40, height: 20 }, ), ); @@ -582,12 +581,9 @@ export const FillHachureIcon = React.memo( export const FillCrossHatchIcon = React.memo( ({ appearance }: { appearance: "light" | "dark" }) => createIcon( - - - + + + , { width: 40, height: 20 }, ), @@ -595,18 +591,10 @@ export const FillCrossHatchIcon = React.memo( export const FillSolidIcon = React.memo( ({ appearance }: { appearance: "light" | "dark" }) => - createIcon( - <> - - - , - { width: 40, height: 20 }, - ), + createIcon(, { + width: 40, + height: 20, + }), ); export const StrokeWidthIcon = React.memo( @@ -619,7 +607,7 @@ export const StrokeWidthIcon = React.memo( }) => createIcon( createIcon( , - { width: 40, height: 20 }, + { + width: 40, + height: 20, + }, ), ); @@ -645,11 +636,11 @@ export const StrokeStyleDashedIcon = React.memo( ({ appearance }: { appearance: "light" | "dark" }) => createIcon( , { width: 40, height: 20 }, ), @@ -659,11 +650,11 @@ export const StrokeStyleDottedIcon = React.memo( ({ appearance }: { appearance: "light" | "dark" }) => createIcon( , { width: 40, height: 20 }, ), @@ -673,7 +664,7 @@ export const SloppinessArchitectIcon = React.memo( ({ appearance }: { appearance: "light" | "dark" }) => createIcon( createIcon( createIcon( - <> - - - , + , { width: 40, height: 20, mirror: true }, ), ); @@ -720,7 +703,7 @@ export const EdgeSharpIcon = React.memo( ({ appearance }: { appearance: "light" | "dark" }) => createIcon( createIcon( + createIcon( + + + + , + { width: 40, height: 20, mirror: true }, + ), +); diff --git a/src/css/styles.scss b/src/css/styles.scss index 0b929053..9b944b1d 100644 --- a/src/css/styles.scss +++ b/src/css/styles.scss @@ -93,7 +93,8 @@ display: inline-block; } - input[type="radio"] { + input[type="radio"], + input[type="button"] { opacity: 0; position: absolute; pointer-events: none; diff --git a/src/data/restore.ts b/src/data/restore.ts index 80c4ffa3..675b080d 100644 --- a/src/data/restore.ts +++ b/src/data/restore.ts @@ -90,6 +90,11 @@ const restoreElement = ( case "draw": case "line": case "arrow": { + const { + startArrowhead = null, + endArrowhead = element.type === "arrow" ? "arrow" : null, + } = element; + return restoreElementWithProperties(element, { startBinding: element.startBinding, endBinding: element.endBinding, @@ -102,6 +107,8 @@ const restoreElement = ( ] : element.points, lastCommittedPoint: null, + startArrowhead, + endArrowhead, }); } // generic elements diff --git a/src/element/bounds.ts b/src/element/bounds.ts index 35788592..e2494214 100644 --- a/src/element/bounds.ts +++ b/src/element/bounds.ts @@ -1,4 +1,4 @@ -import { ExcalidrawElement, ExcalidrawLinearElement } from "./types"; +import { ExcalidrawElement, ExcalidrawLinearElement, Arrowhead } from "./types"; import { distance2d, rotate } from "../math"; import rough from "roughjs/bin/rough"; import { Drawable, Op } from "roughjs/bin/core"; @@ -160,24 +160,29 @@ const getLinearElementAbsoluteCoords = ( ]; }; -export const getArrowPoints = ( +export const getArrowheadPoints = ( element: ExcalidrawLinearElement, shape: Drawable[], + position: "start" | "end", + arrowhead: Arrowhead, ) => { const ops = getCurvePathOps(shape[0]); if (ops.length < 1) { return null; } - const data = ops[ops.length - 1].data; + // The index of the bCurve operation to examine. + const index = position === "start" ? 1 : ops.length - 1; + + const data = ops[index].data; const p3 = [data[4], data[5]] as Point; const p2 = [data[2], data[3]] as Point; const p1 = [data[0], data[1]] as Point; - // we need to find p0 of the bezier curve - // it is typically the last point of the previous - // curve; it can also be the position of moveTo operation - const prevOp = ops[ops.length - 2]; + // We need to find p0 of the bezier curve. + // It is typically the last point of the previous + // curve; it can also be the position of moveTo operation. + const prevOp = ops[index - 1]; let p0: Point = [0, 0]; if (prevOp.op === "move") { p0 = (prevOp.data as unknown) as Point; @@ -192,38 +197,40 @@ export const getArrowPoints = ( 3 * Math.pow(t, 2) * (1 - t) * p1[idx] + p0[idx] * Math.pow(t, 3); - // we know the last point of the arrow - const [x2, y2] = p3; + // Ee know the last point of the arrow (or the first, if start arrowhead). + const [x2, y2] = position === "start" ? p0 : p3; - // by using cubic bezier equation (B(t)) and the given parameters, - // we calculate a point that is closer to the last point + // By using cubic bezier equation (B(t)) and the given parameters, + // we calculate a point that is closer to the last point. // The value 0.3 is chosen arbitrarily and it works best for all - // the tested cases + // the tested cases. const [x1, y1] = [equation(0.3, 0), equation(0.3, 1)]; - // find the normalized direction vector based on the - // previously calculated points + // Find the normalized direction vector based on the + // previously calculated points. const distance = Math.hypot(x2 - x1, y2 - y1); const nx = (x2 - x1) / distance; const ny = (y2 - y1) / distance; - const size = 30; // pixels - const arrowLength = element.points.reduce((total, [cx, cy], idx, points) => { + const size = 30; // pixels (will differ for each arrowhead) + + const length = element.points.reduce((total, [cx, cy], idx, points) => { const [px, py] = idx > 0 ? points[idx - 1] : [0, 0]; return total + Math.hypot(cx - px, cy - py); }, 0); - // Scale down the arrow until we hit a certain size so that it doesn't look weird - // This value is selected by minizing a minmum size with the whole length of the arrow - // intead of last segment of the arrow - const minSize = Math.min(size, arrowLength / 2); + // Scale down the arrowhead until we hit a certain size so that it doesn't look weird. + // This value is selected by minimizing a minimum size with the whole length of the + // arrowhead instead of last segment of the arrowhead. + const minSize = Math.min(size, length / 2); const xs = x2 - nx * minSize; const ys = y2 - ny * minSize; const angle = 20; // degrees + + // Return points const [x3, y3] = rotate(xs, ys, x2, y2, (-angle * Math.PI) / 180); const [x4, y4] = rotate(xs, ys, x2, y2, (angle * Math.PI) / 180); - return [x2, y2, x3, y3, x4, y4]; }; diff --git a/src/element/index.ts b/src/element/index.ts index e578ee13..e49bc633 100644 --- a/src/element/index.ts +++ b/src/element/index.ts @@ -18,7 +18,7 @@ export { getElementBounds, getCommonBounds, getDiamondPoints, - getArrowPoints, + getArrowheadPoints, getClosestElementBounds, } from "./bounds"; diff --git a/src/element/newElement.ts b/src/element/newElement.ts index ab2742b8..5ac66885 100644 --- a/src/element/newElement.ts +++ b/src/element/newElement.ts @@ -8,6 +8,7 @@ import { FontFamily, GroupId, VerticalAlign, + Arrowhead, } from "../element/types"; import { measureText, getFontString } from "../utils"; import { randomInteger, randomId } from "../random"; @@ -214,6 +215,8 @@ export const updateTextElement = ( export const newLinearElement = ( opts: { type: ExcalidrawLinearElement["type"]; + startArrowhead: Arrowhead | null; + endArrowhead: Arrowhead | null; } & ElementConstructorOpts, ): NonDeleted => { return { @@ -222,6 +225,8 @@ export const newLinearElement = ( lastCommittedPoint: null, startBinding: null, endBinding: null, + startArrowhead: opts.startArrowhead, + endArrowhead: opts.endArrowhead, }; }; diff --git a/src/element/types.ts b/src/element/types.ts index 900234d1..e2b54dc2 100644 --- a/src/element/types.ts +++ b/src/element/types.ts @@ -90,13 +90,17 @@ export type PointBinding = { gap: number; }; +export type Arrowhead = "arrow"; + export type ExcalidrawLinearElement = _ExcalidrawElementBase & Readonly<{ - type: "arrow" | "line" | "draw"; + type: "line" | "draw" | "arrow"; points: readonly Point[]; lastCommittedPoint: Point | null; startBinding: PointBinding | null; endBinding: PointBinding | null; + startArrowhead: Arrowhead | null; + endArrowhead: Arrowhead | null; }>; export type PointerType = "mouse" | "pen" | "touch"; diff --git a/src/locales/en.json b/src/locales/en.json index aacfedae..c9bd590c 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -28,6 +28,9 @@ "edges": "Edges", "sharp": "Sharp", "round": "Round", + "arrowheads": "Arrowheads", + "arrowhead_none": "None", + "arrowhead_arrow": "Arrow", "fontSize": "Font size", "fontFamily": "Font family", "onlySelected": "Only selected", diff --git a/src/renderer/renderElement.ts b/src/renderer/renderElement.ts index ed2af187..1e5f94dd 100644 --- a/src/renderer/renderElement.ts +++ b/src/renderer/renderElement.ts @@ -1,13 +1,15 @@ import { ExcalidrawElement, + ExcalidrawLinearElement, ExcalidrawTextElement, + Arrowhead, NonDeletedExcalidrawElement, } from "../element/types"; import { isTextElement, isLinearElement } from "../element/typeChecks"; import { getDiamondPoints, - getArrowPoints, getElementAbsoluteCoords, + getArrowheadPoints, } from "../element/bounds"; import { RoughCanvas } from "roughjs/bin/canvas"; import { Drawable, Options } from "roughjs/bin/core"; @@ -334,22 +336,64 @@ const generateElementShape = ( // add lines only in arrow if (element.type === "arrow") { - const arrowPoints = getArrowPoints(element, shape); - if (arrowPoints) { - const [x2, y2, x3, y3, x4, y4] = arrowPoints; - // for dotted arrows caps, reduce gap to make it more legible + const { startArrowhead = null, endArrowhead = "arrow" } = element; + + function getArrowheadShapes( + element: ExcalidrawLinearElement, + shape: Drawable[], + position: "start" | "end", + arrowhead: Arrowhead, + ) { + const arrowheadPoints = getArrowheadPoints( + element, + shape, + position, + arrowhead, + ); + + if (arrowheadPoints === null) { + return []; + } + + // Other arrowheads here... + + // Arrow arrowheads + const [x2, y2, x3, y3, x4, y4] = arrowheadPoints; if (element.strokeStyle === "dotted") { + // for dotted arrows caps, reduce gap to make it more legible options.strokeLineDash = [3, 4]; - // for solid/dashed, keep solid arrow cap } else { + // for solid/dashed, keep solid arrow cap delete options.strokeLineDash; } - shape.push( - ...[ - generator.line(x3, y3, x2, y2, options), - generator.line(x4, y4, x2, y2, options), - ], + return [ + generator.line(x3, y3, x2, y2, options), + generator.line(x4, y4, x2, y2, options), + ]; + } + + if (startArrowhead !== null) { + const shapes = getArrowheadShapes( + element, + shape, + "start", + startArrowhead, ); + shape.push(...shapes); + } + + if (endArrowhead !== null) { + if (endArrowhead === undefined) { + // Hey, we have an old arrow here! + } + + const shapes = getArrowheadShapes( + element, + shape, + "end", + endArrowhead, + ); + shape.push(...shapes); } } break; diff --git a/src/scene/comparisons.ts b/src/scene/comparisons.ts index 831add1c..a615b81d 100644 --- a/src/scene/comparisons.ts +++ b/src/scene/comparisons.ts @@ -28,6 +28,8 @@ export const canChangeSharpness = (type: string) => export const hasText = (type: string) => type === "text"; +export const canHaveArrowheads = (type: string) => type === "arrow"; + export const getElementAtPosition = ( elements: readonly NonDeletedExcalidrawElement[], isAtPositionFn: (element: NonDeletedExcalidrawElement) => boolean, diff --git a/src/scene/index.ts b/src/scene/index.ts index 6f3999a3..0b98f6f2 100644 --- a/src/scene/index.ts +++ b/src/scene/index.ts @@ -10,6 +10,7 @@ export { normalizeScroll, calculateScrollCenter } from "./scroll"; export { hasBackground, hasStroke, + canHaveArrowheads, canChangeSharpness, getElementAtPosition, getElementContainingPosition, diff --git a/src/tests/__snapshots__/dragCreate.test.tsx.snap b/src/tests/__snapshots__/dragCreate.test.tsx.snap index 7c8a34c2..d2721d30 100644 --- a/src/tests/__snapshots__/dragCreate.test.tsx.snap +++ b/src/tests/__snapshots__/dragCreate.test.tsx.snap @@ -7,6 +7,7 @@ Object { "angle": 0, "backgroundColor": "transparent", "boundElementIds": null, + "endArrowhead": "arrow", "endBinding": null, "fillStyle": "hachure", "groupIds": Array [], @@ -27,6 +28,7 @@ Object { ], "roughness": 1, "seed": 337897, + "startArrowhead": null, "startBinding": null, "strokeColor": "#000000", "strokeSharpness": "round", @@ -102,6 +104,7 @@ Object { "angle": 0, "backgroundColor": "transparent", "boundElementIds": null, + "endArrowhead": null, "endBinding": null, "fillStyle": "hachure", "groupIds": Array [], @@ -122,6 +125,7 @@ Object { ], "roughness": 1, "seed": 337897, + "startArrowhead": null, "startBinding": null, "strokeColor": "#000000", "strokeSharpness": "round", diff --git a/src/tests/__snapshots__/move.test.tsx.snap b/src/tests/__snapshots__/move.test.tsx.snap index 611f07d5..18969e8d 100644 --- a/src/tests/__snapshots__/move.test.tsx.snap +++ b/src/tests/__snapshots__/move.test.tsx.snap @@ -139,6 +139,7 @@ Object { "angle": 0, "backgroundColor": "transparent", "boundElementIds": null, + "endArrowhead": null, "endBinding": Object { "elementId": "id1", "focus": -0.46666666666666673, @@ -163,6 +164,7 @@ Object { ], "roughness": 1, "seed": 401146281, + "startArrowhead": null, "startBinding": Object { "elementId": "id0", "focus": -0.6000000000000001, diff --git a/src/tests/__snapshots__/multiPointCreate.test.tsx.snap b/src/tests/__snapshots__/multiPointCreate.test.tsx.snap index 607916d9..807e17a5 100644 --- a/src/tests/__snapshots__/multiPointCreate.test.tsx.snap +++ b/src/tests/__snapshots__/multiPointCreate.test.tsx.snap @@ -5,6 +5,7 @@ Object { "angle": 0, "backgroundColor": "transparent", "boundElementIds": null, + "endArrowhead": "arrow", "endBinding": null, "fillStyle": "hachure", "groupIds": Array [], @@ -32,6 +33,7 @@ Object { ], "roughness": 1, "seed": 337897, + "startArrowhead": null, "startBinding": null, "strokeColor": "#000000", "strokeSharpness": "round", @@ -51,6 +53,7 @@ Object { "angle": 0, "backgroundColor": "transparent", "boundElementIds": null, + "endArrowhead": null, "endBinding": null, "fillStyle": "hachure", "groupIds": Array [], @@ -78,6 +81,7 @@ Object { ], "roughness": 1, "seed": 337897, + "startArrowhead": null, "startBinding": null, "strokeColor": "#000000", "strokeSharpness": "round", diff --git a/src/tests/__snapshots__/regressionTests.test.tsx.snap b/src/tests/__snapshots__/regressionTests.test.tsx.snap index fa05c2ce..33bd69cc 100644 --- a/src/tests/__snapshots__/regressionTests.test.tsx.snap +++ b/src/tests/__snapshots__/regressionTests.test.tsx.snap @@ -4,6 +4,10 @@ exports[`given element A and group of elements B and given both are selected whe Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -457,6 +461,10 @@ exports[`given element A and group of elements B and given both are selected whe Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -916,6 +924,10 @@ exports[`regression tests Cmd/Ctrl-click exclusively select element under pointe Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -1684,6 +1696,10 @@ exports[`regression tests Drags selected element when hitting only bounding box Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -1880,6 +1896,10 @@ exports[`regression tests adjusts z order when grouping: [end of test] appState Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -2330,6 +2350,10 @@ exports[`regression tests alt-drag duplicates an element: [end of test] appState Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -2575,6 +2599,10 @@ exports[`regression tests arrow keys: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -2731,6 +2759,10 @@ exports[`regression tests can drag element that covers another element, while an Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -3200,6 +3232,10 @@ exports[`regression tests change the properties of a shape: [end of test] appSta Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "#fa5252", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -3500,6 +3536,10 @@ exports[`regression tests click on an element and drag it: [dragged] appState 1` Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -3696,6 +3736,10 @@ exports[`regression tests click on an element and drag it: [end of test] appStat Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -3932,6 +3976,10 @@ exports[`regression tests click to select a shape: [end of test] appState 1`] = Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -4176,6 +4224,10 @@ exports[`regression tests click-drag to select a group: [end of test] appState 1 Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -4529,6 +4581,10 @@ exports[`regression tests deselects group of selected elements on pointer down w Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -4816,6 +4872,10 @@ exports[`regression tests deselects group of selected elements on pointer up whe Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -5115,6 +5175,10 @@ exports[`regression tests deselects selected element on pointer down when pointe Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -5315,6 +5379,10 @@ exports[`regression tests deselects selected element, on pointer up, when click Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -5493,6 +5561,10 @@ exports[`regression tests double click to edit a group: [end of test] appState 1 Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -5938,6 +6010,10 @@ exports[`regression tests drags selected elements from point inside common bound Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -6248,6 +6324,10 @@ exports[`regression tests draw every type of shape: [end of test] appState 1`] = Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -6398,6 +6478,7 @@ Object { "angle": 0, "backgroundColor": "transparent", "boundElementIds": null, + "endArrowhead": "arrow", "endBinding": null, "fillStyle": "hachure", "groupIds": Array [], @@ -6418,6 +6499,7 @@ Object { ], "roughness": 1, "seed": 1150084233, + "startArrowhead": null, "startBinding": null, "strokeColor": "#000000", "strokeSharpness": "round", @@ -6437,6 +6519,7 @@ Object { "angle": 0, "backgroundColor": "transparent", "boundElementIds": null, + "endArrowhead": null, "endBinding": null, "fillStyle": "hachure", "groupIds": Array [], @@ -6457,6 +6540,7 @@ Object { ], "roughness": 1, "seed": 238820263, + "startArrowhead": null, "startBinding": null, "strokeColor": "#000000", "strokeSharpness": "round", @@ -6476,6 +6560,7 @@ Object { "angle": 0, "backgroundColor": "transparent", "boundElementIds": null, + "endArrowhead": "arrow", "endBinding": null, "fillStyle": "hachure", "groupIds": Array [], @@ -6503,6 +6588,7 @@ Object { ], "roughness": 1, "seed": 1505387817, + "startArrowhead": null, "startBinding": null, "strokeColor": "#000000", "strokeSharpness": "round", @@ -6522,6 +6608,7 @@ Object { "angle": 0, "backgroundColor": "transparent", "boundElementIds": null, + "endArrowhead": null, "endBinding": null, "fillStyle": "hachure", "groupIds": Array [], @@ -6549,6 +6636,7 @@ Object { ], "roughness": 1, "seed": 760410951, + "startArrowhead": null, "startBinding": null, "strokeColor": "#000000", "strokeSharpness": "round", @@ -6568,6 +6656,7 @@ Object { "angle": 0, "backgroundColor": "transparent", "boundElementIds": null, + "endArrowhead": null, "endBinding": null, "fillStyle": "hachure", "groupIds": Array [], @@ -6588,6 +6677,7 @@ Object { ], "roughness": 1, "seed": 941653321, + "startArrowhead": null, "startBinding": null, "strokeColor": "#000000", "strokeSharpness": "round", @@ -6878,6 +6968,7 @@ Object { "angle": 0, "backgroundColor": "transparent", "boundElementIds": null, + "endArrowhead": "arrow", "endBinding": null, "fillStyle": "hachure", "groupIds": Array [], @@ -6898,6 +6989,7 @@ Object { ], "roughness": 1, "seed": 1150084233, + "startArrowhead": null, "startBinding": null, "strokeColor": "#000000", "strokeSharpness": "round", @@ -6996,6 +7088,7 @@ Object { "angle": 0, "backgroundColor": "transparent", "boundElementIds": null, + "endArrowhead": "arrow", "endBinding": null, "fillStyle": "hachure", "groupIds": Array [], @@ -7016,6 +7109,7 @@ Object { ], "roughness": 1, "seed": 1150084233, + "startArrowhead": null, "startBinding": null, "strokeColor": "#000000", "strokeSharpness": "round", @@ -7032,6 +7126,7 @@ Object { "angle": 0, "backgroundColor": "transparent", "boundElementIds": null, + "endArrowhead": null, "endBinding": null, "fillStyle": "hachure", "groupIds": Array [], @@ -7052,6 +7147,7 @@ Object { ], "roughness": 1, "seed": 238820263, + "startArrowhead": null, "startBinding": null, "strokeColor": "#000000", "strokeSharpness": "round", @@ -7150,6 +7246,7 @@ Object { "angle": 0, "backgroundColor": "transparent", "boundElementIds": null, + "endArrowhead": "arrow", "endBinding": null, "fillStyle": "hachure", "groupIds": Array [], @@ -7170,6 +7267,7 @@ Object { ], "roughness": 1, "seed": 1150084233, + "startArrowhead": null, "startBinding": null, "strokeColor": "#000000", "strokeSharpness": "round", @@ -7186,6 +7284,7 @@ Object { "angle": 0, "backgroundColor": "transparent", "boundElementIds": null, + "endArrowhead": null, "endBinding": null, "fillStyle": "hachure", "groupIds": Array [], @@ -7206,6 +7305,7 @@ Object { ], "roughness": 1, "seed": 238820263, + "startArrowhead": null, "startBinding": null, "strokeColor": "#000000", "strokeSharpness": "round", @@ -7222,6 +7322,7 @@ Object { "angle": 0, "backgroundColor": "transparent", "boundElementIds": null, + "endArrowhead": "arrow", "endBinding": null, "fillStyle": "hachure", "groupIds": Array [], @@ -7245,6 +7346,7 @@ Object { ], "roughness": 1, "seed": 1505387817, + "startArrowhead": null, "startBinding": null, "strokeColor": "#000000", "strokeSharpness": "round", @@ -7343,6 +7445,7 @@ Object { "angle": 0, "backgroundColor": "transparent", "boundElementIds": null, + "endArrowhead": "arrow", "endBinding": null, "fillStyle": "hachure", "groupIds": Array [], @@ -7363,6 +7466,7 @@ Object { ], "roughness": 1, "seed": 1150084233, + "startArrowhead": null, "startBinding": null, "strokeColor": "#000000", "strokeSharpness": "round", @@ -7379,6 +7483,7 @@ Object { "angle": 0, "backgroundColor": "transparent", "boundElementIds": null, + "endArrowhead": null, "endBinding": null, "fillStyle": "hachure", "groupIds": Array [], @@ -7399,6 +7504,7 @@ Object { ], "roughness": 1, "seed": 238820263, + "startArrowhead": null, "startBinding": null, "strokeColor": "#000000", "strokeSharpness": "round", @@ -7415,6 +7521,7 @@ Object { "angle": 0, "backgroundColor": "transparent", "boundElementIds": null, + "endArrowhead": "arrow", "endBinding": null, "fillStyle": "hachure", "groupIds": Array [], @@ -7442,6 +7549,7 @@ Object { ], "roughness": 1, "seed": 1505387817, + "startArrowhead": null, "startBinding": null, "strokeColor": "#000000", "strokeSharpness": "round", @@ -7540,6 +7648,7 @@ Object { "angle": 0, "backgroundColor": "transparent", "boundElementIds": null, + "endArrowhead": "arrow", "endBinding": null, "fillStyle": "hachure", "groupIds": Array [], @@ -7560,6 +7669,7 @@ Object { ], "roughness": 1, "seed": 1150084233, + "startArrowhead": null, "startBinding": null, "strokeColor": "#000000", "strokeSharpness": "round", @@ -7576,6 +7686,7 @@ Object { "angle": 0, "backgroundColor": "transparent", "boundElementIds": null, + "endArrowhead": null, "endBinding": null, "fillStyle": "hachure", "groupIds": Array [], @@ -7596,6 +7707,7 @@ Object { ], "roughness": 1, "seed": 238820263, + "startArrowhead": null, "startBinding": null, "strokeColor": "#000000", "strokeSharpness": "round", @@ -7612,6 +7724,7 @@ Object { "angle": 0, "backgroundColor": "transparent", "boundElementIds": null, + "endArrowhead": "arrow", "endBinding": null, "fillStyle": "hachure", "groupIds": Array [], @@ -7639,6 +7752,7 @@ Object { ], "roughness": 1, "seed": 1505387817, + "startArrowhead": null, "startBinding": null, "strokeColor": "#000000", "strokeSharpness": "round", @@ -7655,6 +7769,7 @@ Object { "angle": 0, "backgroundColor": "transparent", "boundElementIds": null, + "endArrowhead": null, "endBinding": null, "fillStyle": "hachure", "groupIds": Array [], @@ -7678,6 +7793,7 @@ Object { ], "roughness": 1, "seed": 760410951, + "startArrowhead": null, "startBinding": null, "strokeColor": "#000000", "strokeSharpness": "round", @@ -7776,6 +7892,7 @@ Object { "angle": 0, "backgroundColor": "transparent", "boundElementIds": null, + "endArrowhead": "arrow", "endBinding": null, "fillStyle": "hachure", "groupIds": Array [], @@ -7796,6 +7913,7 @@ Object { ], "roughness": 1, "seed": 1150084233, + "startArrowhead": null, "startBinding": null, "strokeColor": "#000000", "strokeSharpness": "round", @@ -7812,6 +7930,7 @@ Object { "angle": 0, "backgroundColor": "transparent", "boundElementIds": null, + "endArrowhead": null, "endBinding": null, "fillStyle": "hachure", "groupIds": Array [], @@ -7832,6 +7951,7 @@ Object { ], "roughness": 1, "seed": 238820263, + "startArrowhead": null, "startBinding": null, "strokeColor": "#000000", "strokeSharpness": "round", @@ -7848,6 +7968,7 @@ Object { "angle": 0, "backgroundColor": "transparent", "boundElementIds": null, + "endArrowhead": "arrow", "endBinding": null, "fillStyle": "hachure", "groupIds": Array [], @@ -7875,6 +7996,7 @@ Object { ], "roughness": 1, "seed": 1505387817, + "startArrowhead": null, "startBinding": null, "strokeColor": "#000000", "strokeSharpness": "round", @@ -7891,6 +8013,7 @@ Object { "angle": 0, "backgroundColor": "transparent", "boundElementIds": null, + "endArrowhead": null, "endBinding": null, "fillStyle": "hachure", "groupIds": Array [], @@ -7918,6 +8041,7 @@ Object { ], "roughness": 1, "seed": 760410951, + "startArrowhead": null, "startBinding": null, "strokeColor": "#000000", "strokeSharpness": "round", @@ -8016,6 +8140,7 @@ Object { "angle": 0, "backgroundColor": "transparent", "boundElementIds": null, + "endArrowhead": "arrow", "endBinding": null, "fillStyle": "hachure", "groupIds": Array [], @@ -8036,6 +8161,7 @@ Object { ], "roughness": 1, "seed": 1150084233, + "startArrowhead": null, "startBinding": null, "strokeColor": "#000000", "strokeSharpness": "round", @@ -8052,6 +8178,7 @@ Object { "angle": 0, "backgroundColor": "transparent", "boundElementIds": null, + "endArrowhead": null, "endBinding": null, "fillStyle": "hachure", "groupIds": Array [], @@ -8072,6 +8199,7 @@ Object { ], "roughness": 1, "seed": 238820263, + "startArrowhead": null, "startBinding": null, "strokeColor": "#000000", "strokeSharpness": "round", @@ -8088,6 +8216,7 @@ Object { "angle": 0, "backgroundColor": "transparent", "boundElementIds": null, + "endArrowhead": "arrow", "endBinding": null, "fillStyle": "hachure", "groupIds": Array [], @@ -8115,6 +8244,7 @@ Object { ], "roughness": 1, "seed": 1505387817, + "startArrowhead": null, "startBinding": null, "strokeColor": "#000000", "strokeSharpness": "round", @@ -8131,6 +8261,7 @@ Object { "angle": 0, "backgroundColor": "transparent", "boundElementIds": null, + "endArrowhead": null, "endBinding": null, "fillStyle": "hachure", "groupIds": Array [], @@ -8158,6 +8289,7 @@ Object { ], "roughness": 1, "seed": 760410951, + "startArrowhead": null, "startBinding": null, "strokeColor": "#000000", "strokeSharpness": "round", @@ -8174,6 +8306,7 @@ Object { "angle": 0, "backgroundColor": "transparent", "boundElementIds": null, + "endArrowhead": null, "endBinding": null, "fillStyle": "hachure", "groupIds": Array [], @@ -8194,6 +8327,7 @@ Object { ], "roughness": 1, "seed": 941653321, + "startArrowhead": null, "startBinding": null, "strokeColor": "#000000", "strokeSharpness": "round", @@ -8220,6 +8354,10 @@ exports[`regression tests given a group of selected elements with an element tha Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -8574,6 +8712,10 @@ exports[`regression tests given a selected element A and a not selected element Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "#fa5252", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -8821,6 +8963,10 @@ exports[`regression tests given selected element A with lower z-index than unsel Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "#fa5252", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -9066,6 +9212,10 @@ exports[`regression tests given selected element A with lower z-index than unsel Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "#fa5252", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -9373,6 +9523,10 @@ exports[`regression tests key 2 selects rectangle tool: [end of test] appState 1 Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -9529,6 +9683,10 @@ exports[`regression tests key 3 selects diamond tool: [end of test] appState 1`] Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -9685,6 +9843,10 @@ exports[`regression tests key 4 selects ellipse tool: [end of test] appState 1`] Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -9841,6 +10003,10 @@ exports[`regression tests key 5 selects arrow tool: [end of test] appState 1`] = Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -9913,6 +10079,7 @@ Object { "angle": 0, "backgroundColor": "transparent", "boundElementIds": null, + "endArrowhead": "arrow", "endBinding": null, "fillStyle": "hachure", "groupIds": Array [], @@ -9933,6 +10100,7 @@ Object { ], "roughness": 1, "seed": 337897, + "startArrowhead": null, "startBinding": null, "strokeColor": "#000000", "strokeSharpness": "round", @@ -9977,6 +10145,7 @@ Object { "angle": 0, "backgroundColor": "transparent", "boundElementIds": null, + "endArrowhead": "arrow", "endBinding": null, "fillStyle": "hachure", "groupIds": Array [], @@ -9997,6 +10166,7 @@ Object { ], "roughness": 1, "seed": 337897, + "startArrowhead": null, "startBinding": null, "strokeColor": "#000000", "strokeSharpness": "round", @@ -10023,6 +10193,10 @@ exports[`regression tests key 6 selects line tool: [end of test] appState 1`] = Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -10095,6 +10269,7 @@ Object { "angle": 0, "backgroundColor": "transparent", "boundElementIds": null, + "endArrowhead": null, "endBinding": null, "fillStyle": "hachure", "groupIds": Array [], @@ -10115,6 +10290,7 @@ Object { ], "roughness": 1, "seed": 337897, + "startArrowhead": null, "startBinding": null, "strokeColor": "#000000", "strokeSharpness": "round", @@ -10159,6 +10335,7 @@ Object { "angle": 0, "backgroundColor": "transparent", "boundElementIds": null, + "endArrowhead": null, "endBinding": null, "fillStyle": "hachure", "groupIds": Array [], @@ -10179,6 +10356,7 @@ Object { ], "roughness": 1, "seed": 337897, + "startArrowhead": null, "startBinding": null, "strokeColor": "#000000", "strokeSharpness": "round", @@ -10205,6 +10383,10 @@ exports[`regression tests key 7 selects draw tool: [end of test] appState 1`] = Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -10277,6 +10459,7 @@ Object { "angle": 0, "backgroundColor": "transparent", "boundElementIds": null, + "endArrowhead": null, "endBinding": null, "fillStyle": "hachure", "groupIds": Array [], @@ -10297,6 +10480,7 @@ Object { ], "roughness": 1, "seed": 337897, + "startArrowhead": null, "startBinding": null, "strokeColor": "#000000", "strokeSharpness": "round", @@ -10341,6 +10525,7 @@ Object { "angle": 0, "backgroundColor": "transparent", "boundElementIds": null, + "endArrowhead": null, "endBinding": null, "fillStyle": "hachure", "groupIds": Array [], @@ -10361,6 +10546,7 @@ Object { ], "roughness": 1, "seed": 337897, + "startArrowhead": null, "startBinding": null, "strokeColor": "#000000", "strokeSharpness": "round", @@ -10387,6 +10573,10 @@ exports[`regression tests key a selects arrow tool: [end of test] appState 1`] = Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -10459,6 +10649,7 @@ Object { "angle": 0, "backgroundColor": "transparent", "boundElementIds": null, + "endArrowhead": "arrow", "endBinding": null, "fillStyle": "hachure", "groupIds": Array [], @@ -10479,6 +10670,7 @@ Object { ], "roughness": 1, "seed": 337897, + "startArrowhead": null, "startBinding": null, "strokeColor": "#000000", "strokeSharpness": "round", @@ -10523,6 +10715,7 @@ Object { "angle": 0, "backgroundColor": "transparent", "boundElementIds": null, + "endArrowhead": "arrow", "endBinding": null, "fillStyle": "hachure", "groupIds": Array [], @@ -10543,6 +10736,7 @@ Object { ], "roughness": 1, "seed": 337897, + "startArrowhead": null, "startBinding": null, "strokeColor": "#000000", "strokeSharpness": "round", @@ -10569,6 +10763,10 @@ exports[`regression tests key d selects diamond tool: [end of test] appState 1`] Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -10725,6 +10923,10 @@ exports[`regression tests key e selects ellipse tool: [end of test] appState 1`] Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -10881,6 +11083,10 @@ exports[`regression tests key l selects line tool: [end of test] appState 1`] = Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -10953,6 +11159,7 @@ Object { "angle": 0, "backgroundColor": "transparent", "boundElementIds": null, + "endArrowhead": null, "endBinding": null, "fillStyle": "hachure", "groupIds": Array [], @@ -10973,6 +11180,7 @@ Object { ], "roughness": 1, "seed": 337897, + "startArrowhead": null, "startBinding": null, "strokeColor": "#000000", "strokeSharpness": "round", @@ -11017,6 +11225,7 @@ Object { "angle": 0, "backgroundColor": "transparent", "boundElementIds": null, + "endArrowhead": null, "endBinding": null, "fillStyle": "hachure", "groupIds": Array [], @@ -11037,6 +11246,7 @@ Object { ], "roughness": 1, "seed": 337897, + "startArrowhead": null, "startBinding": null, "strokeColor": "#000000", "strokeSharpness": "round", @@ -11063,6 +11273,10 @@ exports[`regression tests key r selects rectangle tool: [end of test] appState 1 Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -11219,6 +11433,10 @@ exports[`regression tests key x selects draw tool: [end of test] appState 1`] = Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -11291,6 +11509,7 @@ Object { "angle": 0, "backgroundColor": "transparent", "boundElementIds": null, + "endArrowhead": null, "endBinding": null, "fillStyle": "hachure", "groupIds": Array [], @@ -11311,6 +11530,7 @@ Object { ], "roughness": 1, "seed": 337897, + "startArrowhead": null, "startBinding": null, "strokeColor": "#000000", "strokeSharpness": "round", @@ -11355,6 +11575,7 @@ Object { "angle": 0, "backgroundColor": "transparent", "boundElementIds": null, + "endArrowhead": null, "endBinding": null, "fillStyle": "hachure", "groupIds": Array [], @@ -11375,6 +11596,7 @@ Object { ], "roughness": 1, "seed": 337897, + "startArrowhead": null, "startBinding": null, "strokeColor": "#000000", "strokeSharpness": "round", @@ -11401,6 +11623,10 @@ exports[`regression tests make a group and duplicate it: [end of test] appState Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -12109,6 +12335,10 @@ exports[`regression tests noop interaction after undo shouldn't create history e Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -12354,6 +12584,10 @@ exports[`regression tests pinch-to-zoom works: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -12448,6 +12682,10 @@ exports[`regression tests rerenders UI on language change: [end of test] appStat Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -12540,6 +12778,10 @@ exports[`regression tests selecting 'Add to library' in context menu adds elemen Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -12696,6 +12938,10 @@ exports[`regression tests selecting 'Bring forward' in context menu brings eleme Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -12996,6 +13242,10 @@ exports[`regression tests selecting 'Bring to front' in context menu brings elem Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -13296,6 +13546,10 @@ exports[`regression tests selecting 'Copy styles' in context menu copies styles: Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -13452,6 +13706,10 @@ exports[`regression tests selecting 'Delete' in context menu deletes element: [e Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -13640,6 +13898,10 @@ exports[`regression tests selecting 'Duplicate' in context menu duplicates eleme Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -13881,6 +14143,10 @@ exports[`regression tests selecting 'Group selection' in context menu groups sel Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -14197,6 +14463,10 @@ exports[`regression tests selecting 'Paste styles' in context menu pastes styles Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "#e64980", "currentItemFillStyle": "cross-hatch", "currentItemFontFamily": 1, @@ -15028,6 +15298,10 @@ exports[`regression tests selecting 'Send backward' in context menu sends elemen Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -15328,6 +15602,10 @@ exports[`regression tests selecting 'Send to back' in context menu sends element Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -15628,6 +15906,10 @@ exports[`regression tests selecting 'Ungroup selection' in context menu ungroups Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -15999,6 +16281,10 @@ exports[`regression tests shift click on selected element should deselect it on Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -16158,6 +16444,10 @@ exports[`regression tests shift-click to multiselect, then drag: [end of test] a Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -16471,6 +16761,10 @@ exports[`regression tests should show fill icons when element has non transparen Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "#fa5252", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -16702,6 +16996,10 @@ exports[`regression tests shows 'Group selection' in context menu for multiple s Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -16949,6 +17247,10 @@ exports[`regression tests shows 'Ungroup selection' in context menu for group in Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -17268,6 +17570,10 @@ exports[`regression tests shows context menu for canvas: [end of test] appState Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -17360,6 +17666,10 @@ exports[`regression tests shows context menu for element: [end of test] appState Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -17516,6 +17826,10 @@ exports[`regression tests single-clicking on a subgroup of a selected group shou Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -18329,6 +18643,10 @@ exports[`regression tests spacebar + drag scrolls the canvas: [end of test] appS Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -18421,6 +18739,10 @@ exports[`regression tests supports nested groups: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -19143,6 +19465,10 @@ exports[`regression tests switches from group of selected elements to another el Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -19540,6 +19866,10 @@ exports[`regression tests switches selected element on pointer down: [end of tes Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -19827,6 +20157,10 @@ exports[`regression tests two-finger scroll works: [end of test] appState 1`] = Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -19921,6 +20255,10 @@ exports[`regression tests undo/redo drawing an element: [end of test] appState 1 Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, @@ -20045,6 +20383,7 @@ Object { "angle": 0, "backgroundColor": "transparent", "boundElementIds": null, + "endArrowhead": "arrow", "endBinding": null, "fillStyle": "hachure", "groupIds": Array [], @@ -20068,6 +20407,7 @@ Object { ], "roughness": 1, "seed": 401146281, + "startArrowhead": null, "startBinding": null, "strokeColor": "#000000", "strokeSharpness": "round", @@ -20147,6 +20487,7 @@ Object { "angle": 0, "backgroundColor": "transparent", "boundElementIds": null, + "endArrowhead": "arrow", "endBinding": null, "fillStyle": "hachure", "groupIds": Array [], @@ -20174,6 +20515,7 @@ Object { ], "roughness": 1, "seed": 401146281, + "startArrowhead": null, "startBinding": null, "strokeColor": "#000000", "strokeSharpness": "round", @@ -20249,6 +20591,7 @@ Object { "angle": 0, "backgroundColor": "transparent", "boundElementIds": null, + "endArrowhead": "arrow", "endBinding": null, "fillStyle": "hachure", "groupIds": Array [], @@ -20272,6 +20615,7 @@ Object { ], "roughness": 1, "seed": 401146281, + "startArrowhead": null, "startBinding": null, "strokeColor": "#000000", "strokeSharpness": "round", @@ -20405,6 +20749,10 @@ exports[`regression tests updates fontSize & fontFamily appState: [end of test] Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 3, @@ -20497,6 +20845,10 @@ exports[`regression tests zoom hotkeys: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentItemArrowheads": Object { + "end": "arrow", + "start": null, + }, "currentItemBackgroundColor": "transparent", "currentItemFillStyle": "hachure", "currentItemFontFamily": 1, diff --git a/src/tests/__snapshots__/selection.test.tsx.snap b/src/tests/__snapshots__/selection.test.tsx.snap index c5294a86..5eb07b06 100644 --- a/src/tests/__snapshots__/selection.test.tsx.snap +++ b/src/tests/__snapshots__/selection.test.tsx.snap @@ -5,6 +5,7 @@ Object { "angle": 0, "backgroundColor": "transparent", "boundElementIds": null, + "endArrowhead": "arrow", "endBinding": null, "fillStyle": "hachure", "groupIds": Array [], @@ -25,6 +26,7 @@ Object { ], "roughness": 1, "seed": 337897, + "startArrowhead": null, "startBinding": null, "strokeColor": "#000000", "strokeSharpness": "round", @@ -44,6 +46,7 @@ Object { "angle": 0, "backgroundColor": "transparent", "boundElementIds": null, + "endArrowhead": null, "endBinding": null, "fillStyle": "hachure", "groupIds": Array [], @@ -64,6 +67,7 @@ Object { ], "roughness": 1, "seed": 337897, + "startArrowhead": null, "startBinding": null, "strokeColor": "#000000", "strokeSharpness": "round", diff --git a/src/tests/helpers/api.ts b/src/tests/helpers/api.ts index c0563296..37e9f08c 100644 --- a/src/tests/helpers/api.ts +++ b/src/tests/helpers/api.ts @@ -130,6 +130,8 @@ export class API { case "draw": element = newLinearElement({ type: type as "arrow" | "line" | "draw", + startArrowhead: null, + endArrowhead: null, ...base, }); break; diff --git a/src/types.ts b/src/types.ts index 377b2197..161b7263 100644 --- a/src/types.ts +++ b/src/types.ts @@ -8,6 +8,7 @@ import { FontFamily, GroupId, ExcalidrawBindableElement, + Arrowhead, } from "./element/types"; import { SHAPES } from "./shapes"; import { Point as RoughPoint } from "roughjs/bin/geometry"; @@ -60,6 +61,10 @@ export type AppState = { currentItemFontSize: number; currentItemTextAlign: TextAlign; currentItemStrokeSharpness: ExcalidrawElement["strokeSharpness"]; + currentItemArrowheads: { + start: Arrowhead | null; + end: Arrowhead | null; + }; currentItemLinearStrokeSharpness: ExcalidrawElement["strokeSharpness"]; viewBackgroundColor: string; scrollX: FlooredNumber;