import React, { ChangeEvent, RefObject, useRef } from "react"; import { twMerge } from "tailwind-merge"; import { disableHotkeyInput, DomLevels, enableHotkeyInput, } from "~/pages/PageEnigma/signals"; interface InputVectorProps { x: string; y: string; z: string; onChange: (v: Record) => void; increment?: number; disabled?: boolean; } export const InputVector = ({ x, y, z, onChange, increment = 0.1, disabled, }: InputVectorProps) => { const xRef = useRef(null); const yRef = useRef(null); const zRef = useRef(null); const isDragging = useRef(false); const previousMousePosition = useRef(0); const oldX = useRef(""); const oldY = useRef(""); const oldZ = useRef(""); oldX.current = x; oldY.current = y; oldZ.current = z; const inputCommonClasses = "relative h-6 rounded-r-lg bg-brand-secondary-900/35 p-2 text-sm text-white transition-all duration-100 ease-in-out outline-none -outline-offset-2 text-end w-full hover:cursor-e-resize hover:bg-brand-secondary-900"; const wrapperCommonClasses = "relative flex items-center before:inline-block before:h-6 before:bg-brand-primary before:text-white before:rounded-l-lg before:w-1.5 before:text-center before:justify-center before:items-center before:font-semibold before:flex before:align-middle before:leading-8 text-xs"; const lockedCommonClasses = "hover:cursor-not-allowed hover:bg-brand-secondary"; function validateInput(newValue: string, oldValue: string) { if (newValue === "" || newValue === "-" || newValue === ".") { return newValue; } return /^-?\d*(\.\d{0,2})?$/.test(newValue) ? newValue : oldValue; } function handleOnChange(event: ChangeEvent) { const newVector: Record = { x: oldX.current, y: oldY.current, z: oldZ.current, }; newVector[event.target.name] = validateInput( event.target.value, newVector[event.target.name], ); onChange(newVector); } const blurAllInputs = () => { xRef.current?.blur(); yRef.current?.blur(); zRef.current?.blur(); }; // For dragging the input value to increment/decrement const handleMouseDown = ( e: React.MouseEvent, ref: RefObject, ) => { e.stopPropagation(); blurAllInputs(); previousMousePosition.current = e.clientX; isDragging.current = true; const mouseMoveHandler = (e: MouseEvent) => { e.stopPropagation(); const currentMousePosition = e.clientX; const direction = currentMousePosition === previousMousePosition.current ? 0 : currentMousePosition > previousMousePosition.current ? 1 : -1; previousMousePosition.current = currentMousePosition; const newVector = { x: oldX.current, y: oldY.current, z: oldZ.current, } as Record; const newValue = parseFloat(newVector[ref.current?.name ?? ""]) + direction * increment; newVector[ref.current?.name ?? ""] = ( Math.round(newValue * 1000) / 1000 ).toString(); onChange(newVector); }; const mouseUpHandler = () => { document.removeEventListener("mousemove", mouseMoveHandler); document.removeEventListener("mouseup", mouseUpHandler); isDragging.current = false; }; document.addEventListener("mousemove", mouseMoveHandler); document.addEventListener("mouseup", mouseUpHandler); }; const handleKeyDown = (e: React.KeyboardEvent) => { if (e.key === "Enter") { (e.currentTarget as HTMLInputElement).blur(); // Unfocus the input field on pressing Enter } }; return (
X
{ disableHotkeyInput(DomLevels.INPUT); }} onBlur={() => { enableHotkeyInput(DomLevels.INPUT); }} onMouseDown={(e) => { handleMouseDown(e, xRef); }} onKeyDown={handleKeyDown} />
Y
{ disableHotkeyInput(DomLevels.INPUT); }} onBlur={() => { enableHotkeyInput(DomLevels.INPUT); }} onMouseDown={(e) => { handleMouseDown(e, yRef); }} onKeyDown={handleKeyDown} />
Z
{ disableHotkeyInput(DomLevels.INPUT); }} onBlur={() => { enableHotkeyInput(DomLevels.INPUT); }} onMouseDown={(e) => { handleMouseDown(e, zRef); }} onKeyDown={handleKeyDown} />
); };