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 }) => (
+
+ ),
+});
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")}