+ {/* Stroke Color */}
+ {canChangeStrokeColor(appState, targetElements) && (
+
+ {renderAction("changeStrokeColor", { compactMode: true })}
+
+ )}
+
+ {/* Background Color */}
+ {canChangeBackgroundColor(appState, targetElements) && (
+
+ {renderAction("changeBackgroundColor", { compactMode: true })}
+
+ )}
+
+ {/* Combined Properties (Fill, Stroke, Opacity) */}
+ {(showFillIcons ||
+ hasStrokeWidth(appState.activeTool.type) ||
+ targetElements.some((element) => hasStrokeWidth(element.type)) ||
+ hasStrokeStyle(appState.activeTool.type) ||
+ targetElements.some((element) => hasStrokeStyle(element.type)) ||
+ canChangeRoundness(appState.activeTool.type) ||
+ targetElements.some((element) => canChangeRoundness(element.type))) && (
+
+
+
+
+
+ {strokePopoverOpen && (
+ setStrokePopoverOpen(false)}
+ >
+
+ {showFillIcons && renderAction("changeFillStyle")}
+ {(hasStrokeWidth(appState.activeTool.type) ||
+ targetElements.some((element) =>
+ hasStrokeWidth(element.type),
+ )) &&
+ renderAction("changeStrokeWidth")}
+ {(hasStrokeStyle(appState.activeTool.type) ||
+ targetElements.some((element) =>
+ hasStrokeStyle(element.type),
+ )) && (
+ <>
+ {renderAction("changeStrokeStyle")}
+ {renderAction("changeSloppiness")}
+ >
+ )}
+ {(canChangeRoundness(appState.activeTool.type) ||
+ targetElements.some((element) =>
+ canChangeRoundness(element.type),
+ )) &&
+ renderAction("changeRoundness")}
+ {renderAction("changeOpacity")}
+
+
+ )}
+
+
+ )}
+
+ {/* Combined Arrow Properties */}
+ {(toolIsArrow(appState.activeTool.type) ||
+ targetElements.some((element) => toolIsArrow(element.type))) && (
+
+
{
+ setAppState({ openPopup: open ? "arrowProperties" : null });
+ }}
+ >
+
+
+
+ {appState.openPopup === "arrowProperties" && (
+ setAppState({ openPopup: null })}
+ >
+ {renderAction("changeArrowProperties")}
+
+ )}
+
+
+ )}
+
+ {/* Linear Editor */}
+ {showLineEditorAction && (
+
+ {renderAction("toggleLinearEditor", { compactMode: true })}
+
+ )}
+
+ {/* Text Properties */}
+ {(appState.activeTool.type === "text" ||
+ targetElements.some(isTextElement)) && (
+ <>
+
+ {renderAction("changeFontFamily", {
+ compactMode: true,
+ })}
+
+
+
{
+ setAppState({ openPopup: open ? "textAlign" : null });
+ }}
+ >
+
+
+
+ {appState.openPopup === "textAlign" && (
+ setAppState({ openPopup: null })}
+ >
+
+ {(appState.activeTool.type === "text" ||
+ suppportsHorizontalAlign(targetElements, elementsMap)) &&
+ renderAction("changeTextAlign")}
+ {shouldAllowVerticalAlign(targetElements, elementsMap) &&
+ renderAction("changeVerticalAlign")}
+ {(appState.activeTool.type === "text" ||
+ targetElements.some(isTextElement)) &&
+ renderAction("changeFontSize")}
+
+
+ )}
+
+
+ >
+ )}
+
+ {/* Dedicated Copy Button */}
+ {!isEditingTextOrNewElement && targetElements.length > 0 && (
+
+ {renderAction("duplicateSelection", { compactMode: true })}
+
+ )}
+
+ {/* Dedicated Delete Button */}
+ {!isEditingTextOrNewElement && targetElements.length > 0 && (
+
+ {renderAction("deleteSelectedElements", { compactMode: true })}
+
+ )}
+
+ {/* Combined Other Actions */}
+ {!isEditingTextOrNewElement && targetElements.length > 0 && (
+
+
+
+
+
+ {otherActionsPopoverOpen && (
+ setOtherActionsPopoverOpen(false)}
+ >
+
+
+
+ {showAlignActions && !isSingleElementBoundContainer && (
+
+ )}
+
+
+
+ )}
+
+
+ )}
+
+ );
+};
+
export const ShapesSwitcher = ({
activeTool,
appState,
diff --git a/packages/excalidraw/components/ColorPicker/ColorPicker.scss b/packages/excalidraw/components/ColorPicker/ColorPicker.scss
index 1267bcc14..0e3768dcc 100644
--- a/packages/excalidraw/components/ColorPicker/ColorPicker.scss
+++ b/packages/excalidraw/components/ColorPicker/ColorPicker.scss
@@ -86,6 +86,16 @@
}
}
+ .color-picker__button-background {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ svg {
+ width: 100%;
+ height: 100%;
+ }
+ }
+
&.active {
.color-picker__button-outline {
position: absolute;
diff --git a/packages/excalidraw/components/ColorPicker/ColorPicker.tsx b/packages/excalidraw/components/ColorPicker/ColorPicker.tsx
index f66e9bd44..32d5c9f77 100644
--- a/packages/excalidraw/components/ColorPicker/ColorPicker.tsx
+++ b/packages/excalidraw/components/ColorPicker/ColorPicker.tsx
@@ -18,7 +18,7 @@ import { useExcalidrawContainer } from "../App";
import { ButtonSeparator } from "../ButtonSeparator";
import { activeEyeDropperAtom } from "../EyeDropper";
import { PropertiesPopover } from "../PropertiesPopover";
-import { slashIcon } from "../icons";
+import { backgroundIcon, slashIcon, strokeIcon } from "../icons";
import { ColorInput } from "./ColorInput";
import { Picker } from "./Picker";
@@ -189,10 +189,14 @@ const ColorPickerTrigger = ({
label,
color,
type,
+ compactMode = false,
+ mode = "background",
}: {
color: string | null;
label: string;
type: ColorPickerType;
+ compactMode?: boolean;
+ mode?: "background" | "stroke";
}) => {
return (