import { useEffect, useState, type Dispatch, type SetStateAction } from "react"; import { BoundingBox } from "@phosphor-icons/react"; import { commandIds } from "@commands/ids"; import type { Rect } from "@core/geometry"; import type { AppStore } from "@editor/store"; import type { TransformTarget } from "@editor/transform"; import { BottomControlDivider } from "./Divider"; import { bottomControlIconSlotClass, bottomControlInputClass, bottomControlLabelClass } from "./styles"; export type TransformControlsProps = { bounds: Rect; target: TransformTarget; dispatch: AppStore["dispatch"]; }; type BoundsField = keyof Rect; export function TransformControls({ bounds, target, dispatch }: TransformControlsProps) { const [draft, setDraft] = useState(() => draftFromBounds(bounds)); useEffect(() => { setDraft(draftFromBounds(bounds)); }, [bounds.x, bounds.y, bounds.w, bounds.h]); const commitField = (field: BoundsField) => { const value = Number.parseFloat(draft[field]); if (!Number.isFinite(value)) { setDraft(draftFromBounds(bounds)); return; } dispatch(commandIds.transformSetBounds, { target, bounds: { ...bounds, [field]: field === "w" || field === "h" ? Math.max(1, value) : value, }, }); }; return (
); } function BoundsInput({ label, field, draft, setDraft, commitField, }: { label: string; field: BoundsField; draft: string; setDraft: Dispatch>>; commitField: (field: BoundsField) => void; }) { return ( ); } function draftFromBounds(bounds: Rect): Record { return { x: String(Math.round(bounds.x)), y: String(Math.round(bounds.y)), w: String(Math.round(bounds.w)), h: String(Math.round(bounds.h)), }; }