| 231 | |
| 232 | @Listen('keydown', { target: 'document' }) |
| 233 | onKeydown(ev: any) { |
| 234 | const inputTypes = new Set(this.processedInputs.map((i) => i.type)); |
| 235 | |
| 236 | /** |
| 237 | * Based on keyboard navigation requirements, the |
| 238 | * checkbox should not respond to the enter keydown event. |
| 239 | */ |
| 240 | if (inputTypes.has('checkbox') && ev.key === 'Enter') { |
| 241 | ev.preventDefault(); |
| 242 | return; |
| 243 | } |
| 244 | |
| 245 | /** |
| 246 | * Ensure when alert container is being focused, and the user presses the tab + shift keys, the focus will be set to the last alert button. |
| 247 | */ |
| 248 | if (ev.target.classList.contains('alert-wrapper')) { |
| 249 | if (ev.key === 'Tab' && ev.shiftKey) { |
| 250 | ev.preventDefault(); |
| 251 | const lastChildBtn = this.wrapperEl?.querySelector('.alert-button:last-child') as HTMLButtonElement; |
| 252 | lastChildBtn.focus(); |
| 253 | return; |
| 254 | } |
| 255 | } |
| 256 | |
| 257 | // The only inputs we want to navigate between using arrow keys are the radios |
| 258 | // ignore the keydown event if it is not on a radio button |
| 259 | if ( |
| 260 | !inputTypes.has('radio') || |
| 261 | (ev.target && !this.el.contains(ev.target)) || |
| 262 | ev.target.classList.contains('alert-button') |
| 263 | ) { |
| 264 | return; |
| 265 | } |
| 266 | |
| 267 | // Get all radios inside of the radio group and then |
| 268 | // filter out disabled radios since we need to skip those |
| 269 | const query = this.el.querySelectorAll('.alert-radio') as NodeListOf<HTMLButtonElement>; |
| 270 | const radios = Array.from(query).filter((radio) => !radio.disabled); |
| 271 | |
| 272 | // The focused radio is the one that shares the same id as |
| 273 | // the event target |
| 274 | const index = radios.findIndex((radio) => radio.id === ev.target.id); |
| 275 | |
| 276 | // We need to know what the next radio element should |
| 277 | // be in order to change the focus |
| 278 | let nextEl: HTMLButtonElement | undefined; |
| 279 | |
| 280 | // If hitting arrow down or arrow right, move to the next radio |
| 281 | // If we're on the last radio, move to the first radio |
| 282 | if (['ArrowDown', 'ArrowRight'].includes(ev.key)) { |
| 283 | nextEl = index === radios.length - 1 ? radios[0] : radios[index + 1]; |
| 284 | } |
| 285 | |
| 286 | // If hitting arrow up or arrow left, move to the previous radio |
| 287 | // If we're on the first radio, move to the last radio |
| 288 | if (['ArrowUp', 'ArrowLeft'].includes(ev.key)) { |
| 289 | nextEl = index === 0 ? radios[radios.length - 1] : radios[index - 1]; |
| 290 | } |