Rework the modal close + focus logic

- 'Esc' a modal will focus on "behind" nested modal
- All modals will have 'esc'
This commit is contained in:
Lim Chee Aun 2023-09-14 20:39:23 +08:00
parent fce5e45bc9
commit 27274eeab1
4 changed files with 46 additions and 28 deletions

View file

@ -11,8 +11,6 @@ function AccountSheet({ account, instance: propInstance, onClose }) {
const { masto, instance, authenticated } = api({ instance: propInstance }); const { masto, instance, authenticated } = api({ instance: propInstance });
const isString = typeof account === 'string'; const isString = typeof account === 'string';
const escRef = useHotkeys('esc', onClose, [onClose]);
useEffect(() => { useEffect(() => {
if (!isString) { if (!isString) {
states.accounts[`${account.id}@${instance}`] = account; states.accounts[`${account.id}@${instance}`] = account;

View file

@ -2,10 +2,11 @@ import './modal.css';
import { createPortal } from 'preact/compat'; import { createPortal } from 'preact/compat';
import { useEffect, useRef } from 'preact/hooks'; import { useEffect, useRef } from 'preact/hooks';
import { useHotkeys } from 'react-hotkeys-hook';
const $modalContainer = document.getElementById('modal-container'); const $modalContainer = document.getElementById('modal-container');
function Modal({ children, onClick, class: className }) { function Modal({ children, onClose, onClick, class: className }) {
if (!children) return null; if (!children) return null;
const modalRef = useRef(); const modalRef = useRef();
@ -19,8 +20,28 @@ function Modal({ children, onClick, class: className }) {
return () => clearTimeout(timer); return () => clearTimeout(timer);
}, []); }, []);
const escRef = useHotkeys('esc', onClose, [onClose], {
enabled: !!onClose,
});
const Modal = ( const Modal = (
<div ref={modalRef} className={className} onClick={onClick}> <div
ref={(node) => {
modalRef.current = node;
escRef.current = node?.querySelector?.('[tabindex="-1"]') || node;
}}
className={className}
onClick={(e) => {
onClick?.(e);
if (e.target === e.currentTarget) {
onClose?.(e);
}
}}
tabIndex="-1"
onFocus={(e) => {
modalRef.current?.querySelector?.('[tabindex="-1"]')?.focus?.();
}}
>
{children} {children}
</div> </div>
); );

View file

@ -76,10 +76,8 @@ export default function Modals() {
)} )}
{!!snapStates.showSettings && ( {!!snapStates.showSettings && (
<Modal <Modal
onClick={(e) => { onClose={() => {
if (e.target === e.currentTarget) { states.showSettings = false;
states.showSettings = false;
}
}} }}
> >
<Settings <Settings
@ -91,10 +89,8 @@ export default function Modals() {
)} )}
{!!snapStates.showAccounts && ( {!!snapStates.showAccounts && (
<Modal <Modal
onClick={(e) => { onClose={() => {
if (e.target === e.currentTarget) { states.showAccounts = false;
states.showAccounts = false;
}
}} }}
> >
<Accounts <Accounts
@ -107,10 +103,8 @@ export default function Modals() {
{!!snapStates.showAccount && ( {!!snapStates.showAccount && (
<Modal <Modal
class="light" class="light"
onClick={(e) => { onClose={() => {
if (e.target === e.currentTarget) { states.showAccount = false;
states.showAccount = false;
}
}} }}
> >
<AccountSheet <AccountSheet
@ -127,10 +121,8 @@ export default function Modals() {
)} )}
{!!snapStates.showDrafts && ( {!!snapStates.showDrafts && (
<Modal <Modal
onClick={(e) => { onClose={() => {
if (e.target === e.currentTarget) { states.showDrafts = false;
states.showDrafts = false;
}
}} }}
> >
<Drafts onClose={() => (states.showDrafts = false)} /> <Drafts onClose={() => (states.showDrafts = false)} />
@ -161,10 +153,8 @@ export default function Modals() {
{!!snapStates.showShortcutsSettings && ( {!!snapStates.showShortcutsSettings && (
<Modal <Modal
class="light" class="light"
onClick={(e) => { onClose={() => {
if (e.target === e.currentTarget) { states.showShortcutsSettings = false;
states.showShortcutsSettings = false;
}
}} }}
> >
<ShortcutsSettings <ShortcutsSettings
@ -175,10 +165,8 @@ export default function Modals() {
{!!snapStates.showGenericAccounts && ( {!!snapStates.showGenericAccounts && (
<Modal <Modal
class="light" class="light"
onClick={(e) => { onClose={() => {
if (e.target === e.currentTarget) { states.showGenericAccounts = false;
states.showGenericAccounts = false;
}
}} }}
> >
<GenericAccounts <GenericAccounts

View file

@ -5,6 +5,17 @@ const focusDeck = () => {
// Focus first column // Focus first column
// columns.querySelector('.deck-container')?.focus?.(); // columns.querySelector('.deck-container')?.focus?.();
} else { } else {
const modals = document.querySelectorAll('#modal-container > *');
if (modals?.length) {
// Focus last modal
const modal = modals[modals.length - 1]; // last one
const modalFocusElement =
modal.querySelector('[tabindex="-1"]') || modal;
if (modalFocusElement) {
modalFocusElement.focus();
return;
}
}
const backDrop = document.querySelector('.deck-backdrop'); const backDrop = document.querySelector('.deck-backdrop');
if (backDrop) return; if (backDrop) return;
// Focus last deck // Focus last deck