import clsx from "clsx"; import { useRef } from "react"; import { Popover } from "radix-ui"; import { CLASSES } from "@excalidraw/common"; import { isArrowElement } from "@excalidraw/element"; import type { ExcalidrawElement, NonDeletedElementsMap, NonDeletedSceneElementsMap, } from "@excalidraw/element/types"; import { actionToggleZenMode } from "../actions"; import { t } from "../i18n"; import { getTargetElements } from "../scene"; import { getFormValue } from "../actions/actionProperties"; import { useTextEditorFocus } from "../hooks/useTextEditorFocus"; import { actionToggleViewMode } from "../actions/actionToggleViewMode"; import "./Actions.scss"; import { useExcalidrawContainer } from "./App"; import Stack from "./Stack"; import { Tooltip } from "./Tooltip"; import { PropertiesPopover } from "./PropertiesPopover"; import { sharpArrowIcon, roundArrowIcon, elbowArrowIcon, TextSizeIcon, adjustmentsIcon, DotsHorizontalIcon, pencilIcon, } from "./icons"; import { Island } from "./Island"; import { getShapeActionPredicates } from "./shapeActionPredicates"; import type { ShapeActionPredicates } from "./shapeActionPredicates"; import type { AppClassProperties, UIAppState, AppState } from "../types"; import type { ActionManager } from "../actions/manager"; // re-exported for consumers outside the styles panel (e.g. CommandPalette) export { canChangeStrokeColor, canChangeBackgroundColor, } from "./shapeActionPredicates"; // Common CSS class combinations const PROPERTIES_CLASSES = clsx([ CLASSES.SHAPE_ACTIONS_THEME_SCOPE, "properties-content", ]); /** * The "arrange" (z-order) fieldset, identical across every styles-panel layout. */ const LayersFieldset = ({ renderAction, }: { renderAction: ActionManager["renderAction"]; }) => (
); /** * The align + distribute fieldset, identical across every styles-panel layout. * Button order is mirrored for RTL so the leftmost button always aligns left. */ const AlignFieldset = ({ renderAction, showDistribute, }: { renderAction: ActionManager["renderAction"]; showDistribute: boolean; }) => { const isRTL = document.documentElement.getAttribute("dir") === "rtl"; return ( ); }; /** * Full styles panel: the wide, always-expanded layout used on desktop when the * UI is in "full" mode. */ export const SelectedShapeActions = ({ appState, elementsMap, renderAction, app, }: { appState: UIAppState; elementsMap: NonDeletedElementsMap | NonDeletedSceneElementsMap; renderAction: ActionManager["renderAction"]; app: AppClassProperties; }) => { const targetElements = getTargetElements(elementsMap, appState); const predicates = getShapeActionPredicates( appState, targetElements, elementsMap, app, ); // the bucket fill tool configures only the fill it creates: color, fill // style, and opacity (shared `currentItem*` values; no stroke properties) if (appState.activeTool.type === "bucketfill") { return (