import { FocusEventHandler, HTMLInputAutoCompleteAttribute, HTMLInputTypeAttribute, JSX, useEffect, useRef, useState } from "react"; import { twMerge } from "tailwind-merge"; import { useOptionContext } from "./OptionSpace"; import { useFocusable } from "@noriginmedia/norigin-spatial-navigation"; import { systemApi } from "../../scripts/clientApi"; import { CheckIcon, X } from "lucide-react"; import { oneShot } from "@/mainview/scripts/audio/audio"; import { GamePadButtonCode, Shortcut, useShortcuts } from "@/mainview/scripts/shortcuts"; export function OptionInput (data: { name: string; type: HTMLInputTypeAttribute; className?: string; placeholder?: string; icon?: JSX.Element; value?: string | boolean | number; min?: number; max?: number; step?: number; defaultValue?: string | boolean | number; autocomplete?: HTMLInputAutoCompleteAttribute; compact?: boolean; onBlur?: FocusEventHandler; onChange?: (value: string | number | boolean) => void; }) { const handlePress = () => { if (data.type === 'checkbox') { inputRef.current?.click(); } else { inputRef.current?.focus(); } oneShot('click'); }; const [inputFocused, setInputFocused] = useState(false); const inputRef = useRef(null); const { ref, focusKey } = useFocusable({ focusKey: data.name, onEnterPress: handlePress, onBlur: () => inputRef.current?.blur() }); const option = useOptionContext({ onOptionEnterPress: handlePress, }); useEffect(() => { if (data.type === 'range') { option.setFocusBoundary(inputFocused); option.setFocusBoundaryDirections(['left', 'right']); } }, [inputFocused, option, data.type]); useShortcuts(focusKey, () => { const shortcuts: Shortcut[] = []; if (inputFocused && data.type === 'range') { shortcuts.push( { label: "Decrease", button: GamePadButtonCode.Left, action () { if (!inputRef.current) return; inputRef.current?.stepDown(); data.onChange?.(inputRef.current.valueAsNumber); } }, { label: "Increase", button: GamePadButtonCode.Right, action (e) { if (!inputRef.current) return; inputRef.current?.stepUp(); data.onChange?.(inputRef.current.valueAsNumber); } } ); } if (inputFocused) { shortcuts.push({ label: "Unfocus", button: GamePadButtonCode.B, action (e) { inputRef.current?.blur(); } }); } return shortcuts; }, [inputFocused, data.type]); const handleInputFocus = () => { option.focus(); setInputFocused(true); if (inputRef.current) { var rect = inputRef.current?.getBoundingClientRect(); systemApi.api.system.show_keyboard.post({ XPosition: rect.x, YPosition: rect.y, Width: rect.width, Height: rect.height }); } }; const handleInputBlur = (e: any) => { data.onBlur?.(e); setInputFocused(false); }; return ( ); }