Forráskód Böngészése

refactor: decouple radio button selection from `.buttonList` wrapper (#9528)

* refactor: decouple radio button selection from `.buttonList`

* fix
David Luzar 2 hónapja
szülő
commit
95d89a751a

+ 1 - 1
examples/with-script-in-browser/components/ExampleApp.scss

@@ -52,7 +52,7 @@
   transform: none;
   transform: none;
 }
 }
 
 
-.excalidraw .panelColumn {
+.excalidraw .selected-shape-actions {
   text-align: left;
   text-align: left;
 }
 }
 
 

+ 375 - 353
packages/excalidraw/actions/actionProperties.tsx

@@ -76,7 +76,7 @@ import type { Scene } from "@excalidraw/element";
 import type { CaptureUpdateActionType } from "@excalidraw/element";
 import type { CaptureUpdateActionType } from "@excalidraw/element";
 
 
 import { trackEvent } from "../analytics";
 import { trackEvent } from "../analytics";
-import { ButtonIconSelect } from "../components/ButtonIconSelect";
+import { RadioSelection } from "../components/RadioSelection";
 import { ColorPicker } from "../components/ColorPicker/ColorPicker";
 import { ColorPicker } from "../components/ColorPicker/ColorPicker";
 import { FontPicker } from "../components/FontPicker/FontPicker";
 import { FontPicker } from "../components/FontPicker/FontPicker";
 import { IconPicker } from "../components/IconPicker";
 import { IconPicker } from "../components/IconPicker";
@@ -421,50 +421,52 @@ export const actionChangeFillStyle = register({
     return (
     return (
       <fieldset>
       <fieldset>
         <legend>{t("labels.fill")}</legend>
         <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>
       </fieldset>
     );
     );
   },
   },
@@ -488,38 +490,40 @@ export const actionChangeStrokeWidth = register({
   PanelComponent: ({ elements, appState, updateData, app }) => (
   PanelComponent: ({ elements, appState, updateData, app }) => (
     <fieldset>
     <fieldset>
       <legend>{t("labels.strokeWidth")}</legend>
       <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>
     </fieldset>
   ),
   ),
 });
 });
@@ -543,35 +547,37 @@ export const actionChangeSloppiness = register({
   PanelComponent: ({ elements, appState, updateData, app }) => (
   PanelComponent: ({ elements, appState, updateData, app }) => (
     <fieldset>
     <fieldset>
       <legend>{t("labels.sloppiness")}</legend>
       <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>
     </fieldset>
   ),
   ),
 });
 });
@@ -594,35 +600,37 @@ export const actionChangeStrokeStyle = register({
   PanelComponent: ({ elements, appState, updateData, app }) => (
   PanelComponent: ({ elements, appState, updateData, app }) => (
     <fieldset>
     <fieldset>
       <legend>{t("labels.strokeStyle")}</legend>
       <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>
     </fieldset>
   ),
   ),
 });
 });
@@ -661,63 +669,65 @@ export const actionChangeFontSize = register({
   PanelComponent: ({ elements, appState, updateData, app }) => (
   PanelComponent: ({ elements, appState, updateData, app }) => (
     <fieldset>
     <fieldset>
       <legend>{t("labels.fontSize")}</legend>
       <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>
     </fieldset>
   ),
   ),
 });
 });
@@ -1189,52 +1199,54 @@ export const actionChangeTextAlign = register({
     return (
     return (
       <fieldset>
       <fieldset>
         <legend>{t("labels.textAlign")}</legend>
         <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>
       </fieldset>
     );
     );
   },
   },
