import { isFocusable , getClosestFocusable , closest } from "reakit-utils" ; import { warning } from "reakit-warning" ; import { fireEvent } from "./fireEvent" ; import { focus } from "./focus" ; import { hover } from "./hover" ; import { blur } from "./blur" ; import "./mockClientRects" ; function getClosestLabel ( element ) { if ( ! isFocusable ( element ) ) { return closest ( element , "label" ) ; } return null ; } function getInputFromLabel ( element ) { const input = element . htmlFor ? element . ownerDocument ?. getElementById ( element . htmlFor ) : element . querySelector ( "input,textarea,select" ) ; return input as HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement | null | undefined ; } function clickLabel ( element , options ? ) { const input = getInputFromLabel ( element ) ; const isInputDisabled = Boolean ( input ?. disabled ) ; if ( input ) { input . disabled = true ; } const defaultAllowed = fireEvent . click ( element , options ) ; if ( input ) { input . disabled = isInputDisabled ; if ( defaultAllowed && isFocusable ( input ) ) { focus ( input ) ; fireEvent . click ( input ) ; } } } function setSelected ( element , selected ) { element . setAttribute ( "selected" , selected ? "selected" : "" ) ; element . selected = selected ; } function clickOption ( element , eventOptions ? ) { const select = closest ( element , "select" ) as HTMLSelectElement & { lastOptionSelectedNotByShiftKey ? : HTMLOptionElement ; } ; if ( ! select ) { fireEvent . click ( element , eventOptions ) ; warning ( true , "[reakit-test-utils/click]" , "You're trying to click on an <option> element that's not wrapped by a <select> element, which will not produce any result." ) ; return ; } if ( select . multiple ) { const options = Array . from ( select . options ) ; const resetOptions = ( ) => options . forEach ( ( option ) => { setSelected ( option , false ) ; } ) ; const selectRange = ( a , b ) => { const from = Math . min ( a , b ) ; const to = Math . max ( a , b ) + 1 ; const selectedOptions = options . slice ( from , to ) ; selectedOptions . forEach ( ( option ) => { setSelected ( option , true ) ; } ) ; } ; if ( eventOptions ?. shiftKey ) { const elementIndex = options . indexOf ( element ) ; const referenceOption = select . lastOptionSelectedNotByShiftKey ; const referenceOptionIndex = referenceOption ? options . indexOf ( referenceOption ) : - 1 ; resetOptions ( ) ; selectRange ( elementIndex , referenceOptionIndex ) ; setSelected ( element , true ) ; } else { select . lastOptionSelectedNotByShiftKey = element ; if ( eventOptions ?. ctrlKey ) { setSelected ( element , ! element . selected ) ; } else { resetOptions ( ) ; setSelected ( element , true ) ; } } } else { setSelected ( element , true ) ; } fireEvent . input ( select ) ; fireEvent . change ( select ) ; fireEvent . click ( element , eventOptions ) ; } export function click ( element , options ? ) { hover ( element , options ) ; const { disabled } = element as HTMLButtonElement ; let defaultAllowed = fireEvent . pointerDown ( element , options ) ; if ( ! disabled ) { if ( ! fireEvent . mouseDown ( element , options ) ) { defaultAllowed = false ; } } if ( defaultAllowed ) { if ( isFocusable ( element ) && getComputedStyle ( element ) . pointerEvents !== "none" ) { focus ( element ) ; } else if ( element . parentElement ) { const closestFocusable = getClosestFocusable ( element . parentElement ) ; if ( closestFocusable ) { focus ( closestFocusable ) ; } else { blur ( ) ; } } } fireEvent . pointerUp ( element , options ) ; if ( disabled ) return ; fireEvent . mouseUp ( element , options ) ; const label = getClosestLabel ( element ) ; if ( label ) { clickLabel ( label , options ) ; } else if ( element instanceof HTMLOptionElement ) { clickOption ( element , options ) ; } else { fireEvent . click ( element , options ) ; } }