Fix navigation in modal + dropdown combination
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
parent
6ea766d93b
commit
f48dc1f0b8
4 changed files with 23 additions and 27 deletions
|
@ -24,9 +24,14 @@ const closeModal = (type?: ModalType) => ({
|
|||
modalType: type,
|
||||
});
|
||||
|
||||
type ModalsAction =
|
||||
ReturnType<typeof openModalSuccess>
|
||||
| ReturnType<typeof closeModal>;
|
||||
|
||||
export {
|
||||
MODAL_OPEN,
|
||||
MODAL_CLOSE,
|
||||
openModal,
|
||||
closeModal,
|
||||
type ModalsAction,
|
||||
};
|
||||
|
|
|
@ -111,6 +111,7 @@ const DropdownMenu = (props: IDropdownMenu) => {
|
|||
const { state } = history.location;
|
||||
if (goBack && state && (state as any).soapboxDropdownKey === dropdownHistoryKey.current) {
|
||||
history.goBack();
|
||||
(history.location.state as any).soapboxDropdownKey = true;
|
||||
}
|
||||
|
||||
closeDropdownMenu();
|
||||
|
@ -145,6 +146,7 @@ const DropdownMenu = (props: IDropdownMenu) => {
|
|||
const handleDocumentClick = (event: Event) => {
|
||||
if (refs.floating.current && !refs.floating.current.contains(event.target as Node)) {
|
||||
handleClose();
|
||||
event.stopPropagation();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -244,7 +246,7 @@ const DropdownMenu = (props: IDropdownMenu) => {
|
|||
|
||||
unlistenHistory.current = history.listen(({ state }, action) => {
|
||||
if (!(state as any)?.soapboxDropdownKey) {
|
||||
handleClose();
|
||||
handleClose(false);
|
||||
} else if (action === 'POP') {
|
||||
handleClose(false);
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import { cancelReplyCompose } from 'soapbox/actions/compose';
|
|||
import { saveDraftStatus } from 'soapbox/actions/draft-statuses';
|
||||
import { cancelEventCompose } from 'soapbox/actions/events';
|
||||
import { openModal, closeModal } from 'soapbox/actions/modals';
|
||||
import { useAppDispatch, usePrevious } from 'soapbox/hooks';
|
||||
import { useAppDispatch, useAppSelector, usePrevious } from 'soapbox/hooks';
|
||||
|
||||
import type { ModalType } from 'soapbox/features/ui/components/modal-root';
|
||||
import type { ReducerCompose } from 'soapbox/reducers/compose';
|
||||
|
@ -49,6 +49,8 @@ const ModalRoot: React.FC<IModalRoot> = ({ children, onCancel, onClose, type })
|
|||
const dispatch = useAppDispatch();
|
||||
|
||||
const [revealed, setRevealed] = useState(!!children);
|
||||
const isDropdownOpen = useAppSelector(state => state.dropdown_menu.isOpen);
|
||||
const wasDropdownOpen = usePrevious(isDropdownOpen);
|
||||
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const activeElement = useRef<HTMLDivElement | null>(revealed ? document.activeElement as HTMLDivElement | null : null);
|
||||
|
@ -56,7 +58,6 @@ const ModalRoot: React.FC<IModalRoot> = ({ children, onCancel, onClose, type })
|
|||
const unlistenHistory = useRef<ReturnType<typeof history.listen>>();
|
||||
|
||||
const prevChildren = usePrevious(children);
|
||||
const prevType = usePrevious(type);
|
||||
|
||||
const visible = !!children;
|
||||
|
||||
|
@ -158,7 +159,7 @@ const ModalRoot: React.FC<IModalRoot> = ({ children, onCancel, onClose, type })
|
|||
});
|
||||
};
|
||||
|
||||
const handleModalClose = (type: string) => {
|
||||
const handleModalClose = () => {
|
||||
if (unlistenHistory.current) {
|
||||
unlistenHistory.current();
|
||||
}
|
||||
|
@ -206,7 +207,7 @@ const ModalRoot: React.FC<IModalRoot> = ({ children, onCancel, onClose, type })
|
|||
activeElement.current = null;
|
||||
getSiblings().forEach(sibling => (sibling as HTMLDivElement).removeAttribute('inert'));
|
||||
|
||||
handleModalClose(prevType!);
|
||||
handleModalClose();
|
||||
}
|
||||
|
||||
if (children) {
|
||||
|
@ -218,6 +219,15 @@ const ModalRoot: React.FC<IModalRoot> = ({ children, onCancel, onClose, type })
|
|||
}
|
||||
}, [children]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isDropdownOpen && unlistenHistory.current) {
|
||||
unlistenHistory.current();
|
||||
} else if (!isDropdownOpen && wasDropdownOpen) {
|
||||
// TODO find a better solution
|
||||
setTimeout(() => handleModalOpen(), 100);
|
||||
}
|
||||
}, [isDropdownOpen]);
|
||||
|
||||
if (!visible) {
|
||||
return (
|
||||
<div className='z-50 transition-all' ref={ref} style={{ opacity: 0 }} />
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import clsx from 'clsx';
|
||||
import { supportsPassiveEvents } from 'detect-passive-events';
|
||||
import React, { useRef, useEffect } from 'react';
|
||||
import React, { useRef } from 'react';
|
||||
import { useIntl, defineMessages, FormattedMessage } from 'react-intl';
|
||||
|
||||
import { changeComposeFederated, changeComposeVisibility } from 'soapbox/actions/compose';
|
||||
|
@ -28,8 +27,6 @@ const messages = defineMessages({
|
|||
local: { id: 'privacy.local', defaultMessage: '{privacy} (local-only)' },
|
||||
});
|
||||
|
||||
const listenerOptions = supportsPassiveEvents ? { passive: true } : false;
|
||||
|
||||
interface Option {
|
||||
icon: string;
|
||||
value: string;
|
||||
|
@ -54,12 +51,6 @@ const PrivacyDropdownMenu: React.FC<IPrivacyDropdownMenu> = ({
|
|||
const node = useRef<HTMLUListElement>(null);
|
||||
const focusedItem = useRef<HTMLLIElement>(null);
|
||||
|
||||
const handleDocumentClick = (e: MouseEvent | TouchEvent) => {
|
||||
if (node.current && !node.current.contains(e.target as HTMLElement)) {
|
||||
onClose();
|
||||
}
|
||||
};
|
||||
|
||||
const handleKeyDown: React.KeyboardEventHandler = e => {
|
||||
const index = [...e.currentTarget.parentElement!.children].indexOf(e.currentTarget);
|
||||
let element: ChildNode | null | undefined = null;
|
||||
|
@ -113,18 +104,6 @@ const PrivacyDropdownMenu: React.FC<IPrivacyDropdownMenu> = ({
|
|||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
document.addEventListener('click', handleDocumentClick, false);
|
||||
document.addEventListener('touchend', handleDocumentClick, listenerOptions);
|
||||
|
||||
focusedItem.current?.focus({ preventScroll: true });
|
||||
|
||||
return () => {
|
||||
document.removeEventListener('click', handleDocumentClick, false);
|
||||
document.removeEventListener('touchend', handleDocumentClick);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<ul ref={node}>
|
||||
{items.map(item => {
|
||||
|
|
Loading…
Reference in a new issue