alignment setting

This commit is contained in:
hamid zarghami
2026-05-02 16:14:34 +03:30
parent 47309c30dc
commit acb2f33b67
7 changed files with 433 additions and 9 deletions
@@ -0,0 +1,115 @@
import {
AlignBottom,
AlignHorizontally,
AlignLeft,
AlignRight,
AlignTop,
AlignVertically,
} from "iconsax-react";
import { useEditorStore, type EditorObject } from "../../../store/editorStore";
import type { AlignKind } from "./alignmentUtils";
import {
deltasForAlign,
pageBounds,
unionBoundsOfAlignTargets,
computeGroupFrameUpdate,
updatesFromDeltas,
} from "./alignmentUtils";
type AlignmentSettingsProps = {
pageWidth: number;
pageHeight: number;
onUpdate: (id: string, updates: Partial<EditorObject>) => void;
};
const alignIconProps = { size: 24, color: "currentColor" as const, variant: "Linear" as const };
const AlignmentSettings = ({
pageWidth,
pageHeight,
onUpdate,
}: AlignmentSettingsProps) => {
// const selectedObjectIds = useEditorStore((s) => s.selectedObjectIds);
/** دقیقاً دو شیٔ مجزا (هنوز یک گروه نشده‌اند) → مرز همان دو شی؛ یک شی یا گروه یا بیش از دو تا → صفحه */
// const alignToSelection = selectedObjectIds.length === 2;
const applyAlign = (kind: AlignKind) => {
const { objects: objs, selectedObjectIds: ids, layerRef } = useEditorStore.getState();
const layer = layerRef?.current ?? null;
const initial = new Map<string, EditorObject>();
for (const id of ids) {
const o = objs.find((x) => x.id === id);
if (o && o.visible !== false) initial.set(id, { ...o });
}
if (initial.size === 0) return;
const initialList = [...initial.values()];
const useSelectionBounds = ids.length === 2;
const target =
useSelectionBounds && initialList.length === 2
? unionBoundsOfAlignTargets(initialList, objs, layer)
: pageBounds(pageWidth, pageHeight);
if (!target) return;
const alignedGroupIds = new Set<string>();
for (const id of initial.keys()) {
const obj = initial.get(id)!;
const { dx, dy } = deltasForAlign(obj, kind, target, objs, layer);
const updates = updatesFromDeltas(obj, dx, dy);
if (Object.keys(updates).length === 0) continue;
onUpdate(id, updates);
if (obj.type === "group") {
alignedGroupIds.add(id);
}
}
const { updateObject } = useEditorStore.getState();
const afterObjects = useEditorStore.getState().objects;
for (const gid of alignedGroupIds) {
const patch = computeGroupFrameUpdate(gid, afterObjects, layer);
if (patch) updateObject(gid, patch);
}
};
// const hint = alignToSelection ? "نسبت به دو شی انتخاب‌شده" : "نسبت به صفحه";
return (
<div className="space-y-3 border-t border-border pt-4">
<div>
<h4 className="text-sm font-bold text-foreground">ابزار جابهجایی</h4>
{/* <p className="mt-1 text-xs text-muted-foreground">{hint}</p> */}
</div>
<div className="space-y-2">
<p className="text-xs font-medium text-muted-foreground">افقی</p>
<div className="flex gap-12 items-center mt-4">
<AlignRight onClick={() => applyAlign("right")} {...alignIconProps} />
<AlignHorizontally onClick={() => applyAlign("centerH")} {...alignIconProps} />
<AlignLeft onClick={() => applyAlign("left")} {...alignIconProps} />
</div>
</div>
<div className="space-y-2">
<p className="text-xs font-medium text-muted-foreground mt-4">عمودی</p>
<div className="flex gap-12 items-center mt-4">
<AlignTop onClick={() => applyAlign("top")} {...alignIconProps} />
<AlignVertically onClick={() => applyAlign("centerV")} {...alignIconProps} />
<AlignBottom onClick={() => applyAlign("bottom")} {...alignIconProps} />
</div>
</div>
</div>
);
};
export default AlignmentSettings;