import { LuArrowUp, LuArrowDown, LuX, LuTrash2 } from "react-icons/lu"; import { Button } from "@/components/Button"; import { Combobox } from "@/components/Combobox"; import { SelectMenuBasic } from "@/components/SelectMenuBasic"; import Card from "@/components/Card"; import { keys, modifiers, keyDisplayMap } from "@/keyboardMappings"; import { MAX_KEYS_PER_STEP, DEFAULT_DELAY } from "@/constants/macros"; import FieldLabel from "@/components/FieldLabel"; // Filter out modifier keys since they're handled in the modifiers section const modifierKeyPrefixes = ['Alt', 'Control', 'Shift', 'Meta']; const keyOptions = Object.keys(keys) .filter(key => !modifierKeyPrefixes.some(prefix => key.startsWith(prefix))) .map(key => ({ value: key, label: keyDisplayMap[key] || key, })); const modifierOptions = Object.keys(modifiers).map(modifier => ({ value: modifier, label: modifier.replace(/^(Control|Alt|Shift|Meta)(Left|Right)$/, "$1 $2"), })); const groupedModifiers: Record = { Control: modifierOptions.filter(mod => mod.value.startsWith('Control')), Shift: modifierOptions.filter(mod => mod.value.startsWith('Shift')), Alt: modifierOptions.filter(mod => mod.value.startsWith('Alt')), Meta: modifierOptions.filter(mod => mod.value.startsWith('Meta')), }; const basePresetDelays = [ { value: "50", label: "50ms" }, { value: "100", label: "100ms" }, { value: "200", label: "200ms" }, { value: "300", label: "300ms" }, { value: "500", label: "500ms" }, { value: "750", label: "750ms" }, { value: "1000", label: "1000ms" }, { value: "1500", label: "1500ms" }, { value: "2000", label: "2000ms" }, ]; const PRESET_DELAYS = basePresetDelays.map(delay => { if (parseInt(delay.value, 10) === DEFAULT_DELAY) { return { ...delay, label: "Default" }; } return delay; }); interface MacroStep { keys: string[]; modifiers: string[]; delay: number; } interface MacroStepCardProps { step: MacroStep; stepIndex: number; onDelete?: () => void; onMoveUp?: () => void; onMoveDown?: () => void; onKeySelect: (option: { value: string | null; keys?: string[] }) => void; onKeyQueryChange: (query: string) => void; keyQuery: string; onModifierChange: (modifiers: string[]) => void; onDelayChange: (delay: number) => void; isLastStep: boolean; } const ensureArray = (arr: T[] | null | undefined): T[] => { return Array.isArray(arr) ? arr : []; }; export function MacroStepCard({ step, stepIndex, onDelete, onMoveUp, onMoveDown, onKeySelect, onKeyQueryChange, keyQuery, onModifierChange, onDelayChange, isLastStep }: MacroStepCardProps) { const getFilteredKeys = () => { const selectedKeys = ensureArray(step.keys); const availableKeys = keyOptions.filter(option => !selectedKeys.includes(option.value)); if (keyQuery === '') { return availableKeys; } else { return availableKeys.filter(option => option.label.toLowerCase().includes(keyQuery.toLowerCase())); } }; return (
{stepIndex + 1}
{onDelete && (
{Object.entries(groupedModifiers).map(([group, mods]) => (
{group}
{mods.map(option => (
))}
{ensureArray(step.keys) && step.keys.length > 0 && (
{step.keys.map((key, keyIndex) => ( {keyDisplayMap[key] || key}
)}
{ onKeySelect(value); onKeyQueryChange(''); }} displayValue={() => keyQuery} onInputChange={onKeyQueryChange} options={getFilteredKeys} disabledMessage="Max keys reached" size="SM" immediate disabled={ensureArray(step.keys).length >= MAX_KEYS_PER_STEP} placeholder={ensureArray(step.keys).length >= MAX_KEYS_PER_STEP ? "Max keys reached" : "Search for key..."} emptyMessage="No matching keys found" />
onDelayChange(parseInt(e.target.value, 10))} options={PRESET_DELAYS} />
); }