always show undo & redo and improve styling

This commit is contained in:
Ryan Di
2025-09-24 14:36:47 +10:00
parent ce6a9549e1
commit 1bf169b4e9
10 changed files with 43 additions and 39 deletions

View File

@@ -331,7 +331,8 @@ export const actionDeleteSelected = register({
!isSomeElementSelected(getNonDeletedElements(elements), appState)
}
style={{
...(appState.stylesPanelMode === "mobile"
...(appState.stylesPanelMode === "mobile" &&
appState.openPopup !== "compactOtherProperties"
? MOBILE_ACTION_BUTTON_BG
: {}),
}}

View File

@@ -120,7 +120,8 @@ export const actionDuplicateSelection = register({
!isSomeElementSelected(getNonDeletedElements(elements), appState)
}
style={{
...(appState.stylesPanelMode === "mobile"
...(appState.stylesPanelMode === "mobile" &&
appState.openPopup !== "compactOtherProperties"
? MOBILE_ACTION_BUTTON_BG
: {}),
}}

View File

@@ -192,6 +192,9 @@
background: transparent;
border-radius: var(--border-radius-lg);
box-shadow: none;
overflow: none;
scrollbar-width: none;
-ms-overflow-style: none;
}
.shape-actions-theme-scope {

View File

@@ -328,14 +328,7 @@ const CombinedShapeProperties = ({
hasBackground(element.type) && !isTransparent(element.backgroundColor),
);
const shouldShowCombinedProperties =
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));
const shouldShowCombinedProperties = targetElements.length > 0;
const isOpen = appState.openPopup === "compactStrokeStyles";
@@ -606,7 +599,6 @@ const CombinedExtraActions = ({
setAppState,
container,
app,
showRedo,
showDuplicate,
showDelete,
}: {
@@ -616,7 +608,6 @@ const CombinedExtraActions = ({
setAppState: React.Component<any, AppState>["setState"];
container: HTMLDivElement | null;
app: AppClassProperties;
showRedo?: boolean;
showDuplicate?: boolean;
showDelete?: boolean;
}) => {
@@ -740,11 +731,10 @@ const CombinedExtraActions = ({
<div className="buttonList">
{renderAction("group")}
{renderAction("ungroup")}
{showRedo && renderAction("redo")}
{showDuplicate && renderAction("duplicateSelection")}
{showDelete && renderAction("deleteSelectedElements")}
{showLinkIcon && renderAction("hyperlink")}
{showCropEditorAction && renderAction("cropEditor")}
{showDuplicate && renderAction("duplicateSelection")}
{showDelete && renderAction("deleteSelectedElements")}
</div>
</fieldset>
</div>
@@ -907,19 +897,22 @@ export const MobileShapeActions = ({
const { container } = useExcalidrawContainer();
const mobileActionsRef = useRef<HTMLDivElement>(null);
const width = mobileActionsRef.current?.getBoundingClientRect()?.width ?? 0;
const ACTIONS_WIDTH =
mobileActionsRef.current?.getBoundingClientRect()?.width ?? 0;
// 7 actions + 2 for undo/redo
const MIN_ACTIONS = 9;
const WIDTH = 36;
const GAP = 6;
const WIDTH = 32;
// max 7 actions + undo
const MIN_WIDTH = 8 * WIDTH + 7 * GAP;
const MIN_WIDTH = MIN_ACTIONS * WIDTH + (MIN_ACTIONS - 1) * GAP;
const ADDITIONAL_WIDTH = WIDTH + GAP;
const showRedoOutside = width >= MIN_WIDTH + 1 * ADDITIONAL_WIDTH;
const showDeleteOutside = width >= 2 * MIN_WIDTH;
const showDuplicateOutside = width >= MIN_WIDTH + 3 * ADDITIONAL_WIDTH;
const showDeleteOutside = ACTIONS_WIDTH >= MIN_WIDTH + ADDITIONAL_WIDTH;
const showDuplicateOutside =
ACTIONS_WIDTH >= MIN_WIDTH + 2 * ADDITIONAL_WIDTH;
return (
<Island
@@ -930,8 +923,8 @@ export const MobileShapeActions = ({
padding: 0,
zIndex: 2,
backgroundColor: "transparent",
height: WIDTH * 1.25,
marginBottom: 2,
height: WIDTH * 1.35,
marginBottom: 4,
alignItems: "center",
gap: GAP,
pointerEvents: "none",
@@ -1004,7 +997,6 @@ export const MobileShapeActions = ({
setAppState={setAppState}
container={container}
app={app}
showRedo={!showRedoOutside}
showDuplicate={!showDuplicateOutside}
showDelete={!showDeleteOutside}
/>
@@ -1017,9 +1009,7 @@ export const MobileShapeActions = ({
}}
>
<div className="compact-action-item">{renderAction("undo")}</div>
{showRedoOutside && (
<div className="compact-action-item">{renderAction("redo")}</div>
)}
<div className="compact-action-item">{renderAction("redo")}</div>
{showDuplicateOutside && (
<div className="compact-action-item">
{renderAction("duplicateSelection")}

View File

@@ -1,5 +1,7 @@
import * as Popover from "@radix-ui/react-popover";
import { MOBILE_ACTION_BUTTON_BG } from "@excalidraw/common";
import type { FontFamilyValues } from "@excalidraw/element/types";
import { t } from "../../i18n";
@@ -23,11 +25,9 @@ export const FontPickerTrigger = ({
const compactStyle = compactMode
? {
background: "rgba(255, 255, 255, 0.1)",
backdropFilter: "blur(20px)",
WebkitBackdropFilter: "blur(20px)",
width: "2.25rem",
height: "2.25rem",
...MOBILE_ACTION_BUTTON_BG,
width: "2rem",
height: "2rem",
}
: {};

View File

@@ -6,7 +6,7 @@
display: flex;
flex: 1;
align-items: center;
padding: 4px;
padding: 0px;
gap: 4px;
border-radius: var(--space-factor);
overflow-x: auto;

View File

@@ -50,6 +50,7 @@ export const ToolPopover = ({
}: ToolPopoverProps) => {
const [isPopupOpen, setIsPopupOpen] = useState(false);
const currentType = activeTool.type;
const SIDE_OFFSET = 32 / 2 + 10;
// if currentType is not in options, close popup
if (!options.some((o) => o.type === currentType) && isPopupOpen) {
@@ -87,7 +88,10 @@ export const ToolPopover = ({
/>
</Popover.Trigger>
<Popover.Content className="tool-popover-content" sideOffset={28}>
<Popover.Content
className="tool-popover-content"
sideOffset={SIDE_OFFSET}
>
{options.map(({ type, icon, title }) => (
<ToolButton
className={clsx(className, {

View File

@@ -245,7 +245,7 @@ body.excalidraw-cursor-resize * {
position: absolute;
// account for margins
width: calc(100% - 28px);
max-width: 400px;
max-width: 450px;
bottom: 0;
left: 50%;
transform: translateX(-50%);

View File

@@ -42,7 +42,7 @@
--lg-button-size: 2.25rem;
--lg-icon-size: 1rem;
--editor-container-padding: 1rem;
--mobile-action-button-size: 2.25rem;
--mobile-action-button-size: 2rem;
@include isMobile {
--editor-container-padding: 0.75rem;

View File

@@ -122,6 +122,11 @@
color: var(--button-color, var(--color-on-primary-container));
}
}
@include isMobile() {
width: var(--mobile-action-button-size, var(--default-button-size));
height: var(--mobile-action-button-size, var(--default-button-size));
}
}
@mixin outlineButtonIconStyles {
@@ -183,8 +188,8 @@
border: none;
box-shadow: 0 0 0 1px var(--color-surface-lowest);
background-color: var(--color-surface-low);
width: var(--moobile-action-button-size, 2.25rem);
height: var(--moobile-action-button-size, 2.25rem);
width: var(--mobile-action-button-size, 2rem);
height: var(--mobile-action-button-size, 2rem);
&:active {
box-shadow: 0 0 0 1px var(--color-brand-active);