Spaces, channels, files, members and the account move into a left drawer, the top bar keeps only the essentials, and touch devices get a tap menu instead of always-visible delete buttons. Also fixes the history checkboxes in the channel settings sheet.
30 lines
1.2 KiB
TypeScript
30 lines
1.2 KiB
TypeScript
import { useEffect, useRef, type ReactNode } from 'react';
|
|
import { createPortal } from 'react-dom';
|
|
import { useBackToClose } from '@/lib/useBackToClose';
|
|
import styles from './Drawer.module.css';
|
|
|
|
interface Props { label: string; onClose: () => void; children: ReactNode }
|
|
|
|
/** 手机的左侧抽屉:遮罩是纯色,返回键关闭(与 Sheet 一致) */
|
|
export function Drawer({ label, onClose, children }: Props) {
|
|
const ref = useRef<HTMLDivElement>(null);
|
|
const close = useRef(onClose);
|
|
useEffect(() => { close.current = onClose; }, [onClose]);
|
|
useBackToClose(onClose);
|
|
useEffect(() => {
|
|
const prev = document.activeElement as HTMLElement | null;
|
|
ref.current?.focus();
|
|
const onKey = (event: KeyboardEvent) => { if (event.key === 'Escape') close.current(); };
|
|
window.addEventListener('keydown', onKey);
|
|
return () => { window.removeEventListener('keydown', onKey); prev?.focus(); };
|
|
}, []);
|
|
return createPortal(
|
|
<div className={styles.scrim} onClick={onClose}>
|
|
<div ref={ref} tabIndex={-1} role="dialog" aria-modal="true" aria-label={label} className={styles.drawer} onClick={(event) => event.stopPropagation()}>
|
|
{children}
|
|
</div>
|
|
</div>,
|
|
document.body,
|
|
);
|
|
}
|