( props: AriaHiddenSelectOptions, state: SelectState<T, M>, triggerRef: RefObject<FocusableElement | null> )
| 76 | * navigation, and native HTML form submission. |
| 77 | */ |
| 78 | export function useHiddenSelect<T, M extends SelectionMode = 'single'>( |
| 79 | props: AriaHiddenSelectOptions, |
| 80 | state: SelectState<T, M>, |
| 81 | triggerRef: RefObject<FocusableElement | null> |
| 82 | ): HiddenSelectAria { |
| 83 | let data = selectData.get(state) || {}; |
| 84 | let {autoComplete, name = data.name, form = data.form, isDisabled = data.isDisabled} = props; |
| 85 | let {validationBehavior, isRequired} = data; |
| 86 | let {visuallyHiddenProps} = useVisuallyHidden({ |
| 87 | style: { |
| 88 | // Prevent page scrolling. |
| 89 | position: 'fixed', |
| 90 | top: 0, |
| 91 | left: 0 |
| 92 | } |
| 93 | }); |
| 94 | |
| 95 | useFormReset(props.selectRef, state.defaultValue, state.setValue); |
| 96 | useFormValidation( |
| 97 | { |
| 98 | validationBehavior, |
| 99 | focus: () => triggerRef.current?.focus() |
| 100 | }, |
| 101 | state, |
| 102 | props.selectRef |
| 103 | ); |
| 104 | |
| 105 | let setValue = state.setValue; |
| 106 | let onChange = useCallback( |
| 107 | (e: React.ChangeEvent<HTMLSelectElement>) => { |
| 108 | let eventTarget = getEventTarget(e); |
| 109 | if (eventTarget.multiple) { |
| 110 | setValue(Array.from(eventTarget.selectedOptions, option => option.value) as any); |
| 111 | } else { |
| 112 | setValue(e.currentTarget.value as any); |
| 113 | } |
| 114 | }, |
| 115 | [setValue] |
| 116 | ); |
| 117 | |
| 118 | // In Safari, the <select> cannot have `display: none` or `hidden` for autofill to work. |
| 119 | // In Firefox, there must be a <label> to identify the <select> whereas other browsers |
| 120 | // seem to identify it just by surrounding text. |
| 121 | // The solution is to use <VisuallyHidden> to hide the elements, which clips the elements to a |
| 122 | // 1px rectangle. In addition, we hide from screen readers with aria-hidden, and make the <select> |
| 123 | // non tabbable with tabIndex={-1}. |
| 124 | return { |
| 125 | containerProps: { |
| 126 | ...visuallyHiddenProps, |
| 127 | 'aria-hidden': true, |
| 128 | // @ts-ignore |
| 129 | ['data-react-aria-prevent-focus']: true, |
| 130 | // @ts-ignore |
| 131 | ['data-a11y-ignore']: 'aria-hidden-focus' |
| 132 | }, |
| 133 | inputProps: { |
| 134 | style: {display: 'none'} |
| 135 | }, |
no test coverage detected