import { CustomIcon } from 'components/CustomIcon' import decamelize from 'decamelize' import { useInteractionMapContext } from 'hooks/useInteractionMapContext' import { resolveInteractionEvent } from 'lib/keyboard' import { InteractionMapItem, makeOverrideKey, } from 'machines/interactionMapMachine' import { FormEvent, HTMLProps, useEffect, useRef, useState } from 'react' export function AllKeybindingsFields() { const { state } = useInteractionMapContext() return (
{Object.entries(state.context.interactionMap).map( ([category, categoryItems]) => ( ) )}
) } function KeybindingSection({ category, items, ...props }: HTMLProps & { category: string items: Record }) { return (

{decamelize(category, { separator: ' ' })}

{Object.entries(items).map(([_, item]) => ( ))}
) } function KeybindingField({ item }: { item: InteractionMapItem }) { const { send, state } = useInteractionMapContext() const [isEditing, setIsEditing] = useState(false) const [newSequence, setNewSequence] = useState('') const submitRef = useRef(null) function handleSubmit(e: FormEvent) { e.preventDefault() if (newSequence !== item.sequence) { send({ type: 'Update overrides', data: { [makeOverrideKey(item)]: newSequence, }, }) } setIsEditing(false) } useEffect(() => { const blockOtherEvents = (e: KeyboardEvent | MouseEvent) => { e.preventDefault() e.stopPropagation() e.stopImmediatePropagation() } const handleInteraction = (e: KeyboardEvent | MouseEvent) => { if (e instanceof KeyboardEvent && e.key === 'Escape') { blockOtherEvents(e) setIsEditing(false) return } else if (e instanceof KeyboardEvent && e.key === 'Enter') { return } else if (e instanceof MouseEvent && e.target === submitRef.current) { return } blockOtherEvents(e) const resolvedInteraction = resolveInteractionEvent(e) if (resolvedInteraction.isModifier) return setNewSequence((prev) => { const newSequence = prev + (prev.length ? ' ' : '') + resolvedInteraction.asString console.log('newSequence', newSequence) return newSequence }) } const handleContextMenu = (e: MouseEvent) => { blockOtherEvents(e) } if (!isEditing) { setNewSequence('') globalThis?.window?.removeEventListener('keydown', handleInteraction, { capture: true, }) globalThis?.window?.removeEventListener('mousedown', handleInteraction, { capture: true, }) globalThis?.window?.removeEventListener( 'contextmenu', handleContextMenu, { capture: true } ) } else { globalThis?.window?.addEventListener('keydown', handleInteraction, { capture: true, }) globalThis?.window?.addEventListener('mousedown', handleInteraction, { capture: true, }) globalThis?.window?.addEventListener('contextmenu', handleContextMenu, { capture: true, }) } return () => { globalThis?.window?.removeEventListener('keydown', handleInteraction, { capture: true, }) globalThis?.window?.removeEventListener('mousedown', handleInteraction, { capture: true, }) globalThis?.window?.removeEventListener( 'contextmenu', handleContextMenu, { capture: true } ) } }, [isEditing, setNewSequence]) return isEditing ? (

{item.title}

) : (

{item.title}

) } export function InteractionSequence({ sequence, className = '', showNoSequence = false, ...props }: HTMLProps & { sequence: string; showNoSequence?: boolean }) { return sequence.length ? (
{sequence.split(' ').map((chord, i) => ( {chord} ))}
) : ( showNoSequence && (
No sequence set
) ) }