2021-01-05 20:06:14 +02:00
|
|
|
import { AppState } from "../../src/types";
|
|
|
|
import { ButtonIconSelect } from "../components/ButtonIconSelect";
|
|
|
|
import { ColorPicker } from "../components/ColorPicker";
|
|
|
|
import { IconPicker } from "../components/IconPicker";
|
2020-04-08 21:00:27 +01:00
|
|
|
import {
|
2021-01-05 20:06:14 +02:00
|
|
|
ArrowheadArrowIcon,
|
|
|
|
ArrowheadBarIcon,
|
|
|
|
ArrowheadDotIcon,
|
2021-10-27 18:27:39 +01:00
|
|
|
ArrowheadTriangleIcon,
|
2021-01-05 20:06:14 +02:00
|
|
|
ArrowheadNoneIcon,
|
|
|
|
EdgeRoundIcon,
|
|
|
|
EdgeSharpIcon,
|
|
|
|
FillCrossHatchIcon,
|
|
|
|
FillHachureIcon,
|
|
|
|
FillSolidIcon,
|
2021-06-13 21:26:55 +05:30
|
|
|
FontFamilyCodeIcon,
|
|
|
|
FontFamilyHandDrawnIcon,
|
|
|
|
FontFamilyNormalIcon,
|
|
|
|
FontSizeExtraLargeIcon,
|
|
|
|
FontSizeLargeIcon,
|
|
|
|
FontSizeMediumIcon,
|
|
|
|
FontSizeSmallIcon,
|
2021-01-05 20:06:14 +02:00
|
|
|
SloppinessArchitectIcon,
|
|
|
|
SloppinessArtistIcon,
|
|
|
|
SloppinessCartoonistIcon,
|
|
|
|
StrokeStyleDashedIcon,
|
|
|
|
StrokeStyleDottedIcon,
|
|
|
|
StrokeStyleSolidIcon,
|
|
|
|
StrokeWidthIcon,
|
2021-03-22 18:56:35 +05:30
|
|
|
TextAlignCenterIcon,
|
2021-06-13 21:26:55 +05:30
|
|
|
TextAlignLeftIcon,
|
2021-03-22 18:56:35 +05:30
|
|
|
TextAlignRightIcon,
|
2021-01-05 20:06:14 +02:00
|
|
|
} from "../components/icons";
|
2021-06-13 21:26:55 +05:30
|
|
|
import {
|
|
|
|
DEFAULT_FONT_FAMILY,
|
|
|
|
DEFAULT_FONT_SIZE,
|
|
|
|
FONT_FAMILY,
|
|
|
|
} from "../constants";
|
2021-01-05 20:06:14 +02:00
|
|
|
import {
|
|
|
|
getNonDeletedElements,
|
|
|
|
isTextElement,
|
|
|
|
redrawTextBoundingBox,
|
|
|
|
} from "../element";
|
|
|
|
import { newElementWith } from "../element/mutateElement";
|
2022-01-05 17:58:03 +05:30
|
|
|
import { getBoundTextElement } from "../element/textElement";
|
2021-01-05 20:06:14 +02:00
|
|
|
import { isLinearElement, isLinearElementType } from "../element/typeChecks";
|
|
|
|
import {
|
|
|
|
Arrowhead,
|
2020-04-08 21:00:27 +01:00
|
|
|
ExcalidrawElement,
|
2021-01-05 20:06:14 +02:00
|
|
|
ExcalidrawLinearElement,
|
2020-04-08 21:00:27 +01:00
|
|
|
ExcalidrawTextElement,
|
2021-06-13 21:26:55 +05:30
|
|
|
FontFamilyValues,
|
2021-01-05 20:06:14 +02:00
|
|
|
TextAlign,
|
2020-04-08 21:00:27 +01:00
|
|
|
} from "../element/types";
|
2021-01-05 20:06:14 +02:00
|
|
|
import { getLanguage, t } from "../i18n";
|
|
|
|
import { randomInteger } from "../random";
|
2020-02-16 22:54:50 +01:00
|
|
|
import {
|
2020-08-15 00:59:43 +09:00
|
|
|
canChangeSharpness,
|
2020-12-08 15:02:55 +00:00
|
|
|
canHaveArrowheads,
|
2021-01-05 20:06:14 +02:00
|
|
|
getCommonAttributeOfSelectedElements,
|
2021-12-29 16:49:52 +05:30
|
|
|
getSelectedElements,
|
2021-01-05 20:06:14 +02:00
|
|
|
getTargetElements,
|
|
|
|
isSomeElementSelected,
|
2020-02-16 22:54:50 +01:00
|
|
|
} from "../scene";
|
2021-10-21 22:05:48 +02:00
|
|
|
import { hasStrokeColor } from "../scene/comparisons";
|
2021-12-23 17:02:35 +05:30
|
|
|
import Scene from "../scene/Scene";
|
2021-12-29 16:49:52 +05:30
|
|
|
import { arrayToMap } from "../utils";
|
2020-03-07 10:20:38 -05:00
|
|
|
import { register } from "./register";
|
2020-01-12 02:22:03 +04:00
|
|
|
|
|
|
|
const changeProperty = (
|
|
|
|
elements: readonly ExcalidrawElement[],
|
2020-03-08 10:20:55 -07:00
|
|
|
appState: AppState,
|
2020-01-24 12:04:54 +02:00
|
|
|
callback: (element: ExcalidrawElement) => ExcalidrawElement,
|
2021-12-29 16:49:52 +05:30
|
|
|
includeBoundText = false,
|
2020-01-12 02:22:03 +04:00
|
|
|
) => {
|
2021-12-29 16:49:52 +05:30
|
|
|
const selectedElementIds = arrayToMap(
|
|
|
|
getSelectedElements(elements, appState, includeBoundText),
|
|
|
|
);
|
2020-03-23 13:05:07 +02:00
|
|
|
return elements.map((element) => {
|
2020-04-11 17:10:56 +01:00
|
|
|
if (
|
2021-12-29 16:49:52 +05:30
|
|
|
selectedElementIds.get(element.id) ||
|
2020-04-11 17:10:56 +01:00
|
|
|
element.id === appState.editingElement?.id
|
|
|
|
) {
|
2020-01-12 02:22:03 +04:00
|
|
|
return callback(element);
|
|
|
|
}
|
|
|
|
return element;
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2020-03-23 13:05:07 +02:00
|
|
|
const getFormValue = function <T>(
|
2020-01-21 00:16:22 +01:00
|
|
|
elements: readonly ExcalidrawElement[],
|
2020-03-08 10:20:55 -07:00
|
|
|
appState: AppState,
|
2020-01-21 00:16:22 +01:00
|
|
|
getAttribute: (element: ExcalidrawElement) => T,
|
2020-01-24 12:04:54 +02:00
|
|
|
defaultValue?: T,
|
2020-01-21 00:16:22 +01:00
|
|
|
): T | null {
|
2020-03-08 10:20:55 -07:00
|
|
|
const editingElement = appState.editingElement;
|
2020-04-08 09:49:52 -07:00
|
|
|
const nonDeletedElements = getNonDeletedElements(elements);
|
2020-01-21 00:16:22 +01:00
|
|
|
return (
|
2020-01-22 20:51:56 +01:00
|
|
|
(editingElement && getAttribute(editingElement)) ??
|
2020-04-08 09:49:52 -07:00
|
|
|
(isSomeElementSelected(nonDeletedElements, appState)
|
|
|
|
? getCommonAttributeOfSelectedElements(
|
|
|
|
nonDeletedElements,
|
|
|
|
appState,
|
|
|
|
getAttribute,
|
|
|
|
)
|
2020-01-26 04:12:47 -08:00
|
|
|
: defaultValue) ??
|
2020-01-21 00:16:22 +01:00
|
|
|
null
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
2020-03-07 10:20:38 -05:00
|
|
|
export const actionChangeStrokeColor = register({
|
2020-01-12 02:22:03 +04:00
|
|
|
name: "changeStrokeColor",
|
|
|
|
perform: (elements, appState, value) => {
|
|
|
|
return {
|
2021-05-28 17:22:42 +05:30
|
|
|
...(value.currentItemStrokeColor && {
|
2022-01-05 16:27:48 +05:30
|
|
|
elements: changeProperty(
|
|
|
|
elements,
|
|
|
|
appState,
|
|
|
|
(el) => {
|
|
|
|
return hasStrokeColor(el.type)
|
|
|
|
? newElementWith(el, {
|
|
|
|
strokeColor: value.currentItemStrokeColor,
|
|
|
|
})
|
|
|
|
: el;
|
|
|
|
},
|
|
|
|
true,
|
|
|
|
),
|
2021-05-28 17:22:42 +05:30
|
|
|
}),
|
|
|
|
appState: {
|
|
|
|
...appState,
|
|
|
|
...value,
|
|
|
|
},
|
|
|
|
commitToHistory: !!value.currentItemStrokeColor,
|
2020-01-12 02:22:03 +04:00
|
|
|
};
|
|
|
|
},
|
2020-01-31 21:06:06 +00:00
|
|
|
PanelComponent: ({ elements, appState, updateData }) => (
|
2020-01-21 00:16:22 +01:00
|
|
|
<>
|
2020-01-25 14:52:03 -03:00
|
|
|
<h3 aria-hidden="true">{t("labels.stroke")}</h3>
|
2020-01-21 00:16:22 +01:00
|
|
|
<ColorPicker
|
|
|
|
type="elementStroke"
|
2020-01-25 14:52:03 -03:00
|
|
|
label={t("labels.stroke")}
|
2020-01-21 00:16:22 +01:00
|
|
|
color={getFormValue(
|
|
|
|
elements,
|
2020-03-08 10:20:55 -07:00
|
|
|
appState,
|
2020-03-23 13:05:07 +02:00
|
|
|
(element) => element.strokeColor,
|
2020-01-24 12:04:54 +02:00
|
|
|
appState.currentItemStrokeColor,
|
2020-01-21 00:16:22 +01:00
|
|
|
)}
|
2021-05-28 17:22:42 +05:30
|
|
|
onChange={(color) => updateData({ currentItemStrokeColor: color })}
|
2021-05-30 12:05:07 +02:00
|
|
|
isActive={appState.openPopup === "strokeColorPicker"}
|
2021-05-28 17:22:42 +05:30
|
|
|
setActive={(active) =>
|
2021-05-30 12:05:07 +02:00
|
|
|
updateData({ openPopup: active ? "strokeColorPicker" : null })
|
2021-05-28 17:22:42 +05:30
|
|
|
}
|
2020-01-21 00:16:22 +01:00
|
|
|
/>
|
|
|
|
</>
|
2020-01-24 12:04:54 +02:00
|
|
|
),
|
2020-03-07 10:20:38 -05:00
|
|
|
});
|
2020-01-12 02:22:03 +04:00
|
|
|
|
2020-03-07 10:20:38 -05:00
|
|
|
export const actionChangeBackgroundColor = register({
|
2020-01-12 02:22:03 +04:00
|
|
|
name: "changeBackgroundColor",
|
|
|
|
perform: (elements, appState, value) => {
|
|
|
|
return {
|
2021-05-28 17:22:42 +05:30
|
|
|
...(value.currentItemBackgroundColor && {
|
|
|
|
elements: changeProperty(elements, appState, (el) =>
|
|
|
|
newElementWith(el, {
|
|
|
|
backgroundColor: value.currentItemBackgroundColor,
|
|
|
|
}),
|
|
|
|
),
|
|
|
|
}),
|
|
|
|
appState: {
|
|
|
|
...appState,
|
|
|
|
...value,
|
|
|
|
},
|
|
|
|
commitToHistory: !!value.currentItemBackgroundColor,
|
2020-01-12 02:22:03 +04:00
|
|
|
};
|
|
|
|
},
|
2020-01-31 21:06:06 +00:00
|
|
|
PanelComponent: ({ elements, appState, updateData }) => (
|
2020-01-15 20:42:02 +05:00
|
|
|
<>
|
2020-01-25 14:52:03 -03:00
|
|
|
<h3 aria-hidden="true">{t("labels.background")}</h3>
|
2020-01-15 20:42:02 +05:00
|
|
|
<ColorPicker
|
|
|
|
type="elementBackground"
|
2020-01-25 14:52:03 -03:00
|
|
|
label={t("labels.background")}
|
2020-01-21 00:16:22 +01:00
|
|
|
color={getFormValue(
|
|
|
|
elements,
|
2020-03-08 10:20:55 -07:00
|
|
|
appState,
|
2020-03-23 13:05:07 +02:00
|
|
|
(element) => element.backgroundColor,
|
2020-01-24 12:04:54 +02:00
|
|
|
appState.currentItemBackgroundColor,
|
2020-01-21 00:16:22 +01:00
|
|
|
)}
|
2021-05-28 17:22:42 +05:30
|
|
|
onChange={(color) => updateData({ currentItemBackgroundColor: color })}
|
2021-05-30 12:05:07 +02:00
|
|
|
isActive={appState.openPopup === "backgroundColorPicker"}
|
2021-05-28 17:22:42 +05:30
|
|
|
setActive={(active) =>
|
2021-05-30 12:05:07 +02:00
|
|
|
updateData({ openPopup: active ? "backgroundColorPicker" : null })
|
2021-05-28 17:22:42 +05:30
|
|
|
}
|
2020-01-15 20:42:02 +05:00
|
|
|
/>
|
|
|
|
</>
|
2020-01-24 12:04:54 +02:00
|
|
|
),
|
2020-03-07 10:20:38 -05:00
|
|
|
});
|
2020-01-12 02:22:03 +04:00
|
|
|
|
2020-03-07 10:20:38 -05:00
|
|
|
export const actionChangeFillStyle = register({
|
2020-01-12 02:22:03 +04:00
|
|
|
name: "changeFillStyle",
|
|
|
|
perform: (elements, appState, value) => {
|
|
|
|
return {
|
2020-03-23 13:05:07 +02:00
|
|
|
elements: changeProperty(elements, appState, (el) =>
|
2020-03-10 20:11:02 -07:00
|
|
|
newElementWith(el, {
|
|
|
|
fillStyle: value,
|
|
|
|
}),
|
|
|
|
),
|
2020-01-25 18:58:57 +01:00
|
|
|
appState: { ...appState, currentItemFillStyle: value },
|
2020-03-19 14:51:05 +01:00
|
|
|
commitToHistory: true,
|
2020-01-12 02:22:03 +04:00
|
|
|
};
|
|
|
|
},
|
2020-01-31 21:06:06 +00:00
|
|
|
PanelComponent: ({ elements, appState, updateData }) => (
|
2020-01-25 14:52:03 -03:00
|
|
|
<fieldset>
|
|
|
|
<legend>{t("labels.fill")}</legend>
|
2020-11-01 20:08:48 +01:00
|
|
|
<ButtonIconSelect
|
2020-01-12 02:22:03 +04:00
|
|
|
options={[
|
2020-11-01 20:08:48 +01:00
|
|
|
{
|
|
|
|
value: "hachure",
|
|
|
|
text: t("labels.hachure"),
|
2021-03-13 18:58:06 +05:30
|
|
|
icon: <FillHachureIcon theme={appState.theme} />,
|
2020-11-01 20:08:48 +01:00
|
|
|
},
|
|
|
|
{
|
|
|
|
value: "cross-hatch",
|
|
|
|
text: t("labels.crossHatch"),
|
2021-03-13 18:58:06 +05:30
|
|
|
icon: <FillCrossHatchIcon theme={appState.theme} />,
|
2020-11-01 20:08:48 +01:00
|
|
|
},
|
|
|
|
{
|
|
|
|
value: "solid",
|
|
|
|
text: t("labels.solid"),
|
2021-03-13 18:58:06 +05:30
|
|
|
icon: <FillSolidIcon theme={appState.theme} />,
|
2020-11-01 20:08:48 +01:00
|
|
|
},
|
2020-01-12 02:22:03 +04:00
|
|
|
]}
|
2020-01-25 14:52:03 -03:00
|
|
|
group="fill"
|
2020-01-21 00:16:22 +01:00
|
|
|
value={getFormValue(
|
|
|
|
elements,
|
2020-03-08 10:20:55 -07:00
|
|
|
appState,
|
2020-03-23 13:05:07 +02:00
|
|
|
(element) => element.fillStyle,
|
2020-01-26 19:09:11 +00:00
|
|
|
appState.currentItemFillStyle,
|
2020-01-21 00:16:22 +01:00
|
|
|
)}
|
2020-03-23 13:05:07 +02:00
|
|
|
onChange={(value) => {
|
2020-01-12 02:22:03 +04:00
|
|
|
updateData(value);
|
|
|
|
}}
|
|
|
|
/>
|
2020-01-25 14:52:03 -03:00
|
|
|
</fieldset>
|
2020-01-24 12:04:54 +02:00
|
|
|
),
|
2020-03-07 10:20:38 -05:00
|
|
|
});
|
2020-01-12 02:22:03 +04:00
|
|
|
|
2020-03-07 10:20:38 -05:00
|
|
|
export const actionChangeStrokeWidth = register({
|
2020-01-12 02:22:03 +04:00
|
|
|
name: "changeStrokeWidth",
|
|
|
|
perform: (elements, appState, value) => {
|
|
|
|
return {
|
2020-03-23 13:05:07 +02:00
|
|
|
elements: changeProperty(elements, appState, (el) =>
|
2020-03-10 20:11:02 -07:00
|
|
|
newElementWith(el, {
|
|
|
|
strokeWidth: value,
|
|
|
|
}),
|
|
|
|
),
|
2020-01-25 18:58:57 +01:00
|
|
|
appState: { ...appState, currentItemStrokeWidth: value },
|
2020-03-19 14:51:05 +01:00
|
|
|
commitToHistory: true,
|
2020-01-12 02:22:03 +04:00
|
|
|
};
|
|
|
|
},
|
2020-01-31 21:06:06 +00:00
|
|
|
PanelComponent: ({ elements, appState, updateData }) => (
|
2020-01-25 14:52:03 -03:00
|
|
|
<fieldset>
|
|
|
|
<legend>{t("labels.strokeWidth")}</legend>
|
2020-11-01 20:08:48 +01:00
|
|
|
<ButtonIconSelect
|
2020-01-25 14:52:03 -03:00
|
|
|
group="stroke-width"
|
2020-01-12 02:22:03 +04:00
|
|
|
options={[
|
2020-11-01 20:08:48 +01:00
|
|
|
{
|
|
|
|
value: 1,
|
|
|
|
text: t("labels.thin"),
|
2021-03-13 18:58:06 +05:30
|
|
|
icon: <StrokeWidthIcon theme={appState.theme} strokeWidth={2} />,
|
2020-11-01 20:08:48 +01:00
|
|
|
},
|
|
|
|
{
|
|
|
|
value: 2,
|
|
|
|
text: t("labels.bold"),
|
2021-03-13 18:58:06 +05:30
|
|
|
icon: <StrokeWidthIcon theme={appState.theme} strokeWidth={6} />,
|
2020-11-01 20:08:48 +01:00
|
|
|
},
|
|
|
|
{
|
|
|
|
value: 4,
|
|
|
|
text: t("labels.extraBold"),
|
2021-03-13 18:58:06 +05:30
|
|
|
icon: <StrokeWidthIcon theme={appState.theme} strokeWidth={10} />,
|
2020-11-01 20:08:48 +01:00
|
|
|
},
|
2020-01-12 02:22:03 +04:00
|
|
|
]}
|
2020-01-21 00:16:22 +01:00
|
|
|
value={getFormValue(
|
|
|
|
elements,
|
2020-03-08 10:20:55 -07:00
|
|
|
appState,
|
2020-03-23 13:05:07 +02:00
|
|
|
(element) => element.strokeWidth,
|
2020-01-26 19:09:11 +00:00
|
|
|
appState.currentItemStrokeWidth,
|
2020-01-21 00:16:22 +01:00
|
|
|
)}
|
2020-03-23 13:05:07 +02:00
|
|
|
onChange={(value) => updateData(value)}
|
2020-01-12 02:22:03 +04:00
|
|
|
/>
|
2020-01-25 14:52:03 -03:00
|
|
|
</fieldset>
|
2020-01-24 12:04:54 +02:00
|
|
|
),
|
2020-03-07 10:20:38 -05:00
|
|
|
});
|
2020-01-12 02:22:03 +04:00
|
|
|
|
2020-03-07 10:20:38 -05:00
|
|
|
export const actionChangeSloppiness = register({
|
2020-01-12 02:22:03 +04:00
|
|
|
name: "changeSloppiness",
|
|
|
|
perform: (elements, appState, value) => {
|
|
|
|
return {
|
2020-03-23 13:05:07 +02:00
|
|
|
elements: changeProperty(elements, appState, (el) =>
|
2020-03-10 20:11:02 -07:00
|
|
|
newElementWith(el, {
|
2020-07-30 20:14:38 +02:00
|
|
|
seed: randomInteger(),
|
2020-03-10 20:11:02 -07:00
|
|
|
roughness: value,
|
|
|
|
}),
|
|
|
|
),
|
2020-01-25 18:58:57 +01:00
|
|
|
appState: { ...appState, currentItemRoughness: value },
|
2020-03-19 14:51:05 +01:00
|
|
|
commitToHistory: true,
|
2020-01-12 02:22:03 +04:00
|
|
|
};
|
|
|
|
},
|
2020-01-31 21:06:06 +00:00
|
|
|
PanelComponent: ({ elements, appState, updateData }) => (
|
2020-01-25 14:52:03 -03:00
|
|
|
<fieldset>
|
|
|
|
<legend>{t("labels.sloppiness")}</legend>
|
2020-11-01 20:08:48 +01:00
|
|
|
<ButtonIconSelect
|
2020-01-25 14:52:03 -03:00
|
|
|
group="sloppiness"
|
2020-01-12 02:22:03 +04:00
|
|
|
options={[
|
2020-11-01 20:08:48 +01:00
|
|
|
{
|
|
|
|
value: 0,
|
|
|
|
text: t("labels.architect"),
|
2021-03-13 18:58:06 +05:30
|
|
|
icon: <SloppinessArchitectIcon theme={appState.theme} />,
|
2020-11-01 20:08:48 +01:00
|
|
|
},
|
|
|
|
{
|
|
|
|
value: 1,
|
|
|
|
text: t("labels.artist"),
|
2021-03-13 18:58:06 +05:30
|
|
|
icon: <SloppinessArtistIcon theme={appState.theme} />,
|
2020-11-01 20:08:48 +01:00
|
|
|
},
|
|
|
|
{
|
|
|
|
value: 2,
|
|
|
|
text: t("labels.cartoonist"),
|
2021-03-13 18:58:06 +05:30
|
|
|
icon: <SloppinessCartoonistIcon theme={appState.theme} />,
|
2020-11-01 20:08:48 +01:00
|
|
|
},
|
2020-01-12 02:22:03 +04:00
|
|
|
]}
|
2020-01-21 00:16:22 +01:00
|
|
|
value={getFormValue(
|
|
|
|
elements,
|
2020-03-08 10:20:55 -07:00
|
|
|
appState,
|
2020-03-23 13:05:07 +02:00
|
|
|
(element) => element.roughness,
|
2020-01-26 19:09:11 +00:00
|
|
|
appState.currentItemRoughness,
|
2020-01-21 00:16:22 +01:00
|
|
|
)}
|
2020-03-23 13:05:07 +02:00
|
|
|
onChange={(value) => updateData(value)}
|
2020-01-12 02:22:03 +04:00
|
|
|
/>
|
2020-01-25 14:52:03 -03:00
|
|
|
</fieldset>
|
2020-01-24 12:04:54 +02:00
|
|
|
),
|
2020-03-07 10:20:38 -05:00
|
|
|
});
|
2020-01-12 02:22:03 +04:00
|
|
|
|
2020-05-14 17:04:33 +02:00
|
|
|
export const actionChangeStrokeStyle = register({
|
|
|
|
name: "changeStrokeStyle",
|
|
|
|
perform: (elements, appState, value) => {
|
|
|
|
return {
|
|
|
|
elements: changeProperty(elements, appState, (el) =>
|
|
|
|
newElementWith(el, {
|
|
|
|
strokeStyle: value,
|
|
|
|
}),
|
|
|
|
),
|
|
|
|
appState: { ...appState, currentItemStrokeStyle: value },
|
|
|
|
commitToHistory: true,
|
|
|
|
};
|
|
|
|
},
|
|
|
|
PanelComponent: ({ elements, appState, updateData }) => (
|
|
|
|
<fieldset>
|
|
|
|
<legend>{t("labels.strokeStyle")}</legend>
|
2020-11-01 20:08:48 +01:00
|
|
|
<ButtonIconSelect
|
2020-05-14 17:04:33 +02:00
|
|
|
group="strokeStyle"
|
|
|
|
options={[
|
2020-11-01 20:08:48 +01:00
|
|
|
{
|
|
|
|
value: "solid",
|
|
|
|
text: t("labels.strokeStyle_solid"),
|
2021-03-13 18:58:06 +05:30
|
|
|
icon: <StrokeStyleSolidIcon theme={appState.theme} />,
|
2020-11-01 20:08:48 +01:00
|
|
|
},
|
|
|
|
{
|
|
|
|
value: "dashed",
|
|
|
|
text: t("labels.strokeStyle_dashed"),
|
2021-03-13 18:58:06 +05:30
|
|
|
icon: <StrokeStyleDashedIcon theme={appState.theme} />,
|
2020-11-01 20:08:48 +01:00
|
|
|
},
|
|
|
|
{
|
|
|
|
value: "dotted",
|
|
|
|
text: t("labels.strokeStyle_dotted"),
|
2021-03-13 18:58:06 +05:30
|
|
|
icon: <StrokeStyleDottedIcon theme={appState.theme} />,
|
2020-11-01 20:08:48 +01:00
|
|
|
},
|
2020-05-14 17:04:33 +02:00
|
|
|
]}
|
|
|
|
value={getFormValue(
|
|
|
|
elements,
|
|
|
|
appState,
|
|
|
|
(element) => element.strokeStyle,
|
|
|
|
appState.currentItemStrokeStyle,
|
|
|
|
)}
|
|
|
|
onChange={(value) => updateData(value)}
|
|
|
|
/>
|
|
|
|
</fieldset>
|
|
|
|
),
|
|
|
|
});
|
|
|
|
|
2020-03-07 10:20:38 -05:00
|
|
|
export const actionChangeOpacity = register({
|
2020-01-12 02:22:03 +04:00
|
|
|
name: "changeOpacity",
|
|
|
|
perform: (elements, appState, value) => {
|
|
|
|
return {
|
2020-03-23 13:05:07 +02:00
|
|
|
elements: changeProperty(elements, appState, (el) =>
|
2020-03-10 20:11:02 -07:00
|
|
|
newElementWith(el, {
|
|
|
|
opacity: value,
|
|
|
|
}),
|
|
|
|
),
|
2020-01-25 18:58:57 +01:00
|
|
|
appState: { ...appState, currentItemOpacity: value },
|
2020-03-19 14:51:05 +01:00
|
|
|
commitToHistory: true,
|
2020-01-12 02:22:03 +04:00
|
|
|
};
|
|
|
|
},
|
2020-01-31 21:06:06 +00:00
|
|
|
PanelComponent: ({ elements, appState, updateData }) => (
|
2020-01-25 14:52:03 -03:00
|
|
|
<label className="control-label">
|
|
|
|
{t("labels.opacity")}
|
2020-01-12 02:22:03 +04:00
|
|
|
<input
|
|
|
|
type="range"
|
|
|
|
min="0"
|
|
|
|
max="100"
|
2020-02-02 17:09:50 -08:00
|
|
|
step="10"
|
2020-03-23 13:05:07 +02:00
|
|
|
onChange={(event) => updateData(+event.target.value)}
|
|
|
|
onWheel={(event) => {
|
2020-02-28 23:03:53 +01:00
|
|
|
event.stopPropagation();
|
|
|
|
const target = event.target as HTMLInputElement;
|
2020-02-03 01:48:41 +00:00
|
|
|
const STEP = 10;
|
|
|
|
const MAX = 100;
|
|
|
|
const MIN = 0;
|
|
|
|
const value = +target.value;
|
|
|
|
|
2020-02-28 23:03:53 +01:00
|
|
|
if (event.deltaY < 0 && value < MAX) {
|
2020-02-03 01:48:41 +00:00
|
|
|
updateData(value + STEP);
|
2020-02-28 23:03:53 +01:00
|
|
|
} else if (event.deltaY > 0 && value > MIN) {
|
2020-02-03 01:48:41 +00:00
|
|
|
updateData(value - STEP);
|
|
|
|
}
|
|
|
|
}}
|
2020-01-12 02:22:03 +04:00
|
|
|
value={
|
2020-01-21 00:16:22 +01:00
|
|
|
getFormValue(
|
|
|
|
elements,
|
2020-03-08 10:20:55 -07:00
|
|
|
appState,
|
2020-03-23 13:05:07 +02:00
|
|
|
(element) => element.opacity,
|
2020-01-26 19:09:11 +00:00
|
|
|
appState.currentItemOpacity,
|
2020-01-22 20:51:56 +01:00
|
|
|
) ?? undefined
|
2020-01-12 02:22:03 +04:00
|
|
|
}
|
|
|
|
/>
|
2020-01-25 14:52:03 -03:00
|
|
|
</label>
|
2020-01-24 12:04:54 +02:00
|
|
|
),
|
2020-03-07 10:20:38 -05:00
|
|
|
});
|
2020-01-12 02:22:03 +04:00
|
|
|
|
2020-03-07 10:20:38 -05:00
|
|
|
export const actionChangeFontSize = register({
|
2020-01-12 02:22:03 +04:00
|
|
|
name: "changeFontSize",
|
|
|
|
perform: (elements, appState, value) => {
|
|
|
|
return {
|
2021-12-29 16:49:52 +05:30
|
|
|
elements: changeProperty(
|
|
|
|
elements,
|
|
|
|
appState,
|
|
|
|
(el) => {
|
|
|
|
if (isTextElement(el)) {
|
|
|
|
const element: ExcalidrawTextElement = newElementWith(el, {
|
|
|
|
fontSize: value,
|
|
|
|
});
|
|
|
|
let container = null;
|
|
|
|
if (el.containerId) {
|
|
|
|
container = Scene.getScene(el)!.getElement(el.containerId);
|
|
|
|
}
|
|
|
|
redrawTextBoundingBox(element, container, appState);
|
|
|
|
return element;
|
2021-12-23 17:02:35 +05:30
|
|
|
}
|
2020-01-12 02:22:03 +04:00
|
|
|
|
2021-12-29 16:49:52 +05:30
|
|
|
return el;
|
|
|
|
},
|
|
|
|
true,
|
|
|
|
),
|
2020-01-25 18:58:57 +01:00
|
|
|
appState: {
|
|
|
|
...appState,
|
2020-05-27 15:14:50 +02:00
|
|
|
currentItemFontSize: value,
|
2020-01-25 18:58:57 +01:00
|
|
|
},
|
2020-03-19 14:51:05 +01:00
|
|
|
commitToHistory: true,
|
2020-01-12 02:22:03 +04:00
|
|
|
};
|
|
|
|
},
|
2020-01-31 21:06:06 +00:00
|
|
|
PanelComponent: ({ elements, appState, updateData }) => (
|
2020-01-25 14:52:03 -03:00
|
|
|
<fieldset>
|
|
|
|
<legend>{t("labels.fontSize")}</legend>
|
2021-03-22 18:56:35 +05:30
|
|
|
<ButtonIconSelect
|
2020-01-25 14:52:03 -03:00
|
|
|
group="font-size"
|
2020-01-12 02:22:03 +04:00
|
|
|
options={[
|
2021-03-22 18:56:35 +05:30
|
|
|
{
|
|
|
|
value: 16,
|
|
|
|
text: t("labels.small"),
|
|
|
|
icon: <FontSizeSmallIcon theme={appState.theme} />,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
value: 20,
|
|
|
|
text: t("labels.medium"),
|
|
|
|
icon: <FontSizeMediumIcon theme={appState.theme} />,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
value: 28,
|
|
|
|
text: t("labels.large"),
|
|
|
|
icon: <FontSizeLargeIcon theme={appState.theme} />,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
value: 36,
|
|
|
|
text: t("labels.veryLarge"),
|
|
|
|
icon: <FontSizeExtraLargeIcon theme={appState.theme} />,
|
|
|
|
},
|
2020-01-12 02:22:03 +04:00
|
|
|
]}
|
2020-01-21 00:16:22 +01:00
|
|
|
value={getFormValue(
|
2020-01-12 02:22:03 +04:00
|
|
|
elements,
|
2020-03-08 10:20:55 -07:00
|
|
|
appState,
|
2022-01-05 17:58:03 +05:30
|
|
|
(element) => {
|
|
|
|
if (isTextElement(element)) {
|
|
|
|
return element.fontSize;
|
|
|
|
}
|
|
|
|
const boundTextElement = getBoundTextElement(element);
|
|
|
|
if (boundTextElement) {
|
|
|
|
return boundTextElement.fontSize;
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
},
|
2020-05-27 15:14:50 +02:00
|
|
|
appState.currentItemFontSize || DEFAULT_FONT_SIZE,
|
2020-01-12 02:22:03 +04:00
|
|
|
)}
|
2020-03-23 13:05:07 +02:00
|
|
|
onChange={(value) => updateData(value)}
|
2020-01-12 02:22:03 +04:00
|
|
|
/>
|
2020-01-25 14:52:03 -03:00
|
|
|
</fieldset>
|
2020-01-24 12:04:54 +02:00
|
|
|
),
|
2020-03-07 10:20:38 -05:00
|
|
|
});
|
2020-01-12 02:22:03 +04:00
|
|
|
|
2020-03-07 10:20:38 -05:00
|
|
|
export const actionChangeFontFamily = register({
|
2020-01-12 02:22:03 +04:00
|
|
|
name: "changeFontFamily",
|
|
|
|
perform: (elements, appState, value) => {
|
|
|
|
return {
|
2021-12-29 16:49:52 +05:30
|
|
|
elements: changeProperty(
|
|
|
|
elements,
|
|
|
|
appState,
|
|
|
|
(el) => {
|
|
|
|
if (isTextElement(el)) {
|
|
|
|
const element: ExcalidrawTextElement = newElementWith(el, {
|
|
|
|
fontFamily: value,
|
|
|
|
});
|
|
|
|
let container = null;
|
|
|
|
if (el.containerId) {
|
|
|
|
container = Scene.getScene(el)!.getElement(el.containerId);
|
|
|
|
}
|
|
|
|
redrawTextBoundingBox(element, container, appState);
|
|
|
|
return element;
|
2021-12-23 17:02:35 +05:30
|
|
|
}
|
2020-01-12 02:22:03 +04:00
|
|
|
|
2021-12-29 16:49:52 +05:30
|
|
|
return el;
|
|
|
|
},
|
|
|
|
true,
|
|
|
|
),
|
2020-01-25 18:58:57 +01:00
|
|
|
appState: {
|
|
|
|
...appState,
|
2020-05-29 21:59:39 +02:00
|
|
|
currentItemFontFamily: value,
|
2020-01-25 18:58:57 +01:00
|
|
|
},
|
2020-03-19 14:51:05 +01:00
|
|
|
commitToHistory: true,
|
2020-01-12 02:22:03 +04:00
|
|
|
};
|
|
|
|
},
|
2020-05-27 15:14:50 +02:00
|
|
|
PanelComponent: ({ elements, appState, updateData }) => {
|
2021-06-13 21:26:55 +05:30
|
|
|
const options: {
|
|
|
|
value: FontFamilyValues;
|
|
|
|
text: string;
|
|
|
|
icon: JSX.Element;
|
|
|
|
}[] = [
|
2021-03-22 18:56:35 +05:30
|
|
|
{
|
2021-06-13 21:26:55 +05:30
|
|
|
value: FONT_FAMILY.Virgil,
|
2021-03-22 18:56:35 +05:30
|
|
|
text: t("labels.handDrawn"),
|
|
|
|
icon: <FontFamilyHandDrawnIcon theme={appState.theme} />,
|
|
|
|
},
|
|
|
|
{
|
2021-06-13 21:26:55 +05:30
|
|
|
value: FONT_FAMILY.Helvetica,
|
2021-03-22 18:56:35 +05:30
|
|
|
text: t("labels.normal"),
|
|
|
|
icon: <FontFamilyNormalIcon theme={appState.theme} />,
|
|
|
|
},
|
|
|
|
{
|
2021-06-13 21:26:55 +05:30
|
|
|
value: FONT_FAMILY.Cascadia,
|
2021-03-22 18:56:35 +05:30
|
|
|
text: t("labels.code"),
|
|
|
|
icon: <FontFamilyCodeIcon theme={appState.theme} />,
|
|
|
|
},
|
2020-05-27 15:14:50 +02:00
|
|
|
];
|
|
|
|
|
|
|
|
return (
|
|
|
|
<fieldset>
|
|
|
|
<legend>{t("labels.fontFamily")}</legend>
|
2021-06-13 21:26:55 +05:30
|
|
|
<ButtonIconSelect<FontFamilyValues | false>
|
2020-05-27 15:14:50 +02:00
|
|
|
group="font-family"
|
|
|
|
options={options}
|
|
|
|
value={getFormValue(
|
|
|
|
elements,
|
|
|
|
appState,
|
2022-01-05 17:58:03 +05:30
|
|
|
(element) => {
|
|
|
|
if (isTextElement(element)) {
|
|
|
|
return element.fontFamily;
|
|
|
|
}
|
|
|
|
const boundTextElement = getBoundTextElement(element);
|
|
|
|
if (boundTextElement) {
|
|
|
|
return boundTextElement.fontFamily;
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
},
|
2020-05-27 15:14:50 +02:00
|
|
|
appState.currentItemFontFamily || DEFAULT_FONT_FAMILY,
|
|
|
|
)}
|
|
|
|
onChange={(value) => updateData(value)}
|
|
|
|
/>
|
|
|
|
</fieldset>
|
|
|
|
);
|
|
|
|
},
|
2020-03-07 10:20:38 -05:00
|
|
|
});
|
2020-04-08 21:00:27 +01:00
|
|
|
|
|
|
|
export const actionChangeTextAlign = register({
|
|
|
|
name: "changeTextAlign",
|
|
|
|
perform: (elements, appState, value) => {
|
|
|
|
return {
|
2021-12-29 16:49:52 +05:30
|
|
|
elements: changeProperty(
|
|
|
|
elements,
|
|
|
|
appState,
|
|
|
|
(el) => {
|
|
|
|
if (isTextElement(el)) {
|
|
|
|
const element: ExcalidrawTextElement = newElementWith(el, {
|
|
|
|
textAlign: value,
|
|
|
|
});
|
|
|
|
let container = null;
|
|
|
|
if (el.containerId) {
|
|
|
|
container = Scene.getScene(el)!.getElement(el.containerId);
|
|
|
|
}
|
|
|
|
redrawTextBoundingBox(element, container, appState);
|
|
|
|
return element;
|
2021-12-23 17:02:35 +05:30
|
|
|
}
|
2020-04-08 21:00:27 +01:00
|
|
|
|
2021-12-29 16:49:52 +05:30
|
|
|
return el;
|
|
|
|
},
|
|
|
|
true,
|
|
|
|
),
|
2020-04-08 21:00:27 +01:00
|
|
|
appState: {
|
|
|
|
...appState,
|
|
|
|
currentItemTextAlign: value,
|
|
|
|
},
|
|
|
|
commitToHistory: true,
|
|
|
|
};
|
|
|
|
},
|
|
|
|
PanelComponent: ({ elements, appState, updateData }) => (
|
|
|
|
<fieldset>
|
|
|
|
<legend>{t("labels.textAlign")}</legend>
|
2021-03-22 18:56:35 +05:30
|
|
|
<ButtonIconSelect<TextAlign | false>
|
2020-04-08 21:00:27 +01:00
|
|
|
group="text-align"
|
|
|
|
options={[
|
2021-03-22 18:56:35 +05:30
|
|
|
{
|
|
|
|
value: "left",
|
|
|
|
text: t("labels.left"),
|
|
|
|
icon: <TextAlignLeftIcon theme={appState.theme} />,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
value: "center",
|
|
|
|
text: t("labels.center"),
|
|
|
|
icon: <TextAlignCenterIcon theme={appState.theme} />,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
value: "right",
|
|
|
|
text: t("labels.right"),
|
|
|
|
icon: <TextAlignRightIcon theme={appState.theme} />,
|
|
|
|
},
|
2020-04-08 21:00:27 +01:00
|
|
|
]}
|
|
|
|
value={getFormValue(
|
|
|
|
elements,
|
|
|
|
appState,
|
2022-01-05 17:58:03 +05:30
|
|
|
(element) => {
|
|
|
|
if (isTextElement(element)) {
|
|
|
|
return element.textAlign;
|
|
|
|
}
|
|
|
|
const boundTextElement = getBoundTextElement(element);
|
|
|
|
if (boundTextElement) {
|
|
|
|
return boundTextElement.textAlign;
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
},
|
2020-04-08 21:00:27 +01:00
|
|
|
appState.currentItemTextAlign,
|
|
|
|
)}
|
|
|
|
onChange={(value) => updateData(value)}
|
|
|
|
/>
|
|
|
|
</fieldset>
|
|
|
|
),
|
|
|
|
});
|
2020-08-15 00:59:43 +09:00
|
|
|
|
|
|
|
export const actionChangeSharpness = register({
|
|
|
|
name: "changeSharpness",
|
|
|
|
perform: (elements, appState, value) => {
|
2020-12-07 18:35:16 +02:00
|
|
|
const targetElements = getTargetElements(
|
2020-08-15 00:59:43 +09:00
|
|
|
getNonDeletedElements(elements),
|
|
|
|
appState,
|
|
|
|
);
|
|
|
|
const shouldUpdateForNonLinearElements = targetElements.length
|
2020-11-05 19:06:18 +02:00
|
|
|
? targetElements.every((el) => !isLinearElement(el))
|
2020-08-15 00:59:43 +09:00
|
|
|
: !isLinearElementType(appState.elementType);
|
|
|
|
const shouldUpdateForLinearElements = targetElements.length
|
|
|
|
? targetElements.every(isLinearElement)
|
|
|
|
: isLinearElementType(appState.elementType);
|
|
|
|
return {
|
|
|
|
elements: changeProperty(elements, appState, (el) =>
|
|
|
|
newElementWith(el, {
|
|
|
|
strokeSharpness: value,
|
|
|
|
}),
|
|
|
|
),
|
|
|
|
appState: {
|
|
|
|
...appState,
|
|
|
|
currentItemStrokeSharpness: shouldUpdateForNonLinearElements
|
|
|
|
? value
|
|
|
|
: appState.currentItemStrokeSharpness,
|
|
|
|
currentItemLinearStrokeSharpness: shouldUpdateForLinearElements
|
|
|
|
? value
|
|
|
|
: appState.currentItemLinearStrokeSharpness,
|
|
|
|
},
|
|
|
|
commitToHistory: true,
|
|
|
|
};
|
|
|
|
},
|
|
|
|
PanelComponent: ({ elements, appState, updateData }) => (
|
|
|
|
<fieldset>
|
|
|
|
<legend>{t("labels.edges")}</legend>
|
2020-11-01 20:08:48 +01:00
|
|
|
<ButtonIconSelect
|
2020-08-15 00:59:43 +09:00
|
|
|
group="edges"
|
|
|
|
options={[
|
2020-11-01 20:08:48 +01:00
|
|
|
{
|
|
|
|
value: "sharp",
|
|
|
|
text: t("labels.sharp"),
|
2021-03-13 18:58:06 +05:30
|
|
|
icon: <EdgeSharpIcon theme={appState.theme} />,
|
2020-11-01 20:08:48 +01:00
|
|
|
},
|
|
|
|
{
|
|
|
|
value: "round",
|
|
|
|
text: t("labels.round"),
|
2021-03-13 18:58:06 +05:30
|
|
|
icon: <EdgeRoundIcon theme={appState.theme} />,
|
2020-11-01 20:08:48 +01:00
|
|
|
},
|
2020-08-15 00:59:43 +09:00
|
|
|
]}
|
|
|
|
value={getFormValue(
|
|
|
|
elements,
|
|
|
|
appState,
|
|
|
|
(element) => element.strokeSharpness,
|
|
|
|
(canChangeSharpness(appState.elementType) &&
|
|
|
|
(isLinearElementType(appState.elementType)
|
|
|
|
? appState.currentItemLinearStrokeSharpness
|
|
|
|
: appState.currentItemStrokeSharpness)) ||
|
|
|
|
null,
|
|
|
|
)}
|
|
|
|
onChange={(value) => updateData(value)}
|
|
|
|
/>
|
|
|
|
</fieldset>
|
|
|
|
),
|
|
|
|
});
|
2020-12-08 15:02:55 +00:00
|
|
|
|
|
|
|
export const actionChangeArrowhead = register({
|
|
|
|
name: "changeArrowhead",
|
|
|
|
perform: (
|
|
|
|
elements,
|
|
|
|
appState,
|
|
|
|
value: { position: "start" | "end"; type: Arrowhead },
|
|
|
|
) => {
|
|
|
|
return {
|
|
|
|
elements: changeProperty(elements, appState, (el) => {
|
|
|
|
if (isLinearElement(el)) {
|
|
|
|
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,
|
2020-12-12 16:42:30 +00:00
|
|
|
[value.position === "start"
|
|
|
|
? "currentItemStartArrowhead"
|
|
|
|
: "currentItemEndArrowhead"]: value.type,
|
2020-12-08 15:02:55 +00:00
|
|
|
},
|
|
|
|
commitToHistory: true,
|
|
|
|
};
|
|
|
|
},
|
2020-12-11 17:17:28 +00:00
|
|
|
PanelComponent: ({ elements, appState, updateData }) => {
|
|
|
|
const isRTL = getLanguage().rtl;
|
|
|
|
|
|
|
|
return (
|
|
|
|
<fieldset>
|
|
|
|
<legend>{t("labels.arrowheads")}</legend>
|
|
|
|
<div className="iconSelectList">
|
|
|
|
<IconPicker
|
|
|
|
label="arrowhead_start"
|
|
|
|
options={[
|
|
|
|
{
|
|
|
|
value: null,
|
|
|
|
text: t("labels.arrowhead_none"),
|
2021-03-13 18:58:06 +05:30
|
|
|
icon: <ArrowheadNoneIcon theme={appState.theme} />,
|
2020-12-11 17:17:28 +00:00
|
|
|
keyBinding: "q",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
value: "arrow",
|
|
|
|
text: t("labels.arrowhead_arrow"),
|
|
|
|
icon: (
|
2021-03-13 18:58:06 +05:30
|
|
|
<ArrowheadArrowIcon theme={appState.theme} flip={!isRTL} />
|
2020-12-11 17:17:28 +00:00
|
|
|
),
|
|
|
|
keyBinding: "w",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
value: "bar",
|
|
|
|
text: t("labels.arrowhead_bar"),
|
2021-03-13 18:58:06 +05:30
|
|
|
icon: <ArrowheadBarIcon theme={appState.theme} flip={!isRTL} />,
|
2020-12-11 17:17:28 +00:00
|
|
|
keyBinding: "e",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
value: "dot",
|
|
|
|
text: t("labels.arrowhead_dot"),
|
2021-03-13 18:58:06 +05:30
|
|
|
icon: <ArrowheadDotIcon theme={appState.theme} flip={!isRTL} />,
|
2020-12-11 17:17:28 +00:00
|
|
|
keyBinding: "r",
|
|
|
|
},
|
2021-10-27 18:27:39 +01:00
|
|
|
{
|
|
|
|
value: "triangle",
|
|
|
|
text: t("labels.arrowhead_triangle"),
|
|
|
|
icon: (
|
|
|
|
<ArrowheadTriangleIcon theme={appState.theme} flip={!isRTL} />
|
|
|
|
),
|
|
|
|
keyBinding: "t",
|
|
|
|
},
|
2020-12-11 17:17:28 +00:00
|
|
|
]}
|
|
|
|
value={getFormValue<Arrowhead | null>(
|
|
|
|
elements,
|
|
|
|
appState,
|
|
|
|
(element) =>
|
|
|
|
isLinearElement(element) && canHaveArrowheads(element.type)
|
|
|
|
? element.startArrowhead
|
2020-12-12 16:42:30 +00:00
|
|
|
: appState.currentItemStartArrowhead,
|
|
|
|
appState.currentItemStartArrowhead,
|
2020-12-11 17:17:28 +00:00
|
|
|
)}
|
|
|
|
onChange={(value) => updateData({ position: "start", type: value })}
|
|
|
|
/>
|
|
|
|
<IconPicker
|
|
|
|
label="arrowhead_end"
|
|
|
|
group="arrowheads"
|
|
|
|
options={[
|
|
|
|
{
|
|
|
|
value: null,
|
|
|
|
text: t("labels.arrowhead_none"),
|
|
|
|
keyBinding: "q",
|
2021-03-13 18:58:06 +05:30
|
|
|
icon: <ArrowheadNoneIcon theme={appState.theme} />,
|
2020-12-11 17:17:28 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
value: "arrow",
|
|
|
|
text: t("labels.arrowhead_arrow"),
|
|
|
|
keyBinding: "w",
|
|
|
|
icon: (
|
2021-03-13 18:58:06 +05:30
|
|
|
<ArrowheadArrowIcon theme={appState.theme} flip={isRTL} />
|
2020-12-11 17:17:28 +00:00
|
|
|
),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
value: "bar",
|
|
|
|
text: t("labels.arrowhead_bar"),
|
|
|
|
keyBinding: "e",
|
2021-03-13 18:58:06 +05:30
|
|
|
icon: <ArrowheadBarIcon theme={appState.theme} flip={isRTL} />,
|
2020-12-11 17:17:28 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
value: "dot",
|
|
|
|
text: t("labels.arrowhead_dot"),
|
|
|
|
keyBinding: "r",
|
2021-03-13 18:58:06 +05:30
|
|
|
icon: <ArrowheadDotIcon theme={appState.theme} flip={isRTL} />,
|
2020-12-11 17:17:28 +00:00
|
|
|
},
|
2021-10-27 18:27:39 +01:00
|
|
|
{
|
|
|
|
value: "triangle",
|
|
|
|
text: t("labels.arrowhead_triangle"),
|
|
|
|
icon: (
|
|
|
|
<ArrowheadTriangleIcon theme={appState.theme} flip={isRTL} />
|
|
|
|
),
|
|
|
|
keyBinding: "t",
|
|
|
|
},
|
2020-12-11 17:17:28 +00:00
|
|
|
]}
|
|
|
|
value={getFormValue<Arrowhead | null>(
|
|
|
|
elements,
|
|
|
|
appState,
|
|
|
|
(element) =>
|
|
|
|
isLinearElement(element) && canHaveArrowheads(element.type)
|
|
|
|
? element.endArrowhead
|
2020-12-12 16:42:30 +00:00
|
|
|
: appState.currentItemEndArrowhead,
|
|
|
|
appState.currentItemEndArrowhead,
|
2020-12-11 17:17:28 +00:00
|
|
|
)}
|
|
|
|
onChange={(value) => updateData({ position: "end", type: value })}
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
</fieldset>
|
|
|
|
);
|
|
|
|
},
|
2020-12-08 15:02:55 +00:00
|
|
|
});
|