import { getPreviousTabbableIn , getNextTabbableIn , isFocusable , isTextField , } from "reakit-utils" ; import { fireEvent } from "./fireEvent" ; import { focus } from "./focus" ; import { blur } from "./blur" ; import "./mockClientRects" ; const clickableInputTypes = [ "button" , "color" , "file" , "image" , "reset" , "submit" , ] ; function submitFormByPressingEnterOn ( element , options ) { const { form } = element ; if ( ! form ) return ; const elements = Array . from ( form . elements ) ; const validInputs = elements . filter ( ( el ) => el instanceof HTMLInputElement && isTextField ( el ) ) ; const submitButton = elements . find ( ( el ) => ( el instanceof HTMLInputElement || el instanceof HTMLButtonElement ) && el . type === "submit" ) ; if ( validInputs . length === 1 || submitButton ) { fireEvent . submit ( form , options ) ; } } const keyDownMap = { Tab ( element , { shiftKey } ) { const body = element . ownerDocument ?. body || document . body ; const nextElement = shiftKey ? getPreviousTabbableIn ( body ) : getNextTabbableIn ( body ) ; if ( nextElement ) { focus ( nextElement ) ; } } , Enter ( element , options ) { const nonSubmittableTypes = [ ... clickableInputTypes , "hidden" ] ; const isClickable = element . tagName === "BUTTON" || ( element instanceof HTMLInputElement && clickableInputTypes . includes ( element . type ) ) ; const isSubmittable = element instanceof HTMLInputElement && ! nonSubmittableTypes . includes ( element . type ) ; const isLineBreakable = element instanceof HTMLTextAreaElement ; if ( isClickable ) { fireEvent . click ( element , options ) ; } else if ( isLineBreakable ) { ( element as HTMLTextAreaElement ) . value += "\n" ; } else if ( isSubmittable ) { submitFormByPressingEnterOn ( element as HTMLInputElement , options ) ; } } , } ; const keyUpMap = { " " : ( element , options ) => { const spaceableTypes = [ ... clickableInputTypes , "checkbox" , "radio" ] ; const isSpaceable = element . tagName === "BUTTON" || ( element instanceof HTMLInputElement && spaceableTypes . includes ( element . type ) ) ; if ( isSpaceable ) { fireEvent . click ( element , options ) ; } } , } ; export function press ( key , element ? , options = { } ) { if ( element == null ) { element = document . activeElement || document . body ; } if ( ! element ) return ; if ( ! isFocusable ( element ) && element . tagName !== "BODY" ) return ; if ( element . ownerDocument ?. activeElement !== element ) { if ( element . tagName === "BODY" ) { blur ( ) ; } else { focus ( element ) ; } } let defaultAllowed = fireEvent . keyDown ( element , { key , ... options } ) ; if ( defaultAllowed && key in keyDownMap && ! options . metaKey ) { keyDownMap [ key ] ( element , options ) ; } if ( element . ownerDocument ?. activeElement !== element ) { element = element . ownerDocument ! . activeElement ! ; } if ( ! fireEvent . keyUp ( element , { key , ... options } ) ) { defaultAllowed = false ; } if ( defaultAllowed && key in keyUpMap && ! options . metaKey ) { keyUpMap [ key ] ( element , options ) ; } } function createPress ( key , defaultOptions = { } ) { return ( element ? , options = { } ) => press ( key , element , { ... defaultOptions , ... options } ) ; } press . Escape = createPress ( "Escape" ) ; press . Backspace = createPress ( "Backspace" ) ; press . Delete = createPress ( "Delete" ) ; press . Tab = createPress ( "Tab" ) ; press . ShiftTab = createPress ( "Tab" , { shiftKey : true } ) ; press . Enter = createPress ( "Enter" ) ; press . Space = createPress ( " " ) ; press . ArrowUp = createPress ( "ArrowUp" ) ; press . ArrowRight = createPress ( "ArrowRight" ) ; press . ArrowDown = createPress ( "ArrowDown" ) ; press . ArrowLeft = createPress ( "ArrowLeft" ) ; press . End = createPress ( "End" ) ; press . Home = createPress ( "Home" ) ; press . PageUp = createPress ( "PageUp" ) ; press . PageDown = createPress ( "PageDown" ) ;