From 6ec259a0e71174651bae95d4628138bf6fd68742 Mon Sep 17 00:00:00 2001 From: kj_sh604 Date: Sun, 15 Mar 2026 16:19:35 -0400 Subject: refactor: packages/ --- packages/excalidraw/actions/actionDistribute.tsx | 110 +++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 packages/excalidraw/actions/actionDistribute.tsx (limited to 'packages/excalidraw/actions/actionDistribute.tsx') diff --git a/packages/excalidraw/actions/actionDistribute.tsx b/packages/excalidraw/actions/actionDistribute.tsx new file mode 100644 index 0000000..15d33b1 --- /dev/null +++ b/packages/excalidraw/actions/actionDistribute.tsx @@ -0,0 +1,110 @@ +import { + DistributeHorizontallyIcon, + DistributeVerticallyIcon, +} from "../components/icons"; +import { ToolButton } from "../components/ToolButton"; +import type { Distribution } from "../distribute"; +import { distributeElements } from "../distribute"; +import { getNonDeletedElements } from "../element"; +import { isFrameLikeElement } from "../element/typeChecks"; +import type { ExcalidrawElement } from "../element/types"; +import { updateFrameMembershipOfSelectedElements } from "../frame"; +import { t } from "../i18n"; +import { CODES, KEYS } from "../keys"; +import { isSomeElementSelected } from "../scene"; +import { CaptureUpdateAction } from "../store"; +import type { AppClassProperties, AppState } from "../types"; +import { arrayToMap, getShortcutKey } from "../utils"; +import { register } from "./register"; + +const enableActionGroup = (appState: AppState, app: AppClassProperties) => { + const selectedElements = app.scene.getSelectedElements(appState); + return ( + selectedElements.length > 1 && + // TODO enable distributing frames when implemented properly + !selectedElements.some((el) => isFrameLikeElement(el)) + ); +}; + +const distributeSelectedElements = ( + elements: readonly ExcalidrawElement[], + appState: Readonly, + app: AppClassProperties, + distribution: Distribution, +) => { + const selectedElements = app.scene.getSelectedElements(appState); + + const updatedElements = distributeElements( + selectedElements, + app.scene.getNonDeletedElementsMap(), + distribution, + ); + + const updatedElementsMap = arrayToMap(updatedElements); + + return updateFrameMembershipOfSelectedElements( + elements.map((element) => updatedElementsMap.get(element.id) || element), + appState, + app, + ); +}; + +export const distributeHorizontally = register({ + name: "distributeHorizontally", + label: "labels.distributeHorizontally", + trackEvent: { category: "element" }, + perform: (elements, appState, _, app) => { + return { + appState, + elements: distributeSelectedElements(elements, appState, app, { + space: "between", + axis: "x", + }), + captureUpdate: CaptureUpdateAction.IMMEDIATELY, + }; + }, + keyTest: (event) => + !event[KEYS.CTRL_OR_CMD] && event.altKey && event.code === CODES.H, + PanelComponent: ({ elements, appState, updateData, app }) => ( +