@@ -1277,54 +1289,56 @@ export const actionChangeVerticalAlign = register({
   PanelComponent: ({ elements, appState, updateData, app }) => {
   PanelComponent: ({ elements, appState, updateData, app }) => {
     return (
     return (
       <fieldset>
       <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>
       </fieldset>
     );
     );
   },
   },
@@ -1372,32 +1386,38 @@ export const actionChangeRoundness = register({
     return (
     return (
       <fieldset>
       <fieldset>
         <legend>{t("labels.edges")}</legend>
         <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>
       </fieldset>
     );
     );
   },
   },
@@ -1760,48 +1780,50 @@ export const actionChangeArrowType = register({
     return (
     return (
       <fieldset>
       <fieldset>
         <legend>{t("labels.arrowtypes")}</legend>
         <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>
       </fieldset>
     );
     );
   },
   },

+ 1 - 1
packages/excalidraw/components/Actions.tsx

@@ -154,7 +154,7 @@ export const SelectedShapeActions = ({
     !isSingleElementBoundContainer && alignActionsPredicate(appState, app);
     !isSingleElementBoundContainer && alignActionsPredicate(appState, app);
 
 
   return (
   return (
-    <div className="panelColumn">
+    <div className="selected-shape-actions">
       <div>
       <div>
         {canChangeStrokeColor(appState, targetElements) &&
         {canChangeStrokeColor(appState, targetElements) &&
           renderAction("changeStrokeColor")}
           renderAction("changeStrokeColor")}

+ 0 - 30
packages/excalidraw/components/ButtonSelect.tsx

@@ -1,30 +0,0 @@
-import clsx from "clsx";
-
-export const ButtonSelect = <T extends Object>({
-  options,
-  value,
-  onChange,
-  group,
-}: {
-  options: { value: T; text: string }[];
-  value: T | null;
-  onChange: (value: T) => void;
-  group: string;
-}) => (
-  <div className="buttonList">
-    {options.map((option) => (
-      <label
-        key={option.text}
-        className={clsx({ active: value === option.value })}
-      >
-        <input
-          type="radio"
-          name={group}
-          onChange={() => onChange(option.value)}
-          checked={value === option.value}
-        />
-        {option.text}
-      </label>
-    ))}
-  </div>
-);

+ 9 - 7
packages/excalidraw/components/FontPicker/FontPicker.tsx

@@ -6,7 +6,7 @@ import { FONT_FAMILY } from "@excalidraw/common";
 import type { FontFamilyValues } from "@excalidraw/element/types";
 import type { FontFamilyValues } from "@excalidraw/element/types";
 
 
 import { t } from "../../i18n";
 import { t } from "../../i18n";
-import { ButtonIconSelect } from "../ButtonIconSelect";
+import { RadioSelection } from "../RadioSelection";
 import { ButtonSeparator } from "../ButtonSeparator";
 import { ButtonSeparator } from "../ButtonSeparator";
 import {
 import {
   FontFamilyCodeIcon,
   FontFamilyCodeIcon,
@@ -82,12 +82,14 @@ export const FontPicker = React.memo(
 
 
     return (
     return (
       <div role="dialog" aria-modal="true" className="FontPicker__container">
       <div role="dialog" aria-modal="true" className="FontPicker__container">
-        <ButtonIconSelect<FontFamilyValues | false>
-          type="button"
-          options={defaultFonts}
-          value={selectedFontFamily}
-          onClick={onSelectCallback}
-        />
+        <div className="buttonList">
+          <RadioSelection<FontFamilyValues | false>
+            type="button"
+            options={defaultFonts}
+            value={selectedFontFamily}
+            onClick={onSelectCallback}
+          />
+        </div>
         <ButtonSeparator />
         <ButtonSeparator />
         <Popover.Root open={isOpened} onOpenChange={onPopupChange}>
         <Popover.Root open={isOpened} onOpenChange={onPopupChange}>
           <FontPickerTrigger selectedFontFamily={selectedFontFamily} />
           <FontPickerTrigger selectedFontFamily={selectedFontFamily} />

+ 3 - 4
packages/excalidraw/components/ButtonIconSelect.tsx → packages/excalidraw/components/RadioSelection.tsx

@@ -4,8 +4,7 @@ import { ButtonIcon } from "./ButtonIcon";
 
 
 import type { JSX } from "react";
 import type { JSX } from "react";
 
 
-// TODO: It might be "clever" to add option.icon to the existing component <ButtonSelect />
-export const ButtonIconSelect = <T extends Object>(
+export const RadioSelection = <T extends Object>(
   props: {
   props: {
     options: {
     options: {
       value: T;
       value: T;
@@ -28,7 +27,7 @@ export const ButtonIconSelect = <T extends Object>(
       }
       }
   ),
   ),
 ) => (
 ) => (
-  <div className="buttonList">
+  <>
     {props.options.map((option) =>
     {props.options.map((option) =>
       props.type === "button" ? (
       props.type === "button" ? (
         <ButtonIcon
         <ButtonIcon
@@ -56,5 +55,5 @@ export const ButtonIconSelect = <T extends Object>(
         </label>
         </label>
       ),
       ),
     )}
     )}
-  </div>
+  </>
 );
 );

+ 5 - 9
packages/excalidraw/css/styles.scss

@@ -140,7 +140,7 @@ body.excalidraw-cursor-resize * {
     justify-content: space-between;
     justify-content: space-between;
   }
   }
 
 
-  .panelColumn {
+  .selected-shape-actions {
     display: flex;
     display: flex;
     flex-direction: column;
     flex-direction: column;
     row-gap: 0.75rem;
     row-gap: 0.75rem;
@@ -245,10 +245,6 @@ body.excalidraw-cursor-resize * {
     left: 0;
     left: 0;
     right: 0;
     right: 0;
     --bar-padding: calc(4 * var(--space-factor));
     --bar-padding: calc(4 * var(--space-factor));
-    padding-top: #{"max(var(--bar-padding), var(--sat,0))"};
-    padding-right: var(--sar, 0);
-    padding-bottom: var(--sab, 0);
-    padding-left: var(--sal, 0);
     z-index: 4;
     z-index: 4;
     display: flex;
     display: flex;
     align-items: flex-end;
     align-items: flex-end;
@@ -263,10 +259,6 @@ body.excalidraw-cursor-resize * {
       display: flex;
       display: flex;
       flex-direction: column;
       flex-direction: column;
       pointer-events: var(--ui-pointerEvents);
       pointer-events: var(--ui-pointerEvents);
-
-      .panelColumn {
-        padding: 8px 8px 0 8px;
-      }
     }
     }
   }
   }
 
 
@@ -302,6 +294,10 @@ body.excalidraw-cursor-resize * {
     overflow-y: auto;
     overflow-y: auto;
     box-sizing: border-box;
     box-sizing: border-box;
     margin-bottom: var(--bar-padding);
     margin-bottom: var(--bar-padding);
+
+    .selected-shape-actions {
+      padding: 8px 8px 0 8px;
+    }
   }
   }
 
 
   .App-menu {
   .App-menu {