|
@@ -76,7 +76,7 @@ import type { Scene } from "@excalidraw/element";
|
|
|
import type { CaptureUpdateActionType } from "@excalidraw/element";
|
|
|
|
|
|
import { trackEvent } from "../analytics";
|
|
|
-import { ButtonIconSelect } from "../components/ButtonIconSelect";
|
|
|
+import { RadioSelection } from "../components/RadioSelection";
|
|
|
import { ColorPicker } from "../components/ColorPicker/ColorPicker";
|
|
|
import { FontPicker } from "../components/FontPicker/FontPicker";
|
|
|
import { IconPicker } from "../components/IconPicker";
|
|
@@ -421,50 +421,52 @@ export const actionChangeFillStyle = register({
|
|
|
return (
|
|
|
<fieldset>
|
|
|
<legend>{t("labels.fill")}</legend>
|
|
|
- <ButtonIconSelect
|
|
|
- type="button"
|
|
|
- options={[
|
|
|
- {
|
|
|
- value: "hachure",
|
|
|
- text: `${
|
|
|
- allElementsZigZag ? t("labels.zigzag") : t("labels.hachure")
|
|
|
- } (${getShortcutKey("Alt-Click")})`,
|
|
|
- icon: allElementsZigZag ? FillZigZagIcon : FillHachureIcon,
|
|
|
- active: allElementsZigZag ? true : undefined,
|
|
|
- testId: `fill-hachure`,
|
|
|
- },
|
|
|
- {
|
|
|
- value: "cross-hatch",
|
|
|
- text: t("labels.crossHatch"),
|
|
|
- icon: FillCrossHatchIcon,
|
|
|
- testId: `fill-cross-hatch`,
|
|
|
- },
|
|
|
- {
|
|
|
- value: "solid",
|
|
|
- text: t("labels.solid"),
|
|
|
- icon: FillSolidIcon,
|
|
|
- testId: `fill-solid`,
|
|
|
- },
|
|
|
- ]}
|
|
|
- value={getFormValue(
|
|
|
- elements,
|
|
|
- app,
|
|
|
- (element) => element.fillStyle,
|
|
|
- (element) => element.hasOwnProperty("fillStyle"),
|
|
|
- (hasSelection) =>
|
|
|
- hasSelection ? null : appState.currentItemFillStyle,
|
|
|
- )}
|
|
|
- onClick={(value, event) => {
|
|
|
- const nextValue =
|
|
|
- event.altKey &&
|
|
|
- value === "hachure" &&
|
|
|
- selectedElements.every((el) => el.fillStyle === "hachure")
|
|
|
- ? "zigzag"
|
|
|
- : value;
|
|
|
-
|
|
|
- updateData(nextValue);
|
|
|
- }}
|
|
|
- />
|
|
|
+ <div className="buttonList">
|
|
|
+ <RadioSelection
|
|
|
+ type="button"
|
|
|
+ options={[
|
|
|
+ {
|
|
|
+ value: "hachure",
|
|
|
+ text: `${
|
|
|
+ allElementsZigZag ? t("labels.zigzag") : t("labels.hachure")
|
|
|
+ } (${getShortcutKey("Alt-Click")})`,
|
|
|
+ icon: allElementsZigZag ? FillZigZagIcon : FillHachureIcon,
|
|
|
+ active: allElementsZigZag ? true : undefined,
|
|
|
+ testId: `fill-hachure`,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: "cross-hatch",
|
|
|
+ text: t("labels.crossHatch"),
|
|
|
+ icon: FillCrossHatchIcon,
|
|
|
+ testId: `fill-cross-hatch`,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: "solid",
|
|
|
+ text: t("labels.solid"),
|
|
|
+ icon: FillSolidIcon,
|
|
|
+ testId: `fill-solid`,
|
|
|
+ },
|
|
|
+ ]}
|
|
|
+ value={getFormValue(
|
|
|
+ elements,
|
|
|
+ app,
|
|
|
+ (element) => element.fillStyle,
|
|
|
+ (element) => element.hasOwnProperty("fillStyle"),
|
|
|
+ (hasSelection) =>
|
|
|
+ hasSelection ? null : appState.currentItemFillStyle,
|
|
|
+ )}
|
|
|
+ onClick={(value, event) => {
|
|
|
+ const nextValue =
|
|
|
+ event.altKey &&
|
|
|
+ value === "hachure" &&
|
|
|
+ selectedElements.every((el) => el.fillStyle === "hachure")
|
|
|
+ ? "zigzag"
|
|
|
+ : value;
|
|
|
+
|
|
|
+ updateData(nextValue);
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
</fieldset>
|
|
|
);
|
|
|
},
|
|
@@ -488,38 +490,40 @@ export const actionChangeStrokeWidth = register({
|
|
|
PanelComponent: ({ elements, appState, updateData, app }) => (
|
|
|
<fieldset>
|
|
|
<legend>{t("labels.strokeWidth")}</legend>
|
|
|
- <ButtonIconSelect
|
|
|
- group="stroke-width"
|
|
|
- options={[
|
|
|
- {
|
|
|
- value: STROKE_WIDTH.thin,
|
|
|
- text: t("labels.thin"),
|
|
|
- icon: StrokeWidthBaseIcon,
|
|
|
- testId: "strokeWidth-thin",
|
|
|
- },
|
|
|
- {
|
|
|
- value: STROKE_WIDTH.bold,
|
|
|
- text: t("labels.bold"),
|
|
|
- icon: StrokeWidthBoldIcon,
|
|
|
- testId: "strokeWidth-bold",
|
|
|
- },
|
|
|
- {
|
|
|
- value: STROKE_WIDTH.extraBold,
|
|
|
- text: t("labels.extraBold"),
|
|
|
- icon: StrokeWidthExtraBoldIcon,
|
|
|
- testId: "strokeWidth-extraBold",
|
|
|
- },
|
|
|
- ]}
|
|
|
- value={getFormValue(
|
|
|
- elements,
|
|
|
- app,
|
|
|
- (element) => element.strokeWidth,
|
|
|
- (element) => element.hasOwnProperty("strokeWidth"),
|
|
|
- (hasSelection) =>
|
|
|
- hasSelection ? null : appState.currentItemStrokeWidth,
|
|
|
- )}
|
|
|
- onChange={(value) => updateData(value)}
|
|
|
- />
|
|
|
+ <div className="buttonList">
|
|
|
+ <RadioSelection
|
|
|
+ group="stroke-width"
|
|
|
+ options={[
|
|
|
+ {
|
|
|
+ value: STROKE_WIDTH.thin,
|
|
|
+ text: t("labels.thin"),
|
|
|
+ icon: StrokeWidthBaseIcon,
|
|
|
+ testId: "strokeWidth-thin",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: STROKE_WIDTH.bold,
|
|
|
+ text: t("labels.bold"),
|
|
|
+ icon: StrokeWidthBoldIcon,
|
|
|
+ testId: "strokeWidth-bold",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: STROKE_WIDTH.extraBold,
|
|
|
+ text: t("labels.extraBold"),
|
|
|
+ icon: StrokeWidthExtraBoldIcon,
|
|
|
+ testId: "strokeWidth-extraBold",
|
|
|
+ },
|
|
|
+ ]}
|
|
|
+ value={getFormValue(
|
|
|
+ elements,
|
|
|
+ app,
|
|
|
+ (element) => element.strokeWidth,
|
|
|
+ (element) => element.hasOwnProperty("strokeWidth"),
|
|
|
+ (hasSelection) =>
|
|
|
+ hasSelection ? null : appState.currentItemStrokeWidth,
|
|
|
+ )}
|
|
|
+ onChange={(value) => updateData(value)}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
</fieldset>
|
|
|
),
|
|
|
});
|
|
@@ -543,35 +547,37 @@ export const actionChangeSloppiness = register({
|
|
|
PanelComponent: ({ elements, appState, updateData, app }) => (
|
|
|
<fieldset>
|
|
|
<legend>{t("labels.sloppiness")}</legend>
|
|
|
- <ButtonIconSelect
|
|
|
- group="sloppiness"
|
|
|
- options={[
|
|
|
- {
|
|
|
- value: 0,
|
|
|
- text: t("labels.architect"),
|
|
|
- icon: SloppinessArchitectIcon,
|
|
|
- },
|
|
|
- {
|
|
|
- value: 1,
|
|
|
- text: t("labels.artist"),
|
|
|
- icon: SloppinessArtistIcon,
|
|
|
- },
|
|
|
- {
|
|
|
- value: 2,
|
|
|
- text: t("labels.cartoonist"),
|
|
|
- icon: SloppinessCartoonistIcon,
|
|
|
- },
|
|
|
- ]}
|
|
|
- value={getFormValue(
|
|
|
- elements,
|
|
|
- app,
|
|
|
- (element) => element.roughness,
|
|
|
- (element) => element.hasOwnProperty("roughness"),
|
|
|
- (hasSelection) =>
|
|
|
- hasSelection ? null : appState.currentItemRoughness,
|
|
|
- )}
|
|
|
- onChange={(value) => updateData(value)}
|
|
|
- />
|
|
|
+ <div className="buttonList">
|
|
|
+ <RadioSelection
|
|
|
+ group="sloppiness"
|
|
|
+ options={[
|
|
|
+ {
|
|
|
+ value: 0,
|
|
|
+ text: t("labels.architect"),
|
|
|
+ icon: SloppinessArchitectIcon,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: 1,
|
|
|
+ text: t("labels.artist"),
|
|
|
+ icon: SloppinessArtistIcon,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: 2,
|
|
|
+ text: t("labels.cartoonist"),
|
|
|
+ icon: SloppinessCartoonistIcon,
|
|
|
+ },
|
|
|
+ ]}
|
|
|
+ value={getFormValue(
|
|
|
+ elements,
|
|
|
+ app,
|
|
|
+ (element) => element.roughness,
|
|
|
+ (element) => element.hasOwnProperty("roughness"),
|
|
|
+ (hasSelection) =>
|
|
|
+ hasSelection ? null : appState.currentItemRoughness,
|
|
|
+ )}
|
|
|
+ onChange={(value) => updateData(value)}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
</fieldset>
|
|
|
),
|
|
|
});
|
|
@@ -594,35 +600,37 @@ export const actionChangeStrokeStyle = register({
|
|
|
PanelComponent: ({ elements, appState, updateData, app }) => (
|
|
|
<fieldset>
|
|
|
<legend>{t("labels.strokeStyle")}</legend>
|
|
|
- <ButtonIconSelect
|
|
|
- group="strokeStyle"
|
|
|
- options={[
|
|
|
- {
|
|
|
- value: "solid",
|
|
|
- text: t("labels.strokeStyle_solid"),
|
|
|
- icon: StrokeWidthBaseIcon,
|
|
|
- },
|
|
|
- {
|
|
|
- value: "dashed",
|
|
|
- text: t("labels.strokeStyle_dashed"),
|
|
|
- icon: StrokeStyleDashedIcon,
|
|
|
- },
|
|
|
- {
|
|
|
- value: "dotted",
|
|
|
- text: t("labels.strokeStyle_dotted"),
|
|
|
- icon: StrokeStyleDottedIcon,
|
|
|
- },
|
|
|
- ]}
|
|
|
- value={getFormValue(
|
|
|
- elements,
|
|
|
- app,
|
|
|
- (element) => element.strokeStyle,
|
|
|
- (element) => element.hasOwnProperty("strokeStyle"),
|
|
|
- (hasSelection) =>
|
|
|
- hasSelection ? null : appState.currentItemStrokeStyle,
|
|
|
- )}
|
|
|
- onChange={(value) => updateData(value)}
|
|
|
- />
|
|
|
+ <div className="buttonList">
|
|
|
+ <RadioSelection
|
|
|
+ group="strokeStyle"
|
|
|
+ options={[
|
|
|
+ {
|
|
|
+ value: "solid",
|
|
|
+ text: t("labels.strokeStyle_solid"),
|
|
|
+ icon: StrokeWidthBaseIcon,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: "dashed",
|
|
|
+ text: t("labels.strokeStyle_dashed"),
|
|
|
+ icon: StrokeStyleDashedIcon,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: "dotted",
|
|
|
+ text: t("labels.strokeStyle_dotted"),
|
|
|
+ icon: StrokeStyleDottedIcon,
|
|
|
+ },
|
|
|
+ ]}
|
|
|
+ value={getFormValue(
|
|
|
+ elements,
|
|
|
+ app,
|
|
|
+ (element) => element.strokeStyle,
|
|
|
+ (element) => element.hasOwnProperty("strokeStyle"),
|
|
|
+ (hasSelection) =>
|
|
|
+ hasSelection ? null : appState.currentItemStrokeStyle,
|
|
|
+ )}
|
|
|
+ onChange={(value) => updateData(value)}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
</fieldset>
|
|
|
),
|
|
|
});
|
|
@@ -661,63 +669,65 @@ export const actionChangeFontSize = register({
|
|
|
PanelComponent: ({ elements, appState, updateData, app }) => (
|
|
|
<fieldset>
|
|
|
<legend>{t("labels.fontSize")}</legend>
|
|
|
- <ButtonIconSelect
|
|
|
- group="font-size"
|
|
|
- options={[
|
|
|
- {
|
|
|
- value: 16,
|
|
|
- text: t("labels.small"),
|
|
|
- icon: FontSizeSmallIcon,
|
|
|
- testId: "fontSize-small",
|
|
|
- },
|
|
|
- {
|
|
|
- value: 20,
|
|
|
- text: t("labels.medium"),
|
|
|
- icon: FontSizeMediumIcon,
|
|
|
- testId: "fontSize-medium",
|
|
|
- },
|
|
|
- {
|
|
|
- value: 28,
|
|
|
- text: t("labels.large"),
|
|
|
- icon: FontSizeLargeIcon,
|
|
|
- testId: "fontSize-large",
|
|
|
- },
|
|
|
- {
|
|
|
- value: 36,
|
|
|
- text: t("labels.veryLarge"),
|
|
|
- icon: FontSizeExtraLargeIcon,
|
|
|
- testId: "fontSize-veryLarge",
|
|
|
- },
|
|
|
- ]}
|
|
|
- value={getFormValue(
|
|
|
- elements,
|
|
|
- app,
|
|
|
- (element) => {
|
|
|
- if (isTextElement(element)) {
|
|
|
- return element.fontSize;
|
|
|
- }
|
|
|
- const boundTextElement = getBoundTextElement(
|
|
|
- element,
|
|
|
- app.scene.getNonDeletedElementsMap(),
|
|
|
- );
|
|
|
- if (boundTextElement) {
|
|
|
- return boundTextElement.fontSize;
|
|
|
- }
|
|
|
- return null;
|
|
|
- },
|
|
|
- (element) =>
|
|
|
- isTextElement(element) ||
|
|
|
- getBoundTextElement(
|
|
|
- element,
|
|
|
- app.scene.getNonDeletedElementsMap(),
|
|
|
- ) !== null,
|
|
|
- (hasSelection) =>
|
|
|
- hasSelection
|
|
|
- ? null
|
|
|
- : appState.currentItemFontSize || DEFAULT_FONT_SIZE,
|
|
|
- )}
|
|
|
- onChange={(value) => updateData(value)}
|
|
|
- />
|
|
|
+ <div className="buttonList">
|
|
|
+ <RadioSelection
|
|
|
+ group="font-size"
|
|
|
+ options={[
|
|
|
+ {
|
|
|
+ value: 16,
|
|
|
+ text: t("labels.small"),
|
|
|
+ icon: FontSizeSmallIcon,
|
|
|
+ testId: "fontSize-small",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: 20,
|
|
|
+ text: t("labels.medium"),
|
|
|
+ icon: FontSizeMediumIcon,
|
|
|
+ testId: "fontSize-medium",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: 28,
|
|
|
+ text: t("labels.large"),
|
|
|
+ icon: FontSizeLargeIcon,
|
|
|
+ testId: "fontSize-large",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: 36,
|
|
|
+ text: t("labels.veryLarge"),
|
|
|
+ icon: FontSizeExtraLargeIcon,
|
|
|
+ testId: "fontSize-veryLarge",
|
|
|
+ },
|
|
|
+ ]}
|
|
|
+ value={getFormValue(
|
|
|
+ elements,
|
|
|
+ app,
|
|
|
+ (element) => {
|
|
|
+ if (isTextElement(element)) {
|
|
|
+ return element.fontSize;
|
|
|
+ }
|
|
|
+ const boundTextElement = getBoundTextElement(
|
|
|
+ element,
|
|
|
+ app.scene.getNonDeletedElementsMap(),
|
|
|
+ );
|
|
|
+ if (boundTextElement) {
|
|
|
+ return boundTextElement.fontSize;
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ },
|
|
|
+ (element) =>
|
|
|
+ isTextElement(element) ||
|
|
|
+ getBoundTextElement(
|
|
|
+ element,
|
|
|
+ app.scene.getNonDeletedElementsMap(),
|
|
|
+ ) !== null,
|
|
|
+ (hasSelection) =>
|
|
|
+ hasSelection
|
|
|
+ ? null
|
|
|
+ : appState.currentItemFontSize || DEFAULT_FONT_SIZE,
|
|
|
+ )}
|
|
|
+ onChange={(value) => updateData(value)}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
</fieldset>
|
|
|
),
|
|
|
});
|
|
@@ -1189,52 +1199,54 @@ export const actionChangeTextAlign = register({
|
|
|
return (
|
|
|
<fieldset>
|
|
|
<legend>{t("labels.textAlign")}</legend>
|
|
|
- <ButtonIconSelect<TextAlign | false>
|
|
|
- group="text-align"
|
|
|
- options={[
|
|
|
- {
|
|
|
- value: "left",
|
|
|
- text: t("labels.left"),
|
|
|
- icon: TextAlignLeftIcon,
|
|
|
- testId: "align-left",
|
|
|
- },
|
|
|
- {
|
|
|
- value: "center",
|
|
|
- text: t("labels.center"),
|
|
|
- icon: TextAlignCenterIcon,
|
|
|
- testId: "align-horizontal-center",
|
|
|
- },
|
|
|
- {
|
|
|
- value: "right",
|
|
|
- text: t("labels.right"),
|
|
|
- icon: TextAlignRightIcon,
|
|
|
- testId: "align-right",
|
|
|
- },
|
|
|
- ]}
|
|
|
- value={getFormValue(
|
|
|
- elements,
|
|
|
- app,
|
|
|
- (element) => {
|
|
|
- if (isTextElement(element)) {
|
|
|
- return element.textAlign;
|
|
|
- }
|
|
|
- const boundTextElement = getBoundTextElement(
|
|
|
- element,
|
|
|
- elementsMap,
|
|
|
- );
|
|
|
- if (boundTextElement) {
|
|
|
- return boundTextElement.textAlign;
|
|
|
- }
|
|
|
- return null;
|
|
|
- },
|
|
|
- (element) =>
|
|
|
- isTextElement(element) ||
|
|
|
- getBoundTextElement(element, elementsMap) !== null,
|
|
|
- (hasSelection) =>
|
|
|
- hasSelection ? null : appState.currentItemTextAlign,
|
|
|
- )}
|
|
|
- onChange={(value) => updateData(value)}
|
|
|
- />
|
|
|
+ <div className="buttonList">
|
|
|
+ <RadioSelection<TextAlign | false>
|
|
|
+ group="text-align"
|
|
|
+ options={[
|
|
|
+ {
|
|
|
+ value: "left",
|
|
|
+ text: t("labels.left"),
|
|
|
+ icon: TextAlignLeftIcon,
|
|
|
+ testId: "align-left",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: "center",
|
|
|
+ text: t("labels.center"),
|
|
|
+ icon: TextAlignCenterIcon,
|
|
|
+ testId: "align-horizontal-center",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: "right",
|
|
|
+ text: t("labels.right"),
|
|
|
+ icon: TextAlignRightIcon,
|
|
|
+ testId: "align-right",
|
|
|
+ },
|
|
|
+ ]}
|
|
|
+ value={getFormValue(
|
|
|
+ elements,
|
|
|
+ app,
|
|
|
+ (element) => {
|
|
|
+ if (isTextElement(element)) {
|
|
|
+ return element.textAlign;
|
|
|
+ }
|
|
|
+ const boundTextElement = getBoundTextElement(
|
|
|
+ element,
|
|
|
+ elementsMap,
|
|
|
+ );
|
|
|
+ if (boundTextElement) {
|
|
|
+ return boundTextElement.textAlign;
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ },
|
|
|
+ (element) =>
|
|
|
+ isTextElement(element) ||
|
|
|
+ getBoundTextElement(element, elementsMap) !== null,
|
|
|
+ (hasSelection) =>
|
|
|
+ hasSelection ? null : appState.currentItemTextAlign,
|
|
|
+ )}
|
|
|
+ onChange={(value) => updateData(value)}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
</fieldset>
|
|
|
);
|
|
|
},
|
|
@@ -1277,54 +1289,56 @@ export const actionChangeVerticalAlign = register({
|
|
|
PanelComponent: ({ elements, appState, updateData, app }) => {
|
|
|
return (
|
|
|
<fieldset>
|
|
|
- <ButtonIconSelect<VerticalAlign | false>
|
|
|
- group="text-align"
|
|
|
- options={[
|
|
|
- {
|
|
|
- value: VERTICAL_ALIGN.TOP,
|
|
|
- text: t("labels.alignTop"),
|
|
|
- icon: <TextAlignTopIcon theme={appState.theme} />,
|
|
|
- testId: "align-top",
|
|
|
- },
|
|
|
- {
|
|
|
- value: VERTICAL_ALIGN.MIDDLE,
|
|
|
- text: t("labels.centerVertically"),
|
|
|
- icon: <TextAlignMiddleIcon theme={appState.theme} />,
|
|
|
- testId: "align-middle",
|
|
|
- },
|
|
|
- {
|
|
|
- value: VERTICAL_ALIGN.BOTTOM,
|
|
|
- text: t("labels.alignBottom"),
|
|
|
- icon: <TextAlignBottomIcon theme={appState.theme} />,
|
|
|
- testId: "align-bottom",
|
|
|
- },
|
|
|
- ]}
|
|
|
- value={getFormValue(
|
|
|
- elements,
|
|
|
- app,
|
|
|
- (element) => {
|
|
|
- if (isTextElement(element) && element.containerId) {
|
|
|
- return element.verticalAlign;
|
|
|
- }
|
|
|
- const boundTextElement = getBoundTextElement(
|
|
|
- element,
|
|
|
- app.scene.getNonDeletedElementsMap(),
|
|
|
- );
|
|
|
- if (boundTextElement) {
|
|
|
- return boundTextElement.verticalAlign;
|
|
|
- }
|
|
|
- return null;
|
|
|
- },
|
|
|
- (element) =>
|
|
|
- isTextElement(element) ||
|
|
|
- getBoundTextElement(
|
|
|
- element,
|
|
|
- app.scene.getNonDeletedElementsMap(),
|
|
|
- ) !== null,
|
|
|
- (hasSelection) => (hasSelection ? null : VERTICAL_ALIGN.MIDDLE),
|
|
|
- )}
|
|
|
- onChange={(value) => updateData(value)}
|
|
|
- />
|
|
|
+ <div className="buttonList">
|
|
|
+ <RadioSelection<VerticalAlign | false>
|
|
|
+ group="text-align"
|
|
|
+ options={[
|
|
|
+ {
|
|
|
+ value: VERTICAL_ALIGN.TOP,
|
|
|
+ text: t("labels.alignTop"),
|
|
|
+ icon: <TextAlignTopIcon theme={appState.theme} />,
|
|
|
+ testId: "align-top",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: VERTICAL_ALIGN.MIDDLE,
|
|
|
+ text: t("labels.centerVertically"),
|
|
|
+ icon: <TextAlignMiddleIcon theme={appState.theme} />,
|
|
|
+ testId: "align-middle",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: VERTICAL_ALIGN.BOTTOM,
|
|
|
+ text: t("labels.alignBottom"),
|
|
|
+ icon: <TextAlignBottomIcon theme={appState.theme} />,
|
|
|
+ testId: "align-bottom",
|
|
|
+ },
|
|
|
+ ]}
|
|
|
+ value={getFormValue(
|
|
|
+ elements,
|
|
|
+ app,
|
|
|
+ (element) => {
|
|
|
+ if (isTextElement(element) && element.containerId) {
|
|
|
+ return element.verticalAlign;
|
|
|
+ }
|
|
|
+ const boundTextElement = getBoundTextElement(
|
|
|
+ element,
|
|
|
+ app.scene.getNonDeletedElementsMap(),
|
|
|
+ );
|
|
|
+ if (boundTextElement) {
|
|
|
+ return boundTextElement.verticalAlign;
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ },
|
|
|
+ (element) =>
|
|
|
+ isTextElement(element) ||
|
|
|
+ getBoundTextElement(
|
|
|
+ element,
|
|
|
+ app.scene.getNonDeletedElementsMap(),
|
|
|
+ ) !== null,
|
|
|
+ (hasSelection) => (hasSelection ? null : VERTICAL_ALIGN.MIDDLE),
|
|
|
+ )}
|
|
|
+ onChange={(value) => updateData(value)}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
</fieldset>
|
|
|
);
|
|
|
},
|
|
@@ -1372,32 +1386,38 @@ export const actionChangeRoundness = register({
|
|
|
return (
|
|
|
<fieldset>
|
|
|
<legend>{t("labels.edges")}</legend>
|
|
|
- <ButtonIconSelect
|
|
|
- group="edges"
|
|
|
- options={[
|
|
|
- {
|
|
|
- value: "sharp",
|
|
|
- text: t("labels.sharp"),
|
|
|
- icon: EdgeSharpIcon,
|
|
|
- },
|
|
|
- {
|
|
|
- value: "round",
|
|
|
- text: t("labels.round"),
|
|
|
- icon: EdgeRoundIcon,
|
|
|
- },
|
|
|
- ]}
|
|
|
- value={getFormValue(
|
|
|
- elements,
|
|
|
- app,
|
|
|
- (element) =>
|
|
|
- hasLegacyRoundness ? null : element.roundness ? "round" : "sharp",
|
|
|
- (element) =>
|
|
|
- !isArrowElement(element) && element.hasOwnProperty("roundness"),
|
|
|
- (hasSelection) =>
|
|
|
- hasSelection ? null : appState.currentItemRoundness,
|
|
|
- )}
|
|
|
- onChange={(value) => updateData(value)}
|
|
|
- />
|
|
|
+ <div className="buttonList">
|
|
|
+ <RadioSelection
|
|
|
+ group="edges"
|
|
|
+ options={[
|
|
|
+ {
|
|
|
+ value: "sharp",
|
|
|
+ text: t("labels.sharp"),
|
|
|
+ icon: EdgeSharpIcon,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: "round",
|
|
|
+ text: t("labels.round"),
|
|
|
+ icon: EdgeRoundIcon,
|
|
|
+ },
|
|
|
+ ]}
|
|
|
+ value={getFormValue(
|
|
|
+ elements,
|
|
|
+ app,
|
|
|
+ (element) =>
|
|
|
+ hasLegacyRoundness
|
|
|
+ ? null
|
|
|
+ : element.roundness
|
|
|
+ ? "round"
|
|
|
+ : "sharp",
|
|
|
+ (element) =>
|
|
|
+ !isArrowElement(element) && element.hasOwnProperty("roundness"),
|
|
|
+ (hasSelection) =>
|
|
|
+ hasSelection ? null : appState.currentItemRoundness,
|
|
|
+ )}
|
|
|
+ onChange={(value) => updateData(value)}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
</fieldset>
|
|
|
);
|
|
|
},
|
|
@@ -1760,48 +1780,50 @@ export const actionChangeArrowType = register({
|
|
|
return (
|
|
|
<fieldset>
|
|
|
<legend>{t("labels.arrowtypes")}</legend>
|
|
|
- <ButtonIconSelect
|
|
|
- group="arrowtypes"
|
|
|
- options={[
|
|
|
- {
|
|
|
- value: ARROW_TYPE.sharp,
|
|
|
- text: t("labels.arrowtype_sharp"),
|
|
|
- icon: sharpArrowIcon,
|
|
|
- testId: "sharp-arrow",
|
|
|
- },
|
|
|
- {
|
|
|
- value: ARROW_TYPE.round,
|
|
|
- text: t("labels.arrowtype_round"),
|
|
|
- icon: roundArrowIcon,
|
|
|
- testId: "round-arrow",
|
|
|
- },
|
|
|
- {
|
|
|
- value: ARROW_TYPE.elbow,
|
|
|
- text: t("labels.arrowtype_elbowed"),
|
|
|
- icon: elbowArrowIcon,
|
|
|
- testId: "elbow-arrow",
|
|
|
- },
|
|
|
- ]}
|
|
|
- value={getFormValue(
|
|
|
- elements,
|
|
|
- app,
|
|
|
- (element) => {
|
|
|
- if (isArrowElement(element)) {
|
|
|
- return element.elbowed
|
|
|
- ? ARROW_TYPE.elbow
|
|
|
- : element.roundness
|
|
|
- ? ARROW_TYPE.round
|
|
|
- : ARROW_TYPE.sharp;
|
|
|
- }
|
|
|
+ <div className="buttonList">
|
|
|
+ <RadioSelection
|
|
|
+ group="arrowtypes"
|
|
|
+ options={[
|
|
|
+ {
|
|
|
+ value: ARROW_TYPE.sharp,
|
|
|
+ text: t("labels.arrowtype_sharp"),
|
|
|
+ icon: sharpArrowIcon,
|
|
|
+ testId: "sharp-arrow",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: ARROW_TYPE.round,
|
|
|
+ text: t("labels.arrowtype_round"),
|
|
|
+ icon: roundArrowIcon,
|
|
|
+ testId: "round-arrow",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ value: ARROW_TYPE.elbow,
|
|
|
+ text: t("labels.arrowtype_elbowed"),
|
|
|
+ icon: elbowArrowIcon,
|
|
|
+ testId: "elbow-arrow",
|
|
|
+ },
|
|
|
+ ]}
|
|
|
+ value={getFormValue(
|
|
|
+ elements,
|
|
|
+ app,
|
|
|
+ (element) => {
|
|
|
+ if (isArrowElement(element)) {
|
|
|
+ return element.elbowed
|
|
|
+ ? ARROW_TYPE.elbow
|
|
|
+ : element.roundness
|
|
|
+ ? ARROW_TYPE.round
|
|
|
+ : ARROW_TYPE.sharp;
|
|
|
+ }
|
|
|
|
|
|
- return null;
|
|
|
- },
|
|
|
- (element) => isArrowElement(element),
|
|
|
- (hasSelection) =>
|
|
|
- hasSelection ? null : appState.currentItemArrowType,
|
|
|
- )}
|
|
|
- onChange={(value) => updateData(value)}
|
|
|
- />
|
|
|
+ return null;
|
|
|
+ },
|
|
|
+ (element) => isArrowElement(element),
|
|
|
+ (hasSelection) =>
|
|
|
+ hasSelection ? null : appState.currentItemArrowType,
|
|
|
+ )}
|
|
|
+ onChange={(value) => updateData(value)}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
</fieldset>
|
|
|
);
|
|
|
},
|