Potion/web/src/components/forms/InstructionElement.tsx
2025-12-28 22:20:39 -07:00

77 lines
2.5 KiB
TypeScript

import { type ChangeEvent } from "react";
import type { RecipeInstruction } from "../../types/recipe";
import { Reorder, useDragControls } from "motion/react";
import DragIconSmall from "../icons/DragIconSmall";
import DeleteIconSmall from "../icons/DeleteIconSmall";
interface InstructionElementProps {
instruction: RecipeInstruction;
index: number;
allowDelete: boolean;
onChange: (id: string, value: string) => void;
onDelete: (id: string) => void;
valid: boolean;
dirty: boolean;
markDirty: (id: string) => void;
}
export default function InstructionElement({ instruction, index, allowDelete, onChange, onDelete, valid, dirty, markDirty }: InstructionElementProps) {
const controls = useDragControls();
const changeHandler = (e: ChangeEvent<HTMLTextAreaElement>) => {
if (!dirty) markDirty(instruction.Id)
onChange(instruction.Id, e.target.value);
}
return (
<Reorder.Item
value={instruction}
dragListener={false}
dragControls={controls}
className="flex items-center"
>
<div className="flex flex-grow items-center select-none">
<h2 className="text-lg md:text-xl mr-4 text-gray-500">{index + 1}.</h2>
<div className="flex flex-col flex-grow">
<textarea
className={`flex-grow border border-gray-300 px-4 py-2 rounded-lg focus:outline-none focus:ring-blue-500 focus:ring-2 duration-200 ease-in-out transition-all min-h-40 md:min-h-26 shadow-sm ${!valid && dirty ? "border-red-500" : ""}`}
name="instructions"
value={instruction.Content}
onChange={changeHandler}
rows={3}
required
minLength={1}
placeholder="Describe this step..."
/>
{(!valid && dirty) && (
<p className="text-xs text-red-500 my-1">
Please enter an instruction (blank entries are not allowed).
</p>
)}
</div>
</div>
<div className="flex flex-col items-center">
<div
className="p-2 pr-0 cursor-grab touch-none"
onPointerDown={e => {
e.preventDefault();
controls.start(e);
}}
>
<DragIconSmall />
</div>
<button
tabIndex={-1}
disabled={!allowDelete}
onClick={() => onDelete(instruction.Id)}
className="p-2 pr-0 cursor-pointer text-gray-500 hover:text-red-500 disabled:text-gray-200 disabled:cursor-not-allowed duration-300"
>
<DeleteIconSmall />
</button>
</div>
</Reorder.Item>
);
}